diff options
Diffstat (limited to 'android')
-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 |
8 files changed, 319 insertions, 3 deletions
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 { |