summaryrefslogtreecommitdiffstats
path: root/gfx/layers/client
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:34:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:34:50 +0000
commitdef92d1b8e9d373e2f6f27c366d578d97d8960c6 (patch)
tree2ef34b9ad8bb9a9220e05d60352558b15f513894 /gfx/layers/client
parentAdding debian version 125.0.3-1. (diff)
downloadfirefox-def92d1b8e9d373e2f6f27c366d578d97d8960c6.tar.xz
firefox-def92d1b8e9d373e2f6f27c366d578d97d8960c6.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.cpp7
-rw-r--r--gfx/layers/client/TextureClient.h20
-rw-r--r--gfx/layers/client/TextureClientPool.cpp307
-rw-r--r--gfx/layers/client/TextureClientPool.h175
-rw-r--r--gfx/layers/client/TextureRecorded.cpp48
-rw-r--r--gfx/layers/client/TextureRecorded.h2
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;