Bug 1265824 - Add a new texture source type "DirectMapTextureSource" r?mattwoodrow draft
authorDoug Thayer <dothayer@mozilla.com>
Wed, 02 May 2018 18:20:10 -0700
changeset 816207 518709ad59c3e71e47fbbae9010b4a8fae6829d0
parent 816206 d27f05c9cf4a3dc2704ca1c300774e7697e543ca
child 816208 f5245fe9246daab68f433ec38f741187d7c12ee9
push id115776
push userbmo:dothayer@mozilla.com
push dateTue, 10 Jul 2018 18:33:51 +0000
reviewersmattwoodrow
bugs1265824
milestone63.0a1
Bug 1265824 - Add a new texture source type "DirectMapTextureSource" r?mattwoodrow The DirectMapTextureSource could let the compositor to read the buffer directly. That could get rid of some memory copy operations during texture uploading. MozReview-Commit-ID: CHhoR96P7VG
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextSymbols.h
gfx/layers/composite/TextureHost.h
gfx/layers/opengl/TextureHostOGL.cpp
gfx/layers/opengl/TextureHostOGL.h
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -76,16 +76,17 @@ static const char* const sExtensionNames
     "GL_ANGLE_depth_texture",
     "GL_ANGLE_framebuffer_blit",
     "GL_ANGLE_framebuffer_multisample",
     "GL_ANGLE_instanced_arrays",
     "GL_ANGLE_texture_compression_dxt3",
     "GL_ANGLE_texture_compression_dxt5",
     "GL_ANGLE_timer_query",
     "GL_APPLE_client_storage",
+    "GL_APPLE_fence",
     "GL_APPLE_framebuffer_multisample",
     "GL_APPLE_sync",
     "GL_APPLE_texture_range",
     "GL_APPLE_vertex_array_object",
     "GL_ARB_ES2_compatibility",
     "GL_ARB_ES3_compatibility",
     "GL_ARB_color_buffer_float",
     "GL_ARB_compatibility",
@@ -1075,16 +1076,25 @@ GLContext::LoadMoreSymbols(const char* p
     if (IsExtensionSupported(APPLE_texture_range)) {
         const SymLoadStruct symbols[] = {
             { (PRFuncPtr*) &mSymbols.fTextureRangeAPPLE, { "TextureRangeAPPLE", nullptr } },
             END_SYMBOLS
         };
         fnLoadForExt(symbols, APPLE_texture_range);
     }
 
+    if (IsExtensionSupported(APPLE_fence)) {
+        const SymLoadStruct symbols[] = {
+            { (PRFuncPtr*) &mSymbols.fFinishObjectAPPLE, { "FinishObjectAPPLE", nullptr } },
+            { (PRFuncPtr*) &mSymbols.fTestObjectAPPLE, { "TestObjectAPPLE", nullptr } },
+            END_SYMBOLS
+        };
+        fnLoadForExt(symbols, APPLE_fence);
+    }
+
     if (IsSupported(GLFeature::vertex_array_object)) {
         const SymLoadStruct coreSymbols[] = {
             { (PRFuncPtr*) &mSymbols.fIsVertexArray, { "IsVertexArray", nullptr } },
             { (PRFuncPtr*) &mSymbols.fGenVertexArrays, { "GenVertexArrays", nullptr } },
             { (PRFuncPtr*) &mSymbols.fBindVertexArray, { "BindVertexArray", nullptr } },
             { (PRFuncPtr*) &mSymbols.fDeleteVertexArrays, { "DeleteVertexArrays", nullptr } },
             END_SYMBOLS
         };
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -375,16 +375,17 @@ public:
         ANGLE_depth_texture,
         ANGLE_framebuffer_blit,
         ANGLE_framebuffer_multisample,
         ANGLE_instanced_arrays,
         ANGLE_texture_compression_dxt3,
         ANGLE_texture_compression_dxt5,
         ANGLE_timer_query,
         APPLE_client_storage,
+        APPLE_fence,
         APPLE_framebuffer_multisample,
         APPLE_sync,
         APPLE_texture_range,
         APPLE_vertex_array_object,
         ARB_ES2_compatibility,
         ARB_ES3_compatibility,
         ARB_color_buffer_float,
         ARB_compatibility,
@@ -3298,16 +3299,35 @@ public:
     void fResolveMultisampleFramebufferAPPLE() {
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fResolveMultisampleFramebufferAPPLE);
         mSymbols.fResolveMultisampleFramebufferAPPLE();
         AFTER_GL_CALL;
     }
 
 // -----------------------------------------------------------------------------
+// APPLE_fence
+
+    void fFinishObjectAPPLE(GLenum object, GLint name) {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fFinishObjectAPPLE);
+        mSymbols.fFinishObjectAPPLE(object, name);
+        AFTER_GL_CALL;
+    }
+
+    realGLboolean fTestObjectAPPLE(GLenum object, GLint name) {
+        realGLboolean ret = false;
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fTestObjectAPPLE);
+        ret = mSymbols.fTestObjectAPPLE(object, name);
+        AFTER_GL_CALL;
+        return ret;
+    }
+
+// -----------------------------------------------------------------------------
 // prim_restart
 
     void fPrimitiveRestartIndex(GLuint index) {
         BEFORE_GL_CALL;
         ASSERT_SYMBOL_PRESENT(fPrimitiveRestartIndex);
         mSymbols.fPrimitiveRestartIndex(index);
         AFTER_GL_CALL;
     }
--- a/gfx/gl/GLContextSymbols.h
+++ b/gfx/gl/GLContextSymbols.h
@@ -132,16 +132,18 @@ struct GLContextSymbols final
     void (GLAPIENTRY * fStencilMaskSeparate)(GLenum, GLuint);
     void (GLAPIENTRY * fStencilOp)(GLenum, GLenum, GLenum);
     void (GLAPIENTRY * fStencilOpSeparate)(GLenum, GLenum, GLenum, GLenum);
     void (GLAPIENTRY * fTexImage2D)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint,
                                     GLenum, GLenum, const GLvoid*);
     void (GLAPIENTRY * fTexSubImage2D)(GLenum, GLint, GLint, GLint, GLsizei,
                                         GLsizei, GLenum, GLenum, const void*);
     void (GLAPIENTRY * fTextureRangeAPPLE)(GLenum, GLsizei, GLvoid*);
+    void (GLAPIENTRY * fFinishObjectAPPLE)(GLenum, GLint);
+    realGLboolean (GLAPIENTRY * fTestObjectAPPLE)(GLenum, GLint);
     void (GLAPIENTRY * fUniform1f)(GLint, GLfloat);
     void (GLAPIENTRY * fUniform1fv)(GLint, GLsizei, const GLfloat*);
     void (GLAPIENTRY * fUniform1i)(GLint, GLint);
     void (GLAPIENTRY * fUniform1iv)(GLint, GLsizei, const GLint*);
     void (GLAPIENTRY * fUniform2f)(GLint, GLfloat, GLfloat);
     void (GLAPIENTRY * fUniform2fv)(GLint, GLsizei, const GLfloat*);
     void (GLAPIENTRY * fUniform2i)(GLint, GLint, GLint);
     void (GLAPIENTRY * fUniform2iv)(GLint, GLsizei, const GLint*);
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -178,16 +178,24 @@ public:
   // individual tiles.
   virtual RefPtr<TextureSource> ExtractCurrentTile() {
     NS_WARNING("Implementation does not expose tile sources");
     return nullptr;
   }
 
   int NumCompositableRefs() const { return mCompositableCount; }
 
+  // Some texture sources could wrap the cpu buffer to gpu directly. Then,
+  // we could get better performance of texture uploading.
+  virtual bool IsDirectMap() { return false; }
+  // The direct-map cpu buffer should be alive when gpu uses it. And it
+  // should not be updated while gpu reads it. This Sync() function
+  // implements this synchronized behavior.
+  virtual void Sync() { }
+
 protected:
 
   RefPtr<TextureSource> mNextSibling;
   int mCompositableCount;
 };
 
 /// Equivalent of a RefPtr<TextureSource>, that calls AddCompositableRef and
 /// ReleaseCompositableRef in addition to the usual AddRef and Release.
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -305,16 +305,103 @@ GLTextureSource::SetTextureSourceProvide
 
 bool
 GLTextureSource::IsValid() const
 {
   return !!gl() && mTextureHandle != 0;
 }
 
 ////////////////////////////////////////////////////////////////////////
+// DirectMapTextureSource
+
+DirectMapTextureSource::DirectMapTextureSource(TextureSourceProvider* aProvider,
+                                               gfx::DataSourceSurface* aSurface)
+  : GLTextureSource(aProvider,
+                    0,
+                    LOCAL_GL_TEXTURE_2D,
+                    aSurface->GetSize(),
+                    aSurface->GetFormat())
+{
+  MOZ_ASSERT(aSurface);
+
+  UpdateInternal(aSurface, nullptr, nullptr, true);
+}
+
+bool
+DirectMapTextureSource::Update(gfx::DataSourceSurface* aSurface,
+                               nsIntRegion* aDestRegion,
+                               gfx::IntPoint* aSrcOffset)
+{
+  if (!aSurface) {
+    return false;
+  }
+
+  return UpdateInternal(aSurface, aDestRegion, aSrcOffset, false);
+}
+
+void
+DirectMapTextureSource::Sync()
+{
+  gl()->MakeCurrent();
+  if (!gl()->IsDestroyed()) {
+    gl()->fFinishObjectAPPLE(LOCAL_GL_TEXTURE, mTextureHandle);
+  }
+}
+
+bool
+DirectMapTextureSource::UpdateInternal(gfx::DataSourceSurface* aSurface,
+                                       nsIntRegion* aDestRegion,
+                                       gfx::IntPoint* aSrcOffset,
+                                       bool aInit)
+{
+  gl()->MakeCurrent();
+
+  if (aInit) {
+    gl()->fGenTextures(1, &mTextureHandle);
+    gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, mTextureHandle);
+
+    gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D,
+                         LOCAL_GL_TEXTURE_STORAGE_HINT_APPLE,
+                         LOCAL_GL_STORAGE_CACHED_APPLE);
+
+    gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D,
+                         LOCAL_GL_TEXTURE_WRAP_S,
+                         LOCAL_GL_CLAMP_TO_EDGE);
+    gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D,
+                         LOCAL_GL_TEXTURE_WRAP_T,
+                         LOCAL_GL_CLAMP_TO_EDGE);
+  }
+
+  MOZ_ASSERT(mTextureHandle);
+
+  // APPLE_client_storage
+  gl()->fPixelStorei(LOCAL_GL_UNPACK_CLIENT_STORAGE_APPLE, LOCAL_GL_TRUE);
+
+  nsIntRegion destRegion = aDestRegion ? *aDestRegion
+                                       : IntRect(0, 0,
+                                                 aSurface->GetSize().width,
+                                                 aSurface->GetSize().height);
+  gfx::IntPoint srcPoint = aSrcOffset ? *aSrcOffset
+                                      : gfx::IntPoint(0, 0);
+  mFormat = gl::UploadSurfaceToTexture(gl(),
+                                       aSurface,
+                                       destRegion,
+                                       mTextureHandle,
+                                       aSurface->GetSize(),
+                                       nullptr,
+                                       aInit,
+                                       srcPoint,
+                                       LOCAL_GL_TEXTURE0,
+                                       LOCAL_GL_TEXTURE_2D);
+
+  gl()->fPixelStorei(LOCAL_GL_UNPACK_CLIENT_STORAGE_APPLE, LOCAL_GL_FALSE);
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////
 // SurfaceTextureHost
 
 #ifdef MOZ_WIDGET_ANDROID
 
 SurfaceTextureSource::SurfaceTextureSource(TextureSourceProvider* aProvider,
                                            mozilla::java::GeckoSurfaceTexture::Ref& aSurfTex,
                                            gfx::SurfaceFormat aFormat,
--- a/gfx/layers/opengl/TextureHostOGL.h
+++ b/gfx/layers/opengl/TextureHostOGL.h
@@ -219,27 +219,27 @@ protected:
 /**
  * A texture source for GL textures.
  *
  * It does not own any GL texture, and attaches its shared handle to one of
  * the compositor's temporary textures when binding.
  *
  * The shared texture handle is owned by the TextureHost.
  */
-class GLTextureSource : public TextureSource
+class GLTextureSource : public DataTextureSource
                       , public TextureSourceOGL
 {
 public:
   GLTextureSource(TextureSourceProvider* aProvider,
                   GLuint aTextureHandle,
                   GLenum aTarget,
                   gfx::IntSize aSize,
                   gfx::SurfaceFormat aFormat);
 
-  ~GLTextureSource();
+  virtual ~GLTextureSource();
 
   virtual const char* Name() const override { return "GLTextureSource"; }
 
   virtual GLTextureSource* AsGLTextureSource() override { return this; }
 
   virtual TextureSourceOGL* AsSourceOGL() override { return this; }
 
   virtual void BindTexture(GLenum activetex,
@@ -264,27 +264,61 @@ public:
   void SetFormat(gfx::SurfaceFormat aFormat) { mFormat = aFormat; }
 
   GLuint GetTextureHandle() const { return mTextureHandle; }
 
   gl::GLContext* gl() const {
     return mGL;
   }
 
+  virtual bool Update(gfx::DataSourceSurface* aSurface,
+                      nsIntRegion* aDestRegion = nullptr,
+                      gfx::IntPoint* aSrcOffset = nullptr) override
+  {
+    return false;
+  }
+
 protected:
   void DeleteTextureHandle();
 
   RefPtr<gl::GLContext> mGL;
   RefPtr<CompositorOGL> mCompositor;
   GLuint mTextureHandle;
   GLenum mTextureTarget;
   gfx::IntSize mSize;
   gfx::SurfaceFormat mFormat;
 };
 
+// This texture source try to wrap "aSurface" in ctor for compositor direct
+// access. Since we can't know the timing for gpu buffer access, the surface
+// should be alive until the ~ClientStorageTextureSource(). And if we try to
+// update the surface we mapped before, we need to call Sync() to make sure
+// the surface is not used by compositor.
+class DirectMapTextureSource : public GLTextureSource
+{
+public:
+  DirectMapTextureSource(TextureSourceProvider* aProvider,
+                         gfx::DataSourceSurface* aSurface);
+
+  virtual bool Update(gfx::DataSourceSurface* aSurface,
+                      nsIntRegion* aDestRegion = nullptr,
+                      gfx::IntPoint* aSrcOffset = nullptr) override;
+
+  virtual bool IsDirectMap() override { return true; }
+
+  // Wait until this texture source is not used by the compositor.
+  virtual void Sync() override;
+
+private:
+  bool UpdateInternal(gfx::DataSourceSurface* aSurface,
+                      nsIntRegion* aDestRegion,
+                      gfx::IntPoint* aSrcOffset,
+                      bool aInit);
+};
+
 class GLTextureHost : public TextureHost
 {
 public:
   GLTextureHost(TextureFlags aFlags,
                 GLuint aTextureHandle,
                 GLenum aTarget,
                 GLsync aSync,
                 gfx::IntSize aSize,