1 // Copyright 2019 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/wire/WireTest.h"
16
17 #include "dawn_wire/WireClient.h"
18
19 using namespace testing;
20 using namespace dawn_wire;
21
22 namespace {
23
24 // Mock class to add expectations on the wire calling callbacks
25 class MockBufferMapCallback {
26 public:
27 MOCK_METHOD(void,
28 Call,
29 (WGPUBufferMapAsyncStatus status,
30 void* userdata));
31 };
32
33 std::unique_ptr<StrictMock<MockBufferMapCallback>> mockBufferMapCallback;
ToMockBufferMapCallback(WGPUBufferMapAsyncStatus status,void * userdata)34 void ToMockBufferMapCallback(WGPUBufferMapAsyncStatus status, void* userdata) {
35 mockBufferMapCallback->Call(status, userdata);
36 }
37
38 } // anonymous namespace
39
40 class WireBufferMappingTests : public WireTest {
41 public:
WireBufferMappingTests()42 WireBufferMappingTests() {
43 }
44 ~WireBufferMappingTests() override = default;
45
SetUp()46 void SetUp() override {
47 WireTest::SetUp();
48
49 mockBufferMapCallback = std::make_unique<StrictMock<MockBufferMapCallback>>();
50 apiBuffer = api.GetNewBuffer();
51 }
52
TearDown()53 void TearDown() override {
54 WireTest::TearDown();
55
56 // Delete mock so that expectations are checked
57 mockBufferMapCallback = nullptr;
58 }
59
FlushClient()60 void FlushClient() {
61 WireTest::FlushClient();
62 Mock::VerifyAndClearExpectations(&mockBufferMapCallback);
63 }
64
FlushServer()65 void FlushServer() {
66 WireTest::FlushServer();
67 Mock::VerifyAndClearExpectations(&mockBufferMapCallback);
68 }
69
SetupBuffer(WGPUBufferUsageFlags usage)70 void SetupBuffer(WGPUBufferUsageFlags usage) {
71 WGPUBufferDescriptor descriptor = {};
72 descriptor.size = kBufferSize;
73 descriptor.usage = usage;
74
75 buffer = wgpuDeviceCreateBuffer(device, &descriptor);
76
77 EXPECT_CALL(api, DeviceCreateBuffer(apiDevice, _))
78 .WillOnce(Return(apiBuffer))
79 .RetiresOnSaturation();
80 FlushClient();
81 }
82
83 protected:
84 static constexpr uint64_t kBufferSize = sizeof(uint32_t);
85 // A successfully created buffer
86 WGPUBuffer buffer;
87 WGPUBuffer apiBuffer;
88 };
89
90 // Tests specific to mapping for reading
91 class WireBufferMappingReadTests : public WireBufferMappingTests {
92 public:
WireBufferMappingReadTests()93 WireBufferMappingReadTests() {
94 }
95 ~WireBufferMappingReadTests() override = default;
96
SetUp()97 void SetUp() override {
98 WireBufferMappingTests::SetUp();
99
100 SetupBuffer(WGPUBufferUsage_MapRead);
101 }
102 };
103
104 // Check mapping for reading a succesfully created buffer
TEST_F(WireBufferMappingReadTests,MappingForReadSuccessBuffer)105 TEST_F(WireBufferMappingReadTests, MappingForReadSuccessBuffer) {
106 wgpuBufferMapAsync(buffer, WGPUMapMode_Read, 0, kBufferSize, ToMockBufferMapCallback, nullptr);
107
108 uint32_t bufferContent = 31337;
109 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Read, 0, kBufferSize, _, _))
110 .WillOnce(InvokeWithoutArgs([&]() {
111 api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
112 }));
113 EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer, 0, kBufferSize))
114 .WillOnce(Return(&bufferContent));
115
116 FlushClient();
117
118 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_Success, _)).Times(1);
119
120 FlushServer();
121
122 EXPECT_EQ(bufferContent,
123 *static_cast<const uint32_t*>(wgpuBufferGetConstMappedRange(buffer, 0, kBufferSize)));
124
125 wgpuBufferUnmap(buffer);
126 EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1);
127
128 FlushClient();
129 }
130
131 // Check that things work correctly when a validation error happens when mapping the buffer for
132 // reading
TEST_F(WireBufferMappingReadTests,ErrorWhileMappingForRead)133 TEST_F(WireBufferMappingReadTests, ErrorWhileMappingForRead) {
134 wgpuBufferMapAsync(buffer, WGPUMapMode_Read, 0, kBufferSize, ToMockBufferMapCallback, nullptr);
135
136 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Read, 0, kBufferSize, _, _))
137 .WillOnce(InvokeWithoutArgs(
138 [&]() { api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Error); }));
139
140 FlushClient();
141
142 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_Error, _)).Times(1);
143
144 FlushServer();
145
146 EXPECT_EQ(nullptr, wgpuBufferGetConstMappedRange(buffer, 0, kBufferSize));
147 }
148
149 // Check that the map read callback is called with UNKNOWN when the buffer is destroyed before the
150 // request is finished
TEST_F(WireBufferMappingReadTests,DestroyBeforeReadRequestEnd)151 TEST_F(WireBufferMappingReadTests, DestroyBeforeReadRequestEnd) {
152 wgpuBufferMapAsync(buffer, WGPUMapMode_Read, 0, kBufferSize, ToMockBufferMapCallback, nullptr);
153
154 // Return success
155 uint32_t bufferContent = 0;
156 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Read, 0, kBufferSize, _, _))
157 .WillOnce(InvokeWithoutArgs([&]() {
158 api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
159 }));
160 EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer, 0, kBufferSize))
161 .WillOnce(Return(&bufferContent));
162
163 // Destroy before the client gets the success, so the callback is called with
164 // DestroyedBeforeCallback.
165 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_DestroyedBeforeCallback, _))
166 .Times(1);
167 wgpuBufferRelease(buffer);
168 EXPECT_CALL(api, BufferRelease(apiBuffer));
169
170 FlushClient();
171 FlushServer();
172 }
173
174 // Check the map read callback is called with "UnmappedBeforeCallback" when the map request would
175 // have worked, but Unmap was called
TEST_F(WireBufferMappingReadTests,UnmapCalledTooEarlyForRead)176 TEST_F(WireBufferMappingReadTests, UnmapCalledTooEarlyForRead) {
177 wgpuBufferMapAsync(buffer, WGPUMapMode_Read, 0, kBufferSize, ToMockBufferMapCallback, nullptr);
178
179 uint32_t bufferContent = 31337;
180 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Read, 0, kBufferSize, _, _))
181 .WillOnce(InvokeWithoutArgs([&]() {
182 api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
183 }));
184 EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer, 0, kBufferSize))
185 .WillOnce(Return(&bufferContent));
186
187 // Oh no! We are calling Unmap too early! However the callback gets fired only after we get
188 // an answer from the server.
189 wgpuBufferUnmap(buffer);
190 EXPECT_CALL(api, BufferUnmap(apiBuffer));
191
192 FlushClient();
193
194 // The callback shouldn't get called with success, even when the request succeeded on the
195 // server side
196 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_UnmappedBeforeCallback, _))
197 .Times(1);
198
199 FlushServer();
200 }
201
202 // Check that even if Unmap() was called early client-side, we correctly surface server-side
203 // validation errors.
TEST_F(WireBufferMappingReadTests,UnmapCalledTooEarlyForReadButServerSideError)204 TEST_F(WireBufferMappingReadTests, UnmapCalledTooEarlyForReadButServerSideError) {
205 wgpuBufferMapAsync(buffer, WGPUMapMode_Read, 0, kBufferSize, ToMockBufferMapCallback, nullptr);
206
207 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Read, 0, kBufferSize, _, _))
208 .WillOnce(InvokeWithoutArgs(
209 [&]() { api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Error); }));
210
211 // Oh no! We are calling Unmap too early! However the callback gets fired only after we get
212 // an answer from the server that the mapAsync call was an error.
213 wgpuBufferUnmap(buffer);
214 EXPECT_CALL(api, BufferUnmap(apiBuffer));
215
216 FlushClient();
217
218 // The callback should be called with the server-side error and not the UnmappedBeforeCallback.
219 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_Error, _))
220 .Times(1);
221
222 FlushServer();
223 }
224
225 // Check the map read callback is called with "DestroyedBeforeCallback" when the map request would
226 // have worked, but Destroy was called
TEST_F(WireBufferMappingReadTests,DestroyCalledTooEarlyForRead)227 TEST_F(WireBufferMappingReadTests, DestroyCalledTooEarlyForRead) {
228 wgpuBufferMapAsync(buffer, WGPUMapMode_Read, 0, kBufferSize, ToMockBufferMapCallback, nullptr);
229
230 uint32_t bufferContent = 31337;
231 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Read, 0, kBufferSize, _, _))
232 .WillOnce(InvokeWithoutArgs([&]() {
233 api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
234 }));
235 EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer, 0, kBufferSize))
236 .WillOnce(Return(&bufferContent));
237
238 // Oh no! We are calling Unmap too early! However the callback gets fired only after we get
239 // an answer from the server.
240 wgpuBufferDestroy(buffer);
241 EXPECT_CALL(api, BufferDestroy(apiBuffer));
242
243 FlushClient();
244
245 // The callback shouldn't get called with success, even when the request succeeded on the
246 // server side
247 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_DestroyedBeforeCallback, _))
248 .Times(1);
249
250 FlushServer();
251 }
252
253 // Check that even if Destroy() was called early client-side, we correctly surface server-side
254 // validation errors.
TEST_F(WireBufferMappingReadTests,DestroyCalledTooEarlyForReadButServerSideError)255 TEST_F(WireBufferMappingReadTests, DestroyCalledTooEarlyForReadButServerSideError) {
256 wgpuBufferMapAsync(buffer, WGPUMapMode_Read, 0, kBufferSize, ToMockBufferMapCallback, nullptr);
257
258 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Read, 0, kBufferSize, _, _))
259 .WillOnce(InvokeWithoutArgs(
260 [&]() { api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Error); }));
261
262 // Oh no! We are calling Destroy too early! However the callback gets fired only after we get
263 // an answer from the server that the mapAsync call was an error.
264 wgpuBufferDestroy(buffer);
265 EXPECT_CALL(api, BufferDestroy(apiBuffer));
266
267 FlushClient();
268
269 // The callback should be called with the server-side error and not the DestroyedBeforCallback..
270 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_Error, _))
271 .Times(1);
272
273 FlushServer();
274 }
275
276 // Check that an error map read while a buffer is already mapped won't changed the result of get
277 // mapped range
TEST_F(WireBufferMappingReadTests,MappingForReadingErrorWhileAlreadyMappedUnchangeMapData)278 TEST_F(WireBufferMappingReadTests, MappingForReadingErrorWhileAlreadyMappedUnchangeMapData) {
279 // Successful map
280 wgpuBufferMapAsync(buffer, WGPUMapMode_Read, 0, kBufferSize, ToMockBufferMapCallback, nullptr);
281
282 uint32_t bufferContent = 31337;
283 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Read, 0, kBufferSize, _, _))
284 .WillOnce(InvokeWithoutArgs([&]() {
285 api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
286 }));
287 EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer, 0, kBufferSize))
288 .WillOnce(Return(&bufferContent));
289
290 FlushClient();
291
292 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_Success, _)).Times(1);
293
294 FlushServer();
295
296 // Map failure while the buffer is already mapped
297 wgpuBufferMapAsync(buffer, WGPUMapMode_Read, 0, kBufferSize, ToMockBufferMapCallback, nullptr);
298 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Read, 0, kBufferSize, _, _))
299 .WillOnce(InvokeWithoutArgs(
300 [&]() { api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Error); }));
301
302 FlushClient();
303
304 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_Error, _)).Times(1);
305
306 FlushServer();
307
308 EXPECT_EQ(bufferContent,
309 *static_cast<const uint32_t*>(wgpuBufferGetConstMappedRange(buffer, 0, kBufferSize)));
310 }
311
312 // Test that the MapReadCallback isn't fired twice when unmap() is called inside the callback
TEST_F(WireBufferMappingReadTests,UnmapInsideMapReadCallback)313 TEST_F(WireBufferMappingReadTests, UnmapInsideMapReadCallback) {
314 wgpuBufferMapAsync(buffer, WGPUMapMode_Read, 0, kBufferSize, ToMockBufferMapCallback, nullptr);
315
316 uint32_t bufferContent = 31337;
317 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Read, 0, kBufferSize, _, _))
318 .WillOnce(InvokeWithoutArgs([&]() {
319 api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
320 }));
321 EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer, 0, kBufferSize))
322 .WillOnce(Return(&bufferContent));
323
324 FlushClient();
325
326 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
327 .WillOnce(InvokeWithoutArgs([&]() { wgpuBufferUnmap(buffer); }));
328
329 FlushServer();
330
331 EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1);
332
333 FlushClient();
334 }
335
336 // Test that the MapReadCallback isn't fired twice the buffer external refcount reaches 0 in the
337 // callback
TEST_F(WireBufferMappingReadTests,DestroyInsideMapReadCallback)338 TEST_F(WireBufferMappingReadTests, DestroyInsideMapReadCallback) {
339 wgpuBufferMapAsync(buffer, WGPUMapMode_Read, 0, kBufferSize, ToMockBufferMapCallback, nullptr);
340
341 uint32_t bufferContent = 31337;
342 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Read, 0, kBufferSize, _, _))
343 .WillOnce(InvokeWithoutArgs([&]() {
344 api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
345 }));
346 EXPECT_CALL(api, BufferGetConstMappedRange(apiBuffer, 0, kBufferSize))
347 .WillOnce(Return(&bufferContent));
348
349 FlushClient();
350
351 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
352 .WillOnce(InvokeWithoutArgs([&]() { wgpuBufferRelease(buffer); }));
353
354 FlushServer();
355
356 EXPECT_CALL(api, BufferRelease(apiBuffer));
357
358 FlushClient();
359 }
360
361 // Tests specific to mapping for writing
362 class WireBufferMappingWriteTests : public WireBufferMappingTests {
363 public:
WireBufferMappingWriteTests()364 WireBufferMappingWriteTests() {
365 }
366 ~WireBufferMappingWriteTests() override = default;
367
SetUp()368 void SetUp() override {
369 WireBufferMappingTests::SetUp();
370
371 SetupBuffer(WGPUBufferUsage_MapWrite);
372 }
373 };
374
375 // Check mapping for writing a succesfully created buffer
TEST_F(WireBufferMappingWriteTests,MappingForWriteSuccessBuffer)376 TEST_F(WireBufferMappingWriteTests, MappingForWriteSuccessBuffer) {
377 wgpuBufferMapAsync(buffer, WGPUMapMode_Write, 0, kBufferSize, ToMockBufferMapCallback, nullptr);
378
379 uint32_t serverBufferContent = 31337;
380 uint32_t updatedContent = 4242;
381
382 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _, _))
383 .WillOnce(InvokeWithoutArgs([&]() {
384 api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
385 }));
386 EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize))
387 .WillOnce(Return(&serverBufferContent));
388
389 FlushClient();
390
391 // The map write callback always gets a buffer full of zeroes.
392 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_Success, _)).Times(1);
393
394 FlushServer();
395
396 uint32_t* lastMapWritePointer =
397 static_cast<uint32_t*>(wgpuBufferGetMappedRange(buffer, 0, kBufferSize));
398 ASSERT_EQ(0u, *lastMapWritePointer);
399
400 // Write something to the mapped pointer
401 *lastMapWritePointer = updatedContent;
402
403 wgpuBufferUnmap(buffer);
404 EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1);
405
406 FlushClient();
407
408 // After the buffer is unmapped, the content of the buffer is updated on the server
409 ASSERT_EQ(serverBufferContent, updatedContent);
410 }
411
412 // Check that things work correctly when a validation error happens when mapping the buffer for
413 // writing
TEST_F(WireBufferMappingWriteTests,ErrorWhileMappingForWrite)414 TEST_F(WireBufferMappingWriteTests, ErrorWhileMappingForWrite) {
415 wgpuBufferMapAsync(buffer, WGPUMapMode_Write, 0, kBufferSize, ToMockBufferMapCallback, nullptr);
416
417 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _, _))
418 .WillOnce(InvokeWithoutArgs(
419 [&]() { api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Error); }));
420
421 FlushClient();
422
423 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_Error, _)).Times(1);
424
425 FlushServer();
426
427 EXPECT_EQ(nullptr, wgpuBufferGetMappedRange(buffer, 0, kBufferSize));
428 }
429
430 // Check that the map write callback is called with "DestroyedBeforeCallback" when the buffer is
431 // destroyed before the request is finished
TEST_F(WireBufferMappingWriteTests,DestroyBeforeWriteRequestEnd)432 TEST_F(WireBufferMappingWriteTests, DestroyBeforeWriteRequestEnd) {
433 wgpuBufferMapAsync(buffer, WGPUMapMode_Write, 0, kBufferSize, ToMockBufferMapCallback, nullptr);
434
435 // Return success
436 uint32_t bufferContent = 31337;
437 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _, _))
438 .WillOnce(InvokeWithoutArgs([&]() {
439 api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
440 }));
441 EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize))
442 .WillOnce(Return(&bufferContent));
443
444 // Destroy before the client gets the success, so the callback is called with
445 // DestroyedBeforeCallback.
446 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_DestroyedBeforeCallback, _))
447 .Times(1);
448 wgpuBufferRelease(buffer);
449 EXPECT_CALL(api, BufferRelease(apiBuffer));
450
451 FlushClient();
452 FlushServer();
453 }
454
455 // Check the map write callback is called with "UnmappedBeforeCallback" when the map request would
456 // have worked, but Unmap was called
TEST_F(WireBufferMappingWriteTests,UnmapCalledTooEarlyForWrite)457 TEST_F(WireBufferMappingWriteTests, UnmapCalledTooEarlyForWrite) {
458 wgpuBufferMapAsync(buffer, WGPUMapMode_Write, 0, kBufferSize, ToMockBufferMapCallback, nullptr);
459
460 uint32_t bufferContent = 31337;
461 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _, _))
462 .WillOnce(InvokeWithoutArgs([&]() {
463 api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
464 }));
465 EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize))
466 .WillOnce(Return(&bufferContent));
467
468 FlushClient();
469
470 // Oh no! We are calling Unmap too early!
471 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_UnmappedBeforeCallback, _))
472 .Times(1);
473 wgpuBufferUnmap(buffer);
474
475 // The callback shouldn't get called, even when the request succeeded on the server side
476 FlushServer();
477 }
478
479 // Check that an error map write while a buffer is already mapped
TEST_F(WireBufferMappingWriteTests,MappingForWritingErrorWhileAlreadyMapped)480 TEST_F(WireBufferMappingWriteTests, MappingForWritingErrorWhileAlreadyMapped) {
481 // Successful map
482 wgpuBufferMapAsync(buffer, WGPUMapMode_Write, 0, kBufferSize, ToMockBufferMapCallback, nullptr);
483
484 uint32_t bufferContent = 31337;
485 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _, _))
486 .WillOnce(InvokeWithoutArgs([&]() {
487 api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
488 }));
489 EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize))
490 .WillOnce(Return(&bufferContent));
491
492 FlushClient();
493
494 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_Success, _)).Times(1);
495
496 FlushServer();
497
498 // Map failure while the buffer is already mapped
499 wgpuBufferMapAsync(buffer, WGPUMapMode_Write, 0, kBufferSize, ToMockBufferMapCallback, nullptr);
500 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _, _))
501 .WillOnce(InvokeWithoutArgs(
502 [&]() { api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Error); }));
503
504 FlushClient();
505
506 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_Error, _)).Times(1);
507
508 FlushServer();
509
510 EXPECT_NE(nullptr,
511 static_cast<const uint32_t*>(wgpuBufferGetConstMappedRange(buffer, 0, kBufferSize)));
512 }
513
514 // Test that the MapWriteCallback isn't fired twice when unmap() is called inside the callback
TEST_F(WireBufferMappingWriteTests,UnmapInsideMapWriteCallback)515 TEST_F(WireBufferMappingWriteTests, UnmapInsideMapWriteCallback) {
516 wgpuBufferMapAsync(buffer, WGPUMapMode_Write, 0, kBufferSize, ToMockBufferMapCallback, nullptr);
517
518 uint32_t bufferContent = 31337;
519 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _, _))
520 .WillOnce(InvokeWithoutArgs([&]() {
521 api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
522 }));
523 EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize))
524 .WillOnce(Return(&bufferContent));
525
526 FlushClient();
527
528 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
529 .WillOnce(InvokeWithoutArgs([&]() { wgpuBufferUnmap(buffer); }));
530
531 FlushServer();
532
533 EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1);
534
535 FlushClient();
536 }
537
538 // Test that the MapWriteCallback isn't fired twice the buffer external refcount reaches 0 in the
539 // callback
TEST_F(WireBufferMappingWriteTests,DestroyInsideMapWriteCallback)540 TEST_F(WireBufferMappingWriteTests, DestroyInsideMapWriteCallback) {
541 wgpuBufferMapAsync(buffer, WGPUMapMode_Write, 0, kBufferSize, ToMockBufferMapCallback, nullptr);
542
543 uint32_t bufferContent = 31337;
544 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _, _))
545 .WillOnce(InvokeWithoutArgs([&]() {
546 api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
547 }));
548 EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize))
549 .WillOnce(Return(&bufferContent));
550
551 FlushClient();
552
553 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_Success, _))
554 .WillOnce(InvokeWithoutArgs([&]() { wgpuBufferRelease(buffer); }));
555
556 FlushServer();
557
558 EXPECT_CALL(api, BufferRelease(apiBuffer));
559
560 FlushClient();
561 }
562
563 // Test successful buffer creation with mappedAtCreation=true
TEST_F(WireBufferMappingTests,MappedAtCreationSuccess)564 TEST_F(WireBufferMappingTests, MappedAtCreationSuccess) {
565 WGPUBufferDescriptor descriptor = {};
566 descriptor.size = 4;
567 descriptor.mappedAtCreation = true;
568
569 WGPUBuffer apiBuffer = api.GetNewBuffer();
570 uint32_t apiBufferData = 1234;
571
572 WGPUBuffer buffer = wgpuDeviceCreateBuffer(device, &descriptor);
573
574 EXPECT_CALL(api, DeviceCreateBuffer(apiDevice, _)).WillOnce(Return(apiBuffer));
575 EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, 4)).WillOnce(Return(&apiBufferData));
576
577 FlushClient();
578
579 wgpuBufferUnmap(buffer);
580 EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1);
581
582 FlushClient();
583 }
584
585 // Test that releasing a buffer mapped at creation does not call Unmap
TEST_F(WireBufferMappingTests,MappedAtCreationReleaseBeforeUnmap)586 TEST_F(WireBufferMappingTests, MappedAtCreationReleaseBeforeUnmap) {
587 WGPUBufferDescriptor descriptor = {};
588 descriptor.size = 4;
589 descriptor.mappedAtCreation = true;
590
591 WGPUBuffer apiBuffer = api.GetNewBuffer();
592 uint32_t apiBufferData = 1234;
593
594 WGPUBuffer buffer = wgpuDeviceCreateBuffer(device, &descriptor);
595
596 EXPECT_CALL(api, DeviceCreateBuffer(apiDevice, _)).WillOnce(Return(apiBuffer));
597 EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, 4)).WillOnce(Return(&apiBufferData));
598
599 FlushClient();
600
601 wgpuBufferRelease(buffer);
602 EXPECT_CALL(api, BufferRelease(apiBuffer)).Times(1);
603
604 FlushClient();
605 }
606
607 // Test that it is valid to map a buffer after it is mapped at creation and unmapped
TEST_F(WireBufferMappingTests,MappedAtCreationThenMapSuccess)608 TEST_F(WireBufferMappingTests, MappedAtCreationThenMapSuccess) {
609 WGPUBufferDescriptor descriptor = {};
610 descriptor.size = 4;
611 descriptor.usage = WGPUMapMode_Write;
612 descriptor.mappedAtCreation = true;
613
614 WGPUBuffer apiBuffer = api.GetNewBuffer();
615 uint32_t apiBufferData = 1234;
616
617 WGPUBuffer buffer = wgpuDeviceCreateBuffer(device, &descriptor);
618
619 EXPECT_CALL(api, DeviceCreateBuffer(apiDevice, _)).WillOnce(Return(apiBuffer));
620 EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, 4)).WillOnce(Return(&apiBufferData));
621
622 FlushClient();
623
624 wgpuBufferUnmap(buffer);
625 EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1);
626
627 FlushClient();
628
629 wgpuBufferMapAsync(buffer, WGPUMapMode_Write, 0, kBufferSize, ToMockBufferMapCallback, nullptr);
630
631 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _, _))
632 .WillOnce(InvokeWithoutArgs([&]() {
633 api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
634 }));
635 EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize))
636 .WillOnce(Return(&apiBufferData));
637
638 FlushClient();
639
640 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_Success, _)).Times(1);
641
642 FlushServer();
643 }
644
645 // Test that it is invalid to map a buffer after mappedAtCreation but before Unmap
TEST_F(WireBufferMappingTests,MappedAtCreationThenMapFailure)646 TEST_F(WireBufferMappingTests, MappedAtCreationThenMapFailure) {
647 WGPUBufferDescriptor descriptor = {};
648 descriptor.size = 4;
649 descriptor.mappedAtCreation = true;
650
651 WGPUBuffer apiBuffer = api.GetNewBuffer();
652 uint32_t apiBufferData = 1234;
653
654 WGPUBuffer buffer = wgpuDeviceCreateBuffer(device, &descriptor);
655
656 EXPECT_CALL(api, DeviceCreateBuffer(apiDevice, _)).WillOnce(Return(apiBuffer));
657 EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, 4)).WillOnce(Return(&apiBufferData));
658
659 FlushClient();
660
661 wgpuBufferMapAsync(buffer, WGPUMapMode_Write, 0, kBufferSize, ToMockBufferMapCallback, nullptr);
662
663 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _, _))
664 .WillOnce(InvokeWithoutArgs(
665 [&]() { api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Error); }));
666
667 FlushClient();
668
669 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_Error, _)).Times(1);
670
671 FlushServer();
672
673 EXPECT_NE(nullptr,
674 static_cast<const uint32_t*>(wgpuBufferGetConstMappedRange(buffer, 0, kBufferSize)));
675
676 wgpuBufferUnmap(buffer);
677 EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1);
678
679 FlushClient();
680 }
681
682 // Check that trying to create a buffer of size MAX_SIZE_T is an error handling in the client and
683 // never gets to the server-side.
TEST_F(WireBufferMappingTests,MaxSizeMappableBufferOOMDirectly)684 TEST_F(WireBufferMappingTests, MaxSizeMappableBufferOOMDirectly) {
685 size_t kOOMSize = std::numeric_limits<size_t>::max();
686 WGPUBuffer apiBuffer = api.GetNewBuffer();
687
688 // Check for CreateBufferMapped.
689 {
690 WGPUBufferDescriptor descriptor = {};
691 descriptor.usage = WGPUBufferUsage_CopySrc;
692 descriptor.size = kOOMSize;
693 descriptor.mappedAtCreation = true;
694
695 wgpuDeviceCreateBuffer(device, &descriptor);
696 EXPECT_CALL(api, DeviceInjectError(apiDevice, WGPUErrorType_OutOfMemory, _));
697 EXPECT_CALL(api, DeviceCreateErrorBuffer(apiDevice)).WillOnce(Return(apiBuffer));
698 FlushClient();
699 }
700
701 // Check for MapRead usage.
702 {
703 WGPUBufferDescriptor descriptor = {};
704 descriptor.usage = WGPUBufferUsage_MapRead;
705 descriptor.size = kOOMSize;
706
707 wgpuDeviceCreateBuffer(device, &descriptor);
708 EXPECT_CALL(api, DeviceInjectError(apiDevice, WGPUErrorType_OutOfMemory, _));
709 EXPECT_CALL(api, DeviceCreateErrorBuffer(apiDevice)).WillOnce(Return(apiBuffer));
710 FlushClient();
711 }
712
713 // Check for MapWrite usage.
714 {
715 WGPUBufferDescriptor descriptor = {};
716 descriptor.usage = WGPUBufferUsage_MapWrite;
717 descriptor.size = kOOMSize;
718
719 wgpuDeviceCreateBuffer(device, &descriptor);
720 EXPECT_CALL(api, DeviceInjectError(apiDevice, WGPUErrorType_OutOfMemory, _));
721 EXPECT_CALL(api, DeviceCreateErrorBuffer(apiDevice)).WillOnce(Return(apiBuffer));
722 FlushClient();
723 }
724 }
725
726 // Test that registering a callback then wire disconnect calls the callback with
727 // DeviceLost.
TEST_F(WireBufferMappingTests,MapThenDisconnect)728 TEST_F(WireBufferMappingTests, MapThenDisconnect) {
729 SetupBuffer(WGPUMapMode_Write);
730 wgpuBufferMapAsync(buffer, WGPUMapMode_Write, 0, kBufferSize, ToMockBufferMapCallback, this);
731
732 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _, _))
733 .WillOnce(InvokeWithoutArgs([&]() {
734 api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
735 }));
736 EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize)).Times(1);
737
738 FlushClient();
739
740 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_DeviceLost, this)).Times(1);
741 GetWireClient()->Disconnect();
742 }
743
744 // Test that registering a callback after wire disconnect calls the callback with
745 // DeviceLost.
TEST_F(WireBufferMappingTests,MapAfterDisconnect)746 TEST_F(WireBufferMappingTests, MapAfterDisconnect) {
747 SetupBuffer(WGPUMapMode_Read);
748
749 GetWireClient()->Disconnect();
750
751 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_DeviceLost, this)).Times(1);
752 wgpuBufferMapAsync(buffer, WGPUMapMode_Read, 0, kBufferSize, ToMockBufferMapCallback, this);
753 }
754
755 // Hack to pass in test context into user callback
756 struct TestData {
757 WireBufferMappingTests* pTest;
758 WGPUBuffer* pTestBuffer;
759 size_t numRequests;
760 };
761
ToMockBufferMapCallbackWithNewRequests(WGPUBufferMapAsyncStatus status,void * userdata)762 static void ToMockBufferMapCallbackWithNewRequests(WGPUBufferMapAsyncStatus status,
763 void* userdata) {
764 TestData* testData = reinterpret_cast<TestData*>(userdata);
765 // Mimic the user callback is sending new requests
766 ASSERT_NE(testData, nullptr);
767 ASSERT_NE(testData->pTest, nullptr);
768 ASSERT_NE(testData->pTestBuffer, nullptr);
769
770 mockBufferMapCallback->Call(status, testData->pTest);
771
772 // Send the requests a number of times
773 for (size_t i = 0; i < testData->numRequests; i++) {
774 wgpuBufferMapAsync(*(testData->pTestBuffer), WGPUMapMode_Write, 0, sizeof(uint32_t),
775 ToMockBufferMapCallback, testData->pTest);
776 }
777 }
778
779 // Test that requests inside user callbacks before disconnect are called
TEST_F(WireBufferMappingTests,MapInsideCallbackBeforeDisconnect)780 TEST_F(WireBufferMappingTests, MapInsideCallbackBeforeDisconnect) {
781 SetupBuffer(WGPUMapMode_Write);
782 TestData testData = {this, &buffer, 10};
783 wgpuBufferMapAsync(buffer, WGPUMapMode_Write, 0, kBufferSize,
784 ToMockBufferMapCallbackWithNewRequests, &testData);
785
786 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _, _))
787 .WillOnce(InvokeWithoutArgs([&]() {
788 api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
789 }));
790 EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize)).Times(1);
791
792 FlushClient();
793
794 EXPECT_CALL(*mockBufferMapCallback, Call(WGPUBufferMapAsyncStatus_DeviceLost, this))
795 .Times(1 + testData.numRequests);
796 GetWireClient()->Disconnect();
797 }
798
799 // Test that requests inside user callbacks before object destruction are called
TEST_F(WireBufferMappingWriteTests,MapInsideCallbackBeforeDestruction)800 TEST_F(WireBufferMappingWriteTests, MapInsideCallbackBeforeDestruction) {
801 TestData testData = {this, &buffer, 10};
802 wgpuBufferMapAsync(buffer, WGPUMapMode_Write, 0, kBufferSize,
803 ToMockBufferMapCallbackWithNewRequests, &testData);
804
805 EXPECT_CALL(api, OnBufferMapAsync(apiBuffer, WGPUMapMode_Write, 0, kBufferSize, _, _))
806 .WillOnce(InvokeWithoutArgs([&]() {
807 api.CallBufferMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Success);
808 }));
809 EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, kBufferSize)).Times(1);
810
811 FlushClient();
812
813 EXPECT_CALL(*mockBufferMapCallback,
814 Call(WGPUBufferMapAsyncStatus_DestroyedBeforeCallback, this))
815 .Times(1 + testData.numRequests);
816 wgpuBufferRelease(buffer);
817 }