Bug 1265824 - Add a new texture source type "DirectMapTextureSource" r=mattwoodrow
authorDoug Thayer <dothayer@mozilla.com>
Wed, 02 May 2018 18:20:10 -0700
changeset 427957 cf95b1f62eae89e0988f750b6a56871c79067d15
parent 427956 3b0192c401cf32dbbf25d36f2bbbec0e0b392562
child 427958 1fe8be31198a89812f1a1108359ddd75d8af1a78
push id34322
push userrgurzau@mozilla.com
push dateTue, 24 Jul 2018 15:47:07 +0000
treeherdermozilla-central@db9d47b49936 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1265824
milestone63.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 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,