12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688 |
- /*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "src/sksl/SkSLMetalCodeGenerator.h"
- #include "src/sksl/SkSLCompiler.h"
- #include "src/sksl/ir/SkSLExpressionStatement.h"
- #include "src/sksl/ir/SkSLExtension.h"
- #include "src/sksl/ir/SkSLIndexExpression.h"
- #include "src/sksl/ir/SkSLModifiersDeclaration.h"
- #include "src/sksl/ir/SkSLNop.h"
- #include "src/sksl/ir/SkSLVariableReference.h"
- #ifdef SK_MOLTENVK
- static const uint32_t MVKMagicNum = 0x19960412;
- #endif
- namespace SkSL {
- void MetalCodeGenerator::setupIntrinsics() {
- #define METAL(x) std::make_pair(kMetal_IntrinsicKind, k ## x ## _MetalIntrinsic)
- #define SPECIAL(x) std::make_pair(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic)
- fIntrinsicMap[String("texture")] = SPECIAL(Texture);
- fIntrinsicMap[String("mod")] = SPECIAL(Mod);
- fIntrinsicMap[String("equal")] = METAL(Equal);
- fIntrinsicMap[String("notEqual")] = METAL(NotEqual);
- fIntrinsicMap[String("lessThan")] = METAL(LessThan);
- fIntrinsicMap[String("lessThanEqual")] = METAL(LessThanEqual);
- fIntrinsicMap[String("greaterThan")] = METAL(GreaterThan);
- fIntrinsicMap[String("greaterThanEqual")] = METAL(GreaterThanEqual);
- }
- void MetalCodeGenerator::write(const char* s) {
- if (!s[0]) {
- return;
- }
- if (fAtLineStart) {
- for (int i = 0; i < fIndentation; i++) {
- fOut->writeText(" ");
- }
- }
- fOut->writeText(s);
- fAtLineStart = false;
- }
- void MetalCodeGenerator::writeLine(const char* s) {
- this->write(s);
- fOut->writeText(fLineEnding);
- fAtLineStart = true;
- }
- void MetalCodeGenerator::write(const String& s) {
- this->write(s.c_str());
- }
- void MetalCodeGenerator::writeLine(const String& s) {
- this->writeLine(s.c_str());
- }
- void MetalCodeGenerator::writeLine() {
- this->writeLine("");
- }
- void MetalCodeGenerator::writeExtension(const Extension& ext) {
- this->writeLine("#extension " + ext.fName + " : enable");
- }
- void MetalCodeGenerator::writeType(const Type& type) {
- switch (type.kind()) {
- case Type::kStruct_Kind:
- for (const Type* search : fWrittenStructs) {
- if (*search == type) {
- // already written
- this->write(type.name());
- return;
- }
- }
- fWrittenStructs.push_back(&type);
- this->writeLine("struct " + type.name() + " {");
- fIndentation++;
- this->writeFields(type.fields(), type.fOffset);
- fIndentation--;
- this->write("}");
- break;
- case Type::kVector_Kind:
- this->writeType(type.componentType());
- this->write(to_string(type.columns()));
- break;
- case Type::kMatrix_Kind:
- this->writeType(type.componentType());
- this->write(to_string(type.columns()));
- this->write("x");
- this->write(to_string(type.rows()));
- break;
- case Type::kSampler_Kind:
- this->write("texture2d<float> "); // FIXME - support other texture types;
- break;
- default:
- if (type == *fContext.fHalf_Type) {
- // FIXME - Currently only supporting floats in MSL to avoid type coercion issues.
- this->write(fContext.fFloat_Type->name());
- } else if (type == *fContext.fByte_Type) {
- this->write("char");
- } else if (type == *fContext.fUByte_Type) {
- this->write("uchar");
- } else {
- this->write(type.name());
- }
- }
- }
- void MetalCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
- switch (expr.fKind) {
- case Expression::kBinary_Kind:
- this->writeBinaryExpression((BinaryExpression&) expr, parentPrecedence);
- break;
- case Expression::kBoolLiteral_Kind:
- this->writeBoolLiteral((BoolLiteral&) expr);
- break;
- case Expression::kConstructor_Kind:
- this->writeConstructor((Constructor&) expr, parentPrecedence);
- break;
- case Expression::kIntLiteral_Kind:
- this->writeIntLiteral((IntLiteral&) expr);
- break;
- case Expression::kFieldAccess_Kind:
- this->writeFieldAccess(((FieldAccess&) expr));
- break;
- case Expression::kFloatLiteral_Kind:
- this->writeFloatLiteral(((FloatLiteral&) expr));
- break;
- case Expression::kFunctionCall_Kind:
- this->writeFunctionCall((FunctionCall&) expr);
- break;
- case Expression::kPrefix_Kind:
- this->writePrefixExpression((PrefixExpression&) expr, parentPrecedence);
- break;
- case Expression::kPostfix_Kind:
- this->writePostfixExpression((PostfixExpression&) expr, parentPrecedence);
- break;
- case Expression::kSetting_Kind:
- this->writeSetting((Setting&) expr);
- break;
- case Expression::kSwizzle_Kind:
- this->writeSwizzle((Swizzle&) expr);
- break;
- case Expression::kVariableReference_Kind:
- this->writeVariableReference((VariableReference&) expr);
- break;
- case Expression::kTernary_Kind:
- this->writeTernaryExpression((TernaryExpression&) expr, parentPrecedence);
- break;
- case Expression::kIndex_Kind:
- this->writeIndexExpression((IndexExpression&) expr);
- break;
- default:
- ABORT("unsupported expression: %s", expr.description().c_str());
- }
- }
- void MetalCodeGenerator::writeIntrinsicCall(const FunctionCall& c) {
- auto i = fIntrinsicMap.find(c.fFunction.fName);
- SkASSERT(i != fIntrinsicMap.end());
- Intrinsic intrinsic = i->second;
- int32_t intrinsicId = intrinsic.second;
- switch (intrinsic.first) {
- case kSpecial_IntrinsicKind:
- return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId);
- break;
- case kMetal_IntrinsicKind:
- this->writeExpression(*c.fArguments[0], kSequence_Precedence);
- switch ((MetalIntrinsic) intrinsicId) {
- case kEqual_MetalIntrinsic:
- this->write(" == ");
- break;
- case kNotEqual_MetalIntrinsic:
- this->write(" != ");
- break;
- case kLessThan_MetalIntrinsic:
- this->write(" < ");
- break;
- case kLessThanEqual_MetalIntrinsic:
- this->write(" <= ");
- break;
- case kGreaterThan_MetalIntrinsic:
- this->write(" > ");
- break;
- case kGreaterThanEqual_MetalIntrinsic:
- this->write(" >= ");
- break;
- default:
- ABORT("unsupported metal intrinsic kind");
- }
- this->writeExpression(*c.fArguments[1], kSequence_Precedence);
- break;
- default:
- ABORT("unsupported intrinsic kind");
- }
- }
- void MetalCodeGenerator::writeFunctionCall(const FunctionCall& c) {
- const auto& entry = fIntrinsicMap.find(c.fFunction.fName);
- if (entry != fIntrinsicMap.end()) {
- this->writeIntrinsicCall(c);
- return;
- }
- if (c.fFunction.fBuiltin && "atan" == c.fFunction.fName && 2 == c.fArguments.size()) {
- this->write("atan2");
- } else if (c.fFunction.fBuiltin && "inversesqrt" == c.fFunction.fName) {
- this->write("rsqrt");
- } else if (c.fFunction.fBuiltin && "inverse" == c.fFunction.fName) {
- SkASSERT(c.fArguments.size() == 1);
- this->writeInverseHack(*c.fArguments[0]);
- } else if (c.fFunction.fBuiltin && "dFdx" == c.fFunction.fName) {
- this->write("dfdx");
- } else if (c.fFunction.fBuiltin && "dFdy" == c.fFunction.fName) {
- // Flipping Y also negates the Y derivatives.
- this->write((fProgram.fSettings.fFlipY) ? "-dfdy" : "dfdy");
- } else {
- this->writeName(c.fFunction.fName);
- }
- this->write("(");
- const char* separator = "";
- if (this->requirements(c.fFunction) & kInputs_Requirement) {
- this->write("_in");
- separator = ", ";
- }
- if (this->requirements(c.fFunction) & kOutputs_Requirement) {
- this->write(separator);
- this->write("_out");
- separator = ", ";
- }
- if (this->requirements(c.fFunction) & kUniforms_Requirement) {
- this->write(separator);
- this->write("_uniforms");
- separator = ", ";
- }
- if (this->requirements(c.fFunction) & kGlobals_Requirement) {
- this->write(separator);
- this->write("_globals");
- separator = ", ";
- }
- for (size_t i = 0; i < c.fArguments.size(); ++i) {
- const Expression& arg = *c.fArguments[i];
- this->write(separator);
- separator = ", ";
- if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
- this->write("&");
- }
- this->writeExpression(arg, kSequence_Precedence);
- }
- this->write(")");
- }
- void MetalCodeGenerator::writeInverseHack(const Expression& mat) {
- String typeName = mat.fType.name();
- String name = typeName + "_inverse";
- if (mat.fType == *fContext.fFloat2x2_Type || mat.fType == *fContext.fHalf2x2_Type) {
- if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
- fWrittenIntrinsics.insert(name);
- fExtraFunctions.writeText((
- typeName + " " + name + "(" + typeName + " m) {"
- " return float2x2(m[1][1], -m[0][1], -m[1][0], m[0][0]) * (1/determinant(m));"
- "}"
- ).c_str());
- }
- }
- else if (mat.fType == *fContext.fFloat3x3_Type || mat.fType == *fContext.fHalf3x3_Type) {
- if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
- fWrittenIntrinsics.insert(name);
- fExtraFunctions.writeText((
- typeName + " " + name + "(" + typeName + " m) {"
- " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
- " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
- " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
- " float b01 = a22 * a11 - a12 * a21;"
- " float b11 = -a22 * a10 + a12 * a20;"
- " float b21 = a21 * a10 - a11 * a20;"
- " float det = a00 * b01 + a01 * b11 + a02 * b21;"
- " return " + typeName +
- " (b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),"
- " b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),"
- " b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) * "
- " (1/det);"
- "}"
- ).c_str());
- }
- }
- else if (mat.fType == *fContext.fFloat4x4_Type || mat.fType == *fContext.fHalf4x4_Type) {
- if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
- fWrittenIntrinsics.insert(name);
- fExtraFunctions.writeText((
- typeName + " " + name + "(" + typeName + " m) {"
- " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
- " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
- " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
- " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
- " float b00 = a00 * a11 - a01 * a10;"
- " float b01 = a00 * a12 - a02 * a10;"
- " float b02 = a00 * a13 - a03 * a10;"
- " float b03 = a01 * a12 - a02 * a11;"
- " float b04 = a01 * a13 - a03 * a11;"
- " float b05 = a02 * a13 - a03 * a12;"
- " float b06 = a20 * a31 - a21 * a30;"
- " float b07 = a20 * a32 - a22 * a30;"
- " float b08 = a20 * a33 - a23 * a30;"
- " float b09 = a21 * a32 - a22 * a31;"
- " float b10 = a21 * a33 - a23 * a31;"
- " float b11 = a22 * a33 - a23 * a32;"
- " float det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - "
- " b04 * b07 + b05 * b06;"
- " return " + typeName + "(a11 * b11 - a12 * b10 + a13 * b09,"
- " a02 * b10 - a01 * b11 - a03 * b09,"
- " a31 * b05 - a32 * b04 + a33 * b03,"
- " a22 * b04 - a21 * b05 - a23 * b03,"
- " a12 * b08 - a10 * b11 - a13 * b07,"
- " a00 * b11 - a02 * b08 + a03 * b07,"
- " a32 * b02 - a30 * b05 - a33 * b01,"
- " a20 * b05 - a22 * b02 + a23 * b01,"
- " a10 * b10 - a11 * b08 + a13 * b06,"
- " a01 * b08 - a00 * b10 - a03 * b06,"
- " a30 * b04 - a31 * b02 + a33 * b00,"
- " a21 * b02 - a20 * b04 - a23 * b00,"
- " a11 * b07 - a10 * b09 - a12 * b06,"
- " a00 * b09 - a01 * b07 + a02 * b06,"
- " a31 * b01 - a30 * b03 - a32 * b00,"
- " a20 * b03 - a21 * b01 + a22 * b00) / det;"
- "}"
- ).c_str());
- }
- }
- this->write(name);
- }
- void MetalCodeGenerator::writeSpecialIntrinsic(const FunctionCall & c, SpecialIntrinsic kind) {
- switch (kind) {
- case kTexture_SpecialIntrinsic:
- this->writeExpression(*c.fArguments[0], kSequence_Precedence);
- this->write(".sample(");
- this->writeExpression(*c.fArguments[0], kSequence_Precedence);
- this->write(SAMPLER_SUFFIX);
- this->write(", ");
- this->writeExpression(*c.fArguments[1], kSequence_Precedence);
- if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
- this->write(".xy)"); // FIXME - add projection functionality
- } else {
- SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
- this->write(")");
- }
- break;
- case kMod_SpecialIntrinsic:
- // fmod(x, y) in metal calculates x - y * trunc(x / y) instead of x - y * floor(x / y)
- this->write("((");
- this->writeExpression(*c.fArguments[0], kSequence_Precedence);
- this->write(") - (");
- this->writeExpression(*c.fArguments[1], kSequence_Precedence);
- this->write(") * floor((");
- this->writeExpression(*c.fArguments[0], kSequence_Precedence);
- this->write(") / (");
- this->writeExpression(*c.fArguments[1], kSequence_Precedence);
- this->write(")))");
- break;
- default:
- ABORT("unsupported special intrinsic kind");
- }
- }
- // If it hasn't already been written, writes a constructor for 'matrix' which takes a single value
- // of type 'arg'.
- String MetalCodeGenerator::getMatrixConstructHelper(const Type& matrix, const Type& arg) {
- String key = matrix.name() + arg.name();
- auto found = fHelpers.find(key);
- if (found != fHelpers.end()) {
- return found->second;
- }
- String name;
- int columns = matrix.columns();
- int rows = matrix.rows();
- if (arg.isNumber()) {
- // creating a matrix from a single scalar value
- name = "float" + to_string(columns) + "x" + to_string(rows) + "_from_float";
- fExtraFunctions.printf("float%dx%d %s(float x) {\n",
- columns, rows, name.c_str());
- fExtraFunctions.printf(" return float%dx%d(", columns, rows);
- for (int i = 0; i < columns; ++i) {
- if (i > 0) {
- fExtraFunctions.writeText(", ");
- }
- fExtraFunctions.printf("float%d(", rows);
- for (int j = 0; j < rows; ++j) {
- if (j > 0) {
- fExtraFunctions.writeText(", ");
- }
- if (i == j) {
- fExtraFunctions.writeText("x");
- } else {
- fExtraFunctions.writeText("0");
- }
- }
- fExtraFunctions.writeText(")");
- }
- fExtraFunctions.writeText(");\n}\n");
- } else if (arg.kind() == Type::kMatrix_Kind) {
- // creating a matrix from another matrix
- int argColumns = arg.columns();
- int argRows = arg.rows();
- name = "float" + to_string(columns) + "x" + to_string(rows) + "_from_float" +
- to_string(argColumns) + "x" + to_string(argRows);
- fExtraFunctions.printf("float%dx%d %s(float%dx%d m) {\n",
- columns, rows, name.c_str(), argColumns, argRows);
- fExtraFunctions.printf(" return float%dx%d(", columns, rows);
- for (int i = 0; i < columns; ++i) {
- if (i > 0) {
- fExtraFunctions.writeText(", ");
- }
- fExtraFunctions.printf("float%d(", rows);
- for (int j = 0; j < rows; ++j) {
- if (j > 0) {
- fExtraFunctions.writeText(", ");
- }
- if (i < argColumns && j < argRows) {
- fExtraFunctions.printf("m[%d][%d]", i, j);
- } else {
- fExtraFunctions.writeText("0");
- }
- }
- fExtraFunctions.writeText(")");
- }
- fExtraFunctions.writeText(");\n}\n");
- } else if (matrix.rows() == 2 && matrix.columns() == 2 && arg == *fContext.fFloat4_Type) {
- // float2x2(float4) doesn't work, need to split it into float2x2(float2, float2)
- name = "float2x2_from_float4";
- fExtraFunctions.printf(
- "float2x2 %s(float4 v) {\n"
- " return float2x2(float2(v[0], v[1]), float2(v[2], v[3]));\n"
- "}\n",
- name.c_str()
- );
- } else {
- SkASSERT(false);
- name = "<error>";
- }
- fHelpers[key] = name;
- return name;
- }
- bool MetalCodeGenerator::canCoerce(const Type& t1, const Type& t2) {
- if (t1.columns() != t2.columns() || t1.rows() != t2.rows()) {
- return false;
- }
- if (t1.columns() > 1) {
- return this->canCoerce(t1.componentType(), t2.componentType());
- }
- return t1.isFloat() && t2.isFloat();
- }
- void MetalCodeGenerator::writeConstructor(const Constructor& c, Precedence parentPrecedence) {
- if (c.fArguments.size() == 1 && this->canCoerce(c.fType, c.fArguments[0]->fType)) {
- this->writeExpression(*c.fArguments[0], parentPrecedence);
- return;
- }
- if (c.fType.kind() == Type::kMatrix_Kind && c.fArguments.size() == 1) {
- const Expression& arg = *c.fArguments[0];
- String name = this->getMatrixConstructHelper(c.fType, arg.fType);
- this->write(name);
- this->write("(");
- this->writeExpression(arg, kSequence_Precedence);
- this->write(")");
- } else {
- this->writeType(c.fType);
- this->write("(");
- const char* separator = "";
- int scalarCount = 0;
- for (const auto& arg : c.fArguments) {
- this->write(separator);
- separator = ", ";
- if (Type::kMatrix_Kind == c.fType.kind() && arg->fType.columns() != c.fType.rows()) {
- // merge scalars and smaller vectors together
- if (!scalarCount) {
- this->writeType(c.fType.componentType());
- this->write(to_string(c.fType.rows()));
- this->write("(");
- }
- scalarCount += arg->fType.columns();
- }
- this->writeExpression(*arg, kSequence_Precedence);
- if (scalarCount && scalarCount == c.fType.rows()) {
- this->write(")");
- scalarCount = 0;
- }
- }
- this->write(")");
- }
- }
- void MetalCodeGenerator::writeFragCoord() {
- if (fProgram.fInputs.fRTHeight) {
- this->write("float4(_fragCoord.x, _anonInterface0.u_skRTHeight - _fragCoord.y, 0.0, "
- "_fragCoord.w)");
- } else {
- this->write("float4(_fragCoord.x, _fragCoord.y, 0.0, _fragCoord.w)");
- }
- }
- void MetalCodeGenerator::writeVariableReference(const VariableReference& ref) {
- switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
- case SK_FRAGCOLOR_BUILTIN:
- this->write("_out->sk_FragColor");
- break;
- case SK_FRAGCOORD_BUILTIN:
- this->writeFragCoord();
- break;
- case SK_VERTEXID_BUILTIN:
- this->write("sk_VertexID");
- break;
- case SK_INSTANCEID_BUILTIN:
- this->write("sk_InstanceID");
- break;
- case SK_CLOCKWISE_BUILTIN:
- // We'd set the front facing winding in the MTLRenderCommandEncoder to be counter
- // clockwise to match Skia convention. This is also the default in MoltenVK.
- this->write(fProgram.fSettings.fFlipY ? "_frontFacing" : "(!_frontFacing)");
- break;
- default:
- if (Variable::kGlobal_Storage == ref.fVariable.fStorage) {
- if (ref.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) {
- this->write("_in.");
- } else if (ref.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag) {
- this->write("_out->");
- } else if (ref.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag &&
- ref.fVariable.fType.kind() != Type::kSampler_Kind) {
- this->write("_uniforms.");
- } else {
- this->write("_globals->");
- }
- }
- this->writeName(ref.fVariable.fName);
- }
- }
- void MetalCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
- this->writeExpression(*expr.fBase, kPostfix_Precedence);
- this->write("[");
- this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
- this->write("]");
- }
- void MetalCodeGenerator::writeFieldAccess(const FieldAccess& f) {
- const Type::Field* field = &f.fBase->fType.fields()[f.fFieldIndex];
- if (FieldAccess::kDefault_OwnerKind == f.fOwnerKind) {
- this->writeExpression(*f.fBase, kPostfix_Precedence);
- this->write(".");
- }
- switch (field->fModifiers.fLayout.fBuiltin) {
- case SK_CLIPDISTANCE_BUILTIN:
- this->write("gl_ClipDistance");
- break;
- case SK_POSITION_BUILTIN:
- this->write("_out->sk_Position");
- break;
- default:
- if (field->fName == "sk_PointSize") {
- this->write("_out->sk_PointSize");
- } else {
- if (FieldAccess::kAnonymousInterfaceBlock_OwnerKind == f.fOwnerKind) {
- this->write("_globals->");
- this->write(fInterfaceBlockNameMap[fInterfaceBlockMap[field]]);
- this->write("->");
- }
- this->writeName(field->fName);
- }
- }
- }
- void MetalCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
- int last = swizzle.fComponents.back();
- if (last == SKSL_SWIZZLE_0 || last == SKSL_SWIZZLE_1) {
- this->writeType(swizzle.fType);
- this->write("(");
- }
- this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
- this->write(".");
- for (int c : swizzle.fComponents) {
- if (c >= 0) {
- this->write(&("x\0y\0z\0w\0"[c * 2]));
- }
- }
- if (last == SKSL_SWIZZLE_0) {
- this->write(", 0)");
- }
- else if (last == SKSL_SWIZZLE_1) {
- this->write(", 1)");
- }
- }
- MetalCodeGenerator::Precedence MetalCodeGenerator::GetBinaryPrecedence(Token::Kind op) {
- switch (op) {
- case Token::STAR: // fall through
- case Token::SLASH: // fall through
- case Token::PERCENT: return MetalCodeGenerator::kMultiplicative_Precedence;
- case Token::PLUS: // fall through
- case Token::MINUS: return MetalCodeGenerator::kAdditive_Precedence;
- case Token::SHL: // fall through
- case Token::SHR: return MetalCodeGenerator::kShift_Precedence;
- case Token::LT: // fall through
- case Token::GT: // fall through
- case Token::LTEQ: // fall through
- case Token::GTEQ: return MetalCodeGenerator::kRelational_Precedence;
- case Token::EQEQ: // fall through
- case Token::NEQ: return MetalCodeGenerator::kEquality_Precedence;
- case Token::BITWISEAND: return MetalCodeGenerator::kBitwiseAnd_Precedence;
- case Token::BITWISEXOR: return MetalCodeGenerator::kBitwiseXor_Precedence;
- case Token::BITWISEOR: return MetalCodeGenerator::kBitwiseOr_Precedence;
- case Token::LOGICALAND: return MetalCodeGenerator::kLogicalAnd_Precedence;
- case Token::LOGICALXOR: return MetalCodeGenerator::kLogicalXor_Precedence;
- case Token::LOGICALOR: return MetalCodeGenerator::kLogicalOr_Precedence;
- case Token::EQ: // fall through
- case Token::PLUSEQ: // fall through
- case Token::MINUSEQ: // fall through
- case Token::STAREQ: // fall through
- case Token::SLASHEQ: // fall through
- case Token::PERCENTEQ: // fall through
- case Token::SHLEQ: // fall through
- case Token::SHREQ: // fall through
- case Token::LOGICALANDEQ: // fall through
- case Token::LOGICALXOREQ: // fall through
- case Token::LOGICALOREQ: // fall through
- case Token::BITWISEANDEQ: // fall through
- case Token::BITWISEXOREQ: // fall through
- case Token::BITWISEOREQ: return MetalCodeGenerator::kAssignment_Precedence;
- case Token::COMMA: return MetalCodeGenerator::kSequence_Precedence;
- default: ABORT("unsupported binary operator");
- }
- }
- void MetalCodeGenerator::writeMatrixTimesEqualHelper(const Type& left, const Type& right,
- const Type& result) {
- String key = "TimesEqual" + left.name() + right.name();
- if (fHelpers.find(key) == fHelpers.end()) {
- fExtraFunctions.printf("%s operator*=(thread %s& left, thread const %s& right) {\n"
- " left = left * right;\n"
- " return left;\n"
- "}", result.name().c_str(), left.name().c_str(),
- right.name().c_str());
- }
- }
- void MetalCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
- Precedence parentPrecedence) {
- Precedence precedence = GetBinaryPrecedence(b.fOperator);
- bool needParens = precedence >= parentPrecedence;
- switch (b.fOperator) {
- case Token::EQEQ:
- if (b.fLeft->fType.kind() == Type::kVector_Kind) {
- this->write("all");
- needParens = true;
- }
- break;
- case Token::NEQ:
- if (b.fLeft->fType.kind() == Type::kVector_Kind) {
- this->write("any");
- needParens = true;
- }
- break;
- default:
- break;
- }
- if (needParens) {
- this->write("(");
- }
- if (Compiler::IsAssignment(b.fOperator) &&
- Expression::kVariableReference_Kind == b.fLeft->fKind &&
- Variable::kParameter_Storage == ((VariableReference&) *b.fLeft).fVariable.fStorage &&
- (((VariableReference&) *b.fLeft).fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) {
- // writing to an out parameter. Since we have to turn those into pointers, we have to
- // dereference it here.
- this->write("*");
- }
- if (b.fOperator == Token::STAREQ && b.fLeft->fType.kind() == Type::kMatrix_Kind &&
- b.fRight->fType.kind() == Type::kMatrix_Kind) {
- this->writeMatrixTimesEqualHelper(b.fLeft->fType, b.fRight->fType, b.fType);
- }
- this->writeExpression(*b.fLeft, precedence);
- if (b.fOperator != Token::EQ && Compiler::IsAssignment(b.fOperator) &&
- Expression::kSwizzle_Kind == b.fLeft->fKind && !b.fLeft->hasSideEffects()) {
- // This doesn't compile in Metal:
- // float4 x = float4(1);
- // x.xy *= float2x2(...);
- // with the error message "non-const reference cannot bind to vector element",
- // but switching it to x.xy = x.xy * float2x2(...) fixes it. We perform this tranformation
- // as long as the LHS has no side effects, and hope for the best otherwise.
- this->write(" = ");
- this->writeExpression(*b.fLeft, kAssignment_Precedence);
- this->write(" ");
- String op = Compiler::OperatorName(b.fOperator);
- SkASSERT(op.endsWith("="));
- this->write(op.substr(0, op.size() - 1).c_str());
- this->write(" ");
- } else {
- this->write(String(" ") + Compiler::OperatorName(b.fOperator) + " ");
- }
- this->writeExpression(*b.fRight, precedence);
- if (needParens) {
- this->write(")");
- }
- }
- void MetalCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
- Precedence parentPrecedence) {
- if (kTernary_Precedence >= parentPrecedence) {
- this->write("(");
- }
- this->writeExpression(*t.fTest, kTernary_Precedence);
- this->write(" ? ");
- this->writeExpression(*t.fIfTrue, kTernary_Precedence);
- this->write(" : ");
- this->writeExpression(*t.fIfFalse, kTernary_Precedence);
- if (kTernary_Precedence >= parentPrecedence) {
- this->write(")");
- }
- }
- void MetalCodeGenerator::writePrefixExpression(const PrefixExpression& p,
- Precedence parentPrecedence) {
- if (kPrefix_Precedence >= parentPrecedence) {
- this->write("(");
- }
- this->write(Compiler::OperatorName(p.fOperator));
- this->writeExpression(*p.fOperand, kPrefix_Precedence);
- if (kPrefix_Precedence >= parentPrecedence) {
- this->write(")");
- }
- }
- void MetalCodeGenerator::writePostfixExpression(const PostfixExpression& p,
- Precedence parentPrecedence) {
- if (kPostfix_Precedence >= parentPrecedence) {
- this->write("(");
- }
- this->writeExpression(*p.fOperand, kPostfix_Precedence);
- this->write(Compiler::OperatorName(p.fOperator));
- if (kPostfix_Precedence >= parentPrecedence) {
- this->write(")");
- }
- }
- void MetalCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
- this->write(b.fValue ? "true" : "false");
- }
- void MetalCodeGenerator::writeIntLiteral(const IntLiteral& i) {
- if (i.fType == *fContext.fUInt_Type) {
- this->write(to_string(i.fValue & 0xffffffff) + "u");
- } else {
- this->write(to_string((int32_t) i.fValue));
- }
- }
- void MetalCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
- this->write(to_string(f.fValue));
- }
- void MetalCodeGenerator::writeSetting(const Setting& s) {
- ABORT("internal error; setting was not folded to a constant during compilation\n");
- }
- void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) {
- const char* separator = "";
- if ("main" == f.fDeclaration.fName) {
- switch (fProgram.fKind) {
- case Program::kFragment_Kind:
- #ifdef SK_MOLTENVK
- this->write("fragment Outputs main0");
- #else
- this->write("fragment Outputs fragmentMain");
- #endif
- break;
- case Program::kVertex_Kind:
- #ifdef SK_MOLTENVK
- this->write("vertex Outputs main0");
- #else
- this->write("vertex Outputs vertexMain");
- #endif
- break;
- default:
- SkASSERT(false);
- }
- this->write("(Inputs _in [[stage_in]]");
- if (-1 != fUniformBuffer) {
- this->write(", constant Uniforms& _uniforms [[buffer(" +
- to_string(fUniformBuffer) + ")]]");
- }
- for (const auto& e : fProgram) {
- if (ProgramElement::kVar_Kind == e.fKind) {
- VarDeclarations& decls = (VarDeclarations&) e;
- if (!decls.fVars.size()) {
- continue;
- }
- for (const auto& stmt: decls.fVars) {
- VarDeclaration& var = (VarDeclaration&) *stmt;
- if (var.fVar->fType.kind() == Type::kSampler_Kind) {
- this->write(", texture2d<float> "); // FIXME - support other texture types
- this->writeName(var.fVar->fName);
- this->write("[[texture(");
- this->write(to_string(var.fVar->fModifiers.fLayout.fBinding));
- this->write(")]]");
- this->write(", sampler ");
- this->writeName(var.fVar->fName);
- this->write(SAMPLER_SUFFIX);
- this->write("[[sampler(");
- this->write(to_string(var.fVar->fModifiers.fLayout.fBinding));
- this->write(")]]");
- }
- }
- } else if (ProgramElement::kInterfaceBlock_Kind == e.fKind) {
- InterfaceBlock& intf = (InterfaceBlock&) e;
- if ("sk_PerVertex" == intf.fTypeName) {
- continue;
- }
- this->write(", constant ");
- this->writeType(intf.fVariable.fType);
- this->write("& " );
- this->write(fInterfaceBlockNameMap[&intf]);
- this->write(" [[buffer(");
- #ifdef SK_MOLTENVK
- this->write(to_string(intf.fVariable.fModifiers.fLayout.fSet));
- #else
- this->write(to_string(intf.fVariable.fModifiers.fLayout.fBinding));
- #endif
- this->write(")]]");
- }
- }
- if (fProgram.fKind == Program::kFragment_Kind) {
- if (fProgram.fInputs.fRTHeight && fInterfaceBlockNameMap.empty()) {
- #ifdef SK_MOLTENVK
- this->write(", constant sksl_synthetic_uniforms& _anonInterface0 [[buffer(0)]]");
- #else
- this->write(", constant sksl_synthetic_uniforms& _anonInterface0 [[buffer(1)]]");
- #endif
- }
- this->write(", bool _frontFacing [[front_facing]]");
- this->write(", float4 _fragCoord [[position]]");
- } else if (fProgram.fKind == Program::kVertex_Kind) {
- this->write(", uint sk_VertexID [[vertex_id]], uint sk_InstanceID [[instance_id]]");
- }
- separator = ", ";
- } else {
- this->writeType(f.fDeclaration.fReturnType);
- this->write(" ");
- this->writeName(f.fDeclaration.fName);
- this->write("(");
- if (this->requirements(f.fDeclaration) & kInputs_Requirement) {
- this->write("Inputs _in");
- separator = ", ";
- }
- if (this->requirements(f.fDeclaration) & kOutputs_Requirement) {
- this->write(separator);
- this->write("thread Outputs* _out");
- separator = ", ";
- }
- if (this->requirements(f.fDeclaration) & kUniforms_Requirement) {
- this->write(separator);
- this->write("Uniforms _uniforms");
- separator = ", ";
- }
- if (this->requirements(f.fDeclaration) & kGlobals_Requirement) {
- this->write(separator);
- this->write("thread Globals* _globals");
- separator = ", ";
- }
- }
- for (const auto& param : f.fDeclaration.fParameters) {
- this->write(separator);
- separator = ", ";
- this->writeModifiers(param->fModifiers, false);
- std::vector<int> sizes;
- const Type* type = ¶m->fType;
- while (Type::kArray_Kind == type->kind()) {
- sizes.push_back(type->columns());
- type = &type->componentType();
- }
- this->writeType(*type);
- if (param->fModifiers.fFlags & Modifiers::kOut_Flag) {
- this->write("*");
- }
- this->write(" ");
- this->writeName(param->fName);
- for (int s : sizes) {
- if (s <= 0) {
- this->write("[]");
- } else {
- this->write("[" + to_string(s) + "]");
- }
- }
- }
- this->writeLine(") {");
- SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
- if ("main" == f.fDeclaration.fName) {
- if (fNeedsGlobalStructInit) {
- this->writeLine(" Globals globalStruct;");
- this->writeLine(" thread Globals* _globals = &globalStruct;");
- for (const auto& intf: fInterfaceBlockNameMap) {
- const auto& intfName = intf.second;
- this->write(" _globals->");
- this->writeName(intfName);
- this->write(" = &");
- this->writeName(intfName);
- this->write(";\n");
- }
- for (const auto& var: fInitNonConstGlobalVars) {
- this->write(" _globals->");
- this->writeName(var->fVar->fName);
- this->write(" = ");
- this->writeVarInitializer(*var->fVar, *var->fValue);
- this->writeLine(";");
- }
- for (const auto& texture: fTextures) {
- this->write(" _globals->");
- this->writeName(texture->fName);
- this->write(" = ");
- this->writeName(texture->fName);
- this->write(";\n");
- this->write(" _globals->");
- this->writeName(texture->fName);
- this->write(SAMPLER_SUFFIX);
- this->write(" = ");
- this->writeName(texture->fName);
- this->write(SAMPLER_SUFFIX);
- this->write(";\n");
- }
- }
- this->writeLine(" Outputs _outputStruct;");
- this->writeLine(" thread Outputs* _out = &_outputStruct;");
- }
- fFunctionHeader = "";
- OutputStream* oldOut = fOut;
- StringStream buffer;
- fOut = &buffer;
- fIndentation++;
- this->writeStatements(((Block&) *f.fBody).fStatements);
- if ("main" == f.fDeclaration.fName) {
- switch (fProgram.fKind) {
- case Program::kFragment_Kind:
- this->writeLine("return *_out;");
- break;
- case Program::kVertex_Kind:
- this->writeLine("_out->sk_Position.y = -_out->sk_Position.y;");
- this->writeLine("return *_out;"); // FIXME - detect if function already has return
- break;
- default:
- SkASSERT(false);
- }
- }
- fIndentation--;
- this->writeLine("}");
- fOut = oldOut;
- this->write(fFunctionHeader);
- this->write(buffer.str());
- }
- void MetalCodeGenerator::writeModifiers(const Modifiers& modifiers,
- bool globalContext) {
- if (modifiers.fFlags & Modifiers::kOut_Flag) {
- this->write("thread ");
- }
- if (modifiers.fFlags & Modifiers::kConst_Flag) {
- this->write("constant ");
- }
- }
- void MetalCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
- if ("sk_PerVertex" == intf.fTypeName) {
- return;
- }
- this->writeModifiers(intf.fVariable.fModifiers, true);
- this->write("struct ");
- this->writeLine(intf.fTypeName + " {");
- const Type* structType = &intf.fVariable.fType;
- fWrittenStructs.push_back(structType);
- while (Type::kArray_Kind == structType->kind()) {
- structType = &structType->componentType();
- }
- fIndentation++;
- writeFields(structType->fields(), structType->fOffset, &intf);
- if (fProgram.fInputs.fRTHeight) {
- this->writeLine("float u_skRTHeight;");
- }
- fIndentation--;
- this->write("}");
- if (intf.fInstanceName.size()) {
- this->write(" ");
- this->write(intf.fInstanceName);
- for (const auto& size : intf.fSizes) {
- this->write("[");
- if (size) {
- this->writeExpression(*size, kTopLevel_Precedence);
- }
- this->write("]");
- }
- fInterfaceBlockNameMap[&intf] = intf.fInstanceName;
- } else {
- fInterfaceBlockNameMap[&intf] = "_anonInterface" + to_string(fAnonInterfaceCount++);
- }
- this->writeLine(";");
- }
- void MetalCodeGenerator::writeFields(const std::vector<Type::Field>& fields, int parentOffset,
- const InterfaceBlock* parentIntf) {
- #ifdef SK_MOLTENVK
- MemoryLayout memoryLayout(MemoryLayout::k140_Standard);
- #else
- MemoryLayout memoryLayout(MemoryLayout::kMetal_Standard);
- #endif
- int currentOffset = 0;
- for (const auto& field: fields) {
- int fieldOffset = field.fModifiers.fLayout.fOffset;
- const Type* fieldType = field.fType;
- if (fieldOffset != -1) {
- if (currentOffset > fieldOffset) {
- fErrors.error(parentOffset,
- "offset of field '" + field.fName + "' must be at least " +
- to_string((int) currentOffset));
- } else if (currentOffset < fieldOffset) {
- this->write("char pad");
- this->write(to_string(fPaddingCount++));
- this->write("[");
- this->write(to_string(fieldOffset - currentOffset));
- this->writeLine("];");
- currentOffset = fieldOffset;
- }
- int alignment = memoryLayout.alignment(*fieldType);
- if (fieldOffset % alignment) {
- fErrors.error(parentOffset,
- "offset of field '" + field.fName + "' must be a multiple of " +
- to_string((int) alignment));
- }
- }
- #ifdef SK_MOLTENVK
- if (fieldType->kind() == Type::kVector_Kind &&
- fieldType->columns() == 3) {
- SkASSERT(memoryLayout.size(*fieldType) == 3);
- // Pack all vec3 types so that their size in bytes will match what was expected in the
- // original SkSL code since MSL has vec3 sizes equal to 4 * component type, while SkSL
- // has vec3 equal to 3 * component type.
- // FIXME - Packed vectors can't be accessed by swizzles, but can be indexed into. A
- // combination of this being a problem which only occurs when using MoltenVK and the
- // fact that we haven't swizzled a vec3 yet means that this problem hasn't been
- // addressed.
- this->write(PACKED_PREFIX);
- }
- #endif
- currentOffset += memoryLayout.size(*fieldType);
- std::vector<int> sizes;
- while (fieldType->kind() == Type::kArray_Kind) {
- sizes.push_back(fieldType->columns());
- fieldType = &fieldType->componentType();
- }
- this->writeModifiers(field.fModifiers, false);
- this->writeType(*fieldType);
- this->write(" ");
- this->writeName(field.fName);
- for (int s : sizes) {
- if (s <= 0) {
- this->write("[]");
- } else {
- this->write("[" + to_string(s) + "]");
- }
- }
- this->writeLine(";");
- if (parentIntf) {
- fInterfaceBlockMap[&field] = parentIntf;
- }
- }
- }
- void MetalCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
- this->writeExpression(value, kTopLevel_Precedence);
- }
- void MetalCodeGenerator::writeName(const String& name) {
- if (fReservedWords.find(name) != fReservedWords.end()) {
- this->write("_"); // adding underscore before name to avoid conflict with reserved words
- }
- this->write(name);
- }
- void MetalCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
- SkASSERT(decl.fVars.size() > 0);
- bool wroteType = false;
- for (const auto& stmt : decl.fVars) {
- VarDeclaration& var = (VarDeclaration&) *stmt;
- if (global && !(var.fVar->fModifiers.fFlags & Modifiers::kConst_Flag)) {
- continue;
- }
- if (wroteType) {
- this->write(", ");
- } else {
- this->writeModifiers(var.fVar->fModifiers, global);
- this->writeType(decl.fBaseType);
- this->write(" ");
- wroteType = true;
- }
- this->writeName(var.fVar->fName);
- for (const auto& size : var.fSizes) {
- this->write("[");
- if (size) {
- this->writeExpression(*size, kTopLevel_Precedence);
- }
- this->write("]");
- }
- if (var.fValue) {
- this->write(" = ");
- this->writeVarInitializer(*var.fVar, *var.fValue);
- }
- }
- if (wroteType) {
- this->write(";");
- }
- }
- void MetalCodeGenerator::writeStatement(const Statement& s) {
- switch (s.fKind) {
- case Statement::kBlock_Kind:
- this->writeBlock((Block&) s);
- break;
- case Statement::kExpression_Kind:
- this->writeExpression(*((ExpressionStatement&) s).fExpression, kTopLevel_Precedence);
- this->write(";");
- break;
- case Statement::kReturn_Kind:
- this->writeReturnStatement((ReturnStatement&) s);
- break;
- case Statement::kVarDeclarations_Kind:
- this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
- break;
- case Statement::kIf_Kind:
- this->writeIfStatement((IfStatement&) s);
- break;
- case Statement::kFor_Kind:
- this->writeForStatement((ForStatement&) s);
- break;
- case Statement::kWhile_Kind:
- this->writeWhileStatement((WhileStatement&) s);
- break;
- case Statement::kDo_Kind:
- this->writeDoStatement((DoStatement&) s);
- break;
- case Statement::kSwitch_Kind:
- this->writeSwitchStatement((SwitchStatement&) s);
- break;
- case Statement::kBreak_Kind:
- this->write("break;");
- break;
- case Statement::kContinue_Kind:
- this->write("continue;");
- break;
- case Statement::kDiscard_Kind:
- this->write("discard_fragment();");
- break;
- case Statement::kNop_Kind:
- this->write(";");
- break;
- default:
- ABORT("unsupported statement: %s", s.description().c_str());
- }
- }
- void MetalCodeGenerator::writeStatements(const std::vector<std::unique_ptr<Statement>>& statements) {
- for (const auto& s : statements) {
- if (!s->isEmpty()) {
- this->writeStatement(*s);
- this->writeLine();
- }
- }
- }
- void MetalCodeGenerator::writeBlock(const Block& b) {
- this->writeLine("{");
- fIndentation++;
- this->writeStatements(b.fStatements);
- fIndentation--;
- this->write("}");
- }
- void MetalCodeGenerator::writeIfStatement(const IfStatement& stmt) {
- this->write("if (");
- this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
- this->write(") ");
- this->writeStatement(*stmt.fIfTrue);
- if (stmt.fIfFalse) {
- this->write(" else ");
- this->writeStatement(*stmt.fIfFalse);
- }
- }
- void MetalCodeGenerator::writeForStatement(const ForStatement& f) {
- this->write("for (");
- if (f.fInitializer && !f.fInitializer->isEmpty()) {
- this->writeStatement(*f.fInitializer);
- } else {
- this->write("; ");
- }
- if (f.fTest) {
- this->writeExpression(*f.fTest, kTopLevel_Precedence);
- }
- this->write("; ");
- if (f.fNext) {
- this->writeExpression(*f.fNext, kTopLevel_Precedence);
- }
- this->write(") ");
- this->writeStatement(*f.fStatement);
- }
- void MetalCodeGenerator::writeWhileStatement(const WhileStatement& w) {
- this->write("while (");
- this->writeExpression(*w.fTest, kTopLevel_Precedence);
- this->write(") ");
- this->writeStatement(*w.fStatement);
- }
- void MetalCodeGenerator::writeDoStatement(const DoStatement& d) {
- this->write("do ");
- this->writeStatement(*d.fStatement);
- this->write(" while (");
- this->writeExpression(*d.fTest, kTopLevel_Precedence);
- this->write(");");
- }
- void MetalCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
- this->write("switch (");
- this->writeExpression(*s.fValue, kTopLevel_Precedence);
- this->writeLine(") {");
- fIndentation++;
- for (const auto& c : s.fCases) {
- if (c->fValue) {
- this->write("case ");
- this->writeExpression(*c->fValue, kTopLevel_Precedence);
- this->writeLine(":");
- } else {
- this->writeLine("default:");
- }
- fIndentation++;
- for (const auto& stmt : c->fStatements) {
- this->writeStatement(*stmt);
- this->writeLine();
- }
- fIndentation--;
- }
- fIndentation--;
- this->write("}");
- }
- void MetalCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
- this->write("return");
- if (r.fExpression) {
- this->write(" ");
- this->writeExpression(*r.fExpression, kTopLevel_Precedence);
- }
- this->write(";");
- }
- void MetalCodeGenerator::writeHeader() {
- this->write("#include <metal_stdlib>\n");
- this->write("#include <simd/simd.h>\n");
- this->write("using namespace metal;\n");
- }
- void MetalCodeGenerator::writeUniformStruct() {
- for (const auto& e : fProgram) {
- if (ProgramElement::kVar_Kind == e.fKind) {
- VarDeclarations& decls = (VarDeclarations&) e;
- if (!decls.fVars.size()) {
- continue;
- }
- const Variable& first = *((VarDeclaration&) *decls.fVars[0]).fVar;
- if (first.fModifiers.fFlags & Modifiers::kUniform_Flag &&
- first.fType.kind() != Type::kSampler_Kind) {
- if (-1 == fUniformBuffer) {
- this->write("struct Uniforms {\n");
- fUniformBuffer = first.fModifiers.fLayout.fSet;
- if (-1 == fUniformBuffer) {
- fErrors.error(decls.fOffset, "Metal uniforms must have 'layout(set=...)'");
- }
- } else if (first.fModifiers.fLayout.fSet != fUniformBuffer) {
- if (-1 == fUniformBuffer) {
- fErrors.error(decls.fOffset, "Metal backend requires all uniforms to have "
- "the same 'layout(set=...)'");
- }
- }
- this->write(" ");
- this->writeType(first.fType);
- this->write(" ");
- for (const auto& stmt : decls.fVars) {
- VarDeclaration& var = (VarDeclaration&) *stmt;
- this->writeName(var.fVar->fName);
- }
- this->write(";\n");
- }
- }
- }
- if (-1 != fUniformBuffer) {
- this->write("};\n");
- }
- }
- void MetalCodeGenerator::writeInputStruct() {
- this->write("struct Inputs {\n");
- for (const auto& e : fProgram) {
- if (ProgramElement::kVar_Kind == e.fKind) {
- VarDeclarations& decls = (VarDeclarations&) e;
- if (!decls.fVars.size()) {
- continue;
- }
- const Variable& first = *((VarDeclaration&) *decls.fVars[0]).fVar;
- if (first.fModifiers.fFlags & Modifiers::kIn_Flag &&
- -1 == first.fModifiers.fLayout.fBuiltin) {
- this->write(" ");
- this->writeType(first.fType);
- this->write(" ");
- for (const auto& stmt : decls.fVars) {
- VarDeclaration& var = (VarDeclaration&) *stmt;
- this->writeName(var.fVar->fName);
- if (-1 != var.fVar->fModifiers.fLayout.fLocation) {
- if (fProgram.fKind == Program::kVertex_Kind) {
- this->write(" [[attribute(" +
- to_string(var.fVar->fModifiers.fLayout.fLocation) + ")]]");
- } else if (fProgram.fKind == Program::kFragment_Kind) {
- this->write(" [[user(locn" +
- to_string(var.fVar->fModifiers.fLayout.fLocation) + ")]]");
- }
- }
- }
- this->write(";\n");
- }
- }
- }
- this->write("};\n");
- }
- void MetalCodeGenerator::writeOutputStruct() {
- this->write("struct Outputs {\n");
- if (fProgram.fKind == Program::kVertex_Kind) {
- this->write(" float4 sk_Position [[position]];\n");
- } else if (fProgram.fKind == Program::kFragment_Kind) {
- this->write(" float4 sk_FragColor [[color(0)]];\n");
- }
- for (const auto& e : fProgram) {
- if (ProgramElement::kVar_Kind == e.fKind) {
- VarDeclarations& decls = (VarDeclarations&) e;
- if (!decls.fVars.size()) {
- continue;
- }
- const Variable& first = *((VarDeclaration&) *decls.fVars[0]).fVar;
- if (first.fModifiers.fFlags & Modifiers::kOut_Flag &&
- -1 == first.fModifiers.fLayout.fBuiltin) {
- this->write(" ");
- this->writeType(first.fType);
- this->write(" ");
- for (const auto& stmt : decls.fVars) {
- VarDeclaration& var = (VarDeclaration&) *stmt;
- this->writeName(var.fVar->fName);
- if (fProgram.fKind == Program::kVertex_Kind) {
- this->write(" [[user(locn" +
- to_string(var.fVar->fModifiers.fLayout.fLocation) + ")]]");
- } else if (fProgram.fKind == Program::kFragment_Kind) {
- this->write(" [[color(" +
- to_string(var.fVar->fModifiers.fLayout.fLocation) +")");
- int colorIndex = var.fVar->fModifiers.fLayout.fIndex;
- if (colorIndex) {
- this->write(", index(" + to_string(colorIndex) + ")");
- }
- this->write("]]");
- }
- }
- this->write(";\n");
- }
- }
- }
- if (fProgram.fKind == Program::kVertex_Kind) {
- this->write(" float sk_PointSize;\n");
- }
- this->write("};\n");
- }
- void MetalCodeGenerator::writeInterfaceBlocks() {
- bool wroteInterfaceBlock = false;
- for (const auto& e : fProgram) {
- if (ProgramElement::kInterfaceBlock_Kind == e.fKind) {
- this->writeInterfaceBlock((InterfaceBlock&) e);
- wroteInterfaceBlock = true;
- }
- }
- if (!wroteInterfaceBlock && fProgram.fInputs.fRTHeight) {
- this->writeLine("struct sksl_synthetic_uniforms {");
- this->writeLine(" float u_skRTHeight;");
- this->writeLine("};");
- }
- }
- void MetalCodeGenerator::writeGlobalStruct() {
- bool wroteStructDecl = false;
- for (const auto& intf : fInterfaceBlockNameMap) {
- if (!wroteStructDecl) {
- this->write("struct Globals {\n");
- wroteStructDecl = true;
- }
- fNeedsGlobalStructInit = true;
- const auto& intfType = intf.first;
- const auto& intfName = intf.second;
- this->write(" constant ");
- this->write(intfType->fTypeName);
- this->write("* ");
- this->writeName(intfName);
- this->write(";\n");
- }
- for (const auto& e : fProgram) {
- if (ProgramElement::kVar_Kind == e.fKind) {
- VarDeclarations& decls = (VarDeclarations&) e;
- if (!decls.fVars.size()) {
- continue;
- }
- const Variable& first = *((VarDeclaration&) *decls.fVars[0]).fVar;
- if ((!first.fModifiers.fFlags && -1 == first.fModifiers.fLayout.fBuiltin) ||
- first.fType.kind() == Type::kSampler_Kind) {
- if (!wroteStructDecl) {
- this->write("struct Globals {\n");
- wroteStructDecl = true;
- }
- fNeedsGlobalStructInit = true;
- this->write(" ");
- this->writeType(first.fType);
- this->write(" ");
- for (const auto& stmt : decls.fVars) {
- VarDeclaration& var = (VarDeclaration&) *stmt;
- this->writeName(var.fVar->fName);
- if (var.fVar->fType.kind() == Type::kSampler_Kind) {
- fTextures.push_back(var.fVar);
- this->write(";\n");
- this->write(" sampler ");
- this->writeName(var.fVar->fName);
- this->write(SAMPLER_SUFFIX);
- }
- if (var.fValue) {
- fInitNonConstGlobalVars.push_back(&var);
- }
- }
- this->write(";\n");
- }
- }
- }
- if (wroteStructDecl) {
- this->write("};\n");
- }
- }
- void MetalCodeGenerator::writeProgramElement(const ProgramElement& e) {
- switch (e.fKind) {
- case ProgramElement::kExtension_Kind:
- break;
- case ProgramElement::kVar_Kind: {
- VarDeclarations& decl = (VarDeclarations&) e;
- if (decl.fVars.size() > 0) {
- int builtin = ((VarDeclaration&) *decl.fVars[0]).fVar->fModifiers.fLayout.fBuiltin;
- if (-1 == builtin) {
- // normal var
- this->writeVarDeclarations(decl, true);
- this->writeLine();
- } else if (SK_FRAGCOLOR_BUILTIN == builtin) {
- // ignore
- }
- }
- break;
- }
- case ProgramElement::kInterfaceBlock_Kind:
- // handled in writeInterfaceBlocks, do nothing
- break;
- case ProgramElement::kFunction_Kind:
- this->writeFunction((FunctionDefinition&) e);
- break;
- case ProgramElement::kModifiers_Kind:
- this->writeModifiers(((ModifiersDeclaration&) e).fModifiers, true);
- this->writeLine(";");
- break;
- default:
- printf("%s\n", e.description().c_str());
- ABORT("unsupported program element");
- }
- }
- MetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const Expression& e) {
- switch (e.fKind) {
- case Expression::kFunctionCall_Kind: {
- const FunctionCall& f = (const FunctionCall&) e;
- Requirements result = this->requirements(f.fFunction);
- for (const auto& e : f.fArguments) {
- result |= this->requirements(*e);
- }
- return result;
- }
- case Expression::kConstructor_Kind: {
- const Constructor& c = (const Constructor&) e;
- Requirements result = kNo_Requirements;
- for (const auto& e : c.fArguments) {
- result |= this->requirements(*e);
- }
- return result;
- }
- case Expression::kFieldAccess_Kind: {
- const FieldAccess& f = (const FieldAccess&) e;
- if (FieldAccess::kAnonymousInterfaceBlock_OwnerKind == f.fOwnerKind) {
- return kGlobals_Requirement;
- }
- return this->requirements(*((const FieldAccess&) e).fBase);
- }
- case Expression::kSwizzle_Kind:
- return this->requirements(*((const Swizzle&) e).fBase);
- case Expression::kBinary_Kind: {
- const BinaryExpression& b = (const BinaryExpression&) e;
- return this->requirements(*b.fLeft) | this->requirements(*b.fRight);
- }
- case Expression::kIndex_Kind: {
- const IndexExpression& idx = (const IndexExpression&) e;
- return this->requirements(*idx.fBase) | this->requirements(*idx.fIndex);
- }
- case Expression::kPrefix_Kind:
- return this->requirements(*((const PrefixExpression&) e).fOperand);
- case Expression::kPostfix_Kind:
- return this->requirements(*((const PostfixExpression&) e).fOperand);
- case Expression::kTernary_Kind: {
- const TernaryExpression& t = (const TernaryExpression&) e;
- return this->requirements(*t.fTest) | this->requirements(*t.fIfTrue) |
- this->requirements(*t.fIfFalse);
- }
- case Expression::kVariableReference_Kind: {
- const VariableReference& v = (const VariableReference&) e;
- Requirements result = kNo_Requirements;
- if (v.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN) {
- result = kInputs_Requirement;
- } else if (Variable::kGlobal_Storage == v.fVariable.fStorage) {
- if (v.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) {
- result = kInputs_Requirement;
- } else if (v.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag) {
- result = kOutputs_Requirement;
- } else if (v.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag &&
- v.fVariable.fType.kind() != Type::kSampler_Kind) {
- result = kUniforms_Requirement;
- } else {
- result = kGlobals_Requirement;
- }
- }
- return result;
- }
- default:
- return kNo_Requirements;
- }
- }
- MetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const Statement& s) {
- switch (s.fKind) {
- case Statement::kBlock_Kind: {
- Requirements result = kNo_Requirements;
- for (const auto& child : ((const Block&) s).fStatements) {
- result |= this->requirements(*child);
- }
- return result;
- }
- case Statement::kVarDeclaration_Kind: {
- Requirements result = kNo_Requirements;
- const VarDeclaration& var = (const VarDeclaration&) s;
- if (var.fValue) {
- result = this->requirements(*var.fValue);
- }
- return result;
- }
- case Statement::kVarDeclarations_Kind: {
- Requirements result = kNo_Requirements;
- const VarDeclarations& decls = *((const VarDeclarationsStatement&) s).fDeclaration;
- for (const auto& stmt : decls.fVars) {
- result |= this->requirements(*stmt);
- }
- return result;
- }
- case Statement::kExpression_Kind:
- return this->requirements(*((const ExpressionStatement&) s).fExpression);
- case Statement::kReturn_Kind: {
- const ReturnStatement& r = (const ReturnStatement&) s;
- if (r.fExpression) {
- return this->requirements(*r.fExpression);
- }
- return kNo_Requirements;
- }
- case Statement::kIf_Kind: {
- const IfStatement& i = (const IfStatement&) s;
- return this->requirements(*i.fTest) |
- this->requirements(*i.fIfTrue) |
- (i.fIfFalse && this->requirements(*i.fIfFalse));
- }
- case Statement::kFor_Kind: {
- const ForStatement& f = (const ForStatement&) s;
- return this->requirements(*f.fInitializer) |
- this->requirements(*f.fTest) |
- this->requirements(*f.fNext) |
- this->requirements(*f.fStatement);
- }
- case Statement::kWhile_Kind: {
- const WhileStatement& w = (const WhileStatement&) s;
- return this->requirements(*w.fTest) |
- this->requirements(*w.fStatement);
- }
- case Statement::kDo_Kind: {
- const DoStatement& d = (const DoStatement&) s;
- return this->requirements(*d.fTest) |
- this->requirements(*d.fStatement);
- }
- case Statement::kSwitch_Kind: {
- const SwitchStatement& sw = (const SwitchStatement&) s;
- Requirements result = this->requirements(*sw.fValue);
- for (const auto& c : sw.fCases) {
- for (const auto& st : c->fStatements) {
- result |= this->requirements(*st);
- }
- }
- return result;
- }
- default:
- return kNo_Requirements;
- }
- }
- MetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const FunctionDeclaration& f) {
- if (f.fBuiltin) {
- return kNo_Requirements;
- }
- auto found = fRequirements.find(&f);
- if (found == fRequirements.end()) {
- fRequirements[&f] = kNo_Requirements;
- for (const auto& e : fProgram) {
- if (ProgramElement::kFunction_Kind == e.fKind) {
- const FunctionDefinition& def = (const FunctionDefinition&) e;
- if (&def.fDeclaration == &f) {
- Requirements reqs = this->requirements(*def.fBody);
- fRequirements[&f] = reqs;
- return reqs;
- }
- }
- }
- }
- return found->second;
- }
- bool MetalCodeGenerator::generateCode() {
- OutputStream* rawOut = fOut;
- fOut = &fHeader;
- #ifdef SK_MOLTENVK
- fOut->write((const char*) &MVKMagicNum, sizeof(MVKMagicNum));
- #endif
- fProgramKind = fProgram.fKind;
- this->writeHeader();
- this->writeUniformStruct();
- this->writeInputStruct();
- this->writeOutputStruct();
- this->writeInterfaceBlocks();
- this->writeGlobalStruct();
- StringStream body;
- fOut = &body;
- for (const auto& e : fProgram) {
- this->writeProgramElement(e);
- }
- fOut = rawOut;
- write_stringstream(fHeader, *rawOut);
- write_stringstream(fExtraFunctions, *rawOut);
- write_stringstream(body, *rawOut);
- #ifdef SK_MOLTENVK
- this->write("\0");
- #endif
- return true;
- }
- }
|