diff options
-rw-r--r-- | android/console.c | 46 | ||||
-rw-r--r-- | android/display-core.c | 124 | ||||
-rw-r--r-- | android/display-core.h | 34 | ||||
-rw-r--r-- | android/protocol/fb-updates-proxy.c | 70 | ||||
-rw-r--r-- | android/protocol/fb-updates-proxy.h | 13 | ||||
-rw-r--r-- | console.c | 17 | ||||
-rw-r--r-- | console.h | 35 |
7 files changed, 133 insertions, 206 deletions
diff --git a/android/console.c b/android/console.c index d776a5c..d883002 100644 --- a/android/console.c +++ b/android/console.c @@ -121,9 +121,6 @@ typedef struct ControlGlobalRec_ /* UI client currently attached to the core. */ ControlClient attached_ui_client = NULL; -/* Core framebuffer service client. */ -ControlClient framebuffer_client = NULL; - /* User events service client. */ ControlClient user_events_client = NULL; @@ -245,15 +242,6 @@ control_client_destroy( ControlClient client ) attached_ui_client = NULL; } - if (client == framebuffer_client) { - ProxyFramebuffer* core_fb = coredisplay_detach_fb_service(); - if (core_fb != NULL) { - proxyFb_destroy(core_fb); - AFREE(core_fb); - } - framebuffer_client = NULL; - } - if (client == user_events_client) { userEventsImpl_destroy(); user_events_client = NULL; @@ -2525,14 +2513,12 @@ destroy_attach_ui_client(void) } } -/* Core display instance. */ -extern CoreDisplay core_display; - static int do_create_framebuffer_service( ControlClient client, char* args ) { ProxyFramebuffer* core_fb; const char* protocol = "-raw"; // Default framebuffer exchange protocol. + char reply_buf[64]; // Protocol type is defined by the arguments passed with the stream switch // command. @@ -2555,38 +2541,20 @@ do_create_framebuffer_service( ControlClient client, char* args ) } } - // Make sure that there are no framebuffer client already existing. - if (framebuffer_client != NULL) { - control_write( client, "KO: Another framebuffer service is already existing!\r\n" ); - control_client_destroy(client); - return -1; - } - - core_fb = proxyFb_create(client->sock, protocol, coredisplay_get_framebuffer()); - if (!coredisplay_attach_fb_service(core_fb)) { - char reply_buf[4096]; - framebuffer_client = client; - // Reply "OK" with the framebuffer's bits per pixel - snprintf(reply_buf, sizeof(reply_buf), "OK: -bitsperpixel=%d\r\n", - proxyFb_get_bits_per_pixel(core_fb)); - control_write( client, reply_buf); - } else { + core_fb = proxyFb_create(client->sock, protocol); + if (core_fb == NULL) { control_write( client, "KO\r\n" ); control_client_destroy(client); return -1; } + // Reply "OK" with the framebuffer's bits per pixel + snprintf(reply_buf, sizeof(reply_buf), "OK: -bitsperpixel=%d\r\n", + proxyFb_get_bits_per_pixel(core_fb)); + control_write( client, reply_buf); return 0; } -void -destroy_control_fb_client(void) -{ - if (framebuffer_client != NULL) { - control_client_destroy(framebuffer_client); - } -} - static int do_create_user_events_service( ControlClient client, char* args ) { diff --git a/android/display-core.c b/android/display-core.c index 6834cd6..80b7665 100644 --- a/android/display-core.c +++ b/android/display-core.c @@ -15,120 +15,54 @@ * by the core to communicate display changes to the attached UI */ -#include "android/utils/system.h" #include "android/display-core.h" +#include "qemu-common.h" -/* Core display descriptor. */ -struct CoreDisplay { - /* Display state for this core display. */ - DisplayState* ds; - - /* Framebuffer for this core display. */ - QFrameBuffer* fb; - - /* Framebuffer service associated with this core display. */ - ProxyFramebuffer* core_fb; -}; - -/* One and only one core display instance. */ -CoreDisplay core_display; - -/* - * Framebuffer calls this routine when it detects changes. This routine will - * initiate a "push" of the framebuffer changes to the UI. - * See QFrameBufferUpdateFunc in framebuffer.h for more info on this callback. - */ -static void -coredisplay_fb_update(void* opaque, int x, int y, int w, int h) -{ - CoreDisplay* cd = (CoreDisplay*)opaque; - if (cd->core_fb) { - proxyFb_update(cd->core_fb, cd->fb, x, y, w, h); - } -} - -/* - * Framebuffer callback. See QFrameBufferRotateFunc in framebuffer.h for more - * info on this callback. +/* This callback is call periodically by the GUI timer. + * Its purpose is to ensure that hw framebuffer updates are properly + * detected. Call the normal QEMU function for this here. */ static void -coredisplay_fb_rotate(void* opaque, int rotation) +coredisplay_refresh(DisplayState* ds) { + (void)ds; + vga_hw_update(); } -/* - * Framebuffer callback. See QFrameBufferPollFunc in framebuffer.h for more - * info on this callback. +/* Don't do anything here because this callback can't differentiate + * between several listeners. This will be handled by a DisplayUpdateListener + * instead. See Android-specific changes in console.h + * + * In the core, the DisplayUpdateListener is registered by the ProxyFramebuffer + * object. See android/protocol/fb-updates-proxy.c. */ static void -coredisplay_fb_poll(void* opaque) +coredisplay_update(DisplayState* ds, int x, int y, int w, int h) { - // This will eventually call core_display_fb_update. - qframebuffer_check_updates(); + (void)ds; + (void)x; + (void)y; + (void)w; + (void)h; } -/* - * Framebuffer callback. See QFrameBufferDoneFunc in framebuffer.h for more - * info on this callback. +/* This callback is normally used to indicate that the display resolution + * was changed by the guest (e.g. when a Windows PC changes the display from + * 1024x768 to 800x600. Since this doesn't happen in Android, ignore it. */ static void -coredisplay_fb_done(void* opaque) +coredisplay_resize(DisplayState* ds) { + (void)ds; } void coredisplay_init(DisplayState* ds) { - int format; - - core_display.ds = ds; - /* Create and initialize framebuffer instance that will be used for core - * display. - */ - ANEW0(core_display.fb); - core_display.core_fb = NULL; - - /* In the core, there is no skin to parse and the format of ds->surface - * is determined by the -android-gui option. - */ - format = QFRAME_BUFFER_RGB565; - if (ds->surface->pf.bytes_per_pixel == 4) - format = QFRAME_BUFFER_RGBX_8888; - - qframebuffer_init(core_display.fb, ds->surface->width, ds->surface->height, - 0, format); - qframebuffer_fifo_add(core_display.fb); - /* Register core display as the client for the framebuffer, so we can start - * receiving framebuffer notifications. Note that until UI connects to the - * core all framebuffer callbacks are essentially no-ops. - */ - qframebuffer_add_client(core_display.fb, &core_display, - coredisplay_fb_update, coredisplay_fb_rotate, - coredisplay_fb_poll, coredisplay_fb_done); - android_display_init(ds, core_display.fb); -} - -int -coredisplay_attach_fb_service(ProxyFramebuffer* core_fb) -{ - if (core_display.core_fb == NULL) { - core_display.core_fb = core_fb; - return 0; - } else { - return -1; - } -} - -ProxyFramebuffer* -coredisplay_detach_fb_service(void) -{ - ProxyFramebuffer* ret = core_display.core_fb; - core_display.core_fb = NULL; - return ret; -} + static DisplayChangeListener dcl[1]; -QFrameBuffer* -coredisplay_get_framebuffer(void) -{ - return core_display.fb; + dcl->dpy_update = coredisplay_update; + dcl->dpy_refresh = coredisplay_refresh; + dcl->dpy_resize = coredisplay_resize; + register_displaychangelistener(ds, dcl); } diff --git a/android/display-core.h b/android/display-core.h index edeccac..e6a1b7d 100644 --- a/android/display-core.h +++ b/android/display-core.h @@ -18,42 +18,14 @@ #ifndef _ANDROID_DISPLAY_CORE_H #define _ANDROID_DISPLAY_CORE_H -#include "android/framebuffer.h" -#include "android/display.h" -#include "android/protocol/fb-updates-proxy.h" - -/* Descriptor for a core display instance */ -typedef struct CoreDisplay CoreDisplay; +#include "console.h" /* * Initializes one and only one instance of a core display. - * Param: + * Only used to register a dummy display change listener that + * will trigger a timer. * ds - Display state to use for the core display. */ extern void coredisplay_init(DisplayState* ds); -/* - * Attaches framebuffer service to the core display. - * Param: - * core_fb - Framebuffer service descriptor to attach. - * Return: - * 0 on success, or -1 on failure. - */ -extern int coredisplay_attach_fb_service(ProxyFramebuffer* core_fb); - -/* - * Detaches framebuffer service previously attached to the core display. - * Return: - * Framebuffer service descriptor attached to the core display, or NULL if - * the core display didn't have framebuffer service attached to it. - */ -extern ProxyFramebuffer* coredisplay_detach_fb_service(void); - -/* - * Get framebuffer descriptor for core display. - * Return: - * Framebuffer descriptor for core display. - */ -extern QFrameBuffer* coredisplay_get_framebuffer(void); - #endif /* _ANDROID_DISPLAY_CORE_H */ diff --git a/android/protocol/fb-updates-proxy.c b/android/protocol/fb-updates-proxy.c index 359c942..ec7414d 100644 --- a/android/protocol/fb-updates-proxy.c +++ b/android/protocol/fb-updates-proxy.c @@ -16,7 +16,6 @@ */ #include "console.h" -#include "android/framebuffer.h" #include "android/looper.h" #include "android/display-core.h" #include "android/async-utils.h" @@ -37,8 +36,9 @@ struct ProxyFramebuffer { /* I/O associated with this descriptor. */ LoopIo io; - /* Framebuffer used for this service. */ - QFrameBuffer* fb; + /* Display state used for this service */ + DisplayState* ds; + DisplayUpdateListener* ds_listener; /* Looper used to communicate framebuffer updates. */ Looper* looper; @@ -80,9 +80,9 @@ typedef struct FBUpdateNotify { * Pointer in framebuffer's pixels for the given pixel. */ static const uint8_t* -_pixel_offset(const QFrameBuffer* fb, int x, int y) +_pixel_offset(const DisplaySurface* dsu, int x, int y) { - return (const uint8_t*)fb->pixels + y * fb->pitch + x * fb->bytes_per_pixel; + return (const uint8_t*)dsu->data + y * dsu->linesize + x * dsu->pf.bytes_per_pixel; } /* @@ -93,13 +93,13 @@ _pixel_offset(const QFrameBuffer* fb, int x, int y) * x, y, w, and h - dimensions of the rectangle to copy. */ static void -_copy_fb_rect(uint8_t* rect, const QFrameBuffer* fb, int x, int y, int w, int h) +_copy_fb_rect(uint8_t* rect, const DisplaySurface* dsu, int x, int y, int w, int h) { - const uint8_t* start = _pixel_offset(fb, x, y); + const uint8_t* start = _pixel_offset(dsu, x, y); for (; h > 0; h--) { - memcpy(rect, start, w * fb->bytes_per_pixel); - start += fb->pitch; - rect += w * fb->bytes_per_pixel; + memcpy(rect, start, w * dsu->pf.bytes_per_pixel); + start += dsu->linesize; + rect += w * dsu->pf.bytes_per_pixel; } } @@ -113,10 +113,10 @@ _copy_fb_rect(uint8_t* rect, const QFrameBuffer* fb, int x, int y, int w, int h) * Initialized framebuffer update notification descriptor. */ static FBUpdateNotify* -fbupdatenotify_create(ProxyFramebuffer* proxy_fb, const QFrameBuffer* fb, +fbupdatenotify_create(ProxyFramebuffer* proxy_fb, int x, int y, int w, int h) { - const size_t rect_size = w * h * fb->bytes_per_pixel; + const size_t rect_size = w * h * proxy_fb->ds->surface->pf.bytes_per_pixel; FBUpdateNotify* ret = malloc(sizeof(FBUpdateNotify) + rect_size); ret->next_fb_update = NULL; @@ -126,7 +126,7 @@ fbupdatenotify_create(ProxyFramebuffer* proxy_fb, const QFrameBuffer* fb, ret->message.y = y; ret->message.w = w; ret->message.h = h; - _copy_fb_rect(ret->message.rect, fb, x, y, w, h); + _copy_fb_rect(ret->message.rect, proxy_fb->ds->surface, x, y, w, h); return ret; } @@ -143,9 +143,6 @@ fbupdatenotify_delete(FBUpdateNotify* desc) } } -/* Implemented in android/console.c */ -extern void destroy_control_fb_client(void); - /* * Asynchronous write I/O callback launched when writing framebuffer * notifications to the socket. @@ -191,6 +188,8 @@ _proxyFb_io_write(ProxyFramebuffer* proxy_fb) } } +static void proxyFb_update(void* opaque, int x, int y, int w, int h); + /* * Asynchronous read I/O callback launched when reading framebuffer requests * from the socket. @@ -201,6 +200,7 @@ static void _proxyFb_io_read(ProxyFramebuffer* proxy_fb) { // Read the request header. + DisplaySurface* dsu; const AsyncStatus status = asyncReader_read(&proxy_fb->fb_req_reader, &proxy_fb->io); switch (status) { @@ -209,9 +209,9 @@ _proxyFb_io_read(ProxyFramebuffer* proxy_fb) switch (proxy_fb->fb_req_header.request_type) { case AFB_REQUEST_REFRESH: // Force full screen update to be sent - proxyFb_update(proxy_fb, proxy_fb->fb, - 0, 0, proxy_fb->fb->width, - proxy_fb->fb->height); + dsu = proxy_fb->ds->surface; + proxyFb_update(proxy_fb, + 0, 0, dsu->width, dsu->height); break; default: derror("Unknown framebuffer request %d\n", @@ -226,7 +226,7 @@ _proxyFb_io_read(ProxyFramebuffer* proxy_fb) loopIo_dontWantRead(&proxy_fb->io); if (errno == ECONNRESET) { // UI has exited. We need to destroy framebuffer service. - destroy_control_fb_client(); + proxyFb_destroy(proxy_fb); } break; @@ -253,14 +253,24 @@ _proxyFb_io_fun(void* opaque, int fd, unsigned events) } ProxyFramebuffer* -proxyFb_create(int sock, const char* protocol, QFrameBuffer* fb) +proxyFb_create(int sock, const char* protocol) { // At this point we're implementing the -raw protocol only. ProxyFramebuffer* ret; + DisplayState* ds = get_displaystate(); + DisplayUpdateListener* dul; + ANEW0(ret); ret->sock = sock; ret->looper = looper_newCore(); - ret->fb = fb; + ret->ds = ds; + + ANEW0(dul); + dul->opaque = ret; + dul->dpy_update = proxyFb_update; + register_displayupdatelistener(ds, dul); + ret->ds_listener = dul; + ret->fb_update_head = NULL; ret->fb_update_tail = NULL; loopIo_init(&ret->io, ret->looper, sock, _proxyFb_io_fun, ret); @@ -273,6 +283,7 @@ void proxyFb_destroy(ProxyFramebuffer* proxy_fb) { if (proxy_fb != NULL) { + unregister_displayupdatelistener(proxy_fb->ds, proxy_fb->ds_listener); if (proxy_fb->looper != NULL) { // Stop all I/O that may still be going on. loopIo_done(&proxy_fb->io); @@ -286,15 +297,16 @@ proxyFb_destroy(ProxyFramebuffer* proxy_fb) looper_free(proxy_fb->looper); proxy_fb->looper = NULL; } + AFREE(proxy_fb); } } -void -proxyFb_update(ProxyFramebuffer* proxy_fb, - struct QFrameBuffer* fb, int x, int y, int w, int h) +static void +proxyFb_update(void* opaque, int x, int y, int w, int h) { + ProxyFramebuffer* proxy_fb = opaque; AsyncStatus status; - FBUpdateNotify* descr = fbupdatenotify_create(proxy_fb, fb, x, y, w, h); + FBUpdateNotify* descr = fbupdatenotify_create(proxy_fb, x, y, w, h); // Lets see if we should list it behind other pending updates. if (proxy_fb->fb_update_tail != NULL) { @@ -327,6 +339,8 @@ proxyFb_update(ProxyFramebuffer* proxy_fb, int proxyFb_get_bits_per_pixel(ProxyFramebuffer* proxy_fb) { - return (proxy_fb != NULL && proxy_fb->fb != NULL) ? - proxy_fb->fb->bits_per_pixel : -1; + if (proxy_fb == NULL || proxy_fb->ds == NULL) + return -1; + + return proxy_fb->ds->surface->pf.bits_per_pixel; } diff --git a/android/protocol/fb-updates-proxy.h b/android/protocol/fb-updates-proxy.h index e750f1a..15b1d5b 100644 --- a/android/protocol/fb-updates-proxy.h +++ b/android/protocol/fb-updates-proxy.h @@ -29,11 +29,10 @@ typedef struct ProxyFramebuffer ProxyFramebuffer; * supported values ar: * -raw Transfers the updating rectangle buffer over the socket. * -shared Used a shared memory to transfer the updating rectangle buffer. - * fb - Framebuffer descriptor for this service. * Return: * Framebuffer service descriptor. */ -ProxyFramebuffer* proxyFb_create(int sock, const char* protocol, struct QFrameBuffer* fb); +ProxyFramebuffer* proxyFb_create(int sock, const char* protocol); /* * Destroys framebuffer service created with proxyFb_create. @@ -43,16 +42,6 @@ ProxyFramebuffer* proxyFb_create(int sock, const char* protocol, struct QFrameBu void proxyFb_destroy(ProxyFramebuffer* core_fb); /* - * Notifies framebuffer client about changes in framebuffer. - * Param: - * core_fb - Framebuffer service descriptor created with proxyFb_create - * fb Framebuffer containing pixels. - * x, y, w, and h identify the rectangle that has benn changed. - */ -void proxyFb_update(ProxyFramebuffer* core_fb, struct QFrameBuffer* fb, - int x, int y, int w, int h); - -/* * Gets number of bits used to encode a single pixel. * Param: * core_fb - Framebuffer service descriptor created with proxyFb_create @@ -1733,6 +1733,23 @@ PixelFormat qemu_default_pixelformat(int bpp) } #ifdef CONFIG_ANDROID + +void +unregister_displayupdatelistener(DisplayState *ds, DisplayUpdateListener *dul) +{ + DisplayUpdateListener **pnode = &ds->update_listeners; + for (;;) { + if (*pnode == NULL) + break; + if (*pnode == dul) { + *pnode = dul->next; + break; + } + pnode = &(*pnode)->next; + } + dul->next = NULL; +} + void android_display_reset(DisplayState* ds, int width, int height, int bitspp) { @@ -169,6 +169,19 @@ struct DisplayChangeListener { struct DisplayChangeListener *next; }; +#ifdef CONFIG_ANDROID +/* The problem with DisplayChangeListener is that the callbacks can't + * differentiate between different DisplayChangeListeners. Instead of + * modifying the type above, which is going to generate conflicts with + * upstream changes, we define our own listener type here. + */ +typedef struct DisplayUpdateListener { + void* opaque; + void (*dpy_update)(void* opaque, int x, int y, int w, int h); + struct DisplayUpdateListener *next; +} DisplayUpdateListener; +#endif + struct DisplayAllocator { DisplaySurface* (*create_displaysurface)(int width, int height); DisplaySurface* (*resize_displaysurface)(DisplaySurface *surface, int width, int height); @@ -182,7 +195,9 @@ struct DisplayState { struct DisplayAllocator* allocator; struct DisplayChangeListener* listeners; - +#ifdef CONFIG_ANDROID + struct DisplayUpdateListener* update_listeners; +#endif void (*mouse_set)(int x, int y, int on); void (*cursor_define)(QEMUCursor *cursor); @@ -233,6 +248,17 @@ static inline void register_displaychangelistener(DisplayState *ds, DisplayChang ds->listeners = dcl; } +#ifdef CONFIG_ANDROID +static inline void register_displayupdatelistener(DisplayState *ds, DisplayUpdateListener *dul) +{ + dul->next = ds->update_listeners; + ds->update_listeners = dul; +} + +void unregister_displayupdatelistener(DisplayState *ds, DisplayUpdateListener *dul); + +#endif + static inline void dpy_update(DisplayState *s, int x, int y, int w, int h) { struct DisplayChangeListener *dcl = s->listeners; @@ -240,6 +266,13 @@ static inline void dpy_update(DisplayState *s, int x, int y, int w, int h) dcl->dpy_update(s, x, y, w, h); dcl = dcl->next; } +#ifdef CONFIG_ANDROID + DisplayUpdateListener* dul = s->update_listeners; + while (dul != NULL) { + dul->dpy_update(dul->opaque, x, y, w, h); + dul = dul->next; + } +#endif } static inline void dpy_resize(DisplayState *s) |