Bug 1014614 - Expose Android native window via AndroidNativeWindow wrapper r=blassey
💩💩 backed out by 53e24fd12cd1 💩 💩
authorJames Willcox <snorp@snorp.net>
Fri, 17 Oct 2014 10:35:10 -0500
changeset 210947 8b530a9a2f99
parent 210946 7fa1b78de684
child 210948 2b72e71f1fdf
push id50598
push userjwillcox@mozilla.com
push date2014-10-17 15:36 +0000
treeherdermozilla-inbound@40f99ba7f616 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersblassey
bugs1014614
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1014614 - Expose Android native window via AndroidNativeWindow wrapper r=blassey
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
@@ -185,16 +185,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
@@ -39,16 +39,20 @@ public:
   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();
   
   ~AndroidSurfaceTexture();
 
+  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; }
 
   // The callback is guaranteed to be called on the main thread even
   // if the upstream callback is received on a different thread
@@ -63,16 +67,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',
@@ -110,16 +111,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',