• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "dawn_native/DynamicUploader.h"
16 #include "common/Math.h"
17 #include "dawn_native/Device.h"
18 
19 namespace dawn_native {
20 
DynamicUploader(DeviceBase * device)21     DynamicUploader::DynamicUploader(DeviceBase* device) : mDevice(device) {
22     }
23 
CreateStagingBuffer(size_t size)24     ResultOrError<std::unique_ptr<StagingBufferBase>> DynamicUploader::CreateStagingBuffer(
25         size_t size) {
26         std::unique_ptr<StagingBufferBase> stagingBuffer;
27         DAWN_TRY_ASSIGN(stagingBuffer, mDevice->CreateStagingBuffer(size));
28         DAWN_TRY(stagingBuffer->Initialize());
29         return stagingBuffer;
30     }
31 
ReleaseStagingBuffer(std::unique_ptr<StagingBufferBase> stagingBuffer)32     void DynamicUploader::ReleaseStagingBuffer(std::unique_ptr<StagingBufferBase> stagingBuffer) {
33         mReleasedStagingBuffers.Enqueue(std::move(stagingBuffer),
34                                         mDevice->GetPendingCommandSerial());
35     }
36 
CreateAndAppendBuffer(size_t size)37     MaybeError DynamicUploader::CreateAndAppendBuffer(size_t size) {
38         std::unique_ptr<RingBuffer> ringBuffer = std::make_unique<RingBuffer>(mDevice, size);
39         DAWN_TRY(ringBuffer->Initialize());
40         mRingBuffers.emplace_back(std::move(ringBuffer));
41         return {};
42     }
43 
Allocate(uint32_t size,uint32_t alignment)44     ResultOrError<UploadHandle> DynamicUploader::Allocate(uint32_t size, uint32_t alignment) {
45         ASSERT(IsPowerOfTwo(alignment));
46 
47         // Align the requested allocation size
48         const size_t alignedSize = Align(size, alignment);
49 
50         RingBuffer* largestRingBuffer = GetLargestBuffer();
51         UploadHandle uploadHandle = largestRingBuffer->SubAllocate(alignedSize);
52 
53         // Upon failure, append a newly created (and much larger) ring buffer to fulfill the
54         // request.
55         if (uploadHandle.mappedBuffer == nullptr) {
56             // Compute the new max size (in powers of two to preserve alignment).
57             size_t newMaxSize = largestRingBuffer->GetSize();
58             while (newMaxSize < size) {
59                 newMaxSize *= 2;
60             }
61 
62             // TODO(bryan.bernhart@intel.com): Fall-back to no sub-allocations should this fail.
63             DAWN_TRY(CreateAndAppendBuffer(newMaxSize));
64             largestRingBuffer = GetLargestBuffer();
65             uploadHandle = largestRingBuffer->SubAllocate(alignedSize);
66         }
67 
68         uploadHandle.stagingBuffer = largestRingBuffer->GetStagingBuffer();
69 
70         return uploadHandle;
71     }
72 
Tick(Serial lastCompletedSerial)73     void DynamicUploader::Tick(Serial lastCompletedSerial) {
74         // Reclaim memory within the ring buffers by ticking (or removing requests no longer
75         // in-flight).
76         for (size_t i = 0; i < mRingBuffers.size(); ++i) {
77             mRingBuffers[i]->Tick(lastCompletedSerial);
78 
79             // Never erase the last buffer as to prevent re-creating smaller buffers
80             // again. The last buffer is the largest.
81             if (mRingBuffers[i]->Empty() && i < mRingBuffers.size() - 1) {
82                 mRingBuffers.erase(mRingBuffers.begin() + i);
83             }
84         }
85         mReleasedStagingBuffers.ClearUpTo(lastCompletedSerial);
86     }
87 
GetLargestBuffer()88     RingBuffer* DynamicUploader::GetLargestBuffer() {
89         ASSERT(!mRingBuffers.empty());
90         return mRingBuffers.back().get();
91     }
92 
IsEmpty() const93     bool DynamicUploader::IsEmpty() const {
94         return mRingBuffers.empty();
95     }
96 }  // namespace dawn_native