Bug 1293586: Don't use command lists for an effect when that command list already has an effect with a command list used inside of it. r=mstange draft
authorBas Schouten <bschouten@mozilla.com>
Mon, 22 Aug 2016 13:22:01 +0200
changeset 403867 f569e9b5613bf8cf419792251335e07a7f743607
parent 399104 3d92407a320cb79fde6d1d365557aa20d5cc9db4
child 529023 86c4d195ba7d1ef36b12a56f83abac5ae00f6309
push id27036
push userbschouten@mozilla.com
push dateMon, 22 Aug 2016 11:22:20 +0000
reviewersmstange
bugs1293586
milestone51.0a1
Bug 1293586: Don't use command lists for an effect when that command list already has an effect with a command list used inside of it. r=mstange MozReview-Commit-ID: 2T2wdUaWgMC
gfx/2d/DrawTargetD2D1.cpp
gfx/2d/DrawTargetD2D1.h
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -36,16 +36,17 @@ ID2D1Factory1* DrawTargetD2D1::mFactory 
 ID2D1Factory1 *D2DFactory1()
 {
   return DrawTargetD2D1::factory();
 }
 
 DrawTargetD2D1::DrawTargetD2D1()
   : mPushedLayers(1)
   , mUsedCommandListsSincePurge(0)
+  , mDidComplexBlendWithListInList(false)
 {
 }
 
 DrawTargetD2D1::~DrawTargetD2D1()
 {
   PopAllClips();
 
   if (mSnapshot) {
@@ -1297,16 +1298,23 @@ DrawTargetD2D1::FinalizeDrawing(Composit
 
     RefPtr<ID2D1Image> tmpImage = GetImageForLayerContent();
 
     blendEffect->SetInput(0, tmpImage);
     blendEffect->SetInput(1, source);
     blendEffect->SetValue(D2D1_BLEND_PROP_MODE, D2DBlendMode(aOp));
 
     mDC->DrawImage(blendEffect, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY);
+
+    // This may seem a little counter intuitive. If this is false, we go through the regular
+    // codepaths and set it to true. When this was true, GetImageForLayerContent will return
+    // a bitmap for the current command list and we will no longer have a complex blend
+    // with a list for tmpImage. Therefore we can set it to false again.
+    mDidComplexBlendWithListInList = !mDidComplexBlendWithListInList;
+
     return;
   }
 
   const RadialGradientPattern *pat = static_cast<const RadialGradientPattern*>(&aPattern);
   if (pat->mCenter1 == pat->mCenter2 && pat->mRadius1 == pat->mRadius2) {
     // Draw nothing!
     return;
   }
@@ -1395,21 +1403,34 @@ DrawTargetD2D1::GetImageForLayerContent(
   } else {
     PopAllClips();
 
     RefPtr<ID2D1CommandList> list = CurrentLayer().mCurrentList;
     mDC->CreateCommandList(getter_AddRefs(CurrentLayer().mCurrentList));
     mDC->SetTarget(CurrentTarget());
     list->Close();
 
+    RefPtr<ID2D1Bitmap1> tmpBitmap;
+    if (mDidComplexBlendWithListInList) {
+      mDC->CreateBitmap(mBitmap->GetPixelSize(), nullptr, 0, &D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_TARGET, D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)), getter_AddRefs(tmpBitmap));
+      mDC->SetTransform(D2D1::IdentityMatrix());
+      mDC->SetTarget(tmpBitmap);
+      mDC->DrawImage(list, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY);
+      mDC->SetTarget(CurrentTarget());
+    }
+
     DCCommandSink sink(mDC);
     list->Stream(&sink);
 
     PushAllClips();
 
+    if (mDidComplexBlendWithListInList) {
+      return tmpBitmap.forget();
+    }
+
     return list.forget();
   }
 }
 
 already_AddRefed<ID2D1Geometry>
 DrawTargetD2D1::GetClippedGeometry(IntRect *aClipBounds)
 {
   if (mCurrentClippedGeometry) {
--- a/gfx/2d/DrawTargetD2D1.h
+++ b/gfx/2d/DrawTargetD2D1.h
@@ -268,16 +268,22 @@ private:
   // target is modified. We keep it alive as a cache.
   RefPtr<SourceSurfaceD2D1> mSnapshot;
   // A list of targets we need to flush when we're modified.
   TargetSet mDependentTargets;
   // A list of targets which have this object in their mDependentTargets set
   TargetSet mDependingOnTargets;
 
   uint32_t mUsedCommandListsSincePurge;
+  // When a BlendEffect has been drawn to a command list, and that command list is
+  // subsequently used -again- as an input to a blend effect for a command list,
+  // this causes an infinite recursion inside D2D as it tries to resolve the bounds.
+  // If we resolve the current command list before this happens
+  // we can avoid the subsequent hang. (See bug 1293586)
+  bool mDidComplexBlendWithListInList;
 
   static ID2D1Factory1 *mFactory;
   static IDWriteFactory *mDWriteFactory;
 };
 
 }
 }