From: Francisco Casas fcasas@codeweavers.com
--- libs/vkd3d-shader/ir.c | 138 +++++++++++++++++++++++ libs/vkd3d-shader/spirv.c | 10 +- libs/vkd3d-shader/vkd3d_shader_main.c | 21 ++++ libs/vkd3d-shader/vkd3d_shader_private.h | 6 + 4 files changed, 170 insertions(+), 5 deletions(-)
diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index bac426919..7ca6f21b5 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -36,6 +36,141 @@ static void vkd3d_shader_instruction_make_nop(struct vkd3d_shader_instruction *i vsir_instruction_init(ins, &location, VKD3DSIH_NOP); }
+static uint32_t parser_get_extra_temp(struct vkd3d_shader_parser *parser) +{ + if (!parser->shader_desc.extra_temp_allocated) + { + parser->shader_desc.extra_temp = parser->shader_desc.temp_count++; + parser->shader_desc.extra_temp_allocated = true; + } + return parser->shader_desc.extra_temp; +} + +static enum vkd3d_result instruction_array_lower_texkills(struct vkd3d_shader_parser *parser) +{ + struct vkd3d_shader_instruction_array *instructions = &parser->instructions; + struct vkd3d_shader_instruction *texkill_ins, *ins; + struct vkd3d_shader_src_param *src_param; + struct vkd3d_shader_dst_param *dst_param; + + for (int i = 0; i < instructions->count; ++i) + { + unsigned int tmp_idx; + + texkill_ins = &instructions->elements[i]; + + if (texkill_ins->handler_idx != VKD3DSIH_TEXKILL) + continue; + + if (!shader_instruction_array_insert_at(instructions, i + 1, 4)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + tmp_idx = parser_get_extra_temp(parser); + + /* tmp = ins->src[0] < 0 */ + + ins = texkill_ins + 1; + vsir_instruction_init(ins, &texkill_ins->location, VKD3DSIH_LTO); + + ins->dst_count = 1; + if (!(ins->dst = dst_param = shader_parser_get_dst_params(parser, ins->dst_count))) + return VKD3D_ERROR_OUT_OF_MEMORY; + memset(dst_param, 0, sizeof(*dst_param) * ins->dst_count); + vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_INT, 1); + dst_param->reg.dimension = VSIR_DIMENSION_VEC4; + dst_param->reg.idx[0].offset = tmp_idx; + dst_param->write_mask = VKD3DSP_WRITEMASK_ALL; + + ins->src_count = 2; + if (!(ins->src = src_param = shader_parser_get_src_params(parser, ins->src_count))) + return VKD3D_ERROR_OUT_OF_MEMORY; + memset(src_param, 0, sizeof(*src_param) * ins->src_count); + src_param[0] = texkill_ins->src[0]; + vsir_register_init(&src_param[1].reg, VKD3DSPR_IMMCONST, VKD3D_DATA_FLOAT, 0); + src_param[1].reg.dimension = VSIR_DIMENSION_VEC4; + src_param[1].reg.u.immconst_f32[0] = 0.0f; + src_param[1].reg.u.immconst_f32[1] = 0.0f; + src_param[1].reg.u.immconst_f32[2] = 0.0f; + src_param[1].reg.u.immconst_f32[3] = 0.0f; + + /* tmp.x = tmp.x || tmp.y */ + + ins = texkill_ins + 2; + vsir_instruction_init(ins, &texkill_ins->location, VKD3DSIH_OR); + + ins->dst_count = 1; + if (!(ins->dst = dst_param = shader_parser_get_dst_params(parser, ins->dst_count))) + return VKD3D_ERROR_OUT_OF_MEMORY; + memset(dst_param, 0, sizeof(*dst_param) * ins->dst_count); + vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_INT, 1); + dst_param->reg.dimension = VSIR_DIMENSION_VEC4; + dst_param->reg.idx[0].offset = tmp_idx; + dst_param->write_mask = VKD3DSP_WRITEMASK_0; + + ins->src_count = 2; + if (!(ins->src = src_param = shader_parser_get_src_params(parser, ins->src_count))) + return VKD3D_ERROR_OUT_OF_MEMORY; + memset(src_param, 0, sizeof(*src_param) * ins->src_count); + vsir_register_init(&src_param[0].reg, VKD3DSPR_TEMP, VKD3D_DATA_INT, 1); + src_param[0].reg.dimension = VSIR_DIMENSION_VEC4; + src_param[0].reg.idx[0].offset = tmp_idx; + src_param[0].swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X); + vsir_register_init(&src_param[1].reg, VKD3DSPR_TEMP, VKD3D_DATA_INT, 1); + src_param[1].reg.dimension = VSIR_DIMENSION_VEC4; + src_param[1].reg.idx[0].offset = tmp_idx; + src_param[1].swizzle = VKD3D_SHADER_SWIZZLE(Y, Y, Y, Y); + + /* tmp.x = tmp.x || tmp.z */ + + ins = texkill_ins + 3; + vsir_instruction_init(ins, &texkill_ins->location, VKD3DSIH_OR); + + ins->dst_count = 1; + if (!(ins->dst = dst_param = shader_parser_get_dst_params(parser, ins->dst_count))) + return VKD3D_ERROR_OUT_OF_MEMORY; + memset(dst_param, 0, sizeof(*dst_param) * ins->dst_count); + vsir_register_init(&dst_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_INT, 1); + dst_param->reg.dimension = VSIR_DIMENSION_VEC4; + dst_param->reg.idx[0].offset = tmp_idx; + dst_param->write_mask = VKD3DSP_WRITEMASK_0; + + ins->src_count = 2; + if (!(ins->src = src_param = shader_parser_get_src_params(parser, ins->src_count))) + return VKD3D_ERROR_OUT_OF_MEMORY; + memset(src_param, 0, sizeof(*src_param) * ins->src_count); + vsir_register_init(&src_param[0].reg, VKD3DSPR_TEMP, VKD3D_DATA_INT, 1); + src_param[0].reg.dimension = VSIR_DIMENSION_VEC4; + src_param[0].reg.idx[0].offset = tmp_idx; + src_param[0].swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X); + vsir_register_init(&src_param[1].reg, VKD3DSPR_TEMP, VKD3D_DATA_INT, 1); + src_param[1].reg.dimension = VSIR_DIMENSION_VEC4; + src_param[1].reg.idx[0].offset = tmp_idx; + src_param[1].swizzle = VKD3D_SHADER_SWIZZLE(Z, Z, Z, Z); + + /* discard_nz tmp.x */ + + ins = texkill_ins + 4; + vsir_instruction_init(ins, &texkill_ins->location, VKD3DSIH_DISCARD); + ins->flags = VKD3D_SHADER_CONDITIONAL_OP_NZ; + + ins->dst_count = 0; + + ins->src_count = 1; + if (!(ins->src = src_param = shader_parser_get_src_params(parser, ins->src_count))) + return VKD3D_ERROR_OUT_OF_MEMORY; + memset(src_param, 0, sizeof(*src_param) * ins->src_count); + vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, VKD3D_DATA_INT, 1); + src_param->reg.dimension = VSIR_DIMENSION_VEC4; + src_param->reg.idx[0].offset = tmp_idx; + src_param->swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X); + + /* Make the original instruction no-op */ + vkd3d_shader_instruction_make_nop(texkill_ins); + } + + return VKD3D_OK; +} + static void shader_register_eliminate_phase_addressing(struct vkd3d_shader_register *reg, unsigned int instance_id) { @@ -1485,6 +1620,9 @@ enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser, if (parser->shader_desc.is_dxil) return result;
+ if (result >= 0) + result = instruction_array_lower_texkills(parser); + if (parser->shader_version.type != VKD3D_SHADER_TYPE_PIXEL && (result = remap_output_signature(parser, compile_info)) < 0) return result; diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index aa8ceaa67..0b1a49a40 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -9939,11 +9939,6 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, enum vkd3d_result result = VKD3D_OK; unsigned int i;
- if (parser->shader_desc.temp_count) - spirv_compiler_emit_temps(compiler, parser->shader_desc.temp_count); - if (parser->shader_desc.ssa_count) - spirv_compiler_allocate_ssa_register_ids(compiler, parser->shader_desc.ssa_count); - spirv_compiler_emit_descriptor_declarations(compiler);
compiler->location.column = 0; @@ -9952,6 +9947,11 @@ 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.temp_count) + spirv_compiler_emit_temps(compiler, parser->shader_desc.temp_count); + if (parser->shader_desc.ssa_count) + spirv_compiler_allocate_ssa_register_ids(compiler, parser->shader_desc.ssa_count); + instructions = parser->instructions; memset(&parser->instructions, 0, sizeof(parser->instructions));
diff --git a/libs/vkd3d-shader/vkd3d_shader_main.c b/libs/vkd3d-shader/vkd3d_shader_main.c index f12b11adb..55fd52d89 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -2057,6 +2057,27 @@ bool shader_instruction_array_reserve(struct vkd3d_shader_instruction_array *ins return true; }
+bool shader_instruction_array_insert_at(struct vkd3d_shader_instruction_array *instructions, + unsigned int idx, unsigned int count) +{ + unsigned int i; + + assert(idx <= instructions->count); + + if (!shader_instruction_array_reserve(instructions, instructions->count + count)) + return false; + + for (i = instructions->count - 1; i >= idx; --i) + instructions->elements[i + count] = instructions->elements[i]; + + for (i = idx; i < idx + count; ++i) + memset(&instructions->elements[i], 0, sizeof(*instructions->elements)); + + instructions->count += count; + + return true; +} + bool shader_instruction_array_add_icb(struct vkd3d_shader_instruction_array *instructions, struct vkd3d_shader_immediate_constant_buffer *icb) { diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index 199a47a76..2a16b8568 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1022,6 +1022,10 @@ struct vkd3d_shader_desc } flat_constant_count[3];
bool use_vocp; + + /* Whether an extra temp has been allocated for VSIR compilation passes, and its index. */ + bool extra_temp_allocated; + uint32_t extra_temp; };
struct vkd3d_shader_register_semantic @@ -1230,6 +1234,8 @@ struct vkd3d_shader_instruction_array
bool shader_instruction_array_init(struct vkd3d_shader_instruction_array *instructions, unsigned int reserve); bool shader_instruction_array_reserve(struct vkd3d_shader_instruction_array *instructions, unsigned int reserve); +bool shader_instruction_array_insert_at(struct vkd3d_shader_instruction_array *instructions, + unsigned int idx, unsigned int count); bool shader_instruction_array_add_icb(struct vkd3d_shader_instruction_array *instructions, struct vkd3d_shader_immediate_constant_buffer *icb); bool shader_instruction_array_clone_instruction(struct vkd3d_shader_instruction_array *instructions,