From 94a2fba98924c6684650d66409934358cb0c9d09 Mon Sep 17 00:00:00 2001 From: Vladimir Chtchetkine Date: Mon, 31 Jan 2011 10:49:06 -0800 Subject: Refactor the framebuffer service Change-Id: I8ac4580af65b8d58976c97b77b309dd202e75003 --- android/console.c | 12 +- android/display-core.c | 10 +- android/display-core.h | 6 +- android/framebuffer-common.h | 45 ----- android/framebuffer-core.c | 330 ----------------------------------- android/framebuffer-core.h | 64 ------- android/framebuffer-ui.c | 281 ------------------------------ android/framebuffer-ui.h | 52 ------ android/main-ui.c | 10 +- android/protocol/fb-updates-impl.c | 264 ++++++++++++++++++++++++++++ android/protocol/fb-updates-impl.h | 44 +++++ android/protocol/fb-updates-proxy.c | 332 ++++++++++++++++++++++++++++++++++++ android/protocol/fb-updates-proxy.h | 64 +++++++ android/protocol/fb-updates.h | 45 +++++ 14 files changed, 766 insertions(+), 793 deletions(-) delete mode 100644 android/framebuffer-common.h delete mode 100644 android/framebuffer-core.c delete mode 100644 android/framebuffer-core.h delete mode 100644 android/framebuffer-ui.c delete mode 100644 android/framebuffer-ui.h create mode 100644 android/protocol/fb-updates-impl.c create mode 100644 android/protocol/fb-updates-impl.h create mode 100644 android/protocol/fb-updates-proxy.c create mode 100644 android/protocol/fb-updates-proxy.h create mode 100644 android/protocol/fb-updates.h (limited to 'android') diff --git a/android/console.c b/android/console.c index 59610eb..e797d9e 100644 --- a/android/console.c +++ b/android/console.c @@ -51,7 +51,7 @@ #include "android/keycode-array.h" #include "android/charmap.h" #include "android/display-core.h" -#include "android/framebuffer-core.h" +#include "android/protocol/fb-updates-proxy.h" #include "android/protocol/user-events-impl.h" #include "android/protocol/ui-commands-api.h" #include "android/protocol/core-commands-impl.h" @@ -247,9 +247,9 @@ control_client_destroy( ControlClient client ) } if (client == framebuffer_client) { - CoreFramebuffer* core_fb = coredisplay_detach_fb_service(); + ProxyFramebuffer* core_fb = coredisplay_detach_fb_service(); if (core_fb != NULL) { - corefb_destroy(core_fb); + proxyFb_destroy(core_fb); AFREE(core_fb); } framebuffer_client = NULL; @@ -2523,7 +2523,7 @@ extern CoreDisplay core_display; static int do_create_framebuffer_service( ControlClient client, char* args ) { - CoreFramebuffer* core_fb; + ProxyFramebuffer* core_fb; const char* protocol = "-raw"; // Default framebuffer exchange protocol. // Protocol type is defined by the arguments passed with the stream switch @@ -2554,13 +2554,13 @@ do_create_framebuffer_service( ControlClient client, char* args ) return -1; } - core_fb = corefb_create(client->sock, protocol, coredisplay_get_framebuffer()); + 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", - corefb_get_bits_per_pixel(core_fb)); + proxyFb_get_bits_per_pixel(core_fb)); control_write( client, reply_buf); } else { control_write( client, "KO\r\n" ); diff --git a/android/display-core.c b/android/display-core.c index 27b0706..6834cd6 100644 --- a/android/display-core.c +++ b/android/display-core.c @@ -27,7 +27,7 @@ struct CoreDisplay { QFrameBuffer* fb; /* Framebuffer service associated with this core display. */ - CoreFramebuffer* core_fb; + ProxyFramebuffer* core_fb; }; /* One and only one core display instance. */ @@ -43,7 +43,7 @@ coredisplay_fb_update(void* opaque, int x, int y, int w, int h) { CoreDisplay* cd = (CoreDisplay*)opaque; if (cd->core_fb) { - corefb_update(cd->core_fb, cd->fb, x, y, w, h); + proxyFb_update(cd->core_fb, cd->fb, x, y, w, h); } } @@ -109,7 +109,7 @@ coredisplay_init(DisplayState* ds) } int -coredisplay_attach_fb_service(CoreFramebuffer* core_fb) +coredisplay_attach_fb_service(ProxyFramebuffer* core_fb) { if (core_display.core_fb == NULL) { core_display.core_fb = core_fb; @@ -119,10 +119,10 @@ coredisplay_attach_fb_service(CoreFramebuffer* core_fb) } } -CoreFramebuffer* +ProxyFramebuffer* coredisplay_detach_fb_service(void) { - CoreFramebuffer* ret = core_display.core_fb; + ProxyFramebuffer* ret = core_display.core_fb; core_display.core_fb = NULL; return ret; } diff --git a/android/display-core.h b/android/display-core.h index 4e1d07f..6204e56 100644 --- a/android/display-core.h +++ b/android/display-core.h @@ -20,7 +20,7 @@ #include "framebuffer.h" #include "android/display.h" -#include "android/framebuffer-core.h" +#include "android/protocol/fb-updates-proxy.h" /* Descriptor for a core display instance */ typedef struct CoreDisplay CoreDisplay; @@ -39,7 +39,7 @@ extern void coredisplay_init(DisplayState* ds); * Return: * 0 on success, or -1 on failure. */ -extern int coredisplay_attach_fb_service(CoreFramebuffer* core_fb); +extern int coredisplay_attach_fb_service(ProxyFramebuffer* core_fb); /* * Detaches framebuffer service previously attached to the core display. @@ -47,7 +47,7 @@ extern int coredisplay_attach_fb_service(CoreFramebuffer* core_fb); * Framebuffer service descriptor attached to the core display, or NULL if * the core display didn't have framebuffer service attached to it. */ -extern CoreFramebuffer* coredisplay_detach_fb_service(void); +extern ProxyFramebuffer* coredisplay_detach_fb_service(void); /* * Get framebuffer descriptor for core display. diff --git a/android/framebuffer-common.h b/android/framebuffer-common.h deleted file mode 100644 index da773b7..0000000 --- a/android/framebuffer-common.h +++ /dev/null @@ -1,45 +0,0 @@ -/* Copyright (C) 2010 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ - -/* - * Contains framebuffer declarations that are shared by the core and the UI. - */ - -#ifndef _ANDROID_FRAMEBUFFER_COMMON_H -#define _ANDROID_FRAMEBUFFER_COMMON_H - -#include "sysemu.h" - -/* Header of framebuffer update message sent from the core to the UI. */ -typedef struct FBUpdateMessage { - /* x, y, w, and h identify the rectangle that is being updated. */ - uint16_t x; - uint16_t y; - uint16_t w; - uint16_t h; - - /* Contains updating rectangle copied over from the framebuffer's pixels. */ - uint8_t rect[0]; -} FBUpdateMessage; - -/* Requests the service to refresh framebuffer. */ -#define AFB_REQUEST_REFRESH 1 - -/* Header for framebuffer requests sent from the client (UI) - * to the service (core). - */ -typedef struct FBRequestHeader { - /* Request type. See AFB_REQUEST_XXX for the values. */ - uint8_t request_type; -} FBRequestHeader; - -#endif /* _ANDROID_FRAMEBUFFER_UI_H */ diff --git a/android/framebuffer-core.c b/android/framebuffer-core.c deleted file mode 100644 index 89b7b46..0000000 --- a/android/framebuffer-core.c +++ /dev/null @@ -1,330 +0,0 @@ -/* Copyright (C) 2010 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ - -/* - * Contains core-side framebuffer service that sends framebuffer updates - * to the UI connected to the core. - */ - -#include "console.h" -#include "framebuffer.h" -#include "android/looper.h" -#include "android/display-core.h" -#include "android/async-utils.h" -#include "android/framebuffer-common.h" -#include "android/framebuffer-core.h" -#include "android/utils/system.h" -#include "android/utils/debug.h" - -/* Core framebuffer descriptor. */ -struct CoreFramebuffer { - /* Writer used to send FB update notification messages. */ - AsyncWriter fb_update_writer; - - /* Reader used to read FB requests from the client. */ - AsyncReader fb_req_reader; - - /* I/O associated with this descriptor. */ - LoopIo io; - - /* Framebuffer used for this service. */ - QFrameBuffer* fb; - - /* Looper used to communicate framebuffer updates. */ - Looper* looper; - - /* Head of the list of pending FB update notifications. */ - struct FBUpdateNotify* fb_update_head; - - /* Tail of the list of pending FB update notifications. */ - struct FBUpdateNotify* fb_update_tail; - - /* Socket used to communicate framebuffer updates. */ - int sock; - - /* Framebuffer request header. */ - FBRequestHeader fb_req_header; -}; - -/* Framebuffer update notification descriptor to the core. */ -typedef struct FBUpdateNotify { - /* Links all pending FB update notifications. */ - struct FBUpdateNotify* next_fb_update; - - /* Core framebuffer instance that owns the message. */ - CoreFramebuffer* core_fb; - - /* Size of the message to transfer. */ - size_t message_size; - - /* Update message. */ - FBUpdateMessage message; -} FBUpdateNotify; - -/* - * Gets pointer in framebuffer's pixels for the given pixel. - * Param: - * fb Framebuffer containing pixels. - * x, and y identify the pixel to get pointer for. - * Return: - * Pointer in framebuffer's pixels for the given pixel. - */ -static const uint8_t* -_pixel_offset(const QFrameBuffer* fb, int x, int y) -{ - return (const uint8_t*)fb->pixels + y * fb->pitch + x * fb->bytes_per_pixel; -} - -/* - * Copies pixels from a framebuffer rectangle. - * Param: - * rect - Buffer where to copy pixel. - * fb - Framebuffer containing the rectangle to copy. - * 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) -{ - const uint8_t* start = _pixel_offset(fb, x, y); - for (; h > 0; h--) { - memcpy(rect, start, w * fb->bytes_per_pixel); - start += fb->pitch; - rect += w * fb->bytes_per_pixel; - } -} - -/* - * Allocates and initializes framebuffer update notification descriptor. - * Param: - * ds - Display state for the framebuffer. - * fb Framebuffer containing pixels. - * x, y, w, and h identify the rectangle that is being updated. - * Return: - * Initialized framebuffer update notification descriptor. - */ -static FBUpdateNotify* -fbupdatenotify_create(CoreFramebuffer* core_fb, const QFrameBuffer* fb, - int x, int y, int w, int h) -{ - const size_t rect_size = w * h * fb->bytes_per_pixel; - FBUpdateNotify* ret = malloc(sizeof(FBUpdateNotify) + rect_size); - - ret->next_fb_update = NULL; - ret->core_fb = core_fb; - ret->message_size = sizeof(FBUpdateMessage) + rect_size; - ret->message.x = x; - ret->message.y = y; - ret->message.w = w; - ret->message.h = h; - _copy_fb_rect(ret->message.rect, fb, x, y, w, h); - return ret; -} - -/* - * Deletes FBUpdateNotify descriptor, created with fbupdatenotify_create. - * Param: - * desc - Descreptor to delete. - */ -static void -fbupdatenotify_delete(FBUpdateNotify* desc) -{ - if (desc != NULL) { - free(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. - * Param: - * core_fb - CoreFramebuffer instance. - */ -static void -corefb_io_write(CoreFramebuffer* core_fb) -{ - while (core_fb->fb_update_head != NULL) { - FBUpdateNotify* current_update = core_fb->fb_update_head; - // Lets continue writing of the current notification. - const AsyncStatus status = - asyncWriter_write(&core_fb->fb_update_writer, &core_fb->io); - switch (status) { - case ASYNC_COMPLETE: - // Done with the current update. Move on to the next one. - break; - case ASYNC_ERROR: - // Done with the current update. Move on to the next one. - loopIo_dontWantWrite(&core_fb->io); - break; - - case ASYNC_NEED_MORE: - // Transfer will eventually come back into this routine. - return; - } - - // Advance the list of updates - core_fb->fb_update_head = current_update->next_fb_update; - if (core_fb->fb_update_head == NULL) { - core_fb->fb_update_tail = NULL; - } - fbupdatenotify_delete(current_update); - - if (core_fb->fb_update_head != NULL) { - // Schedule the next one. - asyncWriter_init(&core_fb->fb_update_writer, - &core_fb->fb_update_head->message, - core_fb->fb_update_head->message_size, - &core_fb->io); - } - } -} - -/* - * Asynchronous read I/O callback launched when reading framebuffer requests - * from the socket. - * Param: - * core_fb - CoreFramebuffer instance. - */ -static void -corefb_io_read(CoreFramebuffer* core_fb) -{ - // Read the request header. - const AsyncStatus status = - asyncReader_read(&core_fb->fb_req_reader, &core_fb->io); - switch (status) { - case ASYNC_COMPLETE: - // Request header is received - switch (core_fb->fb_req_header.request_type) { - case AFB_REQUEST_REFRESH: - // Force full screen update to be sent - corefb_update(core_fb, core_fb->fb, - 0, 0, core_fb->fb->width, core_fb->fb->height); - break; - default: - derror("Unknown framebuffer request %d\n", - core_fb->fb_req_header.request_type); - break; - } - core_fb->fb_req_header.request_type = -1; - asyncReader_init(&core_fb->fb_req_reader, &core_fb->fb_req_header, - sizeof(core_fb->fb_req_header), &core_fb->io); - break; - case ASYNC_ERROR: - loopIo_dontWantRead(&core_fb->io); - if (errno == ECONNRESET) { - // UI has exited. We need to destroy framebuffer service. - destroy_control_fb_client(); - } - break; - - case ASYNC_NEED_MORE: - // Transfer will eventually come back into this routine. - return; - } -} - -/* - * Asynchronous I/O callback launched when writing framebuffer notifications - * to the socket. - * Param: - * opaque - CoreFramebuffer instance. - */ -static void -corefb_io_func(void* opaque, int fd, unsigned events) -{ - if (events & LOOP_IO_READ) { - corefb_io_read((CoreFramebuffer*)opaque); - } else if (events & LOOP_IO_WRITE) { - corefb_io_write((CoreFramebuffer*)opaque); - } -} - -CoreFramebuffer* -corefb_create(int sock, const char* protocol, QFrameBuffer* fb) -{ - // At this point we're implementing the -raw protocol only. - CoreFramebuffer* ret; - ANEW0(ret); - ret->sock = sock; - ret->looper = looper_newCore(); - ret->fb = fb; - ret->fb_update_head = NULL; - ret->fb_update_tail = NULL; - loopIo_init(&ret->io, ret->looper, sock, corefb_io_func, ret); - asyncReader_init(&ret->fb_req_reader, &ret->fb_req_header, - sizeof(ret->fb_req_header), &ret->io); - return ret; -} - -void -corefb_destroy(CoreFramebuffer* core_fb) -{ - if (core_fb != NULL) { - if (core_fb->looper != NULL) { - // Stop all I/O that may still be going on. - loopIo_done(&core_fb->io); - // Delete all pending frame updates. - while (core_fb->fb_update_head != NULL) { - FBUpdateNotify* pending_update = core_fb->fb_update_head; - core_fb->fb_update_head = pending_update->next_fb_update; - fbupdatenotify_delete(pending_update); - } - core_fb->fb_update_tail = NULL; - looper_free(core_fb->looper); - core_fb->looper = NULL; - } - } -} - -void -corefb_update(CoreFramebuffer* core_fb, - struct QFrameBuffer* fb, int x, int y, int w, int h) -{ - AsyncStatus status; - FBUpdateNotify* descr = fbupdatenotify_create(core_fb, fb, x, y, w, h); - - // Lets see if we should list it behind other pending updates. - if (core_fb->fb_update_tail != NULL) { - core_fb->fb_update_tail->next_fb_update = descr; - core_fb->fb_update_tail = descr; - return; - } - - // We're first in the list. Just send it now. - core_fb->fb_update_head = core_fb->fb_update_tail = descr; - asyncWriter_init(&core_fb->fb_update_writer, - &core_fb->fb_update_head->message, - core_fb->fb_update_head->message_size, &core_fb->io); - status = asyncWriter_write(&core_fb->fb_update_writer, &core_fb->io); - switch (status) { - case ASYNC_COMPLETE: - fbupdatenotify_delete(descr); - core_fb->fb_update_head = core_fb->fb_update_tail = NULL; - return; - case ASYNC_ERROR: - fbupdatenotify_delete(descr); - core_fb->fb_update_head = core_fb->fb_update_tail = NULL; - return; - case ASYNC_NEED_MORE: - // Update transfer will eventually complete in corefb_io_func - return; - } -} - -int -corefb_get_bits_per_pixel(CoreFramebuffer* core_fb) -{ - return (core_fb != NULL && core_fb->fb != NULL) ? - core_fb->fb->bits_per_pixel : -1; -} diff --git a/android/framebuffer-core.h b/android/framebuffer-core.h deleted file mode 100644 index 773c248..0000000 --- a/android/framebuffer-core.h +++ /dev/null @@ -1,64 +0,0 @@ -/* Copyright (C) 2010 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ - -/* - * Contains core-side framebuffer service that sends framebuffer updates - * to the UI connected to the core. - */ - -#ifndef _ANDROID_FRAMEBUFFER_CORE_H -#define _ANDROID_FRAMEBUFFER_CORE_H - -/* Descriptor for a framebuffer core service instance */ -typedef struct CoreFramebuffer CoreFramebuffer; - -/* - * Creates framebuffer service. - * Param: - * sock - Socket descriptor for the service - * protocol - Defines protocol to use when sending FB updates to the UI. The - * 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. - */ -CoreFramebuffer* corefb_create(int sock, const char* protocol, struct QFrameBuffer* fb); - -/* - * Destroys framebuffer service created with corefb_create. - * Param: - * core_fb - Framebuffer service descriptor created with corefb_create - */ -void corefb_destroy(CoreFramebuffer* core_fb); - -/* - * Notifies framebuffer client about changes in framebuffer. - * Param: - * core_fb - Framebuffer service descriptor created with corefb_create - * fb Framebuffer containing pixels. - * x, y, w, and h identify the rectangle that has benn changed. - */ -void corefb_update(CoreFramebuffer* 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 corefb_create - * Return: - * Number of bits used to encode a single pixel. - */ -int corefb_get_bits_per_pixel(CoreFramebuffer* core_fb); - -#endif /* _ANDROID_FRAMEBUFFER_CORE_H */ diff --git a/android/framebuffer-ui.c b/android/framebuffer-ui.c deleted file mode 100644 index 0ae109f..0000000 --- a/android/framebuffer-ui.c +++ /dev/null @@ -1,281 +0,0 @@ -/* Copyright (C) 2010 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ - -/* - * Contains UI-side framebuffer client that receives framebuffer updates - * from the core. - */ - -#include "android/framebuffer-common.h" -#include "android/framebuffer-ui.h" -#include "android/utils/system.h" -#include "android/utils/debug.h" -#include "android/sync-utils.h" - -#define PANIC(...) do { fprintf(stderr, __VA_ARGS__); \ - exit(1); \ - } while (0) - -/* - * Enumerates states for the client framebuffer update reader. - */ -typedef enum ClientFBState { - /* The reader is waiting on update header. */ - WAIT_HEADER, - - /* The reader is waiting on pixels. */ - WAIT_PIXELS, -} ClientFBState; - -/* - * Descriptor for the framebuffer client. - */ -struct ClientFramebuffer { - /* Framebuffer for this client. */ - QFrameBuffer* fb; - - /* Core connection instance for the framebuffer client. */ - CoreConnection* core_connection; - - /* Current update header. */ - FBUpdateMessage update_header; - - /* Reader's buffer. */ - uint8_t* reader_buffer; - - /* Offset in the reader's buffer where to read next chunk of data. */ - size_t reader_offset; - - /* Total number of bytes the reader expects to read. */ - size_t reader_bytes; - - /* Current state of the update reader. */ - ClientFBState fb_state; - - /* Socket descriptor for the framebuffer client. */ - int sock; - - /* Number of bits used to encode single pixel. */ - int bits_per_pixel; -}; - -/* The only instance of framebuffer client. */ -static ClientFramebuffer _client_fb; - -/* - * Updates a display rectangle. - * Param - * fb - Framebuffer where to update the rectangle. - * x, y, w, and h define rectangle to update. - * bits_per_pixel define number of bits used to encode a single pixel. - * pixels contains pixels for the rectangle. Buffer addressed by this parameter - * must be eventually freed with free() - */ -static void -update_rect(QFrameBuffer* fb, uint16_t x, uint16_t y, uint16_t w, uint16_t h, - uint8_t bits_per_pixel, uint8_t* pixels) -{ - if (fb != NULL) { - uint16_t n; - const uint8_t* src = pixels; - const uint16_t src_line_size = w * ((bits_per_pixel + 7) / 8); - uint8_t* dst = (uint8_t*)fb->pixels + y * fb->pitch + x * fb->bytes_per_pixel; - for (n = 0; n < h; n++) { - memcpy(dst, src, src_line_size); - src += src_line_size; - dst += fb->pitch; - } - qframebuffer_update(fb, x, y, w, h); - } - free(pixels); -} - -/* - * Asynchronous I/O callback launched when framebuffer notifications are ready - * to be read. - * Param: - * opaque - ClientFramebuffer instance. - */ -static void -_clientfb_read_cb(void* opaque) -{ - ClientFramebuffer* fb_client = opaque; - int ret; - - // Read updates while they are immediately available. - for (;;) { - // Read next chunk of data. - ret = read(fb_client->sock, fb_client->reader_buffer + fb_client->reader_offset, - fb_client->reader_bytes - fb_client->reader_offset); - if (ret == 0) { - /* disconnection ! */ - clientfb_destroy(fb_client); - return; - } - if (ret < 0) { - if (errno == EINTR) { - /* loop on EINTR */ - continue; - } else if (errno == EWOULDBLOCK || errno == EAGAIN) { - // Chunk is not avalable at this point. Come back later. - return; - } - } - - fb_client->reader_offset += ret; - if (fb_client->reader_offset != fb_client->reader_bytes) { - // There are still some data left in the pipe. - continue; - } - - // All expected data has been read. Time to change the state. - if (fb_client->fb_state == WAIT_HEADER) { - // Update header has been read. Prepare for the pixels. - fb_client->fb_state = WAIT_PIXELS; - fb_client->reader_offset = 0; - fb_client->reader_bytes = fb_client->update_header.w * - fb_client->update_header.h * - (fb_client->bits_per_pixel / 8); - fb_client->reader_buffer = malloc(fb_client->reader_bytes); - if (fb_client->reader_buffer == NULL) { - PANIC("Unable to allocate memory for framebuffer update\n"); - } - } else { - // Pixels have been read. Prepare for the header. - uint8_t* pixels = fb_client->reader_buffer; - - fb_client->fb_state = WAIT_HEADER; - fb_client->reader_offset = 0; - fb_client->reader_bytes = sizeof(FBUpdateMessage); - fb_client->reader_buffer = (uint8_t*)&fb_client->update_header; - - // Perform the update. Note that pixels buffer must be freed there. - update_rect(fb_client->fb, fb_client->update_header.x, - fb_client->update_header.y, fb_client->update_header.w, - fb_client->update_header.h, fb_client->bits_per_pixel, - pixels); - } - } -} - -ClientFramebuffer* -clientfb_create(SockAddress* console_socket, - const char* protocol, - QFrameBuffer* fb) -{ - char* connect_message = NULL; - char switch_cmd[256]; - - // Connect to the framebuffer service. - _client_fb.core_connection = core_connection_create(console_socket); - if (_client_fb.core_connection == NULL) { - derror("Framebuffer client is unable to connect to the console: %s\n", - errno_str); - return NULL; - } - if (core_connection_open(_client_fb.core_connection)) { - core_connection_free(_client_fb.core_connection); - _client_fb.core_connection = NULL; - derror("Framebuffer client is unable to open the console: %s\n", - errno_str); - return NULL; - } - snprintf(switch_cmd, sizeof(switch_cmd), "framebuffer %s", protocol); - if (core_connection_switch_stream(_client_fb.core_connection, switch_cmd, - &connect_message)) { - derror("Unable to attach to the framebuffer %s: %s\n", - switch_cmd, connect_message ? connect_message : ""); - if (connect_message != NULL) { - free(connect_message); - } - core_connection_close(_client_fb.core_connection); - core_connection_free(_client_fb.core_connection); - _client_fb.core_connection = NULL; - return NULL; - } - - // We expect core framebuffer to return us bits per pixel property in - // the handshake message. - _client_fb.bits_per_pixel = 0; - if (connect_message != NULL) { - char* bpp = strstr(connect_message, "bitsperpixel="); - if (bpp != NULL) { - char* end; - bpp += strlen("bitsperpixel="); - end = strchr(bpp, ' '); - if (end == NULL) { - end = bpp + strlen(bpp); - } - _client_fb.bits_per_pixel = strtol(bpp, &end, 0); - } - } - - if (!_client_fb.bits_per_pixel) { - derror("Unexpected core framebuffer reply: %s\n" - "Bits per pixel property is not there, or is invalid\n", connect_message); - core_connection_close(_client_fb.core_connection); - core_connection_free(_client_fb.core_connection); - _client_fb.core_connection = NULL; - return NULL; - } - - // Now that we're connected lets initialize the descriptor. - _client_fb.fb = fb; - _client_fb.sock = core_connection_get_socket(_client_fb.core_connection); - _client_fb.fb_state = WAIT_HEADER; - _client_fb.reader_buffer = (uint8_t*)&_client_fb.update_header; - _client_fb.reader_offset = 0; - _client_fb.reader_bytes = sizeof(FBUpdateMessage); - - if (connect_message != NULL) { - free(connect_message); - } - - // At last setup read callback, and start receiving the updates. - if (qemu_set_fd_handler(_client_fb.sock, _clientfb_read_cb, NULL, &_client_fb)) { - derror("Unable to set up framebuffer read callback\n"); - core_connection_close(_client_fb.core_connection); - core_connection_free(_client_fb.core_connection); - _client_fb.core_connection = NULL; - return NULL; - } - { - // Force the core to send us entire framebuffer now, when we're prepared - // to receive it. - FBRequestHeader hd; - SyncSocket* sk = syncsocket_init(_client_fb.sock); - - hd.request_type = AFB_REQUEST_REFRESH; - syncsocket_start_write(sk); - syncsocket_write(sk, &hd, sizeof(hd), 500); - syncsocket_stop_write(sk); - syncsocket_free(sk); - } - fprintf(stdout, "Framebuffer %s is now attached to the core %s\n", - protocol, sock_address_to_string(console_socket)); - - return &_client_fb; -} - -void -clientfb_destroy(ClientFramebuffer* client_fb) -{ - if (client_fb != NULL && client_fb->core_connection != NULL) { - // Disable the reader callback. - qemu_set_fd_handler(client_fb->sock, NULL, NULL, NULL); - - // Close framebuffer connection. - core_connection_close(client_fb->core_connection); - core_connection_free(client_fb->core_connection); - client_fb->core_connection = NULL; - } -} diff --git a/android/framebuffer-ui.h b/android/framebuffer-ui.h deleted file mode 100644 index 158f137..0000000 --- a/android/framebuffer-ui.h +++ /dev/null @@ -1,52 +0,0 @@ -/* Copyright (C) 2010 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ - -/* - * Contains UI-side framebuffer client that receives framebuffer updates - * from the core. - */ - -#ifndef _ANDROID_FRAMEBUFFER_UI_H -#define _ANDROID_FRAMEBUFFER_UI_H - -#include "console.h" -#include "framebuffer.h" -#include "android/looper.h" -#include "android/async-utils.h" -#include "android/core-connection.h" - -/* Descriptor for the framebuffer client. */ -typedef struct ClientFramebuffer ClientFramebuffer; - -/* - * Creates framebuffer client, and connects it with the core. - * Param: - * console_socket Address of the core's console socket. - * protocol Protocol to use for the updates: - * -raw Stream pixels over socket - * -shared Use shared memory for pixels. - * fb - Framebuffer associated with this FB client. - * Return: - * Descriptor for the framebuffer client on success, or NULL on failure. - */ -ClientFramebuffer* clientfb_create(SockAddress* console_socket, - const char* protocol, - QFrameBuffer* fb); - -/* - * Disconnects and destroys framebuffer client. - * Param: - * client_fb Framebuffer client descriptor created with clientfb_create. - */ -void clientfb_destroy(ClientFramebuffer* client_fb); - -#endif /* _ANDROID_FRAMEBUFFER_UI_H */ diff --git a/android/main-ui.c b/android/main-ui.c index 4b86ad1..968eeeb 100644 --- a/android/main-ui.c +++ b/android/main-ui.c @@ -60,7 +60,7 @@ #include "android/snapshot.h" #include "android/core-connection.h" -#include "android/framebuffer-ui.h" +#include "android/protocol/fb-updates-impl.h" #include "android/protocol/user-events-proxy.h" #include "android/protocol/core-commands-proxy.h" #include "android/protocol/ui-commands-impl.h" @@ -106,9 +106,6 @@ unsigned long android_verbose; /* Instance of the "attach-UI" Emulator's core console client. */ CoreConnection* attach_client = NULL; -/* Instance of the "framebuffer" console client. */ -ClientFramebuffer* fb_client = NULL; - /* -ui-settings parameters received from the core on UI attachment. */ char* core_ui_settings = ""; @@ -960,9 +957,8 @@ attach_to_core(AndroidOptions* opts) { qemulator_set_title(emulator); // Connect to the core's framebuffer service - fb_client = clientfb_create(&console_socket, "-raw", - qemulator_get_first_framebuffer(emulator)); - if (fb_client == NULL) { + if (implFb_create(&console_socket, "-raw", + qemulator_get_first_framebuffer(emulator))) { return -1; } diff --git a/android/protocol/fb-updates-impl.c b/android/protocol/fb-updates-impl.c new file mode 100644 index 0000000..ebe7309 --- /dev/null +++ b/android/protocol/fb-updates-impl.c @@ -0,0 +1,264 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains UI-side framebuffer client that receives framebuffer updates + * from the core. + */ + +#include "sysemu.h" +#include "android/utils/system.h" +#include "android/utils/debug.h" +#include "android/utils/panic.h" +#include "android/sync-utils.h" +#include "android/protocol/fb-updates.h" +#include "android/protocol/fb-updates-impl.h" + +/*Enumerates states for the client framebuffer update reader. */ +typedef enum ImplFBState { + /* The reader is waiting on update header. */ + EXPECTS_HEADER, + + /* The reader is waiting on pixels. */ + EXPECTS_PIXELS, +} ImplFBState; + +/* Descriptor for the UI-side implementation of the "framebufer" service. + */ +typedef struct ImplFramebuffer { + /* Framebuffer for this client. */ + QFrameBuffer* fb; + + /* Core connection instance for the framebuffer client. */ + CoreConnection* core_connection; + + /* Current update header. */ + FBUpdateMessage update_header; + + /* Reader's buffer. */ + uint8_t* reader_buffer; + + /* Offset in the reader's buffer where to read next chunk of data. */ + size_t reader_offset; + + /* Total number of bytes the reader expects to read. */ + size_t reader_bytes; + + /* Current state of the update reader. */ + ImplFBState fb_state; + + /* Socket descriptor for the framebuffer client. */ + int sock; + + /* Number of bits used to encode single pixel. */ + int bits_per_pixel; +} ImplFramebuffer; + +/* One and the only ImplFramebuffer instance. */ +static ImplFramebuffer _implFb; + +/* + * Updates a display rectangle. + * Param + * fb - Framebuffer where to update the rectangle. + * x, y, w, and h define rectangle to update. + * bits_per_pixel define number of bits used to encode a single pixel. + * pixels contains pixels for the rectangle. Buffer addressed by this parameter + * must be eventually freed with free() + */ +static void +_update_rect(QFrameBuffer* fb, uint16_t x, uint16_t y, uint16_t w, uint16_t h, + uint8_t bits_per_pixel, uint8_t* pixels) +{ + if (fb != NULL) { + uint16_t n; + const uint8_t* src = pixels; + const uint16_t src_line_size = w * ((bits_per_pixel + 7) / 8); + uint8_t* dst = (uint8_t*)fb->pixels + y * fb->pitch + x * + fb->bytes_per_pixel; + for (n = 0; n < h; n++) { + memcpy(dst, src, src_line_size); + src += src_line_size; + dst += fb->pitch; + } + qframebuffer_update(fb, x, y, w, h); + } + free(pixels); +} + +/* + * Asynchronous I/O callback launched when framebuffer notifications are ready + * to be read. + * Param: + * opaque - ImplFramebuffer instance. + */ +static void +_implFb_read_cb(void* opaque) +{ + ImplFramebuffer* fb_client = opaque; + int ret; + + // Read updates while they are immediately available. + for (;;) { + // Read next chunk of data. + ret = read(fb_client->sock, fb_client->reader_buffer + fb_client->reader_offset, + fb_client->reader_bytes - fb_client->reader_offset); + if (ret == 0) { + /* disconnection ! */ + implFb_destroy(); + return; + } + if (ret < 0) { + if (errno == EINTR) { + /* loop on EINTR */ + continue; + } else if (errno == EWOULDBLOCK || errno == EAGAIN) { + // Chunk is not avalable at this point. Come back later. + return; + } + } + + fb_client->reader_offset += ret; + if (fb_client->reader_offset != fb_client->reader_bytes) { + // There are still some data left in the pipe. + continue; + } + + // All expected data has been read. Time to change the state. + if (fb_client->fb_state == EXPECTS_HEADER) { + // Update header has been read. Prepare for the pixels. + fb_client->fb_state = EXPECTS_PIXELS; + fb_client->reader_offset = 0; + fb_client->reader_bytes = fb_client->update_header.w * + fb_client->update_header.h * + (fb_client->bits_per_pixel / 8); + fb_client->reader_buffer = malloc(fb_client->reader_bytes); + if (fb_client->reader_buffer == NULL) { + APANIC("Unable to allocate memory for framebuffer update\n"); + } + } else { + // Pixels have been read. Prepare for the header. + uint8_t* pixels = fb_client->reader_buffer; + + fb_client->fb_state = EXPECTS_HEADER; + fb_client->reader_offset = 0; + fb_client->reader_bytes = sizeof(FBUpdateMessage); + fb_client->reader_buffer = (uint8_t*)&fb_client->update_header; + + // Perform the update. Note that pixels buffer must be freed there. + _update_rect(fb_client->fb, fb_client->update_header.x, + fb_client->update_header.y, fb_client->update_header.w, + fb_client->update_header.h, fb_client->bits_per_pixel, + pixels); + } + } +} + +int +implFb_create(SockAddress* console_socket, const char* protocol, QFrameBuffer* fb) +{ + char* handshake = NULL; + char switch_cmd[256]; + + // Initialize descriptor. + _implFb.fb = fb; + _implFb.reader_buffer = (uint8_t*)&_implFb.update_header; + _implFb.reader_offset = 0; + _implFb.reader_bytes = sizeof(FBUpdateMessage); + + // Connect to the framebuffer service. + snprintf(switch_cmd, sizeof(switch_cmd), "framebuffer %s", protocol); + _implFb.core_connection = + core_connection_create_and_switch(console_socket, switch_cmd, &handshake); + if (_implFb.core_connection == NULL) { + derror("Unable to connect to the framebuffer service: %s\n", + errno_str); + return -1; + } + + // We expect core framebuffer to return us bits per pixel property in + // the handshake message. + _implFb.bits_per_pixel = 0; + if (handshake != NULL) { + char* bpp = strstr(handshake, "bitsperpixel="); + if (bpp != NULL) { + char* end; + bpp += strlen("bitsperpixel="); + end = strchr(bpp, ' '); + if (end == NULL) { + end = bpp + strlen(bpp); + } + _implFb.bits_per_pixel = strtol(bpp, &end, 0); + } + } + if (!_implFb.bits_per_pixel) { + derror("Unexpected core framebuffer reply: %s\n" + "Bits per pixel property is not there, or is invalid\n", + handshake); + implFb_destroy(); + return -1; + } + + _implFb.sock = core_connection_get_socket(_implFb.core_connection); + + // At last setup read callback, and start receiving the updates. + if (qemu_set_fd_handler(_implFb.sock, _implFb_read_cb, NULL, &_implFb)) { + derror("Unable to set up framebuffer read callback.\n"); + implFb_destroy(); + return -1; + } + { + // Force the core to send us entire framebuffer now, when we're prepared + // to receive it. + FBRequestHeader hd; + SyncSocket* sk = syncsocket_init(_implFb.sock); + + hd.request_type = AFB_REQUEST_REFRESH; + syncsocket_start_write(sk); + syncsocket_write(sk, &hd, sizeof(hd), 5000); + syncsocket_stop_write(sk); + syncsocket_free(sk); + } + + fprintf(stdout, "framebuffer is now connected to the core at %s.", + sock_address_to_string(console_socket)); + if (handshake != NULL) { + if (handshake[0] != '\0') { + fprintf(stdout, " Handshake: %s", handshake); + } + free(handshake); + } + fprintf(stdout, "\n"); + + return 0; +} + +void +implFb_destroy(void) +{ + if (_implFb.core_connection != NULL) { + // Disable the reader callback. + qemu_set_fd_handler(_implFb.sock, NULL, NULL, NULL); + + // Close framebuffer connection. + core_connection_close(_implFb.core_connection); + core_connection_free(_implFb.core_connection); + _implFb.core_connection = NULL; + } + + _implFb.fb = NULL; + if (_implFb.reader_buffer != NULL && + _implFb.reader_buffer != (uint8_t*)&_implFb.update_header) { + free(_implFb.reader_buffer); + _implFb.reader_buffer = (uint8_t*)&_implFb.update_header; + } +} diff --git a/android/protocol/fb-updates-impl.h b/android/protocol/fb-updates-impl.h new file mode 100644 index 0000000..0c351aa --- /dev/null +++ b/android/protocol/fb-updates-impl.h @@ -0,0 +1,44 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains UI-side "framebuffer" client that receives framebuffer updates + * from the Core. + */ + +#ifndef _ANDROID_FRAMEBUFFER_UI_H +#define _ANDROID_FRAMEBUFFER_UI_H + +#include "console.h" +#include "framebuffer.h" +#include "android/looper.h" +#include "android/async-utils.h" +#include "android/core-connection.h" + +/* Creates framebuffer client, and connects it with the core. + * Param: + * console_socket Address of the core's console socket. + * protocol Protocol to use for the updates: + * -raw Stream pixels over socket + * -shared Use shared memory for pixels. + * fb - Framebuffer associated with this FB client. + * Return: + * 0 on success, or < 0 on failure. + */ +int implFb_create(SockAddress* console_socket, + const char* protocol, + QFrameBuffer* fb); + +/* Disconnects and destroys framebuffer client. */ +void implFb_destroy(void); + +#endif /* _ANDROID_FRAMEBUFFER_UI_H */ diff --git a/android/protocol/fb-updates-proxy.c b/android/protocol/fb-updates-proxy.c new file mode 100644 index 0000000..fee1195 --- /dev/null +++ b/android/protocol/fb-updates-proxy.c @@ -0,0 +1,332 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains core-side framebuffer service that sends framebuffer updates + * to the UI connected to the core. + */ + +#include "console.h" +#include "framebuffer.h" +#include "android/looper.h" +#include "android/display-core.h" +#include "android/async-utils.h" +#include "android/protocol/fb-updates.h" +#include "android/protocol/fb-updates-proxy.h" +#include "android/utils/system.h" +#include "android/utils/debug.h" + +/* Descriptor for the Core-side implementation of the "framebufer" service. + */ +struct ProxyFramebuffer { + /* Writer used to send FB update notification messages. */ + AsyncWriter fb_update_writer; + + /* Reader used to read FB requests from the client. */ + AsyncReader fb_req_reader; + + /* I/O associated with this descriptor. */ + LoopIo io; + + /* Framebuffer used for this service. */ + QFrameBuffer* fb; + + /* Looper used to communicate framebuffer updates. */ + Looper* looper; + + /* Head of the list of pending FB update notifications. */ + struct FBUpdateNotify* fb_update_head; + + /* Tail of the list of pending FB update notifications. */ + struct FBUpdateNotify* fb_update_tail; + + /* Socket used to communicate framebuffer updates. */ + int sock; + + /* Framebuffer request header. */ + FBRequestHeader fb_req_header; +}; + +/* Framebuffer update notification descriptor. */ +typedef struct FBUpdateNotify { + /* Links all pending FB update notifications. */ + struct FBUpdateNotify* next_fb_update; + + /* Core framebuffer instance that owns the message. */ + ProxyFramebuffer* proxy_fb; + + /* Size of the message to transfer. */ + size_t message_size; + + /* Update message. */ + FBUpdateMessage message; +} FBUpdateNotify; + +/* + * Gets pointer in framebuffer's pixels for the given pixel. + * Param: + * fb Framebuffer containing pixels. + * x, and y identify the pixel to get pointer for. + * Return: + * Pointer in framebuffer's pixels for the given pixel. + */ +static const uint8_t* +_pixel_offset(const QFrameBuffer* fb, int x, int y) +{ + return (const uint8_t*)fb->pixels + y * fb->pitch + x * fb->bytes_per_pixel; +} + +/* + * Copies pixels from a framebuffer rectangle. + * Param: + * rect - Buffer where to copy pixel. + * fb - Framebuffer containing the rectangle to copy. + * 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) +{ + const uint8_t* start = _pixel_offset(fb, x, y); + for (; h > 0; h--) { + memcpy(rect, start, w * fb->bytes_per_pixel); + start += fb->pitch; + rect += w * fb->bytes_per_pixel; + } +} + +/* + * Allocates and initializes framebuffer update notification descriptor. + * Param: + * ds - Display state for the framebuffer. + * fb Framebuffer containing pixels. + * x, y, w, and h identify the rectangle that is being updated. + * Return: + * Initialized framebuffer update notification descriptor. + */ +static FBUpdateNotify* +fbupdatenotify_create(ProxyFramebuffer* proxy_fb, const QFrameBuffer* fb, + int x, int y, int w, int h) +{ + const size_t rect_size = w * h * fb->bytes_per_pixel; + FBUpdateNotify* ret = malloc(sizeof(FBUpdateNotify) + rect_size); + + ret->next_fb_update = NULL; + ret->proxy_fb = proxy_fb; + ret->message_size = sizeof(FBUpdateMessage) + rect_size; + ret->message.x = x; + ret->message.y = y; + ret->message.w = w; + ret->message.h = h; + _copy_fb_rect(ret->message.rect, fb, x, y, w, h); + return ret; +} + +/* + * Deletes FBUpdateNotify descriptor, created with fbupdatenotify_create. + * Param: + * desc - Descreptor to delete. + */ +static void +fbupdatenotify_delete(FBUpdateNotify* desc) +{ + if (desc != NULL) { + free(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. + * Param: + * proxy_fb - ProxyFramebuffer instance. + */ +static void +_proxyFb_io_write(ProxyFramebuffer* proxy_fb) +{ + while (proxy_fb->fb_update_head != NULL) { + FBUpdateNotify* current_update = proxy_fb->fb_update_head; + // Lets continue writing of the current notification. + const AsyncStatus status = + asyncWriter_write(&proxy_fb->fb_update_writer, &proxy_fb->io); + switch (status) { + case ASYNC_COMPLETE: + // Done with the current update. Move on to the next one. + break; + case ASYNC_ERROR: + // Done with the current update. Move on to the next one. + loopIo_dontWantWrite(&proxy_fb->io); + break; + + case ASYNC_NEED_MORE: + // Transfer will eventually come back into this routine. + return; + } + + // Advance the list of updates + proxy_fb->fb_update_head = current_update->next_fb_update; + if (proxy_fb->fb_update_head == NULL) { + proxy_fb->fb_update_tail = NULL; + } + fbupdatenotify_delete(current_update); + + if (proxy_fb->fb_update_head != NULL) { + // Schedule the next one. + asyncWriter_init(&proxy_fb->fb_update_writer, + &proxy_fb->fb_update_head->message, + proxy_fb->fb_update_head->message_size, + &proxy_fb->io); + } + } +} + +/* + * Asynchronous read I/O callback launched when reading framebuffer requests + * from the socket. + * Param: + * proxy_fb - ProxyFramebuffer instance. + */ +static void +_proxyFb_io_read(ProxyFramebuffer* proxy_fb) +{ + // Read the request header. + const AsyncStatus status = + asyncReader_read(&proxy_fb->fb_req_reader, &proxy_fb->io); + switch (status) { + case ASYNC_COMPLETE: + // Request header is received + 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); + break; + default: + derror("Unknown framebuffer request %d\n", + proxy_fb->fb_req_header.request_type); + break; + } + proxy_fb->fb_req_header.request_type = -1; + asyncReader_init(&proxy_fb->fb_req_reader, &proxy_fb->fb_req_header, + sizeof(proxy_fb->fb_req_header), &proxy_fb->io); + break; + case ASYNC_ERROR: + loopIo_dontWantRead(&proxy_fb->io); + if (errno == ECONNRESET) { + // UI has exited. We need to destroy framebuffer service. + destroy_control_fb_client(); + } + break; + + case ASYNC_NEED_MORE: + // Transfer will eventually come back into this routine. + return; + } +} + +/* + * Asynchronous I/O callback launched when writing framebuffer notifications + * to the socket. + * Param: + * opaque - ProxyFramebuffer instance. + */ +static void +_proxyFb_io_fun(void* opaque, int fd, unsigned events) +{ + if (events & LOOP_IO_READ) { + _proxyFb_io_read((ProxyFramebuffer*)opaque); + } else if (events & LOOP_IO_WRITE) { + _proxyFb_io_write((ProxyFramebuffer*)opaque); + } +} + +ProxyFramebuffer* +proxyFb_create(int sock, const char* protocol, QFrameBuffer* fb) +{ + // At this point we're implementing the -raw protocol only. + ProxyFramebuffer* ret; + ANEW0(ret); + ret->sock = sock; + ret->looper = looper_newCore(); + ret->fb = fb; + ret->fb_update_head = NULL; + ret->fb_update_tail = NULL; + loopIo_init(&ret->io, ret->looper, sock, _proxyFb_io_fun, ret); + asyncReader_init(&ret->fb_req_reader, &ret->fb_req_header, + sizeof(ret->fb_req_header), &ret->io); + return ret; +} + +void +proxyFb_destroy(ProxyFramebuffer* proxy_fb) +{ + if (proxy_fb != NULL) { + if (proxy_fb->looper != NULL) { + // Stop all I/O that may still be going on. + loopIo_done(&proxy_fb->io); + // Delete all pending frame updates. + while (proxy_fb->fb_update_head != NULL) { + FBUpdateNotify* pending_update = proxy_fb->fb_update_head; + proxy_fb->fb_update_head = pending_update->next_fb_update; + fbupdatenotify_delete(pending_update); + } + proxy_fb->fb_update_tail = NULL; + looper_free(proxy_fb->looper); + proxy_fb->looper = NULL; + } + } +} + +void +proxyFb_update(ProxyFramebuffer* proxy_fb, + struct QFrameBuffer* fb, int x, int y, int w, int h) +{ + AsyncStatus status; + FBUpdateNotify* descr = fbupdatenotify_create(proxy_fb, fb, x, y, w, h); + + // Lets see if we should list it behind other pending updates. + if (proxy_fb->fb_update_tail != NULL) { + proxy_fb->fb_update_tail->next_fb_update = descr; + proxy_fb->fb_update_tail = descr; + return; + } + + // We're first in the list. Just send it now. + proxy_fb->fb_update_head = proxy_fb->fb_update_tail = descr; + asyncWriter_init(&proxy_fb->fb_update_writer, + &proxy_fb->fb_update_head->message, + proxy_fb->fb_update_head->message_size, &proxy_fb->io); + status = asyncWriter_write(&proxy_fb->fb_update_writer, &proxy_fb->io); + switch (status) { + case ASYNC_COMPLETE: + fbupdatenotify_delete(descr); + proxy_fb->fb_update_head = proxy_fb->fb_update_tail = NULL; + return; + case ASYNC_ERROR: + fbupdatenotify_delete(descr); + proxy_fb->fb_update_head = proxy_fb->fb_update_tail = NULL; + return; + case ASYNC_NEED_MORE: + // Update transfer will eventually complete in _proxyFb_io_fun + return; + } +} + +int +proxyFb_get_bits_per_pixel(ProxyFramebuffer* proxy_fb) +{ + return (proxy_fb != NULL && proxy_fb->fb != NULL) ? + proxy_fb->fb->bits_per_pixel : -1; +} diff --git a/android/protocol/fb-updates-proxy.h b/android/protocol/fb-updates-proxy.h new file mode 100644 index 0000000..e750f1a --- /dev/null +++ b/android/protocol/fb-updates-proxy.h @@ -0,0 +1,64 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains core-side framebuffer service that sends framebuffer updates + * to the UI connected to the core. + */ + +#ifndef _ANDROID_PROTOCOL_FB_UPDATES_PROXY_H +#define _ANDROID_PROTOCOL_FB_UPDATES_PROXY_H + +/* Descriptor for a framebuffer core service instance */ +typedef struct ProxyFramebuffer ProxyFramebuffer; + +/* + * Creates framebuffer service. + * Param: + * sock - Socket descriptor for the service + * protocol - Defines protocol to use when sending FB updates to the UI. The + * 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); + +/* + * Destroys framebuffer service created with proxyFb_create. + * Param: + * core_fb - Framebuffer service descriptor created with proxyFb_create + */ +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 + * Return: + * Number of bits used to encode a single pixel. + */ +int proxyFb_get_bits_per_pixel(ProxyFramebuffer* core_fb); + +#endif /* _ANDROID_PROTOCOL_FB_UPDATES_PROXY_H */ diff --git a/android/protocol/fb-updates.h b/android/protocol/fb-updates.h new file mode 100644 index 0000000..c4f9779 --- /dev/null +++ b/android/protocol/fb-updates.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2010 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* + * Contains the API for calling into the UI with Core's framebuffer updates. + */ + +#ifndef _ANDROID_PROTOCOL_FB_UPDATES_H +#define _ANDROID_PROTOCOL_FB_UPDATES_H + +#include "sysemu.h" + +/* Requests the Core to refresh framebuffer. + * This message is sent by the UI to the Core right after the UI is initialized. + * This message forces the Core to send a full display update back to the UI. */ +#define AFB_REQUEST_REFRESH 1 + +/* Header of framebuffer update message sent from the core to the UI. */ +typedef struct FBUpdateMessage { + /* x, y, w, and h identify the rectangle that is being updated. */ + uint16_t x; + uint16_t y; + uint16_t w; + uint16_t h; + + /* Contains updating rectangle copied over from the framebuffer's pixels. */ + uint8_t rect[0]; +} FBUpdateMessage; + +/* Header for framebuffer requests sent from the UI to the Core. */ +typedef struct FBRequestHeader { + /* Request type. See AFB_REQUEST_XXX for the values. */ + uint8_t request_type; +} FBRequestHeader; + +#endif /* _ANDROID_PROTOCOL_FB_UPDATES_H */ -- cgit v1.1