Add Metal support for the findLSB intrinsic.

Change-Id: Id38a3d04fcb1904a4c666d92087b4fe14bd03a27
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/343110
Commit-Queue: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
This commit is contained in:
John Stiles 2020-12-11 11:17:14 -05:00 committed by Skia Commit-Bot
parent 6ecee7f0f5
commit 86424eb0cf
6 changed files with 48 additions and 14 deletions

View File

@ -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");
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -20,9 +20,9 @@ fragment Outputs fragmentMain(Inputs _in [[stage_in]], texture2d<float> 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;
}

View File

@ -17,9 +17,9 @@ fragment Outputs fragmentMain(Inputs _in [[stage_in]], texture2d<float> 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;
}