diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-15 03:35:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-15 03:35:49 +0000 |
commit | d8bbc7858622b6d9c278469aab701ca0b609cddf (patch) | |
tree | eff41dc61d9f714852212739e6b3738b82a2af87 /gfx/layers/client | |
parent | Releasing progress-linux version 125.0.3-1~progress7.99u1. (diff) | |
download | firefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.tar.xz firefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.zip |
Merging upstream version 126.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/layers/client')
-rw-r--r-- | gfx/layers/client/TextureClient.cpp | 7 | ||||
-rw-r--r-- | gfx/layers/client/TextureClient.h | 20 | ||||
-rw-r--r-- | gfx/layers/client/TextureClientPool.cpp | 307 | ||||
-rw-r--r-- | gfx/layers/client/TextureClientPool.h | 175 | ||||
-rw-r--r-- | gfx/layers/client/TextureRecorded.cpp | 48 | ||||
-rw-r--r-- | gfx/layers/client/TextureRecorded.h | 2 |
6 files changed, 36 insertions, 523 deletions
diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index 4187e48955..12a34ff92f 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -1546,12 +1546,7 @@ TextureClient::TextureClient(TextureData* aData, TextureFlags aFlags, mUpdated(false), mAddedToCompositableClient(false), mFwdTransactionId(0), - mSerial(++sSerialCounter) -#ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL - , - mPoolTracker(nullptr) -#endif -{ + mSerial(++sSerialCounter) { mData->FillInfo(mInfo); mFlags |= mData->GetTextureFlags(); } diff --git a/gfx/layers/client/TextureClient.h b/gfx/layers/client/TextureClient.h index ac0a755698..cf1701e3f0 100644 --- a/gfx/layers/client/TextureClient.h +++ b/gfx/layers/client/TextureClient.h @@ -44,12 +44,6 @@ struct ID3D11Device; namespace mozilla { -// When defined, we track which pool the tile came from and test for -// any inconsistencies. This can be defined in release build as well. -#ifdef DEBUG -# define GFX_DEBUG_TRACK_CLIENTS_IN_POOL 1 -#endif - namespace layers { class AndroidHardwareBufferTextureData; @@ -68,9 +62,6 @@ class GPUVideoTextureData; class TextureClient; class ITextureClientRecycleAllocator; class SharedSurfaceTextureData; -#ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL -class TextureClientPool; -#endif class TextureForwarder; struct RemoteTextureOwnerId; @@ -696,11 +687,6 @@ class TextureClient : public AtomicRefCountedWithFinalize<TextureClient> { static void TextureClientRecycleCallback(TextureClient* aClient, void* aClosure); - // Internal helpers for creating texture clients using the actual forwarder - // instead of KnowsCompositor. TextureClientPool uses these to let it cache - // texture clients per-process instead of per ShadowLayerForwarder, but - // everyone else should use the public functions instead. - friend class TextureClientPool; static already_AddRefed<TextureClient> CreateForDrawing( TextureForwarder* aAllocator, gfx::SurfaceFormat aFormat, gfx::IntSize aSize, KnowsCompositor* aKnowsCompositor, @@ -795,12 +781,6 @@ class TextureClient : public AtomicRefCountedWithFinalize<TextureClient> { friend void TestTextureClientYCbCr(TextureClient*, PlanarYCbCrData&); friend already_AddRefed<TextureHost> CreateTextureHostWithBackend( TextureClient*, ISurfaceAllocator*, LayersBackend&); - -#ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL - public: - // Pointer to the pool this tile came from. - TextureClientPool* mPoolTracker; -#endif }; /** diff --git a/gfx/layers/client/TextureClientPool.cpp b/gfx/layers/client/TextureClientPool.cpp deleted file mode 100644 index 3eb0c908b6..0000000000 --- a/gfx/layers/client/TextureClientPool.cpp +++ /dev/null @@ -1,307 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "TextureClientPool.h" -#include "CompositableClient.h" -#include "mozilla/layers/CompositableForwarder.h" -#include "mozilla/layers/TextureForwarder.h" -#include "mozilla/StaticPrefs_layers.h" - -#include "nsComponentManagerUtils.h" - -#define TCP_LOG(...) -// #define TCP_LOG(...) printf_stderr(__VA_ARGS__); - -namespace mozilla { -namespace layers { - -// We want to shrink to our maximum size of N unused tiles -// after a timeout to allow for short-term budget requirements -static void ShrinkCallback(nsITimer* aTimer, void* aClosure) { - static_cast<TextureClientPool*>(aClosure)->ShrinkToMaximumSize(); -} - -// After a certain amount of inactivity, let's clear the pool so that -// we don't hold onto tiles needlessly. In general, allocations are -// cheap enough that re-allocating isn't an issue unless we're allocating -// at an inopportune time (e.g. mid-animation). -static void ClearCallback(nsITimer* aTimer, void* aClosure) { - static_cast<TextureClientPool*>(aClosure)->Clear(); -} - -TextureClientPool::TextureClientPool( - KnowsCompositor* aKnowsCompositor, gfx::SurfaceFormat aFormat, - gfx::IntSize aSize, TextureFlags aFlags, uint32_t aShrinkTimeoutMsec, - uint32_t aClearTimeoutMsec, uint32_t aInitialPoolSize, - uint32_t aPoolUnusedSize, TextureForwarder* aAllocator) - : mKnowsCompositor(aKnowsCompositor), - mFormat(aFormat), - mSize(aSize), - mFlags(aFlags), - mShrinkTimeoutMsec(aShrinkTimeoutMsec), - mClearTimeoutMsec(aClearTimeoutMsec), - mInitialPoolSize(aInitialPoolSize), - mPoolUnusedSize(aPoolUnusedSize), - mOutstandingClients(0), - mSurfaceAllocator(aAllocator), - mDestroyed(false) { - TCP_LOG("TexturePool %p created with maximum unused texture clients %u\n", - this, mInitialPoolSize); - mShrinkTimer = NS_NewTimer(); - mClearTimer = NS_NewTimer(); - if (aFormat == gfx::SurfaceFormat::UNKNOWN) { - gfxWarning() << "Creating texture pool for SurfaceFormat::UNKNOWN format"; - } -} - -TextureClientPool::~TextureClientPool() { - mShrinkTimer->Cancel(); - mClearTimer->Cancel(); -} - -#ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL -static bool TestClientPool(const char* what, TextureClient* aClient, - TextureClientPool* aPool) { - if (!aClient || !aPool) { - return false; - } - - TextureClientPool* actual = aClient->mPoolTracker; - bool ok = (actual == aPool); - if (ok) { - ok = (aClient->GetFormat() == aPool->GetFormat()); - } - - if (!ok) { - if (actual) { - gfxCriticalError() << "Pool error(" << what << "): " << aPool << "-" - << aPool->GetFormat() << ", " << actual << "-" - << actual->GetFormat() << ", " << aClient->GetFormat(); - MOZ_CRASH("GFX: Crashing with actual"); - } else { - gfxCriticalError() << "Pool error(" << what << "): " << aPool << "-" - << aPool->GetFormat() << ", nullptr, " - << aClient->GetFormat(); - MOZ_CRASH("GFX: Crashing without actual"); - } - } - return ok; -} -#endif - -already_AddRefed<TextureClient> TextureClientPool::GetTextureClient() { - // Try to fetch a client from the pool - RefPtr<TextureClient> textureClient; - - // We initially allocate mInitialPoolSize for our pool. If we run - // out of TextureClients, we allocate additional TextureClients to try and - // keep around mPoolUnusedSize - if (mTextureClients.empty()) { - AllocateTextureClient(); - } - - if (mTextureClients.empty()) { - // All our allocations failed, return nullptr - return nullptr; - } - - mOutstandingClients++; - textureClient = mTextureClients.top(); - mTextureClients.pop(); -#ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL - if (textureClient) { - textureClient->mPoolTracker = this; - } - DebugOnly<bool> ok = TestClientPool("fetch", textureClient, this); - MOZ_ASSERT(ok); -#endif - TCP_LOG("TexturePool %p giving %p from pool; size %u outstanding %u\n", this, - textureClient.get(), mTextureClients.size(), mOutstandingClients); - - return textureClient.forget(); -} - -void TextureClientPool::AllocateTextureClient() { - TCP_LOG("TexturePool %p allocating TextureClient, outstanding %u\n", this, - mOutstandingClients); - - TextureAllocationFlags allocFlags = ALLOC_DEFAULT; - - RefPtr<TextureClient> newClient; - if (StaticPrefs::layers_force_shmem_tiles_AtStartup()) { - // gfx::BackendType::NONE means use the content backend - newClient = TextureClient::CreateForRawBufferAccess( - mSurfaceAllocator, mFormat, mSize, gfx::BackendType::NONE, GetBackend(), - mFlags, allocFlags); - } else { - newClient = TextureClient::CreateForDrawing( - mSurfaceAllocator, mFormat, mSize, mKnowsCompositor, - BackendSelector::Content, mFlags, allocFlags); - } - - if (newClient) { - mTextureClients.push(newClient); - } -} - -void TextureClientPool::ResetTimers() { - // Shrink down if we're beyond our maximum size - if (mShrinkTimeoutMsec && - mTextureClients.size() + mTextureClientsDeferred.size() > - mPoolUnusedSize) { - TCP_LOG("TexturePool %p scheduling a shrink-to-max-size\n", this); - mShrinkTimer->InitWithNamedFuncCallback( - ShrinkCallback, this, mShrinkTimeoutMsec, nsITimer::TYPE_ONE_SHOT, - "layers::TextureClientPool::ResetTimers"); - } - - // Clear pool after a period of inactivity to reduce memory consumption - if (mClearTimeoutMsec) { - TCP_LOG("TexturePool %p scheduling a clear\n", this); - mClearTimer->InitWithNamedFuncCallback( - ClearCallback, this, mClearTimeoutMsec, nsITimer::TYPE_ONE_SHOT, - "layers::TextureClientPool::ResetTimers"); - } -} - -void TextureClientPool::ReturnTextureClient(TextureClient* aClient) { - if (!aClient || mDestroyed) { - return; - } -#ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL - DebugOnly<bool> ok = TestClientPool("return", aClient, this); - MOZ_ASSERT(ok); -#endif - // Add the client to the pool: - MOZ_ASSERT(mOutstandingClients > mTextureClientsDeferred.size()); - mOutstandingClients--; - mTextureClients.push(aClient); - TCP_LOG("TexturePool %p had client %p returned; size %u outstanding %u\n", - this, aClient, mTextureClients.size(), mOutstandingClients); - - ResetTimers(); -} - -void TextureClientPool::ReturnTextureClientDeferred(TextureClient* aClient) { - if (!aClient || mDestroyed) { - return; - } - MOZ_ASSERT(aClient->HasReadLock()); -#ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL - DebugOnly<bool> ok = TestClientPool("defer", aClient, this); - MOZ_ASSERT(ok); -#endif - mTextureClientsDeferred.push_back(aClient); - TCP_LOG( - "TexturePool %p had client %p defer-returned, size %u outstanding %u\n", - this, aClient, mTextureClientsDeferred.size(), mOutstandingClients); - - ResetTimers(); -} - -void TextureClientPool::ShrinkToMaximumSize() { - // We're over our desired maximum size, immediately shrink down to the - // maximum. - // - // We cull from the deferred TextureClients first, as we can't reuse those - // until they get returned. - uint32_t totalUnusedTextureClients = - mTextureClients.size() + mTextureClientsDeferred.size(); - - // If we have > mInitialPoolSize outstanding, then we want to keep around - // mPoolUnusedSize at a maximum. If we have fewer than mInitialPoolSize - // outstanding, then keep around the entire initial pool size. - uint32_t targetUnusedClients; - if (mOutstandingClients > mInitialPoolSize) { - targetUnusedClients = mPoolUnusedSize; - } else { - targetUnusedClients = mInitialPoolSize; - } - - TCP_LOG( - "TexturePool %p shrinking to maximum unused size %u; current pool size " - "%u; total outstanding %u\n", - this, targetUnusedClients, totalUnusedTextureClients, - mOutstandingClients); - - while (totalUnusedTextureClients > targetUnusedClients) { - if (!mTextureClientsDeferred.empty()) { - mOutstandingClients--; - TCP_LOG("TexturePool %p dropped deferred client %p; %u remaining\n", this, - mTextureClientsDeferred.front().get(), - mTextureClientsDeferred.size() - 1); - mTextureClientsDeferred.pop_front(); - } else { - TCP_LOG("TexturePool %p dropped non-deferred client %p; %u remaining\n", - this, mTextureClients.top().get(), mTextureClients.size() - 1); - mTextureClients.pop(); - } - totalUnusedTextureClients--; - } -} - -void TextureClientPool::ReturnDeferredClients() { - if (mTextureClientsDeferred.empty()) { - return; - } - - TCP_LOG("TexturePool %p returning %u deferred clients to pool\n", this, - mTextureClientsDeferred.size()); - - ReturnUnlockedClients(); - ShrinkToMaximumSize(); -} - -void TextureClientPool::ReturnUnlockedClients() { - for (auto it = mTextureClientsDeferred.begin(); - it != mTextureClientsDeferred.end();) { - MOZ_ASSERT((*it)->GetNonBlockingReadLockCount() >= 1); - // Last count is held by the lock itself. - if (!(*it)->IsReadLocked()) { - mTextureClients.push(*it); - it = mTextureClientsDeferred.erase(it); - - MOZ_ASSERT(mOutstandingClients > 0); - mOutstandingClients--; - } else { - it++; - } - } -} - -void TextureClientPool::ReportClientLost() { - MOZ_ASSERT(mOutstandingClients > mTextureClientsDeferred.size()); - mOutstandingClients--; - TCP_LOG("TexturePool %p getting report client lost; down to %u outstanding\n", - this, mOutstandingClients); -} - -void TextureClientPool::Clear() { - TCP_LOG("TexturePool %p getting cleared\n", this); - while (!mTextureClients.empty()) { - TCP_LOG("TexturePool %p releasing client %p\n", this, - mTextureClients.top().get()); - mTextureClients.pop(); - } - while (!mTextureClientsDeferred.empty()) { - MOZ_ASSERT(mOutstandingClients > 0); - mOutstandingClients--; - TCP_LOG("TexturePool %p releasing deferred client %p\n", this, - mTextureClientsDeferred.front().get()); - mTextureClientsDeferred.pop_front(); - } -} - -void TextureClientPool::Destroy() { - Clear(); - mDestroyed = true; - mInitialPoolSize = 0; - mPoolUnusedSize = 0; - mKnowsCompositor = nullptr; -} - -} // namespace layers -} // namespace mozilla diff --git a/gfx/layers/client/TextureClientPool.h b/gfx/layers/client/TextureClientPool.h deleted file mode 100644 index d557ca9a03..0000000000 --- a/gfx/layers/client/TextureClientPool.h +++ /dev/null @@ -1,175 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef MOZILLA_GFX_TEXTURECLIENTPOOL_H -#define MOZILLA_GFX_TEXTURECLIENTPOOL_H - -#include "mozilla/gfx/Types.h" -#include "mozilla/gfx/Point.h" -#include "mozilla/RefPtr.h" -#include "mozilla/layers/KnowsCompositor.h" -#include "TextureClient.h" -#include "nsITimer.h" -#include <stack> -#include <list> - -namespace mozilla { -namespace layers { - -class ISurfaceAllocator; -class TextureForwarder; -class TextureReadLock; - -class TextureClientAllocator { - protected: - virtual ~TextureClientAllocator() = default; - - public: - NS_INLINE_DECL_REFCOUNTING(TextureClientAllocator) - - virtual already_AddRefed<TextureClient> GetTextureClient() = 0; - - /** - * Return a TextureClient that is not yet ready to be reused, but will be - * imminently. - */ - virtual void ReturnTextureClientDeferred(TextureClient* aClient) = 0; - - virtual void ReportClientLost() = 0; -}; - -class TextureClientPool final : public TextureClientAllocator { - virtual ~TextureClientPool(); - - public: - TextureClientPool(KnowsCompositor* aKnowsCompositor, - gfx::SurfaceFormat aFormat, gfx::IntSize aSize, - TextureFlags aFlags, uint32_t aShrinkTimeoutMsec, - uint32_t aClearTimeoutMsec, uint32_t aInitialPoolSize, - uint32_t aPoolUnusedSize, TextureForwarder* aAllocator); - - /** - * Gets an allocated TextureClient of size and format that are determined - * by the initialisation parameters given to the pool. This will either be - * a cached client that was returned to the pool, or a newly allocated - * client if one isn't available. - * - * All clients retrieved by this method should be returned using the return - * functions, or reported lost so that the pool can manage its size correctly. - */ - already_AddRefed<TextureClient> GetTextureClient() override; - - /** - * Return a TextureClient that is no longer being used and is ready for - * immediate re-use or destruction. - */ - void ReturnTextureClient(TextureClient* aClient); - - /** - * Return a TextureClient that is not yet ready to be reused, but will be - * imminently. - */ - void ReturnTextureClientDeferred(TextureClient* aClient) override; - - /** - * Return any clients to the pool that were previously returned in - * ReturnTextureClientDeferred. - */ - void ReturnDeferredClients(); - - /** - * Attempt to shrink the pool so that there are no more than - * mInitialPoolSize outstanding. - */ - void ShrinkToMaximumSize(); - - /** - * Report that a client retrieved via GetTextureClient() has become - * unusable, so that it will no longer be tracked. - */ - void ReportClientLost() override; - - /** - * Calling this will cause the pool to attempt to relinquish any unused - * clients. - */ - void Clear(); - - LayersBackend GetBackend() const { - return mKnowsCompositor->GetCompositorBackendType(); - } - int32_t GetMaxTextureSize() const { - return mKnowsCompositor->GetMaxTextureSize(); - } - gfx::SurfaceFormat GetFormat() { return mFormat; } - TextureFlags GetFlags() const { return mFlags; } - - /** - * Clear the pool and put it in a state where it won't recycle any new - * texture. - */ - void Destroy(); - - private: - void ReturnUnlockedClients(); - - /// Allocate a single TextureClient to be returned from the pool. - void AllocateTextureClient(); - - /// Reset and/or initialise timers for shrinking/clearing the pool. - void ResetTimers(); - - /// KnowsCompositor passed to the TextureClient for buffer creation. - RefPtr<KnowsCompositor> mKnowsCompositor; - - /// Format is passed to the TextureClient for buffer creation. - gfx::SurfaceFormat mFormat; - - /// The width and height of the tiles to be used. - gfx::IntSize mSize; - - /// Flags passed to the TextureClient for buffer creation. - const TextureFlags mFlags; - - /// How long to wait after a TextureClient is returned before trying - /// to shrink the pool to its maximum size of mPoolUnusedSize. - uint32_t mShrinkTimeoutMsec; - - /// How long to wait after a TextureClient is returned before trying - /// to clear the pool. - uint32_t mClearTimeoutMsec; - - // The initial number of unused texture clients to seed the pool with - // on construction - uint32_t mInitialPoolSize; - - // How many unused texture clients to try and keep around if we go over - // the initial allocation - uint32_t mPoolUnusedSize; - - /// This is a total number of clients in the wild and in the stack of - /// deferred clients (see below). So, the total number of clients in - /// existence is always mOutstandingClients + the size of mTextureClients. - uint32_t mOutstandingClients; - - std::stack<RefPtr<TextureClient>> mTextureClients; - - std::list<RefPtr<TextureClient>> mTextureClientsDeferred; - RefPtr<nsITimer> mShrinkTimer; - RefPtr<nsITimer> mClearTimer; - // This mSurfaceAllocator owns us, so no need to hold a ref to it - TextureForwarder* mSurfaceAllocator; - - // Keep track of whether this pool has been destroyed or not. If it has, - // we won't accept returns of TextureClients anymore, and the refcounting - // should take care of their destruction. - bool mDestroyed; -}; - -} // namespace layers -} // namespace mozilla - -#endif /* MOZILLA_GFX_TEXTURECLIENTPOOL_H */ diff --git a/gfx/layers/client/TextureRecorded.cpp b/gfx/layers/client/TextureRecorded.cpp index da4ca4f8f3..b3596efdc3 100644 --- a/gfx/layers/client/TextureRecorded.cpp +++ b/gfx/layers/client/TextureRecorded.cpp @@ -33,7 +33,7 @@ RecordedTextureData::~RecordedTextureData() { // We need the translator to drop its reference for the DrawTarget first, // because the TextureData might need to destroy its DrawTarget within a lock. mSnapshot = nullptr; - mSnapshotWrapper = nullptr; + DetachSnapshotWrapper(); mDT = nullptr; mCanvasChild->CleanupTexture(mTextureId); mCanvasChild->RecordEvent(RecordedTextureDestruction( @@ -92,10 +92,25 @@ bool RecordedTextureData::Lock(OpenMode aMode) { return true; } +void RecordedTextureData::DetachSnapshotWrapper(bool aInvalidate, + bool aRelease) { + if (mSnapshotWrapper) { + // If the snapshot only has one ref, then we don't need to worry about + // copying before invalidation since it is about to be deleted. Otherwise, + // we need to ensure any internal data is appropriately copied before + // shmems are potentially overwritten if there are still existing users. + mCanvasChild->DetachSurface(mSnapshotWrapper, + aInvalidate && !mSnapshotWrapper->hasOneRef()); + if (aRelease) { + mSnapshotWrapper = nullptr; + } + } +} + void RecordedTextureData::Unlock() { if ((mLockedMode == OpenMode::OPEN_READ_WRITE) && mCanvasChild->ShouldCacheDataSurface()) { - mSnapshotWrapper = nullptr; + DetachSnapshotWrapper(); mSnapshot = mDT->Snapshot(); mDT->DetachAllSnapshots(); mCanvasChild->RecordEvent(RecordedCacheDataSurface(mSnapshot.get())); @@ -108,11 +123,9 @@ void RecordedTextureData::Unlock() { already_AddRefed<gfx::DrawTarget> RecordedTextureData::BorrowDrawTarget() { if (mLockedMode & OpenMode::OPEN_WRITE) { + // The snapshot will be invalidated. mSnapshot = nullptr; - if (mSnapshotWrapper) { - mCanvasChild->DetachSurface(mSnapshotWrapper); - mSnapshotWrapper = nullptr; - } + DetachSnapshotWrapper(true); } return do_AddRef(mDT); } @@ -122,18 +135,22 @@ void RecordedTextureData::EndDraw() { MOZ_ASSERT(mLockedMode == OpenMode::OPEN_READ_WRITE); if (mCanvasChild->ShouldCacheDataSurface()) { - mSnapshotWrapper = nullptr; + DetachSnapshotWrapper(); mSnapshot = mDT->Snapshot(); mCanvasChild->RecordEvent(RecordedCacheDataSurface(mSnapshot.get())); } } already_AddRefed<gfx::SourceSurface> RecordedTextureData::BorrowSnapshot() { - if (mSnapshotWrapper && (!mDT || !mDT->IsDirty())) { - // The DT is unmodified since the last time snapshot was borrowed, so it - // is safe to reattach the snapshot for shmem readbacks. - mCanvasChild->AttachSurface(mSnapshotWrapper); - return do_AddRef(mSnapshotWrapper); + if (mSnapshotWrapper) { + if (!mDT || !mDT->IsDirty()) { + // The DT is unmodified since the last time snapshot was borrowed, so it + // is safe to reattach the snapshot for shmem readbacks. + mCanvasChild->AttachSurface(mSnapshotWrapper); + return do_AddRef(mSnapshotWrapper); + } + + DetachSnapshotWrapper(); } // There are some failure scenarios where we have no DrawTarget and @@ -153,9 +170,10 @@ already_AddRefed<gfx::SourceSurface> RecordedTextureData::BorrowSnapshot() { void RecordedTextureData::ReturnSnapshot( already_AddRefed<gfx::SourceSurface> aSnapshot) { RefPtr<gfx::SourceSurface> snapshot = aSnapshot; - if (mSnapshotWrapper) { - mCanvasChild->DetachSurface(mSnapshotWrapper); - } + // The snapshot needs to be marked detached but we keep the wrapper around + // so that it can be reused without repeatedly creating it and accidentally + // reading back data for each new instantiation. + DetachSnapshotWrapper(false, false); } void RecordedTextureData::Deallocate(LayersIPCChannel* aAllocator) {} diff --git a/gfx/layers/client/TextureRecorded.h b/gfx/layers/client/TextureRecorded.h index 56e504fb54..9e4e69e78d 100644 --- a/gfx/layers/client/TextureRecorded.h +++ b/gfx/layers/client/TextureRecorded.h @@ -58,6 +58,8 @@ class RecordedTextureData final : public TextureData { ~RecordedTextureData() override; + void DetachSnapshotWrapper(bool aInvalidate = false, bool aRelease = true); + int64_t mTextureId; RefPtr<CanvasChild> mCanvasChild; gfx::IntSize mSize; |