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
--- 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;
};
}
}