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