diff --git a/src/sksl/SkSLMetalCodeGenerator.cpp b/src/sksl/SkSLMetalCodeGenerator.cpp index cfc94ff2c8..41184bf43f 100644 --- a/src/sksl/SkSLMetalCodeGenerator.cpp +++ b/src/sksl/SkSLMetalCodeGenerator.cpp @@ -381,6 +381,10 @@ String MetalCodeGenerator::getOutParamHelper(const FunctionCall& call, return name; } +String MetalCodeGenerator::getBitcastIntrinsic(const Type& outType) { + return "as_type<" + outType.displayName() + ">"; +} + void MetalCodeGenerator::writeFunctionCall(const FunctionCall& c) { const FunctionDeclaration& function = c.function(); const ExpressionArray& arguments = c.arguments(); @@ -390,34 +394,38 @@ void MetalCodeGenerator::writeFunctionCall(const FunctionCall& c) { return; } String name = function.name(); - bool builtin = function.isBuiltin(); - if (builtin && name == "atan" && arguments.size() == 2) { - name = "atan2"; - } else if (builtin && name == "inversesqrt") { - name = "rsqrt"; - } else if (builtin && name == "inverse") { - SkASSERT(arguments.size() == 1); - name = this->getInverseHack(*arguments[0]); - } else if (builtin && name == "dFdx") { - name = "dfdx"; - } else if (builtin && name == "dFdy") { - // Flipping Y also negates the Y derivatives. - if (fProgram.fSettings.fFlipY) { - this->write("-"); + if (function.isBuiltin()) { + if (name == "atan" && arguments.size() == 2) { + name = "atan2"; + } else if (name == "inversesqrt") { + name = "rsqrt"; + } else if (name == "inverse") { + SkASSERT(arguments.size() == 1); + name = this->getInverseHack(*arguments[0]); + } else if (name == "dFdx") { + name = "dfdx"; + } else if (name == "dFdy") { + // Flipping Y also negates the Y derivatives. + if (fProgram.fSettings.fFlipY) { + this->write("-"); + } + name = "dfdy"; + } else if (name == "floatBitsToInt" || name == "floatBitsToUint" || + name == "intBitsToFloat" || name == "uintBitsToFloat") { + name = this->getBitcastIntrinsic(c.type()); } - name = "dfdy"; } - // GLSL supports passing swizzled variables to out params; Metal doesn't. Walk the list of - // parameters and see if any are out parameters; if so, check if the passed-in expression is a - // swizzle. Take a note of all the swizzled variables that we find. + // We emulate GLSL's out-param semantics for Metal using a helper function. (Specifically, + // results are only written back to the original variable at the end of the function call; also, + // swizzles are supported, whereas Metal doesn't allow a swizzle to be passed to a `floatN&`.) const std::vector& parameters = function.parameters(); SkASSERT(arguments.size() == parameters.size()); bool foundOutParam = false; SkSTArray<16, VariableReference*> outVars; - outVars.push_back_n(arguments.size(), (VariableReference*)nullptr); + outVars.push_back_n(arguments.count(), (VariableReference*)nullptr); for (int index = 0; index < arguments.count(); ++index) { // If this is an out parameter... diff --git a/src/sksl/SkSLMetalCodeGenerator.h b/src/sksl/SkSLMetalCodeGenerator.h index 1f49b63d02..7fde7c45bd 100644 --- a/src/sksl/SkSLMetalCodeGenerator.h +++ b/src/sksl/SkSLMetalCodeGenerator.h @@ -215,6 +215,8 @@ protected: String getInverseHack(const Expression& mat); + String getBitcastIntrinsic(const Type& outType); + void writeFunctionCall(const FunctionCall& c); bool matrixConstructHelperIsNeeded(const Constructor& c); diff --git a/tests/sksl/intrinsics/golden/FloatBitsToInt.metal b/tests/sksl/intrinsics/golden/FloatBitsToInt.metal index 4fd471d81a..1a97bb5b91 100644 --- a/tests/sksl/intrinsics/golden/FloatBitsToInt.metal +++ b/tests/sksl/intrinsics/golden/FloatBitsToInt.metal @@ -11,6 +11,6 @@ struct Outputs { fragment Outputs fragmentMain(Inputs _in [[stage_in]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) { Outputs _outputStruct; thread Outputs* _out = &_outputStruct; - _out->sk_FragColor.x = float(floatBitsToInt(_in.a)); + _out->sk_FragColor.x = float(as_type(_in.a)); return *_out; } diff --git a/tests/sksl/intrinsics/golden/FloatBitsToUint.metal b/tests/sksl/intrinsics/golden/FloatBitsToUint.metal index 0a456a105a..6703d17cd0 100644 --- a/tests/sksl/intrinsics/golden/FloatBitsToUint.metal +++ b/tests/sksl/intrinsics/golden/FloatBitsToUint.metal @@ -11,6 +11,6 @@ struct Outputs { fragment Outputs fragmentMain(Inputs _in [[stage_in]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) { Outputs _outputStruct; thread Outputs* _out = &_outputStruct; - _out->sk_FragColor.x = float(floatBitsToUint(_in.a)); + _out->sk_FragColor.x = float(as_type(_in.a)); return *_out; } diff --git a/tests/sksl/intrinsics/golden/IntBitsToFloat.metal b/tests/sksl/intrinsics/golden/IntBitsToFloat.metal index 176ad33dea..1d482dddb3 100644 --- a/tests/sksl/intrinsics/golden/IntBitsToFloat.metal +++ b/tests/sksl/intrinsics/golden/IntBitsToFloat.metal @@ -11,6 +11,6 @@ struct Outputs { fragment Outputs fragmentMain(Inputs _in [[stage_in]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) { Outputs _outputStruct; thread Outputs* _out = &_outputStruct; - _out->sk_FragColor.x = intBitsToFloat(_in.a); + _out->sk_FragColor.x = as_type(_in.a); return *_out; } diff --git a/tests/sksl/intrinsics/golden/UintBitsToFloat.metal b/tests/sksl/intrinsics/golden/UintBitsToFloat.metal index 40c89eb9be..47010eba72 100644 --- a/tests/sksl/intrinsics/golden/UintBitsToFloat.metal +++ b/tests/sksl/intrinsics/golden/UintBitsToFloat.metal @@ -11,6 +11,6 @@ struct Outputs { fragment Outputs fragmentMain(Inputs _in [[stage_in]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) { Outputs _outputStruct; thread Outputs* _out = &_outputStruct; - _out->sk_FragColor.x = uintBitsToFloat(_in.a); + _out->sk_FragColor.x = as_type(_in.a); return *_out; }