glthread: add option to put autogenerated marshal structures in the header file

This is used when we want to be able to read the calls of autogenerated
functions, or when we want to use the default structure for our custom
marshal functions.

Reviewed-by: Timothy Arceri <tarceri@itsqueeze.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26548>
This commit is contained in:
Marek Olšák 2023-11-27 21:51:47 -05:00 committed by Marge Bot
parent bdb771b27c
commit a02ed8a95f
4 changed files with 106 additions and 83 deletions

View file

@ -44,6 +44,7 @@
marshal_count CDATA #IMPLIED>
marshal_call_before CDATA #IMPLIED>
marshal_call_after CDATA #IMPLIED>
marshal_struct CDATA #IMPLIED>
<!ATTLIST size name NMTOKEN #REQUIRED
count NMTOKEN #IMPLIED
mode (get | set) "set">
@ -138,6 +139,10 @@ param:
marshal_call_before - insert the string at the beginning of the marshal
function
marshal_call_after - insert the string at the end of the marshal function
marshal_struct - if "public", insert the structure into the generated
header file instead of the C file. It's done even with
marshal="custom", in which case you don't have to define the structure
manually.
glx:
rop - Opcode value for "render" commands

View file

@ -103,91 +103,12 @@ class PrintCode(gl_XML.gl_print_base):
out('')
out('')
def get_type_size(self, str):
if str.find('*') != -1:
return 8;
mapping = {
'GLboolean': 1,
'GLbyte': 1,
'GLubyte': 1,
'GLenum': 2, # uses GLenum16, clamped to 0xffff (invalid enum)
'GLshort': 2,
'GLushort': 2,
'GLhalfNV': 2,
'GLint': 4,
'GLuint': 4,
'GLbitfield': 4,
'GLsizei': 4,
'GLfloat': 4,
'GLclampf': 4,
'GLfixed': 4,
'GLclampx': 4,
'GLhandleARB': 4,
'int': 4,
'float': 4,
'GLdouble': 8,
'GLclampd': 8,
'GLintptr': 8,
'GLsizeiptr': 8,
'GLint64': 8,
'GLuint64': 8,
'GLuint64EXT': 8,
'GLsync': 8,
}
val = mapping.get(str, 9999)
if val == 9999:
print('Unhandled type in gl_marshal.py.get_type_size: ' + str, file=sys.stderr)
assert False
return val
def print_async_body(self, func):
# We want glthread to ignore variable-sized parameters if the only thing
# we want is to pass the pointer parameter as-is, e.g. when a PBO is bound.
# Making it conditional on marshal_sync is kinda hacky, but it's the easiest
# path towards handling PBOs in glthread, which use marshal_sync to check whether
# a PBO is bound.
if func.marshal_sync:
fixed_params = func.fixed_params + func.variable_params
variable_params = []
else:
fixed_params = func.fixed_params
variable_params = func.variable_params
fixed_params = func.get_fixed_params()
variable_params = func.get_variable_params()
out('/* {0}: marshalled asynchronously */'.format(func.name))
out('struct marshal_cmd_{0}'.format(func.name))
out('{')
with indent():
out('struct marshal_cmd_base cmd_base;')
# Sort the parameters according to their size to pack the structure optimally
for p in sorted(fixed_params, key=lambda p: self.get_type_size(p.type_string())):
if p.count:
out('{0} {1}[{2}];'.format(
p.get_base_type_string(), p.name, p.count))
else:
type = p.type_string()
if type == 'GLenum':
type = 'GLenum16'
out('{0} {1};'.format(type, p.name))
for p in variable_params:
if p.img_null_flag:
out('bool {0}_null; /* If set, no data follows '
'for "{0}" */'.format(p.name))
for p in variable_params:
if p.count_scale != 1:
out(('/* Next {0} bytes are '
'{1} {2}[{3}][{4}] */').format(
p.size_string(marshal=1), p.get_base_type_string(),
p.name, p.counter, p.count_scale))
else:
out(('/* Next {0} bytes are '
'{1} {2}[{3}] */').format(
p.size_string(marshal=1), p.get_base_type_string(),
p.name, p.counter))
out('};')
func.print_struct()
out('uint32_t')
out(('_mesa_unmarshal_{0}(struct gl_context *ctx, '

View file

@ -66,9 +66,11 @@ class PrintCode(gl_XML.gl_print_base):
print('')
for func in api.functionIterateAll():
func.print_struct(is_header=True)
flavor = func.marshal_flavor()
if flavor in ('custom', 'async'):
print('struct marshal_cmd_{0};'.format(func.name))
print(('uint32_t _mesa_unmarshal_{0}(struct gl_context *ctx, '
'const struct marshal_cmd_{0} *restrict cmd);').format(func.name))

View file

@ -25,6 +25,43 @@
import gl_XML
def get_type_size(str):
if str.find('*') != -1:
return 8;
mapping = {
'GLboolean': 1,
'GLbyte': 1,
'GLubyte': 1,
'GLenum': 2, # uses GLenum16, clamped to 0xffff (invalid enum)
'GLshort': 2,
'GLushort': 2,
'GLhalfNV': 2,
'GLint': 4,
'GLuint': 4,
'GLbitfield': 4,
'GLsizei': 4,
'GLfloat': 4,
'GLclampf': 4,
'GLfixed': 4,
'GLclampx': 4,
'GLhandleARB': 4,
'int': 4,
'float': 4,
'GLdouble': 8,
'GLclampd': 8,
'GLintptr': 8,
'GLsizeiptr': 8,
'GLint64': 8,
'GLuint64': 8,
'GLuint64EXT': 8,
'GLsync': 8,
}
val = mapping.get(str, 9999)
if val == 9999:
print('Unhandled type in marshal_XML.get_type_size: ' + str, file=sys.stderr)
assert False
return val
class marshal_item_factory(gl_XML.gl_item_factory):
"""Factory to create objects derived from gl_item containing
@ -60,6 +97,7 @@ class marshal_function(gl_XML.gl_function):
self.marshal_sync = element.get('marshal_sync')
self.marshal_call_before = element.get('marshal_call_before')
self.marshal_call_after = element.get('marshal_call_after')
self.marshal_struct = element.get('marshal_struct')
def marshal_flavor(self):
"""Find out how this function should be marshalled between
@ -91,3 +129,60 @@ class marshal_function(gl_XML.gl_function):
return (self.marshal_flavor() != 'custom' and
self.name[0:8] != 'Internal' and
self.exec_flavor != 'beginend')
def get_fixed_params(self):
# We want glthread to ignore variable-sized parameters if the only thing
# we want is to pass the pointer parameter as-is, e.g. when a PBO is bound.
# Making it conditional on marshal_sync is kinda hacky, but it's the easiest
# path towards handling PBOs in glthread, which use marshal_sync to check whether
# a PBO is bound.
if self.marshal_sync:
return self.fixed_params + self.variable_params
else:
return self.fixed_params
def get_variable_params(self):
if self.marshal_sync:
return []
else:
return self.variable_params
def print_struct(self, is_header=False):
fixed_params = self.get_fixed_params()
variable_params = self.get_variable_params()
if (self.marshal_struct == 'public') == is_header:
print('struct marshal_cmd_{0}'.format(self.name))
print('{')
print(' struct marshal_cmd_base cmd_base;')
# Sort the parameters according to their size to pack the structure optimally
for p in sorted(fixed_params, key=lambda p: get_type_size(p.type_string())):
if p.count:
print(' {0} {1}[{2}];'.format(
p.get_base_type_string(), p.name, p.count))
else:
type = p.type_string()
if type == 'GLenum':
type = 'GLenum16'
print(' {0} {1};'.format(type, p.name))
for p in variable_params:
if p.img_null_flag:
print(' bool {0}_null; /* If set, no data follows '
'for "{0}" */'.format(p.name))
for p in variable_params:
if p.count_scale != 1:
print((' /* Next {0} bytes are '
'{1} {2}[{3}][{4}] */').format(
p.size_string(marshal=1), p.get_base_type_string(),
p.name, p.counter, p.count_scale))
else:
print((' /* Next {0} bytes are '
'{1} {2}[{3}] */').format(
p.size_string(marshal=1), p.get_base_type_string(),
p.name, p.counter))
print('};')
elif self.marshal_flavor() in ('custom', 'async'):
print('struct marshal_cmd_{0};'.format(self.name))