• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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