Bug 1258168: Push ClearType compatible clipping layers when the last pushed layer was marked as opaque. r=jrmuizel
authorBas Schouten <bschouten@mozilla.com>
Sun, 20 Mar 2016 19:51:46 +0100
changeset 329000 538d248fa252a4100082fd9bc3fdc08d322cda22
parent 328999 ca5142203259cd252723d34e75d3e3b799b21765
child 329001 53400e993cb8a295a72dc247436b862844686588
child 329187 38fa3ece64fbd82cd88a0dc91c820b786cbcee4c
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1258168
milestone48.0a1
first release with
nightly linux32
538d248fa252 / 48.0a1 / 20160401030216 / files
nightly linux64
538d248fa252 / 48.0a1 / 20160401030216 / files
nightly mac
538d248fa252 / 48.0a1 / 20160401030216 / files
nightly win32
538d248fa252 / 48.0a1 / 20160401030216 / files
nightly win64
538d248fa252 / 48.0a1 / 20160401030216 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1258168: Push ClearType compatible clipping layers when the last pushed layer was marked as opaque. r=jrmuizel MozReview-Commit-ID: IM1srXx7CfB
gfx/2d/DrawTargetD2D1.cpp
gfx/2d/DrawTargetD2D1.h
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -1166,79 +1166,97 @@ DrawTargetD2D1::MarkChanged()
          iter != tmpTargets.end(); iter++) {
       (*iter)->Flush();
     }
     // The Flush() should have broken all dependencies on this target.
     MOZ_ASSERT(!mDependentTargets.size());
   }
 }
 
+bool
+DrawTargetD2D1::ShouldClipTemporarySurfaceDrawing(CompositionOp aOp,
+                                                  const Pattern& aPattern,
+                                                  bool aClipIsComplex)
+{
+  bool patternSupported = IsPatternSupportedByD2D(aPattern);
+  return patternSupported && !CurrentLayer().mIsOpaque && D2DSupportsCompositeMode(aOp) &&
+         IsOperatorBoundByMask(aOp) && aClipIsComplex;
+}
+
 void
 DrawTargetD2D1::PrepareForDrawing(CompositionOp aOp, const Pattern &aPattern)
 {
   MarkChanged();
 
-  if (D2DSupportsPrimitiveBlendMode(aOp) && IsPatternSupportedByD2D(aPattern)) {
+  bool patternSupported = IsPatternSupportedByD2D(aPattern);
+
+  if (D2DSupportsPrimitiveBlendMode(aOp) && patternSupported) {
     // It's important to do this before FlushTransformToDC! As this will cause
     // the transform to become dirty.
     PushAllClips();
 
     FlushTransformToDC();
 
     if (aOp != CompositionOp::OP_OVER)
       mDC->SetPrimitiveBlend(D2DPrimitiveBlendMode(aOp));
 
     return;
   }
 
-  PopAllClips();
-
   mDC->CreateCommandList(getter_AddRefs(mCommandList));
   mDC->SetTarget(mCommandList);
   mUsedCommandListsSincePurge++;
 
-  PushAllClips();
+  D2D1_RECT_F rect;
+  bool isAligned;
+  bool clipIsComplex = CurrentLayer().mPushedClips.size() && !GetDeviceSpaceClipRect(rect, isAligned);
+
+  if (ShouldClipTemporarySurfaceDrawing(aOp, aPattern, clipIsComplex)) {
+    PushClipsToDC(mDC);
+  }
+
   FlushTransformToDC();
 }
 
 void
 DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
 {
   bool patternSupported = IsPatternSupportedByD2D(aPattern);
 
   if (D2DSupportsPrimitiveBlendMode(aOp) && patternSupported) {
     if (aOp != CompositionOp::OP_OVER)
       mDC->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_SOURCE_OVER);
     return;
   }
 
-  PopAllClips();
+  D2D1_RECT_F rect;
+  bool isAligned;
+  bool clipIsComplex = CurrentLayer().mPushedClips.size() && !GetDeviceSpaceClipRect(rect, isAligned);
+
+  if (ShouldClipTemporarySurfaceDrawing(aOp, aPattern, clipIsComplex)) {
+    PopClipsFromDC(mDC);
+  }
 
   mDC->SetTarget(CurrentTarget());
   mCommandList->Close();
 
   RefPtr<ID2D1CommandList> source = mCommandList;
   mCommandList = nullptr;
 
   mDC->SetTransform(D2D1::IdentityMatrix());
   mTransformDirty = true;
 
   if (patternSupported) {
     if (D2DSupportsCompositeMode(aOp)) {
-      D2D1_RECT_F rect;
-      bool isAligned;
       RefPtr<ID2D1Image> tmpImage;
-      bool clipIsComplex = CurrentLayer().mPushedClips.size() && !GetDeviceSpaceClipRect(rect, isAligned);
-
       if (clipIsComplex) {
+        PopAllClips();
         if (!IsOperatorBoundByMask(aOp)) {
           tmpImage = GetImageForLayerContent();
         }
-      } else {
-        PushAllClips();
       }
       mDC->DrawImage(source, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2DCompositionMode(aOp));
 
       if (tmpImage) {
         RefPtr<ID2D1ImageBrush> brush;
         RefPtr<ID2D1Geometry> inverseGeom = GetInverseClippedGeometry();
         mDC->CreateImageBrush(tmpImage, D2D1::ImageBrushProperties(D2D1::RectF(0, 0, mSize.width, mSize.height)),
                               getter_AddRefs(brush));
@@ -1259,30 +1277,26 @@ DrawTargetD2D1::FinalizeDrawing(Composit
     }
 
     RefPtr<ID2D1Image> tmpImage = GetImageForLayerContent();
 
     blendEffect->SetInput(0, tmpImage);
     blendEffect->SetInput(1, source);
     blendEffect->SetValue(D2D1_BLEND_PROP_MODE, D2DBlendMode(aOp));
 
-    PushAllClips();
-
     mDC->DrawImage(blendEffect, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY);
     return;
   }
 
   const RadialGradientPattern *pat = static_cast<const RadialGradientPattern*>(&aPattern);
   if (pat->mCenter1 == pat->mCenter2 && pat->mRadius1 == pat->mRadius2) {
     // Draw nothing!
     return;
   }
 
-  PushAllClips();
-
   RefPtr<ID2D1Effect> radialGradientEffect;
 
   HRESULT hr = mDC->CreateEffect(CLSID_RadialGradientEffect, getter_AddRefs(radialGradientEffect));
   if (FAILED(hr) || !radialGradientEffect) {
     gfxWarning() << "Failed to create radial gradient effect. Code: " << hexa(hr);
     return;
   }
 
@@ -1355,24 +1369,28 @@ DrawTargetD2D1::GetImageForLayerContent(
       // null and CopyFromBitmap call below dereferences it.
       // return;
     }
     mDC->Flush();
 
     tmpBitmap->CopyFromBitmap(nullptr, mBitmap, nullptr);
     return tmpBitmap.forget();
   } else {
+    PopAllClips();
+
     RefPtr<ID2D1CommandList> list = CurrentLayer().mCurrentList;
     mDC->CreateCommandList(getter_AddRefs(CurrentLayer().mCurrentList));
     mDC->SetTarget(CurrentTarget());
     list->Close();
 
     DCCommandSink sink(mDC);
     list->Stream(&sink);
 
+    PushAllClips();
+
     return list.forget();
   }
 }
 
 already_AddRefed<ID2D1Geometry>
 DrawTargetD2D1::GetClippedGeometry(IntRect *aClipBounds)
 {
   if (mCurrentClippedGeometry) {
@@ -1781,17 +1799,17 @@ DrawTargetD2D1::OptimizeSourceSurface(So
 }
 
 void
 DrawTargetD2D1::PushD2DLayer(ID2D1DeviceContext *aDC, ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTransform,
                              bool aForceIgnoreAlpha, const D2D1_RECT_F& aMaxRect)
 {
   D2D1_LAYER_OPTIONS1 options = D2D1_LAYER_OPTIONS1_NONE;
 
-  if (aDC->GetPixelFormat().alphaMode == D2D1_ALPHA_MODE_IGNORE || aForceIgnoreAlpha) {
+  if (CurrentLayer().mIsOpaque || aForceIgnoreAlpha) {
     options = D2D1_LAYER_OPTIONS1_IGNORE_ALPHA | D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND;
   }
 
   mDC->PushLayer(D2D1::LayerParameters1(aMaxRect, aGeometry,
                                         D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, aTransform,
                                         1.0, nullptr, options), nullptr);
 }
 
--- a/gfx/2d/DrawTargetD2D1.h
+++ b/gfx/2d/DrawTargetD2D1.h
@@ -159,16 +159,17 @@ public:
 private:
   friend class SourceSurfaceD2D1;
 
   typedef std::unordered_set<DrawTargetD2D1*> TargetSet;
 
   // This function will mark the surface as changing, and make sure any
   // copy-on-write snapshots are notified.
   void MarkChanged();
+  bool ShouldClipTemporarySurfaceDrawing(CompositionOp aOp, const Pattern& aPattern, bool aClipIsComplex);
   void PrepareForDrawing(CompositionOp aOp, const Pattern &aPattern);
   void FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern);
   void FlushTransformToDC() {
     if (mTransformDirty) {
       mDC->SetTransform(D2DMatrix(mTransform));
       mTransformDirty = false;
     }
   }