Bug 1322650 - Use SurfaceTexture for WebGL on Android in E10S r=jgilbert draft
authorJames Willcox <snorp@snorp.net>
Fri, 03 Mar 2017 15:14:27 -0600
changeset 568950 e98cce97ad96cc38db05725645679071802c4391
parent 568949 e72517cd17ad76dd6e235d4e5bf10a9b6a7e9ea1
child 568951 4aa73902dd654e87a86eb4f47c981fdc765969ee
push id56033
push userbmo:snorp@snorp.net
push dateWed, 26 Apr 2017 20:29:44 +0000
reviewersjgilbert
bugs1322650
milestone55.0a1
Bug 1322650 - Use SurfaceTexture for WebGL on Android in E10S r=jgilbert The main advantage here is that it works cross-process. MozReview-Commit-ID: 7YUTVB4Bydg
gfx/gl/AndroidNativeWindow.h
gfx/gl/GLContextEGL.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/CanvasClient.cpp
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/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/GLContextEGL.h
+++ b/gfx/gl/GLContextEGL.h
@@ -64,16 +64,19 @@ public:
         return sEGLLibrary.IsWARP();
     }
 
     virtual bool BindTexImage() override;
 
     virtual bool ReleaseTexImage() override;
 
     void SetEGLSurfaceOverride(EGLSurface surf);
+    EGLSurface GetEGLSurfaceOverride() {
+        return mSurfaceOverride;
+    }
 
     virtual bool MakeCurrentImpl(bool aForce) override;
 
     virtual bool IsCurrent() override;
 
     virtual bool RenewSurface(widget::CompositorWidget* aWidget) override;
 
     virtual void ReleaseSurface() override;
--- 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
@@ -91,16 +91,20 @@ public:
 
     // This locks the SharedSurface as the production buffer for the context.
     // This is needed by backends which use PBuffers and/or EGLSurfaces.
     void LockProd();
 
     // Unlocking is harmless if we're already unlocked.
     void UnlockProd();
 
+    // This surface has been moved to the front buffer and will not be locked again
+    // until it is recycled. Do any finalization steps here.
+    virtual void Commit(){}
+
 protected:
     virtual void LockProdImpl() = 0;
     virtual void UnlockProdImpl() = 0;
 
     virtual void ProducerAcquireImpl() = 0;
     virtual void ProducerReleaseImpl() = 0;
     virtual void ProducerReadAcquireImpl() { ProducerAcquireImpl(); }
     virtual void ProducerReadReleaseImpl() { ProducerReleaseImpl(); }
--- 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"
 
 namespace mozilla {
 namespace gl {
 
@@ -180,11 +181,154 @@ 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()
+{
+    MOZ_RELEASE_ASSERT(mSurface->GetAvailable());
+
+    GLContextEGL *gl = GLContextEGL::Cast(mGL);
+    mOrigEglSurface = gl->GetEGLSurfaceOverride();
+    gl->SetEGLSurfaceOverride(mEglSurface);
+}
+
+void
+SharedSurface_SurfaceTexture::UnlockProdImpl()
+{
+    MOZ_RELEASE_ASSERT(mSurface->GetAvailable());
+
+    GLContextEGL::Cast(mGL)->SetEGLSurfaceOverride(mOrigEglSurface);
+    mOrigEglSurface = nullptr;
+}
+
+void
+SharedSurface_SurfaceTexture::Commit()
+{
+    MOZ_RELEASE_ASSERT(mSurface->GetAvailable());
+
+    LockProdImpl();
+    mGL->SwapBuffers();
+    UnlockProdImpl();
+    mSurface->SetAvailable(false);
+}
+
+void
+SharedSurface_SurfaceTexture::WaitForBufferOwnership()
+{
+    MOZ_RELEASE_ASSERT(!mSurface->GetAvailable());
+    mSurface->SetAvailable(true);
+}
+
+bool
+SharedSurface_SurfaceTexture::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
+{
+    *out_descriptor = layers::SurfaceTextureDescriptor(mSurface->GetHandle(), mSize);
+    return true;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+/*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));
+}
+
+#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 SharedSurface_EGLImage
     : public SharedSurface
@@ -105,13 +110,97 @@ 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;
+    EGLSurface mOrigEglSurface;
+
+    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 { return false; }
+
+    virtual void Commit() override;
+
+    virtual void WaitForBufferOwnership() 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;
+};
+
+#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/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -456,16 +456,18 @@ CanvasClientSharedSurface::UpdateRendere
     auto layersBackend = shadowForwarder->GetCompositorBackendType();
     mReadbackClient = TexClientFromReadback(surf, forwarder, flags, layersBackend);
 
     newFront = mReadbackClient;
   } else {
     mReadbackClient = nullptr;
   }
 
+  surf->Commit();
+
   if (asyncRenderer) {
     // If surface type is Basic, above codes will readback
     // the GLContext to mReadbackClient in order to send frame to
     // compositor. We copy from this TextureClient directly by
     // calling CopyFromTextureClient().
     // Therefore, if main-thread want the content of GLContext,
     // it doesn't have to readback from GLContext again.
     //
--- 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
@@ -593,17 +593,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,22 @@ 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());
+
+      MOZ_RELEASE_ASSERT(surfaceTexture);
+
       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,
@@ -330,17 +334,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)
@@ -356,22 +360,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();
@@ -390,42 +389,57 @@ SurfaceTextureSource::IsValid() const
 }
 
 gfx::Matrix4x4
 SurfaceTextureSource::GetTextureTransform()
 {
   MOZ_ASSERT(mSurfTex);
 
   gfx::Matrix4x4 ret;
-  mSurfTex->GetTransformMatrix(ret);
+
+  const auto& surf = java::sdk::SurfaceTexture::LocalRef(java::sdk::SurfaceTexture::Ref::From(mSurfTex));
+  AndroidSurfaceTexture::GetTransformMatrix(surf, 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()
@@ -433,34 +447,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();
@@ -469,16 +476,28 @@ SurfaceTextureHost::SetTextureSourceProv
     mProvider = aProvider;
   }
 
   if (mTextureSource) {
     mTextureSource->SetTextureSourceProvider(aProvider);
   }
 }
 
+void
+SurfaceTextureHost::NotifyNotUsed()
+{
+  if (mSurfTex->IsSingleBuffer()) {
+    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/geckoview/src/main/java/org/mozilla/gecko/gfx/SurfaceAllocator.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/SurfaceAllocator.java
@@ -37,23 +37,28 @@ public final class SurfaceAllocator {
 
         // 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
-    public static GeckoSurface acquireSurface(int width, int height, boolean singleBufferMode) throws Exception {
-        ensureConnection();
-
+    public static GeckoSurface acquireSurface(int width, int height, boolean singleBufferMode) {
         try {
+            ensureConnection();
+
+            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
     public static void disposeSurface(GeckoSurface surface) {
         try {
             ensureConnection();
         } catch (Exception e) {