vkd3d-shader/hlsl: Record semantic extern vars separately for each entry function.

This is required in order to process the entry point function and the
patch constant function in hull shaders.
This commit is contained in:
Shaun Ren 2024-09-23 21:40:59 -04:00 committed by Henri Verbeet
parent bbc6b56ab0
commit f15a1c0b23
Notes: Henri Verbeet 2024-10-15 17:03:41 +02:00
Approved-by: Elizabeth Figura (@zfigura)
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1154
4 changed files with 80 additions and 63 deletions

View File

@ -2545,6 +2545,7 @@ struct hlsl_ir_function_decl *hlsl_new_func_decl(struct hlsl_ctx *ctx,
decl->return_type = return_type;
decl->parameters = *parameters;
decl->loc = *loc;
list_init(&decl->extern_vars);
if (!hlsl_types_are_equal(return_type, ctx->builtin_types.Void))
{

View File

@ -611,6 +611,12 @@ struct hlsl_ir_function_decl
* executed. Needed to deal with return statements in non-uniform control
* flow, since some backends can't handle them. */
struct hlsl_ir_var *early_return_var;
/* List of all the extern semantic variables; linked by the
* hlsl_ir_var.extern_entry fields. This exists as a convenience because
* it is often necessary to iterate all extern variables and these can be
* declared in as function parameters, or as the function return value. */
struct list extern_vars;
};
struct hlsl_ir_call
@ -1019,10 +1025,11 @@ struct hlsl_ctx
struct hlsl_scope *dummy_scope;
/* List of all the scopes in the program; linked by the hlsl_scope.entry fields. */
struct list scopes;
/* List of all the extern variables; linked by the hlsl_ir_var.extern_entry fields.
* This exists as a convenience because it is often necessary to iterate all extern variables
* and these can be declared in global scope, as function parameters, or as the function
* return value. */
/* List of all the extern variables, excluding semantic variables; linked
* by the hlsl_ir_var.extern_entry fields. This exists as a convenience
* because it is often necessary to iterate all extern variables declared
* in the global scope or as function parameters. */
struct list extern_vars;
/* List containing both the built-in HLSL buffers ($Globals and $Params) and the ones declared

View File

@ -276,8 +276,8 @@ static bool types_are_semantic_equivalent(struct hlsl_ctx *ctx, const struct hls
== base_type_get_semantic_equivalent(type2->e.numeric.type);
}
static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir_var *var,
struct hlsl_type *type, uint32_t modifiers, struct hlsl_semantic *semantic,
static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *func,
struct hlsl_ir_var *var, struct hlsl_type *type, uint32_t modifiers, struct hlsl_semantic *semantic,
uint32_t index, bool output, const struct vkd3d_shader_location *loc)
{
struct hlsl_semantic new_semantic;
@ -287,7 +287,7 @@ static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir
if (!(new_name = hlsl_sprintf_alloc(ctx, "<%s-%s%u>", output ? "output" : "input", semantic->name, index)))
return NULL;
LIST_FOR_EACH_ENTRY(ext_var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
LIST_FOR_EACH_ENTRY(ext_var, &func->extern_vars, struct hlsl_ir_var, extern_entry)
{
if (!ascii_strcasecmp(ext_var->name, new_name))
{
@ -339,12 +339,12 @@ static struct hlsl_ir_var *add_semantic_var(struct hlsl_ctx *ctx, struct hlsl_ir
ext_var->is_input_semantic = 1;
ext_var->is_param = var->is_param;
list_add_before(&var->scope_entry, &ext_var->scope_entry);
list_add_tail(&ctx->extern_vars, &ext_var->extern_entry);
list_add_tail(&func->extern_vars, &ext_var->extern_entry);
return ext_var;
}
static void prepend_input_copy(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_load *lhs,
static void prepend_input_copy(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *func, struct hlsl_ir_load *lhs,
uint32_t modifiers, struct hlsl_semantic *semantic, uint32_t semantic_index)
{
struct hlsl_type *type = lhs->node.data_type, *vector_type_src, *vector_type_dst;
@ -375,7 +375,7 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct hlsl_block *block, s
struct hlsl_ir_var *input;
struct hlsl_ir_load *load;
if (!(input = add_semantic_var(ctx, var, vector_type_src, modifiers, semantic,
if (!(input = add_semantic_var(ctx, func, var, vector_type_src, modifiers, semantic,
semantic_index + i, false, loc)))
return;
@ -408,8 +408,8 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct hlsl_block *block, s
}
}
static void prepend_input_copy_recurse(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_load *lhs,
uint32_t modifiers, struct hlsl_semantic *semantic, uint32_t semantic_index)
static void prepend_input_copy_recurse(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *func,
struct hlsl_ir_load *lhs, uint32_t modifiers, struct hlsl_semantic *semantic, uint32_t semantic_index)
{
struct vkd3d_shader_location *loc = &lhs->node.loc;
struct hlsl_type *type = lhs->node.data_type;
@ -466,30 +466,30 @@ static void prepend_input_copy_recurse(struct hlsl_ctx *ctx, struct hlsl_block *
return;
list_add_after(&c->entry, &element_load->node.entry);
prepend_input_copy_recurse(ctx, block, element_load, element_modifiers, semantic, elem_semantic_index);
prepend_input_copy_recurse(ctx, func, element_load, element_modifiers, semantic, elem_semantic_index);
}
}
else
{
prepend_input_copy(ctx, block, lhs, modifiers, semantic, semantic_index);
prepend_input_copy(ctx, func, lhs, modifiers, semantic, semantic_index);
}
}
/* Split inputs into two variables representing the semantic and temp registers,
* and copy the former to the latter, so that writes to input variables work. */
static void prepend_input_var_copy(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_var *var)
static void prepend_input_var_copy(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *func, struct hlsl_ir_var *var)
{
struct hlsl_ir_load *load;
/* This redundant load is expected to be deleted later by DCE. */
if (!(load = hlsl_new_var_load(ctx, var, &var->loc)))
return;
list_add_head(&block->instrs, &load->node.entry);
list_add_head(&func->body.instrs, &load->node.entry);
prepend_input_copy_recurse(ctx, block, load, var->storage_modifiers, &var->semantic, var->semantic.index);
prepend_input_copy_recurse(ctx, func, load, var->storage_modifiers, &var->semantic, var->semantic.index);
}
static void append_output_copy(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_load *rhs,
static void append_output_copy(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *func, struct hlsl_ir_load *rhs,
uint32_t modifiers, struct hlsl_semantic *semantic, uint32_t semantic_index)
{
struct hlsl_type *type = rhs->node.data_type, *vector_type;
@ -517,18 +517,19 @@ static void append_output_copy(struct hlsl_ctx *ctx, struct hlsl_block *block, s
struct hlsl_ir_var *output;
struct hlsl_ir_load *load;
if (!(output = add_semantic_var(ctx, var, vector_type, modifiers, semantic, semantic_index + i, true, loc)))
if (!(output = add_semantic_var(ctx, func, var, vector_type,
modifiers, semantic, semantic_index + i, true, loc)))
return;
if (type->class == HLSL_CLASS_MATRIX)
{
if (!(c = hlsl_new_uint_constant(ctx, i, &var->loc)))
return;
hlsl_block_add_instr(block, c);
hlsl_block_add_instr(&func->body, c);
if (!(load = hlsl_new_load_index(ctx, &rhs->src, c, &var->loc)))
return;
hlsl_block_add_instr(block, &load->node);
hlsl_block_add_instr(&func->body, &load->node);
}
else
{
@ -536,17 +537,17 @@ static void append_output_copy(struct hlsl_ctx *ctx, struct hlsl_block *block, s
if (!(load = hlsl_new_load_index(ctx, &rhs->src, NULL, &var->loc)))
return;
hlsl_block_add_instr(block, &load->node);
hlsl_block_add_instr(&func->body, &load->node);
}
if (!(store = hlsl_new_simple_store(ctx, output, &load->node)))
return;
hlsl_block_add_instr(block, store);
hlsl_block_add_instr(&func->body, store);
}
}
static void append_output_copy_recurse(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_load *rhs,
uint32_t modifiers, struct hlsl_semantic *semantic, uint32_t semantic_index)
static void append_output_copy_recurse(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *func,
struct hlsl_ir_load *rhs, uint32_t modifiers, struct hlsl_semantic *semantic, uint32_t semantic_index)
{
struct vkd3d_shader_location *loc = &rhs->node.loc;
struct hlsl_type *type = rhs->node.data_type;
@ -580,34 +581,34 @@ static void append_output_copy_recurse(struct hlsl_ctx *ctx, struct hlsl_block *
if (!(c = hlsl_new_uint_constant(ctx, i, &var->loc)))
return;
hlsl_block_add_instr(block, c);
hlsl_block_add_instr(&func->body, c);
if (!(element_load = hlsl_new_load_index(ctx, &rhs->src, c, loc)))
return;
hlsl_block_add_instr(block, &element_load->node);
hlsl_block_add_instr(&func->body, &element_load->node);
append_output_copy_recurse(ctx, block, element_load, modifiers, semantic, elem_semantic_index);
append_output_copy_recurse(ctx, func, element_load, modifiers, semantic, elem_semantic_index);
}
}
else
{
append_output_copy(ctx, block, rhs, modifiers, semantic, semantic_index);
append_output_copy(ctx, func, rhs, modifiers, semantic, semantic_index);
}
}
/* Split outputs into two variables representing the temp and semantic
* registers, and copy the former to the latter, so that reads from output
* variables work. */
static void append_output_var_copy(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_var *var)
static void append_output_var_copy(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *func, struct hlsl_ir_var *var)
{
struct hlsl_ir_load *load;
/* This redundant load is expected to be deleted later by DCE. */
if (!(load = hlsl_new_var_load(ctx, var, &var->loc)))
return;
hlsl_block_add_instr(block, &load->node);
hlsl_block_add_instr(&func->body, &load->node);
append_output_copy_recurse(ctx, block, load, var->storage_modifiers, &var->semantic, var->semantic.index);
append_output_copy_recurse(ctx, func, load, var->storage_modifiers, &var->semantic, var->semantic.index);
}
bool hlsl_transform_ir(struct hlsl_ctx *ctx, bool (*func)(struct hlsl_ctx *ctx, struct hlsl_ir_node *, void *),
@ -4142,11 +4143,11 @@ static char get_regset_name(enum hlsl_regset regset)
vkd3d_unreachable();
}
static void allocate_register_reservations(struct hlsl_ctx *ctx)
static void allocate_register_reservations(struct hlsl_ctx *ctx, struct list *extern_vars)
{
struct hlsl_ir_var *var;
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
LIST_FOR_EACH_ENTRY(var, extern_vars, struct hlsl_ir_var, extern_entry)
{
const struct hlsl_reg_reservation *reservation = &var->reg_reservation;
unsigned int r;
@ -4352,6 +4353,14 @@ static void compute_liveness_recurse(struct hlsl_block *block, unsigned int loop
}
}
static void init_var_liveness(struct hlsl_ir_var *var)
{
if (var->is_uniform || var->is_input_semantic)
var->first_write = 1;
else if (var->is_output_semantic)
var->last_read = UINT_MAX;
}
static void compute_liveness(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func)
{
struct hlsl_scope *scope;
@ -4366,12 +4375,10 @@ static void compute_liveness(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl
}
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
{
if (var->is_uniform || var->is_input_semantic)
var->first_write = 1;
else if (var->is_output_semantic)
var->last_read = UINT_MAX;
}
init_var_liveness(var);
LIST_FOR_EACH_ENTRY(var, &entry_func->extern_vars, struct hlsl_ir_var, extern_entry)
init_var_liveness(var);
compute_liveness_recurse(&entry_func->body, 0, 0);
}
@ -5194,12 +5201,12 @@ static void allocate_semantic_register(struct hlsl_ctx *ctx, struct hlsl_ir_var
}
}
static void allocate_semantic_registers(struct hlsl_ctx *ctx)
static void allocate_semantic_registers(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func)
{
unsigned int input_counter = 0, output_counter = 0;
struct hlsl_ir_var *var;
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
LIST_FOR_EACH_ENTRY(var, &entry_func->extern_vars, struct hlsl_ir_var, extern_entry)
{
if (var->is_input_semantic)
allocate_semantic_register(ctx, var, &input_counter, false);
@ -5510,15 +5517,15 @@ static const struct hlsl_ir_var *get_allocated_object(struct hlsl_ctx *ctx, enum
return NULL;
}
static void allocate_objects(struct hlsl_ctx *ctx, enum hlsl_regset regset)
static void allocate_objects(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *func, enum hlsl_regset regset)
{
char regset_name = get_regset_name(regset);
uint32_t min_index = 0, id = 0;
struct hlsl_ir_var *var;
if (regset == HLSL_REGSET_UAVS)
if (regset == HLSL_REGSET_UAVS && ctx->profile->type == VKD3D_SHADER_TYPE_PIXEL)
{
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
LIST_FOR_EACH_ENTRY(var, &func->extern_vars, struct hlsl_ir_var, extern_entry)
{
if (var->semantic.name && (!ascii_strcasecmp(var->semantic.name, "color")
|| !ascii_strcasecmp(var->semantic.name, "sv_target")))
@ -6293,11 +6300,12 @@ static void sm1_generate_vsir_signature_entry(struct hlsl_ctx *ctx,
element->interpolation_mode = VKD3DSIM_LINEAR;
}
static void sm1_generate_vsir_signature(struct hlsl_ctx *ctx, struct vsir_program *program)
static void sm1_generate_vsir_signature(struct hlsl_ctx *ctx,
struct hlsl_ir_function_decl *func, struct vsir_program *program)
{
struct hlsl_ir_var *var;
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
LIST_FOR_EACH_ENTRY(var, &func->extern_vars, struct hlsl_ir_var, extern_entry)
{
if (var->is_input_semantic)
sm1_generate_vsir_signature_entry(ctx, program, false, var);
@ -7262,7 +7270,7 @@ static void sm1_generate_vsir(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl
ctab->code = buffer.data;
ctab->size = buffer.size;
sm1_generate_vsir_signature(ctx, program);
sm1_generate_vsir_signature(ctx, entry_func, program);
hlsl_block_init(&block);
sm1_generate_vsir_constant_defs(ctx, program, &block);
@ -7629,9 +7637,9 @@ static void process_entry_function(struct hlsl_ctx *ctx, struct hlsl_ir_function
}
if (var->storage_modifiers & HLSL_STORAGE_IN)
prepend_input_var_copy(ctx, body, var);
prepend_input_var_copy(ctx, entry_func, var);
if (var->storage_modifiers & HLSL_STORAGE_OUT)
append_output_var_copy(ctx, body, var);
append_output_var_copy(ctx, entry_func, var);
}
}
if (entry_func->return_var)
@ -7640,7 +7648,7 @@ static void process_entry_function(struct hlsl_ctx *ctx, struct hlsl_ir_function
hlsl_error(ctx, &entry_func->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_SEMANTIC,
"Entry point \"%s\" is missing a return value semantic.", entry_func->func->name);
append_output_var_copy(ctx, body, entry_func->return_var);
append_output_var_copy(ctx, entry_func, entry_func->return_var);
}
if (profile->major_version >= 4)
@ -7723,10 +7731,10 @@ static void process_entry_function(struct hlsl_ctx *ctx, struct hlsl_ir_function
calculate_resource_register_counts(ctx);
allocate_register_reservations(ctx);
allocate_register_reservations(ctx, &ctx->extern_vars);
allocate_register_reservations(ctx, &entry_func->extern_vars);
allocate_temp_registers(ctx, entry_func);
allocate_semantic_registers(ctx);
allocate_semantic_registers(ctx, entry_func);
}
int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_func,
@ -7755,10 +7763,10 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry
else
{
allocate_buffers(ctx);
allocate_objects(ctx, HLSL_REGSET_TEXTURES);
allocate_objects(ctx, HLSL_REGSET_UAVS);
allocate_objects(ctx, entry_func, HLSL_REGSET_TEXTURES);
allocate_objects(ctx, entry_func, HLSL_REGSET_UAVS);
}
allocate_objects(ctx, HLSL_REGSET_SAMPLERS);
allocate_objects(ctx, entry_func, HLSL_REGSET_SAMPLERS);
if (TRACE_ON())
rb_for_each_entry(&ctx->functions, dump_function, ctx);

View File

@ -3133,7 +3133,8 @@ static void add_section(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc,
ctx->result = buffer->status;
}
static void write_sm4_signature(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc, bool output)
static void write_sm4_signature(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc,
const struct hlsl_ir_function_decl *func, bool output)
{
struct vkd3d_bytecode_buffer buffer = {0};
struct vkd3d_string_buffer *string;
@ -3145,7 +3146,7 @@ static void write_sm4_signature(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc,
count_position = put_u32(&buffer, 0);
put_u32(&buffer, 8); /* unknown */
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
LIST_FOR_EACH_ENTRY(var, &func->extern_vars, struct hlsl_ir_var, extern_entry)
{
unsigned int width = (1u << var->data_type->dimx) - 1, use_mask;
enum vkd3d_shader_sysval_semantic semantic;
@ -3210,7 +3211,7 @@ static void write_sm4_signature(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc,
}
i = 0;
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
LIST_FOR_EACH_ENTRY(var, &func->extern_vars, struct hlsl_ir_var, extern_entry)
{
enum vkd3d_shader_sysval_semantic semantic;
const char *name = var->semantic.name;
@ -6440,7 +6441,7 @@ static void write_sm4_shdr(struct hlsl_ctx *ctx, const struct hlsl_ir_function_d
if (entry_func->early_depth_test && profile->major_version >= 5)
write_sm4_dcl_global_flags(&tpf, VKD3DSGF_FORCE_EARLY_DEPTH_STENCIL);
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry)
LIST_FOR_EACH_ENTRY(var, &entry_func->extern_vars, struct hlsl_ir_var, extern_entry)
{
if ((var->is_input_semantic && var->last_read) || (var->is_output_semantic && var->first_write))
write_sm4_dcl_semantic(&tpf, var);
@ -6565,8 +6566,8 @@ int hlsl_sm4_write(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry_fun
dxbc_writer_init(&dxbc);
write_sm4_signature(ctx, &dxbc, false);
write_sm4_signature(ctx, &dxbc, true);
write_sm4_signature(ctx, &dxbc, entry_func, false);
write_sm4_signature(ctx, &dxbc, entry_func, true);
write_sm4_rdef(ctx, &dxbc);
write_sm4_shdr(ctx, entry_func, &stat, &dxbc);
write_sm4_sfi0(ctx, &dxbc);