From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/ir.c | 146 ++++++++++++++++++++++++++++++++++ libs/vkd3d-shader/spirv.c | 162 ++------------------------------------ 2 files changed, 154 insertions(+), 154 deletions(-)
diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index 97a88e21f..9c1cd90f3 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -1484,8 +1484,12 @@ struct clip_cull_normaliser size_t instruction_count;
struct clip_cull_normaliser_signature input_signature; + struct clip_cull_normaliser_signature output_signature; + struct clip_cull_normaliser_signature patch_constant_signature;
unsigned int temp_count; + + enum vkd3d_shader_opcode phase; };
static unsigned int mask_find_free_array_slot(unsigned int used_mask, unsigned int array_size) @@ -1752,8 +1756,20 @@ static void shader_instruction_src_param_clip_cull_normalise(struct vkd3d_shader switch (reg->type) { case VKD3DSPR_INPUT: + /* Sysvals are not needed for domain shader inputs. */ + if (parser->program.shader_version.type == VKD3D_SHADER_TYPE_DOMAIN) + return; signature = &normaliser->input_signature; break; + case VKD3DSPR_OUTPUT: + /* Sysvals are not needed for hull shader outputs. */ + if (parser->program.shader_version.type == VKD3D_SHADER_TYPE_HULL) + return; + signature = &normaliser->output_signature; + break; + case VKD3DSPR_PATCHCONST: + signature = &normaliser->patch_constant_signature; + break; default: return; } @@ -1842,6 +1858,119 @@ static void shader_instruction_src_param_clip_cull_normalise(struct vkd3d_shader reg->idx[0].offset = parser->program.temp_count; }
+static void shader_dst_param_clip_cull_normalise(struct vkd3d_shader_dst_param *dst_param, + struct clip_cull_normaliser *normaliser) + { + struct vkd3d_shader_parser *parser = normaliser->parser; + const struct clip_cull_normaliser_signature *signature; + unsigned int i, element_idx, write_mask, array_offset; + struct vkd3d_shader_register *reg = &dst_param->reg; + struct vsir_program *program = &parser->program; + struct vkd3d_shader_src_param *src_param; + struct vkd3d_shader_dst_param *mov_dst; + + if (!reg->idx_count) + return; + + switch (reg->type) + { + /* VKD3DSPR_INPUT must not occur in a dst param. */ + + case VKD3DSPR_OUTPUT: + if (normaliser->phase == VKD3DSIH_HS_FORK_PHASE || normaliser->phase == VKD3DSIH_HS_JOIN_PHASE) + { + signature = &normaliser->patch_constant_signature; + } + else + { + /* Sysvals are not needed for hull shader outputs. */ + if (parser->program.shader_version.type == VKD3D_SHADER_TYPE_HULL) + return; + signature = &normaliser->output_signature; + } + break; + + case VKD3DSPR_PATCHCONST: + signature = &normaliser->patch_constant_signature; + break; + + default: + return; + } + + element_idx = reg->idx[reg->idx_count - 1].offset; + + if (!signature->scan[element_idx].need_normalisation) + return; + + /* Elements with an array offset are remapped to the base element. */ + if ((array_offset = signature->scan[element_idx].offset)) + { + element_idx = signature->scan[element_idx].remap; + reg->idx[reg->idx_count - 1].offset = element_idx; + } + + write_mask = dst_param->write_mask; + + /* Dynamic array addressing of clip/cull outputs is not supported. */ + if (reg->idx_count >= ARRAY_SIZE(reg->idx)) + { + WARN("Unexpected index count %u.\n", reg->idx_count); + vkd3d_shader_parser_error(parser, VKD3D_SHADER_ERROR_VSIR_INVALID_INDEX_COUNT, + "Invalid register index count %u for a clip/cull store.", reg->idx_count); + normaliser->result = VKD3D_ERROR_INVALID_SHADER; + return; + } + + /* Move the indices up so the array index can be placed in idx[0]. */ + memmove(®->idx[1], ®->idx[0], reg->idx_count * sizeof(reg->idx[0])); + memset(®->idx[0], 0, sizeof(reg->idx[0])); + ++reg->idx_count; + + if (vsir_write_mask_component_count(write_mask) == 1) + { + reg->idx[0].offset = array_offset + vsir_write_mask_get_component_idx(write_mask); + dst_param->write_mask = VKD3DSP_WRITEMASK_0; + return; + } + + for (i = 0; i < VKD3D_VEC4_SIZE; ++i) + { + if (!(write_mask & (1u << i))) + continue; + + /* For each component, emit a MOV from a temp to the clip/cull array. */ + + if (!(src_param = vsir_program_get_src_params(program, 1))) + { + ERR("Failed to allocate instruction dst param.\n"); + normaliser->result = VKD3D_ERROR_OUT_OF_MEMORY; + return; + } + src_param->swizzle = vkd3d_shader_create_swizzle(i, i, i, i); + src_param->modifiers = 0; + vsir_register_init(&src_param->reg, VKD3DSPR_TEMP, reg->data_type, 1); + src_param->reg.dimension = reg->dimension; + src_param->reg.idx[0].offset = parser->program.temp_count; + normaliser->temp_count = 1; + + if (!(mov_dst = clip_cull_normaliser_emit_mov(normaliser, src_param))) + return; + mov_dst->reg = *reg; + mov_dst->reg.idx[0].offset = array_offset + i; + mov_dst->write_mask = VKD3DSP_WRITEMASK_0; + mov_dst->modifiers = 0; + mov_dst->shift = 0; + } + + /* Substitute the temp for the vector clip/cull destination. If this is for a MOV instruction with + * clip/cull source, it results in a harmless no-op MOV, because shader_src_param_clip_cull_normalise() + * has already written the clip/cull source to the temp. */ + vsir_register_init(reg, VKD3DSPR_TEMP, reg->data_type, 1); + reg->dimension = VSIR_DIMENSION_VEC4; + reg->idx[0].offset = parser->program.temp_count; +} + static void shader_instruction_normalise_clip_cull_params(struct vkd3d_shader_instruction *ins, struct clip_cull_normaliser *normaliser) { @@ -1858,6 +1987,14 @@ static void shader_instruction_normalise_clip_cull_params(struct vkd3d_shader_in return; }
+ if (ins->handler_idx == VKD3DSIH_HS_CONTROL_POINT_PHASE || ins->handler_idx == VKD3DSIH_HS_FORK_PHASE + || ins->handler_idx == VKD3DSIH_HS_JOIN_PHASE) + { + normaliser->phase = ins->handler_idx; + clip_cull_normaliser_copy_instruction(normaliser, ins); + return; + } + for (i = 0, write_mask = 0; i < ins->dst_count; ++i) if (ins->dst[i].reg.type != VKD3DSPR_NULL) write_mask |= ins->dst[i].write_mask; @@ -1866,6 +2003,9 @@ static void shader_instruction_normalise_clip_cull_params(struct vkd3d_shader_in shader_instruction_src_param_clip_cull_normalise(ins, i, write_mask, normaliser);
clip_cull_normaliser_copy_instruction(normaliser, ins); + + for (i = 0; i < ins->dst_count; ++i) + shader_dst_param_clip_cull_normalise(&ins->dst[i], normaliser); }
static enum vkd3d_result normalise_clip_cull(struct vkd3d_shader_parser *parser) @@ -1875,9 +2015,15 @@ static enum vkd3d_result normalise_clip_cull(struct vkd3d_shader_parser *parser)
normaliser.parser = parser; normaliser.input_signature.s = &parser->shader_desc.input_signature; + normaliser.output_signature.s = &parser->shader_desc.output_signature; + normaliser.patch_constant_signature.s = &parser->shader_desc.patch_constant_signature; + normaliser.phase = VKD3DSIH_INVALID;
if (parser->program.shader_version.type != VKD3D_SHADER_TYPE_DOMAIN) normaliser_signature_transform_clip_cull(&normaliser.input_signature, &normaliser); + if (parser->program.shader_version.type != VKD3D_SHADER_TYPE_HULL) + normaliser_signature_transform_clip_cull(&normaliser.output_signature, &normaliser); + normaliser_signature_transform_clip_cull(&normaliser.patch_constant_signature, &normaliser);
if (parser->failed) return VKD3D_ERROR_INVALID_SHADER; diff --git a/libs/vkd3d-shader/spirv.c b/libs/vkd3d-shader/spirv.c index 24f75a085..cb9ab927e 100644 --- a/libs/vkd3d-shader/spirv.c +++ b/libs/vkd3d-shader/spirv.c @@ -2332,7 +2332,6 @@ struct spirv_compiler { uint32_t id; enum vkd3d_shader_component_type component_type; - uint32_t array_element_mask; } *output_info; uint32_t private_output_variable[MAX_REG_OUTPUT + 1]; /* 1 entry for oDepth */ uint32_t private_output_variable_write_mask[MAX_REG_OUTPUT + 1]; /* 1 entry for oDepth */ @@ -5088,88 +5087,6 @@ static bool is_dual_source_blending(const struct spirv_compiler *compiler) return compiler->shader_type == VKD3D_SHADER_TYPE_PIXEL && info && info->dual_source_blending; }
-static void calculate_clip_or_cull_distance_mask(const struct signature_element *e, uint32_t *mask) -{ - unsigned int write_mask; - - if (e->semantic_index >= sizeof(*mask) * CHAR_BIT / VKD3D_VEC4_SIZE) - { - FIXME("Invalid semantic index %u for clip/cull distance.\n", e->semantic_index); - return; - } - - write_mask = e->mask >> vsir_write_mask_get_component_idx(e->mask); - *mask |= (write_mask & VKD3DSP_WRITEMASK_ALL) << (VKD3D_VEC4_SIZE * e->semantic_index); -} - -/* Emits arrayed SPIR-V built-in variables. */ -static void spirv_compiler_emit_shader_signature_outputs(struct spirv_compiler *compiler) -{ - const struct shader_signature *output_signature = &compiler->output_signature; - uint32_t clip_distance_mask = 0, clip_distance_id = 0; - uint32_t cull_distance_mask = 0, cull_distance_id = 0; - const struct vkd3d_spirv_builtin *builtin; - unsigned int i, count; - - for (i = 0; i < output_signature->element_count; ++i) - { - const struct signature_element *e = &output_signature->elements[i]; - - switch (e->sysval_semantic) - { - case VKD3D_SHADER_SV_CLIP_DISTANCE: - calculate_clip_or_cull_distance_mask(e, &clip_distance_mask); - break; - - case VKD3D_SHADER_SV_CULL_DISTANCE: - calculate_clip_or_cull_distance_mask(e, &cull_distance_mask); - break; - - default: - break; - } - } - - if (clip_distance_mask) - { - count = vkd3d_popcount(clip_distance_mask); - builtin = get_spirv_builtin_for_sysval(compiler, VKD3D_SHADER_SV_CLIP_DISTANCE); - clip_distance_id = spirv_compiler_emit_builtin_variable(compiler, - builtin, SpvStorageClassOutput, count); - } - - if (cull_distance_mask) - { - count = vkd3d_popcount(cull_distance_mask); - builtin = get_spirv_builtin_for_sysval(compiler, VKD3D_SHADER_SV_CULL_DISTANCE); - cull_distance_id = spirv_compiler_emit_builtin_variable(compiler, - builtin, SpvStorageClassOutput, count); - } - - for (i = 0; i < output_signature->element_count; ++i) - { - const struct signature_element *e = &output_signature->elements[i]; - - switch (e->sysval_semantic) - { - case VKD3D_SHADER_SV_CLIP_DISTANCE: - compiler->output_info[i].id = clip_distance_id; - compiler->output_info[i].component_type = VKD3D_SHADER_COMPONENT_FLOAT; - compiler->output_info[i].array_element_mask = clip_distance_mask; - break; - - case VKD3D_SHADER_SV_CULL_DISTANCE: - compiler->output_info[i].id = cull_distance_id; - compiler->output_info[i].component_type = VKD3D_SHADER_COMPONENT_FLOAT; - compiler->output_info[i].array_element_mask = cull_distance_mask; - break; - - default: - break; - } - } -} - static void spirv_compiler_emit_output_register(struct spirv_compiler *compiler, const struct vkd3d_shader_dst_param *dst) { @@ -5259,7 +5176,8 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, sysval = VKD3D_SHADER_SV_NONE; array_sizes[0] = signature_element->register_count; array_sizes[1] = (reg_type == VKD3DSPR_PATCHCONST ? 0 : compiler->output_control_point_count); - if (array_sizes[0] == 1 && !vsir_sysval_semantic_is_tess_factor(signature_element->sysval_semantic)) + if (array_sizes[0] == 1 && !vsir_sysval_semantic_is_tess_factor(signature_element->sysval_semantic) + && (!vsir_sysval_semantic_is_clip_cull(sysval) || array_sizes[1])) array_sizes[0] = 0;
builtin = vkd3d_get_spirv_builtin(compiler, reg_type, sysval); @@ -5285,8 +5203,7 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, use_private_variable = true;
if (!is_patch_constant - && (get_shader_output_swizzle(compiler, signature_element->register_index) != VKD3D_SHADER_NO_SWIZZLE - || (compiler->output_info[element_idx].id && compiler->output_info[element_idx].array_element_mask))) + && get_shader_output_swizzle(compiler, signature_element->register_index) != VKD3D_SHADER_NO_SWIZZLE) { use_private_variable = true; } @@ -5301,11 +5218,7 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, return; }
- if (!is_patch_constant && compiler->output_info[element_idx].id) - { - id = compiler->output_info[element_idx].id; - } - else if (builtin) + if (builtin) { if (spirv_compiler_get_current_shader_phase(compiler)) id = spirv_compiler_emit_shader_phase_builtin_variable(compiler, builtin, array_sizes, 2); @@ -5386,51 +5299,18 @@ static void spirv_compiler_emit_output(struct spirv_compiler *compiler, } }
-static uint32_t spirv_compiler_get_output_array_index(struct spirv_compiler *compiler, - const struct signature_element *e) -{ - enum vkd3d_shader_sysval_semantic sysval = e->sysval_semantic; - const struct vkd3d_spirv_builtin *builtin; - - builtin = get_spirv_builtin_for_sysval(compiler, sysval); - - switch (sysval) - { - case VKD3D_SHADER_SV_TESS_FACTOR_LINEDEN: - case VKD3D_SHADER_SV_TESS_FACTOR_LINEDET: - return builtin->member_idx; - default: - return e->semantic_index; - } -} - static void spirv_compiler_emit_store_shader_output(struct spirv_compiler *compiler, const struct shader_signature *signature, const struct signature_element *output, const struct vkd3d_shader_output_info *output_info, uint32_t output_index_id, uint32_t val_id, uint32_t write_mask) { - uint32_t dst_write_mask, use_mask, uninit_mask, swizzle, mask; + uint32_t dst_write_mask, use_mask, uninit_mask, swizzle, type_id, zero_id, ptr_type_id; struct vkd3d_spirv_builder *builder = &compiler->spirv_builder; - uint32_t type_id, zero_id, ptr_type_id, chain_id, object_id; - const struct signature_element *element; - unsigned int i, index, array_idx; + unsigned int index; uint32_t output_id;
dst_write_mask = output->mask; use_mask = output->used_mask; - if (!output->sysval_semantic) - { - for (i = 0; i < signature->element_count; ++i) - { - element = &signature->elements[i]; - if (element->register_index != output->register_index) - continue; - if (element->sysval_semantic) - continue; - dst_write_mask |= element->mask; - use_mask |= element->used_mask; - } - } index = vsir_write_mask_get_component_idx(output->mask); dst_write_mask >>= index; use_mask >>= index; @@ -5472,31 +5352,8 @@ static void spirv_compiler_emit_store_shader_output(struct spirv_compiler *compi output_id = vkd3d_spirv_build_op_access_chain1(builder, ptr_type_id, output_id, output_index_id); }
- if (!output_info->array_element_mask) - { - spirv_compiler_emit_store(compiler, - output_id, dst_write_mask, output_info->component_type, SpvStorageClassOutput, write_mask, val_id); - return; - } - - type_id = vkd3d_spirv_get_type_id(builder, output_info->component_type, 1); - ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassOutput, type_id); - mask = output_info->array_element_mask; - array_idx = spirv_compiler_get_output_array_index(compiler, output); - mask &= (1u << (array_idx * VKD3D_VEC4_SIZE)) - 1; - for (i = 0, index = vkd3d_popcount(mask); i < VKD3D_VEC4_SIZE; ++i) - { - if (!(write_mask & (VKD3DSP_WRITEMASK_0 << i))) - continue; - - chain_id = vkd3d_spirv_build_op_access_chain1(builder, - ptr_type_id, output_id, spirv_compiler_get_constant_uint(compiler, index)); - object_id = spirv_compiler_emit_swizzle(compiler, val_id, write_mask, - output_info->component_type, VKD3D_SHADER_NO_SWIZZLE, VKD3DSP_WRITEMASK_0 << i); - spirv_compiler_emit_store(compiler, chain_id, VKD3DSP_WRITEMASK_0, - output_info->component_type, SpvStorageClassOutput, VKD3DSP_WRITEMASK_0 << i, object_id); - ++index; - } + spirv_compiler_emit_store(compiler, + output_id, dst_write_mask, output_info->component_type, SpvStorageClassOutput, write_mask, val_id); }
static void spirv_compiler_emit_shader_epilogue_function(struct spirv_compiler *compiler) @@ -9943,9 +9800,6 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler, compiler->input_control_point_count = program->input_control_point_count; compiler->output_control_point_count = program->output_control_point_count;
- if (compiler->shader_type != VKD3D_SHADER_TYPE_HULL) - spirv_compiler_emit_shader_signature_outputs(compiler); - for (i = 0; i < instructions.count && result >= 0; ++i) { compiler->location.line = i + 1;