From: Francisco Casas fcasas@codeweavers.com
--- libs/vkd3d-shader/ir.c | 115 +++++++++++++++++++++++ libs/vkd3d-shader/spirv.c | 12 +-- libs/vkd3d-shader/vkd3d_shader_main.c | 17 ++++ libs/vkd3d-shader/vkd3d_shader_private.h | 2 + 4 files changed, 139 insertions(+), 7 deletions(-)
diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index 9fd60fa76..ea195f4c0 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -36,6 +36,118 @@ static void vkd3d_shader_instruction_make_nop(struct vkd3d_shader_instruction *i vsir_instruction_init(ins, &location, VKD3DSIH_NOP); }
+static bool vsir_instruction_init_with_params(struct vkd3d_shader_parser *parser, + struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location, + enum vkd3d_shader_opcode handler_idx, unsigned int dst_count, unsigned int src_count) +{ + vsir_instruction_init(ins, location, handler_idx); + ins->dst_count = dst_count; + ins->src_count = src_count; + + if (!(ins->dst = shader_parser_get_dst_params(parser, ins->dst_count))) + { + ERR("Failed to allocate %u destination parameters.\n", dst_count); + return false; + } + + if (!(ins->src = shader_parser_get_src_params(parser, ins->src_count))) + { + ERR("Failed to allocate %u source parameters.\n", src_count); + return false; + } + + memset(ins->dst, 0, sizeof(*ins->dst) * ins->dst_count); + memset(ins->src, 0, sizeof(*ins->src) * ins->src_count); + return true; +} + +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; + unsigned int componets_read = 3 + (parser->shader_version.major >= 2); + unsigned int tmp_idx = ~0u; + unsigned int i, k; + + for (i = 0; i < instructions->count; ++i) + { + texkill_ins = &instructions->elements[i]; + + if (texkill_ins->handler_idx != VKD3DSIH_TEXKILL) + continue; + + assert(texkill_ins->dst_count == 1); + assert(texkill_ins->src_count == 0); + + if (!shader_instruction_array_insert_at(instructions, i + 1, 5)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + if (tmp_idx == ~0u) + tmp_idx = parser->shader_desc.temp_count++; + + /* tmp = ins->dst[0] < 0 */ + + ins = texkill_ins + 1; + if (!vsir_instruction_init_with_params(parser, ins, &texkill_ins->location, VKD3DSIH_LTO, 1, 2)) + return VKD3D_ERROR_OUT_OF_MEMORY; + + vsir_register_init(&ins->dst[0].reg, VKD3DSPR_TEMP, VKD3D_DATA_INT, 1); + ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; + ins->dst[0].reg.idx[0].offset = tmp_idx; + ins->dst[0].write_mask = VKD3DSP_WRITEMASK_ALL; + + ins->src[0].reg = texkill_ins->dst[0].reg; + vsir_register_init(&ins->src[1].reg, VKD3DSPR_IMMCONST, VKD3D_DATA_FLOAT, 0); + ins->src[1].reg.dimension = VSIR_DIMENSION_VEC4; + ins->src[1].reg.u.immconst_f32[0] = 0.0f; + ins->src[1].reg.u.immconst_f32[1] = 0.0f; + ins->src[1].reg.u.immconst_f32[2] = 0.0f; + ins->src[1].reg.u.immconst_f32[3] = 0.0f; + + /* tmp.x = tmp.x || tmp.y */ + /* tmp.x = tmp.x || tmp.z */ + /* tmp.x = tmp.x || tmp.w, if sm >= 2.0 */ + + for (k = 1; k < componets_read; ++k) + { + ins = texkill_ins + 1 + k; + if (!(vsir_instruction_init_with_params(parser, ins, &texkill_ins->location, VKD3DSIH_OR, 1, 2))) + return VKD3D_ERROR_OUT_OF_MEMORY; + + vsir_register_init(&ins->dst[0].reg, VKD3DSPR_TEMP, VKD3D_DATA_INT, 1); + ins->dst[0].reg.dimension = VSIR_DIMENSION_VEC4; + ins->dst[0].reg.idx[0].offset = tmp_idx; + ins->dst[0].write_mask = VKD3DSP_WRITEMASK_0; + + vsir_register_init(&ins->src[0].reg, VKD3DSPR_TEMP, VKD3D_DATA_INT, 1); + ins->src[0].reg.dimension = VSIR_DIMENSION_VEC4; + ins->src[0].reg.idx[0].offset = tmp_idx; + ins->src[0].swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X); + vsir_register_init(&ins->src[1].reg, VKD3DSPR_TEMP, VKD3D_DATA_INT, 1); + ins->src[1].reg.dimension = VSIR_DIMENSION_VEC4; + ins->src[1].reg.idx[0].offset = tmp_idx; + ins->src[1].swizzle = vkd3d_shader_create_swizzle(k, k, k, k); + } + + /* discard_nz tmp.x */ + + ins = texkill_ins + 5; + if (!(vsir_instruction_init_with_params(parser, ins, &texkill_ins->location, VKD3DSIH_DISCARD, 0, 1))) + return VKD3D_ERROR_OUT_OF_MEMORY; + ins->flags = VKD3D_SHADER_CONDITIONAL_OP_NZ; + + vsir_register_init(&ins->src[0].reg, VKD3DSPR_TEMP, VKD3D_DATA_INT, 1); + ins->src[0].reg.dimension = VSIR_DIMENSION_VEC4; + ins->src[0].reg.idx[0].offset = tmp_idx; + ins->src[0].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 +1597,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..d48c8b617 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -7957,7 +7957,6 @@ static int spirv_compiler_emit_control_flow_instruction(struct spirv_compiler *c break;
case VKD3DSIH_DISCARD: - case VKD3DSIH_TEXKILL: spirv_compiler_emit_kill(compiler, instruction); break;
@@ -9729,7 +9728,6 @@ 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_DSX: @@ -9939,11 +9937,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 +9945,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..248a55a10 100644 --- a/libs/vkd3d-shader/vkd3d_shader_main.c +++ b/libs/vkd3d-shader/vkd3d_shader_main.c @@ -2057,6 +2057,23 @@ 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) +{ + assert(idx <= instructions->count); + + if (!shader_instruction_array_reserve(instructions, instructions->count + count)) + return false; + + memmove(&instructions->elements[idx + count], &instructions->elements[idx], + (instructions->count - idx) * sizeof(*instructions->elements)); + memset(&instructions->elements[idx], 0, count * 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 b4de44e63..94c2f62bc 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -1230,6 +1230,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,