From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d-shader/tpf.c | 76 +++++++++++++++++++++--- libs/vkd3d-shader/vkd3d_shader_private.h | 1 + 2 files changed, 69 insertions(+), 8 deletions(-)
diff --git a/libs/vkd3d-shader/tpf.c b/libs/vkd3d-shader/tpf.c index ea7f2082..c0675b66 100644 --- a/libs/vkd3d-shader/tpf.c +++ b/libs/vkd3d-shader/tpf.c @@ -564,6 +564,11 @@ struct vkd3d_shader_sm4_parser
unsigned int output_map[MAX_REG_OUTPUT];
+ enum vkd3d_shader_opcode phase; + unsigned int input_register_masks[MAX_REG_OUTPUT]; + unsigned int output_register_masks[MAX_REG_OUTPUT]; + unsigned int patch_constant_register_masks[MAX_REG_OUTPUT]; + struct vkd3d_shader_parser p; };
@@ -1425,7 +1430,7 @@ static void map_register(const struct vkd3d_shader_sm4_parser *sm4, struct vkd3d
if (reg_idx >= ARRAY_SIZE(sm4->output_map)) { - ERR("Invalid output index %u.\n", reg_idx); + /* Validated later */ break; }
@@ -1762,9 +1767,20 @@ static bool shader_register_is_input_output(const struct vkd3d_shader_register * } }
+static unsigned int mask_from_swizzle(unsigned int swizzle) +{ + return (1u << vkd3d_swizzle_get_component(swizzle, 0)) + | (1u << vkd3d_swizzle_get_component(swizzle, 1)) + | (1u << vkd3d_swizzle_get_component(swizzle, 2)) + | (1u << vkd3d_swizzle_get_component(swizzle, 3)); +} + static bool shader_sm4_validate_input_output_register(struct vkd3d_shader_sm4_parser *priv, - const struct vkd3d_shader_register *reg) + const struct vkd3d_shader_register *reg, unsigned int mask) { + const unsigned int *masks; + unsigned int register_idx; + if (!reg->idx_count || reg->idx_count > 2) { /* No I/O registers use order 0 or > 2. The normaliser relies on this. TODO: strict validation. */ @@ -1773,6 +1789,41 @@ static bool shader_sm4_validate_input_output_register(struct vkd3d_shader_sm4_pa return false; }
+ switch (reg->type) + { + case VKD3DSPR_INPUT: + case VKD3DSPR_INCONTROLPOINT: + masks = priv->input_register_masks; + break; + case VKD3DSPR_OUTPUT: + masks = (priv->phase == VKD3DSIH_HS_FORK_PHASE || priv->phase == VKD3DSIH_HS_JOIN_PHASE) + ? priv->patch_constant_register_masks + : priv->output_register_masks; + break; + case VKD3DSPR_COLOROUT: + case VKD3DSPR_OUTCONTROLPOINT: + masks = priv->output_register_masks; + break; + case VKD3DSPR_PATCHCONST: + masks = priv->patch_constant_register_masks; + break; + + default: + vkd3d_unreachable(); + } + + register_idx = reg->idx[reg->idx_count - 1].offset; + /* The signature element registers have already been checked against MAX_REG_OUTPUT. */ + if (register_idx >= MAX_REG_OUTPUT || (masks[register_idx] & mask) != mask) + { + WARN("Failed to find signature element for register type %#x, index %u and mask %#x.\n", + reg->type, register_idx, mask); + vkd3d_shader_parser_error(&priv->p, VKD3D_SHADER_ERROR_TPF_INVALID_IO_REGISTER, + "Could not find signature element matching register type %#x, index %u and mask %#x.\n", + reg->type, register_idx, mask); + return false; + } + return true; }
@@ -1828,7 +1879,7 @@ static bool shader_sm4_read_src_param(struct vkd3d_shader_sm4_parser *priv, cons }
if (shader_register_is_input_output(&src_param->reg) && !shader_sm4_validate_input_output_register(priv, - &src_param->reg)) + &src_param->reg, mask_from_swizzle(src_param->swizzle))) return false;
return true; @@ -1869,7 +1920,7 @@ static bool shader_sm4_read_dst_param(struct vkd3d_shader_sm4_parser *priv, cons dst_param->shift = 0;
if (shader_register_is_input_output(&dst_param->reg) && !shader_sm4_validate_input_output_register(priv, - &dst_param->reg)) + &dst_param->reg, dst_param->write_mask)) return false;
return true; @@ -2009,6 +2060,9 @@ static void shader_sm4_read_instruction(struct vkd3d_shader_sm4_parser *sm4, str }
ins->handler_idx = opcode_info->handler_idx; + if (ins->handler_idx == VKD3DSIH_HS_CONTROL_POINT_PHASE || ins->handler_idx == VKD3DSIH_HS_FORK_PHASE + || ins->handler_idx == VKD3DSIH_HS_JOIN_PHASE) + sm4->phase = ins->handler_idx; ins->flags = 0; ins->coissue = false; ins->raw = false; @@ -2188,7 +2242,7 @@ static bool shader_sm4_init(struct vkd3d_shader_sm4_parser *sm4, const uint32_t }
static bool shader_sm4_parser_validate_signature(struct vkd3d_shader_sm4_parser *sm4, - const struct vkd3d_shader_signature *signature, const char *name) + const struct vkd3d_shader_signature *signature, unsigned int *masks, const char *name) { unsigned int i, register_idx, mask;
@@ -2208,6 +2262,9 @@ static bool shader_sm4_parser_validate_signature(struct vkd3d_shader_sm4_parser vkd3d_shader_parser_warning(&sm4->p, VKD3D_SHADER_WARNING_TPF_MASK_NOT_CONTIGUOUS, "%s signature element %u mask %#x is not contiguous.\n", name, i, mask); } + + if (register_idx != ~0u) + masks[register_idx] |= mask; }
return true; @@ -2246,9 +2303,12 @@ int vkd3d_shader_sm4_parser_create(const struct vkd3d_shader_compile_info *compi return VKD3D_ERROR_INVALID_ARGUMENT; }
- if (!shader_sm4_parser_validate_signature(sm4, &shader_desc->input_signature, "Input") - || !shader_sm4_parser_validate_signature(sm4, &shader_desc->output_signature, "Output") - || !shader_sm4_parser_validate_signature(sm4, &shader_desc->patch_constant_signature, "Patch constant")) + if (!shader_sm4_parser_validate_signature(sm4, &shader_desc->input_signature, + sm4->input_register_masks, "Input") + || !shader_sm4_parser_validate_signature(sm4, &shader_desc->output_signature, + sm4->output_register_masks, "Output") + || !shader_sm4_parser_validate_signature(sm4, &shader_desc->patch_constant_signature, + sm4->patch_constant_register_masks, "Patch constant")) { shader_sm4_destroy(&sm4->p); return VKD3D_ERROR_INVALID_SHADER; diff --git a/libs/vkd3d-shader/vkd3d_shader_private.h b/libs/vkd3d-shader/vkd3d_shader_private.h index dede7a2d..dabd3c6b 100644 --- a/libs/vkd3d-shader/vkd3d_shader_private.h +++ b/libs/vkd3d-shader/vkd3d_shader_private.h @@ -76,6 +76,7 @@ enum vkd3d_shader_error VKD3D_SHADER_ERROR_TPF_OUT_OF_MEMORY = 1002, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_INDEX_COUNT = 1003, VKD3D_SHADER_ERROR_TPF_TOO_MANY_REGISTERS = 1004, + VKD3D_SHADER_ERROR_TPF_INVALID_IO_REGISTER = 1005,
VKD3D_SHADER_WARNING_TPF_MASK_NOT_CONTIGUOUS = 1300,