Bug 1221616: Use ID2D1CommandList instead of a bitmap for temporary D2D drawing. r=jrmuizel
authorBas Schouten <bschouten@mozilla.com>
Thu, 12 Nov 2015 17:00:52 +0100
changeset 308646 e4944eb37eecb1587c5acec96a14bd7f7d6fde57
parent 308645 b4c27ab3cafeef188e84a704cbe72f27419a1eea
child 308647 0df5a6f549d415fb52e768529f90599e364fa341
push id7513
push useratolfsen@mozilla.com
push dateFri, 13 Nov 2015 14:03:43 +0000
reviewersjrmuizel
bugs1221616
milestone45.0a1
Bug 1221616: Use ID2D1CommandList instead of a bitmap for temporary D2D drawing. r=jrmuizel
gfx/2d/DrawTargetD2D1.cpp
gfx/2d/DrawTargetD2D1.h
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -249,30 +249,33 @@ DrawTargetD2D1::ClearRect(const Rect &aR
     mDC->PushAxisAlignedClip(clipRect, isPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
     mDC->Clear();
     mDC->PopAxisAlignedClip();
 
     PopClip();
     return;
   }
 
-  mDC->SetTarget(mTempBitmap);
-  mDC->Clear();
+  RefPtr<ID2D1CommandList> list;
+  mDC->CreateCommandList(getter_AddRefs(list));
+  mDC->SetTarget(list);
 
   IntRect addClipRect;
   RefPtr<ID2D1Geometry> geom = GetClippedGeometry(&addClipRect);
 
   RefPtr<ID2D1SolidColorBrush> brush;
   mDC->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), getter_AddRefs(brush));
   mDC->PushAxisAlignedClip(D2D1::RectF(addClipRect.x, addClipRect.y, addClipRect.XMost(), addClipRect.YMost()), D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
   mDC->FillGeometry(geom, brush);
   mDC->PopAxisAlignedClip();
 
   mDC->SetTarget(mBitmap);
-  mDC->DrawImage(mTempBitmap, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_DESTINATION_OUT);
+  list->Close();
+
+  mDC->DrawImage(list, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_DESTINATION_OUT);
 
   PopClip();
 
   return;
 }
 
 void
 DrawTargetD2D1::MaskSurface(const Pattern &aSource,
@@ -856,28 +859,18 @@ DrawTargetD2D1::Init(ID3D11Texture2D* aT
   if (FAILED(hr)) {
     gfxCriticalError() << "[D2D1.1] CreateBitmapFromDxgiSurface failure Code: " << hexa(hr) << " format " << (int)aFormat;
     return false;
   }
 
   mFormat = aFormat;
   D3D11_TEXTURE2D_DESC desc;
   aTexture->GetDesc(&desc);
-  desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
   mSize.width = desc.Width;
   mSize.height = desc.Height;
-  props.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
-  props.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
-
-  hr = mDC->CreateBitmap(D2DIntSize(mSize), nullptr, 0, props, (ID2D1Bitmap1**)getter_AddRefs(mTempBitmap));
-
-  if (FAILED(hr)) {
-    gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(mSize))) << "[D2D1.1] 2CreateBitmap failure " << mSize << " Code: " << hexa(hr);
-    return false;
-  }
 
   // This single solid color brush system is not very 'threadsafe', however,
   // issueing multiple drawing commands simultaneously to a single drawtarget
   // from multiple threads is unexpected since there's no way to guarantee
   // ordering in that situation anyway.
   hr = mDC->CreateSolidColorBrush(D2D1::ColorF(0, 0), getter_AddRefs(mSolidColorBrush));
 
   if (FAILED(hr)) {
@@ -924,26 +917,16 @@ DrawTargetD2D1::Init(const IntSize &aSiz
   props.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET;
   hr = mDC->CreateBitmap(D2DIntSize(aSize), nullptr, 0, props, (ID2D1Bitmap1**)getter_AddRefs(mBitmap));
 
   if (FAILED(hr)) {
     gfxCriticalError() << "[D2D1.1] 3CreateBitmap failure " << aSize << " Code: " << hexa(hr) << " format " << (int)aFormat;
     return false;
   }
 
-  props.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
-  props.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
-
-  hr = mDC->CreateBitmap(D2DIntSize(aSize), nullptr, 0, props, (ID2D1Bitmap1**)getter_AddRefs(mTempBitmap));
-
-  if (FAILED(hr)) {
-    gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(aSize))) << "[D2D1.1] failed to create new TempBitmap " << aSize << " Code: " << hexa(hr);
-    return false;
-  }
-
   mDC->SetTarget(mBitmap);
 
   hr = mDC->CreateSolidColorBrush(D2D1::ColorF(0, 0), getter_AddRefs(mSolidColorBrush));
 
   if (FAILED(hr)) {
     gfxCriticalError() << "[D2D1.1] Failure creating solid color brush.";
     return false;
   }
@@ -1040,18 +1023,18 @@ DrawTargetD2D1::PrepareForDrawing(Compos
     if (aOp != CompositionOp::OP_OVER)
       mDC->SetPrimitiveBlend(D2DPrimitiveBlendMode(aOp));
 
     return;
   }
 
   PopAllClips();
 
-  mDC->SetTarget(mTempBitmap);
-  mDC->Clear(D2D1::ColorF(0, 0));
+  mDC->CreateCommandList(getter_AddRefs(mCommandList));
+  mDC->SetTarget(mCommandList);
 
   PushAllClips();
   FlushTransformToDC();
 }
 
 void
 DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
 {
@@ -1060,20 +1043,21 @@ DrawTargetD2D1::FinalizeDrawing(Composit
   if (D2DSupportsPrimitiveBlendMode(aOp) && patternSupported) {
     if (aOp != CompositionOp::OP_OVER)
       mDC->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_SOURCE_OVER);
     return;
   }
 
   PopAllClips();
 
-  RefPtr<ID2D1Image> image;
-  mDC->GetTarget(getter_AddRefs(image));
+  mDC->SetTarget(mBitmap);
+  mCommandList->Close();
 
-  mDC->SetTarget(mBitmap);
+  RefPtr<ID2D1CommandList> source = mCommandList;
+  mCommandList = nullptr;
 
   mDC->SetTransform(D2D1::IdentityMatrix());
   mTransformDirty = true;
 
   if (patternSupported) {
     if (D2DSupportsCompositeMode(aOp)) {
       D2D1_RECT_F rect;
       bool isAligned;
@@ -1091,17 +1075,17 @@ DrawTargetD2D1::FinalizeDrawing(Composit
           }
           mDC->Flush();
 
           tmpBitmap->CopyFromBitmap(nullptr, mBitmap, nullptr);
         }
       } else {
         PushAllClips();
       }
-      mDC->DrawImage(image, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2DCompositionMode(aOp));
+      mDC->DrawImage(source, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2DCompositionMode(aOp));
 
       if (tmpBitmap) {
         RefPtr<ID2D1BitmapBrush> brush;
         RefPtr<ID2D1Geometry> inverseGeom = GetInverseClippedGeometry();
         mDC->CreateBitmapBrush(tmpBitmap, getter_AddRefs(brush));
 
         mDC->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_COPY);
         mDC->FillGeometry(inverseGeom, brush);
@@ -1130,17 +1114,17 @@ DrawTargetD2D1::FinalizeDrawing(Composit
     // We also need to pop all the clips to make sure any drawn content will have made it to the final bitmap.
     mDC->Flush();
 
     // We need to use a copy here because affects don't accept a surface on
     // both their in- and outputs.
     tmpBitmap->CopyFromBitmap(nullptr, mBitmap, nullptr);
 
     mBlendEffect->SetInput(0, tmpBitmap);
-    mBlendEffect->SetInput(1, mTempBitmap);
+    mBlendEffect->SetInput(1, source);
     mBlendEffect->SetValue(D2D1_BLEND_PROP_MODE, D2DBlendMode(aOp));
 
     PushAllClips();
 
     mDC->DrawImage(mBlendEffect, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY);
     return;
   }
 
@@ -1163,17 +1147,17 @@ DrawTargetD2D1::FinalizeDrawing(Composit
   radialGradientEffect->SetValue(RADIAL_PROP_STOP_COLLECTION,
                                  static_cast<const GradientStopsD2D*>(pat->mStops.get())->mStopCollection);
   radialGradientEffect->SetValue(RADIAL_PROP_CENTER_1, D2D1::Vector2F(pat->mCenter1.x, pat->mCenter1.y));
   radialGradientEffect->SetValue(RADIAL_PROP_CENTER_2, D2D1::Vector2F(pat->mCenter2.x, pat->mCenter2.y));
   radialGradientEffect->SetValue(RADIAL_PROP_RADIUS_1, pat->mRadius1);
   radialGradientEffect->SetValue(RADIAL_PROP_RADIUS_2, pat->mRadius2);
   radialGradientEffect->SetValue(RADIAL_PROP_RADIUS_2, pat->mRadius2);
   radialGradientEffect->SetValue(RADIAL_PROP_TRANSFORM, D2DMatrix(pat->mMatrix * mTransform));
-  radialGradientEffect->SetInput(0, image);
+  radialGradientEffect->SetInput(0, source);
 
   mDC->DrawImage(radialGradientEffect, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2DCompositionMode(aOp));
 }
 
 void
 DrawTargetD2D1::AddDependencyOnSource(SourceSurfaceD2D1* aSource)
 {
   if (aSource->mDrawTarget && !mDependingOnTargets.count(aSource->mDrawTarget)) {
--- a/gfx/2d/DrawTargetD2D1.h
+++ b/gfx/2d/DrawTargetD2D1.h
@@ -195,17 +195,17 @@ private:
   RefPtr<ID3D11Texture2D> mTexture;
   RefPtr<ID2D1Geometry> mCurrentClippedGeometry;
   // This is only valid if mCurrentClippedGeometry is non-null. And will
   // only be the intersection of all pixel-aligned retangular clips. This is in
   // device space.
   IntRect mCurrentClipBounds;
   mutable RefPtr<ID2D1DeviceContext> mDC;
   RefPtr<ID2D1Bitmap1> mBitmap;
-  RefPtr<ID2D1Bitmap1> mTempBitmap;
+  RefPtr<ID2D1CommandList> mCommandList;
   RefPtr<ID2D1Effect> mBlendEffect;
 
   RefPtr<ID2D1SolidColorBrush> mSolidColorBrush;
 
   // We store this to prevent excessive SetTextRenderingParams calls.
   RefPtr<IDWriteRenderingParams> mTextRenderingParams;
 
   // List of pushed clips.