Bug 1294481 - Implement new frame available callbacks; r=snorp
authorJim Chen <nchen@mozilla.com>
Tue, 23 Aug 2016 18:52:30 -0400
changeset 352243 84529160c383f11b0e0654ea7953bd0eb0bb4b81
parent 352242 3c447a8c81c6ff404d835fb8bdb033cecc3705dd
child 352244 fce9511bf4eab8925024a4f3c1659b49120d4d25
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp
bugs1294481
milestone51.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 1294481 - Implement new frame available callbacks; r=snorp Implement a new OnFrameAvailableListener callback system for AndroidSurfaceTexture using native methods. Each AndroidSurfaceTexture creates its own SurfaceTextureListener object and uses it to forward OnFrameAvailableListener callbacks to the corresponding nsIRunnable.
gfx/gl/AndroidSurfaceTexture.cpp
gfx/gl/AndroidSurfaceTexture.h
mobile/android/base/moz.build
mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/SurfaceTextureListener.java
--- a/gfx/gl/AndroidSurfaceTexture.cpp
+++ b/gfx/gl/AndroidSurfaceTexture.cpp
@@ -10,28 +10,47 @@
 #include <android/native_window_jni.h>
 #include <android/log.h>
 #include "AndroidSurfaceTexture.h"
 #include "gfxImageSurface.h"
 #include "gfxPrefs.h"
 #include "AndroidBridge.h"
 #include "nsThreadUtils.h"
 #include "mozilla/gfx/Matrix.h"
-#include "GeneratedJNIWrappers.h"
-#include "SurfaceTexture.h"
+#include "GeneratedJNINatives.h"
 #include "GLContext.h"
 
 using namespace mozilla;
-using namespace mozilla::jni;
-using namespace mozilla::java;
-using namespace mozilla::java::sdk;
 
 namespace mozilla {
 namespace gl {
 
+class AndroidSurfaceTexture::Listener
+  : public java::SurfaceTextureListener::Natives<Listener>
+{
+  using Base = java::SurfaceTextureListener::Natives<Listener>;
+
+  const nsCOMPtr<nsIRunnable> mCallback;
+
+public:
+  using Base::AttachNative;
+  using Base::DisposeNative;
+
+  Listener(nsIRunnable* aCallback) : mCallback(aCallback) {}
+
+  void OnFrameAvailable()
+  {
+    if (NS_IsMainThread()) {
+      mCallback->Run();
+      return;
+    }
+    NS_DispatchToMainThread(mCallback);
+  }
+};
+
 static bool
 IsSTSupported()
 {
   return AndroidBridge::Bridge()->GetAPIVersion() >= 14; /* ICS */
 }
 
 already_AddRefed<AndroidSurfaceTexture>
 AndroidSurfaceTexture::Create()
@@ -128,50 +147,51 @@ AndroidSurfaceTexture::Init(GLContext* a
 {
 
   if (!aTexture && !CanDetach()) {
     // We have no texture and cannot initialize detached, bail out
     return false;
   }
 
   if (NS_WARN_IF(NS_FAILED(
-      SurfaceTexture::New(aTexture, ReturnTo(&mSurfaceTexture))))) {
+      java::sdk::SurfaceTexture::New(aTexture, ReturnTo(&mSurfaceTexture))))) {
     return false;
   }
 
   if (!aTexture) {
     mSurfaceTexture->DetachFromGLContext();
   }
 
   mAttachedContext = aContext;
 
   if (NS_WARN_IF(NS_FAILED(
-      Surface::New(mSurfaceTexture, ReturnTo(&mSurface))))) {
+      java::sdk::Surface::New(mSurfaceTexture, ReturnTo(&mSurface))))) {
     return false;
   }
 
   mNativeWindow = ANativeWindow_fromSurface(jni::GetEnvForThread(),
                                             mSurface.Get());
   MOZ_ASSERT(mNativeWindow, "Failed to create native window from surface");
 
   return true;
 }
 
 AndroidSurfaceTexture::AndroidSurfaceTexture()
   : mTexture(0)
   , mSurfaceTexture()
   , mSurface()
   , mAttachedContext(nullptr)
-  , mMonitor("AndroidSurfaceTexture::mContextMonitor")
+  , mMonitor("AndroidSurfaceTexture")
 {
 }
 
 AndroidSurfaceTexture::~AndroidSurfaceTexture()
 {
   if (mSurfaceTexture) {
+    SetFrameAvailableCallback(nullptr);
     mSurfaceTexture = nullptr;
   }
 
   if (mNativeWindow) {
     ANativeWindow_release(mNativeWindow);
     mNativeWindow = nullptr;
   }
 }
@@ -182,17 +202,17 @@ AndroidSurfaceTexture::UpdateTexImage()
   mSurfaceTexture->UpdateTexImage();
 }
 
 void
 AndroidSurfaceTexture::GetTransformMatrix(gfx::Matrix4x4& aMatrix) const
 {
   JNIEnv* const env = jni::GetEnvForThread();
 
-  auto jarray = FloatArray::LocalRef::Adopt(env, env->NewFloatArray(16));
+  auto jarray = jni::FloatArray::LocalRef::Adopt(env, env->NewFloatArray(16));
   mSurfaceTexture->GetTransformMatrix(jarray);
 
   jfloat* array = env->GetFloatArrayElements(jarray.Get(), nullptr);
 
   aMatrix._11 = array[0];
   aMatrix._12 = array[1];
   aMatrix._13 = array[2];
   aMatrix._14 = array[3];
@@ -213,16 +233,34 @@ AndroidSurfaceTexture::GetTransformMatri
   aMatrix._44 = array[15];
 
   env->ReleaseFloatArrayElements(jarray.Get(), array, 0);
 }
 
 void
 AndroidSurfaceTexture::SetFrameAvailableCallback(nsIRunnable* aRunnable)
 {
+  java::SurfaceTextureListener::LocalRef newListener;
+
+  if (aRunnable) {
+    newListener = java::SurfaceTextureListener::New();
+    Listener::AttachNative(newListener, MakeUnique<Listener>(aRunnable));
+  }
+
+  if (aRunnable || mListener) {
+    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
+        mSurfaceTexture->SetOnFrameAvailableListener(newListener)));
+  }
+
+  if (mListener) {
+    Listener::DisposeNative(java::SurfaceTextureListener::LocalRef(
+        newListener.Env(), mListener));
+  }
+
+  mListener = newListener;
 }
 
 void
 AndroidSurfaceTexture::SetDefaultSize(mozilla::gfx::IntSize size)
 {
   mSurfaceTexture->SetDefaultBufferSize(size.width, size.height);
 }
 
--- a/gfx/gl/AndroidSurfaceTexture.h
+++ b/gfx/gl/AndroidSurfaceTexture.h
@@ -12,16 +12,17 @@
 #include <android/native_window.h>
 #include "nsIRunnable.h"
 #include "gfxPlatform.h"
 #include "GLDefs.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/MatrixFwd.h"
 #include "mozilla/Monitor.h"
 
+#include "GeneratedJNIWrappers.h"
 #include "SurfaceTexture.h"
 
 namespace mozilla {
 namespace gl {
 
 class GLContext;
 
 /**
@@ -74,30 +75,33 @@ public:
   // The callback is guaranteed to be called on the main thread even
   // if the upstream callback is received on a different thread
   void SetFrameAvailableCallback(nsIRunnable* aRunnable);
 
   GLuint Texture() const { return mTexture; }
   const java::sdk::Surface::Ref& JavaSurface() const { return mSurface; }
 
 private:
+  class Listener;
+
   AndroidSurfaceTexture();
   ~AndroidSurfaceTexture();
 
   bool Init(GLContext* aContext, GLuint aTexture);
 
   GLuint mTexture;
   java::sdk::SurfaceTexture::GlobalRef mSurfaceTexture;
   java::sdk::Surface::GlobalRef mSurface;
+  java::SurfaceTextureListener::GlobalRef mListener;
 
   GLContext* mAttachedContext;
 
   ANativeWindow* mNativeWindow;
 
-  mutable Monitor mMonitor;
+  Monitor mMonitor;
 };
 
 }
 }
 
 
 #endif
 #endif
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -250,16 +250,17 @@ geckoview_java_files = [
     'gfx/PanZoomTarget.java',
     'gfx/PointUtils.java',
     'gfx/ProgressiveUpdateData.java',
     'gfx/RectUtils.java',
     'gfx/RenderTask.java',
     'gfx/SimpleScaleGestureDetector.java',
     'gfx/StackScroller.java',
     'gfx/SubdocumentScrollHelper.java',
+    'gfx/SurfaceTextureListener.java',
     'gfx/ViewTransform.java',
     'InputConnectionListener.java',
     'InputMethods.java',
     'notifications/AppNotificationClient.java',
     'notifications/NotificationClient.java',
     'notifications/NotificationHandler.java',
     'notifications/NotificationHelper.java',
     'notifications/NotificationReceiver.java',
new file mode 100644
--- /dev/null
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/SurfaceTextureListener.java
@@ -0,0 +1,38 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * 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/. */
+
+package org.mozilla.gecko;
+
+import org.mozilla.gecko.annotation.WrapForJNI;
+import org.mozilla.gecko.mozglue.JNIObject;
+
+import android.graphics.SurfaceTexture;
+
+final class SurfaceTextureListener
+    extends JNIObject implements SurfaceTexture.OnFrameAvailableListener
+{
+    @WrapForJNI(calledFrom = "gecko")
+    private SurfaceTextureListener() {
+    }
+
+    @Override
+    protected void disposeNative() {
+        // SurfaceTextureListener is disposed inside AndroidSurfaceTexture.
+        throw new IllegalStateException("unreachable code");
+    }
+
+    @WrapForJNI(stubName = "OnFrameAvailable")
+    private native void nativeOnFrameAvailable();
+
+    @Override // SurfaceTexture.OnFrameAvailableListener
+    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
+        try {
+            nativeOnFrameAvailable();
+        } catch (final NullPointerException e) {
+            // Ignore exceptions caused by a disposed object, i.e.
+            // getting a callback after this listener is no longer in use.
+        }
+    }
+}