Bug 1989517 - Ensure DrawTarget removed from RecordedTextureDestruction playback. r=aosmond, a=RyanVM

CanvasTranslator::RemoveTexture delayed the call to RemoveDrawTarget till all keepalives are
gone. However, this may take place long after RecordedTextureDestruction actually called
RemoveTexture. This gives time for subsequent DrawTargets with the same ReferencePtr to be
created, causing the wrong DrawTargets to be removed.

This patch ensures that when RemoveTexture is called from a RecordedTextureDestruction event
that the DrawTarget is always removed then and there, rather than waiting.

Differential Revision: https://phabricator.services.mozilla.com/D265867
This commit is contained in:
Lee Salzman
2025-09-24 06:02:23 +00:00
committed by rvandermeulen@mozilla.com
parent 509a406228
commit 1d97d5f6f4
2 changed files with 42 additions and 11 deletions

View File

@@ -533,7 +533,9 @@ bool CanvasTranslator::TryDrawTargetWebglFallback(
CreateFallbackDrawTarget(info.mRefPtr, aTextureOwnerId, CreateFallbackDrawTarget(info.mRefPtr, aTextureOwnerId,
aWebgl->GetSize(), aWebgl->GetFormat())) { aWebgl->GetSize(), aWebgl->GetFormat())) {
bool success = aWebgl->CopyToFallback(dt); bool success = aWebgl->CopyToFallback(dt);
AddDrawTarget(info.mRefPtr, dt); if (info.mRefPtr) {
AddDrawTarget(info.mRefPtr, dt);
}
return success; return success;
} }
return false; return false;
@@ -1084,16 +1086,18 @@ void CanvasTranslator::CacheSnapshotShmem(
if (gfx::DrawTargetWebgl* webgl = GetDrawTargetWebgl(aTextureOwnerId)) { if (gfx::DrawTargetWebgl* webgl = GetDrawTargetWebgl(aTextureOwnerId)) {
if (auto shmemHandle = webgl->TakeShmemHandle()) { if (auto shmemHandle = webgl->TakeShmemHandle()) {
// Lock the DT so that it doesn't get removed while shmem is in transit. // Lock the DT so that it doesn't get removed while shmem is in transit.
mTextureInfo[aTextureOwnerId].mLocked++; AddTextureKeepAlive(aTextureOwnerId);
nsCOMPtr<nsIThread> thread = nsCOMPtr<nsIThread> thread =
gfx::CanvasRenderThread::GetCanvasRenderThread(); gfx::CanvasRenderThread::GetCanvasRenderThread();
RefPtr<CanvasTranslator> translator = this; RefPtr<CanvasTranslator> translator = this;
SendSnapshotShmem(aTextureOwnerId, std::move(shmemHandle)) SendSnapshotShmem(aTextureOwnerId, std::move(shmemHandle))
->Then( ->Then(
thread, __func__, thread, __func__,
[=](bool) { translator->RemoveTexture(aTextureOwnerId); }, [=](bool) {
translator->RemoveTextureKeepAlive(aTextureOwnerId);
},
[=](ipc::ResponseRejectReason) { [=](ipc::ResponseRejectReason) {
translator->RemoveTexture(aTextureOwnerId); translator->RemoveTextureKeepAlive(aTextureOwnerId);
}); });
} }
} }
@@ -1267,7 +1271,9 @@ already_AddRefed<gfx::DrawTarget> CanvasTranslator::CreateDrawTarget(
dt = CreateFallbackDrawTarget(aRefPtr, aTextureOwnerId, aSize, aFormat); dt = CreateFallbackDrawTarget(aRefPtr, aTextureOwnerId, aSize, aFormat);
} }
AddDrawTarget(aRefPtr, dt); if (dt && aRefPtr) {
AddDrawTarget(aRefPtr, dt);
}
return dt.forget(); return dt.forget();
} }
@@ -1290,9 +1296,23 @@ void CanvasTranslator::NotifyTextureDestruction(
Unused << SendNotifyTextureDestruction(aTextureOwnerId); Unused << SendNotifyTextureDestruction(aTextureOwnerId);
} }
void CanvasTranslator::AddTextureKeepAlive(const RemoteTextureOwnerId& aId) {
auto result = mTextureInfo.find(aId);
if (result == mTextureInfo.end()) {
return;
}
auto& info = result->second;
++info.mKeepAlive;
}
void CanvasTranslator::RemoveTextureKeepAlive(const RemoteTextureOwnerId& aId) {
RemoveTexture(aId, 0, 0, false);
}
void CanvasTranslator::RemoveTexture(const RemoteTextureOwnerId aTextureOwnerId, void CanvasTranslator::RemoveTexture(const RemoteTextureOwnerId aTextureOwnerId,
RemoteTextureTxnType aTxnType, RemoteTextureTxnType aTxnType,
RemoteTextureTxnId aTxnId) { RemoteTextureTxnId aTxnId,
bool aFinalize) {
// Don't erase the texture if still in use // Don't erase the texture if still in use
auto result = mTextureInfo.find(aTextureOwnerId); auto result = mTextureInfo.find(aTextureOwnerId);
if (result == mTextureInfo.end()) { if (result == mTextureInfo.end()) {
@@ -1302,10 +1322,17 @@ void CanvasTranslator::RemoveTexture(const RemoteTextureOwnerId aTextureOwnerId,
if (mRemoteTextureOwner && aTxnType && aTxnId) { if (mRemoteTextureOwner && aTxnType && aTxnId) {
mRemoteTextureOwner->WaitForTxn(aTextureOwnerId, aTxnType, aTxnId); mRemoteTextureOwner->WaitForTxn(aTextureOwnerId, aTxnType, aTxnId);
} }
if (--info.mLocked > 0) { // Remove the DrawTarget only if this is being called from a recorded event
// or if there are no remaining keepalives. If this is being called only to
// remove a keepalive without forcing removal, then the DrawTarget is still
// being used by the recording.
if ((aFinalize || info.mKeepAlive <= 1) && info.mRefPtr) {
RemoveDrawTarget(info.mRefPtr);
info.mRefPtr = ReferencePtr();
}
if (--info.mKeepAlive > 0) {
return; return;
} }
RemoveDrawTarget(info.mRefPtr);
if (info.mTextureData) { if (info.mTextureData) {
if (info.mFallbackDrawTarget) { if (info.mFallbackDrawTarget) {
info.mTextureData->ReturnDrawTarget(info.mFallbackDrawTarget.forget()); info.mTextureData->ReturnDrawTarget(info.mFallbackDrawTarget.forget());

View File

@@ -210,8 +210,8 @@ class CanvasTranslator final : public gfx::InlineTranslator,
* @param aTextureOwnerId the texture ID to remove * @param aTextureOwnerId the texture ID to remove
*/ */
void RemoveTexture(const RemoteTextureOwnerId aTextureOwnerId, void RemoveTexture(const RemoteTextureOwnerId aTextureOwnerId,
RemoteTextureTxnType aTxnType = 0, RemoteTextureTxnType aTxnType, RemoteTextureTxnId aTxnId,
RemoteTextureTxnId aTxnId = 0); bool aFinalize = true);
bool LockTexture(const RemoteTextureOwnerId aTextureOwnerId, OpenMode aMode, bool LockTexture(const RemoteTextureOwnerId aTextureOwnerId, OpenMode aMode,
bool aInvalidContents = false); bool aInvalidContents = false);
@@ -563,7 +563,7 @@ class CanvasTranslator final : public gfx::InlineTranslator,
RefPtr<gfx::DrawTarget> mFallbackDrawTarget; RefPtr<gfx::DrawTarget> mFallbackDrawTarget;
bool mNotifiedRequiresRefresh = false; bool mNotifiedRequiresRefresh = false;
// Ref-count of how active uses of the DT. Avoids deletion when locked. // Ref-count of how active uses of the DT. Avoids deletion when locked.
int32_t mLocked = 1; int32_t mKeepAlive = 1;
OpenMode mTextureLockMode = OpenMode::OPEN_NONE; OpenMode mTextureLockMode = OpenMode::OPEN_NONE;
gfx::DrawTargetWebgl* GetDrawTargetWebgl( gfx::DrawTargetWebgl* GetDrawTargetWebgl(
@@ -572,6 +572,10 @@ class CanvasTranslator final : public gfx::InlineTranslator,
std::unordered_map<RemoteTextureOwnerId, TextureInfo, std::unordered_map<RemoteTextureOwnerId, TextureInfo,
RemoteTextureOwnerId::HashFn> RemoteTextureOwnerId::HashFn>
mTextureInfo; mTextureInfo;
void AddTextureKeepAlive(const RemoteTextureOwnerId& aId);
void RemoveTextureKeepAlive(const RemoteTextureOwnerId& aId);
nsRefPtrHashtable<nsPtrHashKey<void>, gfx::DataSourceSurface> mDataSurfaces; nsRefPtrHashtable<nsPtrHashKey<void>, gfx::DataSourceSurface> mDataSurfaces;
gfx::ReferencePtr mMappedSurface; gfx::ReferencePtr mMappedSurface;
UniquePtr<gfx::DataSourceSurface::ScopedMap> mPreparedMap; UniquePtr<gfx::DataSourceSurface::ScopedMap> mPreparedMap;