mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-06-30 18:33:46 +00:00
Currently Dawn always doubles the size of the largest ring buffer everytime when DynamicUploader::Allocate() is called, which is not necessary and will cause out-of-memory errors when this function is called for too many times. This time fixes this behaviour by only doubling the size of the largest ring buffer when it is not big enough for the request buffer size. BUG=dawn:108 TEST=dawn_end2end_tests Change-Id: I734493dbc632ca8e9a30c1ceeb0b7b9e0474656b Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/9160 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org> Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
96 lines
3.7 KiB
C++
96 lines
3.7 KiB
C++
// Copyright 2018 The Dawn Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "dawn_native/DynamicUploader.h"
|
|
#include "common/Math.h"
|
|
#include "dawn_native/Device.h"
|
|
|
|
namespace dawn_native {
|
|
|
|
DynamicUploader::DynamicUploader(DeviceBase* device) : mDevice(device) {
|
|
}
|
|
|
|
ResultOrError<std::unique_ptr<StagingBufferBase>> DynamicUploader::CreateStagingBuffer(
|
|
size_t size) {
|
|
std::unique_ptr<StagingBufferBase> stagingBuffer;
|
|
DAWN_TRY_ASSIGN(stagingBuffer, mDevice->CreateStagingBuffer(size));
|
|
DAWN_TRY(stagingBuffer->Initialize());
|
|
return stagingBuffer;
|
|
}
|
|
|
|
void DynamicUploader::ReleaseStagingBuffer(std::unique_ptr<StagingBufferBase> stagingBuffer) {
|
|
mReleasedStagingBuffers.Enqueue(std::move(stagingBuffer),
|
|
mDevice->GetPendingCommandSerial());
|
|
}
|
|
|
|
MaybeError DynamicUploader::CreateAndAppendBuffer(size_t size) {
|
|
std::unique_ptr<RingBuffer> ringBuffer = std::make_unique<RingBuffer>(mDevice, size);
|
|
DAWN_TRY(ringBuffer->Initialize());
|
|
mRingBuffers.emplace_back(std::move(ringBuffer));
|
|
return {};
|
|
}
|
|
|
|
ResultOrError<UploadHandle> DynamicUploader::Allocate(uint32_t size, uint32_t alignment) {
|
|
ASSERT(IsPowerOfTwo(alignment));
|
|
|
|
// Align the requested allocation size
|
|
const size_t alignedSize = Align(size, alignment);
|
|
|
|
RingBuffer* largestRingBuffer = GetLargestBuffer();
|
|
UploadHandle uploadHandle = largestRingBuffer->SubAllocate(alignedSize);
|
|
|
|
// Upon failure, append a newly created (and much larger) ring buffer to fulfill the
|
|
// request.
|
|
if (uploadHandle.mappedBuffer == nullptr) {
|
|
// Compute the new max size (in powers of two to preserve alignment).
|
|
size_t newMaxSize = largestRingBuffer->GetSize();
|
|
while (newMaxSize < size) {
|
|
newMaxSize *= 2;
|
|
}
|
|
|
|
// TODO(bryan.bernhart@intel.com): Fall-back to no sub-allocations should this fail.
|
|
DAWN_TRY(CreateAndAppendBuffer(newMaxSize));
|
|
largestRingBuffer = GetLargestBuffer();
|
|
uploadHandle = largestRingBuffer->SubAllocate(alignedSize);
|
|
}
|
|
|
|
uploadHandle.stagingBuffer = largestRingBuffer->GetStagingBuffer();
|
|
|
|
return uploadHandle;
|
|
}
|
|
|
|
void DynamicUploader::Tick(Serial lastCompletedSerial) {
|
|
// Reclaim memory within the ring buffers by ticking (or removing requests no longer
|
|
// in-flight).
|
|
for (size_t i = 0; i < mRingBuffers.size(); ++i) {
|
|
mRingBuffers[i]->Tick(lastCompletedSerial);
|
|
|
|
// Never erase the last buffer as to prevent re-creating smaller buffers
|
|
// again. The last buffer is the largest.
|
|
if (mRingBuffers[i]->Empty() && i < mRingBuffers.size() - 1) {
|
|
mRingBuffers.erase(mRingBuffers.begin() + i);
|
|
}
|
|
}
|
|
mReleasedStagingBuffers.ClearUpTo(lastCompletedSerial);
|
|
}
|
|
|
|
RingBuffer* DynamicUploader::GetLargestBuffer() {
|
|
ASSERT(!mRingBuffers.empty());
|
|
return mRingBuffers.back().get();
|
|
}
|
|
|
|
bool DynamicUploader::IsEmpty() const {
|
|
return mRingBuffers.empty();
|
|
}
|
|
} // namespace dawn_native
|