Disallow inlining a function with out-parameters.

It is difficult to do this both efficiently and correctly while honoring
GLSL semantics (which require the lvalues to be kept distinct, even when
they point to the same variable). We could make it work by making copies
of every out parameter in each direction (going in for inouts, and
coming out for outs and inouts).

However, this could be self-defeating if it makes it harder for the
driver to track variable lifetimes. Simply opting out of inlining these
functions entirely seems like the best tradeoff; let the driver optimize
them if it can, and we can enjoy reduced complexity in the SkSL inliner.

Change-Id: I62f7b4550cc181cfe789e4f2ff4e408ba1baf9cb
Bug: skia:11326
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/370257
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
This commit is contained in:
John Stiles 2021-03-17 13:20:10 -04:00 committed by Skia Commit-Bot
parent b73f737aae
commit bff24abab8
16 changed files with 1211 additions and 765 deletions

View File

@ -1,10 +1,11 @@
inline void tooBig(inout int x) {
inline int tooBig(int x) {
++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x;
++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x;
return x;
}
void main() {
int y = 0;
tooBig(y);
tooBig(y);
y = tooBig(y);
y = tooBig(y);
}

View File

@ -1,3 +1,4 @@
// We don't inline functions with out parameters. (skia:11326)
inline void outParameter(inout half x) {
x *= 2;
}

View File

@ -1,11 +1,12 @@
void foo(out half x) {
half foo(half x) {
++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x; ++x;
--x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x; --x;
x = 42;
return x;
}
half bar(half y) {
foo(y);
y = foo(y);
return y;
}

View File

@ -4,16 +4,11 @@ half4 flip(half4 v) {
return v.wzyx;
}
void mutating_flip(out half4 v) {
v = v.wzyx;
}
void main() {
half4 color = inColor;
sk_FragColor = color.xyzy.wzyx;
sk_FragColor = flip(color.xyzy);
mutating_flip(color);
sk_FragColor = color;
}

View File

@ -10,24 +10,24 @@ struct S {
half h;
};
void funcb(bool b, out half4 outColor) {
outColor = b ? outColor.xxxx : outColor.yyyy;
half4 funcb(bool b) {
return b ? sk_FragColor.xxxx : sk_FragColor.yyyy;
}
void func1(half h, out half4 outColor) {
outColor = h.xxxx;
half4 func1(half h) {
return h.xxxx;
}
void func2(half2 h2, out half4 outColor) {
outColor = h2.xyxy;
half4 func2(half2 h2) {
return h2.xyxy;
}
void func3(half3 h3, out half4 outColor) {
outColor = h3.xyzx;
half4 func3(half3 h3) {
return h3.xyzx;
}
void func4(half4 h4, out half4 outColor) {
outColor = h4;
half4 func4(half4 h4) {
return h4;
}
void main() {
@ -42,24 +42,24 @@ void main() {
// These expressions are considered "trivial" and will be cloned directly into the inlined
// function without a temporary variable.
funcb(sk_Caps.floatIs32Bits, sk_FragColor);
func1(+s.h, sk_FragColor);
funcb(b, sk_FragColor);
func2(s.ah4[0].yw, sk_FragColor);
func2(as[0].ah4[0].xy, sk_FragColor);
func3(s.h4.zzz, sk_FragColor);
func3(uh4.xyz, sk_FragColor);
func3(s.h.xxx, sk_FragColor);
func4(half4(s.h), sk_FragColor);
func4(s.ah4[0].xxxy, sk_FragColor);
func4(uh4, sk_FragColor);
sk_FragColor = funcb(sk_Caps.floatIs32Bits);
sk_FragColor = func1(+s.h);
sk_FragColor = funcb(b);
sk_FragColor = func2(s.ah4[0].yw);
sk_FragColor = func2(as[0].ah4[0].xy);
sk_FragColor = func3(s.h4.zzz);
sk_FragColor = func3(uh4.xyz);
sk_FragColor = func3(s.h.xxx);
sk_FragColor = func4(half4(s.h));
sk_FragColor = func4(s.ah4[0].xxxy);
sk_FragColor = func4(uh4);
// These expressions are considered "non-trivial" and will be placed in a temporary variable
// when inlining occurs.
funcb(!sk_Caps.floatIs32Bits, sk_FragColor);
func1(-s.h, sk_FragColor);
funcb(!b, sk_FragColor);
func2(s.ah4[ui].yw, sk_FragColor);
func3(s.h4.yyy + s.h4.zzz, sk_FragColor);
func4(s.h4.y001, sk_FragColor);
sk_FragColor = funcb(!sk_Caps.floatIs32Bits);
sk_FragColor = func1(-s.h);
sk_FragColor = funcb(!b);
sk_FragColor = func2(s.ah4[ui].yw);
sk_FragColor = func3(s.h4.yyy + s.h4.zzz);
sk_FragColor = func4(s.h4.y001);
}

View File

@ -542,6 +542,9 @@ Inliner::InlineVariable Inliner::makeInlineVariable(const String& baseName,
type = &type->scalarTypeForLiteral();
}
// Out parameters aren't supported.
SkASSERT(!(modifiers.fFlags & Modifiers::kOut_Flag));
// Provide our new variable with a unique name, and add it to our symbol table.
const String* namePtr = symbolTable->takeOwnershipOfString(
std::make_unique<String>(fMangler.uniqueName(baseName, symbolTable)));
@ -556,15 +559,9 @@ Inliner::InlineVariable Inliner::makeInlineVariable(const String& baseName,
isBuiltinCode,
Variable::Storage::kLocal);
// Prepare the variable declaration (taking extra care with `out` params to not clobber any
// initial value).
if (*initialValue && (modifiers.fFlags & Modifiers::kOut_Flag)) {
result.fVarDecl = std::make_unique<VarDeclaration>(var.get(), type, /*arraySize=*/0,
(*initialValue)->clone());
} else {
result.fVarDecl = std::make_unique<VarDeclaration>(var.get(), type, /*arraySize=*/0,
std::move(*initialValue));
}
// Create our variable declaration.
result.fVarDecl = std::make_unique<VarDeclaration>(var.get(), type, /*arraySize=*/0,
std::move(*initialValue));
var->setDeclaration(&result.fVarDecl->as<VarDeclaration>());
result.fVarSymbol = symbolTable->add(std::move(var));
return result;
@ -619,23 +616,17 @@ Inliner::InlinedCall Inliner::inlineCall(FunctionCall* call,
// Create variables in the extra statements to hold the arguments, and assign the arguments to
// them.
VariableRewriteMap varMap;
std::vector<int> argsToCopyBack;
for (int i = 0; i < (int) arguments.size(); ++i) {
const Variable* param = function.declaration().parameters()[i];
bool isOutParam = param->modifiers().fFlags & Modifiers::kOut_Flag;
for (int i = 0; i < arguments.count(); ++i) {
// If this argument can be inlined trivially (e.g. a swizzle, or a constant array index)...
const Variable* param = function.declaration().parameters()[i];
if (Analysis::IsTrivialExpression(*arguments[i])) {
// ... and it's an `out` param, or it isn't written to within the inline function...
if (isOutParam || !Analysis::StatementWritesToVariable(*function.body(), *param)) {
// ... and isn't written to within the inline function...
if (!Analysis::StatementWritesToVariable(*function.body(), *param)) {
// ... we don't need to copy it at all! We can just use the existing expression.
varMap[param] = arguments[i]->clone();
continue;
}
}
if (isOutParam) {
argsToCopyBack.push_back(i);
}
InlineVariable var = this->makeInlineVariable(param->name(), &arguments[i]->type(),
symbolTable.get(), param->modifiers(),
caller->isBuiltin(), &arguments[i]);
@ -646,25 +637,13 @@ Inliner::InlinedCall Inliner::inlineCall(FunctionCall* call,
const Block& body = function.body()->as<Block>();
StatementArray* inlineStatements = &inlinedBlockStmts;
inlineStatements->reserve_back(body.children().size() + argsToCopyBack.size());
inlineStatements->reserve_back(body.children().size());
for (const std::unique_ptr<Statement>& stmt : body.children()) {
inlineStatements->push_back(this->inlineStatement(offset, &varMap, symbolTable.get(),
&resultExpr, returnComplexity, *stmt,
caller->isBuiltin()));
}
// Copy back the values of `out` parameters into their real destinations.
for (int i : argsToCopyBack) {
const Variable* p = function.declaration().parameters()[i];
SkASSERT(varMap.find(p) != varMap.end());
inlineStatements->push_back(ExpressionStatement::Make(
*fContext,
BinaryExpression::Make(*fContext,
clone_with_ref_kind(*arguments[i], VariableRefKind::kWrite),
Token::Kind::TK_EQ,
std::move(varMap[p]))));
}
// Wrap all of the generated statements in a block. We need a real Block here, so we can't use
// MakeUnscoped. This is because we need to add another child statement to the Block later.
inlinedCall.fInlinedBody = Block::Make(offset, std::move(inlinedBlockStmts),
@ -712,6 +691,13 @@ bool Inliner::isSafeToInline(const FunctionDefinition* functionDef) {
return false;
}
// We don't allow inlining a function with out parameters. (See skia:11326 for rationale.)
for (const Variable* param : functionDef->declaration().parameters()) {
if (param->modifiers().fFlags & Modifiers::Flag::kOut_Flag) {
return false;
}
}
// We don't have a mechanism to simulate early returns, so we can't inline if there is one.
return GetReturnComplexity(*functionDef) < ReturnComplexity::kEarlyReturns;
}

View File

@ -135,6 +135,10 @@ SKSL_TEST(SkSLShortCircuitBoolFolding, "folding/ShortCircuitBoolFolding.
SKSL_TEST(SkSLVectorScalarFolding, "folding/VectorScalarFolding.sksl")
SKSL_TEST(SkSLVectorVectorFolding, "folding/VectorVectorFolding.sksl")
// TODO(skia:11052): SPIR-V does not yet honor `out` param semantics correctly
SKSL_TEST_CPU(SkSLInlinerHonorsGLSLOutParamSemantics,
"inliner/InlinerHonorsGLSLOutParamSemantics.sksl")
SKSL_TEST(SkSLIntrinsicAbsFloat, "intrinsics/AbsFloat.sksl")
SKSL_TEST(SkSLIntrinsicCeil, "intrinsics/Ceil.sksl")
SKSL_TEST(SkSLIntrinsicClampFloat, "intrinsics/ClampFloat.sksl")

View File

@ -1,74 +1,76 @@
void main() {
int y = 0;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
false;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
++y;
false;
int _0_x = y;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
++_0_x;
y = _0_x;
int _1_x = y;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
++_1_x;
y = _1_x;
}

View File

@ -1,8 +1,10 @@
out vec4 sk_FragColor;
void outParameter(inout float x) {
x *= 2.0;
}
void main() {
float x = 1.0;
x *= 2.0;
false;
outParameter(x);
sk_FragColor.x = x;
}

View File

@ -2,42 +2,44 @@
out vec4 sk_FragColor;
void main() {
float z = 0.0;
float _0_y = z;
++_0_y;
++_0_y;
++_0_y;
++_0_y;
++_0_y;
++_0_y;
++_0_y;
++_0_y;
++_0_y;
++_0_y;
++_0_y;
++_0_y;
++_0_y;
++_0_y;
++_0_y;
++_0_y;
++_0_y;
--_0_y;
--_0_y;
--_0_y;
--_0_y;
--_0_y;
--_0_y;
--_0_y;
--_0_y;
--_0_y;
--_0_y;
--_0_y;
--_0_y;
--_0_y;
--_0_y;
--_0_y;
--_0_y;
--_0_y;
_0_y = 42.0;
_0_y;
float _2_y = z;
float _3_x = _2_y;
++_3_x;
++_3_x;
++_3_x;
++_3_x;
++_3_x;
++_3_x;
++_3_x;
++_3_x;
++_3_x;
++_3_x;
++_3_x;
++_3_x;
++_3_x;
++_3_x;
++_3_x;
++_3_x;
++_3_x;
--_3_x;
--_3_x;
--_3_x;
--_3_x;
--_3_x;
--_3_x;
--_3_x;
--_3_x;
--_3_x;
--_3_x;
--_3_x;
--_3_x;
--_3_x;
--_3_x;
--_3_x;
--_3_x;
--_3_x;
_3_x = 42.0;
_2_y = _3_x;
_2_y;
sk_FragColor.x = z;
}

View File

@ -2,9 +2,12 @@
out vec4 sk_FragColor;
uniform vec4 colorGreen;
uniform vec4 colorRed;
bool out_params_are_distinct(out float x, out float y) {
x = 1.0;
y = 2.0;
return x == 1.0 && y == 2.0;
}
vec4 main() {
float x = 0.0;
x = 1.0;
x = 2.0;
return x == 1.0 && x == 2.0 ? colorGreen : colorRed;
return out_params_are_distinct(x, x) ? colorGreen : colorRed;
}

View File

@ -5,7 +5,5 @@ void main() {
vec4 color = inColor;
sk_FragColor = color.yzyx;
sk_FragColor = color.yzyx;
color = color.wzyx;
false;
sk_FragColor = color;
}

View File

@ -19,42 +19,25 @@ void main() {
S as[1];
as[0].ah4[0] = vec4(val);
sk_FragColor = sk_FragColor.xxxx;
false;
sk_FragColor = vec4(s.h);
false;
sk_FragColor = b ? sk_FragColor.xxxx : sk_FragColor.yyyy;
false;
sk_FragColor = s.ah4[0].ywyw;
false;
sk_FragColor = as[0].ah4[0].xyxy;
false;
sk_FragColor = s.h4.zzzz;
false;
sk_FragColor = uh4.xyzx;
false;
sk_FragColor = vec4(s.h);
false;
sk_FragColor = vec4(s.h);
false;
sk_FragColor = s.ah4[0].xxxy;
false;
sk_FragColor = uh4;
false;
sk_FragColor = sk_FragColor.yyyy;
false;
float _0_h = -s.h;
sk_FragColor = vec4(_0_h);
false;
bool _1_b = !b;
sk_FragColor = _1_b ? sk_FragColor.xxxx : sk_FragColor.yyyy;
false;
vec2 _2_h2 = s.ah4[ui].yw;
sk_FragColor = _2_h2.xyxy;
false;
vec3 _3_h3 = s.h4.yyy + s.h4.zzz;
sk_FragColor = _3_h3.xyzx;
false;
vec4 _4_h4 = vec4(s.h4.y, 0.0, 0.0, 1.0);
sk_FragColor = _4_h4;
false;
}

File diff suppressed because it is too large Load Diff

View File

@ -3,99 +3,130 @@ out vec4 sk_FragColor;
uniform vec4 colorGreen;
uniform vec4 colorRed;
uniform vec4 colorWhite;
void out_half(out float v) {
v = colorWhite.x;
}
void out_half2(out vec2 v) {
v = vec2(colorWhite.y);
}
void out_half3(out vec3 v) {
v = vec3(colorWhite.z);
}
void out_half4(out vec4 v) {
v = vec4(colorWhite.w);
}
void out_half2x2(out mat2 v) {
v = mat2(colorWhite.x);
}
void out_half3x3(out mat3 v) {
v = mat3(colorWhite.y);
}
void out_half4x4(out mat4 v) {
v = mat4(colorWhite.z);
}
void out_int(out int v) {
v = int(colorWhite.x);
}
void out_int2(out ivec2 v) {
v = ivec2(int(colorWhite.y));
}
void out_int3(out ivec3 v) {
v = ivec3(int(colorWhite.z));
}
void out_int4(out ivec4 v) {
v = ivec4(int(colorWhite.w));
}
void out_float(out float v) {
v = colorWhite.x;
}
void out_float2(out vec2 v) {
v = vec2(colorWhite.y);
}
void out_float3(out vec3 v) {
v = vec3(colorWhite.z);
}
void out_float4(out vec4 v) {
v = vec4(colorWhite.w);
}
void out_float2x2(out mat2 v) {
v = mat2(colorWhite.x);
}
void out_float3x3(out mat3 v) {
v = mat3(colorWhite.y);
}
void out_float4x4(out mat4 v) {
v = mat4(colorWhite.z);
}
void out_bool(out bool v) {
v = bool(colorWhite.x);
}
void out_bool2(out bvec2 v) {
v = bvec2(bool(colorWhite.y));
}
void out_bool3(out bvec3 v) {
v = bvec3(bool(colorWhite.z));
}
void out_bool4(out bvec4 v) {
v = bvec4(bool(colorWhite.w));
}
vec4 main() {
float h;
h = colorWhite.x;
false;
out_half(h);
vec2 h2;
h2 = vec2(colorWhite.y);
false;
out_half2(h2);
vec3 h3;
h3 = vec3(colorWhite.z);
false;
out_half3(h3);
vec4 h4;
h4 = vec4(colorWhite.w);
false;
h3.y = colorWhite.x;
false;
h3.xz = vec2(colorWhite.y);
false;
h4.zwxy = vec4(colorWhite.w);
false;
out_half4(h4);
out_half(h3.y);
out_half2(h3.xz);
out_half4(h4.zwxy);
mat2 h2x2;
h2x2 = mat2(colorWhite.x);
false;
out_half2x2(h2x2);
mat3 h3x3;
h3x3 = mat3(colorWhite.y);
false;
out_half3x3(h3x3);
mat4 h4x4;
h4x4 = mat4(colorWhite.z);
false;
h3x3[1] = vec3(colorWhite.z);
false;
h4x4[3].w = colorWhite.x;
false;
h2x2[0].x = colorWhite.x;
false;
out_half4x4(h4x4);
out_half3(h3x3[1]);
out_half(h4x4[3].w);
out_half(h2x2[0].x);
int i;
i = int(colorWhite.x);
false;
out_int(i);
ivec2 i2;
i2 = ivec2(int(colorWhite.y));
false;
out_int2(i2);
ivec3 i3;
i3 = ivec3(int(colorWhite.z));
false;
out_int3(i3);
ivec4 i4;
i4 = ivec4(int(colorWhite.w));
false;
i4.xyz = ivec3(int(colorWhite.z));
false;
i2.y = int(colorWhite.x);
false;
out_int4(i4);
out_int3(i4.xyz);
out_int(i2.y);
float f;
f = colorWhite.x;
false;
out_float(f);
vec2 f2;
f2 = vec2(colorWhite.y);
false;
out_float2(f2);
vec3 f3;
f3 = vec3(colorWhite.z);
false;
out_float3(f3);
vec4 f4;
f4 = vec4(colorWhite.w);
false;
f3.xy = vec2(colorWhite.y);
false;
f2.x = colorWhite.x;
false;
out_float4(f4);
out_float2(f3.xy);
out_float(f2.x);
mat2 f2x2;
f2x2 = mat2(colorWhite.x);
false;
out_float2x2(f2x2);
mat3 f3x3;
f3x3 = mat3(colorWhite.y);
false;
out_float3x3(f3x3);
mat4 f4x4;
f4x4 = mat4(colorWhite.z);
false;
f2x2[0].x = colorWhite.x;
false;
out_float4x4(f4x4);
out_float(f2x2[0].x);
bool b;
b = bool(colorWhite.x);
false;
out_bool(b);
bvec2 b2;
b2 = bvec2(bool(colorWhite.y));
false;
out_bool2(b2);
bvec3 b3;
b3 = bvec3(bool(colorWhite.z));
false;
out_bool3(b3);
bvec4 b4;
b4 = bvec4(bool(colorWhite.w));
false;
b4.xw = bvec2(bool(colorWhite.y));
false;
b3.z = bool(colorWhite.x);
false;
out_bool4(b4);
out_bool2(b4.xw);
out_bool(b3.z);
bool ok = true;
ok = ok && 1.0 == (((((h * h2.x) * h3.x) * h4.x) * h2x2[0].x) * h3x3[0].x) * h4x4[0].x;
ok = ok && 1.0 == (((((f * f2.x) * f3.x) * f4.x) * f2x2[0].x) * f3x3[0].x) * f4x4[0].x;

View File

@ -11,102 +11,343 @@ struct Inputs {
struct Outputs {
float4 sk_FragColor [[color(0)]];
};
void out_half(Uniforms _uniforms, thread float& v);
void _skOutParamHelper0_out_half(Uniforms _uniforms, thread float& h) {
float _var0;
out_half(_uniforms, _var0);
h = _var0;
}
void out_half2(Uniforms _uniforms, thread float2& v);
void _skOutParamHelper1_out_half2(Uniforms _uniforms, thread float2& h2) {
float2 _var0;
out_half2(_uniforms, _var0);
h2 = _var0;
}
void out_half3(Uniforms _uniforms, thread float3& v);
void _skOutParamHelper2_out_half3(Uniforms _uniforms, thread float3& h3) {
float3 _var0;
out_half3(_uniforms, _var0);
h3 = _var0;
}
void out_half4(Uniforms _uniforms, thread float4& v);
void _skOutParamHelper3_out_half4(Uniforms _uniforms, thread float4& h4) {
float4 _var0;
out_half4(_uniforms, _var0);
h4 = _var0;
}
void out_half(Uniforms _uniforms, thread float& v);
void _skOutParamHelper4_out_half(Uniforms _uniforms, thread float3& h3) {
float _var0;
out_half(_uniforms, _var0);
h3.y = _var0;
}
void out_half2(Uniforms _uniforms, thread float2& v);
void _skOutParamHelper5_out_half2(Uniforms _uniforms, thread float3& h3) {
float2 _var0;
out_half2(_uniforms, _var0);
h3.xz = _var0;
}
void out_half4(Uniforms _uniforms, thread float4& v);
void _skOutParamHelper6_out_half4(Uniforms _uniforms, thread float4& h4) {
float4 _var0;
out_half4(_uniforms, _var0);
h4.zwxy = _var0;
}
void out_half2x2(Uniforms _uniforms, thread float2x2& v);
void _skOutParamHelper7_out_half2x2(Uniforms _uniforms, thread float2x2& h2x2) {
float2x2 _var0;
out_half2x2(_uniforms, _var0);
h2x2 = _var0;
}
void out_half3x3(Uniforms _uniforms, thread float3x3& v);
void _skOutParamHelper8_out_half3x3(Uniforms _uniforms, thread float3x3& h3x3) {
float3x3 _var0;
out_half3x3(_uniforms, _var0);
h3x3 = _var0;
}
void out_half4x4(Uniforms _uniforms, thread float4x4& v);
void _skOutParamHelper9_out_half4x4(Uniforms _uniforms, thread float4x4& h4x4) {
float4x4 _var0;
out_half4x4(_uniforms, _var0);
h4x4 = _var0;
}
void out_half3(Uniforms _uniforms, thread float3& v);
void _skOutParamHelper10_out_half3(Uniforms _uniforms, thread float3x3& h3x3) {
float3 _var0;
out_half3(_uniforms, _var0);
h3x3[1] = _var0;
}
void out_half(Uniforms _uniforms, thread float& v);
void _skOutParamHelper11_out_half(Uniforms _uniforms, thread float4x4& h4x4) {
float _var0;
out_half(_uniforms, _var0);
h4x4[3].w = _var0;
}
void out_half(Uniforms _uniforms, thread float& v);
void _skOutParamHelper12_out_half(Uniforms _uniforms, thread float2x2& h2x2) {
float _var0;
out_half(_uniforms, _var0);
h2x2[0].x = _var0;
}
void out_int(Uniforms _uniforms, thread int& v);
void _skOutParamHelper13_out_int(Uniforms _uniforms, thread int& i) {
int _var0;
out_int(_uniforms, _var0);
i = _var0;
}
void out_int2(Uniforms _uniforms, thread int2& v);
void _skOutParamHelper14_out_int2(Uniforms _uniforms, thread int2& i2) {
int2 _var0;
out_int2(_uniforms, _var0);
i2 = _var0;
}
void out_int3(Uniforms _uniforms, thread int3& v);
void _skOutParamHelper15_out_int3(Uniforms _uniforms, thread int3& i3) {
int3 _var0;
out_int3(_uniforms, _var0);
i3 = _var0;
}
void out_int4(Uniforms _uniforms, thread int4& v);
void _skOutParamHelper16_out_int4(Uniforms _uniforms, thread int4& i4) {
int4 _var0;
out_int4(_uniforms, _var0);
i4 = _var0;
}
void out_int3(Uniforms _uniforms, thread int3& v);
void _skOutParamHelper17_out_int3(Uniforms _uniforms, thread int4& i4) {
int3 _var0;
out_int3(_uniforms, _var0);
i4.xyz = _var0;
}
void out_int(Uniforms _uniforms, thread int& v);
void _skOutParamHelper18_out_int(Uniforms _uniforms, thread int2& i2) {
int _var0;
out_int(_uniforms, _var0);
i2.y = _var0;
}
void out_float(Uniforms _uniforms, thread float& v);
void _skOutParamHelper19_out_float(Uniforms _uniforms, thread float& f) {
float _var0;
out_float(_uniforms, _var0);
f = _var0;
}
void out_float2(Uniforms _uniforms, thread float2& v);
void _skOutParamHelper20_out_float2(Uniforms _uniforms, thread float2& f2) {
float2 _var0;
out_float2(_uniforms, _var0);
f2 = _var0;
}
void out_float3(Uniforms _uniforms, thread float3& v);
void _skOutParamHelper21_out_float3(Uniforms _uniforms, thread float3& f3) {
float3 _var0;
out_float3(_uniforms, _var0);
f3 = _var0;
}
void out_float4(Uniforms _uniforms, thread float4& v);
void _skOutParamHelper22_out_float4(Uniforms _uniforms, thread float4& f4) {
float4 _var0;
out_float4(_uniforms, _var0);
f4 = _var0;
}
void out_float2(Uniforms _uniforms, thread float2& v);
void _skOutParamHelper23_out_float2(Uniforms _uniforms, thread float3& f3) {
float2 _var0;
out_float2(_uniforms, _var0);
f3.xy = _var0;
}
void out_float(Uniforms _uniforms, thread float& v);
void _skOutParamHelper24_out_float(Uniforms _uniforms, thread float2& f2) {
float _var0;
out_float(_uniforms, _var0);
f2.x = _var0;
}
void out_float2x2(Uniforms _uniforms, thread float2x2& v);
void _skOutParamHelper25_out_float2x2(Uniforms _uniforms, thread float2x2& f2x2) {
float2x2 _var0;
out_float2x2(_uniforms, _var0);
f2x2 = _var0;
}
void out_float3x3(Uniforms _uniforms, thread float3x3& v);
void _skOutParamHelper26_out_float3x3(Uniforms _uniforms, thread float3x3& f3x3) {
float3x3 _var0;
out_float3x3(_uniforms, _var0);
f3x3 = _var0;
}
void out_float4x4(Uniforms _uniforms, thread float4x4& v);
void _skOutParamHelper27_out_float4x4(Uniforms _uniforms, thread float4x4& f4x4) {
float4x4 _var0;
out_float4x4(_uniforms, _var0);
f4x4 = _var0;
}
void out_float(Uniforms _uniforms, thread float& v);
void _skOutParamHelper28_out_float(Uniforms _uniforms, thread float2x2& f2x2) {
float _var0;
out_float(_uniforms, _var0);
f2x2[0].x = _var0;
}
void out_bool(Uniforms _uniforms, thread bool& v);
void _skOutParamHelper29_out_bool(Uniforms _uniforms, thread bool& b) {
bool _var0;
out_bool(_uniforms, _var0);
b = _var0;
}
void out_bool2(Uniforms _uniforms, thread bool2& v);
void _skOutParamHelper30_out_bool2(Uniforms _uniforms, thread bool2& b2) {
bool2 _var0;
out_bool2(_uniforms, _var0);
b2 = _var0;
}
void out_bool3(Uniforms _uniforms, thread bool3& v);
void _skOutParamHelper31_out_bool3(Uniforms _uniforms, thread bool3& b3) {
bool3 _var0;
out_bool3(_uniforms, _var0);
b3 = _var0;
}
void out_bool4(Uniforms _uniforms, thread bool4& v);
void _skOutParamHelper32_out_bool4(Uniforms _uniforms, thread bool4& b4) {
bool4 _var0;
out_bool4(_uniforms, _var0);
b4 = _var0;
}
void out_bool2(Uniforms _uniforms, thread bool2& v);
void _skOutParamHelper33_out_bool2(Uniforms _uniforms, thread bool4& b4) {
bool2 _var0;
out_bool2(_uniforms, _var0);
b4.xw = _var0;
}
void out_bool(Uniforms _uniforms, thread bool& v);
void _skOutParamHelper34_out_bool(Uniforms _uniforms, thread bool3& b3) {
bool _var0;
out_bool(_uniforms, _var0);
b3.z = _var0;
}
void out_half(Uniforms _uniforms, thread float& v) {
v = _uniforms.colorWhite.x;
}
void out_half2(Uniforms _uniforms, thread float2& v) {
v = float2(_uniforms.colorWhite.y);
}
void out_half3(Uniforms _uniforms, thread float3& v) {
v = float3(_uniforms.colorWhite.z);
}
void out_half4(Uniforms _uniforms, thread float4& v) {
v = float4(_uniforms.colorWhite.w);
}
void out_half2x2(Uniforms _uniforms, thread float2x2& v) {
v = float2x2(_uniforms.colorWhite.x);
}
void out_half3x3(Uniforms _uniforms, thread float3x3& v) {
v = float3x3(_uniforms.colorWhite.y);
}
void out_half4x4(Uniforms _uniforms, thread float4x4& v) {
v = float4x4(_uniforms.colorWhite.z);
}
void out_int(Uniforms _uniforms, thread int& v) {
v = int(_uniforms.colorWhite.x);
}
void out_int2(Uniforms _uniforms, thread int2& v) {
v = int2(int(_uniforms.colorWhite.y));
}
void out_int3(Uniforms _uniforms, thread int3& v) {
v = int3(int(_uniforms.colorWhite.z));
}
void out_int4(Uniforms _uniforms, thread int4& v) {
v = int4(int(_uniforms.colorWhite.w));
}
void out_float(Uniforms _uniforms, thread float& v) {
v = _uniforms.colorWhite.x;
}
void out_float2(Uniforms _uniforms, thread float2& v) {
v = float2(_uniforms.colorWhite.y);
}
void out_float3(Uniforms _uniforms, thread float3& v) {
v = float3(_uniforms.colorWhite.z);
}
void out_float4(Uniforms _uniforms, thread float4& v) {
v = float4(_uniforms.colorWhite.w);
}
void out_float2x2(Uniforms _uniforms, thread float2x2& v) {
v = float2x2(_uniforms.colorWhite.x);
}
void out_float3x3(Uniforms _uniforms, thread float3x3& v) {
v = float3x3(_uniforms.colorWhite.y);
}
void out_float4x4(Uniforms _uniforms, thread float4x4& v) {
v = float4x4(_uniforms.colorWhite.z);
}
void out_bool(Uniforms _uniforms, thread bool& v) {
v = bool(_uniforms.colorWhite.x);
}
void out_bool2(Uniforms _uniforms, thread bool2& v) {
v = bool2(bool(_uniforms.colorWhite.y));
}
void out_bool3(Uniforms _uniforms, thread bool3& v) {
v = bool3(bool(_uniforms.colorWhite.z));
}
void out_bool4(Uniforms _uniforms, thread bool4& v) {
v = bool4(bool(_uniforms.colorWhite.w));
}
fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant Uniforms& _uniforms [[buffer(0)]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
Outputs _out;
(void)_out;
float h;
h = _uniforms.colorWhite.x;
false;
_skOutParamHelper0_out_half(_uniforms, h);
float2 h2;
h2 = float2(_uniforms.colorWhite.y);
false;
_skOutParamHelper1_out_half2(_uniforms, h2);
float3 h3;
h3 = float3(_uniforms.colorWhite.z);
false;
_skOutParamHelper2_out_half3(_uniforms, h3);
float4 h4;
h4 = float4(_uniforms.colorWhite.w);
false;
h3.y = _uniforms.colorWhite.x;
false;
h3.xz = float2(_uniforms.colorWhite.y);
false;
h4.zwxy = float4(_uniforms.colorWhite.w);
false;
_skOutParamHelper3_out_half4(_uniforms, h4);
_skOutParamHelper4_out_half(_uniforms, h3);
_skOutParamHelper5_out_half2(_uniforms, h3);
_skOutParamHelper6_out_half4(_uniforms, h4);
float2x2 h2x2;
h2x2 = float2x2(_uniforms.colorWhite.x);
false;
_skOutParamHelper7_out_half2x2(_uniforms, h2x2);
float3x3 h3x3;
h3x3 = float3x3(_uniforms.colorWhite.y);
false;
_skOutParamHelper8_out_half3x3(_uniforms, h3x3);
float4x4 h4x4;
h4x4 = float4x4(_uniforms.colorWhite.z);
false;
h3x3[1] = float3(_uniforms.colorWhite.z);
false;
h4x4[3].w = _uniforms.colorWhite.x;
false;
h2x2[0].x = _uniforms.colorWhite.x;
false;
_skOutParamHelper9_out_half4x4(_uniforms, h4x4);
_skOutParamHelper10_out_half3(_uniforms, h3x3);
_skOutParamHelper11_out_half(_uniforms, h4x4);
_skOutParamHelper12_out_half(_uniforms, h2x2);
int i;
i = int(_uniforms.colorWhite.x);
false;
_skOutParamHelper13_out_int(_uniforms, i);
int2 i2;
i2 = int2(int(_uniforms.colorWhite.y));
false;
_skOutParamHelper14_out_int2(_uniforms, i2);
int3 i3;
i3 = int3(int(_uniforms.colorWhite.z));
false;
_skOutParamHelper15_out_int3(_uniforms, i3);
int4 i4;
i4 = int4(int(_uniforms.colorWhite.w));
false;
i4.xyz = int3(int(_uniforms.colorWhite.z));
false;
i2.y = int(_uniforms.colorWhite.x);
false;
_skOutParamHelper16_out_int4(_uniforms, i4);
_skOutParamHelper17_out_int3(_uniforms, i4);
_skOutParamHelper18_out_int(_uniforms, i2);
float f;
f = _uniforms.colorWhite.x;
false;
_skOutParamHelper19_out_float(_uniforms, f);
float2 f2;
f2 = float2(_uniforms.colorWhite.y);
false;
_skOutParamHelper20_out_float2(_uniforms, f2);
float3 f3;
f3 = float3(_uniforms.colorWhite.z);
false;
_skOutParamHelper21_out_float3(_uniforms, f3);
float4 f4;
f4 = float4(_uniforms.colorWhite.w);
false;
f3.xy = float2(_uniforms.colorWhite.y);
false;
f2.x = _uniforms.colorWhite.x;
false;
_skOutParamHelper22_out_float4(_uniforms, f4);
_skOutParamHelper23_out_float2(_uniforms, f3);
_skOutParamHelper24_out_float(_uniforms, f2);
float2x2 f2x2;
f2x2 = float2x2(_uniforms.colorWhite.x);
false;
_skOutParamHelper25_out_float2x2(_uniforms, f2x2);
float3x3 f3x3;
f3x3 = float3x3(_uniforms.colorWhite.y);
false;
_skOutParamHelper26_out_float3x3(_uniforms, f3x3);
float4x4 f4x4;
f4x4 = float4x4(_uniforms.colorWhite.z);
false;
f2x2[0].x = _uniforms.colorWhite.x;
false;
_skOutParamHelper27_out_float4x4(_uniforms, f4x4);
_skOutParamHelper28_out_float(_uniforms, f2x2);
bool b;
b = bool(_uniforms.colorWhite.x);
false;
_skOutParamHelper29_out_bool(_uniforms, b);
bool2 b2;
b2 = bool2(bool(_uniforms.colorWhite.y));
false;
_skOutParamHelper30_out_bool2(_uniforms, b2);
bool3 b3;
b3 = bool3(bool(_uniforms.colorWhite.z));
false;
_skOutParamHelper31_out_bool3(_uniforms, b3);
bool4 b4;
b4 = bool4(bool(_uniforms.colorWhite.w));
false;
b4.xw = bool2(bool(_uniforms.colorWhite.y));
false;
b3.z = bool(_uniforms.colorWhite.x);
false;
_skOutParamHelper32_out_bool4(_uniforms, b4);
_skOutParamHelper33_out_bool2(_uniforms, b4);
_skOutParamHelper34_out_bool(_uniforms, b3);
bool ok = true;
ok = ok && 1.0 == (((((h * h2.x) * h3.x) * h4.x) * h2x2[0].x) * h3x3[0].x) * h4x4[0].x;
ok = ok && 1.0 == (((((f * f2.x) * f3.x) * f4.x) * f2x2[0].x) * f3x3[0].x) * f4x4[0].x;