When mix-blending, only copy intersecting backdrop pixels. (bug 1235995 part 2, r=mattwoodrow)
authorDavid Anderson <danderson@mozilla.com>
Tue, 19 Jan 2016 13:28:08 +0700
changeset 315594 77ce3012d481b480f87ff2a0063e1b11d9999f68
parent 315593 5b8303030d9ce36b350e170c3787defc0ebc0c5d
child 315595 2007ddbc08c9acf8d032b62c2005b9d65ba8e31b
push id5703
push userraliiev@mozilla.com
push dateMon, 07 Mar 2016 14:18:41 +0000
treeherdermozilla-beta@31e373ad5b5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1235995
milestone46.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
When mix-blending, only copy intersecting backdrop pixels. (bug 1235995 part 2, r=mattwoodrow)
gfx/layers/Compositor.cpp
gfx/layers/Compositor.h
gfx/layers/opengl/CompositorOGL.cpp
gfx/layers/opengl/CompositorOGL.h
gfx/layers/opengl/OGLShaderProgram.cpp
gfx/layers/opengl/OGLShaderProgram.h
--- a/gfx/layers/Compositor.cpp
+++ b/gfx/layers/Compositor.cpp
@@ -352,16 +352,38 @@ DecomposeIntoNoRepeatRects(const gfx::Re
            flipped);
   SetRects(3, aLayerRects, aTextureRects,
            xmid, ymid, aRect.XMost(), aRect.YMost(),
            0.0f, 0.0f, br.x, br.y,
            flipped);
   return 4;
 }
 
+gfx::IntRect
+Compositor::ComputeBackdropCopyRect(const gfx::Rect& aRect,
+                                    const gfx::Rect& aClipRect,
+                                    const gfx::Matrix4x4& aTransform)
+{
+  gfx::Rect renderBounds = mRenderBounds;
+
+  // Compute the clip.
+  renderBounds.IntersectRect(renderBounds, aClipRect);
+
+  // Apply the layer transform.
+  gfx::Rect dest = aTransform.TransformAndClipBounds(aRect, renderBounds);
+  dest.RoundOut();
+
+  gfx::IntRect result;
+  dest.ToIntRect(&result);
+
+  gfx::IntPoint offset = GetCurrentRenderTarget()->GetOrigin();
+  result.MoveBy(-offset);
+  return result;
+}
+
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
 void
 Compositor::SetDispAcquireFence(Layer* aLayer, nsIWidget* aWidget)
 {
   // OpenGL does not provide ReleaseFence for rendering.
   // Instead use DispAcquireFence as layer buffer's ReleaseFence
   // to prevent flickering and tearing.
   // DispAcquireFence is DisplaySurface's AcquireFence.
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -510,16 +510,26 @@ protected:
                                const gfx::Rect& aVisibleRect,
                                const gfx::Rect& aClipRect,
                                const gfx::Matrix4x4& transform,
                                uint32_t aFlashCounter);
 
   bool ShouldDrawDiagnostics(DiagnosticFlags);
 
   /**
+   * Given a layer rect, clip, and transform, compute the area of the backdrop that
+   * needs to be copied for mix-blending. The output transform translates from 0..1
+   * space into the backdrop rect space.
+   */
+  gfx::IntRect ComputeBackdropCopyRect(
+    const gfx::Rect& aRect,
+    const gfx::Rect& aClipRect,
+    const gfx::Matrix4x4& aTransform);
+
+  /**
    * Render time for the current composition.
    */
   TimeStamp mCompositionTime;
   /**
    * When nonnull, during rendering, some compositable indicated that it will
    * change its rendering at this time. In order not to miss it, we composite
    * on every vsync until this time occurs (this is the latest such time).
    */
@@ -537,16 +547,18 @@ protected:
   size_t mPixelsPerFrame;
   size_t mPixelsFilled;
 
   ScreenRotation mScreenRotation;
 
   RefPtr<gfx::DrawTarget> mTarget;
   gfx::IntRect mTargetBounds;
 
+  gfx::Rect mRenderBounds;
+
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
   FenceHandle mReleaseFenceHandle;
 #endif
 
 private:
   static LayersBackend sBackend;
 
 };
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -481,17 +481,17 @@ void
 CompositorOGL::PrepareViewport(CompositingRenderTargetOGL* aRenderTarget)
 {
   MOZ_ASSERT(aRenderTarget);
   const gfx::IntSize& size = aRenderTarget->mInitParams.mSize;
 
   // Set the viewport correctly.
   mGLContext->fViewport(0, 0, size.width, size.height);
 
-  mRenderBound = Rect(0, 0, size.width, size.height);
+  mRenderBounds = Rect(0, 0, size.width, size.height);
 
   mViewportSize = size;
 
   if (!aRenderTarget->HasComplexProjection()) {
     // We flip the view matrix around so that everything is right-side up; we're
     // drawing directly into the window's back buffer, so this keeps things
     // looking correct.
     // XXX: We keep track of whether the window size changed, so we could skip
@@ -1002,31 +1002,31 @@ CompositorOGL::DrawQuad(const Rect& aRec
   MOZ_ASSERT(mCurrentRenderTarget, "No destination");
 
   if (aEffectChain.mPrimaryEffect->mType == EffectTypes::VR_DISTORTION) {
     DrawVRDistortion(aRect, aClipRect, aEffectChain, aOpacity, aTransform);
     return;
   }
 
   IntPoint offset = mCurrentRenderTarget->GetOrigin();
-  Rect renderBound = mRenderBound;
+  Rect renderBound = mRenderBounds;
   renderBound.IntersectRect(renderBound, aClipRect);
   renderBound.MoveBy(offset);
 
   Rect destRect = aTransform.TransformAndClipBounds(aRect, renderBound);
 
   // XXX: This doesn't handle 3D transforms. It also doesn't handled rotated
   //      quads. Fix me.
   mPixelsFilled += destRect.width * destRect.height;
 
   // Do a simple culling if this rect is out of target buffer.
   // Inflate a small size to avoid some numerical imprecision issue.
   destRect.Inflate(1, 1);
   destRect.MoveBy(-offset);
-  if (!mRenderBound.Intersects(destRect)) {
+  if (!mRenderBounds.Intersects(destRect)) {
     return;
   }
 
   LayerScope::DrawBegin();
 
   Rect clipRect = aClipRect;
   // aClipRect is in destination coordinate space (after all
   // transforms and offsets have been applied) so if our
@@ -1094,21 +1094,16 @@ CompositorOGL::DrawQuad(const Rect& aRec
 
   GLuint mixBlendBackdrop = 0;
   gfx::CompositionOp blendMode = gfx::CompositionOp::OP_OVER;
 
   if (aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE]) {
     EffectBlendMode *blendEffect =
       static_cast<EffectBlendMode*>(aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE].get());
     blendMode = blendEffect->mBlendMode;
-    if (BlendOpIsMixBlendMode(blendMode)) {
-      gfx::IntRect rect(gfx::IntPoint(0, 0), mCurrentRenderTarget->GetSize());
-
-      mixBlendBackdrop = CreateTexture(rect, true, mCurrentRenderTarget->GetFBO());
-    }
   }
 
   // Only apply DEAA to quads that have been transformed such that aliasing
   // could be visible
   bool bEnableAA = gfxPrefs::LayersDEAAEnabled() &&
                    !aTransform.Is2DIntegerTranslation();
 
   bool colorMatrix = aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX];
@@ -1122,16 +1117,30 @@ CompositorOGL::DrawQuad(const Rect& aRec
   program->SetLayerTransform(aTransform);
   LayerScope::SetLayerTransform(aTransform);
   if (colorMatrix) {
       EffectColorMatrix* effectColorMatrix =
         static_cast<EffectColorMatrix*>(aEffectChain.mSecondaryEffects[EffectTypes::COLOR_MATRIX].get());
       program->SetColorMatrix(effectColorMatrix->mColorMatrix);
   }
 
+  if (BlendOpIsMixBlendMode(blendMode)) {
+    gfx::IntRect rect = ComputeBackdropCopyRect(aRect, aClipRect, aTransform);
+    mixBlendBackdrop = CreateTexture(rect, true, mCurrentRenderTarget->GetFBO());
+
+    // Create a transform from adjusted clip space to render target space,
+    // translate it for the backdrop rect, then transform it into the backdrop's
+    // uv-space.
+    gfx::Matrix4x4 transform;
+    transform.PostScale(mRenderBounds.width, mRenderBounds.height, 1.0);
+    transform.PostTranslate(-rect.x, -rect.y, 0.0);
+    transform.PostScale(1 / float(rect.width), 1 / float(rect.height), 1.0);
+    program->SetBackdropTransform(transform);
+  }
+
   program->SetRenderOffset(offset.x, offset.y);
   LayerScope::SetRenderOffset(offset.x, offset.y);
 
   if (aOpacity != 1.f)
     program->SetLayerOpacity(aOpacity);
   if (config.mFeatures & ENABLE_TEXTURE_RECT) {
     TexturedEffect* texturedEffect =
         static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -483,18 +483,16 @@ private:
   /**
    * Size of the OpenGL context's primary framebuffer in pixels. Used by
    * FlipY for the y-flipping calculation and by the DEAA shader.
    */
   gfx::IntSize mViewportSize;
 
   ShaderProgramOGL *mCurrentProgram;
 
-  gfx::Rect mRenderBound;
-
   CompositorOGLVRObjects mVR;
 
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
   nsTHashtable<nsPtrHashKey<ImageHostOverlay> > mImageHostOverlays;
 #endif
 
 };
 
--- a/gfx/layers/opengl/OGLShaderProgram.cpp
+++ b/gfx/layers/opengl/OGLShaderProgram.cpp
@@ -25,16 +25,17 @@ using namespace std;
 void
 AddUniforms(ProgramProfileOGL& aProfile)
 {
     // This needs to be kept in sync with the KnownUniformName enum
     static const char *sKnownUniformNames[] = {
         "uLayerTransform",
         "uLayerTransformInverse",
         "uMaskTransform",
+        "uBackdropTransform",
         "uLayerRects",
         "uMatrixProj",
         "uTextureTransform",
         "uTextureRects",
         "uRenderTargetOffset",
         "uLayerOpacity",
         "uTexture",
         "uYTexture",
@@ -195,16 +196,17 @@ ProgramProfileOGL::GetProfileFor(ShaderC
 
   if (!(aConfig.mFeatures & ENABLE_RENDER_COLOR)) {
     vs << "uniform mat4 uTextureTransform;" << endl;
     vs << "uniform vec4 uTextureRects[4];" << endl;
     vs << "varying vec2 vTexCoord;" << endl;
   }
 
   if (BlendOpIsMixBlendMode(blendOp)) {
+    vs << "uniform mat4 uBackdropTransform;" << endl;
     vs << "varying vec2 vBackdropCoord;" << endl;
   }
 
   if (aConfig.mFeatures & ENABLE_MASK_2D ||
       aConfig.mFeatures & ENABLE_MASK_3D) {
     vs << "uniform mat4 uMaskTransform;" << endl;
     vs << "varying vec3 vMaskCoord;" << endl;
   }
@@ -282,18 +284,22 @@ ProgramProfileOGL::GetProfileFor(ShaderC
       // correct for perspective correct interpolation, see comment in D3D10 shader
       vs << "  vMaskCoord.z = 1.0;" << endl;
       vs << "  vMaskCoord *= finalPosition.w;" << endl;
     }
   }
   vs << "  finalPosition.xy -= uRenderTargetOffset * finalPosition.w;" << endl;
   vs << "  finalPosition = uMatrixProj * finalPosition;" << endl;
   if (BlendOpIsMixBlendMode(blendOp)) {
-    // Move from clip space coordinates into texture/uv-coordinates.
-    vs << "  vBackdropCoord = (finalPosition.xy + vec2(1.0, 1.0)) / 2.0;" << endl;
+    // Translate from clip space (-1, 1) to (0..1), apply the backdrop
+    // transform, then invert the y-axis.
+    vs << "  vBackdropCoord.x = (finalPosition.x + 1.0) / 2.0;" << endl;
+    vs << "  vBackdropCoord.y = 1.0 - (finalPosition.y + 1.0) / 2.0;" << endl;
+    vs << "  vBackdropCoord = (uBackdropTransform * vec4(vBackdropCoord.xy, 0.0, 1.0)).xy;" << endl;
+    vs << "  vBackdropCoord.y = 1.0 - vBackdropCoord.y;" << endl;
   }
   vs << "  gl_Position = finalPosition;" << endl;
   vs << "}" << endl;
 
   if (aConfig.mFeatures & ENABLE_TEXTURE_RECT) {
     fs << "#extension GL_ARB_texture_rectangle : require" << endl;
   }
   if (aConfig.mFeatures & ENABLE_TEXTURE_EXTERNAL) {
--- a/gfx/layers/opengl/OGLShaderProgram.h
+++ b/gfx/layers/opengl/OGLShaderProgram.h
@@ -47,16 +47,17 @@ class KnownUniform {
 public:
   // this needs to be kept in sync with strings in 'AddUniforms'
   enum KnownUniformName {
     NotAKnownUniform = -1,
 
     LayerTransform = 0,
     LayerTransformInverse,
     MaskTransform,
+    BackdropTransform,
     LayerRects,
     MatrixProj,
     TextureTransform,
     TextureRects,
     RenderTargetOffset,
     LayerOpacity,
     Texture,
     YTexture,
@@ -347,16 +348,20 @@ public:
   void SetLayerTransformInverse(const gfx::Matrix4x4& aMatrix) {
     SetMatrixUniform(KnownUniform::LayerTransformInverse, aMatrix);
   }
 
   void SetMaskLayerTransform(const gfx::Matrix4x4& aMatrix) {
     SetMatrixUniform(KnownUniform::MaskTransform, aMatrix);
   }
 
+  void SetBackdropTransform(const gfx::Matrix4x4& aMatrix) {
+    SetMatrixUniform(KnownUniform::BackdropTransform, aMatrix);
+  }
+
   void SetDEAAEdges(const gfx::Point3D* aEdges) {
     SetArrayUniform(KnownUniform::SSEdges, 4, aEdges);
   }
 
   void SetViewportSize(const gfx::IntSize& aSize) {
     float vals[2] = { (float)aSize.width, (float)aSize.height };
     SetUniform(KnownUniform::ViewportSize, 2, vals);
   }