Bug 1161815 - Use a single ID2D1SolidColorBrush per DrawTarget. r=jrmuizel, a=lizzard
authorBas Schouten <bschouten@mozilla.com>
Thu, 07 May 2015 02:38:10 +0200
changeset 267478 13e298c9841e5d8fdf01f2ef1084b8ba2674ea5c
parent 267477 498a842f6d9e5518705ae72a437371be8834d38c
child 267479 b38b8126e4d1749706afe0bf89dd074d3efd075b
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel, lizzard
bugs1161815
milestone39.0
Bug 1161815 - Use a single ID2D1SolidColorBrush per DrawTarget. r=jrmuizel, a=lizzard
gfx/2d/DrawTargetD2D1.cpp
gfx/2d/DrawTargetD2D1.h
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -778,19 +778,31 @@ DrawTargetD2D1::Init(ID3D11Texture2D* aT
 
   hr = mDC->CreateBitmap(D2DIntSize(mSize), nullptr, 0, props, (ID2D1Bitmap1**)byRef(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), byRef(mSolidColorBrush));
+
+  if (FAILED(hr)) {
+    gfxCriticalError() << "[D2D1.1] Failure creating solid color brush.";
+    return false;
+  }
+
   mDC->SetTarget(mBitmap);
 
   mDC->BeginDraw();
+
   return true;
 }
 
 bool
 DrawTargetD2D1::Init(const IntSize &aSize, SurfaceFormat aFormat)
 {
   HRESULT hr;
 
@@ -828,16 +840,23 @@ DrawTargetD2D1::Init(const IntSize &aSiz
 
   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), byRef(mSolidColorBrush));
+
+  if (FAILED(hr)) {
+    gfxCriticalError() << "[D2D1.1] Failure creating solid color brush.";
+    return false;
+  }
+
   mDC->BeginDraw();
 
   mDC->Clear();
 
   mFormat = aFormat;
   mSize = aSize;
 
   return true;
@@ -1247,60 +1266,56 @@ DrawTargetD2D1::PopClipsFromDC(ID2D1Devi
       aDC->PopAxisAlignedClip();
     }
   }
 }
 
 TemporaryRef<ID2D1Brush>
 DrawTargetD2D1::CreateTransparentBlackBrush()
 {
-  RefPtr<ID2D1SolidColorBrush> brush;
-  mDC->CreateSolidColorBrush(D2D1::ColorF(0, 0), byRef(brush));
+  return GetSolidColorBrush(D2D1::ColorF(0, 0));
+}
+
+TemporaryRef<ID2D1SolidColorBrush>
+DrawTargetD2D1::GetSolidColorBrush(const D2D_COLOR_F& aColor)
+{
+  RefPtr<ID2D1SolidColorBrush> brush = mSolidColorBrush;
+  brush->SetColor(aColor);
   return brush;
 }
 
 TemporaryRef<ID2D1Brush>
 DrawTargetD2D1::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
 {
   if (!IsPatternSupportedByD2D(aPattern)) {
-    RefPtr<ID2D1SolidColorBrush> colBrush;
-    mDC->CreateSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), byRef(colBrush));
-    return colBrush.forget();
+    return GetSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f));
   }
 
   if (aPattern.GetType() == PatternType::COLOR) {
-    RefPtr<ID2D1SolidColorBrush> colBrush;
     Color color = static_cast<const ColorPattern*>(&aPattern)->mColor;
-    mDC->CreateSolidColorBrush(D2D1::ColorF(color.r, color.g,
-                                            color.b, color.a),
-                               D2D1::BrushProperties(aAlpha),
-                               byRef(colBrush));
-    return colBrush.forget();
+    return GetSolidColorBrush(D2D1::ColorF(color.r, color.g, color.b, color.a * aAlpha));
   }
   if (aPattern.GetType() == PatternType::LINEAR_GRADIENT) {
     RefPtr<ID2D1LinearGradientBrush> gradBrush;
     const LinearGradientPattern *pat =
       static_cast<const LinearGradientPattern*>(&aPattern);
 
     GradientStopsD2D *stops = static_cast<GradientStopsD2D*>(pat->mStops.get());
 
     if (!stops) {
       gfxDebug() << "No stops specified for gradient pattern.";
       return CreateTransparentBlackBrush();
     }
 
     if (pat->mBegin == pat->mEnd) {
-      RefPtr<ID2D1SolidColorBrush> colBrush;
       uint32_t stopCount = stops->mStopCollection->GetGradientStopCount();
       vector<D2D1_GRADIENT_STOP> d2dStops(stopCount);
       stops->mStopCollection->GetGradientStops(&d2dStops.front(), stopCount);
-      mDC->CreateSolidColorBrush(d2dStops.back().color,
-                                 D2D1::BrushProperties(aAlpha),
-                                 byRef(colBrush));
-      return colBrush.forget();
+      d2dStops.back().color.a *= aAlpha;
+      return GetSolidColorBrush(d2dStops.back().color);
     }
 
     mDC->CreateLinearGradientBrush(D2D1::LinearGradientBrushProperties(D2DPoint(pat->mBegin),
                                                                        D2DPoint(pat->mEnd)),
                                    D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)),
                                    stops->mStopCollection,
                                    byRef(gradBrush));
 
@@ -1376,16 +1391,22 @@ DrawTargetD2D1::CreateBrushForPattern(co
 
     mDC->CreateImageBrush(image,
                           D2D1::ImageBrushProperties(samplingBounds,
                                                      D2DExtend(pat->mExtendMode),
                                                      D2DExtend(pat->mExtendMode),
                                                      D2DInterpolationMode(pat->mFilter)),
                           D2D1::BrushProperties(aAlpha, D2DMatrix(mat)),
                           byRef(imageBrush));
+
+    if (!imageBrush) {
+      gfxWarning() << "Couldn't create image brush!";
+      return CreateTransparentBlackBrush();
+    }
+
     return imageBrush.forget();
   }
 
   gfxWarning() << "Invalid pattern type detected.";
   return CreateTransparentBlackBrush();
 }
 
 TemporaryRef<ID2D1Image>
--- a/gfx/2d/DrawTargetD2D1.h
+++ b/gfx/2d/DrawTargetD2D1.h
@@ -180,16 +180,17 @@ private:
   bool GetDeviceSpaceClipRect(D2D1_RECT_F& aClipRect, bool& aIsPixelAligned);
 
   void PopAllClips();
   void PushAllClips();
   void PushClipsToDC(ID2D1DeviceContext *aDC);
   void PopClipsFromDC(ID2D1DeviceContext *aDC);
 
   TemporaryRef<ID2D1Brush> CreateTransparentBlackBrush();
+  TemporaryRef<ID2D1SolidColorBrush> GetSolidColorBrush(const D2D_COLOR_F& aColor);
   TemporaryRef<ID2D1Brush> CreateBrushForPattern(const Pattern &aPattern, Float aAlpha = 1.0f);
 
   void PushD2DLayer(ID2D1DeviceContext *aDC, ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTransform);
 
   IntSize mSize;
 
   RefPtr<ID3D11Device> mDevice;
   RefPtr<ID3D11Texture2D> mTexture;
@@ -198,16 +199,18 @@ private:
   // 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<ID2D1Effect> mBlendEffect;
 
+  RefPtr<ID2D1SolidColorBrush> mSolidColorBrush;
+
   // We store this to prevent excessive SetTextRenderingParams calls.
   RefPtr<IDWriteRenderingParams> mTextRenderingParams;
 
   // List of pushed clips.
   struct PushedClip
   {
     D2D1_RECT_F mBounds;
     union {