diff --git a/gn/sksl_tests.gni b/gn/sksl_tests.gni index 2e691f7e3c..3a966a8a03 100644 --- a/gn/sksl_tests.gni +++ b/gn/sksl_tests.gni @@ -70,6 +70,7 @@ sksl_error_tests = [ "/sksl/errors/LayoutMultiplePrimitiveTypes.sksl", "/sksl/errors/LayoutRepeatedQualifiers.sksl", "/sksl/errors/MatrixToVectorCast3x3.sksl", + "/sksl/errors/MatrixToVectorCastInteger.sksl", "/sksl/errors/MatrixToVectorCastTooSmall.sksl", "/sksl/errors/MismatchedNumbers.sksl", "/sksl/errors/ModifiersInStruct.sksl", diff --git a/resources/sksl/errors/MatrixToVectorCastInteger.sksl b/resources/sksl/errors/MatrixToVectorCastInteger.sksl new file mode 100644 index 0000000000..9a9966f184 --- /dev/null +++ b/resources/sksl/errors/MatrixToVectorCastInteger.sksl @@ -0,0 +1,7 @@ +// Expect 3 errors + +const half2x2 testMatrix2x2 = half2x2(1, 2, 3, 4); +int testScalar = int (testMatrix2x2); +int2 testVec2 = int2(testMatrix2x2); +int3 testVec3 = int3(testMatrix2x2); +int4 testVec4 = int4(testMatrix2x2); // not an error diff --git a/resources/sksl/shared/MatrixToVectorCast.sksl b/resources/sksl/shared/MatrixToVectorCast.sksl index cf13861957..121a06cf20 100644 --- a/resources/sksl/shared/MatrixToVectorCast.sksl +++ b/resources/sksl/shared/MatrixToVectorCast.sksl @@ -14,5 +14,9 @@ half4 main(float2 coords) { ok = ok && float4(half2x2(1, 2, 3, 4)) == float4(1, 2, 3, 4); ok = ok && float4(mat1234) == float4(1, 2, 3, 4); + ok = ok && int4(testMatrix2x2) == int4(1, 2, 3, 4); + ok = ok && int4(half2x2(1, 2, 3, 4)) == int4(1, 2, 3, 4); + ok = ok && int4(mat1234) == int4(1, 2, 3, 4); + return ok ? colorGreen : colorRed; } diff --git a/src/sksl/ir/SkSLConstructor.cpp b/src/sksl/ir/SkSLConstructor.cpp index 3d00114d69..9c9ad91d44 100644 --- a/src/sksl/ir/SkSLConstructor.cpp +++ b/src/sksl/ir/SkSLConstructor.cpp @@ -51,9 +51,9 @@ static std::unique_ptr convert_compound_constructor(const Context& c return ConstructorCompoundCast::Make(context, offset, type, std::move(argument)); } } else if (argument->type().isMatrix()) { - // A vector or matrix constructor containing a single matrix can be a resize, typecast, - // or both. GLSL lumps these into one category, but internally SkSL keeps them distinct. - if (type.isVector() || type.isMatrix()) { + // A matrix constructor containing a single matrix can be a resize, typecast, or both. + // GLSL lumps these into one category, but internally SkSL keeps them distinct. + if (type.isMatrix()) { // First, handle type conversion. If the component types differ, synthesize the // destination type with the argument's rows/columns. (This will be a no-op if it's // already the right type.) @@ -64,17 +64,25 @@ static std::unique_ptr convert_compound_constructor(const Context& c argument = ConstructorCompoundCast::Make(context, offset, typecastType, std::move(argument)); - // Next, wrap the typecasted expression in another constructor depending on its - // type. - if (type.isMatrix()) { - // Casting a matrix type into another matrix type is a resize. - return ConstructorMatrixResize::Make(context, offset, type, - std::move(argument)); - } - if (type.isVector() && type.columns() == 4 && argument->type().slotCount() == 4) { - // Casting a 2x2 matrix into a 4-slot vector is compound construction. - return ConstructorCompound::Make(context, offset, type, std::move(args)); - } + // Casting a matrix type into another matrix type is a resize. + return ConstructorMatrixResize::Make(context, offset, type, + std::move(argument)); + } + + // A vector constructor containing a single matrix can be compound construction if the + // matrix is 2x2 and the vector is 4-slot. + if (type.isVector() && type.columns() == 4 && argument->type().slotCount() == 4) { + // Casting a 2x2 matrix to a vector is a form of compound construction. + // First, reshape the matrix into a 4-slot vector of the same type. + const Type& vectorType = argument->type().componentType().toCompound(context, + /*columns=*/4, + /*rows=*/1); + std::unique_ptr vecCtor = + ConstructorCompound::Make(context, offset, vectorType, std::move(args)); + + // Then, add a typecast to the result expression to ensure the types match. + // This will be a no-op if no typecasting is needed. + return ConstructorCompoundCast::Make(context, offset, type, std::move(vecCtor)); } } } diff --git a/src/sksl/ir/SkSLConstructorCompoundCast.cpp b/src/sksl/ir/SkSLConstructorCompoundCast.cpp index b147501199..3e0c30fa1b 100644 --- a/src/sksl/ir/SkSLConstructorCompoundCast.cpp +++ b/src/sksl/ir/SkSLConstructorCompoundCast.cpp @@ -52,10 +52,10 @@ static std::unique_ptr cast_constant_composite(const Context& contex std::move(arg))); } else { // Convert inner constant-composites recursively. - SkASSERT(argType.isVector()); + SkASSERT(argType.isVector() || (argType.isMatrix() && argType.slotCount() == 4)); typecastArgs.push_back(cast_constant_composite( context, - scalarType.toCompound(context, /*columns=*/argType.columns(), /*rows=*/1), + scalarType.toCompound(context, /*columns=*/argType.slotCount(), /*rows=*/1), std::move(arg))); } } diff --git a/tests/sksl/errors/MatrixToVectorCastInteger.glsl b/tests/sksl/errors/MatrixToVectorCastInteger.glsl new file mode 100644 index 0000000000..f5632a6d4a --- /dev/null +++ b/tests/sksl/errors/MatrixToVectorCastInteger.glsl @@ -0,0 +1,6 @@ +### Compilation failed: + +error: 4: invalid argument to 'int' constructor (expected a number or bool, but found 'half2x2') +error: 5: 'half2x2' is not a valid parameter to 'int2' constructor +error: 6: 'half2x2' is not a valid parameter to 'int3' constructor +3 errors diff --git a/tests/sksl/shared/MatrixToVectorCast.asm.frag b/tests/sksl/shared/MatrixToVectorCast.asm.frag index ef22a32a7a..cacacb4ca8 100644 --- a/tests/sksl/shared/MatrixToVectorCast.asm.frag +++ b/tests/sksl/shared/MatrixToVectorCast.asm.frag @@ -37,10 +37,26 @@ OpDecorate %43 RelaxedPrecision OpDecorate %48 RelaxedPrecision OpDecorate %53 RelaxedPrecision OpDecorate %57 RelaxedPrecision +OpDecorate %58 RelaxedPrecision +OpDecorate %59 RelaxedPrecision +OpDecorate %60 RelaxedPrecision +OpDecorate %61 RelaxedPrecision +OpDecorate %62 RelaxedPrecision OpDecorate %66 RelaxedPrecision +OpDecorate %70 RelaxedPrecision +OpDecorate %71 RelaxedPrecision +OpDecorate %72 RelaxedPrecision +OpDecorate %73 RelaxedPrecision +OpDecorate %74 RelaxedPrecision OpDecorate %75 RelaxedPrecision +OpDecorate %76 RelaxedPrecision OpDecorate %78 RelaxedPrecision -OpDecorate %79 RelaxedPrecision +OpDecorate %80 RelaxedPrecision +OpDecorate %82 RelaxedPrecision +OpDecorate %93 RelaxedPrecision +OpDecorate %102 RelaxedPrecision +OpDecorate %104 RelaxedPrecision +OpDecorate %105 RelaxedPrecision %float = OpTypeFloat 32 %v4float = OpTypeVector %float 4 %_ptr_Output_v4float = OpTypePointer Output %v4float @@ -71,10 +87,14 @@ OpDecorate %79 RelaxedPrecision %float_4 = OpConstant %float 4 %48 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4 %v4bool = OpTypeVector %bool 4 +%v4int = OpTypeVector %int 4 +%int_1 = OpConstant %int 1 +%int_3 = OpConstant %int 3 +%int_4 = OpConstant %int 4 +%89 = OpConstantComposite %v4int %int_1 %int_2 %int_3 %int_4 %_ptr_Function_v4float = OpTypePointer Function %v4float %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float %int_0 = OpConstant %int 0 -%int_1 = OpConstant %int 1 %_entrypoint_v = OpFunction %void None %17 %18 = OpLabel %21 = OpVariable %_ptr_Function_v2float Function @@ -87,7 +107,7 @@ OpFunctionEnd %25 = OpFunctionParameter %_ptr_Function_v2float %26 = OpLabel %ok = OpVariable %_ptr_Function_bool Function -%67 = OpVariable %_ptr_Function_v4float Function +%94 = OpVariable %_ptr_Function_v4float Function OpStore %ok %true %31 = OpLoad %bool %ok OpSelectionMerge %33 None @@ -124,19 +144,45 @@ OpBranch %55 %65 = OpPhi %bool %false %33 %64 %54 OpStore %ok %65 %66 = OpLoad %bool %ok -OpSelectionMerge %71 None -OpBranchConditional %66 %69 %70 -%69 = OpLabel -%72 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0 -%75 = OpLoad %v4float %72 -OpStore %67 %75 -OpBranch %71 -%70 = OpLabel -%76 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1 -%78 = OpLoad %v4float %76 -OpStore %67 %78 -OpBranch %71 -%71 = OpLabel -%79 = OpLoad %v4float %67 -OpReturnValue %79 +OpSelectionMerge %68 None +OpBranchConditional %66 %67 %68 +%67 = OpLabel +%69 = OpAccessChain %_ptr_Uniform_mat2v2float %10 %int_2 +%70 = OpLoad %mat2v2float %69 +%71 = OpCompositeExtract %float %70 0 0 +%72 = OpCompositeExtract %float %70 0 1 +%73 = OpCompositeExtract %float %70 1 0 +%74 = OpCompositeExtract %float %70 1 1 +%75 = OpCompositeConstruct %v4float %71 %72 %73 %74 +%76 = OpCompositeExtract %float %75 0 +%77 = OpConvertFToS %int %76 +%78 = OpCompositeExtract %float %75 1 +%79 = OpConvertFToS %int %78 +%80 = OpCompositeExtract %float %75 2 +%81 = OpConvertFToS %int %80 +%82 = OpCompositeExtract %float %75 3 +%83 = OpConvertFToS %int %82 +%84 = OpCompositeConstruct %v4int %77 %79 %81 %83 +%90 = OpIEqual %v4bool %84 %89 +%91 = OpAll %bool %90 +OpBranch %68 +%68 = OpLabel +%92 = OpPhi %bool %false %55 %91 %67 +OpStore %ok %92 +%93 = OpLoad %bool %ok +OpSelectionMerge %98 None +OpBranchConditional %93 %96 %97 +%96 = OpLabel +%99 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0 +%102 = OpLoad %v4float %99 +OpStore %94 %102 +OpBranch %98 +%97 = OpLabel +%103 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1 +%104 = OpLoad %v4float %103 +OpStore %94 %104 +OpBranch %98 +%98 = OpLabel +%105 = OpLoad %v4float %94 +OpReturnValue %105 OpFunctionEnd diff --git a/tests/sksl/shared/MatrixToVectorCast.glsl b/tests/sksl/shared/MatrixToVectorCast.glsl index ba4aa5763b..9e222e767d 100644 --- a/tests/sksl/shared/MatrixToVectorCast.glsl +++ b/tests/sksl/shared/MatrixToVectorCast.glsl @@ -7,5 +7,6 @@ vec4 main() { bool ok = true; ok = ok && vec4(testMatrix2x2) == vec4(1.0, 2.0, 3.0, 4.0); ok = ok && vec4(testMatrix2x2) == vec4(1.0, 2.0, 3.0, 4.0); + ok = ok && ivec4(vec4(testMatrix2x2)) == ivec4(1, 2, 3, 4); return ok ? colorGreen : colorRed; } diff --git a/tests/sksl/shared/MatrixToVectorCast.metal b/tests/sksl/shared/MatrixToVectorCast.metal index 60065d1b7f..b76d500408 100644 --- a/tests/sksl/shared/MatrixToVectorCast.metal +++ b/tests/sksl/shared/MatrixToVectorCast.metal @@ -20,6 +20,7 @@ fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant Uniforms& _unifo bool ok = true; ok = ok && all(float4_from_float2x2(_uniforms.testMatrix2x2) == float4(1.0, 2.0, 3.0, 4.0)); ok = ok && all(float4_from_float2x2(_uniforms.testMatrix2x2) == float4(1.0, 2.0, 3.0, 4.0)); + ok = ok && all(int4(float4_from_float2x2(_uniforms.testMatrix2x2)) == int4(1, 2, 3, 4)); _out.sk_FragColor = ok ? _uniforms.colorGreen : _uniforms.colorRed; return _out; }