Bug 1014614 - Expose Android native window via AndroidNativeWindow wrapper r=blassey a=lsblakk
authorJames Willcox <snorp@snorp.net>
Wed, 05 Nov 2014 10:50:02 -0600
changeset 225861 455ad700e6fa
parent 225860 395fe44f05b2
child 225862 1f11fc564737
push id7210
push userjwillcox@mozilla.com
push date2014-11-05 16:57 +0000
treeherdermozilla-aurora@ba9a79c05e9a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersblassey, lsblakk
bugs1014614
milestone35.0a2
Bug 1014614 - Expose Android native window via AndroidNativeWindow wrapper r=blassey a=lsblakk
gfx/gl/AndroidNativeWindow.cpp
gfx/gl/AndroidNativeWindow.h
gfx/gl/AndroidSurfaceTexture.cpp
gfx/gl/AndroidSurfaceTexture.h
gfx/gl/moz.build
new file mode 100644
--- /dev/null
+++ b/gfx/gl/AndroidNativeWindow.cpp
@@ -0,0 +1,281 @@
+#ifdef MOZ_WIDGET_ANDROID
+
+#include "AndroidNativeWindow.h"
+#include "prlink.h"
+
+// #define ANDROID_NATIVE_WINDOW_DEBUG
+
+#if defined(ANDROID_NATIVE_WINDOW_DEBUG) || defined(DEBUG)
+#define ALOG(args...)  __android_log_print(ANDROID_LOG_INFO, "AndroidNativeWindow" , ## args)
+#else
+#define ALOG(args...) ((void)0)
+#endif
+
+using namespace mozilla::gfx;
+using namespace mozilla::gl;
+using namespace mozilla;
+
+class NativeWindowLibrary
+{
+public:
+
+  NativeWindowLibrary()
+    : fANativeWindow_fromSurface(nullptr)
+    , fANativeWindow_release(nullptr)
+    , fANativeWindow_setBuffersGeometry(nullptr)
+    , fANativeWindow_lock(nullptr)
+    , fANativeWindow_unlockAndPost(nullptr)
+    , fANativeWindow_getFormat(nullptr)
+    , fANativeWindow_getWidth(nullptr)
+    , fANativeWindow_getHeight(nullptr)
+  {
+    PRLibrary* lib = PR_LoadLibrary("libandroid.so");
+
+    fANativeWindow_fromSurface = (pfnANativeWindow_fromSurface)PR_FindSymbol(lib, "ANativeWindow_fromSurface");
+    fANativeWindow_release = (pfnANativeWindow_release)PR_FindSymbol(lib, "ANativeWindow_release");
+    fANativeWindow_setBuffersGeometry = (pfnANativeWindow_setBuffersGeometry)PR_FindSymbol(lib, "ANativeWindow_setBuffersGeometry");
+    fANativeWindow_lock = (pfnANativeWindow_lock)PR_FindSymbol(lib, "ANativeWindow_lock");
+    fANativeWindow_unlockAndPost = (pfnANativeWindow_unlockAndPost)PR_FindSymbol(lib, "ANativeWindow_unlockAndPost");
+    fANativeWindow_getFormat = (pfnANativeWindow_getFormat)PR_FindSymbol(lib, "ANativeWindow_getFormat");
+    fANativeWindow_getWidth = (pfnANativeWindow_getWidth)PR_FindSymbol(lib, "ANativeWindow_getWidth");
+    fANativeWindow_getHeight = (pfnANativeWindow_getHeight)PR_FindSymbol(lib, "ANativeWindow_getHeight");
+  }
+
+  void* ANativeWindow_fromSurface(JNIEnv* aEnv, jobject aSurface) {
+    ALOG("%s: env=%p, surface=%p\n", __PRETTY_FUNCTION__, aEnv, aSurface);
+    if (!Initialized()) {
+      return nullptr;
+    }
+
+    return fANativeWindow_fromSurface(aEnv, aSurface);
+  }
+
+  void ANativeWindow_release(void* aWindow) {
+    ALOG("%s: window=%p\n", __PRETTY_FUNCTION__, aWindow);
+    if (!Initialized()) {
+      return;
+    }
+
+    fANativeWindow_release(aWindow);
+  }
+
+  bool ANativeWindow_setBuffersGeometry(void* aWindow, int32_t aWidth, int32_t aHeight, int32_t aFormat) {
+    ALOG("%s: window=%p, width=%d, height=%d, format=%d\n", __PRETTY_FUNCTION__, aWindow, aWidth, aHeight, aFormat);
+    if (!Initialized()) {
+      return nullptr;
+    }
+
+    return fANativeWindow_setBuffersGeometry(aWindow, aWidth, aHeight, (int32_t)aFormat) == 0;
+  }
+
+  bool ANativeWindow_lock(void* aWindow, void* out_buffer, void*in_out_dirtyBounds) {
+    ALOG("%s: window=%p, out_buffer=%p, in_out_dirtyBounds=%p\n", __PRETTY_FUNCTION__,
+         aWindow, out_buffer, in_out_dirtyBounds);
+    if (!Initialized()) {
+      return false;
+    }
+
+    return fANativeWindow_lock(aWindow, out_buffer, in_out_dirtyBounds) == 0;
+  }
+
+  bool ANativeWindow_unlockAndPost(void* aWindow) {
+    ALOG("%s: window=%p\n", __PRETTY_FUNCTION__, aWindow);
+    if (!Initialized()) {
+      return false;
+    }
+
+    return fANativeWindow_unlockAndPost(aWindow) == 0;
+  }
+
+  AndroidWindowFormat ANativeWindow_getFormat(void* aWindow) {
+    ALOG("%s: window=%p\n", __PRETTY_FUNCTION__, aWindow);
+    if (!Initialized()) {
+      return AndroidWindowFormat::Unknown;
+    }
+
+    return (AndroidWindowFormat)fANativeWindow_getFormat(aWindow);
+  }
+
+  int32_t ANativeWindow_getWidth(void* aWindow) {
+    ALOG("%s: window=%p\n", __PRETTY_FUNCTION__, aWindow);
+    if (!Initialized()) {
+      return -1;
+    }
+
+    return fANativeWindow_getWidth(aWindow);
+  }
+
+  int32_t ANativeWindow_getHeight(void* aWindow) {
+    ALOG("%s: window=%p\n", __PRETTY_FUNCTION__, aWindow);
+    if (!Initialized()) {
+      return -1;
+    }
+
+    return fANativeWindow_getHeight(aWindow);
+  }
+
+  bool Initialized() {
+    return fANativeWindow_fromSurface && fANativeWindow_release && fANativeWindow_setBuffersGeometry
+      && fANativeWindow_lock && fANativeWindow_unlockAndPost && fANativeWindow_getFormat && fANativeWindow_getWidth
+      && fANativeWindow_getHeight;
+  }
+
+private:
+
+  typedef void* (*pfnANativeWindow_fromSurface)(JNIEnv* env, jobject surface);
+  pfnANativeWindow_fromSurface fANativeWindow_fromSurface;
+
+  typedef void (*pfnANativeWindow_release)(void* window);
+  pfnANativeWindow_release fANativeWindow_release;
+
+  typedef int32_t (*pfnANativeWindow_setBuffersGeometry)(void* window, int32_t width, int32_t height, int32_t format);
+  pfnANativeWindow_setBuffersGeometry fANativeWindow_setBuffersGeometry;
+
+  typedef int32_t (*pfnANativeWindow_lock)(void *window, void *out_buffer, void *in_out_dirtyBounds);
+  pfnANativeWindow_lock fANativeWindow_lock;
+
+  typedef int32_t (*pfnANativeWindow_unlockAndPost)(void *window);
+  pfnANativeWindow_unlockAndPost fANativeWindow_unlockAndPost;
+
+  typedef AndroidWindowFormat (*pfnANativeWindow_getFormat)(void* window);
+  pfnANativeWindow_getFormat fANativeWindow_getFormat;
+
+  typedef int32_t (*pfnANativeWindow_getWidth)(void* window);
+  pfnANativeWindow_getWidth fANativeWindow_getWidth;
+
+  typedef int32_t (*pfnANativeWindow_getHeight)(void* window);
+  pfnANativeWindow_getHeight fANativeWindow_getHeight;
+};
+
+static NativeWindowLibrary* sLibrary = nullptr;
+
+static bool
+EnsureInit()
+{
+  static bool initialized = false;
+  if (!initialized) {
+    if (!sLibrary) {
+      sLibrary = new NativeWindowLibrary();
+    }
+    initialized = sLibrary->Initialized();
+  }
+
+  return initialized;
+}
+
+
+namespace mozilla {
+
+/* static */ AndroidNativeWindow*
+AndroidNativeWindow::CreateFromSurface(JNIEnv* aEnv, jobject aSurface)
+{
+  if (!EnsureInit()) {
+    ALOG("Not initialized");
+    return nullptr;
+  }
+
+  void* window = sLibrary->ANativeWindow_fromSurface(aEnv, aSurface);
+  if (!window) {
+    ALOG("Failed to create window from surface");
+    return nullptr;
+  }
+
+  return new AndroidNativeWindow(window);
+}
+
+AndroidNativeWindow::~AndroidNativeWindow()
+{
+  if (EnsureInit() && mWindow) {
+    sLibrary->ANativeWindow_release(mWindow);
+    mWindow = nullptr;
+  }
+}
+
+IntSize
+AndroidNativeWindow::Size()
+{
+  MOZ_ASSERT(mWindow);
+  if (!EnsureInit()) {
+    return IntSize(0, 0);
+  }
+
+  return IntSize(sLibrary->ANativeWindow_getWidth(mWindow), sLibrary->ANativeWindow_getHeight(mWindow));
+}
+
+AndroidWindowFormat
+AndroidNativeWindow::Format()
+{
+  MOZ_ASSERT(mWindow);
+  if (!EnsureInit()) {
+    return AndroidWindowFormat::Unknown;
+  }
+
+  return sLibrary->ANativeWindow_getFormat(mWindow);
+}
+
+bool
+AndroidNativeWindow::SetBuffersGeometry(int32_t aWidth, int32_t aHeight, AndroidWindowFormat aFormat)
+{
+  MOZ_ASSERT(mWindow);
+  if (!EnsureInit())
+    return false;
+
+  return sLibrary->ANativeWindow_setBuffersGeometry(mWindow, aWidth, aHeight, (int32_t)aFormat);
+}
+
+bool
+AndroidNativeWindow::Lock(void** out_bits,int32_t* out_width, int32_t* out_height,
+                          int32_t* out_stride, AndroidWindowFormat* out_format)
+{
+  /* Copied from native_window.h in Android NDK (platform-9) */
+  typedef struct ANativeWindow_Buffer {
+      // The number of pixels that are show horizontally.
+      int32_t width;
+
+      // The number of pixels that are shown vertically.
+      int32_t height;
+
+      // The number of *pixels* that a line in the buffer takes in
+      // memory.  This may be >= width.
+      int32_t stride;
+
+      // The format of the buffer.  One of WINDOW_FORMAT_*
+      int32_t format;
+
+      // The actual bits.
+      void* bits;
+
+      // Do not touch.
+      uint32_t reserved[6];
+  } ANativeWindow_Buffer; 
+
+
+  ANativeWindow_Buffer buffer;
+
+  if (!sLibrary->ANativeWindow_lock(mWindow, &buffer, nullptr)) {
+    ALOG("Failed to lock");
+    return false;
+  }
+
+  *out_bits = buffer.bits;
+  *out_width = buffer.width;
+  *out_height = buffer.height;
+  *out_stride = buffer.stride;
+  *out_format = (AndroidWindowFormat)buffer.format;
+  return true;
+}
+
+bool
+AndroidNativeWindow::UnlockAndPost()
+{
+  if (!EnsureInit()) {
+    ALOG("Not initialized");
+    return false;
+  }
+
+  return sLibrary->ANativeWindow_unlockAndPost(mWindow);
+}
+
+}
+
+#endif // MOZ_WIDGET_ANDROID
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gfx/gl/AndroidNativeWindow.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+// vim:set ts=2 sts=2 sw=2 et cin:
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef AndroidNativeWindow_h__
+#define AndroidNativeWindow_h__
+#ifdef MOZ_WIDGET_ANDROID
+
+#include <jni.h>
+#include "GLDefs.h"
+
+#include "nsISupports.h"
+#include "mozilla/TypedEnum.h"
+#include "mozilla/gfx/2D.h"
+
+
+namespace mozilla {
+namespace gl {
+
+MOZ_BEGIN_ENUM_CLASS(AndroidWindowFormat)
+  Unknown = -1,
+  RGBA_8888 = 1,
+  RGBX_8888 = 1 << 1,
+  RGB_565 = 1 << 2
+MOZ_END_ENUM_CLASS(AndroidWindowFormat)
+
+/**
+ * This class is a wrapper around Android's SurfaceTexture class.
+ * Usage is pretty much exactly like the Java class, so see
+ * the Android documentation for details.
+ */
+class AndroidNativeWindow {
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AndroidNativeWindow)
+
+public:
+
+  static AndroidNativeWindow* CreateFromSurface(JNIEnv* aEnv, jobject aSurface);
+
+  gfx::IntSize Size();
+  AndroidWindowFormat Format();
+
+  bool SetBuffersGeometry(int32_t aWidth, int32_t aHeight, AndroidWindowFormat aFormat);
+
+  bool Lock(void** out_bits, int32_t* out_width, int32_t* out_height, int32_t* out_stride, AndroidWindowFormat* out_format);
+  bool UnlockAndPost();
+
+  void* Handle() { return mWindow; }
+
+protected:
+  AndroidNativeWindow(void* aWindow)
+    : mWindow(aWindow)
+  {
+
+  }
+
+  virtual ~AndroidNativeWindow();
+
+  void* mWindow;
+};
+
+}
+}
+
+
+#endif
+#endif
--- a/gfx/gl/AndroidSurfaceTexture.cpp
+++ b/gfx/gl/AndroidSurfaceTexture.cpp
@@ -198,16 +198,18 @@ AndroidSurfaceTexture::Init(GLuint aText
     return false;
   }
 
   mSurface = sJNIFunctions.CreateSurface(mSurfaceTexture);
   if (!mSurface) {
     return false;
   }
 
+  mNativeWindow = AndroidNativeWindow::CreateFromSurface(env, mSurface);
+
   mID = ++sNextID;
   sInstances.insert(std::pair<int, AndroidSurfaceTexture*>(mID, this));
 
   mTexture = aTexture;
 
   return true;
 }
 
--- a/gfx/gl/AndroidSurfaceTexture.h
+++ b/gfx/gl/AndroidSurfaceTexture.h
@@ -37,16 +37,20 @@ class AndroidSurfaceTexture {
 public:
   static AndroidSurfaceTexture* Create(GLuint aTexture);
   static AndroidSurfaceTexture* Find(int id);
 
   // Returns with reasonable certainty whether or not we'll
   // be able to create and use a SurfaceTexture
   static bool Check();
 
+  AndroidNativeWindow* NativeWindow() {
+    return mNativeWindow;
+  }
+
   // This attaches the updated data to the TEXTURE_EXTERNAL target
   void UpdateTexImage();
 
   bool GetTransformMatrix(mozilla::gfx::Matrix4x4& aMatrix);
   int ID() { return mID; }
 
   void SetDefaultSize(mozilla::gfx::IntSize size);
 
@@ -65,16 +69,17 @@ private:
   ~AndroidSurfaceTexture();
 
   bool Init(GLuint aTexture);
 
   GLuint mTexture;
   jobject mSurfaceTexture;
   jobject mSurface;
 
+  RefPtr<AndroidNativeWindow> mNativeWindow;
   int mID;
   nsRefPtr<nsIRunnable> mFrameAvailableCallback;
 };
   
 }
 }
 
 
--- a/gfx/gl/moz.build
+++ b/gfx/gl/moz.build
@@ -21,16 +21,17 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'an
     gl_provider = 'EGL'
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     gl_provider = 'EGL'
 
 if CONFIG['MOZ_GL_PROVIDER']:
     gl_provider = CONFIG['MOZ_GL_PROVIDER']
 
 EXPORTS += [
+    'AndroidNativeWindow.h',
     'AndroidSurfaceTexture.h',
     'DecomposeIntoNoRepeatTriangles.h',
     'EGLUtils.h',
     'ForceDiscreteGPUHelperCGL.h',
     'GfxTexturesReporter.h',
     'GLBlitHelper.h',
     'GLBlitTextureImageHelper.h',
     'GLConsts.h',
@@ -111,16 +112,17 @@ elif gl_provider == 'GLX':
         'GLContextProviderGLX.cpp',
     ]
 else:
     UNIFIED_SOURCES += [
         'GLContextProvider%s.cpp' % gl_provider,
     ]
 
 UNIFIED_SOURCES += [
+    'AndroidNativeWindow.cpp',
     'AndroidSurfaceTexture.cpp',
     'DecomposeIntoNoRepeatTriangles.cpp',
     'EGLUtils.cpp',
     'GfxTexturesReporter.cpp',
     'GLBlitHelper.cpp',
     'GLBlitTextureImageHelper.cpp',
     'GLContext.cpp',
     'GLContextFeatures.cpp',