Fix array-of-vector comparisons in Metal.

Comparing `vec1 == vec2` returns a bvec in Metal, so the result must be
wrapped in `all()` in order to boil it down to a single boolean result.
Our array-comparison helper function did not do this. Fortunately,
`all(scalar)` is a no-op, so we can just wrap the result unilaterally.

Change-Id: I4f1f09a6832164ae2e6577d53b317f561332d581
Bug: skia:12324
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/437736
Auto-Submit: John Stiles <johnstiles@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
John Stiles 2021-08-09 13:21:41 -04:00 committed by SkCQ
parent b493175504
commit 130338c9e1
6 changed files with 227 additions and 160 deletions

View File

@ -9,9 +9,15 @@ half4 main(float2 coords) {
float f2[4] = float[4](1, 2, 3, 4);
float f3[4] = float[4](1, 2, 3, -4);
int3 v1[2] = int3[2](int3(1, 2, 3), int3(4, 5, 6));
int3 v2[2] = int3[2](int3(1, 2, 3), int3(4, 5, 6));
int3 v3[2] = int3[2](int3(1, 2, 3), int3(4, 5, -6));
S s1[3] = S[3](S(1, 2), S(3, 4), S(5, 6));
S s2[3] = S[3](S(1, 2), S(0, 0), S(5, 6));
S s3[3] = S[3](S(1, 2), S(3, 4), S(5, 6));
return (f1 == f2) && (f1 != f3) && (s1 != s2) && (s3 == s1) ? colorGreen : colorRed;
return (f1 == f2) && (f1 != f3) &&
(v1 == v2) && (v1 != v3) &&
(s1 != s2) && (s3 == s1) ? colorGreen : colorRed;
}

View File

@ -1345,7 +1345,7 @@ void MetalCodeGenerator::writeArrayEqualityHelpers(const Type& type) {
template <typename T1, typename T2, size_t N>
bool operator==(thread const array<T1, N>& left, thread const array<T2, N>& right) {
for (size_t index = 0; index < N; ++index) {
if (!(left[index] == right[index])) {
if (!all(left[index] == right[index])) {
return false;
}
}

View File

@ -13,6 +13,9 @@ OpName %main "main"
OpName %f1 "f1"
OpName %f2 "f2"
OpName %f3 "f3"
OpName %v1 "v1"
OpName %v2 "v2"
OpName %v3 "v3"
OpName %S "S"
OpMemberName %S 0 "x"
OpMemberName %S 1 "y"
@ -31,16 +34,17 @@ OpDecorate %_UniformBuffer Block
OpDecorate %10 Binding 0
OpDecorate %10 DescriptorSet 0
OpDecorate %_arr_float_int_4 ArrayStride 16
OpDecorate %_arr_v3int_int_2 ArrayStride 16
OpMemberDecorate %S 0 Offset 0
OpMemberDecorate %S 1 Offset 4
OpDecorate %_arr_S_int_3 ArrayStride 16
OpDecorate %105 RelaxedPrecision
OpDecorate %106 RelaxedPrecision
OpDecorate %139 RelaxedPrecision
OpDecorate %140 RelaxedPrecision
OpDecorate %178 RelaxedPrecision
OpDecorate %180 RelaxedPrecision
OpDecorate %147 RelaxedPrecision
OpDecorate %148 RelaxedPrecision
OpDecorate %181 RelaxedPrecision
OpDecorate %182 RelaxedPrecision
OpDecorate %220 RelaxedPrecision
OpDecorate %222 RelaxedPrecision
OpDecorate %223 RelaxedPrecision
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
@ -67,16 +71,24 @@ OpDecorate %181 RelaxedPrecision
%float_3 = OpConstant %float 3
%float_4 = OpConstant %float 4
%float_n4 = OpConstant %float -4
%S = OpTypeStruct %int %int
%int_3 = OpConstant %int 3
%_arr_S_int_3 = OpTypeArray %S %int_3
%_ptr_Function__arr_S_int_3 = OpTypePointer Function %_arr_S_int_3
%int_1 = OpConstant %int 1
%v3int = OpTypeVector %int 3
%int_2 = OpConstant %int 2
%_arr_v3int_int_2 = OpTypeArray %v3int %int_2
%_ptr_Function__arr_v3int_int_2 = OpTypePointer Function %_arr_v3int_int_2
%int_1 = OpConstant %int 1
%int_3 = OpConstant %int 3
%48 = OpConstantComposite %v3int %int_1 %int_2 %int_3
%int_5 = OpConstant %int 5
%int_6 = OpConstant %int 6
%51 = OpConstantComposite %v3int %int_4 %int_5 %int_6
%int_n6 = OpConstant %int -6
%57 = OpConstantComposite %v3int %int_4 %int_5 %int_n6
%S = OpTypeStruct %int %int
%_arr_S_int_3 = OpTypeArray %S %int_3
%_ptr_Function__arr_S_int_3 = OpTypePointer Function %_arr_S_int_3
%int_0 = OpConstant %int 0
%false = OpConstantFalse %bool
%v3bool = OpTypeVector %bool 3
%_ptr_Function_v4float = OpTypePointer Function %v4float
%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
%_entrypoint_v = OpFunction %void None %15
@ -93,158 +105,201 @@ OpFunctionEnd
%f1 = OpVariable %_ptr_Function__arr_float_int_4 Function
%f2 = OpVariable %_ptr_Function__arr_float_int_4 Function
%f3 = OpVariable %_ptr_Function__arr_float_int_4 Function
%v1 = OpVariable %_ptr_Function__arr_v3int_int_2 Function
%v2 = OpVariable %_ptr_Function__arr_v3int_int_2 Function
%v3 = OpVariable %_ptr_Function__arr_v3int_int_2 Function
%s1 = OpVariable %_ptr_Function__arr_S_int_3 Function
%s2 = OpVariable %_ptr_Function__arr_S_int_3 Function
%s3 = OpVariable %_ptr_Function__arr_S_int_3 Function
%171 = OpVariable %_ptr_Function_v4float Function
%213 = OpVariable %_ptr_Function_v4float Function
%35 = OpCompositeConstruct %_arr_float_int_4 %float_1 %float_2 %float_3 %float_4
OpStore %f1 %35
%37 = OpCompositeConstruct %_arr_float_int_4 %float_1 %float_2 %float_3 %float_4
OpStore %f2 %37
%40 = OpCompositeConstruct %_arr_float_int_4 %float_1 %float_2 %float_3 %float_n4
OpStore %f3 %40
%48 = OpCompositeConstruct %S %int_1 %int_2
%49 = OpCompositeConstruct %S %int_3 %int_4
%52 = OpCompositeConstruct %S %int_5 %int_6
%53 = OpCompositeConstruct %_arr_S_int_3 %48 %49 %52
OpStore %s1 %53
%55 = OpCompositeConstruct %S %int_1 %int_2
%57 = OpCompositeConstruct %S %int_0 %int_0
%58 = OpCompositeConstruct %S %int_5 %int_6
%59 = OpCompositeConstruct %_arr_S_int_3 %55 %57 %58
OpStore %s2 %59
%61 = OpCompositeConstruct %S %int_1 %int_2
%62 = OpCompositeConstruct %S %int_3 %int_4
%63 = OpCompositeConstruct %S %int_5 %int_6
%64 = OpCompositeConstruct %_arr_S_int_3 %61 %62 %63
OpStore %s3 %64
%66 = OpLoad %_arr_float_int_4 %f1
%67 = OpLoad %_arr_float_int_4 %f2
%68 = OpCompositeExtract %float %66 0
%69 = OpCompositeExtract %float %67 0
%70 = OpFOrdEqual %bool %68 %69
%71 = OpCompositeExtract %float %66 1
%72 = OpCompositeExtract %float %67 1
%73 = OpFOrdEqual %bool %71 %72
%74 = OpLogicalAnd %bool %73 %70
%75 = OpCompositeExtract %float %66 2
%76 = OpCompositeExtract %float %67 2
%77 = OpFOrdEqual %bool %75 %76
%78 = OpLogicalAnd %bool %77 %74
%79 = OpCompositeExtract %float %66 3
%80 = OpCompositeExtract %float %67 3
%81 = OpFOrdEqual %bool %79 %80
%82 = OpLogicalAnd %bool %81 %78
OpSelectionMerge %84 None
OpBranchConditional %82 %83 %84
%83 = OpLabel
%85 = OpLoad %_arr_float_int_4 %f1
%86 = OpLoad %_arr_float_int_4 %f3
%87 = OpCompositeExtract %float %85 0
%88 = OpCompositeExtract %float %86 0
%89 = OpFOrdNotEqual %bool %87 %88
%90 = OpCompositeExtract %float %85 1
%91 = OpCompositeExtract %float %86 1
%92 = OpFOrdNotEqual %bool %90 %91
%93 = OpLogicalOr %bool %92 %89
%94 = OpCompositeExtract %float %85 2
%95 = OpCompositeExtract %float %86 2
%96 = OpFOrdNotEqual %bool %94 %95
%97 = OpLogicalOr %bool %96 %93
%98 = OpCompositeExtract %float %85 3
%99 = OpCompositeExtract %float %86 3
%100 = OpFOrdNotEqual %bool %98 %99
%101 = OpLogicalOr %bool %100 %97
OpBranch %84
%84 = OpLabel
%102 = OpPhi %bool %false %25 %101 %83
OpSelectionMerge %104 None
OpBranchConditional %102 %103 %104
%103 = OpLabel
%105 = OpLoad %_arr_S_int_3 %s1
%106 = OpLoad %_arr_S_int_3 %s2
%107 = OpCompositeExtract %S %105 0
%108 = OpCompositeExtract %S %106 0
%109 = OpCompositeExtract %int %107 0
%110 = OpCompositeExtract %int %108 0
%111 = OpINotEqual %bool %109 %110
%112 = OpCompositeExtract %int %107 1
%113 = OpCompositeExtract %int %108 1
%114 = OpINotEqual %bool %112 %113
%115 = OpLogicalOr %bool %114 %111
%116 = OpCompositeExtract %S %105 1
%117 = OpCompositeExtract %S %106 1
%118 = OpCompositeExtract %int %116 0
%119 = OpCompositeExtract %int %117 0
%120 = OpINotEqual %bool %118 %119
%121 = OpCompositeExtract %int %116 1
%122 = OpCompositeExtract %int %117 1
%123 = OpINotEqual %bool %121 %122
%124 = OpLogicalOr %bool %123 %120
%125 = OpLogicalOr %bool %124 %115
%126 = OpCompositeExtract %S %105 2
%127 = OpCompositeExtract %S %106 2
%128 = OpCompositeExtract %int %126 0
%129 = OpCompositeExtract %int %127 0
%130 = OpINotEqual %bool %128 %129
%131 = OpCompositeExtract %int %126 1
%132 = OpCompositeExtract %int %127 1
%133 = OpINotEqual %bool %131 %132
%134 = OpLogicalOr %bool %133 %130
%135 = OpLogicalOr %bool %134 %125
OpBranch %104
%104 = OpLabel
%136 = OpPhi %bool %false %84 %135 %103
OpSelectionMerge %138 None
OpBranchConditional %136 %137 %138
%137 = OpLabel
%139 = OpLoad %_arr_S_int_3 %s3
%140 = OpLoad %_arr_S_int_3 %s1
%141 = OpCompositeExtract %S %139 0
%142 = OpCompositeExtract %S %140 0
%143 = OpCompositeExtract %int %141 0
%144 = OpCompositeExtract %int %142 0
%145 = OpIEqual %bool %143 %144
%146 = OpCompositeExtract %int %141 1
%147 = OpCompositeExtract %int %142 1
%148 = OpIEqual %bool %146 %147
%149 = OpLogicalAnd %bool %148 %145
%150 = OpCompositeExtract %S %139 1
%151 = OpCompositeExtract %S %140 1
%52 = OpCompositeConstruct %_arr_v3int_int_2 %48 %51
OpStore %v1 %52
%54 = OpCompositeConstruct %_arr_v3int_int_2 %48 %51
OpStore %v2 %54
%58 = OpCompositeConstruct %_arr_v3int_int_2 %48 %57
OpStore %v3 %58
%63 = OpCompositeConstruct %S %int_1 %int_2
%64 = OpCompositeConstruct %S %int_3 %int_4
%65 = OpCompositeConstruct %S %int_5 %int_6
%66 = OpCompositeConstruct %_arr_S_int_3 %63 %64 %65
OpStore %s1 %66
%68 = OpCompositeConstruct %S %int_1 %int_2
%70 = OpCompositeConstruct %S %int_0 %int_0
%71 = OpCompositeConstruct %S %int_5 %int_6
%72 = OpCompositeConstruct %_arr_S_int_3 %68 %70 %71
OpStore %s2 %72
%74 = OpCompositeConstruct %S %int_1 %int_2
%75 = OpCompositeConstruct %S %int_3 %int_4
%76 = OpCompositeConstruct %S %int_5 %int_6
%77 = OpCompositeConstruct %_arr_S_int_3 %74 %75 %76
OpStore %s3 %77
%79 = OpLoad %_arr_float_int_4 %f1
%80 = OpLoad %_arr_float_int_4 %f2
%81 = OpCompositeExtract %float %79 0
%82 = OpCompositeExtract %float %80 0
%83 = OpFOrdEqual %bool %81 %82
%84 = OpCompositeExtract %float %79 1
%85 = OpCompositeExtract %float %80 1
%86 = OpFOrdEqual %bool %84 %85
%87 = OpLogicalAnd %bool %86 %83
%88 = OpCompositeExtract %float %79 2
%89 = OpCompositeExtract %float %80 2
%90 = OpFOrdEqual %bool %88 %89
%91 = OpLogicalAnd %bool %90 %87
%92 = OpCompositeExtract %float %79 3
%93 = OpCompositeExtract %float %80 3
%94 = OpFOrdEqual %bool %92 %93
%95 = OpLogicalAnd %bool %94 %91
OpSelectionMerge %97 None
OpBranchConditional %95 %96 %97
%96 = OpLabel
%98 = OpLoad %_arr_float_int_4 %f1
%99 = OpLoad %_arr_float_int_4 %f3
%100 = OpCompositeExtract %float %98 0
%101 = OpCompositeExtract %float %99 0
%102 = OpFOrdNotEqual %bool %100 %101
%103 = OpCompositeExtract %float %98 1
%104 = OpCompositeExtract %float %99 1
%105 = OpFOrdNotEqual %bool %103 %104
%106 = OpLogicalOr %bool %105 %102
%107 = OpCompositeExtract %float %98 2
%108 = OpCompositeExtract %float %99 2
%109 = OpFOrdNotEqual %bool %107 %108
%110 = OpLogicalOr %bool %109 %106
%111 = OpCompositeExtract %float %98 3
%112 = OpCompositeExtract %float %99 3
%113 = OpFOrdNotEqual %bool %111 %112
%114 = OpLogicalOr %bool %113 %110
OpBranch %97
%97 = OpLabel
%115 = OpPhi %bool %false %25 %114 %96
OpSelectionMerge %117 None
OpBranchConditional %115 %116 %117
%116 = OpLabel
%118 = OpLoad %_arr_v3int_int_2 %v1
%119 = OpLoad %_arr_v3int_int_2 %v2
%120 = OpCompositeExtract %v3int %118 0
%121 = OpCompositeExtract %v3int %119 0
%122 = OpIEqual %v3bool %120 %121
%124 = OpAll %bool %122
%125 = OpCompositeExtract %v3int %118 1
%126 = OpCompositeExtract %v3int %119 1
%127 = OpIEqual %v3bool %125 %126
%128 = OpAll %bool %127
%129 = OpLogicalAnd %bool %128 %124
OpBranch %117
%117 = OpLabel
%130 = OpPhi %bool %false %97 %129 %116
OpSelectionMerge %132 None
OpBranchConditional %130 %131 %132
%131 = OpLabel
%133 = OpLoad %_arr_v3int_int_2 %v1
%134 = OpLoad %_arr_v3int_int_2 %v3
%135 = OpCompositeExtract %v3int %133 0
%136 = OpCompositeExtract %v3int %134 0
%137 = OpINotEqual %v3bool %135 %136
%138 = OpAny %bool %137
%139 = OpCompositeExtract %v3int %133 1
%140 = OpCompositeExtract %v3int %134 1
%141 = OpINotEqual %v3bool %139 %140
%142 = OpAny %bool %141
%143 = OpLogicalOr %bool %142 %138
OpBranch %132
%132 = OpLabel
%144 = OpPhi %bool %false %117 %143 %131
OpSelectionMerge %146 None
OpBranchConditional %144 %145 %146
%145 = OpLabel
%147 = OpLoad %_arr_S_int_3 %s1
%148 = OpLoad %_arr_S_int_3 %s2
%149 = OpCompositeExtract %S %147 0
%150 = OpCompositeExtract %S %148 0
%151 = OpCompositeExtract %int %149 0
%152 = OpCompositeExtract %int %150 0
%153 = OpCompositeExtract %int %151 0
%154 = OpIEqual %bool %152 %153
%153 = OpINotEqual %bool %151 %152
%154 = OpCompositeExtract %int %149 1
%155 = OpCompositeExtract %int %150 1
%156 = OpCompositeExtract %int %151 1
%157 = OpIEqual %bool %155 %156
%158 = OpLogicalAnd %bool %157 %154
%159 = OpLogicalAnd %bool %158 %149
%160 = OpCompositeExtract %S %139 2
%161 = OpCompositeExtract %S %140 2
%162 = OpCompositeExtract %int %160 0
%163 = OpCompositeExtract %int %161 0
%164 = OpIEqual %bool %162 %163
%165 = OpCompositeExtract %int %160 1
%166 = OpCompositeExtract %int %161 1
%167 = OpIEqual %bool %165 %166
%168 = OpLogicalAnd %bool %167 %164
%169 = OpLogicalAnd %bool %168 %159
OpBranch %138
%138 = OpLabel
%170 = OpPhi %bool %false %104 %169 %137
OpSelectionMerge %175 None
OpBranchConditional %170 %173 %174
%173 = OpLabel
%176 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
%178 = OpLoad %v4float %176
OpStore %171 %178
OpBranch %175
%174 = OpLabel
%179 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
%180 = OpLoad %v4float %179
OpStore %171 %180
OpBranch %175
%175 = OpLabel
%181 = OpLoad %v4float %171
OpReturnValue %181
%156 = OpINotEqual %bool %154 %155
%157 = OpLogicalOr %bool %156 %153
%158 = OpCompositeExtract %S %147 1
%159 = OpCompositeExtract %S %148 1
%160 = OpCompositeExtract %int %158 0
%161 = OpCompositeExtract %int %159 0
%162 = OpINotEqual %bool %160 %161
%163 = OpCompositeExtract %int %158 1
%164 = OpCompositeExtract %int %159 1
%165 = OpINotEqual %bool %163 %164
%166 = OpLogicalOr %bool %165 %162
%167 = OpLogicalOr %bool %166 %157
%168 = OpCompositeExtract %S %147 2
%169 = OpCompositeExtract %S %148 2
%170 = OpCompositeExtract %int %168 0
%171 = OpCompositeExtract %int %169 0
%172 = OpINotEqual %bool %170 %171
%173 = OpCompositeExtract %int %168 1
%174 = OpCompositeExtract %int %169 1
%175 = OpINotEqual %bool %173 %174
%176 = OpLogicalOr %bool %175 %172
%177 = OpLogicalOr %bool %176 %167
OpBranch %146
%146 = OpLabel
%178 = OpPhi %bool %false %132 %177 %145
OpSelectionMerge %180 None
OpBranchConditional %178 %179 %180
%179 = OpLabel
%181 = OpLoad %_arr_S_int_3 %s3
%182 = OpLoad %_arr_S_int_3 %s1
%183 = OpCompositeExtract %S %181 0
%184 = OpCompositeExtract %S %182 0
%185 = OpCompositeExtract %int %183 0
%186 = OpCompositeExtract %int %184 0
%187 = OpIEqual %bool %185 %186
%188 = OpCompositeExtract %int %183 1
%189 = OpCompositeExtract %int %184 1
%190 = OpIEqual %bool %188 %189
%191 = OpLogicalAnd %bool %190 %187
%192 = OpCompositeExtract %S %181 1
%193 = OpCompositeExtract %S %182 1
%194 = OpCompositeExtract %int %192 0
%195 = OpCompositeExtract %int %193 0
%196 = OpIEqual %bool %194 %195
%197 = OpCompositeExtract %int %192 1
%198 = OpCompositeExtract %int %193 1
%199 = OpIEqual %bool %197 %198
%200 = OpLogicalAnd %bool %199 %196
%201 = OpLogicalAnd %bool %200 %191
%202 = OpCompositeExtract %S %181 2
%203 = OpCompositeExtract %S %182 2
%204 = OpCompositeExtract %int %202 0
%205 = OpCompositeExtract %int %203 0
%206 = OpIEqual %bool %204 %205
%207 = OpCompositeExtract %int %202 1
%208 = OpCompositeExtract %int %203 1
%209 = OpIEqual %bool %207 %208
%210 = OpLogicalAnd %bool %209 %206
%211 = OpLogicalAnd %bool %210 %201
OpBranch %180
%180 = OpLabel
%212 = OpPhi %bool %false %146 %211 %179
OpSelectionMerge %217 None
OpBranchConditional %212 %215 %216
%215 = OpLabel
%218 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
%220 = OpLoad %v4float %218
OpStore %213 %220
OpBranch %217
%216 = OpLabel
%221 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
%222 = OpLoad %v4float %221
OpStore %213 %222
OpBranch %217
%217 = OpLabel
%223 = OpLoad %v4float %213
OpReturnValue %223
OpFunctionEnd

View File

@ -10,8 +10,11 @@ vec4 main() {
float f1[4] = float[4](1.0, 2.0, 3.0, 4.0);
float f2[4] = float[4](1.0, 2.0, 3.0, 4.0);
float f3[4] = float[4](1.0, 2.0, 3.0, -4.0);
ivec3 v1[2] = ivec3[2](ivec3(1, 2, 3), ivec3(4, 5, 6));
ivec3 v2[2] = ivec3[2](ivec3(1, 2, 3), ivec3(4, 5, 6));
ivec3 v3[2] = ivec3[2](ivec3(1, 2, 3), ivec3(4, 5, -6));
S s1[3] = S[3](S(1, 2), S(3, 4), S(5, 6));
S s2[3] = S[3](S(1, 2), S(0, 0), S(5, 6));
S s3[3] = S[3](S(1, 2), S(3, 4), S(5, 6));
return ((f1 == f2 && f1 != f3) && s1 != s2) && s3 == s1 ? colorGreen : colorRed;
return ((((f1 == f2 && f1 != f3) && v1 == v2) && v1 != v3) && s1 != s2) && s3 == s1 ? colorGreen : colorRed;
}

View File

@ -18,7 +18,7 @@ struct Outputs {
template <typename T1, typename T2, size_t N>
bool operator==(thread const array<T1, N>& left, thread const array<T2, N>& right) {
for (size_t index = 0; index < N; ++index) {
if (!(left[index] == right[index])) {
if (!all(left[index] == right[index])) {
return false;
}
}
@ -42,9 +42,12 @@ fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant Uniforms& _unifo
array<float, 4> f1 = array<float, 4>{1.0, 2.0, 3.0, 4.0};
array<float, 4> f2 = array<float, 4>{1.0, 2.0, 3.0, 4.0};
array<float, 4> f3 = array<float, 4>{1.0, 2.0, 3.0, -4.0};
array<int3, 2> v1 = array<int3, 2>{int3(1, 2, 3), int3(4, 5, 6)};
array<int3, 2> v2 = array<int3, 2>{int3(1, 2, 3), int3(4, 5, 6)};
array<int3, 2> v3 = array<int3, 2>{int3(1, 2, 3), int3(4, 5, -6)};
array<S, 3> s1 = array<S, 3>{S{1, 2}, S{3, 4}, S{5, 6}};
array<S, 3> s2 = array<S, 3>{S{1, 2}, S{0, 0}, S{5, 6}};
array<S, 3> s3 = array<S, 3>{S{1, 2}, S{3, 4}, S{5, 6}};
_out.sk_FragColor = ((f1 == f2 && f1 != f3) && s1 != s2) && s3 == s1 ? _uniforms.colorGreen : _uniforms.colorRed;
_out.sk_FragColor = ((((f1 == f2 && f1 != f3) && v1 == v2) && v1 != v3) && s1 != s2) && s3 == s1 ? _uniforms.colorGreen : _uniforms.colorRed;
return _out;
}

View File

@ -14,7 +14,7 @@ struct Outputs {
template <typename T1, typename T2, size_t N>
bool operator==(thread const array<T1, N>& left, thread const array<T2, N>& right) {
for (size_t index = 0; index < N; ++index) {
if (!(left[index] == right[index])) {
if (!all(left[index] == right[index])) {
return false;
}
}