vkd3d-shader/ir: Allow failure in shader_signature_find_element_for_reg().

shader_signature_find_element_for_reg() is also used in the TPF parser,
where the program has not been validated yet, so it must not crash
on errors.

The I/O normaliser can instead assume that the shader is already
validated.

This fixes a crash with a shader used by The Falconeer. The bug is still
present, because the shader will be incorrectly rejected, but at least
the vkd3d-shader will fail gracefully.
This commit is contained in:
Giovanni Mascellani 2024-09-16 16:11:11 +02:00 committed by Henri Verbeet
parent 32ced3bd8f
commit 637a3cabe7
Notes: Henri Verbeet 2024-09-20 17:31:34 +02:00
Approved-by: Giovanni Mascellani (@giomasce)
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1089
3 changed files with 45 additions and 14 deletions

View File

@ -1208,8 +1208,8 @@ static bool io_normaliser_is_in_control_point_phase(const struct io_normaliser *
return normaliser->phase == VKD3DSIH_HS_CONTROL_POINT_PHASE;
}
static unsigned int shader_signature_find_element_for_reg(const struct shader_signature *signature,
unsigned int reg_idx, unsigned int write_mask)
static bool shader_signature_find_element_for_reg(const struct shader_signature *signature,
unsigned int reg_idx, unsigned int write_mask, unsigned int *element_idx)
{
unsigned int i, base_write_mask;
@ -1219,7 +1219,8 @@ static unsigned int shader_signature_find_element_for_reg(const struct shader_si
if (e->register_index <= reg_idx && e->register_index + e->register_count > reg_idx
&& (e->mask & write_mask) == write_mask)
{
return i;
*element_idx = i;
return true;
}
}
@ -1229,15 +1230,20 @@ static unsigned int shader_signature_find_element_for_reg(const struct shader_si
reg_idx, write_mask);
base_write_mask = 1u << vsir_write_mask_get_component_idx(write_mask);
if (base_write_mask != write_mask)
return shader_signature_find_element_for_reg(signature, reg_idx, base_write_mask);
return shader_signature_find_element_for_reg(signature, reg_idx, base_write_mask, element_idx);
vkd3d_unreachable();
return false;
}
struct signature_element *vsir_signature_find_element_for_reg(const struct shader_signature *signature,
unsigned int reg_idx, unsigned int write_mask)
{
return &signature->elements[shader_signature_find_element_for_reg(signature, reg_idx, write_mask)];
unsigned int element_idx;
if (shader_signature_find_element_for_reg(signature, reg_idx, write_mask, &element_idx))
return &signature->elements[element_idx];
return NULL;
}
static unsigned int range_map_get_register_count(uint8_t range_map[][VKD3D_VEC4_SIZE],
@ -1291,9 +1297,10 @@ static void io_normaliser_add_index_range(struct io_normaliser *normaliser,
{
const struct vkd3d_shader_index_range *range = &ins->declaration.index_range;
const struct vkd3d_shader_register *reg = &range->dst.reg;
unsigned int reg_idx, write_mask, element_idx;
const struct shader_signature *signature;
uint8_t (*range_map)[VKD3D_VEC4_SIZE];
struct signature_element *element;
unsigned int reg_idx, write_mask;
switch (reg->type)
{
@ -1325,9 +1332,8 @@ static void io_normaliser_add_index_range(struct io_normaliser *normaliser,
reg_idx = reg->idx[reg->idx_count - 1].offset;
write_mask = range->dst.write_mask;
element_idx = shader_signature_find_element_for_reg(signature, reg_idx, write_mask);
range_map_set_register_range(range_map, reg_idx, range->register_count,
signature->elements[element_idx].mask, true);
element = vsir_signature_find_element_for_reg(signature, reg_idx, write_mask);
range_map_set_register_range(range_map, reg_idx, range->register_count, element->mask, true);
}
static int signature_element_mask_compare(const void *a, const void *b)
@ -1648,7 +1654,8 @@ static bool shader_dst_param_io_normalise(struct vkd3d_shader_dst_param *dst_par
id_idx = reg->idx_count - 1;
write_mask = dst_param->write_mask;
element_idx = shader_signature_find_element_for_reg(signature, reg_idx, write_mask);
if (!shader_signature_find_element_for_reg(signature, reg_idx, write_mask, &element_idx))
vkd3d_unreachable();
e = &signature->elements[element_idx];
dst_param->write_mask >>= vsir_write_mask_get_component_idx(e->mask);
@ -1771,7 +1778,8 @@ static void shader_src_param_io_normalise(struct vkd3d_shader_src_param *src_par
id_idx = reg->idx_count - 1;
write_mask = VKD3DSP_WRITEMASK_0 << vsir_swizzle_get_component(src_param->swizzle, 0);
element_idx = shader_signature_find_element_for_reg(signature, reg_idx, write_mask);
if (!shader_signature_find_element_for_reg(signature, reg_idx, write_mask, &element_idx))
vkd3d_unreachable();
e = &signature->elements[element_idx];
if ((e->register_count > 1 || vsir_sysval_semantic_is_tess_factor(e->sysval_semantic)))

View File

@ -1157,7 +1157,18 @@ static void shader_sm4_read_dcl_input_ps(struct vkd3d_shader_instruction *ins, u
struct signature_element *e = vsir_signature_find_element_for_reg(
&priv->p.program->input_signature, dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask);
e->interpolation_mode = ins->flags;
if (!e)
{
WARN("No matching signature element for input register %u with mask %#x.\n",
dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask);
vkd3d_shader_parser_error(&priv->p, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DCL,
"No matching signature element for input register %u with mask %#x.\n",
dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask);
}
else
{
e->interpolation_mode = ins->flags;
}
}
}
@ -1172,7 +1183,18 @@ static void shader_sm4_read_dcl_input_ps_siv(struct vkd3d_shader_instruction *in
struct signature_element *e = vsir_signature_find_element_for_reg(
&priv->p.program->input_signature, dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask);
e->interpolation_mode = ins->flags;
if (!e)
{
WARN("No matching signature element for input register %u with mask %#x.\n",
dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask);
vkd3d_shader_parser_error(&priv->p, VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DCL,
"No matching signature element for input register %u with mask %#x.\n",
dst->reg.idx[dst->reg.idx_count - 1].offset, dst->write_mask);
}
else
{
e->interpolation_mode = ins->flags;
}
}
ins->declaration.register_semantic.sysval_semantic = *tokens;
}

View File

@ -80,6 +80,7 @@ enum vkd3d_shader_error
VKD3D_SHADER_ERROR_TPF_INVALID_CASE_VALUE = 1007,
VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DIMENSION = 1008,
VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_SWIZZLE = 1009,
VKD3D_SHADER_ERROR_TPF_INVALID_REGISTER_DCL = 1010,
VKD3D_SHADER_WARNING_TPF_MASK_NOT_CONTIGUOUS = 1300,
VKD3D_SHADER_WARNING_TPF_UNHANDLED_INDEX_RANGE_MASK = 1301,