This commit is part of a series of commits intended to remove all uses of hlsl_type_get_regset().
However, I think it deserves to be upstreamed sooner since it solves a rather important SM1 regression (explained below) introduced in e0031d2a1f40792ac85619a495bf5197f248b0e1 .
---
In SM1 we can expect all variables to always belong to a single regset. structs in particular, should always be allocated to HLSL_REGSET_NUM, since they are only allowed if all their components are numeric.
We are not covering the structs case because of the use of hlsl_type_get_regset(), which is currently not defined for structs.
So the current shader
```hlsl struct { float4 a; float4 b; } apple;
float4 main() : sv_target { return apple.a + apple.b; } ```
fails with
``` vkd3d/libs/vkd3d-shader/hlsl.c:224: Aborting, reached unreachable code. ```
The solution is to iterate over all regsets to find the one where the variable is allocated (if any), and ignore all others.
From: Francisco Casas fcasas@codeweavers.com
In SM1 we can expect all variables to always belong to a single regset. structs in particular, should always be allocated to HLSL_REGSET_NUM, since they are only allowed if all their components are numeric.
We are not covering the structs case because of the use of hlsl_type_get_regset(), which is currently not defined for structs.
So the current shader
struct { float4 a; float4 b; } apple;
float4 main() : sv_target { return apple.a + apple.b; }
fails with
vkd3d/libs/vkd3d-shader/hlsl.c:224: Aborting, reached unreachable code.
The solution is to iterate over all regsets to find the one where the variable is allocated (if any), and ignore all others. --- libs/vkd3d-shader/d3dbc.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-)
diff --git a/libs/vkd3d-shader/d3dbc.c b/libs/vkd3d-shader/d3dbc.c index c35f8ca0f..712613ac1 100644 --- a/libs/vkd3d-shader/d3dbc.c +++ b/libs/vkd3d-shader/d3dbc.c @@ -1281,10 +1281,13 @@ static void write_sm1_uniforms(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffe
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) { - enum hlsl_regset regset = hlsl_type_get_regset(var->data_type); + unsigned int r;
- if (!var->semantic.name && var->regs[regset].allocated) + for (r = 0; r <= HLSL_REGSET_LAST; ++r) { + if (var->semantic.name || !var->regs[r].allocated) + continue; + ++uniform_count;
if (var->is_param && var->is_uniform) @@ -1321,20 +1324,23 @@ static void write_sm1_uniforms(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffe
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) { - enum hlsl_regset regset = hlsl_type_get_regset(var->data_type); + unsigned int r;
- if (!var->semantic.name && var->regs[regset].allocated) + for (r = 0; r <= HLSL_REGSET_LAST; ++r) { + if (var->semantic.name || !var->regs[r].allocated) + continue; + put_u32(buffer, 0); /* name */ - if (regset == HLSL_REGSET_NUMERIC) + if (r == HLSL_REGSET_NUMERIC) { - put_u32(buffer, vkd3d_make_u32(D3DXRS_FLOAT4, var->regs[regset].id)); - put_u32(buffer, var->data_type->reg_size[regset] / 4); + put_u32(buffer, vkd3d_make_u32(D3DXRS_FLOAT4, var->regs[r].id)); + put_u32(buffer, var->data_type->reg_size[r] / 4); } else { - put_u32(buffer, vkd3d_make_u32(D3DXRS_SAMPLER, var->regs[regset].id)); - put_u32(buffer, var->regs[regset].bind_count); + put_u32(buffer, vkd3d_make_u32(D3DXRS_SAMPLER, var->regs[r].id)); + put_u32(buffer, var->regs[r].bind_count); } put_u32(buffer, 0); /* type */ put_u32(buffer, 0); /* FIXME: default value */ @@ -1345,12 +1351,16 @@ static void write_sm1_uniforms(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffe
LIST_FOR_EACH_ENTRY(var, &ctx->extern_vars, struct hlsl_ir_var, extern_entry) { - enum hlsl_regset regset = hlsl_type_get_regset(var->data_type); + unsigned int r;
- if (!var->semantic.name && var->regs[regset].allocated) + for (r = 0; r <= HLSL_REGSET_LAST; ++r) { - size_t var_offset = vars_start + (uniform_count * 5 * sizeof(uint32_t)); - size_t name_offset; + size_t var_offset, name_offset; + + if (var->semantic.name || !var->regs[r].allocated) + continue; + + var_offset = vars_start + (uniform_count * 5 * sizeof(uint32_t));
name_offset = put_string(buffer, var->name); set_u32(buffer, var_offset, name_offset - ctab_start);
Why not using something like: ```c enum hlsl_regset regset = (var->data_type->class == HLSL_CLASS_STRUCT ? HLSL_REGSET_NUMERIC : hlsl_type_get_regset(var->data_type)); ``` possibly with a comment?
It seems simpler and it better conveys the fact that variables in SM1 are still essentially considered to have a single regset. Not that your solution is bad.
On Mon Jun 19 13:25:33 2023 +0000, Giovanni Mascellani wrote:
I am trying to get rid of hlsl_type_get_regset() at some point, to discourage using it and having to consider exceptions such as this.
Perhaps the alternative would be making a sm1-exclusive sm1_type_get_regset() that is defined for structs, but using these `for`s also works.
On Mon Jun 19 13:25:33 2023 +0000, Francisco Casas wrote:
Ah, yes, it makes sense. I guess it makes sense to remove the assumption that variables only span a single regset, as much as possible.
This merge request was approved by Giovanni Mascellani.
On Tue Jun 20 09:39:47 2023 +0000, Giovanni Mascellani wrote:
Ah, yes, it makes sense. I guess it makes sense to remove the assumption that variables only span a single regset, as much as possible.
To be clear I haven't exactly been trying to say "hlsl_type_get_regset()" shouldn't exist. It makes me uneasy but it does (kind of) have a single definite answer for sm1.
That's not to say that the current code isn't an improvement, but at this point it probably still depends on how we actually deal with variables that have multiple register sets. From the discussion in 209 it's not really clear to me how that's shaking out.
In particular, if we end up moving object fields out of structs and into their own vars, then hlsl_type_get_regset() *does* always have a single, definite answer.
This merge request was approved by Zebediah Figura.
This merge request was closed by Giovanni Mascellani.
Merged through !244, closing.