Bug 1322650 - Use SurfaceTexture for WebGL on Android in E10S r=jgilbert
☠☠ backed out by a5e2d088c2ed ☠ ☠
authorJames Willcox <snorp@snorp.net>
Fri, 03 Mar 2017 15:14:27 -0600
changeset 357990 e56e5e1c8786935a8d03bc308622ccfd631b7a15
parent 357989 96fe52231b575c343ed056b432766c67de7d9a5d
child 357991 4519296a323e8c4cf78a71686f538805ce9e1b06
push id31808
push usercbook@mozilla.com
push dateFri, 12 May 2017 12:37:49 +0000
treeherdermozilla-central@030c0a7c8781 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert
bugs1322650
milestone55.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 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 {
 
@@ -95,22 +96,16 @@ SharedSurface_EGLImage::~SharedSurface_E
 
     if (!mGL || !mGL->MakeCurrent())
         return;
 
     mGL->fDeleteTextures(1, &mProdTex);
     mProdTex = 0;
 }
 
-layers::TextureFlags
-SharedSurface_EGLImage::GetTextureFlags() const
-{
-    return layers::TextureFlags::DEALLOCATE_CLIENT;
-}
-
 void
 SharedSurface_EGLImage::ProducerReleaseImpl()
 {
     MutexAutoLock lock(mMutex);
     mGL->MakeCurrent();
 
     if (mEGL->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync) &&
         mGL->IsExtensionSupported(GLContext::OES_EGL_sync))
@@ -180,11 +175,141 @@ 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);
+}
+
+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);
+}
+
+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 *gl = GLContextEGL::Cast(mGL);
+    MOZ_ASSERT(gl->GetEGLSurfaceOverride() == mEglSurface);
+
+    gl->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)
+{
+    UniquePtr<SurfaceFactory_SurfaceTexture> ret(
+        new SurfaceFactory_SurfaceTexture(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
+            NS_WARNING("Failed to allocate SurfaceTexture!");
+            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
@@ -53,17 +58,19 @@ protected:
                            EGLImage image);
 
     EGLDisplay Display() const;
     void UpdateProdTexture(const MutexAutoLock& curAutoLock);
 
 public:
     virtual ~SharedSurface_EGLImage();
 
-    virtual layers::TextureFlags GetTextureFlags() const override;
+    virtual layers::TextureFlags GetTextureFlags() const override {
+      return layers::TextureFlags::DEALLOCATE_CLIENT;
+    }
 
     virtual void LockProdImpl() override {}
     virtual void UnlockProdImpl() override {}
 
     virtual void ProducerAcquireImpl() override {}
     virtual void ProducerReleaseImpl() override;
 
     virtual void ProducerReadAcquireImpl() override;
@@ -105,13 +112,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;
+    }
+
+    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 {
+      return layers::TextureFlags::DEALLOCATE_CLIENT;
+    }
+
+    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
@@ -596,17 +596,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,26 @@ SurfaceTextureHost::SetTextureSourceProv
     mProvider = aProvider;
   }
 
   if (mTextureSource) {
     mTextureSource->SetTextureSourceProvider(aProvider);
   }
 }
 
+void
+SurfaceTextureHost::NotifyNotUsed()
+{
+  if (mSurfTex->IsSingleBuffer()) {
+    mSurfTex->ReleaseTexImage();
+  }
+
+  TextureHost::NotifyNotUsed();
+}
+
 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) {