Bug 1639626: Hold BackendType in CanvasTranslator to guard against the reference DrawTarget being null. r=mattwoodrow
authorBob Owen <bobowencode@gmail.com>
Thu, 21 May 2020 00:05:27 +0000
changeset 531392 29b8614020142dfcf89a3df60f3cbad23d992f84
parent 531391 e1a8383cf9f9d914a35efd6298e3c7990e1e37f7
child 531393 959fb2c1e8daea3a2cb47aa012c8fe290e0fdf64
push id37439
push userbtara@mozilla.com
push dateThu, 21 May 2020 21:49:34 +0000
treeherdermozilla-central@92c11f0bf14b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1639626
milestone78.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 1639626: Hold BackendType in CanvasTranslator to guard against the reference DrawTarget being null. r=mattwoodrow Differential Revision: https://phabricator.services.mozilla.com/D76177
gfx/layers/RecordedCanvasEventImpl.h
gfx/layers/ipc/CanvasTranslator.cpp
gfx/layers/ipc/CanvasTranslator.h
--- a/gfx/layers/RecordedCanvasEventImpl.h
+++ b/gfx/layers/RecordedCanvasEventImpl.h
@@ -151,18 +151,17 @@ class RecordedTextureLock final
 
 inline bool RecordedTextureLock::PlayCanvasEvent(
     CanvasTranslator* aTranslator) const {
   TextureData* textureData = aTranslator->LookupTextureData(mDT);
   if (!textureData) {
     return false;
   }
 
-  gfx::AutoSerializeWithMoz2D serializeWithMoz2D(
-      aTranslator->GetReferenceDrawTarget()->GetBackendType());
+  gfx::AutoSerializeWithMoz2D serializeWithMoz2D(aTranslator->GetBackendType());
   textureData->Lock(mMode);
   return true;
 }
 
 template <class S>
 void RecordedTextureLock::Record(S& aStream) const {
   WriteElement(aStream, mDT);
   WriteElement(aStream, mMode);
@@ -198,18 +197,17 @@ class RecordedTextureUnlock final
 
 inline bool RecordedTextureUnlock::PlayCanvasEvent(
     CanvasTranslator* aTranslator) const {
   TextureData* textureData = aTranslator->LookupTextureData(mDT);
   if (!textureData) {
     return false;
   }
 
-  gfx::AutoSerializeWithMoz2D serializeWithMoz2D(
-      aTranslator->GetReferenceDrawTarget()->GetBackendType());
+  gfx::AutoSerializeWithMoz2D serializeWithMoz2D(aTranslator->GetBackendType());
   textureData->Unlock();
   return true;
 }
 
 template <class S>
 void RecordedTextureUnlock::Record(S& aStream) const {
   WriteElement(aStream, mDT);
 }
--- a/gfx/layers/ipc/CanvasTranslator.cpp
+++ b/gfx/layers/ipc/CanvasTranslator.cpp
@@ -274,18 +274,17 @@ void CanvasTranslator::BeginTransaction(
 
 void CanvasTranslator::Flush() {
 #if defined(XP_WIN)
   // We can end up without a device, due to a reset and failure to re-create.
   if (!mDevice) {
     return;
   }
 
-  gfx::AutoSerializeWithMoz2D serializeWithMoz2D(
-      GetReferenceDrawTarget()->GetBackendType());
+  gfx::AutoSerializeWithMoz2D serializeWithMoz2D(GetBackendType());
   RefPtr<ID3D11DeviceContext> deviceContext;
   mDevice->GetImmediateContext(getter_AddRefs(deviceContext));
   deviceContext->Flush();
 #endif
 }
 
 void CanvasTranslator::EndTransaction() {
   Flush();
@@ -307,16 +306,19 @@ bool CanvasTranslator::CreateReferenceTe
   mReferenceTextureData.reset(CreateTextureData(
       mTextureType, gfx::IntSize(1, 1), gfx::SurfaceFormat::B8G8R8A8));
   if (!mReferenceTextureData) {
     return false;
   }
 
   mReferenceTextureData->Lock(OpenMode::OPEN_READ_WRITE);
   mBaseDT = mReferenceTextureData->BorrowDrawTarget();
+  if (mBaseDT) {
+    mBackendType = mBaseDT->GetBackendType();
+  }
   return true;
 }
 
 bool CanvasTranslator::CheckForFreshCanvasDevice(int aLineNumber) {
 #if defined(XP_WIN)
   // If a new device has already been created, use that one.
   RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetCanvasDevice();
   if (device && device != mDevice) {
@@ -376,35 +378,33 @@ void CanvasTranslator::AddSurfaceDescrip
 already_AddRefed<gfx::DrawTarget> CanvasTranslator::CreateDrawTarget(
     gfx::ReferencePtr aRefPtr, const gfx::IntSize& aSize,
     gfx::SurfaceFormat aFormat) {
   RefPtr<gfx::DrawTarget> dt;
   do {
     // It is important that AutoSerializeWithMoz2D is called within the loop
     // and doesn't hold during calls to CheckForFreshCanvasDevice, because that
     // might cause a deadlock with device reset code on the main thread.
-    gfx::AutoSerializeWithMoz2D serializeWithMoz2D(
-        GetReferenceDrawTarget()->GetBackendType());
+    gfx::AutoSerializeWithMoz2D serializeWithMoz2D(GetBackendType());
     TextureData* textureData = CreateTextureData(mTextureType, aSize, aFormat);
     if (textureData) {
       textureData->Lock(OpenMode::OPEN_READ_WRITE);
       mTextureDatas[aRefPtr] = UniquePtr<TextureData>(textureData);
       AddSurfaceDescriptor(aRefPtr, textureData);
       dt = textureData->BorrowDrawTarget();
     }
   } while (!dt && CheckForFreshCanvasDevice(__LINE__));
   AddDrawTarget(aRefPtr, dt);
 
   return dt.forget();
 }
 
 void CanvasTranslator::RemoveDrawTarget(gfx::ReferencePtr aDrawTarget) {
   InlineTranslator::RemoveDrawTarget(aDrawTarget);
-  gfx::AutoSerializeWithMoz2D serializeWithMoz2D(
-      GetReferenceDrawTarget()->GetBackendType());
+  gfx::AutoSerializeWithMoz2D serializeWithMoz2D(GetBackendType());
   mTextureDatas.erase(aDrawTarget);
 
   // It is possible that the texture from the content process has never been
   // forwarded to the GPU process, so we have to make sure it is removed here
   // otherwise if the same pointer gets used for a DrawTarget again in the
   // content process then it could pick up the old (now invalid) descriptor.
   MonitorAutoLock lock(mSurfaceDescriptorsMonitor);
   mSurfaceDescriptors.erase(aDrawTarget);
--- a/gfx/layers/ipc/CanvasTranslator.h
+++ b/gfx/layers/ipc/CanvasTranslator.h
@@ -237,16 +237,21 @@ class CanvasTranslator final : public gf
    * Gets the ScopedMap stored using SetPreparedMap.
    *
    * @param aSurface must match the surface from the SetPreparedMap call
    * @returns the ScopedMap if aSurface matches otherwise nullptr
    */
   UniquePtr<gfx::DataSourceSurface::ScopedMap> GetPreparedMap(
       gfx::ReferencePtr aSurface);
 
+  /**
+   * @return the BackendType being used for translation
+   */
+  gfx::BackendType GetBackendType() { return mBackendType; }
+
  private:
   explicit CanvasTranslator(
       already_AddRefed<CanvasThreadHolder> aCanvasThreadHolder);
 
   ~CanvasTranslator();
 
   void Bind(Endpoint<PCanvasParent>&& aEndpoint);
 
@@ -272,16 +277,19 @@ class CanvasTranslator final : public gf
 #if defined(XP_WIN)
   RefPtr<ID3D11Device> mDevice;
 #endif
   // We hold the ring buffer as a UniquePtr so we can drop it once
   // mTranslationTaskQueue has shutdown to break a RefPtr cycle.
   UniquePtr<CanvasEventRingBuffer> mStream;
   TextureType mTextureType = TextureType::Unknown;
   UniquePtr<TextureData> mReferenceTextureData;
+  // Sometimes during device reset our reference DrawTarget can be null, so we
+  // hold the BackendType separately.
+  gfx::BackendType mBackendType = gfx::BackendType::NONE;
   typedef std::unordered_map<void*, UniquePtr<TextureData>> TextureMap;
   TextureMap mTextureDatas;
   nsRefPtrHashtable<nsPtrHashKey<void>, gfx::DataSourceSurface> mDataSurfaces;
   gfx::ReferencePtr mMappedSurface;
   UniquePtr<gfx::DataSourceSurface::ScopedMap> mPreparedMap;
   typedef std::unordered_map<void*, UniquePtr<SurfaceDescriptor>> DescriptorMap;
   DescriptorMap mSurfaceDescriptors;
   Monitor mSurfaceDescriptorsMonitor{