Add wire_cmd.py and dawn_wire.json to autogenerate all wire commands.
Unify code generation for Client->Server and Server->Client commands.
Methods in dawn.json are converted into command records and additional
commands are specified in dawn_wire.json. This can then be used to
completely generate the command handlers and command struct definitions.
Bug: dawn:88
Change-Id: Ic796796ede0aafe02e14f1f96790324dad92f4c0
Reviewed-on: https://dawn-review.googlesource.com/c/3800
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/generator/templates/dawn_wire/WireClient.cpp b/generator/templates/dawn_wire/WireClient.cpp
index ce708e4..9f8dd49 100644
--- a/generator/templates/dawn_wire/WireClient.cpp
+++ b/generator/templates/dawn_wire/WireClient.cpp
@@ -13,7 +13,8 @@
//* limitations under the License.
#include "dawn_wire/Wire.h"
-#include "dawn_wire/WireCmd.h"
+#include "dawn_wire/WireCmd_autogen.h"
+#include "dawn_wire/WireDeserializeAllocator.h"
#include "common/Assert.h"
#include "common/SerialMap.h"
@@ -66,12 +67,7 @@
BuilderCallbackData builderCallback;
};
- {% set special_objects = [
- "device",
- "buffer",
- "fence",
- ] %}
- {% for type in by_category["object"] if not type.name.canonical_case() in special_objects %}
+ {% for type in by_category["object"] if not type.name.CamelCase() in client_special_objects %}
struct {{type.name.CamelCase()}} : ObjectBase {
using ObjectBase::ObjectBase;
};
@@ -269,8 +265,6 @@
CommandSerializer* mSerializer = nullptr;
};
- {% set client_side_commands = ["FenceGetCompletedValue"] %}
-
//* Implementation of the client API functions.
{% for type in by_category["object"] %}
{% set Type = type.name.CamelCase() %}
@@ -305,8 +299,7 @@
self->builderCallback.canCall = false;
{% endif %}
- cmd.resultId = allocation->object->id;
- cmd.resultSerial = allocation->serial;
+ cmd.result = ObjectHandle{allocation->object->id, allocation->serial};
{% endif %}
{% for arg in method.arguments %}
@@ -353,8 +346,9 @@
cmd.objectType = ObjectType::{{type.name.CamelCase()}};
cmd.objectId = obj->id;
- auto allocCmd = static_cast<decltype(cmd)*>(obj->device->GetCmdSpace(sizeof(cmd)));
- *allocCmd = cmd;
+ size_t requiredSize = cmd.GetRequiredSize();
+ char* allocatedBuffer = static_cast<char*>(obj->device->GetCmdSpace(requiredSize));
+ cmd.Serialize(allocatedBuffer);
obj->device->{{type.name.camelCase()}}.Free(obj);
}
@@ -386,8 +380,9 @@
cmd.size = size;
cmd.isWrite = false;
- auto allocCmd = static_cast<decltype(cmd)*>(buffer->device->GetCmdSpace(sizeof(cmd)));
- *allocCmd = cmd;
+ size_t requiredSize = cmd.GetRequiredSize();
+ char* allocatedBuffer = static_cast<char*>(buffer->device->GetCmdSpace(requiredSize));
+ cmd.Serialize(allocatedBuffer);
}
void ClientBufferMapWriteAsync(dawnBuffer cBuffer, uint32_t start, uint32_t size, dawnBufferMapWriteCallback callback, dawnCallbackUserdata userdata) {
@@ -410,8 +405,9 @@
cmd.size = size;
cmd.isWrite = true;
- auto allocCmd = static_cast<decltype(cmd)*>(buffer->device->GetCmdSpace(sizeof(cmd)));
- *allocCmd = cmd;
+ size_t requiredSize = cmd.GetRequiredSize();
+ char* allocatedBuffer = static_cast<char*>(buffer->device->GetCmdSpace(requiredSize));
+ cmd.Serialize(allocatedBuffer);
}
uint64_t ClientFenceGetCompletedValue(dawnFence cSelf) {
@@ -458,12 +454,11 @@
BufferUpdateMappedDataCmd cmd;
cmd.bufferId = buffer->id;
cmd.dataLength = static_cast<uint32_t>(buffer->mappedDataSize);
+ cmd.data = reinterpret_cast<const uint8_t*>(buffer->mappedData);
- auto allocCmd = static_cast<decltype(cmd)*>(buffer->device->GetCmdSpace(sizeof(cmd)));
- *allocCmd = cmd;
-
- void* dataAlloc = buffer->device->GetCmdSpace(cmd.dataLength);
- memcpy(dataAlloc, buffer->mappedData, cmd.dataLength);
+ size_t requiredSize = cmd.GetRequiredSize();
+ char* allocatedBuffer = static_cast<char*>(buffer->device->GetCmdSpace(requiredSize));
+ cmd.Serialize(allocatedBuffer);
}
free(buffer->mappedData);
@@ -510,14 +505,12 @@
// - An autogenerated Client{{suffix}} method that sends the command on the wire
// - A manual ProxyClient{{suffix}} method that will be inserted in the proctable instead of
// the autogenerated one, and that will have to call Client{{suffix}}
- {% set proxied_commands = ["BufferUnmap", "DeviceCreateFence", "QueueSignal"] %}
-
dawnProcTable GetProcs() {
dawnProcTable table;
{% for type in by_category["object"] %}
{% for method in native_methods(type) %}
{% set suffix = as_MethodSuffix(type.name, method.name) %}
- {% if suffix in proxied_commands %}
+ {% if suffix in client_proxied_commands %}
table.{{as_varName(type.name, method.name)}} = ProxyClient{{suffix}};
{% else %}
table.{{as_varName(type.name, method.name)}} = Client{{suffix}};
@@ -538,23 +531,11 @@
bool success = false;
switch (cmdId) {
- case ReturnWireCmd::DeviceErrorCallback:
- success = HandleDeviceErrorCallbackCmd(&commands, &size);
- break;
- {% for type in by_category["object"] if type.is_builder %}
- case ReturnWireCmd::{{type.name.CamelCase()}}ErrorCallback:
- success = Handle{{type.name.CamelCase()}}ErrorCallbackCmd(&commands, &size);
+ {% for command in cmd_records["return command"] %}
+ case ReturnWireCmd::{{command.name.CamelCase()}}:
+ success = Handle{{command.name.CamelCase()}}(&commands, &size);
break;
{% endfor %}
- case ReturnWireCmd::BufferMapReadAsyncCallback:
- success = HandleBufferMapReadAsyncCallback(&commands, &size);
- break;
- case ReturnWireCmd::BufferMapWriteAsyncCallback:
- success = HandleBufferMapWriteAsyncCallback(&commands, &size);
- break;
- case ReturnWireCmd::FenceUpdateCompletedValue:
- success = HandleFenceUpdateCompletedValue(&commands, &size);
- break;
default:
success = false;
}
@@ -562,6 +543,7 @@
if (!success) {
return nullptr;
}
+ mAllocator.Reset();
}
if (size != 0) {
@@ -573,72 +555,47 @@
private:
Device* mDevice = nullptr;
+ WireDeserializeAllocator mAllocator;
- //* Helper function for the getting of the command data in command handlers.
- //* Checks there is enough data left, updates the buffer / size and returns
- //* the command (or nullptr for an error).
- template <typename T>
- static const T* GetData(const char** buffer, size_t* size, size_t count) {
- // TODO(cwallez@chromium.org): Check for overflow
- size_t totalSize = count * sizeof(T);
- if (*size < totalSize) {
- return nullptr;
- }
+ bool HandleDeviceErrorCallback(const char** commands, size_t* size) {
+ ReturnDeviceErrorCallbackCmd cmd;
+ DeserializeResult deserializeResult = cmd.Deserialize(commands, size, &mAllocator);
- const T* data = reinterpret_cast<const T*>(*buffer);
-
- *buffer += totalSize;
- *size -= totalSize;
-
- return data;
- }
- template <typename T>
- static const T* GetCommand(const char** commands, size_t* size) {
- return GetData<T>(commands, size, 1);
- }
-
- bool HandleDeviceErrorCallbackCmd(const char** commands, size_t* size) {
- const auto* cmd = GetCommand<ReturnDeviceErrorCallbackCmd>(commands, size);
- if (cmd == nullptr) {
+ if (deserializeResult == DeserializeResult::FatalError) {
return false;
}
- const char* message = GetData<char>(commands, size, cmd->messageStrlen + 1);
- if (message == nullptr || message[cmd->messageStrlen] != '\0') {
- return false;
- }
-
- mDevice->HandleError(message);
+ DAWN_ASSERT(cmd.message != nullptr);
+ mDevice->HandleError(cmd.message);
return true;
}
{% for type in by_category["object"] if type.is_builder %}
{% set Type = type.name.CamelCase() %}
- bool Handle{{Type}}ErrorCallbackCmd(const char** commands, size_t* size) {
- const auto* cmd = GetCommand<Return{{Type}}ErrorCallbackCmd>(commands, size);
- if (cmd == nullptr) {
+ bool Handle{{Type}}ErrorCallback(const char** commands, size_t* size) {
+ Return{{Type}}ErrorCallbackCmd cmd;
+ DeserializeResult deserializeResult = cmd.Deserialize(commands, size, &mAllocator);
+
+ if (deserializeResult == DeserializeResult::FatalError) {
return false;
}
- const char* message = GetData<char>(commands, size, cmd->messageStrlen + 1);
- if (message == nullptr || message[cmd->messageStrlen] != '\0') {
- return false;
- }
+ DAWN_ASSERT(cmd.message != nullptr);
- auto* builtObject = mDevice->{{type.built_type.name.camelCase()}}.GetObject(cmd->builtObjectId);
- uint32_t objectSerial = mDevice->{{type.built_type.name.camelCase()}}.GetSerial(cmd->builtObjectId);
+ auto* builtObject = mDevice->{{type.built_type.name.camelCase()}}.GetObject(cmd.builtObject.id);
+ uint32_t objectSerial = mDevice->{{type.built_type.name.camelCase()}}.GetSerial(cmd.builtObject.id);
//* The object might have been deleted or a new object created with the same ID.
- if (builtObject == nullptr || objectSerial != cmd->builtObjectSerial) {
+ if (builtObject == nullptr || objectSerial != cmd.builtObject.serial) {
return true;
}
- bool called = builtObject->builderCallback.Call(static_cast<dawnBuilderErrorStatus>(cmd->status), message);
+ bool called = builtObject->builderCallback.Call(static_cast<dawnBuilderErrorStatus>(cmd.status), cmd.message);
// Unhandled builder errors are forwarded to the device
- if (!called && cmd->status != DAWN_BUILDER_ERROR_STATUS_SUCCESS && cmd->status != DAWN_BUILDER_ERROR_STATUS_UNKNOWN) {
- mDevice->HandleError(("Unhandled builder error: " + std::string(message)).c_str());
+ if (!called && cmd.status != DAWN_BUILDER_ERROR_STATUS_SUCCESS && cmd.status != DAWN_BUILDER_ERROR_STATUS_UNKNOWN) {
+ mDevice->HandleError(("Unhandled builder error: " + std::string(cmd.message)).c_str());
}
return true;
@@ -646,31 +603,23 @@
{% endfor %}
bool HandleBufferMapReadAsyncCallback(const char** commands, size_t* size) {
- const auto* cmd = GetCommand<ReturnBufferMapReadAsyncCallbackCmd>(commands, size);
- if (cmd == nullptr) {
+ ReturnBufferMapReadAsyncCallbackCmd cmd;
+ DeserializeResult deserializeResult = cmd.Deserialize(commands, size, &mAllocator);
+
+ if (deserializeResult == DeserializeResult::FatalError) {
return false;
}
- //* Unconditionnally get the data from the buffer so that the correct amount of data is
- //* consumed from the buffer, even when we ignore the command and early out.
- const char* requestData = nullptr;
- if (cmd->status == DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS) {
- requestData = GetData<char>(commands, size, cmd->dataLength);
- if (requestData == nullptr) {
- return false;
- }
- }
-
- auto* buffer = mDevice->buffer.GetObject(cmd->bufferId);
- uint32_t bufferSerial = mDevice->buffer.GetSerial(cmd->bufferId);
+ auto* buffer = mDevice->buffer.GetObject(cmd.buffer.id);
+ uint32_t bufferSerial = mDevice->buffer.GetSerial(cmd.buffer.id);
//* The buffer might have been deleted or recreated so this isn't an error.
- if (buffer == nullptr || bufferSerial != cmd->bufferSerial) {
+ if (buffer == nullptr || bufferSerial != cmd.buffer.serial) {
return true;
}
//* The requests can have been deleted via an Unmap so this isn't an error.
- auto requestIt = buffer->requests.find(cmd->requestSerial);
+ auto requestIt = buffer->requests.find(cmd.requestSerial);
if (requestIt == buffer->requests.end()) {
return true;
}
@@ -686,14 +635,14 @@
buffer->requests.erase(requestIt);
//* On success, we copy the data locally because the IPC buffer isn't valid outside of this function
- if (cmd->status == DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS) {
+ if (cmd.status == DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS) {
//* The server didn't send the right amount of data, this is an error and could cause
//* the application to crash if we did call the callback.
- if (request.size != cmd->dataLength) {
+ if (request.size != cmd.dataLength) {
return false;
}
- ASSERT(requestData != nullptr);
+ ASSERT(cmd.data != nullptr);
if (buffer->mappedData != nullptr) {
return false;
@@ -702,32 +651,34 @@
buffer->isWriteMapped = false;
buffer->mappedDataSize = request.size;
buffer->mappedData = malloc(request.size);
- memcpy(buffer->mappedData, requestData, request.size);
+ memcpy(buffer->mappedData, cmd.data, request.size);
- request.readCallback(static_cast<dawnBufferMapAsyncStatus>(cmd->status), buffer->mappedData, request.userdata);
+ request.readCallback(static_cast<dawnBufferMapAsyncStatus>(cmd.status), buffer->mappedData, request.userdata);
} else {
- request.readCallback(static_cast<dawnBufferMapAsyncStatus>(cmd->status), nullptr, request.userdata);
+ request.readCallback(static_cast<dawnBufferMapAsyncStatus>(cmd.status), nullptr, request.userdata);
}
return true;
}
bool HandleBufferMapWriteAsyncCallback(const char** commands, size_t* size) {
- const auto* cmd = GetCommand<ReturnBufferMapWriteAsyncCallbackCmd>(commands, size);
- if (cmd == nullptr) {
+ ReturnBufferMapWriteAsyncCallbackCmd cmd;
+ DeserializeResult deserializeResult = cmd.Deserialize(commands, size, &mAllocator);
+
+ if (deserializeResult == DeserializeResult::FatalError) {
return false;
}
- auto* buffer = mDevice->buffer.GetObject(cmd->bufferId);
- uint32_t bufferSerial = mDevice->buffer.GetSerial(cmd->bufferId);
+ auto* buffer = mDevice->buffer.GetObject(cmd.buffer.id);
+ uint32_t bufferSerial = mDevice->buffer.GetSerial(cmd.buffer.id);
//* The buffer might have been deleted or recreated so this isn't an error.
- if (buffer == nullptr || bufferSerial != cmd->bufferSerial) {
+ if (buffer == nullptr || bufferSerial != cmd.buffer.serial) {
return true;
}
//* The requests can have been deleted via an Unmap so this isn't an error.
- auto requestIt = buffer->requests.find(cmd->requestSerial);
+ auto requestIt = buffer->requests.find(cmd.requestSerial);
if (requestIt == buffer->requests.end()) {
return true;
}
@@ -742,7 +693,7 @@
buffer->requests.erase(requestIt);
//* On success, we copy the data locally because the IPC buffer isn't valid outside of this function
- if (cmd->status == DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS) {
+ if (cmd.status == DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS) {
if (buffer->mappedData != nullptr) {
return false;
}
@@ -752,29 +703,31 @@
buffer->mappedData = malloc(request.size);
memset(buffer->mappedData, 0, request.size);
- request.writeCallback(static_cast<dawnBufferMapAsyncStatus>(cmd->status), buffer->mappedData, request.userdata);
+ request.writeCallback(static_cast<dawnBufferMapAsyncStatus>(cmd.status), buffer->mappedData, request.userdata);
} else {
- request.writeCallback(static_cast<dawnBufferMapAsyncStatus>(cmd->status), nullptr, request.userdata);
+ request.writeCallback(static_cast<dawnBufferMapAsyncStatus>(cmd.status), nullptr, request.userdata);
}
return true;
}
bool HandleFenceUpdateCompletedValue(const char** commands, size_t* size) {
- const auto* cmd = GetCommand<ReturnFenceUpdateCompletedValueCmd>(commands, size);
- if (cmd == nullptr) {
+ ReturnFenceUpdateCompletedValueCmd cmd;
+ DeserializeResult deserializeResult = cmd.Deserialize(commands, size, &mAllocator);
+
+ if (deserializeResult == DeserializeResult::FatalError) {
return false;
}
- auto* fence = mDevice->fence.GetObject(cmd->fenceId);
- uint32_t fenceSerial = mDevice->fence.GetSerial(cmd->fenceId);
+ auto* fence = mDevice->fence.GetObject(cmd.fence.id);
+ uint32_t fenceSerial = mDevice->fence.GetSerial(cmd.fence.id);
//* The fence might have been deleted or recreated so this isn't an error.
- if (fence == nullptr || fenceSerial != cmd->fenceSerial) {
+ if (fence == nullptr || fenceSerial != cmd.fence.serial) {
return true;
}
- fence->completedValue = cmd->value;
+ fence->completedValue = cmd.value;
fence->CheckPassedFences();
return true;
}
diff --git a/generator/templates/dawn_wire/WireCmd.cpp b/generator/templates/dawn_wire/WireCmd.cpp
index 8bb4235..782cbd3 100644
--- a/generator/templates/dawn_wire/WireCmd.cpp
+++ b/generator/templates/dawn_wire/WireCmd.cpp
@@ -12,7 +12,7 @@
//* See the License for the specific language governing permissions and
//* limitations under the License.
-#include "dawn_wire/WireCmd.h"
+#include "dawn_wire/WireCmd_autogen.h"
#include "common/Assert.h"
@@ -49,10 +49,14 @@
//* Outputs the serialization code to put `in` in `out`
{% macro serialize_member(member, in, out) %}
{%- if member.type.category == "object" -%}
- {% set Optional = "Optional" if member.optional else "" %}
+ {%- set Optional = "Optional" if member.optional else "" -%}
{{out}} = provider.Get{{Optional}}Id({{in}});
- {% elif member.type.category == "structure"%}
- {{as_cType(member.type.name)}}Serialize({{in}}, &{{out}}, buffer, provider);
+ {%- elif member.type.category == "structure" -%}
+ {{as_cType(member.type.name)}}Serialize({{in}}, &{{out}}, buffer
+ {%- if member.type.has_dawn_object -%}
+ , provider
+ {%- endif -%}
+ );
{%- else -%}
{{out}} = {{in}};
{%- endif -%}
@@ -61,42 +65,34 @@
//* Outputs the deserialization code to put `in` in `out`
{% macro deserialize_member(member, in, out) %}
{%- if member.type.category == "object" -%}
- {% set Optional = "Optional" if member.optional else "" %}
+ {%- set Optional = "Optional" if member.optional else "" -%}
DESERIALIZE_TRY(resolver.Get{{Optional}}FromId({{in}}, &{{out}}));
- {% elif member.type.category == "structure"%}
- DESERIALIZE_TRY({{as_cType(member.type.name)}}Deserialize(&{{out}}, &{{in}}, buffer, size, allocator, resolver));
+ {%- elif member.type.category == "structure" -%}
+ DESERIALIZE_TRY({{as_cType(member.type.name)}}Deserialize(&{{out}}, &{{in}}, buffer, size, allocator
+ {%- if member.type.has_dawn_object -%}
+ , resolver
+ {%- endif -%}
+ ));
{%- else -%}
{{out}} = {{in}};
{%- endif -%}
{% endmacro %}
//* The main [de]serialization macro
-
//* Methods are very similar to structures that have one member corresponding to each arguments.
//* This macro takes advantage of the similarity to output [de]serialization code for a record
//* that is either a structure or a method, with some special cases for each.
-{% macro write_serialization_methods(name, members, as_method=None, as_struct=None, is_return_command=False) %}
+{% macro write_record_serialization_helpers(record, name, members, is_cmd=False, is_method=False, is_return_command=False) %}
{% set Return = "Return" if is_return_command else "" %}
- {% set is_method = as_method != None %}
- {% set is_struct = as_struct != None %}
+ {% set Cmd = "Cmd" if is_cmd else "" %}
//* Structure for the wire format of each of the records. Members that are values
//* are embedded directly in the structure. Other members are assumed to be in the
//* memory directly following the structure in the buffer.
- struct {{name}}Transfer {
- {% if is_method %}
+ struct {{Return}}{{name}}Transfer {
+ {% if is_cmd %}
//* Start the transfer structure with the command ID, so that casting to WireCmd gives the ID.
{{Return}}WireCmd commandId;
-
- //* Methods always have an implicit "self" argument.
- ObjectId self;
-
- //* Methods that return objects need to declare to the server which ID will be used for the
- //* return value.
- {% if as_method.return_type.category == "object" %}
- ObjectId resultId;
- ObjectSerial resultSerial;
- {% endif %}
{% endif %}
//* Value types are directly in the command, objects being replaced with their IDs.
@@ -111,7 +107,7 @@
};
//* Returns the required transfer size for `record` in addition to the transfer structure.
- DAWN_DECLARE_UNUSED size_t {{name}}GetExtraRequiredSize(const {{name}}& record) {
+ DAWN_DECLARE_UNUSED size_t {{Return}}{{name}}GetExtraRequiredSize(const {{Return}}{{name}}{{Cmd}}& record) {
DAWN_UNUSED(record);
size_t result = 0;
@@ -140,24 +136,21 @@
}
// GetExtraRequiredSize isn't used for structures that are value members of other structures
// because we assume they cannot contain pointers themselves.
- DAWN_UNUSED_FUNC({{name}}GetExtraRequiredSize);
+ DAWN_UNUSED_FUNC({{Return}}{{name}}GetExtraRequiredSize);
//* Serializes `record` into `transfer`, using `buffer` to get more space for pointed-to data
//* and `provider` to serialize objects.
- void {{name}}Serialize(const {{name}}& record, {{name}}Transfer* transfer,
- char** buffer, const ObjectIdProvider& provider) {
- DAWN_UNUSED(provider);
+ void {{Return}}{{name}}Serialize(const {{Return}}{{name}}{{Cmd}}& record, {{Return}}{{name}}Transfer* transfer,
+ char** buffer
+ {%- if record.has_dawn_object -%}
+ , const ObjectIdProvider& provider
+ {%- endif -%}
+ ) {
DAWN_UNUSED(buffer);
//* Handle special transfer members of methods.
- {% if is_method %}
- {% if as_method.return_type.category == "object" %}
- transfer->resultId = record.resultId;
- transfer->resultSerial = record.resultSerial;
- {% endif %}
-
+ {% if is_cmd %}
transfer->commandId = {{Return}}WireCmd::{{name}};
- transfer->self = provider.GetId(record.self);
{% endif %}
//* Value types are directly in the transfer record, objects being replaced with their IDs.
@@ -193,30 +186,56 @@
//* Deserializes `transfer` into `record` getting more serialized data from `buffer` and `size`
//* if needed, using `allocator` to store pointed-to values and `resolver` to translate object
//* Ids to actual objects.
- DeserializeResult {{name}}Deserialize({{name}}* record, const {{name}}Transfer* transfer,
- const char** buffer, size_t* size, DeserializeAllocator* allocator, const ObjectIdResolver& resolver) {
+ DeserializeResult {{Return}}{{name}}Deserialize({{Return}}{{name}}{{Cmd}}* record, const {{Return}}{{name}}Transfer* transfer,
+ const char** buffer, size_t* size, DeserializeAllocator* allocator
+ {%- if record.has_dawn_object -%}
+ , const ObjectIdResolver& resolver
+ {%- endif -%}
+ ) {
DAWN_UNUSED(allocator);
- DAWN_UNUSED(resolver);
DAWN_UNUSED(buffer);
DAWN_UNUSED(size);
+ {% if is_cmd %}
+ ASSERT(transfer->commandId == {{Return}}WireCmd::{{name}});
+ {% endif %}
+
+ //* First assign result ObjectHandles:
+ //* Deserialize guarantees they are filled even if there is an ID for an error object
+ //* for the Maybe monad mechanism.
+ //* TODO(enga): This won't need to be done first once we have "WebGPU error handling".
+ {% set return_handles = members
+ |selectattr("is_return_value")
+ |selectattr("annotation", "equalto", "value")
+ |selectattr("type.dict_name", "equalto", "ObjectHandle")
+ |list %}
+
+ //* Strip return_handles so we don't deserialize it again
+ {% set members = members|reject("in", return_handles)|list %}
+
+ {% for member in return_handles %}
+ {% set memberName = as_varName(member.name) %}
+ {{deserialize_member(member, "transfer->" + memberName, "record->" + memberName)}}
+ {% endfor %}
+
//* Handle special transfer members for methods
{% if is_method %}
- {% if as_method.return_type.category == "object" %}
- record->resultId = transfer->resultId;
- record->resultSerial = transfer->resultSerial;
- {% endif %}
-
- ASSERT(transfer->commandId == {{Return}}WireCmd::{{name}});
-
+ //* First assign selfId:
+ //* Deserialize guarantees they are filled even if there is an ID for an error object
+ //* for the Maybe monad mechanism.
+ //* TODO(enga): This won't need to be done first once we have "WebGPU error handling".
+ //* We can also remove is_method
record->selfId = transfer->self;
//* This conversion is done after the copying of result* and selfId: Deserialize
//* guarantees they are filled even if there is an ID for an error object for the
//* Maybe monad mechanism.
DESERIALIZE_TRY(resolver.GetFromId(record->selfId, &record->self));
+ //* Strip self so we don't deserialize it again
+ {% set members = members|rejectattr("name.chunks", "equalto", ["self"])|list %}
+
//* The object resolver returns a success even if the object is null because the
- //* frontend is reponsible to validate that (null objects sometimes have special
+ //* frontend is responsible to validate that (null objects sometimes have special
//* meanings). However it is never valid to call a method on a null object so we
//* can error out in that case.
if (record->self == nullptr) {
@@ -224,7 +243,7 @@
}
{% endif %}
- {% if is_struct and as_struct.extensible %}
+ {% if record.extensible %}
record->nextInChain = nullptr;
{% endif %}
@@ -272,6 +291,47 @@
}
{% endmacro %}
+{% macro write_command_serialization_methods(command, is_return) %}
+ {% set Return = "Return" if is_return else "" %}
+ {% set Name = Return + command.name.CamelCase() %}
+ {% set Cmd = Name + "Cmd" %}
+
+ size_t {{Cmd}}::GetRequiredSize() const {
+ size_t size = sizeof({{Name}}Transfer) + {{Name}}GetExtraRequiredSize(*this);
+ return size;
+ }
+
+ void {{Cmd}}::Serialize(char* buffer
+ {%- if command.has_dawn_object -%}
+ , const ObjectIdProvider& objectIdProvider
+ {%- endif -%}
+ ) const {
+ auto transfer = reinterpret_cast<{{Name}}Transfer*>(buffer);
+ buffer += sizeof({{Name}}Transfer);
+
+ {{Name}}Serialize(*this, transfer, &buffer
+ {%- if command.has_dawn_object -%}
+ , objectIdProvider
+ {%- endif -%}
+ );
+ }
+
+ DeserializeResult {{Cmd}}::Deserialize(const char** buffer, size_t* size, DeserializeAllocator* allocator
+ {%- if command.has_dawn_object -%}
+ , const ObjectIdResolver& resolver
+ {%- endif -%}
+ ) {
+ const {{Name}}Transfer* transfer = nullptr;
+ DESERIALIZE_TRY(GetPtrFromBuffer(buffer, size, 1, &transfer));
+
+ return {{Name}}Deserialize(this, transfer, buffer, size, allocator
+ {%- if command.has_dawn_object -%}
+ , resolver
+ {%- endif -%}
+ );
+ }
+{% endmacro %}
+
namespace dawn_wire {
// Macro to simplify error handling, similar to DAWN_TRY but for DeserializeResult.
@@ -324,46 +384,35 @@
return DeserializeResult::Success;
}
- //* Output structure [de]serialization first because it is used by methods.
+ //* Output structure [de]serialization first because it is used by commands.
{% for type in by_category["structure"] %}
{% set name = as_cType(type.name) %}
- {{write_serialization_methods(name, type.members, as_struct=type)}}
+ {{write_record_serialization_helpers(type, name, type.members,
+ is_cmd=False)}}
{% endfor %}
- // * Output [de]serialization helpers for methods
- {% for type in by_category["object"] %}
- {% for method in type.methods %}
- {% set name = as_MethodSuffix(type.name, method.name) %}
+ //* Output [de]serialization helpers for commands
+ {% for command in cmd_records["command"] %}
+ {% set name = command.name.CamelCase() %}
+ {{write_record_serialization_helpers(command, name, command.members,
+ is_cmd=True, is_method=command.derived_method != None)}}
+ {% endfor %}
- using {{name}} = {{name}}Cmd;
- {{write_serialization_methods(name, method.arguments, as_method=method)}}
- {% endfor %}
+ //* Output [de]serialization helpers for return commands
+ {% for command in cmd_records["return command"] %}
+ {% set name = command.name.CamelCase() %}
+ {{write_record_serialization_helpers(command, name, command.members,
+ is_cmd=True, is_method=command.derived_method != None,
+ is_return_command=True)}}
{% endfor %}
} // anonymous namespace
- {% for type in by_category["object"] %}
- {% for method in type.methods %}
- {% set name = as_MethodSuffix(type.name, method.name) %}
- {% set Cmd = name + "Cmd" %}
+ {% for command in cmd_records["command"] %}
+ {{ write_command_serialization_methods(command, False) }}
+ {% endfor %}
- size_t {{Cmd}}::GetRequiredSize() const {
- return sizeof({{name}}Transfer) + {{name}}GetExtraRequiredSize(*this);
- }
-
- void {{Cmd}}::Serialize(char* buffer, const ObjectIdProvider& objectIdProvider) const {
- auto transfer = reinterpret_cast<{{name}}Transfer*>(buffer);
- buffer += sizeof({{name}}Transfer);
-
- {{name}}Serialize(*this, transfer, &buffer, objectIdProvider);
- }
-
- DeserializeResult {{Cmd}}::Deserialize(const char** buffer, size_t* size, DeserializeAllocator* allocator, const ObjectIdResolver& resolver) {
- const {{name}}Transfer* transfer = nullptr;
- DESERIALIZE_TRY(GetPtrFromBuffer(buffer, size, 1, &transfer));
-
- return {{name}}Deserialize(this, transfer, buffer, size, allocator, resolver);
- }
- {% endfor %}
+ {% for command in cmd_records["return command"] %}
+ {{ write_command_serialization_methods(command, True) }}
{% endfor %}
} // namespace dawn_wire
diff --git a/generator/templates/dawn_wire/WireCmd.h b/generator/templates/dawn_wire/WireCmd.h
index 28bc1ae..d92de2c 100644
--- a/generator/templates/dawn_wire/WireCmd.h
+++ b/generator/templates/dawn_wire/WireCmd.h
@@ -15,10 +15,16 @@
#ifndef DAWNWIRE_WIRECMD_AUTOGEN_H_
#define DAWNWIRE_WIRECMD_AUTOGEN_H_
+#include <dawn/dawn.h>
+
namespace dawn_wire {
using ObjectId = uint32_t;
using ObjectSerial = uint32_t;
+ struct ObjectHandle {
+ ObjectId id;
+ ObjectSerial serial;
+ };
enum class DeserializeResult {
Success,
@@ -61,84 +67,68 @@
//* Enum used as a prefix to each command on the wire format.
enum class WireCmd : uint32_t {
- {% for type in by_category["object"] %}
- {% for method in type.methods %}
- {{as_MethodSuffix(type.name, method.name)}},
- {% endfor %}
+ {% for command in cmd_records["command"] %}
+ {{command.name.CamelCase()}},
{% endfor %}
- BufferMapAsync,
- BufferUpdateMappedDataCmd,
- DestroyObject,
};
- {% for type in by_category["object"] %}
- {% for method in type.methods %}
- {% set Suffix = as_MethodSuffix(type.name, method.name) %}
- {% set Cmd = Suffix + "Cmd" %}
-
- //* These are "structure" version of the list of arguments to the different Dawn methods.
- //* They provide helpers to serialize/deserialize to/from a buffer.
- struct {{Cmd}} {
- //* From a filled structure, compute how much size will be used in the serialization buffer.
- size_t GetRequiredSize() const;
-
- //* Serialize the structure and everything it points to into serializeBuffer which must be
- //* big enough to contain all the data (as queried from GetRequiredSize).
- void Serialize(char* serializeBuffer, const ObjectIdProvider& objectIdProvider) const;
-
- //* Deserializes the structure from a buffer, consuming a maximum of *size bytes. When this
- //* function returns, buffer and size will be updated by the number of bytes consumed to
- //* deserialize the structure. Structures containing pointers will use allocator to get
- //* scratch space to deserialize the pointed-to data.
- //* Deserialize returns:
- //* - Success if everything went well (yay!)
- //* - FatalError is something bad happened (buffer too small for example)
- //* - ErrorObject if one if the deserialized object is an error value, for the implementation
- //* of the Maybe monad.
- //* If the return value is not FatalError, selfId, resultId and resultSerial (if present) are
- //* filled.
- DeserializeResult Deserialize(const char** buffer, size_t* size, DeserializeAllocator* allocator, const ObjectIdResolver& resolver);
-
- {{as_cType(type.name)}} self;
-
- //* Command handlers want to know the object ID in addition to the backing object.
- //* Doesn't need to be filled before Serialize, or GetRequiredSize.
- ObjectId selfId;
-
- //* Commands creating objects say which ID the created object will be referred as.
- {% if method.return_type.category == "object" %}
- ObjectId resultId;
- ObjectSerial resultSerial;
- {% endif %}
-
- {% for arg in method.arguments %}
- {{as_annotated_cType(arg)}};
- {% endfor %}
- };
- {% endfor %}
- {% endfor %}
-
//* Enum used as a prefix to each command on the return wire format.
enum class ReturnWireCmd : uint32_t {
- DeviceErrorCallback,
- {% for type in by_category["object"] if type.is_builder %}
- {{type.name.CamelCase()}}ErrorCallback,
+ {% for command in cmd_records["return command"] %}
+ {{command.name.CamelCase()}},
{% endfor %}
- BufferMapReadAsyncCallback,
- BufferMapWriteAsyncCallback,
- FenceUpdateCompletedValue,
};
- //* Command for the server calling a builder status callback.
- {% for type in by_category["object"] if type.is_builder %}
- struct Return{{type.name.CamelCase()}}ErrorCallbackCmd {
- ReturnWireCmd commandId = ReturnWireCmd::{{type.name.CamelCase()}}ErrorCallback;
+{% macro write_command_struct(command, is_return_command) %}
+ {% set Return = "Return" if is_return_command else "" %}
+ {% set Cmd = command.name.CamelCase() + "Cmd" %}
+ struct {{Return}}{{Cmd}} {
+ //* From a filled structure, compute how much size will be used in the serialization buffer.
+ size_t GetRequiredSize() const;
- ObjectId builtObjectId;
- ObjectSerial builtObjectSerial;
- uint32_t status;
- size_t messageStrlen;
- };
+ //* Serialize the structure and everything it points to into serializeBuffer which must be
+ //* big enough to contain all the data (as queried from GetRequiredSize).
+ void Serialize(char* serializeBuffer
+ {%- if command.has_dawn_object -%}
+ , const ObjectIdProvider& objectIdProvider
+ {%- endif -%}
+ ) const;
+
+ //* Deserializes the structure from a buffer, consuming a maximum of *size bytes. When this
+ //* function returns, buffer and size will be updated by the number of bytes consumed to
+ //* deserialize the structure. Structures containing pointers will use allocator to get
+ //* scratch space to deserialize the pointed-to data.
+ //* Deserialize returns:
+ //* - Success if everything went well (yay!)
+ //* - FatalError is something bad happened (buffer too small for example)
+ //* - ErrorObject if one if the deserialized object is an error value, for the implementation
+ //* of the Maybe monad.
+ //* If the return value is not FatalError, selfId, resultId and resultSerial (if present) are
+ //* filled.
+ DeserializeResult Deserialize(const char** buffer, size_t* size, DeserializeAllocator* allocator
+ {%- if command.has_dawn_object -%}
+ , const ObjectIdResolver& resolver
+ {%- endif -%}
+ );
+
+ {% if command.derived_method %}
+ //* Command handlers want to know the object ID in addition to the backing object.
+ //* Doesn't need to be filled before Serialize, or GetRequiredSize.
+ ObjectId selfId;
+ {% endif %}
+
+ {% for member in command.members %}
+ {{as_annotated_cType(member)}};
+ {% endfor %}
+ };
+{% endmacro %}
+
+ {% for command in cmd_records["command"] %}
+ {{write_command_struct(command, False)}}
+ {% endfor %}
+
+ {% for command in cmd_records["return command"] %}
+ {{write_command_struct(command, True)}}
{% endfor %}
} // namespace dawn_wire
diff --git a/generator/templates/dawn_wire/WireServer.cpp b/generator/templates/dawn_wire/WireServer.cpp
index e186a42..7997f4f 100644
--- a/generator/templates/dawn_wire/WireServer.cpp
+++ b/generator/templates/dawn_wire/WireServer.cpp
@@ -14,7 +14,8 @@
#include "dawn_wire/TypeTraits_autogen.h"
#include "dawn_wire/Wire.h"
-#include "dawn_wire/WireCmd.h"
+#include "dawn_wire/WireCmd_autogen.h"
+#include "dawn_wire/WireDeserializeAllocator.h"
#include "common/Assert.h"
@@ -32,8 +33,7 @@
struct MapUserdata {
Server* server;
- uint32_t bufferId;
- uint32_t bufferSerial;
+ ObjectHandle buffer;
uint32_t requestSerial;
uint32_t size;
bool isWrite;
@@ -41,8 +41,7 @@
struct FenceCompletionUserdata {
Server* server;
- uint32_t fenceId;
- uint32_t fenceSerial;
+ ObjectHandle fence;
uint64_t value;
};
@@ -69,8 +68,7 @@
template <typename T>
struct ObjectData<T, true> : public ObjectDataBase<T> {
- uint32_t builtObjectId = 0;
- uint32_t builtObjectSerial = 0;
+ ObjectHandle builtObject = ObjectHandle{0, 0};
};
template <>
@@ -214,59 +212,6 @@
void ForwardFenceCompletedValue(dawnFenceCompletionStatus status,
dawnCallbackUserdata userdata);
- // A really really simple implementation of the DeserializeAllocator. It's main feature
- // is that it has some inline storage so as to avoid allocations for the majority of
- // commands.
- class ServerAllocator : public DeserializeAllocator {
- public:
- ServerAllocator() {
- Reset();
- }
-
- ~ServerAllocator() {
- Reset();
- }
-
- void* GetSpace(size_t size) override {
- // Return space in the current buffer if possible first.
- if (mRemainingSize >= size) {
- char* buffer = mCurrentBuffer;
- mCurrentBuffer += size;
- mRemainingSize -= size;
- return buffer;
- }
-
- // Otherwise allocate a new buffer and try again.
- size_t allocationSize = std::max(size, size_t(2048));
- char* allocation = static_cast<char*>(malloc(allocationSize));
- if (allocation == nullptr) {
- return nullptr;
- }
-
- mAllocations.push_back(allocation);
- mCurrentBuffer = allocation;
- mRemainingSize = allocationSize;
- return GetSpace(size);
- }
-
- void Reset() {
- for (auto allocation : mAllocations) {
- free(allocation);
- }
- mAllocations.clear();
-
- // The initial buffer is the inline buffer so that some allocations can be skipped
- mCurrentBuffer = mStaticBuffer;
- mRemainingSize = sizeof(mStaticBuffer);
- }
-
- private:
- size_t mRemainingSize = 0;
- char* mCurrentBuffer = nullptr;
- char mStaticBuffer[2048];
- std::vector<char*> mAllocations;
- };
-
class Server : public CommandHandler, public ObjectIdResolver {
public:
Server(dawnDevice device, const dawnProcTable& procs, CommandSerializer* serializer)
@@ -294,13 +239,11 @@
void OnDeviceError(const char* message) {
ReturnDeviceErrorCallbackCmd cmd;
- cmd.messageStrlen = std::strlen(message);
+ cmd.message = message;
- auto allocCmd = static_cast<ReturnDeviceErrorCallbackCmd*>(GetCmdSpace(sizeof(cmd)));
- *allocCmd = cmd;
-
- char* messageAlloc = static_cast<char*>(GetCmdSpace(cmd.messageStrlen + 1));
- strcpy(messageAlloc, message);
+ size_t requiredSize = cmd.GetRequiredSize();
+ char* allocatedBuffer = static_cast<char*>(GetCmdSpace(requiredSize));
+ cmd.Serialize(allocatedBuffer);
}
{% for type in by_category["object"] if type.is_builder%}
@@ -319,18 +262,16 @@
if (status != DAWN_BUILDER_ERROR_STATUS_UNKNOWN) {
//* Unknown is the only status that can be returned without a call to GetResult
//* so we are guaranteed to have created an object.
- ASSERT(builder->builtObjectId != 0);
+ ASSERT(builder->builtObject.id != 0);
Return{{Type}}ErrorCallbackCmd cmd;
- cmd.builtObjectId = builder->builtObjectId;
- cmd.builtObjectSerial = builder->builtObjectSerial;
+ cmd.builtObject = builder->builtObject;
cmd.status = status;
- cmd.messageStrlen = std::strlen(message);
+ cmd.message = message;
- auto allocCmd = static_cast<Return{{Type}}ErrorCallbackCmd*>(GetCmdSpace(sizeof(cmd)));
- *allocCmd = cmd;
- char* messageAlloc = static_cast<char*>(GetCmdSpace(strlen(message) + 1));
- strcpy(messageAlloc, message);
+ size_t requiredSize = cmd.GetRequiredSize();
+ char* allocatedBuffer = static_cast<char*>(GetCmdSpace(requiredSize));
+ cmd.Serialize(allocatedBuffer);
}
}
{% endfor %}
@@ -339,46 +280,44 @@
std::unique_ptr<MapUserdata> data(userdata);
// Skip sending the callback if the buffer has already been destroyed.
- auto* bufferData = mKnownBuffer.Get(data->bufferId);
- if (bufferData == nullptr || bufferData->serial != data->bufferSerial) {
+ auto* bufferData = mKnownBuffer.Get(data->buffer.id);
+ if (bufferData == nullptr || bufferData->serial != data->buffer.serial) {
return;
}
ReturnBufferMapReadAsyncCallbackCmd cmd;
- cmd.bufferId = data->bufferId;
- cmd.bufferSerial = data->bufferSerial;
+ cmd.buffer = data->buffer;
cmd.requestSerial = data->requestSerial;
cmd.status = status;
cmd.dataLength = 0;
-
- auto allocCmd = static_cast<ReturnBufferMapReadAsyncCallbackCmd*>(GetCmdSpace(sizeof(cmd)));
- *allocCmd = cmd;
+ cmd.data = reinterpret_cast<const uint8_t*>(ptr);
if (status == DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS) {
- allocCmd->dataLength = data->size;
-
- void* dataAlloc = GetCmdSpace(data->size);
- memcpy(dataAlloc, ptr, data->size);
+ cmd.dataLength = data->size;
}
+
+ size_t requiredSize = cmd.GetRequiredSize();
+ char* allocatedBuffer = static_cast<char*>(GetCmdSpace(requiredSize));
+ cmd.Serialize(allocatedBuffer);
}
void OnMapWriteAsyncCallback(dawnBufferMapAsyncStatus status, void* ptr, MapUserdata* userdata) {
std::unique_ptr<MapUserdata> data(userdata);
// Skip sending the callback if the buffer has already been destroyed.
- auto* bufferData = mKnownBuffer.Get(data->bufferId);
- if (bufferData == nullptr || bufferData->serial != data->bufferSerial) {
+ auto* bufferData = mKnownBuffer.Get(data->buffer.id);
+ if (bufferData == nullptr || bufferData->serial != data->buffer.serial) {
return;
}
ReturnBufferMapWriteAsyncCallbackCmd cmd;
- cmd.bufferId = data->bufferId;
- cmd.bufferSerial = data->bufferSerial;
+ cmd.buffer = data->buffer;
cmd.requestSerial = data->requestSerial;
cmd.status = status;
- auto allocCmd = static_cast<ReturnBufferMapWriteAsyncCallbackCmd*>(GetCmdSpace(sizeof(cmd)));
- *allocCmd = cmd;
+ size_t requiredSize = cmd.GetRequiredSize();
+ char* allocatedBuffer = static_cast<char*>(GetCmdSpace(requiredSize));
+ cmd.Serialize(allocatedBuffer);
if (status == DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS) {
bufferData->mappedData = ptr;
@@ -390,15 +329,14 @@
std::unique_ptr<FenceCompletionUserdata> data(userdata);
ReturnFenceUpdateCompletedValueCmd cmd;
- cmd.fenceId = data->fenceId;
- cmd.fenceSerial = data->fenceSerial;
+ cmd.fence = data->fence;
cmd.value = data->value;
- auto allocCmd = static_cast<ReturnFenceUpdateCompletedValueCmd*>(GetCmdSpace(sizeof(cmd)));
- *allocCmd = cmd;
+ size_t requiredSize = cmd.GetRequiredSize();
+ char* allocatedBuffer = static_cast<char*>(GetCmdSpace(requiredSize));
+ cmd.Serialize(allocatedBuffer);
}
- {% set client_side_commands = ["FenceGetCompletedValue"] %}
const char* HandleCommands(const char* commands, size_t size) override {
mProcs.deviceTick(mKnownDevice.Get(1)->handle);
@@ -407,25 +345,11 @@
bool success = false;
switch (cmdId) {
- {% for type in by_category["object"] %}
- {% for method in type.methods %}
- {% set Suffix = as_MethodSuffix(type.name, method.name) %}
- {% if Suffix not in client_side_commands %}
- case WireCmd::{{Suffix}}:
- success = Handle{{Suffix}}(&commands, &size);
- break;
- {% endif %}
- {% endfor %}
+ {% for command in cmd_records["command"] %}
+ case WireCmd::{{command.name.CamelCase()}}:
+ success = Handle{{command.name.CamelCase()}}(&commands, &size);
+ break;
{% endfor %}
- case WireCmd::BufferMapAsync:
- success = HandleBufferMapAsync(&commands, &size);
- break;
- case WireCmd::BufferUpdateMappedDataCmd:
- success = HandleBufferUpdateMappedData(&commands, &size);
- break;
- case WireCmd::DestroyObject:
- success = HandleDestroyObject(&commands, &size);
- break;
default:
success = false;
}
@@ -447,7 +371,7 @@
dawnProcTable mProcs;
CommandSerializer* mSerializer = nullptr;
- ServerAllocator mAllocator;
+ WireDeserializeAllocator mAllocator;
void* GetCmdSpace(size_t size) {
return mSerializer->GetCmdSpace(size);
@@ -484,36 +408,10 @@
KnownObjects<{{as_cType(type.name)}}> mKnown{{type.name.CamelCase()}};
{% endfor %}
- {% set reverse_lookup_object_types = ["Fence"] %}
- {% for type in by_category["object"] if type.name.CamelCase() in reverse_lookup_object_types %}
+ {% for type in by_category["object"] if type.name.CamelCase() in server_reverse_lookup_objects %}
ObjectIdLookupTable<{{as_cType(type.name)}}> m{{type.name.CamelCase()}}IdTable;
{% endfor %}
- //* Helper function for the getting of the command data in command handlers.
- //* Checks there is enough data left, updates the buffer / size and returns
- //* the command (or nullptr for an error).
- template <typename T>
- static const T* GetData(const char** buffer, size_t* size, size_t count) {
- // TODO(cwallez@chromium.org): Check for overflow
- size_t totalSize = count * sizeof(T);
- if (*size < totalSize) {
- return nullptr;
- }
-
- const T* data = reinterpret_cast<const T*>(*buffer);
-
- *buffer += totalSize;
- *size -= totalSize;
-
- return data;
- }
- template <typename T>
- static const T* GetCommand(const char** commands, size_t* size) {
- return GetData<T>(commands, size, 1);
- }
-
- {% set custom_pre_handler_commands = ["BufferUnmap"] %}
-
bool PreHandleBufferUnmap(const BufferUnmapCmd& cmd) {
auto* selfData = mKnownBuffer.Get(cmd.selfId);
ASSERT(selfData != nullptr);
@@ -523,8 +421,6 @@
return true;
}
- {% set custom_post_handler_commands = ["QueueSignal"] %}
-
bool PostHandleQueueSignal(const QueueSignalCmd& cmd) {
if (cmd.fence == nullptr) {
return false;
@@ -536,8 +432,7 @@
auto* data = new FenceCompletionUserdata;
data->server = this;
- data->fenceId = fenceId;
- data->fenceSerial = fence->serial;
+ data->fence = ObjectHandle{fenceId, fence->serial};
data->value = cmd.signalValue;
auto userdata = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(data));
@@ -560,7 +455,7 @@
return false;
}
- {% if Suffix in custom_pre_handler_commands %}
+ {% if Suffix in server_custom_pre_handler_commands %}
if (!PreHandle{{Suffix}}(cmd)) {
return false;
}
@@ -575,15 +470,14 @@
{% set returns = return_type.name.canonical_case() != "void" %}
{% if returns %}
{% set Type = method.return_type.name.CamelCase() %}
- auto* resultData = mKnown{{Type}}.Allocate(cmd.resultId);
+ auto* resultData = mKnown{{Type}}.Allocate(cmd.result.id);
if (resultData == nullptr) {
return false;
}
- resultData->serial = cmd.resultSerial;
+ resultData->serial = cmd.result.serial;
{% if type.is_builder %}
- selfData->builtObjectId = cmd.resultId;
- selfData->builtObjectSerial = cmd.resultSerial;
+ selfData->builtObject = cmd.result;
{% endif %}
{% endif %}
@@ -608,7 +502,7 @@
{%- endfor -%}
);
- {% if Suffix in custom_post_handler_commands %}
+ {% if Suffix in server_custom_post_handler_commands %}
if (!PostHandle{{Suffix}}(cmd)) {
return false;
}
@@ -618,10 +512,10 @@
resultData->handle = result;
resultData->valid = result != nullptr;
- {% if return_type.name.CamelCase() in reverse_lookup_object_types %}
+ {% if return_type.name.CamelCase() in server_reverse_lookup_objects %}
//* For created objects, store a mapping from them back to their client IDs
if (result) {
- m{{return_type.name.CamelCase()}}IdTable.Store(result, cmd.resultId);
+ m{{return_type.name.CamelCase()}}IdTable.Store(result, cmd.result.id);
}
{% endif %}
@@ -630,7 +524,7 @@
{% if return_type.is_builder %}
if (result != nullptr) {
uint64_t userdata1 = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(this));
- uint64_t userdata2 = (uint64_t(resultData->serial) << uint64_t(32)) + cmd.resultId;
+ uint64_t userdata2 = (uint64_t(resultData->serial) << uint64_t(32)) + cmd.result.id;
mProcs.{{as_varName(return_type.name, Name("set error callback"))}}(result, Forward{{return_type.name.CamelCase()}}ToClient, userdata1, userdata2);
}
{% endif %}
@@ -645,16 +539,18 @@
bool HandleBufferMapAsync(const char** commands, size_t* size) {
//* These requests are just forwarded to the buffer, with userdata containing what the client
//* will require in the return command.
- const auto* cmd = GetCommand<BufferMapAsyncCmd>(commands, size);
- if (cmd == nullptr) {
+ BufferMapAsyncCmd cmd;
+ DeserializeResult deserializeResult = cmd.Deserialize(commands, size, &mAllocator);
+
+ if (deserializeResult == DeserializeResult::FatalError) {
return false;
}
- ObjectId bufferId = cmd->bufferId;
- uint32_t requestSerial = cmd->requestSerial;
- uint32_t requestSize = cmd->size;
- uint32_t requestStart = cmd->start;
- bool isWrite = cmd->isWrite;
+ ObjectId bufferId = cmd.bufferId;
+ uint32_t requestSerial = cmd.requestSerial;
+ uint32_t requestSize = cmd.size;
+ uint32_t requestStart = cmd.start;
+ bool isWrite = cmd.isWrite;
//* The null object isn't valid as `self`
if (bufferId == 0) {
@@ -668,8 +564,7 @@
auto* data = new MapUserdata;
data->server = this;
- data->bufferId = bufferId;
- data->bufferSerial = buffer->serial;
+ data->buffer = ObjectHandle{bufferId, buffer->serial};
data->requestSerial = requestSerial;
data->size = requestSize;
data->isWrite = isWrite;
@@ -696,13 +591,15 @@
}
bool HandleBufferUpdateMappedData(const char** commands, size_t* size) {
- const auto* cmd = GetCommand<BufferUpdateMappedDataCmd>(commands, size);
- if (cmd == nullptr) {
+ BufferUpdateMappedDataCmd cmd;
+ DeserializeResult deserializeResult = cmd.Deserialize(commands, size, &mAllocator);
+
+ if (deserializeResult == DeserializeResult::FatalError) {
return false;
}
- ObjectId bufferId = cmd->bufferId;
- size_t dataLength = cmd->dataLength;
+ ObjectId bufferId = cmd.bufferId;
+ size_t dataLength = cmd.dataLength;
//* The null object isn't valid as `self`
if (bufferId == 0) {
@@ -715,29 +612,28 @@
return false;
}
- const char* data = GetData<char>(commands, size, dataLength);
- if (data == nullptr) {
- return false;
- }
+ DAWN_ASSERT(cmd.data != nullptr);
- memcpy(buffer->mappedData, data, dataLength);
+ memcpy(buffer->mappedData, cmd.data, dataLength);
return true;
}
bool HandleDestroyObject(const char** commands, size_t* size) {
- const auto* cmd = GetCommand<DestroyObjectCmd>(commands, size);
- if (cmd == nullptr) {
+ DestroyObjectCmd cmd;
+ DeserializeResult deserializeResult = cmd.Deserialize(commands, size, &mAllocator);
+
+ if (deserializeResult == DeserializeResult::FatalError) {
return false;
}
- ObjectId objectId = cmd->objectId;
+ ObjectId objectId = cmd.objectId;
//* ID 0 are reserved for nullptr and cannot be destroyed.
if (objectId == 0) {
return false;
}
- switch (cmd->objectType) {
+ switch (cmd.objectType) {
{% for type in by_category["object"] %}
{% set ObjectType = type.name.CamelCase() %}
case ObjectType::{{ObjectType}}: {
@@ -749,7 +645,7 @@
if (data == nullptr) {
return false;
}
- {% if type.name.CamelCase() in reverse_lookup_object_types %}
+ {% if type.name.CamelCase() in server_reverse_lookup_objects %}
m{{type.name.CamelCase()}}IdTable.Remove(data->handle);
{% endif %}