Bug 1529870 - Add handling of single buffer mode android SurfaceTexture r=nical
authorsotaro <sotaro.ikeda.g@gmail.com>
Wed, 03 Apr 2019 22:05:27 +0000
changeset 467862 d1f9761ddeb17f16aea167448988a4445c7114f7
parent 467861 d63733e7f42fc5da3b8896099b69bef27456ddbe
child 467863 91b055c0dadb8032a44fb659695d6487c7d43d5e
push id35810
push useraciure@mozilla.com
push dateThu, 04 Apr 2019 04:33:36 +0000
treeherdermozilla-central@b72c02e34261 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1529870
milestone68.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 1529870 - Add handling of single buffer mode android SurfaceTexture r=nical When SurfaceTexture is single buffer mode, UpdateTexImage() should be called only once for each publish. If UpdateTexImage() is called more than once, it causes hand on puglish side. Differential Revision: https://phabricator.services.mozilla.com/D24483
gfx/layers/composite/TextureHost.h
gfx/layers/opengl/TextureHostOGL.h
gfx/layers/wr/WebRenderImageHost.cpp
gfx/layers/wr/WebRenderTextureHost.cpp
gfx/layers/wr/WebRenderTextureHost.h
gfx/webrender_bindings/RenderAndroidSurfaceTextureHostOGL.cpp
gfx/webrender_bindings/RenderAndroidSurfaceTextureHostOGL.h
gfx/webrender_bindings/RenderTextureHost.cpp
gfx/webrender_bindings/RenderTextureHost.h
gfx/webrender_bindings/RenderThread.cpp
gfx/webrender_bindings/RenderThread.h
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -52,16 +52,17 @@ class BufferTextureHost;
 class Compositor;
 class CompositableParentManager;
 class ReadLockDescriptor;
 class CompositorBridgeParent;
 class SurfaceDescriptor;
 class HostIPCAllocator;
 class ISurfaceAllocator;
 class MacIOSurfaceTextureHostOGL;
+class SurfaceTextureHost;
 class TextureHostOGL;
 class TextureReadLock;
 class TextureSourceOGL;
 class TextureSourceD3D11;
 class TextureSourceBasic;
 class DataTextureSource;
 class PTextureParent;
 class TextureParent;
@@ -618,16 +619,17 @@ class TextureHost : public AtomicRefCoun
 
   TextureReadLock* GetReadLock() { return mReadLock; }
 
   virtual BufferTextureHost* AsBufferTextureHost() { return nullptr; }
   virtual MacIOSurfaceTextureHostOGL* AsMacIOSurfaceTextureHost() {
     return nullptr;
   }
   virtual WebRenderTextureHost* AsWebRenderTextureHost() { return nullptr; }
+  virtual SurfaceTextureHost* AsSurfaceTextureHost() { return nullptr; }
 
   // Create the corresponding RenderTextureHost type of this texture, and
   // register the RenderTextureHost into render thread.
   virtual void CreateRenderTexture(
       const wr::ExternalImageId& aExternalImageId) {
     MOZ_RELEASE_ASSERT(
         false,
         "No CreateRenderTexture() implementation for this TextureHost type.");
--- a/gfx/layers/opengl/TextureHostOGL.h
+++ b/gfx/layers/opengl/TextureHostOGL.h
@@ -432,16 +432,18 @@ class SurfaceTextureHost : public Textur
   }
 
   gl::GLContext* gl() const;
 
   virtual gfx::IntSize GetSize() const override { return mSize; }
 
   virtual const char* Name() override { return "SurfaceTextureHost"; }
 
+  virtual SurfaceTextureHost* AsSurfaceTextureHost() override { return this; }
+
   virtual void CreateRenderTexture(
       const wr::ExternalImageId& aExternalImageId) override;
 
   virtual void PushResourceUpdates(wr::TransactionBuilder& aResources,
                                    ResourceUpdateOp aOp,
                                    const Range<wr::ImageKey>& aImageKeys,
                                    const wr::ExternalImageId& aExtID) override;
 
--- a/gfx/layers/wr/WebRenderImageHost.cpp
+++ b/gfx/layers/wr/WebRenderImageHost.cpp
@@ -8,16 +8,17 @@
 
 #include "LayersLogging.h"
 #include "mozilla/Move.h"
 #include "mozilla/layers/Compositor.h"                // for Compositor
 #include "mozilla/layers/CompositorVsyncScheduler.h"  // for CompositorVsyncScheduler
 #include "mozilla/layers/Effects.h"  // for TexturedEffect, Effect, etc
 #include "mozilla/layers/LayerManagerComposite.h"  // for TexturedEffect, Effect, etc
 #include "mozilla/layers/WebRenderBridgeParent.h"
+#include "mozilla/layers/WebRenderTextureHost.h"
 #include "mozilla/layers/AsyncImagePipelineManager.h"
 #include "nsAString.h"
 #include "nsDebug.h"          // for NS_WARNING, NS_ASSERTION
 #include "nsPrintfCString.h"  // for nsPrintfCString
 #include "nsString.h"         // for nsAutoCString
 
 namespace mozilla {
 
@@ -158,16 +159,23 @@ TextureHost* WebRenderImageHost::GetAsTe
   return mCurrentTextureHost;
 }
 
 void WebRenderImageHost::SetCurrentTextureHost(TextureHost* aTexture) {
   if (aTexture == mCurrentTextureHost.get()) {
     return;
   }
 
+  if (aTexture && aTexture->AsWebRenderTextureHost()) {
+    // If WebRenderTextureHost wraps SurfaceTextureHost, it is important to call
+    // PrepareForUse for each texture that we receive.
+    // See RenderAndroidSurfaceTextureHostOGL::PrepareForUse.
+    aTexture->AsWebRenderTextureHost()->PrepareForUse();
+  }
+
   mCurrentTextureHost = aTexture;
 }
 
 void WebRenderImageHost::Attach(Layer* aLayer, TextureSourceProvider* aProvider,
                                 AttachFlags aFlags) {}
 
 void WebRenderImageHost::Composite(
     Compositor* aCompositor, LayerComposite* aLayer, EffectChain& aEffectChain,
--- a/gfx/layers/wr/WebRenderTextureHost.cpp
+++ b/gfx/layers/wr/WebRenderTextureHost.cpp
@@ -5,16 +5,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebRenderTextureHost.h"
 
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/LayersSurfaces.h"
 #include "mozilla/webrender/RenderThread.h"
 
+#ifdef MOZ_WIDGET_ANDROID
+#  include "mozilla/layers/TextureHostOGL.h"
+#endif
+
 namespace mozilla {
 namespace layers {
 
 WebRenderTextureHost::WebRenderTextureHost(
     const SurfaceDescriptor& aDesc, TextureFlags aFlags, TextureHost* aTexture,
     wr::ExternalImageId& aExternalImageId)
     : TextureHost(aFlags), mExternalImageId(aExternalImageId) {
   // The wrapped textureHost will be used in WebRender, and the WebRender could
@@ -86,16 +90,35 @@ gfx::IntSize WebRenderTextureHost::GetSi
 
 gfx::SurfaceFormat WebRenderTextureHost::GetFormat() const {
   if (!mWrappedTextureHost) {
     return gfx::SurfaceFormat::UNKNOWN;
   }
   return mWrappedTextureHost->GetFormat();
 }
 
+void WebRenderTextureHost::NotifyNotUsed() {
+#ifdef MOZ_WIDGET_ANDROID
+  if (mWrappedTextureHost && mWrappedTextureHost->AsSurfaceTextureHost()) {
+    wr::RenderThread::Get()->NotifyNotUsed(wr::AsUint64(mExternalImageId));
+  }
+#endif
+  TextureHost::NotifyNotUsed();
+}
+
+void WebRenderTextureHost::PrepareForUse() {
+#ifdef MOZ_WIDGET_ANDROID
+  if (mWrappedTextureHost && mWrappedTextureHost->AsSurfaceTextureHost()) {
+    // Call PrepareForUse on render thread.
+    // See RenderAndroidSurfaceTextureHostOGL::PrepareForUse.
+    wr::RenderThread::Get()->PrepareForUse(wr::AsUint64(mExternalImageId));
+  }
+#endif
+}
+
 gfx::SurfaceFormat WebRenderTextureHost::GetReadFormat() const {
   if (!mWrappedTextureHost) {
     return gfx::SurfaceFormat::UNKNOWN;
   }
   return mWrappedTextureHost->GetReadFormat();
 }
 
 int32_t WebRenderTextureHost::GetRGBStride() {
--- a/gfx/layers/wr/WebRenderTextureHost.h
+++ b/gfx/layers/wr/WebRenderTextureHost.h
@@ -34,16 +34,18 @@ class WebRenderTextureHost : public Text
       TextureSourceProvider* aProvider) override;
 
   virtual bool Lock() override;
 
   virtual void Unlock() override;
 
   virtual gfx::SurfaceFormat GetFormat() const override;
 
+  virtual void NotifyNotUsed() override;
+
   // Return the format used for reading the texture. Some hardware specific
   // textureHosts use their special data representation internally, but we could
   // treat these textureHost as the read-format when we read them.
   // Please check TextureHost::GetReadFormat().
   virtual gfx::SurfaceFormat GetReadFormat() const override;
 
   virtual bool BindTextureSource(
       CompositableTextureSourceRef& aTexture) override;
@@ -57,16 +59,18 @@ class WebRenderTextureHost : public Text
 #ifdef MOZ_LAYERS_HAVE_LOG
   virtual const char* Name() override { return "WebRenderTextureHost"; }
 #endif
 
   virtual WebRenderTextureHost* AsWebRenderTextureHost() override {
     return this;
   }
 
+  virtual void PrepareForUse();
+
   wr::ExternalImageId GetExternalImageKey() { return mExternalImageId; }
 
   int32_t GetRGBStride();
 
   virtual bool HasIntermediateBuffer() const override;
 
   virtual uint32_t NumSubTextures() const override;
 
--- a/gfx/webrender_bindings/RenderAndroidSurfaceTextureHostOGL.cpp
+++ b/gfx/webrender_bindings/RenderAndroidSurfaceTextureHostOGL.cpp
@@ -2,34 +2,43 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 "RenderAndroidSurfaceTextureHostOGL.h"
 
 #include "mozilla/gfx/Logging.h"
+#include "mozilla/webrender/RenderThread.h"
 #include "GLContext.h"
 
 namespace mozilla {
 namespace wr {
 
 RenderAndroidSurfaceTextureHostOGL::RenderAndroidSurfaceTextureHostOGL(
     const java::GeckoSurfaceTexture::GlobalRef& aSurfTex, gfx::IntSize aSize,
     gfx::SurfaceFormat aFormat, bool aContinuousUpdate)
-    : mSurfTex(aSurfTex), mSize(aSize) {
+    : mSurfTex(aSurfTex),
+      mSize(aSize),
+      mIsPrepared(false),
+      mAttachedToGLContext(false) {
   MOZ_COUNT_CTOR_INHERITED(RenderAndroidSurfaceTextureHostOGL,
                            RenderTextureHostOGL);
 
   if (mSurfTex) {
     mSurfTex->IncrementUse();
   }
+
+  if (mSurfTex && !mSurfTex->IsSingleBuffer()) {
+    mIsPrepared = true;
+  }
 }
 
 RenderAndroidSurfaceTextureHostOGL::~RenderAndroidSurfaceTextureHostOGL() {
+  MOZ_ASSERT(RenderThread::IsInRenderThread());
   MOZ_COUNT_DTOR_INHERITED(RenderAndroidSurfaceTextureHostOGL,
                            RenderTextureHostOGL);
   DeleteTextureHandle();
   if (mSurfTex) {
     mSurfTex->DecrementUse();
   }
 }
 
@@ -46,60 +55,108 @@ gfx::IntSize RenderAndroidSurfaceTexture
   return mSize;
 }
 
 wr::WrExternalImage RenderAndroidSurfaceTextureHostOGL::Lock(
     uint8_t aChannelIndex, gl::GLContext* aGL, wr::ImageRendering aRendering) {
   MOZ_ASSERT(aChannelIndex == 0);
 
   if (mGL.get() != aGL) {
-    // release the texture handle in the previous gl context
-    DeleteTextureHandle();
-    mGL = aGL;
-    mGL->MakeCurrent();
+    // This should not happen. On android, SharedGL is used.
+    MOZ_ASSERT_UNREACHABLE("Unexpected GL context");
+    return InvalidToWrExternalImage();
   }
 
   if (!mSurfTex || !mGL || !mGL->MakeCurrent()) {
     return InvalidToWrExternalImage();
   }
 
-  if (!mSurfTex->IsAttachedToGLContext((int64_t)mGL.get())) {
-    GLuint texName;
-    mGL->fGenTextures(1, &texName);
-    // Cache rendering filter.
+  if (!mAttachedToGLContext) {
+    // Cache new rendering filter.
     mCachedRendering = aRendering;
-    ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0,
-                                 LOCAL_GL_TEXTURE_EXTERNAL_OES, texName,
-                                 aRendering);
-
-    if (NS_FAILED(mSurfTex->AttachToGLContext((int64_t)mGL.get(), texName))) {
-      MOZ_ASSERT(0);
-      mGL->fDeleteTextures(1, &texName);
+    if (!EnsureAttachedToGLContext()) {
       return InvalidToWrExternalImage();
-      ;
     }
   } else if (IsFilterUpdateNecessary(aRendering)) {
     // Cache new rendering filter.
     mCachedRendering = aRendering;
     ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0,
                                  LOCAL_GL_TEXTURE_EXTERNAL_OES,
                                  mSurfTex->GetTexName(), aRendering);
   }
 
-  // XXX Call UpdateTexImage() only when it is necessary.
-  // For now, alyways call UpdateTexImage().
-  // if (mContinuousUpdate) {
-  mSurfTex->UpdateTexImage();
-  //}
+  // Bug 1507078, Call UpdateTexImage() only when mContinuousUpdate is true
+  if (mSurfTex && !mSurfTex->IsSingleBuffer()) {
+    mSurfTex->UpdateTexImage();
+  }
 
   return NativeTextureToWrExternalImage(mSurfTex->GetTexName(), 0, 0,
                                         mSize.width, mSize.height);
 }
 
 void RenderAndroidSurfaceTextureHostOGL::Unlock() {}
 
 void RenderAndroidSurfaceTextureHostOGL::DeleteTextureHandle() {
-  // XXX Do we need to call mSurfTex->DetachFromGLContext() here?
-  // But Surface texture is shared among many SurfaceTextureHosts.
+  NotifyNotUsed();
+}
+
+bool RenderAndroidSurfaceTextureHostOGL::EnsureAttachedToGLContext() {
+  if (mAttachedToGLContext) {
+    return true;
+  }
+
+  if (!mGL) {
+    mGL = RenderThread::Get()->SharedGL();
+  }
+
+  if (!mSurfTex || !mGL || !mGL->MakeCurrent()) {
+    return false;
+  }
+
+  if (!mSurfTex->IsAttachedToGLContext((int64_t)mGL.get())) {
+    GLuint texName;
+    mGL->fGenTextures(1, &texName);
+    ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0,
+                                 LOCAL_GL_TEXTURE_EXTERNAL_OES, texName,
+                                 mCachedRendering);
+
+    if (NS_FAILED(mSurfTex->AttachToGLContext((int64_t)mGL.get(), texName))) {
+      MOZ_ASSERT(0);
+      mGL->fDeleteTextures(1, &texName);
+      return false;
+    }
+  }
+
+  mAttachedToGLContext = true;
+  return true;
+}
+
+void RenderAndroidSurfaceTextureHostOGL::PrepareForUse() {
+  // When SurfaceTexture is single buffer mode, UpdateTexImage neeeds to be
+  // called only once for each publish. If UpdateTexImage is called more
+  // than once, it causes hang on puglish side. And UpdateTexImage needs to
+  // be called on render thread, since the SurfaceTexture is consumed on render
+  // thread.
+
+  MOZ_ASSERT(RenderThread::IsInRenderThread());
+
+  EnsureAttachedToGLContext();
+
+  if (mSurfTex && mSurfTex->IsSingleBuffer() && !mIsPrepared) {
+    mSurfTex->UpdateTexImage();
+    mIsPrepared = true;
+  }
+}
+
+void RenderAndroidSurfaceTextureHostOGL::NotifyNotUsed() {
+  MOZ_ASSERT(RenderThread::IsInRenderThread());
+
+  EnsureAttachedToGLContext();
+
+  if (mSurfTex && mSurfTex->IsSingleBuffer() && mIsPrepared) {
+    mGL->MakeCurrent();
+    mSurfTex->ReleaseTexImage();
+    mIsPrepared = false;
+  }
 }
 
 }  // namespace wr
 }  // namespace mozilla
--- a/gfx/webrender_bindings/RenderAndroidSurfaceTextureHostOGL.h
+++ b/gfx/webrender_bindings/RenderAndroidSurfaceTextureHostOGL.h
@@ -23,24 +23,30 @@ class RenderAndroidSurfaceTextureHostOGL
 
   wr::WrExternalImage Lock(uint8_t aChannelIndex, gl::GLContext* aGL,
                            wr::ImageRendering aRendering) override;
   void Unlock() override;
 
   virtual gfx::IntSize GetSize(uint8_t aChannelIndex) const override;
   virtual GLuint GetGLHandle(uint8_t aChannelIndex) const override;
 
+  virtual void PrepareForUse() override;
+  virtual void NotifyNotUsed() override;
+
  private:
   virtual ~RenderAndroidSurfaceTextureHostOGL();
   void DeleteTextureHandle();
+  bool EnsureAttachedToGLContext();
 
   const mozilla::java::GeckoSurfaceTexture::GlobalRef mSurfTex;
   const gfx::IntSize mSize;
   // XXX const bool mContinuousUpdate;
   // XXX const bool mIgnoreTransform;
+  bool mIsPrepared;
+  bool mAttachedToGLContext;
 
   RefPtr<gl::GLContext> mGL;
 };
 
 }  // namespace wr
 }  // namespace mozilla
 
 #endif  // MOZILLA_GFX_RENDERANDROIDSURFACETEXTUREHOSTOGL_H
--- a/gfx/webrender_bindings/RenderTextureHost.cpp
+++ b/gfx/webrender_bindings/RenderTextureHost.cpp
@@ -20,17 +20,20 @@ void ActivateBindAndTexParameteri(gl::GL
                           ? LOCAL_GL_NEAREST
                           : LOCAL_GL_LINEAR);
   aGL->fTexParameteri(aBindTarget, LOCAL_GL_TEXTURE_MAG_FILTER,
                       aRendering == wr::ImageRendering::Pixelated
                           ? LOCAL_GL_NEAREST
                           : LOCAL_GL_LINEAR);
 }
 
-RenderTextureHost::RenderTextureHost() { MOZ_COUNT_CTOR(RenderTextureHost); }
+RenderTextureHost::RenderTextureHost()
+    : mCachedRendering(wr::ImageRendering::Auto) {
+  MOZ_COUNT_CTOR(RenderTextureHost);
+}
 
 RenderTextureHost::~RenderTextureHost() {
   MOZ_ASSERT(RenderThread::IsInRenderThread());
   MOZ_COUNT_DTOR(RenderTextureHost);
 }
 
 bool RenderTextureHost::IsFilterUpdateNecessary(wr::ImageRendering aRendering) {
   return mCachedRendering != aRendering;
--- a/gfx/webrender_bindings/RenderTextureHost.h
+++ b/gfx/webrender_bindings/RenderTextureHost.h
@@ -40,16 +40,19 @@ class RenderTextureHost {
                                    wr::ImageRendering aRendering) = 0;
   virtual void Unlock() = 0;
   virtual void ClearCachedResources() {}
 
   virtual RenderTextureHostWrapper* AsRenderTextureHostWrapper() {
     return nullptr;
   }
 
+  virtual void PrepareForUse() {}
+  virtual void NotifyNotUsed() {}
+
  protected:
   virtual ~RenderTextureHost();
 
   bool IsFilterUpdateNecessary(wr::ImageRendering aRendering);
 
   wr::ImageRendering mCachedRendering;
 };
 
--- a/gfx/webrender_bindings/RenderThread.cpp
+++ b/gfx/webrender_bindings/RenderThread.cpp
@@ -607,16 +607,62 @@ void RenderThread::UnregisterExternalIma
     Loop()->PostTask(NewRunnableMethod(
         "RenderThread::DeferredRenderTextureHostDestroy", this,
         &RenderThread::DeferredRenderTextureHostDestroy));
   } else {
     mRenderTextures.erase(it);
   }
 }
 
+void RenderThread::PrepareForUse(uint64_t aExternalImageId) {
+  if (!IsInRenderThread()) {
+    Loop()->PostTask(NewRunnableMethod<uint64_t>(
+        "RenderThread::PrepareForUse", this, &RenderThread::PrepareForUse,
+        aExternalImageId));
+    return;
+  }
+
+  MutexAutoLock lock(mRenderTextureMapLock);
+  if (mHasShutdown) {
+    return;
+  }
+
+  auto it = mRenderTextures.find(aExternalImageId);
+  MOZ_ASSERT(it != mRenderTextures.end());
+  if (it == mRenderTextures.end()) {
+    return;
+  }
+
+  RefPtr<RenderTextureHost> texture = it->second;
+  texture->PrepareForUse();
+}
+
+void RenderThread::NotifyNotUsed(uint64_t aExternalImageId) {
+  if (!IsInRenderThread()) {
+    Loop()->PostTask(NewRunnableMethod<uint64_t>(
+        "RenderThread::NotifyNotUsed", this, &RenderThread::NotifyNotUsed,
+        aExternalImageId));
+    return;
+  }
+
+  MutexAutoLock lock(mRenderTextureMapLock);
+  if (mHasShutdown) {
+    return;
+  }
+
+  auto it = mRenderTextures.find(aExternalImageId);
+  MOZ_ASSERT(it != mRenderTextures.end());
+  if (it == mRenderTextures.end()) {
+    return;
+  }
+
+  RefPtr<RenderTextureHost> texture = it->second;
+  texture->NotifyNotUsed();
+}
+
 void RenderThread::UpdateRenderTextureHost(uint64_t aSrcExternalImageId,
                                            uint64_t aWrappedExternalImageId) {
   MOZ_ASSERT(aSrcExternalImageId != aWrappedExternalImageId);
   MOZ_ASSERT(RenderThread::IsInRenderThread());
 
   MutexAutoLock lock(mRenderTextureMapLock);
   if (mHasShutdown) {
     return;
--- a/gfx/webrender_bindings/RenderThread.h
+++ b/gfx/webrender_bindings/RenderThread.h
@@ -182,16 +182,22 @@ class RenderThread final {
 
   /// Can be called from any thread.
   void RegisterExternalImage(uint64_t aExternalImageId,
                              already_AddRefed<RenderTextureHost> aTexture);
 
   /// Can be called from any thread.
   void UnregisterExternalImage(uint64_t aExternalImageId);
 
+  /// Can be called from any thread.
+  void PrepareForUse(uint64_t aExternalImageId);
+
+  /// Can be called from any thread.
+  void NotifyNotUsed(uint64_t aExternalImageId);
+
   /// Can only be called from the render thread.
   void UpdateRenderTextureHost(uint64_t aSrcExternalImageId,
                                uint64_t aWrappedExternalImageId);
 
   /// Can only be called from the render thread.
   void UnregisterExternalImageDuringShutdown(uint64_t aExternalImageId);
 
   /// Can only be called from the render thread.