updated Animation Plugin for NativeWindow interface

bug:5114637

Uses new ANativeWindow plugin API, supports either software rendering or GL
rendering via flag in RenderingThread.h

Note: Currently crashes on close

Change-Id: Ia7338a6c38c0ca9db02c19814d99b29970cc7b8e
diff --git a/samples/BrowserPlugin/jni/RenderingThread.cpp b/samples/BrowserPlugin/jni/RenderingThread.cpp
index 7f267ed..91ffb4a 100644
--- a/samples/BrowserPlugin/jni/RenderingThread.cpp
+++ b/samples/BrowserPlugin/jni/RenderingThread.cpp
@@ -24,30 +24,55 @@
  */
 #include "RenderingThread.h"
 
-#include "ANPOpenGL_npapi.h"
+#include "ANPNativeWindow_npapi.h"
 
-extern ANPLogInterfaceV0       gLogI;
-extern ANPOpenGLInterfaceV0    gOpenGLI;
+extern ANPLogInterfaceV0           gLogI;
+extern ANPNativeWindowInterfaceV0  gNativeWindowI;
 
 RenderingThread::RenderingThread(NPP npp) : android::Thread() {
     m_npp = npp;
     m_width = -1;
     m_height = -1;
-    gLogI.log(kError_ANPLogType, "Created Rendering Thread");
+
+    m_ANW = NULL;
+#if (!USE_SOFTWARE_RENDERING)
+    m_eglSurface = EGL_NO_SURFACE;
+    m_eglContext = EGL_NO_CONTEXT;
+    m_eglDisplay = EGL_NO_DISPLAY;
+#endif
 }
 
 android::status_t RenderingThread::readyToRun() {
-
-    gLogI.log(kError_ANPLogType, "in ready to run");
-
-    EGLContext context = gOpenGLI.acquireContext(m_npp);
-
-    gLogI.log(kError_ANPLogType, "context: %p", context);
-
-    if (context == EGL_NO_CONTEXT) {
-        gLogI.log(kError_ANPLogType, "Unable to create EGLContext for a TextureProducer thread");
-        return android::UNKNOWN_ERROR;
+    while (m_ANW == NULL) {
+        m_ANW = gNativeWindowI.acquireNativeWindow(m_npp);
     }
+
+#if (!USE_SOFTWARE_RENDERING)
+    m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+    //initialize context
+    EGLint numConfigs;
+    static const EGLint configAttribs[] = {
+        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+        EGL_RED_SIZE, 8,
+        EGL_GREEN_SIZE, 8,
+        EGL_BLUE_SIZE, 8,
+        EGL_ALPHA_SIZE, 8,
+        EGL_NONE
+    };
+
+    eglChooseConfig(m_eglDisplay, configAttribs, &m_eglConfig, 1, &numConfigs);
+    checkGlError("eglChooseConfig");
+
+    static const EGLint contextAttribs[] = {
+        EGL_CONTEXT_CLIENT_VERSION, 2,
+        EGL_NONE
+    };
+
+    m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, NULL, contextAttribs);
+    checkGlError("eglCreateContext");
+#endif
+
     return android::NO_ERROR;
 }
 
@@ -109,34 +134,70 @@
     }
 }
 
-void RenderingThread::createTextureWithBitmap(GLuint texture, SkBitmap& bitmap) {
-    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-    glBindTexture(GL_TEXTURE_2D, texture);
-    checkGlError("glBindTexture");
-    SkBitmap::Config config = bitmap.getConfig();
-    int internalformat = getInternalFormat(config);
-    int type = getType(config);
-    bitmap.lockPixels();
-    glTexImage2D(GL_TEXTURE_2D, 0, internalformat, bitmap.width(), bitmap.height(),
-                 0, internalformat, type, bitmap.getPixels());
-    bitmap.unlockPixels();
-    checkGlError("glTexImage2D");
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+void RenderingThread::setupNativeWindow(ANativeWindow* ANW, const SkBitmap& bitmap)
+{
+    int result = ANativeWindow_setBuffersGeometry(ANW, bitmap.width(),
+            bitmap.height(), WINDOW_FORMAT_RGBA_8888);
+
+    if (android::NO_ERROR != result) {
+        gLogI.log(kError_ANPLogType, "ERROR setBuffersGeometry() status is (%d)", result);
+    }
+
+#if (!USE_SOFTWARE_RENDERING)
+    if (m_eglSurface != EGL_NO_SURFACE) {
+        gLogI.log(kDebug_ANPLogType, "destroying old surface");
+        eglDestroySurface(m_eglDisplay, m_eglSurface);
+    }
+
+    m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, ANW, NULL);
+    checkGlError("eglCreateWindowSurface");
+
+    eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
+
+    //optional: enable async mode
+    //eglSwapInterval(m_eglDisplay, 0);
+#endif
+
+    updateNativeWindow(ANW, bitmap);
 }
 
-void RenderingThread::updateTextureWithBitmap(GLuint texture, SkBitmap& bitmap) {
-    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-    glBindTexture(GL_TEXTURE_2D, texture);
-    checkGlError("glBindTexture");
-    SkBitmap::Config config = bitmap.getConfig();
-    int internalformat = getInternalFormat(config);
-    int type = getType(config);
+void RenderingThread::updateNativeWindow(ANativeWindow* ANW,
+                                         const SkBitmap& bitmap)
+{
+#if USE_SOFTWARE_RENDERING
+
+    //STEP 1: lock the ANW, getting a buffer
+    ANativeWindow_Buffer buffer;
+    if (ANativeWindow_lock(ANW, &buffer, NULL) < 0 ) // todo: use rect parameter for efficiency
+        return;
+
+    //STEP 2: draw into the buffer
+    uint8_t* img = (uint8_t*)buffer.bits;
+    int row, col;
+    int bpp = 4; // Here we only deal with RGBA8888 format.
     bitmap.lockPixels();
-    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
-                    internalformat, type, bitmap.getPixels());
+    uint8_t* bitmapOrigin = static_cast<uint8_t*>(bitmap.getPixels());
+    // Copy line by line to handle offsets and stride
+    for (row = 0 ; row < bitmap.height(); row ++) {
+        uint8_t* dst = &(img[(buffer.stride * (row + 0) + 0) * bpp]);
+        uint8_t* src = &(bitmapOrigin[bitmap.width() * row * bpp]);
+        memcpy(dst, src, bpp * bitmap.width());
+    }
     bitmap.unlockPixels();
-    checkGlError("glTexSubImage2D");
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+    //STEP 3: push the buffer to the queue
+    ANativeWindow_unlockAndPost(ANW);
+
+#else
+
+    //rotate the intensity of the green channel, other channels fixed
+    static int i = 0;
+    i = (i >= 245) ? 0 : i+10;
+
+    glClearColor(0.6, (i*1.0/256), 0.6, 0.6);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    eglSwapBuffers(m_eglDisplay, m_eglSurface);
+#endif
 }
+