Bug 1519760: Attempt to initialize D2D off the main thread as much as possible. r=rhunt
authorBas Schouten <bschouten@mozilla.com>
Sun, 13 Jan 2019 23:14:33 +0100
changeset 511619 42e89a539b98214d8be40cbc7c7860051599e1b6
parent 511618 a7238b0eac40faf3472969790f8b7849ad2677c5
child 511620 7eac43ea765ebb657f9749a6a8fb2c5c006fae8d
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrhunt
bugs1519760
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1519760: Attempt to initialize D2D off the main thread as much as possible. r=rhunt Differential Revision: https://phabricator.services.mozilla.com/D16432
gfx/2d/2D.h
gfx/2d/DrawTargetD2D1.cpp
gfx/2d/DrawTargetD2D1.h
gfx/2d/Factory.cpp
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -55,16 +55,17 @@ typedef FT_LibraryRec_ *FT_Library;
 struct FT_FaceRec_;
 typedef FT_FaceRec_ *FT_Face;
 
 typedef int FT_Error;
 
 struct ID3D11Texture2D;
 struct ID3D11Device;
 struct ID2D1Device;
+struct ID2D1DeviceContext;
 struct IDWriteFactory;
 struct IDWriteRenderingParams;
 struct IDWriteFontFace;
 struct IDWriteFontCollection;
 
 class GrContext;
 class SkCanvas;
 struct gfxFontStyle;
@@ -1788,16 +1789,17 @@ class GFX2D_API Factory {
   static RefPtr<ID3D11Device> GetDirect3D11Device();
   static RefPtr<ID2D1Device> GetD2D1Device(uint32_t *aOutSeqNo = nullptr);
   static bool HasD2D1Device();
   static RefPtr<IDWriteFactory> GetDWriteFactory();
   static RefPtr<IDWriteFactory> EnsureDWriteFactory();
   static bool SupportsD2D1();
   static RefPtr<IDWriteFontCollection> GetDWriteSystemFonts(
       bool aUpdate = false);
+  static RefPtr<ID2D1DeviceContext> GetD2DDeviceContext();
 
   static uint64_t GetD2DVRAMUsageDrawTarget();
   static uint64_t GetD2DVRAMUsageSourceSurface();
   static void D2DCleanup();
 
   static already_AddRefed<ScaledFont> CreateScaledFontForDWriteFont(
       IDWriteFontFace *aFontFace, const gfxFontStyle *aStyle,
       const RefPtr<UnscaledFont> &aUnscaledFont, Float aSize,
@@ -1807,16 +1809,18 @@ class GFX2D_API Factory {
   static void SetSystemTextQuality(uint8_t aQuality);
 
  private:
   static StaticRefPtr<ID2D1Device> mD2D1Device;
   static StaticRefPtr<ID3D11Device> mD3D11Device;
   static StaticRefPtr<IDWriteFactory> mDWriteFactory;
   static bool mDWriteFactoryInitialized;
   static StaticRefPtr<IDWriteFontCollection> mDWriteSystemFonts;
+  static StaticRefPtr<ID2D1DeviceContext> mMTDC;
+  static StaticRefPtr<ID2D1DeviceContext> mOffMTDC;
 
  protected:
   // This guards access to the singleton devices above, as well as the
   // singleton devices in DrawTargetD2D1.
   static StaticMutex mDeviceLock;
   // This synchronizes access between different D2D drawtargets and their
   // implied dependency graph.
   static StaticMutex mDTDependencyLock;
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -38,17 +38,18 @@ StaticRefPtr<ID2D1Factory1> DrawTargetD2
 RefPtr<ID2D1Factory1> D2DFactory() { return DrawTargetD2D1::factory(); }
 
 DrawTargetD2D1::DrawTargetD2D1()
     : mPushedLayers(1),
       mSnapshotLock(make_shared<Mutex>("DrawTargetD2D1::mSnapshotLock")),
       mUsedCommandListsSincePurge(0),
       mTransformedGlyphsSinceLastPurge(0),
       mComplexBlendsWithListInList(0),
-      mDeviceSeq(0) {}
+      mDeviceSeq(0),
+      mIsInitialized(false) {}
 
 DrawTargetD2D1::~DrawTargetD2D1() {
   PopAllClips();
 
   if (mSnapshot) {
     MutexAutoLock lock(*mSnapshotLock);
     // We may hold the only reference. MarkIndependent will clear mSnapshot;
     // keep the snapshot object alive so it doesn't get destroyed while
@@ -81,16 +82,20 @@ DrawTargetD2D1::~DrawTargetD2D1() {
     for (TargetSet::iterator iter = mDependingOnTargets.begin();
          iter != mDependingOnTargets.end(); iter++) {
       (*iter)->mDependentTargets.erase(this);
     }
   }
 }
 
 already_AddRefed<SourceSurface> DrawTargetD2D1::Snapshot() {
+  if (!EnsureInitialized()) {
+    return nullptr;
+  }
+
   MutexAutoLock lock(*mSnapshotLock);
   if (mSnapshot) {
     RefPtr<SourceSurface> snapshot(mSnapshot);
     return snapshot.forget();
   }
   PopAllClips();
 
   Flush();
@@ -120,16 +125,19 @@ bool DrawTargetD2D1::EnsureLuminanceEffe
   mLuminanceEffect->SetValue(D2D1_COLORMATRIX_PROP_COLOR_MATRIX, matrix);
   mLuminanceEffect->SetValue(D2D1_COLORMATRIX_PROP_ALPHA_MODE,
                              D2D1_COLORMATRIX_ALPHA_MODE_STRAIGHT);
   return true;
 }
 
 already_AddRefed<SourceSurface> DrawTargetD2D1::IntoLuminanceSource(
     LuminanceType aLuminanceType, float aOpacity) {
+  if (!EnsureInitialized()) {
+    return nullptr;
+  }
   if ((aLuminanceType != LuminanceType::LUMINANCE) ||
       // See bug 1372577, some race condition where we get invalid
       // results with D2D in the parent process. Fallback in that case.
       XRE_IsParentProcess()) {
     return DrawTarget::IntoLuminanceSource(aLuminanceType, aOpacity);
   }
 
   // Create the luminance effect
@@ -263,16 +271,19 @@ void DrawTargetD2D1::DrawFilter(FilterNo
   FinalizeDrawing(aOptions.mCompositionOp, ColorPattern(Color()));
 }
 
 void DrawTargetD2D1::DrawSurfaceWithShadow(SourceSurface *aSurface,
                                            const Point &aDest,
                                            const Color &aColor,
                                            const Point &aOffset, Float aSigma,
                                            CompositionOp aOperator) {
+  if (!EnsureInitialized()) {
+    return;
+  }
   MarkChanged();
   mDC->SetTransform(D2D1::IdentityMatrix());
   mTransformDirty = true;
 
   Matrix mat;
   RefPtr<ID2D1Image> image =
       GetImageForSurface(aSurface, mat, ExtendMode::CLAMP, nullptr, false);
 
@@ -315,16 +326,19 @@ void DrawTargetD2D1::DrawSurfaceWithShad
   if (aSurface->GetFormat() != SurfaceFormat::A8) {
     D2D1_POINT_2F imgPoint = D2DPoint(aDest);
     mDC->DrawImage(image, &imgPoint, nullptr, D2D1_INTERPOLATION_MODE_LINEAR,
                    D2DCompositionMode(aOperator));
   }
 }
 
 void DrawTargetD2D1::ClearRect(const Rect &aRect) {
+  if (!EnsureInitialized()) {
+    return;
+  }
   MarkChanged();
 
   PopAllClips();
 
   PushClipRect(aRect);
 
   if (mTransformDirty || !mTransform.IsIdentity()) {
     mDC->SetTransform(D2D1::IdentityMatrix());
@@ -371,16 +385,19 @@ void DrawTargetD2D1::ClearRect(const Rec
 
   PopClip();
 
   return;
 }
 
 void DrawTargetD2D1::MaskSurface(const Pattern &aSource, SourceSurface *aMask,
                                  Point aOffset, const DrawOptions &aOptions) {
+  if (!EnsureInitialized()) {
+    return;
+  }
   MarkChanged();
 
   RefPtr<ID2D1Bitmap> bitmap;
 
   Matrix mat = Matrix::Translation(aOffset);
   RefPtr<ID2D1Image> image =
       GetImageForSurface(aMask, mat, ExtendMode::CLAMP, nullptr);
 
@@ -447,16 +464,19 @@ void DrawTargetD2D1::MaskSurface(const P
   mDC->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
 
   FinalizeDrawing(aOptions.mCompositionOp, aSource);
 }
 
 void DrawTargetD2D1::CopySurface(SourceSurface *aSurface,
                                  const IntRect &aSourceRect,
                                  const IntPoint &aDestination) {
+  if (!EnsureInitialized()) {
+    return;
+  }
   MarkChanged();
 
   PopAllClips();
 
   mDC->SetTransform(D2D1::IdentityMatrix());
   mTransformDirty = true;
 
   Matrix mat = Matrix::Translation(aDestination.x - aSourceRect.X(),
@@ -783,23 +803,29 @@ void DrawTargetD2D1::PushClipGeometry(ID
   }
 }
 
 void DrawTargetD2D1::PushClip(const Path *aPath) {
   if (aPath->GetBackendType() != BackendType::DIRECT2D1_1) {
     gfxDebug() << *this << ": Ignoring clipping call for incompatible path.";
     return;
   }
+  if (!EnsureInitialized()) {
+    return;
+  }
 
   RefPtr<PathD2D> pathD2D = static_cast<PathD2D *>(const_cast<Path *>(aPath));
 
   PushClipGeometry(pathD2D->GetGeometry(), D2DMatrix(mTransform));
 }
 
 void DrawTargetD2D1::PushClipRect(const Rect &aRect) {
+  if (!EnsureInitialized()) {
+    return;
+  }
   if (!mTransform.IsRectilinear()) {
     // Whoops, this isn't a rectangle in device space, Direct2D will not deal
     // with this transform the way we want it to.
     // See remarks:
     // http://msdn.microsoft.com/en-us/library/dd316860%28VS.85%29.aspx
     RefPtr<ID2D1Geometry> geom = ConvertRectToGeometry(D2DRect(aRect));
     return PushClipGeometry(geom, D2DMatrix(mTransform));
   }
@@ -823,16 +849,19 @@ void DrawTargetD2D1::PushClipRect(const 
     mDC->PushAxisAlignedClip(
         clip.mBounds, clip.mIsPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED
                                            : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
   }
 }
 
 void DrawTargetD2D1::PushDeviceSpaceClipRects(const IntRect *aRects,
                                               uint32_t aCount) {
+  if (!EnsureInitialized()) {
+    return;
+  }
   // Build a path for the union of the rects.
   RefPtr<ID2D1PathGeometry> path;
   factory()->CreatePathGeometry(getter_AddRefs(path));
   RefPtr<ID2D1GeometrySink> sink;
   path->Open(getter_AddRefs(sink));
   sink->SetFillMode(D2D1_FILL_MODE_WINDING);
   for (uint32_t i = 0; i < aCount; i++) {
     const IntRect &rect = aRects[i];
@@ -846,16 +875,19 @@ void DrawTargetD2D1::PushDeviceSpaceClip
   sink->Close();
 
   // The path is in device-space, so there is no transform needed,
   // and all rects are pixel aligned.
   PushClipGeometry(path, D2D1::IdentityMatrix(), true);
 }
 
 void DrawTargetD2D1::PopClip() {
+  if (!EnsureInitialized()) {
+    return;
+  }
   mCurrentClippedGeometry = nullptr;
   if (CurrentLayer().mPushedClips.empty()) {
     gfxDevCrash(LogReason::UnbalancedClipStack)
         << "DrawTargetD2D1::PopClip: No clip to pop.";
     return;
   }
 
   if (CurrentLayer().mClipsArePushed) {
@@ -867,16 +899,19 @@ void DrawTargetD2D1::PopClip() {
   }
   CurrentLayer().mPushedClips.pop_back();
 }
 
 void DrawTargetD2D1::PushLayer(bool aOpaque, Float aOpacity,
                                SourceSurface *aMask,
                                const Matrix &aMaskTransform,
                                const IntRect &aBounds, bool aCopyBackground) {
+  if (!EnsureInitialized()) {
+    return;
+  }
   D2D1_LAYER_OPTIONS1 options = D2D1_LAYER_OPTIONS1_NONE;
 
   if (aOpaque) {
     options |= D2D1_LAYER_OPTIONS1_IGNORE_ALPHA;
   }
   if (aCopyBackground) {
     options |= D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND;
   }
@@ -935,17 +970,19 @@ void DrawTargetD2D1::PushLayer(bool aOpa
 
   mDC->SetTarget(CurrentTarget());
 
   mUsedCommandListsSincePurge++;
 }
 
 void DrawTargetD2D1::PopLayer() {
   MOZ_ASSERT(CurrentLayer().mPushedClips.size() == 0);
-
+  if (!EnsureInitialized()) {
+    return;
+  }
   RefPtr<ID2D1CommandList> list = CurrentLayer().mCurrentList;
   mPermitSubpixelAA = CurrentLayer().mOldPermitSubpixelAA;
 
   mPushedLayers.pop_back();
   mDC->SetTarget(CurrentTarget());
 
   list->Close();
   mDC->SetTransform(D2D1::IdentityMatrix());
@@ -959,48 +996,50 @@ void DrawTargetD2D1::PopLayer() {
   mDC->PopLayer();
 }
 
 already_AddRefed<SourceSurface> DrawTargetD2D1::CreateSourceSurfaceFromData(
     unsigned char *aData, const IntSize &aSize, int32_t aStride,
     SurfaceFormat aFormat) const {
   RefPtr<ID2D1Bitmap1> bitmap;
 
-  HRESULT hr =
-      mDC->CreateBitmap(D2DIntSize(aSize), aData, aStride,
-                        D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_NONE,
-                                                D2DPixelFormat(aFormat)),
-                        getter_AddRefs(bitmap));
+  HRESULT hr = Factory::GetD2DDeviceContext()->CreateBitmap(
+      D2DIntSize(aSize), aData, aStride,
+      D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_NONE,
+                              D2DPixelFormat(aFormat)),
+      getter_AddRefs(bitmap));
 
   if (FAILED(hr) || !bitmap) {
     gfxCriticalError(
         CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(aSize)))
         << "[D2D1.1] 1CreateBitmap failure " << aSize << " Code: " << hexa(hr)
         << " format " << (int)aFormat;
     return nullptr;
   }
 
-  return MakeAndAddRef<SourceSurfaceD2D1>(bitmap.get(), mDC, aFormat, aSize);
+  return MakeAndAddRef<SourceSurfaceD2D1>(
+      bitmap.get(), Factory::GetD2DDeviceContext().get(), aFormat, aSize);
 }
 
 already_AddRefed<DrawTarget> DrawTargetD2D1::CreateSimilarDrawTarget(
     const IntSize &aSize, SurfaceFormat aFormat) const {
   RefPtr<DrawTargetD2D1> dt = new DrawTargetD2D1();
 
   if (!dt->Init(aSize, aFormat)) {
     return nullptr;
   }
 
   return dt.forget();
 }
 
 bool DrawTargetD2D1::CanCreateSimilarDrawTarget(const IntSize &aSize,
                                                 SurfaceFormat aFormat) const {
-  return (mDC->GetMaximumBitmapSize() >= UINT32(aSize.width) &&
-          mDC->GetMaximumBitmapSize() >= UINT32(aSize.height));
+  RefPtr<ID2D1DeviceContext> dc = Factory::GetD2DDeviceContext();
+  return (dc->GetMaximumBitmapSize() >= UINT32(aSize.width) &&
+          dc->GetMaximumBitmapSize() >= UINT32(aSize.height));
 }
 
 already_AddRefed<PathBuilder> DrawTargetD2D1::CreatePathBuilder(
     FillRule aFillRule) const {
   RefPtr<ID2D1PathGeometry> path;
   HRESULT hr = factory()->CreatePathGeometry(getter_AddRefs(path));
 
   if (FAILED(hr)) {
@@ -1037,17 +1076,17 @@ already_AddRefed<GradientStops> DrawTarg
 
   for (uint32_t i = 0; i < aNumStops; i++) {
     stops[i].position = rawStops[i].offset;
     stops[i].color = D2DColor(rawStops[i].color);
   }
 
   RefPtr<ID2D1GradientStopCollection1> stopCollection;
 
-  HRESULT hr = mDC->CreateGradientStopCollection(
+  HRESULT hr = Factory::GetD2DDeviceContext()->CreateGradientStopCollection(
       stops, aNumStops, D2D1_COLOR_SPACE_SRGB, D2D1_COLOR_SPACE_SRGB,
       D2D1_BUFFER_PRECISION_8BPC_UNORM, D2DExtend(aExtendMode, Axis::BOTH),
       D2D1_COLOR_INTERPOLATION_MODE_PREMULTIPLIED,
       getter_AddRefs(stopCollection));
   delete[] stops;
 
   if (FAILED(hr)) {
     gfxWarning() << *this << ": Failed to create GradientStopCollection. Code: "
@@ -1055,16 +1094,19 @@ already_AddRefed<GradientStops> DrawTarg
     return nullptr;
   }
 
   RefPtr<ID3D11Device> device = Factory::GetDirect3D11Device();
   return MakeAndAddRef<GradientStopsD2D>(stopCollection, device);
 }
 
 already_AddRefed<FilterNode> DrawTargetD2D1::CreateFilter(FilterType aType) {
+  if (!EnsureInitialized()) {
+    return nullptr;
+  }
   return FilterNodeD2D1::Create(mDC, aType);
 }
 
 void DrawTargetD2D1::GetGlyphRasterizationMetrics(ScaledFont *aScaledFont,
                                                   const uint16_t *aGlyphIndices,
                                                   uint32_t aNumGlyphs,
                                                   GlyphMetrics *aGlyphMetrics) {
   MOZ_ASSERT(aScaledFont->GetType() == FontType::DWRITE);
@@ -1077,145 +1119,54 @@ void DrawTargetD2D1::GetGlyphRasterizati
     if (aGlyphMetrics[i].mWidth > 0 && aGlyphMetrics[i].mHeight > 0) {
       aGlyphMetrics[i].mWidth += 2.0f;
       aGlyphMetrics[i].mXBearing -= 1.0f;
     }
   }
 }
 
 bool DrawTargetD2D1::Init(ID3D11Texture2D *aTexture, SurfaceFormat aFormat) {
-  HRESULT hr;
-
   RefPtr<ID2D1Device> device = Factory::GetD2D1Device(&mDeviceSeq);
   if (!device) {
     gfxCriticalNote << "[D2D1.1] Failed to obtain a device for "
                        "DrawTargetD2D1::Init(ID3D11Texture2D*, SurfaceFormat).";
     return false;
   }
 
-  hr = device->CreateDeviceContext(
-      D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS,
-      getter_AddRefs(mDC));
-
-  if (FAILED(hr)) {
-    gfxCriticalError() << "[D2D1.1] 1Failed to create a DeviceContext, code: "
-                       << hexa(hr) << " format " << (int)aFormat;
-    return false;
-  }
-
-  RefPtr<IDXGISurface> dxgiSurface;
   aTexture->QueryInterface(
       __uuidof(IDXGISurface),
-      (void **)((IDXGISurface **)getter_AddRefs(dxgiSurface)));
-  if (!dxgiSurface) {
+      (void **)((IDXGISurface **)getter_AddRefs(mSurface)));
+  if (!mSurface) {
     gfxCriticalError() << "[D2D1.1] Failed to obtain a DXGI surface.";
     return false;
   }
 
-  D2D1_BITMAP_PROPERTIES1 props;
-  props.dpiX = 96;
-  props.dpiY = 96;
-  props.pixelFormat = D2DPixelFormat(aFormat);
-  props.colorContext = nullptr;
-  props.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET;
-  hr = mDC->CreateBitmapFromDxgiSurface(
-      dxgiSurface, props, (ID2D1Bitmap1 **)getter_AddRefs(mBitmap));
+  mFormat = aFormat;
 
-  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);
   mSize.width = desc.Width;
   mSize.height = desc.Height;
 
-  // 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)) {
-    gfxCriticalError() << "[D2D1.1] Failure creating solid color brush (I1).";
-    return false;
-  }
-
-  mDC->SetTarget(CurrentTarget());
-
-  mDC->BeginDraw();
-
-  CurrentLayer().mIsOpaque = aFormat == SurfaceFormat::B8G8R8X8;
-
   return true;
 }
 
 bool DrawTargetD2D1::Init(const IntSize &aSize, SurfaceFormat aFormat) {
-  HRESULT hr;
-
   RefPtr<ID2D1Device> device = Factory::GetD2D1Device(&mDeviceSeq);
   if (!device) {
     gfxCriticalNote << "[D2D1.1] Failed to obtain a device for "
                        "DrawTargetD2D1::Init(IntSize, SurfaceFormat).";
     return false;
   }
 
-  hr = device->CreateDeviceContext(
-      D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS,
-      getter_AddRefs(mDC));
-
-  if (FAILED(hr)) {
-    gfxCriticalError() << "[D2D1.1] 2Failed to create a DeviceContext, code: "
-                       << hexa(hr) << " format " << (int)aFormat;
-    return false;
-  }
-
-  if (mDC->GetMaximumBitmapSize() < UINT32(aSize.width) ||
-      mDC->GetMaximumBitmapSize() < UINT32(aSize.height)) {
-    // This is 'ok', so don't assert
-    gfxCriticalNote << "[D2D1.1] Attempt to use unsupported surface size "
-                    << aSize;
+  if (!CanCreateSimilarDrawTarget(aSize, aFormat)) {
+    // Size unsupported.
     return false;
   }
 
-  D2D1_BITMAP_PROPERTIES1 props;
-  props.dpiX = 96;
-  props.dpiY = 96;
-  props.pixelFormat = D2DPixelFormat(aFormat);
-  props.colorContext = nullptr;
-  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;
-  }
-
-  mDC->SetTarget(CurrentTarget());
-
-  hr = mDC->CreateSolidColorBrush(D2D1::ColorF(0, 0),
-                                  getter_AddRefs(mSolidColorBrush));
-
-  if (FAILED(hr)) {
-    gfxCriticalError() << "[D2D1.1] Failure creating solid color brush (I2).";
-    return false;
-  }
-
-  mDC->BeginDraw();
-
-  CurrentLayer().mIsOpaque = aFormat == SurfaceFormat::B8G8R8X8;
-
-  mDC->Clear();
-
   mFormat = aFormat;
   mSize = aSize;
 
   return true;
 }
 
 /**
  * Private helpers.
@@ -1317,16 +1268,104 @@ void DrawTargetD2D1::FlushInternal(bool 
   // We no longer depend on any target.
   for (TargetSet::iterator iter = mDependingOnTargets.begin();
        iter != mDependingOnTargets.end(); iter++) {
     (*iter)->mDependentTargets.erase(this);
   }
   mDependingOnTargets.clear();
 }
 
+bool DrawTargetD2D1::EnsureInitialized() {
+  if (mIsInitialized) {
+    return true;
+  }
+
+  HRESULT hr;
+
+  RefPtr<ID2D1Device> device = Factory::GetD2D1Device(&mDeviceSeq);
+  if (!device) {
+    gfxCriticalNote << "[D2D1.1] Failed to obtain a device for "
+                       "DrawTargetD2D1::EnsureInitialized().";
+    return false;
+  }
+
+  hr = device->CreateDeviceContext(
+      D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS,
+      getter_AddRefs(mDC));
+
+  if (FAILED(hr)) {
+    gfxCriticalError() << "[D2D1.1] 2Failed to create a DeviceContext, code: "
+                       << hexa(hr) << " format " << (int)mFormat;
+    return false;
+  }
+
+  if (!mSurface) {
+    if (mDC->GetMaximumBitmapSize() < UINT32(mSize.width) ||
+        mDC->GetMaximumBitmapSize() < UINT32(mSize.height)) {
+      // This is 'ok', so don't assert
+      gfxCriticalNote << "[D2D1.1] Attempt to use unsupported surface size "
+                      << mSize;
+      return false;
+    }
+
+    D2D1_BITMAP_PROPERTIES1 props;
+    props.dpiX = 96;
+    props.dpiY = 96;
+    props.pixelFormat = D2DPixelFormat(mFormat);
+    props.colorContext = nullptr;
+    props.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET;
+    hr = mDC->CreateBitmap(D2DIntSize(mSize), nullptr, 0, props,
+                           (ID2D1Bitmap1 **)getter_AddRefs(mBitmap));
+
+    if (FAILED(hr)) {
+      gfxCriticalError() << "[D2D1.1] 3CreateBitmap failure " << mSize
+                         << " Code: " << hexa(hr) << " format " << (int)mFormat;
+      return false;
+    }
+  } else {
+    D2D1_BITMAP_PROPERTIES1 props;
+    props.dpiX = 96;
+    props.dpiY = 96;
+    props.pixelFormat = D2DPixelFormat(mFormat);
+    props.colorContext = nullptr;
+    props.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET;
+    hr = mDC->CreateBitmapFromDxgiSurface(
+        mSurface, props, (ID2D1Bitmap1 **)getter_AddRefs(mBitmap));
+
+    if (FAILED(hr)) {
+      gfxCriticalError()
+          << "[D2D1.1] CreateBitmapFromDxgiSurface failure Code: " << hexa(hr)
+          << " format " << (int)mFormat;
+      return false;
+    }
+  }
+
+  mDC->SetTarget(CurrentTarget());
+
+  hr = mDC->CreateSolidColorBrush(D2D1::ColorF(0, 0),
+                                  getter_AddRefs(mSolidColorBrush));
+
+  if (FAILED(hr)) {
+    gfxCriticalError() << "[D2D1.1] Failure creating solid color brush (I2).";
+    return false;
+  }
+
+  mDC->BeginDraw();
+
+  CurrentLayer().mIsOpaque = mFormat == SurfaceFormat::B8G8R8X8;
+
+  if (!mSurface) {
+    mDC->Clear();
+  }
+
+  mIsInitialized = true;
+
+  return true;
+}
+
 void DrawTargetD2D1::MarkChanged() {
   if (mSnapshot) {
     MutexAutoLock lock(*mSnapshotLock);
     if (mSnapshot->hasOneRef()) {
       // Just destroy it, since no-one else knows about it.
       mSnapshot = nullptr;
     } else {
       mSnapshot->DrawTargetWillChange();
@@ -1356,16 +1395,19 @@ bool DrawTargetD2D1::ShouldClipTemporary
   bool patternSupported = IsPatternSupportedByD2D(aPattern);
   return patternSupported && !CurrentLayer().mIsOpaque &&
          D2DSupportsCompositeMode(aOp) && IsOperatorBoundByMask(aOp) &&
          aClipIsComplex;
 }
 
 void DrawTargetD2D1::PrepareForDrawing(CompositionOp aOp,
                                        const Pattern &aPattern) {
+  if (!EnsureInitialized()) {
+    return;
+  }
   MarkChanged();
 
   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();
@@ -2075,17 +2117,17 @@ already_AddRefed<SourceSurface> DrawTarg
 
   RefPtr<ID2D1Bitmap1> bitmap;
   {
     DataSourceSurface::ScopedMap map(data, DataSourceSurface::READ);
     if (MOZ2D_WARN_IF(!map.IsMapped())) {
       return nullptr;
     }
 
-    HRESULT hr = mDC->CreateBitmap(
+    HRESULT hr = Factory::GetD2DDeviceContext()->CreateBitmap(
         D2DIntSize(data->GetSize()), map.GetData(), map.GetStride(),
         D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_NONE,
                                 D2DPixelFormat(data->GetFormat())),
         getter_AddRefs(bitmap));
 
     if (FAILED(hr)) {
       gfxCriticalError(CriticalLog::DefaultOptions(
           Factory::ReasonableSurfaceSize(data->GetSize())))
@@ -2093,18 +2135,19 @@ already_AddRefed<SourceSurface> DrawTarg
           << " Code: " << hexa(hr) << " format " << (int)data->GetFormat();
     }
   }
 
   if (!bitmap) {
     return data.forget();
   }
 
-  return MakeAndAddRef<SourceSurfaceD2D1>(bitmap.get(), mDC, data->GetFormat(),
-                                          data->GetSize());
+  return MakeAndAddRef<SourceSurfaceD2D1>(bitmap.get(),
+                                          Factory::GetD2DDeviceContext().get(),
+                                          data->GetFormat(), data->GetSize());
 }
 
 void DrawTargetD2D1::PushD2DLayer(ID2D1DeviceContext *aDC,
                                   ID2D1Geometry *aGeometry,
                                   const D2D1_MATRIX_3X2_F &aTransform,
                                   bool aPixelAligned, bool aForceIgnoreAlpha,
                                   const D2D1_RECT_F &aMaxRect) {
   D2D1_LAYER_OPTIONS1 options = D2D1_LAYER_OPTIONS1_NONE;
@@ -2120,13 +2163,13 @@ void DrawTargetD2D1::PushD2DLayer(ID2D1D
 
   mDC->PushLayer(D2D1::LayerParameters1(aMaxRect, aGeometry, antialias,
                                         aTransform, 1.0, nullptr, options),
                  nullptr);
 }
 
 bool DrawTargetD2D1::IsDeviceContextValid() {
   uint32_t seqNo;
-  return Factory::GetD2D1Device(&seqNo) && seqNo == mDeviceSeq;
+  return mDC && Factory::GetD2D1Device(&seqNo) && seqNo == mDeviceSeq;
 }
 
 }  // namespace gfx
 }  // namespace mozilla
--- a/gfx/2d/DrawTargetD2D1.h
+++ b/gfx/2d/DrawTargetD2D1.h
@@ -169,16 +169,17 @@ class DrawTargetD2D1 : public DrawTarget
 
   static uint64_t mVRAMUsageDT;
   static uint64_t mVRAMUsageSS;
 
  private:
   friend class SourceSurfaceD2D1;
 
   void FlushInternal(bool aHasDependencyMutex = false);
+  bool EnsureInitialized();
 
   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,
@@ -306,14 +307,17 @@ class DrawTargetD2D1 : public DrawTarget
   static StaticRefPtr<ID2D1Factory1> mFactory;
   // This value is uesed to verify if the DrawTarget is created by a stale
   // device.
   uint32_t mDeviceSeq;
 
   // List of effects we use
   bool EnsureLuminanceEffect();
   RefPtr<ID2D1Effect> mLuminanceEffect;
+
+  bool mIsInitialized;
+  RefPtr<IDXGISurface> mSurface;
 };
 
 }  // namespace gfx
 }  // namespace mozilla
 
 #endif /* MOZILLA_GFX_DRAWTARGETD2D_H_ */
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -198,16 +198,18 @@ StaticMutex Factory::mFTLock;
 #endif
 
 #ifdef WIN32
 // Note: mDeviceLock must be held when mutating these values.
 static uint32_t mDeviceSeq = 0;
 StaticRefPtr<ID3D11Device> Factory::mD3D11Device;
 StaticRefPtr<ID2D1Device> Factory::mD2D1Device;
 StaticRefPtr<IDWriteFactory> Factory::mDWriteFactory;
+StaticRefPtr<ID2D1DeviceContext> Factory::mMTDC;
+StaticRefPtr<ID2D1DeviceContext> Factory::mOffMTDC;
 bool Factory::mDWriteFactoryInitialized = false;
 StaticRefPtr<IDWriteFontCollection> Factory::mDWriteSystemFonts;
 StaticMutex Factory::mDeviceLock;
 StaticMutex Factory::mDTDependencyLock;
 #endif
 
 DrawEventRecorder* Factory::mRecorder;
 
@@ -750,16 +752,18 @@ bool Factory::SetDirect3D11Device(ID3D11
   RefPtr<ID2D1Factory1> factory = D2DFactory();
 
   StaticMutexAutoLock lock(mDeviceLock);
 
   mD3D11Device = aDevice;
 
   if (mD2D1Device) {
     mD2D1Device = nullptr;
+    mMTDC = nullptr;
+    mOffMTDC = nullptr;
   }
 
   if (!aDevice) {
     return true;
   }
 
   RefPtr<IDXGIDevice> device;
   aDevice->QueryInterface((IDXGIDevice**)getter_AddRefs(device));
@@ -848,16 +852,44 @@ RefPtr<IDWriteFontCollection> Factory::G
     gfxWarning() << "Failed to create DWrite system font collection";
     return nullptr;
   }
   mDWriteSystemFonts = systemFonts;
 
   return mDWriteSystemFonts;
 }
 
+RefPtr<ID2D1DeviceContext> Factory::GetD2DDeviceContext() {
+  StaticRefPtr<ID2D1DeviceContext>* ptr;
+
+  if (NS_IsMainThread()) {
+    ptr = &mMTDC;
+  } else {
+    ptr = &mOffMTDC;
+  }
+
+  if (*ptr) {
+    return *ptr;
+  }
+
+  RefPtr<ID2D1DeviceContext> dc;
+  HRESULT hr = mD2D1Device->CreateDeviceContext(
+      D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS,
+      getter_AddRefs(dc));
+
+  if (FAILED(hr)) {
+    gfxCriticalError() << "Failed to create global device context";
+    return nullptr;
+  }
+
+  *ptr = dc;
+
+  return *ptr;
+}
+
 bool Factory::SupportsD2D1() { return !!D2DFactory(); }
 
 BYTE sSystemTextQuality = CLEARTYPE_QUALITY;
 void Factory::SetSystemTextQuality(uint8_t aQuality) {
   sSystemTextQuality = aQuality;
 }
 
 uint64_t Factory::GetD2DVRAMUsageDrawTarget() {