EmuGL: Deliver every frame to a callback

To enable multi-touch on a tethered device, allow a callback to be
registered with the OpenGL renderer. On every frame, the framebuffer
is read into system memory and provided to the callback, so it can be
mirrored to the device.

This change is co-dependent on Idae3b026d52ed8dd666cbcdc3f3af80175c90ad3
in external/qemu.

Change-Id: I03c49bc55ed9e66ffb59462333181f77e7e46035
diff --git a/tools/emulator/opengl/host/include/libOpenglRender/render_api.h b/tools/emulator/opengl/host/include/libOpenglRender/render_api.h
index bb33192..537d8cd 100644
--- a/tools/emulator/opengl/host/include/libOpenglRender/render_api.h
+++ b/tools/emulator/opengl/host/include/libOpenglRender/render_api.h
@@ -22,6 +22,38 @@
 
 #include "render_api_platform_types.h"
 
+/* If a function with this signature is passed to initOpenGLRenderer(),
+ * it will be called by the renderer just before each new frame is displayed,
+ * providing a copy of the framebuffer contents.
+ *
+ * The callback will be called from one of the renderer's threads, so will
+ * probably need synchronization on any data structures it modifies. The
+ * pixels buffer may be overwritten as soon as the callback returns; if it needs
+ * the pixels afterwards it must copy them.
+ *
+ * The pixels buffer is intentionally not const: the callback may modify the
+ * data without copying to another buffer if it wants, e.g. in-place RGBA to RGB
+ * conversion, or in-place y-inversion.
+ *
+ * Parameters are:
+ *   context        The pointer optionally provided when the callback was
+ *                  registered. The client can use this to pass whatever
+ *                  information it wants to the callback.
+ *   width, height  Dimensions of the image, in pixels. Rows are tightly packed;
+ *                  there is no inter-row padding.
+ *   ydir           Indicates row order: 1 means top-to-bottom order, -1 means
+ *                  bottom-to-top order.
+ *   format, type   Format and type GL enums, as used in glTexImage2D() or
+ *                  glReadPixels(), describing the pixel format.
+ *   pixels         The framebuffer image.
+ *
+ * In the first implementation, ydir is always -1 (bottom to top), format and
+ * type are always GL_RGBA and GL_UNSIGNED_BYTE, and the width and height will
+ * always be the same as the ones passed to initOpenGLRenderer().
+ */
+typedef void (*OnPostFn)(void* context, int width, int height, int ydir,
+                         int format, int type, unsigned char* pixels);
+
 // initLibrary - initialize the library and tries to load the corresponding
 //     GLES translator libraries. This function must be called before anything
 //     else to ensure that everything works. If it returns an error, then
@@ -53,8 +85,8 @@
 // This function is *NOT* thread safe and should be called first
 // to initialize the renderer after initLibrary().
 //
-bool initOpenGLRenderer(int width, int height, int portNum);
-
+bool initOpenGLRenderer(int width, int height, int portNum,
+                        OnPostFn onPost, void* onPostContext);
 
 //
 // createOpenGLSubwindow -
diff --git a/tools/emulator/opengl/host/libs/libOpenglRender/FrameBuffer.cpp b/tools/emulator/opengl/host/libs/libOpenglRender/FrameBuffer.cpp
index ef38bec..0c0e774 100644
--- a/tools/emulator/opengl/host/libs/libOpenglRender/FrameBuffer.cpp
+++ b/tools/emulator/opengl/host/libs/libOpenglRender/FrameBuffer.cpp
@@ -101,7 +101,7 @@
     }
 }
 
-bool FrameBuffer::initialize(int width, int height)
+bool FrameBuffer::initialize(int width, int height, OnPostFn onPost, void* onPostContext)
 {
     if (s_theFrameBuffer != NULL) {
         return true;
@@ -110,7 +110,7 @@
     //
     // allocate space for the FrameBuffer object
     //
-    FrameBuffer *fb = new FrameBuffer(width, height);
+    FrameBuffer *fb = new FrameBuffer(width, height, onPost, onPostContext);
     if (!fb) {
         ERR("Failed to create fb\n");
         return false;
@@ -334,6 +334,17 @@
     //
     fb->initGLState();
 
+    //
+    // Allocate space for the onPost framebuffer image
+    //
+    if (onPost) {
+        fb->m_fbImage = (unsigned char*)malloc(4 * width * height);
+        if (!fb->m_fbImage) {
+            delete fb;
+            return false;
+        }
+    }
+
     // release the FB context
     fb->unbind_locked();
 
@@ -344,7 +355,8 @@
     return true;
 }
 
-FrameBuffer::FrameBuffer(int p_width, int p_height) :
+FrameBuffer::FrameBuffer(int p_width, int p_height,
+        OnPostFn onPost, void* onPostContext) :
     m_width(p_width),
     m_height(p_height),
     m_eglDisplay(EGL_NO_DISPLAY),
@@ -360,13 +372,17 @@
     m_zRot(0.0f),
     m_eglContextInitialized(false),
     m_statsNumFrames(0),
-    m_statsStartTime(0LL)
+    m_statsStartTime(0LL),
+    m_onPost(onPost),
+    m_onPostContext(onPostContext),
+    m_fbImage(NULL)
 {
     m_fpsStats = getenv("SHOW_FPS_STATS") != NULL;
 }
 
 FrameBuffer::~FrameBuffer()
 {
+    free(m_fbImage);
 }
 
 bool FrameBuffer::setupSubWindow(FBNativeWindowType p_window,
@@ -780,6 +796,15 @@
         s_gl.glPopMatrix();
 
         if (ret) {
+            //
+            // Send framebuffer (without FPS overlay) to callback
+            //
+            if (m_onPost) {
+                s_gl.glReadPixels(0, 0, m_width, m_height,
+                        GL_RGBA, GL_UNSIGNED_BYTE, m_fbImage);
+                m_onPost(m_onPostContext, m_width, m_height, -1,
+                        GL_RGBA, GL_UNSIGNED_BYTE, m_fbImage);
+            }
 
             //
             // output FPS statistics
diff --git a/tools/emulator/opengl/host/libs/libOpenglRender/FrameBuffer.h b/tools/emulator/opengl/host/libs/libOpenglRender/FrameBuffer.h
index 4725317..ff0aa1b 100644
--- a/tools/emulator/opengl/host/libs/libOpenglRender/FrameBuffer.h
+++ b/tools/emulator/opengl/host/libs/libOpenglRender/FrameBuffer.h
@@ -42,7 +42,7 @@
 class FrameBuffer
 {
 public:
-    static bool initialize(int width, int height);
+    static bool initialize(int width, int height, OnPostFn onPost, void* onPostContext);
     static bool setupSubWindow(FBNativeWindowType p_window,
                                 int x, int y,
                                 int width, int height, float zRot);
@@ -85,7 +85,7 @@
     }
 
 private:
-    FrameBuffer(int p_width, int p_height);
+    FrameBuffer(int p_width, int p_height, OnPostFn onPost, void* onPostContext);
     ~FrameBuffer();
     HandleType genHandle();
     bool bindSubwin_locked();
@@ -124,5 +124,9 @@
     int m_statsNumFrames;
     long long m_statsStartTime;
     bool m_fpsStats;
+
+    OnPostFn m_onPost;
+    void* m_onPostContext;
+    unsigned char* m_fbImage;
 };
 #endif
diff --git a/tools/emulator/opengl/host/libs/libOpenglRender/render_api.cpp b/tools/emulator/opengl/host/libs/libOpenglRender/render_api.cpp
index 8a5f464..c8d3e06 100644
--- a/tools/emulator/opengl/host/libs/libOpenglRender/render_api.cpp
+++ b/tools/emulator/opengl/host/libs/libOpenglRender/render_api.cpp
@@ -76,7 +76,8 @@
     return true;
 }
 
-bool initOpenGLRenderer(int width, int height, int portNum)
+bool initOpenGLRenderer(int width, int height, int portNum,
+        OnPostFn onPost, void* onPostContext)
 {
 
     //
@@ -93,7 +94,7 @@
     // initialize the renderer and listen to connections
     // on a thread in the current process.
     //
-    bool inited = FrameBuffer::initialize(width, height);
+    bool inited = FrameBuffer::initialize(width, height, onPost, onPostContext);
     if (!inited) {
         return false;
     }
@@ -106,6 +107,17 @@
     s_renderThread->start();
 
 #else
+    if (onPost) {
+        // onPost callback not supported with separate renderer process.
+        //
+        // If we ever revive separate process support, we could make the choice
+        // between thread and process at runtime instead of compile time, and
+        // choose the thread path if an onPost callback is requested. Or, the
+        // callback could be supported with a separate process using shmem or
+        // other IPC mechanism.
+        return false;
+    }
+
     //
     // Launch emulator_renderer
     //
diff --git a/tools/emulator/opengl/host/renderer/main.cpp b/tools/emulator/opengl/host/renderer/main.cpp
index 4549c56..ae7ace3 100644
--- a/tools/emulator/opengl/host/renderer/main.cpp
+++ b/tools/emulator/opengl/host/renderer/main.cpp
@@ -120,7 +120,7 @@
     //
     // initialize Framebuffer
     //
-    bool inited = FrameBuffer::initialize(winWidth, winHeight);
+    bool inited = FrameBuffer::initialize(winWidth, winHeight, NULL, NULL);
     if (!inited) {
         fprintf(stderr,"Failed to initialize Framebuffer\n");
         return -1;