Merge changes I1fa3512b,I47df0cae

* changes:
  Add hw.gpu.enabled hardware property
  Fix a crash when GPU emulation doesn't work.
diff --git a/Makefile.android b/Makefile.android
index 01cb35b..95287fd 100644
--- a/Makefile.android
+++ b/Makefile.android
@@ -242,6 +242,7 @@
     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 @@
     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 @@
     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 @@
 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 2a09718..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 @@
 };
 #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,25 +467,34 @@
     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);
 
-    // Disable TCP nagle algorithm to improve throughput of small packets
-    socket_set_nodelay(pipe->io->fd);
+    if (pipe != NULL) {
+        // Disable TCP nagle algorithm to improve throughput of small packets
+        socket_set_nodelay(pipe->io->fd);
 
     // On Win32, adjust buffer sizes
 #ifdef _WIN32
-    {
-        int sndbuf = 128 * 1024;
-        int len = sizeof(sndbuf);
-        if (setsockopt(pipe->io->fd, SOL_SOCKET, SO_SNDBUF,
-                       (char*)&sndbuf, len) == SOCKET_ERROR) {
-            D("Failed to set SO_SNDBUF to %d error=0x%x\n",
-               sndbuf, WSAGetLastError());
+        {
+            int sndbuf = 128 * 1024;
+            int len = sizeof(sndbuf);
+            if (setsockopt(pipe->io->fd, SOL_SOCKET, SO_SNDBUF,
+                        (char*)&sndbuf, len) == SOCKET_ERROR) {
+                D("Failed to set SO_SNDBUF to %d error=0x%x\n",
+                sndbuf, WSAGetLastError());
+            }
         }
-    }
 #endif /* _WIN32 */
+    }
 
     return pipe;
 }
@@ -494,7 +508,6 @@
     netPipe_wakeOn,
 };
 
-
 void
 android_net_pipes_init(void)
 {
@@ -506,3 +519,13 @@
 #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 @@
 
 
 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 @@
                                      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 @@
     }
 }
 
+/* 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 @@
         dprint( "emulator window was out of view and was recentered\n" );
     }
 
+    skin_window_show_opengles(window);
+
     return window;
 }
 
@@ -1261,6 +1302,9 @@
 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 @@
         }
 
         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_scaler_set( window->scaler, scale, window->effective_x, window->effective_y );
         }
+
+        skin_window_show_opengles(window);
     }
 }
 
@@ -1552,6 +1601,7 @@
 
             SDL_UpdateRects( window->surface, 1, &rd );
         }
+        skin_window_redraw_opengles( window );
     }
 }
 
@@ -1681,6 +1731,10 @@
             }
         }
         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 @@
         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");