summaryrefslogtreecommitdiffstats
path: root/gfx/layers/mlgpu/SharedBufferMLGPU.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /gfx/layers/mlgpu/SharedBufferMLGPU.cpp
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/layers/mlgpu/SharedBufferMLGPU.cpp')
-rw-r--r--gfx/layers/mlgpu/SharedBufferMLGPU.cpp275
1 files changed, 275 insertions, 0 deletions
diff --git a/gfx/layers/mlgpu/SharedBufferMLGPU.cpp b/gfx/layers/mlgpu/SharedBufferMLGPU.cpp
new file mode 100644
index 0000000000..b6c9978c80
--- /dev/null
+++ b/gfx/layers/mlgpu/SharedBufferMLGPU.cpp
@@ -0,0 +1,275 @@
+/* -*- 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 "SharedBufferMLGPU.h"
+#include "BufferCache.h"
+#include "MLGDevice.h"
+
+namespace mozilla {
+namespace layers {
+
+SharedBufferMLGPU::SharedBufferMLGPU(MLGDevice* aDevice, MLGBufferType aType,
+ size_t aDefaultSize)
+ : mDevice(aDevice),
+ mType(aType),
+ mDefaultSize(aDefaultSize),
+ mCanUseOffsetAllocation(true),
+ mCurrentPosition(0),
+ mMaxSize(0),
+ mMap(),
+ mMapped(false),
+ mBytesUsedThisFrame(0),
+ mNumSmallFrames(0) {
+ MOZ_COUNT_CTOR(SharedBufferMLGPU);
+}
+
+SharedBufferMLGPU::~SharedBufferMLGPU() {
+ MOZ_COUNT_DTOR(SharedBufferMLGPU);
+ Unmap();
+}
+
+bool SharedBufferMLGPU::Init() {
+ // If we can't use buffer offset binding, we never allocated shared buffers.
+ if (!mCanUseOffsetAllocation) {
+ return true;
+ }
+
+ // If we can use offset binding, allocate an initial shared buffer now.
+ if (!GrowBuffer(mDefaultSize)) {
+ return false;
+ }
+ return true;
+}
+
+void SharedBufferMLGPU::Reset() {
+ // We shouldn't be mapped here, but just in case, unmap now.
+ Unmap();
+ mBytesUsedThisFrame = 0;
+
+ // If we allocated a large buffer for a particularly heavy layer tree,
+ // but have not used most of the buffer again for many frames, we
+ // discard the buffer. This is to prevent having to perform large
+ // pointless uploads after visiting a single havy page - it also
+ // lessens ping-ponging between large and small buffers.
+ if (mBuffer && (mBuffer->GetSize() > mDefaultSize * 4) &&
+ mNumSmallFrames >= 10) {
+ mBuffer = nullptr;
+ }
+
+ // Note that we do not aggressively map a new buffer. There's no reason to,
+ // and it'd cause unnecessary uploads when painting empty frames.
+}
+
+bool SharedBufferMLGPU::EnsureMappedBuffer(size_t aBytes) {
+ if (!mBuffer || (mMaxSize - mCurrentPosition < aBytes)) {
+ if (!GrowBuffer(aBytes)) {
+ return false;
+ }
+ }
+ if (!mMapped && !Map()) {
+ return false;
+ }
+ return true;
+}
+
+// We don't want to cache large buffers, since it results in larger uploads
+// that might not be needed.
+static const size_t kMaxCachedBufferSize = 128 * 1024;
+
+bool SharedBufferMLGPU::GrowBuffer(size_t aBytes) {
+ // We only pre-allocate buffers if we can use offset allocation.
+ MOZ_ASSERT(mCanUseOffsetAllocation);
+
+ // Unmap the previous buffer. This will retain mBuffer, but free up the
+ // address space used by its mapping.
+ Unmap();
+
+ size_t maybeSize = mDefaultSize;
+ if (mBuffer) {
+ // Try to first grow the previous allocation size.
+ maybeSize = std::min(kMaxCachedBufferSize, mBuffer->GetSize() * 2);
+ }
+
+ size_t bytes = std::max(aBytes, maybeSize);
+ mBuffer = mDevice->CreateBuffer(mType, bytes, MLGUsage::Dynamic);
+ if (!mBuffer) {
+ return false;
+ }
+
+ mCurrentPosition = 0;
+ mMaxSize = mBuffer->GetSize();
+ return true;
+}
+
+void SharedBufferMLGPU::PrepareForUsage() {
+ Unmap();
+
+ if (mBytesUsedThisFrame <= mDefaultSize) {
+ mNumSmallFrames++;
+ } else {
+ mNumSmallFrames = 0;
+ }
+}
+
+bool SharedBufferMLGPU::Map() {
+ MOZ_ASSERT(mBuffer);
+ MOZ_ASSERT(!mMapped);
+
+ if (!mDevice->Map(mBuffer, MLGMapType::WRITE_DISCARD, &mMap)) {
+ // Don't retain the buffer, it's useless if we can't map it.
+ mBuffer = nullptr;
+ return false;
+ }
+
+ mCurrentPosition = 0;
+ mMapped = true;
+ return true;
+}
+
+void SharedBufferMLGPU::Unmap() {
+ if (!mMapped) {
+ return;
+ }
+
+ mBytesUsedThisFrame += mCurrentPosition;
+
+ mDevice->Unmap(mBuffer);
+ mMap = MLGMappedResource();
+ mMapped = false;
+}
+
+uint8_t* SharedBufferMLGPU::GetBufferPointer(size_t aBytes,
+ ptrdiff_t* aOutOffset,
+ RefPtr<MLGBuffer>* aOutBuffer) {
+ if (!EnsureMappedBuffer(aBytes)) {
+ return nullptr;
+ }
+
+ ptrdiff_t newPos = mCurrentPosition + aBytes;
+ MOZ_ASSERT(size_t(newPos) <= mMaxSize);
+
+ *aOutOffset = mCurrentPosition;
+ *aOutBuffer = mBuffer;
+
+ uint8_t* ptr = reinterpret_cast<uint8_t*>(mMap.mData) + mCurrentPosition;
+ mCurrentPosition = newPos;
+ return ptr;
+}
+
+VertexBufferSection::VertexBufferSection()
+ : mOffset(-1), mNumVertices(0), mStride(0) {}
+
+void VertexBufferSection::Init(MLGBuffer* aBuffer, ptrdiff_t aOffset,
+ size_t aNumVertices, size_t aStride) {
+ mBuffer = aBuffer;
+ mOffset = aOffset;
+ mNumVertices = aNumVertices;
+ mStride = aStride;
+}
+
+ConstantBufferSection::ConstantBufferSection()
+ : mOffset(-1), mNumBytes(0), mNumItems(0) {}
+
+void ConstantBufferSection::Init(MLGBuffer* aBuffer, ptrdiff_t aOffset,
+ size_t aBytes, size_t aNumItems) {
+ mBuffer = aBuffer;
+ mOffset = aOffset;
+ mNumBytes = aBytes;
+ mNumItems = aNumItems;
+}
+
+SharedVertexBuffer::SharedVertexBuffer(MLGDevice* aDevice, size_t aDefaultSize)
+ : SharedBufferMLGPU(aDevice, MLGBufferType::Vertex, aDefaultSize) {}
+
+bool SharedVertexBuffer::Allocate(VertexBufferSection* aHolder,
+ size_t aNumItems, size_t aSizeOfItem,
+ const void* aData) {
+ RefPtr<MLGBuffer> buffer;
+ ptrdiff_t offset;
+ size_t bytes = aSizeOfItem * aNumItems;
+ uint8_t* ptr = GetBufferPointer(bytes, &offset, &buffer);
+ if (!ptr) {
+ return false;
+ }
+
+ memcpy(ptr, aData, bytes);
+ aHolder->Init(buffer, offset, aNumItems, aSizeOfItem);
+ return true;
+}
+
+AutoBufferUploadBase::AutoBufferUploadBase() : mPtr(nullptr) {}
+
+AutoBufferUploadBase::~AutoBufferUploadBase() {
+ if (mBuffer) {
+ UnmapBuffer();
+ }
+}
+
+void AutoBufferUploadBase::Init(void* aPtr, MLGDevice* aDevice,
+ MLGBuffer* aBuffer) {
+ MOZ_ASSERT(!mPtr && aPtr);
+ mPtr = aPtr;
+ mDevice = aDevice;
+ mBuffer = aBuffer;
+}
+
+SharedConstantBuffer::SharedConstantBuffer(MLGDevice* aDevice,
+ size_t aDefaultSize)
+ : SharedBufferMLGPU(aDevice, MLGBufferType::Constant, aDefaultSize) {
+ mMaxConstantBufferBindSize = aDevice->GetMaxConstantBufferBindSize();
+ mCanUseOffsetAllocation = aDevice->CanUseConstantBufferOffsetBinding();
+}
+
+bool SharedConstantBuffer::Allocate(ConstantBufferSection* aHolder,
+ AutoBufferUploadBase* aPtr,
+ size_t aNumItems, size_t aSizeOfItem) {
+ MOZ_ASSERT(aSizeOfItem % 16 == 0, "Items must be padded to 16 bytes");
+
+ size_t bytes = aNumItems * aSizeOfItem;
+ if (bytes > mMaxConstantBufferBindSize) {
+ gfxWarning()
+ << "Attempted to allocate too many bytes into a constant buffer";
+ return false;
+ }
+
+ RefPtr<MLGBuffer> buffer;
+ ptrdiff_t offset;
+ if (!GetBufferPointer(aPtr, bytes, &offset, &buffer)) {
+ return false;
+ }
+
+ aHolder->Init(buffer, offset, bytes, aNumItems);
+ return true;
+}
+
+uint8_t* SharedConstantBuffer::AllocateNewBuffer(
+ size_t aBytes, ptrdiff_t* aOutOffset, RefPtr<MLGBuffer>* aOutBuffer) {
+ RefPtr<MLGBuffer> buffer;
+ if (BufferCache* cache = mDevice->GetConstantBufferCache()) {
+ buffer = cache->GetOrCreateBuffer(aBytes);
+ } else {
+ buffer = mDevice->CreateBuffer(MLGBufferType::Constant, aBytes,
+ MLGUsage::Dynamic);
+ }
+ if (!buffer) {
+ return nullptr;
+ }
+
+ MLGMappedResource map;
+ if (!mDevice->Map(buffer, MLGMapType::WRITE_DISCARD, &map)) {
+ return nullptr;
+ }
+
+ // Signal that offsetting is not supported.
+ *aOutOffset = -1;
+ *aOutBuffer = buffer;
+ return reinterpret_cast<uint8_t*>(map.mData);
+}
+
+void AutoBufferUploadBase::UnmapBuffer() { mDevice->Unmap(mBuffer); }
+
+} // namespace layers
+} // namespace mozilla