From 86424eb0cfb217107dc5f9b0246adcd0e5058e09 Mon Sep 17 00:00:00 2001 From: John Stiles Date: Fri, 11 Dec 2020 11:17:14 -0500 Subject: [PATCH] Add Metal support for the `findLSB` intrinsic. Change-Id: Id38a3d04fcb1904a4c666d92087b4fe14bd03a27 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/343110 Commit-Queue: John Stiles Reviewed-by: Brian Osman Auto-Submit: John Stiles --- src/sksl/SkSLMetalCodeGenerator.cpp | 40 ++++++++++++++++--- src/sksl/SkSLMetalCodeGenerator.h | 3 ++ tests/sksl/intrinsics/golden/FindLSB.metal | 6 ++- tests/sksl/intrinsics/golden/Mod.metal | 5 ++- .../sksl/shared/golden/RectangleTexture.metal | 4 +- tests/sksl/shared/golden/Texture2D.metal | 4 +- 6 files changed, 48 insertions(+), 14 deletions(-) diff --git a/src/sksl/SkSLMetalCodeGenerator.cpp b/src/sksl/SkSLMetalCodeGenerator.cpp index d3f8ea1384..d27272b0a8 100644 --- a/src/sksl/SkSLMetalCodeGenerator.cpp +++ b/src/sksl/SkSLMetalCodeGenerator.cpp @@ -49,6 +49,7 @@ void MetalCodeGenerator::setupIntrinsics() { fIntrinsicMap[String("distance")] = SPECIAL(Distance); fIntrinsicMap[String("dot")] = SPECIAL(Dot); fIntrinsicMap[String("faceforward")] = SPECIAL(Faceforward); + fIntrinsicMap[String("findLSB")] = SPECIAL(FindLSB); fIntrinsicMap[String("length")] = SPECIAL(Length); fIntrinsicMap[String("mod")] = SPECIAL(Mod); fIntrinsicMap[String("normalize")] = SPECIAL(Normalize); @@ -550,6 +551,12 @@ String MetalCodeGenerator::getInverseHack(const Expression& mat) { return name; } +String MetalCodeGenerator::getTempVariable(const Type& type) { + String tempVar = "_skTemp" + to_string(fVarCount++); + this->fFunctionHeader += " " + this->typeName(type) + " " + tempVar + ";\n"; + return tempVar; +} + void MetalCodeGenerator::writeSpecialIntrinsic(const FunctionCall & c, SpecialIntrinsic kind) { const ExpressionArray& arguments = c.arguments(); switch (kind) { @@ -562,8 +569,7 @@ void MetalCodeGenerator::writeSpecialIntrinsic(const FunctionCall & c, SpecialIn const Type& arg1Type = arguments[1]->type(); if (arg1Type == *fContext.fFloat3_Type) { // have to store the vector in a temp variable to avoid double evaluating it - String tmpVar = "tmpCoord" + to_string(fVarCount++); - this->fFunctionHeader += " " + this->typeName(arg1Type) + " " + tmpVar + ";\n"; + String tmpVar = this->getTempVariable(arg1Type); this->write("(" + tmpVar + " = "); this->writeExpression(*arguments[1], kSequence_Precedence); this->write(", " + tmpVar + ".xy / " + tmpVar + ".z))"); @@ -576,10 +582,8 @@ void MetalCodeGenerator::writeSpecialIntrinsic(const FunctionCall & c, SpecialIn } case kMod_SpecialIntrinsic: { // fmod(x, y) in metal calculates x - y * trunc(x / y) instead of x - y * floor(x / y) - String tmpX = "tmpX" + to_string(fVarCount++); - String tmpY = "tmpY" + to_string(fVarCount++); - this->fFunctionHeader += " " + this->typeName(arguments[0]->type()) + - " " + tmpX + ", " + tmpY + ";\n"; + String tmpX = this->getTempVariable(arguments[0]->type()); + String tmpY = this->getTempVariable(arguments[0]->type()); this->write("(" + tmpX + " = "); this->writeExpression(*arguments[0], kSequence_Precedence); this->write(", " + tmpY + " = "); @@ -672,6 +676,30 @@ void MetalCodeGenerator::writeSpecialIntrinsic(const FunctionCall & c, SpecialIn this->write(") * 0.0174532925)"); break; } + case kFindLSB_SpecialIntrinsic: { + // Create a temp variable to store the expression, to avoid double-evaluating it. + String skTemp = this->getTempVariable(arguments[0]->type()); + String exprType = this->typeName(arguments[0]->type()); + + // ctz returns numbits(type) on zero inputs; GLSL documents it as generating -1 instead. + // Use select to detect zero inputs and force a -1 result. + + // (_skTemp1 = (.....), select(ctz(_skTemp1), int4(-1), _skTemp1 == int4(0))) + this->write("("); + this->write(skTemp); + this->write(" = ("); + this->writeExpression(*arguments[0], kSequence_Precedence); + this->write("), select(ctz("); + this->write(skTemp); + this->write("), "); + this->write(exprType); + this->write("(-1), "); + this->write(skTemp); + this->write(" == "); + this->write(exprType); + this->write("(0)))"); + break; + } default: ABORT("unsupported special intrinsic kind"); } diff --git a/src/sksl/SkSLMetalCodeGenerator.h b/src/sksl/SkSLMetalCodeGenerator.h index 6b600f1da8..635ddc3c54 100644 --- a/src/sksl/SkSLMetalCodeGenerator.h +++ b/src/sksl/SkSLMetalCodeGenerator.h @@ -109,6 +109,7 @@ protected: kDistance_SpecialIntrinsic, kDot_SpecialIntrinsic, kFaceforward_SpecialIntrinsic, + kFindLSB_SpecialIntrinsic, kLength_SpecialIntrinsic, kMod_SpecialIntrinsic, kNormalize_SpecialIntrinsic, @@ -221,6 +222,8 @@ protected: String getBitcastIntrinsic(const Type& outType); + String getTempVariable(const Type& varType); + void writeFunctionCall(const FunctionCall& c); bool matrixConstructHelperIsNeeded(const Constructor& c); diff --git a/tests/sksl/intrinsics/golden/FindLSB.metal b/tests/sksl/intrinsics/golden/FindLSB.metal index d8799565cd..b750032651 100644 --- a/tests/sksl/intrinsics/golden/FindLSB.metal +++ b/tests/sksl/intrinsics/golden/FindLSB.metal @@ -13,7 +13,9 @@ 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(findLSB(_in.a)); - _out->sk_FragColor.y = float(findLSB(int(_in.b))); + int _skTemp0; + int _skTemp1; + _out->sk_FragColor.x = float((_skTemp0 = (_in.a), select(ctz(_skTemp0), int(-1), _skTemp0 == int(0)))); + _out->sk_FragColor.y = float((_skTemp1 = (int(_in.b)), select(ctz(_skTemp1), int(-1), _skTemp1 == int(0)))); return *_out; } diff --git a/tests/sksl/intrinsics/golden/Mod.metal b/tests/sksl/intrinsics/golden/Mod.metal index af7a3e1cb2..a1f716c016 100644 --- a/tests/sksl/intrinsics/golden/Mod.metal +++ b/tests/sksl/intrinsics/golden/Mod.metal @@ -13,7 +13,8 @@ struct Outputs { fragment Outputs fragmentMain(Inputs _in [[stage_in]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) { Outputs _outputStruct; thread Outputs* _out = &_outputStruct; - float tmpX0, tmpY1; - _out->sk_FragColor.x = (tmpX0 = _in.a, tmpY1 = _in.b, tmpX0 - tmpY1 * floor(tmpX0 / tmpY1)); + float _skTemp0; + float _skTemp1; + _out->sk_FragColor.x = (_skTemp0 = _in.a, _skTemp1 = _in.b, _skTemp0 - _skTemp1 * floor(_skTemp0 / _skTemp1)); return *_out; } diff --git a/tests/sksl/shared/golden/RectangleTexture.metal b/tests/sksl/shared/golden/RectangleTexture.metal index abd156a25e..fce9c13eef 100644 --- a/tests/sksl/shared/golden/RectangleTexture.metal +++ b/tests/sksl/shared/golden/RectangleTexture.metal @@ -20,9 +20,9 @@ fragment Outputs fragmentMain(Inputs _in [[stage_in]], texture2d test2D[[ (void)_globals; Outputs _outputStruct; thread Outputs* _out = &_outputStruct; - float3 tmpCoord0; + float3 _skTemp0; _out->sk_FragColor = _globals->test2D.sample(_globals->test2DSmplr, float2(0.5)); _out->sk_FragColor = _globals->test2DRect.sample(_globals->test2DRectSmplr, float2(0.5)); - _out->sk_FragColor = _globals->test2DRect.sample(_globals->test2DRectSmplr, (tmpCoord0 = float3(0.5), tmpCoord0.xy / tmpCoord0.z)); + _out->sk_FragColor = _globals->test2DRect.sample(_globals->test2DRectSmplr, (_skTemp0 = float3(0.5), _skTemp0.xy / _skTemp0.z)); return *_out; } diff --git a/tests/sksl/shared/golden/Texture2D.metal b/tests/sksl/shared/golden/Texture2D.metal index 91b00ec287..2c38f2660d 100644 --- a/tests/sksl/shared/golden/Texture2D.metal +++ b/tests/sksl/shared/golden/Texture2D.metal @@ -17,9 +17,9 @@ fragment Outputs fragmentMain(Inputs _in [[stage_in]], texture2d tex[[tex (void)_globals; Outputs _outputStruct; thread Outputs* _out = &_outputStruct; - float3 tmpCoord0; + float3 _skTemp0; float4 a = _globals->tex.sample(_globals->texSmplr, float2(0.0)); - float4 b = _globals->tex.sample(_globals->texSmplr, (tmpCoord0 = float3(0.0), tmpCoord0.xy / tmpCoord0.z)); + float4 b = _globals->tex.sample(_globals->texSmplr, (_skTemp0 = float3(0.0), _skTemp0.xy / _skTemp0.z)); _out->sk_FragColor = float4(a.xy, b.zw); return *_out; }