dawn_wire: Implement CreateBufferMapped on top of mappedAtCreation

Reland with a fix for narrowing of uint64_t to size_t of the buffer size
in 32 bit mode.

This inverts the shimming to have the old mapping at creation method
be implemented on top of the new method..

Also updates Wire tests to use mappedAtCreation instead of
CreateBufferMapped.

TBR=senorblanco@chromium.org
Bug: dawn:445
Change-Id: I89fe84b6e0b5d0d4a5c6a2db7b38cb7d6cd063f0
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/25981
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Corentin Wallez 2020-07-29 17:01:11 +00:00 committed by Commit Bot service account
parent ab04da48f4
commit f93fa6acd9
7 changed files with 175 additions and 221 deletions

View File

@ -38,7 +38,7 @@
{ "name": "write flush info length", "type": "uint64_t" }, { "name": "write flush info length", "type": "uint64_t" },
{ "name": "write flush info", "type": "uint8_t", "annotation": "const*", "length": "write flush info length", "skip_serialize": true} { "name": "write flush info", "type": "uint8_t", "annotation": "const*", "length": "write flush info length", "skip_serialize": true}
], ],
"device create buffer mapped": [ "device create buffer": [
{ "name": "device", "type": "device" }, { "name": "device", "type": "device" },
{ "name": "descriptor", "type": "buffer descriptor", "annotation": "const*" }, { "name": "descriptor", "type": "buffer descriptor", "annotation": "const*" },
{ "name": "result", "type": "ObjectHandle", "handle_type": "buffer" }, { "name": "result", "type": "ObjectHandle", "handle_type": "buffer" },
@ -108,6 +108,8 @@
"BufferSetSubData", "BufferSetSubData",
"BufferGetConstMappedRange", "BufferGetConstMappedRange",
"BufferGetMappedRange", "BufferGetMappedRange",
"DeviceCreateBuffer",
"DeviceCreateBufferMapped",
"DevicePopErrorScope", "DevicePopErrorScope",
"DeviceSetDeviceLostCallback", "DeviceSetDeviceLostCallback",
"DeviceSetUncapturedErrorCallback", "DeviceSetUncapturedErrorCallback",
@ -119,8 +121,6 @@
"client_handwritten_commands": [ "client_handwritten_commands": [
"BufferDestroy", "BufferDestroy",
"BufferUnmap", "BufferUnmap",
"DeviceCreateBuffer",
"DeviceCreateBufferMapped",
"DeviceCreateErrorBuffer", "DeviceCreateErrorBuffer",
"DeviceGetDefaultQueue", "DeviceGetDefaultQueue",
"DeviceInjectError", "DeviceInjectError",

View File

@ -23,95 +23,69 @@ namespace dawn_wire { namespace client {
WGPUBuffer Buffer::Create(Device* device_, const WGPUBufferDescriptor* descriptor) { WGPUBuffer Buffer::Create(Device* device_, const WGPUBufferDescriptor* descriptor) {
Client* wireClient = device_->GetClient(); Client* wireClient = device_->GetClient();
if ((descriptor->usage & (WGPUBufferUsage_MapRead | WGPUBufferUsage_MapWrite)) != 0 && bool mappable =
descriptor->size > std::numeric_limits<size_t>::max()) { (descriptor->usage & (WGPUBufferUsage_MapRead | WGPUBufferUsage_MapWrite)) != 0 ||
descriptor->mappedAtCreation;
if (mappable && descriptor->size > std::numeric_limits<size_t>::max()) {
device_->InjectError(WGPUErrorType_OutOfMemory, "Buffer is too large for map usage"); device_->InjectError(WGPUErrorType_OutOfMemory, "Buffer is too large for map usage");
return device_->CreateErrorBuffer(); return device_->CreateErrorBuffer();
} }
std::unique_ptr<MemoryTransferService::WriteHandle> writeHandle = nullptr;
void* writeData = nullptr;
size_t writeHandleCreateInfoLength = 0;
// If the buffer is mapped at creation, create a write handle that will represent the
// mapping of the whole buffer.
if (descriptor->mappedAtCreation) {
// Create the handle.
writeHandle.reset(
wireClient->GetMemoryTransferService()->CreateWriteHandle(descriptor->size));
if (writeHandle == nullptr) {
device_->InjectError(WGPUErrorType_OutOfMemory, "Buffer mapping allocation failed");
return device_->CreateErrorBuffer();
}
// Open the handle, it may fail by returning a nullptr in writeData.
size_t writeDataLength = 0;
std::tie(writeData, writeDataLength) = writeHandle->Open();
if (writeData == nullptr) {
device_->InjectError(WGPUErrorType_OutOfMemory, "Buffer mapping allocation failed");
return device_->CreateErrorBuffer();
}
ASSERT(writeDataLength == descriptor->size);
// Get the serialization size of the write handle.
writeHandleCreateInfoLength = writeHandle->SerializeCreateSize();
}
// Create the buffer and send the creation command.
auto* bufferObjectAndSerial = wireClient->BufferAllocator().New(device_); auto* bufferObjectAndSerial = wireClient->BufferAllocator().New(device_);
Buffer* buffer = bufferObjectAndSerial->object.get(); Buffer* buffer = bufferObjectAndSerial->object.get();
// Store the size of the buffer so that mapping operations can allocate a
// MemoryTransfer handle of the proper size.
buffer->mSize = descriptor->size; buffer->mSize = descriptor->size;
DeviceCreateBufferCmd cmd; DeviceCreateBufferCmd cmd;
cmd.self = ToAPI(device_);
cmd.descriptor = descriptor;
cmd.result = ObjectHandle{buffer->id, bufferObjectAndSerial->generation};
wireClient->SerializeCommand(cmd);
return ToAPI(buffer);
}
// static
WGPUCreateBufferMappedResult Buffer::CreateMapped(Device* device_,
const WGPUBufferDescriptor* descriptor) {
Client* wireClient = device_->GetClient();
WGPUCreateBufferMappedResult result;
result.data = nullptr;
result.dataLength = 0;
// This buffer is too large to be mapped and to make a WriteHandle for.
if (descriptor->size > std::numeric_limits<size_t>::max()) {
device_->InjectError(WGPUErrorType_OutOfMemory, "Buffer is too large for mapping");
result.buffer = device_->CreateErrorBuffer();
return result;
}
// Create a WriteHandle for the map request. This is the client's intent to write GPU
// memory.
std::unique_ptr<MemoryTransferService::WriteHandle> writeHandle =
std::unique_ptr<MemoryTransferService::WriteHandle>(
wireClient->GetMemoryTransferService()->CreateWriteHandle(descriptor->size));
if (writeHandle == nullptr) {
device_->InjectError(WGPUErrorType_OutOfMemory, "Buffer mapping allocation failed");
result.buffer = device_->CreateErrorBuffer();
return result;
}
// CreateBufferMapped is synchronous and the staging buffer for upload should be immediately
// available.
// Open the WriteHandle. This returns a pointer and size of mapped memory.
// |result.data| may be null on error.
std::tie(result.data, result.dataLength) = writeHandle->Open();
if (result.data == nullptr) {
device_->InjectError(WGPUErrorType_OutOfMemory, "Buffer mapping allocation failed");
result.buffer = device_->CreateErrorBuffer();
return result;
}
auto* bufferObjectAndSerial = wireClient->BufferAllocator().New(device_);
Buffer* buffer = bufferObjectAndSerial->object.get();
buffer->mSize = descriptor->size;
// Successfully created staging memory. The buffer now owns the WriteHandle.
buffer->mWriteHandle = std::move(writeHandle);
buffer->mMappedData = result.data;
buffer->mMapOffset = 0;
buffer->mMapSize = descriptor->size;
result.buffer = ToAPI(buffer);
// Get the serialization size of the WriteHandle.
size_t handleCreateInfoLength = buffer->mWriteHandle->SerializeCreateSize();
DeviceCreateBufferMappedCmd cmd;
cmd.device = ToAPI(device_); cmd.device = ToAPI(device_);
cmd.descriptor = descriptor; cmd.descriptor = descriptor;
cmd.result = ObjectHandle{buffer->id, bufferObjectAndSerial->generation}; cmd.result = ObjectHandle{buffer->id, bufferObjectAndSerial->generation};
cmd.handleCreateInfoLength = handleCreateInfoLength; cmd.handleCreateInfoLength = writeHandleCreateInfoLength;
cmd.handleCreateInfo = nullptr; cmd.handleCreateInfo = nullptr;
char* writeHandleSpace = char* writeHandleSpace = wireClient->SerializeCommand(cmd, writeHandleCreateInfoLength);
buffer->device->GetClient()->SerializeCommand(cmd, handleCreateInfoLength);
if (descriptor->mappedAtCreation) {
// Serialize the WriteHandle into the space after the command. // Serialize the WriteHandle into the space after the command.
buffer->mWriteHandle->SerializeCreate(writeHandleSpace); writeHandle->SerializeCreate(writeHandleSpace);
return result; // Set the buffer state for the mapping at creation. The buffer now owns the write
// handle..
buffer->mWriteHandle = std::move(writeHandle);
buffer->mMappedData = writeData;
buffer->mMapOffset = 0;
buffer->mMapSize = buffer->mSize;
}
return ToAPI(buffer);
} }
// static // static

View File

@ -29,8 +29,6 @@ namespace dawn_wire { namespace client {
using ObjectBase::ObjectBase; using ObjectBase::ObjectBase;
static WGPUBuffer Create(Device* device, const WGPUBufferDescriptor* descriptor); static WGPUBuffer Create(Device* device, const WGPUBufferDescriptor* descriptor);
static WGPUCreateBufferMappedResult CreateMapped(Device* device,
const WGPUBufferDescriptor* descriptor);
static WGPUBuffer CreateError(Device* device); static WGPUBuffer CreateError(Device* device);
~Buffer(); ~Buffer();

View File

@ -146,16 +146,20 @@ namespace dawn_wire { namespace client {
} }
WGPUBuffer Device::CreateBuffer(const WGPUBufferDescriptor* descriptor) { WGPUBuffer Device::CreateBuffer(const WGPUBufferDescriptor* descriptor) {
if (descriptor->mappedAtCreation) {
return CreateBufferMapped(descriptor).buffer;
} else {
return Buffer::Create(this, descriptor); return Buffer::Create(this, descriptor);
} }
}
WGPUCreateBufferMappedResult Device::CreateBufferMapped( WGPUCreateBufferMappedResult Device::CreateBufferMapped(
const WGPUBufferDescriptor* descriptor) { const WGPUBufferDescriptor* descriptor) {
return Buffer::CreateMapped(this, descriptor); WGPUBufferDescriptor descMappedAtCreation = *descriptor;
descMappedAtCreation.mappedAtCreation = true;
WGPUCreateBufferMappedResult result;
result.buffer = CreateBuffer(&descMappedAtCreation);
result.data = FromAPI(result.buffer)->GetMappedRange(0, descriptor->size);
result.dataLength = result.data == nullptr ? 0 : descriptor->size;
return result;
} }
WGPUBuffer Device::CreateErrorBuffer() { WGPUBuffer Device::CreateErrorBuffer() {

View File

@ -118,50 +118,52 @@ namespace dawn_wire { namespace server {
return true; return true;
} }
bool Server::DoDeviceCreateBufferMapped(WGPUDevice device, bool Server::DoDeviceCreateBuffer(WGPUDevice device,
const WGPUBufferDescriptor* descriptor, const WGPUBufferDescriptor* descriptor,
ObjectHandle bufferResult, ObjectHandle bufferResult,
uint64_t handleCreateInfoLength, uint64_t handleCreateInfoLength,
const uint8_t* handleCreateInfo) { const uint8_t* handleCreateInfo) {
if (handleCreateInfoLength > std::numeric_limits<size_t>::max()) { // Create and register the buffer object.
// This is the size of data deserialized from the command stream, which must be
// CPU-addressable.
return false;
}
auto* resultData = BufferObjects().Allocate(bufferResult.id); auto* resultData = BufferObjects().Allocate(bufferResult.id);
if (resultData == nullptr) { if (resultData == nullptr) {
return false; return false;
} }
resultData->generation = bufferResult.generation; resultData->generation = bufferResult.generation;
resultData->handle = mProcs.deviceCreateBuffer(device, descriptor);
WGPUCreateBufferMappedResult result = mProcs.deviceCreateBufferMapped(device, descriptor); // If the buffer isn't mapped at creation, we are done.
ASSERT(result.buffer != nullptr); if (!descriptor->mappedAtCreation) {
if (result.data == nullptr && result.dataLength != 0) { return handleCreateInfoLength == 0;
// Non-zero dataLength but null data is used to indicate an allocation error. }
// Don't return false because this is not fatal. result.buffer is an ErrorBuffer
// and subsequent operations will be errors. // This is the size of data deserialized from the command stream to create the write handle,
// This should only happen when fuzzing with the Null backend. // which must be CPU-addressable.
if (handleCreateInfoLength > std::numeric_limits<size_t>::max()) {
return false;
}
void* mapping = mProcs.bufferGetMappedRange(resultData->handle, 0, descriptor->size);
if (mapping == nullptr) {
// A zero mapping is used to indicate an allocation error of an error buffer. This is a
// valid case and isn't fatal. Remember the buffer is an error so as to skip subsequent
// mapping operations.
resultData->mapWriteState = BufferMapWriteState::MapError; resultData->mapWriteState = BufferMapWriteState::MapError;
} else { return true;
}
// Deserialize metadata produced from the client to create a companion server handle. // Deserialize metadata produced from the client to create a companion server handle.
MemoryTransferService::WriteHandle* writeHandle = nullptr; MemoryTransferService::WriteHandle* writeHandle = nullptr;
if (!mMemoryTransferService->DeserializeWriteHandle( if (!mMemoryTransferService->DeserializeWriteHandle(
handleCreateInfo, static_cast<size_t>(handleCreateInfoLength), &writeHandle)) { handleCreateInfo, static_cast<size_t>(handleCreateInfoLength), &writeHandle)) {
return false; return false;
} }
ASSERT(writeHandle != nullptr);
// Set the target of the WriteHandle to the mapped GPU memory. // Set the target of the WriteHandle to the mapped GPU memory.
writeHandle->SetTarget(result.data, result.dataLength); ASSERT(writeHandle != nullptr);
writeHandle->SetTarget(mapping, descriptor->size);
// The buffer is mapped and has a valid mappedData pointer.
// The buffer may still be an error with fake staging data.
resultData->mapWriteState = BufferMapWriteState::Mapped; resultData->mapWriteState = BufferMapWriteState::Mapped;
resultData->writeHandle = resultData->writeHandle.reset(writeHandle);
std::unique_ptr<MemoryTransferService::WriteHandle>(writeHandle);
}
resultData->handle = result.buffer;
return true; return true;
} }

View File

@ -477,84 +477,72 @@ TEST_F(WireBufferMappingTests, DestroyInsideMapWriteCallback) {
FlushClient(); FlushClient();
} }
// Test successful CreateBufferMapped // Test successful buffer creation with mappedAtCreation=true
TEST_F(WireBufferMappingTests, CreateBufferMappedSuccess) { TEST_F(WireBufferMappingTests, MappedAtCreationSuccess) {
WGPUBufferDescriptor descriptor = {}; WGPUBufferDescriptor descriptor = {};
descriptor.size = 4; descriptor.size = 4;
descriptor.mappedAtCreation = true;
WGPUBuffer apiBuffer = api.GetNewBuffer(); WGPUBuffer apiBuffer = api.GetNewBuffer();
WGPUCreateBufferMappedResult apiResult;
uint32_t apiBufferData = 1234; uint32_t apiBufferData = 1234;
apiResult.buffer = apiBuffer;
apiResult.data = reinterpret_cast<uint8_t*>(&apiBufferData);
apiResult.dataLength = 4;
WGPUCreateBufferMappedResult result = wgpuDeviceCreateBufferMapped(device, &descriptor); WGPUBuffer buffer = wgpuDeviceCreateBuffer(device, &descriptor);
EXPECT_CALL(api, DeviceCreateBufferMapped(apiDevice, _)) EXPECT_CALL(api, DeviceCreateBuffer(apiDevice, _)).WillOnce(Return(apiBuffer));
.WillOnce(Return(apiResult)) EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, 4)).WillOnce(Return(&apiBufferData));
.RetiresOnSaturation();
FlushClient(); FlushClient();
wgpuBufferUnmap(result.buffer); wgpuBufferUnmap(buffer);
EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1); EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1);
FlushClient(); FlushClient();
} }
// Test that releasing after CreateBufferMapped does not call Unmap // Test that releasing a buffer mapped at creation does not call Unmap
TEST_F(WireBufferMappingTests, ReleaseAfterCreateBufferMapped) { TEST_F(WireBufferMappingTests, MappedAtCreationReleaseBeforeUnmap) {
WGPUBufferDescriptor descriptor = {}; WGPUBufferDescriptor descriptor = {};
descriptor.size = 4; descriptor.size = 4;
descriptor.mappedAtCreation = true;
WGPUBuffer apiBuffer = api.GetNewBuffer(); WGPUBuffer apiBuffer = api.GetNewBuffer();
WGPUCreateBufferMappedResult apiResult;
uint32_t apiBufferData = 1234; uint32_t apiBufferData = 1234;
apiResult.buffer = apiBuffer;
apiResult.data = reinterpret_cast<uint8_t*>(&apiBufferData);
apiResult.dataLength = 4;
WGPUCreateBufferMappedResult result = wgpuDeviceCreateBufferMapped(device, &descriptor); WGPUBuffer buffer = wgpuDeviceCreateBuffer(device, &descriptor);
EXPECT_CALL(api, DeviceCreateBufferMapped(apiDevice, _)) EXPECT_CALL(api, DeviceCreateBuffer(apiDevice, _)).WillOnce(Return(apiBuffer));
.WillOnce(Return(apiResult)) EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, 4)).WillOnce(Return(&apiBufferData));
.RetiresOnSaturation();
FlushClient(); FlushClient();
wgpuBufferRelease(result.buffer); wgpuBufferRelease(buffer);
EXPECT_CALL(api, BufferRelease(apiBuffer)).Times(1); EXPECT_CALL(api, BufferRelease(apiBuffer)).Times(1);
FlushClient(); FlushClient();
} }
// Test that it is valid to map a buffer after CreateBufferMapped and Unmap // Test that it is valid to map a buffer after it is mapped at creation and unmapped
TEST_F(WireBufferMappingTests, CreateBufferMappedThenMapSuccess) { TEST_F(WireBufferMappingTests, MappedAtCreationThenMapSuccess) {
WGPUBufferDescriptor descriptor = {}; WGPUBufferDescriptor descriptor = {};
descriptor.size = 4; descriptor.size = 4;
descriptor.mappedAtCreation = true;
WGPUBuffer apiBuffer = api.GetNewBuffer(); WGPUBuffer apiBuffer = api.GetNewBuffer();
WGPUCreateBufferMappedResult apiResult; uint32_t apiBufferData = 1234;
uint32_t apiBufferData = 9863;
apiResult.buffer = apiBuffer;
apiResult.data = reinterpret_cast<uint8_t*>(&apiBufferData);
apiResult.dataLength = 4;
WGPUCreateBufferMappedResult result = wgpuDeviceCreateBufferMapped(device, &descriptor); WGPUBuffer buffer = wgpuDeviceCreateBuffer(device, &descriptor);
EXPECT_CALL(api, DeviceCreateBufferMapped(apiDevice, _)) EXPECT_CALL(api, DeviceCreateBuffer(apiDevice, _)).WillOnce(Return(apiBuffer));
.WillOnce(Return(apiResult)) EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, 4)).WillOnce(Return(&apiBufferData));
.RetiresOnSaturation();
FlushClient(); FlushClient();
wgpuBufferUnmap(result.buffer); wgpuBufferUnmap(buffer);
EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1); EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1);
FlushClient(); FlushClient();
wgpuBufferMapWriteAsync(result.buffer, ToMockBufferMapWriteCallback, nullptr); wgpuBufferMapWriteAsync(buffer, ToMockBufferMapWriteCallback, nullptr);
uint32_t zero = 0; uint32_t zero = 0;
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
@ -572,27 +560,23 @@ TEST_F(WireBufferMappingTests, CreateBufferMappedThenMapSuccess) {
FlushServer(); FlushServer();
} }
// Test that it is invalid to map a buffer after CreateBufferMapped before Unmap // Test that it is invalid to map a buffer after mappedAtCreation but before Unmap
TEST_F(WireBufferMappingTests, CreateBufferMappedThenMapFailure) { TEST_F(WireBufferMappingTests, MappedAtCreationThenMapFailure) {
WGPUBufferDescriptor descriptor = {}; WGPUBufferDescriptor descriptor = {};
descriptor.size = 4; descriptor.size = 4;
descriptor.mappedAtCreation = true;
WGPUBuffer apiBuffer = api.GetNewBuffer(); WGPUBuffer apiBuffer = api.GetNewBuffer();
WGPUCreateBufferMappedResult apiResult; uint32_t apiBufferData = 1234;
uint32_t apiBufferData = 9863;
apiResult.buffer = apiBuffer;
apiResult.data = reinterpret_cast<uint8_t*>(&apiBufferData);
apiResult.dataLength = 4;
WGPUCreateBufferMappedResult result = wgpuDeviceCreateBufferMapped(device, &descriptor); WGPUBuffer buffer = wgpuDeviceCreateBuffer(device, &descriptor);
EXPECT_CALL(api, DeviceCreateBufferMapped(apiDevice, _)) EXPECT_CALL(api, DeviceCreateBuffer(apiDevice, _)).WillOnce(Return(apiBuffer));
.WillOnce(Return(apiResult)) EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, 4)).WillOnce(Return(&apiBufferData));
.RetiresOnSaturation();
FlushClient(); FlushClient();
wgpuBufferMapWriteAsync(result.buffer, ToMockBufferMapWriteCallback, nullptr); wgpuBufferMapWriteAsync(buffer, ToMockBufferMapWriteCallback, nullptr);
EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() { EXPECT_CALL(api, OnBufferMapAsyncCallback(apiBuffer, _, _)).WillOnce(InvokeWithoutArgs([&]() {
api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Error); api.CallMapAsyncCallback(apiBuffer, WGPUBufferMapAsyncStatus_Error);
@ -605,7 +589,7 @@ TEST_F(WireBufferMappingTests, CreateBufferMappedThenMapFailure) {
FlushServer(); FlushServer();
wgpuBufferUnmap(result.buffer); wgpuBufferUnmap(buffer);
EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1); EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1);
FlushClient(); FlushClient();

View File

@ -155,24 +155,20 @@ class WireMemoryTransferServiceTests : public WireTest {
return std::make_pair(apiBuffer, buffer); return std::make_pair(apiBuffer, buffer);
} }
std::pair<WGPUCreateBufferMappedResult, WGPUCreateBufferMappedResult> CreateBufferMapped() { std::pair<WGPUBuffer, WGPUBuffer> CreateBufferMapped() {
WGPUBufferDescriptor descriptor = {}; WGPUBufferDescriptor descriptor = {};
descriptor.size = sizeof(mBufferContent); descriptor.size = sizeof(mBufferContent);
descriptor.mappedAtCreation = true;
WGPUBuffer apiBuffer = api.GetNewBuffer(); WGPUBuffer apiBuffer = api.GetNewBuffer();
WGPUCreateBufferMappedResult apiResult; WGPUBuffer buffer = wgpuDeviceCreateBuffer(device, &descriptor);
apiResult.buffer = apiBuffer;
apiResult.data = reinterpret_cast<uint8_t*>(&mMappedBufferContent);
apiResult.dataLength = sizeof(mMappedBufferContent);
WGPUCreateBufferMappedResult result = wgpuDeviceCreateBufferMapped(device, &descriptor); EXPECT_CALL(api, DeviceCreateBuffer(apiDevice, _)).WillOnce(Return(apiBuffer));
EXPECT_CALL(api, BufferGetMappedRange(apiBuffer, 0, sizeof(mBufferContent)))
.WillOnce(Return(&mMappedBufferContent));
EXPECT_CALL(api, DeviceCreateBufferMapped(apiDevice, _)) return std::make_pair(apiBuffer, buffer);
.WillOnce(Return(apiResult))
.RetiresOnSaturation();
return std::make_pair(apiResult, result);
} }
ClientReadHandle* ExpectReadHandleCreation() { ClientReadHandle* ExpectReadHandleCreation() {
@ -891,8 +887,8 @@ TEST_F(WireMemoryTransferServiceTests, BufferMapWriteDestroyBeforeUnmap) {
} }
} }
// Test successful CreateBufferMapped. // Test successful buffer creation with mappedAtCreation = true.
TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedSuccess) { TEST_F(WireMemoryTransferServiceTests, MappedAtCreationSuccess) {
// The client should create and serialize a WriteHandle on createBufferMapped. // The client should create and serialize a WriteHandle on createBufferMapped.
ClientWriteHandle* clientHandle = ExpectWriteHandleCreation(); ClientWriteHandle* clientHandle = ExpectWriteHandleCreation();
@ -904,9 +900,9 @@ TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedSuccess) {
// The server should then deserialize the WriteHandle from the client. // The server should then deserialize the WriteHandle from the client.
ServerWriteHandle* serverHandle = ExpectServerWriteHandleDeserialization(); ServerWriteHandle* serverHandle = ExpectServerWriteHandleDeserialization();
WGPUCreateBufferMappedResult result; WGPUBuffer buffer;
WGPUCreateBufferMappedResult apiResult; WGPUBuffer apiBuffer;
std::tie(apiResult, result) = CreateBufferMapped(); std::tie(apiBuffer, buffer) = CreateBufferMapped();
FlushClient(); FlushClient();
// Update the mapped contents. // Update the mapped contents.
@ -916,35 +912,33 @@ TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedSuccess) {
ExpectClientWriteHandleSerializeFlush(clientHandle); ExpectClientWriteHandleSerializeFlush(clientHandle);
EXPECT_CALL(clientMemoryTransferService, OnWriteHandleDestroy(clientHandle)).Times(1); EXPECT_CALL(clientMemoryTransferService, OnWriteHandleDestroy(clientHandle)).Times(1);
wgpuBufferUnmap(result.buffer); wgpuBufferUnmap(buffer);
// The server deserializes the Flush message. // The server deserializes the Flush message.
ExpectServerWriteHandleDeserializeFlush(serverHandle, mUpdatedBufferContent); ExpectServerWriteHandleDeserializeFlush(serverHandle, mUpdatedBufferContent);
// After the handle is updated it can be destroyed. // After the handle is updated it can be destroyed.
EXPECT_CALL(serverMemoryTransferService, OnWriteHandleDestroy(serverHandle)).Times(1); EXPECT_CALL(serverMemoryTransferService, OnWriteHandleDestroy(serverHandle)).Times(1);
EXPECT_CALL(api, BufferUnmap(apiResult.buffer)).Times(1); EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1);
FlushClient(); FlushClient();
} }
// Test CreateBufferMapped WriteHandle creation failure. // Test buffer creation with mappedAtCreation WriteHandle creation failure.
TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedWriteHandleCreationFailure) { TEST_F(WireMemoryTransferServiceTests, MappedAtCreationWriteHandleCreationFailure) {
// Mock a WriteHandle creation failure // Mock a WriteHandle creation failure
MockWriteHandleCreationFailure(); MockWriteHandleCreationFailure();
WGPUBufferDescriptor descriptor = {}; WGPUBufferDescriptor descriptor = {};
descriptor.size = sizeof(mBufferContent); descriptor.size = sizeof(mBufferContent);
descriptor.mappedAtCreation = true;
WGPUCreateBufferMappedResult result = wgpuDeviceCreateBufferMapped(device, &descriptor); WGPUBuffer buffer = wgpuDeviceCreateBuffer(device, &descriptor);
EXPECT_EQ(nullptr, wgpuBufferGetMappedRange(buffer, 0, sizeof(mBufferContent)));
// TODO(enga): Check that the client generated a context lost.
EXPECT_EQ(result.data, nullptr);
EXPECT_EQ(result.dataLength, 0u);
} }
// Test CreateBufferMapped DeserializeWriteHandle failure. // Test buffer creation with mappedAtCreation DeserializeWriteHandle failure.
TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedDeserializeWriteHandleFailure) { TEST_F(WireMemoryTransferServiceTests, MappedAtCreationDeserializeWriteHandleFailure) {
// The client should create and serialize a WriteHandle on createBufferMapped. // The client should create and serialize a WriteHandle on createBufferMapped.
ClientWriteHandle* clientHandle = ExpectWriteHandleCreation(); ClientWriteHandle* clientHandle = ExpectWriteHandleCreation();
@ -956,16 +950,16 @@ TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedDeserializeWriteHandleF
// The server should then deserialize the WriteHandle from the client. // The server should then deserialize the WriteHandle from the client.
MockServerWriteHandleDeserializeFailure(); MockServerWriteHandleDeserializeFailure();
WGPUCreateBufferMappedResult result; WGPUBuffer buffer;
WGPUCreateBufferMappedResult apiResult; WGPUBuffer apiBuffer;
std::tie(apiResult, result) = CreateBufferMapped(); std::tie(apiBuffer, buffer) = CreateBufferMapped();
FlushClient(false); FlushClient(false);
EXPECT_CALL(clientMemoryTransferService, OnWriteHandleDestroy(clientHandle)).Times(1); EXPECT_CALL(clientMemoryTransferService, OnWriteHandleDestroy(clientHandle)).Times(1);
} }
// Test CreateBufferMapped handle Open failure. // Test buffer creation with mappedAtCreation handle Open failure.
TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedHandleOpenFailure) { TEST_F(WireMemoryTransferServiceTests, MappedAtCreationHandleOpenFailure) {
// The client should create a WriteHandle on createBufferMapped. // The client should create a WriteHandle on createBufferMapped.
ClientWriteHandle* clientHandle = ExpectWriteHandleCreation(); ClientWriteHandle* clientHandle = ExpectWriteHandleCreation();
@ -979,16 +973,14 @@ TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedHandleOpenFailure) {
WGPUBufferDescriptor descriptor = {}; WGPUBufferDescriptor descriptor = {};
descriptor.size = sizeof(mBufferContent); descriptor.size = sizeof(mBufferContent);
descriptor.mappedAtCreation = true;
WGPUCreateBufferMappedResult result = wgpuDeviceCreateBufferMapped(device, &descriptor); WGPUBuffer buffer = wgpuDeviceCreateBuffer(device, &descriptor);
EXPECT_EQ(nullptr, wgpuBufferGetMappedRange(buffer, 0, sizeof(mBufferContent)));
// TODO(enga): Check that the client generated a context lost.
EXPECT_EQ(result.data, nullptr);
EXPECT_EQ(result.dataLength, 0u);
} }
// Test CreateBufferMapped DeserializeFlush failure. // Test buffer creation with mappedAtCreation = true DeserializeFlush failure.
TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedDeserializeFlushFailure) { TEST_F(WireMemoryTransferServiceTests, MappedAtCreationDeserializeFlushFailure) {
// The client should create and serialize a WriteHandle on createBufferMapped. // The client should create and serialize a WriteHandle on createBufferMapped.
ClientWriteHandle* clientHandle = ExpectWriteHandleCreation(); ClientWriteHandle* clientHandle = ExpectWriteHandleCreation();
@ -1000,9 +992,9 @@ TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedDeserializeFlushFailure
// The server should then deserialize the WriteHandle from the client. // The server should then deserialize the WriteHandle from the client.
ServerWriteHandle* serverHandle = ExpectServerWriteHandleDeserialization(); ServerWriteHandle* serverHandle = ExpectServerWriteHandleDeserialization();
WGPUCreateBufferMappedResult result; WGPUBuffer buffer;
WGPUCreateBufferMappedResult apiResult; WGPUBuffer apiBuffer;
std::tie(apiResult, result) = CreateBufferMapped(); std::tie(apiBuffer, buffer) = CreateBufferMapped();
FlushClient(); FlushClient();
// Update the mapped contents. // Update the mapped contents.
@ -1012,7 +1004,7 @@ TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedDeserializeFlushFailure
ExpectClientWriteHandleSerializeFlush(clientHandle); ExpectClientWriteHandleSerializeFlush(clientHandle);
EXPECT_CALL(clientMemoryTransferService, OnWriteHandleDestroy(clientHandle)).Times(1); EXPECT_CALL(clientMemoryTransferService, OnWriteHandleDestroy(clientHandle)).Times(1);
wgpuBufferUnmap(result.buffer); wgpuBufferUnmap(buffer);
// The server deserializes the Flush message. Mock a deserialization failure. // The server deserializes the Flush message. Mock a deserialization failure.
MockServerWriteHandleDeserializeFlushFailure(serverHandle); MockServerWriteHandleDeserializeFlushFailure(serverHandle);
@ -1022,8 +1014,8 @@ TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedDeserializeFlushFailure
EXPECT_CALL(serverMemoryTransferService, OnWriteHandleDestroy(serverHandle)).Times(1); EXPECT_CALL(serverMemoryTransferService, OnWriteHandleDestroy(serverHandle)).Times(1);
} }
// Test CreateBufferMapped destroying the buffer before unmapping on the client side. // Test mappedAtCreation=true destroying the buffer before unmapping on the client side.
TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedDestroyBeforeUnmap) { TEST_F(WireMemoryTransferServiceTests, MappedAtCreationDestroyBeforeUnmap) {
// The client should create and serialize a WriteHandle on createBufferMapped. // The client should create and serialize a WriteHandle on createBufferMapped.
ClientWriteHandle* clientHandle = ExpectWriteHandleCreation(); ClientWriteHandle* clientHandle = ExpectWriteHandleCreation();
@ -1035,9 +1027,9 @@ TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedDestroyBeforeUnmap) {
// The server should then deserialize the WriteHandle from the client. // The server should then deserialize the WriteHandle from the client.
ServerWriteHandle* serverHandle = ExpectServerWriteHandleDeserialization(); ServerWriteHandle* serverHandle = ExpectServerWriteHandleDeserialization();
WGPUCreateBufferMappedResult result; WGPUBuffer buffer;
WGPUCreateBufferMappedResult apiResult; WGPUBuffer apiBuffer;
std::tie(apiResult, result) = CreateBufferMapped(); std::tie(apiBuffer, buffer) = CreateBufferMapped();
FlushClient(); FlushClient();
// Update the mapped contents. // Update the mapped contents.
@ -1047,16 +1039,16 @@ TEST_F(WireMemoryTransferServiceTests, CreateBufferMappedDestroyBeforeUnmap) {
// immediately, both in the client and server side. // immediately, both in the client and server side.
{ {
EXPECT_CALL(clientMemoryTransferService, OnWriteHandleDestroy(clientHandle)).Times(1); EXPECT_CALL(clientMemoryTransferService, OnWriteHandleDestroy(clientHandle)).Times(1);
wgpuBufferDestroy(result.buffer); wgpuBufferDestroy(buffer);
EXPECT_CALL(serverMemoryTransferService, OnWriteHandleDestroy(serverHandle)).Times(1); EXPECT_CALL(serverMemoryTransferService, OnWriteHandleDestroy(serverHandle)).Times(1);
EXPECT_CALL(api, BufferDestroy(apiResult.buffer)).Times(1); EXPECT_CALL(api, BufferDestroy(apiBuffer)).Times(1);
FlushClient(); FlushClient();
// The handle is already destroyed so unmap only results in a server unmap call. // The handle is already destroyed so unmap only results in a server unmap call.
wgpuBufferUnmap(result.buffer); wgpuBufferUnmap(buffer);
EXPECT_CALL(api, BufferUnmap(apiResult.buffer)).Times(1); EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1);
FlushClient(); FlushClient();
} }
} }