blob: 7bb1633824b287867b8c08874960a7dcdbf75d97 [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/Buffer.h"
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040016
Austin Enge3fd0262021-01-05 07:40:48 +000017#include "common/Alloc.h"
Corentin Wallezfd589f32017-07-10 13:46:05 -040018#include "common/Assert.h"
Jiawei Shaoc11a1912020-07-28 01:58:50 +000019#include "dawn_native/Commands.h"
Corentin Wallezd37523f2018-07-24 13:53:51 +020020#include "dawn_native/Device.h"
Bryan Bernhart67a73bd2019-02-15 21:18:40 +000021#include "dawn_native/DynamicUploader.h"
Natasha Lee0ecc48e2020-01-15 19:02:13 +000022#include "dawn_native/ErrorData.h"
Corentin Wallez47a33412020-06-02 09:24:39 +000023#include "dawn_native/Queue.h"
Corentin Wallez82b65732018-08-22 15:37:29 +020024#include "dawn_native/ValidationUtils_autogen.h"
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040025
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040026#include <cstdio>
Stephen White68d97ad2019-07-23 17:04:34 +000027#include <cstring>
Corentin Wallezc1400f02017-11-24 13:59:42 -050028#include <utility>
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040029
Corentin Wallez49a65d02018-07-24 16:45:45 +020030namespace dawn_native {
Corentin Wallezf07e3bd2017-04-20 14:38:20 -040031
Corentin Walleza594f8f2019-02-13 13:09:18 +000032 namespace {
Natasha Lee51af1b42020-10-12 22:32:33 +000033 struct MapRequestTask : QueueBase::TaskInFlight {
34 MapRequestTask(Ref<BufferBase> buffer, MapRequestID id)
35 : buffer(std::move(buffer)), id(id) {
36 }
37 void Finish() override {
Corentin Wallezc1d3a662021-01-27 15:54:12 +000038 buffer->OnMapRequestCompleted(id, WGPUBufferMapAsyncStatus_Success);
39 }
40 void HandleDeviceLoss() override {
41 buffer->OnMapRequestCompleted(id, WGPUBufferMapAsyncStatus_DeviceLost);
Natasha Lee51af1b42020-10-12 22:32:33 +000042 }
43 ~MapRequestTask() override = default;
44
45 private:
46 Ref<BufferBase> buffer;
47 MapRequestID id;
48 };
Corentin Walleza594f8f2019-02-13 13:09:18 +000049
Rafael Cintronc64242d2020-04-06 18:20:02 +000050 class ErrorBuffer final : public BufferBase {
Corentin Walleza594f8f2019-02-13 13:09:18 +000051 public:
Corentin Wallezb2ea1912020-07-07 11:21:51 +000052 ErrorBuffer(DeviceBase* device, const BufferDescriptor* descriptor)
53 : BufferBase(device, descriptor, ObjectBase::kError) {
54 if (descriptor->mappedAtCreation) {
55 // Check that the size can be used to allocate an mFakeMappedData. A malloc(0)
56 // is invalid, and on 32bit systems we should avoid a narrowing conversion that
57 // would make size = 1 << 32 + 1 allocate one byte.
58 bool isValidSize =
59 descriptor->size != 0 &&
60 descriptor->size < uint64_t(std::numeric_limits<size_t>::max());
Corentin Walleza594f8f2019-02-13 13:09:18 +000061
Corentin Wallezb2ea1912020-07-07 11:21:51 +000062 if (isValidSize) {
Austin Enge3fd0262021-01-05 07:40:48 +000063 mFakeMappedData =
64 std::unique_ptr<uint8_t[]>(AllocNoThrow<uint8_t>(descriptor->size));
Corentin Wallezb2ea1912020-07-07 11:21:51 +000065 }
66 }
Austin Eng740995c2019-05-15 18:55:22 +000067 }
68
Austin Eng9cd21f12019-06-05 18:35:31 +000069 void ClearMappedData() {
70 mFakeMappedData.reset();
71 }
72
Corentin Walleza594f8f2019-02-13 13:09:18 +000073 private:
Jiawei Shao1c4a7f72020-09-01 08:08:57 +000074 bool IsCPUWritableAtCreation() const override {
Austin Eng9cd21f12019-06-05 18:35:31 +000075 UNREACHABLE();
Austin Eng9cd21f12019-06-05 18:35:31 +000076 }
77
Corentin Wallezb2ea1912020-07-07 11:21:51 +000078 MaybeError MapAtCreationImpl() override {
Austin Eng740995c2019-05-15 18:55:22 +000079 UNREACHABLE();
Austin Eng740995c2019-05-15 18:55:22 +000080 }
81
Corentin Wallez0d52f802020-07-14 12:30:14 +000082 MaybeError MapAsyncImpl(wgpu::MapMode mode, size_t offset, size_t size) override {
83 UNREACHABLE();
Corentin Wallez0d52f802020-07-14 12:30:14 +000084 }
Natasha Lee949f1e42020-05-19 01:29:32 +000085 void* GetMappedPointerImpl() override {
86 return mFakeMappedData.get();
87 }
Corentin Walleza594f8f2019-02-13 13:09:18 +000088 void UnmapImpl() override {
Austin Eng9cd21f12019-06-05 18:35:31 +000089 UNREACHABLE();
Corentin Walleza594f8f2019-02-13 13:09:18 +000090 }
Natasha Lee718e1db2019-03-11 17:05:22 +000091 void DestroyImpl() override {
92 UNREACHABLE();
93 }
Austin Eng740995c2019-05-15 18:55:22 +000094
95 std::unique_ptr<uint8_t[]> mFakeMappedData;
Corentin Walleza594f8f2019-02-13 13:09:18 +000096 };
97
98 } // anonymous namespace
99
Corentin Wallez82b65732018-08-22 15:37:29 +0200100 MaybeError ValidateBufferDescriptor(DeviceBase*, const BufferDescriptor* descriptor) {
Corentin Wallez6fee61c2018-09-10 16:17:24 +0200101 if (descriptor->nextInChain != nullptr) {
102 return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
103 }
104
Corentin Wallez9e9e29f2019-08-27 08:21:39 +0000105 DAWN_TRY(ValidateBufferUsage(descriptor->usage));
Corentin Wallez82b65732018-08-22 15:37:29 +0200106
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000107 wgpu::BufferUsage usage = descriptor->usage;
Corentin Wallez82b65732018-08-22 15:37:29 +0200108
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000109 const wgpu::BufferUsage kMapWriteAllowedUsages =
110 wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc;
111 if (usage & wgpu::BufferUsage::MapWrite && (usage & kMapWriteAllowedUsages) != usage) {
Corentin Wallezec053552019-07-08 10:05:46 +0000112 return DAWN_VALIDATION_ERROR("Only CopySrc is allowed with MapWrite");
Corentin Wallez82b65732018-08-22 15:37:29 +0200113 }
114
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000115 const wgpu::BufferUsage kMapReadAllowedUsages =
116 wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst;
117 if (usage & wgpu::BufferUsage::MapRead && (usage & kMapReadAllowedUsages) != usage) {
Corentin Wallezec053552019-07-08 10:05:46 +0000118 return DAWN_VALIDATION_ERROR("Only CopyDst is allowed with MapRead");
Corentin Wallez82b65732018-08-22 15:37:29 +0200119 }
120
Corentin Wallezb2ea1912020-07-07 11:21:51 +0000121 if (descriptor->mappedAtCreation && descriptor->size % 4 != 0) {
122 return DAWN_VALIDATION_ERROR("size must be aligned to 4 when mappedAtCreation is true");
123 }
124
Corentin Wallez82b65732018-08-22 15:37:29 +0200125 return {};
126 }
127
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400128 // Buffer
129
Corentin Wallez82b65732018-08-22 15:37:29 +0200130 BufferBase::BufferBase(DeviceBase* device, const BufferDescriptor* descriptor)
Austin Eng446ab442019-02-13 21:26:48 +0000131 : ObjectBase(device),
132 mSize(descriptor->size),
133 mUsage(descriptor->usage),
134 mState(BufferState::Unmapped) {
Yunchao He64cfaea2019-11-07 07:09:07 +0000135 // Add readonly storage usage if the buffer has a storage usage. The validation rules in
Corentin Wallez2dd2d672021-05-05 15:41:13 +0000136 // ValidateSyncScopeResourceUsage will make sure we don't use both at the same time.
Yunchao He64cfaea2019-11-07 07:09:07 +0000137 if (mUsage & wgpu::BufferUsage::Storage) {
Jiawei Shaoe89b4872020-04-21 00:48:10 +0000138 mUsage |= kReadOnlyStorageBuffer;
Yunchao He64cfaea2019-11-07 07:09:07 +0000139 }
Hao Li6f833b72021-01-14 03:26:08 +0000140
Li Hao551e7a12021-07-02 09:51:18 +0000141 // The query resolve buffer need to be used as a storage buffer in the internal compute
142 // pipeline which does timestamp uint conversion for timestamp query, it requires the buffer
143 // has Storage usage in the binding group. Implicitly add an InternalStorage usage which is
144 // only compatible with InternalStorageBuffer binding type in BGL. It shouldn't be
145 // compatible with StorageBuffer binding type and the query resolve buffer cannot be bound
146 // as storage buffer if it's created without Storage usage.
Hao Li6f833b72021-01-14 03:26:08 +0000147 if (mUsage & wgpu::BufferUsage::QueryResolve) {
Li Haob936d232021-06-16 14:33:27 +0000148 mUsage |= kInternalStorageBuffer;
Hao Li6f833b72021-01-14 03:26:08 +0000149 }
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400150 }
151
Corentin Wallezb2ea1912020-07-07 11:21:51 +0000152 BufferBase::BufferBase(DeviceBase* device,
153 const BufferDescriptor* descriptor,
154 ObjectBase::ErrorTag tag)
155 : ObjectBase(device, tag), mSize(descriptor->size), mState(BufferState::Unmapped) {
156 if (descriptor->mappedAtCreation) {
157 mState = BufferState::MappedAtCreation;
Corentin Wallezf6e70442020-07-17 18:50:37 +0000158 mMapOffset = 0;
159 mMapSize = mSize;
Corentin Wallezb2ea1912020-07-07 11:21:51 +0000160 }
Corentin Walleza594f8f2019-02-13 13:09:18 +0000161 }
162
Corentin Wallezb1c19ee2017-06-09 10:51:29 -0400163 BufferBase::~BufferBase() {
Austin Eng446ab442019-02-13 21:26:48 +0000164 if (mState == BufferState::Mapped) {
Corentin Walleza594f8f2019-02-13 13:09:18 +0000165 ASSERT(!IsError());
Corentin Wallez53cdbea2020-09-28 14:14:44 +0000166 CallMapCallback(mLastMapID, WGPUBufferMapAsyncStatus_DestroyedBeforeCallback);
Corentin Wallezb1c19ee2017-06-09 10:51:29 -0400167 }
168 }
169
Corentin Walleza594f8f2019-02-13 13:09:18 +0000170 // static
Corentin Wallezb2ea1912020-07-07 11:21:51 +0000171 BufferBase* BufferBase::MakeError(DeviceBase* device, const BufferDescriptor* descriptor) {
172 return new ErrorBuffer(device, descriptor);
Austin Eng740995c2019-05-15 18:55:22 +0000173 }
174
Austin Eng9cd21f12019-06-05 18:35:31 +0000175 uint64_t BufferBase::GetSize() const {
Corentin Walleza594f8f2019-02-13 13:09:18 +0000176 ASSERT(!IsError());
Corentin Wallezfbecc282017-11-23 10:32:51 -0800177 return mSize;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400178 }
179
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000180 wgpu::BufferUsage BufferBase::GetUsage() const {
Corentin Walleza594f8f2019-02-13 13:09:18 +0000181 ASSERT(!IsError());
Corentin Wallez62c77432018-08-22 15:08:02 +0200182 return mUsage;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400183 }
184
Corentin Wallezb2ea1912020-07-07 11:21:51 +0000185 MaybeError BufferBase::MapAtCreation() {
Jiawei Shao1c4a7f72020-09-01 08:08:57 +0000186 DAWN_TRY(MapAtCreationInternal());
187
Jiawei Shao1c4a7f72020-09-01 08:08:57 +0000188 DeviceBase* device = GetDevice();
Jiawei Shao88001352020-09-02 00:21:08 +0000189 if (device->IsToggleEnabled(Toggle::LazyClearResourceOnFirstUse)) {
Corentin Wallez79c9d122021-03-31 11:24:42 +0000190 memset(GetMappedRange(0, mSize), uint8_t(0u), mSize);
Jiawei Shao1c4a7f72020-09-01 08:08:57 +0000191 SetIsDataInitialized();
192 device->IncrementLazyClearCountForTesting();
193 } else if (device->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) {
Corentin Wallez79c9d122021-03-31 11:24:42 +0000194 memset(GetMappedRange(0, mSize), uint8_t(1u), mSize);
Jiawei Shao1c4a7f72020-09-01 08:08:57 +0000195 }
196
197 return {};
198 }
199
200 MaybeError BufferBase::MapAtCreationInternal() {
Austin Eng740995c2019-05-15 18:55:22 +0000201 ASSERT(!IsError());
Corentin Wallez2008d152020-06-30 11:05:44 +0000202 mState = BufferState::MappedAtCreation;
Corentin Wallezf6e70442020-07-17 18:50:37 +0000203 mMapOffset = 0;
204 mMapSize = mSize;
Corentin Wallez2008d152020-06-30 11:05:44 +0000205
Corentin Wallez91904cd2020-06-30 12:21:54 +0000206 // 0-sized buffers are not supposed to be written to, Return back any non-null pointer.
207 // Handle 0-sized buffers first so we don't try to map them in the backend.
208 if (mSize == 0) {
Corentin Wallez91904cd2020-06-30 12:21:54 +0000209 return {};
210 }
211
Corentin Wallez13f46502020-06-11 11:07:05 +0000212 // Mappable buffers don't use a staging buffer and are just as if mapped through MapAsync.
Jiawei Shao1c4a7f72020-09-01 08:08:57 +0000213 if (IsCPUWritableAtCreation()) {
Corentin Wallezb2ea1912020-07-07 11:21:51 +0000214 DAWN_TRY(MapAtCreationImpl());
Jiawei Shao1c4a7f72020-09-01 08:08:57 +0000215 } else {
216 // If any of these fail, the buffer will be deleted and replaced with an
217 // error buffer.
Austin Enged8a8c02021-06-04 22:23:56 +0000218 // TODO(crbug.com/dawn/828): Suballocate and reuse memory from a larger staging buffer
219 // so we don't create many small buffers.
Jiawei Shao1c4a7f72020-09-01 08:08:57 +0000220 DAWN_TRY_ASSIGN(mStagingBuffer, GetDevice()->CreateStagingBuffer(GetSize()));
Austin Eng740995c2019-05-15 18:55:22 +0000221 }
222
Austin Eng740995c2019-05-15 18:55:22 +0000223 return {};
224 }
225
Corentin Wallez47a33412020-06-02 09:24:39 +0000226 MaybeError BufferBase::ValidateCanUseOnQueueNow() const {
Corentin Walleza594f8f2019-02-13 13:09:18 +0000227 ASSERT(!IsError());
228
Austin Eng446ab442019-02-13 21:26:48 +0000229 switch (mState) {
230 case BufferState::Destroyed:
231 return DAWN_VALIDATION_ERROR("Destroyed buffer used in a submit");
232 case BufferState::Mapped:
Corentin Wallez13f46502020-06-11 11:07:05 +0000233 case BufferState::MappedAtCreation:
Austin Eng446ab442019-02-13 21:26:48 +0000234 return DAWN_VALIDATION_ERROR("Buffer used in a submit while mapped");
235 case BufferState::Unmapped:
236 return {};
Corentin Wallez679ff4e2018-11-07 10:02:43 +0000237 }
Corentin Wallez679ff4e2018-11-07 10:02:43 +0000238 }
239
Corentin Wallez53cdbea2020-09-28 14:14:44 +0000240 void BufferBase::CallMapCallback(MapRequestID mapID, WGPUBufferMapAsyncStatus status) {
Corentin Wallez0d52f802020-07-14 12:30:14 +0000241 ASSERT(!IsError());
Corentin Wallez53cdbea2020-09-28 14:14:44 +0000242 if (mMapCallback != nullptr && mapID == mLastMapID) {
Corentin Wallez0d52f802020-07-14 12:30:14 +0000243 // Tag the callback as fired before firing it, otherwise it could fire a second time if
244 // for example buffer.Unmap() is called inside the application-provided callback.
245 WGPUBufferMapCallback callback = mMapCallback;
246 mMapCallback = nullptr;
247
248 if (GetDevice()->IsLost()) {
249 callback(WGPUBufferMapAsyncStatus_DeviceLost, mMapUserdata);
250 } else {
251 callback(status, mMapUserdata);
252 }
253 }
254 }
255
Corentin Wallez2ce4b902021-03-29 14:02:05 +0000256 void BufferBase::APIMapAsync(wgpu::MapMode mode,
257 size_t offset,
258 size_t size,
259 WGPUBufferMapCallback callback,
260 void* userdata) {
Corentin Wallez0d52f802020-07-14 12:30:14 +0000261 // Handle the defaulting of size required by WebGPU, even if in webgpu_cpp.h it is not
262 // possible to default the function argument (because there is the callback later in the
263 // argument list)
264 if (size == 0 && offset < mSize) {
265 size = mSize - offset;
266 }
267
268 WGPUBufferMapAsyncStatus status;
269 if (GetDevice()->ConsumedError(ValidateMapAsync(mode, offset, size, &status))) {
270 if (callback) {
271 callback(status, userdata);
272 }
273 return;
274 }
275 ASSERT(!IsError());
276
Corentin Wallez53cdbea2020-09-28 14:14:44 +0000277 mLastMapID++;
Corentin Wallez0d52f802020-07-14 12:30:14 +0000278 mMapMode = mode;
279 mMapOffset = offset;
Corentin Wallezf6e70442020-07-17 18:50:37 +0000280 mMapSize = size;
Corentin Wallez0d52f802020-07-14 12:30:14 +0000281 mMapCallback = callback;
282 mMapUserdata = userdata;
283 mState = BufferState::Mapped;
284
285 if (GetDevice()->ConsumedError(MapAsyncImpl(mode, offset, size))) {
Corentin Wallez53cdbea2020-09-28 14:14:44 +0000286 CallMapCallback(mLastMapID, WGPUBufferMapAsyncStatus_DeviceLost);
Corentin Wallez0d52f802020-07-14 12:30:14 +0000287 return;
288 }
Natasha Lee51af1b42020-10-12 22:32:33 +0000289 std::unique_ptr<MapRequestTask> request =
290 std::make_unique<MapRequestTask>(this, mLastMapID);
Corentin Walleze91975c2021-03-29 15:40:55 +0000291 GetDevice()->GetQueue()->TrackTask(std::move(request),
292 GetDevice()->GetPendingCommandSerial());
Corentin Wallezb1c19ee2017-06-09 10:51:29 -0400293 }
294
Corentin Wallez2ce4b902021-03-29 14:02:05 +0000295 void* BufferBase::APIGetMappedRange(size_t offset, size_t size) {
Corentin Wallez79c9d122021-03-31 11:24:42 +0000296 return GetMappedRange(offset, size, true);
Corentin Wallez1325ab12020-06-30 11:51:14 +0000297 }
298
Corentin Wallez2ce4b902021-03-29 14:02:05 +0000299 const void* BufferBase::APIGetConstMappedRange(size_t offset, size_t size) {
Corentin Wallez79c9d122021-03-31 11:24:42 +0000300 return GetMappedRange(offset, size, false);
Corentin Wallezdbf805f2020-07-06 18:08:10 +0000301 }
302
Corentin Wallez79c9d122021-03-31 11:24:42 +0000303 void* BufferBase::GetMappedRange(size_t offset, size_t size, bool writable) {
Corentin Wallezf6e70442020-07-17 18:50:37 +0000304 if (!CanGetMappedRange(writable, offset, size)) {
Corentin Wallez1325ab12020-06-30 11:51:14 +0000305 return nullptr;
306 }
Corentin Wallezdbf805f2020-07-06 18:08:10 +0000307
Corentin Wallez1325ab12020-06-30 11:51:14 +0000308 if (mStagingBuffer != nullptr) {
Corentin Wallezf6e70442020-07-17 18:50:37 +0000309 return static_cast<uint8_t*>(mStagingBuffer->GetMappedPointer()) + offset;
Corentin Wallez1325ab12020-06-30 11:51:14 +0000310 }
Corentin Wallezdbf805f2020-07-06 18:08:10 +0000311 if (mSize == 0) {
312 return reinterpret_cast<uint8_t*>(intptr_t(0xCAFED00D));
313 }
Austin Enge3fd0262021-01-05 07:40:48 +0000314 uint8_t* start = static_cast<uint8_t*>(GetMappedPointerImpl());
315 return start == nullptr ? nullptr : start + offset;
Corentin Wallez1325ab12020-06-30 11:51:14 +0000316 }
317
Corentin Wallez2ce4b902021-03-29 14:02:05 +0000318 void BufferBase::APIDestroy() {
Austin Eng9cd21f12019-06-05 18:35:31 +0000319 if (IsError()) {
320 // It is an error to call Destroy() on an ErrorBuffer, but we still need to reclaim the
321 // fake mapped staging data.
Corentin Wallezb2ea1912020-07-07 11:21:51 +0000322 static_cast<ErrorBuffer*>(this)->ClearMappedData();
323 mState = BufferState::Destroyed;
Austin Eng9cd21f12019-06-05 18:35:31 +0000324 }
Austin Eng446ab442019-02-13 21:26:48 +0000325 if (GetDevice()->ConsumedError(ValidateDestroy())) {
326 return;
327 }
328 ASSERT(!IsError());
329
330 if (mState == BufferState::Mapped) {
Jiawei Shaoed2b4652020-09-27 02:00:52 +0000331 UnmapInternal(WGPUBufferMapAsyncStatus_DestroyedBeforeCallback);
Corentin Wallez13f46502020-06-11 11:07:05 +0000332 } else if (mState == BufferState::MappedAtCreation) {
333 if (mStagingBuffer != nullptr) {
334 mStagingBuffer.reset();
Corentin Wallez2008d152020-06-30 11:05:44 +0000335 } else if (mSize != 0) {
Jiawei Shao1c4a7f72020-09-01 08:08:57 +0000336 ASSERT(IsCPUWritableAtCreation());
Jiawei Shaoed2b4652020-09-27 02:00:52 +0000337 UnmapInternal(WGPUBufferMapAsyncStatus_DestroyedBeforeCallback);
Austin Eng9cd21f12019-06-05 18:35:31 +0000338 }
Austin Eng446ab442019-02-13 21:26:48 +0000339 }
Corentin Wallez13f46502020-06-11 11:07:05 +0000340
Natasha Lee20b0c332019-04-01 19:49:04 +0000341 DestroyInternal();
Austin Eng446ab442019-02-13 21:26:48 +0000342 }
343
Austin Eng9cd21f12019-06-05 18:35:31 +0000344 MaybeError BufferBase::CopyFromStagingBuffer() {
345 ASSERT(mStagingBuffer);
Corentin Wallez45aed832020-06-05 15:44:03 +0000346 if (GetSize() == 0) {
347 return {};
348 }
349
Austin Eng9cd21f12019-06-05 18:35:31 +0000350 DAWN_TRY(GetDevice()->CopyFromStagingToBuffer(mStagingBuffer.get(), 0, this, 0, GetSize()));
351
Bryan Bernhart450e2122019-09-18 22:06:41 +0000352 DynamicUploader* uploader = GetDevice()->GetDynamicUploader();
Austin Eng9cd21f12019-06-05 18:35:31 +0000353 uploader->ReleaseStagingBuffer(std::move(mStagingBuffer));
354
355 return {};
356 }
357
Corentin Wallez2ce4b902021-03-29 14:02:05 +0000358 void BufferBase::APIUnmap() {
Corentin Wallez79c9d122021-03-31 11:24:42 +0000359 Unmap();
360 }
361
362 void BufferBase::Unmap() {
Jiawei Shaoed2b4652020-09-27 02:00:52 +0000363 UnmapInternal(WGPUBufferMapAsyncStatus_UnmappedBeforeCallback);
364 }
365
366 void BufferBase::UnmapInternal(WGPUBufferMapAsyncStatus callbackStatus) {
Austin Eng740995c2019-05-15 18:55:22 +0000367 if (IsError()) {
368 // It is an error to call Unmap() on an ErrorBuffer, but we still need to reclaim the
369 // fake mapped staging data.
Corentin Wallezb2ea1912020-07-07 11:21:51 +0000370 static_cast<ErrorBuffer*>(this)->ClearMappedData();
371 mState = BufferState::Unmapped;
Austin Eng740995c2019-05-15 18:55:22 +0000372 }
Corentin Wallez9e4518b2018-10-15 12:54:30 +0000373 if (GetDevice()->ConsumedError(ValidateUnmap())) {
Corentin Wallezb1c19ee2017-06-09 10:51:29 -0400374 return;
375 }
Corentin Walleza594f8f2019-02-13 13:09:18 +0000376 ASSERT(!IsError());
Corentin Wallezb1c19ee2017-06-09 10:51:29 -0400377
Corentin Wallez13f46502020-06-11 11:07:05 +0000378 if (mState == BufferState::Mapped) {
Austin Eng9cd21f12019-06-05 18:35:31 +0000379 // A map request can only be called once, so this will fire only if the request wasn't
380 // completed before the Unmap.
381 // Callbacks are not fired if there is no callback registered, so this is correct for
Corentin Wallezf7123d72020-08-20 14:22:29 +0000382 // mappedAtCreation = true.
Corentin Wallez53cdbea2020-09-28 14:14:44 +0000383 CallMapCallback(mLastMapID, callbackStatus);
Austin Eng9cd21f12019-06-05 18:35:31 +0000384 UnmapImpl();
Corentin Wallez13f46502020-06-11 11:07:05 +0000385
Corentin Wallez2088cde2020-08-12 19:32:25 +0000386 mMapCallback = nullptr;
Corentin Wallez13f46502020-06-11 11:07:05 +0000387 mMapUserdata = 0;
388
389 } else if (mState == BufferState::MappedAtCreation) {
390 if (mStagingBuffer != nullptr) {
391 GetDevice()->ConsumedError(CopyFromStagingBuffer());
Corentin Wallez2008d152020-06-30 11:05:44 +0000392 } else if (mSize != 0) {
Jiawei Shao1c4a7f72020-09-01 08:08:57 +0000393 ASSERT(IsCPUWritableAtCreation());
Corentin Wallez2008d152020-06-30 11:05:44 +0000394 UnmapImpl();
Corentin Wallez13f46502020-06-11 11:07:05 +0000395 }
Austin Eng9cd21f12019-06-05 18:35:31 +0000396 }
Corentin Wallez13f46502020-06-11 11:07:05 +0000397
Austin Eng446ab442019-02-13 21:26:48 +0000398 mState = BufferState::Unmapped;
Corentin Wallezb1c19ee2017-06-09 10:51:29 -0400399 }
400
Natasha Lee74f50542020-01-28 22:18:58 +0000401 MaybeError BufferBase::ValidateMap(wgpu::BufferUsage requiredUsage,
402 WGPUBufferMapAsyncStatus* status) const {
403 *status = WGPUBufferMapAsyncStatus_DeviceLost;
Natasha Lee0ecc48e2020-01-15 19:02:13 +0000404 DAWN_TRY(GetDevice()->ValidateIsAlive());
Natasha Lee74f50542020-01-28 22:18:58 +0000405
406 *status = WGPUBufferMapAsyncStatus_Error;
Corentin Walleza594f8f2019-02-13 13:09:18 +0000407 DAWN_TRY(GetDevice()->ValidateObject(this));
408
Austin Eng9cd21f12019-06-05 18:35:31 +0000409 switch (mState) {
410 case BufferState::Mapped:
Corentin Wallez13f46502020-06-11 11:07:05 +0000411 case BufferState::MappedAtCreation:
Corentin Wallez0d52f802020-07-14 12:30:14 +0000412 return DAWN_VALIDATION_ERROR("Buffer is already mapped");
Austin Eng9cd21f12019-06-05 18:35:31 +0000413 case BufferState::Destroyed:
414 return DAWN_VALIDATION_ERROR("Buffer is destroyed");
415 case BufferState::Unmapped:
416 break;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400417 }
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400418
Corentin Wallez62c77432018-08-22 15:08:02 +0200419 if (!(mUsage & requiredUsage)) {
Corentin Wallez6fee61c2018-09-10 16:17:24 +0200420 return DAWN_VALIDATION_ERROR("Buffer needs the correct map usage bit");
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400421 }
Corentin Wallezd8c068f2018-07-09 15:15:07 +0200422
Natasha Lee74f50542020-01-28 22:18:58 +0000423 *status = WGPUBufferMapAsyncStatus_Success;
Corentin Wallez79149582018-07-18 21:20:07 +0200424 return {};
425 }
426
Corentin Wallez0d52f802020-07-14 12:30:14 +0000427 MaybeError BufferBase::ValidateMapAsync(wgpu::MapMode mode,
428 size_t offset,
429 size_t size,
430 WGPUBufferMapAsyncStatus* status) const {
431 *status = WGPUBufferMapAsyncStatus_DeviceLost;
432 DAWN_TRY(GetDevice()->ValidateIsAlive());
433
434 *status = WGPUBufferMapAsyncStatus_Error;
435 DAWN_TRY(GetDevice()->ValidateObject(this));
436
Corentin Wallez41711342020-10-07 17:19:53 +0000437 if (offset % 8 != 0) {
438 return DAWN_VALIDATION_ERROR("offset must be a multiple of 8");
Corentin Wallez0d52f802020-07-14 12:30:14 +0000439 }
440
441 if (size % 4 != 0) {
442 return DAWN_VALIDATION_ERROR("size must be a multiple of 4");
443 }
444
445 if (uint64_t(offset) > mSize || uint64_t(size) > mSize - uint64_t(offset)) {
446 return DAWN_VALIDATION_ERROR("size + offset must fit in the buffer");
447 }
448
449 switch (mState) {
450 case BufferState::Mapped:
451 case BufferState::MappedAtCreation:
452 return DAWN_VALIDATION_ERROR("Buffer is already mapped");
453 case BufferState::Destroyed:
454 return DAWN_VALIDATION_ERROR("Buffer is destroyed");
455 case BufferState::Unmapped:
456 break;
457 }
458
459 bool isReadMode = mode & wgpu::MapMode::Read;
460 bool isWriteMode = mode & wgpu::MapMode::Write;
461 if (!(isReadMode ^ isWriteMode)) {
462 return DAWN_VALIDATION_ERROR("Exactly one of Read or Write mode must be set");
463 }
464
465 if (mode & wgpu::MapMode::Read) {
466 if (!(mUsage & wgpu::BufferUsage::MapRead)) {
467 return DAWN_VALIDATION_ERROR("The buffer must have the MapRead usage");
468 }
469 } else {
470 ASSERT(mode & wgpu::MapMode::Write);
471
472 if (!(mUsage & wgpu::BufferUsage::MapWrite)) {
473 return DAWN_VALIDATION_ERROR("The buffer must have the MapWrite usage");
474 }
475 }
476
477 *status = WGPUBufferMapAsyncStatus_Success;
478 return {};
479 }
480
Corentin Wallezf6e70442020-07-17 18:50:37 +0000481 bool BufferBase::CanGetMappedRange(bool writable, size_t offset, size_t size) const {
Corentin Wallez41711342020-10-07 17:19:53 +0000482 if (offset % 8 != 0 || size % 4 != 0) {
483 return false;
484 }
485
Corentin Wallezf6e70442020-07-17 18:50:37 +0000486 if (size > mMapSize || offset < mMapOffset) {
487 return false;
488 }
489
490 size_t offsetInMappedRange = offset - mMapOffset;
491 if (offsetInMappedRange > mMapSize - size) {
492 return false;
493 }
494
Corentin Wallezdbf805f2020-07-06 18:08:10 +0000495 // Note that:
496 //
497 // - We don't check that the device is alive because the application can ask for the
498 // mapped pointer before it knows, and even Dawn knows, that the device was lost, and
499 // still needs to work properly.
500 // - We don't check that the object is alive because we need to return mapped pointers
501 // for error buffers too.
Corentin Wallez1325ab12020-06-30 11:51:14 +0000502
503 switch (mState) {
504 // Writeable Buffer::GetMappedRange is always allowed when mapped at creation.
505 case BufferState::MappedAtCreation:
Corentin Wallezdbf805f2020-07-06 18:08:10 +0000506 return true;
Corentin Wallez1325ab12020-06-30 11:51:14 +0000507
508 case BufferState::Mapped:
Corentin Wallezce78ce22020-08-22 11:08:34 +0000509 ASSERT(bool(mMapMode & wgpu::MapMode::Read) ^
510 bool(mMapMode & wgpu::MapMode::Write));
511 return !writable || (mMapMode & wgpu::MapMode::Write);
Corentin Wallez1325ab12020-06-30 11:51:14 +0000512
513 case BufferState::Unmapped:
514 case BufferState::Destroyed:
Corentin Wallezdbf805f2020-07-06 18:08:10 +0000515 return false;
Corentin Wallez1325ab12020-06-30 11:51:14 +0000516 }
517 }
518
Corentin Wallez79149582018-07-18 21:20:07 +0200519 MaybeError BufferBase::ValidateUnmap() const {
Natasha Lee0ecc48e2020-01-15 19:02:13 +0000520 DAWN_TRY(GetDevice()->ValidateIsAlive());
Corentin Walleza594f8f2019-02-13 13:09:18 +0000521 DAWN_TRY(GetDevice()->ValidateObject(this));
522
Austin Eng446ab442019-02-13 21:26:48 +0000523 switch (mState) {
Austin Eng446ab442019-02-13 21:26:48 +0000524 case BufferState::Mapped:
Corentin Wallez13f46502020-06-11 11:07:05 +0000525 case BufferState::MappedAtCreation:
Corentin Wallezf7123d72020-08-20 14:22:29 +0000526 // A buffer may be in the Mapped state if it was created with mappedAtCreation
Austin Eng9cd21f12019-06-05 18:35:31 +0000527 // even if it did not have a mappable usage.
528 return {};
529 case BufferState::Unmapped:
Corentin Wallezc1cce0c2020-10-07 15:14:03 +0000530 return DAWN_VALIDATION_ERROR("Buffer is unmapped");
Austin Eng446ab442019-02-13 21:26:48 +0000531 case BufferState::Destroyed:
532 return DAWN_VALIDATION_ERROR("Buffer is destroyed");
533 }
534 }
Corentin Wallez79149582018-07-18 21:20:07 +0200535
Austin Eng446ab442019-02-13 21:26:48 +0000536 MaybeError BufferBase::ValidateDestroy() const {
537 DAWN_TRY(GetDevice()->ValidateObject(this));
Corentin Wallez79149582018-07-18 21:20:07 +0200538 return {};
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400539 }
540
Natasha Lee20b0c332019-04-01 19:49:04 +0000541 void BufferBase::DestroyInternal() {
542 if (mState != BufferState::Destroyed) {
543 DestroyImpl();
544 }
545 mState = BufferState::Destroyed;
546 }
547
Corentin Wallezc1d3a662021-01-27 15:54:12 +0000548 void BufferBase::OnMapRequestCompleted(MapRequestID mapID, WGPUBufferMapAsyncStatus status) {
549 CallMapCallback(mapID, status);
Natasha Lee949f1e42020-05-19 01:29:32 +0000550 }
551
Jiawei Shao80f927d2020-07-06 08:24:30 +0000552 bool BufferBase::IsDataInitialized() const {
553 return mIsDataInitialized;
554 }
555
556 void BufferBase::SetIsDataInitialized() {
557 mIsDataInitialized = true;
558 }
559
560 bool BufferBase::IsFullBufferRange(uint64_t offset, uint64_t size) const {
561 return offset == 0 && size == GetSize();
562 }
Corentin Wallez49a65d02018-07-24 16:45:45 +0200563} // namespace dawn_native