Bug 1322650 - Use SurfaceTexture for WebGL on Android r=jgilbert draft
authorJames Willcox <snorp@snorp.net>
Fri, 03 Mar 2017 15:14:27 -0600
changeset 552482 e5b1d0beb2d1a3e02404ffb6c15b5880f7ea5f8d
parent 552481 43b50e91cee06a33d2de67d2e427075f81f830d7
child 552483 da31b12fc1c63e6d856f06089c6c49cba2e8b0dd
push id51353
push userbmo:snorp@snorp.net
push dateTue, 28 Mar 2017 13:31:07 +0000
reviewersjgilbert
bugs1322650
milestone55.0a1
Bug 1322650 - Use SurfaceTexture for WebGL on Android r=jgilbert The main advantage here is that it works cross-process. MozReview-Commit-ID: 7YUTVB4Bydg
gfx/gl/AndroidNativeWindow.h
gfx/gl/AndroidSurfaceTexture.cpp
gfx/gl/AndroidSurfaceTexture.h
gfx/gl/GLScreenBuffer.cpp
gfx/gl/SharedSurface.h
gfx/gl/SharedSurfaceEGL.cpp
gfx/gl/SharedSurfaceEGL.h
gfx/gl/SurfaceTypes.h
gfx/gl/moz.build
gfx/layers/GLImages.cpp
gfx/layers/GLImages.h
gfx/layers/client/ImageClient.cpp
gfx/layers/composite/TextureHost.h
gfx/layers/ipc/LayersSurfaces.ipdlh
gfx/layers/opengl/TextureClientOGL.cpp
gfx/layers/opengl/TextureClientOGL.h
gfx/layers/opengl/TextureHostOGL.cpp
gfx/layers/opengl/TextureHostOGL.h
mobile/android/base/Makefile.in
mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/SurfaceAllocator.java
new file mode 100644
--- /dev/null
+++ b/gfx/gl/AndroidNativeWindow.h
@@ -0,0 +1,52 @@
+/* -*- 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 <android/native_window.h>
+#include <android/native_window_jni.h>
+#include "GeneratedJNIWrappers.h"
+#include "SurfaceTexture.h"
+
+namespace mozilla {
+namespace gl {
+
+class AndroidNativeWindow {
+public:
+  AndroidNativeWindow(java::sdk::Surface::Param aSurface) {
+    mNativeWindow = ANativeWindow_fromSurface(jni::GetEnvForThread(),
+                                              aSurface.Get());
+  }
+
+  AndroidNativeWindow(java::GeckoSurface::Param aSurface) {
+    auto surf = java::sdk::Surface::LocalRef(java::sdk::Surface::Ref::From(aSurface));
+    mNativeWindow = ANativeWindow_fromSurface(jni::GetEnvForThread(),
+                                              surf.Get());
+  }
+
+  ~AndroidNativeWindow() {
+    if (mNativeWindow) {
+      ANativeWindow_release(mNativeWindow);
+      mNativeWindow = nullptr;
+    }
+  }
+
+  ANativeWindow* NativeWindow() const {
+    return mNativeWindow;
+  }
+
+private:
+  ANativeWindow* mNativeWindow;
+};
+
+} // gl
+} // mozilla
+
+#endif // MOZ_WIDGET_ANDROID
+#endif // AndroidNativeWindow_h__
--- a/gfx/gl/AndroidSurfaceTexture.cpp
+++ b/gfx/gl/AndroidSurfaceTexture.cpp
@@ -1,209 +1,25 @@
-/* -*- 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/. */
-
 #ifdef MOZ_WIDGET_ANDROID
 
-#include <map>
-#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 "GeneratedJNINatives.h"
-#include "GLContext.h"
 
 using namespace mozilla;
 
 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);
-  }
-};
-
-already_AddRefed<AndroidSurfaceTexture>
-AndroidSurfaceTexture::Create()
-{
-  return Create(nullptr, 0);
-}
-
-already_AddRefed<AndroidSurfaceTexture>
-AndroidSurfaceTexture::Create(GLContext* aContext, GLuint aTexture)
-{
-  RefPtr<AndroidSurfaceTexture> st = new AndroidSurfaceTexture();
-  if (!st->Init(aContext, aTexture)) {
-    printf_stderr("Failed to initialize AndroidSurfaceTexture");
-    st = nullptr;
-  }
-
-  return st.forget();
-}
-
-nsresult
-AndroidSurfaceTexture::Attach(GLContext* aContext, PRIntervalTime aTimeout)
-{
-  MonitorAutoLock lock(mMonitor);
-
-  if (mAttachedContext == aContext) {
-    NS_WARNING("Tried to attach same GLContext to AndroidSurfaceTexture");
-    return NS_OK;
-  }
-
-  if (!CanDetach()) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-
-  while (mAttachedContext) {
-    // Wait until it's detached (or we time out)
-    if (NS_FAILED(lock.Wait(aTimeout))) {
-      return NS_ERROR_NOT_AVAILABLE;
-    }
-  }
-
-  MOZ_ASSERT(aContext->IsOwningThreadCurrent(), "Trying to attach GLContext from different thread");
-
-  aContext->fGenTextures(1, &mTexture);
-
-  if (NS_FAILED(mSurfaceTexture->AttachToGLContext(mTexture))) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-  mAttachedContext = aContext;
-  mAttachedContext->MakeCurrent();
-
-  return NS_OK;
-}
-
-nsresult
-AndroidSurfaceTexture::Detach()
-{
-  MonitorAutoLock lock(mMonitor);
-
-  if (!CanDetach() ||
-      !mAttachedContext ||
-      !mAttachedContext->IsOwningThreadCurrent())
-  {
-    return NS_ERROR_FAILURE;
-  }
-
-  mAttachedContext->MakeCurrent();
-
-  mSurfaceTexture->DetachFromGLContext();
-
-  mTexture = 0;
-  mAttachedContext = nullptr;
-  lock.NotifyAll();
-  return NS_OK;
-}
-
-bool
-AndroidSurfaceTexture::CanDetach() const
-{
-  // The API for attach/detach only exists on 16+, and PowerVR has some sort of
-  // fencing issue. Additionally, attach/detach seems to be busted on at least
-  // some Mali adapters (400MP2 for sure, bug 1131793)
-  return AndroidBridge::Bridge()->GetAPIVersion() >= 16 &&
-    (!mAttachedContext || mAttachedContext->Vendor() != GLVendor::Imagination) &&
-    (!mAttachedContext || mAttachedContext->Vendor() != GLVendor::ARM /* Mali */) &&
-    gfxPrefs::SurfaceTextureDetachEnabled();
-}
-
-bool
-AndroidSurfaceTexture::Init(GLContext* aContext, GLuint aTexture)
-{
-
-  if (!aTexture && !CanDetach()) {
-    // We have no texture and cannot initialize detached, bail out
-    return false;
-  }
-
-  if (NS_WARN_IF(NS_FAILED(
-      java::sdk::SurfaceTexture::New(aTexture, ReturnTo(&mSurfaceTexture))))) {
-    return false;
-  }
-
-  if (!aTexture) {
-    mSurfaceTexture->DetachFromGLContext();
-  }
-
-  mAttachedContext = aContext;
-
-  if (NS_WARN_IF(NS_FAILED(
-      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")
-{
-}
-
-AndroidSurfaceTexture::~AndroidSurfaceTexture()
-{
-  if (mSurfaceTexture) {
-    SetFrameAvailableCallback(nullptr);
-    mSurfaceTexture = nullptr;
-  }
-
-  if (mNativeWindow) {
-    ANativeWindow_release(mNativeWindow);
-    mNativeWindow = nullptr;
-  }
-}
-
 void
-AndroidSurfaceTexture::UpdateTexImage()
-{
-  mSurfaceTexture->UpdateTexImage();
-}
-
-void
-AndroidSurfaceTexture::GetTransformMatrix(gfx::Matrix4x4& aMatrix) const
+AndroidSurfaceTexture::GetTransformMatrix(java::sdk::SurfaceTexture::LocalRef aSurfaceTexture,
+                                          gfx::Matrix4x4& aMatrix)
 {
   JNIEnv* const env = jni::GetEnvForThread();
 
   auto jarray = jni::FloatArray::LocalRef::Adopt(env, env->NewFloatArray(16));
-  mSurfaceTexture->GetTransformMatrix(jarray);
+  aSurfaceTexture->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];
 
@@ -220,41 +36,11 @@ AndroidSurfaceTexture::GetTransformMatri
   aMatrix._41 = array[12];
   aMatrix._42 = array[13];
   aMatrix._43 = array[14];
   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);
-}
-
 } // gl
 } // mozilla
-
 #endif // MOZ_WIDGET_ANDROID
--- a/gfx/gl/AndroidSurfaceTexture.h
+++ b/gfx/gl/AndroidSurfaceTexture.h
@@ -3,105 +3,28 @@
 /* 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 AndroidSurfaceTexture_h__
 #define AndroidSurfaceTexture_h__
 #ifdef MOZ_WIDGET_ANDROID
 
-#include <jni.h>
-#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 "mozilla/gfx/Matrix.h"
+#include "SurfaceTexture.h"
 
-#include "GeneratedJNIWrappers.h"
-#include "SurfaceTexture.h"
+typedef uint64_t AndroidSurfaceTextureHandle;
 
 namespace mozilla {
 namespace gl {
 
-class GLContext;
-
-/**
- * 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 AndroidSurfaceTexture {
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AndroidSurfaceTexture)
-
 public:
-
-  // The SurfaceTexture is created in an attached state. This method requires
-  // Android Ice Cream Sandwich.
-  static already_AddRefed<AndroidSurfaceTexture> Create(GLContext* aGLContext, GLuint aTexture);
-
-  // Here the SurfaceTexture will be created in a detached state. You must call
-  // Attach() with the GLContext you wish to composite with. It must be done
-  // on the thread where that GLContext is current. This method requires
-  // Android Jelly Bean.
-  static already_AddRefed<AndroidSurfaceTexture> Create();
-
-  // If we are on Jelly Bean, the SurfaceTexture can be detached and reattached
-  // to allow consumption from different GLContexts. It is recommended to only
-  // attach while you are consuming in order to allow this.
-  //
-  // Only one GLContext may be attached at any given time. If another is already
-  // attached, we try to wait for it to become detached.
-  nsresult Attach(GLContext* aContext, PRIntervalTime aTiemout = PR_INTERVAL_NO_TIMEOUT);
-
-  nsresult Detach();
-
-  // Ability to detach is based on API version (16+), and we also block PowerVR
-  // since it has some type of fencing problem. Bug 1100126.
-  bool CanDetach() const;
+  static void GetTransformMatrix(java::sdk::SurfaceTexture::LocalRef aSurfaceTexture,
+                                 mozilla::gfx::Matrix4x4& aMatrix);
 
-  GLContext* AttachedContext() const { return mAttachedContext; }
-
-  ANativeWindow* NativeWindow() const {
-    return mNativeWindow;
-  }
-
-  // This attaches the updated data to the TEXTURE_EXTERNAL target
-  void UpdateTexImage();
-
-  void GetTransformMatrix(mozilla::gfx::Matrix4x4& aMatrix) const;
-
-  void SetDefaultSize(mozilla::gfx::IntSize size);
-
-  // 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;
-
-  Monitor mMonitor;
 };
 
-}
-}
+} // gl
+} // mozilla
 
-
-#endif
-#endif
+#endif // MOZ_WIDGET_ANDROID
+#endif // AndroidSurfaceTexture_h__
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -85,16 +85,22 @@ GLScreenBuffer::CreateFactory(GLContext*
             case mozilla::layers::LayersBackend::LAYERS_OPENGL: {
 #if defined(XP_MACOSX)
                 factory = SurfaceFactory_IOSurface::Create(gl, caps, ipcChannel, flags);
 #elif defined(GL_PROVIDER_GLX)
                 if (sGLXLibrary.UseTextureFromPixmap())
                   factory = SurfaceFactory_GLXDrawable::Create(gl, caps, ipcChannel, flags);
 #elif defined(MOZ_WIDGET_UIKIT)
                 factory = MakeUnique<SurfaceFactory_GLTexture>(mGLContext, caps, ipcChannel, mFlags);
+#elif defined(MOZ_WIDGET_ANDROID)
+                if (XRE_IsParentProcess()) {
+                    factory = SurfaceFactory_EGLImage::Create(gl, caps, ipcChannel, flags);
+                } else {
+                    factory = SurfaceFactory_SurfaceTexture::Create(gl, caps, ipcChannel, flags);
+                }
 #else
                 if (gl->GetContextType() == GLContextType::EGL) {
                     if (XRE_IsParentProcess()) {
                         factory = SurfaceFactory_EGLImage::Create(gl, caps, ipcChannel, flags);
                     }
                 }
 #endif
                 break;
--- a/gfx/gl/SharedSurface.h
+++ b/gfx/gl/SharedSurface.h
@@ -302,17 +302,17 @@ protected:
 public:
     UniquePtr<SharedSurface> NewSharedSurface(const gfx::IntSize& size);
     //already_AddRefed<ShSurfHandle> NewShSurfHandle(const gfx::IntSize& size);
     already_AddRefed<layers::SharedSurfaceTextureClient> NewTexClient(const gfx::IntSize& size);
 
     static void RecycleCallback(layers::TextureClient* tc, void* /*closure*/);
 
     // Auto-deletes surfs of the wrong type.
-    bool Recycle(layers::SharedSurfaceTextureClient* texClient);
+    virtual bool Recycle(layers::SharedSurfaceTextureClient* texClient);
 };
 
 class ScopedReadbackFB
 {
     GLContext* const mGL;
     ScopedBindFramebuffer mAutoFB;
     GLuint mTempFB;
     GLuint mTempTex;
--- a/gfx/gl/SharedSurfaceEGL.cpp
+++ b/gfx/gl/SharedSurfaceEGL.cpp
@@ -2,16 +2,17 @@
 /* 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/. */
 
 #include "SharedSurfaceEGL.h"
 
 #include "GLBlitHelper.h"
 #include "GLContextEGL.h"
+#include "GLContextProvider.h"
 #include "GLLibraryEGL.h"
 #include "GLReadTexImageHelper.h"
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor, etc
 #include "SharedSurface.h"
 #include "TextureGarbageBin.h"
 
 namespace mozilla {
 namespace gl {
@@ -181,11 +182,155 @@ SurfaceFactory_EGLImage::Create(GLContex
     GLLibraryEGL* egl = &sEGLLibrary;
     if (SharedSurface_EGLImage::HasExtensions(egl, prodGL)) {
         ret.reset( new ptrT(prodGL, caps, allocator, flags, context) );
     }
 
     return Move(ret);
 }
 
+////////////////////////////////////////////////////////////////////////
+
+#ifdef MOZ_WIDGET_ANDROID
+
+/*static*/ UniquePtr<SharedSurface_SurfaceTexture>
+SharedSurface_SurfaceTexture::Create(GLContext* prodGL,
+                                     const GLFormats& formats,
+                                     const gfx::IntSize& size,
+                                     bool hasAlpha,
+                                     java::GeckoSurface::Param surface)
+{
+    MOZ_ASSERT(surface);
+
+    UniquePtr<SharedSurface_SurfaceTexture> ret;
+
+    AndroidNativeWindow window(surface);
+    EGLSurface eglSurface = GLContextProviderEGL::CreateEGLSurface(window.NativeWindow());
+    if (!eglSurface) {
+        return Move(ret);
+    }
+
+    ret.reset(new SharedSurface_SurfaceTexture(prodGL, size, hasAlpha,
+                                               formats, surface, eglSurface));
+    return Move(ret);
+}
+
+bool
+SharedSurface_SurfaceTexture::IsAvailable()
+{
+    return true;
+}
+
+SharedSurface_SurfaceTexture::SharedSurface_SurfaceTexture(GLContext* gl,
+                                                           const gfx::IntSize& size,
+                                                           bool hasAlpha,
+                                                           const GLFormats& formats,
+                                                           java::GeckoSurface::Param surface,
+                                                           EGLSurface eglSurface)
+    : SharedSurface(SharedSurfaceType::AndroidSurfaceTexture,
+                    AttachmentType::Screen,
+                    gl,
+                    size,
+                    hasAlpha,
+                    true)
+    , mSurface(surface)
+    , mEglSurface(eglSurface)
+{
+}
+
+SharedSurface_SurfaceTexture::~SharedSurface_SurfaceTexture()
+{
+    GLContextProviderEGL::DestroyEGLSurface(mEglSurface);
+    java::SurfaceAllocator::DisposeSurface(mSurface);
+}
+
+layers::TextureFlags
+SharedSurface_SurfaceTexture::GetTextureFlags() const
+{
+    return layers::TextureFlags::DEALLOCATE_CLIENT;
+}
+
+void
+SharedSurface_SurfaceTexture::LockProdImpl()
+{
+    if (!mSurface->GetAvailable()) {
+        return;
+    }
+
+    GLContextEGL::Cast(mGL)->SetEGLSurfaceOverride(mEglSurface);
+
+}
+
+void
+SharedSurface_SurfaceTexture::UnlockProdImpl()
+{
+    if (!mSurface->GetAvailable()) {
+        return;
+    }
+
+    mGL->SwapBuffers();
+    mSurface->SetAvailable(false);
+    GLContextEGL::Cast(mGL)->SetEGLSurfaceOverride(nullptr);
+}
+
+bool
+SharedSurface_SurfaceTexture::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
+{
+    *out_descriptor = layers::SurfaceTextureDescriptor(mSurface->GetHandle(), mSize);
+    return true;
+}
+
+bool
+SharedSurface_SurfaceTexture::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface)
+{
+    return false;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+/*static*/ UniquePtr<SurfaceFactory_SurfaceTexture>
+SurfaceFactory_SurfaceTexture::Create(GLContext* prodGL, const SurfaceCaps& caps,
+                                      const RefPtr<layers::LayersIPCChannel>& allocator,
+                                      const layers::TextureFlags& flags)
+{
+    typedef SurfaceFactory_SurfaceTexture ptrT;
+    UniquePtr<ptrT> ret;
+
+    if (SharedSurface_SurfaceTexture::IsAvailable()) {
+        ret.reset(new ptrT(prodGL, caps, allocator, flags));
+    }
+
+    return Move(ret);
+}
+
+UniquePtr<SharedSurface>
+SurfaceFactory_SurfaceTexture::CreateShared(const gfx::IntSize& size)
+{
+    bool hasAlpha = mReadCaps.alpha;
+
+    jni::Object::LocalRef surface = java::SurfaceAllocator::AcquireSurface(size.width, size.height, true);
+    if (!surface) {
+        // Try multi-buffer mode
+        surface = java::SurfaceAllocator::AcquireSurface(size.width, size.height, false);
+        if (!surface) {
+            // Give up
+            return nullptr;
+        }
+    }
+
+    return SharedSurface_SurfaceTexture::Create(mGL, mFormats, size, hasAlpha,
+                                                java::GeckoSurface::Ref::From(surface));
+}
+
+bool
+SurfaceFactory_SurfaceTexture::Recycle(layers::SharedSurfaceTextureClient* texClient)
+{
+    SharedSurface_SurfaceTexture* surf = static_cast<SharedSurface_SurfaceTexture*>(texClient->Surf());
+    surf->JavaSurface()->SetAvailable(true);
+
+    return SurfaceFactory::Recycle(texClient);
+}
+
+#endif // MOZ_WIDGET_ANDROID
+
 } // namespace gl
 
 } /* namespace mozilla */
--- a/gfx/gl/SharedSurfaceEGL.h
+++ b/gfx/gl/SharedSurfaceEGL.h
@@ -5,16 +5,21 @@
 
 #ifndef SHARED_SURFACE_EGL_H_
 #define SHARED_SURFACE_EGL_H_
 
 #include "mozilla/Attributes.h"
 #include "mozilla/Mutex.h"
 #include "SharedSurface.h"
 
+#ifdef MOZ_WIDGET_ANDROID
+#include "GeneratedJNIWrappers.h"
+#include "AndroidNativeWindow.h"
+#endif
+
 namespace mozilla {
 namespace gl {
 
 class GLContext;
 class GLLibraryEGL;
 class TextureGarbageBin;
 
 class SharedSurface_EGLImage
@@ -106,13 +111,94 @@ protected:
 
 public:
     virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override {
         bool hasAlpha = mReadCaps.alpha;
         return SharedSurface_EGLImage::Create(mGL, mFormats, size, hasAlpha, mContext);
     }
 };
 
+#ifdef MOZ_WIDGET_ANDROID
+
+class SharedSurface_SurfaceTexture
+    : public SharedSurface
+{
+public:
+    static UniquePtr<SharedSurface_SurfaceTexture> Create(GLContext* prodGL,
+                                                          const GLFormats& formats,
+                                                          const gfx::IntSize& size,
+                                                          bool hasAlpha,
+                                                          java::GeckoSurface::Param surface);
+
+    static SharedSurface_SurfaceTexture* Cast(SharedSurface* surf) {
+        MOZ_ASSERT(surf->mType == SharedSurfaceType::AndroidSurfaceTexture);
+
+        return (SharedSurface_SurfaceTexture*)surf;
+    }
+
+    static bool IsAvailable();
+
+    java::GeckoSurface::Param JavaSurface() { return mSurface; }
+
+protected:
+    java::GeckoSurface::GlobalRef mSurface;
+    EGLSurface mEglSurface;
+
+    SharedSurface_SurfaceTexture(GLContext* gl,
+                                 const gfx::IntSize& size,
+                                 bool hasAlpha,
+                                 const GLFormats& formats,
+                                 java::GeckoSurface::Param surface,
+                                 EGLSurface eglSurface);
+
+public:
+    virtual ~SharedSurface_SurfaceTexture();
+
+    virtual layers::TextureFlags GetTextureFlags() const override;
+
+    virtual void LockProdImpl() override;
+    virtual void UnlockProdImpl() override;
+
+    virtual void ProducerAcquireImpl() override {}
+    virtual void ProducerReleaseImpl() override {}
+
+    virtual void ProducerReadAcquireImpl() override {}
+    virtual void ProducerReadReleaseImpl() override {}
+
+    // Implementation-specific functions below:
+    // Returns texture and target
+    virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
+
+    virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) override;
+};
+
+
+
+class SurfaceFactory_SurfaceTexture
+    : public SurfaceFactory
+{
+public:
+    // Fallible:
+    static UniquePtr<SurfaceFactory_SurfaceTexture> Create(GLContext* prodGL,
+                                                           const SurfaceCaps& caps,
+                                                           const RefPtr<layers::LayersIPCChannel>& allocator,
+                                                           const layers::TextureFlags& flags);
+
+protected:
+    SurfaceFactory_SurfaceTexture(GLContext* prodGL, const SurfaceCaps& caps,
+                            const RefPtr<layers::LayersIPCChannel>& allocator,
+                            const layers::TextureFlags& flags)
+        : SurfaceFactory(SharedSurfaceType::AndroidSurfaceTexture, prodGL, caps, allocator, flags)
+    { }
+
+public:
+    virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override;
+
+    virtual bool Recycle(layers::SharedSurfaceTextureClient* texClient) override;
+};
+
+#endif // MOZ_WIDGET_ANDROID
+
 } // namespace gl
 
 } /* namespace mozilla */
 
 #endif /* SHARED_SURFACE_EGL_H_ */
--- a/gfx/gl/SurfaceTypes.h
+++ b/gfx/gl/SurfaceTypes.h
@@ -72,16 +72,17 @@ enum class SharedSurfaceType : uint8_t {
     Basic,
     EGLImageShare,
     EGLSurfaceANGLE,
     DXGLInterop,
     DXGLInterop2,
     IOSurface,
     GLXDrawable,
     SharedGLTexture,
+    AndroidSurfaceTexture,
 
     Max
 };
 
 enum class AttachmentType : uint8_t {
     Screen = 0,
 
     GLTexture,
--- a/gfx/gl/moz.build
+++ b/gfx/gl/moz.build
@@ -19,16 +19,17 @@ elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT
         gl_provider = 'GLX'
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
     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',
     'GLConsts.h',
     'GLContext.h',
--- a/gfx/layers/GLImages.cpp
+++ b/gfx/layers/GLImages.cpp
@@ -93,21 +93,22 @@ GLImage::GetAsSourceSurface()
   }
 
   ScopedBindFramebuffer bind(sSnapshotContext, autoFBForTex.FB());
   ReadPixelsIntoDataSurface(sSnapshotContext, source);
   return source.forget();
 }
 
 #ifdef MOZ_WIDGET_ANDROID
-SurfaceTextureImage::SurfaceTextureImage(gl::AndroidSurfaceTexture* aSurfTex,
+SurfaceTextureImage::SurfaceTextureImage(AndroidSurfaceTextureHandle aHandle,
                                          const gfx::IntSize& aSize,
                                          gl::OriginPos aOriginPos)
  : GLImage(ImageFormat::SURFACE_TEXTURE),
-   mSurfaceTexture(aSurfTex),
+   mHandle(aHandle),
    mSize(aSize),
    mOriginPos(aOriginPos)
 {
+  MOZ_ASSERT(mHandle);
 }
 #endif
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/GLImages.h
+++ b/gfx/layers/GLImages.h
@@ -59,34 +59,34 @@ private:
   gl::OriginPos mPos;
   bool mOwns;
 };
 
 #ifdef MOZ_WIDGET_ANDROID
 
 class SurfaceTextureImage : public GLImage {
 public:
-  SurfaceTextureImage(gl::AndroidSurfaceTexture* aSurfTex,
+  SurfaceTextureImage(AndroidSurfaceTextureHandle aHandle,
                       const gfx::IntSize& aSize,
                       gl::OriginPos aOriginPos);
 
   gfx::IntSize GetSize() override { return mSize; }
-  gl::AndroidSurfaceTexture* GetSurfaceTexture() const {
-    return mSurfaceTexture;
+  AndroidSurfaceTextureHandle GetHandle() const {
+    return mHandle;
   }
   gl::OriginPos GetOriginPos() const {
     return mOriginPos;
   }
 
   SurfaceTextureImage* AsSurfaceTextureImage() override {
     return this;
   }
 
 private:
-  RefPtr<gl::AndroidSurfaceTexture> mSurfaceTexture;
+  AndroidSurfaceTextureHandle mHandle;
   gfx::IntSize mSize;
   gl::OriginPos mOriginPos;
 };
 
 #endif // MOZ_WIDGET_ANDROID
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/client/ImageClient.cpp
+++ b/gfx/layers/client/ImageClient.cpp
@@ -127,17 +127,17 @@ ImageClient::CreateTextureClientForImage
     if (aImage->GetFormat() == ImageFormat::EGLIMAGE) {
       EGLImageImage* typedImage = aImage->AsEGLImageImage();
       texture = EGLImageTextureData::CreateTextureClient(
         typedImage, size, aForwarder->GetTextureForwarder(), TextureFlags::DEFAULT);
 #ifdef MOZ_WIDGET_ANDROID
     } else if (aImage->GetFormat() == ImageFormat::SURFACE_TEXTURE) {
       SurfaceTextureImage* typedImage = aImage->AsSurfaceTextureImage();
       texture = AndroidSurfaceTextureData::CreateTextureClient(
-        typedImage->GetSurfaceTexture(), size, typedImage->GetOriginPos(),
+        typedImage->GetHandle(), size, typedImage->GetOriginPos(),
         aForwarder->GetTextureForwarder(), TextureFlags::DEFAULT);
 #endif
     } else {
       MOZ_ASSERT(false, "Bad ImageFormat.");
     }
   } else {
     RefPtr<gfx::SourceSurface> surface = aImage->GetAsSourceSurface();
     MOZ_ASSERT(surface);
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -592,17 +592,17 @@ protected:
 
   void RecycleTexture(TextureFlags aFlags);
 
   virtual void UpdatedInternal(const nsIntRegion *Region) {}
 
   /**
    * Called when mCompositableCount becomes 0.
    */
-  void NotifyNotUsed();
+  virtual void NotifyNotUsed();
 
   // for Compositor.
   void CallNotifyNotUsed();
 
   PTextureParent* mActor;
   RefPtr<TextureSourceProvider> mProvider;
   RefPtr<TextureReadLock> mReadLock;
   TextureFlags mFlags;
--- a/gfx/layers/ipc/LayersSurfaces.ipdlh
+++ b/gfx/layers/ipc/LayersSurfaces.ipdlh
@@ -55,17 +55,17 @@ struct SurfaceDescriptorDXGIYCbCr {
 
 struct SurfaceDescriptorMacIOSurface {
   uint32_t surfaceId;
   double scaleFactor;
   bool isOpaque;
 };
 
 struct SurfaceTextureDescriptor {
-  uintptr_t surfTex;
+  uint64_t handle;
   IntSize size;
 };
 
 struct EGLImageDescriptor {
   uintptr_t image; // `EGLImage` is a `void*`.
   uintptr_t fence;
   IntSize size;
   bool hasAlpha;
--- a/gfx/layers/opengl/TextureClientOGL.cpp
+++ b/gfx/layers/opengl/TextureClientOGL.cpp
@@ -74,44 +74,39 @@ EGLImageTextureData::Serialize(SurfaceDe
 }
 
 ////////////////////////////////////////////////////////////////////////
 // AndroidSurface
 
 #ifdef MOZ_WIDGET_ANDROID
 
 already_AddRefed<TextureClient>
-AndroidSurfaceTextureData::CreateTextureClient(AndroidSurfaceTexture* aSurfTex,
+AndroidSurfaceTextureData::CreateTextureClient(AndroidSurfaceTextureHandle aHandle,
                                                gfx::IntSize aSize,
                                                gl::OriginPos aOriginPos,
                                                LayersIPCChannel* aAllocator,
                                                TextureFlags aFlags)
 {
-  MOZ_ASSERT(XRE_IsParentProcess(),
-             "Can't pass an android surfaces between processes.");
-
-  if (!aSurfTex || !XRE_IsParentProcess()) {
-    return nullptr;
-  }
-
   if (aOriginPos == gl::OriginPos::BottomLeft) {
     aFlags |= TextureFlags::ORIGIN_BOTTOM_LEFT;
   }
 
   return TextureClient::CreateWithData(
-    new AndroidSurfaceTextureData(aSurfTex, aSize),
+    new AndroidSurfaceTextureData(aHandle, aSize),
     aFlags, aAllocator
   );
 }
 
-AndroidSurfaceTextureData::AndroidSurfaceTextureData(AndroidSurfaceTexture* aSurfTex,
+AndroidSurfaceTextureData::AndroidSurfaceTextureData(AndroidSurfaceTextureHandle aHandle,
                                                      gfx::IntSize aSize)
-  : mSurfTex(aSurfTex)
+  : mHandle(aHandle)
   , mSize(aSize)
-{}
+{
+  MOZ_ASSERT(mHandle);
+}
 
 AndroidSurfaceTextureData::~AndroidSurfaceTextureData()
 {}
 
 void
 AndroidSurfaceTextureData::FillInfo(TextureData::Info& aInfo) const
 {
   aInfo.size = mSize;
@@ -120,17 +115,16 @@ AndroidSurfaceTextureData::FillInfo(Text
   aInfo.hasSynchronization = false;
   aInfo.supportsMoz2D = false;
   aInfo.canExposeMappedData = false;
 }
 
 bool
 AndroidSurfaceTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
 {
-  aOutDescriptor = SurfaceTextureDescriptor((uintptr_t)mSurfTex.get(),
-                                            mSize);
+  aOutDescriptor = SurfaceTextureDescriptor(mHandle, mSize);
   return true;
 }
 
 #endif // MOZ_WIDGET_ANDROID
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/opengl/TextureClientOGL.h
+++ b/gfx/layers/opengl/TextureClientOGL.h
@@ -49,17 +49,17 @@ protected:
 };
 
 #ifdef MOZ_WIDGET_ANDROID
 
 class AndroidSurfaceTextureData : public TextureData
 {
 public:
   static already_AddRefed<TextureClient>
-  CreateTextureClient(gl::AndroidSurfaceTexture* aSurfTex,
+  CreateTextureClient(AndroidSurfaceTextureHandle aHandle,
                       gfx::IntSize aSize,
                       gl::OriginPos aOriginPos,
                       LayersIPCChannel* aAllocator,
                       TextureFlags aFlags);
 
   ~AndroidSurfaceTextureData();
 
   virtual void FillInfo(TextureData::Info& aInfo) const override;
@@ -70,19 +70,19 @@ public:
   virtual bool Lock(OpenMode) override { return true; }
 
   virtual void Unlock() override {}
 
   // Our data is always owned externally.
   virtual void Deallocate(LayersIPCChannel*) override {}
 
 protected:
-  AndroidSurfaceTextureData(gl::AndroidSurfaceTexture* aSurfTex, gfx::IntSize aSize);
+  AndroidSurfaceTextureData(AndroidSurfaceTextureHandle aHandle, gfx::IntSize aSize);
 
-  const RefPtr<gl::AndroidSurfaceTexture> mSurfTex;
+  const AndroidSurfaceTextureHandle mHandle;
   const gfx::IntSize mSize;
 };
 
 #endif // MOZ_WIDGET_ANDROID
 
 } // namespace layers
 } // namespace mozilla
 
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -51,18 +51,23 @@ CreateTextureHostOGL(const SurfaceDescri
                                                    aBackend,
                                                    aFlags);
       break;
     }
 
 #ifdef MOZ_WIDGET_ANDROID
     case SurfaceDescriptor::TSurfaceTextureDescriptor: {
       const SurfaceTextureDescriptor& desc = aDesc.get_SurfaceTextureDescriptor();
+      java::GeckoSurfaceTexture::LocalRef surfaceTexture = java::GeckoSurfaceTexture::Lookup(desc.handle());
+      if (!surfaceTexture) {
+        return nullptr;
+      }
+
       result = new SurfaceTextureHost(aFlags,
-                                      (AndroidSurfaceTexture*)desc.surfTex(),
+                                      surfaceTexture,
                                       desc.size());
       break;
     }
 #endif
 
     case SurfaceDescriptor::TEGLImageDescriptor: {
       const EGLImageDescriptor& desc = aDesc.get_EGLImageDescriptor();
       result = new EGLImageTextureHost(aFlags,
@@ -331,17 +336,17 @@ GLTextureSource::IsValid() const
 
 ////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////
 // SurfaceTextureHost
 
 #ifdef MOZ_WIDGET_ANDROID
 
 SurfaceTextureSource::SurfaceTextureSource(TextureSourceProvider* aProvider,
-                                           AndroidSurfaceTexture* aSurfTex,
+                                           mozilla::java::GeckoSurfaceTexture::Ref& aSurfTex,
                                            gfx::SurfaceFormat aFormat,
                                            GLenum aTarget,
                                            GLenum aWrapMode,
                                            gfx::IntSize aSize)
   : mGL(aProvider->GetGLContext())
   , mSurfTex(aSurfTex)
   , mFormat(aFormat)
   , mTextureTarget(aTarget)
@@ -357,22 +362,17 @@ SurfaceTextureSource::BindTexture(GLenum
   MOZ_ASSERT(mSurfTex);
   GLContext* gl = this->gl();
   if (!gl || !gl->MakeCurrent()) {
     NS_WARNING("Trying to bind a texture without a GLContext");
     return;
   }
 
   gl->fActiveTexture(aTextureUnit);
-
-  // SurfaceTexture spams us if there are any existing GL errors, so
-  // we'll clear them here in order to avoid that.
-  gl->FlushErrors();
-
-  mSurfTex->UpdateTexImage();
+  gl->fBindTexture(mTextureTarget, mSurfTex->GetTexName());
 
   ApplySamplingFilterToBoundTexture(gl, aSamplingFilter, mTextureTarget);
 }
 
 void
 SurfaceTextureSource::SetTextureSourceProvider(TextureSourceProvider* aProvider)
 {
   GLContext* newGL = aProvider->GetGLContext();
@@ -391,42 +391,56 @@ SurfaceTextureSource::IsValid() const
 }
 
 gfx::Matrix4x4
 SurfaceTextureSource::GetTextureTransform()
 {
   MOZ_ASSERT(mSurfTex);
 
   gfx::Matrix4x4 ret;
-  mSurfTex->GetTransformMatrix(ret);
+
+  AndroidSurfaceTexture::GetTransformMatrix(java::sdk::SurfaceTexture::LocalRef(java::sdk::SurfaceTexture::Ref::From(mSurfTex)), ret);
 
   return ret;
 }
 
 void
 SurfaceTextureSource::DeallocateDeviceData()
 {
   mSurfTex = nullptr;
 }
 
 ////////////////////////////////////////////////////////////////////////
 
 SurfaceTextureHost::SurfaceTextureHost(TextureFlags aFlags,
-                                       AndroidSurfaceTexture* aSurfTex,
+                                       mozilla::java::GeckoSurfaceTexture::Ref& aSurfTex,
                                        gfx::IntSize aSize)
   : TextureHost(aFlags)
   , mSurfTex(aSurfTex)
   , mSize(aSize)
 {
 }
 
 SurfaceTextureHost::~SurfaceTextureHost()
 {
 }
 
+void
+SurfaceTextureHost::PrepareTextureSource(CompositableTextureSourceRef& aTexture)
+{
+  GLContext* gl = this->gl();
+  if (!gl || !gl->MakeCurrent()) {
+    return;
+  }
+
+  // This advances the SurfaceTexture's internal buffer queue. We only want to do this
+  // once per transaction. We can then composite that texture as many times as needed.
+  mSurfTex->UpdateTexImage();
+}
+
 gl::GLContext*
 SurfaceTextureHost::gl() const
 {
   return mProvider ? mProvider->GetGLContext() : nullptr;
 }
 
 bool
 SurfaceTextureHost::Lock()
@@ -434,34 +448,27 @@ SurfaceTextureHost::Lock()
   MOZ_ASSERT(mSurfTex);
   GLContext* gl = this->gl();
   if (!gl || !gl->MakeCurrent()) {
     return false;
   }
 
   if (!mTextureSource) {
     gfx::SurfaceFormat format = gfx::SurfaceFormat::R8G8B8A8;
-    GLenum target = LOCAL_GL_TEXTURE_EXTERNAL;
+    GLenum target = LOCAL_GL_TEXTURE_EXTERNAL; // This is required by SurfaceTexture
     GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE;
     mTextureSource = new SurfaceTextureSource(mProvider,
                                               mSurfTex,
                                               format,
                                               target,
                                               wrapMode,
                                               mSize);
   }
 
-  return NS_SUCCEEDED(mSurfTex->Attach(gl));
-}
-
-void
-SurfaceTextureHost::Unlock()
-{
-  MOZ_ASSERT(mSurfTex);
-  mSurfTex->Detach();
+  return true;
 }
 
 void
 SurfaceTextureHost::SetTextureSourceProvider(TextureSourceProvider* aProvider)
 {
   if (mProvider != aProvider) {
     if (!aProvider || !aProvider->GetGLContext()) {
       DeallocateDeviceData();
@@ -470,16 +477,28 @@ SurfaceTextureHost::SetTextureSourceProv
     mProvider = aProvider;
   }
 
   if (mTextureSource) {
     mTextureSource->SetTextureSourceProvider(aProvider);
   }
 }
 
+void
+SurfaceTextureHost::NotifyNotUsed()
+{
+  if (mSurfTex->GetIsSingleBuffer()) {
+    mSurfTex->ReleaseTexImage();
+  }
+
+  // We don't want to wait until it's done compositing, there are fences that protect
+  // us from problems there. Send a message to recycle this surface immediately.
+  CallNotifyNotUsed();
+}
+
 gfx::SurfaceFormat
 SurfaceTextureHost::GetFormat() const
 {
   return mTextureSource ? mTextureSource->GetFormat() : gfx::SurfaceFormat::UNKNOWN;
 }
 
 void
 SurfaceTextureHost::DeallocateDeviceData()
--- a/gfx/layers/opengl/TextureHostOGL.h
+++ b/gfx/layers/opengl/TextureHostOGL.h
@@ -26,25 +26,26 @@
 #include "mozilla/layers/TextureHost.h"  // for TextureHost, etc
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_WARNING
 #include "nsISupportsImpl.h"            // for TextureImage::Release, etc
 #include "nsRegionFwd.h"                // for nsIntRegion
 #include "OGLShaderProgram.h"           // for ShaderProgramType, etc
 
+#ifdef MOZ_WIDGET_ANDROID
+#include "GeneratedJNIWrappers.h"
+#include "AndroidSurfaceTexture.h"
+#endif
+
 namespace mozilla {
 namespace gfx {
 class DataSourceSurface;
 } // namespace gfx
 
-namespace gl {
-class AndroidSurfaceTexture;
-} // namespace gl
-
 namespace layers {
 
 class Compositor;
 class CompositorOGL;
 class TextureImageTextureSourceOGL;
 class GLTextureSource;
 
 inline void ApplySamplingFilterToBoundTexture(gl::GLContext* aGL,
@@ -336,17 +337,17 @@ protected:
 
 #ifdef MOZ_WIDGET_ANDROID
 
 class SurfaceTextureSource : public TextureSource
                            , public TextureSourceOGL
 {
 public:
   SurfaceTextureSource(TextureSourceProvider* aProvider,
-                       mozilla::gl::AndroidSurfaceTexture* aSurfTex,
+                       java::GeckoSurfaceTexture::Ref& aSurfTex,
                        gfx::SurfaceFormat aFormat,
                        GLenum aTarget,
                        GLenum aWrapMode,
                        gfx::IntSize aSize);
 
   virtual const char* Name() const override { return "SurfaceTextureSource"; }
 
   virtual TextureSourceOGL* AsSourceOGL() override { return this; }
@@ -371,41 +372,43 @@ public:
   virtual void SetTextureSourceProvider(TextureSourceProvider* aProvider) override;
 
   gl::GLContext* gl() const {
     return mGL;
   }
 
 protected:
   RefPtr<gl::GLContext> mGL;
-  RefPtr<gl::AndroidSurfaceTexture> mSurfTex;
+  mozilla::java::GeckoSurfaceTexture::GlobalRef mSurfTex;
   const gfx::SurfaceFormat mFormat;
   const GLenum mTextureTarget;
   const GLenum mWrapMode;
   const gfx::IntSize mSize;
 };
 
 class SurfaceTextureHost : public TextureHost
 {
 public:
   SurfaceTextureHost(TextureFlags aFlags,
-                     mozilla::gl::AndroidSurfaceTexture* aSurfTex,
+                     mozilla::java::GeckoSurfaceTexture::Ref& aSurfTex,
                      gfx::IntSize aSize);
 
   virtual ~SurfaceTextureHost();
 
+  virtual void PrepareTextureSource(CompositableTextureSourceRef& aTexture) override;
+
   virtual void DeallocateDeviceData() override;
 
   virtual void SetTextureSourceProvider(TextureSourceProvider* aProvider) override;
 
   virtual bool Lock() override;
 
-  virtual void Unlock() override;
+  virtual gfx::SurfaceFormat GetFormat() const override;
 
-  virtual gfx::SurfaceFormat GetFormat() const override;
+  virtual void NotifyNotUsed() override;
 
   virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override
   {
     aTexture = mTextureSource;
     return !!aTexture;
   }
 
   virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override
@@ -415,17 +418,17 @@ public:
 
   gl::GLContext* gl() const;
 
   virtual gfx::IntSize GetSize() const override { return mSize; }
 
   virtual const char* Name() override { return "SurfaceTextureHost"; }
 
 protected:
-  RefPtr<gl::AndroidSurfaceTexture> mSurfTex;
+  mozilla::java::GeckoSurfaceTexture::GlobalRef mSurfTex;
   const gfx::IntSize mSize;
   RefPtr<CompositorOGL> mCompositor;
   RefPtr<SurfaceTextureSource> mTextureSource;
 };
 
 #endif // MOZ_WIDGET_ANDROID
 
 ////////////////////////////////////////////////////////////////////////
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -576,16 +576,17 @@ media_pkg := org/mozilla/gecko/media
 	@echo "Processing AIDL: $< => $@"
 	$(AIDL) -p$(ANDROID_SDK)/framework.aidl -I$(aidl_geckoview_src_path) -o$(aidl_target_path) $<
 
 $(aidl_target_path)/$(media_pkg)/%.java:$(aidl_geckoview_src_path)/$(media_pkg)/%.aidl
 	@echo "Processing AIDL: $< => $@"
 	$(AIDL) -p$(ANDROID_SDK)/framework.aidl -I$(aidl_geckoview_src_path) -o$(aidl_target_path) $<
 
 GECKOVIEW_AIDLS = \
+  org/mozilla/gecko/gfx/ISurfaceAllocator.aidl \
   org/mozilla/gecko/IGeckoEditableChild.aidl \
   org/mozilla/gecko/IGeckoEditableParent.aidl \
   org/mozilla/gecko/media/ICodec.java \
   org/mozilla/gecko/media/ICodecCallbacks.java \
   org/mozilla/gecko/media/IMediaDrmBridge.java \
   org/mozilla/gecko/media/IMediaDrmBridgeCallbacks.java \
   org/mozilla/gecko/media/IMediaManager.java \
   org/mozilla/gecko/process/IChildProcess.aidl \
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/SurfaceAllocator.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/SurfaceAllocator.java
@@ -36,24 +36,29 @@ public final class SurfaceAllocator {
                             "org.mozilla.gecko.gfx.SurfaceAllocatorService");
 
         // FIXME: may not want to auto create
         if (!GeckoAppShell.getApplicationContext().bindService(intent, sConnection, Context.BIND_AUTO_CREATE)) {
             throw new Exception("Failed to connect to surface allocator service!");
         }
     }
 
-    @WrapForJNI(exceptionMode = "nsresult")
-    public static GeckoSurface acquireSurface(int width, int height, boolean singleBufferMode) throws Exception {
-        ensureConnection();
+    @WrapForJNI(exceptionMode = "ignore")
+    public static GeckoSurface acquireSurface(int width, int height, boolean singleBufferMode) {
+        try {
+            ensureConnection();
 
-        try {
+            if (singleBufferMode && !GeckoSurfaceTexture.isSingleBufferSupported()) {
+                return null;
+            }
+
             return sConnection.getAllocator().acquireSurface(width, height, singleBufferMode);
-        } catch (RemoteException e) {
-            throw new Exception("Failed to acquire GeckoSurface", e);
+        } catch (Exception e) {
+            Log.w(LOGTAG, "Failed to acquire GeckoSurface", e);
+            return null;
         }
     }
 
     @WrapForJNI(exceptionMode = "ignore")
     public static void disposeSurface(GeckoSurface surface) {
         try {
             ensureConnection();
         } catch (Exception e) {