diff options
author | David 'Digit' Turner <digit@android.com> | 2010-07-27 11:34:16 -0700 |
---|---|---|
committer | David 'Digit' Turner <digit@android.com> | 2010-07-27 12:25:52 -0700 |
commit | 055ae42d36d9d78a7920f66ee2df485d81d24264 (patch) | |
tree | a1d84474063ea614199ab6a31602711b88d02175 | |
parent | 657a3521a1f4d354b57f0e524b1cd57bed177bb0 (diff) | |
download | external_qemu-055ae42d36d9d78a7920f66ee2df485d81d24264.zip external_qemu-055ae42d36d9d78a7920f66ee2df485d81d24264.tar.gz external_qemu-055ae42d36d9d78a7920f66ee2df485d81d24264.tar.bz2 |
Better separation of UI and Core sources for framebuffer emulation.
+ new document under docs/DISPLAY-STATE.TXT to explain what's happening.
Change-Id: Ia0d233377266212da49af932c7528f46f5feb92d
-rw-r--r-- | Makefile.android | 1 | ||||
-rw-r--r-- | android/display.c | 102 | ||||
-rw-r--r-- | android/display.h | 20 | ||||
-rw-r--r-- | android/main.c | 316 | ||||
-rw-r--r-- | android/qemulator.c | 280 | ||||
-rw-r--r-- | android/skin/window.c | 22 | ||||
-rw-r--r-- | android/ui-core-protocol.c | 24 | ||||
-rw-r--r-- | android/ui-core-protocol.h | 7 | ||||
-rw-r--r-- | console.h | 5 | ||||
-rw-r--r-- | docs/DISPLAY-STATE.TXT | 263 | ||||
-rw-r--r-- | framebuffer.c | 12 | ||||
-rw-r--r-- | framebuffer.h | 11 | ||||
-rw-r--r-- | hw/android_arm.c | 3 | ||||
-rw-r--r-- | hw/goldfish_device.h | 2 | ||||
-rw-r--r-- | hw/goldfish_events_device.c | 2 | ||||
-rw-r--r-- | hw/goldfish_fb.c | 84 |
16 files changed, 787 insertions, 367 deletions
diff --git a/Makefile.android b/Makefile.android index 2eb39c4..ae3e53d 100644 --- a/Makefile.android +++ b/Makefile.android @@ -632,6 +632,7 @@ CORE_MISC_SOURCES = vl-android.c \ bt-vhci.c \ module.c \ android/boot-properties.c \ + android/display.c \ android/hw-kmsg.c \ android/hw-lcd.c \ android/gps.c \ diff --git a/android/display.c b/android/display.c new file mode 100644 index 0000000..0cfd98d --- /dev/null +++ b/android/display.c @@ -0,0 +1,102 @@ +/* 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. +*/ + +/* Initialization of the Android-specific DisplayState. + * Read docs/DISPLAY-STATE.TXT to understand what this + * is supposed to do. + */ +#include "android/display.h" + +/* + +TECHNICAL NOTE: + +DisplayState <--> QFrameBuffer <--> QEmulator/SDL + +*/ + +/* QFrameBuffer producer callbacks */ + +/* this is called periodically by the GUI timer to check for updates + * and poll user events. Use vga_hw_update(). + */ +static void +android_display_producer_check(void *opaque) +{ + /* core: call vga_hw_update(). this will eventually + * lead to calls to android_display_update() + */ + (void)opaque; + vga_hw_update(); +} + +static void +android_display_producer_invalidate(void *opaque) +{ + (void)opaque; + vga_hw_invalidate(); +} + +/* QFrameBuffer client callbacks */ + +/* this is called from dpy_update() each time a hardware framebuffer + * rectangular update was detected. Send this to the QFrameBuffer. + */ +static void +android_display_update(DisplayState *ds, int x, int y, int w, int h) +{ + QFrameBuffer* qfbuff = ds->opaque; + qframebuffer_update(qfbuff, x, y, w, h); +} + +static void +android_display_resize(DisplayState *ds) +{ + QFrameBuffer* qfbuff = ds->opaque; + qframebuffer_rotate(qfbuff, 0); +} + +static void +android_display_refresh(DisplayState *ds) +{ + QFrameBuffer* qfbuff = ds->opaque; + qframebuffer_poll(qfbuff); +} + + +void android_display_init(DisplayState* ds, QFrameBuffer* qf) +{ + DisplayChangeListener* dcl; + + qframebuffer_set_producer(qf, ds, + android_display_producer_check, + android_display_producer_invalidate, + NULL); // detach + + /* Replace the display surface with one with the right dimensions */ + qemu_free_displaysurface(ds); + ds->opaque = qf; + ds->surface = qemu_create_displaysurface_from(qf->width, + qf->height, + 16, + qf->pitch, + qf->pixels); + + /* Register a change listener for it */ + dcl = (DisplayChangeListener *) qemu_mallocz(sizeof(DisplayChangeListener)); + dcl->dpy_update = android_display_update; + dcl->dpy_resize = android_display_resize; + dcl->dpy_refresh = android_display_refresh; + dcl->dpy_text_cursor = NULL; + + register_displaychangelistener(ds, dcl); +} diff --git a/android/display.h b/android/display.h new file mode 100644 index 0000000..111979c --- /dev/null +++ b/android/display.h @@ -0,0 +1,20 @@ +/* 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. +*/ +#ifndef _ANDROID_DISPLAY_H +#define _ANDROID_DISPLAY_H + +#include "console.h" +#include "framebuffer.h" + +extern void android_display_init(DisplayState* ds, QFrameBuffer* qfbuff); + +#endif /* _ANDROID_DISPLAY_H */ diff --git a/android/main.c b/android/main.c index 88ce36b..99720f5 100644 --- a/android/main.c +++ b/android/main.c @@ -70,11 +70,13 @@ #include "tcpdump.h" #include "android/qemulator.h" +#include "android/display.h" /* in vl.c */ extern void qemu_help(int code); #include "framebuffer.h" + AndroidRotation android_framebuffer_rotation; #define STRINGIFY(x) _STRINGIFY(x) @@ -103,8 +105,6 @@ extern int qemu_milli_needed; static int opts->flashkeys; /* forward */ #endif -static void handle_key_command( void* opaque, SkinKeyCommand command, int param ); - #ifdef CONFIG_TRACE extern void start_tracing(void); extern void stop_tracing(void); @@ -247,298 +247,6 @@ uint64_t convertMBToBytes( unsigned megaBytes ) /***** *****/ /***********************************************************************/ /***********************************************************************/ - -/* called by the emulated framebuffer device each time the content of the - * framebuffer has changed. the rectangle is the bounding box of all changes - */ -static void -sdl_update(DisplayState *ds, int x, int y, int w, int h) -{ - /* this function is being called from the console code that is currently inactive - ** simple totally ignore it... - */ - (void)ds; - (void)x; - (void)y; - (void)w; - (void)h; -} - - - - -/* called by the emulated framebuffer device each time the framebuffer - * is resized or rotated */ -static void -sdl_resize(DisplayState *ds) -{ - //fprintf(stderr, "weird, sdl_resize being called with framebuffer interface\n"); - //exit(1); -} - - -/* called periodically to poll for user input events */ -static void sdl_refresh(DisplayState *ds) -{ - QEmulator* emulator = ds->opaque; - SDL_Event ev; - SkinWindow* window = emulator->window; - SkinKeyboard* keyboard = emulator->keyboard; - - /* this will eventually call sdl_update if the content of the VGA framebuffer - * has changed */ - qframebuffer_check_updates(); - - if (window == NULL) - return; - - while(SDL_PollEvent(&ev)){ - switch(ev.type){ - case SDL_VIDEOEXPOSE: - skin_window_redraw( window, NULL ); - break; - - case SDL_KEYDOWN: -#ifdef _WIN32 - /* special code to deal with Alt-F4 properly */ - if (ev.key.keysym.sym == SDLK_F4 && - ev.key.keysym.mod & KMOD_ALT) { - goto CleanExit; - } -#endif -#ifdef __APPLE__ - /* special code to deal with Command-Q properly */ - if (ev.key.keysym.sym == SDLK_q && - ev.key.keysym.mod & KMOD_META) { - goto CleanExit; - } -#endif - skin_keyboard_process_event( keyboard, &ev, 1 ); - break; - - case SDL_KEYUP: - skin_keyboard_process_event( keyboard, &ev, 0 ); - break; - - case SDL_MOUSEMOTION: - skin_window_process_event( window, &ev ); - break; - - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - { - int down = (ev.type == SDL_MOUSEBUTTONDOWN); - if (ev.button.button == 4) - { - /* scroll-wheel simulates DPad up */ - AndroidKeyCode kcode; - - kcode = // qemulator_rotate_keycode(kKeyCodeDpadUp); - android_keycode_rotate(kKeyCodeDpadUp, - skin_layout_get_dpad_rotation(qemulator_get_layout(qemulator_get()))); - user_event_key( kcode, down ); - } - else if (ev.button.button == 5) - { - /* scroll-wheel simulates DPad down */ - AndroidKeyCode kcode; - - kcode = // qemulator_rotate_keycode(kKeyCodeDpadDown); - android_keycode_rotate(kKeyCodeDpadDown, - skin_layout_get_dpad_rotation(qemulator_get_layout(qemulator_get()))); - user_event_key( kcode, down ); - } - else if (ev.button.button == SDL_BUTTON_LEFT) { - skin_window_process_event( window, &ev ); - } -#if 0 - else { - fprintf(stderr, "... mouse button %s: button=%d state=%04x x=%d y=%d\n", - down ? "down" : "up ", - ev.button.button, ev.button.state, ev.button.x, ev.button.y); - } -#endif - } - break; - - case SDL_QUIT: -#if defined _WIN32 || defined __APPLE__ - CleanExit: -#endif - /* only save emulator config through clean exit */ - qemulator_done(qemulator_get()); - qemu_system_shutdown_request(); - return; - } - } - - skin_keyboard_flush( keyboard ); -} - - -/* used to respond to a given keyboard command shortcut - */ -static void -handle_key_command( void* opaque, SkinKeyCommand command, int down ) -{ - static const struct { SkinKeyCommand cmd; AndroidKeyCode kcode; } keycodes[] = - { - { SKIN_KEY_COMMAND_BUTTON_CALL, kKeyCodeCall }, - { SKIN_KEY_COMMAND_BUTTON_HOME, kKeyCodeHome }, - { SKIN_KEY_COMMAND_BUTTON_BACK, kKeyCodeBack }, - { SKIN_KEY_COMMAND_BUTTON_HANGUP, kKeyCodeEndCall }, - { SKIN_KEY_COMMAND_BUTTON_POWER, kKeyCodePower }, - { SKIN_KEY_COMMAND_BUTTON_SEARCH, kKeyCodeSearch }, - { SKIN_KEY_COMMAND_BUTTON_MENU, kKeyCodeMenu }, - { SKIN_KEY_COMMAND_BUTTON_DPAD_UP, kKeyCodeDpadUp }, - { SKIN_KEY_COMMAND_BUTTON_DPAD_LEFT, kKeyCodeDpadLeft }, - { SKIN_KEY_COMMAND_BUTTON_DPAD_RIGHT, kKeyCodeDpadRight }, - { SKIN_KEY_COMMAND_BUTTON_DPAD_DOWN, kKeyCodeDpadDown }, - { SKIN_KEY_COMMAND_BUTTON_DPAD_CENTER, kKeyCodeDpadCenter }, - { SKIN_KEY_COMMAND_BUTTON_VOLUME_UP, kKeyCodeVolumeUp }, - { SKIN_KEY_COMMAND_BUTTON_VOLUME_DOWN, kKeyCodeVolumeDown }, - { SKIN_KEY_COMMAND_BUTTON_CAMERA, kKeyCodeCamera }, - { SKIN_KEY_COMMAND_NONE, 0 } - }; - int nn; -#ifdef CONFIG_TRACE - static int tracing = 0; -#endif - QEmulator* emulator = opaque; - - - for (nn = 0; keycodes[nn].kcode != 0; nn++) { - if (command == keycodes[nn].cmd) { - unsigned code = keycodes[nn].kcode; - if (down) - code |= 0x200; - kbd_put_keycode( code ); - return; - } - } - - // for the show-trackball command, handle down events to enable, and - // up events to disable - if (command == SKIN_KEY_COMMAND_SHOW_TRACKBALL) { - emulator->show_trackball = (down != 0); - skin_window_show_trackball( emulator->window, emulator->show_trackball ); - //qemulator_set_title( emulator ); - return; - } - - // only handle down events for the rest - if (down == 0) - return; - - switch (command) - { - case SKIN_KEY_COMMAND_TOGGLE_NETWORK: - { - qemu_net_disable = !qemu_net_disable; - if (android_modem) { - amodem_set_data_registration( - android_modem, - qemu_net_disable ? A_REGISTRATION_UNREGISTERED - : A_REGISTRATION_HOME); - } - D( "network is now %s", qemu_net_disable ? "disconnected" : "connected" ); - } - break; - - case SKIN_KEY_COMMAND_TOGGLE_FULLSCREEN: - if (emulator->window) { - skin_window_toggle_fullscreen(emulator->window); - } - break; - - case SKIN_KEY_COMMAND_TOGGLE_TRACING: - { -#ifdef CONFIG_TRACE - tracing = !tracing; - if (tracing) - start_tracing(); - else - stop_tracing(); -#endif - } - break; - - case SKIN_KEY_COMMAND_TOGGLE_TRACKBALL: - emulator->show_trackball = !emulator->show_trackball; - skin_window_show_trackball( emulator->window, emulator->show_trackball ); - qemulator_set_title(emulator); - break; - - case SKIN_KEY_COMMAND_ONION_ALPHA_UP: - case SKIN_KEY_COMMAND_ONION_ALPHA_DOWN: - if (emulator->onion) - { - int alpha = emulator->onion_alpha; - - if (command == SKIN_KEY_COMMAND_ONION_ALPHA_UP) - alpha += 16; - else - alpha -= 16; - - if (alpha > 256) - alpha = 256; - else if (alpha < 0) - alpha = 0; - - emulator->onion_alpha = alpha; - skin_window_set_onion( emulator->window, emulator->onion, emulator->onion_rotation, alpha ); - skin_window_redraw( emulator->window, NULL ); - //dprint( "onion alpha set to %d (%.f %%)", alpha, alpha/2.56 ); - } - break; - - case SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV: - case SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT: - { - SkinLayout* layout = NULL; - - if (command == SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT) { - layout = emulator->layout->next; - if (layout == NULL) - layout = emulator->layout_file->layouts; - } - else if (command == SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV) { - layout = emulator->layout_file->layouts; - while (layout->next && layout->next != emulator->layout) - layout = layout->next; - } - if (layout != NULL) { - SkinRotation rotation; - - emulator->layout = layout; - skin_window_reset( emulator->window, layout ); - - rotation = skin_layout_get_dpad_rotation( layout ); - - if (emulator->keyboard) - skin_keyboard_set_rotation( emulator->keyboard, rotation ); - - if (emulator->trackball) { - skin_trackball_set_rotation( emulator->trackball, rotation ); - skin_window_set_trackball( emulator->window, emulator->trackball ); - skin_window_show_trackball( emulator->window, emulator->show_trackball ); - } - - skin_window_set_lcd_brightness( emulator->window, emulator->lcd_brightness ); - - qframebuffer_invalidate_all(); - qframebuffer_check_updates(); - } - } - break; - - default: - /* XXX: TODO ? */ - ; - } -} - - static void sdl_at_exit(void) { emulator_config_done(); @@ -551,8 +259,8 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) { QEmulator* emulator = qemulator_get(); SkinDisplay* disp = skin_layout_get_display(emulator->layout); - DisplayChangeListener* dcl; int width, height; + char buf[128]; if (disp->rotation & 1) { width = disp->rect.size.h; @@ -562,22 +270,8 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) height = disp->rect.size.h; } - /* Register a display state object for the emulated framebuffer */ - ds->allocator = &default_allocator; - ds->opaque = emulator; - ds->surface = qemu_create_displaysurface(ds, width, height); - register_displaystate(ds); - - /* Register a change listener for it */ - dcl = (DisplayChangeListener *) qemu_mallocz(sizeof(DisplayChangeListener)); - dcl->dpy_update = sdl_update; - dcl->dpy_resize = sdl_resize; - dcl->dpy_refresh = sdl_refresh; - dcl->dpy_text_cursor = NULL; - register_displaychangelistener(ds, dcl); - - skin_keyboard_enable( emulator->keyboard, 1 ); - skin_keyboard_on_command( emulator->keyboard, handle_key_command, emulator ); + snprintf(buf, sizeof buf, "width=%d,height=%d", width, height); + android_display_init(ds, qframebuffer_fifo_get()); } diff --git a/android/qemulator.c b/android/qemulator.c index 7d2d2e8..f6dc550 100644 --- a/android/qemulator.c +++ b/android/qemulator.c @@ -15,6 +15,7 @@ #include "android/globals.h" #include "android/qemulator.h" #include "android/ui-core-protocol.h" +#include "user-events.h" #define D(...) do { if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0) static double get_default_scale( AndroidOptions* opts ); @@ -22,6 +23,9 @@ static double get_default_scale( AndroidOptions* opts ); /* QEmulator structure instance. */ static QEmulator qemulator[1]; +static void handle_key_command( void* opaque, SkinKeyCommand command, int param ); +static void qemulator_refresh(QEmulator* emulator); + static void qemulator_light_brightness( void* opaque, const char* light, int value ) { @@ -98,11 +102,18 @@ qemulator_fb_update( void* _emulator, int x, int y, int w, int h ) static void qemulator_fb_rotate( void* _emulator, int rotation ) { - QEmulator* emulator = _emulator; + QEmulator* emulator = _emulator; qemulator_setup( emulator ); } +static void +qemulator_fb_poll( void* _emulator ) +{ + QEmulator* emulator = _emulator; + qemulator_refresh(emulator); +} + QEmulator* qemulator_get(void) { @@ -141,12 +152,17 @@ qemulator_init( QEmulator* emulator, SkinDisplay* disp = part->display; if (disp->valid) { qframebuffer_add_client( disp->qfbuff, - emulator, - qemulator_fb_update, - qemulator_fb_rotate, - NULL ); + emulator, + qemulator_fb_update, + qemulator_fb_rotate, + qemulator_fb_poll, + NULL ); } SKIN_FILE_LOOP_END_PARTS + + skin_keyboard_enable( emulator->keyboard, 1 ); + skin_keyboard_on_command( emulator->keyboard, handle_key_command, emulator ); + return 0; } @@ -301,6 +317,260 @@ get_default_scale( AndroidOptions* opts ) return scale; } +/* used to respond to a given keyboard command shortcut + */ +static void +handle_key_command( void* opaque, SkinKeyCommand command, int down ) +{ + static const struct { SkinKeyCommand cmd; AndroidKeyCode kcode; } keycodes[] = + { + { SKIN_KEY_COMMAND_BUTTON_CALL, kKeyCodeCall }, + { SKIN_KEY_COMMAND_BUTTON_HOME, kKeyCodeHome }, + { SKIN_KEY_COMMAND_BUTTON_BACK, kKeyCodeBack }, + { SKIN_KEY_COMMAND_BUTTON_HANGUP, kKeyCodeEndCall }, + { SKIN_KEY_COMMAND_BUTTON_POWER, kKeyCodePower }, + { SKIN_KEY_COMMAND_BUTTON_SEARCH, kKeyCodeSearch }, + { SKIN_KEY_COMMAND_BUTTON_MENU, kKeyCodeMenu }, + { SKIN_KEY_COMMAND_BUTTON_DPAD_UP, kKeyCodeDpadUp }, + { SKIN_KEY_COMMAND_BUTTON_DPAD_LEFT, kKeyCodeDpadLeft }, + { SKIN_KEY_COMMAND_BUTTON_DPAD_RIGHT, kKeyCodeDpadRight }, + { SKIN_KEY_COMMAND_BUTTON_DPAD_DOWN, kKeyCodeDpadDown }, + { SKIN_KEY_COMMAND_BUTTON_DPAD_CENTER, kKeyCodeDpadCenter }, + { SKIN_KEY_COMMAND_BUTTON_VOLUME_UP, kKeyCodeVolumeUp }, + { SKIN_KEY_COMMAND_BUTTON_VOLUME_DOWN, kKeyCodeVolumeDown }, + { SKIN_KEY_COMMAND_BUTTON_CAMERA, kKeyCodeCamera }, + { SKIN_KEY_COMMAND_NONE, 0 } + }; + int nn; +#ifdef CONFIG_TRACE + static int tracing = 0; +#endif + QEmulator* emulator = opaque; + + + for (nn = 0; keycodes[nn].kcode != 0; nn++) { + if (command == keycodes[nn].cmd) { + unsigned code = keycodes[nn].kcode; + if (down) + code |= 0x200; + user_event_keycode( code ); + return; + } + } + + // for the show-trackball command, handle down events to enable, and + // up events to disable + if (command == SKIN_KEY_COMMAND_SHOW_TRACKBALL) { + emulator->show_trackball = (down != 0); + skin_window_show_trackball( emulator->window, emulator->show_trackball ); + //qemulator_set_title( emulator ); + return; + } + + // only handle down events for the rest + if (down == 0) + return; + + switch (command) + { + case SKIN_KEY_COMMAND_TOGGLE_NETWORK: + { + qemu_net_disable = !qemu_net_disable; + android_core_set_network_enabled(!qemu_net_disable); + D( "network is now %s", qemu_net_disable ? "disconnected" : "connected" ); + } + break; + + case SKIN_KEY_COMMAND_TOGGLE_FULLSCREEN: + if (emulator->window) { + skin_window_toggle_fullscreen(emulator->window); + } + break; + + case SKIN_KEY_COMMAND_TOGGLE_TRACING: + { +#ifdef CONFIG_TRACE + tracing = !tracing; + if (tracing) + android_core_tracing_start(); + else + android_core_tracing_stop(); +#endif + } + break; + + case SKIN_KEY_COMMAND_TOGGLE_TRACKBALL: + emulator->show_trackball = !emulator->show_trackball; + skin_window_show_trackball( emulator->window, emulator->show_trackball ); + qemulator_set_title(emulator); + break; + + case SKIN_KEY_COMMAND_ONION_ALPHA_UP: + case SKIN_KEY_COMMAND_ONION_ALPHA_DOWN: + if (emulator->onion) + { + int alpha = emulator->onion_alpha; + + if (command == SKIN_KEY_COMMAND_ONION_ALPHA_UP) + alpha += 16; + else + alpha -= 16; + + if (alpha > 256) + alpha = 256; + else if (alpha < 0) + alpha = 0; + + emulator->onion_alpha = alpha; + skin_window_set_onion( emulator->window, emulator->onion, emulator->onion_rotation, alpha ); + skin_window_redraw( emulator->window, NULL ); + //dprint( "onion alpha set to %d (%.f %%)", alpha, alpha/2.56 ); + } + break; + + case SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV: + case SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT: + { + SkinLayout* layout = NULL; + + if (command == SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT) { + layout = emulator->layout->next; + if (layout == NULL) + layout = emulator->layout_file->layouts; + } + else if (command == SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV) { + layout = emulator->layout_file->layouts; + while (layout->next && layout->next != emulator->layout) + layout = layout->next; + } + if (layout != NULL) { + SkinRotation rotation; + + emulator->layout = layout; + skin_window_reset( emulator->window, layout ); + + rotation = skin_layout_get_dpad_rotation( layout ); + + if (emulator->keyboard) + skin_keyboard_set_rotation( emulator->keyboard, rotation ); + + if (emulator->trackball) { + skin_trackball_set_rotation( emulator->trackball, rotation ); + skin_window_set_trackball( emulator->window, emulator->trackball ); + skin_window_show_trackball( emulator->window, emulator->show_trackball ); + } + + skin_window_set_lcd_brightness( emulator->window, emulator->lcd_brightness ); + + qframebuffer_invalidate_all(); + qframebuffer_check_updates(); + } + } + break; + + default: + /* XXX: TODO ? */ + ; + } +} + +/* called periodically to poll for user input events */ +static void qemulator_refresh(QEmulator* emulator) +{ + SDL_Event ev; + SkinWindow* window = emulator->window; + SkinKeyboard* keyboard = emulator->keyboard; + + /* this will eventually call sdl_update if the content of the VGA framebuffer + * has changed */ + qframebuffer_check_updates(); + + if (window == NULL) + return; + + while(SDL_PollEvent(&ev)){ + switch(ev.type){ + case SDL_VIDEOEXPOSE: + skin_window_redraw( window, NULL ); + break; + + case SDL_KEYDOWN: +#ifdef _WIN32 + /* special code to deal with Alt-F4 properly */ + if (ev.key.keysym.sym == SDLK_F4 && + ev.key.keysym.mod & KMOD_ALT) { + goto CleanExit; + } +#endif +#ifdef __APPLE__ + /* special code to deal with Command-Q properly */ + if (ev.key.keysym.sym == SDLK_q && + ev.key.keysym.mod & KMOD_META) { + goto CleanExit; + } +#endif + skin_keyboard_process_event( keyboard, &ev, 1 ); + break; + + case SDL_KEYUP: + skin_keyboard_process_event( keyboard, &ev, 0 ); + break; + + case SDL_MOUSEMOTION: + skin_window_process_event( window, &ev ); + break; + + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + { + int down = (ev.type == SDL_MOUSEBUTTONDOWN); + if (ev.button.button == 4) + { + /* scroll-wheel simulates DPad up */ + AndroidKeyCode kcode; + + kcode = // qemulator_rotate_keycode(kKeyCodeDpadUp); + android_keycode_rotate(kKeyCodeDpadUp, + skin_layout_get_dpad_rotation(qemulator_get_layout(qemulator_get()))); + user_event_key( kcode, down ); + } + else if (ev.button.button == 5) + { + /* scroll-wheel simulates DPad down */ + AndroidKeyCode kcode; + + kcode = // qemulator_rotate_keycode(kKeyCodeDpadDown); + android_keycode_rotate(kKeyCodeDpadDown, + skin_layout_get_dpad_rotation(qemulator_get_layout(qemulator_get()))); + user_event_key( kcode, down ); + } + else if (ev.button.button == SDL_BUTTON_LEFT) { + skin_window_process_event( window, &ev ); + } +#if 0 + else { + fprintf(stderr, "... mouse button %s: button=%d state=%04x x=%d y=%d\n", + down ? "down" : "up ", + ev.button.button, ev.button.state, ev.button.x, ev.button.y); + } +#endif + } + break; + + case SDL_QUIT: +#if defined _WIN32 || defined __APPLE__ + CleanExit: +#endif + /* only save emulator config through clean exit */ + qemulator_done(qemulator_get()); + qemu_system_shutdown_request(); + return; + } + } + + skin_keyboard_flush( keyboard ); +} + /* * android/console.c helper routines. */ diff --git a/android/skin/window.c b/android/skin/window.c index 4765bba..48e5916 100644 --- a/android/skin/window.c +++ b/android/skin/window.c @@ -1220,15 +1220,6 @@ skin_window_reset_internal ( SkinWindow* window, SkinLayout* slayout ) skin_window_redraw( window, NULL ); - if (slayout->event_type != 0) { - user_event_generic( slayout->event_type, slayout->event_code, slayout->event_value ); - /* XXX: hack, replace by better code here */ - if (slayout->event_value != 0) - android_sensors_set_coarse_orientation( ANDROID_COARSE_PORTRAIT ); - else - android_sensors_set_coarse_orientation( ANDROID_COARSE_LANDSCAPE ); - } - return 0; } @@ -1238,7 +1229,18 @@ skin_window_reset ( SkinWindow* window, SkinLayout* slayout ) if (!window->fullscreen) { SDL_WM_GetPos(&window->x_pos, &window->y_pos); } - return skin_window_reset_internal( window, slayout ); + if (skin_window_reset_internal( window, slayout ) < 0) + return -1; + + if (slayout->event_type != 0) { + user_event_generic( slayout->event_type, slayout->event_code, slayout->event_value ); + /* XXX: hack, replace by better code here */ + if (slayout->event_value != 0) + android_sensors_set_coarse_orientation( ANDROID_COARSE_PORTRAIT ); + else + android_sensors_set_coarse_orientation( ANDROID_COARSE_LANDSCAPE ); + } + return 0; } void diff --git a/android/ui-core-protocol.c b/android/ui-core-protocol.c index c62f09e..3e4fdcc 100644 --- a/android/ui-core-protocol.c +++ b/android/ui-core-protocol.c @@ -23,6 +23,8 @@ #include "android/globals.h" #include "android/hw-control.h" #include "android/ui-core-protocol.h" +#include "telephony/modem_driver.h" +#include "trace.h" int android_core_get_hw_lcd_density(void) @@ -45,3 +47,25 @@ android_core_get_base_port(void) { return android_base_port; } + +void +android_core_set_network_enabled(int enabled) +{ + if (android_modem) { + amodem_set_data_registration( + android_modem, + qemu_net_disable ? A_REGISTRATION_UNREGISTERED + : A_REGISTRATION_HOME); + } +} + +void android_core_tracing_start(void) +{ + start_tracing(); +} + +void android_core_tracing_stop(void) +{ + stop_tracing(); +} + diff --git a/android/ui-core-protocol.h b/android/ui-core-protocol.h index 7b12f24..4ec025f 100644 --- a/android/ui-core-protocol.h +++ b/android/ui-core-protocol.h @@ -40,4 +40,11 @@ void android_core_set_brightness_change_callback(AndroidHwLightBrightnessCallbac /* Returns base port assigned for the emulated system. */ int android_core_get_base_port(void); +/* Sets/toggles the network state */ +void android_core_set_network_enabled(int enabled); + +/* Start/stop tracing in the guest system */ +void android_core_tracing_start(void); +void android_core_tracing_stop(void); + #endif // QEMU_ANDROID_UI_CORE_PROTOCOL_H @@ -330,4 +330,9 @@ char *vnc_display_local_addr(DisplayState *ds); /* curses.c */ void curses_display_init(DisplayState *ds, int full_screen); +#if defined(CONFIG_ANDROID) +/* android-display.c */ +void android_display_init(DisplayState *ds); +#endif + #endif diff --git a/docs/DISPLAY-STATE.TXT b/docs/DISPLAY-STATE.TXT new file mode 100644 index 0000000..b76376f --- /dev/null +++ b/docs/DISPLAY-STATE.TXT @@ -0,0 +1,263 @@ +This tries to document the mess that is DisplayState in QEMU. +See "console.h" for the main definitions, and below for some +explanations: + + +DISPLAY STATE OBJECTS: +====================== + +A DisplayState holds state for stuff to be displayed on QEMU. More +precisely: + + - A DisplayState owns a 'DisplaySurface' which is nothing more than a + pixel buffer with specific dimensions, pitch and format plus bytes + to carry its content. + + - A DisplayState also holds a 'DisplayAllocator' which allows it to + allocate its surface through a proper API. For example, this is + used in the upstream sdl UI backend to allocate the surface pixels + through SDL_SetVideoMode(). The default allocator simply uses + 'malloc' to do the allocation (with 32-bits/pixel). + + - A DisplayState also holds a list of DisplayChangeListener object. + Each listener contains a small set of callbacks that will be called + whenever an "event" happens on the display state. Events examples + are: + + dpy_update: a rectangular portion of the surface has been updated. + dpy_resize: the hardware decided to resize the framebuffer. + dpy_refresh: called periodically by the GUI timer. + dpy_copy: the hardware performed a rectangular copy operation. + dpy_fill: the hardware performed a rectangular fill operation. + dpy_setdata: the hardware decided to change the framebuffer address. + dpy_text_cursor: the hardware placed the text cursor at a given (x,y). + + NOTE: dpy_setdata is essentially the same than dpy_resize except that + there is a guarantee that the size didn't change. + + More on DisplayChangeListeners below. + + - The file "console.h" provides many helper functions to call all listeners + registered for a given DisplayState. For example, dpy_update(ds,x,y,w,h) + will call the 'dpy_update' callback of all listeners for the display + state 'ds'. + + +CONSOLES: +========= + +A "console" is something that can write pixels into a DisplayState. +There are two kinds of consoles, and they're fairly different in usage. + + GRAPHICAL CONSOLE: + ------------------ + + A "Graphical console" creates and owns a DisplayState. It is used when one + needs to write directly to the DisplaySurface pixel buffer. A typical + hardware framebuffer emulator (e.g. hw/vga-pic.c) will call the + function graphic_console_init() to create the DisplayState. Note that + this functions accepts several callbacks and is defined as: + + typedef void (*vga_hw_update_ptr)(void *); + typedef void (*vga_hw_invalidate_ptr)(void *); + typedef void (*vga_hw_screen_dump_ptr)(void *, const char *); + typedef void (*vga_hw_text_update_ptr)(void *, console_ch_t *); + + DisplayState *graphic_console_init(vga_hw_update_ptr update, + vga_hw_invalidate_ptr invalidate, + vga_hw_screen_dump_ptr screen_dump, + vga_hw_text_update_ptr text_update, + void *opaque); + + The update/invalidate/screen_dump/text_update functions must be provided + by the hardware framebuffer emulation, and will be called under various + circumstances: + + 'update' is called periodically to check for any hw framebuffer + updates (and then copy them to the DisplayState, to finally send + them through dpy_update() to the listeners). + + 'invalidate' is called to indicate that the next call to 'update' + should send the content of _all_ the framebuffer, instead of only + the smallest possible update. + + 'screen_dump' is called to force a screen dump (i.e. print the + content of the framebuffer to a ppm file, which name is passed as + a parameter). + + 'text_update' is called to display one single character. XXX: Code is + not very clear, but probably related to text console. + + + TEXT CONSOLES: + -------------- + + A "Text console" attaches to an existing DisplayState, and is able to + take over its rendering in order to display a text *terminal*. It's not + sure whether this emulates VT101 or something else (see the code inside + the console_putchar() for all the gory details), but the main idea is + that you create a console with a call to: + + CharDriverState* text_console_init(const char* p); + + The function returns a CharDriverState* (see docs/CHAR-DEVICES.TXT) that + will be connected to a host device identified by the string in 'p'. This + allows you, for example, to connect the console to stdio. + + The text console code is capable of producing a bitmap each time you update + its content (i.e. it includes code to manage fixed-size font rendering, + scrolling, escape sequences, color, blinking cursor, etc...). + + - By default, the graphics console writes to its DisplayState, but you can + use console_select() to change that at runtime. This function can be used + to force switching between virtual terminals and the graphics display. + There can be several text consoles associated to a single DisplayState + object. + + +DISPLAY CHANGE LISTENERES: +========================== + +There QEMU sources provide the implementation for various +DisplayChangeListeners, most notables are the following: + + - In sdl.c: This one uses the SDL library to display the content of a + DisplaySurface through a SDL_Window. The implementation also supports + zooming the output to an arbitrary size (using SDL functions). + + - In vnc.c: This listener implements a VNC Server that can be used to + display the DisplaySurface remotely through the RDP protocol. + + - In curses.c: This listener is used to display text consoles through the + "curses" library on Unix systems. It cannot be used to display any + graphics though. + +NOTE: The initialization sequence in vl.c only allows for a single listener +on the main display state, but the rest of the code deals with several +listeners per DisplayState just fine. + +Each DisplayChangeListener can specify a refresh period (e.g. every 1/60th +of second). QEMU will then create a timer that will be programmed to called +the listener's 'dpy_refresh' callback periodically. The point of this +callback is to perform the following: + +- poll for new user input events from the underlying UI (e.g. from the SDL + event loop, or from the network for VNC). These should be translated into + guest event codes with functions like 'kbd_put_keycode' or 'kbd_mouse_event'. + +- call the global vga_hw_update() function. It will, if the graphics console + is being displayed, call the 'update' callback that was passed to + graphic_console_init(). If a text console is being displayed, the does + nothing. + +- eventually call the global vga_hw_invalidate() to indicate that the whole + framebuffer content should be resent as an update. This can happen when a + UI window was minimized and is made visible again, for example. + + +INITIALIZATION AND RUNTIME EXECUTION: +===================================== + +Initialization happens in the qemu main() function in the vl.c source file. + +First, the hardware machine is initialized. The hardware fraembuffer emulation +shall call graphic_console_init() to create a new DisplayState. Note that the +object returned by this function has a default DisplaySurface of 640x480 pixels +allocated through malloc(). In other words, the hardware emulation does not +set the size of the display state by default! + +After that, the listener's initialization function (e.g. sdl_display_init) +is called. It is passed the DisplayState object and can replace the +corresponding DisplaySurface with another one with proper dimensions, and +eventually created with a different DisplayAllocator. It also registers a +DisplayChangeListener to receive later state changes. + +Note that the VNC listener doesn't change the dimension of the DisplayState +surface it is initialized with. However, it will react to dpy_resize events +accordingly. + +NOTE: dpy_resize()s are currently only generated when switching between +consoles, or when the framebuffer's size is modified by the guest kernel. + + +The GUI timer, corresponding to the first listener than has one refresh +period, drives the whole update process (if no listener provides a refresh +period, a default 'no_graphic' timer is setup with a default refresh period +of 30 frame/s). + +Things happen in this order: + + - the GUI timer kicks in, and calls the 'dpy_refresh()' callback of + the listener (each listener has its own timer, btw). + + - the listener callback polls for user events, and calls vga_hw_update() + to see if there are hardware framebuffer updates. + + - vga_hw_update() checks that the graphics console is displayed (otherwise + it exits) + + - it then calls the graphics console's 'update' callback + + - the callback, implemented by the framebuffer hw emulation, checks for + dirty pages in order to detect what changed since it was invoked. + + For every rectangle of the hw framebuffer that was modified, it copies + the pixels from VRAM into the DisplayState's surface buffer (eventually + performing format conversion at the same time). + + After that, it calls dpy_update() to send the update to all registered + listeners for the DisplayState. + + - The listener's 'dpy_update' callback is called and receives a pointer + to the DisplayState, and the rectangle corresponding to the update. Its + implementation can then update the content of the screen (or the internal + VNC framebuffer). + +Eventually, hardware emulation can also trigger other dpy_xxxx events (e.g. +dpy_resize, dpy_copy, dpy_fill....) + +Here's a simplified diagram of what happens in the typical case: + + _____________ + | | + | hardware | + | framebuffer |-------+ + | | | + |_____________| | + ^ | + | | + | 3/ ds.update() | 4/ dpy_update(ds,x,y,w,h) + | | + | | + _____________ | + | | | + | Display | <-----+ + | State | + | | ----------+ + |_____________| | + ^ | + | | + | 2/ vga_hw_update() | + | | + | | + | | + | +---------------+ + | | | + | | 5/listener.dpy_update(ds,x,y,w,h) + | | | + | | | 6/listener.dpy_update(...) + | | | + | v v + _____________ _____________ + | | | | + | SDL | | VNC | + | Listener | | Listener | + | | | | + |_____________| |_____________| + ^ + | + | 1/ listener.dpy_refresh() + | + + GUI timer + diff --git a/framebuffer.c b/framebuffer.c index d0f9b40..adbebb3 100644 --- a/framebuffer.c +++ b/framebuffer.c @@ -19,6 +19,7 @@ typedef struct { void* fb_opaque; QFrameBufferUpdateFunc fb_update; QFrameBufferRotateFunc fb_rotate; + QFrameBufferPollFunc fb_poll; QFrameBufferDoneFunc fb_done; void* pr_opaque; @@ -122,6 +123,7 @@ qframebuffer_add_client( QFrameBuffer* qfbuff, void* fb_opaque, QFrameBufferUpdateFunc fb_update, QFrameBufferRotateFunc fb_rotate, + QFrameBufferPollFunc fb_poll, QFrameBufferDoneFunc fb_done ) { QFrameBufferExtra* extra = qfbuff->extra; @@ -129,6 +131,7 @@ qframebuffer_add_client( QFrameBuffer* qfbuff, extra->fb_opaque = fb_opaque; extra->fb_update = fb_update; extra->fb_rotate = fb_rotate; + extra->fb_poll = fb_poll; extra->fb_done = fb_done; } @@ -170,6 +173,15 @@ qframebuffer_rotate( QFrameBuffer* qfbuff, int rotation ) extra->fb_rotate( extra->fb_opaque, rotation ); } +void +qframebuffer_poll( QFrameBuffer* qfbuff ) +{ + QFrameBufferExtra* extra = qfbuff->extra; + + if (extra->fb_poll) + extra->fb_poll( extra->fb_opaque ); +} + extern void qframebuffer_done( QFrameBuffer* qfbuff ) diff --git a/framebuffer.h b/framebuffer.h index 1dce0d9..9e99d26 100644 --- a/framebuffer.h +++ b/framebuffer.h @@ -106,6 +106,13 @@ typedef void (*QFrameBufferUpdateFunc)( void* opaque, int x, int y, */ typedef void (*QFrameBufferRotateFunc)( void* opaque, int rotation ); +/* the Client::Poll method is called periodically to poll for input + * events and act on them. Putting this here is not 100% pure but + * make things simpler due to QEMU's weird architecture where the + * GUI timer drivers event polling. + */ +typedef void (*QFrameBufferPollFunc)( void* opaque ); + /* the Client::Done func tells a client that a framebuffer object was freed. * no more reference to its pixels should be done. */ @@ -121,6 +128,7 @@ qframebuffer_add_client( QFrameBuffer* qfbuff, void* fb_opaque, QFrameBufferUpdateFunc fb_update, QFrameBufferRotateFunc fb_rotate, + QFrameBufferPollFunc fb_poll, QFrameBufferDoneFunc fb_done ); /* Producer::CheckUpdate is called to let the producer check the @@ -161,6 +169,9 @@ qframebuffer_update( QFrameBuffer* qfbuff, int x, int y, int w, int h ); extern void qframebuffer_rotate( QFrameBuffer* qfbuff, int rotation ); +extern void +qframebuffer_poll( QFrameBuffer* qfbuff ); + /* finalize a framebuffer, release its pixel buffer. Should be called * from the framebuffer object's owner */ diff --git a/hw/android_arm.c b/hw/android_arm.c index f5df7f2..d805b0e 100644 --- a/hw/android_arm.c +++ b/hw/android_arm.c @@ -70,7 +70,6 @@ static void android_arm_init_(ram_addr_t ram_size, int i; struct arm_boot_info info; ram_addr_t ram_offset; - DisplayState* ds = get_displaystate(); if (!cpu_model) cpu_model = "arm926"; @@ -116,7 +115,7 @@ static void android_arm_init_(ram_addr_t ram_size, } } - goldfish_fb_init(ds, 0); + goldfish_fb_init(0); #ifdef HAS_AUDIO goldfish_audio_init(0xff004000, 0, audio_input_source); #endif diff --git a/hw/goldfish_device.h b/hw/goldfish_device.h index d04a166..19f4b32 100644 --- a/hw/goldfish_device.h +++ b/hw/goldfish_device.h @@ -41,7 +41,7 @@ int goldfish_device_bus_init(uint32_t base, uint32_t irq); qemu_irq *goldfish_interrupt_init(uint32_t base, qemu_irq parent_irq, qemu_irq parent_fiq); void goldfish_timer_and_rtc_init(uint32_t timerbase, int timerirq); int goldfish_tty_add(CharDriverState *cs, int id, uint32_t base, int irq); -void goldfish_fb_init(DisplayState *ds, int id); +void goldfish_fb_init(int id); void goldfish_audio_init(uint32_t base, int id, const char* input_source); void goldfish_battery_init(); void goldfish_battery_set_prop(int ac, int property, int value); diff --git a/hw/goldfish_events_device.c b/hw/goldfish_events_device.c index 9e98dac..3f5bf0b 100644 --- a/hw/goldfish_events_device.c +++ b/hw/goldfish_events_device.c @@ -102,7 +102,7 @@ static void enqueue_event(events_state *s, unsigned int type, unsigned int code, return; } - if(s->first == s->last){ + if(s->first == s->last) { qemu_irq_raise(s->irq); } diff --git a/hw/goldfish_fb.c b/hw/goldfish_fb.c index d092fe4..8300e7c 100644 --- a/hw/goldfish_fb.c +++ b/hw/goldfish_fb.c @@ -12,7 +12,7 @@ #include "qemu_file.h" #include "android/android.h" #include "goldfish_device.h" -#include "framebuffer.h" +#include "console.h" enum { FB_GET_WIDTH = 0x00, @@ -31,7 +31,7 @@ enum { struct goldfish_fb_state { struct goldfish_device dev; - QFrameBuffer* qfbuff; + DisplayState* ds; uint32_t fb_base; uint32_t base_valid : 1; uint32_t need_update : 1; @@ -41,20 +41,21 @@ struct goldfish_fb_state { uint32_t int_status; uint32_t int_enable; int rotation; /* 0, 1, 2 or 3 */ + int dpi; }; -#define GOLDFISH_FB_SAVE_VERSION 1 +#define GOLDFISH_FB_SAVE_VERSION 2 static void goldfish_fb_save(QEMUFile* f, void* opaque) { struct goldfish_fb_state* s = opaque; - QFrameBuffer* q = s->qfbuff; + DisplayState* ds = s->ds; - qemu_put_be32(f, q->width); - qemu_put_be32(f, q->height); - qemu_put_be32(f, q->pitch); - qemu_put_byte(f, q->rotation); + qemu_put_be32(f, ds->surface->width); + qemu_put_be32(f, ds->surface->height); + qemu_put_be32(f, ds->surface->linesize); + qemu_put_byte(f, 0); qemu_put_be32(f, s->fb_base); qemu_put_byte(f, s->base_valid); @@ -65,13 +66,12 @@ static void goldfish_fb_save(QEMUFile* f, void* opaque) qemu_put_be32(f, s->int_status); qemu_put_be32(f, s->int_enable); qemu_put_be32(f, s->rotation); + qemu_put_be32(f, s->dpi); } static int goldfish_fb_load(QEMUFile* f, void* opaque, int version_id) { struct goldfish_fb_state* s = opaque; - - QFrameBuffer* q = s->qfbuff; int ret = -1; int ds_w, ds_h, ds_pitch, ds_rot; @@ -83,10 +83,12 @@ static int goldfish_fb_load(QEMUFile* f, void* opaque, int version_id) ds_pitch = qemu_get_be32(f); ds_rot = qemu_get_byte(f); - if (q->width != ds_w || - q->height != ds_h || - q->pitch != ds_pitch || - q->rotation != ds_rot ) + DisplayState* ds = s->ds; + + if (ds->surface->width != ds_w || + ds->surface->height != ds_h || + ds->surface->linesize != ds_pitch || + ds_rot != 0) { /* XXX: We should be able to force a resize/rotation from here ? */ fprintf(stderr, "%s: framebuffer dimensions mismatch\n", __FUNCTION__); @@ -102,6 +104,7 @@ static int goldfish_fb_load(QEMUFile* f, void* opaque, int version_id) s->int_status = qemu_get_be32(f); s->int_enable = qemu_get_be32(f); s->rotation = qemu_get_be32(f); + s->dpi = qemu_get_be32(f); /* force a refresh */ s->need_update = 1; @@ -111,6 +114,17 @@ Exit: return ret; } +static int +pixels_to_mm(int pixels, int dpi) +{ + /* dpi = dots / inch + ** inch = dots / dpi + ** mm / 25.4 = dots / dpi + ** mm = (dots * 25.4)/dpi + */ + return (int)(0.5 + 25.4 * pixels / dpi); +} + #define STATS 0 @@ -156,10 +170,11 @@ static void goldfish_fb_update_display(void *opaque) } src_line = qemu_get_ram_ptr( base ); - dst_line = s->qfbuff->pixels; - pitch = s->qfbuff->pitch; - width = s->qfbuff->width; - height = s->qfbuff->height; + + dst_line = s->ds->surface->data; + pitch = s->ds->surface->linesize; + width = s->ds->surface->width; + height = s->ds->surface->height; #if STATS if (full_update) @@ -272,7 +287,7 @@ static void goldfish_fb_update_display(void *opaque) base + y_last * width * 2, VGA_DIRTY_FLAG); - qframebuffer_update( s->qfbuff, 0, y_first, width, y_last-y_first ); + dpy_update(s->ds, 0, y_first, width, y_last-y_first); } static void goldfish_fb_invalidate_display(void * opaque) @@ -282,12 +297,6 @@ static void goldfish_fb_invalidate_display(void * opaque) s->need_update = 1; } -static void goldfish_fb_detach_display(void* opaque) -{ - struct goldfish_fb_state *s = (struct goldfish_fb_state *)opaque; - s->qfbuff = NULL; -} - static uint32_t goldfish_fb_read(void *opaque, target_phys_addr_t offset) { uint32_t ret; @@ -295,12 +304,12 @@ static uint32_t goldfish_fb_read(void *opaque, target_phys_addr_t offset) switch(offset) { case FB_GET_WIDTH: - ret = s->qfbuff->width; + ret = ds_get_width(s->ds); //printf("FB_GET_WIDTH => %d\n", ret); return ret; case FB_GET_HEIGHT: - ret = s->qfbuff->height; + ret = ds_get_height(s->ds); //printf( "FB_GET_HEIGHT = %d\n", ret); return ret; @@ -313,12 +322,12 @@ static uint32_t goldfish_fb_read(void *opaque, target_phys_addr_t offset) return ret; case FB_GET_PHYS_WIDTH: - ret = s->qfbuff->phys_width_mm; + ret = pixels_to_mm( ds_get_width(s->ds), s->dpi ); //printf( "FB_GET_PHYS_WIDTH => %d\n", ret ); return ret; case FB_GET_PHYS_HEIGHT: - ret = s->qfbuff->phys_height_mm; + ret = pixels_to_mm( ds_get_height(s->ds), s->dpi ); //printf( "FB_GET_PHYS_HEIGHT => %d\n", ret ); return ret; @@ -353,7 +362,7 @@ static void goldfish_fb_write(void *opaque, target_phys_addr_t offset, goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable)); if (need_resize) { //printf("FB_SET_BASE: need resize (rotation=%d)\n", s->rotation ); - qframebuffer_rotate( s->qfbuff, s->rotation ); + dpy_resize(s->ds); } } break; case FB_SET_ROTATION: @@ -381,7 +390,7 @@ static CPUWriteMemoryFunc *goldfish_fb_writefn[] = { goldfish_fb_write }; -void goldfish_fb_init(DisplayState *ds, int id) +void goldfish_fb_init(int id) { struct goldfish_fb_state *s; @@ -391,15 +400,16 @@ void goldfish_fb_init(DisplayState *ds, int id) s->dev.size = 0x1000; s->dev.irq_count = 1; - s->qfbuff = qframebuffer_fifo_get(); - qframebuffer_set_producer( s->qfbuff, s, - goldfish_fb_update_display, - goldfish_fb_invalidate_display, - goldfish_fb_detach_display ); + s->ds = graphic_console_init(goldfish_fb_update_display, + goldfish_fb_invalidate_display, + NULL, + NULL, + s); + + s->dpi = 165; /* XXX: Find better way to get actual value ! */ goldfish_device_add(&s->dev, goldfish_fb_readfn, goldfish_fb_writefn, s); register_savevm( "goldfish_fb", 0, GOLDFISH_FB_SAVE_VERSION, goldfish_fb_save, goldfish_fb_load, s); } - |