blob: 49a7717ea40bd6265286cb989348dabadc8baaca [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
Corentin Wallezfd589f32017-07-10 13:46:05 -040017#include "common/Assert.h"
Jiawei Shaoc11a1912020-07-28 01:58:50 +000018#include "dawn_native/Commands.h"
Corentin Wallezd37523f2018-07-24 13:53:51 +020019#include "dawn_native/Device.h"
Bryan Bernhart67a73bd2019-02-15 21:18:40 +000020#include "dawn_native/DynamicUploader.h"
Natasha Lee0ecc48e2020-01-15 19:02:13 +000021#include "dawn_native/ErrorData.h"
Natasha Lee949f1e42020-05-19 01:29:32 +000022#include "dawn_native/MapRequestTracker.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 {
33
Rafael Cintronc64242d2020-04-06 18:20:02 +000034 class ErrorBuffer final : public BufferBase {
Corentin Walleza594f8f2019-02-13 13:09:18 +000035 public:
Corentin Wallezb2ea1912020-07-07 11:21:51 +000036 ErrorBuffer(DeviceBase* device, const BufferDescriptor* descriptor)
37 : BufferBase(device, descriptor, ObjectBase::kError) {
38 if (descriptor->mappedAtCreation) {
39 // Check that the size can be used to allocate an mFakeMappedData. A malloc(0)
40 // is invalid, and on 32bit systems we should avoid a narrowing conversion that
41 // would make size = 1 << 32 + 1 allocate one byte.
42 bool isValidSize =
43 descriptor->size != 0 &&
44 descriptor->size < uint64_t(std::numeric_limits<size_t>::max());
Corentin Walleza594f8f2019-02-13 13:09:18 +000045
Corentin Wallezb2ea1912020-07-07 11:21:51 +000046 if (isValidSize) {
47 mFakeMappedData = std::unique_ptr<uint8_t[]>(new (std::nothrow)
48 uint8_t[descriptor->size]);
49 }
50 }
Austin Eng740995c2019-05-15 18:55:22 +000051 }
52
Austin Eng9cd21f12019-06-05 18:35:31 +000053 void ClearMappedData() {
54 mFakeMappedData.reset();
55 }
56
Corentin Walleza594f8f2019-02-13 13:09:18 +000057 private:
Jiawei Shao1c4a7f72020-09-01 08:08:57 +000058 bool IsCPUWritableAtCreation() const override {
Austin Eng9cd21f12019-06-05 18:35:31 +000059 UNREACHABLE();
60 return false;
61 }
62
Corentin Wallezb2ea1912020-07-07 11:21:51 +000063 MaybeError MapAtCreationImpl() override {
Austin Eng740995c2019-05-15 18:55:22 +000064 UNREACHABLE();
65 return {};
66 }
67
Corentin Wallez0d52f802020-07-14 12:30:14 +000068 MaybeError MapAsyncImpl(wgpu::MapMode mode, size_t offset, size_t size) override {
69 UNREACHABLE();
70 return {};
71 }
Natasha Lee949f1e42020-05-19 01:29:32 +000072 void* GetMappedPointerImpl() override {
73 return mFakeMappedData.get();
74 }
Corentin Walleza594f8f2019-02-13 13:09:18 +000075 void UnmapImpl() override {
Austin Eng9cd21f12019-06-05 18:35:31 +000076 UNREACHABLE();
Corentin Walleza594f8f2019-02-13 13:09:18 +000077 }
Natasha Lee718e1db2019-03-11 17:05:22 +000078 void DestroyImpl() override {
79 UNREACHABLE();
80 }
Austin Eng740995c2019-05-15 18:55:22 +000081
82 std::unique_ptr<uint8_t[]> mFakeMappedData;
Corentin Walleza594f8f2019-02-13 13:09:18 +000083 };
84
85 } // anonymous namespace
86
Corentin Wallez82b65732018-08-22 15:37:29 +020087 MaybeError ValidateBufferDescriptor(DeviceBase*, const BufferDescriptor* descriptor) {
Corentin Wallez6fee61c2018-09-10 16:17:24 +020088 if (descriptor->nextInChain != nullptr) {
89 return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
90 }
91
Corentin Wallez9e9e29f2019-08-27 08:21:39 +000092 DAWN_TRY(ValidateBufferUsage(descriptor->usage));
Corentin Wallez82b65732018-08-22 15:37:29 +020093
Corentin Wallez1f6c8c42019-10-23 11:57:41 +000094 wgpu::BufferUsage usage = descriptor->usage;
Corentin Wallez82b65732018-08-22 15:37:29 +020095
Corentin Wallez1f6c8c42019-10-23 11:57:41 +000096 const wgpu::BufferUsage kMapWriteAllowedUsages =
97 wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc;
98 if (usage & wgpu::BufferUsage::MapWrite && (usage & kMapWriteAllowedUsages) != usage) {
Corentin Wallezec053552019-07-08 10:05:46 +000099 return DAWN_VALIDATION_ERROR("Only CopySrc is allowed with MapWrite");
Corentin Wallez82b65732018-08-22 15:37:29 +0200100 }
101
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000102 const wgpu::BufferUsage kMapReadAllowedUsages =
103 wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst;
104 if (usage & wgpu::BufferUsage::MapRead && (usage & kMapReadAllowedUsages) != usage) {
Corentin Wallezec053552019-07-08 10:05:46 +0000105 return DAWN_VALIDATION_ERROR("Only CopyDst is allowed with MapRead");
Corentin Wallez82b65732018-08-22 15:37:29 +0200106 }
107
Corentin Wallezb2ea1912020-07-07 11:21:51 +0000108 if (descriptor->mappedAtCreation && descriptor->size % 4 != 0) {
109 return DAWN_VALIDATION_ERROR("size must be aligned to 4 when mappedAtCreation is true");
110 }
111
Corentin Wallez82b65732018-08-22 15:37:29 +0200112 return {};
113 }
114
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400115 // Buffer
116
Corentin Wallez82b65732018-08-22 15:37:29 +0200117 BufferBase::BufferBase(DeviceBase* device, const BufferDescriptor* descriptor)
Austin Eng446ab442019-02-13 21:26:48 +0000118 : ObjectBase(device),
119 mSize(descriptor->size),
120 mUsage(descriptor->usage),
121 mState(BufferState::Unmapped) {
Yunchao He64cfaea2019-11-07 07:09:07 +0000122 // Add readonly storage usage if the buffer has a storage usage. The validation rules in
Austin Eng4b0b7a52019-11-21 22:09:41 +0000123 // ValidatePassResourceUsage will make sure we don't use both at the same
Yunchao He64cfaea2019-11-07 07:09:07 +0000124 // time.
125 if (mUsage & wgpu::BufferUsage::Storage) {
Jiawei Shaoe89b4872020-04-21 00:48:10 +0000126 mUsage |= kReadOnlyStorageBuffer;
Yunchao He64cfaea2019-11-07 07:09:07 +0000127 }
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400128 }
129
Corentin Wallezb2ea1912020-07-07 11:21:51 +0000130 BufferBase::BufferBase(DeviceBase* device,
131 const BufferDescriptor* descriptor,
132 ObjectBase::ErrorTag tag)
133 : ObjectBase(device, tag), mSize(descriptor->size), mState(BufferState::Unmapped) {
134 if (descriptor->mappedAtCreation) {
135 mState = BufferState::MappedAtCreation;
Corentin Wallezf6e70442020-07-17 18:50:37 +0000136 mMapOffset = 0;
137 mMapSize = mSize;
Corentin Wallezb2ea1912020-07-07 11:21:51 +0000138 }
Corentin Walleza594f8f2019-02-13 13:09:18 +0000139 }
140
Corentin Wallezb1c19ee2017-06-09 10:51:29 -0400141 BufferBase::~BufferBase() {
Austin Eng446ab442019-02-13 21:26:48 +0000142 if (mState == BufferState::Mapped) {
Corentin Walleza594f8f2019-02-13 13:09:18 +0000143 ASSERT(!IsError());
Corentin Wallez2088cde2020-08-12 19:32:25 +0000144 CallMapCallback(mMapSerial, WGPUBufferMapAsyncStatus_Unknown);
Corentin Wallezb1c19ee2017-06-09 10:51:29 -0400145 }
146 }
147
Corentin Walleza594f8f2019-02-13 13:09:18 +0000148 // static
Corentin Wallezb2ea1912020-07-07 11:21:51 +0000149 BufferBase* BufferBase::MakeError(DeviceBase* device, const BufferDescriptor* descriptor) {
150 return new ErrorBuffer(device, descriptor);
Austin Eng740995c2019-05-15 18:55:22 +0000151 }
152
Austin Eng9cd21f12019-06-05 18:35:31 +0000153 uint64_t BufferBase::GetSize() const {
Corentin Walleza594f8f2019-02-13 13:09:18 +0000154 ASSERT(!IsError());
Corentin Wallezfbecc282017-11-23 10:32:51 -0800155 return mSize;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400156 }
157
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000158 wgpu::BufferUsage BufferBase::GetUsage() const {
Corentin Walleza594f8f2019-02-13 13:09:18 +0000159 ASSERT(!IsError());
Corentin Wallez62c77432018-08-22 15:08:02 +0200160 return mUsage;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400161 }
162
Corentin Wallezb2ea1912020-07-07 11:21:51 +0000163 MaybeError BufferBase::MapAtCreation() {
Jiawei Shao1c4a7f72020-09-01 08:08:57 +0000164 DAWN_TRY(MapAtCreationInternal());
165
166 // TODO(jiawei.shao@intel.com): check Toggle::LazyClearResourceOnFirstUse instead when
167 // buffer lazy initialization is completely supported.
168 DeviceBase* device = GetDevice();
169 if (device->IsToggleEnabled(Toggle::LazyClearBufferOnFirstUse)) {
170 memset(GetMappedRange(0, mSize), uint8_t(0u), mSize);
171 SetIsDataInitialized();
172 device->IncrementLazyClearCountForTesting();
173 } else if (device->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) {
174 memset(GetMappedRange(0, mSize), uint8_t(1u), mSize);
175 }
176
177 return {};
178 }
179
180 MaybeError BufferBase::MapAtCreationInternal() {
Austin Eng740995c2019-05-15 18:55:22 +0000181 ASSERT(!IsError());
Corentin Wallez2008d152020-06-30 11:05:44 +0000182 mState = BufferState::MappedAtCreation;
Corentin Wallezf6e70442020-07-17 18:50:37 +0000183 mMapOffset = 0;
184 mMapSize = mSize;
Corentin Wallez2008d152020-06-30 11:05:44 +0000185
Corentin Wallez91904cd2020-06-30 12:21:54 +0000186 // 0-sized buffers are not supposed to be written to, Return back any non-null pointer.
187 // Handle 0-sized buffers first so we don't try to map them in the backend.
188 if (mSize == 0) {
Corentin Wallez91904cd2020-06-30 12:21:54 +0000189 return {};
190 }
191
Corentin Wallez13f46502020-06-11 11:07:05 +0000192 // Mappable buffers don't use a staging buffer and are just as if mapped through MapAsync.
Jiawei Shao1c4a7f72020-09-01 08:08:57 +0000193 if (IsCPUWritableAtCreation()) {
Corentin Wallezb2ea1912020-07-07 11:21:51 +0000194 DAWN_TRY(MapAtCreationImpl());
Jiawei Shao1c4a7f72020-09-01 08:08:57 +0000195 } else {
196 // If any of these fail, the buffer will be deleted and replaced with an
197 // error buffer.
198 // TODO(enga): Suballocate and reuse memory from a larger staging buffer so we don't
199 // create many small buffers.
200 DAWN_TRY_ASSIGN(mStagingBuffer, GetDevice()->CreateStagingBuffer(GetSize()));
Austin Eng740995c2019-05-15 18:55:22 +0000201 }
202
Austin Eng740995c2019-05-15 18:55:22 +0000203 return {};
204 }
205
Corentin Wallez47a33412020-06-02 09:24:39 +0000206 MaybeError BufferBase::ValidateCanUseOnQueueNow() const {
Corentin Walleza594f8f2019-02-13 13:09:18 +0000207 ASSERT(!IsError());
208
Austin Eng446ab442019-02-13 21:26:48 +0000209 switch (mState) {
210 case BufferState::Destroyed:
211 return DAWN_VALIDATION_ERROR("Destroyed buffer used in a submit");
212 case BufferState::Mapped:
Corentin Wallez13f46502020-06-11 11:07:05 +0000213 case BufferState::MappedAtCreation:
Austin Eng446ab442019-02-13 21:26:48 +0000214 return DAWN_VALIDATION_ERROR("Buffer used in a submit while mapped");
215 case BufferState::Unmapped:
216 return {};
Corentin Walleze51f8dd2020-02-18 02:44:05 +0000217 default:
218 UNREACHABLE();
Corentin Wallez679ff4e2018-11-07 10:02:43 +0000219 }
Corentin Wallez679ff4e2018-11-07 10:02:43 +0000220 }
221
Corentin Wallez0d52f802020-07-14 12:30:14 +0000222 void BufferBase::CallMapCallback(uint32_t serial, WGPUBufferMapAsyncStatus status) {
223 ASSERT(!IsError());
224 if (mMapCallback != nullptr && serial == mMapSerial) {
225 // Tag the callback as fired before firing it, otherwise it could fire a second time if
226 // for example buffer.Unmap() is called inside the application-provided callback.
227 WGPUBufferMapCallback callback = mMapCallback;
228 mMapCallback = nullptr;
229
230 if (GetDevice()->IsLost()) {
231 callback(WGPUBufferMapAsyncStatus_DeviceLost, mMapUserdata);
232 } else {
233 callback(status, mMapUserdata);
234 }
235 }
236 }
237
Corentin Wallez0d52f802020-07-14 12:30:14 +0000238 void BufferBase::MapAsync(wgpu::MapMode mode,
239 size_t offset,
240 size_t size,
241 WGPUBufferMapCallback callback,
242 void* userdata) {
243 // Handle the defaulting of size required by WebGPU, even if in webgpu_cpp.h it is not
244 // possible to default the function argument (because there is the callback later in the
245 // argument list)
246 if (size == 0 && offset < mSize) {
247 size = mSize - offset;
248 }
249
250 WGPUBufferMapAsyncStatus status;
251 if (GetDevice()->ConsumedError(ValidateMapAsync(mode, offset, size, &status))) {
252 if (callback) {
253 callback(status, userdata);
254 }
255 return;
256 }
257 ASSERT(!IsError());
258
259 // TODO(cwallez@chromium.org): what to do on wraparound? Could cause crashes.
260 mMapSerial++;
261 mMapMode = mode;
262 mMapOffset = offset;
Corentin Wallezf6e70442020-07-17 18:50:37 +0000263 mMapSize = size;
Corentin Wallez0d52f802020-07-14 12:30:14 +0000264 mMapCallback = callback;
265 mMapUserdata = userdata;
266 mState = BufferState::Mapped;
267
268 if (GetDevice()->ConsumedError(MapAsyncImpl(mode, offset, size))) {
269 CallMapCallback(mMapSerial, WGPUBufferMapAsyncStatus_DeviceLost);
270 return;
271 }
272
273 MapRequestTracker* tracker = GetDevice()->GetMapRequestTracker();
Corentin Wallezf7123d72020-08-20 14:22:29 +0000274 tracker->Track(this, mMapSerial);
Corentin Wallezb1c19ee2017-06-09 10:51:29 -0400275 }
276
Corentin Wallezf6e70442020-07-17 18:50:37 +0000277 void* BufferBase::GetMappedRange(size_t offset, size_t size) {
278 return GetMappedRangeInternal(true, offset, size);
Corentin Wallez1325ab12020-06-30 11:51:14 +0000279 }
280
Corentin Wallezf6e70442020-07-17 18:50:37 +0000281 const void* BufferBase::GetConstMappedRange(size_t offset, size_t size) {
282 return GetMappedRangeInternal(false, offset, size);
Corentin Wallezdbf805f2020-07-06 18:08:10 +0000283 }
284
Corentin Wallezf6e70442020-07-17 18:50:37 +0000285 void* BufferBase::GetMappedRangeInternal(bool writable, size_t offset, size_t size) {
286 if (!CanGetMappedRange(writable, offset, size)) {
Corentin Wallez1325ab12020-06-30 11:51:14 +0000287 return nullptr;
288 }
Corentin Wallezdbf805f2020-07-06 18:08:10 +0000289
Corentin Wallez1325ab12020-06-30 11:51:14 +0000290 if (mStagingBuffer != nullptr) {
Corentin Wallezf6e70442020-07-17 18:50:37 +0000291 return static_cast<uint8_t*>(mStagingBuffer->GetMappedPointer()) + offset;
Corentin Wallez1325ab12020-06-30 11:51:14 +0000292 }
Corentin Wallezdbf805f2020-07-06 18:08:10 +0000293 if (mSize == 0) {
294 return reinterpret_cast<uint8_t*>(intptr_t(0xCAFED00D));
295 }
Corentin Wallezf6e70442020-07-17 18:50:37 +0000296 return static_cast<uint8_t*>(GetMappedPointerImpl()) + offset;
Corentin Wallez1325ab12020-06-30 11:51:14 +0000297 }
298
Austin Eng446ab442019-02-13 21:26:48 +0000299 void BufferBase::Destroy() {
Austin Eng9cd21f12019-06-05 18:35:31 +0000300 if (IsError()) {
301 // It is an error to call Destroy() on an ErrorBuffer, but we still need to reclaim the
302 // fake mapped staging data.
Corentin Wallezb2ea1912020-07-07 11:21:51 +0000303 static_cast<ErrorBuffer*>(this)->ClearMappedData();
304 mState = BufferState::Destroyed;
Austin Eng9cd21f12019-06-05 18:35:31 +0000305 }
Austin Eng446ab442019-02-13 21:26:48 +0000306 if (GetDevice()->ConsumedError(ValidateDestroy())) {
307 return;
308 }
309 ASSERT(!IsError());
310
311 if (mState == BufferState::Mapped) {
Corentin Wallez13f46502020-06-11 11:07:05 +0000312 Unmap();
313 } else if (mState == BufferState::MappedAtCreation) {
314 if (mStagingBuffer != nullptr) {
315 mStagingBuffer.reset();
Corentin Wallez2008d152020-06-30 11:05:44 +0000316 } else if (mSize != 0) {
Jiawei Shao1c4a7f72020-09-01 08:08:57 +0000317 ASSERT(IsCPUWritableAtCreation());
Corentin Wallez2008d152020-06-30 11:05:44 +0000318 Unmap();
Austin Eng9cd21f12019-06-05 18:35:31 +0000319 }
Austin Eng446ab442019-02-13 21:26:48 +0000320 }
Corentin Wallez13f46502020-06-11 11:07:05 +0000321
Natasha Lee20b0c332019-04-01 19:49:04 +0000322 DestroyInternal();
Austin Eng446ab442019-02-13 21:26:48 +0000323 }
324
Austin Eng9cd21f12019-06-05 18:35:31 +0000325 MaybeError BufferBase::CopyFromStagingBuffer() {
326 ASSERT(mStagingBuffer);
Corentin Wallez45aed832020-06-05 15:44:03 +0000327 if (GetSize() == 0) {
328 return {};
329 }
330
Austin Eng9cd21f12019-06-05 18:35:31 +0000331 DAWN_TRY(GetDevice()->CopyFromStagingToBuffer(mStagingBuffer.get(), 0, this, 0, GetSize()));
332
Bryan Bernhart450e2122019-09-18 22:06:41 +0000333 DynamicUploader* uploader = GetDevice()->GetDynamicUploader();
Austin Eng9cd21f12019-06-05 18:35:31 +0000334 uploader->ReleaseStagingBuffer(std::move(mStagingBuffer));
335
336 return {};
337 }
338
Corentin Wallezb1c19ee2017-06-09 10:51:29 -0400339 void BufferBase::Unmap() {
Austin Eng740995c2019-05-15 18:55:22 +0000340 if (IsError()) {
341 // It is an error to call Unmap() on an ErrorBuffer, but we still need to reclaim the
342 // fake mapped staging data.
Corentin Wallezb2ea1912020-07-07 11:21:51 +0000343 static_cast<ErrorBuffer*>(this)->ClearMappedData();
344 mState = BufferState::Unmapped;
Austin Eng740995c2019-05-15 18:55:22 +0000345 }
Corentin Wallez9e4518b2018-10-15 12:54:30 +0000346 if (GetDevice()->ConsumedError(ValidateUnmap())) {
Corentin Wallezb1c19ee2017-06-09 10:51:29 -0400347 return;
348 }
Corentin Walleza594f8f2019-02-13 13:09:18 +0000349 ASSERT(!IsError());
Corentin Wallezb1c19ee2017-06-09 10:51:29 -0400350
Corentin Wallez13f46502020-06-11 11:07:05 +0000351 if (mState == BufferState::Mapped) {
Austin Eng9cd21f12019-06-05 18:35:31 +0000352 // A map request can only be called once, so this will fire only if the request wasn't
353 // completed before the Unmap.
354 // Callbacks are not fired if there is no callback registered, so this is correct for
Corentin Wallezf7123d72020-08-20 14:22:29 +0000355 // mappedAtCreation = true.
Corentin Wallez0d52f802020-07-14 12:30:14 +0000356 CallMapCallback(mMapSerial, WGPUBufferMapAsyncStatus_Unknown);
Austin Eng9cd21f12019-06-05 18:35:31 +0000357 UnmapImpl();
Corentin Wallez13f46502020-06-11 11:07:05 +0000358
Corentin Wallez2088cde2020-08-12 19:32:25 +0000359 mMapCallback = nullptr;
Corentin Wallez13f46502020-06-11 11:07:05 +0000360 mMapUserdata = 0;
361
362 } else if (mState == BufferState::MappedAtCreation) {
363 if (mStagingBuffer != nullptr) {
364 GetDevice()->ConsumedError(CopyFromStagingBuffer());
Corentin Wallez2008d152020-06-30 11:05:44 +0000365 } else if (mSize != 0) {
Jiawei Shao1c4a7f72020-09-01 08:08:57 +0000366 ASSERT(IsCPUWritableAtCreation());
Corentin Wallez2008d152020-06-30 11:05:44 +0000367 UnmapImpl();
Corentin Wallez13f46502020-06-11 11:07:05 +0000368 }
Austin Eng9cd21f12019-06-05 18:35:31 +0000369 }
Corentin Wallez13f46502020-06-11 11:07:05 +0000370
Austin Eng446ab442019-02-13 21:26:48 +0000371 mState = BufferState::Unmapped;
Corentin Wallezb1c19ee2017-06-09 10:51:29 -0400372 }
373
Natasha Lee74f50542020-01-28 22:18:58 +0000374 MaybeError BufferBase::ValidateMap(wgpu::BufferUsage requiredUsage,
375 WGPUBufferMapAsyncStatus* status) const {
376 *status = WGPUBufferMapAsyncStatus_DeviceLost;
Natasha Lee0ecc48e2020-01-15 19:02:13 +0000377 DAWN_TRY(GetDevice()->ValidateIsAlive());
Natasha Lee74f50542020-01-28 22:18:58 +0000378
379 *status = WGPUBufferMapAsyncStatus_Error;
Corentin Walleza594f8f2019-02-13 13:09:18 +0000380 DAWN_TRY(GetDevice()->ValidateObject(this));
381
Austin Eng9cd21f12019-06-05 18:35:31 +0000382 switch (mState) {
383 case BufferState::Mapped:
Corentin Wallez13f46502020-06-11 11:07:05 +0000384 case BufferState::MappedAtCreation:
Corentin Wallez0d52f802020-07-14 12:30:14 +0000385 return DAWN_VALIDATION_ERROR("Buffer is already mapped");
Austin Eng9cd21f12019-06-05 18:35:31 +0000386 case BufferState::Destroyed:
387 return DAWN_VALIDATION_ERROR("Buffer is destroyed");
388 case BufferState::Unmapped:
389 break;
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400390 }
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400391
Corentin Wallez62c77432018-08-22 15:08:02 +0200392 if (!(mUsage & requiredUsage)) {
Corentin Wallez6fee61c2018-09-10 16:17:24 +0200393 return DAWN_VALIDATION_ERROR("Buffer needs the correct map usage bit");
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400394 }
Corentin Wallezd8c068f2018-07-09 15:15:07 +0200395
Natasha Lee74f50542020-01-28 22:18:58 +0000396 *status = WGPUBufferMapAsyncStatus_Success;
Corentin Wallez79149582018-07-18 21:20:07 +0200397 return {};
398 }
399
Corentin Wallez0d52f802020-07-14 12:30:14 +0000400 MaybeError BufferBase::ValidateMapAsync(wgpu::MapMode mode,
401 size_t offset,
402 size_t size,
403 WGPUBufferMapAsyncStatus* status) const {
404 *status = WGPUBufferMapAsyncStatus_DeviceLost;
405 DAWN_TRY(GetDevice()->ValidateIsAlive());
406
407 *status = WGPUBufferMapAsyncStatus_Error;
408 DAWN_TRY(GetDevice()->ValidateObject(this));
409
410 if (offset % 4 != 0) {
411 return DAWN_VALIDATION_ERROR("offset must be a multiple of 4");
412 }
413
414 if (size % 4 != 0) {
415 return DAWN_VALIDATION_ERROR("size must be a multiple of 4");
416 }
417
418 if (uint64_t(offset) > mSize || uint64_t(size) > mSize - uint64_t(offset)) {
419 return DAWN_VALIDATION_ERROR("size + offset must fit in the buffer");
420 }
421
422 switch (mState) {
423 case BufferState::Mapped:
424 case BufferState::MappedAtCreation:
425 return DAWN_VALIDATION_ERROR("Buffer is already mapped");
426 case BufferState::Destroyed:
427 return DAWN_VALIDATION_ERROR("Buffer is destroyed");
428 case BufferState::Unmapped:
429 break;
430 }
431
432 bool isReadMode = mode & wgpu::MapMode::Read;
433 bool isWriteMode = mode & wgpu::MapMode::Write;
434 if (!(isReadMode ^ isWriteMode)) {
435 return DAWN_VALIDATION_ERROR("Exactly one of Read or Write mode must be set");
436 }
437
438 if (mode & wgpu::MapMode::Read) {
439 if (!(mUsage & wgpu::BufferUsage::MapRead)) {
440 return DAWN_VALIDATION_ERROR("The buffer must have the MapRead usage");
441 }
442 } else {
443 ASSERT(mode & wgpu::MapMode::Write);
444
445 if (!(mUsage & wgpu::BufferUsage::MapWrite)) {
446 return DAWN_VALIDATION_ERROR("The buffer must have the MapWrite usage");
447 }
448 }
449
450 *status = WGPUBufferMapAsyncStatus_Success;
451 return {};
452 }
453
Corentin Wallezf6e70442020-07-17 18:50:37 +0000454 bool BufferBase::CanGetMappedRange(bool writable, size_t offset, size_t size) const {
455 if (size > mMapSize || offset < mMapOffset) {
456 return false;
457 }
458
459 size_t offsetInMappedRange = offset - mMapOffset;
460 if (offsetInMappedRange > mMapSize - size) {
461 return false;
462 }
463
Corentin Wallezdbf805f2020-07-06 18:08:10 +0000464 // Note that:
465 //
466 // - We don't check that the device is alive because the application can ask for the
467 // mapped pointer before it knows, and even Dawn knows, that the device was lost, and
468 // still needs to work properly.
469 // - We don't check that the object is alive because we need to return mapped pointers
470 // for error buffers too.
Corentin Wallez1325ab12020-06-30 11:51:14 +0000471
472 switch (mState) {
473 // Writeable Buffer::GetMappedRange is always allowed when mapped at creation.
474 case BufferState::MappedAtCreation:
Corentin Wallezdbf805f2020-07-06 18:08:10 +0000475 return true;
Corentin Wallez1325ab12020-06-30 11:51:14 +0000476
477 case BufferState::Mapped:
Corentin Wallezce78ce22020-08-22 11:08:34 +0000478 ASSERT(bool(mMapMode & wgpu::MapMode::Read) ^
479 bool(mMapMode & wgpu::MapMode::Write));
480 return !writable || (mMapMode & wgpu::MapMode::Write);
Corentin Wallez1325ab12020-06-30 11:51:14 +0000481
482 case BufferState::Unmapped:
483 case BufferState::Destroyed:
Corentin Wallezdbf805f2020-07-06 18:08:10 +0000484 return false;
485
Corentin Wallez1325ab12020-06-30 11:51:14 +0000486 default:
487 UNREACHABLE();
488 }
489 }
490
Corentin Wallez79149582018-07-18 21:20:07 +0200491 MaybeError BufferBase::ValidateUnmap() const {
Natasha Lee0ecc48e2020-01-15 19:02:13 +0000492 DAWN_TRY(GetDevice()->ValidateIsAlive());
Corentin Walleza594f8f2019-02-13 13:09:18 +0000493 DAWN_TRY(GetDevice()->ValidateObject(this));
494
Austin Eng446ab442019-02-13 21:26:48 +0000495 switch (mState) {
Austin Eng446ab442019-02-13 21:26:48 +0000496 case BufferState::Mapped:
Corentin Wallez13f46502020-06-11 11:07:05 +0000497 case BufferState::MappedAtCreation:
Corentin Wallezf7123d72020-08-20 14:22:29 +0000498 // A buffer may be in the Mapped state if it was created with mappedAtCreation
Austin Eng9cd21f12019-06-05 18:35:31 +0000499 // even if it did not have a mappable usage.
500 return {};
501 case BufferState::Unmapped:
Corentin Wallez1f6c8c42019-10-23 11:57:41 +0000502 if ((mUsage & (wgpu::BufferUsage::MapRead | wgpu::BufferUsage::MapWrite)) == 0) {
Austin Eng9cd21f12019-06-05 18:35:31 +0000503 return DAWN_VALIDATION_ERROR("Buffer does not have map usage");
504 }
Austin Eng446ab442019-02-13 21:26:48 +0000505 return {};
506 case BufferState::Destroyed:
507 return DAWN_VALIDATION_ERROR("Buffer is destroyed");
Corentin Walleze51f8dd2020-02-18 02:44:05 +0000508 default:
509 UNREACHABLE();
Austin Eng446ab442019-02-13 21:26:48 +0000510 }
511 }
Corentin Wallez79149582018-07-18 21:20:07 +0200512
Austin Eng446ab442019-02-13 21:26:48 +0000513 MaybeError BufferBase::ValidateDestroy() const {
514 DAWN_TRY(GetDevice()->ValidateObject(this));
Corentin Wallez79149582018-07-18 21:20:07 +0200515 return {};
Corentin Wallezf07e3bd2017-04-20 14:38:20 -0400516 }
517
Natasha Lee20b0c332019-04-01 19:49:04 +0000518 void BufferBase::DestroyInternal() {
519 if (mState != BufferState::Destroyed) {
520 DestroyImpl();
521 }
522 mState = BufferState::Destroyed;
523 }
524
Corentin Wallezf7123d72020-08-20 14:22:29 +0000525 void BufferBase::OnMapCommandSerialFinished(uint32_t mapSerial) {
526 CallMapCallback(mapSerial, WGPUBufferMapAsyncStatus_Success);
Natasha Lee949f1e42020-05-19 01:29:32 +0000527 }
528
Jiawei Shao80f927d2020-07-06 08:24:30 +0000529 bool BufferBase::IsDataInitialized() const {
530 return mIsDataInitialized;
531 }
532
533 void BufferBase::SetIsDataInitialized() {
534 mIsDataInitialized = true;
535 }
536
537 bool BufferBase::IsFullBufferRange(uint64_t offset, uint64_t size) const {
538 return offset == 0 && size == GetSize();
539 }
Corentin Wallez49a65d02018-07-24 16:45:45 +0200540} // namespace dawn_native