Implement CreateBufferMapped in dawn_wire
Bug: dawn:7 Change-Id: I7112c87c3b671cd7a7774af7f3a094a189f2b4b0 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/7402 Reviewed-by: Kai Ninomiya <kainino@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
1c85976abe
commit
76e3de4b08
|
@ -25,6 +25,11 @@
|
||||||
{ "name": "data length", "type": "uint32_t" },
|
{ "name": "data length", "type": "uint32_t" },
|
||||||
{ "name": "data", "type": "uint8_t", "annotation": "const*", "length": "data length" }
|
{ "name": "data", "type": "uint8_t", "annotation": "const*", "length": "data length" }
|
||||||
],
|
],
|
||||||
|
"device create buffer mapped": [
|
||||||
|
{ "name": "device", "type": "device" },
|
||||||
|
{ "name": "descriptor", "type": "buffer descriptor", "annotation": "const*" },
|
||||||
|
{ "name": "result", "type": "ObjectHandle", "handle_type": "buffer" }
|
||||||
|
],
|
||||||
"destroy object": [
|
"destroy object": [
|
||||||
{ "name": "object type", "type": "ObjectType" },
|
{ "name": "object type", "type": "ObjectType" },
|
||||||
{ "name": "object id", "type": "ObjectId" }
|
{ "name": "object id", "type": "ObjectId" }
|
||||||
|
|
|
@ -280,6 +280,7 @@ namespace dawn_native {
|
||||||
result.buffer = reinterpret_cast<DawnBuffer>(buffer);
|
result.buffer = reinterpret_cast<DawnBuffer>(buffer);
|
||||||
result.data = data;
|
result.data = data;
|
||||||
result.dataLength = descriptor->size;
|
result.dataLength = descriptor->size;
|
||||||
|
memset(result.data, 0, result.dataLength);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,9 +71,34 @@ namespace dawn_wire { namespace client {
|
||||||
DawnCreateBufferMappedResult ClientDeviceCreateBufferMapped(
|
DawnCreateBufferMappedResult ClientDeviceCreateBufferMapped(
|
||||||
DawnDevice cDevice,
|
DawnDevice cDevice,
|
||||||
const DawnBufferDescriptor* descriptor) {
|
const DawnBufferDescriptor* descriptor) {
|
||||||
// TODO(enga): Not implemented
|
Device* device = reinterpret_cast<Device*>(cDevice);
|
||||||
UNREACHABLE();
|
Client* wireClient = device->GetClient();
|
||||||
return {};
|
|
||||||
|
auto* bufferObjectAndSerial = wireClient->BufferAllocator().New(device);
|
||||||
|
Buffer* buffer = bufferObjectAndSerial->object.get();
|
||||||
|
buffer->isWriteMapped = true;
|
||||||
|
// |mappedData| is freed in Unmap or the Buffer destructor.
|
||||||
|
// TODO(enga): Add dependency injection for buffer mapping so staging
|
||||||
|
// memory can live in shared memory.
|
||||||
|
buffer->mappedData = malloc(descriptor->size);
|
||||||
|
memset(buffer->mappedData, 0, descriptor->size);
|
||||||
|
buffer->mappedDataSize = descriptor->size;
|
||||||
|
|
||||||
|
DeviceCreateBufferMappedCmd cmd;
|
||||||
|
cmd.device = cDevice;
|
||||||
|
cmd.descriptor = descriptor;
|
||||||
|
cmd.result = ObjectHandle{buffer->id, bufferObjectAndSerial->serial};
|
||||||
|
|
||||||
|
size_t requiredSize = cmd.GetRequiredSize();
|
||||||
|
char* allocatedBuffer = static_cast<char*>(wireClient->GetCmdSpace(requiredSize));
|
||||||
|
cmd.Serialize(allocatedBuffer, *wireClient);
|
||||||
|
|
||||||
|
DawnCreateBufferMappedResult result;
|
||||||
|
result.buffer = reinterpret_cast<DawnBuffer>(buffer);
|
||||||
|
result.data = reinterpret_cast<uint8_t*>(buffer->mappedData);
|
||||||
|
result.dataLength = descriptor->size;
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t ClientFenceGetCompletedValue(DawnFence cSelf) {
|
uint64_t ClientFenceGetCompletedValue(DawnFence cSelf) {
|
||||||
|
|
|
@ -108,6 +108,9 @@ namespace dawn_wire { namespace client {
|
||||||
|
|
||||||
buffer->isWriteMapped = true;
|
buffer->isWriteMapped = true;
|
||||||
buffer->mappedDataSize = dataLength;
|
buffer->mappedDataSize = dataLength;
|
||||||
|
// |mappedData| is freed in Unmap or the Buffer destructor.
|
||||||
|
// TODO(enga): Add dependency injection for buffer mapping so staging
|
||||||
|
// memory can live in shared memory.
|
||||||
buffer->mappedData = malloc(dataLength);
|
buffer->mappedData = malloc(dataLength);
|
||||||
memset(buffer->mappedData, 0, dataLength);
|
memset(buffer->mappedData, 0, dataLength);
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,25 @@ namespace dawn_wire { namespace server {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Server::DoDeviceCreateBufferMapped(DawnDevice device,
|
||||||
|
const DawnBufferDescriptor* descriptor,
|
||||||
|
ObjectHandle bufferResult) {
|
||||||
|
auto* resultData = BufferObjects().Allocate(bufferResult.id);
|
||||||
|
if (resultData == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
resultData->serial = bufferResult.serial;
|
||||||
|
|
||||||
|
DawnCreateBufferMappedResult result = mProcs.deviceCreateBufferMapped(device, descriptor);
|
||||||
|
ASSERT(result.buffer != nullptr);
|
||||||
|
ASSERT(result.data != nullptr);
|
||||||
|
resultData->handle = result.buffer;
|
||||||
|
resultData->mappedData = result.data;
|
||||||
|
resultData->mappedDataSize = result.dataLength;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Server::DoBufferUpdateMappedData(ObjectId bufferId, uint32_t count, const uint8_t* data) {
|
bool Server::DoBufferUpdateMappedData(ObjectId bufferId, uint32_t count, const uint8_t* data) {
|
||||||
// The null object isn't valid as `self`
|
// The null object isn't valid as `self`
|
||||||
if (bufferId == 0) {
|
if (bufferId == 0) {
|
||||||
|
|
|
@ -269,6 +269,89 @@ TEST_P(CreateBufferMappedTests, LargeSyncWrite) {
|
||||||
EXPECT_BUFFER_U32_RANGE_EQ(myData.data(), result.buffer, 0, kDataSize);
|
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, ZeroInitialized) {
|
||||||
|
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(*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));
|
||||||
|
result.buffer.Unmap();
|
||||||
|
|
||||||
|
EXPECT_BUFFER_U32_EQ(myData, result.buffer, 0);
|
||||||
|
|
||||||
|
bool done = false;
|
||||||
|
result.buffer.MapWriteAsync(
|
||||||
|
[](DawnBufferMapAsyncStatus status, void* data, uint64_t, DawnCallbackUserdata userdata) {
|
||||||
|
ASSERT_EQ(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, status);
|
||||||
|
ASSERT_NE(nullptr, data);
|
||||||
|
|
||||||
|
*reinterpret_cast<uint32_t*>(data) = myData2;
|
||||||
|
*reinterpret_cast<bool*>(static_cast<uintptr_t>(userdata)) = true;
|
||||||
|
},
|
||||||
|
static_cast<DawnCallbackUserdata>(reinterpret_cast<uintptr_t>(&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 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));
|
||||||
|
|
||||||
|
ASSERT_DEVICE_ERROR([&]() {
|
||||||
|
bool done = false;
|
||||||
|
result.buffer.MapWriteAsync(
|
||||||
|
[](DawnBufferMapAsyncStatus status, void* data, uint64_t,
|
||||||
|
DawnCallbackUserdata userdata) {
|
||||||
|
ASSERT_EQ(DAWN_BUFFER_MAP_ASYNC_STATUS_ERROR, status);
|
||||||
|
ASSERT_EQ(nullptr, data);
|
||||||
|
|
||||||
|
*reinterpret_cast<bool*>(static_cast<uintptr_t>(userdata)) = true;
|
||||||
|
},
|
||||||
|
static_cast<DawnCallbackUserdata>(reinterpret_cast<uintptr_t>(&done)));
|
||||||
|
|
||||||
|
while (!done) {
|
||||||
|
WaitABit();
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
|
||||||
|
// CreateBufferMapped is unaffected by the MapWrite error.
|
||||||
|
result.buffer.Unmap();
|
||||||
|
EXPECT_BUFFER_U32_EQ(myData, result.buffer, 0);
|
||||||
|
}
|
||||||
|
|
||||||
DAWN_INSTANTIATE_TEST(CreateBufferMappedTests,
|
DAWN_INSTANTIATE_TEST(CreateBufferMappedTests,
|
||||||
D3D12Backend,
|
D3D12Backend,
|
||||||
MetalBackend,
|
MetalBackend,
|
||||||
|
|
|
@ -494,3 +494,146 @@ TEST_F(WireBufferMappingTests, DestroyInsideMapWriteCallback) {
|
||||||
|
|
||||||
FlushClient();
|
FlushClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test successful CreateBufferMapped
|
||||||
|
TEST_F(WireBufferMappingTests, CreateBufferMappedSuccess) {
|
||||||
|
DawnBufferDescriptor descriptor;
|
||||||
|
descriptor.nextInChain = nullptr;
|
||||||
|
descriptor.size = 4;
|
||||||
|
|
||||||
|
DawnBuffer apiBuffer = api.GetNewBuffer();
|
||||||
|
DawnCreateBufferMappedResult apiResult;
|
||||||
|
uint32_t apiBufferData = 1234;
|
||||||
|
apiResult.buffer = apiBuffer;
|
||||||
|
apiResult.data = reinterpret_cast<uint8_t*>(&apiBufferData);
|
||||||
|
apiResult.dataLength = 4;
|
||||||
|
|
||||||
|
DawnCreateBufferMappedResult result = dawnDeviceCreateBufferMapped(device, &descriptor);
|
||||||
|
|
||||||
|
EXPECT_CALL(api, DeviceCreateBufferMapped(apiDevice, _))
|
||||||
|
.WillOnce(Return(apiResult))
|
||||||
|
.RetiresOnSaturation();
|
||||||
|
|
||||||
|
FlushClient();
|
||||||
|
|
||||||
|
dawnBufferUnmap(result.buffer);
|
||||||
|
EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1);
|
||||||
|
|
||||||
|
FlushClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that releasing after CreateBufferMapped does not call Unmap
|
||||||
|
TEST_F(WireBufferMappingTests, ReleaseAfterCreateBufferMapped) {
|
||||||
|
DawnBufferDescriptor descriptor;
|
||||||
|
descriptor.nextInChain = nullptr;
|
||||||
|
descriptor.size = 4;
|
||||||
|
|
||||||
|
DawnBuffer apiBuffer = api.GetNewBuffer();
|
||||||
|
DawnCreateBufferMappedResult apiResult;
|
||||||
|
uint32_t apiBufferData = 1234;
|
||||||
|
apiResult.buffer = apiBuffer;
|
||||||
|
apiResult.data = reinterpret_cast<uint8_t*>(&apiBufferData);
|
||||||
|
apiResult.dataLength = 4;
|
||||||
|
|
||||||
|
DawnCreateBufferMappedResult result = dawnDeviceCreateBufferMapped(device, &descriptor);
|
||||||
|
|
||||||
|
EXPECT_CALL(api, DeviceCreateBufferMapped(apiDevice, _))
|
||||||
|
.WillOnce(Return(apiResult))
|
||||||
|
.RetiresOnSaturation();
|
||||||
|
|
||||||
|
FlushClient();
|
||||||
|
|
||||||
|
dawnBufferRelease(result.buffer);
|
||||||
|
EXPECT_CALL(api, BufferRelease(apiBuffer)).Times(1);
|
||||||
|
|
||||||
|
FlushClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that it is valid to map a buffer after CreateBufferMapped and Unmap
|
||||||
|
TEST_F(WireBufferMappingTests, CreateBufferMappedThenMapSuccess) {
|
||||||
|
DawnBufferDescriptor descriptor;
|
||||||
|
descriptor.nextInChain = nullptr;
|
||||||
|
descriptor.size = 4;
|
||||||
|
|
||||||
|
DawnBuffer apiBuffer = api.GetNewBuffer();
|
||||||
|
DawnCreateBufferMappedResult apiResult;
|
||||||
|
uint32_t apiBufferData = 9863;
|
||||||
|
apiResult.buffer = apiBuffer;
|
||||||
|
apiResult.data = reinterpret_cast<uint8_t*>(&apiBufferData);
|
||||||
|
apiResult.dataLength = 4;
|
||||||
|
|
||||||
|
DawnCreateBufferMappedResult result = dawnDeviceCreateBufferMapped(device, &descriptor);
|
||||||
|
|
||||||
|
EXPECT_CALL(api, DeviceCreateBufferMapped(apiDevice, _))
|
||||||
|
.WillOnce(Return(apiResult))
|
||||||
|
.RetiresOnSaturation();
|
||||||
|
|
||||||
|
FlushClient();
|
||||||
|
|
||||||
|
dawnBufferUnmap(result.buffer);
|
||||||
|
EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1);
|
||||||
|
|
||||||
|
FlushClient();
|
||||||
|
|
||||||
|
DawnCallbackUserdata userdata = 2499;
|
||||||
|
dawnBufferMapWriteAsync(result.buffer, ToMockBufferMapWriteCallback, userdata);
|
||||||
|
|
||||||
|
uint32_t zero = 0;
|
||||||
|
EXPECT_CALL(api, OnBufferMapWriteAsyncCallback(apiBuffer, _, _))
|
||||||
|
.WillOnce(InvokeWithoutArgs([&]() {
|
||||||
|
api.CallMapWriteCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
||||||
|
&apiBufferData, sizeof(uint32_t));
|
||||||
|
}));
|
||||||
|
|
||||||
|
FlushClient();
|
||||||
|
|
||||||
|
EXPECT_CALL(*mockBufferMapWriteCallback,
|
||||||
|
Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
||||||
|
Pointee(Eq(zero)), sizeof(uint32_t), userdata))
|
||||||
|
.Times(1);
|
||||||
|
|
||||||
|
FlushServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that it is invalid to map a buffer after CreateBufferMapped before Unmap
|
||||||
|
TEST_F(WireBufferMappingTests, CreateBufferMappedThenMapFailure) {
|
||||||
|
DawnBufferDescriptor descriptor;
|
||||||
|
descriptor.nextInChain = nullptr;
|
||||||
|
descriptor.size = 4;
|
||||||
|
|
||||||
|
DawnBuffer apiBuffer = api.GetNewBuffer();
|
||||||
|
DawnCreateBufferMappedResult apiResult;
|
||||||
|
uint32_t apiBufferData = 9863;
|
||||||
|
apiResult.buffer = apiBuffer;
|
||||||
|
apiResult.data = reinterpret_cast<uint8_t*>(&apiBufferData);
|
||||||
|
apiResult.dataLength = 4;
|
||||||
|
|
||||||
|
DawnCreateBufferMappedResult result = dawnDeviceCreateBufferMapped(device, &descriptor);
|
||||||
|
|
||||||
|
EXPECT_CALL(api, DeviceCreateBufferMapped(apiDevice, _))
|
||||||
|
.WillOnce(Return(apiResult))
|
||||||
|
.RetiresOnSaturation();
|
||||||
|
|
||||||
|
FlushClient();
|
||||||
|
|
||||||
|
DawnCallbackUserdata userdata = 2499;
|
||||||
|
dawnBufferMapWriteAsync(result.buffer, ToMockBufferMapWriteCallback, userdata);
|
||||||
|
|
||||||
|
EXPECT_CALL(api, OnBufferMapWriteAsyncCallback(apiBuffer, _, _))
|
||||||
|
.WillOnce(InvokeWithoutArgs([&]() {
|
||||||
|
api.CallMapWriteCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_ERROR, nullptr, 0);
|
||||||
|
}));
|
||||||
|
|
||||||
|
FlushClient();
|
||||||
|
|
||||||
|
EXPECT_CALL(*mockBufferMapWriteCallback,
|
||||||
|
Call(DAWN_BUFFER_MAP_ASYNC_STATUS_ERROR, nullptr, 0, userdata))
|
||||||
|
.Times(1);
|
||||||
|
|
||||||
|
FlushServer();
|
||||||
|
|
||||||
|
dawnBufferUnmap(result.buffer);
|
||||||
|
EXPECT_CALL(api, BufferUnmap(apiBuffer)).Times(1);
|
||||||
|
|
||||||
|
FlushClient();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue