mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-16 16:37:08 +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:
committed by
Commit Bot service account
parent
49aae0f3bd
commit
6a5418a760
@@ -23,7 +23,9 @@ namespace dawn_wire { namespace server {
|
||||
auto* buffer = BufferObjects().Get(cmd.selfId);
|
||||
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;
|
||||
|
||||
return true;
|
||||
@@ -31,7 +33,9 @@ namespace dawn_wire { namespace server {
|
||||
|
||||
bool Server::DoBufferMapAsync(ObjectId bufferId,
|
||||
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
|
||||
// client will require in the return command.
|
||||
|
||||
@@ -45,16 +49,44 @@ namespace dawn_wire { namespace server {
|
||||
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->buffer = ObjectHandle{bufferId, buffer->serial};
|
||||
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) {
|
||||
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 {
|
||||
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;
|
||||
@@ -62,7 +94,15 @@ namespace dawn_wire { namespace server {
|
||||
|
||||
bool Server::DoDeviceCreateBufferMapped(DawnDevice device,
|
||||
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);
|
||||
if (resultData == nullptr) {
|
||||
return false;
|
||||
@@ -73,15 +113,29 @@ namespace dawn_wire { namespace server {
|
||||
ASSERT(result.buffer != nullptr);
|
||||
if (result.data == nullptr && result.dataLength != 0) {
|
||||
// Non-zero dataLength but null data is used to indicate an allocation error.
|
||||
// Don't return false because this is not fatal. result.buffer is an ErrorBuffer
|
||||
// and subsequent operations will be errors.
|
||||
// This should only happen when fuzzing with the Null backend.
|
||||
resultData->mapWriteState = BufferMapWriteState::MapError;
|
||||
} 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 may still be an error with fake staging data.
|
||||
resultData->mapWriteState = BufferMapWriteState::Mapped;
|
||||
resultData->writeHandle =
|
||||
std::unique_ptr<MemoryTransferService::WriteHandle>(writeHandle);
|
||||
}
|
||||
resultData->handle = result.buffer;
|
||||
resultData->mappedData = result.data;
|
||||
resultData->mappedDataSize = result.dataLength;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -89,8 +143,11 @@ namespace dawn_wire { namespace server {
|
||||
bool Server::DoDeviceCreateBufferMappedAsync(DawnDevice device,
|
||||
const DawnBufferDescriptor* descriptor,
|
||||
uint32_t requestSerial,
|
||||
ObjectHandle bufferResult) {
|
||||
if (!DoDeviceCreateBufferMapped(device, descriptor, bufferResult)) {
|
||||
ObjectHandle bufferResult,
|
||||
uint64_t handleCreateInfoLength,
|
||||
const uint8_t* handleCreateInfo) {
|
||||
if (!DoDeviceCreateBufferMapped(device, descriptor, bufferResult, handleCreateInfoLength,
|
||||
handleCreateInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -103,7 +160,6 @@ namespace dawn_wire { namespace server {
|
||||
cmd.status = bufferData->mapWriteState == BufferMapWriteState::Mapped
|
||||
? DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS
|
||||
: DAWN_BUFFER_MAP_ASYNC_STATUS_ERROR;
|
||||
cmd.dataLength = bufferData->mappedDataSize;
|
||||
|
||||
size_t requiredSize = cmd.GetRequiredSize();
|
||||
char* allocatedBuffer = static_cast<char*>(GetCmdSpace(requiredSize));
|
||||
@@ -130,14 +186,20 @@ namespace dawn_wire { namespace server {
|
||||
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`
|
||||
if (bufferId == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (writeFlushInfoLength > std::numeric_limits<size_t>::max()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* buffer = BufferObjects().Get(bufferId);
|
||||
if (buffer == nullptr || buffer->mappedDataSize != count) {
|
||||
if (buffer == nullptr) {
|
||||
return false;
|
||||
}
|
||||
switch (buffer->mapWriteState) {
|
||||
@@ -150,12 +212,15 @@ namespace dawn_wire { namespace server {
|
||||
case BufferMapWriteState::Mapped:
|
||||
break;
|
||||
}
|
||||
|
||||
ASSERT(data != nullptr);
|
||||
ASSERT(buffer->mappedData != nullptr);
|
||||
memcpy(buffer->mappedData, data, count);
|
||||
|
||||
return true;
|
||||
if (!buffer->writeHandle) {
|
||||
// This check is performed after the check for the MapError state. It is permissible
|
||||
// to Unmap and attempt to update mapped data of an error buffer.
|
||||
return false;
|
||||
}
|
||||
// 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,
|
||||
@@ -186,20 +251,34 @@ namespace dawn_wire { namespace server {
|
||||
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;
|
||||
cmd.buffer = data->buffer;
|
||||
cmd.requestSerial = data->requestSerial;
|
||||
cmd.status = status;
|
||||
cmd.dataLength = 0;
|
||||
cmd.data = static_cast<const uint8_t*>(ptr);
|
||||
cmd.initialDataInfoLength = initialDataInfoLength;
|
||||
cmd.initialDataInfo = nullptr;
|
||||
|
||||
if (status == DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS) {
|
||||
cmd.dataLength = dataLength;
|
||||
}
|
||||
|
||||
size_t requiredSize = cmd.GetRequiredSize();
|
||||
size_t commandSize = cmd.GetRequiredSize();
|
||||
size_t requiredSize = commandSize + initialDataInfoLength;
|
||||
char* allocatedBuffer = static_cast<char*>(GetCmdSpace(requiredSize));
|
||||
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,
|
||||
@@ -218,16 +297,18 @@ namespace dawn_wire { namespace server {
|
||||
cmd.buffer = data->buffer;
|
||||
cmd.requestSerial = data->requestSerial;
|
||||
cmd.status = status;
|
||||
cmd.dataLength = dataLength;
|
||||
|
||||
size_t requiredSize = cmd.GetRequiredSize();
|
||||
char* allocatedBuffer = static_cast<char*>(GetCmdSpace(requiredSize));
|
||||
cmd.Serialize(allocatedBuffer);
|
||||
|
||||
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->mappedData = ptr;
|
||||
bufferData->mappedDataSize = dataLength;
|
||||
// Set the target of the WriteHandle to the mapped buffer data.
|
||||
bufferData->writeHandle->SetTarget(ptr, dataLength);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user