aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid 'Digit' Turner <digit@android.com>2011-02-02 15:58:45 +0100
committerDavid 'Digit' Turner <digit@android.com>2011-02-02 21:09:41 +0100
commit7a5ee57895822a769f48ab40e590711a2459e2d1 (patch)
tree1c4ff6ef3cc7bd0c944b65385bba8782de35c875
parentce747472342237e882369e486254684ab7708362 (diff)
downloadexternal_qemu-7a5ee57895822a769f48ab40e590711a2459e2d1.zip
external_qemu-7a5ee57895822a769f48ab40e590711a2459e2d1.tar.gz
external_qemu-7a5ee57895822a769f48ab40e590711a2459e2d1.tar.bz2
Simplify core framebuffer management.
Remove one layer of indirection between the core's DisplayState and a ProxyFramebuffer object. The main ideas behind this patch are that: - We don't need a QFrameBuffer object when in the core process, each proxy can receive display updates directly from QEMU. - The DisplayChangeListener is really lame: its can't dissociate between several listeners that use the same callback pointers, so introduce DisplayUpdateListener in console.h to work around this. This is preferably to modifying DisplayChangeListener which is going to introduce conflicts with upstream. - Simplify a lot the console code and display-core. Note that we can have several framebuffer clients at the same time now. Note that QFrameBuffer is still used by both the UI program and the standalone emulator. Change-Id: I6d5ad6ecd9b34b9d9d1a30ea5000e875c285e84e
-rw-r--r--android/console.c46
-rw-r--r--android/display-core.c124
-rw-r--r--android/display-core.h34
-rw-r--r--android/protocol/fb-updates-proxy.c70
-rw-r--r--android/protocol/fb-updates-proxy.h13
-rw-r--r--console.c17
-rw-r--r--console.h35
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
diff --git a/console.c b/console.c
index 5c9a16b..f6694b2 100644
--- a/console.c
+++ b/console.c
@@ -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)
{
diff --git a/console.h b/console.h
index bfbc71c..eda9207 100644
--- a/console.h
+++ b/console.h
@@ -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)