Bug 1524554: Ensure Canvas surfaces are initialized on the main thread and ensure their validity. r=rhunt
authorBas Schouten <bschouten@mozilla.com>
Fri, 01 Feb 2019 13:18:55 +0100
changeset 456653 161ce405f2e077be8ad56ee6f521720bdc68baef
parent 456610 55bcbbc351541e7b942a958b2eb58156d670808b
child 456654 be4b4f86782314fb58838dbcf57e06044499413c
push id77397
push userbtara@mozilla.com
push dateMon, 04 Feb 2019 17:40:17 +0000
treeherderautoland@d1fc75359013 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrhunt
bugs1524554
milestone67.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 1524554: Ensure Canvas surfaces are initialized on the main thread and ensure their validity. r=rhunt This isn't the prettiest solution but it's minimally invasive. More long-term a better solution may be to expose a call on DrawTargets to ensure their initialization even if they're on the main thread. IsValid probably isn't a good candidate for this as we want it to be usable freely on the main thread to ensure none of the basic conditions of the surface are still valid. Differential Revision: https://phabricator.services.mozilla.com/D18339
gfx/2d/DrawTargetD2D1.cpp
gfx/layers/PersistentBufferProvider.cpp
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -339,16 +339,22 @@ void DrawTargetD2D1::DrawSurfaceWithShad
                    D2DCompositionMode(aOperator));
   }
 }
 
 void DrawTargetD2D1::ClearRect(const Rect &aRect) {
   if (!EnsureInitialized()) {
     return;
   }
+
+  if (aRect.IsEmpty()) {
+    // Nothing to be done.
+    return;
+  }
+
   MarkChanged();
 
   PopAllClips();
 
   PushClipRect(aRect);
 
   if (mTransformDirty || !mTransform.IsIdentity()) {
     mDC->SetTransform(D2D1::IdentityMatrix());
--- a/gfx/layers/PersistentBufferProvider.cpp
+++ b/gfx/layers/PersistentBufferProvider.cpp
@@ -72,17 +72,23 @@ void PersistentBufferProviderBasic::Dest
 already_AddRefed<PersistentBufferProviderBasic>
 PersistentBufferProviderBasic::Create(gfx::IntSize aSize,
                                       gfx::SurfaceFormat aFormat,
                                       gfx::BackendType aBackend) {
   RefPtr<DrawTarget> dt =
       gfxPlatform::GetPlatform()->CreateDrawTargetForBackend(aBackend, aSize,
                                                              aFormat);
 
-  if (!dt) {
+  if (dt) {
+    // This is simply to ensure the DrawTarget gets initialized, and will detect a
+    // device reset, even if we're on the main thread.
+    dt->ClearRect(Rect(0, 0, 0, 0));
+  }
+
+  if (!dt || !dt->IsValid()) {
     return nullptr;
   }
 
   RefPtr<PersistentBufferProviderBasic> provider =
       new PersistentBufferProviderBasic(dt);
 
   return provider.forget();
 }
@@ -334,16 +340,26 @@ PersistentBufferProviderShared::BorrowDr
       MOZ_ASSERT(success);
 
       previous->Unlock();
     }
   }
 
   mDrawTarget = tex->BorrowDrawTarget();
 
+  if (mDrawTarget) {
+    // This is simply to ensure the DrawTarget gets initialized, and will detect a
+    // device reset, even if we're on the main thread.
+    mDrawTarget->ClearRect(Rect(0, 0, 0, 0));
+
+    if (!mDrawTarget->IsValid()) {
+      mDrawTarget = nullptr;
+    }
+  }
+
   RefPtr<gfx::DrawTarget> dt(mDrawTarget);
   return dt.forget();
 }
 
 bool PersistentBufferProviderShared::ReturnDrawTarget(
     already_AddRefed<gfx::DrawTarget> aDT) {
   RefPtr<gfx::DrawTarget> dt(aDT);
   MOZ_ASSERT(mDrawTarget == dt);