Bug 1073036. layers: Track program state more carefully to avoid setting unnecessarily. r=nical
authorJeff Muizelaar <jmuizelaar@mozilla.com>
Mon, 10 Nov 2014 14:34:06 -0500
changeset 216297 5140b218e6cccd5c1e2047e9b6c855b05fd19a28
parent 216296 3c31429a668f672ae4e966d64cb1664475b89556
child 216298 2f6e437218565bed30b659b1f50a40cb5b136cf5
push id27845
push userkwierso@gmail.com
push dateWed, 19 Nov 2014 02:08:01 +0000
treeherdermozilla-central@64e7a6391916 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1073036
milestone36.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 1073036. layers: Track program state more carefully to avoid setting unnecessarily. r=nical This introduces some infrastructure to start tracking the program state more carefully. Currently it only tracks the program because UseProgram was showing up the most in profiles, but more state could also be added as needed.
gfx/layers/opengl/CompositorOGL.cpp
gfx/layers/opengl/CompositorOGL.h
gfx/layers/opengl/GLBlitTextureImageHelper.cpp
gfx/layers/opengl/GLManager.cpp
gfx/layers/opengl/GLManager.h
gfx/layers/opengl/OGLShaderProgram.cpp
gfx/layers/opengl/OGLShaderProgram.h
widget/android/nsWindow.cpp
widget/cocoa/nsChildView.mm
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -82,16 +82,17 @@ CompositorOGL::CompositorOGL(nsIWidget *
   : mWidget(aWidget)
   , mWidgetSize(-1, -1)
   , mSurfaceSize(aSurfaceWidth, aSurfaceHeight)
   , mHasBGRA(0)
   , mUseExternalSurfaceSize(aUseExternalSurfaceSize)
   , mFrameInProgress(false)
   , mDestroyed(false)
   , mHeight(0)
+  , mCurrentProgram(nullptr)
 {
   MOZ_COUNT_CTOR(CompositorOGL);
   SetBackend(LayersBackend::LAYERS_OPENGL);
 }
 
 CompositorOGL::~CompositorOGL()
 {
   MOZ_COUNT_DTOR(CompositorOGL);
@@ -810,16 +811,33 @@ CompositorOGL::GetShaderProgramFor(const
     delete shader;
     return nullptr;
   }
 
   mPrograms[aConfig] = shader;
   return shader;
 }
 
+void
+CompositorOGL::ActivateProgram(ShaderProgramOGL* aProg)
+{
+  if (mCurrentProgram != aProg) {
+    gl()->fUseProgram(aProg->GetProgram());
+    mCurrentProgram = aProg;
+  }
+}
+
+void
+CompositorOGL::ResetProgram()
+{
+  mCurrentProgram = nullptr;
+}
+
+
+
 static bool SetBlendMode(GLContext* aGL, gfx::CompositionOp aBlendMode, bool aIsPremultiplied = true)
 {
   if (aBlendMode == gfx::CompositionOp::OP_OVER && aIsPremultiplied) {
     return false;
   }
 
   GLenum srcBlend;
   GLenum dstBlend;
@@ -952,17 +970,17 @@ CompositorOGL::DrawQuad(const Rect& aRec
       static_cast<EffectBlendMode*>(aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE].get());
     blendMode = blendEffect->mBlendMode;
   }
 
   bool colorMatrix = aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX];
   ShaderConfigOGL config = GetShaderConfigFor(aEffectChain.mPrimaryEffect, maskType, blendMode, colorMatrix);
   config.SetOpacity(aOpacity != 1.f);
   ShaderProgramOGL *program = GetShaderProgramFor(config);
-  program->Activate();
+  ActivateProgram(program);
   program->SetProjectionMatrix(mProjMatrix);
   program->SetLayerTransform(aTransform);
 
   if (colorMatrix) {
       EffectColorMatrix* effectColorMatrix =
         static_cast<EffectColorMatrix*>(aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX].get());
       program->SetColorMatrix(effectColorMatrix->mColorMatrix);
   }
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -250,16 +250,21 @@ public:
   }
 
   virtual void Pause() MOZ_OVERRIDE;
   virtual bool Resume() MOZ_OVERRIDE;
 
   virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
 
   GLContext* gl() const { return mGLContext; }
+  /**
+   * Clear the program state. This must be called
+   * before operating on the GLContext directly. */
+  void ResetProgram();
+
   gfx::SurfaceFormat GetFBOFormat() const {
     return gfx::SurfaceFormat::R8G8B8A8;
   }
 
   GLBlitTextureImageHelper* BlitTextureImageHelper();
 
   /**
    * The compositor provides with temporary textures for use with direct
@@ -365,16 +370,17 @@ private:
     textureRects[0] = aTextureRect;
     BindAndDrawQuads(aProg, 1, layerRects, textureRects);
   }
   void BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
                                       const gfx::Rect& aRect,
                                       const gfx::Rect& aTexCoordRect,
                                       TextureSource *aTexture);
 
+  void ActivateProgram(ShaderProgramOGL *aProg);
   void CleanupResources();
 
   /**
    * Copies the content of our backbuffer to the set transaction target.
    * Does not restore the target FBO, so only call from EndFrame.
    */
   void CopyToTarget(gfx::DrawTarget* aTarget, const nsIntPoint& aTopLeft, const gfx::Matrix& aWorldMatrix);
 
@@ -397,14 +403,15 @@ private:
 
   /**
    * Height of the OpenGL context's primary framebuffer in pixels. Used by
    * FlipY for the y-flipping calculation.
    */
   GLint mHeight;
 
   FenceHandle mReleaseFenceHandle;
+  ShaderProgramOGL *mCurrentProgram;
 };
 
 }
 }
 
 #endif /* MOZILLA_GFX_COMPOSITOROGL_H */
--- a/gfx/layers/opengl/GLBlitTextureImageHelper.cpp
+++ b/gfx/layers/opengl/GLBlitTextureImageHelper.cpp
@@ -192,16 +192,20 @@ GLBlitTextureImageHelper::SetBlitFramebu
         // size via a call to TexImage2D.
         NS_RUNTIMEABORT(msg.get());
     }
 }
 
 void
 GLBlitTextureImageHelper::UseBlitProgram()
 {
+    // XXX: GLBlitTextureImageHelper doesn't use ShaderProgramOGL
+    // so we need to Reset the program
+    mCompositor->ResetProgram();
+
     GLContext *gl = mCompositor->gl();
     if (mBlitProgram) {
         gl->fUseProgram(mBlitProgram);
         return;
     }
 
     mBlitProgram = gl->fCreateProgram();
 
--- a/gfx/layers/opengl/GLManager.cpp
+++ b/gfx/layers/opengl/GLManager.cpp
@@ -27,16 +27,21 @@ public:
     : mImpl(aCompositor)
   {}
 
   virtual GLContext* gl() const MOZ_OVERRIDE
   {
     return mImpl->gl();
   }
 
+  virtual void ActivateProgram(ShaderProgramOGL *aProg) MOZ_OVERRIDE
+  {
+    mImpl->ActivateProgram(aProg);
+  }
+
   virtual ShaderProgramOGL* GetProgram(GLenum aTarget, gfx::SurfaceFormat aFormat) MOZ_OVERRIDE
   {
     ShaderConfigOGL config = ShaderConfigFromTargetAndFormat(aTarget, aFormat);
     return mImpl->GetShaderProgramFor(config);
   }
 
   virtual const gfx::Matrix4x4& GetProjMatrix() const MOZ_OVERRIDE
   {
--- a/gfx/layers/opengl/GLManager.h
+++ b/gfx/layers/opengl/GLManager.h
@@ -27,16 +27,17 @@ class GLManager
 {
 public:
   static GLManager* CreateGLManager(LayerManagerComposite* aManager);
 
   virtual ~GLManager() {}
 
   virtual gl::GLContext* gl() const = 0;
   virtual ShaderProgramOGL* GetProgram(GLenum aTarget, gfx::SurfaceFormat aFormat) = 0;
+  virtual void ActivateProgram(ShaderProgramOGL* aPrg) = 0;
   virtual const gfx::Matrix4x4& GetProjMatrix() const = 0;
   virtual void BindAndDrawQuad(ShaderProgramOGL *aProg, const gfx::Rect& aLayerRect,
                                const gfx::Rect& aTextureRect) = 0;
 };
 
 }
 }
 #endif
--- a/gfx/layers/opengl/OGLShaderProgram.cpp
+++ b/gfx/layers/opengl/OGLShaderProgram.cpp
@@ -535,27 +535,26 @@ ShaderProgramOGL::CreateProgram(const ch
     mGL->fDeleteProgram(result);
     return false;
   }
 
   mProgram = result;
   return true;
 }
 
-void
-ShaderProgramOGL::Activate()
+GLuint
+ShaderProgramOGL::GetProgram()
 {
   if (mProgramState == STATE_NEW) {
     if (!Initialize()) {
       NS_WARNING("Shader could not be initialised");
-      return;
     }
   }
-  NS_ASSERTION(HasInitialized(), "Attempting to activate a program that's not in use!");
-  mGL->fUseProgram(mProgram);
+  MOZ_ASSERT(HasInitialized(), "Attempting to activate a program that's not in use!");
+  return mProgram;
 }
 
 void
 ShaderProgramOGL::SetBlurRadius(float aRX, float aRY)
 {
   float f[] = {aRX, aRY};
   SetUniform(KnownUniform::BlurRadius, 2, f);
 
--- a/gfx/layers/opengl/OGLShaderProgram.h
+++ b/gfx/layers/opengl/OGLShaderProgram.h
@@ -252,17 +252,17 @@ struct ProgramProfileOGL
 
 
 #if defined(DEBUG)
 #define CHECK_CURRENT_PROGRAM 1
 #define ASSERT_THIS_PROGRAM                                             \
   do {                                                                  \
     GLuint currentProgram;                                              \
     mGL->GetUIntegerv(LOCAL_GL_CURRENT_PROGRAM, &currentProgram);       \
-    NS_ASSERTION(currentProgram == mProgram,                            \
+    MOZ_ASSERT(currentProgram == mProgram,                              \
                  "SetUniform with wrong program active!");              \
   } while (0)
 #else
 #define ASSERT_THIS_PROGRAM                                             \
   do { } while (0)
 #endif
 
 /**
@@ -278,17 +278,17 @@ public:
 
   ~ShaderProgramOGL();
 
   bool HasInitialized() {
     NS_ASSERTION(mProgramState != STATE_OK || mProgram > 0, "Inconsistent program state");
     return mProgramState == STATE_OK;
   }
 
-  void Activate();
+  GLuint GetProgram();
 
   bool Initialize();
 
   GLint CreateShader(GLenum aShaderType, const char *aShaderSource);
 
   /**
    * Creates a program and stores its id.
    */
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -2364,17 +2364,19 @@ nsWindow::DrawWindowUnderlay(LayerManage
         return;
     }
 
     mLayerRendererFrame.Init(env, frameObj);
     if (!WidgetPaintsBackground()) {
         return;
     }
 
-    gl::GLContext* gl = static_cast<CompositorOGL*>(aManager->GetCompositor())->gl();
+    CompositorOGL *compositor = static_cast<CompositorOGL*>(aManager->GetCompositor());
+    compositor->ResetProgram();
+    gl::GLContext* gl = compositor->gl();
     bool scissorEnabled = gl->fIsEnabled(LOCAL_GL_SCISSOR_TEST);
     GLint scissorRect[4];
     gl->fGetIntegerv(LOCAL_GL_SCISSOR_BOX, scissorRect);
 
     client->ActivateProgram();
     if (!mLayerRendererFrame.BeginDrawing(&jniFrame)) return;
     if (!mLayerRendererFrame.DrawBackground(&jniFrame)) return;
     client->DeactivateProgramAndRestoreState(scissorEnabled,
@@ -2393,17 +2395,19 @@ nsWindow::DrawWindowOverlay(LayerManager
 
     if (mLayerRendererFrame.isNull()) {
         NS_WARNING("Warning: do not have a LayerRenderer frame; aborting window overlay draw");
         return;
     }
 
     mozilla::widget::android::GeckoLayerClient* client = AndroidBridge::Bridge()->GetLayerClient();
 
-    gl::GLContext* gl = static_cast<CompositorOGL*>(aManager->GetCompositor())->gl();
+    CompositorOGL *compositor = static_cast<CompositorOGL*>(aManager->GetCompositor());
+    compositor->ResetProgram();
+    gl::GLContext* gl = compositor->gl();
     bool scissorEnabled = gl->fIsEnabled(LOCAL_GL_SCISSOR_TEST);
     GLint scissorRect[4];
     gl->fGetIntegerv(LOCAL_GL_SCISSOR_BOX, scissorRect);
 
     client->ActivateProgram();
     if (!mLayerRendererFrame.DrawForeground(&jniFrame)) return;
     if (!mLayerRendererFrame.EndDrawing(&jniFrame)) return;
     client->DeactivateProgramAndRestoreState(scissorEnabled,
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -370,16 +370,20 @@ public:
     MOZ_ASSERT(aTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB);
     MOZ_ASSERT(aFormat == gfx::SurfaceFormat::R8G8B8A8);
     return mRGBARectProgram;
   }
   virtual const gfx::Matrix4x4& GetProjMatrix() const MOZ_OVERRIDE
   {
     return mProjMatrix;
   }
+  virtual void ActivateProgram(ShaderProgramOGL *aProg) MOZ_OVERRIDE
+  {
+    mGLContext->fUseProgram(aProg->GetProgram());
+  }
   virtual void BindAndDrawQuad(ShaderProgramOGL *aProg,
                                const gfx::Rect& aLayerRect,
                                const gfx::Rect& aTextureRect) MOZ_OVERRIDE;
 
   void BeginFrame(nsIntSize aRenderSize);
   void EndFrame();
 
   NSOpenGLContext* GetNSOpenGLContext()
@@ -2951,17 +2955,17 @@ RectTextureImage::Draw(GLManager* aManag
                        const nsIntPoint& aLocation,
                        const Matrix4x4& aTransform)
 {
   ShaderProgramOGL* program = aManager->GetProgram(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
                                                    gfx::SurfaceFormat::R8G8B8A8);
 
   aManager->gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, mTexture);
 
-  program->Activate();
+  aManager->ActivateProgram(program);
   program->SetProjectionMatrix(aManager->GetProjMatrix());
   program->SetLayerTransform(Matrix4x4(aTransform).PostTranslate(aLocation.x, aLocation.y, 0));
   program->SetTextureTransform(gfx::Matrix4x4());
   program->SetRenderOffset(nsIntPoint(0, 0));
   program->SetTexCoordMultiplier(mUsedSize.width, mUsedSize.height);
   program->SetTextureUnit(0);
 
   aManager->BindAndDrawQuad(program,