From: Conor McCarthy cmccarthy@codeweavers.com
Normalise the incoming vkd3d_shader_instruction IR to the shader model 6 pattern. This allows generation of a single patch constant function in SPIR-V. --- Makefile.am | 1 + libs/vkd3d-shader/normalise.c | 310 +++++++++++++++++++++++ libs/vkd3d-shader/spirv.c | 145 +++-------- libs/vkd3d-shader/vkd3d_shader_private.h | 17 ++ 4 files changed, 366 insertions(+), 107 deletions(-) create mode 100644 libs/vkd3d-shader/normalise.c
diff --git a/Makefile.am b/Makefile.am index f9199472..7a3b18c8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -242,6 +242,7 @@ libvkd3d_shader_la_SOURCES = \ libs/vkd3d-shader/hlsl_constant_ops.c \ libs/vkd3d-shader/hlsl_sm1.c \ libs/vkd3d-shader/hlsl_sm4.c \ + libs/vkd3d-shader/normalise.c \ libs/vkd3d-shader/preproc.h \ libs/vkd3d-shader/sm4.h \ libs/vkd3d-shader/spirv.c \ diff --git a/libs/vkd3d-shader/normalise.c b/libs/vkd3d-shader/normalise.c new file mode 100644 index 00000000..6232423a --- /dev/null +++ b/libs/vkd3d-shader/normalise.c @@ -0,0 +1,310 @@ +/* + * Copyright 2023 Conor McCarthy for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "vkd3d_shader_private.h" + +static inline bool shader_register_is_phase_instance_id(const struct vkd3d_shader_register *reg) +{ + return reg->type == VKD3DSPR_FORKINSTID || reg->type == VKD3DSPR_JOININSTID; +} + +static bool shader_instruction_is_dcl(const struct vkd3d_shader_instruction *ins) +{ + return (VKD3DSIH_DCL <= ins->handler_idx && ins->handler_idx <= VKD3DSIH_DCL_VERTICES_OUT) + || ins->handler_idx == VKD3DSIH_HS_DECLS; +} + +static inline bool shader_normaliser_new_instructions(struct vkd3d_shader_normaliser *normaliser, unsigned int extra) +{ + return shader_instruction_array_reserve(&normaliser->instructions, normaliser->instructions.count + extra); +} + +static inline bool shader_src_param_is_phase_instance_id(const struct vkd3d_shader_src_param *param, + const struct vkd3d_shader_normaliser *normaliser) +{ + const struct vkd3d_shader_register *reg = ¶m->reg; + return shader_register_is_phase_instance_id(reg) || (reg->type == VKD3DSPR_TEMP + && !vkd3d_swizzle_get_component(param->swizzle, 0) + && (normaliser->temp_is_instance_id & (1ull << reg->idx[0].offset))); +} + +static void shader_register_eliminate_phase_addressing(struct vkd3d_shader_register *reg, + unsigned int instance_id, const struct vkd3d_shader_normaliser *normaliser) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(reg->idx) && reg->idx[i].offset != ~0u; ++i) + { + if (reg->idx[i].rel_addr && shader_src_param_is_phase_instance_id(reg->idx[i].rel_addr, normaliser)) + { + reg->idx[i].rel_addr = NULL; + reg->idx[i].offset += instance_id; + } + } +} + +static void shader_instruction_eliminate_phase_instance_id(struct vkd3d_shader_instruction *ins, + unsigned int instance_id, const struct vkd3d_shader_normaliser *normaliser) +{ + struct vkd3d_shader_register *reg; + unsigned int i; + + for (i = 0; i < ins->src_count; ++i) + { + reg = (struct vkd3d_shader_register *)&ins->src[i].reg; + if (shader_src_param_is_phase_instance_id(&ins->src[i], normaliser)) + { + reg->type = VKD3DSPR_IMMCONST; + reg->precision = VKD3D_SHADER_REGISTER_PRECISION_DEFAULT; + reg->non_uniform = false; + reg->data_type = VKD3D_DATA_UINT; + reg->idx[0].offset = ~0u; + reg->idx[0].rel_addr = NULL; + reg->idx[1].offset = ~0u; + reg->idx[1].rel_addr = NULL; + reg->idx[2].offset = ~0u; + reg->idx[2].rel_addr = NULL; + reg->immconst_type = VKD3D_IMMCONST_SCALAR; + reg->u.immconst_uint[0] = instance_id; + continue; + } + shader_register_eliminate_phase_addressing(reg, instance_id, normaliser); + } + + for (i = 0; i < ins->dst_count; ++i) + shader_register_eliminate_phase_addressing((struct vkd3d_shader_register *)&ins->dst[i].reg, + instance_id, normaliser); +} + +static bool shader_register_clone_relative_addresses(struct vkd3d_shader_register *reg, + struct vkd3d_shader_instruction_array *instructions) +{ + struct vkd3d_shader_src_param *src; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(reg->idx) && reg->idx[i].offset != ~0u; ++i) + { + if (!reg->idx[i].rel_addr) + continue; + + if (!(src = shader_src_param_allocator_get(&instructions->src_params, 1))) + return false; + + memcpy(src, reg->idx[i].rel_addr, sizeof(*src)); + reg->idx[i].rel_addr = src; + } + + return true; +} + +static bool shader_instruction_array_clone_instruction(struct vkd3d_shader_instruction_array *instructions, + unsigned int dst, const struct vkd3d_shader_instruction *src) +{ + struct vkd3d_shader_instruction *ins = &instructions->elements[dst]; + struct vkd3d_shader_dst_param *dst_params; + struct vkd3d_shader_src_param *src_params; + unsigned int i; + + *ins = *src; + + if (ins->dst_count && ins->dst) + { + if (!(dst_params = shader_dst_param_allocator_get(&instructions->dst_params, ins->dst_count))) + return false; + + memcpy(dst_params, ins->dst, ins->dst_count * sizeof(*ins->dst)); + ins->dst = dst_params; + for (i = 0; i < ins->dst_count; ++i) + { + if (!shader_register_clone_relative_addresses(&dst_params[i].reg, instructions)) + return false; + } + } + if (ins->src_count) + { + if (!(src_params = shader_src_param_allocator_get(&instructions->src_params, ins->src_count))) + return false; + + memcpy(src_params, ins->src, ins->src_count * sizeof(*ins->src)); + ins->src = src_params; + for (i = 0; i < ins->src_count; ++i) + { + if (!shader_register_clone_relative_addresses(&src_params[i].reg, instructions)) + return false; + } + } + + return true; +} + +static bool normaliser_is_in_fork_or_join_phase(const struct vkd3d_shader_normaliser *normaliser) +{ + return normaliser->phase == VKD3DSIH_HS_FORK_PHASE || normaliser->phase == VKD3DSIH_HS_JOIN_PHASE; +} + +static enum vkd3d_result shader_normaliser_eliminate_phase_instance_id(struct vkd3d_shader_normaliser *normaliser, + unsigned int *instruction_count) +{ + struct vkd3d_shader_instruction *ins = &normaliser->instructions.elements[normaliser->instructions.count]; + unsigned int i, j, count; + + if (ins->handler_idx == VKD3DSIH_HS_FORK_PHASE || ins->handler_idx == VKD3DSIH_HS_JOIN_PHASE) + { + /* Leave the first occurrence and delete the rest. */ + *instruction_count = !normaliser_is_in_fork_or_join_phase(normaliser); + /* Reset the phase info. */ + normaliser->phase_body_idx = ~0u; + normaliser->phase = ins->handler_idx; + normaliser->instance_count = 1; + normaliser->temp_is_instance_id = 0; + return VKD3D_OK; + } + else if (ins->handler_idx == VKD3DSIH_DCL_HS_FORK_PHASE_INSTANCE_COUNT + || ins->handler_idx == VKD3DSIH_DCL_HS_JOIN_PHASE_INSTANCE_COUNT) + { + normaliser->instance_count = ins->declaration.count + !ins->declaration.count; + *instruction_count = 0; + return VKD3D_OK; + } + else if (ins->handler_idx == VKD3DSIH_DCL_INPUT && shader_register_is_phase_instance_id( + &ins->declaration.dst.reg)) + { + *instruction_count = 0; + return VKD3D_OK; + } + else if (ins->handler_idx == VKD3DSIH_DCL_TEMPS && normaliser->phase != VKD3DSIH_INVALID) + { + /* Leave only the first temp declaration and set it to the max count later. */ + if (!normaliser->max_temp_count) + normaliser->temp_dcl_idx = normaliser->instructions.count; + else + *instruction_count = 0; + normaliser->max_temp_count = max(normaliser->max_temp_count, ins->declaration.count); + return VKD3D_OK; + } + + if (normaliser->phase == VKD3DSIH_INVALID || shader_instruction_is_dcl(ins)) + return VKD3D_OK; + + if (ins->handler_idx == VKD3DSIH_MOV && shader_register_is_phase_instance_id(&ins->src->reg)) + { + if (ins->dst->reg.type != VKD3DSPR_TEMP) + { + FIXME("Instance id not assigned to temp register.\n"); + return VKD3D_OK; + } + /* Instance id always seems to be assigned to r{n}.x */ + if (ins->dst->write_mask != VKD3DSP_WRITEMASK_0) + FIXME("Unsupported write mask %#x.\n", ins->dst->write_mask); + if (ins->dst->reg.idx[0].offset >= sizeof(normaliser->temp_is_instance_id) * CHAR_BIT) + FIXME("Unsupported temp idx %u.\n", ins->dst->reg.idx[0].offset); + else + normaliser->temp_is_instance_id |= 1ull << ins->dst->reg.idx[0].offset; + *instruction_count = 0; + return VKD3D_OK; + } + + if (normaliser->phase_body_idx == ~0u) + normaliser->phase_body_idx = normaliser->instructions.count; + + if (ins->handler_idx != VKD3DSIH_RET) + return VKD3D_OK; + + count = normaliser->instructions.count - normaliser->phase_body_idx; + + if (!shader_instruction_array_reserve(&normaliser->instructions, count * (normaliser->instance_count - 1))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + /* Make a copy of the non-dcl instructions for each instance. */ + ins = &normaliser->instructions.elements[normaliser->phase_body_idx]; + for (i = 1; i < normaliser->instance_count; ++i) + { + for (j = 0; j < count; ++j) + { + if (!shader_instruction_array_clone_instruction(&normaliser->instructions, + normaliser->phase_body_idx + count * i + j, &ins[j])) + return VKD3D_ERROR_OUT_OF_MEMORY; + } + } + /* Replace each reference to the instance id with a constant instance id. */ + for (i = 0; i < normaliser->instance_count; ++i) + { + for (j = 0; j < count; ++j) + shader_instruction_eliminate_phase_instance_id( + &normaliser->instructions.elements[normaliser->phase_body_idx + count * i + j], i, normaliser); + } + + *instruction_count = count * (normaliser->instance_count - 1); + return VKD3D_OK; +} + +static void shader_instruction_init(struct vkd3d_shader_instruction *ins, enum vkd3d_shader_opcode handler_idx) +{ + memset(ins, 0, sizeof(*ins)); + ins->handler_idx = handler_idx; +} + +enum vkd3d_result shader_normaliser_normalise(struct vkd3d_shader_normaliser *normaliser, + const struct vkd3d_shader_instruction_array *instructions, struct spirv_compiler *compiler) +{ + const struct vkd3d_shader_instruction *ins; + enum vkd3d_result result = VKD3D_OK; + unsigned int i, instruction_count; + + memset(normaliser, 0, sizeof(*normaliser)); + normaliser->phase = VKD3DSIH_INVALID; + if (!shader_instruction_array_init(&normaliser->instructions, instructions->count)) + { + ERR("Failed to allocate instructions.\n"); + return VKD3D_ERROR_OUT_OF_MEMORY; + } + + for (i = 0; i < instructions->count; ++i) + { + if (!shader_normaliser_new_instructions(normaliser, 1)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + ins = &instructions->elements[i]; + + if (!shader_instruction_array_clone_instruction(&normaliser->instructions, normaliser->instructions.count, ins)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + instruction_count = 1; + if ((result = shader_normaliser_eliminate_phase_instance_id(normaliser, &instruction_count)) < 0) + return result; + + normaliser->instructions.count += instruction_count; + } + + if (normaliser->phase != VKD3DSIH_INVALID) + { + if (normaliser->temp_dcl_idx) + normaliser->instructions.elements[normaliser->temp_dcl_idx].declaration.count = normaliser->max_temp_count; + + if (!shader_normaliser_new_instructions(normaliser, 1)) + return VKD3D_ERROR_OUT_OF_MEMORY; + shader_instruction_init(&normaliser->instructions.elements[normaliser->instructions.count++], VKD3DSIH_RET); + } + + return result; +} + +void shader_normaliser_destroy(struct vkd3d_shader_normaliser *normaliser) +{ + shader_instruction_array_destroy(&normaliser->instructions); +} diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index f0cfee47..90f2f7d0 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2199,9 +2199,7 @@ struct vkd3d_shader_phase { enum vkd3d_shader_opcode type; unsigned int idx; - unsigned int instance_count; uint32_t function_id; - uint32_t instance_id; size_t function_location; };
@@ -2887,12 +2885,6 @@ static bool spirv_compiler_get_register_name(char *buffer, unsigned int buffer_s case VKD3DSPR_DEPTHOUTLE: snprintf(buffer, buffer_size, "oDepth"); break; - case VKD3DSPR_FORKINSTID: - snprintf(buffer, buffer_size, "vForkInstanceId"); - break; - case VKD3DSPR_JOININSTID: - snprintf(buffer, buffer_size, "vJoinInstanceId"); - break; case VKD3DSPR_GSINSTID: snprintf(buffer, buffer_size, "vGSInstanceID"); break; @@ -4333,29 +4325,15 @@ static void spirv_compiler_begin_shader_phase(struct spirv_compiler *compiler, { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; uint32_t void_id, function_type_id; - unsigned int param_count; uint32_t param_type_id;
- if (phase->instance_count) - { - param_type_id = vkd3d_spirv_get_type_id(builder, VKD3D_SHADER_COMPONENT_UINT, 1); - param_count = 1; - } - else - { - param_count = 0; - } - phase->function_id = vkd3d_spirv_alloc_id(builder);
void_id = vkd3d_spirv_get_op_type_void(builder); - function_type_id = vkd3d_spirv_get_op_type_function(builder, void_id, ¶m_type_id, param_count); + function_type_id = vkd3d_spirv_get_op_type_function(builder, void_id, ¶m_type_id, 0); vkd3d_spirv_build_op_function(builder, void_id, phase->function_id, SpvFunctionControlMaskNone, function_type_id);
- if (phase->instance_count) - phase->instance_id = vkd3d_spirv_build_op_function_parameter(builder, param_type_id); - vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder)); phase->function_location = vkd3d_spirv_stream_current_location(&builder->function_stream);
@@ -4772,10 +4750,7 @@ static void spirv_compiler_emit_input_register(struct spirv_compiler *compiler, static void spirv_compiler_emit_shader_phase_input(struct spirv_compiler *compiler, const struct vkd3d_shader_phase *phase, const struct vkd3d_shader_dst_param *dst) { - struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; const struct vkd3d_shader_register *reg = &dst->reg; - struct vkd3d_symbol reg_symbol; - uint32_t val_id;
switch (reg->type) { @@ -4787,10 +4762,6 @@ static void spirv_compiler_emit_shader_phase_input(struct spirv_compiler *compil case VKD3DSPR_PRIMID: spirv_compiler_emit_input_register(compiler, dst); return; - case VKD3DSPR_FORKINSTID: - case VKD3DSPR_JOININSTID: - val_id = phase->instance_id; - break; case VKD3DSPR_OUTPOINTID: /* Emitted in spirv_compiler_emit_initial_declarations(). */ case VKD3DSPR_OUTCONTROLPOINT: /* See spirv_compiler_leave_shader_phase(). */ return; @@ -4798,13 +4769,6 @@ static void spirv_compiler_emit_shader_phase_input(struct spirv_compiler *compil FIXME("Unhandled shader phase input register %#x.\n", reg->type); return; } - - vkd3d_symbol_make_register(®_symbol, reg); - vkd3d_symbol_set_register_info(®_symbol, val_id, - SpvStorageClassMax /* Intermediate value */, - VKD3D_SHADER_COMPONENT_UINT, VKD3DSP_WRITEMASK_0); - spirv_compiler_put_symbol(compiler, ®_symbol); - spirv_compiler_emit_register_debug_name(builder, val_id, reg); }
static unsigned int spirv_compiler_get_output_variable_index( @@ -6560,20 +6524,6 @@ static void spirv_compiler_leave_shader_phase(struct spirv_compiler *compiler, } } } - - if (phase->instance_count) - { - memset(®, 0, sizeof(reg)); - reg.type = phase->type == VKD3DSIH_HS_FORK_PHASE ? VKD3DSPR_FORKINSTID : VKD3DSPR_JOININSTID; - reg.idx[0].offset = ~0u; - reg.idx[1].offset = ~0u; - vkd3d_symbol_make_register(®_symbol, ®); - if ((entry = rb_get(&compiler->symbol_table, ®_symbol))) - { - rb_remove(&compiler->symbol_table, entry); - vkd3d_symbol_free(entry, NULL); - } - } }
static void spirv_compiler_enter_shader_phase(struct spirv_compiler *compiler, @@ -6592,34 +6542,12 @@ static void spirv_compiler_enter_shader_phase(struct spirv_compiler *compiler,
phase->type = instruction->handler_idx; phase->idx = compiler->shader_phase_count; - phase->instance_count = 0; phase->function_id = 0; - phase->instance_id = 0; phase->function_location = 0;
++compiler->shader_phase_count; }
-static int spirv_compiler_emit_shader_phase_instance_count(struct spirv_compiler *compiler, - const struct vkd3d_shader_instruction *instruction) -{ - struct vkd3d_shader_phase *phase = &compiler->shader_phases[compiler->shader_phase_count - 1]; - - if (!compiler->shader_phase_count - || (phase->type != VKD3DSIH_HS_FORK_PHASE && phase->type != VKD3DSIH_HS_JOIN_PHASE) - || phase->function_id) - { - WARN("Unexpected dcl_hs_{fork,join}_phase_instance_count instruction.\n"); - return VKD3D_ERROR_INVALID_SHADER; - } - - phase->instance_count = instruction->declaration.count; - - spirv_compiler_begin_shader_phase(compiler, phase); - - return VKD3D_OK; -} - static const struct vkd3d_shader_phase *spirv_compiler_get_control_point_phase( struct spirv_compiler *compiler) { @@ -6851,12 +6779,27 @@ static void spirv_compiler_emit_shader_epilogue_invocation(struct spirv_compiler } }
+static const struct vkd3d_shader_phase *spirv_compiler_get_fork_or_join_phase( + struct spirv_compiler *compiler) +{ + const struct vkd3d_shader_phase *phase; + + assert(compiler->shader_phase_count); + + phase = &compiler->shader_phases[0]; + if (is_control_point_phase(phase)) + { + assert(compiler->shader_phase_count > 1); + phase = &compiler->shader_phases[1]; + } + + return phase; +} + static void spirv_compiler_emit_hull_shader_main(struct spirv_compiler *compiler) { struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - const struct vkd3d_shader_phase *control_point_phase, *phase; - uint32_t phase_instance_id; - unsigned int i, j; + const struct vkd3d_shader_phase *control_point_phase; uint32_t void_id;
vkd3d_spirv_builder_begin_main_function(builder); @@ -6870,30 +6813,12 @@ static void spirv_compiler_emit_hull_shader_main(struct spirv_compiler *compiler else spirv_compiler_emit_default_control_point_phase(compiler);
- if (compiler->use_vocp) - spirv_compiler_emit_hull_shader_barrier(compiler); - - for (i = 0; i < compiler->shader_phase_count; ++i) - { - phase = &compiler->shader_phases[i]; - if (is_control_point_phase(phase)) - continue; - - if (phase->instance_count) - { - for (j = 0; j < phase->instance_count; ++j) - { - phase_instance_id = spirv_compiler_get_constant_uint(compiler, j); - vkd3d_spirv_build_op_function_call(builder, - void_id, phase->function_id, &phase_instance_id, 1); - } - } - else - { - vkd3d_spirv_build_op_function_call(builder, void_id, phase->function_id, NULL, 0); - } - } - + /* TODO: only call the patch constant function for invocation 0. The simplest way + * is to avoid use of private variables there, otherwise we would need a separate + * patch constant epilogue also only called from invocation 0. */ + spirv_compiler_emit_hull_shader_barrier(compiler); + vkd3d_spirv_build_op_function_call(builder, void_id, spirv_compiler_get_fork_or_join_phase(compiler)->function_id, + NULL, 0); spirv_compiler_emit_shader_epilogue_invocation(compiler); vkd3d_spirv_build_op_return(builder); vkd3d_spirv_build_op_function_end(builder); @@ -9699,10 +9624,6 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler, case VKD3DSIH_DCL_THREAD_GROUP: spirv_compiler_emit_dcl_thread_group(compiler, instruction); break; - case VKD3DSIH_DCL_HS_FORK_PHASE_INSTANCE_COUNT: - case VKD3DSIH_DCL_HS_JOIN_PHASE_INSTANCE_COUNT: - ret = spirv_compiler_emit_shader_phase_instance_count(compiler, instruction); - break; case VKD3DSIH_HS_CONTROL_POINT_PHASE: case VKD3DSIH_HS_FORK_PHASE: case VKD3DSIH_HS_JOIN_PHASE: @@ -9955,16 +9876,27 @@ int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, const struct vkd3d_shader_spirv_target_info *info = compiler->spirv_target_info; const struct vkd3d_shader_spirv_domain_shader_target_info *ds_info; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; + struct vkd3d_shader_normaliser normaliser; const struct vkd3d_shader_phase *phase; enum vkd3d_result result = VKD3D_OK; unsigned int i;
- for (i = 0; i < instructions->count; ++i) + if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL) { - if ((result = spirv_compiler_handle_instruction(compiler, &instructions->elements[i])) < 0) + if ((result = shader_normaliser_normalise(&normaliser, instructions, compiler)) < 0) return result; + instructions = &normaliser.instructions; }
+ for (i = 0; i < instructions->count && result >= 0; ++i) + result = spirv_compiler_handle_instruction(compiler, &instructions->elements[i]); + + if (compiler->shader_type == VKD3D_SHADER_TYPE_HULL) + shader_normaliser_destroy(&normaliser); + + if (result < 0) + return result; + if ((phase = spirv_compiler_get_current_shader_phase(compiler))) spirv_compiler_leave_shader_phase(compiler, phase); else @@ -10034,7 +9966,6 @@ void spirv_compiler_destroy(struct spirv_compiler *compiler)
rb_destroy(&compiler->symbol_table, vkd3d_symbol_free, NULL);
- vkd3d_free(compiler->shader_phases); vkd3d_free(compiler->spec_constants);
vkd3d_string_buffer_cache_cleanup(&compiler->string_buffers); diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 6c5a1917..7a5ffe19 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1327,4 +1327,21 @@ void dxbc_writer_add_section(struct dxbc_writer *dxbc, uint32_t tag, const void void dxbc_writer_init(struct dxbc_writer *dxbc); int dxbc_writer_write(struct dxbc_writer *dxbc, struct vkd3d_shader_code *code);
+struct vkd3d_shader_normaliser +{ + struct vkd3d_shader_instruction_array instructions; + + unsigned int max_temp_count; + unsigned int temp_dcl_idx; + uint64_t temp_is_instance_id; + + unsigned int instance_count; + unsigned int phase_body_idx; + enum vkd3d_shader_opcode phase; +}; + +enum vkd3d_result shader_normaliser_normalise(struct vkd3d_shader_normaliser *normaliser, + const struct vkd3d_shader_instruction_array *instructions, struct spirv_compiler *compiler); +void shader_normaliser_destroy(struct vkd3d_shader_normaliser *normaliser); + #endif /* __VKD3D_SHADER_PRIVATE_H */