vulkan/cmd_queue: Handle struct copies that are not pointers

Structs that need explicit copies can be inline members.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/39496>
This commit is contained in:
Konstantin 2026-04-04 14:28:12 +02:00 committed by Marge Bot
parent f48f681fb5
commit 5251cd7236

View file

@ -572,10 +572,31 @@ class ParamCategory(Enum):
NULL = auto()
PNEXT = auto()
STRUCT = auto()
INLINE_STRUCT = auto()
DESCRIPTOR_UPDATE_TEMPLATE_DATA = auto()
DESCRIPTOR_UPDATE_TEMPLATE = auto()
PIPELINE_LAYOUT = auto()
class StructInfo:
def __init__(self):
self.has_explicit_copy = False
self.needs_member_copy = False
self.additional_code = []
def get_struct_info(command, param, types, src=""):
info = StructInfo()
info.has_explicit_copy = param.type in EXPLICIT_PARAM_COPIES
info.needs_member_copy = info.has_explicit_copy
for member in types[param.type].members:
match categorize_param(command, types, param.type, member):
case ParamCategory.PNEXT | ParamCategory.STRUCT | ParamCategory.STRING | ParamCategory.INLINE_STRUCT:
info.needs_member_copy = True
case ParamCategory.PIPELINE_LAYOUT:
info.additional_code.append("enqueue_pipeline_layout(queue, %s->%s);" % (src, member.name))
case ParamCategory.DESCRIPTOR_UPDATE_TEMPLATE:
info.additional_code.append("enqueue_descriptor_template(queue, %s->%s);" % (src, member.name))
return info
def categorize_param(command, types, parent_type, param):
if param.name == 'pNext':
return ParamCategory.PNEXT if not parent_type or types[parent_type].extended_by else ParamCategory.NULL
@ -599,6 +620,11 @@ def categorize_param(command, types, parent_type, param):
return ParamCategory.DESCRIPTOR_UPDATE_TEMPLATE
if "*" not in param.decl:
if param.type in types:
struct_info = get_struct_info(command, param, types)
# If no member needs special handling, the assign/memcpy is enough
if struct_info.needs_member_copy:
return ParamCategory.INLINE_STRUCT
return ParamCategory.ASSIGNABLE
return ParamCategory.STRUCT
@ -641,7 +667,8 @@ def get_param_copy(builder, command, types, src_parent_access, dst_parent_access
src = src_parent_access + param.name
dst = dst_parent_access + (to_field_name(param.name) if dst_snake_case else param.name)
match categorize_param(command, types, None, param):
param_category = categorize_param(command, types, None, param)
match param_category:
case ParamCategory.ASSIGNABLE:
builder.add("%s = %s;" % (dst, src))
case ParamCategory.FLAT_ARRAY:
@ -658,7 +685,11 @@ def get_param_copy(builder, command, types, src_parent_access, dst_parent_access
case ParamCategory.PIPELINE_LAYOUT:
builder.add("%s = %s;" % (dst, src))
builder.add("enqueue_pipeline_layout(queue, %s);" % (src))
case ParamCategory.STRUCT:
case ParamCategory.STRUCT | ParamCategory.INLINE_STRUCT:
if param_category == ParamCategory.INLINE_STRUCT:
nullable = False
src = "&%s" % (src)
dst = "&%s" % (dst)
if nullable:
builder.add("if (%s) {" % (src))
@ -673,9 +704,11 @@ def get_param_copy(builder, command, types, src_parent_access, dst_parent_access
if param.len and param.len != "struct-ptr" and not is_ndarray:
size = "%s * ceil(%s%s)" % (size, src_parent_access, param.len)
builder.add("%s = linear_alloc_child(queue->ctx, %s);" % (dst, size))
builder.add("if (%s == NULL) return NULL;" % (dst))
builder.add("memcpy((void *)%s, %s, %s);" % (dst, src, size))
if param_category != ParamCategory.INLINE_STRUCT:
builder.add("%s = linear_alloc_child(queue->ctx, %s);" % (dst, size))
builder.add("if (%s == NULL) return NULL;" % (dst))
builder.add("memcpy((void *)%s, %s, %s);" % (dst, src, size))
if param.type == 'VkDescriptorSetLayout':
array_index = builder.get_variable_name("i")
builder.add("for (unsigned %s = 0; %s < %s%s; %s++) {" % (array_index, array_index, src_parent_access, param.len, array_index))
@ -685,18 +718,11 @@ def get_param_copy(builder, command, types, src_parent_access, dst_parent_access
builder.add("}")
if param.type in types:
has_explicit_copy = param.type in EXPLICIT_PARAM_COPIES
needs_member_copy = has_explicit_copy
for member in types[param.type].members:
match categorize_param(command, types, param.type, member):
case ParamCategory.PNEXT | ParamCategory.STRUCT | ParamCategory.STRING:
needs_member_copy = True
case ParamCategory.PIPELINE_LAYOUT:
builder.add("enqueue_pipeline_layout(queue, %s->%s);" % (src, member.name))
case ParamCategory.DESCRIPTOR_UPDATE_TEMPLATE:
builder.add("enqueue_descriptor_template(queue, %s->%s);" % (src, member.name))
struct_info = get_struct_info(command, param, types, src)
for code in struct_info.additional_code:
builder.add(code);
if needs_member_copy:
if struct_info.needs_member_copy:
tmp_dst_name = builder.get_variable_name("tmp_dst")
tmp_src_name = builder.get_variable_name("tmp_src")
@ -722,12 +748,12 @@ def get_param_copy(builder, command, types, src_parent_access, dst_parent_access
elif category == ParamCategory.DESCRIPTOR_UPDATE_TEMPLATE_DATA:
get_param_copy(builder, command, types, "%s->" % (tmp_src_name), "%s->" % (tmp_dst_name), member, dst_initialized=True)
if has_explicit_copy:
if struct_info.has_explicit_copy:
builder.add("enqueue_%s(queue, %s, %s);" % (param.type, tmp_dst_name, tmp_src_name))
else:
for member in types[param.type].members:
category = categorize_param(command, types, param.type, member)
if category == ParamCategory.STRUCT or category == ParamCategory.STRING:
if category == ParamCategory.STRUCT or category == ParamCategory.STRING or category == ParamCategory.INLINE_STRUCT:
get_param_copy(builder, command, types, "%s->" % (tmp_src_name), "%s->" % (tmp_dst_name), member, dst_initialized=True)
if struct_array_copy: