1 // Copyright 2017 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 "tests/unittests/validation/ValidationTest.h"
16
17 #include <gmock/gmock.h>
18
19 #include <memory>
20
21 using namespace testing;
22
23 class MockBufferMapAsyncCallback {
24 public:
25 MOCK_METHOD(void, Call, (WGPUBufferMapAsyncStatus status, void* userdata));
26 };
27
28 static std::unique_ptr<MockBufferMapAsyncCallback> mockBufferMapAsyncCallback;
ToMockBufferMapAsyncCallback(WGPUBufferMapAsyncStatus status,void * userdata)29 static void ToMockBufferMapAsyncCallback(WGPUBufferMapAsyncStatus status, void* userdata) {
30 mockBufferMapAsyncCallback->Call(status, userdata);
31 }
32
33 class BufferValidationTest : public ValidationTest {
34 protected:
CreateMapReadBuffer(uint64_t size)35 wgpu::Buffer CreateMapReadBuffer(uint64_t size) {
36 wgpu::BufferDescriptor descriptor;
37 descriptor.size = size;
38 descriptor.usage = wgpu::BufferUsage::MapRead;
39
40 return device.CreateBuffer(&descriptor);
41 }
42
CreateMapWriteBuffer(uint64_t size)43 wgpu::Buffer CreateMapWriteBuffer(uint64_t size) {
44 wgpu::BufferDescriptor descriptor;
45 descriptor.size = size;
46 descriptor.usage = wgpu::BufferUsage::MapWrite;
47
48 return device.CreateBuffer(&descriptor);
49 }
50
BufferMappedAtCreation(uint64_t size,wgpu::BufferUsage usage)51 wgpu::Buffer BufferMappedAtCreation(uint64_t size, wgpu::BufferUsage usage) {
52 wgpu::BufferDescriptor descriptor;
53 descriptor.size = size;
54 descriptor.usage = usage;
55 descriptor.mappedAtCreation = true;
56
57 return device.CreateBuffer(&descriptor);
58 }
59
AssertMapAsyncError(wgpu::Buffer buffer,wgpu::MapMode mode,size_t offset,size_t size)60 void AssertMapAsyncError(wgpu::Buffer buffer, wgpu::MapMode mode, size_t offset, size_t size) {
61 EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Error, _)).Times(1);
62
63 ASSERT_DEVICE_ERROR(
64 buffer.MapAsync(mode, offset, size, ToMockBufferMapAsyncCallback, nullptr));
65 }
66
67 wgpu::Queue queue;
68
69 private:
SetUp()70 void SetUp() override {
71 ValidationTest::SetUp();
72
73 mockBufferMapAsyncCallback = std::make_unique<MockBufferMapAsyncCallback>();
74 queue = device.GetQueue();
75 }
76
TearDown()77 void TearDown() override {
78 // Delete mocks so that expectations are checked
79 mockBufferMapAsyncCallback = nullptr;
80
81 ValidationTest::TearDown();
82 }
83 };
84
85 // Test case where creation should succeed
TEST_F(BufferValidationTest,CreationSuccess)86 TEST_F(BufferValidationTest, CreationSuccess) {
87 // Success
88 {
89 wgpu::BufferDescriptor descriptor;
90 descriptor.size = 4;
91 descriptor.usage = wgpu::BufferUsage::Uniform;
92
93 device.CreateBuffer(&descriptor);
94 }
95 }
96
97 // Test restriction on usages allowed with MapRead and MapWrite
TEST_F(BufferValidationTest,CreationMapUsageRestrictions)98 TEST_F(BufferValidationTest, CreationMapUsageRestrictions) {
99 // MapRead with CopyDst is ok
100 {
101 wgpu::BufferDescriptor descriptor;
102 descriptor.size = 4;
103 descriptor.usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst;
104
105 device.CreateBuffer(&descriptor);
106 }
107
108 // MapRead with something else is an error
109 {
110 wgpu::BufferDescriptor descriptor;
111 descriptor.size = 4;
112 descriptor.usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::Uniform;
113
114 ASSERT_DEVICE_ERROR(device.CreateBuffer(&descriptor));
115 }
116
117 // MapWrite with CopySrc is ok
118 {
119 wgpu::BufferDescriptor descriptor;
120 descriptor.size = 4;
121 descriptor.usage = wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc;
122
123 device.CreateBuffer(&descriptor);
124 }
125
126 // MapWrite with something else is an error
127 {
128 wgpu::BufferDescriptor descriptor;
129 descriptor.size = 4;
130 descriptor.usage = wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::Uniform;
131
132 ASSERT_DEVICE_ERROR(device.CreateBuffer(&descriptor));
133 }
134 }
135
136 // Test the success case for mapping buffer for reading
TEST_F(BufferValidationTest,MapAsync_ReadSuccess)137 TEST_F(BufferValidationTest, MapAsync_ReadSuccess) {
138 wgpu::Buffer buf = CreateMapReadBuffer(4);
139
140 buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
141
142 EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _)).Times(1);
143 WaitForAllOperations(device);
144
145 buf.Unmap();
146 }
147
148 // Test the success case for mapping buffer for writing
TEST_F(BufferValidationTest,MapAsync_WriteSuccess)149 TEST_F(BufferValidationTest, MapAsync_WriteSuccess) {
150 wgpu::Buffer buf = CreateMapWriteBuffer(4);
151
152 buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
153
154 EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _)).Times(1);
155 WaitForAllOperations(device);
156
157 buf.Unmap();
158 }
159
160 // Test map async with a buffer that's an error
TEST_F(BufferValidationTest,MapAsync_ErrorBuffer)161 TEST_F(BufferValidationTest, MapAsync_ErrorBuffer) {
162 wgpu::BufferDescriptor desc;
163 desc.size = 4;
164 desc.usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::MapWrite;
165 wgpu::Buffer buffer;
166 ASSERT_DEVICE_ERROR(buffer = device.CreateBuffer(&desc));
167
168 AssertMapAsyncError(buffer, wgpu::MapMode::Read, 0, 4);
169 AssertMapAsyncError(buffer, wgpu::MapMode::Write, 0, 4);
170 }
171
172 // Test map async with an invalid offset and size alignment.
TEST_F(BufferValidationTest,MapAsync_OffsetSizeAlignment)173 TEST_F(BufferValidationTest, MapAsync_OffsetSizeAlignment) {
174 // Control case, offset aligned to 8 and size to 4 is valid
175 {
176 wgpu::Buffer buffer = CreateMapReadBuffer(12);
177 buffer.MapAsync(wgpu::MapMode::Read, 8, 4, nullptr, nullptr);
178 }
179 {
180 wgpu::Buffer buffer = CreateMapWriteBuffer(12);
181 buffer.MapAsync(wgpu::MapMode::Write, 8, 4, nullptr, nullptr);
182 }
183
184 // Error case, offset aligned to 4 is an error.
185 {
186 wgpu::Buffer buffer = CreateMapReadBuffer(12);
187 AssertMapAsyncError(buffer, wgpu::MapMode::Read, 4, 4);
188 }
189 {
190 wgpu::Buffer buffer = CreateMapWriteBuffer(12);
191 AssertMapAsyncError(buffer, wgpu::MapMode::Write, 4, 4);
192 }
193
194 // Error case, size aligned to 2 is an error.
195 {
196 wgpu::Buffer buffer = CreateMapReadBuffer(8);
197 AssertMapAsyncError(buffer, wgpu::MapMode::Read, 0, 6);
198 }
199 {
200 wgpu::Buffer buffer = CreateMapWriteBuffer(8);
201 AssertMapAsyncError(buffer, wgpu::MapMode::Write, 0, 6);
202 }
203 }
204
205 // Test map async with an invalid offset and size OOB checks
TEST_F(BufferValidationTest,MapAsync_OffsetSizeOOB)206 TEST_F(BufferValidationTest, MapAsync_OffsetSizeOOB) {
207 // Valid case: full buffer is ok.
208 {
209 wgpu::Buffer buffer = CreateMapReadBuffer(8);
210 buffer.MapAsync(wgpu::MapMode::Read, 0, 8, nullptr, nullptr);
211 }
212
213 // Valid case: range in the middle of the buffer is ok.
214 {
215 wgpu::Buffer buffer = CreateMapReadBuffer(16);
216 buffer.MapAsync(wgpu::MapMode::Read, 8, 4, nullptr, nullptr);
217 }
218
219 // Valid case: empty range at the end of the buffer is ok.
220 {
221 wgpu::Buffer buffer = CreateMapReadBuffer(8);
222 buffer.MapAsync(wgpu::MapMode::Read, 8, 0, nullptr, nullptr);
223 }
224
225 // Error case, offset is larger than the buffer size (even if size is 0).
226 {
227 wgpu::Buffer buffer = CreateMapReadBuffer(12);
228 AssertMapAsyncError(buffer, wgpu::MapMode::Read, 16, 0);
229 }
230
231 // Error case, offset + size is larger than the buffer
232 {
233 wgpu::Buffer buffer = CreateMapReadBuffer(12);
234 AssertMapAsyncError(buffer, wgpu::MapMode::Read, 8, 8);
235 }
236
237 // Error case, offset + size is larger than the buffer, overflow case.
238 {
239 wgpu::Buffer buffer = CreateMapReadBuffer(12);
240 AssertMapAsyncError(buffer, wgpu::MapMode::Read, 8,
241 std::numeric_limits<size_t>::max() & ~size_t(7));
242 }
243 }
244
245 // Test map async with a buffer that has the wrong usage
TEST_F(BufferValidationTest,MapAsync_WrongUsage)246 TEST_F(BufferValidationTest, MapAsync_WrongUsage) {
247 {
248 wgpu::BufferDescriptor desc;
249 desc.usage = wgpu::BufferUsage::Vertex;
250 desc.size = 4;
251 wgpu::Buffer buffer = device.CreateBuffer(&desc);
252
253 AssertMapAsyncError(buffer, wgpu::MapMode::Read, 0, 4);
254 AssertMapAsyncError(buffer, wgpu::MapMode::Write, 0, 4);
255 }
256 {
257 wgpu::Buffer buffer = CreateMapReadBuffer(4);
258 AssertMapAsyncError(buffer, wgpu::MapMode::Write, 0, 4);
259 }
260 {
261 wgpu::Buffer buffer = CreateMapWriteBuffer(4);
262 AssertMapAsyncError(buffer, wgpu::MapMode::Read, 0, 4);
263 }
264 }
265
266 // Test map async with a wrong mode
TEST_F(BufferValidationTest,MapAsync_WrongMode)267 TEST_F(BufferValidationTest, MapAsync_WrongMode) {
268 {
269 wgpu::Buffer buffer = CreateMapReadBuffer(4);
270 AssertMapAsyncError(buffer, wgpu::MapMode::None, 0, 4);
271 }
272 {
273 wgpu::Buffer buffer = CreateMapReadBuffer(4);
274 AssertMapAsyncError(buffer, wgpu::MapMode::Read | wgpu::MapMode::Write, 0, 4);
275 }
276 }
277
278 // Test map async with a buffer that's already mapped
TEST_F(BufferValidationTest,MapAsync_AlreadyMapped)279 TEST_F(BufferValidationTest, MapAsync_AlreadyMapped) {
280 {
281 wgpu::Buffer buffer = CreateMapReadBuffer(4);
282 buffer.MapAsync(wgpu::MapMode::Read, 0, 4, nullptr, nullptr);
283 AssertMapAsyncError(buffer, wgpu::MapMode::Read, 0, 4);
284 }
285 {
286 wgpu::Buffer buffer = BufferMappedAtCreation(4, wgpu::BufferUsage::MapRead);
287 AssertMapAsyncError(buffer, wgpu::MapMode::Read, 0, 4);
288 }
289 {
290 wgpu::Buffer buffer = CreateMapWriteBuffer(4);
291 buffer.MapAsync(wgpu::MapMode::Write, 0, 4, nullptr, nullptr);
292 AssertMapAsyncError(buffer, wgpu::MapMode::Write, 0, 4);
293 }
294 {
295 wgpu::Buffer buffer = BufferMappedAtCreation(4, wgpu::BufferUsage::MapWrite);
296 AssertMapAsyncError(buffer, wgpu::MapMode::Write, 0, 4);
297 }
298 }
299
300 // Test map async with a buffer that's destroyed
TEST_F(BufferValidationTest,MapAsync_Destroy)301 TEST_F(BufferValidationTest, MapAsync_Destroy) {
302 {
303 wgpu::Buffer buffer = CreateMapReadBuffer(4);
304 buffer.Destroy();
305 AssertMapAsyncError(buffer, wgpu::MapMode::Read, 0, 4);
306 }
307 {
308 wgpu::Buffer buffer = CreateMapWriteBuffer(4);
309 buffer.Destroy();
310 AssertMapAsyncError(buffer, wgpu::MapMode::Write, 0, 4);
311 }
312 }
313
314 // Test map async but unmapping before the result is ready.
TEST_F(BufferValidationTest,MapAsync_UnmapBeforeResult)315 TEST_F(BufferValidationTest, MapAsync_UnmapBeforeResult) {
316 {
317 wgpu::Buffer buf = CreateMapReadBuffer(4);
318 buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
319
320 EXPECT_CALL(*mockBufferMapAsyncCallback,
321 Call(WGPUBufferMapAsyncStatus_UnmappedBeforeCallback, _))
322 .Times(1);
323 buf.Unmap();
324
325 // The callback shouldn't be called again.
326 WaitForAllOperations(device);
327 }
328 {
329 wgpu::Buffer buf = CreateMapWriteBuffer(4);
330 buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
331
332 EXPECT_CALL(*mockBufferMapAsyncCallback,
333 Call(WGPUBufferMapAsyncStatus_UnmappedBeforeCallback, _))
334 .Times(1);
335 buf.Unmap();
336
337 // The callback shouldn't be called again.
338 WaitForAllOperations(device);
339 }
340 }
341
342 // When a MapAsync is cancelled with Unmap it might still be in flight, test doing a new request
343 // works as expected and we don't get the cancelled request's data.
TEST_F(BufferValidationTest,MapAsync_UnmapBeforeResultAndMapAgain)344 TEST_F(BufferValidationTest, MapAsync_UnmapBeforeResultAndMapAgain) {
345 {
346 wgpu::Buffer buf = CreateMapReadBuffer(4);
347 buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, this + 0);
348
349 EXPECT_CALL(*mockBufferMapAsyncCallback,
350 Call(WGPUBufferMapAsyncStatus_UnmappedBeforeCallback, this + 0))
351 .Times(1);
352 buf.Unmap();
353
354 buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, this + 1);
355 EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, this + 1))
356 .Times(1);
357 WaitForAllOperations(device);
358 }
359 {
360 wgpu::Buffer buf = CreateMapWriteBuffer(4);
361 buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, this + 0);
362
363 EXPECT_CALL(*mockBufferMapAsyncCallback,
364 Call(WGPUBufferMapAsyncStatus_UnmappedBeforeCallback, this + 0))
365 .Times(1);
366 buf.Unmap();
367
368 buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, this + 1);
369 EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, this + 1))
370 .Times(1);
371 WaitForAllOperations(device);
372 }
373 }
374
375 // Test map async but destroying before the result is ready.
TEST_F(BufferValidationTest,MapAsync_DestroyBeforeResult)376 TEST_F(BufferValidationTest, MapAsync_DestroyBeforeResult) {
377 {
378 wgpu::Buffer buf = CreateMapReadBuffer(4);
379 buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
380
381 EXPECT_CALL(*mockBufferMapAsyncCallback,
382 Call(WGPUBufferMapAsyncStatus_DestroyedBeforeCallback, _))
383 .Times(1);
384 buf.Destroy();
385
386 // The callback shouldn't be called again.
387 WaitForAllOperations(device);
388 }
389 {
390 wgpu::Buffer buf = CreateMapWriteBuffer(4);
391 buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
392
393 EXPECT_CALL(*mockBufferMapAsyncCallback,
394 Call(WGPUBufferMapAsyncStatus_DestroyedBeforeCallback, _))
395 .Times(1);
396 buf.Destroy();
397
398 // The callback shouldn't be called again.
399 WaitForAllOperations(device);
400 }
401 }
402
403 // Test that the MapCallback isn't fired twice when unmap() is called inside the callback
TEST_F(BufferValidationTest,MapAsync_UnmapCalledInCallback)404 TEST_F(BufferValidationTest, MapAsync_UnmapCalledInCallback) {
405 {
406 wgpu::Buffer buf = CreateMapReadBuffer(4);
407 buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
408
409 EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
410 .WillOnce(InvokeWithoutArgs([&]() { buf.Unmap(); }));
411
412 WaitForAllOperations(device);
413 }
414 {
415 wgpu::Buffer buf = CreateMapWriteBuffer(4);
416 buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
417
418 EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
419 .WillOnce(InvokeWithoutArgs([&]() { buf.Unmap(); }));
420
421 WaitForAllOperations(device);
422 }
423 }
424
425 // Test that the MapCallback isn't fired twice when destroy() is called inside the callback
TEST_F(BufferValidationTest,MapAsync_DestroyCalledInCallback)426 TEST_F(BufferValidationTest, MapAsync_DestroyCalledInCallback) {
427 {
428 wgpu::Buffer buf = CreateMapReadBuffer(4);
429 buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
430
431 EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
432 .WillOnce(InvokeWithoutArgs([&]() { buf.Destroy(); }));
433
434 WaitForAllOperations(device);
435 }
436 {
437 wgpu::Buffer buf = CreateMapWriteBuffer(4);
438 buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
439
440 EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
441 .WillOnce(InvokeWithoutArgs([&]() { buf.Destroy(); }));
442
443 WaitForAllOperations(device);
444 }
445 }
446
447 // Test the success case for mappedAtCreation
TEST_F(BufferValidationTest,MappedAtCreationSuccess)448 TEST_F(BufferValidationTest, MappedAtCreationSuccess) {
449 BufferMappedAtCreation(4, wgpu::BufferUsage::MapWrite);
450 }
451
452 // Test the success case for mappedAtCreation for a non-mappable usage
TEST_F(BufferValidationTest,NonMappableMappedAtCreationSuccess)453 TEST_F(BufferValidationTest, NonMappableMappedAtCreationSuccess) {
454 BufferMappedAtCreation(4, wgpu::BufferUsage::CopySrc);
455 }
456
457 // Test there is an error when mappedAtCreation is set but the size isn't aligned to 4.
TEST_F(BufferValidationTest,MappedAtCreationSizeAlignment)458 TEST_F(BufferValidationTest, MappedAtCreationSizeAlignment) {
459 ASSERT_DEVICE_ERROR(BufferMappedAtCreation(2, wgpu::BufferUsage::MapWrite));
460 }
461
462 // Test that it is valid to destroy an error buffer
TEST_F(BufferValidationTest,DestroyErrorBuffer)463 TEST_F(BufferValidationTest, DestroyErrorBuffer) {
464 wgpu::BufferDescriptor desc;
465 desc.size = 4;
466 desc.usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::MapWrite;
467 wgpu::Buffer buf;
468 ASSERT_DEVICE_ERROR(buf = device.CreateBuffer(&desc));
469
470 buf.Destroy();
471 }
472
473 // Test that it is valid to Destroy an unmapped buffer
TEST_F(BufferValidationTest,DestroyUnmappedBuffer)474 TEST_F(BufferValidationTest, DestroyUnmappedBuffer) {
475 {
476 wgpu::Buffer buf = CreateMapReadBuffer(4);
477 buf.Destroy();
478 }
479 {
480 wgpu::Buffer buf = CreateMapWriteBuffer(4);
481 buf.Destroy();
482 }
483 }
484
485 // Test that it is valid to Destroy a destroyed buffer
TEST_F(BufferValidationTest,DestroyDestroyedBuffer)486 TEST_F(BufferValidationTest, DestroyDestroyedBuffer) {
487 wgpu::Buffer buf = CreateMapWriteBuffer(4);
488 buf.Destroy();
489 buf.Destroy();
490 }
491
492 // Test that it is invalid to Unmap an error buffer
TEST_F(BufferValidationTest,UnmapErrorBuffer)493 TEST_F(BufferValidationTest, UnmapErrorBuffer) {
494 wgpu::BufferDescriptor desc;
495 desc.size = 4;
496 desc.usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::MapWrite;
497 wgpu::Buffer buf;
498 ASSERT_DEVICE_ERROR(buf = device.CreateBuffer(&desc));
499
500 ASSERT_DEVICE_ERROR(buf.Unmap());
501 }
502
503 // Test that it is invalid to Unmap a destroyed buffer
TEST_F(BufferValidationTest,UnmapDestroyedBuffer)504 TEST_F(BufferValidationTest, UnmapDestroyedBuffer) {
505 {
506 wgpu::Buffer buf = CreateMapReadBuffer(4);
507 buf.Destroy();
508 ASSERT_DEVICE_ERROR(buf.Unmap());
509 }
510 {
511 wgpu::Buffer buf = CreateMapWriteBuffer(4);
512 buf.Destroy();
513 ASSERT_DEVICE_ERROR(buf.Unmap());
514 }
515 }
516
517 // Test that it is valid to submit a buffer in a queue with a map usage if it is unmapped
TEST_F(BufferValidationTest,SubmitBufferWithMapUsage)518 TEST_F(BufferValidationTest, SubmitBufferWithMapUsage) {
519 wgpu::BufferDescriptor descriptorA;
520 descriptorA.size = 4;
521 descriptorA.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::MapWrite;
522
523 wgpu::BufferDescriptor descriptorB;
524 descriptorB.size = 4;
525 descriptorB.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::MapRead;
526
527 wgpu::Buffer bufA = device.CreateBuffer(&descriptorA);
528 wgpu::Buffer bufB = device.CreateBuffer(&descriptorB);
529
530 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
531 encoder.CopyBufferToBuffer(bufA, 0, bufB, 0, 4);
532 wgpu::CommandBuffer commands = encoder.Finish();
533 queue.Submit(1, &commands);
534 }
535
536 // Test that it is invalid to submit a mapped buffer in a queue
TEST_F(BufferValidationTest,SubmitMappedBuffer)537 TEST_F(BufferValidationTest, SubmitMappedBuffer) {
538 wgpu::BufferDescriptor descriptorA;
539 descriptorA.size = 4;
540 descriptorA.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::MapWrite;
541
542 wgpu::BufferDescriptor descriptorB;
543 descriptorB.size = 4;
544 descriptorB.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::MapRead;
545 {
546 wgpu::Buffer bufA = device.CreateBuffer(&descriptorA);
547 wgpu::Buffer bufB = device.CreateBuffer(&descriptorB);
548
549 bufA.MapAsync(wgpu::MapMode::Write, 0, 4, nullptr, nullptr);
550
551 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
552 encoder.CopyBufferToBuffer(bufA, 0, bufB, 0, 4);
553 wgpu::CommandBuffer commands = encoder.Finish();
554 ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
555 WaitForAllOperations(device);
556 }
557 {
558 wgpu::Buffer bufA = device.CreateBuffer(&descriptorA);
559 wgpu::Buffer bufB = device.CreateBuffer(&descriptorB);
560
561 bufB.MapAsync(wgpu::MapMode::Read, 0, 4, nullptr, nullptr);
562
563 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
564 encoder.CopyBufferToBuffer(bufA, 0, bufB, 0, 4);
565 wgpu::CommandBuffer commands = encoder.Finish();
566 ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
567 WaitForAllOperations(device);
568 }
569 {
570 wgpu::BufferDescriptor mappedBufferDesc = descriptorA;
571 mappedBufferDesc.mappedAtCreation = true;
572 wgpu::Buffer bufA = device.CreateBuffer(&mappedBufferDesc);
573 wgpu::Buffer bufB = device.CreateBuffer(&descriptorB);
574
575 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
576 encoder.CopyBufferToBuffer(bufA, 0, bufB, 0, 4);
577 wgpu::CommandBuffer commands = encoder.Finish();
578 ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
579 WaitForAllOperations(device);
580 }
581 {
582 wgpu::BufferDescriptor mappedBufferDesc = descriptorB;
583 mappedBufferDesc.mappedAtCreation = true;
584 wgpu::Buffer bufA = device.CreateBuffer(&descriptorA);
585 wgpu::Buffer bufB = device.CreateBuffer(&mappedBufferDesc);
586
587 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
588 encoder.CopyBufferToBuffer(bufA, 0, bufB, 0, 4);
589 wgpu::CommandBuffer commands = encoder.Finish();
590 ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
591 WaitForAllOperations(device);
592 }
593 }
594
595 // Test that it is invalid to submit a destroyed buffer in a queue
TEST_F(BufferValidationTest,SubmitDestroyedBuffer)596 TEST_F(BufferValidationTest, SubmitDestroyedBuffer) {
597 wgpu::BufferDescriptor descriptorA;
598 descriptorA.size = 4;
599 descriptorA.usage = wgpu::BufferUsage::CopySrc;
600
601 wgpu::BufferDescriptor descriptorB;
602 descriptorB.size = 4;
603 descriptorB.usage = wgpu::BufferUsage::CopyDst;
604
605 wgpu::Buffer bufA = device.CreateBuffer(&descriptorA);
606 wgpu::Buffer bufB = device.CreateBuffer(&descriptorB);
607
608 bufA.Destroy();
609 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
610 encoder.CopyBufferToBuffer(bufA, 0, bufB, 0, 4);
611 wgpu::CommandBuffer commands = encoder.Finish();
612 ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
613 }
614
615 // Test that a map usage is required to call Unmap
TEST_F(BufferValidationTest,UnmapWithoutMapUsage)616 TEST_F(BufferValidationTest, UnmapWithoutMapUsage) {
617 wgpu::BufferDescriptor descriptor;
618 descriptor.size = 4;
619 descriptor.usage = wgpu::BufferUsage::CopyDst;
620 wgpu::Buffer buf = device.CreateBuffer(&descriptor);
621
622 ASSERT_DEVICE_ERROR(buf.Unmap());
623 }
624
625 // Test that it is valid to call Unmap on a buffer that is not mapped
TEST_F(BufferValidationTest,UnmapUnmappedBuffer)626 TEST_F(BufferValidationTest, UnmapUnmappedBuffer) {
627 {
628 wgpu::Buffer buf = CreateMapReadBuffer(4);
629 // Buffer starts unmapped. Unmap should fail.
630 ASSERT_DEVICE_ERROR(buf.Unmap());
631 buf.MapAsync(wgpu::MapMode::Read, 0, 4, nullptr, nullptr);
632 buf.Unmap();
633 // Unmapping a second time should fail.
634 ASSERT_DEVICE_ERROR(buf.Unmap());
635 }
636 {
637 wgpu::Buffer buf = CreateMapWriteBuffer(4);
638 // Buffer starts unmapped. Unmap should fail.
639 ASSERT_DEVICE_ERROR(buf.Unmap());
640 buf.MapAsync(wgpu::MapMode::Write, 0, 4, nullptr, nullptr);
641 buf.Unmap();
642 // Unmapping a second time should fail.
643 ASSERT_DEVICE_ERROR(buf.Unmap());
644 }
645 }
646
647 // Test that it is invalid to call GetMappedRange on an unmapped buffer.
TEST_F(BufferValidationTest,GetMappedRange_OnUnmappedBuffer)648 TEST_F(BufferValidationTest, GetMappedRange_OnUnmappedBuffer) {
649 // Unmapped at creation case.
650 {
651 wgpu::BufferDescriptor desc;
652 desc.size = 4;
653 desc.usage = wgpu::BufferUsage::CopySrc;
654 wgpu::Buffer buf = device.CreateBuffer(&desc);
655
656 ASSERT_EQ(nullptr, buf.GetMappedRange());
657 ASSERT_EQ(nullptr, buf.GetConstMappedRange());
658 }
659
660 // Unmapped after mappedAtCreation case.
661 {
662 wgpu::Buffer buf = BufferMappedAtCreation(4, wgpu::BufferUsage::CopySrc);
663 buf.Unmap();
664
665 ASSERT_EQ(nullptr, buf.GetMappedRange());
666 ASSERT_EQ(nullptr, buf.GetConstMappedRange());
667 }
668
669 // Unmapped after MapAsync read case.
670 {
671 wgpu::Buffer buf = CreateMapReadBuffer(4);
672
673 buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
674 EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
675 .Times(1);
676 WaitForAllOperations(device);
677 buf.Unmap();
678
679 ASSERT_EQ(nullptr, buf.GetMappedRange());
680 ASSERT_EQ(nullptr, buf.GetConstMappedRange());
681 }
682
683 // Unmapped after MapAsync write case.
684 {
685 wgpu::Buffer buf = CreateMapWriteBuffer(4);
686 buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
687 EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
688 .Times(1);
689 WaitForAllOperations(device);
690 buf.Unmap();
691
692 ASSERT_EQ(nullptr, buf.GetMappedRange());
693 ASSERT_EQ(nullptr, buf.GetConstMappedRange());
694 }
695 }
696
697 // Test that it is invalid to call GetMappedRange on a destroyed buffer.
TEST_F(BufferValidationTest,GetMappedRange_OnDestroyedBuffer)698 TEST_F(BufferValidationTest, GetMappedRange_OnDestroyedBuffer) {
699 // Destroyed after creation case.
700 {
701 wgpu::BufferDescriptor desc;
702 desc.size = 4;
703 desc.usage = wgpu::BufferUsage::CopySrc;
704 wgpu::Buffer buf = device.CreateBuffer(&desc);
705 buf.Destroy();
706
707 ASSERT_EQ(nullptr, buf.GetMappedRange());
708 ASSERT_EQ(nullptr, buf.GetConstMappedRange());
709 }
710
711 // Destroyed after mappedAtCreation case.
712 {
713 wgpu::Buffer buf = BufferMappedAtCreation(4, wgpu::BufferUsage::CopySrc);
714 buf.Destroy();
715
716 ASSERT_EQ(nullptr, buf.GetMappedRange());
717 ASSERT_EQ(nullptr, buf.GetConstMappedRange());
718 }
719
720 // Destroyed after MapAsync read case.
721 {
722 wgpu::Buffer buf = CreateMapReadBuffer(4);
723
724 buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
725 EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
726 .Times(1);
727 WaitForAllOperations(device);
728 buf.Destroy();
729
730 ASSERT_EQ(nullptr, buf.GetMappedRange());
731 ASSERT_EQ(nullptr, buf.GetConstMappedRange());
732 }
733
734 // Destroyed after MapAsync write case.
735 {
736 wgpu::Buffer buf = CreateMapWriteBuffer(4);
737 buf.MapAsync(wgpu::MapMode::Write, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
738 EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
739 .Times(1);
740 WaitForAllOperations(device);
741 buf.Destroy();
742
743 ASSERT_EQ(nullptr, buf.GetMappedRange());
744 ASSERT_EQ(nullptr, buf.GetConstMappedRange());
745 }
746 }
747
748 // Test that it is invalid to call GetMappedRange on a buffer after MapAsync for reading
TEST_F(BufferValidationTest,GetMappedRange_NonConstOnMappedForReading)749 TEST_F(BufferValidationTest, GetMappedRange_NonConstOnMappedForReading) {
750 wgpu::Buffer buf = CreateMapReadBuffer(4);
751
752 buf.MapAsync(wgpu::MapMode::Read, 0, 4, ToMockBufferMapAsyncCallback, nullptr);
753 EXPECT_CALL(*mockBufferMapAsyncCallback, Call(WGPUBufferMapAsyncStatus_Success, _)).Times(1);
754 WaitForAllOperations(device);
755
756 ASSERT_EQ(nullptr, buf.GetMappedRange());
757 }
758
759 // Test valid cases to call GetMappedRange on a buffer.
TEST_F(BufferValidationTest,GetMappedRange_ValidBufferStateCases)760 TEST_F(BufferValidationTest, GetMappedRange_ValidBufferStateCases) {
761 // GetMappedRange after mappedAtCreation case.
762 {
763 wgpu::Buffer buffer = BufferMappedAtCreation(4, wgpu::BufferUsage::CopySrc);
764 ASSERT_NE(buffer.GetConstMappedRange(), nullptr);
765 ASSERT_EQ(buffer.GetConstMappedRange(), buffer.GetMappedRange());
766 }
767
768 // GetMappedRange after MapAsync for reading case.
769 {
770 wgpu::Buffer buf = CreateMapReadBuffer(4);
771
772 buf.MapAsync(wgpu::MapMode::Read, 0, 4, nullptr, nullptr);
773 WaitForAllOperations(device);
774
775 ASSERT_NE(buf.GetConstMappedRange(), nullptr);
776 }
777
778 // GetMappedRange after MapAsync for writing case.
779 {
780 wgpu::Buffer buf = CreateMapWriteBuffer(4);
781
782 buf.MapAsync(wgpu::MapMode::Write, 0, 4, nullptr, nullptr);
783 WaitForAllOperations(device);
784
785 ASSERT_NE(buf.GetConstMappedRange(), nullptr);
786 ASSERT_EQ(buf.GetConstMappedRange(), buf.GetMappedRange());
787 }
788 }
789
790 // Test valid cases to call GetMappedRange on an error buffer.
TEST_F(BufferValidationTest,GetMappedRange_OnErrorBuffer)791 TEST_F(BufferValidationTest, GetMappedRange_OnErrorBuffer) {
792 wgpu::BufferDescriptor desc;
793 desc.size = 4;
794 desc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::MapRead;
795
796 uint64_t kStupidLarge = uint64_t(1) << uint64_t(63);
797
798 // GetMappedRange after mappedAtCreation a zero-sized buffer returns a non-nullptr.
799 // This is to check we don't do a malloc(0).
800 {
801 wgpu::Buffer buffer;
802 ASSERT_DEVICE_ERROR(buffer = BufferMappedAtCreation(
803 0, wgpu::BufferUsage::Storage | wgpu::BufferUsage::MapRead));
804
805 ASSERT_NE(buffer.GetConstMappedRange(), nullptr);
806 ASSERT_EQ(buffer.GetConstMappedRange(), buffer.GetMappedRange());
807 }
808
809 // GetMappedRange after mappedAtCreation non-OOM returns a non-nullptr.
810 {
811 wgpu::Buffer buffer;
812 ASSERT_DEVICE_ERROR(buffer = BufferMappedAtCreation(
813 4, wgpu::BufferUsage::Storage | wgpu::BufferUsage::MapRead));
814
815 ASSERT_NE(buffer.GetConstMappedRange(), nullptr);
816 ASSERT_EQ(buffer.GetConstMappedRange(), buffer.GetMappedRange());
817 }
818
819 // GetMappedRange after mappedAtCreation OOM case returns nullptr.
820 {
821 wgpu::Buffer buffer;
822 ASSERT_DEVICE_ERROR(
823 buffer = BufferMappedAtCreation(
824 kStupidLarge, wgpu::BufferUsage::Storage | wgpu::BufferUsage::MapRead));
825
826 ASSERT_EQ(buffer.GetConstMappedRange(), nullptr);
827 ASSERT_EQ(buffer.GetConstMappedRange(), buffer.GetMappedRange());
828 }
829 }
830
831 // Test validation of the GetMappedRange parameters
TEST_F(BufferValidationTest,GetMappedRange_OffsetSizeOOB)832 TEST_F(BufferValidationTest, GetMappedRange_OffsetSizeOOB) {
833 // Valid case: full range is ok
834 {
835 wgpu::Buffer buffer = CreateMapWriteBuffer(8);
836 buffer.MapAsync(wgpu::MapMode::Write, 0, 8, nullptr, nullptr);
837 WaitForAllOperations(device);
838 EXPECT_NE(buffer.GetMappedRange(0, 8), nullptr);
839 }
840
841 // Valid case: full range is ok with defaulted MapAsync size
842 {
843 wgpu::Buffer buffer = CreateMapWriteBuffer(8);
844 buffer.MapAsync(wgpu::MapMode::Write, 0, wgpu::kWholeMapSize, nullptr, nullptr);
845 WaitForAllOperations(device);
846 EXPECT_NE(buffer.GetMappedRange(0, 8), nullptr);
847 }
848
849 // Valid case: empty range at the end is ok
850 {
851 wgpu::Buffer buffer = CreateMapWriteBuffer(8);
852 buffer.MapAsync(wgpu::MapMode::Write, 0, 8, nullptr, nullptr);
853 WaitForAllOperations(device);
854 EXPECT_NE(buffer.GetMappedRange(8, 0), nullptr);
855 }
856
857 // Valid case: range in the middle is ok.
858 {
859 wgpu::Buffer buffer = CreateMapWriteBuffer(16);
860 buffer.MapAsync(wgpu::MapMode::Write, 0, 16, nullptr, nullptr);
861 WaitForAllOperations(device);
862 EXPECT_NE(buffer.GetMappedRange(8, 4), nullptr);
863 }
864
865 // Error case: offset is larger than the mapped range (even with size = 0)
866 {
867 wgpu::Buffer buffer = CreateMapWriteBuffer(8);
868 buffer.MapAsync(wgpu::MapMode::Write, 0, 8, nullptr, nullptr);
869 WaitForAllOperations(device);
870 EXPECT_EQ(buffer.GetMappedRange(9, 0), nullptr);
871 EXPECT_EQ(buffer.GetMappedRange(16, 0), nullptr);
872 }
873
874 // Error case: offset + size is larger than the mapped range
875 {
876 wgpu::Buffer buffer = CreateMapWriteBuffer(12);
877 buffer.MapAsync(wgpu::MapMode::Write, 0, 12, nullptr, nullptr);
878 WaitForAllOperations(device);
879 EXPECT_EQ(buffer.GetMappedRange(8, 5), nullptr);
880 EXPECT_EQ(buffer.GetMappedRange(8, 8), nullptr);
881 }
882
883 // Error case: offset + size is larger than the mapped range, overflow case
884 {
885 wgpu::Buffer buffer = CreateMapWriteBuffer(12);
886 buffer.MapAsync(wgpu::MapMode::Write, 0, 12, nullptr, nullptr);
887 WaitForAllOperations(device);
888 EXPECT_EQ(buffer.GetMappedRange(8, std::numeric_limits<size_t>::max()), nullptr);
889 }
890
891 // Error case: offset is before the start of the range
892 {
893 wgpu::Buffer buffer = CreateMapWriteBuffer(12);
894 buffer.MapAsync(wgpu::MapMode::Write, 8, 4, nullptr, nullptr);
895 WaitForAllOperations(device);
896 EXPECT_EQ(buffer.GetMappedRange(7, 4), nullptr);
897 EXPECT_EQ(buffer.GetMappedRange(0, 4), nullptr);
898 }
899 }
900