aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid 'Digit' Turner <digit@android.com>2011-08-26 01:35:14 +0200
committerDavid 'Digit' Turner <digit@android.com>2011-08-29 17:02:17 +0200
commitcb88e79ecbd16dea5f2201fd12320db5945db83e (patch)
treea4f22e25a58723ae81cb9adc6a9a09e3f6a32a43
parent6a8b698fff4d328c2706776c1c09171cfadb8de4 (diff)
downloadexternal_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.android1
-rw-r--r--Makefile.target2
-rw-r--r--android/avd/hardware-properties.ini8
-rw-r--r--android/hw-pipe-net.c27
-rw-r--r--android/opengles.c167
-rw-r--r--android/opengles.h37
-rw-r--r--android/skin/scaler.c22
-rw-r--r--android/skin/scaler.h6
-rw-r--r--android/skin/window.c54
-rw-r--r--android/utils/debug.h1
-rw-r--r--vl-android.c24
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");