Bug 875211 - use one global gl texture per texture unit rather than one per GrallocTextureHostOGL. r=bjacob
authorNicolas Silva <nical.bugzilla@gmail.com>
Tue, 04 Jun 2013 20:44:37 +0200
changeset 134305 3c7c31aaea7835029b7a16a12186559a5d834868
parent 134304 4dd83c47500671933d0d0570eeb3a8cf47511ef4
child 134306 5dda8a9a6c2de4c1918f58c8795fabe9511d9a99
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersbjacob
bugs875211
milestone24.0a1
Bug 875211 - use one global gl texture per texture unit rather than one per GrallocTextureHostOGL. r=bjacob
gfx/layers/opengl/CompositorOGL.cpp
gfx/layers/opengl/CompositorOGL.h
gfx/layers/opengl/TextureHostOGL.cpp
gfx/layers/opengl/TextureHostOGL.h
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -227,16 +227,17 @@ int ShaderProgramOGL::sCurrentProgramKey
 
 CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth,
                              int aSurfaceHeight, bool aUseExternalSurfaceSize)
   : mWidget(aWidget)
   , mWidgetSize(-1, -1)
   , mSurfaceSize(aSurfaceWidth, aSurfaceHeight)
   , mHasBGRA(0)
   , mUseExternalSurfaceSize(aUseExternalSurfaceSize)
+  , mTextures({0, 0, 0})
   , mFrameInProgress(false)
   , mDestroyed(false)
 {
   MOZ_COUNT_CTOR(CompositorOGL);
   sBackend = LAYERS_OPENGL;
 }
 
 CompositorOGL::~CompositorOGL()
@@ -274,19 +275,39 @@ CompositorOGL::AddPrograms(ShaderProgram
       mPrograms[aType].mVariations[maskType] = new ShaderProgramOGL(this->gl(),
         ProgramProfileOGL::GetProfileFor(aType, static_cast<MaskType>(maskType)));
     } else {
       mPrograms[aType].mVariations[maskType] = nullptr;
     }
   }
 }
 
+GLuint
+CompositorOGL::GetTemporaryTexture(GLenum aTextureUnit)
+{
+  if (!mTextures[aTextureUnit - LOCAL_GL_TEXTURE0]) {
+    gl()->MakeCurrent();
+    gl()->fGenTextures(1, &mTextures[aTextureUnit - LOCAL_GL_TEXTURE0]);
+  }
+  return mTextures[aTextureUnit - LOCAL_GL_TEXTURE0];
+}
+
 void
 CompositorOGL::Destroy()
 {
+  if (gl()) {
+    gl()->MakeCurrent();
+    gl()->fDeleteTextures(3, mTextures);
+    mTextures[0] = 0;
+    mTextures[1] = 0;
+    mTextures[2] = 0;
+  } else {
+    MOZ_ASSERT(!mTextures[0] && !mTextures[1] && !mTextures[2]);
+  }
+
   if (!mDestroyed) {
     mDestroyed = true;
     CleanupResources();
   }
 }
 
 void
 CompositorOGL::CleanupResources()
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -129,16 +129,23 @@ public:
   }
 
   GLContext* gl() const { return mGLContext; }
   gl::ShaderProgramType GetFBOLayerProgramType() const {
     return mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB ?
            gl::RGBARectLayerProgramType : gl::RGBALayerProgramType;
   }
 
+  /**
+   * The compositor provides with temporary textures for use with direct
+   * textruing like gralloc texture.
+   * Doing so lets us use gralloc the way it has been designed to be used
+   * (see https://wiki.mozilla.org/Platform/GFX/Gralloc)
+   */
+  GLuint GetTemporaryTexture(GLenum aUnit);
 private:
   /** 
    * Context target, nullptr when drawing directly to our swap chain.
    */
   nsRefPtr<gfxContext> mTarget;
 
   /** Widget associated with this compositor */
   nsIWidget *mWidget;
@@ -314,16 +321,19 @@ private:
   /**
    * Records the passed frame timestamp and returns the current estimated FPS.
    */
   double AddFrameAndGetFps(const TimeStamp& timestamp);
 
   bool mDestroyed;
 
   nsAutoPtr<FPSState> mFPS;
+  // Textures used for direct texturing of buffers like gralloc.
+  // The index of the texture in this array must correspond to the texture unit.
+  GLuint mTextures[3];
   static bool sDrawFPS;
   static bool sFrameCounter;
 };
 
 }
 }
 
 #endif /* MOZILLA_GFX_COMPOSITOROGL_H */
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -695,38 +695,39 @@ TextureTargetForAndroidPixelFormat(andro
       // we'll take down the compositor process and thus the phone. This seems
       // like undesirable behaviour. We'd rather have a subtle artifact.
       MOZ_ASSERT(false, "Unknown Android pixel format.");
       return LOCAL_GL_TEXTURE_EXTERNAL;
     }
   }
 }
 
+GrallocTextureHostOGL::GrallocTextureHostOGL()
+: mCompositor(nullptr)
+, mTextureTarget(0)
+, mEGLImage(0)
+{
+}
+
 void GrallocTextureHostOGL::SetCompositor(Compositor* aCompositor)
 {
   CompositorOGL* glCompositor = static_cast<CompositorOGL*>(aCompositor);
-  if (mGL && !glCompositor) {
+  if (mCompositor && !glCompositor) {
     DeleteTextures();
   }
-  mGL = glCompositor ? glCompositor->gl() : nullptr;
+  mCompositor = glCompositor;
 }
 
 void
 GrallocTextureHostOGL::DeleteTextures()
 {
-  if (mGLTexture || mEGLImage) {
-    mGL->MakeCurrent();
-    if (mGLTexture) {
-      mGL->fDeleteTextures(1, &mGLTexture);
-      mGLTexture = 0;
-    }
-    if (mEGLImage) {
-      mGL->DestroyEGLImage(mEGLImage);
-      mEGLImage = 0;
-    }
+  if (mEGLImage) {
+    gl()->MakeCurrent();
+    gl()->DestroyEGLImage(mEGLImage);
+    mEGLImage = 0;
   }
 }
 
 // only used for hacky fix in gecko 23 for bug 862324
 static void
 RegisterTextureHostAtGrallocBufferActor(TextureHost* aTextureHost, const SurfaceDescriptor& aSurfaceDescriptor)
 {
   if (IsSurfaceDescriptorValid(aSurfaceDescriptor)) {
@@ -762,30 +763,53 @@ GrallocTextureHostOGL::SwapTexturesImpl(
   DeleteTextures();
 
   // only done for hacky fix in gecko 23 for bug 862324.
   // Doing this in SetBuffer is not enough, as ImageHostBuffered::SwapTextures can
   // change the value of *mBuffer without calling SetBuffer again.
   RegisterTextureHostAtGrallocBufferActor(this, aImage);
 }
 
+gl::GLContext*
+GrallocTextureHostOGL::gl() const
+{
+  return mCompositor ? mCompositor->gl() : nullptr;
+}
+
 void GrallocTextureHostOGL::BindTexture(GLenum aTextureUnit)
 {
-  MOZ_ASSERT(mGLTexture);
+  /*
+   * The job of this function is to ensure that the texture is tied to the
+   * android::GraphicBuffer, so that texturing will source the GraphicBuffer.
+   *
+   * To this effect we create an EGLImage wrapping this GraphicBuffer,
+   * using CreateEGLImageForNativeBuffer, and then we tie this EGLImage to our
+   * texture using fEGLImageTargetTexture2D.
+   *
+   * We try to avoid re-creating the EGLImage everytime, by keeping it around
+   * as the mEGLImage member of this class.
+   */
+  MOZ_ASSERT(gl());
+  gl()->MakeCurrent();
 
-  mGL->MakeCurrent();
-  mGL->fActiveTexture(aTextureUnit);
-  mGL->fBindTexture(mTextureTarget, mGLTexture);
-  mGL->fActiveTexture(LOCAL_GL_TEXTURE0);
+  GLuint tex = mCompositor->GetTemporaryTexture(aTextureUnit);
+
+  gl()->fActiveTexture(aTextureUnit);
+  gl()->fBindTexture(mTextureTarget, tex);
+  if (!mEGLImage) {
+    mEGLImage = gl()->CreateEGLImageForNativeBuffer(mGraphicBuffer->getNativeBuffer());
+  }
+  gl()->fEGLImageTargetTexture2D(mTextureTarget, mEGLImage);
+  gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
 }
 
 bool
 GrallocTextureHostOGL::IsValid() const
 {
-  return !!mGL && !!mGraphicBuffer.get();
+  return !!gl() && !!mGraphicBuffer.get();
 }
 
 GrallocTextureHostOGL::~GrallocTextureHostOGL()
 {
   DeleteTextures();
 
   // only done for hacky fix in gecko 23 for bug 862324.
   if (mBuffer) {
@@ -793,75 +817,24 @@ GrallocTextureHostOGL::~GrallocTextureHo
     // pointer to us.
     RegisterTextureHostAtGrallocBufferActor(nullptr, *mBuffer);
   }
 }
 
 bool
 GrallocTextureHostOGL::Lock()
 {
-  if (!IsValid()) {
-    return false;
-  }
-  /*
-   * The job of this function is to ensure that the texture is tied to the
-   * android::GraphicBuffer, so that texturing will source the GraphicBuffer.
-   *
-   * To this effect we create an EGLImage wrapping this GraphicBuffer,
-   * using CreateEGLImageForNativeBuffer, and then we tie this EGLImage to our
-   * texture using fEGLImageTargetTexture2D.
-   *
-   * We try to avoid re-creating the EGLImage everytime, by keeping it around
-   * as the mEGLImage member of this class.
-   */
-  MOZ_ASSERT(mGraphicBuffer.get());
-
-  mGL->MakeCurrent();
-
-  if (!mGLTexture) {
-    mGL->fGenTextures(1, &mGLTexture);
-  }
-  mGL->fActiveTexture(LOCAL_GL_TEXTURE0);
-  mGL->fBindTexture(mTextureTarget, mGLTexture);
-  if (!mEGLImage) {
-    mEGLImage = mGL->CreateEGLImageForNativeBuffer(mGraphicBuffer->getNativeBuffer());
-  }
-  mGL->fEGLImageTargetTexture2D(mTextureTarget, mEGLImage);
-  return true;
+  // Lock/Unlock is done internally when binding the gralloc buffer to a gl texture
+  return IsValid();
 }
 
 void
 GrallocTextureHostOGL::Unlock()
 {
-  /*
-   * The job of this function is to ensure that we release any read lock placed on
-   * our android::GraphicBuffer by any drawing code that sourced it via this TextureHost.
-   *
-   * Indeed, as soon as we draw with a texture that's tied to a android::GraphicBuffer,
-   * the GL may place read locks on it. We must ensure that we release them early enough,
-   * i.e. before the next time that we will try to acquire a write lock on the same buffer,
-   * because read and write locks on gralloc buffers are mutually exclusive.
-   */
-  if (mGL->Renderer() == GLContext::RendererAdrenoTM205) {
-    /* XXX This is working around a driver bug exhibited on at least the
-     * Geeksphone Peak, where retargeting to a different EGL image is very
-     * slow. See Bug 869696.
-     */
-    if (mGLTexture) {
-      mGL->MakeCurrent();
-      mGL->fDeleteTextures(1, &mGLTexture);
-      mGLTexture = 0;
-    }
-    return;
-  }
-
-  mGL->MakeCurrent();
-  mGL->fActiveTexture(LOCAL_GL_TEXTURE0);
-  mGL->fBindTexture(mTextureTarget, mGLTexture);
-  mGL->fEGLImageTargetTexture2D(mTextureTarget, mGL->GetNullEGLImage());
+  // Lock/Unlock is done internally when binding the gralloc buffer to a gl texture
 }
 
 gfx::SurfaceFormat
 GrallocTextureHostOGL::GetFormat() const
 {
   return mFormat;
 }
 
@@ -872,17 +845,17 @@ GrallocTextureHostOGL::SetBuffer(Surface
   mBuffer = aBuffer;
   mDeAllocator = aAllocator;
 
   // only done for hacky fix in gecko 23 for bug 862324.
   // Doing this in SwapTextures is not enough, as the crash could occur right after SetBuffer.
   RegisterTextureHostAtGrallocBufferActor(this, *mBuffer);
 }
 
-#endif
+#endif // MOZ_WIDGET_GONK
 
 already_AddRefed<gfxImageSurface>
 TextureImageTextureHostOGL::GetAsSurface() {
   nsRefPtr<gfxImageSurface> surf = IsValid() ?
     mGL->GetTexImage(mTexture->GetTextureID(),
                      false,
                      mTexture->GetShaderProgramType())
     : nullptr;
@@ -927,19 +900,29 @@ TiledTextureHostOGL::GetAsSurface() {
                      GetShaderProgram())
     : nullptr;
   return surf.forget();
 }
 
 #ifdef MOZ_WIDGET_GONK
 already_AddRefed<gfxImageSurface>
 GrallocTextureHostOGL::GetAsSurface() {
-  nsRefPtr<gfxImageSurface> surf = IsValid() && mGLTexture ?
-    mGL->GetTexImage(mGLTexture,
-                     false,
-                     GetShaderProgram())
+  gl()->MakeCurrent();
+
+  GLuint tex = mCompositor->GetTemporaryTexture(LOCAL_GL_TEXTURE0);
+  gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
+  gl()->fBindTexture(mTextureTarget, tex);
+  if (!mEGLImage) {
+    mEGLImage = gl()->CreateEGLImageForNativeBuffer(mGraphicBuffer->getNativeBuffer());
+  }
+  gl()->fEGLImageTargetTexture2D(mTextureTarget, mEGLImage);
+
+  nsRefPtr<gfxImageSurface> surf = IsValid() ?
+    gl()->GetTexImage(tex,
+                      false,
+                      GetShaderProgram())
     : nullptr;
   return surf.forget();
 }
 #endif
 
 } // namespace
 } // namespace
--- a/gfx/layers/opengl/TextureHostOGL.h
+++ b/gfx/layers/opengl/TextureHostOGL.h
@@ -16,16 +16,17 @@
 #ifdef MOZ_WIDGET_GONK
 #include <ui/GraphicBuffer.h>
 #endif
 
 namespace mozilla {
 namespace layers {
 
 class TextureImageTextureHostOGL;
+class CompositorOGL;
 
 /*
  * TextureHost implementations for the OpenGL backend.
  *
  * Note that it is important to becareful about the ownership model with
  * the OpenGL backend, due to some widget limitation on Linux: before
  * the nsBaseWidget associated with our OpenGL context has been completely
  * deleted, every resource belonging to the OpenGL context MUST have been
@@ -563,33 +564,22 @@ private:
 // which automatically gets gralloc when it can, in which case the compositor sees that the
 // SurfaceDescriptor is gralloc, and decides to use a GrallocTextureHostOGL to do direct texturing,
 // saving the cost of a texture upload.
 class GrallocTextureHostOGL
   : public TextureHost
   , public TextureSourceOGL
 {
 public:
-  GrallocTextureHostOGL()
-    : mGL(nullptr)
-    , mTextureTarget(0)
-    , mGLTexture(0)
-    , mEGLImage(0)
-  {
-  }
+  GrallocTextureHostOGL();
 
   ~GrallocTextureHostOGL();
 
   virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
 
-  virtual GLuint GetTextureHandle()
-  {
-    return mGLTexture;
-  }
-
   virtual void UpdateImpl(const SurfaceDescriptor& aImage,
                           nsIntRegion* aRegion = nullptr,
                           nsIntPoint* aOffset = nullptr) MOZ_OVERRIDE;
   virtual void SwapTexturesImpl(const SurfaceDescriptor& aImage,
                           nsIntRegion* aRegion = nullptr) MOZ_OVERRIDE;
   virtual bool Lock() MOZ_OVERRIDE;
   virtual void Unlock() MOZ_OVERRIDE;
 
@@ -647,22 +637,23 @@ public:
       mBuffer = nullptr;
     }
 
     mGraphicBuffer = nullptr;
     DeleteTextures();
   }
 
 private:
+  gl::GLContext* gl() const;
+
   void DeleteTextures();
 
-  RefPtr<gl::GLContext> mGL;
+  RefPtr<CompositorOGL> mCompositor;
   android::sp<android::GraphicBuffer> mGraphicBuffer;
   GLenum mTextureTarget;
-  GLuint mGLTexture;
   EGLImage mEGLImage;
 };
 #endif
 
 } // namespace
 } // namespace
 
 #endif /* MOZILLA_GFX_TEXTUREOGL_H */