diff options
author | David 'Digit' Turner <digit@android.com> | 2011-08-26 01:35:14 +0200 |
---|---|---|
committer | David 'Digit' Turner <digit@android.com> | 2011-08-29 17:02:17 +0200 |
commit | cb88e79ecbd16dea5f2201fd12320db5945db83e (patch) | |
tree | a4f22e25a58723ae81cb9adc6a9a09e3f6a32a43 | |
parent | 6a8b698fff4d328c2706776c1c09171cfadb8de4 (diff) | |
download | external_qemu-cb88e79ecbd16dea5f2201fd12320db5945db83e.zip external_qemu-cb88e79ecbd16dea5f2201fd12320db5945db83e.tar.gz external_qemu-cb88e79ecbd16dea5f2201fd12320db5945db83e.tar.bz2 |
Add hw.gpu.enabled hardware property
This patch adds a new hardware property to enable GPU emulation
(named hw.gpu.enabled). It is currently disabled by default.
It also modifies the UI code to display the GL output properly
inside the UI window. And sets the kernel parameter qemu.gles
to either 0 or 1 to indicate to the guest system's GLES libraries
whether to use GPU emulation or fallback to the software renderer.
A future patch will also add auto-detection of desktop GL capabilities.
For example, if the emulator is started on a headless server without
an X11/GL display, hw.gpu.enabled will be forced to 'no', forcing the
guest to use the software renderer.
Another patch will allow to change the property from the command-line
for debugging purpose.
NOTE: If you want to test GPU emulation, change the default value of
the property in android/avd/hardware-properties.ini from 'no'
to 'yes'. You will need to run a ToT master AOSP tree with
the following pending patches applied:
https://review.source.android.com/25797
https://review.source.android.com/25154
https://review.source.android.com/25759
Change-Id: I1fa3512be24395244fd5068f2bf59ad54db5c7d5
-rw-r--r-- | Makefile.android | 1 | ||||
-rw-r--r-- | Makefile.target | 2 | ||||
-rw-r--r-- | android/avd/hardware-properties.ini | 8 | ||||
-rw-r--r-- | android/hw-pipe-net.c | 27 | ||||
-rw-r--r-- | android/opengles.c | 167 | ||||
-rw-r--r-- | android/opengles.h | 37 | ||||
-rw-r--r-- | android/skin/scaler.c | 22 | ||||
-rw-r--r-- | android/skin/scaler.h | 6 | ||||
-rw-r--r-- | android/skin/window.c | 54 | ||||
-rw-r--r-- | android/utils/debug.h | 1 | ||||
-rw-r--r-- | vl-android.c | 24 |
11 files changed, 346 insertions, 3 deletions
diff --git a/Makefile.android b/Makefile.android index 01cb35b..95287fd 100644 --- a/Makefile.android +++ b/Makefile.android @@ -242,6 +242,7 @@ LOCAL_SRC_FILES := \ android/snapshot.c \ android/main-common.c \ android/main.c \ + android/opengles.c \ android/utils/setenv.c \ vl-android-ui.c \ android/protocol/core-connection.c \ diff --git a/Makefile.target b/Makefile.target index ccc86b4..07940bb 100644 --- a/Makefile.target +++ b/Makefile.target @@ -269,6 +269,7 @@ LOCAL_SRC_FILES := \ user-events-qemu.c \ vl-android.c \ android/console.c \ + android/opengles.c \ android/display-core.c \ android/protocol/attach-ui-proxy.c \ android/protocol/fb-updates-proxy.c \ @@ -353,6 +354,7 @@ LOCAL_SRC_FILES := \ android/help.c \ android/main-common.c \ android/main.c \ + android/opengles.c \ android/protocol/core-commands-qemu.c \ android/protocol/ui-commands-qemu.c \ android/ diff --git a/android/avd/hardware-properties.ini b/android/avd/hardware-properties.ini index 0e650bb..e7eb445 100644 --- a/android/avd/hardware-properties.ini +++ b/android/avd/hardware-properties.ini @@ -224,6 +224,14 @@ default = yes abstract = LCD backlight description = Enable/Disable LCD backlight simulation,yes-enabled,no-disabled. +# Hardware OpenGLES emulation support +# +name = hw.gpu.enabled +type = boolean +default = no +abstract = GPU emulation +description = Enable/Disable emulated OpenGLES GPU + # Maximum VM heap size # Higher values are required for high-dpi devices # Default will depend on RAM size. diff --git a/android/hw-pipe-net.c b/android/hw-pipe-net.c index dd8c8b1..8b8017d 100644 --- a/android/hw-pipe-net.c +++ b/android/hw-pipe-net.c @@ -23,6 +23,7 @@ #include "android/utils/panic.h" #include "android/utils/system.h" #include "android/async-utils.h" +#include "android/opengles.h" #include "android/looper.h" #include "hw/goldfish_pipe.h" @@ -454,7 +455,11 @@ static const GoldfishPipeFuncs netPipeUnix_funcs = { }; #endif -#define DEFAULT_OPENGLES_PORT 22468 +/* This is set to 1 in android_init_opengles() below, and tested + * by openglesPipe_init() to refuse a pipe connection if the function + * was never called. + */ +static int _opengles_init; static void* openglesPipe_init( void* hwpipe, void* _looper, const char* args ) @@ -462,8 +467,15 @@ openglesPipe_init( void* hwpipe, void* _looper, const char* args ) char temp[32]; NetPipe *pipe; + if (!_opengles_init) { + /* This should never happen, unless there is a bug in the + * emulator's initialization, or the system image. */ + D("Trying to open the OpenGLES pipe without GPU emulation!"); + return NULL; + } + /* For now, simply connect through tcp */ - snprintf(temp, sizeof temp, "%d", DEFAULT_OPENGLES_PORT); + snprintf(temp, sizeof temp, "%d", ANDROID_OPENGLES_BASE_PORT); pipe = (NetPipe *)netPipe_initTcp(hwpipe, _looper, temp); if (pipe != NULL) { @@ -496,7 +508,6 @@ static const GoldfishPipeFuncs openglesPipe_funcs = { netPipe_wakeOn, }; - void android_net_pipes_init(void) { @@ -508,3 +519,13 @@ android_net_pipes_init(void) #endif goldfish_pipe_add_type( "opengles", looper, &openglesPipe_funcs ); } + +int +android_init_opengles_pipes(void) +{ + /* TODO: Check that we can load and initialize the host emulation + * libraries, and return -1 in case of error. + */ + _opengles_init = 1; + return 0; +} diff --git a/android/opengles.c b/android/opengles.c new file mode 100644 index 0000000..5d0c152 --- /dev/null +++ b/android/opengles.c @@ -0,0 +1,167 @@ +/* Copyright (C) 2011 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. +*/ + +#include "config-host.h" +#include "android/opengles.h" +#include <android/utils/debug.h> +#include <android/utils/path.h> +#include <android/utils/bufprint.h> +#include <android/utils/dll.h> +#include <stdio.h> +#include <stdlib.h> + +#define D(...) VERBOSE_PRINT(init,__VA_ARGS__) +#define DD(...) VERBOSE_PRINT(gles,__VA_ARGS__) + +/* Name of the GLES rendering library we're going to use */ +#define RENDERER_LIB_NAME "libOpenglRender" + +/* These definitions *must* match those under: + * development/tools/emulator/opengl/host/include/libOpenglRender/render_api.h + */ +#define DYNLINK_FUNCTIONS \ + DYNLINK_FUNC(int,initLibrary,(void),(),return) \ + DYNLINK_FUNC(int,initOpenGLRenderer,(int width, int height, int port),(width,height,port),return) \ + DYNLINK_FUNC(int,createOpenGLSubwindow,(void* window, int x, int y, int width, int height, float zRot),(window,x,y,width,height,zRot),return)\ + DYNLINK_FUNC(int,destroyOpenGLSubwindow,(void),(),return)\ + DYNLINK_FUNC(void,repaintOpenGLDisplay,(void),(),)\ + DYNLINK_FUNC(void,stopOpenGLRenderer,(void),(),) + + +#ifndef CONFIG_STANDALONE_UI +/* Defined in android/hw-pipe-net.c */ +extern int android_init_opengles_pipes(void); +#endif + +static ADynamicLibrary* rendererLib; + +/* Define the pointers and the wrapper functions to call them */ +#define DYNLINK_FUNC(result,name,sig,params,ret) \ + static result (*_ptr_##name) sig; \ + static result name sig { \ + ret (*_ptr_##name) params ; \ + } + +DYNLINK_FUNCTIONS + +#undef DYNLINK_FUNC + +static int +initOpenglesEmulationFuncs(ADynamicLibrary* rendererLib) +{ + void* symbol; + char* error; +#define DYNLINK_FUNC(result,name,sig,params,ret) \ + symbol = adynamicLibrary_findSymbol( rendererLib, #name, &error ); \ + if (symbol != NULL) { \ + _ptr_##name = symbol; \ + } else { \ + derror("GLES emulation: Could not find required symbol (%s): %s", #name, error); \ + free(error); \ + return -1; \ + } +DYNLINK_FUNCTIONS +#undef DYNLINK_FUNC + return 0; +} + +int +android_initOpenglesEmulation(void) +{ + char* error = NULL; + + if (rendererLib != NULL) + return 0; + + D("Initializing hardware OpenGLES emulation support"); + + rendererLib = adynamicLibrary_open(RENDERER_LIB_NAME, &error); + if (rendererLib == NULL) { + derror("Could not load OpenGLES emulation library: %s", error); + return -1; + } + +#ifndef CONFIG_STANDALONE_UI + android_init_opengles_pipes(); +#endif + + + /* Resolve the functions */ + if (initOpenglesEmulationFuncs(rendererLib) < 0) { + derror("OpenGLES emulation library mismatch. Be sure to use the correct version!"); + goto BAD_EXIT; + } + + if (!initLibrary()) { + derror("OpenGLES initialization failed!"); + goto BAD_EXIT; + } + + return 0; + +BAD_EXIT: + derror("OpenGLES emulation library could not be initialized!"); + adynamicLibrary_close(rendererLib); + rendererLib = NULL; + return -1; +} + +int +android_startOpenglesRenderer(int width, int height) +{ + if (!rendererLib) { + D("Can't start OpenGLES renderer without support libraries"); + return -1; + } + + if (initOpenGLRenderer(width, height,ANDROID_OPENGLES_BASE_PORT) != 0) { + D("Can't start OpenGLES renderer?"); + return -1; + } + return 0; +} + +void +android_stopOpenglesRenderer(void) +{ + if (rendererLib) { + stopOpenGLRenderer(); + } +} + +int +android_showOpenglesWindow(void* window, int x, int y, int width, int height, float rotation) +{ + if (rendererLib) { + return createOpenGLSubwindow(window, x, y, width, height, rotation); + } else { + return -1; + } +} + +int +android_hideOpenglesWindow(void) +{ + if (rendererLib) { + return destroyOpenGLSubwindow(); + } else { + return -1; + } +} + +void +android_redrawOpenglesWindow(void) +{ + if (rendererLib) { + repaintOpenGLDisplay(); + } +} diff --git a/android/opengles.h b/android/opengles.h new file mode 100644 index 0000000..b31ce11 --- /dev/null +++ b/android/opengles.h @@ -0,0 +1,37 @@ +/* Copyright (C) 2011 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_OPENGLES_H +#define ANDROID_OPENGLES_H + +#define ANDROID_OPENGLES_BASE_PORT 22468 + +/* Call this function to initialize the hardware opengles emulation. + * This function will abort if we can't find the corresponding host + * libraries through dlopen() or equivalent. + */ +int android_initOpenglesEmulation(void); + +/* Tries to start the renderer process. Returns 0 on success, -1 on error. + * At the moment, this must be done before the VM starts. + */ +int android_startOpenglesRenderer(int width, int height); + +int android_showOpenglesWindow(void* window, int x, int y, int width, int height, float rotation); + +int android_hideOpenglesWindow(void); + +void android_redrawOpenglesWindow(void); + +/* Stop the renderer process */ +void android_stopOpenglesRenderer(void); + +#endif /* ANDROID_OPENGLES_H */ diff --git a/android/skin/scaler.c b/android/skin/scaler.c index 907c5ca..5672869 100644 --- a/android/skin/scaler.c +++ b/android/skin/scaler.c @@ -81,6 +81,28 @@ typedef struct { void +skin_scaler_get_scaled_rect( SkinScaler* scaler, + SkinRect* srect, + SkinRect* drect ) +{ + int sx = srect->pos.x; + int sy = srect->pos.y; + int sw = srect->size.w; + int sh = srect->size.h; + double scale = scaler->scale; + + if (!scaler->valid) { + drect[0] = srect[0]; + return; + } + + drect->pos.x = (int)(sx * scale + scaler->xdisp); + drect->pos.y = (int)(sy * scale + scaler->ydisp); + drect->size.w = (int)(ceil((sx + sw) * scale + scaler->xdisp)) - drect->pos.x; + drect->size.h = (int)(ceil((sy + sh) * scale + scaler->ydisp)) - drect->pos.y; +} + +void skin_scaler_scale( SkinScaler* scaler, SDL_Surface* dst_surface, SDL_Surface* src_surface, diff --git a/android/skin/scaler.h b/android/skin/scaler.h index 4e0ec5a..e2d7641 100644 --- a/android/skin/scaler.h +++ b/android/skin/scaler.h @@ -26,6 +26,12 @@ extern int skin_scaler_set( SkinScaler* scaler, double xDisp, double yDisp ); +/* retrieve the position of the scaled source rectangle 'srect' into 'drect' + * you can use the same pointer for both parameters. */ +extern void skin_scaler_get_scaled_rect( SkinScaler* scaler, + SkinRect* srect, + SkinRect* drect ); + extern void skin_scaler_free( SkinScaler* scaler ); extern void skin_scaler_scale( SkinScaler* scaler, diff --git a/android/skin/window.c b/android/skin/window.c index 9a72db5..5d8c684 100644 --- a/android/skin/window.c +++ b/android/skin/window.c @@ -22,6 +22,7 @@ #include <math.h> #include "android/framebuffer.h" +#include "android/opengles.h" /* when shrinking, we reduce the pixel ratio by this fixed amount */ #define SHRINK_SCALE 0.6 @@ -1140,6 +1141,44 @@ skin_window_show_trackball( SkinWindow* window, int enable ) } } +/* Hide the OpenGL ES framebuffer */ +static void +skin_window_hide_opengles( SkinWindow* window ) +{ + android_hideOpenglesWindow(); +} + +/* Show the OpenGL ES framebuffer window */ +static void +skin_window_show_opengles( SkinWindow* window ) +{ + { + SDL_SysWMinfo wminfo; + void* winhandle; + ADisplay* disp = window->layout.displays; + SkinRect drect = disp->rect; + + memset(&wminfo, 0, sizeof(wminfo)); + SDL_GetWMInfo(&wminfo); +#ifdef _WIN32 + winhandle = (void*)wminfo.window; +#elif defined(CONFIG_DARWIN) + winhandle = (void*)wminfo.nsWindowPtr; +#else + winhandle = (void*)wminfo.info.x11.window; +#endif + skin_scaler_get_scaled_rect(window->scaler, &drect, &drect); + + android_showOpenglesWindow(winhandle, drect.pos.x, drect.pos.y, + drect.size.w, drect.size.h, disp->rotation * -90.); + } +} + +static void +skin_window_redraw_opengles( SkinWindow* window ) +{ + android_redrawOpenglesWindow(); +} static int skin_window_reset_internal (SkinWindow*, SkinLayout*); @@ -1224,6 +1263,8 @@ skin_window_create( SkinLayout* slayout, int x, int y, double scale, int no dprint( "emulator window was out of view and was recentered\n" ); } + skin_window_show_opengles(window); + return window; } @@ -1261,6 +1302,9 @@ skin_window_set_title( SkinWindow* window, const char* title ) static void skin_window_resize( SkinWindow* window ) { + if ( !window->no_display ) + skin_window_hide_opengles(window); + /* now resize window */ if (window->surface) { SDL_FreeSurface(window->surface); @@ -1342,7 +1386,10 @@ skin_window_resize( SkinWindow* window ) } if (scale == 1.0) + { window->surface = surface; + skin_scaler_set( window->scaler, 1.0, 0, 0 ); + } else { window_w = (int) ceil(window_w / scale ); @@ -1361,6 +1408,8 @@ skin_window_resize( SkinWindow* window ) } skin_scaler_set( window->scaler, scale, window->effective_x, window->effective_y ); } + + skin_window_show_opengles(window); } } @@ -1552,6 +1601,7 @@ skin_window_redraw( SkinWindow* window, SkinRect* rect ) SDL_UpdateRects( window->surface, 1, &rd ); } + skin_window_redraw_opengles( window ); } } @@ -1681,6 +1731,10 @@ skin_window_process_event( SkinWindow* window, SDL_Event* ev ) } } break; + + case SDL_VIDEOEXPOSE: + skin_window_redraw_opengles(window); + break; } } diff --git a/android/utils/debug.h b/android/utils/debug.h index 76b21be..096b002 100644 --- a/android/utils/debug.h +++ b/android/utils/debug.h @@ -36,6 +36,7 @@ _VERBOSE_TAG(sensors, "emulated sensors") \ _VERBOSE_TAG(memcheck, "memory checker") \ _VERBOSE_TAG(camera, "camera") \ + _VERBOSE_TAG(gles, "hardware OpenGLES emulation") \ #define _VERBOSE_TAG(x,y) VERBOSE_##x, typedef enum { diff --git a/vl-android.c b/vl-android.c index 32b5eac..4c2a433 100644 --- a/vl-android.c +++ b/vl-android.c @@ -65,6 +65,7 @@ #include "android/display-core.h" #include "android/utils/timezone.h" #include "android/snapshot.h" +#include "android/opengles.h" #include "targphys.h" #include "tcpdump.h" @@ -3813,6 +3814,29 @@ int main(int argc, char **argv, char **envp) nand_add_dev(tmp); } + /* qemu.gles will be read by the OpenGLES emulation libraries. + * If set to 0, the software GLES renderer will be used as a fallback. + * If the parameter is undefined, this means the system image runs + * inside an emulator that doesn't support GPU emulation at all. + */ + { + int gles_emul = 0; + + if (android_hw->hw_gpu_enabled) { + if (android_initOpenglesEmulation() == 0) { + gles_emul = 1; + android_startOpenglesRenderer(android_hw->hw_lcd_width, android_hw->hw_lcd_height); + } else { + dwarning("Could not initialize OpenglES emulation, using software renderer."); + } + } + if (gles_emul) { + stralloc_add_str(kernel_params, " qemu.gles=1"); + } else { + stralloc_add_str(kernel_params, " qemu.gles=0"); + } + } + /* We always force qemu=1 when running inside QEMU */ stralloc_add_str(kernel_params, " qemu=1"); |