blob: 94d9b18723bbc513dfd135728fdfcda65dafab95 [file] [log] [blame]
Corentin Wallez4a9ef4e2018-07-18 11:40:26 +02001// Copyright 2017 The Dawn Authors
Corentin Wallezf07e3bd2017-04-20 14:38:20 -04002//
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
Corentin Wallezd37523f2018-07-24 13:53:51 +020015#include "dawn_native/CommandAllocator.h"
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040016
Corentin Wallezfd589f32017-07-10 13:46:05 -040017#include "common/Assert.h"
Corentin Wallezfffe6df2017-07-06 14:41:13 -040018#include "common/Math.h"
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040019
Corentin Wallez944b60f2017-05-29 11:33:33 -070020#include <algorithm>
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040021#include <climits>
22#include <cstdlib>
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040023
Corentin Wallez49a65d02018-07-24 16:45:45 +020024namespace dawn_native {
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040025
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040026 // TODO(cwallez@chromium.org): figure out a way to have more type safety for the iterator
27
Corentin Wallezc1400f02017-11-24 13:59:42 -050028 CommandIterator::CommandIterator() : mEndOfBlock(EndOfBlock) {
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040029 Reset();
30 }
31
32 CommandIterator::~CommandIterator() {
Corentin Wallezfbecc282017-11-23 10:32:51 -080033 ASSERT(mDataWasDestroyed);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040034
35 if (!IsEmpty()) {
Corentin Wallezfbecc282017-11-23 10:32:51 -080036 for (auto& block : mBlocks) {
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040037 free(block.block);
38 }
39 }
40 }
41
Corentin Wallezc1400f02017-11-24 13:59:42 -050042 CommandIterator::CommandIterator(CommandIterator&& other) : mEndOfBlock(EndOfBlock) {
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040043 if (!other.IsEmpty()) {
Corentin Wallezfbecc282017-11-23 10:32:51 -080044 mBlocks = std::move(other.mBlocks);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040045 other.Reset();
46 }
47 other.DataWasDestroyed();
48 Reset();
49 }
50
51 CommandIterator& CommandIterator::operator=(CommandIterator&& other) {
52 if (!other.IsEmpty()) {
Corentin Wallezfbecc282017-11-23 10:32:51 -080053 mBlocks = std::move(other.mBlocks);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040054 other.Reset();
55 } else {
Corentin Wallezfbecc282017-11-23 10:32:51 -080056 mBlocks.clear();
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040057 }
58 other.DataWasDestroyed();
59 Reset();
60 return *this;
61 }
62
63 CommandIterator::CommandIterator(CommandAllocator&& allocator)
Corentin Wallezfbecc282017-11-23 10:32:51 -080064 : mBlocks(allocator.AcquireBlocks()), mEndOfBlock(EndOfBlock) {
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040065 Reset();
66 }
67
68 CommandIterator& CommandIterator::operator=(CommandAllocator&& allocator) {
Corentin Wallezfbecc282017-11-23 10:32:51 -080069 mBlocks = allocator.AcquireBlocks();
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040070 Reset();
71 return *this;
72 }
73
74 void CommandIterator::Reset() {
Corentin Wallezfbecc282017-11-23 10:32:51 -080075 mCurrentBlock = 0;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040076
Corentin Wallezfbecc282017-11-23 10:32:51 -080077 if (mBlocks.empty()) {
Corentin Wallezc1400f02017-11-24 13:59:42 -050078 // This will case the first NextCommandId call to try to move to the next block and stop
79 // the iteration immediately, without special casing the initialization.
Corentin Wallezfbecc282017-11-23 10:32:51 -080080 mCurrentPtr = reinterpret_cast<uint8_t*>(&mEndOfBlock);
81 mBlocks.emplace_back();
82 mBlocks[0].size = sizeof(mEndOfBlock);
83 mBlocks[0].block = mCurrentPtr;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040084 } else {
Corentin Wallezfbecc282017-11-23 10:32:51 -080085 mCurrentPtr = AlignPtr(mBlocks[0].block, alignof(uint32_t));
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040086 }
87 }
88
89 void CommandIterator::DataWasDestroyed() {
Corentin Wallezfbecc282017-11-23 10:32:51 -080090 mDataWasDestroyed = true;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040091 }
92
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040093
94 // Potential TODO(cwallez@chromium.org):
Corentin Wallezc1400f02017-11-24 13:59:42 -050095 // - Host the size and pointer to next block in the block itself to avoid having an allocation
96 // in the vector
97 // - Assume T's alignof is, say 64bits, static assert it, and make commandAlignment a constant
98 // in Allocate
99 // - Be able to optimize allocation to one block, for command buffers expected to live long to
100 // avoid cache misses
Corentin Wallez9fc65342018-07-18 15:28:38 +0200101 // - Better block allocation, maybe have Dawn API to say command buffer is going to have size
Corentin Wallezc1400f02017-11-24 13:59:42 -0500102 // close to another
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400103
104 CommandAllocator::CommandAllocator()
Corentin Wallezc1400f02017-11-24 13:59:42 -0500105 : mCurrentPtr(reinterpret_cast<uint8_t*>(&mDummyEnum[0])),
106 mEndPtr(reinterpret_cast<uint8_t*>(&mDummyEnum[1])) {
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400107 }
108
109 CommandAllocator::~CommandAllocator() {
Corentin Wallezfbecc282017-11-23 10:32:51 -0800110 ASSERT(mBlocks.empty());
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400111 }
112
113 CommandBlocks&& CommandAllocator::AcquireBlocks() {
Corentin Wallezfbecc282017-11-23 10:32:51 -0800114 ASSERT(mCurrentPtr != nullptr && mEndPtr != nullptr);
115 ASSERT(IsPtrAligned(mCurrentPtr, alignof(uint32_t)));
116 ASSERT(mCurrentPtr + sizeof(uint32_t) <= mEndPtr);
117 *reinterpret_cast<uint32_t*>(mCurrentPtr) = EndOfBlock;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400118
Corentin Wallezfbecc282017-11-23 10:32:51 -0800119 mCurrentPtr = nullptr;
120 mEndPtr = nullptr;
121 return std::move(mBlocks);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400122 }
123
Zhenyao Modf9d1b52019-11-13 19:33:59 +0000124 uint8_t* CommandAllocator::AllocateAtEnd(uint32_t commandId,
125 size_t commandSize,
126 size_t commandAlignment) {
Corentin Wallez1c92c152019-03-01 12:04:58 +0000127 static constexpr size_t kWorstCaseAdditionalSize =
128 sizeof(uint32_t) + kMaxSupportedAlignment + alignof(uint32_t) + sizeof(uint32_t);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400129
Corentin Wallez1c92c152019-03-01 12:04:58 +0000130 // When there is not enough space, we signal the EndOfBlock, so that the iterator knows to
131 // move to the next one. EndOfBlock on the last block means the end of the commands.
132 uint32_t* idAlloc = reinterpret_cast<uint32_t*>(mCurrentPtr);
133 *idAlloc = EndOfBlock;
134
135 // We'll request a block that can contain at least the command ID, the command and an
136 // additional ID to contain the EndOfBlock tag.
137 size_t requestedBlockSize = commandSize + kWorstCaseAdditionalSize;
138
139 // The computation of the request could overflow.
140 if (DAWN_UNLIKELY(requestedBlockSize <= commandSize)) {
141 return nullptr;
142 }
143
144 if (DAWN_UNLIKELY(!GetNewBlock(requestedBlockSize))) {
145 return nullptr;
146 }
147 return Allocate(commandId, commandSize, commandAlignment);
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400148 }
149
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400150 bool CommandAllocator::GetNewBlock(size_t minimumSize) {
151 // Allocate blocks doubling sizes each time, to a maximum of 16k (or at least minimumSize).
Corentin Wallezc1400f02017-11-24 13:59:42 -0500152 mLastAllocationSize =
153 std::max(minimumSize, std::min(mLastAllocationSize * 2, size_t(16384)));
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400154
Rafael Cintronf54bb682019-05-03 00:58:27 +0000155 uint8_t* block = static_cast<uint8_t*>(malloc(mLastAllocationSize));
Corentin Wallez1c92c152019-03-01 12:04:58 +0000156 if (DAWN_UNLIKELY(block == nullptr)) {
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400157 return false;
158 }
159
Corentin Wallezfbecc282017-11-23 10:32:51 -0800160 mBlocks.push_back({mLastAllocationSize, block});
161 mCurrentPtr = AlignPtr(block, alignof(uint32_t));
162 mEndPtr = block + mLastAllocationSize;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400163 return true;
164 }
165
Corentin Wallez49a65d02018-07-24 16:45:45 +0200166} // namespace dawn_native