Implement CreateBufferMappedAsync in dawn_wire and dawn_native

Bug: dawn:7
Change-Id: I1a4e5eece53d83a4c5395ba6b41df2e20668c5bb
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/8120
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Austin Eng
2019-06-14 17:35:56 +00:00
committed by Commit Bot service account
parent d1b4b5cba5
commit 21eba761b5
11 changed files with 596 additions and 97 deletions

View File

@@ -226,6 +226,7 @@ DAWN_INSTANTIATE_TEST(BufferSetSubDataTests,
OpenGLBackend,
VulkanBackend);
// TODO(enga): These tests should use the testing toggle to initialize resources to 1.
class CreateBufferMappedTests : public DawnTest {
protected:
static void MapReadCallback(DawnBufferMapAsyncStatus status,
@@ -248,37 +249,97 @@ class CreateBufferMappedTests : public DawnTest {
return mappedData;
}
void CheckResultStartsZeroed(const dawn::CreateBufferMappedResult& result, uint64_t size) {
ASSERT_EQ(result.dataLength, size);
for (uint64_t i = 0; i < result.dataLength; ++i) {
uint8_t value = *(reinterpret_cast<uint8_t*>(result.data) + i);
ASSERT_EQ(value, 0u);
}
}
dawn::CreateBufferMappedResult CreateBufferMapped(dawn::BufferUsageBit usage, uint64_t size) {
dawn::BufferDescriptor descriptor;
descriptor.nextInChain = nullptr;
descriptor.size = size;
descriptor.usage = usage;
dawn::CreateBufferMappedResult result = device.CreateBufferMapped(&descriptor);
CheckResultStartsZeroed(result, size);
return result;
}
dawn::CreateBufferMappedResult CreateBufferMappedWithData(dawn::BufferUsageBit usage,
const std::vector<uint32_t>& data) {
size_t byteLength = data.size() * sizeof(uint32_t);
dawn::CreateBufferMappedResult result = CreateBufferMapped(usage, byteLength);
memcpy(result.data, data.data(), byteLength);
return result;
}
template <DawnBufferMapAsyncStatus expectedStatus = DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS>
dawn::CreateBufferMappedResult CreateBufferMappedAsyncAndWait(dawn::BufferUsageBit usage,
uint64_t size) {
dawn::BufferDescriptor descriptor;
descriptor.nextInChain = nullptr;
descriptor.size = size;
descriptor.usage = usage;
struct ResultInfo {
dawn::CreateBufferMappedResult result;
bool done = false;
} resultInfo;
device.CreateBufferMappedAsync(
&descriptor,
[](DawnBufferMapAsyncStatus status, DawnCreateBufferMappedResult result,
void* userdata) {
ASSERT_EQ(status, expectedStatus);
auto* resultInfo = reinterpret_cast<ResultInfo*>(userdata);
resultInfo->result.buffer = dawn::Buffer::Acquire(result.buffer);
resultInfo->result.data = result.data;
resultInfo->result.dataLength = result.dataLength;
resultInfo->done = true;
},
&resultInfo);
while (!resultInfo.done) {
WaitABit();
}
CheckResultStartsZeroed(resultInfo.result, size);
return resultInfo.result;
}
dawn::CreateBufferMappedResult CreateBufferMappedAsyncWithDataAndWait(
dawn::BufferUsageBit usage,
const std::vector<uint32_t>& data) {
size_t byteLength = data.size() * sizeof(uint32_t);
dawn::CreateBufferMappedResult result = CreateBufferMappedAsyncAndWait(usage, byteLength);
memcpy(result.data, data.data(), byteLength);
return result;
}
private:
const void* mappedData = nullptr;
};
// Test that the simplest CreateBufferMapped works for MapWrite buffers.
TEST_P(CreateBufferMappedTests, MapWriteUsageSmall) {
dawn::BufferDescriptor descriptor;
descriptor.nextInChain = nullptr;
descriptor.size = 4;
descriptor.usage = dawn::BufferUsageBit::MapWrite | dawn::BufferUsageBit::TransferSrc;
uint32_t myData = 230502;
dawn::CreateBufferMappedResult result = device.CreateBufferMapped(&descriptor);
ASSERT_EQ(result.dataLength, descriptor.size);
memcpy(result.data, &myData, sizeof(myData));
dawn::CreateBufferMappedResult result = CreateBufferMappedWithData(
dawn::BufferUsageBit::MapWrite | dawn::BufferUsageBit::TransferSrc, {myData});
result.buffer.Unmap();
EXPECT_BUFFER_U32_EQ(myData, result.buffer, 0);
}
// Test that the simplest CreateBufferMapped works for MapRead buffers.
TEST_P(CreateBufferMappedTests, MapReadUsageSmall) {
dawn::BufferDescriptor descriptor;
descriptor.nextInChain = nullptr;
descriptor.size = 4;
descriptor.usage = dawn::BufferUsageBit::MapRead;
uint32_t myData = 230502;
dawn::CreateBufferMappedResult result = device.CreateBufferMapped(&descriptor);
ASSERT_EQ(result.dataLength, descriptor.size);
memcpy(result.data, &myData, sizeof(myData));
dawn::CreateBufferMappedResult result =
CreateBufferMappedWithData(dawn::BufferUsageBit::MapRead, {myData});
result.buffer.Unmap();
const void* mappedData = MapReadAsyncAndWait(result.buffer);
@@ -288,15 +349,9 @@ TEST_P(CreateBufferMappedTests, MapReadUsageSmall) {
// Test that the simplest CreateBufferMapped works for non-mappable buffers.
TEST_P(CreateBufferMappedTests, NonMappableUsageSmall) {
dawn::BufferDescriptor descriptor;
descriptor.nextInChain = nullptr;
descriptor.size = 4;
descriptor.usage = dawn::BufferUsageBit::TransferSrc;
uint32_t myData = 4239;
dawn::CreateBufferMappedResult result = device.CreateBufferMapped(&descriptor);
ASSERT_EQ(result.dataLength, descriptor.size);
memcpy(result.data, &myData, sizeof(myData));
dawn::CreateBufferMappedResult result =
CreateBufferMappedWithData(dawn::BufferUsageBit::TransferSrc, {myData});
result.buffer.Unmap();
EXPECT_BUFFER_U32_EQ(myData, result.buffer, 0);
@@ -310,14 +365,8 @@ TEST_P(CreateBufferMappedTests, MapWriteUsageLarge) {
myData.push_back(i);
}
dawn::BufferDescriptor descriptor;
descriptor.nextInChain = nullptr;
descriptor.size = static_cast<uint64_t>(kDataSize * sizeof(uint32_t));
descriptor.usage = dawn::BufferUsageBit::MapWrite | dawn::BufferUsageBit::TransferSrc;
dawn::CreateBufferMappedResult result = device.CreateBufferMapped(&descriptor);
ASSERT_EQ(result.dataLength, descriptor.size);
memcpy(result.data, myData.data(), kDataSize * sizeof(uint32_t));
dawn::CreateBufferMappedResult result = CreateBufferMappedWithData(
dawn::BufferUsageBit::MapWrite | dawn::BufferUsageBit::TransferSrc, {myData});
result.buffer.Unmap();
EXPECT_BUFFER_U32_RANGE_EQ(myData.data(), result.buffer, 0, kDataSize);
@@ -331,14 +380,8 @@ TEST_P(CreateBufferMappedTests, MapReadUsageLarge) {
myData.push_back(i);
}
dawn::BufferDescriptor descriptor;
descriptor.nextInChain = nullptr;
descriptor.size = static_cast<uint64_t>(kDataSize * sizeof(uint32_t));
descriptor.usage = dawn::BufferUsageBit::MapRead;
dawn::CreateBufferMappedResult result = device.CreateBufferMapped(&descriptor);
ASSERT_EQ(result.dataLength, descriptor.size);
memcpy(result.data, myData.data(), kDataSize * sizeof(uint32_t));
dawn::CreateBufferMappedResult result =
CreateBufferMappedWithData(dawn::BufferUsageBit::MapRead, myData);
result.buffer.Unmap();
const void* mappedData = MapReadAsyncAndWait(result.buffer);
@@ -354,59 +397,19 @@ TEST_P(CreateBufferMappedTests, NonMappableUsageLarge) {
myData.push_back(i);
}
dawn::BufferDescriptor descriptor;
descriptor.nextInChain = nullptr;
descriptor.size = static_cast<uint64_t>(kDataSize * sizeof(uint32_t));
descriptor.usage = dawn::BufferUsageBit::TransferSrc;
dawn::CreateBufferMappedResult result = device.CreateBufferMapped(&descriptor);
ASSERT_EQ(result.dataLength, descriptor.size);
memcpy(result.data, myData.data(), kDataSize * sizeof(uint32_t));
dawn::CreateBufferMappedResult result =
CreateBufferMappedWithData(dawn::BufferUsageBit::TransferSrc, {myData});
result.buffer.Unmap();
EXPECT_BUFFER_U32_RANGE_EQ(myData.data(), result.buffer, 0, kDataSize);
}
// Test that CreateBufferMapped returns zero-initialized data
// TODO(enga): This should use the testing toggle to initialize resources to 1.
TEST_P(CreateBufferMappedTests, MappableZeroInitialized) {
dawn::BufferDescriptor descriptor;
descriptor.nextInChain = nullptr;
descriptor.size = 4;
descriptor.usage = dawn::BufferUsageBit::MapWrite | dawn::BufferUsageBit::TransferSrc;
dawn::CreateBufferMappedResult result = device.CreateBufferMapped(&descriptor);
ASSERT_EQ(result.dataLength, descriptor.size);
ASSERT_EQ(*reinterpret_cast<uint8_t*>(result.data), 0);
result.buffer.Unmap();
}
// Test that CreateBufferMapped returns zero-initialized data
// TODO(enga): This should use the testing toggle to initialize resources to 1.
TEST_P(CreateBufferMappedTests, NonMappableZeroInitialized) {
dawn::BufferDescriptor descriptor;
descriptor.nextInChain = nullptr;
descriptor.size = 4;
descriptor.usage = dawn::BufferUsageBit::TransferSrc;
dawn::CreateBufferMappedResult result = device.CreateBufferMapped(&descriptor);
ASSERT_EQ(result.dataLength, descriptor.size);
ASSERT_EQ(*reinterpret_cast<uint8_t*>(result.data), 0);
result.buffer.Unmap();
}
// Test that mapping a buffer is valid after CreateBufferMapped and Unmap
TEST_P(CreateBufferMappedTests, CreateThenMapSuccess) {
dawn::BufferDescriptor descriptor;
descriptor.nextInChain = nullptr;
descriptor.size = 4;
descriptor.usage = dawn::BufferUsageBit::MapWrite | dawn::BufferUsageBit::TransferSrc;
static uint32_t myData = 230502;
static uint32_t myData2 = 1337;
dawn::CreateBufferMappedResult result = device.CreateBufferMapped(&descriptor);
ASSERT_EQ(result.dataLength, descriptor.size);
memcpy(result.data, &myData, sizeof(myData));
dawn::CreateBufferMappedResult result = CreateBufferMappedWithData(
dawn::BufferUsageBit::MapWrite | dawn::BufferUsageBit::TransferSrc, {myData});
result.buffer.Unmap();
EXPECT_BUFFER_U32_EQ(myData, result.buffer, 0);
@@ -432,15 +435,9 @@ TEST_P(CreateBufferMappedTests, CreateThenMapSuccess) {
// Test that is is invalid to map a buffer twice when using CreateBufferMapped
TEST_P(CreateBufferMappedTests, CreateThenMapBeforeUnmapFailure) {
dawn::BufferDescriptor descriptor;
descriptor.nextInChain = nullptr;
descriptor.size = 4;
descriptor.usage = dawn::BufferUsageBit::MapWrite | dawn::BufferUsageBit::TransferSrc;
uint32_t myData = 230502;
dawn::CreateBufferMappedResult result = device.CreateBufferMapped(&descriptor);
ASSERT_EQ(result.dataLength, descriptor.size);
memcpy(result.data, &myData, sizeof(myData));
dawn::CreateBufferMappedResult result = CreateBufferMappedWithData(
dawn::BufferUsageBit::MapWrite | dawn::BufferUsageBit::TransferSrc, {myData});
ASSERT_DEVICE_ERROR([&]() {
bool done = false;
@@ -463,6 +460,140 @@ TEST_P(CreateBufferMappedTests, CreateThenMapBeforeUnmapFailure) {
EXPECT_BUFFER_U32_EQ(myData, result.buffer, 0);
}
// Test that the simplest CreateBufferMappedAsync works for MapWrite buffers.
TEST_P(CreateBufferMappedTests, MapWriteUsageSmallAsync) {
uint32_t myData = 230502;
dawn::CreateBufferMappedResult result = CreateBufferMappedAsyncWithDataAndWait(
dawn::BufferUsageBit::MapWrite | dawn::BufferUsageBit::TransferSrc, {myData});
result.buffer.Unmap();
EXPECT_BUFFER_U32_EQ(myData, result.buffer, 0);
}
// Test that the simplest CreateBufferMappedAsync works for MapRead buffers.
TEST_P(CreateBufferMappedTests, MapReadUsageSmallAsync) {
uint32_t myData = 230502;
dawn::CreateBufferMappedResult result =
CreateBufferMappedAsyncWithDataAndWait(dawn::BufferUsageBit::MapRead, {myData});
result.buffer.Unmap();
const void* mappedData = MapReadAsyncAndWait(result.buffer);
ASSERT_EQ(myData, *reinterpret_cast<const uint32_t*>(mappedData));
result.buffer.Unmap();
}
// Test that the simplest CreateBufferMappedAsync works for non-mappable buffers.
TEST_P(CreateBufferMappedTests, NonMappableUsageSmallAsync) {
uint32_t myData = 4239;
dawn::CreateBufferMappedResult result =
CreateBufferMappedAsyncWithDataAndWait(dawn::BufferUsageBit::TransferSrc, {myData});
result.buffer.Unmap();
EXPECT_BUFFER_U32_EQ(myData, result.buffer, 0);
}
// Test CreateBufferMappedAsync for a large MapWrite buffer
TEST_P(CreateBufferMappedTests, MapWriteUsageLargeAsync) {
constexpr uint64_t kDataSize = 1000 * 1000;
std::vector<uint32_t> myData;
for (uint32_t i = 0; i < kDataSize; ++i) {
myData.push_back(i);
}
dawn::CreateBufferMappedResult result = CreateBufferMappedAsyncWithDataAndWait(
dawn::BufferUsageBit::MapWrite | dawn::BufferUsageBit::TransferSrc, {myData});
result.buffer.Unmap();
EXPECT_BUFFER_U32_RANGE_EQ(myData.data(), result.buffer, 0, kDataSize);
}
// Test CreateBufferMappedAsync for a large MapRead buffer
TEST_P(CreateBufferMappedTests, MapReadUsageLargeAsync) {
constexpr uint64_t kDataSize = 1000 * 1000;
std::vector<uint32_t> myData;
for (uint32_t i = 0; i < kDataSize; ++i) {
myData.push_back(i);
}
dawn::CreateBufferMappedResult result =
CreateBufferMappedAsyncWithDataAndWait(dawn::BufferUsageBit::MapRead, {myData});
result.buffer.Unmap();
const void* mappedData = MapReadAsyncAndWait(result.buffer);
ASSERT_EQ(0, memcmp(mappedData, myData.data(), kDataSize * sizeof(uint32_t)));
result.buffer.Unmap();
}
// Test CreateBufferMappedAsync for a large non-mappable buffer
TEST_P(CreateBufferMappedTests, NonMappableUsageLargeAsync) {
constexpr uint64_t kDataSize = 1000 * 1000;
std::vector<uint32_t> myData;
for (uint32_t i = 0; i < kDataSize; ++i) {
myData.push_back(i);
}
dawn::CreateBufferMappedResult result =
CreateBufferMappedAsyncWithDataAndWait(dawn::BufferUsageBit::TransferSrc, {myData});
result.buffer.Unmap();
EXPECT_BUFFER_U32_RANGE_EQ(myData.data(), result.buffer, 0, kDataSize);
}
// Test that mapping a buffer is valid after CreateBufferMappedAsync and Unmap
TEST_P(CreateBufferMappedTests, CreateThenMapSuccessAsync) {
static uint32_t myData = 230502;
static uint32_t myData2 = 1337;
dawn::CreateBufferMappedResult result = CreateBufferMappedAsyncWithDataAndWait(
dawn::BufferUsageBit::MapWrite | dawn::BufferUsageBit::TransferSrc, {myData});
result.buffer.Unmap();
EXPECT_BUFFER_U32_EQ(myData, result.buffer, 0);
bool done = false;
result.buffer.MapWriteAsync(
[](DawnBufferMapAsyncStatus status, void* data, uint64_t, void* userdata) {
ASSERT_EQ(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, status);
ASSERT_NE(nullptr, data);
*static_cast<uint32_t*>(data) = myData2;
*static_cast<bool*>(userdata) = true;
},
&done);
while (!done) {
WaitABit();
}
result.buffer.Unmap();
EXPECT_BUFFER_U32_EQ(myData2, result.buffer, 0);
}
// Test that is is invalid to map a buffer twice when using CreateBufferMappedAsync
TEST_P(CreateBufferMappedTests, CreateThenMapBeforeUnmapFailureAsync) {
uint32_t myData = 230502;
dawn::CreateBufferMappedResult result = CreateBufferMappedAsyncWithDataAndWait(
dawn::BufferUsageBit::MapWrite | dawn::BufferUsageBit::TransferSrc, {myData});
ASSERT_DEVICE_ERROR([&]() {
bool done = false;
result.buffer.MapWriteAsync(
[](DawnBufferMapAsyncStatus status, void* data, uint64_t, void* userdata) {
ASSERT_EQ(DAWN_BUFFER_MAP_ASYNC_STATUS_ERROR, status);
ASSERT_EQ(nullptr, data);
*static_cast<bool*>(userdata) = true;
},
&done);
while (!done) {
WaitABit();
}
}());
// CreateBufferMappedAsync is unaffected by the MapWrite error.
result.buffer.Unmap();
EXPECT_BUFFER_U32_EQ(myData, result.buffer, 0);
}
DAWN_INSTANTIATE_TEST(CreateBufferMappedTests,
D3D12Backend,
MetalBackend,

View File

@@ -59,6 +59,28 @@ namespace {
mockBufferMapWriteCallback->Call(status, lastMapWritePointer, dataLength, userdata);
}
class MockBufferCreateMappedCallback {
public:
MOCK_METHOD5(Call,
void(DawnBufferMapAsyncStatus status,
DawnBuffer buffer,
uint32_t* ptr,
uint64_t dataLength,
void* userdata));
};
std::unique_ptr<StrictMock<MockBufferCreateMappedCallback>> mockCreateBufferMappedCallback;
uint32_t* lastCreateMappedPointer = nullptr;
void ToMockCreateBufferMappedCallback(DawnBufferMapAsyncStatus status,
DawnCreateBufferMappedResult result,
void* userdata) {
// Assume the data is uint32_t to make writing matchers easier
lastCreateMappedPointer = static_cast<uint32_t*>(result.data);
// Unpack DawnCreateBufferMappedResult to make writing matchers easier
mockCreateBufferMappedCallback->Call(status, result.buffer, lastCreateMappedPointer,
result.dataLength, userdata);
}
} // anonymous namespace
class WireBufferMappingTests : public WireTest {
@@ -72,6 +94,8 @@ class WireBufferMappingTests : public WireTest {
mockBufferMapReadCallback = std::make_unique<StrictMock<MockBufferMapReadCallback>>();
mockBufferMapWriteCallback = std::make_unique<StrictMock<MockBufferMapWriteCallback>>();
mockCreateBufferMappedCallback =
std::make_unique<StrictMock<MockBufferCreateMappedCallback>>();
DawnBufferDescriptor descriptor;
descriptor.nextInChain = nullptr;
@@ -91,6 +115,7 @@ class WireBufferMappingTests : public WireTest {
// Delete mocks so that expectations are checked
mockBufferMapReadCallback = nullptr;
mockBufferMapWriteCallback = nullptr;
mockCreateBufferMappedCallback = nullptr;
}
void FlushServer() {
@@ -98,6 +123,7 @@ class WireBufferMappingTests : public WireTest {
Mock::VerifyAndClearExpectations(&mockBufferMapReadCallback);
Mock::VerifyAndClearExpectations(&mockBufferMapWriteCallback);
Mock::VerifyAndClearExpectations(&mockCreateBufferMappedCallback);
}
protected:
@@ -612,3 +638,184 @@ TEST_F(WireBufferMappingTests, CreateBufferMappedThenMapFailure) {
FlushClient();
}
// Test successful CreateBufferMappedAsync
TEST_F(WireBufferMappingTests, CreateBufferMappedAsyncSuccess) {
DawnBufferDescriptor descriptor;
descriptor.nextInChain = nullptr;
DawnCreateBufferMappedResult apiResult;
uint32_t serverBufferContent = 31337;
apiResult.buffer = apiBuffer;
apiResult.data = reinterpret_cast<uint8_t*>(&serverBufferContent);
apiResult.dataLength = 4;
uint32_t updatedContent = 4242;
uint32_t zero = 0;
dawnDeviceCreateBufferMappedAsync(device, &descriptor, ToMockCreateBufferMappedCallback, nullptr);
EXPECT_CALL(api, DeviceCreateBufferMapped(apiDevice, _))
.WillOnce(Return(apiResult))
.RetiresOnSaturation();
FlushClient();
DawnBuffer buffer;
// The callback always gets a buffer full of zeroes.
EXPECT_CALL(*mockCreateBufferMappedCallback, Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, _,
Pointee(Eq(zero)), sizeof(uint32_t), _))
.WillOnce(::testing::SaveArg<1>(&buffer));
FlushServer();
// Write something to the mapped pointer
*lastCreateMappedPointer = updatedContent;
dawnBufferUnmap(buffer);
EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1);
FlushClient();
// After the buffer is unmapped, the content of the buffer is updated on the server
ASSERT_EQ(serverBufferContent, updatedContent);
}
// Test CreateBufferMappedAsync with map error
TEST_F(WireBufferMappingTests, CreateBufferMappedAsyncMapError) {
DawnBufferDescriptor descriptor;
descriptor.nextInChain = nullptr;
DawnCreateBufferMappedResult apiResult;
apiResult.buffer = apiBuffer;
apiResult.data = nullptr; // error mapping
apiResult.dataLength = 4;
dawnDeviceCreateBufferMappedAsync(device, &descriptor, ToMockCreateBufferMappedCallback, nullptr);
EXPECT_CALL(api, DeviceCreateBufferMapped(apiDevice, _))
.WillOnce(Return(apiResult))
.RetiresOnSaturation();
FlushClient();
DawnBuffer buffer;
EXPECT_CALL(*mockCreateBufferMappedCallback,
Call(DAWN_BUFFER_MAP_ASYNC_STATUS_ERROR, _, nullptr, 0, _))
.WillOnce(::testing::SaveArg<1>(&buffer));
FlushServer();
dawnBufferUnmap(buffer);
EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1);
FlushClient();
}
// Test that the CreateBufferMappedCallback isn't fired twice when unmap() is called inside the
// callback
TEST_F(WireBufferMappingTests, UnmapInsideCreateBufferMappedAsyncCallback) {
DawnBufferDescriptor descriptor;
descriptor.nextInChain = nullptr;
DawnCreateBufferMappedResult apiResult;
uint32_t serverBufferContent = 31337;
apiResult.buffer = apiBuffer;
apiResult.data = reinterpret_cast<uint8_t*>(&serverBufferContent);
apiResult.dataLength = 4;
uint32_t zero = 0;
dawnDeviceCreateBufferMappedAsync(device, &descriptor, ToMockCreateBufferMappedCallback, nullptr);
EXPECT_CALL(api, DeviceCreateBufferMapped(apiDevice, _))
.WillOnce(Return(apiResult))
.RetiresOnSaturation();
FlushClient();
DawnBuffer buffer;
// The callback always gets a buffer full of zeroes.
EXPECT_CALL(*mockCreateBufferMappedCallback, Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, _,
Pointee(Eq(zero)), sizeof(uint32_t), _))
.WillOnce(DoAll(::testing::SaveArg<1>(&buffer),
InvokeWithoutArgs([&]() { dawnBufferUnmap(buffer); })));
FlushServer();
EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1);
FlushClient();
}
// Test that the CreateBufferMappedCallback isn't fired twice when the buffer is deleted inside
// the callback
TEST_F(WireBufferMappingTests, ReleaseInsideCreateBufferMappedAsyncCallback) {
DawnBufferDescriptor descriptor;
descriptor.nextInChain = nullptr;
DawnCreateBufferMappedResult apiResult;
uint32_t serverBufferContent = 31337;
apiResult.buffer = apiBuffer;
apiResult.data = reinterpret_cast<uint8_t*>(&serverBufferContent);
apiResult.dataLength = 4;
uint32_t zero = 0;
dawnDeviceCreateBufferMappedAsync(device, &descriptor, ToMockCreateBufferMappedCallback, nullptr);
EXPECT_CALL(api, DeviceCreateBufferMapped(apiDevice, _))
.WillOnce(Return(apiResult))
.RetiresOnSaturation();
FlushClient();
DawnBuffer buffer;
// The callback always gets a buffer full of zeroes.
EXPECT_CALL(*mockCreateBufferMappedCallback, Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, _,
Pointee(Eq(zero)), sizeof(uint32_t), _))
.WillOnce(DoAll(::testing::SaveArg<1>(&buffer),
InvokeWithoutArgs([&]() { dawnBufferRelease(buffer); })));
FlushServer();
EXPECT_CALL(api, BufferRelease(apiBuffer));
FlushClient();
}
// Test that the CreateBufferMappedCallback isn't fired twice when the buffer is destroyed inside
// the callback
TEST_F(WireBufferMappingTests, DestroyInsideCreateBufferMappedAsyncCallback) {
DawnBufferDescriptor descriptor;
descriptor.nextInChain = nullptr;
DawnCreateBufferMappedResult apiResult;
uint32_t serverBufferContent = 31337;
apiResult.buffer = apiBuffer;
apiResult.data = reinterpret_cast<uint8_t*>(&serverBufferContent);
apiResult.dataLength = 4;
uint32_t zero = 0;
dawnDeviceCreateBufferMappedAsync(device, &descriptor, ToMockCreateBufferMappedCallback, nullptr);
EXPECT_CALL(api, DeviceCreateBufferMapped(apiDevice, _))
.WillOnce(Return(apiResult))
.RetiresOnSaturation();
FlushClient();
DawnBuffer buffer;
// The callback always gets a buffer full of zeroes.
EXPECT_CALL(*mockCreateBufferMappedCallback, Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, _,
Pointee(Eq(zero)), sizeof(uint32_t), _))
.WillOnce(DoAll(::testing::SaveArg<1>(&buffer),
InvokeWithoutArgs([&]() { dawnBufferDestroy(buffer); })));
FlushServer();
EXPECT_CALL(api, BufferDestroy(apiBuffer));
FlushClient();
}