Add support for mat2-to-ivec4 conversions in SkSL.
The fuzzer quickly discovered that the newly introduced mat2-to-vec4 conversion code did not account for integer vectors. We now handle `ivec4(mat2)` casts properly. This required some non-trivial restructuring of the logic, but in the vast majority of cases, the types will match and the end result will be identical. Change-Id: If07c2fe4b4345bd767384b1802374910f65cd3f0 Bug: oss-fuzz:35998 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/426756 Auto-Submit: John Stiles <johnstiles@google.com> Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com>
This commit is contained in:
parent
ac69e12664
commit
f9ad6ec852
@ -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",
|
||||
|
7
resources/sksl/errors/MatrixToVectorCastInteger.sksl
Normal file
7
resources/sksl/errors/MatrixToVectorCastInteger.sksl
Normal file
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -51,9 +51,9 @@ static std::unique_ptr<Expression> 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<Expression> 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<Expression> 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,10 +52,10 @@ static std::unique_ptr<Expression> 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)));
|
||||
}
|
||||
}
|
||||
|
6
tests/sksl/errors/MatrixToVectorCastInteger.glsl
Normal file
6
tests/sksl/errors/MatrixToVectorCastInteger.glsl
Normal file
@ -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
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user