diff --git a/gfx/layers/ipc/CanvasTranslator.cpp b/gfx/layers/ipc/CanvasTranslator.cpp index 6b5fea3082bb..491a5fda178b 100644 --- a/gfx/layers/ipc/CanvasTranslator.cpp +++ b/gfx/layers/ipc/CanvasTranslator.cpp @@ -526,6 +526,9 @@ bool CanvasTranslator::TryDrawTargetWebglFallback( NotifyRequiresRefresh(aTextureOwnerId); const auto& info = mTextureInfo[aTextureOwnerId]; + if (info.mTextureData) { + return true; + } if (RefPtr dt = CreateFallbackDrawTarget(info.mRefPtr, aTextureOwnerId, aWebgl->GetSize(), aWebgl->GetFormat())) { @@ -926,6 +929,9 @@ void CanvasTranslator::DeviceResetAcknowledged() { DeviceChangeAcknowledged(); } bool CanvasTranslator::CreateReferenceTexture() { if (mReferenceTextureData) { + if (mBaseDT) { + mReferenceTextureData->ReturnDrawTarget(mBaseDT.forget()); + } mReferenceTextureData->Unlock(); } @@ -1097,14 +1103,12 @@ void CanvasTranslator::PrepareShmem( const RemoteTextureOwnerId aTextureOwnerId) { if (gfx::DrawTargetWebgl* webgl = GetDrawTargetWebgl(aTextureOwnerId, false)) { - if (const auto& fallback = mTextureInfo[aTextureOwnerId].mTextureData) { + if (RefPtr dt = + mTextureInfo[aTextureOwnerId].mFallbackDrawTarget) { // If there was a fallback, copy the fallback to the software framebuffer // shmem for reading. - if (RefPtr dt = fallback->BorrowDrawTarget()) { - if (RefPtr snapshot = dt->Snapshot()) { - webgl->CopySurface(snapshot, snapshot->GetRect(), - gfx::IntPoint(0, 0)); - } + if (RefPtr snapshot = dt->Snapshot()) { + webgl->CopySurface(snapshot, snapshot->GetRect(), gfx::IntPoint(0, 0)); } } else { // Otherwise, just ensure the software framebuffer is up to date. @@ -1207,6 +1211,7 @@ already_AddRefed CanvasTranslator::CreateFallbackDrawTarget( TextureInfo& info = mTextureInfo[aTextureOwnerId]; info.mRefPtr = aRefPtr; + info.mFallbackDrawTarget = dt; info.mTextureData = std::move(textureData); info.mTextureLockMode = kInitMode; } while (!dt && CheckForFreshCanvasDevice(__LINE__)); @@ -1223,6 +1228,19 @@ already_AddRefed CanvasTranslator::CreateDrawTarget( return nullptr; } + { + auto result = mTextureInfo.find(aTextureOwnerId); + if (result != mTextureInfo.end()) { + const TextureInfo& info = result->second; + if (info.mTextureData || info.mDrawTarget) { +#ifndef FUZZING_SNAPSHOT + MOZ_DIAGNOSTIC_CRASH("DrawTarget already exists"); +#endif + return nullptr; + } + } + } + RefPtr dt; if (gfx::gfxVars::UseAcceleratedCanvas2D()) { if (EnsureSharedContextWebgl()) { @@ -1287,7 +1305,11 @@ void CanvasTranslator::RemoveTexture(const RemoteTextureOwnerId aTextureOwnerId, if (--info.mLocked > 0) { return; } + RemoveDrawTarget(info.mRefPtr); if (info.mTextureData) { + if (info.mFallbackDrawTarget) { + info.mTextureData->ReturnDrawTarget(info.mFallbackDrawTarget.forget()); + } info.mTextureData->Unlock(); } if (mRemoteTextureOwner) { @@ -1455,9 +1477,13 @@ void CanvasTranslator::ClearTextureInfo() { mUsedWrapperForSurfaceDescriptor = nullptr; mUsedSurfaceDescriptorForSurfaceDescriptor = Nothing(); - for (auto const& entry : mTextureInfo) { - if (entry.second.mTextureData) { - entry.second.mTextureData->Unlock(); + for (auto& entry : mTextureInfo) { + auto& info = entry.second; + if (info.mTextureData) { + if (info.mFallbackDrawTarget) { + info.mTextureData->ReturnDrawTarget(info.mFallbackDrawTarget.forget()); + } + info.mTextureData->Unlock(); } } mTextureInfo.clear(); @@ -1470,8 +1496,10 @@ void CanvasTranslator::ClearTextureInfo() { if (sSharedContext && sSharedContext->hasOneRef()) { sSharedContext->ClearCaches(); } - mBaseDT = nullptr; if (mReferenceTextureData) { + if (mBaseDT) { + mReferenceTextureData->ReturnDrawTarget(mBaseDT.forget()); + } mReferenceTextureData->Unlock(); } if (mRemoteTextureOwner) { diff --git a/gfx/layers/ipc/CanvasTranslator.h b/gfx/layers/ipc/CanvasTranslator.h index 2f567cb22bee..6e15cc130801 100644 --- a/gfx/layers/ipc/CanvasTranslator.h +++ b/gfx/layers/ipc/CanvasTranslator.h @@ -560,6 +560,7 @@ class CanvasTranslator final : public gfx::InlineTranslator, gfx::ReferencePtr mRefPtr; UniquePtr mTextureData; RefPtr mDrawTarget; + RefPtr mFallbackDrawTarget; bool mNotifiedRequiresRefresh = false; // Ref-count of how active uses of the DT. Avoids deletion when locked. int32_t mLocked = 1;