mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-07-25 14:35:49 +00:00
Add MemoryTransfer interfaces to the wire
This patch adds MemoryTransfer client/server interfaces and uses it to implement data transfers for buffer mapping. This patch also provides a default "inline" implementation of the MemoryTransfer which is used if the embedder does not provide one on initialization. Because implementations of MemoryTransfer perform their own serialization, a skip_serialize option is added to WireCmd records. Bug: dawn:156 Change-Id: I2fa035517628a3ad465b0bc18a6ffc477e2bd67f Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/8642 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
49aae0f3bd
commit
6a5418a760
2
BUILD.gn
2
BUILD.gn
@ -461,6 +461,7 @@ dawn_component("libdawn_wire") {
|
|||||||
"src/dawn_wire/client/Client.cpp",
|
"src/dawn_wire/client/Client.cpp",
|
||||||
"src/dawn_wire/client/Client.h",
|
"src/dawn_wire/client/Client.h",
|
||||||
"src/dawn_wire/client/ClientDoers.cpp",
|
"src/dawn_wire/client/ClientDoers.cpp",
|
||||||
|
"src/dawn_wire/client/ClientInlineMemoryTransferService.cpp",
|
||||||
"src/dawn_wire/client/Device.cpp",
|
"src/dawn_wire/client/Device.cpp",
|
||||||
"src/dawn_wire/client/Device.h",
|
"src/dawn_wire/client/Device.h",
|
||||||
"src/dawn_wire/client/Fence.cpp",
|
"src/dawn_wire/client/Fence.cpp",
|
||||||
@ -472,6 +473,7 @@ dawn_component("libdawn_wire") {
|
|||||||
"src/dawn_wire/server/ServerBuffer.cpp",
|
"src/dawn_wire/server/ServerBuffer.cpp",
|
||||||
"src/dawn_wire/server/ServerDevice.cpp",
|
"src/dawn_wire/server/ServerDevice.cpp",
|
||||||
"src/dawn_wire/server/ServerFence.cpp",
|
"src/dawn_wire/server/ServerFence.cpp",
|
||||||
|
"src/dawn_wire/server/ServerInlineMemoryTransferService.cpp",
|
||||||
"src/dawn_wire/server/ServerQueue.cpp",
|
"src/dawn_wire/server/ServerQueue.cpp",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -18,7 +18,9 @@
|
|||||||
"buffer map async": [
|
"buffer map async": [
|
||||||
{ "name": "buffer id", "type": "ObjectId" },
|
{ "name": "buffer id", "type": "ObjectId" },
|
||||||
{ "name": "request serial", "type": "uint32_t" },
|
{ "name": "request serial", "type": "uint32_t" },
|
||||||
{ "name": "is write", "type": "bool" }
|
{ "name": "is write", "type": "bool" },
|
||||||
|
{ "name": "handle create info length", "type": "uint64_t" },
|
||||||
|
{ "name": "handle create info", "type": "uint8_t", "annotation": "const*", "length": "handle create info length", "skip_serialize": true}
|
||||||
],
|
],
|
||||||
"buffer set sub data internal": [
|
"buffer set sub data internal": [
|
||||||
{"name": "buffer id", "type": "ObjectId" },
|
{"name": "buffer id", "type": "ObjectId" },
|
||||||
@ -28,19 +30,23 @@
|
|||||||
],
|
],
|
||||||
"buffer update mapped data": [
|
"buffer update mapped data": [
|
||||||
{ "name": "buffer id", "type": "ObjectId" },
|
{ "name": "buffer id", "type": "ObjectId" },
|
||||||
{ "name": "data length", "type": "uint32_t" },
|
{ "name": "write flush info length", "type": "uint64_t" },
|
||||||
{ "name": "data", "type": "uint8_t", "annotation": "const*", "length": "data length" }
|
{ "name": "write flush info", "type": "uint8_t", "annotation": "const*", "length": "write flush info length", "skip_serialize": true}
|
||||||
],
|
],
|
||||||
"device create buffer mapped": [
|
"device create buffer mapped": [
|
||||||
{ "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" },
|
||||||
|
{ "name": "handle create info length", "type": "uint64_t" },
|
||||||
|
{ "name": "handle create info", "type": "uint8_t", "annotation": "const*", "length": "handle create info length", "skip_serialize": true}
|
||||||
],
|
],
|
||||||
"device create buffer mapped async": [
|
"device create buffer mapped async": [
|
||||||
{ "name": "device", "type": "device" },
|
{ "name": "device", "type": "device" },
|
||||||
{ "name": "descriptor", "type": "buffer descriptor", "annotation": "const*" },
|
{ "name": "descriptor", "type": "buffer descriptor", "annotation": "const*" },
|
||||||
{ "name": "request serial", "type": "uint32_t" },
|
{ "name": "request serial", "type": "uint32_t" },
|
||||||
{ "name": "result", "type": "ObjectHandle", "handle_type": "buffer" }
|
{ "name": "result", "type": "ObjectHandle", "handle_type": "buffer" },
|
||||||
|
{ "name": "handle create info length", "type": "uint64_t" },
|
||||||
|
{ "name": "handle create info", "type": "uint8_t", "annotation": "const*", "length": "handle create info length", "skip_serialize": true}
|
||||||
],
|
],
|
||||||
"destroy object": [
|
"destroy object": [
|
||||||
{ "name": "object type", "type": "ObjectType" },
|
{ "name": "object type", "type": "ObjectType" },
|
||||||
@ -52,14 +58,13 @@
|
|||||||
{ "name": "buffer", "type": "ObjectHandle", "handle_type": "buffer" },
|
{ "name": "buffer", "type": "ObjectHandle", "handle_type": "buffer" },
|
||||||
{ "name": "request serial", "type": "uint32_t" },
|
{ "name": "request serial", "type": "uint32_t" },
|
||||||
{ "name": "status", "type": "uint32_t" },
|
{ "name": "status", "type": "uint32_t" },
|
||||||
{ "name": "data length", "type": "uint64_t" },
|
{ "name": "initial data info length", "type": "uint64_t" },
|
||||||
{ "name": "data", "type": "uint8_t", "annotation": "const*", "length": "data length" }
|
{ "name": "initial data info", "type": "uint8_t", "annotation": "const*", "length": "initial data info length", "skip_serialize": true }
|
||||||
],
|
],
|
||||||
"buffer map write async callback": [
|
"buffer map write async callback": [
|
||||||
{ "name": "buffer", "type": "ObjectHandle", "handle_type": "buffer" },
|
{ "name": "buffer", "type": "ObjectHandle", "handle_type": "buffer" },
|
||||||
{ "name": "request serial", "type": "uint32_t" },
|
{ "name": "request serial", "type": "uint32_t" },
|
||||||
{ "name": "status", "type": "uint32_t" },
|
{ "name": "status", "type": "uint32_t" }
|
||||||
{ "name": "data length", "type": "uint64_t" }
|
|
||||||
],
|
],
|
||||||
"device error callback": [
|
"device error callback": [
|
||||||
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
|
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
|
||||||
@ -80,6 +85,7 @@
|
|||||||
"client_handwritten_commands": [
|
"client_handwritten_commands": [
|
||||||
"BufferSetSubData",
|
"BufferSetSubData",
|
||||||
"BufferUnmap",
|
"BufferUnmap",
|
||||||
|
"DeviceCreateBuffer",
|
||||||
"DeviceCreateBufferMapped",
|
"DeviceCreateBufferMapped",
|
||||||
"DeviceCreateBufferMappedAsync",
|
"DeviceCreateBufferMappedAsync",
|
||||||
"QueueCreateFence",
|
"QueueCreateFence",
|
||||||
|
@ -121,10 +121,18 @@ dawn::Device CreateCppDawnDevice() {
|
|||||||
c2sBuf = new utils::TerribleCommandBuffer();
|
c2sBuf = new utils::TerribleCommandBuffer();
|
||||||
s2cBuf = new utils::TerribleCommandBuffer();
|
s2cBuf = new utils::TerribleCommandBuffer();
|
||||||
|
|
||||||
wireServer = new dawn_wire::WireServer(backendDevice, backendProcs, s2cBuf);
|
dawn_wire::WireServerDescriptor serverDesc = {};
|
||||||
|
serverDesc.device = backendDevice;
|
||||||
|
serverDesc.procs = &backendProcs;
|
||||||
|
serverDesc.serializer = s2cBuf;
|
||||||
|
|
||||||
|
wireServer = new dawn_wire::WireServer(serverDesc);
|
||||||
c2sBuf->SetHandler(wireServer);
|
c2sBuf->SetHandler(wireServer);
|
||||||
|
|
||||||
wireClient = new dawn_wire::WireClient(c2sBuf);
|
dawn_wire::WireClientDescriptor clientDesc = {};
|
||||||
|
clientDesc.serializer = c2sBuf;
|
||||||
|
|
||||||
|
wireClient = new dawn_wire::WireClient(clientDesc);
|
||||||
DawnDevice clientDevice = wireClient->GetDevice();
|
DawnDevice clientDevice = wireClient->GetDevice();
|
||||||
DawnProcTable clientProcs = wireClient->GetProcs();
|
DawnProcTable clientProcs = wireClient->GetProcs();
|
||||||
s2cBuf->SetHandler(wireClient);
|
s2cBuf->SetHandler(wireClient);
|
||||||
|
@ -95,7 +95,8 @@ class NativelyDefined(Type):
|
|||||||
# method arguments or structure members.
|
# method arguments or structure members.
|
||||||
class RecordMember:
|
class RecordMember:
|
||||||
def __init__(self, name, typ, annotation, optional=False,
|
def __init__(self, name, typ, annotation, optional=False,
|
||||||
is_return_value=False, default_value=None):
|
is_return_value=False, default_value=None,
|
||||||
|
skip_serialize=False):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.type = typ
|
self.type = typ
|
||||||
self.annotation = annotation
|
self.annotation = annotation
|
||||||
@ -104,6 +105,7 @@ class RecordMember:
|
|||||||
self.is_return_value = is_return_value
|
self.is_return_value = is_return_value
|
||||||
self.handle_type = None
|
self.handle_type = None
|
||||||
self.default_value = default_value
|
self.default_value = default_value
|
||||||
|
self.skip_serialize = skip_serialize
|
||||||
|
|
||||||
def set_handle_type(self, handle_type):
|
def set_handle_type(self, handle_type):
|
||||||
assert self.type.dict_name == "ObjectHandle"
|
assert self.type.dict_name == "ObjectHandle"
|
||||||
@ -155,7 +157,8 @@ def linked_record_members(json_data, types):
|
|||||||
m.get('annotation', 'value'),
|
m.get('annotation', 'value'),
|
||||||
optional=m.get('optional', False),
|
optional=m.get('optional', False),
|
||||||
is_return_value=m.get('is_return_value', False),
|
is_return_value=m.get('is_return_value', False),
|
||||||
default_value=m.get('default', None))
|
default_value=m.get('default', None),
|
||||||
|
skip_serialize=m.get('skip_serialize', False))
|
||||||
handle_type = m.get('handle_type')
|
handle_type = m.get('handle_type')
|
||||||
if handle_type:
|
if handle_type:
|
||||||
member.set_handle_type(types[handle_type])
|
member.set_handle_type(types[handle_type])
|
||||||
|
@ -123,7 +123,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
//* Gather how much space will be needed for pointer members.
|
//* Gather how much space will be needed for pointer members.
|
||||||
{% for member in members if member.annotation != "value" and member.length != "strlen" %}
|
{% for member in members if member.annotation != "value" and member.length != "strlen" and not member.skip_serialize %}
|
||||||
{% if member.type.category != "object" and member.optional %}
|
{% if member.type.category != "object" and member.optional %}
|
||||||
if (record.{{as_varName(member.name)}} != nullptr)
|
if (record.{{as_varName(member.name)}} != nullptr)
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -181,7 +181,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
//* Allocate space and write the non-value arguments in it.
|
//* Allocate space and write the non-value arguments in it.
|
||||||
{% for member in members if member.annotation != "value" and member.length != "strlen" %}
|
{% for member in members if member.annotation != "value" and member.length != "strlen" and not member.skip_serialize %}
|
||||||
{% set memberName = as_varName(member.name) %}
|
{% set memberName = as_varName(member.name) %}
|
||||||
|
|
||||||
{% if member.type.category != "object" and member.optional %}
|
{% if member.type.category != "object" and member.optional %}
|
||||||
|
@ -17,7 +17,8 @@
|
|||||||
|
|
||||||
namespace dawn_wire {
|
namespace dawn_wire {
|
||||||
|
|
||||||
WireClient::WireClient(CommandSerializer* serializer) : mImpl(new client::Client(serializer)) {
|
WireClient::WireClient(const WireClientDescriptor& descriptor)
|
||||||
|
: mImpl(new client::Client(descriptor.serializer, descriptor.memoryTransferService)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
WireClient::~WireClient() {
|
WireClient::~WireClient() {
|
||||||
@ -40,4 +41,22 @@ namespace dawn_wire {
|
|||||||
return mImpl->ReserveTexture(device);
|
return mImpl->ReserveTexture(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace client {
|
||||||
|
MemoryTransferService::~MemoryTransferService() = default;
|
||||||
|
|
||||||
|
MemoryTransferService::ReadHandle*
|
||||||
|
MemoryTransferService::CreateReadHandle(DawnBuffer buffer, uint64_t offset, size_t size) {
|
||||||
|
return CreateReadHandle(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryTransferService::WriteHandle*
|
||||||
|
MemoryTransferService::CreateWriteHandle(DawnBuffer buffer, uint64_t offset, size_t size) {
|
||||||
|
return CreateWriteHandle(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryTransferService::ReadHandle::~ReadHandle() = default;
|
||||||
|
|
||||||
|
MemoryTransferService::WriteHandle::~WriteHandle() = default;
|
||||||
|
} // namespace client
|
||||||
|
|
||||||
} // namespace dawn_wire
|
} // namespace dawn_wire
|
||||||
|
@ -17,10 +17,11 @@
|
|||||||
|
|
||||||
namespace dawn_wire {
|
namespace dawn_wire {
|
||||||
|
|
||||||
WireServer::WireServer(DawnDevice device,
|
WireServer::WireServer(const WireServerDescriptor& descriptor)
|
||||||
const DawnProcTable& procs,
|
: mImpl(new server::Server(descriptor.device,
|
||||||
CommandSerializer* serializer)
|
*descriptor.procs,
|
||||||
: mImpl(new server::Server(device, procs, serializer)) {
|
descriptor.serializer,
|
||||||
|
descriptor.memoryTransferService)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
WireServer::~WireServer() {
|
WireServer::~WireServer() {
|
||||||
@ -35,4 +36,17 @@ namespace dawn_wire {
|
|||||||
return mImpl->InjectTexture(texture, id, generation);
|
return mImpl->InjectTexture(texture, id, generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace server {
|
||||||
|
MemoryTransferService::~MemoryTransferService() = default;
|
||||||
|
|
||||||
|
MemoryTransferService::ReadHandle::~ReadHandle() = default;
|
||||||
|
|
||||||
|
MemoryTransferService::WriteHandle::~WriteHandle() = default;
|
||||||
|
|
||||||
|
void MemoryTransferService::WriteHandle::SetTarget(void* data, size_t dataLength) {
|
||||||
|
mTargetData = data;
|
||||||
|
mDataLength = dataLength;
|
||||||
|
}
|
||||||
|
} // namespace server
|
||||||
|
|
||||||
} // namespace dawn_wire
|
} // namespace dawn_wire
|
||||||
|
@ -18,6 +18,34 @@
|
|||||||
|
|
||||||
namespace dawn_wire { namespace client {
|
namespace dawn_wire { namespace client {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
template <typename Handle>
|
||||||
|
void SerializeBufferMapAsync(const Buffer* buffer, uint32_t serial, Handle* handle) {
|
||||||
|
// TODO(enga): Remove the template when Read/Write handles are combined in a tagged
|
||||||
|
// pointer.
|
||||||
|
constexpr bool isWrite =
|
||||||
|
std::is_same<Handle, MemoryTransferService::WriteHandle>::value;
|
||||||
|
|
||||||
|
// Get the serialization size of the handle.
|
||||||
|
size_t handleCreateInfoLength = handle->SerializeCreate();
|
||||||
|
|
||||||
|
BufferMapAsyncCmd cmd;
|
||||||
|
cmd.bufferId = buffer->id;
|
||||||
|
cmd.requestSerial = serial;
|
||||||
|
cmd.isWrite = isWrite;
|
||||||
|
cmd.handleCreateInfoLength = handleCreateInfoLength;
|
||||||
|
cmd.handleCreateInfo = nullptr;
|
||||||
|
|
||||||
|
size_t commandSize = cmd.GetRequiredSize();
|
||||||
|
size_t requiredSize = commandSize + handleCreateInfoLength;
|
||||||
|
char* allocatedBuffer =
|
||||||
|
static_cast<char*>(buffer->device->GetClient()->GetCmdSpace(requiredSize));
|
||||||
|
cmd.Serialize(allocatedBuffer);
|
||||||
|
// Serialize the handle into the space after the command.
|
||||||
|
handle->SerializeCreate(allocatedBuffer + commandSize);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
void ClientBufferMapReadAsync(DawnBuffer cBuffer,
|
void ClientBufferMapReadAsync(DawnBuffer cBuffer,
|
||||||
DawnBufferMapReadCallback callback,
|
DawnBufferMapReadCallback callback,
|
||||||
void* userdata) {
|
void* userdata) {
|
||||||
@ -26,21 +54,26 @@ namespace dawn_wire { namespace client {
|
|||||||
uint32_t serial = buffer->requestSerial++;
|
uint32_t serial = buffer->requestSerial++;
|
||||||
ASSERT(buffer->requests.find(serial) == buffer->requests.end());
|
ASSERT(buffer->requests.find(serial) == buffer->requests.end());
|
||||||
|
|
||||||
Buffer::MapRequestData request;
|
// Create a ReadHandle for the map request. This is the client's intent to read GPU
|
||||||
|
// memory.
|
||||||
|
MemoryTransferService::ReadHandle* readHandle =
|
||||||
|
buffer->device->GetClient()->GetMemoryTransferService()->CreateReadHandle(buffer->size);
|
||||||
|
if (readHandle == nullptr) {
|
||||||
|
callback(DAWN_BUFFER_MAP_ASYNC_STATUS_CONTEXT_LOST, nullptr, 0, userdata);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer::MapRequestData request = {};
|
||||||
request.readCallback = callback;
|
request.readCallback = callback;
|
||||||
request.userdata = userdata;
|
request.userdata = userdata;
|
||||||
request.isWrite = false;
|
// The handle is owned by the MapRequest until the callback returns.
|
||||||
buffer->requests[serial] = request;
|
request.readHandle = std::unique_ptr<MemoryTransferService::ReadHandle>(readHandle);
|
||||||
|
|
||||||
BufferMapAsyncCmd cmd;
|
// Store a mapping from serial -> MapRequest. The client can map/unmap before the map
|
||||||
cmd.bufferId = buffer->id;
|
// operations are returned by the server so multiple requests may be in flight.
|
||||||
cmd.requestSerial = serial;
|
buffer->requests[serial] = std::move(request);
|
||||||
cmd.isWrite = false;
|
|
||||||
|
|
||||||
size_t requiredSize = cmd.GetRequiredSize();
|
SerializeBufferMapAsync(buffer, serial, readHandle);
|
||||||
char* allocatedBuffer =
|
|
||||||
static_cast<char*>(buffer->device->GetClient()->GetCmdSpace(requiredSize));
|
|
||||||
cmd.Serialize(allocatedBuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientBufferMapWriteAsync(DawnBuffer cBuffer,
|
void ClientBufferMapWriteAsync(DawnBuffer cBuffer,
|
||||||
@ -51,21 +84,50 @@ namespace dawn_wire { namespace client {
|
|||||||
uint32_t serial = buffer->requestSerial++;
|
uint32_t serial = buffer->requestSerial++;
|
||||||
ASSERT(buffer->requests.find(serial) == buffer->requests.end());
|
ASSERT(buffer->requests.find(serial) == buffer->requests.end());
|
||||||
|
|
||||||
Buffer::MapRequestData request;
|
// Create a WriteHandle for the map request. This is the client's intent to write GPU
|
||||||
|
// memory.
|
||||||
|
MemoryTransferService::WriteHandle* writeHandle =
|
||||||
|
buffer->device->GetClient()->GetMemoryTransferService()->CreateWriteHandle(
|
||||||
|
buffer->size);
|
||||||
|
if (writeHandle == nullptr) {
|
||||||
|
callback(DAWN_BUFFER_MAP_ASYNC_STATUS_CONTEXT_LOST, nullptr, 0, userdata);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer::MapRequestData request = {};
|
||||||
request.writeCallback = callback;
|
request.writeCallback = callback;
|
||||||
request.userdata = userdata;
|
request.userdata = userdata;
|
||||||
request.isWrite = true;
|
// The handle is owned by the MapRequest until the callback returns.
|
||||||
buffer->requests[serial] = request;
|
request.writeHandle = std::unique_ptr<MemoryTransferService::WriteHandle>(writeHandle);
|
||||||
|
|
||||||
BufferMapAsyncCmd cmd;
|
// Store a mapping from serial -> MapRequest. The client can map/unmap before the map
|
||||||
cmd.bufferId = buffer->id;
|
// operations are returned by the server so multiple requests may be in flight.
|
||||||
cmd.requestSerial = serial;
|
buffer->requests[serial] = std::move(request);
|
||||||
cmd.isWrite = true;
|
|
||||||
|
SerializeBufferMapAsync(buffer, serial, writeHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
DawnBuffer ClientDeviceCreateBuffer(DawnDevice cDevice,
|
||||||
|
const DawnBufferDescriptor* descriptor) {
|
||||||
|
Device* device = reinterpret_cast<Device*>(cDevice);
|
||||||
|
Client* wireClient = device->GetClient();
|
||||||
|
|
||||||
|
auto* bufferObjectAndSerial = wireClient->BufferAllocator().New(device);
|
||||||
|
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->size = descriptor->size;
|
||||||
|
|
||||||
|
DeviceCreateBufferCmd cmd;
|
||||||
|
cmd.self = cDevice;
|
||||||
|
cmd.descriptor = descriptor;
|
||||||
|
cmd.result = ObjectHandle{buffer->id, bufferObjectAndSerial->serial};
|
||||||
|
|
||||||
size_t requiredSize = cmd.GetRequiredSize();
|
size_t requiredSize = cmd.GetRequiredSize();
|
||||||
char* allocatedBuffer =
|
char* allocatedBuffer = static_cast<char*>(wireClient->GetCmdSpace(requiredSize));
|
||||||
static_cast<char*>(buffer->device->GetClient()->GetCmdSpace(requiredSize));
|
cmd.Serialize(allocatedBuffer, *wireClient);
|
||||||
cmd.Serialize(allocatedBuffer);
|
|
||||||
|
return reinterpret_cast<DawnBuffer>(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
DawnCreateBufferMappedResult ClientDeviceCreateBufferMapped(
|
DawnCreateBufferMappedResult ClientDeviceCreateBufferMapped(
|
||||||
@ -76,27 +138,54 @@ namespace dawn_wire { namespace client {
|
|||||||
|
|
||||||
auto* bufferObjectAndSerial = wireClient->BufferAllocator().New(device);
|
auto* bufferObjectAndSerial = wireClient->BufferAllocator().New(device);
|
||||||
Buffer* buffer = bufferObjectAndSerial->object.get();
|
Buffer* buffer = bufferObjectAndSerial->object.get();
|
||||||
buffer->isWriteMapped = true;
|
buffer->size = descriptor->size;
|
||||||
// |mappedData| is freed in Unmap or the Buffer destructor.
|
|
||||||
// TODO(enga): Add dependency injection for buffer mapping so staging
|
DawnCreateBufferMappedResult result;
|
||||||
// memory can live in shared memory.
|
result.buffer = reinterpret_cast<DawnBuffer>(buffer);
|
||||||
buffer->mappedData = malloc(descriptor->size);
|
result.data = nullptr;
|
||||||
memset(buffer->mappedData, 0, descriptor->size);
|
result.dataLength = 0;
|
||||||
buffer->mappedDataSize = descriptor->size;
|
|
||||||
|
// 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) {
|
||||||
|
// TODO(enga): Support context lost generated by the client.
|
||||||
|
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) {
|
||||||
|
// TODO(enga): Support context lost generated by the client.
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Successfully created staging memory. The buffer now owns the WriteHandle.
|
||||||
|
buffer->writeHandle = std::move(writeHandle);
|
||||||
|
|
||||||
|
// Get the serialization size of the WriteHandle.
|
||||||
|
size_t handleCreateInfoLength = buffer->writeHandle->SerializeCreate();
|
||||||
|
|
||||||
DeviceCreateBufferMappedCmd cmd;
|
DeviceCreateBufferMappedCmd cmd;
|
||||||
cmd.device = cDevice;
|
cmd.device = cDevice;
|
||||||
cmd.descriptor = descriptor;
|
cmd.descriptor = descriptor;
|
||||||
cmd.result = ObjectHandle{buffer->id, bufferObjectAndSerial->serial};
|
cmd.result = ObjectHandle{buffer->id, bufferObjectAndSerial->serial};
|
||||||
|
cmd.handleCreateInfoLength = handleCreateInfoLength;
|
||||||
|
cmd.handleCreateInfo = nullptr;
|
||||||
|
|
||||||
size_t requiredSize = cmd.GetRequiredSize();
|
size_t commandSize = cmd.GetRequiredSize();
|
||||||
|
size_t requiredSize = commandSize + handleCreateInfoLength;
|
||||||
char* allocatedBuffer = static_cast<char*>(wireClient->GetCmdSpace(requiredSize));
|
char* allocatedBuffer = static_cast<char*>(wireClient->GetCmdSpace(requiredSize));
|
||||||
cmd.Serialize(allocatedBuffer, *wireClient);
|
cmd.Serialize(allocatedBuffer, *wireClient);
|
||||||
|
// Serialize the WriteHandle into the space after the command.
|
||||||
DawnCreateBufferMappedResult result;
|
buffer->writeHandle->SerializeCreate(allocatedBuffer + commandSize);
|
||||||
result.buffer = reinterpret_cast<DawnBuffer>(buffer);
|
|
||||||
result.data = reinterpret_cast<uint8_t*>(buffer->mappedData);
|
|
||||||
result.dataLength = descriptor->size;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -110,6 +199,7 @@ namespace dawn_wire { namespace client {
|
|||||||
|
|
||||||
auto* bufferObjectAndSerial = wireClient->BufferAllocator().New(device);
|
auto* bufferObjectAndSerial = wireClient->BufferAllocator().New(device);
|
||||||
Buffer* buffer = bufferObjectAndSerial->object.get();
|
Buffer* buffer = bufferObjectAndSerial->object.get();
|
||||||
|
buffer->size = descriptor->size;
|
||||||
|
|
||||||
uint32_t serial = buffer->requestSerial++;
|
uint32_t serial = buffer->requestSerial++;
|
||||||
|
|
||||||
@ -124,6 +214,19 @@ namespace dawn_wire { namespace client {
|
|||||||
info->callback = callback;
|
info->callback = callback;
|
||||||
info->userdata = userdata;
|
info->userdata = userdata;
|
||||||
|
|
||||||
|
// Create a WriteHandle for the map request. This is the client's intent to write GPU
|
||||||
|
// memory.
|
||||||
|
MemoryTransferService::WriteHandle* writeHandle =
|
||||||
|
wireClient->GetMemoryTransferService()->CreateWriteHandle(descriptor->size);
|
||||||
|
if (writeHandle == nullptr) {
|
||||||
|
DawnCreateBufferMappedResult result;
|
||||||
|
result.buffer = reinterpret_cast<DawnBuffer>(buffer);
|
||||||
|
result.data = nullptr;
|
||||||
|
result.dataLength = 0;
|
||||||
|
callback(DAWN_BUFFER_MAP_ASYNC_STATUS_CONTEXT_LOST, result, userdata);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Buffer::MapRequestData request;
|
Buffer::MapRequestData request;
|
||||||
request.writeCallback = [](DawnBufferMapAsyncStatus status, void* data, uint64_t dataLength,
|
request.writeCallback = [](DawnBufferMapAsyncStatus status, void* data, uint64_t dataLength,
|
||||||
void* userdata) {
|
void* userdata) {
|
||||||
@ -138,18 +241,27 @@ namespace dawn_wire { namespace client {
|
|||||||
info->callback(status, result, info->userdata);
|
info->callback(status, result, info->userdata);
|
||||||
};
|
};
|
||||||
request.userdata = info;
|
request.userdata = info;
|
||||||
request.isWrite = true;
|
// The handle is owned by the MapRequest until the callback returns.
|
||||||
buffer->requests[serial] = request;
|
request.writeHandle = std::unique_ptr<MemoryTransferService::WriteHandle>(writeHandle);
|
||||||
|
buffer->requests[serial] = std::move(request);
|
||||||
|
|
||||||
|
// Get the serialization size of the WriteHandle.
|
||||||
|
size_t handleCreateInfoLength = writeHandle->SerializeCreate();
|
||||||
|
|
||||||
DeviceCreateBufferMappedAsyncCmd cmd;
|
DeviceCreateBufferMappedAsyncCmd cmd;
|
||||||
cmd.device = cDevice;
|
cmd.device = cDevice;
|
||||||
cmd.descriptor = descriptor;
|
cmd.descriptor = descriptor;
|
||||||
cmd.requestSerial = serial;
|
cmd.requestSerial = serial;
|
||||||
cmd.result = ObjectHandle{buffer->id, bufferObjectAndSerial->serial};
|
cmd.result = ObjectHandle{buffer->id, bufferObjectAndSerial->serial};
|
||||||
|
cmd.handleCreateInfoLength = handleCreateInfoLength;
|
||||||
|
cmd.handleCreateInfo = nullptr;
|
||||||
|
|
||||||
size_t requiredSize = cmd.GetRequiredSize();
|
size_t commandSize = cmd.GetRequiredSize();
|
||||||
|
size_t requiredSize = commandSize + handleCreateInfoLength;
|
||||||
char* allocatedBuffer = static_cast<char*>(wireClient->GetCmdSpace(requiredSize));
|
char* allocatedBuffer = static_cast<char*>(wireClient->GetCmdSpace(requiredSize));
|
||||||
cmd.Serialize(allocatedBuffer, *wireClient);
|
cmd.Serialize(allocatedBuffer, *wireClient);
|
||||||
|
// Serialize the WriteHandle into the space after the command.
|
||||||
|
writeHandle->SerializeCreate(allocatedBuffer + commandSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t ClientFenceGetCompletedValue(DawnFence cSelf) {
|
uint64_t ClientFenceGetCompletedValue(DawnFence cSelf) {
|
||||||
@ -208,22 +320,31 @@ namespace dawn_wire { namespace client {
|
|||||||
// - Server -> Client: Result of MapRequest1
|
// - Server -> Client: Result of MapRequest1
|
||||||
// - Unmap locally on the client
|
// - Unmap locally on the client
|
||||||
// - Server -> Client: Result of MapRequest2
|
// - Server -> Client: Result of MapRequest2
|
||||||
if (buffer->mappedData) {
|
if (buffer->writeHandle) {
|
||||||
// If the buffer was mapped for writing, send the update to the data to the server
|
// Writes need to be flushed before Unmap is sent. Unmap calls all associated
|
||||||
if (buffer->isWriteMapped) {
|
// in-flight callbacks which may read the updated data.
|
||||||
BufferUpdateMappedDataCmd cmd;
|
ASSERT(buffer->readHandle == nullptr);
|
||||||
cmd.bufferId = buffer->id;
|
|
||||||
cmd.dataLength = static_cast<uint32_t>(buffer->mappedDataSize);
|
|
||||||
cmd.data = static_cast<const uint8_t*>(buffer->mappedData);
|
|
||||||
|
|
||||||
size_t requiredSize = cmd.GetRequiredSize();
|
// Get the serialization size of metadata to flush writes.
|
||||||
char* allocatedBuffer =
|
size_t writeFlushInfoLength = buffer->writeHandle->SerializeFlush();
|
||||||
static_cast<char*>(buffer->device->GetClient()->GetCmdSpace(requiredSize));
|
|
||||||
cmd.Serialize(allocatedBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(buffer->mappedData);
|
BufferUpdateMappedDataCmd cmd;
|
||||||
buffer->mappedData = nullptr;
|
cmd.bufferId = buffer->id;
|
||||||
|
cmd.writeFlushInfoLength = writeFlushInfoLength;
|
||||||
|
cmd.writeFlushInfo = nullptr;
|
||||||
|
|
||||||
|
size_t commandSize = cmd.GetRequiredSize();
|
||||||
|
size_t requiredSize = commandSize + writeFlushInfoLength;
|
||||||
|
char* allocatedBuffer =
|
||||||
|
static_cast<char*>(buffer->device->GetClient()->GetCmdSpace(requiredSize));
|
||||||
|
cmd.Serialize(allocatedBuffer);
|
||||||
|
// Serialize flush metadata into the space after the command.
|
||||||
|
// This closes the handle for writing.
|
||||||
|
buffer->writeHandle->SerializeFlush(allocatedBuffer + commandSize);
|
||||||
|
buffer->writeHandle = nullptr;
|
||||||
|
|
||||||
|
} else if (buffer->readHandle) {
|
||||||
|
buffer->readHandle = nullptr;
|
||||||
}
|
}
|
||||||
buffer->ClearMapRequests(DAWN_BUFFER_MAP_ASYNC_STATUS_UNKNOWN);
|
buffer->ClearMapRequests(DAWN_BUFFER_MAP_ASYNC_STATUS_UNKNOWN);
|
||||||
|
|
||||||
|
@ -20,15 +20,11 @@ namespace dawn_wire { namespace client {
|
|||||||
// Callbacks need to be fired in all cases, as they can handle freeing resources
|
// Callbacks need to be fired in all cases, as they can handle freeing resources
|
||||||
// so we call them with "Unknown" status.
|
// so we call them with "Unknown" status.
|
||||||
ClearMapRequests(DAWN_BUFFER_MAP_ASYNC_STATUS_UNKNOWN);
|
ClearMapRequests(DAWN_BUFFER_MAP_ASYNC_STATUS_UNKNOWN);
|
||||||
|
|
||||||
if (mappedData) {
|
|
||||||
free(mappedData);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Buffer::ClearMapRequests(DawnBufferMapAsyncStatus status) {
|
void Buffer::ClearMapRequests(DawnBufferMapAsyncStatus status) {
|
||||||
for (auto& it : requests) {
|
for (auto& it : requests) {
|
||||||
if (it.second.isWrite) {
|
if (it.second.writeHandle) {
|
||||||
it.second.writeCallback(status, nullptr, 0, it.second.userdata);
|
it.second.writeCallback(status, nullptr, 0, it.second.userdata);
|
||||||
} else {
|
} else {
|
||||||
it.second.readCallback(status, nullptr, 0, it.second.userdata);
|
it.second.readCallback(status, nullptr, 0, it.second.userdata);
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include <dawn/dawn.h>
|
#include <dawn/dawn.h>
|
||||||
|
|
||||||
|
#include "dawn_wire/WireClient.h"
|
||||||
#include "dawn_wire/client/ObjectBase.h"
|
#include "dawn_wire/client/ObjectBase.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -33,19 +34,23 @@ namespace dawn_wire { namespace client {
|
|||||||
// map request in flight at a single time and need to track them separately.
|
// map request in flight at a single time and need to track them separately.
|
||||||
// On well-behaved applications, only one request should exist at a single time.
|
// On well-behaved applications, only one request should exist at a single time.
|
||||||
struct MapRequestData {
|
struct MapRequestData {
|
||||||
|
// TODO(enga): Use a tagged pointer to save space.
|
||||||
DawnBufferMapReadCallback readCallback = nullptr;
|
DawnBufferMapReadCallback readCallback = nullptr;
|
||||||
DawnBufferMapWriteCallback writeCallback = nullptr;
|
DawnBufferMapWriteCallback writeCallback = nullptr;
|
||||||
void* userdata = nullptr;
|
void* userdata = nullptr;
|
||||||
bool isWrite = false;
|
// TODO(enga): Use a tagged pointer to save space.
|
||||||
|
std::unique_ptr<MemoryTransferService::ReadHandle> readHandle = nullptr;
|
||||||
|
std::unique_ptr<MemoryTransferService::WriteHandle> writeHandle = nullptr;
|
||||||
};
|
};
|
||||||
std::map<uint32_t, MapRequestData> requests;
|
std::map<uint32_t, MapRequestData> requests;
|
||||||
uint32_t requestSerial = 0;
|
uint32_t requestSerial = 0;
|
||||||
|
uint64_t size = 0;
|
||||||
|
|
||||||
// Only one mapped pointer can be active at a time because Unmap clears all the in-flight
|
// Only one mapped pointer can be active at a time because Unmap clears all the in-flight
|
||||||
// requests.
|
// requests.
|
||||||
void* mappedData = nullptr;
|
// TODO(enga): Use a tagged pointer to save space.
|
||||||
uint64_t mappedDataSize = 0;
|
std::unique_ptr<MemoryTransferService::ReadHandle> readHandle = nullptr;
|
||||||
bool isWriteMapped = false;
|
std::unique_ptr<MemoryTransferService::WriteHandle> writeHandle = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
}} // namespace dawn_wire::client
|
}} // namespace dawn_wire::client
|
||||||
|
@ -17,10 +17,16 @@
|
|||||||
|
|
||||||
namespace dawn_wire { namespace client {
|
namespace dawn_wire { namespace client {
|
||||||
|
|
||||||
Client::Client(CommandSerializer* serializer)
|
Client::Client(CommandSerializer* serializer, MemoryTransferService* memoryTransferService)
|
||||||
: ClientBase(),
|
: ClientBase(),
|
||||||
mDevice(DeviceAllocator().New(this)->object.get()),
|
mDevice(DeviceAllocator().New(this)->object.get()),
|
||||||
mSerializer(serializer) {
|
mSerializer(serializer),
|
||||||
|
mMemoryTransferService(memoryTransferService) {
|
||||||
|
if (mMemoryTransferService == nullptr) {
|
||||||
|
// If a MemoryTransferService is not provided, fall back to inline memory.
|
||||||
|
mOwnedMemoryTransferService = CreateInlineMemoryTransferService();
|
||||||
|
mMemoryTransferService = mOwnedMemoryTransferService.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Client::~Client() {
|
Client::~Client() {
|
||||||
|
@ -25,10 +25,11 @@
|
|||||||
namespace dawn_wire { namespace client {
|
namespace dawn_wire { namespace client {
|
||||||
|
|
||||||
class Device;
|
class Device;
|
||||||
|
class MemoryTransferService;
|
||||||
|
|
||||||
class Client : public ClientBase {
|
class Client : public ClientBase {
|
||||||
public:
|
public:
|
||||||
Client(CommandSerializer* serializer);
|
Client(CommandSerializer* serializer, MemoryTransferService* memoryTransferService);
|
||||||
~Client();
|
~Client();
|
||||||
|
|
||||||
const char* HandleCommands(const char* commands, size_t size);
|
const char* HandleCommands(const char* commands, size_t size);
|
||||||
@ -42,16 +43,24 @@ namespace dawn_wire { namespace client {
|
|||||||
return reinterpret_cast<DawnDeviceImpl*>(mDevice);
|
return reinterpret_cast<DawnDeviceImpl*>(mDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MemoryTransferService* GetMemoryTransferService() const {
|
||||||
|
return mMemoryTransferService;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#include "dawn_wire/client/ClientPrototypes_autogen.inc"
|
#include "dawn_wire/client/ClientPrototypes_autogen.inc"
|
||||||
|
|
||||||
Device* mDevice = nullptr;
|
Device* mDevice = nullptr;
|
||||||
CommandSerializer* mSerializer = nullptr;
|
CommandSerializer* mSerializer = nullptr;
|
||||||
WireDeserializeAllocator mAllocator;
|
WireDeserializeAllocator mAllocator;
|
||||||
|
MemoryTransferService* mMemoryTransferService = nullptr;
|
||||||
|
std::unique_ptr<MemoryTransferService> mOwnedMemoryTransferService = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
DawnProcTable GetProcs();
|
DawnProcTable GetProcs();
|
||||||
|
|
||||||
|
std::unique_ptr<MemoryTransferService> CreateInlineMemoryTransferService();
|
||||||
|
|
||||||
}} // namespace dawn_wire::client
|
}} // namespace dawn_wire::client
|
||||||
|
|
||||||
#endif // DAWNWIRE_CLIENT_CLIENT_H_
|
#endif // DAWNWIRE_CLIENT_CLIENT_H_
|
||||||
|
@ -27,8 +27,8 @@ namespace dawn_wire { namespace client {
|
|||||||
bool Client::DoBufferMapReadAsyncCallback(Buffer* buffer,
|
bool Client::DoBufferMapReadAsyncCallback(Buffer* buffer,
|
||||||
uint32_t requestSerial,
|
uint32_t requestSerial,
|
||||||
uint32_t status,
|
uint32_t status,
|
||||||
uint64_t dataLength,
|
uint64_t initialDataInfoLength,
|
||||||
const uint8_t* data) {
|
const uint8_t* initialDataInfo) {
|
||||||
// The buffer might have been deleted or recreated so this isn't an error.
|
// The buffer might have been deleted or recreated so this isn't an error.
|
||||||
if (buffer == nullptr) {
|
if (buffer == nullptr) {
|
||||||
return true;
|
return true;
|
||||||
@ -40,44 +40,67 @@ namespace dawn_wire { namespace client {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// It is an error for the server to call the read callback when we asked for a map write
|
auto request = std::move(requestIt->second);
|
||||||
if (requestIt->second.isWrite) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto request = requestIt->second;
|
|
||||||
// Delete the request before calling the callback otherwise the callback could be fired a
|
// Delete the request before calling the callback otherwise the callback could be fired a
|
||||||
// second time. If, for example, buffer.Unmap() is called inside the callback.
|
// second time. If, for example, buffer.Unmap() is called inside the callback.
|
||||||
buffer->requests.erase(requestIt);
|
buffer->requests.erase(requestIt);
|
||||||
|
|
||||||
// On success, we copy the data locally because the IPC buffer isn't valid outside of this
|
const void* mappedData = nullptr;
|
||||||
// function
|
size_t mappedDataLength = 0;
|
||||||
if (status == DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS) {
|
|
||||||
ASSERT(data != nullptr);
|
|
||||||
|
|
||||||
if (buffer->mappedData != nullptr) {
|
auto GetMappedData = [&]() -> bool {
|
||||||
|
// It is an error for the server to call the read callback when we asked for a map write
|
||||||
|
if (request.writeHandle) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer->isWriteMapped = false;
|
if (status == DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS) {
|
||||||
buffer->mappedDataSize = dataLength;
|
if (buffer->readHandle || buffer->writeHandle) {
|
||||||
buffer->mappedData = malloc(dataLength);
|
// Buffer is already mapped.
|
||||||
memcpy(buffer->mappedData, data, dataLength);
|
return false;
|
||||||
|
}
|
||||||
|
if (initialDataInfoLength > std::numeric_limits<size_t>::max()) {
|
||||||
|
// This is the size of data deserialized from the command stream, which must be
|
||||||
|
// CPU-addressable.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ASSERT(request.readHandle != nullptr);
|
||||||
|
|
||||||
request.readCallback(static_cast<DawnBufferMapAsyncStatus>(status), buffer->mappedData,
|
// The server serializes metadata to initialize the contents of the ReadHandle.
|
||||||
dataLength, request.userdata);
|
// Deserialize the message and return a pointer and size of the mapped data for
|
||||||
} else {
|
// reading.
|
||||||
request.readCallback(static_cast<DawnBufferMapAsyncStatus>(status), nullptr, 0,
|
if (!request.readHandle->DeserializeInitialData(
|
||||||
|
initialDataInfo, static_cast<size_t>(initialDataInfoLength), &mappedData,
|
||||||
|
&mappedDataLength)) {
|
||||||
|
// Deserialization shouldn't fail. This is a fatal error.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ASSERT(mappedData != nullptr);
|
||||||
|
|
||||||
|
// The MapRead request was successful. The buffer now owns the ReadHandle until
|
||||||
|
// Unmap().
|
||||||
|
buffer->readHandle = std::move(request.readHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!GetMappedData()) {
|
||||||
|
// Dawn promises that all callbacks are called in finite time. Even if a fatal error
|
||||||
|
// occurs, the callback is called.
|
||||||
|
request.readCallback(DAWN_BUFFER_MAP_ASYNC_STATUS_CONTEXT_LOST, nullptr, 0,
|
||||||
request.userdata);
|
request.userdata);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
request.readCallback(static_cast<DawnBufferMapAsyncStatus>(status), mappedData,
|
||||||
|
static_cast<uint64_t>(mappedDataLength), request.userdata);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Client::DoBufferMapWriteAsyncCallback(Buffer* buffer,
|
bool Client::DoBufferMapWriteAsyncCallback(Buffer* buffer,
|
||||||
uint32_t requestSerial,
|
uint32_t requestSerial,
|
||||||
uint32_t status,
|
uint32_t status) {
|
||||||
uint64_t dataLength) {
|
|
||||||
// The buffer might have been deleted or recreated so this isn't an error.
|
// The buffer might have been deleted or recreated so this isn't an error.
|
||||||
if (buffer == nullptr) {
|
if (buffer == nullptr) {
|
||||||
return true;
|
return true;
|
||||||
@ -89,39 +112,54 @@ namespace dawn_wire { namespace client {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// It is an error for the server to call the write callback when we asked for a map read
|
auto request = std::move(requestIt->second);
|
||||||
if (!requestIt->second.isWrite) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto request = requestIt->second;
|
|
||||||
// Delete the request before calling the callback otherwise the callback could be fired a
|
// Delete the request before calling the callback otherwise the callback could be fired a
|
||||||
// second time. If, for example, buffer.Unmap() is called inside the callback.
|
// second time. If, for example, buffer.Unmap() is called inside the callback.
|
||||||
buffer->requests.erase(requestIt);
|
buffer->requests.erase(requestIt);
|
||||||
|
|
||||||
// On success, we copy the data locally because the IPC buffer isn't valid outside of this
|
void* mappedData = nullptr;
|
||||||
// function
|
size_t mappedDataLength = 0;
|
||||||
if (status == DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS) {
|
|
||||||
if (buffer->mappedData != nullptr) {
|
auto GetMappedData = [&]() -> bool {
|
||||||
|
// It is an error for the server to call the write callback when we asked for a map read
|
||||||
|
if (request.readHandle) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer->isWriteMapped = true;
|
if (status == DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS) {
|
||||||
buffer->mappedDataSize = dataLength;
|
if (buffer->readHandle || buffer->writeHandle) {
|
||||||
// |mappedData| is freed in Unmap or the Buffer destructor.
|
// Buffer is already mapped.
|
||||||
// TODO(enga): Add dependency injection for buffer mapping so staging
|
return false;
|
||||||
// memory can live in shared memory.
|
}
|
||||||
buffer->mappedData = malloc(dataLength);
|
ASSERT(request.writeHandle != nullptr);
|
||||||
memset(buffer->mappedData, 0, dataLength);
|
|
||||||
|
|
||||||
request.writeCallback(static_cast<DawnBufferMapAsyncStatus>(status), buffer->mappedData,
|
// Open the WriteHandle. This returns a pointer and size of mapped memory.
|
||||||
dataLength, request.userdata);
|
// On failure, |mappedData| may be null.
|
||||||
} else {
|
std::tie(mappedData, mappedDataLength) = request.writeHandle->Open();
|
||||||
request.writeCallback(static_cast<DawnBufferMapAsyncStatus>(status), nullptr, 0,
|
|
||||||
|
if (mappedData == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The MapWrite request was successful. The buffer now owns the WriteHandle until
|
||||||
|
// Unmap().
|
||||||
|
buffer->writeHandle = std::move(request.writeHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!GetMappedData()) {
|
||||||
|
// Dawn promises that all callbacks are called in finite time. Even if a fatal error
|
||||||
|
// occurs, the callback is called.
|
||||||
|
request.writeCallback(DAWN_BUFFER_MAP_ASYNC_STATUS_CONTEXT_LOST, nullptr, 0,
|
||||||
request.userdata);
|
request.userdata);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
request.writeCallback(static_cast<DawnBufferMapAsyncStatus>(status), mappedData,
|
||||||
|
static_cast<uint64_t>(mappedDataLength), request.userdata);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Client::DoFenceUpdateCompletedValue(Fence* fence, uint64_t value) {
|
bool Client::DoFenceUpdateCompletedValue(Fence* fence, uint64_t value) {
|
||||||
|
105
src/dawn_wire/client/ClientInlineMemoryTransferService.cpp
Normal file
105
src/dawn_wire/client/ClientInlineMemoryTransferService.cpp
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
// Copyright 2019 The Dawn Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "common/Assert.h"
|
||||||
|
#include "dawn_wire/WireClient.h"
|
||||||
|
#include "dawn_wire/client/Client.h"
|
||||||
|
|
||||||
|
namespace dawn_wire { namespace client {
|
||||||
|
|
||||||
|
class InlineMemoryTransferService : public MemoryTransferService {
|
||||||
|
class ReadHandleImpl : public ReadHandle {
|
||||||
|
public:
|
||||||
|
explicit ReadHandleImpl(size_t size) : mSize(size) {
|
||||||
|
}
|
||||||
|
|
||||||
|
~ReadHandleImpl() override = default;
|
||||||
|
|
||||||
|
size_t SerializeCreate(void*) override {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeserializeInitialData(const void* deserializePointer,
|
||||||
|
size_t deserializeSize,
|
||||||
|
const void** data,
|
||||||
|
size_t* dataLength) override {
|
||||||
|
if (deserializeSize != mSize || deserializePointer == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mStagingData = std::unique_ptr<uint8_t[]>(new uint8_t[mSize]);
|
||||||
|
memcpy(mStagingData.get(), deserializePointer, mSize);
|
||||||
|
|
||||||
|
ASSERT(data != nullptr);
|
||||||
|
ASSERT(dataLength != nullptr);
|
||||||
|
*data = mStagingData.get();
|
||||||
|
*dataLength = mSize;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t mSize;
|
||||||
|
std::unique_ptr<uint8_t[]> mStagingData;
|
||||||
|
};
|
||||||
|
|
||||||
|
class WriteHandleImpl : public WriteHandle {
|
||||||
|
public:
|
||||||
|
explicit WriteHandleImpl(size_t size) : mSize(size) {
|
||||||
|
}
|
||||||
|
|
||||||
|
~WriteHandleImpl() override = default;
|
||||||
|
|
||||||
|
size_t SerializeCreate(void*) override {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<void*, size_t> Open() override {
|
||||||
|
mStagingData = std::unique_ptr<uint8_t[]>(new uint8_t[mSize]);
|
||||||
|
memset(mStagingData.get(), 0, mSize);
|
||||||
|
return std::make_pair(mStagingData.get(), mSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SerializeFlush(void* serializePointer) override {
|
||||||
|
if (serializePointer != nullptr) {
|
||||||
|
ASSERT(mStagingData != nullptr);
|
||||||
|
memcpy(serializePointer, mStagingData.get(), mSize);
|
||||||
|
}
|
||||||
|
return mSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t mSize;
|
||||||
|
std::unique_ptr<uint8_t[]> mStagingData;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
InlineMemoryTransferService() {
|
||||||
|
}
|
||||||
|
~InlineMemoryTransferService() override = default;
|
||||||
|
|
||||||
|
ReadHandle* CreateReadHandle(size_t size) override {
|
||||||
|
return new ReadHandleImpl(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteHandle* CreateWriteHandle(size_t size) override {
|
||||||
|
return new WriteHandleImpl(size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<MemoryTransferService> CreateInlineMemoryTransferService() {
|
||||||
|
return std::make_unique<InlineMemoryTransferService>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace dawn_wire::client
|
@ -16,6 +16,7 @@
|
|||||||
#define DAWNWIRE_SERVER_OBJECTSTORAGE_H_
|
#define DAWNWIRE_SERVER_OBJECTSTORAGE_H_
|
||||||
|
|
||||||
#include "dawn_wire/WireCmd_autogen.h"
|
#include "dawn_wire/WireCmd_autogen.h"
|
||||||
|
#include "dawn_wire/WireServer.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -41,8 +42,9 @@ namespace dawn_wire { namespace server {
|
|||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct ObjectData<DawnBuffer> : public ObjectDataBase<DawnBuffer> {
|
struct ObjectData<DawnBuffer> : public ObjectDataBase<DawnBuffer> {
|
||||||
void* mappedData = nullptr;
|
// TODO(enga): Use a tagged pointer to save space.
|
||||||
size_t mappedDataSize = 0;
|
std::unique_ptr<MemoryTransferService::ReadHandle> readHandle;
|
||||||
|
std::unique_ptr<MemoryTransferService::WriteHandle> writeHandle;
|
||||||
BufferMapWriteState mapWriteState = BufferMapWriteState::Unmapped;
|
BufferMapWriteState mapWriteState = BufferMapWriteState::Unmapped;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -59,7 +61,7 @@ namespace dawn_wire { namespace server {
|
|||||||
Data reservation;
|
Data reservation;
|
||||||
reservation.handle = nullptr;
|
reservation.handle = nullptr;
|
||||||
reservation.allocated = false;
|
reservation.allocated = false;
|
||||||
mKnown.push_back(reservation);
|
mKnown.push_back(std::move(reservation));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a backend objects for a given client ID.
|
// Get a backend objects for a given client ID.
|
||||||
@ -104,7 +106,7 @@ namespace dawn_wire { namespace server {
|
|||||||
data.handle = nullptr;
|
data.handle = nullptr;
|
||||||
|
|
||||||
if (id >= mKnown.size()) {
|
if (id >= mKnown.size()) {
|
||||||
mKnown.push_back(data);
|
mKnown.push_back(std::move(data));
|
||||||
return &mKnown.back();
|
return &mKnown.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +114,7 @@ namespace dawn_wire { namespace server {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
mKnown[id] = data;
|
mKnown[id] = std::move(data);
|
||||||
return &mKnown[id];
|
return &mKnown[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,11 +13,20 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "dawn_wire/server/Server.h"
|
#include "dawn_wire/server/Server.h"
|
||||||
|
#include "dawn_wire/WireServer.h"
|
||||||
|
|
||||||
namespace dawn_wire { namespace server {
|
namespace dawn_wire { namespace server {
|
||||||
|
|
||||||
Server::Server(DawnDevice device, const DawnProcTable& procs, CommandSerializer* serializer)
|
Server::Server(DawnDevice device,
|
||||||
: mSerializer(serializer), mProcs(procs) {
|
const DawnProcTable& procs,
|
||||||
|
CommandSerializer* serializer,
|
||||||
|
MemoryTransferService* memoryTransferService)
|
||||||
|
: mSerializer(serializer), mProcs(procs), mMemoryTransferService(memoryTransferService) {
|
||||||
|
if (mMemoryTransferService == nullptr) {
|
||||||
|
// If a MemoryTransferService is not provided, fallback to inline memory.
|
||||||
|
mOwnedMemoryTransferService = CreateInlineMemoryTransferService();
|
||||||
|
mMemoryTransferService = mOwnedMemoryTransferService.get();
|
||||||
|
}
|
||||||
// The client-server knowledge is bootstrapped with device 1.
|
// The client-server knowledge is bootstrapped with device 1.
|
||||||
auto* deviceData = DeviceObjects().Allocate(1);
|
auto* deviceData = DeviceObjects().Allocate(1);
|
||||||
deviceData->handle = device;
|
deviceData->handle = device;
|
||||||
|
@ -20,13 +20,16 @@
|
|||||||
namespace dawn_wire { namespace server {
|
namespace dawn_wire { namespace server {
|
||||||
|
|
||||||
class Server;
|
class Server;
|
||||||
|
class MemoryTransferService;
|
||||||
|
|
||||||
struct MapUserdata {
|
struct MapUserdata {
|
||||||
Server* server;
|
Server* server;
|
||||||
ObjectHandle buffer;
|
ObjectHandle buffer;
|
||||||
uint32_t requestSerial;
|
uint32_t requestSerial;
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
bool isWrite;
|
// TODO(enga): Use a tagged pointer to save space.
|
||||||
|
std::unique_ptr<MemoryTransferService::ReadHandle> readHandle = nullptr;
|
||||||
|
std::unique_ptr<MemoryTransferService::WriteHandle> writeHandle = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FenceCompletionUserdata {
|
struct FenceCompletionUserdata {
|
||||||
@ -37,7 +40,10 @@ namespace dawn_wire { namespace server {
|
|||||||
|
|
||||||
class Server : public ServerBase {
|
class Server : public ServerBase {
|
||||||
public:
|
public:
|
||||||
Server(DawnDevice device, const DawnProcTable& procs, CommandSerializer* serializer);
|
Server(DawnDevice device,
|
||||||
|
const DawnProcTable& procs,
|
||||||
|
CommandSerializer* serializer,
|
||||||
|
MemoryTransferService* memoryTransferService);
|
||||||
~Server();
|
~Server();
|
||||||
|
|
||||||
const char* HandleCommands(const char* commands, size_t size);
|
const char* HandleCommands(const char* commands, size_t size);
|
||||||
@ -77,8 +83,12 @@ namespace dawn_wire { namespace server {
|
|||||||
CommandSerializer* mSerializer = nullptr;
|
CommandSerializer* mSerializer = nullptr;
|
||||||
WireDeserializeAllocator mAllocator;
|
WireDeserializeAllocator mAllocator;
|
||||||
DawnProcTable mProcs;
|
DawnProcTable mProcs;
|
||||||
|
std::unique_ptr<MemoryTransferService> mOwnedMemoryTransferService = nullptr;
|
||||||
|
MemoryTransferService* mMemoryTransferService = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<MemoryTransferService> CreateInlineMemoryTransferService();
|
||||||
|
|
||||||
}} // namespace dawn_wire::server
|
}} // namespace dawn_wire::server
|
||||||
|
|
||||||
#endif // DAWNWIRE_SERVER_SERVER_H_
|
#endif // DAWNWIRE_SERVER_SERVER_H_
|
||||||
|
@ -23,7 +23,9 @@ namespace dawn_wire { namespace server {
|
|||||||
auto* buffer = BufferObjects().Get(cmd.selfId);
|
auto* buffer = BufferObjects().Get(cmd.selfId);
|
||||||
DAWN_ASSERT(buffer != nullptr);
|
DAWN_ASSERT(buffer != nullptr);
|
||||||
|
|
||||||
buffer->mappedData = nullptr;
|
// The buffer was unmapped. Clear the Read/WriteHandle.
|
||||||
|
buffer->readHandle = nullptr;
|
||||||
|
buffer->writeHandle = nullptr;
|
||||||
buffer->mapWriteState = BufferMapWriteState::Unmapped;
|
buffer->mapWriteState = BufferMapWriteState::Unmapped;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -31,7 +33,9 @@ namespace dawn_wire { namespace server {
|
|||||||
|
|
||||||
bool Server::DoBufferMapAsync(ObjectId bufferId,
|
bool Server::DoBufferMapAsync(ObjectId bufferId,
|
||||||
uint32_t requestSerial,
|
uint32_t requestSerial,
|
||||||
bool isWrite) {
|
bool isWrite,
|
||||||
|
uint64_t handleCreateInfoLength,
|
||||||
|
const uint8_t* handleCreateInfo) {
|
||||||
// These requests are just forwarded to the buffer, with userdata containing what the
|
// These requests are just forwarded to the buffer, with userdata containing what the
|
||||||
// client will require in the return command.
|
// client will require in the return command.
|
||||||
|
|
||||||
@ -45,16 +49,44 @@ namespace dawn_wire { namespace server {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MapUserdata* userdata = new MapUserdata;
|
if (handleCreateInfoLength > std::numeric_limits<size_t>::max()) {
|
||||||
|
// This is the size of data deserialized from the command stream, which must be
|
||||||
|
// CPU-addressable.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<MapUserdata> userdata = std::make_unique<MapUserdata>();
|
||||||
userdata->server = this;
|
userdata->server = this;
|
||||||
userdata->buffer = ObjectHandle{bufferId, buffer->serial};
|
userdata->buffer = ObjectHandle{bufferId, buffer->serial};
|
||||||
userdata->requestSerial = requestSerial;
|
userdata->requestSerial = requestSerial;
|
||||||
userdata->isWrite = isWrite;
|
|
||||||
|
|
||||||
|
// The handle will point to the mapped memory or staging memory for the mapping.
|
||||||
|
// Store it on the map request.
|
||||||
if (isWrite) {
|
if (isWrite) {
|
||||||
mProcs.bufferMapWriteAsync(buffer->handle, ForwardBufferMapWriteAsync, userdata);
|
// Deserialize metadata produced from the client to create a companion server handle.
|
||||||
|
MemoryTransferService::WriteHandle* writeHandle = nullptr;
|
||||||
|
if (!mMemoryTransferService->DeserializeWriteHandle(
|
||||||
|
handleCreateInfo, static_cast<size_t>(handleCreateInfoLength), &writeHandle)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ASSERT(writeHandle != nullptr);
|
||||||
|
|
||||||
|
userdata->writeHandle =
|
||||||
|
std::unique_ptr<MemoryTransferService::WriteHandle>(writeHandle);
|
||||||
|
mProcs.bufferMapWriteAsync(buffer->handle, ForwardBufferMapWriteAsync,
|
||||||
|
userdata.release());
|
||||||
} else {
|
} else {
|
||||||
mProcs.bufferMapReadAsync(buffer->handle, ForwardBufferMapReadAsync, userdata);
|
// Deserialize metadata produced from the client to create a companion server handle.
|
||||||
|
MemoryTransferService::ReadHandle* readHandle = nullptr;
|
||||||
|
if (!mMemoryTransferService->DeserializeReadHandle(
|
||||||
|
handleCreateInfo, static_cast<size_t>(handleCreateInfoLength), &readHandle)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ASSERT(readHandle != nullptr);
|
||||||
|
|
||||||
|
userdata->readHandle = std::unique_ptr<MemoryTransferService::ReadHandle>(readHandle);
|
||||||
|
mProcs.bufferMapReadAsync(buffer->handle, ForwardBufferMapReadAsync,
|
||||||
|
userdata.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -62,7 +94,15 @@ namespace dawn_wire { namespace server {
|
|||||||
|
|
||||||
bool Server::DoDeviceCreateBufferMapped(DawnDevice device,
|
bool Server::DoDeviceCreateBufferMapped(DawnDevice device,
|
||||||
const DawnBufferDescriptor* descriptor,
|
const DawnBufferDescriptor* descriptor,
|
||||||
ObjectHandle bufferResult) {
|
ObjectHandle bufferResult,
|
||||||
|
uint64_t handleCreateInfoLength,
|
||||||
|
const uint8_t* handleCreateInfo) {
|
||||||
|
if (handleCreateInfoLength > std::numeric_limits<size_t>::max()) {
|
||||||
|
// 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;
|
||||||
@ -73,15 +113,29 @@ namespace dawn_wire { namespace server {
|
|||||||
ASSERT(result.buffer != nullptr);
|
ASSERT(result.buffer != nullptr);
|
||||||
if (result.data == nullptr && result.dataLength != 0) {
|
if (result.data == nullptr && result.dataLength != 0) {
|
||||||
// Non-zero dataLength but null data is used to indicate an allocation error.
|
// 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 should only happen when fuzzing with the Null backend.
|
||||||
resultData->mapWriteState = BufferMapWriteState::MapError;
|
resultData->mapWriteState = BufferMapWriteState::MapError;
|
||||||
} else {
|
} else {
|
||||||
|
// Deserialize metadata produced from the client to create a companion server handle.
|
||||||
|
MemoryTransferService::WriteHandle* writeHandle = nullptr;
|
||||||
|
if (!mMemoryTransferService->DeserializeWriteHandle(
|
||||||
|
handleCreateInfo, static_cast<size_t>(handleCreateInfoLength), &writeHandle)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ASSERT(writeHandle != nullptr);
|
||||||
|
|
||||||
|
// Set the target of the WriteHandle to the mapped GPU memory.
|
||||||
|
writeHandle->SetTarget(result.data, result.dataLength);
|
||||||
|
|
||||||
// The buffer is mapped and has a valid mappedData pointer.
|
// The buffer is mapped and has a valid mappedData pointer.
|
||||||
// The buffer may still be an error with fake staging data.
|
// The buffer may still be an error with fake staging data.
|
||||||
resultData->mapWriteState = BufferMapWriteState::Mapped;
|
resultData->mapWriteState = BufferMapWriteState::Mapped;
|
||||||
|
resultData->writeHandle =
|
||||||
|
std::unique_ptr<MemoryTransferService::WriteHandle>(writeHandle);
|
||||||
}
|
}
|
||||||
resultData->handle = result.buffer;
|
resultData->handle = result.buffer;
|
||||||
resultData->mappedData = result.data;
|
|
||||||
resultData->mappedDataSize = result.dataLength;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -89,8 +143,11 @@ namespace dawn_wire { namespace server {
|
|||||||
bool Server::DoDeviceCreateBufferMappedAsync(DawnDevice device,
|
bool Server::DoDeviceCreateBufferMappedAsync(DawnDevice device,
|
||||||
const DawnBufferDescriptor* descriptor,
|
const DawnBufferDescriptor* descriptor,
|
||||||
uint32_t requestSerial,
|
uint32_t requestSerial,
|
||||||
ObjectHandle bufferResult) {
|
ObjectHandle bufferResult,
|
||||||
if (!DoDeviceCreateBufferMapped(device, descriptor, bufferResult)) {
|
uint64_t handleCreateInfoLength,
|
||||||
|
const uint8_t* handleCreateInfo) {
|
||||||
|
if (!DoDeviceCreateBufferMapped(device, descriptor, bufferResult, handleCreateInfoLength,
|
||||||
|
handleCreateInfo)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +160,6 @@ namespace dawn_wire { namespace server {
|
|||||||
cmd.status = bufferData->mapWriteState == BufferMapWriteState::Mapped
|
cmd.status = bufferData->mapWriteState == BufferMapWriteState::Mapped
|
||||||
? DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS
|
? DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS
|
||||||
: DAWN_BUFFER_MAP_ASYNC_STATUS_ERROR;
|
: DAWN_BUFFER_MAP_ASYNC_STATUS_ERROR;
|
||||||
cmd.dataLength = bufferData->mappedDataSize;
|
|
||||||
|
|
||||||
size_t requiredSize = cmd.GetRequiredSize();
|
size_t requiredSize = cmd.GetRequiredSize();
|
||||||
char* allocatedBuffer = static_cast<char*>(GetCmdSpace(requiredSize));
|
char* allocatedBuffer = static_cast<char*>(GetCmdSpace(requiredSize));
|
||||||
@ -130,14 +186,20 @@ namespace dawn_wire { namespace server {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Server::DoBufferUpdateMappedData(ObjectId bufferId, uint32_t count, const uint8_t* data) {
|
bool Server::DoBufferUpdateMappedData(ObjectId bufferId,
|
||||||
|
uint64_t writeFlushInfoLength,
|
||||||
|
const uint8_t* writeFlushInfo) {
|
||||||
// The null object isn't valid as `self`
|
// The null object isn't valid as `self`
|
||||||
if (bufferId == 0) {
|
if (bufferId == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (writeFlushInfoLength > std::numeric_limits<size_t>::max()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auto* buffer = BufferObjects().Get(bufferId);
|
auto* buffer = BufferObjects().Get(bufferId);
|
||||||
if (buffer == nullptr || buffer->mappedDataSize != count) {
|
if (buffer == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
switch (buffer->mapWriteState) {
|
switch (buffer->mapWriteState) {
|
||||||
@ -150,12 +212,15 @@ namespace dawn_wire { namespace server {
|
|||||||
case BufferMapWriteState::Mapped:
|
case BufferMapWriteState::Mapped:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (!buffer->writeHandle) {
|
||||||
ASSERT(data != nullptr);
|
// This check is performed after the check for the MapError state. It is permissible
|
||||||
ASSERT(buffer->mappedData != nullptr);
|
// to Unmap and attempt to update mapped data of an error buffer.
|
||||||
memcpy(buffer->mappedData, data, count);
|
return false;
|
||||||
|
}
|
||||||
return true;
|
// Deserialize the flush info and flush updated data from the handle into the target
|
||||||
|
// of the handle. The target is set via WriteHandle::SetTarget.
|
||||||
|
return buffer->writeHandle->DeserializeFlush(writeFlushInfo,
|
||||||
|
static_cast<size_t>(writeFlushInfoLength));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::ForwardBufferMapReadAsync(DawnBufferMapAsyncStatus status,
|
void Server::ForwardBufferMapReadAsync(DawnBufferMapAsyncStatus status,
|
||||||
@ -186,20 +251,34 @@ namespace dawn_wire { namespace server {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t initialDataInfoLength = 0;
|
||||||
|
if (status == DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS) {
|
||||||
|
// Get the serialization size of the message to initialize ReadHandle data.
|
||||||
|
initialDataInfoLength = data->readHandle->SerializeInitialData(ptr, dataLength);
|
||||||
|
} else {
|
||||||
|
dataLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
ReturnBufferMapReadAsyncCallbackCmd cmd;
|
ReturnBufferMapReadAsyncCallbackCmd cmd;
|
||||||
cmd.buffer = data->buffer;
|
cmd.buffer = data->buffer;
|
||||||
cmd.requestSerial = data->requestSerial;
|
cmd.requestSerial = data->requestSerial;
|
||||||
cmd.status = status;
|
cmd.status = status;
|
||||||
cmd.dataLength = 0;
|
cmd.initialDataInfoLength = initialDataInfoLength;
|
||||||
cmd.data = static_cast<const uint8_t*>(ptr);
|
cmd.initialDataInfo = nullptr;
|
||||||
|
|
||||||
if (status == DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS) {
|
size_t commandSize = cmd.GetRequiredSize();
|
||||||
cmd.dataLength = dataLength;
|
size_t requiredSize = commandSize + initialDataInfoLength;
|
||||||
}
|
|
||||||
|
|
||||||
size_t requiredSize = cmd.GetRequiredSize();
|
|
||||||
char* allocatedBuffer = static_cast<char*>(GetCmdSpace(requiredSize));
|
char* allocatedBuffer = static_cast<char*>(GetCmdSpace(requiredSize));
|
||||||
cmd.Serialize(allocatedBuffer);
|
cmd.Serialize(allocatedBuffer);
|
||||||
|
|
||||||
|
if (status == DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS) {
|
||||||
|
// Serialize the initialization message into the space after the command.
|
||||||
|
data->readHandle->SerializeInitialData(ptr, dataLength, allocatedBuffer + commandSize);
|
||||||
|
|
||||||
|
// The in-flight map request returned successfully.
|
||||||
|
// Move the ReadHandle so it is owned by the buffer.
|
||||||
|
bufferData->readHandle = std::move(data->readHandle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::OnBufferMapWriteAsyncCallback(DawnBufferMapAsyncStatus status,
|
void Server::OnBufferMapWriteAsyncCallback(DawnBufferMapAsyncStatus status,
|
||||||
@ -218,16 +297,18 @@ namespace dawn_wire { namespace server {
|
|||||||
cmd.buffer = data->buffer;
|
cmd.buffer = data->buffer;
|
||||||
cmd.requestSerial = data->requestSerial;
|
cmd.requestSerial = data->requestSerial;
|
||||||
cmd.status = status;
|
cmd.status = status;
|
||||||
cmd.dataLength = dataLength;
|
|
||||||
|
|
||||||
size_t requiredSize = cmd.GetRequiredSize();
|
size_t requiredSize = cmd.GetRequiredSize();
|
||||||
char* allocatedBuffer = static_cast<char*>(GetCmdSpace(requiredSize));
|
char* allocatedBuffer = static_cast<char*>(GetCmdSpace(requiredSize));
|
||||||
cmd.Serialize(allocatedBuffer);
|
cmd.Serialize(allocatedBuffer);
|
||||||
|
|
||||||
if (status == DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS) {
|
if (status == DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS) {
|
||||||
|
// The in-flight map request returned successfully.
|
||||||
|
// Move the WriteHandle so it is owned by the buffer.
|
||||||
|
bufferData->writeHandle = std::move(data->writeHandle);
|
||||||
bufferData->mapWriteState = BufferMapWriteState::Mapped;
|
bufferData->mapWriteState = BufferMapWriteState::Mapped;
|
||||||
bufferData->mappedData = ptr;
|
// Set the target of the WriteHandle to the mapped buffer data.
|
||||||
bufferData->mappedDataSize = dataLength;
|
bufferData->writeHandle->SetTarget(ptr, dataLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
81
src/dawn_wire/server/ServerInlineMemoryTransferService.cpp
Normal file
81
src/dawn_wire/server/ServerInlineMemoryTransferService.cpp
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// Copyright 2019 The Dawn Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "common/Assert.h"
|
||||||
|
#include "dawn_wire/WireServer.h"
|
||||||
|
#include "dawn_wire/server/Server.h"
|
||||||
|
|
||||||
|
namespace dawn_wire { namespace server {
|
||||||
|
|
||||||
|
class InlineMemoryTransferService : public MemoryTransferService {
|
||||||
|
public:
|
||||||
|
class ReadHandleImpl : public ReadHandle {
|
||||||
|
public:
|
||||||
|
ReadHandleImpl() {
|
||||||
|
}
|
||||||
|
~ReadHandleImpl() override = default;
|
||||||
|
|
||||||
|
size_t SerializeInitialData(const void* data,
|
||||||
|
size_t dataLength,
|
||||||
|
void* serializePointer) override {
|
||||||
|
if (serializePointer != nullptr && dataLength > 0) {
|
||||||
|
ASSERT(data != nullptr);
|
||||||
|
memcpy(serializePointer, data, dataLength);
|
||||||
|
}
|
||||||
|
return dataLength;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class WriteHandleImpl : public WriteHandle {
|
||||||
|
public:
|
||||||
|
WriteHandleImpl() {
|
||||||
|
}
|
||||||
|
~WriteHandleImpl() override = default;
|
||||||
|
|
||||||
|
bool DeserializeFlush(const void* deserializePointer, size_t deserializeSize) override {
|
||||||
|
if (deserializeSize != mDataLength || mTargetData == nullptr ||
|
||||||
|
deserializePointer == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(mTargetData, deserializePointer, mDataLength);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
InlineMemoryTransferService() {
|
||||||
|
}
|
||||||
|
~InlineMemoryTransferService() override = default;
|
||||||
|
|
||||||
|
bool DeserializeReadHandle(const void* deserializePointer,
|
||||||
|
size_t deserializeSize,
|
||||||
|
ReadHandle** readHandle) override {
|
||||||
|
ASSERT(readHandle != nullptr);
|
||||||
|
*readHandle = new ReadHandleImpl();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeserializeWriteHandle(const void* deserializePointer,
|
||||||
|
size_t deserializeSize,
|
||||||
|
WriteHandle** writeHandle) override {
|
||||||
|
ASSERT(writeHandle != nullptr);
|
||||||
|
*writeHandle = new WriteHandleImpl();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<MemoryTransferService> CreateInlineMemoryTransferService() {
|
||||||
|
return std::make_unique<InlineMemoryTransferService>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}} // namespace dawn_wire::server
|
@ -73,8 +73,12 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
|||||||
ASSERT(nullDevice.Get() != nullptr);
|
ASSERT(nullDevice.Get() != nullptr);
|
||||||
|
|
||||||
DevNull devNull;
|
DevNull devNull;
|
||||||
std::unique_ptr<dawn_wire::WireServer> wireServer(
|
dawn_wire::WireServerDescriptor serverDesc = {};
|
||||||
new dawn_wire::WireServer(nullDevice.Get(), procs, &devNull));
|
serverDesc.device = nullDevice.Get();
|
||||||
|
serverDesc.procs = &procs;
|
||||||
|
serverDesc.serializer = &devNull;
|
||||||
|
|
||||||
|
std::unique_ptr<dawn_wire::WireServer> wireServer(new dawn_wire::WireServer(serverDesc));
|
||||||
|
|
||||||
wireServer->HandleCommands(reinterpret_cast<const char*>(data), size);
|
wireServer->HandleCommands(reinterpret_cast<const char*>(data), size);
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ namespace dawn_wire {
|
|||||||
|
|
||||||
namespace client {
|
namespace client {
|
||||||
class Client;
|
class Client;
|
||||||
|
class MemoryTransferService;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ReservedTexture {
|
struct ReservedTexture {
|
||||||
@ -31,9 +32,14 @@ namespace dawn_wire {
|
|||||||
uint32_t generation;
|
uint32_t generation;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DAWN_WIRE_EXPORT WireClientDescriptor {
|
||||||
|
CommandSerializer* serializer;
|
||||||
|
client::MemoryTransferService* memoryTransferService = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
class DAWN_WIRE_EXPORT WireClient : public CommandHandler {
|
class DAWN_WIRE_EXPORT WireClient : public CommandHandler {
|
||||||
public:
|
public:
|
||||||
WireClient(CommandSerializer* serializer);
|
WireClient(const WireClientDescriptor& descriptor);
|
||||||
~WireClient();
|
~WireClient();
|
||||||
|
|
||||||
DawnDevice GetDevice() const;
|
DawnDevice GetDevice() const;
|
||||||
@ -46,6 +52,67 @@ namespace dawn_wire {
|
|||||||
std::unique_ptr<client::Client> mImpl;
|
std::unique_ptr<client::Client> mImpl;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace client {
|
||||||
|
class DAWN_WIRE_EXPORT MemoryTransferService {
|
||||||
|
public:
|
||||||
|
class ReadHandle;
|
||||||
|
class WriteHandle;
|
||||||
|
|
||||||
|
virtual ~MemoryTransferService();
|
||||||
|
|
||||||
|
// Create a handle for reading server data.
|
||||||
|
// This may fail and return nullptr.
|
||||||
|
virtual ReadHandle* CreateReadHandle(size_t) = 0;
|
||||||
|
|
||||||
|
// Create a handle for writing server data.
|
||||||
|
// This may fail and return nullptr.
|
||||||
|
virtual WriteHandle* CreateWriteHandle(size_t) = 0;
|
||||||
|
|
||||||
|
// Imported memory implementation needs to override these to create Read/Write
|
||||||
|
// handles associated with a particular buffer. The client should receive a file
|
||||||
|
// descriptor for the buffer out-of-band.
|
||||||
|
virtual ReadHandle* CreateReadHandle(DawnBuffer, uint64_t offset, size_t size);
|
||||||
|
virtual WriteHandle* CreateWriteHandle(DawnBuffer, uint64_t offset, size_t size);
|
||||||
|
|
||||||
|
class ReadHandle {
|
||||||
|
public:
|
||||||
|
// Serialize the handle into |serializePointer| so it can be received by the server.
|
||||||
|
// If |serializePointer| is nullptr, this returns the required serialization space.
|
||||||
|
virtual size_t SerializeCreate(void* serializePointer = nullptr) = 0;
|
||||||
|
|
||||||
|
// Load initial data and open the handle for reading.
|
||||||
|
// This function takes in the serialized result of
|
||||||
|
// server::MemoryTransferService::ReadHandle::SerializeInitialData.
|
||||||
|
// This function should write to |data| and |dataLength| the pointer and size of the
|
||||||
|
// mapped data for reading. It must live at least until the ReadHandle is
|
||||||
|
// destructed.
|
||||||
|
virtual bool DeserializeInitialData(const void* deserializePointer,
|
||||||
|
size_t deserializeSize,
|
||||||
|
const void** data,
|
||||||
|
size_t* dataLength) = 0;
|
||||||
|
virtual ~ReadHandle();
|
||||||
|
};
|
||||||
|
|
||||||
|
class WriteHandle {
|
||||||
|
public:
|
||||||
|
// Serialize the handle into |serializePointer| so it can be received by the server.
|
||||||
|
// If |serializePointer| is nullptr, this returns the required serialization space.
|
||||||
|
virtual size_t SerializeCreate(void* serializePointer = nullptr) = 0;
|
||||||
|
|
||||||
|
// Open the handle for reading. The data returned should be zero-initialized.
|
||||||
|
// The data returned must live at least until the WriteHandle is destructed.
|
||||||
|
// On failure, the pointer returned should be null.
|
||||||
|
virtual std::pair<void*, size_t> Open() = 0;
|
||||||
|
|
||||||
|
// Flush writes to the handle. This should serialize info to send updates to the
|
||||||
|
// server.
|
||||||
|
// If |serializePointer| is nullptr, this returns the required serialization space.
|
||||||
|
virtual size_t SerializeFlush(void* serializePointer = nullptr) = 0;
|
||||||
|
virtual ~WriteHandle();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} // namespace client
|
||||||
|
|
||||||
} // namespace dawn_wire
|
} // namespace dawn_wire
|
||||||
|
|
||||||
#endif // DAWNWIRE_WIRECLIENT_H_
|
#endif // DAWNWIRE_WIRECLIENT_H_
|
||||||
|
@ -23,11 +23,19 @@ namespace dawn_wire {
|
|||||||
|
|
||||||
namespace server {
|
namespace server {
|
||||||
class Server;
|
class Server;
|
||||||
|
class MemoryTransferService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DAWN_WIRE_EXPORT WireServerDescriptor {
|
||||||
|
DawnDevice device;
|
||||||
|
const DawnProcTable* procs;
|
||||||
|
CommandSerializer* serializer;
|
||||||
|
server::MemoryTransferService* memoryTransferService = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
class DAWN_WIRE_EXPORT WireServer : public CommandHandler {
|
class DAWN_WIRE_EXPORT WireServer : public CommandHandler {
|
||||||
public:
|
public:
|
||||||
WireServer(DawnDevice device, const DawnProcTable& procs, CommandSerializer* serializer);
|
WireServer(const WireServerDescriptor& descriptor);
|
||||||
~WireServer();
|
~WireServer();
|
||||||
|
|
||||||
const char* HandleCommands(const char* commands, size_t size) override final;
|
const char* HandleCommands(const char* commands, size_t size) override final;
|
||||||
@ -38,6 +46,53 @@ namespace dawn_wire {
|
|||||||
std::unique_ptr<server::Server> mImpl;
|
std::unique_ptr<server::Server> mImpl;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace server {
|
||||||
|
class DAWN_WIRE_EXPORT MemoryTransferService {
|
||||||
|
public:
|
||||||
|
class ReadHandle;
|
||||||
|
class WriteHandle;
|
||||||
|
|
||||||
|
virtual ~MemoryTransferService();
|
||||||
|
|
||||||
|
// Deserialize data to create Read/Write handles. These handles are for the client
|
||||||
|
// to Read/Write data.
|
||||||
|
virtual bool DeserializeReadHandle(const void* deserializePointer,
|
||||||
|
size_t deserializeSize,
|
||||||
|
ReadHandle** readHandle) = 0;
|
||||||
|
virtual bool DeserializeWriteHandle(const void* deserializePointer,
|
||||||
|
size_t deserializeSize,
|
||||||
|
WriteHandle** writeHandle) = 0;
|
||||||
|
|
||||||
|
class ReadHandle {
|
||||||
|
public:
|
||||||
|
// Initialize the handle data.
|
||||||
|
// Serialize into |serializePointer| so the client can update handle data.
|
||||||
|
// If |serializePointer| is nullptr, this returns the required serialization space.
|
||||||
|
virtual size_t SerializeInitialData(const void* data,
|
||||||
|
size_t dataLength,
|
||||||
|
void* serializePointer = nullptr) = 0;
|
||||||
|
virtual ~ReadHandle();
|
||||||
|
};
|
||||||
|
|
||||||
|
class WriteHandle {
|
||||||
|
public:
|
||||||
|
// Set the target for writes from the client. DeserializeFlush should copy data
|
||||||
|
// into the target.
|
||||||
|
void SetTarget(void* data, size_t dataLength);
|
||||||
|
|
||||||
|
// This function takes in the serialized result of
|
||||||
|
// client::MemoryTransferService::WriteHandle::SerializeFlush.
|
||||||
|
virtual bool DeserializeFlush(const void* deserializePointer,
|
||||||
|
size_t deserializeSize) = 0;
|
||||||
|
virtual ~WriteHandle();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void* mTargetData = nullptr;
|
||||||
|
size_t mDataLength = 0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} // namespace server
|
||||||
|
|
||||||
} // namespace dawn_wire
|
} // namespace dawn_wire
|
||||||
|
|
||||||
#endif // DAWNWIRE_WIRESERVER_H_
|
#endif // DAWNWIRE_WIRESERVER_H_
|
||||||
|
@ -395,10 +395,18 @@ void DawnTest::SetUp() {
|
|||||||
mC2sBuf = std::make_unique<utils::TerribleCommandBuffer>();
|
mC2sBuf = std::make_unique<utils::TerribleCommandBuffer>();
|
||||||
mS2cBuf = std::make_unique<utils::TerribleCommandBuffer>();
|
mS2cBuf = std::make_unique<utils::TerribleCommandBuffer>();
|
||||||
|
|
||||||
mWireServer.reset(new dawn_wire::WireServer(backendDevice, backendProcs, mS2cBuf.get()));
|
dawn_wire::WireServerDescriptor serverDesc = {};
|
||||||
|
serverDesc.device = backendDevice;
|
||||||
|
serverDesc.procs = &backendProcs;
|
||||||
|
serverDesc.serializer = mS2cBuf.get();
|
||||||
|
|
||||||
|
mWireServer.reset(new dawn_wire::WireServer(serverDesc));
|
||||||
mC2sBuf->SetHandler(mWireServer.get());
|
mC2sBuf->SetHandler(mWireServer.get());
|
||||||
|
|
||||||
mWireClient.reset(new dawn_wire::WireClient(mC2sBuf.get()));
|
dawn_wire::WireClientDescriptor clientDesc = {};
|
||||||
|
clientDesc.serializer = mC2sBuf.get();
|
||||||
|
|
||||||
|
mWireClient.reset(new dawn_wire::WireClient(clientDesc));
|
||||||
DawnDevice clientDevice = mWireClient->GetDevice();
|
DawnDevice clientDevice = mWireClient->GetDevice();
|
||||||
DawnProcTable clientProcs = mWireClient->GetProcs();
|
DawnProcTable clientProcs = mWireClient->GetProcs();
|
||||||
mS2cBuf->SetHandler(mWireClient.get());
|
mS2cBuf->SetHandler(mWireClient.get());
|
||||||
|
@ -99,6 +99,7 @@ class WireBufferMappingTests : public WireTest {
|
|||||||
|
|
||||||
DawnBufferDescriptor descriptor;
|
DawnBufferDescriptor descriptor;
|
||||||
descriptor.nextInChain = nullptr;
|
descriptor.nextInChain = nullptr;
|
||||||
|
descriptor.size = kBufferSize;
|
||||||
|
|
||||||
apiBuffer = api.GetNewBuffer();
|
apiBuffer = api.GetNewBuffer();
|
||||||
buffer = dawnDeviceCreateBuffer(device, &descriptor);
|
buffer = dawnDeviceCreateBuffer(device, &descriptor);
|
||||||
@ -127,6 +128,7 @@ class WireBufferMappingTests : public WireTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
static constexpr uint64_t kBufferSize = sizeof(uint32_t);
|
||||||
// A successfully created buffer
|
// A successfully created buffer
|
||||||
DawnBuffer buffer;
|
DawnBuffer buffer;
|
||||||
DawnBuffer apiBuffer;
|
DawnBuffer apiBuffer;
|
||||||
@ -142,13 +144,13 @@ TEST_F(WireBufferMappingTests, MappingForReadSuccessBuffer) {
|
|||||||
EXPECT_CALL(api, OnBufferMapReadAsyncCallback(apiBuffer, _, _))
|
EXPECT_CALL(api, OnBufferMapReadAsyncCallback(apiBuffer, _, _))
|
||||||
.WillOnce(InvokeWithoutArgs([&]() {
|
.WillOnce(InvokeWithoutArgs([&]() {
|
||||||
api.CallMapReadCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, &bufferContent,
|
api.CallMapReadCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, &bufferContent,
|
||||||
sizeof(uint32_t));
|
kBufferSize);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
FlushClient();
|
FlushClient();
|
||||||
|
|
||||||
EXPECT_CALL(*mockBufferMapReadCallback, Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
EXPECT_CALL(*mockBufferMapReadCallback, Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
||||||
Pointee(Eq(bufferContent)), sizeof(uint32_t), _))
|
Pointee(Eq(bufferContent)), kBufferSize, _))
|
||||||
.Times(1);
|
.Times(1);
|
||||||
|
|
||||||
FlushServer();
|
FlushServer();
|
||||||
@ -208,7 +210,7 @@ TEST_F(WireBufferMappingTests, UnmapCalledTooEarlyForRead) {
|
|||||||
EXPECT_CALL(api, OnBufferMapReadAsyncCallback(apiBuffer, _, _))
|
EXPECT_CALL(api, OnBufferMapReadAsyncCallback(apiBuffer, _, _))
|
||||||
.WillOnce(InvokeWithoutArgs([&]() {
|
.WillOnce(InvokeWithoutArgs([&]() {
|
||||||
api.CallMapReadCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, &bufferContent,
|
api.CallMapReadCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, &bufferContent,
|
||||||
sizeof(uint32_t));
|
kBufferSize);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
FlushClient();
|
FlushClient();
|
||||||
@ -232,14 +234,14 @@ TEST_F(WireBufferMappingTests, MappingForReadingErrorWhileAlreadyMappedGetsNullp
|
|||||||
EXPECT_CALL(api, OnBufferMapReadAsyncCallback(apiBuffer, _, _))
|
EXPECT_CALL(api, OnBufferMapReadAsyncCallback(apiBuffer, _, _))
|
||||||
.WillOnce(InvokeWithoutArgs([&]() {
|
.WillOnce(InvokeWithoutArgs([&]() {
|
||||||
api.CallMapReadCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, &bufferContent,
|
api.CallMapReadCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, &bufferContent,
|
||||||
sizeof(uint32_t));
|
kBufferSize);
|
||||||
}))
|
}))
|
||||||
.RetiresOnSaturation();
|
.RetiresOnSaturation();
|
||||||
|
|
||||||
FlushClient();
|
FlushClient();
|
||||||
|
|
||||||
EXPECT_CALL(*mockBufferMapReadCallback, Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
EXPECT_CALL(*mockBufferMapReadCallback, Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
||||||
Pointee(Eq(bufferContent)), sizeof(uint32_t), _))
|
Pointee(Eq(bufferContent)), kBufferSize, _))
|
||||||
.Times(1);
|
.Times(1);
|
||||||
|
|
||||||
FlushServer();
|
FlushServer();
|
||||||
@ -267,13 +269,13 @@ TEST_F(WireBufferMappingTests, UnmapInsideMapReadCallback) {
|
|||||||
EXPECT_CALL(api, OnBufferMapReadAsyncCallback(apiBuffer, _, _))
|
EXPECT_CALL(api, OnBufferMapReadAsyncCallback(apiBuffer, _, _))
|
||||||
.WillOnce(InvokeWithoutArgs([&]() {
|
.WillOnce(InvokeWithoutArgs([&]() {
|
||||||
api.CallMapReadCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, &bufferContent,
|
api.CallMapReadCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, &bufferContent,
|
||||||
sizeof(uint32_t));
|
kBufferSize);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
FlushClient();
|
FlushClient();
|
||||||
|
|
||||||
EXPECT_CALL(*mockBufferMapReadCallback, Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
EXPECT_CALL(*mockBufferMapReadCallback, Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
||||||
Pointee(Eq(bufferContent)), sizeof(uint32_t), _))
|
Pointee(Eq(bufferContent)), kBufferSize, _))
|
||||||
.WillOnce(InvokeWithoutArgs([&]() { dawnBufferUnmap(buffer); }));
|
.WillOnce(InvokeWithoutArgs([&]() { dawnBufferUnmap(buffer); }));
|
||||||
|
|
||||||
FlushServer();
|
FlushServer();
|
||||||
@ -292,13 +294,13 @@ TEST_F(WireBufferMappingTests, DestroyInsideMapReadCallback) {
|
|||||||
EXPECT_CALL(api, OnBufferMapReadAsyncCallback(apiBuffer, _, _))
|
EXPECT_CALL(api, OnBufferMapReadAsyncCallback(apiBuffer, _, _))
|
||||||
.WillOnce(InvokeWithoutArgs([&]() {
|
.WillOnce(InvokeWithoutArgs([&]() {
|
||||||
api.CallMapReadCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, &bufferContent,
|
api.CallMapReadCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, &bufferContent,
|
||||||
sizeof(uint32_t));
|
kBufferSize);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
FlushClient();
|
FlushClient();
|
||||||
|
|
||||||
EXPECT_CALL(*mockBufferMapReadCallback, Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
EXPECT_CALL(*mockBufferMapReadCallback, Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
||||||
Pointee(Eq(bufferContent)), sizeof(uint32_t), _))
|
Pointee(Eq(bufferContent)), kBufferSize, _))
|
||||||
.WillOnce(InvokeWithoutArgs([&]() { dawnBufferRelease(buffer); }));
|
.WillOnce(InvokeWithoutArgs([&]() { dawnBufferRelease(buffer); }));
|
||||||
|
|
||||||
FlushServer();
|
FlushServer();
|
||||||
@ -321,14 +323,14 @@ TEST_F(WireBufferMappingTests, MappingForWriteSuccessBuffer) {
|
|||||||
EXPECT_CALL(api, OnBufferMapWriteAsyncCallback(apiBuffer, _, _))
|
EXPECT_CALL(api, OnBufferMapWriteAsyncCallback(apiBuffer, _, _))
|
||||||
.WillOnce(InvokeWithoutArgs([&]() {
|
.WillOnce(InvokeWithoutArgs([&]() {
|
||||||
api.CallMapWriteCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
api.CallMapWriteCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
||||||
&serverBufferContent, sizeof(uint32_t));
|
&serverBufferContent, kBufferSize);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
FlushClient();
|
FlushClient();
|
||||||
|
|
||||||
// The map write callback always gets a buffer full of zeroes.
|
// The map write callback always gets a buffer full of zeroes.
|
||||||
EXPECT_CALL(*mockBufferMapWriteCallback,
|
EXPECT_CALL(*mockBufferMapWriteCallback,
|
||||||
Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, Pointee(Eq(zero)), sizeof(uint32_t), _))
|
Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, Pointee(Eq(zero)), kBufferSize, _))
|
||||||
.Times(1);
|
.Times(1);
|
||||||
|
|
||||||
FlushServer();
|
FlushServer();
|
||||||
@ -395,7 +397,7 @@ TEST_F(WireBufferMappingTests, UnmapCalledTooEarlyForWrite) {
|
|||||||
EXPECT_CALL(api, OnBufferMapWriteAsyncCallback(apiBuffer, _, _))
|
EXPECT_CALL(api, OnBufferMapWriteAsyncCallback(apiBuffer, _, _))
|
||||||
.WillOnce(InvokeWithoutArgs([&]() {
|
.WillOnce(InvokeWithoutArgs([&]() {
|
||||||
api.CallMapWriteCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
api.CallMapWriteCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
||||||
&bufferContent, sizeof(uint32_t));
|
&bufferContent, kBufferSize);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
FlushClient();
|
FlushClient();
|
||||||
@ -420,14 +422,14 @@ TEST_F(WireBufferMappingTests, MappingForWritingErrorWhileAlreadyMappedGetsNullp
|
|||||||
EXPECT_CALL(api, OnBufferMapWriteAsyncCallback(apiBuffer, _, _))
|
EXPECT_CALL(api, OnBufferMapWriteAsyncCallback(apiBuffer, _, _))
|
||||||
.WillOnce(InvokeWithoutArgs([&]() {
|
.WillOnce(InvokeWithoutArgs([&]() {
|
||||||
api.CallMapWriteCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
api.CallMapWriteCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
||||||
&bufferContent, sizeof(uint32_t));
|
&bufferContent, kBufferSize);
|
||||||
}))
|
}))
|
||||||
.RetiresOnSaturation();
|
.RetiresOnSaturation();
|
||||||
|
|
||||||
FlushClient();
|
FlushClient();
|
||||||
|
|
||||||
EXPECT_CALL(*mockBufferMapWriteCallback,
|
EXPECT_CALL(*mockBufferMapWriteCallback,
|
||||||
Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, Pointee(Eq(zero)), sizeof(uint32_t), _))
|
Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, Pointee(Eq(zero)), kBufferSize, _))
|
||||||
.Times(1);
|
.Times(1);
|
||||||
|
|
||||||
FlushServer();
|
FlushServer();
|
||||||
@ -457,13 +459,13 @@ TEST_F(WireBufferMappingTests, UnmapInsideMapWriteCallback) {
|
|||||||
EXPECT_CALL(api, OnBufferMapWriteAsyncCallback(apiBuffer, _, _))
|
EXPECT_CALL(api, OnBufferMapWriteAsyncCallback(apiBuffer, _, _))
|
||||||
.WillOnce(InvokeWithoutArgs([&]() {
|
.WillOnce(InvokeWithoutArgs([&]() {
|
||||||
api.CallMapWriteCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
api.CallMapWriteCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
||||||
&bufferContent, sizeof(uint32_t));
|
&bufferContent, kBufferSize);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
FlushClient();
|
FlushClient();
|
||||||
|
|
||||||
EXPECT_CALL(*mockBufferMapWriteCallback,
|
EXPECT_CALL(*mockBufferMapWriteCallback,
|
||||||
Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, Pointee(Eq(zero)), sizeof(uint32_t), _))
|
Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, Pointee(Eq(zero)), kBufferSize, _))
|
||||||
.WillOnce(InvokeWithoutArgs([&]() { dawnBufferUnmap(buffer); }));
|
.WillOnce(InvokeWithoutArgs([&]() { dawnBufferUnmap(buffer); }));
|
||||||
|
|
||||||
FlushServer();
|
FlushServer();
|
||||||
@ -483,13 +485,13 @@ TEST_F(WireBufferMappingTests, DestroyInsideMapWriteCallback) {
|
|||||||
EXPECT_CALL(api, OnBufferMapWriteAsyncCallback(apiBuffer, _, _))
|
EXPECT_CALL(api, OnBufferMapWriteAsyncCallback(apiBuffer, _, _))
|
||||||
.WillOnce(InvokeWithoutArgs([&]() {
|
.WillOnce(InvokeWithoutArgs([&]() {
|
||||||
api.CallMapWriteCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
api.CallMapWriteCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
||||||
&bufferContent, sizeof(uint32_t));
|
&bufferContent, kBufferSize);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
FlushClient();
|
FlushClient();
|
||||||
|
|
||||||
EXPECT_CALL(*mockBufferMapWriteCallback,
|
EXPECT_CALL(*mockBufferMapWriteCallback,
|
||||||
Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, Pointee(Eq(zero)), sizeof(uint32_t), _))
|
Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, Pointee(Eq(zero)), kBufferSize, _))
|
||||||
.WillOnce(InvokeWithoutArgs([&]() { dawnBufferRelease(buffer); }));
|
.WillOnce(InvokeWithoutArgs([&]() { dawnBufferRelease(buffer); }));
|
||||||
|
|
||||||
FlushServer();
|
FlushServer();
|
||||||
@ -585,13 +587,13 @@ TEST_F(WireBufferMappingTests, CreateBufferMappedThenMapSuccess) {
|
|||||||
EXPECT_CALL(api, OnBufferMapWriteAsyncCallback(apiBuffer, _, _))
|
EXPECT_CALL(api, OnBufferMapWriteAsyncCallback(apiBuffer, _, _))
|
||||||
.WillOnce(InvokeWithoutArgs([&]() {
|
.WillOnce(InvokeWithoutArgs([&]() {
|
||||||
api.CallMapWriteCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
api.CallMapWriteCallback(apiBuffer, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS,
|
||||||
&apiBufferData, sizeof(uint32_t));
|
&apiBufferData, kBufferSize);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
FlushClient();
|
FlushClient();
|
||||||
|
|
||||||
EXPECT_CALL(*mockBufferMapWriteCallback,
|
EXPECT_CALL(*mockBufferMapWriteCallback,
|
||||||
Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, Pointee(Eq(zero)), sizeof(uint32_t), _))
|
Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, Pointee(Eq(zero)), kBufferSize, _))
|
||||||
.Times(1);
|
.Times(1);
|
||||||
|
|
||||||
FlushServer();
|
FlushServer();
|
||||||
@ -643,12 +645,13 @@ TEST_F(WireBufferMappingTests, CreateBufferMappedThenMapFailure) {
|
|||||||
TEST_F(WireBufferMappingTests, CreateBufferMappedAsyncSuccess) {
|
TEST_F(WireBufferMappingTests, CreateBufferMappedAsyncSuccess) {
|
||||||
DawnBufferDescriptor descriptor;
|
DawnBufferDescriptor descriptor;
|
||||||
descriptor.nextInChain = nullptr;
|
descriptor.nextInChain = nullptr;
|
||||||
|
descriptor.size = kBufferSize;
|
||||||
|
|
||||||
DawnCreateBufferMappedResult apiResult;
|
DawnCreateBufferMappedResult apiResult;
|
||||||
uint32_t serverBufferContent = 31337;
|
uint32_t serverBufferContent = 31337;
|
||||||
apiResult.buffer = apiBuffer;
|
apiResult.buffer = apiBuffer;
|
||||||
apiResult.data = reinterpret_cast<uint8_t*>(&serverBufferContent);
|
apiResult.data = reinterpret_cast<uint8_t*>(&serverBufferContent);
|
||||||
apiResult.dataLength = 4;
|
apiResult.dataLength = kBufferSize;
|
||||||
|
|
||||||
uint32_t updatedContent = 4242;
|
uint32_t updatedContent = 4242;
|
||||||
uint32_t zero = 0;
|
uint32_t zero = 0;
|
||||||
@ -663,8 +666,8 @@ TEST_F(WireBufferMappingTests, CreateBufferMappedAsyncSuccess) {
|
|||||||
|
|
||||||
DawnBuffer buffer;
|
DawnBuffer buffer;
|
||||||
// The callback always gets a buffer full of zeroes.
|
// The callback always gets a buffer full of zeroes.
|
||||||
EXPECT_CALL(*mockCreateBufferMappedCallback, Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, _,
|
EXPECT_CALL(*mockCreateBufferMappedCallback,
|
||||||
Pointee(Eq(zero)), sizeof(uint32_t), _))
|
Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, _, Pointee(Eq(zero)), kBufferSize, _))
|
||||||
.WillOnce(::testing::SaveArg<1>(&buffer));
|
.WillOnce(::testing::SaveArg<1>(&buffer));
|
||||||
|
|
||||||
FlushServer();
|
FlushServer();
|
||||||
@ -689,7 +692,7 @@ TEST_F(WireBufferMappingTests, CreateBufferMappedAsyncMapError) {
|
|||||||
DawnCreateBufferMappedResult apiResult;
|
DawnCreateBufferMappedResult apiResult;
|
||||||
apiResult.buffer = apiBuffer;
|
apiResult.buffer = apiBuffer;
|
||||||
apiResult.data = nullptr; // error mapping
|
apiResult.data = nullptr; // error mapping
|
||||||
apiResult.dataLength = 4;
|
apiResult.dataLength = kBufferSize;
|
||||||
|
|
||||||
dawnDeviceCreateBufferMappedAsync(device, &descriptor, ToMockCreateBufferMappedCallback, nullptr);
|
dawnDeviceCreateBufferMappedAsync(device, &descriptor, ToMockCreateBufferMappedCallback, nullptr);
|
||||||
|
|
||||||
@ -717,12 +720,13 @@ TEST_F(WireBufferMappingTests, CreateBufferMappedAsyncMapError) {
|
|||||||
TEST_F(WireBufferMappingTests, UnmapInsideCreateBufferMappedAsyncCallback) {
|
TEST_F(WireBufferMappingTests, UnmapInsideCreateBufferMappedAsyncCallback) {
|
||||||
DawnBufferDescriptor descriptor;
|
DawnBufferDescriptor descriptor;
|
||||||
descriptor.nextInChain = nullptr;
|
descriptor.nextInChain = nullptr;
|
||||||
|
descriptor.size = kBufferSize;
|
||||||
|
|
||||||
DawnCreateBufferMappedResult apiResult;
|
DawnCreateBufferMappedResult apiResult;
|
||||||
uint32_t serverBufferContent = 31337;
|
uint32_t serverBufferContent = 31337;
|
||||||
apiResult.buffer = apiBuffer;
|
apiResult.buffer = apiBuffer;
|
||||||
apiResult.data = reinterpret_cast<uint8_t*>(&serverBufferContent);
|
apiResult.data = reinterpret_cast<uint8_t*>(&serverBufferContent);
|
||||||
apiResult.dataLength = 4;
|
apiResult.dataLength = kBufferSize;
|
||||||
|
|
||||||
uint32_t zero = 0;
|
uint32_t zero = 0;
|
||||||
|
|
||||||
@ -736,8 +740,8 @@ TEST_F(WireBufferMappingTests, UnmapInsideCreateBufferMappedAsyncCallback) {
|
|||||||
|
|
||||||
DawnBuffer buffer;
|
DawnBuffer buffer;
|
||||||
// The callback always gets a buffer full of zeroes.
|
// The callback always gets a buffer full of zeroes.
|
||||||
EXPECT_CALL(*mockCreateBufferMappedCallback, Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, _,
|
EXPECT_CALL(*mockCreateBufferMappedCallback,
|
||||||
Pointee(Eq(zero)), sizeof(uint32_t), _))
|
Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, _, Pointee(Eq(zero)), kBufferSize, _))
|
||||||
.WillOnce(DoAll(::testing::SaveArg<1>(&buffer),
|
.WillOnce(DoAll(::testing::SaveArg<1>(&buffer),
|
||||||
InvokeWithoutArgs([&]() { dawnBufferUnmap(buffer); })));
|
InvokeWithoutArgs([&]() { dawnBufferUnmap(buffer); })));
|
||||||
|
|
||||||
@ -753,12 +757,13 @@ TEST_F(WireBufferMappingTests, UnmapInsideCreateBufferMappedAsyncCallback) {
|
|||||||
TEST_F(WireBufferMappingTests, ReleaseInsideCreateBufferMappedAsyncCallback) {
|
TEST_F(WireBufferMappingTests, ReleaseInsideCreateBufferMappedAsyncCallback) {
|
||||||
DawnBufferDescriptor descriptor;
|
DawnBufferDescriptor descriptor;
|
||||||
descriptor.nextInChain = nullptr;
|
descriptor.nextInChain = nullptr;
|
||||||
|
descriptor.size = kBufferSize;
|
||||||
|
|
||||||
DawnCreateBufferMappedResult apiResult;
|
DawnCreateBufferMappedResult apiResult;
|
||||||
uint32_t serverBufferContent = 31337;
|
uint32_t serverBufferContent = 31337;
|
||||||
apiResult.buffer = apiBuffer;
|
apiResult.buffer = apiBuffer;
|
||||||
apiResult.data = reinterpret_cast<uint8_t*>(&serverBufferContent);
|
apiResult.data = reinterpret_cast<uint8_t*>(&serverBufferContent);
|
||||||
apiResult.dataLength = 4;
|
apiResult.dataLength = kBufferSize;
|
||||||
|
|
||||||
uint32_t zero = 0;
|
uint32_t zero = 0;
|
||||||
|
|
||||||
@ -772,8 +777,8 @@ TEST_F(WireBufferMappingTests, ReleaseInsideCreateBufferMappedAsyncCallback) {
|
|||||||
|
|
||||||
DawnBuffer buffer;
|
DawnBuffer buffer;
|
||||||
// The callback always gets a buffer full of zeroes.
|
// The callback always gets a buffer full of zeroes.
|
||||||
EXPECT_CALL(*mockCreateBufferMappedCallback, Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, _,
|
EXPECT_CALL(*mockCreateBufferMappedCallback,
|
||||||
Pointee(Eq(zero)), sizeof(uint32_t), _))
|
Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, _, Pointee(Eq(zero)), kBufferSize, _))
|
||||||
.WillOnce(DoAll(::testing::SaveArg<1>(&buffer),
|
.WillOnce(DoAll(::testing::SaveArg<1>(&buffer),
|
||||||
InvokeWithoutArgs([&]() { dawnBufferRelease(buffer); })));
|
InvokeWithoutArgs([&]() { dawnBufferRelease(buffer); })));
|
||||||
|
|
||||||
@ -789,12 +794,13 @@ TEST_F(WireBufferMappingTests, ReleaseInsideCreateBufferMappedAsyncCallback) {
|
|||||||
TEST_F(WireBufferMappingTests, DestroyInsideCreateBufferMappedAsyncCallback) {
|
TEST_F(WireBufferMappingTests, DestroyInsideCreateBufferMappedAsyncCallback) {
|
||||||
DawnBufferDescriptor descriptor;
|
DawnBufferDescriptor descriptor;
|
||||||
descriptor.nextInChain = nullptr;
|
descriptor.nextInChain = nullptr;
|
||||||
|
descriptor.size = kBufferSize;
|
||||||
|
|
||||||
DawnCreateBufferMappedResult apiResult;
|
DawnCreateBufferMappedResult apiResult;
|
||||||
uint32_t serverBufferContent = 31337;
|
uint32_t serverBufferContent = 31337;
|
||||||
apiResult.buffer = apiBuffer;
|
apiResult.buffer = apiBuffer;
|
||||||
apiResult.data = reinterpret_cast<uint8_t*>(&serverBufferContent);
|
apiResult.data = reinterpret_cast<uint8_t*>(&serverBufferContent);
|
||||||
apiResult.dataLength = 4;
|
apiResult.dataLength = kBufferSize;
|
||||||
|
|
||||||
uint32_t zero = 0;
|
uint32_t zero = 0;
|
||||||
|
|
||||||
@ -808,8 +814,8 @@ TEST_F(WireBufferMappingTests, DestroyInsideCreateBufferMappedAsyncCallback) {
|
|||||||
|
|
||||||
DawnBuffer buffer;
|
DawnBuffer buffer;
|
||||||
// The callback always gets a buffer full of zeroes.
|
// The callback always gets a buffer full of zeroes.
|
||||||
EXPECT_CALL(*mockCreateBufferMappedCallback, Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, _,
|
EXPECT_CALL(*mockCreateBufferMappedCallback,
|
||||||
Pointee(Eq(zero)), sizeof(uint32_t), _))
|
Call(DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, _, Pointee(Eq(zero)), kBufferSize, _))
|
||||||
.WillOnce(DoAll(::testing::SaveArg<1>(&buffer),
|
.WillOnce(DoAll(::testing::SaveArg<1>(&buffer),
|
||||||
InvokeWithoutArgs([&]() { dawnBufferDestroy(buffer); })));
|
InvokeWithoutArgs([&]() { dawnBufferDestroy(buffer); })));
|
||||||
|
|
||||||
|
@ -39,10 +39,18 @@ void WireTest::SetUp() {
|
|||||||
mS2cBuf = std::make_unique<utils::TerribleCommandBuffer>();
|
mS2cBuf = std::make_unique<utils::TerribleCommandBuffer>();
|
||||||
mC2sBuf = std::make_unique<utils::TerribleCommandBuffer>(mWireServer.get());
|
mC2sBuf = std::make_unique<utils::TerribleCommandBuffer>(mWireServer.get());
|
||||||
|
|
||||||
mWireServer.reset(new WireServer(mockDevice, mockProcs, mS2cBuf.get()));
|
WireServerDescriptor serverDesc = {};
|
||||||
|
serverDesc.device = mockDevice;
|
||||||
|
serverDesc.procs = &mockProcs;
|
||||||
|
serverDesc.serializer = mS2cBuf.get();
|
||||||
|
|
||||||
|
mWireServer.reset(new WireServer(serverDesc));
|
||||||
mC2sBuf->SetHandler(mWireServer.get());
|
mC2sBuf->SetHandler(mWireServer.get());
|
||||||
|
|
||||||
mWireClient.reset(new WireClient(mC2sBuf.get()));
|
WireClientDescriptor clientDesc = {};
|
||||||
|
clientDesc.serializer = mC2sBuf.get();
|
||||||
|
|
||||||
|
mWireClient.reset(new WireClient(clientDesc));
|
||||||
mS2cBuf->SetHandler(mWireClient.get());
|
mS2cBuf->SetHandler(mWireClient.get());
|
||||||
|
|
||||||
device = mWireClient->GetDevice();
|
device = mWireClient->GetDevice();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user