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>
This commit is contained in:
parent
a483fac90d
commit
c7f416c0c9
|
@ -1,3 +1,5 @@
|
||||||
|
*.pyc
|
||||||
|
|
||||||
# Directories added by gclient sync and the GN build
|
# Directories added by gclient sync and the GN build
|
||||||
.gclient
|
.gclient
|
||||||
.gclient_entries
|
.gclient_entries
|
||||||
|
|
11
BUILD.gn
11
BUILD.gn
|
@ -54,6 +54,8 @@ template("dawn_generator") {
|
||||||
# target using templates in this directory.
|
# target using templates in this directory.
|
||||||
generator_args = [
|
generator_args = [
|
||||||
rebase_path("dawn.json", root_build_dir),
|
rebase_path("dawn.json", root_build_dir),
|
||||||
|
"--wire-json",
|
||||||
|
rebase_path("dawn_wire.json", root_build_dir),
|
||||||
"--template-dir",
|
"--template-dir",
|
||||||
rebase_path("generator/templates", root_build_dir),
|
rebase_path("generator/templates", root_build_dir),
|
||||||
"--targets",
|
"--targets",
|
||||||
|
@ -695,8 +697,8 @@ dawn_static_and_shared_library("libdawn_native") {
|
||||||
]
|
]
|
||||||
|
|
||||||
deps = [
|
deps = [
|
||||||
":libdawn_native_sources",
|
|
||||||
":dawn_common",
|
":dawn_common",
|
||||||
|
":libdawn_native_sources",
|
||||||
]
|
]
|
||||||
sources = [
|
sources = [
|
||||||
"src/dawn_native/DawnNative.cpp",
|
"src/dawn_native/DawnNative.cpp",
|
||||||
|
@ -761,7 +763,10 @@ dawn_static_and_shared_library("libdawn_wire") {
|
||||||
|
|
||||||
configs = [ ":dawn_internal" ]
|
configs = [ ":dawn_internal" ]
|
||||||
sources = get_target_outputs(":libdawn_wire_gen")
|
sources = get_target_outputs(":libdawn_wire_gen")
|
||||||
sources += [ "src/dawn_wire/WireCmd.h" ]
|
sources += [
|
||||||
|
"src/dawn_wire/WireDeserializeAllocator.cpp",
|
||||||
|
"src/dawn_wire/WireDeserializeAllocator.h",
|
||||||
|
]
|
||||||
|
|
||||||
# Make headers publically visible
|
# Make headers publically visible
|
||||||
public_deps = [
|
public_deps = [
|
||||||
|
@ -849,8 +854,8 @@ test("dawn_unittests") {
|
||||||
":dawn_headers",
|
":dawn_headers",
|
||||||
":dawn_utils",
|
":dawn_utils",
|
||||||
":libdawn",
|
":libdawn",
|
||||||
":libdawn_native_sources",
|
|
||||||
":libdawn_native",
|
":libdawn_native",
|
||||||
|
":libdawn_native_sources",
|
||||||
":libdawn_wire",
|
":libdawn_wire",
|
||||||
":mock_dawn_gen",
|
":mock_dawn_gen",
|
||||||
"third_party:gmock_and_gtest",
|
"third_party:gmock_and_gtest",
|
||||||
|
|
12
dawn.json
12
dawn.json
|
@ -1106,6 +1106,18 @@
|
||||||
{"value": 11, "name": "unorm r8 g8"}
|
{"value": 11, "name": "unorm r8 g8"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"ObjectType": {
|
||||||
|
"_comment": "Only used for the wire",
|
||||||
|
"category": "native"
|
||||||
|
},
|
||||||
|
"ObjectId": {
|
||||||
|
"_comment": "Only used for the wire",
|
||||||
|
"category": "native"
|
||||||
|
},
|
||||||
|
"ObjectHandle": {
|
||||||
|
"_comment": "Only used for the wire",
|
||||||
|
"category": "native"
|
||||||
|
},
|
||||||
"void": {
|
"void": {
|
||||||
"category": "native"
|
"category": "native"
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
{
|
||||||
|
"_comment": [
|
||||||
|
"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."
|
||||||
|
],
|
||||||
|
"commands": {
|
||||||
|
"buffer map async": [
|
||||||
|
{ "name": "buffer id", "type": "ObjectId" },
|
||||||
|
{ "name": "request serial", "type": "uint32_t" },
|
||||||
|
{ "name": "start", "type": "uint32_t" },
|
||||||
|
{ "name": "size", "type": "uint32_t" },
|
||||||
|
{ "name": "is write", "type": "bool" }
|
||||||
|
],
|
||||||
|
"buffer update mapped data": [
|
||||||
|
{ "name": "buffer id", "type": "ObjectId" },
|
||||||
|
{ "name": "data length", "type": "uint32_t" },
|
||||||
|
{ "name": "data", "type": "uint8_t", "annotation": "const*", "length": "data length" }
|
||||||
|
],
|
||||||
|
"destroy object": [
|
||||||
|
{ "name": "object type", "type": "ObjectType" },
|
||||||
|
{ "name": "object id", "type": "ObjectId" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"return commands": {
|
||||||
|
"buffer map read async callback": [
|
||||||
|
{ "name": "buffer", "type": "ObjectHandle" },
|
||||||
|
{ "name": "request serial", "type": "uint32_t" },
|
||||||
|
{ "name": "status", "type": "uint32_t" },
|
||||||
|
{ "name": "data length", "type": "uint32_t" },
|
||||||
|
{ "name": "data", "type": "uint8_t", "annotation": "const*", "length": "data length" }
|
||||||
|
],
|
||||||
|
"buffer map write async callback": [
|
||||||
|
{ "name": "buffer", "type": "ObjectHandle" },
|
||||||
|
{ "name": "request serial", "type": "uint32_t" },
|
||||||
|
{ "name": "status", "type": "uint32_t" }
|
||||||
|
],
|
||||||
|
"device error callback": [
|
||||||
|
{ "name": "message", "type": "char", "annotation": "const*", "length": "strlen" }
|
||||||
|
],
|
||||||
|
"fence update completed value": [
|
||||||
|
{ "name": "fence", "type": "ObjectHandle" },
|
||||||
|
{ "name": "value", "type": "uint64_t" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"special items": {
|
||||||
|
"client_side_commands": [
|
||||||
|
"FenceGetCompletedValue"
|
||||||
|
],
|
||||||
|
"client_proxied_commands": [
|
||||||
|
"BufferUnmap",
|
||||||
|
"DeviceCreateFence",
|
||||||
|
"QueueSignal"
|
||||||
|
],
|
||||||
|
"client_special_objects": [
|
||||||
|
"Buffer",
|
||||||
|
"Device",
|
||||||
|
"Fence"
|
||||||
|
],
|
||||||
|
"server_custom_pre_handler_commands": [
|
||||||
|
"BufferUnmap"
|
||||||
|
],
|
||||||
|
"server_custom_post_handler_commands": [
|
||||||
|
"QueueSignal"
|
||||||
|
],
|
||||||
|
"server_reverse_lookup_objects": [
|
||||||
|
"Fence"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,149 @@
|
||||||
|
# Copyright 2017 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.
|
||||||
|
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
|
class Name:
|
||||||
|
def __init__(self, name, native=False):
|
||||||
|
self.native = native
|
||||||
|
if native:
|
||||||
|
self.chunks = [name]
|
||||||
|
else:
|
||||||
|
self.chunks = name.split(' ')
|
||||||
|
|
||||||
|
def CamelChunk(self, chunk):
|
||||||
|
return chunk[0].upper() + chunk[1:]
|
||||||
|
|
||||||
|
def canonical_case(self):
|
||||||
|
return (' '.join(self.chunks)).lower()
|
||||||
|
|
||||||
|
def concatcase(self):
|
||||||
|
return ''.join(self.chunks)
|
||||||
|
|
||||||
|
def camelCase(self):
|
||||||
|
return self.chunks[0] + ''.join([self.CamelChunk(chunk) for chunk in self.chunks[1:]])
|
||||||
|
|
||||||
|
def CamelCase(self):
|
||||||
|
return ''.join([self.CamelChunk(chunk) for chunk in self.chunks])
|
||||||
|
|
||||||
|
def SNAKE_CASE(self):
|
||||||
|
return '_'.join([chunk.upper() for chunk in self.chunks])
|
||||||
|
|
||||||
|
def snake_case(self):
|
||||||
|
return '_'.join(self.chunks)
|
||||||
|
|
||||||
|
class Type:
|
||||||
|
def __init__(self, name, json_data, native=False):
|
||||||
|
self.json_data = json_data
|
||||||
|
self.dict_name = name
|
||||||
|
self.name = Name(name, native=native)
|
||||||
|
self.category = json_data['category']
|
||||||
|
self.is_builder = self.name.canonical_case().endswith(" builder")
|
||||||
|
|
||||||
|
EnumValue = namedtuple('EnumValue', ['name', 'value'])
|
||||||
|
class EnumType(Type):
|
||||||
|
def __init__(self, name, json_data):
|
||||||
|
Type.__init__(self, name, json_data)
|
||||||
|
self.values = [EnumValue(Name(m['name']), m['value']) for m in self.json_data['values']]
|
||||||
|
|
||||||
|
BitmaskValue = namedtuple('BitmaskValue', ['name', 'value'])
|
||||||
|
class BitmaskType(Type):
|
||||||
|
def __init__(self, name, json_data):
|
||||||
|
Type.__init__(self, name, json_data)
|
||||||
|
self.values = [BitmaskValue(Name(m['name']), m['value']) for m in self.json_data['values']]
|
||||||
|
self.full_mask = 0
|
||||||
|
for value in self.values:
|
||||||
|
self.full_mask = self.full_mask | value.value
|
||||||
|
|
||||||
|
class NativeType(Type):
|
||||||
|
def __init__(self, name, json_data):
|
||||||
|
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
|
||||||
|
# method arguments or structure members.
|
||||||
|
class RecordMember:
|
||||||
|
def __init__(self, name, typ, annotation, optional, is_return_value):
|
||||||
|
self.name = name
|
||||||
|
self.type = typ
|
||||||
|
self.annotation = annotation
|
||||||
|
self.length = None
|
||||||
|
self.optional = optional
|
||||||
|
self.is_return_value = is_return_value
|
||||||
|
|
||||||
|
Method = namedtuple('Method', ['name', 'return_type', 'arguments'])
|
||||||
|
class ObjectType(Type):
|
||||||
|
def __init__(self, name, json_data):
|
||||||
|
Type.__init__(self, name, json_data)
|
||||||
|
self.methods = []
|
||||||
|
self.native_methods = []
|
||||||
|
self.built_type = None
|
||||||
|
|
||||||
|
class Record:
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = Name(name)
|
||||||
|
self.members = []
|
||||||
|
self.has_dawn_object = False
|
||||||
|
|
||||||
|
def update_metadata(self):
|
||||||
|
def has_dawn_object(member):
|
||||||
|
if isinstance(member.type, ObjectType):
|
||||||
|
return True
|
||||||
|
elif isinstance(member.type, StructureType):
|
||||||
|
return member.type.has_dawn_object
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.has_dawn_object = any(has_dawn_object(member) for member in self.members)
|
||||||
|
|
||||||
|
class StructureType(Record, Type):
|
||||||
|
def __init__(self, name, json_data):
|
||||||
|
Record.__init__(self, name)
|
||||||
|
Type.__init__(self, name, json_data)
|
||||||
|
self.extensible = json_data.get("extensible", False)
|
||||||
|
|
||||||
|
class Command(Record):
|
||||||
|
def __init__(self, name, members=None):
|
||||||
|
Record.__init__(self, name)
|
||||||
|
self.members = members or []
|
||||||
|
self.derived_object = None
|
||||||
|
self.derived_method = None
|
||||||
|
|
||||||
|
def linked_record_members(json_data, types):
|
||||||
|
members = []
|
||||||
|
members_by_name = {}
|
||||||
|
for m in json_data:
|
||||||
|
member = RecordMember(Name(m['name']), types[m['type']],
|
||||||
|
m.get('annotation', 'value'), m.get('optional', False),
|
||||||
|
m.get('is_return_value', False))
|
||||||
|
members.append(member)
|
||||||
|
members_by_name[member.name.canonical_case()] = member
|
||||||
|
|
||||||
|
for (member, m) in zip(members, json_data):
|
||||||
|
if member.annotation != 'value':
|
||||||
|
if not 'length' in m:
|
||||||
|
if member.type.category == 'structure':
|
||||||
|
member.length = "constant"
|
||||||
|
member.constant_length = 1
|
||||||
|
else:
|
||||||
|
assert(False)
|
||||||
|
elif m['length'] == 'strlen':
|
||||||
|
member.length = 'strlen'
|
||||||
|
else:
|
||||||
|
member.length = members_by_name[m['length']]
|
||||||
|
|
||||||
|
return members
|
|
@ -17,90 +17,9 @@
|
||||||
# COMMON
|
# COMMON
|
||||||
############################################################
|
############################################################
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
from common import Name
|
||||||
class Name:
|
import common
|
||||||
def __init__(self, name, native=False):
|
import wire_cmd
|
||||||
self.native = native
|
|
||||||
if native:
|
|
||||||
self.chunks = [name]
|
|
||||||
else:
|
|
||||||
self.chunks = name.split(' ')
|
|
||||||
|
|
||||||
def CamelChunk(self, chunk):
|
|
||||||
return chunk[0].upper() + chunk[1:]
|
|
||||||
|
|
||||||
def canonical_case(self):
|
|
||||||
return (' '.join(self.chunks)).lower()
|
|
||||||
|
|
||||||
def concatcase(self):
|
|
||||||
return ''.join(self.chunks)
|
|
||||||
|
|
||||||
def camelCase(self):
|
|
||||||
return self.chunks[0] + ''.join([self.CamelChunk(chunk) for chunk in self.chunks[1:]])
|
|
||||||
|
|
||||||
def CamelCase(self):
|
|
||||||
return ''.join([self.CamelChunk(chunk) for chunk in self.chunks])
|
|
||||||
|
|
||||||
def SNAKE_CASE(self):
|
|
||||||
return '_'.join([chunk.upper() for chunk in self.chunks])
|
|
||||||
|
|
||||||
def snake_case(self):
|
|
||||||
return '_'.join(self.chunks)
|
|
||||||
|
|
||||||
class Type:
|
|
||||||
def __init__(self, name, json_data, native=False):
|
|
||||||
self.json_data = json_data
|
|
||||||
self.dict_name = name
|
|
||||||
self.name = Name(name, native=native)
|
|
||||||
self.category = json_data['category']
|
|
||||||
self.is_builder = self.name.canonical_case().endswith(" builder")
|
|
||||||
|
|
||||||
EnumValue = namedtuple('EnumValue', ['name', 'value'])
|
|
||||||
class EnumType(Type):
|
|
||||||
def __init__(self, name, json_data):
|
|
||||||
Type.__init__(self, name, json_data)
|
|
||||||
self.values = [EnumValue(Name(m['name']), m['value']) for m in self.json_data['values']]
|
|
||||||
|
|
||||||
BitmaskValue = namedtuple('BitmaskValue', ['name', 'value'])
|
|
||||||
class BitmaskType(Type):
|
|
||||||
def __init__(self, name, json_data):
|
|
||||||
Type.__init__(self, name, json_data)
|
|
||||||
self.values = [BitmaskValue(Name(m['name']), m['value']) for m in self.json_data['values']]
|
|
||||||
self.full_mask = 0
|
|
||||||
for value in self.values:
|
|
||||||
self.full_mask = self.full_mask | value.value
|
|
||||||
|
|
||||||
class NativeType(Type):
|
|
||||||
def __init__(self, name, json_data):
|
|
||||||
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
|
|
||||||
# method arguments or structure members.
|
|
||||||
class RecordMember:
|
|
||||||
def __init__(self, name, typ, annotation, optional):
|
|
||||||
self.name = name
|
|
||||||
self.type = typ
|
|
||||||
self.annotation = annotation
|
|
||||||
self.length = None
|
|
||||||
self.optional = optional
|
|
||||||
|
|
||||||
Method = namedtuple('Method', ['name', 'return_type', 'arguments'])
|
|
||||||
class ObjectType(Type):
|
|
||||||
def __init__(self, name, json_data):
|
|
||||||
Type.__init__(self, name, json_data)
|
|
||||||
self.methods = []
|
|
||||||
self.native_methods = []
|
|
||||||
self.built_type = None
|
|
||||||
|
|
||||||
class StructureType(Type):
|
|
||||||
def __init__(self, name, json_data):
|
|
||||||
Type.__init__(self, name, json_data)
|
|
||||||
self.extensible = json_data.get("extensible", False)
|
|
||||||
self.members = []
|
|
||||||
|
|
||||||
############################################################
|
############################################################
|
||||||
# PARSE
|
# PARSE
|
||||||
|
@ -111,35 +30,10 @@ def is_native_method(method):
|
||||||
return method.return_type.category == "natively defined" or \
|
return method.return_type.category == "natively defined" or \
|
||||||
any([arg.type.category == "natively defined" for arg in method.arguments])
|
any([arg.type.category == "natively defined" for arg in method.arguments])
|
||||||
|
|
||||||
def linked_record_members(json_data, types):
|
|
||||||
members = []
|
|
||||||
members_by_name = {}
|
|
||||||
for m in json_data:
|
|
||||||
member = RecordMember(Name(m['name']), types[m['type']],
|
|
||||||
m.get('annotation', 'value'), m.get('optional', False))
|
|
||||||
members.append(member)
|
|
||||||
members_by_name[member.name.canonical_case()] = member
|
|
||||||
|
|
||||||
for (member, m) in zip(members, json_data):
|
|
||||||
if member.annotation != 'value':
|
|
||||||
if not 'length' in m:
|
|
||||||
if member.type.category == 'structure':
|
|
||||||
member.length = "constant"
|
|
||||||
member.constant_length = 1
|
|
||||||
else:
|
|
||||||
assert(False)
|
|
||||||
elif m['length'] == 'strlen':
|
|
||||||
member.length = 'strlen'
|
|
||||||
else:
|
|
||||||
member.length = members_by_name[m['length']]
|
|
||||||
|
|
||||||
return members
|
|
||||||
|
|
||||||
|
|
||||||
def link_object(obj, types):
|
def link_object(obj, types):
|
||||||
def make_method(json_data):
|
def make_method(json_data):
|
||||||
arguments = linked_record_members(json_data.get('args', []), types)
|
arguments = common.linked_record_members(json_data.get('args', []), types)
|
||||||
return Method(Name(json_data['name']), types[json_data.get('returns', 'void')], arguments)
|
return common.Method(Name(json_data['name']), types[json_data.get('returns', 'void')], arguments)
|
||||||
|
|
||||||
methods = [make_method(m) for m in obj.json_data.get('methods', [])]
|
methods = [make_method(m) for m in obj.json_data.get('methods', [])]
|
||||||
obj.methods = [method for method in methods if not is_native_method(method)]
|
obj.methods = [method for method in methods if not is_native_method(method)]
|
||||||
|
@ -154,7 +48,7 @@ def link_object(obj, types):
|
||||||
assert(obj.built_type != None)
|
assert(obj.built_type != None)
|
||||||
|
|
||||||
def link_structure(struct, types):
|
def link_structure(struct, types):
|
||||||
struct.members = linked_record_members(struct.json_data['members'], types)
|
struct.members = common.linked_record_members(struct.json_data['members'], 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
|
||||||
|
@ -194,12 +88,12 @@ def topo_sort_structure(structs):
|
||||||
|
|
||||||
def parse_json(json):
|
def parse_json(json):
|
||||||
category_to_parser = {
|
category_to_parser = {
|
||||||
'bitmask': BitmaskType,
|
'bitmask': common.BitmaskType,
|
||||||
'enum': EnumType,
|
'enum': common.EnumType,
|
||||||
'native': NativeType,
|
'native': common.NativeType,
|
||||||
'natively defined': NativelyDefined,
|
'natively defined': common.NativelyDefined,
|
||||||
'object': ObjectType,
|
'object': common.ObjectType,
|
||||||
'structure': StructureType,
|
'structure': common.StructureType,
|
||||||
}
|
}
|
||||||
|
|
||||||
types = {}
|
types = {}
|
||||||
|
@ -227,6 +121,9 @@ def parse_json(json):
|
||||||
|
|
||||||
by_category['structure'] = topo_sort_structure(by_category['structure'])
|
by_category['structure'] = topo_sort_structure(by_category['structure'])
|
||||||
|
|
||||||
|
for struct in by_category['structure']:
|
||||||
|
struct.update_metadata()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'types': types,
|
'types': types,
|
||||||
'by_category': by_category
|
'by_category': by_category
|
||||||
|
@ -392,18 +289,18 @@ def cpp_native_methods(types, typ):
|
||||||
methods = typ.methods + typ.native_methods
|
methods = typ.methods + typ.native_methods
|
||||||
|
|
||||||
if typ.is_builder:
|
if typ.is_builder:
|
||||||
methods.append(Method(Name('set error callback'), types['void'], [
|
methods.append(common.Method(Name('set error callback'), types['void'], [
|
||||||
RecordMember(Name('callback'), types['builder error callback'], 'value', False),
|
common.RecordMember(Name('callback'), types['builder error callback'], 'value', False, False),
|
||||||
RecordMember(Name('userdata1'), types['callback userdata'], 'value', False),
|
common.RecordMember(Name('userdata1'), types['callback userdata'], 'value', False, False),
|
||||||
RecordMember(Name('userdata2'), types['callback userdata'], 'value', False),
|
common.RecordMember(Name('userdata2'), types['callback userdata'], 'value', False, False),
|
||||||
]))
|
]))
|
||||||
|
|
||||||
return methods
|
return methods
|
||||||
|
|
||||||
def c_native_methods(types, typ):
|
def c_native_methods(types, typ):
|
||||||
return cpp_native_methods(types, typ) + [
|
return cpp_native_methods(types, typ) + [
|
||||||
Method(Name('reference'), types['void'], []),
|
common.Method(Name('reference'), types['void'], []),
|
||||||
Method(Name('release'), types['void'], []),
|
common.Method(Name('release'), types['void'], []),
|
||||||
]
|
]
|
||||||
|
|
||||||
def js_native_methods(types, typ):
|
def js_native_methods(types, typ):
|
||||||
|
@ -412,7 +309,7 @@ def js_native_methods(types, typ):
|
||||||
def debug(text):
|
def debug(text):
|
||||||
print(text)
|
print(text)
|
||||||
|
|
||||||
def get_renders_for_targets(api_params, targets):
|
def get_renders_for_targets(api_params, wire_json, targets):
|
||||||
base_params = {
|
base_params = {
|
||||||
'enumerate': enumerate,
|
'enumerate': enumerate,
|
||||||
'format': format,
|
'format': format,
|
||||||
|
@ -471,17 +368,20 @@ def get_renders_for_targets(api_params, targets):
|
||||||
renders.append(FileRender('dawn_native/ProcTable.cpp', 'dawn_native/ProcTable.cpp', frontend_params))
|
renders.append(FileRender('dawn_native/ProcTable.cpp', 'dawn_native/ProcTable.cpp', frontend_params))
|
||||||
|
|
||||||
if 'dawn_wire' in targets:
|
if 'dawn_wire' in targets:
|
||||||
|
additional_params = wire_cmd.compute_wire_params(api_params, wire_json)
|
||||||
|
|
||||||
wire_params = [
|
wire_params = [
|
||||||
base_params,
|
base_params,
|
||||||
api_params,
|
api_params,
|
||||||
c_params,
|
c_params,
|
||||||
{
|
{
|
||||||
'as_wireType': lambda typ: typ.name.CamelCase() + '*' if typ.category == 'object' else as_cppType(typ.name)
|
'as_wireType': lambda typ: typ.name.CamelCase() + '*' if typ.category == 'object' else as_cppType(typ.name)
|
||||||
}
|
},
|
||||||
|
additional_params
|
||||||
]
|
]
|
||||||
renders.append(FileRender('dawn_wire/TypeTraits.h', 'dawn_wire/TypeTraits_autogen.h', wire_params))
|
|
||||||
renders.append(FileRender('dawn_wire/WireCmd.h', 'dawn_wire/WireCmd_autogen.h', wire_params))
|
renders.append(FileRender('dawn_wire/WireCmd.h', 'dawn_wire/WireCmd_autogen.h', wire_params))
|
||||||
renders.append(FileRender('dawn_wire/WireCmd.cpp', 'dawn_wire/WireCmd_autogen.cpp', wire_params))
|
renders.append(FileRender('dawn_wire/WireCmd.cpp', 'dawn_wire/WireCmd_autogen.cpp', wire_params))
|
||||||
|
renders.append(FileRender('dawn_wire/TypeTraits.h', 'dawn_wire/TypeTraits_autogen.h', wire_params))
|
||||||
renders.append(FileRender('dawn_wire/WireClient.cpp', 'dawn_wire/WireClient.cpp', wire_params))
|
renders.append(FileRender('dawn_wire/WireClient.cpp', 'dawn_wire/WireClient.cpp', wire_params))
|
||||||
renders.append(FileRender('dawn_wire/WireServer.cpp', 'dawn_wire/WireServer.cpp', wire_params))
|
renders.append(FileRender('dawn_wire/WireServer.cpp', 'dawn_wire/WireServer.cpp', wire_params))
|
||||||
|
|
||||||
|
@ -507,6 +407,7 @@ def main():
|
||||||
formatter_class = argparse.ArgumentDefaultsHelpFormatter
|
formatter_class = argparse.ArgumentDefaultsHelpFormatter
|
||||||
)
|
)
|
||||||
parser.add_argument('json', metavar='DAWN_JSON', nargs=1, type=str, help ='The DAWN JSON definition to use.')
|
parser.add_argument('json', metavar='DAWN_JSON', nargs=1, type=str, help ='The DAWN JSON definition to use.')
|
||||||
|
parser.add_argument('--wire-json', default=None, type=str, help='The DAWN WIRE JSON definition to use.')
|
||||||
parser.add_argument('-t', '--template-dir', default='templates', type=str, help='Directory with template files.')
|
parser.add_argument('-t', '--template-dir', default='templates', type=str, help='Directory with template files.')
|
||||||
parser.add_argument('-T', '--targets', required=True, type=str, help='Comma-separated subset of targets to output. Available targets: ' + ', '.join(allowed_targets))
|
parser.add_argument('-T', '--targets', required=True, type=str, help='Comma-separated subset of targets to output. Available targets: ' + ', '.join(allowed_targets))
|
||||||
parser.add_argument(kExtraPythonPath, default=None, type=str, help='Additional python path to set before loading Jinja2')
|
parser.add_argument(kExtraPythonPath, default=None, type=str, help='Additional python path to set before loading Jinja2')
|
||||||
|
@ -522,7 +423,17 @@ def main():
|
||||||
api_params = parse_json(loaded_json)
|
api_params = parse_json(loaded_json)
|
||||||
|
|
||||||
targets = args.targets.split(',')
|
targets = args.targets.split(',')
|
||||||
renders = get_renders_for_targets(api_params, targets)
|
dependencies = [
|
||||||
|
os.path.join(os.path.abspath(os.path.dirname(__file__)), "common.py")
|
||||||
|
]
|
||||||
|
|
||||||
|
loaded_wire_json = None
|
||||||
|
if args.wire_json:
|
||||||
|
with open(args.wire_json) as f:
|
||||||
|
loaded_wire_json = json.loads(f.read())
|
||||||
|
dependencies.append(args.wire_json)
|
||||||
|
|
||||||
|
renders = get_renders_for_targets(api_params, loaded_wire_json, targets)
|
||||||
|
|
||||||
# The caller wants to assert that the outputs are what it expects.
|
# The caller wants to assert that the outputs are what it expects.
|
||||||
# Load the file and compare with our renders.
|
# Load the file and compare with our renders.
|
||||||
|
@ -544,8 +455,9 @@ def main():
|
||||||
if args.output_json_tarball != None:
|
if args.output_json_tarball != None:
|
||||||
output_to_json(outputs, args.output_json_tarball)
|
output_to_json(outputs, args.output_json_tarball)
|
||||||
|
|
||||||
dependencies = [args.template_dir + os.path.sep + render.template for render in renders]
|
dependencies += [args.template_dir + os.path.sep + render.template for render in renders]
|
||||||
dependencies.append(args.json[0])
|
dependencies.append(args.json[0])
|
||||||
|
dependencies.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), "wire_cmd.py"))
|
||||||
output_depfile(args.depfile, args.output_json_tarball, dependencies)
|
output_depfile(args.depfile, args.output_json_tarball, dependencies)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -13,7 +13,8 @@
|
||||||
//* limitations under the License.
|
//* limitations under the License.
|
||||||
|
|
||||||
#include "dawn_wire/Wire.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"
|
#include "common/Assert.h"
|
||||||
#include "common/SerialMap.h"
|
#include "common/SerialMap.h"
|
||||||
|
@ -66,12 +67,7 @@ namespace dawn_wire {
|
||||||
BuilderCallbackData builderCallback;
|
BuilderCallbackData builderCallback;
|
||||||
};
|
};
|
||||||
|
|
||||||
{% set special_objects = [
|
{% for type in by_category["object"] if not type.name.CamelCase() in client_special_objects %}
|
||||||
"device",
|
|
||||||
"buffer",
|
|
||||||
"fence",
|
|
||||||
] %}
|
|
||||||
{% for type in by_category["object"] if not type.name.canonical_case() in special_objects %}
|
|
||||||
struct {{type.name.CamelCase()}} : ObjectBase {
|
struct {{type.name.CamelCase()}} : ObjectBase {
|
||||||
using ObjectBase::ObjectBase;
|
using ObjectBase::ObjectBase;
|
||||||
};
|
};
|
||||||
|
@ -269,8 +265,6 @@ namespace dawn_wire {
|
||||||
CommandSerializer* mSerializer = nullptr;
|
CommandSerializer* mSerializer = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
{% set client_side_commands = ["FenceGetCompletedValue"] %}
|
|
||||||
|
|
||||||
//* Implementation of the client API functions.
|
//* Implementation of the client API functions.
|
||||||
{% for type in by_category["object"] %}
|
{% for type in by_category["object"] %}
|
||||||
{% set Type = type.name.CamelCase() %}
|
{% set Type = type.name.CamelCase() %}
|
||||||
|
@ -305,8 +299,7 @@ namespace dawn_wire {
|
||||||
self->builderCallback.canCall = false;
|
self->builderCallback.canCall = false;
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
cmd.resultId = allocation->object->id;
|
cmd.result = ObjectHandle{allocation->object->id, allocation->serial};
|
||||||
cmd.resultSerial = allocation->serial;
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% for arg in method.arguments %}
|
{% for arg in method.arguments %}
|
||||||
|
@ -353,8 +346,9 @@ namespace dawn_wire {
|
||||||
cmd.objectType = ObjectType::{{type.name.CamelCase()}};
|
cmd.objectType = ObjectType::{{type.name.CamelCase()}};
|
||||||
cmd.objectId = obj->id;
|
cmd.objectId = obj->id;
|
||||||
|
|
||||||
auto allocCmd = static_cast<decltype(cmd)*>(obj->device->GetCmdSpace(sizeof(cmd)));
|
size_t requiredSize = cmd.GetRequiredSize();
|
||||||
*allocCmd = cmd;
|
char* allocatedBuffer = static_cast<char*>(obj->device->GetCmdSpace(requiredSize));
|
||||||
|
cmd.Serialize(allocatedBuffer);
|
||||||
|
|
||||||
obj->device->{{type.name.camelCase()}}.Free(obj);
|
obj->device->{{type.name.camelCase()}}.Free(obj);
|
||||||
}
|
}
|
||||||
|
@ -386,8 +380,9 @@ namespace dawn_wire {
|
||||||
cmd.size = size;
|
cmd.size = size;
|
||||||
cmd.isWrite = false;
|
cmd.isWrite = false;
|
||||||
|
|
||||||
auto allocCmd = static_cast<decltype(cmd)*>(buffer->device->GetCmdSpace(sizeof(cmd)));
|
size_t requiredSize = cmd.GetRequiredSize();
|
||||||
*allocCmd = cmd;
|
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) {
|
void ClientBufferMapWriteAsync(dawnBuffer cBuffer, uint32_t start, uint32_t size, dawnBufferMapWriteCallback callback, dawnCallbackUserdata userdata) {
|
||||||
|
@ -410,8 +405,9 @@ namespace dawn_wire {
|
||||||
cmd.size = size;
|
cmd.size = size;
|
||||||
cmd.isWrite = true;
|
cmd.isWrite = true;
|
||||||
|
|
||||||
auto allocCmd = static_cast<decltype(cmd)*>(buffer->device->GetCmdSpace(sizeof(cmd)));
|
size_t requiredSize = cmd.GetRequiredSize();
|
||||||
*allocCmd = cmd;
|
char* allocatedBuffer = static_cast<char*>(buffer->device->GetCmdSpace(requiredSize));
|
||||||
|
cmd.Serialize(allocatedBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t ClientFenceGetCompletedValue(dawnFence cSelf) {
|
uint64_t ClientFenceGetCompletedValue(dawnFence cSelf) {
|
||||||
|
@ -458,12 +454,11 @@ namespace dawn_wire {
|
||||||
BufferUpdateMappedDataCmd cmd;
|
BufferUpdateMappedDataCmd cmd;
|
||||||
cmd.bufferId = buffer->id;
|
cmd.bufferId = buffer->id;
|
||||||
cmd.dataLength = static_cast<uint32_t>(buffer->mappedDataSize);
|
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)));
|
size_t requiredSize = cmd.GetRequiredSize();
|
||||||
*allocCmd = cmd;
|
char* allocatedBuffer = static_cast<char*>(buffer->device->GetCmdSpace(requiredSize));
|
||||||
|
cmd.Serialize(allocatedBuffer);
|
||||||
void* dataAlloc = buffer->device->GetCmdSpace(cmd.dataLength);
|
|
||||||
memcpy(dataAlloc, buffer->mappedData, cmd.dataLength);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buffer->mappedData);
|
free(buffer->mappedData);
|
||||||
|
@ -510,14 +505,12 @@ namespace dawn_wire {
|
||||||
// - An autogenerated Client{{suffix}} method that sends the command on the wire
|
// - 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
|
// - 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}}
|
// the autogenerated one, and that will have to call Client{{suffix}}
|
||||||
{% set proxied_commands = ["BufferUnmap", "DeviceCreateFence", "QueueSignal"] %}
|
|
||||||
|
|
||||||
dawnProcTable GetProcs() {
|
dawnProcTable GetProcs() {
|
||||||
dawnProcTable table;
|
dawnProcTable table;
|
||||||
{% for type in by_category["object"] %}
|
{% for type in by_category["object"] %}
|
||||||
{% for method in native_methods(type) %}
|
{% for method in native_methods(type) %}
|
||||||
{% set suffix = as_MethodSuffix(type.name, method.name) %}
|
{% 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}};
|
table.{{as_varName(type.name, method.name)}} = ProxyClient{{suffix}};
|
||||||
{% else %}
|
{% else %}
|
||||||
table.{{as_varName(type.name, method.name)}} = Client{{suffix}};
|
table.{{as_varName(type.name, method.name)}} = Client{{suffix}};
|
||||||
|
@ -538,23 +531,11 @@ namespace dawn_wire {
|
||||||
|
|
||||||
bool success = false;
|
bool success = false;
|
||||||
switch (cmdId) {
|
switch (cmdId) {
|
||||||
case ReturnWireCmd::DeviceErrorCallback:
|
{% for command in cmd_records["return command"] %}
|
||||||
success = HandleDeviceErrorCallbackCmd(&commands, &size);
|
case ReturnWireCmd::{{command.name.CamelCase()}}:
|
||||||
break;
|
success = Handle{{command.name.CamelCase()}}(&commands, &size);
|
||||||
{% for type in by_category["object"] if type.is_builder %}
|
|
||||||
case ReturnWireCmd::{{type.name.CamelCase()}}ErrorCallback:
|
|
||||||
success = Handle{{type.name.CamelCase()}}ErrorCallbackCmd(&commands, &size);
|
|
||||||
break;
|
break;
|
||||||
{% endfor %}
|
{% 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:
|
default:
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
@ -562,6 +543,7 @@ namespace dawn_wire {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
mAllocator.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size != 0) {
|
if (size != 0) {
|
||||||
|
@ -573,72 +555,47 @@ namespace dawn_wire {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Device* mDevice = nullptr;
|
Device* mDevice = nullptr;
|
||||||
|
WireDeserializeAllocator mAllocator;
|
||||||
|
|
||||||
//* Helper function for the getting of the command data in command handlers.
|
bool HandleDeviceErrorCallback(const char** commands, size_t* size) {
|
||||||
//* Checks there is enough data left, updates the buffer / size and returns
|
ReturnDeviceErrorCallbackCmd cmd;
|
||||||
//* the command (or nullptr for an error).
|
DeserializeResult deserializeResult = cmd.Deserialize(commands, size, &mAllocator);
|
||||||
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);
|
if (deserializeResult == DeserializeResult::FatalError) {
|
||||||
|
|
||||||
*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) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* message = GetData<char>(commands, size, cmd->messageStrlen + 1);
|
DAWN_ASSERT(cmd.message != nullptr);
|
||||||
if (message == nullptr || message[cmd->messageStrlen] != '\0') {
|
mDevice->HandleError(cmd.message);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mDevice->HandleError(message);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
{% for type in by_category["object"] if type.is_builder %}
|
{% for type in by_category["object"] if type.is_builder %}
|
||||||
{% set Type = type.name.CamelCase() %}
|
{% set Type = type.name.CamelCase() %}
|
||||||
bool Handle{{Type}}ErrorCallbackCmd(const char** commands, size_t* size) {
|
bool Handle{{Type}}ErrorCallback(const char** commands, size_t* size) {
|
||||||
const auto* cmd = GetCommand<Return{{Type}}ErrorCallbackCmd>(commands, size);
|
Return{{Type}}ErrorCallbackCmd cmd;
|
||||||
if (cmd == nullptr) {
|
DeserializeResult deserializeResult = cmd.Deserialize(commands, size, &mAllocator);
|
||||||
|
|
||||||
|
if (deserializeResult == DeserializeResult::FatalError) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* message = GetData<char>(commands, size, cmd->messageStrlen + 1);
|
DAWN_ASSERT(cmd.message != nullptr);
|
||||||
if (message == nullptr || message[cmd->messageStrlen] != '\0') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* builtObject = mDevice->{{type.built_type.name.camelCase()}}.GetObject(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->builtObjectId);
|
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.
|
//* 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;
|
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
|
// Unhandled builder errors are forwarded to the device
|
||||||
if (!called && cmd->status != DAWN_BUILDER_ERROR_STATUS_SUCCESS && cmd->status != DAWN_BUILDER_ERROR_STATUS_UNKNOWN) {
|
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());
|
mDevice->HandleError(("Unhandled builder error: " + std::string(cmd.message)).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -646,31 +603,23 @@ namespace dawn_wire {
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
bool HandleBufferMapReadAsyncCallback(const char** commands, size_t* size) {
|
bool HandleBufferMapReadAsyncCallback(const char** commands, size_t* size) {
|
||||||
const auto* cmd = GetCommand<ReturnBufferMapReadAsyncCallbackCmd>(commands, size);
|
ReturnBufferMapReadAsyncCallbackCmd cmd;
|
||||||
if (cmd == nullptr) {
|
DeserializeResult deserializeResult = cmd.Deserialize(commands, size, &mAllocator);
|
||||||
|
|
||||||
|
if (deserializeResult == DeserializeResult::FatalError) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//* Unconditionnally get the data from the buffer so that the correct amount of data is
|
auto* buffer = mDevice->buffer.GetObject(cmd.buffer.id);
|
||||||
//* consumed from the buffer, even when we ignore the command and early out.
|
uint32_t bufferSerial = mDevice->buffer.GetSerial(cmd.buffer.id);
|
||||||
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);
|
|
||||||
|
|
||||||
//* 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 || bufferSerial != cmd->bufferSerial) {
|
if (buffer == nullptr || bufferSerial != cmd.buffer.serial) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//* The requests can have been deleted via an Unmap so this isn't an error.
|
//* 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()) {
|
if (requestIt == buffer->requests.end()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -686,14 +635,14 @@ namespace dawn_wire {
|
||||||
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 function
|
//* 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 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.
|
//* the application to crash if we did call the callback.
|
||||||
if (request.size != cmd->dataLength) {
|
if (request.size != cmd.dataLength) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(requestData != nullptr);
|
ASSERT(cmd.data != nullptr);
|
||||||
|
|
||||||
if (buffer->mappedData != nullptr) {
|
if (buffer->mappedData != nullptr) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -702,32 +651,34 @@ namespace dawn_wire {
|
||||||
buffer->isWriteMapped = false;
|
buffer->isWriteMapped = false;
|
||||||
buffer->mappedDataSize = request.size;
|
buffer->mappedDataSize = request.size;
|
||||||
buffer->mappedData = malloc(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 {
|
} else {
|
||||||
request.readCallback(static_cast<dawnBufferMapAsyncStatus>(cmd->status), nullptr, request.userdata);
|
request.readCallback(static_cast<dawnBufferMapAsyncStatus>(cmd.status), nullptr, request.userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HandleBufferMapWriteAsyncCallback(const char** commands, size_t* size) {
|
bool HandleBufferMapWriteAsyncCallback(const char** commands, size_t* size) {
|
||||||
const auto* cmd = GetCommand<ReturnBufferMapWriteAsyncCallbackCmd>(commands, size);
|
ReturnBufferMapWriteAsyncCallbackCmd cmd;
|
||||||
if (cmd == nullptr) {
|
DeserializeResult deserializeResult = cmd.Deserialize(commands, size, &mAllocator);
|
||||||
|
|
||||||
|
if (deserializeResult == DeserializeResult::FatalError) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* buffer = mDevice->buffer.GetObject(cmd->bufferId);
|
auto* buffer = mDevice->buffer.GetObject(cmd.buffer.id);
|
||||||
uint32_t bufferSerial = mDevice->buffer.GetSerial(cmd->bufferId);
|
uint32_t bufferSerial = mDevice->buffer.GetSerial(cmd.buffer.id);
|
||||||
|
|
||||||
//* 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 || bufferSerial != cmd->bufferSerial) {
|
if (buffer == nullptr || bufferSerial != cmd.buffer.serial) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//* The requests can have been deleted via an Unmap so this isn't an error.
|
//* 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()) {
|
if (requestIt == buffer->requests.end()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -742,7 +693,7 @@ namespace dawn_wire {
|
||||||
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 function
|
//* 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) {
|
if (buffer->mappedData != nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -752,29 +703,31 @@ namespace dawn_wire {
|
||||||
buffer->mappedData = malloc(request.size);
|
buffer->mappedData = malloc(request.size);
|
||||||
memset(buffer->mappedData, 0, 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 {
|
} else {
|
||||||
request.writeCallback(static_cast<dawnBufferMapAsyncStatus>(cmd->status), nullptr, request.userdata);
|
request.writeCallback(static_cast<dawnBufferMapAsyncStatus>(cmd.status), nullptr, request.userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HandleFenceUpdateCompletedValue(const char** commands, size_t* size) {
|
bool HandleFenceUpdateCompletedValue(const char** commands, size_t* size) {
|
||||||
const auto* cmd = GetCommand<ReturnFenceUpdateCompletedValueCmd>(commands, size);
|
ReturnFenceUpdateCompletedValueCmd cmd;
|
||||||
if (cmd == nullptr) {
|
DeserializeResult deserializeResult = cmd.Deserialize(commands, size, &mAllocator);
|
||||||
|
|
||||||
|
if (deserializeResult == DeserializeResult::FatalError) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* fence = mDevice->fence.GetObject(cmd->fenceId);
|
auto* fence = mDevice->fence.GetObject(cmd.fence.id);
|
||||||
uint32_t fenceSerial = mDevice->fence.GetSerial(cmd->fenceId);
|
uint32_t fenceSerial = mDevice->fence.GetSerial(cmd.fence.id);
|
||||||
|
|
||||||
//* The fence might have been deleted or recreated so this isn't an error.
|
//* 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fence->completedValue = cmd->value;
|
fence->completedValue = cmd.value;
|
||||||
fence->CheckPassedFences();
|
fence->CheckPassedFences();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
//* See the License for the specific language governing permissions and
|
//* See the License for the specific language governing permissions and
|
||||||
//* limitations under the License.
|
//* limitations under the License.
|
||||||
|
|
||||||
#include "dawn_wire/WireCmd.h"
|
#include "dawn_wire/WireCmd_autogen.h"
|
||||||
|
|
||||||
#include "common/Assert.h"
|
#include "common/Assert.h"
|
||||||
|
|
||||||
|
@ -49,10 +49,14 @@
|
||||||
//* Outputs the serialization code to put `in` in `out`
|
//* Outputs the serialization code to put `in` in `out`
|
||||||
{% 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}});
|
{{out}} = provider.Get{{Optional}}Id({{in}});
|
||||||
{% elif member.type.category == "structure"%}
|
{%- elif member.type.category == "structure" -%}
|
||||||
{{as_cType(member.type.name)}}Serialize({{in}}, &{{out}}, buffer, provider);
|
{{as_cType(member.type.name)}}Serialize({{in}}, &{{out}}, buffer
|
||||||
|
{%- if member.type.has_dawn_object -%}
|
||||||
|
, provider
|
||||||
|
{%- endif -%}
|
||||||
|
);
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
{{out}} = {{in}};
|
{{out}} = {{in}};
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
|
@ -61,42 +65,34 @@
|
||||||
//* Outputs the deserialization code to put `in` in `out`
|
//* Outputs the deserialization code to put `in` in `out`
|
||||||
{% macro deserialize_member(member, in, out) %}
|
{% macro deserialize_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 "" -%}
|
||||||
DESERIALIZE_TRY(resolver.Get{{Optional}}FromId({{in}}, &{{out}}));
|
DESERIALIZE_TRY(resolver.Get{{Optional}}FromId({{in}}, &{{out}}));
|
||||||
{% elif member.type.category == "structure"%}
|
{%- elif member.type.category == "structure" -%}
|
||||||
DESERIALIZE_TRY({{as_cType(member.type.name)}}Deserialize(&{{out}}, &{{in}}, buffer, size, allocator, resolver));
|
DESERIALIZE_TRY({{as_cType(member.type.name)}}Deserialize(&{{out}}, &{{in}}, buffer, size, allocator
|
||||||
|
{%- if member.type.has_dawn_object -%}
|
||||||
|
, resolver
|
||||||
|
{%- endif -%}
|
||||||
|
));
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
{{out}} = {{in}};
|
{{out}} = {{in}};
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
//* The main [de]serialization macro
|
//* The main [de]serialization macro
|
||||||
|
|
||||||
//* Methods are very similar to structures that have one member corresponding to each arguments.
|
//* 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
|
//* 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.
|
//* 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 Return = "Return" if is_return_command else "" %}
|
||||||
{% set is_method = as_method != None %}
|
{% set Cmd = "Cmd" if is_cmd else "" %}
|
||||||
{% set is_struct = as_struct != None %}
|
|
||||||
|
|
||||||
//* Structure for the wire format of each of the records. Members that are values
|
//* 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
|
//* are embedded directly in the structure. Other members are assumed to be in the
|
||||||
//* memory directly following the structure in the buffer.
|
//* memory directly following the structure in the buffer.
|
||||||
struct {{name}}Transfer {
|
struct {{Return}}{{name}}Transfer {
|
||||||
{% if is_method %}
|
{% if is_cmd %}
|
||||||
//* Start the transfer structure with the command ID, so that casting to WireCmd gives the ID.
|
//* Start the transfer structure with the command ID, so that casting to WireCmd gives the ID.
|
||||||
{{Return}}WireCmd commandId;
|
{{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 %}
|
{% endif %}
|
||||||
|
|
||||||
//* Value types are directly in the command, objects being replaced with their IDs.
|
//* 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.
|
//* 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);
|
DAWN_UNUSED(record);
|
||||||
|
|
||||||
size_t result = 0;
|
size_t result = 0;
|
||||||
|
@ -140,24 +136,21 @@
|
||||||
}
|
}
|
||||||
// GetExtraRequiredSize isn't used for structures that are value members of other structures
|
// GetExtraRequiredSize isn't used for structures that are value members of other structures
|
||||||
// because we assume they cannot contain pointers themselves.
|
// 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
|
//* Serializes `record` into `transfer`, using `buffer` to get more space for pointed-to data
|
||||||
//* and `provider` to serialize objects.
|
//* and `provider` to serialize objects.
|
||||||
void {{name}}Serialize(const {{name}}& record, {{name}}Transfer* transfer,
|
void {{Return}}{{name}}Serialize(const {{Return}}{{name}}{{Cmd}}& record, {{Return}}{{name}}Transfer* transfer,
|
||||||
char** buffer, const ObjectIdProvider& provider) {
|
char** buffer
|
||||||
DAWN_UNUSED(provider);
|
{%- if record.has_dawn_object -%}
|
||||||
|
, const ObjectIdProvider& provider
|
||||||
|
{%- endif -%}
|
||||||
|
) {
|
||||||
DAWN_UNUSED(buffer);
|
DAWN_UNUSED(buffer);
|
||||||
|
|
||||||
//* Handle special transfer members of methods.
|
//* Handle special transfer members of methods.
|
||||||
{% if is_method %}
|
{% if is_cmd %}
|
||||||
{% if as_method.return_type.category == "object" %}
|
|
||||||
transfer->resultId = record.resultId;
|
|
||||||
transfer->resultSerial = record.resultSerial;
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
transfer->commandId = {{Return}}WireCmd::{{name}};
|
transfer->commandId = {{Return}}WireCmd::{{name}};
|
||||||
transfer->self = provider.GetId(record.self);
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
//* Value types are directly in the transfer record, objects being replaced with their IDs.
|
//* 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`
|
//* 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
|
//* if needed, using `allocator` to store pointed-to values and `resolver` to translate object
|
||||||
//* Ids to actual objects.
|
//* Ids to actual objects.
|
||||||
DeserializeResult {{name}}Deserialize({{name}}* record, const {{name}}Transfer* transfer,
|
DeserializeResult {{Return}}{{name}}Deserialize({{Return}}{{name}}{{Cmd}}* record, const {{Return}}{{name}}Transfer* transfer,
|
||||||
const char** buffer, size_t* size, DeserializeAllocator* allocator, const ObjectIdResolver& resolver) {
|
const char** buffer, size_t* size, DeserializeAllocator* allocator
|
||||||
|
{%- if record.has_dawn_object -%}
|
||||||
|
, const ObjectIdResolver& resolver
|
||||||
|
{%- endif -%}
|
||||||
|
) {
|
||||||
DAWN_UNUSED(allocator);
|
DAWN_UNUSED(allocator);
|
||||||
DAWN_UNUSED(resolver);
|
|
||||||
DAWN_UNUSED(buffer);
|
DAWN_UNUSED(buffer);
|
||||||
DAWN_UNUSED(size);
|
DAWN_UNUSED(size);
|
||||||
|
|
||||||
//* Handle special transfer members for methods
|
{% if is_cmd %}
|
||||||
{% if is_method %}
|
ASSERT(transfer->commandId == {{Return}}WireCmd::{{name}});
|
||||||
{% if as_method.return_type.category == "object" %}
|
|
||||||
record->resultId = transfer->resultId;
|
|
||||||
record->resultSerial = transfer->resultSerial;
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
ASSERT(transfer->commandId == {{Return}}WireCmd::{{name}});
|
//* 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 %}
|
||||||
|
//* 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;
|
record->selfId = transfer->self;
|
||||||
//* This conversion is done after the copying of result* and selfId: Deserialize
|
//* 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
|
//* guarantees they are filled even if there is an ID for an error object for the
|
||||||
//* Maybe monad mechanism.
|
//* Maybe monad mechanism.
|
||||||
DESERIALIZE_TRY(resolver.GetFromId(record->selfId, &record->self));
|
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
|
//* 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
|
//* meanings). However it is never valid to call a method on a null object so we
|
||||||
//* can error out in that case.
|
//* can error out in that case.
|
||||||
if (record->self == nullptr) {
|
if (record->self == nullptr) {
|
||||||
|
@ -224,7 +243,7 @@
|
||||||
}
|
}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if is_struct and as_struct.extensible %}
|
{% if record.extensible %}
|
||||||
record->nextInChain = nullptr;
|
record->nextInChain = nullptr;
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
@ -272,6 +291,47 @@
|
||||||
}
|
}
|
||||||
{% endmacro %}
|
{% 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 {
|
namespace dawn_wire {
|
||||||
|
|
||||||
// Macro to simplify error handling, similar to DAWN_TRY but for DeserializeResult.
|
// Macro to simplify error handling, similar to DAWN_TRY but for DeserializeResult.
|
||||||
|
@ -324,46 +384,35 @@ namespace dawn_wire {
|
||||||
return DeserializeResult::Success;
|
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"] %}
|
{% for type in by_category["structure"] %}
|
||||||
{% set name = as_cType(type.name) %}
|
{% 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 %}
|
{% endfor %}
|
||||||
|
|
||||||
// * Output [de]serialization helpers for methods
|
//* Output [de]serialization helpers for commands
|
||||||
{% for type in by_category["object"] %}
|
{% for command in cmd_records["command"] %}
|
||||||
{% for method in type.methods %}
|
{% set name = command.name.CamelCase() %}
|
||||||
{% set name = as_MethodSuffix(type.name, method.name) %}
|
{{write_record_serialization_helpers(command, name, command.members,
|
||||||
|
is_cmd=True, is_method=command.derived_method != None)}}
|
||||||
using {{name}} = {{name}}Cmd;
|
|
||||||
{{write_serialization_methods(name, method.arguments, as_method=method)}}
|
|
||||||
{% endfor %}
|
{% 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 %}
|
{% endfor %}
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
{% for type in by_category["object"] %}
|
{% for command in cmd_records["command"] %}
|
||||||
{% for method in type.methods %}
|
{{ write_command_serialization_methods(command, False) }}
|
||||||
{% set name = as_MethodSuffix(type.name, method.name) %}
|
|
||||||
{% set Cmd = name + "Cmd" %}
|
|
||||||
|
|
||||||
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 %}
|
{% endfor %}
|
||||||
|
|
||||||
|
{% for command in cmd_records["return command"] %}
|
||||||
|
{{ write_command_serialization_methods(command, True) }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
} // namespace dawn_wire
|
} // namespace dawn_wire
|
||||||
|
|
|
@ -15,10 +15,16 @@
|
||||||
#ifndef DAWNWIRE_WIRECMD_AUTOGEN_H_
|
#ifndef DAWNWIRE_WIRECMD_AUTOGEN_H_
|
||||||
#define DAWNWIRE_WIRECMD_AUTOGEN_H_
|
#define DAWNWIRE_WIRECMD_AUTOGEN_H_
|
||||||
|
|
||||||
|
#include <dawn/dawn.h>
|
||||||
|
|
||||||
namespace dawn_wire {
|
namespace dawn_wire {
|
||||||
|
|
||||||
using ObjectId = uint32_t;
|
using ObjectId = uint32_t;
|
||||||
using ObjectSerial = uint32_t;
|
using ObjectSerial = uint32_t;
|
||||||
|
struct ObjectHandle {
|
||||||
|
ObjectId id;
|
||||||
|
ObjectSerial serial;
|
||||||
|
};
|
||||||
|
|
||||||
enum class DeserializeResult {
|
enum class DeserializeResult {
|
||||||
Success,
|
Success,
|
||||||
|
@ -61,30 +67,32 @@ namespace dawn_wire {
|
||||||
|
|
||||||
//* Enum used as a prefix to each command on the wire format.
|
//* Enum used as a prefix to each command on the wire format.
|
||||||
enum class WireCmd : uint32_t {
|
enum class WireCmd : uint32_t {
|
||||||
{% for type in by_category["object"] %}
|
{% for command in cmd_records["command"] %}
|
||||||
{% for method in type.methods %}
|
{{command.name.CamelCase()}},
|
||||||
{{as_MethodSuffix(type.name, method.name)}},
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endfor %}
|
|
||||||
BufferMapAsync,
|
|
||||||
BufferUpdateMappedDataCmd,
|
|
||||||
DestroyObject,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
{% for type in by_category["object"] %}
|
//* Enum used as a prefix to each command on the return wire format.
|
||||||
{% for method in type.methods %}
|
enum class ReturnWireCmd : uint32_t {
|
||||||
{% set Suffix = as_MethodSuffix(type.name, method.name) %}
|
{% for command in cmd_records["return command"] %}
|
||||||
{% set Cmd = Suffix + "Cmd" %}
|
{{command.name.CamelCase()}},
|
||||||
|
{% endfor %}
|
||||||
|
};
|
||||||
|
|
||||||
//* These are "structure" version of the list of arguments to the different Dawn methods.
|
{% macro write_command_struct(command, is_return_command) %}
|
||||||
//* They provide helpers to serialize/deserialize to/from a buffer.
|
{% set Return = "Return" if is_return_command else "" %}
|
||||||
struct {{Cmd}} {
|
{% set Cmd = command.name.CamelCase() + "Cmd" %}
|
||||||
|
struct {{Return}}{{Cmd}} {
|
||||||
//* From a filled structure, compute how much size will be used in the serialization buffer.
|
//* From a filled structure, compute how much size will be used in the serialization buffer.
|
||||||
size_t GetRequiredSize() const;
|
size_t GetRequiredSize() const;
|
||||||
|
|
||||||
//* 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).
|
||||||
void Serialize(char* serializeBuffer, const ObjectIdProvider& objectIdProvider) const;
|
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
|
//* 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
|
||||||
|
@ -97,48 +105,30 @@ namespace dawn_wire {
|
||||||
//* of the Maybe monad.
|
//* of the Maybe monad.
|
||||||
//* If the return value is not FatalError, selfId, resultId and resultSerial (if present) are
|
//* If the return value is not FatalError, selfId, resultId and resultSerial (if present) are
|
||||||
//* filled.
|
//* filled.
|
||||||
DeserializeResult Deserialize(const char** buffer, size_t* size, DeserializeAllocator* allocator, const ObjectIdResolver& resolver);
|
DeserializeResult Deserialize(const char** buffer, size_t* size, DeserializeAllocator* allocator
|
||||||
|
{%- if command.has_dawn_object -%}
|
||||||
{{as_cType(type.name)}} self;
|
, const ObjectIdResolver& resolver
|
||||||
|
{%- endif -%}
|
||||||
|
);
|
||||||
|
|
||||||
|
{% if command.derived_method %}
|
||||||
//* Command handlers want to know the object ID in addition to the backing object.
|
//* Command handlers want to know the object ID in addition to the backing object.
|
||||||
//* Doesn't need to be filled before Serialize, or GetRequiredSize.
|
//* Doesn't need to be filled before Serialize, or GetRequiredSize.
|
||||||
ObjectId selfId;
|
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 %}
|
{% endif %}
|
||||||
|
|
||||||
{% for arg in method.arguments %}
|
{% for member in command.members %}
|
||||||
{{as_annotated_cType(arg)}};
|
{{as_annotated_cType(member)}};
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
};
|
};
|
||||||
{% endfor %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% for command in cmd_records["command"] %}
|
||||||
|
{{write_command_struct(command, False)}}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
//* Enum used as a prefix to each command on the return wire format.
|
{% for command in cmd_records["return command"] %}
|
||||||
enum class ReturnWireCmd : uint32_t {
|
{{write_command_struct(command, True)}}
|
||||||
DeviceErrorCallback,
|
|
||||||
{% for type in by_category["object"] if type.is_builder %}
|
|
||||||
{{type.name.CamelCase()}}ErrorCallback,
|
|
||||||
{% 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;
|
|
||||||
|
|
||||||
ObjectId builtObjectId;
|
|
||||||
ObjectSerial builtObjectSerial;
|
|
||||||
uint32_t status;
|
|
||||||
size_t messageStrlen;
|
|
||||||
};
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
} // namespace dawn_wire
|
} // namespace dawn_wire
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
|
|
||||||
#include "dawn_wire/TypeTraits_autogen.h"
|
#include "dawn_wire/TypeTraits_autogen.h"
|
||||||
#include "dawn_wire/Wire.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"
|
#include "common/Assert.h"
|
||||||
|
|
||||||
|
@ -32,8 +33,7 @@ namespace dawn_wire {
|
||||||
|
|
||||||
struct MapUserdata {
|
struct MapUserdata {
|
||||||
Server* server;
|
Server* server;
|
||||||
uint32_t bufferId;
|
ObjectHandle buffer;
|
||||||
uint32_t bufferSerial;
|
|
||||||
uint32_t requestSerial;
|
uint32_t requestSerial;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
bool isWrite;
|
bool isWrite;
|
||||||
|
@ -41,8 +41,7 @@ namespace dawn_wire {
|
||||||
|
|
||||||
struct FenceCompletionUserdata {
|
struct FenceCompletionUserdata {
|
||||||
Server* server;
|
Server* server;
|
||||||
uint32_t fenceId;
|
ObjectHandle fence;
|
||||||
uint32_t fenceSerial;
|
|
||||||
uint64_t value;
|
uint64_t value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -69,8 +68,7 @@ namespace dawn_wire {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct ObjectData<T, true> : public ObjectDataBase<T> {
|
struct ObjectData<T, true> : public ObjectDataBase<T> {
|
||||||
uint32_t builtObjectId = 0;
|
ObjectHandle builtObject = ObjectHandle{0, 0};
|
||||||
uint32_t builtObjectSerial = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
@ -214,59 +212,6 @@ namespace dawn_wire {
|
||||||
void ForwardFenceCompletedValue(dawnFenceCompletionStatus status,
|
void ForwardFenceCompletedValue(dawnFenceCompletionStatus status,
|
||||||
dawnCallbackUserdata userdata);
|
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 {
|
class Server : public CommandHandler, public ObjectIdResolver {
|
||||||
public:
|
public:
|
||||||
Server(dawnDevice device, const dawnProcTable& procs, CommandSerializer* serializer)
|
Server(dawnDevice device, const dawnProcTable& procs, CommandSerializer* serializer)
|
||||||
|
@ -294,13 +239,11 @@ namespace dawn_wire {
|
||||||
|
|
||||||
void OnDeviceError(const char* message) {
|
void OnDeviceError(const char* message) {
|
||||||
ReturnDeviceErrorCallbackCmd cmd;
|
ReturnDeviceErrorCallbackCmd cmd;
|
||||||
cmd.messageStrlen = std::strlen(message);
|
cmd.message = message;
|
||||||
|
|
||||||
auto allocCmd = static_cast<ReturnDeviceErrorCallbackCmd*>(GetCmdSpace(sizeof(cmd)));
|
size_t requiredSize = cmd.GetRequiredSize();
|
||||||
*allocCmd = cmd;
|
char* allocatedBuffer = static_cast<char*>(GetCmdSpace(requiredSize));
|
||||||
|
cmd.Serialize(allocatedBuffer);
|
||||||
char* messageAlloc = static_cast<char*>(GetCmdSpace(cmd.messageStrlen + 1));
|
|
||||||
strcpy(messageAlloc, message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{% for type in by_category["object"] if type.is_builder%}
|
{% for type in by_category["object"] if type.is_builder%}
|
||||||
|
@ -319,18 +262,16 @@ namespace dawn_wire {
|
||||||
if (status != DAWN_BUILDER_ERROR_STATUS_UNKNOWN) {
|
if (status != DAWN_BUILDER_ERROR_STATUS_UNKNOWN) {
|
||||||
//* Unknown is the only status that can be returned without a call to GetResult
|
//* Unknown is the only status that can be returned without a call to GetResult
|
||||||
//* so we are guaranteed to have created an object.
|
//* so we are guaranteed to have created an object.
|
||||||
ASSERT(builder->builtObjectId != 0);
|
ASSERT(builder->builtObject.id != 0);
|
||||||
|
|
||||||
Return{{Type}}ErrorCallbackCmd cmd;
|
Return{{Type}}ErrorCallbackCmd cmd;
|
||||||
cmd.builtObjectId = builder->builtObjectId;
|
cmd.builtObject = builder->builtObject;
|
||||||
cmd.builtObjectSerial = builder->builtObjectSerial;
|
|
||||||
cmd.status = status;
|
cmd.status = status;
|
||||||
cmd.messageStrlen = std::strlen(message);
|
cmd.message = message;
|
||||||
|
|
||||||
auto allocCmd = static_cast<Return{{Type}}ErrorCallbackCmd*>(GetCmdSpace(sizeof(cmd)));
|
size_t requiredSize = cmd.GetRequiredSize();
|
||||||
*allocCmd = cmd;
|
char* allocatedBuffer = static_cast<char*>(GetCmdSpace(requiredSize));
|
||||||
char* messageAlloc = static_cast<char*>(GetCmdSpace(strlen(message) + 1));
|
cmd.Serialize(allocatedBuffer);
|
||||||
strcpy(messageAlloc, message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -339,46 +280,44 @@ namespace dawn_wire {
|
||||||
std::unique_ptr<MapUserdata> data(userdata);
|
std::unique_ptr<MapUserdata> data(userdata);
|
||||||
|
|
||||||
// Skip sending the callback if the buffer has already been destroyed.
|
// Skip sending the callback if the buffer has already been destroyed.
|
||||||
auto* bufferData = mKnownBuffer.Get(data->bufferId);
|
auto* bufferData = mKnownBuffer.Get(data->buffer.id);
|
||||||
if (bufferData == nullptr || bufferData->serial != data->bufferSerial) {
|
if (bufferData == nullptr || bufferData->serial != data->buffer.serial) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnBufferMapReadAsyncCallbackCmd cmd;
|
ReturnBufferMapReadAsyncCallbackCmd cmd;
|
||||||
cmd.bufferId = data->bufferId;
|
cmd.buffer = data->buffer;
|
||||||
cmd.bufferSerial = data->bufferSerial;
|
|
||||||
cmd.requestSerial = data->requestSerial;
|
cmd.requestSerial = data->requestSerial;
|
||||||
cmd.status = status;
|
cmd.status = status;
|
||||||
cmd.dataLength = 0;
|
cmd.dataLength = 0;
|
||||||
|
cmd.data = reinterpret_cast<const uint8_t*>(ptr);
|
||||||
auto allocCmd = static_cast<ReturnBufferMapReadAsyncCallbackCmd*>(GetCmdSpace(sizeof(cmd)));
|
|
||||||
*allocCmd = cmd;
|
|
||||||
|
|
||||||
if (status == DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS) {
|
if (status == DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS) {
|
||||||
allocCmd->dataLength = data->size;
|
cmd.dataLength = data->size;
|
||||||
|
|
||||||
void* dataAlloc = GetCmdSpace(data->size);
|
|
||||||
memcpy(dataAlloc, ptr, 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) {
|
void OnMapWriteAsyncCallback(dawnBufferMapAsyncStatus status, void* ptr, MapUserdata* userdata) {
|
||||||
std::unique_ptr<MapUserdata> data(userdata);
|
std::unique_ptr<MapUserdata> data(userdata);
|
||||||
|
|
||||||
// Skip sending the callback if the buffer has already been destroyed.
|
// Skip sending the callback if the buffer has already been destroyed.
|
||||||
auto* bufferData = mKnownBuffer.Get(data->bufferId);
|
auto* bufferData = mKnownBuffer.Get(data->buffer.id);
|
||||||
if (bufferData == nullptr || bufferData->serial != data->bufferSerial) {
|
if (bufferData == nullptr || bufferData->serial != data->buffer.serial) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnBufferMapWriteAsyncCallbackCmd cmd;
|
ReturnBufferMapWriteAsyncCallbackCmd cmd;
|
||||||
cmd.bufferId = data->bufferId;
|
cmd.buffer = data->buffer;
|
||||||
cmd.bufferSerial = data->bufferSerial;
|
|
||||||
cmd.requestSerial = data->requestSerial;
|
cmd.requestSerial = data->requestSerial;
|
||||||
cmd.status = status;
|
cmd.status = status;
|
||||||
|
|
||||||
auto allocCmd = static_cast<ReturnBufferMapWriteAsyncCallbackCmd*>(GetCmdSpace(sizeof(cmd)));
|
size_t requiredSize = cmd.GetRequiredSize();
|
||||||
*allocCmd = cmd;
|
char* allocatedBuffer = static_cast<char*>(GetCmdSpace(requiredSize));
|
||||||
|
cmd.Serialize(allocatedBuffer);
|
||||||
|
|
||||||
if (status == DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS) {
|
if (status == DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS) {
|
||||||
bufferData->mappedData = ptr;
|
bufferData->mappedData = ptr;
|
||||||
|
@ -390,15 +329,14 @@ namespace dawn_wire {
|
||||||
std::unique_ptr<FenceCompletionUserdata> data(userdata);
|
std::unique_ptr<FenceCompletionUserdata> data(userdata);
|
||||||
|
|
||||||
ReturnFenceUpdateCompletedValueCmd cmd;
|
ReturnFenceUpdateCompletedValueCmd cmd;
|
||||||
cmd.fenceId = data->fenceId;
|
cmd.fence = data->fence;
|
||||||
cmd.fenceSerial = data->fenceSerial;
|
|
||||||
cmd.value = data->value;
|
cmd.value = data->value;
|
||||||
|
|
||||||
auto allocCmd = static_cast<ReturnFenceUpdateCompletedValueCmd*>(GetCmdSpace(sizeof(cmd)));
|
size_t requiredSize = cmd.GetRequiredSize();
|
||||||
*allocCmd = cmd;
|
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 {
|
const char* HandleCommands(const char* commands, size_t size) override {
|
||||||
mProcs.deviceTick(mKnownDevice.Get(1)->handle);
|
mProcs.deviceTick(mKnownDevice.Get(1)->handle);
|
||||||
|
|
||||||
|
@ -407,25 +345,11 @@ namespace dawn_wire {
|
||||||
|
|
||||||
bool success = false;
|
bool success = false;
|
||||||
switch (cmdId) {
|
switch (cmdId) {
|
||||||
{% for type in by_category["object"] %}
|
{% for command in cmd_records["command"] %}
|
||||||
{% for method in type.methods %}
|
case WireCmd::{{command.name.CamelCase()}}:
|
||||||
{% set Suffix = as_MethodSuffix(type.name, method.name) %}
|
success = Handle{{command.name.CamelCase()}}(&commands, &size);
|
||||||
{% if Suffix not in client_side_commands %}
|
|
||||||
case WireCmd::{{Suffix}}:
|
|
||||||
success = Handle{{Suffix}}(&commands, &size);
|
|
||||||
break;
|
break;
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% 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:
|
default:
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
@ -447,7 +371,7 @@ namespace dawn_wire {
|
||||||
dawnProcTable mProcs;
|
dawnProcTable mProcs;
|
||||||
CommandSerializer* mSerializer = nullptr;
|
CommandSerializer* mSerializer = nullptr;
|
||||||
|
|
||||||
ServerAllocator mAllocator;
|
WireDeserializeAllocator mAllocator;
|
||||||
|
|
||||||
void* GetCmdSpace(size_t size) {
|
void* GetCmdSpace(size_t size) {
|
||||||
return mSerializer->GetCmdSpace(size);
|
return mSerializer->GetCmdSpace(size);
|
||||||
|
@ -484,36 +408,10 @@ namespace dawn_wire {
|
||||||
KnownObjects<{{as_cType(type.name)}}> mKnown{{type.name.CamelCase()}};
|
KnownObjects<{{as_cType(type.name)}}> mKnown{{type.name.CamelCase()}};
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
{% set reverse_lookup_object_types = ["Fence"] %}
|
{% for type in by_category["object"] if type.name.CamelCase() in server_reverse_lookup_objects %}
|
||||||
{% for type in by_category["object"] if type.name.CamelCase() in reverse_lookup_object_types %}
|
|
||||||
ObjectIdLookupTable<{{as_cType(type.name)}}> m{{type.name.CamelCase()}}IdTable;
|
ObjectIdLookupTable<{{as_cType(type.name)}}> m{{type.name.CamelCase()}}IdTable;
|
||||||
{% endfor %}
|
{% 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) {
|
bool PreHandleBufferUnmap(const BufferUnmapCmd& cmd) {
|
||||||
auto* selfData = mKnownBuffer.Get(cmd.selfId);
|
auto* selfData = mKnownBuffer.Get(cmd.selfId);
|
||||||
ASSERT(selfData != nullptr);
|
ASSERT(selfData != nullptr);
|
||||||
|
@ -523,8 +421,6 @@ namespace dawn_wire {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
{% set custom_post_handler_commands = ["QueueSignal"] %}
|
|
||||||
|
|
||||||
bool PostHandleQueueSignal(const QueueSignalCmd& cmd) {
|
bool PostHandleQueueSignal(const QueueSignalCmd& cmd) {
|
||||||
if (cmd.fence == nullptr) {
|
if (cmd.fence == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -536,8 +432,7 @@ namespace dawn_wire {
|
||||||
|
|
||||||
auto* data = new FenceCompletionUserdata;
|
auto* data = new FenceCompletionUserdata;
|
||||||
data->server = this;
|
data->server = this;
|
||||||
data->fenceId = fenceId;
|
data->fence = ObjectHandle{fenceId, fence->serial};
|
||||||
data->fenceSerial = fence->serial;
|
|
||||||
data->value = cmd.signalValue;
|
data->value = cmd.signalValue;
|
||||||
|
|
||||||
auto userdata = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(data));
|
auto userdata = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(data));
|
||||||
|
@ -560,7 +455,7 @@ namespace dawn_wire {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
{% if Suffix in custom_pre_handler_commands %}
|
{% if Suffix in server_custom_pre_handler_commands %}
|
||||||
if (!PreHandle{{Suffix}}(cmd)) {
|
if (!PreHandle{{Suffix}}(cmd)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -575,15 +470,14 @@ namespace dawn_wire {
|
||||||
{% set returns = return_type.name.canonical_case() != "void" %}
|
{% set returns = return_type.name.canonical_case() != "void" %}
|
||||||
{% if returns %}
|
{% if returns %}
|
||||||
{% set Type = method.return_type.name.CamelCase() %}
|
{% 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) {
|
if (resultData == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
resultData->serial = cmd.resultSerial;
|
resultData->serial = cmd.result.serial;
|
||||||
|
|
||||||
{% if type.is_builder %}
|
{% if type.is_builder %}
|
||||||
selfData->builtObjectId = cmd.resultId;
|
selfData->builtObject = cmd.result;
|
||||||
selfData->builtObjectSerial = cmd.resultSerial;
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
@ -608,7 +502,7 @@ namespace dawn_wire {
|
||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
);
|
);
|
||||||
|
|
||||||
{% if Suffix in custom_post_handler_commands %}
|
{% if Suffix in server_custom_post_handler_commands %}
|
||||||
if (!PostHandle{{Suffix}}(cmd)) {
|
if (!PostHandle{{Suffix}}(cmd)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -618,10 +512,10 @@ namespace dawn_wire {
|
||||||
resultData->handle = result;
|
resultData->handle = result;
|
||||||
resultData->valid = result != nullptr;
|
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
|
//* For created objects, store a mapping from them back to their client IDs
|
||||||
if (result) {
|
if (result) {
|
||||||
m{{return_type.name.CamelCase()}}IdTable.Store(result, cmd.resultId);
|
m{{return_type.name.CamelCase()}}IdTable.Store(result, cmd.result.id);
|
||||||
}
|
}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
@ -630,7 +524,7 @@ namespace dawn_wire {
|
||||||
{% if return_type.is_builder %}
|
{% if return_type.is_builder %}
|
||||||
if (result != nullptr) {
|
if (result != nullptr) {
|
||||||
uint64_t userdata1 = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(this));
|
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);
|
mProcs.{{as_varName(return_type.name, Name("set error callback"))}}(result, Forward{{return_type.name.CamelCase()}}ToClient, userdata1, userdata2);
|
||||||
}
|
}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -645,16 +539,18 @@ namespace dawn_wire {
|
||||||
bool HandleBufferMapAsync(const char** commands, size_t* size) {
|
bool HandleBufferMapAsync(const char** commands, size_t* size) {
|
||||||
//* These requests are just forwarded to the buffer, with userdata containing what the client
|
//* These requests are just forwarded to the buffer, with userdata containing what the client
|
||||||
//* will require in the return command.
|
//* will require in the return command.
|
||||||
const auto* cmd = GetCommand<BufferMapAsyncCmd>(commands, size);
|
BufferMapAsyncCmd cmd;
|
||||||
if (cmd == nullptr) {
|
DeserializeResult deserializeResult = cmd.Deserialize(commands, size, &mAllocator);
|
||||||
|
|
||||||
|
if (deserializeResult == DeserializeResult::FatalError) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectId bufferId = cmd->bufferId;
|
ObjectId bufferId = cmd.bufferId;
|
||||||
uint32_t requestSerial = cmd->requestSerial;
|
uint32_t requestSerial = cmd.requestSerial;
|
||||||
uint32_t requestSize = cmd->size;
|
uint32_t requestSize = cmd.size;
|
||||||
uint32_t requestStart = cmd->start;
|
uint32_t requestStart = cmd.start;
|
||||||
bool isWrite = cmd->isWrite;
|
bool isWrite = cmd.isWrite;
|
||||||
|
|
||||||
//* The null object isn't valid as `self`
|
//* The null object isn't valid as `self`
|
||||||
if (bufferId == 0) {
|
if (bufferId == 0) {
|
||||||
|
@ -668,8 +564,7 @@ namespace dawn_wire {
|
||||||
|
|
||||||
auto* data = new MapUserdata;
|
auto* data = new MapUserdata;
|
||||||
data->server = this;
|
data->server = this;
|
||||||
data->bufferId = bufferId;
|
data->buffer = ObjectHandle{bufferId, buffer->serial};
|
||||||
data->bufferSerial = buffer->serial;
|
|
||||||
data->requestSerial = requestSerial;
|
data->requestSerial = requestSerial;
|
||||||
data->size = requestSize;
|
data->size = requestSize;
|
||||||
data->isWrite = isWrite;
|
data->isWrite = isWrite;
|
||||||
|
@ -696,13 +591,15 @@ namespace dawn_wire {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HandleBufferUpdateMappedData(const char** commands, size_t* size) {
|
bool HandleBufferUpdateMappedData(const char** commands, size_t* size) {
|
||||||
const auto* cmd = GetCommand<BufferUpdateMappedDataCmd>(commands, size);
|
BufferUpdateMappedDataCmd cmd;
|
||||||
if (cmd == nullptr) {
|
DeserializeResult deserializeResult = cmd.Deserialize(commands, size, &mAllocator);
|
||||||
|
|
||||||
|
if (deserializeResult == DeserializeResult::FatalError) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectId bufferId = cmd->bufferId;
|
ObjectId bufferId = cmd.bufferId;
|
||||||
size_t dataLength = cmd->dataLength;
|
size_t dataLength = cmd.dataLength;
|
||||||
|
|
||||||
//* The null object isn't valid as `self`
|
//* The null object isn't valid as `self`
|
||||||
if (bufferId == 0) {
|
if (bufferId == 0) {
|
||||||
|
@ -715,29 +612,28 @@ namespace dawn_wire {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* data = GetData<char>(commands, size, dataLength);
|
DAWN_ASSERT(cmd.data != nullptr);
|
||||||
if (data == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(buffer->mappedData, data, dataLength);
|
memcpy(buffer->mappedData, cmd.data, dataLength);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HandleDestroyObject(const char** commands, size_t* size) {
|
bool HandleDestroyObject(const char** commands, size_t* size) {
|
||||||
const auto* cmd = GetCommand<DestroyObjectCmd>(commands, size);
|
DestroyObjectCmd cmd;
|
||||||
if (cmd == nullptr) {
|
DeserializeResult deserializeResult = cmd.Deserialize(commands, size, &mAllocator);
|
||||||
|
|
||||||
|
if (deserializeResult == DeserializeResult::FatalError) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectId objectId = cmd->objectId;
|
ObjectId objectId = cmd.objectId;
|
||||||
//* ID 0 are reserved for nullptr and cannot be destroyed.
|
//* ID 0 are reserved for nullptr and cannot be destroyed.
|
||||||
if (objectId == 0) {
|
if (objectId == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (cmd->objectType) {
|
switch (cmd.objectType) {
|
||||||
{% for type in by_category["object"] %}
|
{% for type in by_category["object"] %}
|
||||||
{% set ObjectType = type.name.CamelCase() %}
|
{% set ObjectType = type.name.CamelCase() %}
|
||||||
case ObjectType::{{ObjectType}}: {
|
case ObjectType::{{ObjectType}}: {
|
||||||
|
@ -749,7 +645,7 @@ namespace dawn_wire {
|
||||||
if (data == nullptr) {
|
if (data == nullptr) {
|
||||||
return false;
|
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);
|
m{{type.name.CamelCase()}}IdTable.Remove(data->handle);
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
from collections import namedtuple
|
||||||
|
from common import Name
|
||||||
|
import common
|
||||||
|
|
||||||
|
def concat_names(*names):
|
||||||
|
return ' '.join([name.canonical_case() for name in names])
|
||||||
|
|
||||||
|
# Create wire commands from api methods
|
||||||
|
def compute_wire_params(api_params, wire_json):
|
||||||
|
wire_params = api_params.copy()
|
||||||
|
types = wire_params['types']
|
||||||
|
|
||||||
|
commands = []
|
||||||
|
return_commands = []
|
||||||
|
|
||||||
|
object_result_member = common.RecordMember(Name('result'), types['ObjectHandle'], 'value', False, True)
|
||||||
|
|
||||||
|
string_message_member = common.RecordMember(Name('message'), types['char'], 'const*', False, False)
|
||||||
|
string_message_member.length = 'strlen'
|
||||||
|
|
||||||
|
built_object_member = common.RecordMember(Name('built object'), types['ObjectHandle'], 'value', False, False)
|
||||||
|
|
||||||
|
callback_status_member = common.RecordMember(Name('status'), types['uint32_t'], 'value', False, False)
|
||||||
|
|
||||||
|
# Generate commands from object methods
|
||||||
|
for api_object in wire_params['by_category']['object']:
|
||||||
|
for method in api_object.methods:
|
||||||
|
if method.return_type.category != 'object' and method.return_type.name.canonical_case() != 'void':
|
||||||
|
# No other return types supported
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Create object method commands by prepending "self"
|
||||||
|
members = [common.RecordMember(Name('self'), types[api_object.dict_name], 'value', False, False)]
|
||||||
|
|
||||||
|
members += method.arguments
|
||||||
|
|
||||||
|
# Client->Server commands that return an object return the result object handle
|
||||||
|
if method.return_type.category == 'object':
|
||||||
|
members.append(object_result_member)
|
||||||
|
|
||||||
|
command_name = concat_names(api_object.name, method.name)
|
||||||
|
command = common.Command(command_name, members)
|
||||||
|
|
||||||
|
command.derived_object = api_object
|
||||||
|
command.derived_method = method
|
||||||
|
commands.append(command)
|
||||||
|
|
||||||
|
# Create builder return ErrorCallback commands
|
||||||
|
# This can be removed when WebGPU error handling is implemented
|
||||||
|
if api_object.is_builder:
|
||||||
|
command_name = concat_names(api_object.name, Name('error callback'))
|
||||||
|
|
||||||
|
command = common.Command(command_name, [
|
||||||
|
built_object_member,
|
||||||
|
callback_status_member,
|
||||||
|
string_message_member,
|
||||||
|
])
|
||||||
|
command.derived_object = api_object
|
||||||
|
return_commands.append(command)
|
||||||
|
|
||||||
|
for (name, json_data) in wire_json['commands'].items():
|
||||||
|
commands.append(common.Command(name, common.linked_record_members(json_data, types)))
|
||||||
|
|
||||||
|
for (name, json_data) in wire_json['return commands'].items():
|
||||||
|
return_commands.append(common.Command(name, common.linked_record_members(json_data, types)))
|
||||||
|
|
||||||
|
wire_params['cmd_records'] = {
|
||||||
|
'command': commands,
|
||||||
|
'return command': return_commands
|
||||||
|
}
|
||||||
|
|
||||||
|
for commands in wire_params['cmd_records'].values():
|
||||||
|
for command in commands:
|
||||||
|
command.update_metadata()
|
||||||
|
commands.sort(key=lambda c: c.name.canonical_case())
|
||||||
|
|
||||||
|
wire_params.update(wire_json.get('special items', {}))
|
||||||
|
|
||||||
|
return wire_params
|
|
@ -1,83 +0,0 @@
|
||||||
// Copyright 2017 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.
|
|
||||||
|
|
||||||
#ifndef DAWNWIRE_WIRECMD_H_
|
|
||||||
#define DAWNWIRE_WIRECMD_H_
|
|
||||||
|
|
||||||
#include <dawn/dawn.h>
|
|
||||||
|
|
||||||
#include "dawn_wire/WireCmd_autogen.h"
|
|
||||||
|
|
||||||
namespace dawn_wire {
|
|
||||||
|
|
||||||
struct ReturnDeviceErrorCallbackCmd {
|
|
||||||
ReturnWireCmd commandId = ReturnWireCmd::DeviceErrorCallback;
|
|
||||||
|
|
||||||
size_t messageStrlen;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BufferMapAsyncCmd {
|
|
||||||
WireCmd commandId = WireCmd::BufferMapAsync;
|
|
||||||
|
|
||||||
ObjectId bufferId;
|
|
||||||
ObjectSerial requestSerial;
|
|
||||||
uint32_t start;
|
|
||||||
uint32_t size;
|
|
||||||
bool isWrite;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ReturnBufferMapReadAsyncCallbackCmd {
|
|
||||||
ReturnWireCmd commandId = ReturnWireCmd::BufferMapReadAsyncCallback;
|
|
||||||
|
|
||||||
ObjectId bufferId;
|
|
||||||
ObjectSerial bufferSerial;
|
|
||||||
uint32_t requestSerial;
|
|
||||||
uint32_t status;
|
|
||||||
uint32_t dataLength;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ReturnBufferMapWriteAsyncCallbackCmd {
|
|
||||||
ReturnWireCmd commandId = ReturnWireCmd::BufferMapWriteAsyncCallback;
|
|
||||||
|
|
||||||
ObjectId bufferId;
|
|
||||||
ObjectSerial bufferSerial;
|
|
||||||
uint32_t requestSerial;
|
|
||||||
uint32_t status;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ReturnFenceUpdateCompletedValueCmd {
|
|
||||||
ReturnWireCmd commandId = ReturnWireCmd::FenceUpdateCompletedValue;
|
|
||||||
|
|
||||||
ObjectId fenceId;
|
|
||||||
ObjectSerial fenceSerial;
|
|
||||||
uint64_t value;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BufferUpdateMappedDataCmd {
|
|
||||||
WireCmd commandId = WireCmd::BufferUpdateMappedDataCmd;
|
|
||||||
|
|
||||||
ObjectId bufferId;
|
|
||||||
uint32_t dataLength;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DestroyObjectCmd {
|
|
||||||
WireCmd commandId = WireCmd::DestroyObject;
|
|
||||||
|
|
||||||
ObjectType objectType;
|
|
||||||
ObjectId objectId;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace dawn_wire
|
|
||||||
|
|
||||||
#endif // DAWNWIRE_WIRECMD_H_
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
// 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 "dawn_wire/WireDeserializeAllocator.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace dawn_wire {
|
||||||
|
WireDeserializeAllocator::WireDeserializeAllocator() {
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
WireDeserializeAllocator::~WireDeserializeAllocator() {
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void* WireDeserializeAllocator::GetSpace(size_t size) {
|
||||||
|
// 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 WireDeserializeAllocator::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);
|
||||||
|
}
|
||||||
|
} // namespace dawn_wire
|
|
@ -0,0 +1,43 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#ifndef DAWNWIRE_WIREDESERIALIZEALLOCATOR_H_
|
||||||
|
#define DAWNWIRE_WIREDESERIALIZEALLOCATOR_H_
|
||||||
|
|
||||||
|
#include "dawn_wire/WireCmd_autogen.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace dawn_wire {
|
||||||
|
// 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 WireDeserializeAllocator : public DeserializeAllocator {
|
||||||
|
public:
|
||||||
|
WireDeserializeAllocator();
|
||||||
|
~WireDeserializeAllocator();
|
||||||
|
|
||||||
|
void* GetSpace(size_t size) override;
|
||||||
|
|
||||||
|
void Reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t mRemainingSize = 0;
|
||||||
|
char* mCurrentBuffer = nullptr;
|
||||||
|
char mStaticBuffer[2048];
|
||||||
|
std::vector<char*> mAllocations;
|
||||||
|
};
|
||||||
|
} // namespace dawn_wire
|
||||||
|
|
||||||
|
#endif // DAWNWIRE_WIREDESERIALIZEALLOCATOR_H_
|
Loading…
Reference in New Issue