Files
sousa-gecko/gfx/layers/client/TextureClientRecycleAllocator.cpp
T
Emilio Cobos Álvarez 02d691fdef Bug 2054311 - Sort includes in gfx/. r=gfx-reviewers,gw
Autogenerated with:

    cp dom/.clang-format gfx/ && mach format gfx/**.{cpp,h,mm}

Manual changes:

    * OSVRSession headers are not system headers and they are not
      standalone / rely on stdint, so tweaked to preserve previous
      ordering.
    * Missing include in GLDefs.h
    * Missing include in gfxOTSUtils.
    * Need to keep the windows header order in DCLayerTree.
    * missing hb_font include in MockScaledFont.h

Differential Revision: https://phabricator.services.mozilla.com/D311695
2026-07-13 09:51:18 +00:00

264 lines
9.5 KiB
C++

/* 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 "TextureClientRecycleAllocator.h"
#include "ImageContainer.h"
#include "gfxPlatform.h"
#include "mozilla/layers/BufferTexture.h"
#include "mozilla/layers/ISurfaceAllocator.h"
#include "mozilla/layers/TextureForwarder.h"
namespace mozilla {
namespace layers {
// Used to keep TextureClient's reference count stable as not to disrupt
// recycling.
class TextureClientHolder final {
~TextureClientHolder() = default;
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureClientHolder)
explicit TextureClientHolder(TextureClient* aClient)
: mTextureClient(aClient), mWillRecycle(true) {}
TextureClient* GetTextureClient() { return mTextureClient; }
bool WillRecycle() { return mWillRecycle; }
void ClearWillRecycle() { mWillRecycle = false; }
void ClearTextureClient() { mTextureClient = nullptr; }
protected:
RefPtr<TextureClient> mTextureClient;
bool mWillRecycle;
};
class MOZ_RAII DefaultTextureClientAllocationHelper
: public ITextureClientAllocationHelper {
public:
DefaultTextureClientAllocationHelper(
TextureClientRecycleAllocator* aAllocator, gfx::SurfaceFormat aFormat,
gfx::IntSize aSize, BackendSelector aSelector, TextureFlags aTextureFlags,
TextureAllocationFlags aAllocationFlags)
: ITextureClientAllocationHelper(aFormat, aSize, aSelector, aTextureFlags,
aAllocationFlags),
mAllocator(aAllocator) {}
bool IsCompatible(TextureClient* aTextureClient) override {
if (aTextureClient->GetFormat() != mFormat ||
aTextureClient->GetSize() != mSize) {
return false;
}
return true;
}
already_AddRefed<TextureClient> Allocate(
KnowsCompositor* aKnowsCompositor) override {
return mAllocator->Allocate(mFormat, mSize, mSelector, mTextureFlags,
mAllocationFlags);
}
protected:
TextureClientRecycleAllocator* mAllocator;
};
YCbCrTextureClientAllocationHelper::YCbCrTextureClientAllocationHelper(
const PlanarYCbCrData& aData, const gfx::IntSize& aYSize,
const gfx::IntSize& aCbCrSize, TextureFlags aTextureFlags)
: ITextureClientAllocationHelper(gfx::SurfaceFormat::YUV420, aYSize,
BackendSelector::Content, aTextureFlags,
ALLOC_DEFAULT),
mData(aData),
mYSize(aYSize),
mCbCrSize(aCbCrSize) {}
YCbCrTextureClientAllocationHelper::YCbCrTextureClientAllocationHelper(
const PlanarYCbCrData& aData, TextureFlags aTextureFlags)
: YCbCrTextureClientAllocationHelper(aData, aData.YDataSize(),
aData.CbCrDataSize(), aTextureFlags) {}
bool YCbCrTextureClientAllocationHelper::IsCompatible(
TextureClient* aTextureClient) {
MOZ_ASSERT(aTextureClient->GetFormat() == gfx::SurfaceFormat::YUV420);
BufferTextureData* bufferData =
aTextureClient->GetInternalData()->AsBufferTextureData();
if (!bufferData ||
!bufferData->GetPictureRect().IsEqualEdges(mData.mPictureRect) ||
bufferData->GetYSize().isNothing() ||
bufferData->GetYSize().ref() != mYSize ||
bufferData->GetCbCrSize().isNothing() ||
bufferData->GetCbCrSize().ref() != mCbCrSize ||
bufferData->GetYStride().isNothing() ||
bufferData->GetYStride().ref() != mData.mYStride ||
bufferData->GetCbCrStride().isNothing() ||
bufferData->GetCbCrStride().ref() != mData.mCbCrStride ||
bufferData->GetYUVColorSpace().isNothing() ||
bufferData->GetYUVColorSpace().ref() != mData.mYUVColorSpace ||
bufferData->GetColorDepth().isNothing() ||
bufferData->GetColorDepth().ref() != mData.mColorDepth ||
bufferData->GetStereoMode().isNothing() ||
bufferData->GetStereoMode().ref() != mData.mStereoMode ||
bufferData->GetChromaSubsampling().isNothing() ||
bufferData->GetChromaSubsampling().ref() != mData.mChromaSubsampling ||
bufferData->GetTransferFunction().isNothing() ||
bufferData->GetTransferFunction().ref() != mData.mTransferFunction) {
return false;
}
return true;
}
already_AddRefed<TextureClient> YCbCrTextureClientAllocationHelper::Allocate(
KnowsCompositor* aKnowsCompositor) {
return TextureClient::CreateForYCbCr(
aKnowsCompositor, mData.mPictureRect, mYSize, mData.mYStride, mCbCrSize,
mData.mCbCrStride, mData.mStereoMode, mData.mColorDepth,
mData.mYUVColorSpace, mData.mColorRange, mData.mTransferFunction,
mData.mChromaSubsampling, mTextureFlags, mData.mHDRMetadata);
}
TextureClientRecycleAllocator::TextureClientRecycleAllocator(
KnowsCompositor* aKnowsCompositor)
: mKnowsCompositor(aKnowsCompositor),
mMaxPooledSize(kMaxPooledSized),
mLock("TextureClientRecycleAllocatorImp.mLock"),
mIsDestroyed(false) {}
TextureClientRecycleAllocator::~TextureClientRecycleAllocator() {
MutexAutoLock lock(mLock);
while (!mPooledClients.empty()) {
mPooledClients.pop();
}
MOZ_ASSERT(mInUseClients.empty());
}
void TextureClientRecycleAllocator::SetMaxPoolSize(uint32_t aMax) {
mMaxPooledSize = aMax;
}
already_AddRefed<TextureClient> TextureClientRecycleAllocator::CreateOrRecycle(
gfx::SurfaceFormat aFormat, gfx::IntSize aSize, BackendSelector aSelector,
TextureFlags aTextureFlags, TextureAllocationFlags aAllocFlags) {
MOZ_ASSERT(!(aTextureFlags & TextureFlags::RECYCLE));
DefaultTextureClientAllocationHelper helper(this, aFormat, aSize, aSelector,
aTextureFlags, aAllocFlags);
return CreateOrRecycle(helper).unwrapOr(nullptr);
}
Result<already_AddRefed<TextureClient>, nsresult>
TextureClientRecycleAllocator::CreateOrRecycle(
ITextureClientAllocationHelper& aHelper) {
MOZ_ASSERT(aHelper.mTextureFlags & TextureFlags::RECYCLE);
RefPtr<TextureClientHolder> textureHolder;
{
MutexAutoLock lock(mLock);
if (mIsDestroyed || !mKnowsCompositor->GetTextureForwarder()) {
return Err(NS_ERROR_NOT_AVAILABLE);
}
if (!mPooledClients.empty()) {
textureHolder = mPooledClients.top();
mPooledClients.pop();
// If the texture's allocator is not open or a pooled TextureClient is
// not compatible, release it.
if (!textureHolder->GetTextureClient()->GetAllocator()->IPCOpen() ||
!aHelper.IsCompatible(textureHolder->GetTextureClient())) {
// Release TextureClient.
RefPtr task = MakeRefPtr<TextureClientReleaseTask>(
textureHolder->GetTextureClient());
textureHolder->ClearTextureClient();
textureHolder = nullptr;
mKnowsCompositor->GetTextureForwarder()->GetThread()->Dispatch(
task.forget());
} else {
textureHolder->GetTextureClient()->RecycleTexture(
aHelper.mTextureFlags);
}
}
}
if (!textureHolder) {
// Allocate new TextureClient
RefPtr<TextureClient> texture = aHelper.Allocate(mKnowsCompositor);
if (!texture) {
return Err(NS_ERROR_OUT_OF_MEMORY);
}
textureHolder = new TextureClientHolder(texture);
}
{
MutexAutoLock lock(mLock);
MOZ_ASSERT(mInUseClients.find(textureHolder->GetTextureClient()) ==
mInUseClients.end());
// Register TextureClient
mInUseClients[textureHolder->GetTextureClient()] = textureHolder;
}
RefPtr<TextureClient> client(textureHolder->GetTextureClient());
// Make sure the texture holds a reference to us, and ask it to call
// RecycleTextureClient when its ref count drops to 1.
client->SetRecycleAllocator(this);
return client.forget();
}
already_AddRefed<TextureClient> TextureClientRecycleAllocator::Allocate(
gfx::SurfaceFormat aFormat, gfx::IntSize aSize, BackendSelector aSelector,
TextureFlags aTextureFlags, TextureAllocationFlags aAllocFlags) {
return TextureClient::CreateForDrawing(mKnowsCompositor, aFormat, aSize,
aSelector, aTextureFlags, aAllocFlags);
}
void TextureClientRecycleAllocator::ShrinkToMinimumSize() {
MutexAutoLock lock(mLock);
while (!mPooledClients.empty()) {
mPooledClients.pop();
}
// We can not clear using TextureClients safely.
// Just clear WillRecycle here.
std::map<TextureClient*, RefPtr<TextureClientHolder> >::iterator it;
for (it = mInUseClients.begin(); it != mInUseClients.end(); it++) {
RefPtr<TextureClientHolder> holder = it->second;
holder->ClearWillRecycle();
}
}
void TextureClientRecycleAllocator::Destroy() {
MutexAutoLock lock(mLock);
while (!mPooledClients.empty()) {
mPooledClients.pop();
}
mIsDestroyed = true;
}
void TextureClientRecycleAllocator::RecycleTextureClient(
TextureClient* aClient) {
// Clearing the recycle allocator drops a reference, so make sure we stay
// alive for the duration of this function.
RefPtr<TextureClientRecycleAllocator> kungFuDeathGrip(this);
aClient->SetRecycleAllocator(nullptr);
RefPtr<TextureClientHolder> textureHolder;
{
MutexAutoLock lock(mLock);
if (mInUseClients.find(aClient) != mInUseClients.end()) {
textureHolder =
mInUseClients[aClient]; // Keep reference count of
// TextureClientHolder within lock.
if (textureHolder->WillRecycle() && !mIsDestroyed &&
mPooledClients.size() < mMaxPooledSize) {
mPooledClients.push(textureHolder);
}
mInUseClients.erase(aClient);
}
}
}
} // namespace layers
} // namespace mozilla