Introduce a "callback" type in dawn.json
This replaces all instances of "natively defined" with callbacks and adds information about the callbacks arguments so that their typedefs can be autogenerated in dawn.json. Also adds all the methods using callbacks to the list of handwritten client commands so that the wire templates don't try to generate code for them. BUG=dawn:22 Change-Id: I30ce01e3e688a16b31efa74d0c94ebafdca00985 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/13901 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
This commit is contained in:
parent
4b0b7a532a
commit
540ababb6b
36
dawn.json
36
dawn.json
|
@ -167,7 +167,12 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"buffer create mapped callback": {
|
"buffer create mapped callback": {
|
||||||
"category": "natively defined"
|
"category": "callback",
|
||||||
|
"args": [
|
||||||
|
{"name": "status", "type": "buffer map async status"},
|
||||||
|
{"name": "result", "type": "create buffer mapped result"},
|
||||||
|
{"name": "userdata", "type": "void", "annotation": "*"}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"buffer copy view": {
|
"buffer copy view": {
|
||||||
"category": "structure",
|
"category": "structure",
|
||||||
|
@ -189,10 +194,22 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"buffer map read callback": {
|
"buffer map read callback": {
|
||||||
"category": "natively defined"
|
"category": "callback",
|
||||||
|
"args": [
|
||||||
|
{"name": "status", "type": "buffer map async status"},
|
||||||
|
{"name": "data", "type": "void", "annotation": "const*"},
|
||||||
|
{"name": "data length", "type": "uint64_t"},
|
||||||
|
{"name": "userdata", "type": "void", "annotation": "*"}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"buffer map write callback": {
|
"buffer map write callback": {
|
||||||
"category": "natively defined"
|
"category": "callback",
|
||||||
|
"args": [
|
||||||
|
{"name": "status", "type": "buffer map async status"},
|
||||||
|
{"name": "data", "type": "void", "annotation": "*"},
|
||||||
|
{"name": "data length", "type": "uint64_t"},
|
||||||
|
{"name": "userdata", "type": "void", "annotation": "*"}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"buffer map async status": {
|
"buffer map async status": {
|
||||||
"category": "enum",
|
"category": "enum",
|
||||||
|
@ -600,7 +617,12 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"error callback": {
|
"error callback": {
|
||||||
"category": "natively defined"
|
"category": "callback",
|
||||||
|
"args": [
|
||||||
|
{"name": "type", "type": "error type"},
|
||||||
|
{"name": "message", "type": "char", "annotation": "const*"},
|
||||||
|
{"name": "userdata", "type": "void", "annotation": "*"}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"error filter": {
|
"error filter": {
|
||||||
"category": "enum",
|
"category": "enum",
|
||||||
|
@ -646,7 +668,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"fence on completion callback": {
|
"fence on completion callback": {
|
||||||
"category": "natively defined"
|
"category": "callback",
|
||||||
|
"args": [
|
||||||
|
{"name": "status", "type": "fence completion status"},
|
||||||
|
{"name": "userdata", "type": "void", "annotation": "*"}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"fence completion status": {
|
"fence completion status": {
|
||||||
"category": "enum",
|
"category": "enum",
|
||||||
|
|
|
@ -89,19 +89,21 @@
|
||||||
"CreateBufferMappedResult"
|
"CreateBufferMappedResult"
|
||||||
],
|
],
|
||||||
"client_side_commands": [
|
"client_side_commands": [
|
||||||
|
"BufferMapReadAsync",
|
||||||
|
"BufferMapWriteAsync",
|
||||||
"BufferSetSubData",
|
"BufferSetSubData",
|
||||||
"FenceGetCompletedValue"
|
"DeviceCreateBufferMappedAsync",
|
||||||
|
"DevicePopErrorScope",
|
||||||
|
"DeviceSetUncapturedErrorCallback",
|
||||||
|
"FenceGetCompletedValue",
|
||||||
|
"FenceOnCompletion"
|
||||||
],
|
],
|
||||||
"client_handwritten_commands": [
|
"client_handwritten_commands": [
|
||||||
"BufferSetSubData",
|
|
||||||
"BufferUnmap",
|
"BufferUnmap",
|
||||||
"DeviceCreateBuffer",
|
"DeviceCreateBuffer",
|
||||||
"DeviceCreateBufferMapped",
|
"DeviceCreateBufferMapped",
|
||||||
"DeviceCreateBufferMappedAsync",
|
|
||||||
"DevicePushErrorScope",
|
"DevicePushErrorScope",
|
||||||
"DevicePopErrorScope",
|
|
||||||
"QueueCreateFence",
|
"QueueCreateFence",
|
||||||
"FenceGetCompletedValue",
|
|
||||||
"QueueSignal"
|
"QueueSignal"
|
||||||
],
|
],
|
||||||
"client_special_objects": [
|
"client_special_objects": [
|
||||||
|
|
|
@ -83,14 +83,15 @@ class BitmaskType(Type):
|
||||||
for value in self.values:
|
for value in self.values:
|
||||||
self.full_mask = self.full_mask | value.value
|
self.full_mask = self.full_mask | value.value
|
||||||
|
|
||||||
|
class CallbackType(Type):
|
||||||
|
def __init__(self, name, json_data):
|
||||||
|
Type.__init__(self, name, json_data)
|
||||||
|
self.arguments = []
|
||||||
|
|
||||||
class NativeType(Type):
|
class NativeType(Type):
|
||||||
def __init__(self, name, json_data):
|
def __init__(self, name, json_data):
|
||||||
Type.__init__(self, name, json_data, native=True)
|
Type.__init__(self, name, json_data, native=True)
|
||||||
|
|
||||||
class NativelyDefined(Type):
|
|
||||||
def __init__(self, name, json_data):
|
|
||||||
Type.__init__(self, name, json_data)
|
|
||||||
|
|
||||||
# Methods and structures are both "records", so record members correspond to
|
# Methods and structures are both "records", so record members correspond to
|
||||||
# method arguments or structure members.
|
# method arguments or structure members.
|
||||||
class RecordMember:
|
class RecordMember:
|
||||||
|
@ -201,6 +202,9 @@ def link_object(obj, types):
|
||||||
def link_structure(struct, types):
|
def link_structure(struct, types):
|
||||||
struct.members = linked_record_members(struct.json_data['members'], types)
|
struct.members = linked_record_members(struct.json_data['members'], types)
|
||||||
|
|
||||||
|
def link_callback(callback, types):
|
||||||
|
callback.arguments = linked_record_members(callback.json_data['args'], types)
|
||||||
|
|
||||||
# Sort structures so that if struct A has struct B as a member, then B is listed before A
|
# Sort structures so that if struct A has struct B as a member, then B is listed before A
|
||||||
# This is a form of topological sort where we try to keep the order reasonably similar to the
|
# This is a form of topological sort where we try to keep the order reasonably similar to the
|
||||||
# original order (though th sort isn't technically stable).
|
# original order (though th sort isn't technically stable).
|
||||||
|
@ -242,7 +246,7 @@ def parse_json(json):
|
||||||
'bitmask': BitmaskType,
|
'bitmask': BitmaskType,
|
||||||
'enum': EnumType,
|
'enum': EnumType,
|
||||||
'native': NativeType,
|
'native': NativeType,
|
||||||
'natively defined': NativelyDefined,
|
'callback': CallbackType,
|
||||||
'object': ObjectType,
|
'object': ObjectType,
|
||||||
'structure': StructureType,
|
'structure': StructureType,
|
||||||
}
|
}
|
||||||
|
@ -267,6 +271,9 @@ def parse_json(json):
|
||||||
for struct in by_category['structure']:
|
for struct in by_category['structure']:
|
||||||
link_structure(struct, types)
|
link_structure(struct, types)
|
||||||
|
|
||||||
|
for callback in by_category['callback']:
|
||||||
|
link_callback(callback, types)
|
||||||
|
|
||||||
for category in by_category.keys():
|
for category in by_category.keys():
|
||||||
by_category[category] = sorted(by_category[category], key=lambda typ: typ.name.canonical_case())
|
by_category[category] = sorted(by_category[category], key=lambda typ: typ.name.canonical_case())
|
||||||
|
|
||||||
|
@ -292,6 +299,8 @@ def compute_wire_params(api_params, wire_json):
|
||||||
commands = []
|
commands = []
|
||||||
return_commands = []
|
return_commands = []
|
||||||
|
|
||||||
|
wire_json['special items']['client_handwritten_commands'] += wire_json['special items']['client_side_commands']
|
||||||
|
|
||||||
# Generate commands from object methods
|
# Generate commands from object methods
|
||||||
for api_object in wire_params['by_category']['object']:
|
for api_object in wire_params['by_category']['object']:
|
||||||
for method in api_object.methods:
|
for method in api_object.methods:
|
||||||
|
@ -477,6 +486,9 @@ def get_methods_sorted_by_name(api_params):
|
||||||
for method in c_native_methods(api_params['types'], typ) ]
|
for method in c_native_methods(api_params['types'], typ) ]
|
||||||
return [(typ, method) for (_, typ, method) in sorted(unsorted)]
|
return [(typ, method) for (_, typ, method) in sorted(unsorted)]
|
||||||
|
|
||||||
|
def has_callback_arguments(method):
|
||||||
|
return any(arg.type.category == 'callback' for arg in method.arguments)
|
||||||
|
|
||||||
class MultiGeneratorFromDawnJSON(Generator):
|
class MultiGeneratorFromDawnJSON(Generator):
|
||||||
def get_description(self):
|
def get_description(self):
|
||||||
return 'Generates code for various target from Dawn.json.'
|
return 'Generates code for various target from Dawn.json.'
|
||||||
|
@ -543,8 +555,16 @@ class MultiGeneratorFromDawnJSON(Generator):
|
||||||
renders.append(FileRender('webgpu_cpp.cpp', 'src/dawn/webgpu_cpp.cpp', [base_params, api_params, cpp_params]))
|
renders.append(FileRender('webgpu_cpp.cpp', 'src/dawn/webgpu_cpp.cpp', [base_params, api_params, cpp_params]))
|
||||||
|
|
||||||
if 'mock_webgpu' in targets:
|
if 'mock_webgpu' in targets:
|
||||||
renders.append(FileRender('mock_webgpu.h', 'src/dawn/mock_webgpu.h', [base_params, api_params, c_params]))
|
mock_params = [
|
||||||
renders.append(FileRender('mock_webgpu.cpp', 'src/dawn/mock_webgpu.cpp', [base_params, api_params, c_params]))
|
base_params,
|
||||||
|
api_params,
|
||||||
|
c_params,
|
||||||
|
{
|
||||||
|
'has_callback_arguments': has_callback_arguments
|
||||||
|
}
|
||||||
|
]
|
||||||
|
renders.append(FileRender('mock_webgpu.h', 'src/dawn/mock_webgpu.h', mock_params))
|
||||||
|
renders.append(FileRender('mock_webgpu.cpp', 'src/dawn/mock_webgpu.cpp', mock_params))
|
||||||
|
|
||||||
if 'dawn_native_utils' in targets:
|
if 'dawn_native_utils' in targets:
|
||||||
frontend_params = [
|
frontend_params = [
|
||||||
|
|
|
@ -23,72 +23,70 @@ namespace dawn_wire { namespace server {
|
||||||
{% set returns = is_method and method.return_type.name.canonical_case() != "void" %}
|
{% set returns = is_method and method.return_type.name.canonical_case() != "void" %}
|
||||||
|
|
||||||
{% set Suffix = command.name.CamelCase() %}
|
{% set Suffix = command.name.CamelCase() %}
|
||||||
{% if Suffix not in client_side_commands %}
|
//* The generic command handlers
|
||||||
//* The generic command handlers
|
bool Server::Handle{{Suffix}}(const volatile char** commands, size_t* size) {
|
||||||
bool Server::Handle{{Suffix}}(const volatile char** commands, size_t* size) {
|
{{Suffix}}Cmd cmd;
|
||||||
{{Suffix}}Cmd cmd;
|
DeserializeResult deserializeResult = cmd.Deserialize(commands, size, &mAllocator
|
||||||
DeserializeResult deserializeResult = cmd.Deserialize(commands, size, &mAllocator
|
{%- if command.has_dawn_object -%}
|
||||||
{%- if command.has_dawn_object -%}
|
, *this
|
||||||
, *this
|
{%- endif -%}
|
||||||
{%- endif -%}
|
);
|
||||||
);
|
|
||||||
|
|
||||||
if (deserializeResult == DeserializeResult::FatalError) {
|
if (deserializeResult == DeserializeResult::FatalError) {
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
{% if Suffix in server_custom_pre_handler_commands %}
|
|
||||||
if (!PreHandle{{Suffix}}(cmd)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
//* Allocate any result objects
|
|
||||||
{%- for member in command.members if member.is_return_value -%}
|
|
||||||
{{ assert(member.handle_type) }}
|
|
||||||
{% set Type = member.handle_type.name.CamelCase() %}
|
|
||||||
{% set name = as_varName(member.name) %}
|
|
||||||
|
|
||||||
auto* {{name}}Data = {{Type}}Objects().Allocate(cmd.{{name}}.id);
|
|
||||||
if ({{name}}Data == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
{{name}}Data->serial = cmd.{{name}}.serial;
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
//* Do command
|
|
||||||
bool success = Do{{Suffix}}(
|
|
||||||
{%- for member in command.members -%}
|
|
||||||
{%- if member.is_return_value -%}
|
|
||||||
{%- if member.handle_type -%}
|
|
||||||
&{{as_varName(member.name)}}Data->handle //* Pass the handle of the output object to be written by the doer
|
|
||||||
{%- else -%}
|
|
||||||
&cmd.{{as_varName(member.name)}}
|
|
||||||
{%- endif -%}
|
|
||||||
{%- else -%}
|
|
||||||
cmd.{{as_varName(member.name)}}
|
|
||||||
{%- endif -%}
|
|
||||||
{%- if not loop.last -%}, {% endif %}
|
|
||||||
{%- endfor -%}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
{%- for member in command.members if member.is_return_value and member.handle_type -%}
|
|
||||||
{% set Type = member.handle_type.name.CamelCase() %}
|
|
||||||
{% set name = as_varName(member.name) %}
|
|
||||||
|
|
||||||
{% if Type in server_reverse_lookup_objects %}
|
|
||||||
//* For created objects, store a mapping from them back to their client IDs
|
|
||||||
{{Type}}ObjectIdTable().Store({{name}}Data->handle, cmd.{{name}}.id);
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
{% endif %}
|
|
||||||
|
{% if Suffix in server_custom_pre_handler_commands %}
|
||||||
|
if (!PreHandle{{Suffix}}(cmd)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
//* Allocate any result objects
|
||||||
|
{%- for member in command.members if member.is_return_value -%}
|
||||||
|
{{ assert(member.handle_type) }}
|
||||||
|
{% set Type = member.handle_type.name.CamelCase() %}
|
||||||
|
{% set name = as_varName(member.name) %}
|
||||||
|
|
||||||
|
auto* {{name}}Data = {{Type}}Objects().Allocate(cmd.{{name}}.id);
|
||||||
|
if ({{name}}Data == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
{{name}}Data->serial = cmd.{{name}}.serial;
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
//* Do command
|
||||||
|
bool success = Do{{Suffix}}(
|
||||||
|
{%- for member in command.members -%}
|
||||||
|
{%- if member.is_return_value -%}
|
||||||
|
{%- if member.handle_type -%}
|
||||||
|
&{{as_varName(member.name)}}Data->handle //* Pass the handle of the output object to be written by the doer
|
||||||
|
{%- else -%}
|
||||||
|
&cmd.{{as_varName(member.name)}}
|
||||||
|
{%- endif -%}
|
||||||
|
{%- else -%}
|
||||||
|
cmd.{{as_varName(member.name)}}
|
||||||
|
{%- endif -%}
|
||||||
|
{%- if not loop.last -%}, {% endif %}
|
||||||
|
{%- endfor -%}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
{%- for member in command.members if member.is_return_value and member.handle_type -%}
|
||||||
|
{% set Type = member.handle_type.name.CamelCase() %}
|
||||||
|
{% set name = as_varName(member.name) %}
|
||||||
|
|
||||||
|
{% if Type in server_reverse_lookup_objects %}
|
||||||
|
//* For created objects, store a mapping from them back to their client IDs
|
||||||
|
{{Type}}ObjectIdTable().Store({{name}}Data->handle, cmd.{{name}}.id);
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
const volatile char* Server::HandleCommands(const volatile char* commands, size_t size) {
|
const volatile char* Server::HandleCommands(const volatile char* commands, size_t size) {
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
//* limitations under the License.
|
//* limitations under the License.
|
||||||
|
|
||||||
// Command handlers & doers
|
// Command handlers & doers
|
||||||
{% for command in cmd_records["command"] if command.name.CamelCase() not in client_side_commands %}
|
{% for command in cmd_records["command"] %}
|
||||||
{% set Suffix = command.name.CamelCase() %}
|
{% set Suffix = command.name.CamelCase() %}
|
||||||
bool Handle{{Suffix}}(const volatile char** commands, size_t* size);
|
bool Handle{{Suffix}}(const volatile char** commands, size_t* size);
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ class ProcTableAsClass {
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% for type in by_category["object"] %}
|
{% for type in by_category["object"] %}
|
||||||
{% for method in type.methods if len(method.arguments) < 10 %}
|
{% for method in type.methods if len(method.arguments) < 10 and not has_callback_arguments(method) %}
|
||||||
virtual {{as_cType(method.return_type.name)}} {{as_MethodSuffix(type.name, method.name)}}(
|
virtual {{as_cType(method.return_type.name)}} {{as_MethodSuffix(type.name, method.name)}}(
|
||||||
{{-as_cType(type.name)}} {{as_varName(type.name)}}
|
{{-as_cType(type.name)}} {{as_varName(type.name)}}
|
||||||
{%- for arg in method.arguments -%}
|
{%- for arg in method.arguments -%}
|
||||||
|
@ -123,7 +123,7 @@ class MockProcTable : public ProcTableAsClass {
|
||||||
void IgnoreAllReleaseCalls();
|
void IgnoreAllReleaseCalls();
|
||||||
|
|
||||||
{% for type in by_category["object"] %}
|
{% for type in by_category["object"] %}
|
||||||
{% for method in type.methods if len(method.arguments) < 10 %}
|
{% for method in type.methods if len(method.arguments) < 10 and not has_callback_arguments(method) %}
|
||||||
MOCK_METHOD{{len(method.arguments) + 1}}(
|
MOCK_METHOD{{len(method.arguments) + 1}}(
|
||||||
{{-as_MethodSuffix(type.name, method.name)}},
|
{{-as_MethodSuffix(type.name, method.name)}},
|
||||||
{{as_cType(method.return_type.name)}}(
|
{{as_cType(method.return_type.name)}}(
|
||||||
|
|
|
@ -89,19 +89,13 @@ typedef uint32_t WGPUFlags;
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef void (*WGPUBufferCreateMappedCallback)(WGPUBufferMapAsyncStatus status,
|
{% for type in by_category["callback"] %}
|
||||||
WGPUCreateBufferMappedResult result,
|
typedef void (*{{as_cType(type.name)}})(
|
||||||
void* userdata);
|
{%- for arg in type.arguments -%}
|
||||||
typedef void (*WGPUBufferMapReadCallback)(WGPUBufferMapAsyncStatus status,
|
{% if not loop.first %}, {% endif %}{{as_annotated_cType(arg)}}
|
||||||
const void* data,
|
{%- endfor -%}
|
||||||
uint64_t dataLength,
|
);
|
||||||
void* userdata);
|
{% endfor %}
|
||||||
typedef void (*WGPUBufferMapWriteCallback)(WGPUBufferMapAsyncStatus status,
|
|
||||||
void* data,
|
|
||||||
uint64_t dataLength,
|
|
||||||
void* userdata);
|
|
||||||
typedef void (*WGPUFenceOnCompletionCallback)(WGPUFenceCompletionStatus status, void* userdata);
|
|
||||||
typedef void (*WGPUErrorCallback)(WGPUErrorType type, const char* message, void* userdata);
|
|
||||||
|
|
||||||
typedef void (*WGPUProc)();
|
typedef void (*WGPUProc)();
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,7 @@ namespace wgpu {
|
||||||
{{as_varName(arg.name)}}.Get()
|
{{as_varName(arg.name)}}.Get()
|
||||||
{%- elif arg.type.category == "enum" or arg.type.category == "bitmask" -%}
|
{%- elif arg.type.category == "enum" or arg.type.category == "bitmask" -%}
|
||||||
static_cast<{{as_cType(arg.type.name)}}>({{as_varName(arg.name)}})
|
static_cast<{{as_cType(arg.type.name)}}>({{as_varName(arg.name)}})
|
||||||
{%- elif arg.type.category in ["native", "natively defined"] -%}
|
{%- elif arg.type.category in ["callback", "native"] -%}
|
||||||
{{as_varName(arg.name)}}
|
{{as_varName(arg.name)}}
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
UNHANDLED
|
UNHANDLED
|
||||||
|
|
|
@ -49,7 +49,7 @@ namespace wgpu {
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
using Proc = WGPUProc;
|
using Proc = WGPUProc;
|
||||||
{% for type in by_category["natively defined"] %}
|
{% for type in by_category["callback"] %}
|
||||||
using {{as_cppType(type.name)}} = {{as_cType(type.name)}};
|
using {{as_cppType(type.name)}} = {{as_cType(type.name)}};
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue