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,35 +424,51 @@ 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
@ -457,99 +476,97 @@ def get_pnext_member_copy(builder, struct, src_type, member, types):
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)) match categorize_param(types, None, param):
builder.level += 1 case ParamCategory.ASSIGNABLE:
builder.add("%s = %s;" % (dst, src))
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 src_type == "void": if param.type == "void":
size = "1" size = 1
else: else:
size = "sizeof(%s)" % src_type size = "sizeof(%s)" % param.type
if len and len != "struct-ptr": is_ndarray = param.len and "," in param.len
size = "%s * %s->%s" % (size, parent_name, len) if param.len and param.len != "struct-ptr" and not is_ndarray:
size = "%s * %s%s" % (size, src_parent_access, param.len)
builder.add("%s = linear_alloc_child(queue->ctx, %s);" % (dst, size)) builder.add("%s = linear_alloc_child(queue->ctx, %s);" % (dst, size))
builder.add("if (%s == NULL) return VK_ERROR_OUT_OF_HOST_MEMORY;" % (dst)) builder.add("if (%s == NULL) return VK_ERROR_OUT_OF_HOST_MEMORY;" % (dst))
builder.add("%s *%s = (void *)%s;" % (src_type, tmp_dst_name, dst)) builder.add("memcpy((void *)%s, %s, %s);" % (dst, src, size))
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" if param.type in types:
if struct_array_copy: needs_member_copy = False
array_index = builder.get_variable_name("i") for member in types[param.type].members:
builder.add("for (uint32_t %s = 0; %s < %s->%s; %s++) {" % (array_index, array_index, parent_name, len, array_index)) category = categorize_param(types, param.type, member)
builder.level += 1 if category == ParamCategory.PNEXT or category == ParamCategory.STRUCT or category == ParamCategory.STRING:
prev_tmp_dst_name = tmp_dst_name needs_member_copy = True
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 needs_member_copy:
for member in types[src_type].members: tmp_dst_name = builder.get_variable_name("tmp_dst")
if member.len and member.len != 'null-terminated': tmp_src_name = builder.get_variable_name("tmp_src")
get_struct_copy(builder, "%s->%s" % (tmp_dst_name, member.name), "%s->%s" % (
tmp_src_name, member.name
), member.type, types, tmp_src_name, member.len)
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: builder.add("%s *%s = (void *)%s;" % (param.type, tmp_dst_name, dst))
builder.level -= 1 builder.add("%s *%s = (void *)%s;" % (param.type, tmp_src_name, src))
builder.add("}")
builder.level -= 1 struct_array_copy = param.len and param.len != "struct-ptr" and param.type != "void"
builder.add("} else {") if struct_array_copy:
builder.level += 1 array_index = builder.get_variable_name("i")
builder.add("%s = NULL;" % (dst)) 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 builder.level += 1
builder.add("}") 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))
def get_param_copy(builder, command, param, types): for member in types[param.type].members:
dst = "cmd->u.%s.%s" % (to_struct_field_name(command.name), to_field_name(param.name)) category = categorize_param(types, param.type, member)
if category == ParamCategory.STRUCT or category == ParamCategory.STRING:
get_param_copy(builder, types, "%s->" % (tmp_src_name), "%s->" % (tmp_dst_name), member)
elif category == ParamCategory.PNEXT:
get_pnext_copy(builder, types, param.type, "%s->pNext" % (tmp_src_name), "%s->pNext" % (tmp_dst_name))
if param.len: if struct_array_copy:
builder.add("if (%s) {" % (param.name)) builder.level -= 1
builder.level += 1 builder.add("}")
get_array_copy(builder, command, param, dst)
builder.level -= 1
builder.add("} else {")
builder.level += 1
builder.add("%s = NULL;" % (dst))
builder.level -= 1
builder.add("}")
return True
if '[' in param.decl: if nullable:
builder.add("memcpy(%s, %s, sizeof(*%s) * %s);" % (dst, param.name, param.name, get_array_len(param))) builder.level -= 1
return False builder.add("} else {")
builder.level += 1
if param.type == "void": builder.add("%s = NULL;" % (dst))
builder.add("%s = (%s)%s;" % (dst, remove_suffix(param.decl.replace("const", ""), param.name), param.name)) builder.level -= 1
return False builder.add("}")
case ParamCategory.NULL:
if '*' in param.decl: assert False
get_struct_copy(builder, dst, param.name, param.type, types) case ParamCategory.PNEXT:
return True assert False
builder.add("cmd->u.%s.%s = %s;" % (to_struct_field_name(command.name), to_field_name(param.name), param.name))
return 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);")