vulkan/cmd_queue: Rework copy codegen

The new code handles pNext chanis correctly.

Reviewed-by: Mike Blumenkrantz <michael.blumenkrantz@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/39902>
This commit is contained in:
Konstantin Seurer 2026-02-15 17:07:37 +01:00 committed by Marge Bot
parent ecb6c5d555
commit f2bb6103c3
2 changed files with 109 additions and 93 deletions

View file

@ -5069,7 +5069,6 @@ void lvp_add_enqueue_cmd_entrypoints(struct vk_device_dispatch_table *disp)
ENQUEUE_CMD(CmdCopyAccelerationStructureKHR) ENQUEUE_CMD(CmdCopyAccelerationStructureKHR)
ENQUEUE_CMD(CmdCopyMemoryToAccelerationStructureKHR) ENQUEUE_CMD(CmdCopyMemoryToAccelerationStructureKHR)
ENQUEUE_CMD(CmdCopyAccelerationStructureToMemoryKHR) ENQUEUE_CMD(CmdCopyAccelerationStructureToMemoryKHR)
ENQUEUE_CMD(CmdBuildAccelerationStructuresIndirectKHR)
ENQUEUE_CMD(CmdWriteAccelerationStructuresPropertiesKHR) ENQUEUE_CMD(CmdWriteAccelerationStructuresPropertiesKHR)
ENQUEUE_CMD(CmdSetRayTracingPipelineStackSizeKHR) ENQUEUE_CMD(CmdSetRayTracingPipelineStackSizeKHR)

View file

@ -27,6 +27,7 @@ import argparse
import os import os
import re import re
from collections import namedtuple from collections import namedtuple
from enum import Enum, auto
import xml.etree.ElementTree as et import xml.etree.ElementTree as et
from mako.template import Template from mako.template import Template
@ -69,6 +70,8 @@ NO_ENQUEUE_COMMANDS = [
'CmdSetPerformanceMarkerINTEL', 'CmdSetPerformanceMarkerINTEL',
'CmdSetPerformanceStreamMarkerINTEL', 'CmdSetPerformanceStreamMarkerINTEL',
'CmdSetPerformanceOverrideINTEL', 'CmdSetPerformanceOverrideINTEL',
'CmdBuildAccelerationStructuresIndirectKHR',
] ]
TEMPLATE_H = Template(COPYRIGHT + """\ TEMPLATE_H = Template(COPYRIGHT + """\
@ -421,135 +424,149 @@ def to_struct_name(name):
def get_array_len(param): def get_array_len(param):
return param.decl[param.decl.find("[") + 1:param.decl.find("]")] return param.decl[param.decl.find("[") + 1:param.decl.find("]")]
def get_array_copy(builder, command, param, field_name): class ParamCategory(Enum):
if param.type == "void": ASSIGNABLE = auto()
field_size = "1" FLAT_ARRAY = auto()
else: UNSIZED_RAW_POINTER = auto()
field_size = "sizeof(*%s)" % field_name STRING = auto()
NULL = auto()
PNEXT = auto()
STRUCT = auto()
builder.add("%s = linear_alloc_child(queue->ctx, %s * (%s));\n if (%s == NULL) return VK_ERROR_OUT_OF_HOST_MEMORY;" % ( def categorize_param(types, parent_type, param):
field_name, field_size, param.len, field_name if param.name == 'pNext':
)) return ParamCategory.PNEXT if not parent_type or types[parent_type].extended_by else ParamCategory.NULL
builder.add("memcpy((void*)%s, %s, %s * (%s));" % (field_name, param.name, field_size, param.len))
def get_pnext_member_copy(builder, struct, src_type, member, types): if '[' in param.decl:
if not types[src_type].extended_by: return ParamCategory.FLAT_ARRAY
if param.type == "void" and not param.len:
return ParamCategory.UNSIZED_RAW_POINTER
if param.len == 'null-terminated':
return ParamCategory.STRING
if "*" not in param.decl:
return ParamCategory.ASSIGNABLE
return ParamCategory.STRUCT
def get_pnext_copy(builder, types, parent_type, src, dst):
if not types[parent_type].extended_by:
return return
field_name = "%s->%s" % (struct, member.name) builder.add("const VkBaseInStructure *pnext = %s;" % (src))
builder.add("void **dst_pnext_link = (void **)&%s;" % (dst))
builder.add("const VkBaseInStructure *pnext = %s;" % (field_name)) builder.add("while (pnext) {")
builder.add("if (pnext) {")
builder.level += 1 builder.level += 1
builder.add("switch ((int32_t)pnext->sType) {") builder.add("switch ((int32_t)pnext->sType) {")
for type in types[src_type].extended_by: for type in types[parent_type].extended_by:
if type.guard is not None: if type.guard is not None:
builder.code += "#ifdef %s\n" % (type.guard) builder.code += "#ifdef %s\n" % (type.guard)
builder.add("case %s:" % (type.enum)) builder.add("case %s:" % (type.enum))
builder.level += 1 builder.level += 1
get_struct_copy(builder, field_name, "pnext", type.name, types) member = EntrypointParam(type=type.name, name="", decl="%s *" % (type.name), len=None)
get_param_copy(builder, types, "pnext", "(*dst_pnext_link)", member, nullable=False)
builder.add("break;") builder.add("break;")
builder.level -= 1 builder.level -= 1
if type.guard is not None: if type.guard is not None:
builder.code += "#endif\n" builder.code += "#endif\n"
builder.add("}") builder.add("}")
builder.add("pnext = pnext->pNext;")
builder.add("dst_pnext_link = (void **)&((VkBaseOutStructure *)*dst_pnext_link)->pNext;")
builder.level -= 1 builder.level -= 1
builder.add("}") builder.add("}")
def get_struct_copy(builder, dst, src_name, src_type, types, parent_name=None, len=None): def get_param_copy(builder, types, src_parent_access, dst_parent_access, param, nullable=True, dst_snake_case=False):
tmp_dst_name = builder.get_variable_name("tmp_dst") src = src_parent_access + param.name
tmp_src_name = builder.get_variable_name("tmp_src") dst = dst_parent_access + (to_field_name(param.name) if dst_snake_case else param.name)
builder.add("if (%s) {" % (src_name))
builder.level += 1
if src_type == "void": match categorize_param(types, None, param):
size = "1" case ParamCategory.ASSIGNABLE:
else: builder.add("%s = %s;" % (dst, src))
size = "sizeof(%s)" % src_type case ParamCategory.FLAT_ARRAY:
builder.add("memcpy(%s, %s, sizeof(*%s) * %s);" % (dst, src, src, get_array_len(param)))
case ParamCategory.UNSIZED_RAW_POINTER:
builder.add("%s = (%s)%s;" % (dst, remove_suffix(param.decl.replace("const", ""), param.name), src))
case ParamCategory.STRING:
builder.add("%s = linear_strdup(queue->ctx, %s);" % (dst, src))
case ParamCategory.STRUCT:
if nullable:
builder.add("if (%s) {" % (src))
builder.level += 1
if len and len != "struct-ptr": if param.type == "void":
size = "%s * %s->%s" % (size, parent_name, len) size = 1
else:
size = "sizeof(%s)" % param.type
builder.add("%s = linear_alloc_child(queue->ctx, %s);" % (dst, size)) is_ndarray = param.len and "," in param.len
builder.add("if (%s == NULL) return VK_ERROR_OUT_OF_HOST_MEMORY;" % (dst)) if param.len and param.len != "struct-ptr" and not is_ndarray:
builder.add("%s *%s = (void *)%s;" % (src_type, tmp_dst_name, dst)) size = "%s * %s%s" % (size, src_parent_access, param.len)
builder.add("%s *%s = (void *)%s;" % (src_type, tmp_src_name, src_name))
builder.add("memcpy(%s, %s, %s);" % (tmp_dst_name, tmp_src_name, size))
struct_array_copy = len and len != "struct-ptr" and src_type != "void" builder.add("%s = linear_alloc_child(queue->ctx, %s);" % (dst, size))
if struct_array_copy: builder.add("if (%s == NULL) return VK_ERROR_OUT_OF_HOST_MEMORY;" % (dst))
array_index = builder.get_variable_name("i") builder.add("memcpy((void *)%s, %s, %s);" % (dst, src, size))
builder.add("for (uint32_t %s = 0; %s < %s->%s; %s++) {" % (array_index, array_index, parent_name, len, array_index))
builder.level += 1
prev_tmp_dst_name = tmp_dst_name
prev_tmp_src_name = tmp_src_name
tmp_dst_name = builder.get_variable_name("tmp_dst")
tmp_src_name = builder.get_variable_name("tmp_src")
builder.add("%s *%s = %s + %s; (void)%s;" % (src_type, tmp_dst_name, prev_tmp_dst_name, array_index, tmp_dst_name))
builder.add("%s *%s = %s + %s; (void)%s;" % (src_type, tmp_src_name, prev_tmp_src_name, array_index, tmp_src_name))
if src_type in types: if param.type in types:
for member in types[src_type].members: needs_member_copy = False
if member.len and member.len != 'null-terminated': for member in types[param.type].members:
get_struct_copy(builder, "%s->%s" % (tmp_dst_name, member.name), "%s->%s" % ( category = categorize_param(types, param.type, member)
tmp_src_name, member.name if category == ParamCategory.PNEXT or category == ParamCategory.STRUCT or category == ParamCategory.STRING:
), member.type, types, tmp_src_name, member.len) needs_member_copy = True
elif member.len and member.len == 'null-terminated':
builder.add("%s->%s = linear_strdup(queue->ctx, %s->%s);" % (tmp_dst_name, member.name, tmp_src_name, member.name))
elif member.name == 'pNext':
get_pnext_member_copy(builder, tmp_dst_name, src_type, member, types)
if struct_array_copy: if needs_member_copy:
builder.level -= 1 tmp_dst_name = builder.get_variable_name("tmp_dst")
builder.add("}") tmp_src_name = builder.get_variable_name("tmp_src")
builder.level -= 1 builder.add("%s *%s = (void *)%s;" % (param.type, tmp_dst_name, dst))
builder.add("} else {") builder.add("%s *%s = (void *)%s;" % (param.type, tmp_src_name, src))
builder.level += 1
builder.add("%s = NULL;" % (dst))
builder.level -= 1
builder.add("}")
def get_param_copy(builder, command, param, types): struct_array_copy = param.len and param.len != "struct-ptr" and param.type != "void"
dst = "cmd->u.%s.%s" % (to_struct_field_name(command.name), to_field_name(param.name)) if struct_array_copy:
array_index = builder.get_variable_name("i")
builder.add("for (uint32_t %s = 0; %s < %s%s; %s++) {" % (array_index, array_index, src_parent_access, param.len, array_index))
builder.level += 1
prev_tmp_dst_name = tmp_dst_name
prev_tmp_src_name = tmp_src_name
tmp_dst_name = builder.get_variable_name("tmp_dst")
tmp_src_name = builder.get_variable_name("tmp_src")
builder.add("%s *%s = %s + %s;" % (param.type, tmp_dst_name, prev_tmp_dst_name, array_index))
builder.add("%s *%s = %s + %s;" % (param.type, tmp_src_name, prev_tmp_src_name, array_index))
if param.len: for member in types[param.type].members:
builder.add("if (%s) {" % (param.name)) category = categorize_param(types, param.type, member)
builder.level += 1 if category == ParamCategory.STRUCT or category == ParamCategory.STRING:
get_array_copy(builder, command, param, dst) get_param_copy(builder, types, "%s->" % (tmp_src_name), "%s->" % (tmp_dst_name), member)
builder.level -= 1 elif category == ParamCategory.PNEXT:
builder.add("} else {") get_pnext_copy(builder, types, param.type, "%s->pNext" % (tmp_src_name), "%s->pNext" % (tmp_dst_name))
builder.level += 1
builder.add("%s = NULL;" % (dst))
builder.level -= 1
builder.add("}")
return True
if '[' in param.decl: if struct_array_copy:
builder.add("memcpy(%s, %s, sizeof(*%s) * %s);" % (dst, param.name, param.name, get_array_len(param))) builder.level -= 1
return False builder.add("}")
if param.type == "void": if nullable:
builder.add("%s = (%s)%s;" % (dst, remove_suffix(param.decl.replace("const", ""), param.name), param.name)) builder.level -= 1
return False builder.add("} else {")
builder.level += 1
if '*' in param.decl: builder.add("%s = NULL;" % (dst))
get_struct_copy(builder, dst, param.name, param.type, types) builder.level -= 1
return True builder.add("}")
case ParamCategory.NULL:
builder.add("cmd->u.%s.%s = %s;" % (to_struct_field_name(command.name), to_field_name(param.name), param.name)) assert False
return False case ParamCategory.PNEXT:
assert False
def get_params_copy(command, types): def get_params_copy(command, types):
builder = CodeBuilder(1) builder = CodeBuilder(1)
struct_access = "cmd->u.%s." % (to_struct_field_name(command.name))
for param in command.params[1:]: for param in command.params[1:]:
get_param_copy(builder, command, param, types) get_param_copy(builder, types, "", struct_access, param, dst_snake_case=True)
builder.code += "\n" builder.code += "\n"
builder.add("list_addtail(&cmd->cmd_link, &queue->cmds);") builder.add("list_addtail(&cmd->cmd_link, &queue->cmds);")