dawn_wire: Support deserializing s->c chained structs

Chained structs *may* contain objects which means
deserialization may need an ObjectIdResolver.
However, in practice, we never need to send chained
structs from the server to the client that contain objects for
a valid command.

The one upcoming need for chained server->client structs is to
serialize limit structs.

Because limit structs never need objects, we provide a dummy
implementation of the ObjectIdResolver which always yields an error.
An analogous change is done for ObjectIdProvider.
These classes will be used in a follow-up CL.

Bug: dawn:685
Change-Id: I1c0f3f2d080377f2e1a77bc6e896f24d3d9ab931
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/63981
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Austin Eng 2021-09-10 20:36:20 +00:00 committed by Dawn LUCI CQ
parent 8ee643c9d0
commit dc7971ce58
4 changed files with 58 additions and 18 deletions

View File

@ -57,7 +57,7 @@
{% macro serialize_member(member, in, out) %} {% macro serialize_member(member, in, out) %}
{%- if member.type.category == "object" -%} {%- 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}}); WIRE_TRY(provider.Get{{Optional}}Id({{in}}, &{{out}}));
{% elif member.type.category == "structure"%} {% elif member.type.category == "structure"%}
{%- set Provider = ", provider" if member.type.may_have_dawn_object else "" -%} {%- set Provider = ", provider" if member.type.may_have_dawn_object else "" -%}
{% if member.annotation == "const*const*" %} {% if member.annotation == "const*const*" %}
@ -416,8 +416,8 @@ namespace {
} }
WireResult {{Cmd}}::Serialize(size_t commandSize, SerializeBuffer* buffer WireResult {{Cmd}}::Serialize(size_t commandSize, SerializeBuffer* buffer
{%- if not is_return -%} {%- if command.may_have_dawn_object -%}
, const ObjectIdProvider& objectIdProvider , const ObjectIdProvider& provider
{%- endif -%} {%- endif -%}
) const { ) const {
{{Name}}Transfer* transfer; {{Name}}Transfer* transfer;
@ -426,7 +426,7 @@ namespace {
WIRE_TRY({{Name}}Serialize(*this, transfer, buffer WIRE_TRY({{Name}}Serialize(*this, transfer, buffer
{%- if command.may_have_dawn_object -%} {%- if command.may_have_dawn_object -%}
, objectIdProvider , provider
{%- endif -%} {%- endif -%}
)); ));
return WireResult::Success; return WireResult::Success;
@ -666,6 +666,36 @@ namespace dawn_wire {
{{ write_command_serialization_methods(command, True) }} {{ write_command_serialization_methods(command, True) }}
{% endfor %} {% endfor %}
// Implementation of ObjectIdResolver that always errors.
// Used when the generator adds a provider argument because of a chained
// struct, but in practice, a chained struct in that location is invalid.
class ErrorObjectIdResolver final : public ObjectIdResolver {
public:
{% for type in by_category["object"] %}
WireResult GetFromId(ObjectId id, {{as_cType(type.name)}}* out) const override {
return WireResult::FatalError;
}
WireResult GetOptionalFromId(ObjectId id, {{as_cType(type.name)}}* out) const override {
return WireResult::FatalError;
}
{% endfor %}
};
// Implementation of ObjectIdProvider that always errors.
// Used when the generator adds a provider argument because of a chained
// struct, but in practice, a chained struct in that location is invalid.
class ErrorObjectIdProvider final : public ObjectIdProvider {
public:
{% for type in by_category["object"] %}
WireResult GetId({{as_cType(type.name)}} object, ObjectId* out) const override {
return WireResult::FatalError;
}
WireResult GetOptionalId({{as_cType(type.name)}} object, ObjectId* out) const override {
return WireResult::FatalError;
}
{% endfor %}
};
// Implementations of serialization/deserialization of WPGUDeviceProperties. // Implementations of serialization/deserialization of WPGUDeviceProperties.
size_t SerializedWGPUDevicePropertiesSize(const WGPUDeviceProperties* deviceProperties) { size_t SerializedWGPUDevicePropertiesSize(const WGPUDeviceProperties* deviceProperties) {
return sizeof(WGPUDeviceProperties) + return sizeof(WGPUDeviceProperties) +

View File

@ -66,8 +66,8 @@ namespace dawn_wire {
class ObjectIdProvider { class ObjectIdProvider {
public: public:
{% for type in by_category["object"] %} {% for type in by_category["object"] %}
virtual ObjectId GetId({{as_cType(type.name)}} object) const = 0; virtual WireResult GetId({{as_cType(type.name)}} object, ObjectId* out) const = 0;
virtual ObjectId GetOptionalId({{as_cType(type.name)}} object) const = 0; virtual WireResult GetOptionalId({{as_cType(type.name)}} object, ObjectId* out) const = 0;
{% endfor %} {% endfor %}
}; };
@ -98,11 +98,17 @@ namespace dawn_wire {
//* Serialize the structure and everything it points to into serializeBuffer which must be //* Serialize the structure and everything it points to into serializeBuffer which must be
//* big enough to contain all the data (as queried from GetRequiredSize). //* big enough to contain all the data (as queried from GetRequiredSize).
WireResult Serialize(size_t commandSize, SerializeBuffer* serializeBuffer {% if command.may_have_dawn_object %}
{%- if not is_return_command -%} WireResult Serialize(size_t commandSize, SerializeBuffer* serializeBuffer, const ObjectIdProvider& objectIdProvider) const;
, const ObjectIdProvider& objectIdProvider {% else %}
{%- endif -%} WireResult Serialize(size_t commandSize, SerializeBuffer* serializeBuffer) const;
) const; // Override which drops the provider if it's not needed.
WireResult Serialize(size_t commandSize,
SerializeBuffer* serializeBuffer,
const ObjectIdProvider&) const {
return Serialize(commandSize, serializeBuffer);
}
{% endif %}
//* Deserializes the structure from a buffer, consuming a maximum of *size bytes. When this //* 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 //* function returns, buffer and size will be updated by the number of bytes consumed to

View File

@ -49,14 +49,18 @@ namespace dawn_wire { namespace client {
private: private:
// Implementation of the ObjectIdProvider interface // Implementation of the ObjectIdProvider interface
{% for type in by_category["object"] %} {% for type in by_category["object"] %}
ObjectId GetId({{as_cType(type.name)}} object) const final { WireResult GetId({{as_cType(type.name)}} object, ObjectId* out) const final {
return object == nullptr ? 0 : reinterpret_cast<{{as_wireType(type)}}>(object)->id; ASSERT(out != nullptr);
}
ObjectId GetOptionalId({{as_cType(type.name)}} object) const final {
if (object == nullptr) { if (object == nullptr) {
return 0; return WireResult::FatalError;
} }
return GetId(object); *out = reinterpret_cast<{{as_wireType(type)}}>(object)->id;
return WireResult::Success;
}
WireResult GetOptionalId({{as_cType(type.name)}} object, ObjectId* out) const final {
ASSERT(out != nullptr);
*out = (object == nullptr ? 0 : reinterpret_cast<{{as_wireType(type)}}>(object)->id);
return WireResult::Success;
} }
{% endfor %} {% endfor %}

View File

@ -21,7 +21,7 @@ class WireWGPUDevicePropertiesTests : public testing::Test {};
// Test that the serialization and deserialization of WGPUDeviceProperties can work correctly. // Test that the serialization and deserialization of WGPUDeviceProperties can work correctly.
TEST_F(WireWGPUDevicePropertiesTests, SerializeWGPUDeviceProperties) { TEST_F(WireWGPUDevicePropertiesTests, SerializeWGPUDeviceProperties) {
WGPUDeviceProperties sentWGPUDeviceProperties; WGPUDeviceProperties sentWGPUDeviceProperties = {};
sentWGPUDeviceProperties.textureCompressionBC = true; sentWGPUDeviceProperties.textureCompressionBC = true;
// Set false to test that the serialization can handle both true and false correctly. // Set false to test that the serialization can handle both true and false correctly.
sentWGPUDeviceProperties.pipelineStatisticsQuery = false; sentWGPUDeviceProperties.pipelineStatisticsQuery = false;