-- v24: vkd3d-shader/ir: Include an initial label instruction in the first control flow block. vkd3d-shader/spirv: Do not emit function code before the main prolog. vkd3d-shader/spirv: Declare indexable temps as Private unless function scope is specified.
From: Conor McCarthy cmccarthy@codeweavers.com
Ensures they are loaded only once per function independent of the control flow graph. --- libs/vkd3d-shader/spirv.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 8a4704e56..6f76715e1 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2440,6 +2440,7 @@ static bool is_in_fork_or_join_phase(const struct spirv_compiler *compiler) }
static void spirv_compiler_emit_initial_declarations(struct spirv_compiler *compiler); +static size_t spirv_compiler_get_current_function_location(struct spirv_compiler *compiler);
static const char *spirv_compiler_get_entry_point_name(const struct spirv_compiler *compiler) { @@ -3520,11 +3521,13 @@ static uint32_t spirv_compiler_get_descriptor_index(struct spirv_compiler *compi index_ids[0] = compiler->descriptor_offsets_member_id; index_ids[1] = spirv_compiler_get_constant_uint(compiler, push_constant_index); ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassPushConstant, type_id); + vkd3d_spirv_begin_function_stream_insertion(builder, + spirv_compiler_get_current_function_location(compiler)); ptr_id = vkd3d_spirv_build_op_in_bounds_access_chain(builder, ptr_type_id, compiler->push_constants_var_id, index_ids, 2); offset_id = vkd3d_spirv_build_op_load(builder, type_id, ptr_id, SpvMemoryAccessMaskNone); - if (!compiler->control_flow_depth) - compiler->descriptor_offset_ids[push_constant_index] = offset_id; + vkd3d_spirv_end_function_stream_insertion(builder); + compiler->descriptor_offset_ids[push_constant_index] = offset_id; } index_id = vkd3d_spirv_build_op_iadd(builder, type_id, index_id, offset_id); } @@ -6664,6 +6667,9 @@ static void spirv_compiler_emit_hull_shader_main(struct spirv_compiler *compiler struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; uint32_t void_id;
+ /* If a patch constant function used descriptor indexing the offsets must be reloaded. */ + memset(compiler->descriptor_offset_ids, 0, compiler->offset_info.descriptor_table_count + * sizeof(*compiler->descriptor_offset_ids)); vkd3d_spirv_builder_begin_main_function(builder);
void_id = vkd3d_spirv_get_op_type_void(builder);
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 6f76715e1..1ce63f71c 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -7975,11 +7975,6 @@ static int spirv_compiler_emit_control_flow_instruction(struct spirv_compiler *c spirv_compiler_emit_retc(compiler, instruction); break;
- case VKD3DSIH_DISCARD: - case VKD3DSIH_TEXKILL: - spirv_compiler_emit_kill(compiler, instruction); - break; - default: ERR("Unexpected instruction %#x.\n", instruction->handler_idx); break; @@ -9738,7 +9733,6 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_CONTINUE: case VKD3DSIH_CONTINUEP: case VKD3DSIH_DEFAULT: - case VKD3DSIH_DISCARD: case VKD3DSIH_ELSE: case VKD3DSIH_ENDIF: case VKD3DSIH_ENDLOOP: @@ -9748,9 +9742,12 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_RET: case VKD3DSIH_RETP: case VKD3DSIH_SWITCH: - case VKD3DSIH_TEXKILL: ret = spirv_compiler_emit_control_flow_instruction(compiler, instruction); break; + case VKD3DSIH_DISCARD: + case VKD3DSIH_TEXKILL: + spirv_compiler_emit_kill(compiler, instruction); + break; case VKD3DSIH_DSX: case VKD3DSIH_DSX_COARSE: case VKD3DSIH_DSX_FINE:
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 1ce63f71c..c249b178d 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -7971,10 +7971,6 @@ static int spirv_compiler_emit_control_flow_instruction(struct spirv_compiler *c compiler->main_block_open = false; break;
- case VKD3DSIH_RETP: - spirv_compiler_emit_retc(compiler, instruction); - break; - default: ERR("Unexpected instruction %#x.\n", instruction->handler_idx); break; @@ -9740,10 +9736,12 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_IF: case VKD3DSIH_LOOP: case VKD3DSIH_RET: - case VKD3DSIH_RETP: case VKD3DSIH_SWITCH: ret = spirv_compiler_emit_control_flow_instruction(compiler, instruction); break; + case VKD3DSIH_RETP: + spirv_compiler_emit_retc(compiler, instruction); + break; case VKD3DSIH_DISCARD: case VKD3DSIH_TEXKILL: spirv_compiler_emit_kill(compiler, instruction);
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/d3d_asm.c | 1 + libs/vkd3d-shader/ir.c | 353 +++++++++++++++++++++++ libs/vkd3d-shader/spirv.c | 179 ++++++------ libs/vkd3d-shader/vkd3d_shader_private.h | 7 + 4 files changed, 452 insertions(+), 88 deletions(-)
diff --git a/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d-shader/d3d_asm.c index 0589bc421..2fbd98936 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -44,6 +44,7 @@ static const char * const shader_opcode_names[] = [VKD3DSIH_BEM ] = "bem", [VKD3DSIH_BFI ] = "bfi", [VKD3DSIH_BFREV ] = "bfrev", + [VKD3DSIH_BRANCH ] = "branch", [VKD3DSIH_BREAK ] = "break", [VKD3DSIH_BREAKC ] = "breakc", [VKD3DSIH_BREAKP ] = "breakp", diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index bac426919..33a6aec8d 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -312,6 +312,21 @@ void vsir_register_init(struct vkd3d_shader_register *reg, enum vkd3d_shader_reg reg->alignment = 0; }
+static void vsir_src_param_init(struct vkd3d_shader_src_param *param, enum vkd3d_shader_register_type reg_type, + enum vkd3d_data_type data_type, unsigned int idx_count) +{ + vsir_register_init(¶m->reg, reg_type, data_type, idx_count); + param->swizzle = 0; + param->modifiers = VKD3DSPSM_NONE; +} + +static void vsir_src_param_init_label(struct vkd3d_shader_src_param *param, unsigned int label_id) +{ + vsir_src_param_init(param, VKD3DSPR_LABEL, VKD3D_DATA_UINT, 1); + param->reg.dimension = VSIR_DIMENSION_NONE; + param->reg.idx[0].offset = label_id; +} + void vsir_instruction_init(struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location, enum vkd3d_shader_opcode handler_idx) { @@ -320,6 +335,23 @@ void vsir_instruction_init(struct vkd3d_shader_instruction *ins, const struct vk ins->handler_idx = handler_idx; }
+static bool vsir_instruction_init_label(struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location, + unsigned int label_id, void *parser) +{ + struct vkd3d_shader_src_param *src_param; + + if (!(src_param = shader_parser_get_src_params(parser, 1))) + return false; + + vsir_src_param_init_label(src_param, label_id); + + vsir_instruction_init(ins, location, VKD3DSIH_LABEL); + ins->src = src_param; + ins->src_count = 1; + + return true; +} + static enum vkd3d_result instruction_array_flatten_hull_shader_phases(struct vkd3d_shader_instruction_array *src_instructions) { struct hull_flattener flattener = {*src_instructions}; @@ -1476,6 +1508,324 @@ static enum vkd3d_result normalise_combined_samplers(struct vkd3d_shader_parser return VKD3D_OK; }
+struct cf_flattener_if_info +{ + struct vkd3d_shader_src_param *false_param; + uint32_t merge_block_id; + unsigned int else_block_id; +}; + +struct cf_flattener_info +{ + union + { + struct cf_flattener_if_info if_; + } u; + + enum + { + VKD3D_BLOCK_IF, + } current_block; + bool inside_block; +}; + +struct cf_flattener +{ + struct vkd3d_shader_parser *parser; + + struct vkd3d_shader_location location; + bool allocation_failed; + + struct vkd3d_shader_instruction *instructions; + size_t instruction_capacity; + size_t instruction_count; + + unsigned int block_id; + + unsigned int control_flow_depth; + struct cf_flattener_info *control_flow_info; + size_t control_flow_info_size; +}; + +static struct vkd3d_shader_instruction *cf_flattener_require_space(struct cf_flattener *flattener, size_t count) +{ + if (!vkd3d_array_reserve((void **)&flattener->instructions, &flattener->instruction_capacity, + flattener->instruction_count + count, sizeof(*flattener->instructions))) + { + ERR("Failed to allocate instructions.\n"); + flattener->allocation_failed = true; + return NULL; + } + return &flattener->instructions[flattener->instruction_count]; +} + +static bool cf_flattener_copy_instruction(struct cf_flattener *flattener, + const struct vkd3d_shader_instruction *instruction) +{ + struct vkd3d_shader_instruction *dst_ins; + + if (instruction->handler_idx == VKD3DSIH_NOP) + return true; + + if (!(dst_ins = cf_flattener_require_space(flattener, 1))) + return false; + + *dst_ins = *instruction; + ++flattener->instruction_count; + return true; +} + +static unsigned int cf_flattener_alloc_block_id(struct cf_flattener *flattener) +{ + return ++flattener->block_id; +} + +static struct vkd3d_shader_src_param *instruction_src_params_alloc(struct vkd3d_shader_instruction *ins, + unsigned int count, struct cf_flattener *flattener) +{ + struct vkd3d_shader_src_param *params = shader_parser_get_src_params(flattener->parser, count); + if (!params) + { + flattener->allocation_failed = true; + return NULL; + } + ins->src = params; + ins->src_count = count; + return params; +} + +static void cf_flattener_emit_label(struct cf_flattener *flattener, unsigned int label_id) +{ + struct vkd3d_shader_instruction *ins; + + if (!(ins = cf_flattener_require_space(flattener, 1))) + return; + if (vsir_instruction_init_label(ins, &flattener->location, label_id, flattener->parser)) + ++flattener->instruction_count; + else + flattener->allocation_failed = true; +} + +/* For conditional branches, this returns the false target branch parameter. */ +static struct vkd3d_shader_src_param *cf_flattener_emit_branch(struct cf_flattener *flattener, + unsigned int merge_block_id, const struct vkd3d_shader_src_param *condition, + unsigned int true_id, unsigned int false_id, + unsigned int flags) +{ + struct vkd3d_shader_src_param *src_params, *false_branch_param; + struct vkd3d_shader_instruction *ins; + + if (!(ins = cf_flattener_require_space(flattener, 1))) + return NULL; + vsir_instruction_init(ins, &flattener->location, VKD3DSIH_BRANCH); + + if (condition) + { + if (!(src_params = instruction_src_params_alloc(ins, 4, flattener))) + return NULL; + src_params[0] = *condition; + if (flags == VKD3D_SHADER_CONDITIONAL_OP_Z) + { + vsir_src_param_init_label(&src_params[1], false_id); + vsir_src_param_init_label(&src_params[2], true_id); + false_branch_param = &src_params[1]; + } + else + { + vsir_src_param_init_label(&src_params[1], true_id); + vsir_src_param_init_label(&src_params[2], false_id); + false_branch_param = &src_params[2]; + } + vsir_src_param_init_label(&src_params[3], merge_block_id); + } + else + { + if (!(src_params = instruction_src_params_alloc(ins, 1, flattener))) + return NULL; + vsir_src_param_init_label(&src_params[0], true_id); + false_branch_param = NULL; + } + + ++flattener->instruction_count; + + return false_branch_param; +} + +static void cf_flattener_emit_unconditional_branch(struct cf_flattener *flattener, unsigned int target_block_id) +{ + cf_flattener_emit_branch(flattener, 0, NULL, target_block_id, 0, 0); +} + +static struct cf_flattener_info *cf_flattener_push_control_flow_level(struct cf_flattener *flattener) +{ + if (!vkd3d_array_reserve((void **)&flattener->control_flow_info, &flattener->control_flow_info_size, + flattener->control_flow_depth + 1, sizeof(*flattener->control_flow_info))) + { + ERR("Failed to allocate control flow info structure.\n"); + flattener->allocation_failed = true; + return NULL; + } + + return &flattener->control_flow_info[flattener->control_flow_depth++]; +} + +static void cf_flattener_pop_control_flow_level(struct cf_flattener *flattener) +{ + struct cf_flattener_info *cf_info; + + cf_info = &flattener->control_flow_info[--flattener->control_flow_depth]; + memset(cf_info, 0, sizeof(*cf_info)); +} + +static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flattener *flattener) +{ + struct vkd3d_shader_parser *parser = flattener->parser; + struct vkd3d_shader_instruction_array *instructions; + struct vkd3d_shader_instruction *dst_ins; + unsigned int depth = 0; + bool main_block_open; + size_t i; + + instructions = &parser->instructions; + main_block_open = parser->shader_version.type != VKD3D_SHADER_TYPE_HULL; + + if (!cf_flattener_require_space(flattener, instructions->count)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + for (i = 0; i < instructions->count; ++i) + { + const struct vkd3d_shader_instruction *instruction = &instructions->elements[i]; + const struct vkd3d_shader_src_param *src = instruction->src; + unsigned int merge_block_id, true_block_id; + struct cf_flattener_info *cf_info; + + flattener->location = instruction->location; + + cf_info = flattener->control_flow_depth + ? &flattener->control_flow_info[flattener->control_flow_depth - 1] : NULL; + + switch (instruction->handler_idx) + { + case VKD3DSIH_LABEL: + vkd3d_shader_parser_error(parser, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, + "Aborting due to not yet implemented feature: Label instruction."); + return VKD3D_ERROR_NOT_IMPLEMENTED; + + case VKD3DSIH_IF: + if (!(cf_info = cf_flattener_push_control_flow_level(flattener))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + true_block_id = cf_flattener_alloc_block_id(flattener); + merge_block_id = cf_flattener_alloc_block_id(flattener); + cf_info->u.if_.false_param = cf_flattener_emit_branch(flattener, merge_block_id, + src, true_block_id, merge_block_id, instruction->flags); + if (!cf_info->u.if_.false_param) + return VKD3D_ERROR_OUT_OF_MEMORY; + + cf_flattener_emit_label(flattener, true_block_id); + + cf_info->u.if_.merge_block_id = merge_block_id; + cf_info->u.if_.else_block_id = 0; + cf_info->inside_block = true; + cf_info->current_block = VKD3D_BLOCK_IF; + break; + + case VKD3DSIH_ELSE: + if (cf_info->inside_block) + cf_flattener_emit_unconditional_branch(flattener, cf_info->u.if_.merge_block_id); + + cf_info->u.if_.else_block_id = cf_flattener_alloc_block_id(flattener); + cf_info->u.if_.false_param->reg.idx[0].offset = cf_info->u.if_.else_block_id; + + cf_flattener_emit_label(flattener, cf_info->u.if_.else_block_id); + + cf_info->inside_block = true; + break; + + case VKD3DSIH_ENDIF: + if (cf_info->inside_block) + cf_flattener_emit_unconditional_branch(flattener, cf_info->u.if_.merge_block_id); + + cf_flattener_emit_label(flattener, cf_info->u.if_.merge_block_id); + + cf_flattener_pop_control_flow_level(flattener); + break; + + case VKD3DSIH_LOOP: + case VKD3DSIH_SWITCH: + ++depth; + if (!cf_flattener_copy_instruction(flattener, instruction)) + return VKD3D_ERROR_OUT_OF_MEMORY; + break; + + case VKD3DSIH_ENDLOOP: + case VKD3DSIH_ENDSWITCH: + --depth; + if (cf_info) + cf_info->inside_block = true; /* Dead code removal ensures this is correct. */ + if (!cf_flattener_copy_instruction(flattener, instruction)) + return VKD3D_ERROR_OUT_OF_MEMORY; + break; + + case VKD3DSIH_RET: + if (!cf_flattener_copy_instruction(flattener, instruction)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + if (cf_info) + cf_info->inside_block = false; + else if (!depth) + main_block_open = false; + break; + + case VKD3DSIH_BREAK: + case VKD3DSIH_CONTINUE: + if (cf_info) + cf_info->inside_block = false; + /* fall through */ + default: + if (!cf_flattener_copy_instruction(flattener, instruction)) + return VKD3D_ERROR_OUT_OF_MEMORY; + break; + } + } + + if (main_block_open) + { + if (!(dst_ins = cf_flattener_require_space(flattener, 1))) + return VKD3D_ERROR_OUT_OF_MEMORY; + vsir_instruction_init(dst_ins, &flattener->location, VKD3DSIH_RET); + ++flattener->instruction_count; + } + + return flattener->allocation_failed ? VKD3D_ERROR_OUT_OF_MEMORY : VKD3D_OK; +} + +static enum vkd3d_result flatten_control_flow_constructs(struct vkd3d_shader_parser *parser) +{ + struct cf_flattener flattener = {0}; + enum vkd3d_result result; + + flattener.parser = parser; + result = cf_flattener_iterate_instruction_array(&flattener); + + if (result >= 0) + { + vkd3d_free(parser->instructions.elements); + parser->instructions.elements = flattener.instructions; + parser->instructions.capacity = flattener.instruction_capacity; + parser->instructions.count = flattener.instruction_count; + parser->shader_desc.block_count = flattener.block_id; + } + else + { + vkd3d_free(flattener.instructions); + } + + vkd3d_free(flattener.control_flow_info); + + return result; +} + enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser, const struct vkd3d_shader_compile_info *compile_info) { @@ -1504,6 +1854,9 @@ enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser, if (result >= 0) remove_dead_code(parser);
+ if (result >= 0) + result = flatten_control_flow_constructs(parser); + if (result >= 0) result = normalise_combined_samplers(parser);
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index c249b178d..8b19b9bb4 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -855,20 +855,6 @@ static void vkd3d_spirv_end_function_stream_insertion(struct vkd3d_spirv_builder builder->insertion_location = ~(size_t)0; }
-struct vkd3d_spirv_op_branch_conditional -{ - uint32_t opcode; - uint32_t condition_id; - uint32_t true_label; - uint32_t false_label; -}; - -static struct vkd3d_spirv_op_branch_conditional *vkd3d_spirv_as_op_branch_conditional( - struct vkd3d_spirv_stream *stream, size_t location) -{ - return (struct vkd3d_spirv_op_branch_conditional *)&stream->words[location]; -} - static void vkd3d_spirv_build_op_capability(struct vkd3d_spirv_stream *stream, SpvCapability cap) { @@ -2267,14 +2253,6 @@ static const char *debug_vkd3d_symbol(const struct vkd3d_symbol *symbol) } }
-struct vkd3d_if_cf_info -{ - size_t stream_location; - unsigned int id; - uint32_t merge_block_id; - uint32_t else_block_id; -}; - struct vkd3d_loop_cf_info { uint32_t header_block_id; @@ -2298,14 +2276,12 @@ struct vkd3d_control_flow_info { union { - struct vkd3d_if_cf_info if_; struct vkd3d_loop_cf_info loop; struct vkd3d_switch_cf_info switch_; } u;
enum { - VKD3D_BLOCK_IF, VKD3D_BLOCK_LOOP, VKD3D_BLOCK_SWITCH, } current_block; @@ -2365,7 +2341,6 @@ struct spirv_compiler
enum vkd3d_shader_type shader_type;
- unsigned int branch_id; unsigned int loop_id; unsigned int switch_id; unsigned int control_flow_depth; @@ -2380,7 +2355,6 @@ struct spirv_compiler struct vkd3d_push_constant_buffer_binding *push_constants; const struct vkd3d_shader_spirv_target_info *spirv_target_info;
- bool main_block_open; bool after_declarations_section; struct shader_signature input_signature; struct shader_signature output_signature; @@ -2422,6 +2396,9 @@ struct spirv_compiler unsigned int ssa_register_count;
uint64_t config_flags; + + uint32_t *block_label_ids; + unsigned int block_count; };
static bool is_in_default_phase(const struct spirv_compiler *compiler) @@ -2471,6 +2448,7 @@ static void spirv_compiler_destroy(struct spirv_compiler *compiler) shader_signature_cleanup(&compiler->patch_constant_signature);
vkd3d_free(compiler->ssa_register_info); + vkd3d_free(compiler->block_label_ids);
vkd3d_free(compiler); } @@ -2806,6 +2784,14 @@ static struct vkd3d_string_buffer *vkd3d_shader_register_range_string(struct spi return buffer; }
+static uint32_t spirv_compiler_get_label_id(struct spirv_compiler *compiler, unsigned int block_id) +{ + --block_id; + if (!compiler->block_label_ids[block_id]) + compiler->block_label_ids[block_id] = vkd3d_spirv_alloc_id(&compiler->spirv_builder); + return compiler->block_label_ids[block_id]; +} + static struct vkd3d_shader_descriptor_binding spirv_compiler_get_descriptor_binding( struct spirv_compiler *compiler, const struct vkd3d_shader_register *reg, const struct vkd3d_shader_register_range *range, enum vkd3d_shader_resource_type resource_type, @@ -5550,7 +5536,6 @@ static void spirv_compiler_emit_initial_declarations(struct spirv_compiler *comp if (compiler->shader_type != VKD3D_SHADER_TYPE_HULL) { vkd3d_spirv_builder_begin_main_function(builder); - compiler->main_block_open = true; } }
@@ -7665,72 +7650,27 @@ static struct vkd3d_control_flow_info *spirv_compiler_find_innermost_breakable_c return NULL; }
+static void spirv_compiler_emit_label(struct spirv_compiler *compiler, + const struct vkd3d_shader_instruction *instruction); + static int spirv_compiler_emit_control_flow_instruction(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { uint32_t loop_header_block_id, loop_body_block_id, continue_block_id; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; const struct vkd3d_shader_src_param *src = instruction->src; - uint32_t merge_block_id, val_id, condition_id, true_label; struct vkd3d_control_flow_info *cf_info; + uint32_t merge_block_id, val_id;
cf_info = compiler->control_flow_depth ? &compiler->control_flow_info[compiler->control_flow_depth - 1] : NULL;
switch (instruction->handler_idx) { - case VKD3DSIH_IF: - if (!(cf_info = spirv_compiler_push_control_flow_level(compiler))) - return VKD3D_ERROR_OUT_OF_MEMORY; - - val_id = spirv_compiler_emit_load_src(compiler, src, VKD3DSP_WRITEMASK_0); - condition_id = spirv_compiler_emit_int_to_bool(compiler, instruction->flags, src->reg.data_type, 1, val_id); - - true_label = vkd3d_spirv_alloc_id(builder); - merge_block_id = vkd3d_spirv_alloc_id(builder); - vkd3d_spirv_build_op_selection_merge(builder, merge_block_id, SpvSelectionControlMaskNone); - cf_info->u.if_.stream_location = vkd3d_spirv_stream_current_location(&builder->function_stream); - vkd3d_spirv_build_op_branch_conditional(builder, condition_id, true_label, merge_block_id); - - vkd3d_spirv_build_op_label(builder, true_label); - - cf_info->u.if_.id = compiler->branch_id; - cf_info->u.if_.merge_block_id = merge_block_id; - cf_info->u.if_.else_block_id = 0; - cf_info->inside_block = true; - cf_info->current_block = VKD3D_BLOCK_IF; - - vkd3d_spirv_build_op_name(builder, merge_block_id, "branch%u_merge", compiler->branch_id); - vkd3d_spirv_build_op_name(builder, true_label, "branch%u_true", compiler->branch_id); - ++compiler->branch_id; - break; - - case VKD3DSIH_ELSE: - assert(compiler->control_flow_depth); - assert(cf_info->current_block == VKD3D_BLOCK_IF); - - if (cf_info->inside_block) - vkd3d_spirv_build_op_branch(builder, cf_info->u.if_.merge_block_id); - - cf_info->u.if_.else_block_id = vkd3d_spirv_alloc_id(builder); - vkd3d_spirv_as_op_branch_conditional(&builder->function_stream, - cf_info->u.if_.stream_location)->false_label = cf_info->u.if_.else_block_id; - vkd3d_spirv_build_op_name(builder, - cf_info->u.if_.else_block_id, "branch%u_false", cf_info->u.if_.id); - vkd3d_spirv_build_op_label(builder, cf_info->u.if_.else_block_id); - cf_info->inside_block = true; - break; - - case VKD3DSIH_ENDIF: - assert(compiler->control_flow_depth); - assert(cf_info->current_block == VKD3D_BLOCK_IF); - - if (cf_info->inside_block) - vkd3d_spirv_build_op_branch(builder, cf_info->u.if_.merge_block_id); - - vkd3d_spirv_build_op_label(builder, cf_info->u.if_.merge_block_id); - - spirv_compiler_pop_control_flow_level(compiler); + case VKD3DSIH_LABEL: + if (cf_info) + cf_info->inside_block = true; + spirv_compiler_emit_label(compiler, instruction); break;
case VKD3DSIH_LOOP: @@ -7967,8 +7907,6 @@ static int spirv_compiler_emit_control_flow_instruction(struct spirv_compiler *c
if (cf_info) cf_info->inside_block = false; - else - compiler->main_block_open = false; break;
default: @@ -7979,6 +7917,70 @@ static int spirv_compiler_emit_control_flow_instruction(struct spirv_compiler *c return VKD3D_OK; }
+static bool spirv_compiler_init_blocks(struct spirv_compiler *compiler, unsigned int block_count) +{ + compiler->block_count = block_count; + + if (!(compiler->block_label_ids = vkd3d_calloc(block_count, sizeof(*compiler->block_label_ids)))) + return false; + + return true; +} + +static void spirv_compiler_emit_label(struct spirv_compiler *compiler, + const struct vkd3d_shader_instruction *instruction) +{ + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + const struct vkd3d_shader_src_param *src = instruction->src; + unsigned int block_id = src->reg.idx[0].offset; + uint32_t label_id; + + label_id = spirv_compiler_get_label_id(compiler, block_id); + vkd3d_spirv_build_op_label(builder, label_id); +} + +static void spirv_compiler_emit_merge(struct spirv_compiler *compiler, + uint32_t merge_block_id) +{ + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + + if (!merge_block_id) + return; + + merge_block_id = spirv_compiler_get_label_id(compiler, merge_block_id); + vkd3d_spirv_build_op_selection_merge(builder, merge_block_id, SpvSelectionControlMaskNone); +} + +static void spirv_compiler_emit_branch(struct spirv_compiler *compiler, + const struct vkd3d_shader_instruction *instruction) +{ + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + const struct vkd3d_shader_src_param *src = instruction->src; + uint32_t condition_id; + + if (vsir_register_is_label(&src[0].reg)) + { + vkd3d_spirv_build_op_branch(builder, spirv_compiler_get_label_id(compiler, src[0].reg.idx[0].offset)); + return; + } + + if (!vkd3d_swizzle_is_scalar(src->swizzle)) + { + WARN("Unexpected src swizzle %#x.\n", src->swizzle); + spirv_compiler_warning(compiler, VKD3D_SHADER_WARNING_SPV_INVALID_SWIZZLE, + "The swizzle for a branch condition value is not scalar."); + } + + condition_id = spirv_compiler_emit_load_src(compiler, &src[0], VKD3DSP_WRITEMASK_0); + condition_id = spirv_compiler_emit_int_to_bool(compiler, + VKD3D_SHADER_CONDITIONAL_OP_NZ, src[0].reg.data_type, 1, condition_id); + /* Emit the merge immediately before the branch instruction. */ + spirv_compiler_emit_merge(compiler, src[3].reg.idx[0].offset); + vkd3d_spirv_build_op_branch_conditional(builder, condition_id, + spirv_compiler_get_label_id(compiler, src[1].reg.idx[0].offset), + spirv_compiler_get_label_id(compiler, src[2].reg.idx[0].offset)); +} + static void spirv_compiler_emit_deriv_instruction(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { @@ -9729,11 +9731,9 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_CONTINUE: case VKD3DSIH_CONTINUEP: case VKD3DSIH_DEFAULT: - case VKD3DSIH_ELSE: - case VKD3DSIH_ENDIF: case VKD3DSIH_ENDLOOP: case VKD3DSIH_ENDSWITCH: - case VKD3DSIH_IF: + case VKD3DSIH_LABEL: case VKD3DSIH_LOOP: case VKD3DSIH_RET: case VKD3DSIH_SWITCH: @@ -9746,6 +9746,9 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_TEXKILL: spirv_compiler_emit_kill(compiler, instruction); break; + case VKD3DSIH_BRANCH: + spirv_compiler_emit_branch(compiler, instruction); + break; case VKD3DSIH_DSX: case VKD3DSIH_DSX_COARSE: case VKD3DSIH_DSX_FINE: @@ -9966,6 +9969,9 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, if ((result = vkd3d_shader_normalise(parser, compile_info)) < 0) return result;
+ if (parser->shader_desc.block_count && !spirv_compiler_init_blocks(compiler, parser->shader_desc.block_count)) + return VKD3D_ERROR_OUT_OF_MEMORY; + instructions = parser->instructions; memset(&parser->instructions, 0, sizeof(parser->instructions));
@@ -9996,9 +10002,6 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, if (result < 0) return result;
- if (compiler->main_block_open) - vkd3d_spirv_build_op_return(builder); - if (!is_in_default_phase(compiler)) spirv_compiler_leave_shader_phase(compiler); else diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 199a47a76..30672950b 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -237,6 +237,7 @@ enum vkd3d_shader_opcode VKD3DSIH_BEM, VKD3DSIH_BFI, VKD3DSIH_BFREV, + VKD3DSIH_BRANCH, VKD3DSIH_BREAK, VKD3DSIH_BREAKC, VKD3DSIH_BREAKP, @@ -1015,6 +1016,7 @@ struct vkd3d_shader_desc
uint32_t temp_count; unsigned int ssa_count; + unsigned int block_count;
struct { @@ -1184,6 +1186,11 @@ static inline bool register_is_constant(const struct vkd3d_shader_register *reg) return (reg->type == VKD3DSPR_IMMCONST || reg->type == VKD3DSPR_IMMCONST64); }
+static inline bool vsir_register_is_label(const struct vkd3d_shader_register *reg) +{ + return reg->type == VKD3DSPR_LABEL; +} + struct vkd3d_shader_param_node { struct vkd3d_shader_param_node *next;
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/ir.c | 194 ++++++++++++++++++++++++++++++++++---- libs/vkd3d-shader/spirv.c | 151 ++++------------------------- 2 files changed, 194 insertions(+), 151 deletions(-)
diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index 33a6aec8d..39c02a14f 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -1515,16 +1515,26 @@ struct cf_flattener_if_info unsigned int else_block_id; };
+struct cf_flattener_loop_info +{ + unsigned int header_block_id; + unsigned int continue_block_id; + uint32_t merge_block_id; +}; + struct cf_flattener_info { union { struct cf_flattener_if_info if_; + struct cf_flattener_loop_info loop; } u;
enum { VKD3D_BLOCK_IF, + VKD3D_BLOCK_LOOP, + VKD3D_BLOCK_SWITCH, } current_block; bool inside_block; }; @@ -1608,8 +1618,8 @@ static void cf_flattener_emit_label(struct cf_flattener *flattener, unsigned int
/* For conditional branches, this returns the false target branch parameter. */ static struct vkd3d_shader_src_param *cf_flattener_emit_branch(struct cf_flattener *flattener, - unsigned int merge_block_id, const struct vkd3d_shader_src_param *condition, - unsigned int true_id, unsigned int false_id, + unsigned int merge_block_id, unsigned int continue_block_id, + const struct vkd3d_shader_src_param *condition, unsigned int true_id, unsigned int false_id, unsigned int flags) { struct vkd3d_shader_src_param *src_params, *false_branch_param; @@ -1621,7 +1631,7 @@ static struct vkd3d_shader_src_param *cf_flattener_emit_branch(struct cf_flatten
if (condition) { - if (!(src_params = instruction_src_params_alloc(ins, 4, flattener))) + if (!(src_params = instruction_src_params_alloc(ins, 4 + !!continue_block_id, flattener))) return NULL; src_params[0] = *condition; if (flags == VKD3D_SHADER_CONDITIONAL_OP_Z) @@ -1637,12 +1647,21 @@ static struct vkd3d_shader_src_param *cf_flattener_emit_branch(struct cf_flatten false_branch_param = &src_params[2]; } vsir_src_param_init_label(&src_params[3], merge_block_id); + if (continue_block_id) + vsir_src_param_init_label(&src_params[4], continue_block_id); } else { - if (!(src_params = instruction_src_params_alloc(ins, 1, flattener))) + if (!(src_params = instruction_src_params_alloc(ins, merge_block_id ? 3 : 1, flattener))) return NULL; vsir_src_param_init_label(&src_params[0], true_id); + if (merge_block_id) + { + /* An unconditional branch may only have merge information for a loop, which + * must have both a merge block and continue block. */ + vsir_src_param_init_label(&src_params[1], merge_block_id); + vsir_src_param_init_label(&src_params[2], continue_block_id); + } false_branch_param = NULL; }
@@ -1651,9 +1670,19 @@ static struct vkd3d_shader_src_param *cf_flattener_emit_branch(struct cf_flatten return false_branch_param; }
+static void cf_flattener_emit_conditional_branch_and_merge(struct cf_flattener *flattener, + const struct vkd3d_shader_src_param *condition, unsigned int true_id, unsigned int flags) +{ + unsigned int merge_block_id; + + merge_block_id = cf_flattener_alloc_block_id(flattener); + cf_flattener_emit_branch(flattener, merge_block_id, 0, condition, true_id, merge_block_id, flags); + cf_flattener_emit_label(flattener, merge_block_id); +} + static void cf_flattener_emit_unconditional_branch(struct cf_flattener *flattener, unsigned int target_block_id) { - cf_flattener_emit_branch(flattener, 0, NULL, target_block_id, 0, 0); + cf_flattener_emit_branch(flattener, 0, 0, NULL, target_block_id, 0, 0); }
static struct cf_flattener_info *cf_flattener_push_control_flow_level(struct cf_flattener *flattener) @@ -1677,12 +1706,38 @@ static void cf_flattener_pop_control_flow_level(struct cf_flattener *flattener) memset(cf_info, 0, sizeof(*cf_info)); }
+static struct cf_flattener_info *cf_flattener_find_innermost_loop(struct cf_flattener *flattener) +{ + int depth; + + for (depth = flattener->control_flow_depth - 1; depth >= 0; --depth) + { + if (flattener->control_flow_info[depth].current_block == VKD3D_BLOCK_LOOP) + return &flattener->control_flow_info[depth]; + } + + return NULL; +} + +static struct cf_flattener_info *cf_flattener_find_innermost_breakable_cf_construct(struct cf_flattener *flattener) +{ + int depth; + + for (depth = flattener->control_flow_depth - 1; depth >= 0; --depth) + { + if (flattener->control_flow_info[depth].current_block == VKD3D_BLOCK_LOOP + || flattener->control_flow_info[depth].current_block == VKD3D_BLOCK_SWITCH) + return &flattener->control_flow_info[depth]; + } + + return NULL; +} + static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flattener *flattener) { struct vkd3d_shader_parser *parser = flattener->parser; struct vkd3d_shader_instruction_array *instructions; struct vkd3d_shader_instruction *dst_ins; - unsigned int depth = 0; bool main_block_open; size_t i;
@@ -1694,9 +1749,9 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte
for (i = 0; i < instructions->count; ++i) { + unsigned int loop_header_block_id, loop_body_block_id, continue_block_id, merge_block_id, true_block_id; const struct vkd3d_shader_instruction *instruction = &instructions->elements[i]; const struct vkd3d_shader_src_param *src = instruction->src; - unsigned int merge_block_id, true_block_id; struct cf_flattener_info *cf_info;
flattener->location = instruction->location; @@ -1717,7 +1772,7 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte
true_block_id = cf_flattener_alloc_block_id(flattener); merge_block_id = cf_flattener_alloc_block_id(flattener); - cf_info->u.if_.false_param = cf_flattener_emit_branch(flattener, merge_block_id, + cf_info->u.if_.false_param = cf_flattener_emit_branch(flattener, merge_block_id, 0, src, true_block_id, merge_block_id, instruction->flags); if (!cf_info->u.if_.false_param) return VKD3D_ERROR_OUT_OF_MEMORY; @@ -1752,36 +1807,137 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte break;
case VKD3DSIH_LOOP: + if (!(cf_info = cf_flattener_push_control_flow_level(flattener))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + loop_header_block_id = cf_flattener_alloc_block_id(flattener); + loop_body_block_id = cf_flattener_alloc_block_id(flattener); + continue_block_id = cf_flattener_alloc_block_id(flattener); + merge_block_id = cf_flattener_alloc_block_id(flattener); + + cf_flattener_emit_unconditional_branch(flattener, loop_header_block_id); + cf_flattener_emit_label(flattener, loop_header_block_id); + cf_flattener_emit_branch(flattener, merge_block_id, continue_block_id, + NULL, loop_body_block_id, 0, 0); + + cf_flattener_emit_label(flattener, loop_body_block_id); + + cf_info->u.loop.header_block_id = loop_header_block_id; + cf_info->u.loop.continue_block_id = continue_block_id; + cf_info->u.loop.merge_block_id = merge_block_id; + cf_info->current_block = VKD3D_BLOCK_LOOP; + cf_info->inside_block = true; + break; + + case VKD3DSIH_ENDLOOP: + if (cf_info->inside_block) + cf_flattener_emit_unconditional_branch(flattener, cf_info->u.loop.continue_block_id); + + cf_flattener_emit_label(flattener, cf_info->u.loop.continue_block_id); + cf_flattener_emit_unconditional_branch(flattener, cf_info->u.loop.header_block_id); + cf_flattener_emit_label(flattener, cf_info->u.loop.merge_block_id); + + cf_flattener_pop_control_flow_level(flattener); + break; + case VKD3DSIH_SWITCH: - ++depth; + if (!(cf_info = cf_flattener_push_control_flow_level(flattener))) + return VKD3D_ERROR_OUT_OF_MEMORY; + if (!cf_flattener_copy_instruction(flattener, instruction)) return VKD3D_ERROR_OUT_OF_MEMORY; + + cf_info->current_block = VKD3D_BLOCK_SWITCH; + break;
- case VKD3DSIH_ENDLOOP: case VKD3DSIH_ENDSWITCH: - --depth; - if (cf_info) - cf_info->inside_block = true; /* Dead code removal ensures this is correct. */ + cf_flattener_pop_control_flow_level(flattener); + if (!cf_flattener_copy_instruction(flattener, instruction)) return VKD3D_ERROR_OUT_OF_MEMORY; break;
+ case VKD3DSIH_BREAK: + { + struct cf_flattener_info *breakable_cf_info; + + if (!(breakable_cf_info = cf_flattener_find_innermost_breakable_cf_construct(flattener))) + { + FIXME("Unhandled break instruction.\n"); + return VKD3D_ERROR_INVALID_SHADER; + } + + if (breakable_cf_info->current_block == VKD3D_BLOCK_LOOP) + { + cf_flattener_emit_unconditional_branch(flattener, breakable_cf_info->u.loop.merge_block_id); + } + else if (breakable_cf_info->current_block == VKD3D_BLOCK_SWITCH) + { + if (!cf_flattener_copy_instruction(flattener, instruction)) + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + cf_info->inside_block = false; + break; + } + + case VKD3DSIH_BREAKP: + { + struct cf_flattener_info *loop_cf_info; + + if (!(loop_cf_info = cf_flattener_find_innermost_loop(flattener))) + { + ERR("Invalid 'breakc' instruction outside loop.\n"); + return VKD3D_ERROR_INVALID_SHADER; + } + + cf_flattener_emit_conditional_branch_and_merge(flattener, + src, loop_cf_info->u.loop.merge_block_id, instruction->flags); + break; + } + + case VKD3DSIH_CONTINUE: + { + struct cf_flattener_info *loop_cf_info; + + if (!(loop_cf_info = cf_flattener_find_innermost_loop(flattener))) + { + ERR("Invalid 'continue' instruction outside loop.\n"); + return VKD3D_ERROR_INVALID_SHADER; + } + + cf_flattener_emit_unconditional_branch(flattener, loop_cf_info->u.loop.continue_block_id); + + cf_info->inside_block = false; + break; + } + + case VKD3DSIH_CONTINUEP: + { + struct cf_flattener_info *loop_cf_info; + + if (!(loop_cf_info = cf_flattener_find_innermost_loop(flattener))) + { + ERR("Invalid 'continuec' instruction outside loop.\n"); + return VKD3D_ERROR_INVALID_SHADER; + } + + cf_flattener_emit_conditional_branch_and_merge(flattener, + src, loop_cf_info->u.loop.continue_block_id, instruction->flags); + break; + } + case VKD3DSIH_RET: if (!cf_flattener_copy_instruction(flattener, instruction)) return VKD3D_ERROR_OUT_OF_MEMORY;
if (cf_info) cf_info->inside_block = false; - else if (!depth) + else main_block_open = false; break;
- case VKD3DSIH_BREAK: - case VKD3DSIH_CONTINUE: - if (cf_info) - cf_info->inside_block = false; - /* fall through */ default: if (!cf_flattener_copy_instruction(flattener, instruction)) return VKD3D_ERROR_OUT_OF_MEMORY; diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 8b19b9bb4..e5bd45d9c 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2253,13 +2253,6 @@ static const char *debug_vkd3d_symbol(const struct vkd3d_symbol *symbol) } }
-struct vkd3d_loop_cf_info -{ - uint32_t header_block_id; - uint32_t continue_block_id; - uint32_t merge_block_id; -}; - struct vkd3d_switch_cf_info { size_t stream_location; @@ -2276,13 +2269,11 @@ struct vkd3d_control_flow_info { union { - struct vkd3d_loop_cf_info loop; struct vkd3d_switch_cf_info switch_; } u;
enum { - VKD3D_BLOCK_LOOP, VKD3D_BLOCK_SWITCH, } current_block; bool inside_block; @@ -2341,7 +2332,6 @@ struct spirv_compiler
enum vkd3d_shader_type shader_type;
- unsigned int loop_id; unsigned int switch_id; unsigned int control_flow_depth; struct vkd3d_control_flow_info *control_flow_info; @@ -7621,20 +7611,6 @@ static void spirv_compiler_pop_control_flow_level(struct spirv_compiler *compile memset(cf_info, 0, sizeof(*cf_info)); }
-static struct vkd3d_control_flow_info *spirv_compiler_find_innermost_loop( - struct spirv_compiler *compiler) -{ - int depth; - - for (depth = compiler->control_flow_depth - 1; depth >= 0; --depth) - { - if (compiler->control_flow_info[depth].current_block == VKD3D_BLOCK_LOOP) - return &compiler->control_flow_info[depth]; - } - - return NULL; -} - static struct vkd3d_control_flow_info *spirv_compiler_find_innermost_breakable_cf_construct( struct spirv_compiler *compiler) { @@ -7642,8 +7618,7 @@ static struct vkd3d_control_flow_info *spirv_compiler_find_innermost_breakable_c
for (depth = compiler->control_flow_depth - 1; depth >= 0; --depth) { - if (compiler->control_flow_info[depth].current_block == VKD3D_BLOCK_LOOP - || compiler->control_flow_info[depth].current_block == VKD3D_BLOCK_SWITCH) + if (compiler->control_flow_info[depth].current_block == VKD3D_BLOCK_SWITCH) return &compiler->control_flow_info[depth]; }
@@ -7656,7 +7631,6 @@ static void spirv_compiler_emit_label(struct spirv_compiler *compiler, static int spirv_compiler_emit_control_flow_instruction(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { - uint32_t loop_header_block_id, loop_body_block_id, continue_block_id; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; const struct vkd3d_shader_src_param *src = instruction->src; struct vkd3d_control_flow_info *cf_info; @@ -7673,51 +7647,6 @@ static int spirv_compiler_emit_control_flow_instruction(struct spirv_compiler *c spirv_compiler_emit_label(compiler, instruction); break;
- case VKD3DSIH_LOOP: - if (!(cf_info = spirv_compiler_push_control_flow_level(compiler))) - return VKD3D_ERROR_OUT_OF_MEMORY; - - loop_header_block_id = vkd3d_spirv_alloc_id(builder); - loop_body_block_id = vkd3d_spirv_alloc_id(builder); - continue_block_id = vkd3d_spirv_alloc_id(builder); - merge_block_id = vkd3d_spirv_alloc_id(builder); - - vkd3d_spirv_build_op_branch(builder, loop_header_block_id); - vkd3d_spirv_build_op_label(builder, loop_header_block_id); - vkd3d_spirv_build_op_loop_merge(builder, merge_block_id, continue_block_id, SpvLoopControlMaskNone); - vkd3d_spirv_build_op_branch(builder, loop_body_block_id); - - vkd3d_spirv_build_op_label(builder, loop_body_block_id); - - cf_info->u.loop.header_block_id = loop_header_block_id; - cf_info->u.loop.continue_block_id = continue_block_id; - cf_info->u.loop.merge_block_id = merge_block_id; - cf_info->current_block = VKD3D_BLOCK_LOOP; - cf_info->inside_block = true; - - vkd3d_spirv_build_op_name(builder, loop_header_block_id, "loop%u_header", compiler->loop_id); - vkd3d_spirv_build_op_name(builder, loop_body_block_id, "loop%u_body", compiler->loop_id); - vkd3d_spirv_build_op_name(builder, continue_block_id, "loop%u_continue", compiler->loop_id); - vkd3d_spirv_build_op_name(builder, merge_block_id, "loop%u_merge", compiler->loop_id); - ++compiler->loop_id; - break; - - case VKD3DSIH_ENDLOOP: - assert(compiler->control_flow_depth); - assert(cf_info->current_block == VKD3D_BLOCK_LOOP); - - /* The loop block may have already been ended by an unconditional - * break instruction right before the end of the loop. */ - if (cf_info->inside_block) - vkd3d_spirv_build_op_branch(builder, cf_info->u.loop.continue_block_id); - - vkd3d_spirv_build_op_label(builder, cf_info->u.loop.continue_block_id); - vkd3d_spirv_build_op_branch(builder, cf_info->u.loop.header_block_id); - vkd3d_spirv_build_op_label(builder, cf_info->u.loop.merge_block_id); - - spirv_compiler_pop_control_flow_level(compiler); - break; - case VKD3DSIH_SWITCH: if (!(cf_info = spirv_compiler_push_control_flow_level(compiler))) return VKD3D_ERROR_OUT_OF_MEMORY; @@ -7834,11 +7763,7 @@ static int spirv_compiler_emit_control_flow_instruction(struct spirv_compiler *c return VKD3D_ERROR_INVALID_SHADER; }
- if (breakable_cf_info->current_block == VKD3D_BLOCK_LOOP) - { - vkd3d_spirv_build_op_branch(builder, breakable_cf_info->u.loop.merge_block_id); - } - else if (breakable_cf_info->current_block == VKD3D_BLOCK_SWITCH) + if (breakable_cf_info->current_block == VKD3D_BLOCK_SWITCH) { /* The current case block may have already been ended by an * unconditional continue instruction. */ @@ -7850,58 +7775,6 @@ static int spirv_compiler_emit_control_flow_instruction(struct spirv_compiler *c break; }
- case VKD3DSIH_BREAKP: - { - struct vkd3d_control_flow_info *loop_cf_info; - - assert(compiler->control_flow_depth); - - if (!(loop_cf_info = spirv_compiler_find_innermost_loop(compiler))) - { - ERR("Invalid 'breakc' instruction outside loop.\n"); - return VKD3D_ERROR_INVALID_SHADER; - } - - merge_block_id = spirv_compiler_emit_conditional_branch(compiler, - instruction, loop_cf_info->u.loop.merge_block_id); - vkd3d_spirv_build_op_label(builder, merge_block_id); - break; - } - - case VKD3DSIH_CONTINUE: - { - struct vkd3d_control_flow_info *loop_cf_info; - - assert(compiler->control_flow_depth); - - if (!(loop_cf_info = spirv_compiler_find_innermost_loop(compiler))) - { - ERR("Invalid 'continue' instruction outside loop.\n"); - return VKD3D_ERROR_INVALID_SHADER; - } - - vkd3d_spirv_build_op_branch(builder, loop_cf_info->u.loop.continue_block_id); - - cf_info->inside_block = false; - break; - } - - case VKD3DSIH_CONTINUEP: - { - struct vkd3d_control_flow_info *loop_cf_info; - - if (!(loop_cf_info = spirv_compiler_find_innermost_loop(compiler))) - { - ERR("Invalid 'continuec' instruction outside loop.\n"); - return VKD3D_ERROR_INVALID_SHADER; - } - - merge_block_id = spirv_compiler_emit_conditional_branch(compiler, - instruction, loop_cf_info->u.loop.continue_block_id); - vkd3d_spirv_build_op_label(builder, merge_block_id); - break; - } - case VKD3DSIH_RET: spirv_compiler_emit_return(compiler, instruction);
@@ -7940,7 +7813,7 @@ static void spirv_compiler_emit_label(struct spirv_compiler *compiler, }
static void spirv_compiler_emit_merge(struct spirv_compiler *compiler, - uint32_t merge_block_id) + uint32_t merge_block_id, uint32_t continue_block_id) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
@@ -7948,7 +7821,15 @@ static void spirv_compiler_emit_merge(struct spirv_compiler *compiler, return;
merge_block_id = spirv_compiler_get_label_id(compiler, merge_block_id); - vkd3d_spirv_build_op_selection_merge(builder, merge_block_id, SpvSelectionControlMaskNone); + if (!continue_block_id) + { + vkd3d_spirv_build_op_selection_merge(builder, merge_block_id, SpvSelectionControlMaskNone); + } + else + { + continue_block_id = spirv_compiler_get_label_id(compiler, continue_block_id); + vkd3d_spirv_build_op_loop_merge(builder, merge_block_id, continue_block_id, SpvLoopControlMaskNone); + } }
static void spirv_compiler_emit_branch(struct spirv_compiler *compiler, @@ -7960,6 +7841,11 @@ static void spirv_compiler_emit_branch(struct spirv_compiler *compiler,
if (vsir_register_is_label(&src[0].reg)) { + if (instruction->src_count > 1) + { + /* Loop merge only. Must have a merge block and a continue block. */ + spirv_compiler_emit_merge(compiler, src[1].reg.idx[0].offset, src[2].reg.idx[0].offset); + } vkd3d_spirv_build_op_branch(builder, spirv_compiler_get_label_id(compiler, src[0].reg.idx[0].offset)); return; } @@ -7975,7 +7861,8 @@ static void spirv_compiler_emit_branch(struct spirv_compiler *compiler, condition_id = spirv_compiler_emit_int_to_bool(compiler, VKD3D_SHADER_CONDITIONAL_OP_NZ, src[0].reg.data_type, 1, condition_id); /* Emit the merge immediately before the branch instruction. */ - spirv_compiler_emit_merge(compiler, src[3].reg.idx[0].offset); + spirv_compiler_emit_merge(compiler, src[3].reg.idx[0].offset, + (instruction->src_count > 4) ? src[4].reg.idx[0].offset : 0); vkd3d_spirv_build_op_branch_conditional(builder, condition_id, spirv_compiler_get_label_id(compiler, src[1].reg.idx[0].offset), spirv_compiler_get_label_id(compiler, src[2].reg.idx[0].offset));
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/d3d_asm.c | 1 + libs/vkd3d-shader/ir.c | 110 ++++++++- libs/vkd3d-shader/spirv.c | 295 ++++------------------- libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 4 files changed, 155 insertions(+), 252 deletions(-)
diff --git a/libs/vkd3d-shader/d3d_asm.c b/libs/vkd3d-shader/d3d_asm.c index 2fbd98936..120eca06b 100644 --- a/libs/vkd3d-shader/d3d_asm.c +++ b/libs/vkd3d-shader/d3d_asm.c @@ -279,6 +279,7 @@ static const char * const shader_opcode_names[] = [VKD3DSIH_SUB ] = "sub", [VKD3DSIH_SWAPC ] = "swapc", [VKD3DSIH_SWITCH ] = "switch", + [VKD3DSIH_SWITCH_MONOLITHIC ] = "switch", [VKD3DSIH_SYNC ] = "sync", [VKD3DSIH_TEX ] = "texld", [VKD3DSIH_TEXBEM ] = "texbem", diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index 39c02a14f..e6758a638 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -1522,12 +1522,30 @@ struct cf_flattener_loop_info uint32_t merge_block_id; };
+struct cf_flattener_switch_case +{ + unsigned int value; + unsigned int block_id; +}; + +struct cf_flattener_switch_info +{ + size_t ins_location; + const struct vkd3d_shader_src_param *condition; + unsigned int merge_block_id; + unsigned int default_block_id; + struct cf_flattener_switch_case *cases; + size_t cases_size; + unsigned int cases_count; +}; + struct cf_flattener_info { union { struct cf_flattener_if_info if_; struct cf_flattener_loop_info loop; + struct cf_flattener_switch_info switch_; } u;
enum @@ -1844,18 +1862,101 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte if (!(cf_info = cf_flattener_push_control_flow_level(flattener))) return VKD3D_ERROR_OUT_OF_MEMORY;
- if (!cf_flattener_copy_instruction(flattener, instruction)) - return VKD3D_ERROR_OUT_OF_MEMORY; + merge_block_id = cf_flattener_alloc_block_id(flattener); + + cf_info->u.switch_.ins_location = flattener->instruction_count; + cf_info->u.switch_.condition = src;
+ if (!(dst_ins = cf_flattener_require_space(flattener, 1))) + return VKD3D_ERROR_OUT_OF_MEMORY; + vsir_instruction_init(dst_ins, &instruction->location, VKD3DSIH_SWITCH_MONOLITHIC); + ++flattener->instruction_count; + + cf_info->u.switch_.merge_block_id = merge_block_id; + cf_info->u.switch_.cases = NULL; + cf_info->u.switch_.cases_size = 0; + cf_info->u.switch_.cases_count = 0; + cf_info->u.switch_.default_block_id = 0; + cf_info->inside_block = false; cf_info->current_block = VKD3D_BLOCK_SWITCH;
+ if (!vkd3d_array_reserve((void **)&cf_info->u.switch_.cases, &cf_info->u.switch_.cases_size, + 10, sizeof(*cf_info->u.switch_.cases))) + return VKD3D_ERROR_OUT_OF_MEMORY; + break;
case VKD3DSIH_ENDSWITCH: + { + struct vkd3d_shader_src_param *src_params; + unsigned int j; + + if (!cf_info->u.switch_.default_block_id) + cf_info->u.switch_.default_block_id = cf_info->u.switch_.merge_block_id; + + cf_flattener_emit_label(flattener, cf_info->u.switch_.merge_block_id); + + /* The SWITCH instruction is completed when the endswitch + * instruction is processed because we do not know the number + * of case statements or the default block id in advance.*/ + dst_ins = &flattener->instructions[cf_info->u.switch_.ins_location]; + if (!(src_params = instruction_src_params_alloc(dst_ins, cf_info->u.switch_.cases_count * 2 + 3, flattener))) + { + vkd3d_free(cf_info->u.switch_.cases); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + src_params[0] = *cf_info->u.switch_.condition; + vsir_src_param_init_label(&src_params[1], cf_info->u.switch_.default_block_id); + vsir_src_param_init_label(&src_params[2], cf_info->u.switch_.merge_block_id); + for (j = 0; j < cf_info->u.switch_.cases_count; ++j) + { + unsigned int index = j * 2 + 3; + vsir_src_param_init(&src_params[index], VKD3DSPR_IMMCONST, VKD3D_DATA_UINT, 0); + src_params[index].reg.u.immconst_u32[0] = cf_info->u.switch_.cases[j].value; + vsir_src_param_init_label(&src_params[index + 1], cf_info->u.switch_.cases[j].block_id); + } + vkd3d_free(cf_info->u.switch_.cases); + cf_flattener_pop_control_flow_level(flattener); + break; + }
- if (!cf_flattener_copy_instruction(flattener, instruction)) + case VKD3DSIH_CASE: + { + unsigned int label_id, value; + + if (src->swizzle != VKD3D_SHADER_SWIZZLE(X, X, X, X)) + { + WARN("Unexpected src swizzle %#x.\n", src->swizzle); + vkd3d_shader_parser_error(parser, VKD3D_SHADER_ERROR_VSIR_INVALID_SWIZZLE, + "The swizzle for a switch case value is not scalar X."); + } + value = *src->reg.u.immconst_u32; + + if (!vkd3d_array_reserve((void **)&cf_info->u.switch_.cases, &cf_info->u.switch_.cases_size, + cf_info->u.switch_.cases_count + 1, sizeof(*cf_info->u.switch_.cases))) return VKD3D_ERROR_OUT_OF_MEMORY; + + label_id = cf_flattener_alloc_block_id(flattener); + if (cf_info->inside_block) /* fall-through */ + cf_flattener_emit_unconditional_branch(flattener, label_id); + + cf_info->u.switch_.cases[cf_info->u.switch_.cases_count].value = value; + cf_info->u.switch_.cases[cf_info->u.switch_.cases_count].block_id = label_id; + ++cf_info->u.switch_.cases_count; + + cf_flattener_emit_label(flattener, label_id); + cf_info->inside_block = true; + break; + } + + case VKD3DSIH_DEFAULT: + cf_info->u.switch_.default_block_id = cf_flattener_alloc_block_id(flattener); + if (cf_info->inside_block) /* fall-through */ + cf_flattener_emit_unconditional_branch(flattener, cf_info->u.switch_.default_block_id); + + cf_flattener_emit_label(flattener, cf_info->u.switch_.default_block_id); + cf_info->inside_block = true; break;
case VKD3DSIH_BREAK: @@ -1874,8 +1975,7 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte } else if (breakable_cf_info->current_block == VKD3D_BLOCK_SWITCH) { - if (!cf_flattener_copy_instruction(flattener, instruction)) - return VKD3D_ERROR_OUT_OF_MEMORY; + cf_flattener_emit_unconditional_branch(flattener, breakable_cf_info->u.switch_.merge_block_id); }
cf_info->inside_block = false; diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index e5bd45d9c..25594e5e9 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2253,32 +2253,6 @@ static const char *debug_vkd3d_symbol(const struct vkd3d_symbol *symbol) } }
-struct vkd3d_switch_cf_info -{ - size_t stream_location; - unsigned int id; - uint32_t selector_id; - uint32_t merge_block_id; - uint32_t default_block_id; - uint32_t *case_blocks; - size_t case_blocks_size; - unsigned int case_block_count; -}; - -struct vkd3d_control_flow_info -{ - union - { - struct vkd3d_switch_cf_info switch_; - } u; - - enum - { - VKD3D_BLOCK_SWITCH, - } current_block; - bool inside_block; -}; - struct vkd3d_push_constant_buffer_binding { struct vkd3d_shader_register reg; @@ -2332,11 +2306,6 @@ struct spirv_compiler
enum vkd3d_shader_type shader_type;
- unsigned int switch_id; - unsigned int control_flow_depth; - struct vkd3d_control_flow_info *control_flow_info; - size_t control_flow_info_size; - struct vkd3d_shader_interface_info shader_interface; struct vkd3d_shader_descriptor_offset_info offset_info; uint32_t descriptor_offsets_member_id; @@ -2418,8 +2387,6 @@ static const char *spirv_compiler_get_entry_point_name(const struct spirv_compil
static void spirv_compiler_destroy(struct spirv_compiler *compiler) { - vkd3d_free(compiler->control_flow_info); - vkd3d_free(compiler->output_info);
vkd3d_free(compiler->push_constants); @@ -7588,208 +7555,6 @@ static void spirv_compiler_emit_kill(struct spirv_compiler *compiler, vkd3d_spirv_build_op_label(builder, merge_block_id); }
-static struct vkd3d_control_flow_info *spirv_compiler_push_control_flow_level( - struct spirv_compiler *compiler) -{ - if (!vkd3d_array_reserve((void **)&compiler->control_flow_info, &compiler->control_flow_info_size, - compiler->control_flow_depth + 1, sizeof(*compiler->control_flow_info))) - { - ERR("Failed to allocate control flow info structure.\n"); - return NULL; - } - - return &compiler->control_flow_info[compiler->control_flow_depth++]; -} - -static void spirv_compiler_pop_control_flow_level(struct spirv_compiler *compiler) -{ - struct vkd3d_control_flow_info *cf_info; - - assert(compiler->control_flow_depth); - - cf_info = &compiler->control_flow_info[--compiler->control_flow_depth]; - memset(cf_info, 0, sizeof(*cf_info)); -} - -static struct vkd3d_control_flow_info *spirv_compiler_find_innermost_breakable_cf_construct( - struct spirv_compiler *compiler) -{ - int depth; - - for (depth = compiler->control_flow_depth - 1; depth >= 0; --depth) - { - if (compiler->control_flow_info[depth].current_block == VKD3D_BLOCK_SWITCH) - return &compiler->control_flow_info[depth]; - } - - return NULL; -} - -static void spirv_compiler_emit_label(struct spirv_compiler *compiler, - const struct vkd3d_shader_instruction *instruction); - -static int spirv_compiler_emit_control_flow_instruction(struct spirv_compiler *compiler, - const struct vkd3d_shader_instruction *instruction) -{ - struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_src_param *src = instruction->src; - struct vkd3d_control_flow_info *cf_info; - uint32_t merge_block_id, val_id; - - cf_info = compiler->control_flow_depth - ? &compiler->control_flow_info[compiler->control_flow_depth - 1] : NULL; - - switch (instruction->handler_idx) - { - case VKD3DSIH_LABEL: - if (cf_info) - cf_info->inside_block = true; - spirv_compiler_emit_label(compiler, instruction); - break; - - case VKD3DSIH_SWITCH: - if (!(cf_info = spirv_compiler_push_control_flow_level(compiler))) - return VKD3D_ERROR_OUT_OF_MEMORY; - - merge_block_id = vkd3d_spirv_alloc_id(builder); - - assert(src->reg.data_type == VKD3D_DATA_INT); - val_id = spirv_compiler_emit_load_src(compiler, src, VKD3DSP_WRITEMASK_0); - - vkd3d_spirv_build_op_selection_merge(builder, merge_block_id, SpvSelectionControlMaskNone); - - cf_info->u.switch_.id = compiler->switch_id; - cf_info->u.switch_.merge_block_id = merge_block_id; - cf_info->u.switch_.stream_location = vkd3d_spirv_stream_current_location(&builder->function_stream); - cf_info->u.switch_.selector_id = val_id; - cf_info->u.switch_.case_blocks = NULL; - cf_info->u.switch_.case_blocks_size = 0; - cf_info->u.switch_.case_block_count = 0; - cf_info->u.switch_.default_block_id = 0; - cf_info->inside_block = false; - cf_info->current_block = VKD3D_BLOCK_SWITCH; - - vkd3d_spirv_build_op_name(builder, merge_block_id, "switch%u_merge", compiler->switch_id); - - ++compiler->switch_id; - - if (!vkd3d_array_reserve((void **)&cf_info->u.switch_.case_blocks, &cf_info->u.switch_.case_blocks_size, - 10, sizeof(*cf_info->u.switch_.case_blocks))) - return VKD3D_ERROR_OUT_OF_MEMORY; - - break; - - case VKD3DSIH_ENDSWITCH: - assert(compiler->control_flow_depth); - assert(cf_info->current_block == VKD3D_BLOCK_SWITCH); - assert(!cf_info->inside_block); - - if (!cf_info->u.switch_.default_block_id) - cf_info->u.switch_.default_block_id = cf_info->u.switch_.merge_block_id; - - vkd3d_spirv_build_op_label(builder, cf_info->u.switch_.merge_block_id); - - /* The OpSwitch instruction is inserted when the endswitch - * instruction is processed because we do not know the number - * of case statements in advance.*/ - vkd3d_spirv_begin_function_stream_insertion(builder, cf_info->u.switch_.stream_location); - vkd3d_spirv_build_op_switch(builder, cf_info->u.switch_.selector_id, - cf_info->u.switch_.default_block_id, cf_info->u.switch_.case_blocks, - cf_info->u.switch_.case_block_count); - vkd3d_spirv_end_function_stream_insertion(builder); - - vkd3d_free(cf_info->u.switch_.case_blocks); - spirv_compiler_pop_control_flow_level(compiler); - break; - - case VKD3DSIH_CASE: - { - uint32_t label_id, value; - - assert(compiler->control_flow_depth); - assert(cf_info->current_block == VKD3D_BLOCK_SWITCH); - - if (src->swizzle != VKD3D_SHADER_SWIZZLE(X, X, X, X)) - { - WARN("Unexpected src swizzle %#x.\n", src->swizzle); - spirv_compiler_warning(compiler, VKD3D_SHADER_WARNING_SPV_INVALID_SWIZZLE, - "The swizzle for a switch case value is not scalar."); - } - assert(src->reg.type == VKD3DSPR_IMMCONST); - value = *src->reg.u.immconst_u32; - - if (!vkd3d_array_reserve((void **)&cf_info->u.switch_.case_blocks, &cf_info->u.switch_.case_blocks_size, - 2 * (cf_info->u.switch_.case_block_count + 1), sizeof(*cf_info->u.switch_.case_blocks))) - return VKD3D_ERROR_OUT_OF_MEMORY; - - label_id = vkd3d_spirv_alloc_id(builder); - if (cf_info->inside_block) /* fall-through */ - vkd3d_spirv_build_op_branch(builder, label_id); - - cf_info->u.switch_.case_blocks[2 * cf_info->u.switch_.case_block_count + 0] = value; - cf_info->u.switch_.case_blocks[2 * cf_info->u.switch_.case_block_count + 1] = label_id; - ++cf_info->u.switch_.case_block_count; - - vkd3d_spirv_build_op_label(builder, label_id); - cf_info->inside_block = true; - vkd3d_spirv_build_op_name(builder, label_id, "switch%u_case%u", cf_info->u.switch_.id, value); - break; - } - - case VKD3DSIH_DEFAULT: - assert(compiler->control_flow_depth); - assert(cf_info->current_block == VKD3D_BLOCK_SWITCH); - assert(!cf_info->u.switch_.default_block_id); - - cf_info->u.switch_.default_block_id = vkd3d_spirv_alloc_id(builder); - if (cf_info->inside_block) /* fall-through */ - vkd3d_spirv_build_op_branch(builder, cf_info->u.switch_.default_block_id); - - vkd3d_spirv_build_op_label(builder, cf_info->u.switch_.default_block_id); - vkd3d_spirv_build_op_name(builder, cf_info->u.switch_.default_block_id, - "switch%u_default", cf_info->u.switch_.id); - cf_info->inside_block = true; - break; - - case VKD3DSIH_BREAK: - { - struct vkd3d_control_flow_info *breakable_cf_info; - - assert(compiler->control_flow_depth); - - if (!(breakable_cf_info = spirv_compiler_find_innermost_breakable_cf_construct(compiler))) - { - FIXME("Unhandled break instruction.\n"); - return VKD3D_ERROR_INVALID_SHADER; - } - - if (breakable_cf_info->current_block == VKD3D_BLOCK_SWITCH) - { - /* The current case block may have already been ended by an - * unconditional continue instruction. */ - if (breakable_cf_info->inside_block) - vkd3d_spirv_build_op_branch(builder, breakable_cf_info->u.switch_.merge_block_id); - } - - cf_info->inside_block = false; - break; - } - - case VKD3DSIH_RET: - spirv_compiler_emit_return(compiler, instruction); - - if (cf_info) - cf_info->inside_block = false; - break; - - default: - ERR("Unexpected instruction %#x.\n", instruction->handler_idx); - break; - } - - return VKD3D_OK; -} - static bool spirv_compiler_init_blocks(struct spirv_compiler *compiler, unsigned int block_count) { compiler->block_count = block_count; @@ -7868,6 +7633,47 @@ static void spirv_compiler_emit_branch(struct spirv_compiler *compiler, spirv_compiler_get_label_id(compiler, src[2].reg.idx[0].offset)); }
+static void spirv_compiler_emit_switch(struct spirv_compiler *compiler, + const struct vkd3d_shader_instruction *instruction) +{ + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + const struct vkd3d_shader_src_param *src = instruction->src; + uint32_t val_id, default_id; + unsigned int i, word_count; + uint32_t *cases; + + if (!vkd3d_swizzle_is_scalar(src[0].swizzle)) + { + WARN("Unexpected src swizzle %#x.\n", src[0].swizzle); + spirv_compiler_warning(compiler, VKD3D_SHADER_WARNING_SPV_INVALID_SWIZZLE, + "The swizzle for a switch value is not scalar."); + } + + word_count = instruction->src_count - 3; + if (!(cases = vkd3d_calloc(word_count, sizeof(*cases)))) + { + spirv_compiler_error(compiler, VKD3D_SHADER_ERROR_SPV_OUT_OF_MEMORY, + "Failed to allocate %u words for switch cases.", word_count); + return; + } + + val_id = spirv_compiler_emit_load_src(compiler, &src[0], VKD3DSP_WRITEMASK_0); + default_id = spirv_compiler_get_label_id(compiler, src[1].reg.idx[0].offset); + /* No instructions may occur between the merge and the switch. */ + spirv_compiler_emit_merge(compiler, src[2].reg.idx[0].offset, 0); + + src = &src[3]; + for (i = 0; i < word_count; i += 2) + { + cases[i] = src[i].reg.u.immconst_u32[0]; + cases[i + 1] = spirv_compiler_get_label_id(compiler, src[i + 1].reg.idx[0].offset); + } + + vkd3d_spirv_build_op_switch(builder, val_id, default_id, cases, word_count / 2u); + + vkd3d_free(cases); +} + static void spirv_compiler_emit_deriv_instruction(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { @@ -9612,19 +9418,8 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_F32TOF16: spirv_compiler_emit_f32tof16(compiler, instruction); break; - case VKD3DSIH_BREAK: - case VKD3DSIH_BREAKP: - case VKD3DSIH_CASE: - case VKD3DSIH_CONTINUE: - case VKD3DSIH_CONTINUEP: - case VKD3DSIH_DEFAULT: - case VKD3DSIH_ENDLOOP: - case VKD3DSIH_ENDSWITCH: - case VKD3DSIH_LABEL: - case VKD3DSIH_LOOP: case VKD3DSIH_RET: - case VKD3DSIH_SWITCH: - ret = spirv_compiler_emit_control_flow_instruction(compiler, instruction); + spirv_compiler_emit_return(compiler, instruction); break; case VKD3DSIH_RETP: spirv_compiler_emit_retc(compiler, instruction); @@ -9633,9 +9428,15 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_TEXKILL: spirv_compiler_emit_kill(compiler, instruction); break; + case VKD3DSIH_LABEL: + spirv_compiler_emit_label(compiler, instruction); + break; case VKD3DSIH_BRANCH: spirv_compiler_emit_branch(compiler, instruction); break; + case VKD3DSIH_SWITCH_MONOLITHIC: + spirv_compiler_emit_switch(compiler, instruction); + break; case VKD3DSIH_DSX: case VKD3DSIH_DSX_COARSE: case VKD3DSIH_DSX_FINE: diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 30672950b..9c85dfc38 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -472,6 +472,7 @@ enum vkd3d_shader_opcode VKD3DSIH_SUB, VKD3DSIH_SWAPC, VKD3DSIH_SWITCH, + VKD3DSIH_SWITCH_MONOLITHIC, VKD3DSIH_SYNC, VKD3DSIH_TEX, VKD3DSIH_TEXBEM,
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxbc.c | 5 ++ libs/vkd3d-shader/ir.c | 58 ++++++++++++++++++++++++ libs/vkd3d-shader/spirv.c | 8 ++++ libs/vkd3d-shader/vkd3d_shader_private.h | 3 ++ 4 files changed, 74 insertions(+)
diff --git a/libs/vkd3d-shader/dxbc.c b/libs/vkd3d-shader/dxbc.c index 63deaaad2..22e29387f 100644 --- a/libs/vkd3d-shader/dxbc.c +++ b/libs/vkd3d-shader/dxbc.c @@ -551,9 +551,14 @@ static int shdr_handler(const struct vkd3d_shader_dxbc_section_desc *section,
void free_shader_desc(struct vkd3d_shader_desc *desc) { + size_t i; + shader_signature_cleanup(&desc->input_signature); shader_signature_cleanup(&desc->output_signature); shader_signature_cleanup(&desc->patch_constant_signature); + for (i = 0; i < desc->block_name_count; ++i) + vkd3d_free((void *)desc->block_names[i]); + vkd3d_free(desc->block_names); }
int shader_extract_from_dxbc(const struct vkd3d_shader_code *dxbc, diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index e6758a638..cddfd0525 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -1511,6 +1511,7 @@ static enum vkd3d_result normalise_combined_samplers(struct vkd3d_shader_parser struct cf_flattener_if_info { struct vkd3d_shader_src_param *false_param; + unsigned int id; uint32_t merge_block_id; unsigned int else_block_id; }; @@ -1532,6 +1533,7 @@ struct cf_flattener_switch_info { size_t ins_location; const struct vkd3d_shader_src_param *condition; + unsigned int id; unsigned int merge_block_id; unsigned int default_block_id; struct cf_flattener_switch_case *cases; @@ -1569,6 +1571,13 @@ struct cf_flattener size_t instruction_count;
unsigned int block_id; + const char **block_names; + size_t block_name_capacity; + size_t block_name_count; + + unsigned int branch_id; + unsigned int loop_id; + unsigned int switch_id;
unsigned int control_flow_depth; struct cf_flattener_info *control_flow_info; @@ -1751,6 +1760,31 @@ static struct cf_flattener_info *cf_flattener_find_innermost_breakable_cf_constr return NULL; }
+static void VKD3D_PRINTF_FUNC(3, 4) cf_flattener_create_block_name(struct cf_flattener *flattener, + unsigned int block_id, const char *fmt, ...) +{ + struct vkd3d_string_buffer buffer; + size_t block_name_count; + va_list args; + + --block_id; + + block_name_count = max(flattener->block_name_count, block_id + 1); + if (!vkd3d_array_reserve((void **)&flattener->block_names, &flattener->block_name_capacity, + block_name_count, sizeof(*flattener->block_names))) + return; + memset(&flattener->block_names[flattener->block_name_count], 0, + (block_name_count - flattener->block_name_count) * sizeof(*flattener->block_names)); + flattener->block_name_count = block_name_count; + + vkd3d_string_buffer_init(&buffer); + va_start(args, fmt); + vkd3d_string_buffer_vprintf(&buffer, fmt, args); + va_end(args); + + flattener->block_names[block_id] = buffer.buffer; +} + static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flattener *flattener) { struct vkd3d_shader_parser *parser = flattener->parser; @@ -1797,10 +1831,15 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte
cf_flattener_emit_label(flattener, true_block_id);
+ cf_info->u.if_.id = flattener->branch_id; cf_info->u.if_.merge_block_id = merge_block_id; cf_info->u.if_.else_block_id = 0; cf_info->inside_block = true; cf_info->current_block = VKD3D_BLOCK_IF; + + cf_flattener_create_block_name(flattener, merge_block_id, "branch%u_merge", flattener->branch_id); + cf_flattener_create_block_name(flattener, true_block_id, "branch%u_true", flattener->branch_id); + ++flattener->branch_id; break;
case VKD3DSIH_ELSE: @@ -1810,6 +1849,8 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte cf_info->u.if_.else_block_id = cf_flattener_alloc_block_id(flattener); cf_info->u.if_.false_param->reg.idx[0].offset = cf_info->u.if_.else_block_id;
+ cf_flattener_create_block_name(flattener, + cf_info->u.if_.else_block_id, "branch%u_false", cf_info->u.if_.id); cf_flattener_emit_label(flattener, cf_info->u.if_.else_block_id);
cf_info->inside_block = true; @@ -1845,6 +1886,12 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte cf_info->u.loop.merge_block_id = merge_block_id; cf_info->current_block = VKD3D_BLOCK_LOOP; cf_info->inside_block = true; + + cf_flattener_create_block_name(flattener, loop_header_block_id, "loop%u_header", flattener->loop_id); + cf_flattener_create_block_name(flattener, loop_body_block_id, "loop%u_body", flattener->loop_id); + cf_flattener_create_block_name(flattener, continue_block_id, "loop%u_continue", flattener->loop_id); + cf_flattener_create_block_name(flattener, merge_block_id, "loop%u_merge", flattener->loop_id); + ++flattener->loop_id; break;
case VKD3DSIH_ENDLOOP: @@ -1872,6 +1919,7 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte vsir_instruction_init(dst_ins, &instruction->location, VKD3DSIH_SWITCH_MONOLITHIC); ++flattener->instruction_count;
+ cf_info->u.switch_.id = flattener->switch_id; cf_info->u.switch_.merge_block_id = merge_block_id; cf_info->u.switch_.cases = NULL; cf_info->u.switch_.cases_size = 0; @@ -1880,6 +1928,9 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte cf_info->inside_block = false; cf_info->current_block = VKD3D_BLOCK_SWITCH;
+ cf_flattener_create_block_name(flattener, merge_block_id, "switch%u_merge", flattener->switch_id); + ++flattener->switch_id; + if (!vkd3d_array_reserve((void **)&cf_info->u.switch_.cases, &cf_info->u.switch_.cases_size, 10, sizeof(*cf_info->u.switch_.cases))) return VKD3D_ERROR_OUT_OF_MEMORY; @@ -1946,6 +1997,7 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte ++cf_info->u.switch_.cases_count;
cf_flattener_emit_label(flattener, label_id); + cf_flattener_create_block_name(flattener, label_id, "switch%u_case%u", cf_info->u.switch_.id, value); cf_info->inside_block = true; break; } @@ -1956,6 +2008,9 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte cf_flattener_emit_unconditional_branch(flattener, cf_info->u.switch_.default_block_id);
cf_flattener_emit_label(flattener, cf_info->u.switch_.default_block_id); + + cf_flattener_create_block_name(flattener, cf_info->u.switch_.default_block_id, + "switch%u_default", cf_info->u.switch_.id); cf_info->inside_block = true; break;
@@ -2078,6 +2133,9 @@ static enum vkd3d_result flatten_control_flow_constructs(struct vkd3d_shader_par }
vkd3d_free(flattener.control_flow_info); + /* Simpler to always free these in free_shader_desc(). */ + parser->shader_desc.block_names = flattener.block_names; + parser->shader_desc.block_name_count = flattener.block_name_count;
return result; } diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 25594e5e9..eff1d7b32 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2358,6 +2358,8 @@ struct spirv_compiler
uint32_t *block_label_ids; unsigned int block_count; + const char **block_names; + size_t block_name_count; };
static bool is_in_default_phase(const struct spirv_compiler *compiler) @@ -7575,6 +7577,10 @@ static void spirv_compiler_emit_label(struct spirv_compiler *compiler,
label_id = spirv_compiler_get_label_id(compiler, block_id); vkd3d_spirv_build_op_label(builder, label_id); + + --block_id; + if (block_id < compiler->block_name_count && compiler->block_names[block_id]) + vkd3d_spirv_build_op_name(builder, label_id, compiler->block_names[block_id]); }
static void spirv_compiler_emit_merge(struct spirv_compiler *compiler, @@ -9670,6 +9676,8 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, memset(&shader_desc->output_signature, 0, sizeof(shader_desc->output_signature)); memset(&shader_desc->patch_constant_signature, 0, sizeof(shader_desc->patch_constant_signature)); compiler->use_vocp = parser->shader_desc.use_vocp; + compiler->block_names = parser->shader_desc.block_names; + compiler->block_name_count = parser->shader_desc.block_name_count;
compiler->input_control_point_count = shader_desc->input_control_point_count; compiler->output_control_point_count = shader_desc->output_control_point_count; diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 9c85dfc38..81c5a0ca7 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1025,6 +1025,9 @@ struct vkd3d_shader_desc } flat_constant_count[3];
bool use_vocp; + + const char **block_names; + size_t block_name_count; };
struct vkd3d_shader_register_semantic
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 9 +++++---- libs/vkd3d-shader/spirv.c | 5 ++++- libs/vkd3d-shader/tpf.c | 2 ++ libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 4 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index c744dfced..85fb3e64a 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -2691,8 +2691,8 @@ static void sm6_parser_declare_icb(struct sm6_parser *sm6, const struct sm6_type }
static void sm6_parser_declare_indexable_temp(struct sm6_parser *sm6, const struct sm6_type *elem_type, - unsigned int count, unsigned int alignment, unsigned int init, struct vkd3d_shader_instruction *ins, - struct sm6_value *dst) + unsigned int count, unsigned int alignment, bool has_function_scope, unsigned int init, + struct vkd3d_shader_instruction *ins, struct sm6_value *dst) { enum vkd3d_data_type data_type = vkd3d_data_type_from_sm6_type(elem_type);
@@ -2705,6 +2705,7 @@ static void sm6_parser_declare_indexable_temp(struct sm6_parser *sm6, const stru ins->declaration.indexable_temp.alignment = alignment; ins->declaration.indexable_temp.data_type = data_type; ins->declaration.indexable_temp.component_count = 1; + ins->declaration.indexable_temp.has_function_scope = has_function_scope; /* The initialiser value index will be resolved later so forward references can be handled. */ ins->declaration.indexable_temp.initialiser = (void *)(uintptr_t)init;
@@ -2832,7 +2833,7 @@ static bool sm6_parser_declare_global(struct sm6_parser *sm6, const struct dxil_ if (is_constant) sm6_parser_declare_icb(sm6, scalar_type, count, alignment, init, dst); else - sm6_parser_declare_indexable_temp(sm6, scalar_type, count, alignment, init, NULL, dst); + sm6_parser_declare_indexable_temp(sm6, scalar_type, count, alignment, false, init, NULL, dst); } else if (address_space == ADDRESS_SPACE_GROUPSHARED) { @@ -3103,7 +3104,7 @@ static void sm6_parser_emit_alloca(struct sm6_parser *sm6, const struct dxil_rec if (packed_operands) WARN("Ignoring flags %#"PRIx64".\n", packed_operands);
- sm6_parser_declare_indexable_temp(sm6, elem_type, type[0]->u.array.count, alignment, 0, ins, dst); + sm6_parser_declare_indexable_temp(sm6, elem_type, type[0]->u.array.count, alignment, true, 0, ins, dst); }
static enum vkd3d_shader_opcode map_binary_op(uint64_t code, const struct sm6_type *type_a, diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index eff1d7b32..4872409ba 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -5597,7 +5597,10 @@ static void spirv_compiler_emit_dcl_indexable_temp(struct spirv_compiler *compil SpvStorageClass storage_class; size_t function_location;
- storage_class = SpvStorageClassFunction; + /* Indexable temps may be used by more than one function in hull shaders, and + * declarations generally should not occur within VSIR code blocks unless function + * scope is specified, e.g. DXIL alloca. */ + storage_class = temp->has_function_scope ? SpvStorageClassFunction : SpvStorageClassPrivate;
vsir_register_init(®, VKD3DSPR_IDXTEMP, VKD3D_DATA_FLOAT, 1); reg.idx[0].offset = temp->register_idx; diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index 2cc56663e..a5a020d57 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -1119,6 +1119,8 @@ static void shader_sm4_read_dcl_indexable_temp(struct vkd3d_shader_instruction * ins->declaration.indexable_temp.alignment = 0; ins->declaration.indexable_temp.data_type = VKD3D_DATA_FLOAT; ins->declaration.indexable_temp.component_count = *tokens; + /* Indexable temp declarations are global, but except for hull shaders the backend currently emits them within a function. */ + ins->declaration.indexable_temp.has_function_scope = priv->p.shader_version.type != VKD3D_SHADER_TYPE_HULL; }
static void shader_sm4_read_dcl_global_flags(struct vkd3d_shader_instruction *ins, uint32_t opcode, diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 81c5a0ca7..95e714368 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -819,6 +819,7 @@ struct vkd3d_shader_indexable_temp unsigned int alignment; enum vkd3d_data_type data_type; unsigned int component_count; + bool has_function_scope; const struct vkd3d_shader_immediate_constant_buffer *initialiser; };
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/spirv.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 4872409ba..447d7e9e5 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2334,7 +2334,9 @@ struct spirv_compiler const struct vkd3d_shader_scan_descriptor_info1 *scan_descriptor_info; unsigned int input_control_point_count; unsigned int output_control_point_count; + bool use_vocp; + bool emit_point_size;
enum vkd3d_shader_opcode phase; bool emit_default_control_point_phase; @@ -2530,6 +2532,8 @@ static struct spirv_compiler *spirv_compiler_create(const struct vkd3d_shader_ve if ((shader_interface = vkd3d_find_struct(compile_info->next, INTERFACE_INFO))) { compiler->xfb_info = vkd3d_find_struct(compile_info->next, TRANSFORM_FEEDBACK_INFO); + compiler->emit_point_size = compiler->xfb_info && compiler->xfb_info->element_count + && compiler->shader_type != VKD3D_SHADER_TYPE_GEOMETRY;
compiler->shader_interface = *shader_interface; if (shader_interface->push_constant_buffer_count) @@ -6332,7 +6336,7 @@ static void spirv_compiler_emit_dcl_output_topology(struct spirv_compiler *compi { case VKD3D_PT_POINTLIST: mode = SpvExecutionModeOutputPoints; - spirv_compiler_emit_point_size(compiler); + compiler->emit_point_size = true; break; case VKD3D_PT_LINESTRIP: mode = SpvExecutionModeOutputLineStrip; @@ -9219,8 +9223,7 @@ static void spirv_compiler_emit_main_prolog(struct spirv_compiler *compiler) { spirv_compiler_emit_push_constant_buffers(compiler);
- if (compiler->xfb_info && compiler->xfb_info->element_count - && compiler->shader_type != VKD3D_SHADER_TYPE_GEOMETRY) + if (compiler->emit_point_size) spirv_compiler_emit_point_size(compiler); }
From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/dxil.c | 14 ++++++ libs/vkd3d-shader/ir.c | 35 +++++++++++++-- libs/vkd3d-shader/spirv.c | 56 +++++++++++++++--------- libs/vkd3d-shader/tpf.c | 3 +- libs/vkd3d-shader/vkd3d_shader_private.h | 2 + 5 files changed, 84 insertions(+), 26 deletions(-)
diff --git a/libs/vkd3d-shader/dxil.c b/libs/vkd3d-shader/dxil.c index 85fb3e64a..0897963cf 100644 --- a/libs/vkd3d-shader/dxil.c +++ b/libs/vkd3d-shader/dxil.c @@ -4869,6 +4869,18 @@ static enum vkd3d_result sm6_parser_module_init(struct sm6_parser *sm6, const st return VKD3D_OK; }
+static void sm6_parser_emit_label(struct sm6_parser *sm6, unsigned int label_id) +{ + struct vkd3d_shader_src_param *src_param; + struct vkd3d_shader_instruction *ins; + + ins = sm6_parser_add_instruction(sm6, VKD3DSIH_LABEL); + + if (!(src_param = instruction_src_params_alloc(ins, 1, sm6))) + return; + vsir_src_param_init_label(src_param, label_id); +} + static bool sm6_parser_allocate_named_metadata(struct sm6_parser *sm6) { struct dxil_block *block; @@ -6217,6 +6229,7 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t }
sm6->p.shader_desc.ssa_count = sm6->ssa_next_id; + sm6->p.shader_desc.block_count = 1;
if (!(fn = sm6_parser_get_function(sm6, sm6->entry_point))) { @@ -6227,6 +6240,7 @@ static enum vkd3d_result sm6_parser_init(struct sm6_parser *sm6, const uint32_t }
assert(sm6->function_count == 1); + sm6_parser_emit_label(sm6, 1); if (!sm6_block_emit_instructions(fn->blocks[0], sm6)) { vkd3d_shader_parser_error(&sm6->p, VKD3D_SHADER_ERROR_DXIL_OUT_OF_MEMORY, diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index cddfd0525..e696bbdaa 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -320,7 +320,7 @@ static void vsir_src_param_init(struct vkd3d_shader_src_param *param, enum vkd3d param->modifiers = VKD3DSPSM_NONE; }
-static void vsir_src_param_init_label(struct vkd3d_shader_src_param *param, unsigned int label_id) +void vsir_src_param_init_label(struct vkd3d_shader_src_param *param, unsigned int label_id) { vsir_src_param_init(param, VKD3DSPR_LABEL, VKD3D_DATA_UINT, 1); param->reg.dimension = VSIR_DIMENSION_NONE; @@ -1574,6 +1574,7 @@ struct cf_flattener const char **block_names; size_t block_name_capacity; size_t block_name_count; + bool after_declarations_section;
unsigned int branch_id; unsigned int loop_id; @@ -1785,18 +1786,26 @@ static void VKD3D_PRINTF_FUNC(3, 4) cf_flattener_create_block_name(struct cf_fla flattener->block_names[block_id] = buffer.buffer; }
+static bool vsir_instruction_is_dcl(const struct vkd3d_shader_instruction *instruction) +{ + enum vkd3d_shader_opcode handler_idx = instruction->handler_idx; + return (VKD3DSIH_DCL <= handler_idx && handler_idx <= VKD3DSIH_DCL_VERTICES_OUT) + || handler_idx == VKD3DSIH_HS_DECLS; +} + static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flattener *flattener) { struct vkd3d_shader_parser *parser = flattener->parser; struct vkd3d_shader_instruction_array *instructions; struct vkd3d_shader_instruction *dst_ins; - bool main_block_open; + bool main_block_open, is_hull_shader; size_t i;
instructions = &parser->instructions; - main_block_open = parser->shader_version.type != VKD3D_SHADER_TYPE_HULL; + is_hull_shader = parser->shader_version.type == VKD3D_SHADER_TYPE_HULL; + main_block_open = !is_hull_shader;
- if (!cf_flattener_require_space(flattener, instructions->count)) + if (!cf_flattener_require_space(flattener, instructions->count + 1)) return VKD3D_ERROR_OUT_OF_MEMORY;
for (i = 0; i < instructions->count; ++i) @@ -1808,11 +1817,29 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte
flattener->location = instruction->location;
+ /* Declarations should occur before the first code block, which in hull shaders is marked by the first + * phase instruction, and in all other shader types begins with the first label instruction. */ + if (!is_hull_shader && !flattener->after_declarations_section && !vsir_instruction_is_dcl(instruction) + && instruction->handler_idx != VKD3DSIH_NOP) + { + flattener->after_declarations_section = true; + cf_flattener_emit_label(flattener, cf_flattener_alloc_block_id(flattener)); + } + cf_info = flattener->control_flow_depth ? &flattener->control_flow_info[flattener->control_flow_depth - 1] : NULL;
switch (instruction->handler_idx) { + case VKD3DSIH_HS_CONTROL_POINT_PHASE: + case VKD3DSIH_HS_FORK_PHASE: + case VKD3DSIH_HS_JOIN_PHASE: + if (!cf_flattener_copy_instruction(flattener, instruction)) + return VKD3D_ERROR_OUT_OF_MEMORY; + if (instruction->handler_idx != VKD3DSIH_HS_CONTROL_POINT_PHASE || !instruction->flags) + cf_flattener_emit_label(flattener, cf_flattener_alloc_block_id(flattener)); + break; + case VKD3DSIH_LABEL: vkd3d_shader_parser_error(parser, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED, "Aborting due to not yet implemented feature: Label instruction."); diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 447d7e9e5..9f78966dc 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -1871,8 +1871,6 @@ static void vkd3d_spirv_builder_begin_main_function(struct vkd3d_spirv_builder *
vkd3d_spirv_build_op_function(builder, void_id, builder->main_function_id, SpvFunctionControlMaskNone, function_type_id); - vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder)); - builder->main_function_location = vkd3d_spirv_stream_current_location(&builder->function_stream); }
static void vkd3d_spirv_builder_free(struct vkd3d_spirv_builder *builder) @@ -2314,7 +2312,7 @@ struct spirv_compiler struct vkd3d_push_constant_buffer_binding *push_constants; const struct vkd3d_shader_spirv_target_info *spirv_target_info;
- bool after_declarations_section; + bool prolog_emitted; struct shader_signature input_signature; struct shader_signature output_signature; struct shader_signature patch_constant_signature; @@ -2381,6 +2379,8 @@ static bool is_in_fork_or_join_phase(const struct spirv_compiler *compiler)
static void spirv_compiler_emit_initial_declarations(struct spirv_compiler *compiler); static size_t spirv_compiler_get_current_function_location(struct spirv_compiler *compiler); +static void spirv_compiler_emit_main_prolog(struct spirv_compiler *compiler); +static void spirv_compiler_emit_io_declarations(struct spirv_compiler *compiler);
static const char *spirv_compiler_get_entry_point_name(const struct spirv_compiler *compiler) { @@ -6498,20 +6498,45 @@ static void spirv_compiler_enter_shader_phase(struct spirv_compiler *compiler, vkd3d_spirv_build_op_function(builder, void_id, function_id, SpvFunctionControlMaskNone, function_type_id);
- vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder)); - compiler->phase = instruction->handler_idx; spirv_compiler_emit_shader_phase_name(compiler, function_id, NULL);
phase = (instruction->handler_idx == VKD3DSIH_HS_CONTROL_POINT_PHASE) ? &compiler->control_point_phase : &compiler->patch_constant_phase; phase->function_id = function_id; - phase->function_location = vkd3d_spirv_stream_current_location(&builder->function_stream); + /* The insertion location must be set after the label is emitted. */ + phase->function_location = 0;
if (instruction->handler_idx == VKD3DSIH_HS_CONTROL_POINT_PHASE) compiler->emit_default_control_point_phase = instruction->flags; }
+static void spirv_compiler_initialise_block(struct spirv_compiler *compiler) +{ + struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + + /* Insertion locations must point immediately after the function's initial label. */ + if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL) + { + struct vkd3d_shader_phase *phase = (compiler->phase == VKD3DSIH_HS_CONTROL_POINT_PHASE) + ? &compiler->control_point_phase : &compiler->patch_constant_phase; + if (!phase->function_location) + phase->function_location = vkd3d_spirv_stream_current_location(&builder->function_stream); + } + else if (!builder->main_function_location) + { + builder->main_function_location = vkd3d_spirv_stream_current_location(&builder->function_stream); + } + + /* I/O declarations can result in emission of fixups, which must occur after the initial label. */ + if (!compiler->prolog_emitted) + { + spirv_compiler_emit_main_prolog(compiler); + spirv_compiler_emit_io_declarations(compiler); + compiler->prolog_emitted = true; + } +} + static void spirv_compiler_emit_default_control_point_phase(struct spirv_compiler *compiler) { const struct shader_signature *output_signature = &compiler->output_signature; @@ -6524,6 +6549,8 @@ static void spirv_compiler_emit_default_control_point_phase(struct spirv_compile unsigned int component_count; unsigned int i;
+ vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder)); + spirv_compiler_initialise_block(compiler); invocation_id = spirv_compiler_emit_load_invocation_id(compiler);
memset(&invocation, 0, sizeof(invocation)); @@ -6622,6 +6649,7 @@ static void spirv_compiler_emit_hull_shader_main(struct spirv_compiler *compiler memset(compiler->descriptor_offset_ids, 0, compiler->offset_info.descriptor_table_count * sizeof(*compiler->descriptor_offset_ids)); vkd3d_spirv_builder_begin_main_function(builder); + vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder));
void_id = vkd3d_spirv_get_op_type_void(builder);
@@ -7588,6 +7616,8 @@ static void spirv_compiler_emit_label(struct spirv_compiler *compiler, --block_id; if (block_id < compiler->block_name_count && compiler->block_names[block_id]) vkd3d_spirv_build_op_name(builder, label_id, compiler->block_names[block_id]); + + spirv_compiler_initialise_block(compiler); }
static void spirv_compiler_emit_merge(struct spirv_compiler *compiler, @@ -9227,23 +9257,11 @@ static void spirv_compiler_emit_main_prolog(struct spirv_compiler *compiler) spirv_compiler_emit_point_size(compiler); }
-static bool is_dcl_instruction(enum vkd3d_shader_opcode handler_idx) -{ - return (VKD3DSIH_DCL <= handler_idx && handler_idx <= VKD3DSIH_DCL_VERTICES_OUT) - || handler_idx == VKD3DSIH_HS_DECLS; -} - static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, const struct vkd3d_shader_instruction *instruction) { int ret = VKD3D_OK;
- if (!is_dcl_instruction(instruction->handler_idx) && !compiler->after_declarations_section) - { - compiler->after_declarations_section = true; - spirv_compiler_emit_main_prolog(compiler); - } - switch (instruction->handler_idx) { case VKD3DSIH_DCL_GLOBAL_FLAGS: @@ -9691,8 +9709,6 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, if (compiler->shader_type != VKD3D_SHADER_TYPE_HULL) spirv_compiler_emit_shader_signature_outputs(compiler);
- spirv_compiler_emit_io_declarations(compiler); - for (i = 0; i < instructions.count && result >= 0; ++i) { compiler->location.line = i + 1; diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index a5a020d57..911c47ef5 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -1119,8 +1119,7 @@ static void shader_sm4_read_dcl_indexable_temp(struct vkd3d_shader_instruction * ins->declaration.indexable_temp.alignment = 0; ins->declaration.indexable_temp.data_type = VKD3D_DATA_FLOAT; ins->declaration.indexable_temp.component_count = *tokens; - /* Indexable temp declarations are global, but except for hull shaders the backend currently emits them within a function. */ - ins->declaration.indexable_temp.has_function_scope = priv->p.shader_version.type != VKD3D_SHADER_TYPE_HULL; + ins->declaration.indexable_temp.has_function_scope = false; }
static void shader_sm4_read_dcl_global_flags(struct vkd3d_shader_instruction *ins, uint32_t opcode, diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 95e714368..fdfbbe4e0 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -885,6 +885,8 @@ struct vkd3d_shader_src_param enum vkd3d_shader_src_modifier modifiers; };
+void vsir_src_param_init_label(struct vkd3d_shader_src_param *param, unsigned int label_id); + struct vkd3d_shader_index_range { struct vkd3d_shader_dst_param dst;