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/DawnTest.h"
16 
17 #include <array>
18 #include <cstring>
19 
20 class BufferMappingTests : public DawnTest {
21   protected:
MapAsyncAndWait(const wgpu::Buffer& buffer, wgpu::MapMode mode, size_t offset, size_t size)22     void MapAsyncAndWait(const wgpu::Buffer& buffer,
23                          wgpu::MapMode mode,
24                          size_t offset,
25                          size_t size) {
26         bool done = false;
27         buffer.MapAsync(
28             mode, offset, size,
29             [](WGPUBufferMapAsyncStatus status, void* userdata) {
30                 ASSERT_EQ(WGPUBufferMapAsyncStatus_Success, status);
31                 *static_cast<bool*>(userdata) = true;
32             },
33             &done);
34 
35         while (!done) {
36             WaitABit();
37         }
38     }
39 
CreateMapReadBuffer(uint64_t size)40     wgpu::Buffer CreateMapReadBuffer(uint64_t size) {
41         wgpu::BufferDescriptor descriptor;
42         descriptor.size = size;
43         descriptor.usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst;
44         return device.CreateBuffer(&descriptor);
45     }
46 
CreateMapWriteBuffer(uint64_t size)47     wgpu::Buffer CreateMapWriteBuffer(uint64_t size) {
48         wgpu::BufferDescriptor descriptor;
49         descriptor.size = size;
50         descriptor.usage = wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc;
51         return device.CreateBuffer(&descriptor);
52     }
53 };
54 
CheckMapping(const void* actual, const void* expected, size_t size)55 void CheckMapping(const void* actual, const void* expected, size_t size) {
56     EXPECT_NE(actual, nullptr);
57     if (actual != nullptr) {
58         EXPECT_EQ(0, memcmp(actual, expected, size));
59     }
60 }
61 
62 // Test that the simplest map read works
TEST_P(BufferMappingTests, MapRead_Basic)63 TEST_P(BufferMappingTests, MapRead_Basic) {
64     wgpu::Buffer buffer = CreateMapReadBuffer(4);
65 
66     uint32_t myData = 0x01020304;
67     constexpr size_t kSize = sizeof(myData);
68     queue.WriteBuffer(buffer, 0, &myData, kSize);
69 
70     MapAsyncAndWait(buffer, wgpu::MapMode::Read, 0, 4);
71     CheckMapping(buffer.GetConstMappedRange(), &myData, kSize);
72     CheckMapping(buffer.GetConstMappedRange(0, kSize), &myData, kSize);
73     buffer.Unmap();
74 }
75 
76 // Test map-reading a zero-sized buffer.
TEST_P(BufferMappingTests, MapRead_ZeroSized)77 TEST_P(BufferMappingTests, MapRead_ZeroSized) {
78     wgpu::Buffer buffer = CreateMapReadBuffer(0);
79 
80     MapAsyncAndWait(buffer, wgpu::MapMode::Read, 0, wgpu::kWholeMapSize);
81     ASSERT_NE(buffer.GetConstMappedRange(), nullptr);
82     buffer.Unmap();
83 }
84 
85 // Test map-reading with a non-zero offset
TEST_P(BufferMappingTests, MapRead_NonZeroOffset)86 TEST_P(BufferMappingTests, MapRead_NonZeroOffset) {
87     wgpu::Buffer buffer = CreateMapReadBuffer(12);
88 
89     uint32_t myData[3] = {0x01020304, 0x05060708, 0x090A0B0C};
90     queue.WriteBuffer(buffer, 0, &myData, sizeof(myData));
91 
92     MapAsyncAndWait(buffer, wgpu::MapMode::Read, 8, 4);
93     ASSERT_EQ(myData[2], *static_cast<const uint32_t*>(buffer.GetConstMappedRange(8)));
94     buffer.Unmap();
95 }
96 
97 // Map read and unmap twice. Test that both of these two iterations work.
TEST_P(BufferMappingTests, MapRead_Twice)98 TEST_P(BufferMappingTests, MapRead_Twice) {
99     wgpu::Buffer buffer = CreateMapReadBuffer(4);
100 
101     uint32_t myData = 0x01020304;
102     queue.WriteBuffer(buffer, 0, &myData, sizeof(myData));
103 
104     MapAsyncAndWait(buffer, wgpu::MapMode::Read, 0, 4);
105     ASSERT_EQ(myData, *static_cast<const uint32_t*>(buffer.GetConstMappedRange()));
106     buffer.Unmap();
107 
108     myData = 0x05060708;
109     queue.WriteBuffer(buffer, 0, &myData, sizeof(myData));
110 
111     MapAsyncAndWait(buffer, wgpu::MapMode::Read, 0, 4);
112     ASSERT_EQ(myData, *static_cast<const uint32_t*>(buffer.GetConstMappedRange()));
113     buffer.Unmap();
114 }
115 
116 // Map read and test multiple get mapped range data
TEST_P(BufferMappingTests, MapRead_MultipleMappedRange)117 TEST_P(BufferMappingTests, MapRead_MultipleMappedRange) {
118     wgpu::Buffer buffer = CreateMapReadBuffer(12);
119 
120     uint32_t myData[] = {0x00010203, 0x04050607, 0x08090a0b};
121     queue.WriteBuffer(buffer, 0, &myData, 12);
122 
123     MapAsyncAndWait(buffer, wgpu::MapMode::Read, 0, 12);
124     ASSERT_EQ(myData[0], *static_cast<const uint32_t*>(buffer.GetConstMappedRange(0)));
125     ASSERT_EQ(myData[1], *(static_cast<const uint32_t*>(buffer.GetConstMappedRange(0)) + 1));
126     ASSERT_EQ(myData[2], *(static_cast<const uint32_t*>(buffer.GetConstMappedRange(0)) + 2));
127     ASSERT_EQ(myData[2], *static_cast<const uint32_t*>(buffer.GetConstMappedRange(8)));
128     buffer.Unmap();
129 }
130 
131 // Test map-reading a large buffer.
TEST_P(BufferMappingTests, MapRead_Large)132 TEST_P(BufferMappingTests, MapRead_Large) {
133     constexpr uint32_t kDataSize = 1000 * 1000;
134     constexpr size_t kByteSize = kDataSize * sizeof(uint32_t);
135     wgpu::Buffer buffer = CreateMapReadBuffer(kByteSize);
136 
137     std::vector<uint32_t> myData;
138     for (uint32_t i = 0; i < kDataSize; ++i) {
139         myData.push_back(i);
140     }
141     queue.WriteBuffer(buffer, 0, myData.data(), kByteSize);
142 
143     MapAsyncAndWait(buffer, wgpu::MapMode::Read, 0, kByteSize);
144     EXPECT_EQ(nullptr, buffer.GetConstMappedRange(0, kByteSize + 4));
145     EXPECT_EQ(0, memcmp(buffer.GetConstMappedRange(), myData.data(), kByteSize));
146     EXPECT_EQ(0, memcmp(buffer.GetConstMappedRange(8), myData.data() + 2, kByteSize - 8));
147     EXPECT_EQ(
148         0, memcmp(buffer.GetConstMappedRange(8, kByteSize - 8), myData.data() + 2, kByteSize - 8));
149     buffer.Unmap();
150 
151     MapAsyncAndWait(buffer, wgpu::MapMode::Read, 16, kByteSize - 16);
152     // Size is too big.
153     EXPECT_EQ(nullptr, buffer.GetConstMappedRange(16, kByteSize - 12));
154     // Offset defaults to 0 which is less than 16
155     EXPECT_EQ(nullptr, buffer.GetConstMappedRange());
156     // Offset less than 8 is less than 16
157     EXPECT_EQ(nullptr, buffer.GetConstMappedRange(8));
158 
159     // Test a couple values.
160     EXPECT_EQ(0, memcmp(buffer.GetConstMappedRange(16), myData.data() + 4, kByteSize - 16));
161     EXPECT_EQ(0, memcmp(buffer.GetConstMappedRange(24), myData.data() + 6, kByteSize - 24));
162 
163     buffer.Unmap();
164 }
165 
166 // Test that GetConstMappedRange works inside map-read callback
TEST_P(BufferMappingTests, MapRead_InCallback)167 TEST_P(BufferMappingTests, MapRead_InCallback) {
168     constexpr size_t kBufferSize = 12;
169     wgpu::Buffer buffer = CreateMapReadBuffer(kBufferSize);
170 
171     uint32_t myData[3] = {0x01020304, 0x05060708, 0x090A0B0C};
172     static constexpr size_t kSize = sizeof(myData);
173     queue.WriteBuffer(buffer, 0, &myData, kSize);
174 
175     struct UserData {
176         bool done;
177         wgpu::Buffer buffer;
178         void* expected;
179     };
180     UserData user{false, buffer, &myData};
181 
182     buffer.MapAsync(
183         wgpu::MapMode::Read, 0, kBufferSize,
184         [](WGPUBufferMapAsyncStatus status, void* userdata) {
185             UserData* user = static_cast<UserData*>(userdata);
186 
187             EXPECT_EQ(WGPUBufferMapAsyncStatus_Success, status);
188             if (status == WGPUBufferMapAsyncStatus_Success) {
189                 CheckMapping(user->buffer.GetConstMappedRange(), user->expected, kSize);
190                 CheckMapping(user->buffer.GetConstMappedRange(0, kSize), user->expected, kSize);
191 
192                 CheckMapping(user->buffer.GetConstMappedRange(8, 4),
193                              static_cast<const uint32_t*>(user->expected) + 2, sizeof(uint32_t));
194 
195                 user->buffer.Unmap();
196             }
197             user->done = true;
198         },
199         &user);
200 
201     while (!user.done) {
202         WaitABit();
203     }
204 }
205 
206 // Test that the simplest map write works.
TEST_P(BufferMappingTests, MapWrite_Basic)207 TEST_P(BufferMappingTests, MapWrite_Basic) {
208     wgpu::Buffer buffer = CreateMapWriteBuffer(4);
209 
210     uint32_t myData = 2934875;
211     MapAsyncAndWait(buffer, wgpu::MapMode::Write, 0, 4);
212     ASSERT_NE(nullptr, buffer.GetMappedRange());
213     ASSERT_NE(nullptr, buffer.GetConstMappedRange());
214     memcpy(buffer.GetMappedRange(), &myData, sizeof(myData));
215     buffer.Unmap();
216 
217     EXPECT_BUFFER_U32_EQ(myData, buffer, 0);
218 }
219 
220 // Test that the simplest map write works with a range.
TEST_P(BufferMappingTests, MapWrite_BasicRange)221 TEST_P(BufferMappingTests, MapWrite_BasicRange) {
222     wgpu::Buffer buffer = CreateMapWriteBuffer(4);
223 
224     uint32_t myData = 2934875;
225     MapAsyncAndWait(buffer, wgpu::MapMode::Write, 0, 4);
226     ASSERT_NE(nullptr, buffer.GetMappedRange(0, 4));
227     ASSERT_NE(nullptr, buffer.GetConstMappedRange(0, 4));
228     memcpy(buffer.GetMappedRange(), &myData, sizeof(myData));
229     buffer.Unmap();
230 
231     EXPECT_BUFFER_U32_EQ(myData, buffer, 0);
232 }
233 
234 // Test map-writing a zero-sized buffer.
TEST_P(BufferMappingTests, MapWrite_ZeroSized)235 TEST_P(BufferMappingTests, MapWrite_ZeroSized) {
236     wgpu::Buffer buffer = CreateMapWriteBuffer(0);
237 
238     MapAsyncAndWait(buffer, wgpu::MapMode::Write, 0, wgpu::kWholeMapSize);
239     ASSERT_NE(buffer.GetConstMappedRange(), nullptr);
240     ASSERT_NE(buffer.GetMappedRange(), nullptr);
241     buffer.Unmap();
242 }
243 
244 // Test map-writing with a non-zero offset.
TEST_P(BufferMappingTests, MapWrite_NonZeroOffset)245 TEST_P(BufferMappingTests, MapWrite_NonZeroOffset) {
246     wgpu::Buffer buffer = CreateMapWriteBuffer(12);
247 
248     uint32_t myData = 2934875;
249     MapAsyncAndWait(buffer, wgpu::MapMode::Write, 8, 4);
250     memcpy(buffer.GetMappedRange(8), &myData, sizeof(myData));
251     buffer.Unmap();
252 
253     EXPECT_BUFFER_U32_EQ(myData, buffer, 8);
254 }
255 
256 // Map, write and unmap twice. Test that both of these two iterations work.
TEST_P(BufferMappingTests, MapWrite_Twice)257 TEST_P(BufferMappingTests, MapWrite_Twice) {
258     wgpu::Buffer buffer = CreateMapWriteBuffer(4);
259 
260     uint32_t myData = 2934875;
261     MapAsyncAndWait(buffer, wgpu::MapMode::Write, 0, 4);
262     memcpy(buffer.GetMappedRange(), &myData, sizeof(myData));
263     buffer.Unmap();
264 
265     EXPECT_BUFFER_U32_EQ(myData, buffer, 0);
266 
267     myData = 9999999;
268     MapAsyncAndWait(buffer, wgpu::MapMode::Write, 0, 4);
269     memcpy(buffer.GetMappedRange(), &myData, sizeof(myData));
270     buffer.Unmap();
271 
272     EXPECT_BUFFER_U32_EQ(myData, buffer, 0);
273 }
274 
275 // Map write and unmap twice with different ranges and make sure the first write is preserved
TEST_P(BufferMappingTests, MapWrite_TwicePreserve)276 TEST_P(BufferMappingTests, MapWrite_TwicePreserve) {
277     wgpu::Buffer buffer = CreateMapWriteBuffer(12);
278 
279     uint32_t data1 = 0x08090a0b;
280     size_t offset1 = 8;
281     MapAsyncAndWait(buffer, wgpu::MapMode::Write, offset1, sizeof(data1));
282     memcpy(buffer.GetMappedRange(offset1), &data1, sizeof(data1));
283     buffer.Unmap();
284 
285     uint32_t data2 = 0x00010203;
286     size_t offset2 = 0;
287     MapAsyncAndWait(buffer, wgpu::MapMode::Write, offset2, sizeof(data2));
288     memcpy(buffer.GetMappedRange(offset2), &data2, sizeof(data2));
289     buffer.Unmap();
290 
291     EXPECT_BUFFER_U32_EQ(data1, buffer, offset1);
292     EXPECT_BUFFER_U32_EQ(data2, buffer, offset2);
293 }
294 
295 // Map write and unmap twice with overlapping ranges and make sure data is updated correctly
TEST_P(BufferMappingTests, MapWrite_TwiceRangeOverlap)296 TEST_P(BufferMappingTests, MapWrite_TwiceRangeOverlap) {
297     wgpu::Buffer buffer = CreateMapWriteBuffer(16);
298 
299     uint32_t data1[] = {0x01234567, 0x89abcdef};
300     size_t offset1 = 8;
301     MapAsyncAndWait(buffer, wgpu::MapMode::Write, offset1, 8);
302     memcpy(buffer.GetMappedRange(offset1), data1, 8);
303     buffer.Unmap();
304 
305     EXPECT_BUFFER_U32_EQ(0x00000000, buffer, 0);
306     EXPECT_BUFFER_U32_EQ(0x00000000, buffer, 4);
307     EXPECT_BUFFER_U32_EQ(0x01234567, buffer, 8);
308     EXPECT_BUFFER_U32_EQ(0x89abcdef, buffer, 12);
309 
310     uint32_t data2[] = {0x01234567, 0x89abcdef, 0x55555555};
311     size_t offset2 = 0;
312     MapAsyncAndWait(buffer, wgpu::MapMode::Write, offset2, 12);
313     memcpy(buffer.GetMappedRange(offset2), data2, 12);
314     buffer.Unmap();
315 
316     EXPECT_BUFFER_U32_EQ(0x01234567, buffer, 0);
317     EXPECT_BUFFER_U32_EQ(0x89abcdef, buffer, 4);
318     EXPECT_BUFFER_U32_EQ(0x55555555, buffer, 8);
319     EXPECT_BUFFER_U32_EQ(0x89abcdef, buffer, 12);
320 }
321 
322 // Map write and test multiple mapped range data get updated correctly
TEST_P(BufferMappingTests, MapWrite_MultipleMappedRange)323 TEST_P(BufferMappingTests, MapWrite_MultipleMappedRange) {
324     wgpu::Buffer buffer = CreateMapWriteBuffer(12);
325 
326     uint32_t data1 = 0x08090a0b;
327     size_t offset1 = 8;
328     uint32_t data2 = 0x00010203;
329     size_t offset2 = 0;
330     MapAsyncAndWait(buffer, wgpu::MapMode::Write, 0, 12);
331     memcpy(buffer.GetMappedRange(offset1), &data1, sizeof(data1));
332     memcpy(buffer.GetMappedRange(offset2), &data2, sizeof(data2));
333     buffer.Unmap();
334 
335     EXPECT_BUFFER_U32_EQ(data1, buffer, offset1);
336     EXPECT_BUFFER_U32_EQ(data2, buffer, offset2);
337 }
338 
339 // Test mapping a large buffer.
TEST_P(BufferMappingTests, MapWrite_Large)340 TEST_P(BufferMappingTests, MapWrite_Large) {
341     constexpr uint32_t kDataSize = 1000 * 1000;
342     constexpr size_t kByteSize = kDataSize * sizeof(uint32_t);
343     wgpu::Buffer buffer = CreateMapWriteBuffer(kDataSize * sizeof(uint32_t));
344 
345     std::vector<uint32_t> myData;
346     for (uint32_t i = 0; i < kDataSize; ++i) {
347         myData.push_back(i);
348     }
349 
350     MapAsyncAndWait(buffer, wgpu::MapMode::Write, 16, kByteSize - 20);
351     EXPECT_EQ(nullptr, buffer.GetMappedRange());
352     EXPECT_EQ(nullptr, buffer.GetMappedRange(0));
353     EXPECT_EQ(nullptr, buffer.GetMappedRange(8));
354     EXPECT_EQ(nullptr, buffer.GetMappedRange(16, kByteSize - 8));
355     memcpy(buffer.GetMappedRange(16), myData.data(), kByteSize - 20);
356     buffer.Unmap();
357     EXPECT_BUFFER_U32_RANGE_EQ(myData.data(), buffer, 16, kDataSize - 5);
358 }
359 
360 // Stress test mapping many buffers.
TEST_P(BufferMappingTests, MapWrite_ManySimultaneous)361 TEST_P(BufferMappingTests, MapWrite_ManySimultaneous) {
362     constexpr uint32_t kDataSize = 1000;
363     std::vector<uint32_t> myData;
364     for (uint32_t i = 0; i < kDataSize; ++i) {
365         myData.push_back(i);
366     }
367 
368     constexpr uint32_t kBuffers = 100;
369     std::array<wgpu::Buffer, kBuffers> buffers;
370     uint32_t mapCompletedCount = 0;
371 
372     // Create buffers and request mapping them.
373     wgpu::BufferDescriptor descriptor;
374     descriptor.size = static_cast<uint32_t>(kDataSize * sizeof(uint32_t));
375     descriptor.usage = wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc;
376     for (uint32_t i = 0; i < kBuffers; ++i) {
377         buffers[i] = device.CreateBuffer(&descriptor);
378 
379         buffers[i].MapAsync(
380             wgpu::MapMode::Write, 0, descriptor.size,
381             [](WGPUBufferMapAsyncStatus status, void* userdata) {
382                 ASSERT_EQ(WGPUBufferMapAsyncStatus_Success, status);
383                 (*static_cast<uint32_t*>(userdata))++;
384             },
385             &mapCompletedCount);
386     }
387 
388     // Wait for all mappings to complete
389     while (mapCompletedCount != kBuffers) {
390         WaitABit();
391     }
392 
393     // All buffers are mapped, write into them and unmap them all.
394     for (uint32_t i = 0; i < kBuffers; ++i) {
395         memcpy(buffers[i].GetMappedRange(0, descriptor.size), myData.data(), descriptor.size);
396         buffers[i].Unmap();
397     }
398 
399     // Check the content of the buffers.
400     for (uint32_t i = 0; i < kBuffers; ++i) {
401         EXPECT_BUFFER_U32_RANGE_EQ(myData.data(), buffers[i], 0, kDataSize);
402     }
403 }
404 
405 // Test that the map offset isn't updated when the call is an error.
TEST_P(BufferMappingTests, OffsetNotUpdatedOnError)406 TEST_P(BufferMappingTests, OffsetNotUpdatedOnError) {
407     uint32_t data[3] = {0xCA7, 0xB0A7, 0xBA7};
408     wgpu::Buffer buffer = CreateMapReadBuffer(sizeof(data));
409     queue.WriteBuffer(buffer, 0, data, sizeof(data));
410 
411     // Map the buffer but do not wait on the result yet.
412     bool done1 = false;
413     bool done2 = false;
414     buffer.MapAsync(
415         wgpu::MapMode::Read, 8, 4,
416         [](WGPUBufferMapAsyncStatus status, void* userdata) {
417             ASSERT_EQ(WGPUBufferMapAsyncStatus_Success, status);
418             *static_cast<bool*>(userdata) = true;
419         },
420         &done1);
421 
422     // Call MapAsync another time, it is an error because the buffer is already being mapped so
423     // mMapOffset is not updated.
424     ASSERT_DEVICE_ERROR(buffer.MapAsync(
425         wgpu::MapMode::Read, 0, 4,
426         [](WGPUBufferMapAsyncStatus status, void* userdata) {
427             *static_cast<bool*>(userdata) = true;
428         },
429         &done2));
430 
431     while (!done1 || !done2) {
432         WaitABit();
433     }
434 
435     // mMapOffset has not been updated so it should still be 4, which is data[1]
436     ASSERT_EQ(0, memcmp(buffer.GetConstMappedRange(8), &data[2], sizeof(uint32_t)));
437 }
438 
439 // Test that Get(Const)MappedRange work inside map-write callback.
TEST_P(BufferMappingTests, MapWrite_InCallbackDefault)440 TEST_P(BufferMappingTests, MapWrite_InCallbackDefault) {
441     wgpu::Buffer buffer = CreateMapWriteBuffer(4);
442 
443     static constexpr uint32_t myData = 2934875;
444     static constexpr size_t kSize = sizeof(myData);
445 
446     struct UserData {
447         bool done;
448         wgpu::Buffer buffer;
449     };
450     UserData user{false, buffer};
451 
452     buffer.MapAsync(
453         wgpu::MapMode::Write, 0, kSize,
454         [](WGPUBufferMapAsyncStatus status, void* userdata) {
455             UserData* user = static_cast<UserData*>(userdata);
456 
457             EXPECT_EQ(WGPUBufferMapAsyncStatus_Success, status);
458             if (status == WGPUBufferMapAsyncStatus_Success) {
459                 EXPECT_NE(nullptr, user->buffer.GetConstMappedRange());
460                 void* ptr = user->buffer.GetMappedRange();
461                 EXPECT_NE(nullptr, ptr);
462                 if (ptr != nullptr) {
463                     uint32_t data = myData;
464                     memcpy(ptr, &data, kSize);
465                 }
466 
467                 user->buffer.Unmap();
468             }
469             user->done = true;
470         },
471         &user);
472 
473     while (!user.done) {
474         WaitABit();
475     }
476 
477     EXPECT_BUFFER_U32_EQ(myData, buffer, 0);
478 }
479 
480 // Test that Get(Const)MappedRange with range work inside map-write callback.
TEST_P(BufferMappingTests, MapWrite_InCallbackRange)481 TEST_P(BufferMappingTests, MapWrite_InCallbackRange) {
482     wgpu::Buffer buffer = CreateMapWriteBuffer(4);
483 
484     static constexpr uint32_t myData = 2934875;
485     static constexpr size_t kSize = sizeof(myData);
486 
487     struct UserData {
488         bool done;
489         wgpu::Buffer buffer;
490     };
491     UserData user{false, buffer};
492 
493     buffer.MapAsync(
494         wgpu::MapMode::Write, 0, kSize,
495         [](WGPUBufferMapAsyncStatus status, void* userdata) {
496             UserData* user = static_cast<UserData*>(userdata);
497 
498             EXPECT_EQ(WGPUBufferMapAsyncStatus_Success, status);
499             if (status == WGPUBufferMapAsyncStatus_Success) {
500                 EXPECT_NE(nullptr, user->buffer.GetConstMappedRange(0, kSize));
501                 void* ptr = user->buffer.GetMappedRange(0, kSize);
502                 EXPECT_NE(nullptr, ptr);
503                 if (ptr != nullptr) {
504                     uint32_t data = myData;
505                     memcpy(ptr, &data, kSize);
506                 }
507 
508                 user->buffer.Unmap();
509             }
510             user->done = true;
511         },
512         &user);
513 
514     while (!user.done) {
515         WaitABit();
516     }
517 
518     EXPECT_BUFFER_U32_EQ(myData, buffer, 0);
519 }
520 
521 // Regression test for crbug.com/dawn/969 where this test
522 // produced invalid barriers.
TEST_P(BufferMappingTests, MapWrite_ZeroSizedTwice)523 TEST_P(BufferMappingTests, MapWrite_ZeroSizedTwice) {
524     wgpu::Buffer buffer = CreateMapWriteBuffer(0);
525 
526     MapAsyncAndWait(buffer, wgpu::MapMode::Write, 0, wgpu::kWholeMapSize);
527     buffer.Unmap();
528 
529     MapAsyncAndWait(buffer, wgpu::MapMode::Write, 0, wgpu::kWholeMapSize);
530 }
531 
532 DAWN_INSTANTIATE_TEST(BufferMappingTests,
533                       D3D12Backend(),
534                       MetalBackend(),
535                       OpenGLBackend(),
536                       OpenGLESBackend(),
537                       VulkanBackend());
538 
539 class BufferMappedAtCreationTests : public DawnTest {
540   protected:
MapCallback(WGPUBufferMapAsyncStatus status, void* userdata)541     static void MapCallback(WGPUBufferMapAsyncStatus status, void* userdata) {
542         EXPECT_EQ(WGPUBufferMapAsyncStatus_Success, status);
543         *static_cast<bool*>(userdata) = true;
544     }
545 
MapAsyncAndWait(const wgpu::Buffer& buffer, wgpu::MapMode mode, size_t size)546     const void* MapAsyncAndWait(const wgpu::Buffer& buffer, wgpu::MapMode mode, size_t size) {
547         bool done = false;
548         buffer.MapAsync(mode, 0, size, MapCallback, &done);
549 
550         while (!done) {
551             WaitABit();
552         }
553 
554         return buffer.GetConstMappedRange(0, size);
555     }
556 
UnmapBuffer(const wgpu::Buffer& buffer)557     void UnmapBuffer(const wgpu::Buffer& buffer) {
558         buffer.Unmap();
559     }
560 
BufferMappedAtCreation(wgpu::BufferUsage usage, uint64_t size)561     wgpu::Buffer BufferMappedAtCreation(wgpu::BufferUsage usage, uint64_t size) {
562         wgpu::BufferDescriptor descriptor;
563         descriptor.size = size;
564         descriptor.usage = usage;
565         descriptor.mappedAtCreation = true;
566         return device.CreateBuffer(&descriptor);
567     }
568 
BufferMappedAtCreationWithData(wgpu::BufferUsage usage, const std::vector<uint32_t>& data)569     wgpu::Buffer BufferMappedAtCreationWithData(wgpu::BufferUsage usage,
570                                                 const std::vector<uint32_t>& data) {
571         size_t byteLength = data.size() * sizeof(uint32_t);
572         wgpu::Buffer buffer = BufferMappedAtCreation(usage, byteLength);
573         memcpy(buffer.GetMappedRange(), data.data(), byteLength);
574         return buffer;
575     }
576 };
577 
578 // Test that the simplest mappedAtCreation works for MapWrite buffers.
TEST_P(BufferMappedAtCreationTests, MapWriteUsageSmall)579 TEST_P(BufferMappedAtCreationTests, MapWriteUsageSmall) {
580     uint32_t myData = 230502;
581     wgpu::Buffer buffer = BufferMappedAtCreationWithData(
582         wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc, {myData});
583     UnmapBuffer(buffer);
584     EXPECT_BUFFER_U32_EQ(myData, buffer, 0);
585 }
586 
587 // Test that the simplest mappedAtCreation works for MapRead buffers.
TEST_P(BufferMappedAtCreationTests, MapReadUsageSmall)588 TEST_P(BufferMappedAtCreationTests, MapReadUsageSmall) {
589     uint32_t myData = 230502;
590     wgpu::Buffer buffer = BufferMappedAtCreationWithData(wgpu::BufferUsage::MapRead, {myData});
591     UnmapBuffer(buffer);
592 
593     const void* mappedData = MapAsyncAndWait(buffer, wgpu::MapMode::Read, 4);
594     ASSERT_EQ(myData, *reinterpret_cast<const uint32_t*>(mappedData));
595     UnmapBuffer(buffer);
596 }
597 
598 // Test that the simplest mappedAtCreation works for non-mappable buffers.
TEST_P(BufferMappedAtCreationTests, NonMappableUsageSmall)599 TEST_P(BufferMappedAtCreationTests, NonMappableUsageSmall) {
600     uint32_t myData = 4239;
601     wgpu::Buffer buffer = BufferMappedAtCreationWithData(wgpu::BufferUsage::CopySrc, {myData});
602     UnmapBuffer(buffer);
603 
604     EXPECT_BUFFER_U32_EQ(myData, buffer, 0);
605 }
606 
607 // Test mappedAtCreation for a large MapWrite buffer
TEST_P(BufferMappedAtCreationTests, MapWriteUsageLarge)608 TEST_P(BufferMappedAtCreationTests, MapWriteUsageLarge) {
609     constexpr uint64_t kDataSize = 1000 * 1000;
610     std::vector<uint32_t> myData;
611     for (uint32_t i = 0; i < kDataSize; ++i) {
612         myData.push_back(i);
613     }
614 
615     wgpu::Buffer buffer = BufferMappedAtCreationWithData(
616         wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc, {myData});
617     UnmapBuffer(buffer);
618 
619     EXPECT_BUFFER_U32_RANGE_EQ(myData.data(), buffer, 0, kDataSize);
620 }
621 
622 // Test mappedAtCreation for a large MapRead buffer
TEST_P(BufferMappedAtCreationTests, MapReadUsageLarge)623 TEST_P(BufferMappedAtCreationTests, MapReadUsageLarge) {
624     constexpr uint64_t kDataSize = 1000 * 1000;
625     std::vector<uint32_t> myData;
626     for (uint32_t i = 0; i < kDataSize; ++i) {
627         myData.push_back(i);
628     }
629 
630     wgpu::Buffer buffer = BufferMappedAtCreationWithData(wgpu::BufferUsage::MapRead, myData);
631     UnmapBuffer(buffer);
632 
633     const void* mappedData =
634         MapAsyncAndWait(buffer, wgpu::MapMode::Read, kDataSize * sizeof(uint32_t));
635     ASSERT_EQ(0, memcmp(mappedData, myData.data(), kDataSize * sizeof(uint32_t)));
636     UnmapBuffer(buffer);
637 }
638 
639 // Test mappedAtCreation for a large non-mappable buffer
TEST_P(BufferMappedAtCreationTests, NonMappableUsageLarge)640 TEST_P(BufferMappedAtCreationTests, NonMappableUsageLarge) {
641     constexpr uint64_t kDataSize = 1000 * 1000;
642     std::vector<uint32_t> myData;
643     for (uint32_t i = 0; i < kDataSize; ++i) {
644         myData.push_back(i);
645     }
646 
647     wgpu::Buffer buffer = BufferMappedAtCreationWithData(wgpu::BufferUsage::CopySrc, {myData});
648     UnmapBuffer(buffer);
649 
650     EXPECT_BUFFER_U32_RANGE_EQ(myData.data(), buffer, 0, kDataSize);
651 }
652 
653 // Test destroying a non-mappable buffer mapped at creation.
654 // This is a regression test for an issue where the D3D12 backend thought the buffer was actually
655 // mapped and tried to unlock the heap residency (when actually the buffer was using a staging
656 // buffer)
TEST_P(BufferMappedAtCreationTests, DestroyNonMappableWhileMappedForCreation)657 TEST_P(BufferMappedAtCreationTests, DestroyNonMappableWhileMappedForCreation) {
658     wgpu::Buffer buffer = BufferMappedAtCreation(wgpu::BufferUsage::CopySrc, 4);
659     buffer.Destroy();
660 }
661 
662 // Test destroying a mappable buffer mapped at creation.
TEST_P(BufferMappedAtCreationTests, DestroyMappableWhileMappedForCreation)663 TEST_P(BufferMappedAtCreationTests, DestroyMappableWhileMappedForCreation) {
664     wgpu::Buffer buffer = BufferMappedAtCreation(wgpu::BufferUsage::MapRead, 4);
665     buffer.Destroy();
666 }
667 
668 // Test that mapping a buffer is valid after mappedAtCreation and Unmap
TEST_P(BufferMappedAtCreationTests, CreateThenMapSuccess)669 TEST_P(BufferMappedAtCreationTests, CreateThenMapSuccess) {
670     static uint32_t myData = 230502;
671     wgpu::Buffer buffer = BufferMappedAtCreationWithData(
672         wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc, {myData});
673     UnmapBuffer(buffer);
674 
675     EXPECT_BUFFER_U32_EQ(myData, buffer, 0);
676 
677     bool done = false;
678     buffer.MapAsync(
679         wgpu::MapMode::Write, 0, 4,
680         [](WGPUBufferMapAsyncStatus status, void* userdata) {
681             ASSERT_EQ(WGPUBufferMapAsyncStatus_Success, status);
682             *static_cast<bool*>(userdata) = true;
683         },
684         &done);
685 
686     while (!done) {
687         WaitABit();
688     }
689 
690     UnmapBuffer(buffer);
691 }
692 
693 // Test that is is invalid to map a buffer twice when using mappedAtCreation
TEST_P(BufferMappedAtCreationTests, CreateThenMapBeforeUnmapFailure)694 TEST_P(BufferMappedAtCreationTests, CreateThenMapBeforeUnmapFailure) {
695     uint32_t myData = 230502;
696     wgpu::Buffer buffer = BufferMappedAtCreationWithData(
697         wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc, {myData});
698 
699     ASSERT_DEVICE_ERROR([&]() {
700         bool done = false;
701         buffer.MapAsync(
702             wgpu::MapMode::Write, 0, 4,
703             [](WGPUBufferMapAsyncStatus status, void* userdata) {
704                 ASSERT_EQ(WGPUBufferMapAsyncStatus_Error, status);
705                 *static_cast<bool*>(userdata) = true;
706             },
707             &done);
708 
709         while (!done) {
710             WaitABit();
711         }
712     }());
713 
714     // mappedAtCreation is unaffected by the MapWrite error.
715     UnmapBuffer(buffer);
716 }
717 
718 // Test that creating a zero-sized buffer mapped is allowed.
TEST_P(BufferMappedAtCreationTests, ZeroSized)719 TEST_P(BufferMappedAtCreationTests, ZeroSized) {
720     wgpu::BufferDescriptor descriptor;
721     descriptor.size = 0;
722     descriptor.usage = wgpu::BufferUsage::Vertex;
723     descriptor.mappedAtCreation = true;
724     wgpu::Buffer buffer = device.CreateBuffer(&descriptor);
725 
726     ASSERT_NE(nullptr, buffer.GetMappedRange());
727 
728     // Check that unmapping the buffer works too.
729     UnmapBuffer(buffer);
730 }
731 
732 // Test that creating a zero-sized mapppable buffer mapped. (it is a different code path)
TEST_P(BufferMappedAtCreationTests, ZeroSizedMappableBuffer)733 TEST_P(BufferMappedAtCreationTests, ZeroSizedMappableBuffer) {
734     wgpu::BufferDescriptor descriptor;
735     descriptor.size = 0;
736     descriptor.usage = wgpu::BufferUsage::MapWrite;
737     descriptor.mappedAtCreation = true;
738     wgpu::Buffer buffer = device.CreateBuffer(&descriptor);
739 
740     ASSERT_NE(nullptr, buffer.GetMappedRange());
741 
742     // Check that unmapping the buffer works too.
743     UnmapBuffer(buffer);
744 }
745 
746 // Test that creating a zero-sized error buffer mapped. (it is a different code path)
TEST_P(BufferMappedAtCreationTests, ZeroSizedErrorBuffer)747 TEST_P(BufferMappedAtCreationTests, ZeroSizedErrorBuffer) {
748     DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("skip_validation"));
749 
750     wgpu::BufferDescriptor descriptor;
751     descriptor.size = 0;
752     descriptor.usage = wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::Storage;
753     descriptor.mappedAtCreation = true;
754     wgpu::Buffer buffer;
755     ASSERT_DEVICE_ERROR(buffer = device.CreateBuffer(&descriptor));
756 
757     ASSERT_NE(nullptr, buffer.GetMappedRange());
758 }
759 
760 // Test the result of GetMappedRange when mapped at creation.
TEST_P(BufferMappedAtCreationTests, GetMappedRange)761 TEST_P(BufferMappedAtCreationTests, GetMappedRange) {
762     wgpu::BufferDescriptor descriptor;
763     descriptor.size = 4;
764     descriptor.usage = wgpu::BufferUsage::CopyDst;
765     descriptor.mappedAtCreation = true;
766     wgpu::Buffer buffer = device.CreateBuffer(&descriptor);
767 
768     ASSERT_EQ(buffer.GetMappedRange(), buffer.GetConstMappedRange());
769     ASSERT_NE(buffer.GetMappedRange(), nullptr);
770     buffer.Unmap();
771 }
772 
773 // Test the result of GetMappedRange when mapped at creation for a zero-sized buffer.
TEST_P(BufferMappedAtCreationTests, GetMappedRangeZeroSized)774 TEST_P(BufferMappedAtCreationTests, GetMappedRangeZeroSized) {
775     wgpu::BufferDescriptor descriptor;
776     descriptor.size = 0;
777     descriptor.usage = wgpu::BufferUsage::CopyDst;
778     descriptor.mappedAtCreation = true;
779     wgpu::Buffer buffer = device.CreateBuffer(&descriptor);
780 
781     ASSERT_EQ(buffer.GetMappedRange(), buffer.GetConstMappedRange());
782     ASSERT_NE(buffer.GetMappedRange(), nullptr);
783     buffer.Unmap();
784 }
785 
786 DAWN_INSTANTIATE_TEST(BufferMappedAtCreationTests,
787                       D3D12Backend(),
788                       D3D12Backend({}, {"use_d3d12_resource_heap_tier2"}),
789                       MetalBackend(),
790                       OpenGLBackend(),
791                       OpenGLESBackend(),
792                       VulkanBackend());
793 
794 class BufferTests : public DawnTest {};
795 
796 // Test that creating a zero-buffer is allowed.
TEST_P(BufferTests, ZeroSizedBuffer)797 TEST_P(BufferTests, ZeroSizedBuffer) {
798     wgpu::BufferDescriptor desc;
799     desc.size = 0;
800     desc.usage = wgpu::BufferUsage::CopyDst;
801     device.CreateBuffer(&desc);
802 }
803 
804 // Test that creating a very large buffers fails gracefully.
TEST_P(BufferTests, CreateBufferOOM)805 TEST_P(BufferTests, CreateBufferOOM) {
806     // TODO(http://crbug.com/dawn/749): Missing support.
807     DAWN_TEST_UNSUPPORTED_IF(IsOpenGL());
808     DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
809     DAWN_TEST_UNSUPPORTED_IF(IsAsan());
810 
811     wgpu::BufferDescriptor descriptor;
812     descriptor.usage = wgpu::BufferUsage::CopyDst;
813 
814     descriptor.size = std::numeric_limits<uint64_t>::max();
815     ASSERT_DEVICE_ERROR(device.CreateBuffer(&descriptor));
816 
817     // UINT64_MAX may be special cased. Test a smaller, but really large buffer also fails
818     descriptor.size = 1ull << 50;
819     ASSERT_DEVICE_ERROR(device.CreateBuffer(&descriptor));
820 }
821 
822 // Test that a very large buffer mappedAtCreation fails gracefully.
TEST_P(BufferTests, BufferMappedAtCreationOOM)823 TEST_P(BufferTests, BufferMappedAtCreationOOM) {
824     // TODO(http://crbug.com/dawn/749): Missing support.
825     DAWN_TEST_UNSUPPORTED_IF(IsOpenGL());
826     DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
827     DAWN_TEST_UNSUPPORTED_IF(IsAsan());
828 
829     // Test non-mappable buffer
830     {
831         wgpu::BufferDescriptor descriptor;
832         descriptor.size = 4;
833         descriptor.usage = wgpu::BufferUsage::CopyDst;
834         descriptor.mappedAtCreation = true;
835 
836         // Control: test a small buffer works.
837         device.CreateBuffer(&descriptor);
838 
839         // Test an enormous buffer fails
840         descriptor.size = std::numeric_limits<uint64_t>::max();
841         ASSERT_DEVICE_ERROR(device.CreateBuffer(&descriptor));
842 
843         // UINT64_MAX may be special cased. Test a smaller, but really large buffer also fails
844         descriptor.size = 1ull << 50;
845         ASSERT_DEVICE_ERROR(device.CreateBuffer(&descriptor));
846     }
847 
848     // Test mappable buffer
849     {
850         wgpu::BufferDescriptor descriptor;
851         descriptor.size = 4;
852         descriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::MapWrite;
853         descriptor.mappedAtCreation = true;
854 
855         // Control: test a small buffer works.
856         device.CreateBuffer(&descriptor);
857 
858         // Test an enormous buffer fails
859         descriptor.size = std::numeric_limits<uint64_t>::max();
860         ASSERT_DEVICE_ERROR(device.CreateBuffer(&descriptor));
861 
862         // UINT64_MAX may be special cased. Test a smaller, but really large buffer also fails
863         descriptor.size = 1ull << 50;
864         ASSERT_DEVICE_ERROR(device.CreateBuffer(&descriptor));
865     }
866 }
867 
868 // Test that mapping an OOM buffer fails gracefully
TEST_P(BufferTests, CreateBufferOOMMapAsync)869 TEST_P(BufferTests, CreateBufferOOMMapAsync) {
870     // TODO(http://crbug.com/dawn/749): Missing support.
871     DAWN_TEST_UNSUPPORTED_IF(IsOpenGL());
872     DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
873     DAWN_TEST_UNSUPPORTED_IF(IsAsan());
874 
875     auto RunTest = [this](const wgpu::BufferDescriptor& descriptor) {
876         wgpu::Buffer buffer;
877         ASSERT_DEVICE_ERROR(buffer = device.CreateBuffer(&descriptor));
878 
879         bool done = false;
880         ASSERT_DEVICE_ERROR(buffer.MapAsync(
881             wgpu::MapMode::Write, 0, 4,
882             [](WGPUBufferMapAsyncStatus status, void* userdata) {
883                 EXPECT_EQ(status, WGPUBufferMapAsyncStatus_Error);
884                 *static_cast<bool*>(userdata) = true;
885             },
886             &done));
887 
888         while (!done) {
889             WaitABit();
890         }
891     };
892 
893     wgpu::BufferDescriptor descriptor;
894     descriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::MapWrite;
895 
896     // Test an enormous buffer
897     descriptor.size = std::numeric_limits<uint64_t>::max();
898     RunTest(descriptor);
899 
900     // UINT64_MAX may be special cased. Test a smaller, but really large buffer also fails
901     descriptor.size = 1ull << 50;
902     RunTest(descriptor);
903 }
904 
905 DAWN_INSTANTIATE_TEST(BufferTests,
906                       D3D12Backend(),
907                       MetalBackend(),
908                       OpenGLBackend(),
909                       OpenGLESBackend(),
910                       VulkanBackend());
911