diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 9cb14288..02a374f8 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -2128,8 +2128,10 @@ static bool add_assignment(struct hlsl_ctx *ctx, struct hlsl_block *block, struc if (hlsl_is_numeric_type(lhs_type)) { - writemask = (1 << lhs_type->e.numeric.dimx) - 1; - width = lhs_type->e.numeric.dimx; + unsigned int size = hlsl_type_component_count(lhs_type); + + writemask = (1 << size) - 1; + width = size; } if (!(rhs = add_implicit_conversion(ctx, block, rhs, lhs_type, &rhs->loc))) @@ -2139,8 +2141,24 @@ static bool add_assignment(struct hlsl_ctx *ctx, struct hlsl_block *block, struc { if (lhs->type == HLSL_IR_EXPR && hlsl_ir_expr(lhs)->op == HLSL_OP1_CAST) { - hlsl_fixme(ctx, &lhs->loc, "Cast on the LHS."); - return false; + struct hlsl_ir_node *cast = lhs; + lhs = hlsl_ir_expr(cast)->operands[0].node; + + if (hlsl_type_component_count(lhs->data_type) != hlsl_type_component_count(cast->data_type)) + { + hlsl_fixme(ctx, &cast->loc, "Size change on the LHS."); + return false; + } + if (hlsl_version_ge(ctx, 4, 0)) + { + hlsl_error(ctx, &cast->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_LVALUE, + "Base type casts are not allowed on the LHS for profiles >= 4."); + return false; + } + + lhs_type = lhs->data_type; + if (lhs_type->class == HLSL_CLASS_VECTOR || (lhs_type->class == HLSL_CLASS_MATRIX && matrix_writemask)) + lhs_type = hlsl_get_vector_type(ctx, lhs->data_type->e.numeric.type, width); } else if (lhs->type == HLSL_IR_SWIZZLE) { @@ -2181,6 +2199,7 @@ static bool add_assignment(struct hlsl_ctx *ctx, struct hlsl_block *block, struc hlsl_block_add_instr(block, new_swizzle); lhs = swizzle->val.node; + lhs_type = hlsl_get_vector_type(ctx, lhs_type->e.numeric.type, width); rhs = new_swizzle; } else @@ -2190,6 +2209,12 @@ static bool add_assignment(struct hlsl_ctx *ctx, struct hlsl_block *block, struc } } + /* lhs casts could have resulted in a discrepancy between the + * rhs->data_type and the type of the variable that will be ulimately + * stored to. This is corrected. */ + if (!(rhs = add_cast(ctx, block, rhs, lhs_type, &rhs->loc))) + return false; + if (lhs->type == HLSL_IR_INDEX && hlsl_index_chain_has_resource_access(hlsl_ir_index(lhs))) { struct hlsl_ir_node *coords = hlsl_ir_index(lhs)->idx.node; diff --git a/tests/hlsl/function-cast.shader_test b/tests/hlsl/function-cast.shader_test index 4da6e0d9..a8135dc1 100644 --- a/tests/hlsl/function-cast.shader_test +++ b/tests/hlsl/function-cast.shader_test @@ -1,6 +1,6 @@ % Test implicit and explicit casts on function output parameters. -[pixel shader todo] +[pixel shader todo(sm>=4)] uniform float4 f; @@ -18,14 +18,14 @@ float4 main() : sv_target [test] uniform 0 float4 -1.9 -1.0 2.9 4.0 -todo(sm<6) draw quad +todo(sm>=4 & sm<6) draw quad probe (0, 0) rgba (-1.0, -1.0, 2.0, 4.0) % As above, but cast "x" to float4 first. % In SM 6 a cast seems to implicitly promote the type to const, % so it fails to match the parameter of func(). -[pixel shader todo fail(sm>=6)] +[pixel shader fail(sm>=6) todo(sm>=4)] uniform float4 f; @@ -43,12 +43,12 @@ float4 main() : sv_target [test] uniform 0 float4 -1.9 -1.0 2.9 4.0 -todo draw quad +todo(sm>=4) draw quad probe (0, 0) rgba (-1.0, -1.0, 2.0, 4.0) % As above, but declare "x" as float4 and cast it to int4. -[pixel shader todo fail(sm>=6)] +[pixel shader fail(sm>=6) todo(sm>=4)] uniform float4 f; @@ -66,11 +66,11 @@ float4 main() : sv_target [test] uniform 0 float4 -1.9 -1.0 2.9 4.0 -todo draw quad -probe (0, 0) rgba (-1.0, -1.0, 2.0, 4.0) +todo(sm>=4) draw quad +todo(sm<4) probe (0, 0) rgba (-1.0, -1.0, 2.0, 4.0) -[pixel shader todo] +[pixel shader todo(sm>=4)] uniform int4 i; void func(inout float4 a) @@ -88,12 +88,12 @@ float4 main() : sv_target [test] if(sm<4) uniform 0 float4 -2 0 1 -3000000 if(sm>=4) uniform 0 int4 -2 0 1 -3000000 -todo(sm<6) draw quad +todo(sm>=4 & sm<6) draw quad probe (0, 0) rgba (-1.0, 0.0, 1.0, -3000000.0) 4 % An explicit cast gets applied right before assignment, as if it was on the lhs. -[pixel shader todo fail(sm>=6)] +[pixel shader fail(sm>=6) todo(sm>=4)] void fun(out float4 f) { f = float4(1.4, 2.6, 3.9, 4.3); @@ -108,8 +108,8 @@ float4 main() : sv_target } [test] -todo draw quad -probe (0, 0) rgba(1, 2, 3, 4) +todo(sm>=4) draw quad +todo probe (0, 0) rgba(1, 2, 3, 4) [pixel shader todo fail] @@ -176,7 +176,7 @@ float4 main() : sv_target } -[pixel shader fail(sm>=4) todo] +[pixel shader fail(sm>=4)] void fun(out float4 f) { f = float4(1.1, 2.3, 3.6, 4.3); @@ -191,5 +191,5 @@ float4 main() : sv_target } [test] -todo draw quad +draw quad probe (0, 0) rgba(1.1, 2.3, 3.6, 4.3) diff --git a/tests/hlsl/lhs-cast.shader_test b/tests/hlsl/lhs-cast.shader_test index ff70bc08..7ced985d 100644 --- a/tests/hlsl/lhs-cast.shader_test +++ b/tests/hlsl/lhs-cast.shader_test @@ -14,7 +14,7 @@ probe (0, 0) rgba(1, 2, 3, 4) % Casts with base type changes are only valid on SM1. -[pixel shader fail(sm>=4) todo] +[pixel shader fail(sm>=4)] float4 main() : sv_target { float4 p = 0; @@ -24,13 +24,13 @@ float4 main() : sv_target } [test] -todo draw quad +draw quad probe (0, 0) rgba(-1, -2, 4, 0) % Casts don't actually perform base type changes, only the outtermost one, which % I suspect is because the implicit cast on the assignment and not the cast itself. -[pixel shader fail(sm>=4) todo] +[pixel shader fail(sm>=4)] float4 main() : sv_target { float4 f = 0; @@ -40,11 +40,11 @@ float4 main() : sv_target } [test] -todo draw quad +draw quad probe (0, 0) rgba(1.3, -2.4, 3.3, 4.7) -[pixel shader fail(sm>=4) todo] +[pixel shader fail(sm>=4)] float4 main() : sv_target { float4 f = 0; @@ -54,7 +54,7 @@ float4 main() : sv_target } [test] -todo draw quad +draw quad probe (0, 0) rgba(1, -2, 3, 4) @@ -69,7 +69,7 @@ float4 main() : sv_target } -[pixel shader fail(sm>=6) todo] +[pixel shader fail(sm>=6) todo(sm>=4)] float4 main() : sv_target { float4 f = 0; @@ -79,11 +79,11 @@ float4 main() : sv_target } [test] -todo draw quad +todo(sm>=4) draw quad probe (0, 0) rgba(1, 2, 3, 4) -[pixel shader fail(sm>=4) todo] +[pixel shader fail(sm>=4)] float4 main() : sv_target { float4 f = 0; @@ -93,11 +93,11 @@ float4 main() : sv_target } [test] -todo draw quad +draw quad probe (0, 0) rgba(1, 3, 0, 0); -[pixel shader fail(sm>=4) todo] +[pixel shader fail(sm>=4)] float4 main() : sv_target { float4 f = 0; @@ -107,5 +107,5 @@ float4 main() : sv_target } [test] -todo draw quad +draw quad probe (0, 0) rgba(1.4, 2.8, 0, 0); diff --git a/tests/hlsl/trigonometry.shader_test b/tests/hlsl/trigonometry.shader_test index af21722d..b966a8aa 100644 --- a/tests/hlsl/trigonometry.shader_test +++ b/tests/hlsl/trigonometry.shader_test @@ -162,7 +162,7 @@ float4 main() : sv_target return float4(6789); } -[pixel shader todo] +[pixel shader todo(sm>=4)] float4 main() : sv_target { int sin_out, cos_out; @@ -171,5 +171,5 @@ float4 main() : sv_target } [test] -todo(sm<6) draw quad +todo(sm>=4 & sm<6) draw quad probe (0, 0) rgba (0, 0, 0, 0);