1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2016 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/sksl/codegen/SkSLMetalCodeGenerator.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "src/core/SkScopeExit.h" 11cb93a386Sopenharmony_ci#include "src/sksl/SkSLCompiler.h" 12cb93a386Sopenharmony_ci#include "src/sksl/SkSLMemoryLayout.h" 13cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLBinaryExpression.h" 14cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLBlock.h" 15cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLConstructorArray.h" 16cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLConstructorArrayCast.h" 17cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLConstructorCompound.h" 18cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLConstructorCompoundCast.h" 19cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h" 20cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLConstructorMatrixResize.h" 21cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLConstructorSplat.h" 22cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLConstructorStruct.h" 23cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLDoStatement.h" 24cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLExpressionStatement.h" 25cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLExtension.h" 26cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLFieldAccess.h" 27cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLForStatement.h" 28cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLFunctionCall.h" 29cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLFunctionDeclaration.h" 30cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLFunctionDefinition.h" 31cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLFunctionPrototype.h" 32cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLIfStatement.h" 33cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLIndexExpression.h" 34cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLInterfaceBlock.h" 35cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLModifiersDeclaration.h" 36cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLNop.h" 37cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLPostfixExpression.h" 38cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLPrefixExpression.h" 39cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLReturnStatement.h" 40cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLSetting.h" 41cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLStructDefinition.h" 42cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLSwitchStatement.h" 43cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLSwizzle.h" 44cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLVarDeclarations.h" 45cb93a386Sopenharmony_ci#include "src/sksl/ir/SkSLVariableReference.h" 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci#include <algorithm> 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_cinamespace SkSL { 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_ciconst char* MetalCodeGenerator::OperatorName(Operator op) { 52cb93a386Sopenharmony_ci switch (op.kind()) { 53cb93a386Sopenharmony_ci case Token::Kind::TK_LOGICALXOR: return "!="; 54cb93a386Sopenharmony_ci default: return op.operatorName(); 55cb93a386Sopenharmony_ci } 56cb93a386Sopenharmony_ci} 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_ciclass MetalCodeGenerator::GlobalStructVisitor { 59cb93a386Sopenharmony_cipublic: 60cb93a386Sopenharmony_ci virtual ~GlobalStructVisitor() = default; 61cb93a386Sopenharmony_ci virtual void visitInterfaceBlock(const InterfaceBlock& block, skstd::string_view blockName) = 0; 62cb93a386Sopenharmony_ci virtual void visitTexture(const Type& type, skstd::string_view name) = 0; 63cb93a386Sopenharmony_ci virtual void visitSampler(const Type& type, skstd::string_view name) = 0; 64cb93a386Sopenharmony_ci virtual void visitVariable(const Variable& var, const Expression* value) = 0; 65cb93a386Sopenharmony_ci}; 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_civoid MetalCodeGenerator::write(skstd::string_view s) { 68cb93a386Sopenharmony_ci if (s.empty()) { 69cb93a386Sopenharmony_ci return; 70cb93a386Sopenharmony_ci } 71cb93a386Sopenharmony_ci if (fAtLineStart) { 72cb93a386Sopenharmony_ci for (int i = 0; i < fIndentation; i++) { 73cb93a386Sopenharmony_ci fOut->writeText(" "); 74cb93a386Sopenharmony_ci } 75cb93a386Sopenharmony_ci } 76cb93a386Sopenharmony_ci fOut->writeText(String(s).c_str()); 77cb93a386Sopenharmony_ci fAtLineStart = false; 78cb93a386Sopenharmony_ci} 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_civoid MetalCodeGenerator::writeLine(skstd::string_view s) { 81cb93a386Sopenharmony_ci this->write(s); 82cb93a386Sopenharmony_ci fOut->writeText(fLineEnding); 83cb93a386Sopenharmony_ci fAtLineStart = true; 84cb93a386Sopenharmony_ci} 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_civoid MetalCodeGenerator::finishLine() { 87cb93a386Sopenharmony_ci if (!fAtLineStart) { 88cb93a386Sopenharmony_ci this->writeLine(); 89cb93a386Sopenharmony_ci } 90cb93a386Sopenharmony_ci} 91cb93a386Sopenharmony_ci 92cb93a386Sopenharmony_civoid MetalCodeGenerator::writeExtension(const Extension& ext) { 93cb93a386Sopenharmony_ci this->writeLine("#extension " + ext.name() + " : enable"); 94cb93a386Sopenharmony_ci} 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ciString MetalCodeGenerator::typeName(const Type& type) { 97cb93a386Sopenharmony_ci switch (type.typeKind()) { 98cb93a386Sopenharmony_ci case Type::TypeKind::kArray: 99cb93a386Sopenharmony_ci SkASSERTF(type.columns() > 0, "invalid array size: %s", type.description().c_str()); 100cb93a386Sopenharmony_ci return String::printf("array<%s, %d>", 101cb93a386Sopenharmony_ci this->typeName(type.componentType()).c_str(), type.columns()); 102cb93a386Sopenharmony_ci 103cb93a386Sopenharmony_ci case Type::TypeKind::kVector: 104cb93a386Sopenharmony_ci return this->typeName(type.componentType()) + to_string(type.columns()); 105cb93a386Sopenharmony_ci 106cb93a386Sopenharmony_ci case Type::TypeKind::kMatrix: 107cb93a386Sopenharmony_ci return this->typeName(type.componentType()) + to_string(type.columns()) + "x" + 108cb93a386Sopenharmony_ci to_string(type.rows()); 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_ci case Type::TypeKind::kSampler: 111cb93a386Sopenharmony_ci return "texture2d<half>"; // FIXME - support other texture types 112cb93a386Sopenharmony_ci 113cb93a386Sopenharmony_ci default: 114cb93a386Sopenharmony_ci return String(type.name()); 115cb93a386Sopenharmony_ci } 116cb93a386Sopenharmony_ci} 117cb93a386Sopenharmony_ci 118cb93a386Sopenharmony_civoid MetalCodeGenerator::writeStructDefinition(const StructDefinition& s) { 119cb93a386Sopenharmony_ci const Type& type = s.type(); 120cb93a386Sopenharmony_ci this->writeLine("struct " + type.name() + " {"); 121cb93a386Sopenharmony_ci fIndentation++; 122cb93a386Sopenharmony_ci this->writeFields(type.fields(), type.fLine); 123cb93a386Sopenharmony_ci fIndentation--; 124cb93a386Sopenharmony_ci this->writeLine("};"); 125cb93a386Sopenharmony_ci} 126cb93a386Sopenharmony_ci 127cb93a386Sopenharmony_civoid MetalCodeGenerator::writeType(const Type& type) { 128cb93a386Sopenharmony_ci this->write(this->typeName(type)); 129cb93a386Sopenharmony_ci} 130cb93a386Sopenharmony_ci 131cb93a386Sopenharmony_civoid MetalCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) { 132cb93a386Sopenharmony_ci switch (expr.kind()) { 133cb93a386Sopenharmony_ci case Expression::Kind::kBinary: 134cb93a386Sopenharmony_ci this->writeBinaryExpression(expr.as<BinaryExpression>(), parentPrecedence); 135cb93a386Sopenharmony_ci break; 136cb93a386Sopenharmony_ci case Expression::Kind::kConstructorArray: 137cb93a386Sopenharmony_ci case Expression::Kind::kConstructorStruct: 138cb93a386Sopenharmony_ci this->writeAnyConstructor(expr.asAnyConstructor(), "{", "}", parentPrecedence); 139cb93a386Sopenharmony_ci break; 140cb93a386Sopenharmony_ci case Expression::Kind::kConstructorArrayCast: 141cb93a386Sopenharmony_ci this->writeConstructorArrayCast(expr.as<ConstructorArrayCast>(), parentPrecedence); 142cb93a386Sopenharmony_ci break; 143cb93a386Sopenharmony_ci case Expression::Kind::kConstructorCompound: 144cb93a386Sopenharmony_ci this->writeConstructorCompound(expr.as<ConstructorCompound>(), parentPrecedence); 145cb93a386Sopenharmony_ci break; 146cb93a386Sopenharmony_ci case Expression::Kind::kConstructorDiagonalMatrix: 147cb93a386Sopenharmony_ci case Expression::Kind::kConstructorSplat: 148cb93a386Sopenharmony_ci this->writeAnyConstructor(expr.asAnyConstructor(), "(", ")", parentPrecedence); 149cb93a386Sopenharmony_ci break; 150cb93a386Sopenharmony_ci case Expression::Kind::kConstructorMatrixResize: 151cb93a386Sopenharmony_ci this->writeConstructorMatrixResize(expr.as<ConstructorMatrixResize>(), 152cb93a386Sopenharmony_ci parentPrecedence); 153cb93a386Sopenharmony_ci break; 154cb93a386Sopenharmony_ci case Expression::Kind::kConstructorScalarCast: 155cb93a386Sopenharmony_ci case Expression::Kind::kConstructorCompoundCast: 156cb93a386Sopenharmony_ci this->writeCastConstructor(expr.asAnyConstructor(), "(", ")", parentPrecedence); 157cb93a386Sopenharmony_ci break; 158cb93a386Sopenharmony_ci case Expression::Kind::kFieldAccess: 159cb93a386Sopenharmony_ci this->writeFieldAccess(expr.as<FieldAccess>()); 160cb93a386Sopenharmony_ci break; 161cb93a386Sopenharmony_ci case Expression::Kind::kLiteral: 162cb93a386Sopenharmony_ci this->writeLiteral(expr.as<Literal>()); 163cb93a386Sopenharmony_ci break; 164cb93a386Sopenharmony_ci case Expression::Kind::kFunctionCall: 165cb93a386Sopenharmony_ci this->writeFunctionCall(expr.as<FunctionCall>()); 166cb93a386Sopenharmony_ci break; 167cb93a386Sopenharmony_ci case Expression::Kind::kPrefix: 168cb93a386Sopenharmony_ci this->writePrefixExpression(expr.as<PrefixExpression>(), parentPrecedence); 169cb93a386Sopenharmony_ci break; 170cb93a386Sopenharmony_ci case Expression::Kind::kPostfix: 171cb93a386Sopenharmony_ci this->writePostfixExpression(expr.as<PostfixExpression>(), parentPrecedence); 172cb93a386Sopenharmony_ci break; 173cb93a386Sopenharmony_ci case Expression::Kind::kSetting: 174cb93a386Sopenharmony_ci this->writeSetting(expr.as<Setting>()); 175cb93a386Sopenharmony_ci break; 176cb93a386Sopenharmony_ci case Expression::Kind::kSwizzle: 177cb93a386Sopenharmony_ci this->writeSwizzle(expr.as<Swizzle>()); 178cb93a386Sopenharmony_ci break; 179cb93a386Sopenharmony_ci case Expression::Kind::kVariableReference: 180cb93a386Sopenharmony_ci this->writeVariableReference(expr.as<VariableReference>()); 181cb93a386Sopenharmony_ci break; 182cb93a386Sopenharmony_ci case Expression::Kind::kTernary: 183cb93a386Sopenharmony_ci this->writeTernaryExpression(expr.as<TernaryExpression>(), parentPrecedence); 184cb93a386Sopenharmony_ci break; 185cb93a386Sopenharmony_ci case Expression::Kind::kIndex: 186cb93a386Sopenharmony_ci this->writeIndexExpression(expr.as<IndexExpression>()); 187cb93a386Sopenharmony_ci break; 188cb93a386Sopenharmony_ci default: 189cb93a386Sopenharmony_ci SkDEBUGFAILF("unsupported expression: %s", expr.description().c_str()); 190cb93a386Sopenharmony_ci break; 191cb93a386Sopenharmony_ci } 192cb93a386Sopenharmony_ci} 193cb93a386Sopenharmony_ci 194cb93a386Sopenharmony_ciString MetalCodeGenerator::getOutParamHelper(const FunctionCall& call, 195cb93a386Sopenharmony_ci const ExpressionArray& arguments, 196cb93a386Sopenharmony_ci const SkTArray<VariableReference*>& outVars) { 197cb93a386Sopenharmony_ci AutoOutputStream outputToExtraFunctions(this, &fExtraFunctions, &fIndentation); 198cb93a386Sopenharmony_ci const FunctionDeclaration& function = call.function(); 199cb93a386Sopenharmony_ci 200cb93a386Sopenharmony_ci String name = "_skOutParamHelper" + to_string(fSwizzleHelperCount++) + 201cb93a386Sopenharmony_ci "_" + function.mangledName(); 202cb93a386Sopenharmony_ci const char* separator = ""; 203cb93a386Sopenharmony_ci 204cb93a386Sopenharmony_ci // Emit a prototype for the function we'll be calling through to in our helper. 205cb93a386Sopenharmony_ci if (!function.isBuiltin()) { 206cb93a386Sopenharmony_ci this->writeFunctionDeclaration(function); 207cb93a386Sopenharmony_ci this->writeLine(";"); 208cb93a386Sopenharmony_ci } 209cb93a386Sopenharmony_ci 210cb93a386Sopenharmony_ci // Synthesize a helper function that takes the same inputs as `function`, except in places where 211cb93a386Sopenharmony_ci // `outVars` is non-null; in those places, we take the type of the VariableReference. 212cb93a386Sopenharmony_ci // 213cb93a386Sopenharmony_ci // float _skOutParamHelper0_originalFuncName(float _var0, float _var1, float& outParam) { 214cb93a386Sopenharmony_ci this->writeType(call.type()); 215cb93a386Sopenharmony_ci this->write(" "); 216cb93a386Sopenharmony_ci this->write(name); 217cb93a386Sopenharmony_ci this->write("("); 218cb93a386Sopenharmony_ci this->writeFunctionRequirementParams(function, separator); 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_ci SkASSERT(outVars.size() == arguments.size()); 221cb93a386Sopenharmony_ci SkASSERT(outVars.size() == function.parameters().size()); 222cb93a386Sopenharmony_ci 223cb93a386Sopenharmony_ci // We need to detect cases where the caller passes the same variable as an out-param more than 224cb93a386Sopenharmony_ci // once, and avoid reusing the variable name. (In those cases we can actually just ignore the 225cb93a386Sopenharmony_ci // redundant input parameter entirely, and not give it any name.) 226cb93a386Sopenharmony_ci std::unordered_set<const Variable*> writtenVars; 227cb93a386Sopenharmony_ci 228cb93a386Sopenharmony_ci for (int index = 0; index < arguments.count(); ++index) { 229cb93a386Sopenharmony_ci this->write(separator); 230cb93a386Sopenharmony_ci separator = ", "; 231cb93a386Sopenharmony_ci 232cb93a386Sopenharmony_ci const Variable* param = function.parameters()[index]; 233cb93a386Sopenharmony_ci this->writeModifiers(param->modifiers()); 234cb93a386Sopenharmony_ci 235cb93a386Sopenharmony_ci const Type* type = outVars[index] ? &outVars[index]->type() : &arguments[index]->type(); 236cb93a386Sopenharmony_ci this->writeType(*type); 237cb93a386Sopenharmony_ci 238cb93a386Sopenharmony_ci if (param->modifiers().fFlags & Modifiers::kOut_Flag) { 239cb93a386Sopenharmony_ci this->write("&"); 240cb93a386Sopenharmony_ci } 241cb93a386Sopenharmony_ci if (outVars[index]) { 242cb93a386Sopenharmony_ci auto [iter, didInsert] = writtenVars.insert(outVars[index]->variable()); 243cb93a386Sopenharmony_ci if (didInsert) { 244cb93a386Sopenharmony_ci this->write(" "); 245cb93a386Sopenharmony_ci fIgnoreVariableReferenceModifiers = true; 246cb93a386Sopenharmony_ci this->writeVariableReference(*outVars[index]); 247cb93a386Sopenharmony_ci fIgnoreVariableReferenceModifiers = false; 248cb93a386Sopenharmony_ci } 249cb93a386Sopenharmony_ci } else { 250cb93a386Sopenharmony_ci this->write(" _var"); 251cb93a386Sopenharmony_ci this->write(to_string(index)); 252cb93a386Sopenharmony_ci } 253cb93a386Sopenharmony_ci } 254cb93a386Sopenharmony_ci this->writeLine(") {"); 255cb93a386Sopenharmony_ci 256cb93a386Sopenharmony_ci ++fIndentation; 257cb93a386Sopenharmony_ci for (int index = 0; index < outVars.count(); ++index) { 258cb93a386Sopenharmony_ci if (!outVars[index]) { 259cb93a386Sopenharmony_ci continue; 260cb93a386Sopenharmony_ci } 261cb93a386Sopenharmony_ci // float3 _var2[ = outParam.zyx]; 262cb93a386Sopenharmony_ci this->writeType(arguments[index]->type()); 263cb93a386Sopenharmony_ci this->write(" _var"); 264cb93a386Sopenharmony_ci this->write(to_string(index)); 265cb93a386Sopenharmony_ci 266cb93a386Sopenharmony_ci const Variable* param = function.parameters()[index]; 267cb93a386Sopenharmony_ci if (param->modifiers().fFlags & Modifiers::kIn_Flag) { 268cb93a386Sopenharmony_ci this->write(" = "); 269cb93a386Sopenharmony_ci fIgnoreVariableReferenceModifiers = true; 270cb93a386Sopenharmony_ci this->writeExpression(*arguments[index], Precedence::kAssignment); 271cb93a386Sopenharmony_ci fIgnoreVariableReferenceModifiers = false; 272cb93a386Sopenharmony_ci } 273cb93a386Sopenharmony_ci 274cb93a386Sopenharmony_ci this->writeLine(";"); 275cb93a386Sopenharmony_ci } 276cb93a386Sopenharmony_ci 277cb93a386Sopenharmony_ci // [int _skResult = ] myFunction(inputs, outputs, _globals, _var0, _var1, _var2, _var3); 278cb93a386Sopenharmony_ci bool hasResult = (call.type().name() != "void"); 279cb93a386Sopenharmony_ci if (hasResult) { 280cb93a386Sopenharmony_ci this->writeType(call.type()); 281cb93a386Sopenharmony_ci this->write(" _skResult = "); 282cb93a386Sopenharmony_ci } 283cb93a386Sopenharmony_ci 284cb93a386Sopenharmony_ci this->writeName(function.mangledName()); 285cb93a386Sopenharmony_ci this->write("("); 286cb93a386Sopenharmony_ci separator = ""; 287cb93a386Sopenharmony_ci this->writeFunctionRequirementArgs(function, separator); 288cb93a386Sopenharmony_ci 289cb93a386Sopenharmony_ci for (int index = 0; index < arguments.count(); ++index) { 290cb93a386Sopenharmony_ci this->write(separator); 291cb93a386Sopenharmony_ci separator = ", "; 292cb93a386Sopenharmony_ci 293cb93a386Sopenharmony_ci this->write("_var"); 294cb93a386Sopenharmony_ci this->write(to_string(index)); 295cb93a386Sopenharmony_ci } 296cb93a386Sopenharmony_ci this->writeLine(");"); 297cb93a386Sopenharmony_ci 298cb93a386Sopenharmony_ci for (int index = 0; index < outVars.count(); ++index) { 299cb93a386Sopenharmony_ci if (!outVars[index]) { 300cb93a386Sopenharmony_ci continue; 301cb93a386Sopenharmony_ci } 302cb93a386Sopenharmony_ci // outParam.zyx = _var2; 303cb93a386Sopenharmony_ci fIgnoreVariableReferenceModifiers = true; 304cb93a386Sopenharmony_ci this->writeExpression(*arguments[index], Precedence::kAssignment); 305cb93a386Sopenharmony_ci fIgnoreVariableReferenceModifiers = false; 306cb93a386Sopenharmony_ci this->write(" = _var"); 307cb93a386Sopenharmony_ci this->write(to_string(index)); 308cb93a386Sopenharmony_ci this->writeLine(";"); 309cb93a386Sopenharmony_ci } 310cb93a386Sopenharmony_ci 311cb93a386Sopenharmony_ci if (hasResult) { 312cb93a386Sopenharmony_ci this->writeLine("return _skResult;"); 313cb93a386Sopenharmony_ci } 314cb93a386Sopenharmony_ci 315cb93a386Sopenharmony_ci --fIndentation; 316cb93a386Sopenharmony_ci this->writeLine("}"); 317cb93a386Sopenharmony_ci 318cb93a386Sopenharmony_ci return name; 319cb93a386Sopenharmony_ci} 320cb93a386Sopenharmony_ci 321cb93a386Sopenharmony_ciString MetalCodeGenerator::getBitcastIntrinsic(const Type& outType) { 322cb93a386Sopenharmony_ci return "as_type<" + outType.displayName() + ">"; 323cb93a386Sopenharmony_ci} 324cb93a386Sopenharmony_ci 325cb93a386Sopenharmony_civoid MetalCodeGenerator::writeFunctionCall(const FunctionCall& c) { 326cb93a386Sopenharmony_ci const FunctionDeclaration& function = c.function(); 327cb93a386Sopenharmony_ci 328cb93a386Sopenharmony_ci // Many intrinsics need to be rewritten in Metal. 329cb93a386Sopenharmony_ci if (function.isIntrinsic()) { 330cb93a386Sopenharmony_ci if (this->writeIntrinsicCall(c, function.intrinsicKind())) { 331cb93a386Sopenharmony_ci return; 332cb93a386Sopenharmony_ci } 333cb93a386Sopenharmony_ci } 334cb93a386Sopenharmony_ci 335cb93a386Sopenharmony_ci // Determine whether or not we need to emulate GLSL's out-param semantics for Metal using a 336cb93a386Sopenharmony_ci // helper function. (Specifically, out-parameters in GLSL are only written back to the original 337cb93a386Sopenharmony_ci // variable at the end of the function call; also, swizzles are supported, whereas Metal doesn't 338cb93a386Sopenharmony_ci // allow a swizzle to be passed to a `floatN&`.) 339cb93a386Sopenharmony_ci const ExpressionArray& arguments = c.arguments(); 340cb93a386Sopenharmony_ci const std::vector<const Variable*>& parameters = function.parameters(); 341cb93a386Sopenharmony_ci SkASSERT(arguments.size() == parameters.size()); 342cb93a386Sopenharmony_ci 343cb93a386Sopenharmony_ci bool foundOutParam = false; 344cb93a386Sopenharmony_ci SkSTArray<16, VariableReference*> outVars; 345cb93a386Sopenharmony_ci outVars.push_back_n(arguments.count(), (VariableReference*)nullptr); 346cb93a386Sopenharmony_ci 347cb93a386Sopenharmony_ci for (int index = 0; index < arguments.count(); ++index) { 348cb93a386Sopenharmony_ci // If this is an out parameter... 349cb93a386Sopenharmony_ci if (parameters[index]->modifiers().fFlags & Modifiers::kOut_Flag) { 350cb93a386Sopenharmony_ci // Find the expression's inner variable being written to. 351cb93a386Sopenharmony_ci Analysis::AssignmentInfo info; 352cb93a386Sopenharmony_ci // Assignability was verified at IRGeneration time, so this should always succeed. 353cb93a386Sopenharmony_ci SkAssertResult(Analysis::IsAssignable(*arguments[index], &info)); 354cb93a386Sopenharmony_ci outVars[index] = info.fAssignedVar; 355cb93a386Sopenharmony_ci foundOutParam = true; 356cb93a386Sopenharmony_ci } 357cb93a386Sopenharmony_ci } 358cb93a386Sopenharmony_ci 359cb93a386Sopenharmony_ci if (foundOutParam) { 360cb93a386Sopenharmony_ci // Out parameters need to be written back to at the end of the function. To do this, we 361cb93a386Sopenharmony_ci // synthesize a helper function which evaluates the out-param expression into a temporary 362cb93a386Sopenharmony_ci // variable, calls the original function, then writes the temp var back into the out param 363cb93a386Sopenharmony_ci // using the original out-param expression. (This lets us support things like swizzles and 364cb93a386Sopenharmony_ci // array indices.) 365cb93a386Sopenharmony_ci this->write(getOutParamHelper(c, arguments, outVars)); 366cb93a386Sopenharmony_ci } else { 367cb93a386Sopenharmony_ci this->write(function.mangledName()); 368cb93a386Sopenharmony_ci } 369cb93a386Sopenharmony_ci 370cb93a386Sopenharmony_ci this->write("("); 371cb93a386Sopenharmony_ci const char* separator = ""; 372cb93a386Sopenharmony_ci this->writeFunctionRequirementArgs(function, separator); 373cb93a386Sopenharmony_ci for (int i = 0; i < arguments.count(); ++i) { 374cb93a386Sopenharmony_ci this->write(separator); 375cb93a386Sopenharmony_ci separator = ", "; 376cb93a386Sopenharmony_ci 377cb93a386Sopenharmony_ci if (outVars[i]) { 378cb93a386Sopenharmony_ci this->writeExpression(*outVars[i], Precedence::kSequence); 379cb93a386Sopenharmony_ci } else { 380cb93a386Sopenharmony_ci this->writeExpression(*arguments[i], Precedence::kSequence); 381cb93a386Sopenharmony_ci } 382cb93a386Sopenharmony_ci } 383cb93a386Sopenharmony_ci this->write(")"); 384cb93a386Sopenharmony_ci} 385cb93a386Sopenharmony_ci 386cb93a386Sopenharmony_cistatic constexpr char kInverse2x2[] = R"( 387cb93a386Sopenharmony_citemplate <typename T> 388cb93a386Sopenharmony_cimatrix<T, 2, 2> mat2_inverse(matrix<T, 2, 2> m) { 389cb93a386Sopenharmony_ci return matrix<T, 2, 2>(m[1][1], -m[0][1], -m[1][0], m[0][0]) * (1/determinant(m)); 390cb93a386Sopenharmony_ci} 391cb93a386Sopenharmony_ci)"; 392cb93a386Sopenharmony_ci 393cb93a386Sopenharmony_cistatic constexpr char kInverse3x3[] = R"( 394cb93a386Sopenharmony_citemplate <typename T> 395cb93a386Sopenharmony_cimatrix<T, 3, 3> mat3_inverse(matrix<T, 3, 3> m) { 396cb93a386Sopenharmony_ci T a00 = m[0][0], a01 = m[0][1], a02 = m[0][2]; 397cb93a386Sopenharmony_ci T a10 = m[1][0], a11 = m[1][1], a12 = m[1][2]; 398cb93a386Sopenharmony_ci T a20 = m[2][0], a21 = m[2][1], a22 = m[2][2]; 399cb93a386Sopenharmony_ci T b01 = a22*a11 - a12*a21; 400cb93a386Sopenharmony_ci T b11 = -a22*a10 + a12*a20; 401cb93a386Sopenharmony_ci T b21 = a21*a10 - a11*a20; 402cb93a386Sopenharmony_ci T det = a00*b01 + a01*b11 + a02*b21; 403cb93a386Sopenharmony_ci return matrix<T, 3, 3>(b01, (-a22*a01 + a02*a21), ( a12*a01 - a02*a11), 404cb93a386Sopenharmony_ci b11, ( a22*a00 - a02*a20), (-a12*a00 + a02*a10), 405cb93a386Sopenharmony_ci b21, (-a21*a00 + a01*a20), ( a11*a00 - a01*a10)) * (1/det); 406cb93a386Sopenharmony_ci} 407cb93a386Sopenharmony_ci)"; 408cb93a386Sopenharmony_ci 409cb93a386Sopenharmony_cistatic constexpr char kInverse4x4[] = R"( 410cb93a386Sopenharmony_citemplate <typename T> 411cb93a386Sopenharmony_cimatrix<T, 4, 4> mat4_inverse(matrix<T, 4, 4> m) { 412cb93a386Sopenharmony_ci T a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3]; 413cb93a386Sopenharmony_ci T a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3]; 414cb93a386Sopenharmony_ci T a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3]; 415cb93a386Sopenharmony_ci T a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3]; 416cb93a386Sopenharmony_ci T b00 = a00*a11 - a01*a10; 417cb93a386Sopenharmony_ci T b01 = a00*a12 - a02*a10; 418cb93a386Sopenharmony_ci T b02 = a00*a13 - a03*a10; 419cb93a386Sopenharmony_ci T b03 = a01*a12 - a02*a11; 420cb93a386Sopenharmony_ci T b04 = a01*a13 - a03*a11; 421cb93a386Sopenharmony_ci T b05 = a02*a13 - a03*a12; 422cb93a386Sopenharmony_ci T b06 = a20*a31 - a21*a30; 423cb93a386Sopenharmony_ci T b07 = a20*a32 - a22*a30; 424cb93a386Sopenharmony_ci T b08 = a20*a33 - a23*a30; 425cb93a386Sopenharmony_ci T b09 = a21*a32 - a22*a31; 426cb93a386Sopenharmony_ci T b10 = a21*a33 - a23*a31; 427cb93a386Sopenharmony_ci T b11 = a22*a33 - a23*a32; 428cb93a386Sopenharmony_ci T det = b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06; 429cb93a386Sopenharmony_ci return matrix<T, 4, 4>(a11*b11 - a12*b10 + a13*b09, 430cb93a386Sopenharmony_ci a02*b10 - a01*b11 - a03*b09, 431cb93a386Sopenharmony_ci a31*b05 - a32*b04 + a33*b03, 432cb93a386Sopenharmony_ci a22*b04 - a21*b05 - a23*b03, 433cb93a386Sopenharmony_ci a12*b08 - a10*b11 - a13*b07, 434cb93a386Sopenharmony_ci a00*b11 - a02*b08 + a03*b07, 435cb93a386Sopenharmony_ci a32*b02 - a30*b05 - a33*b01, 436cb93a386Sopenharmony_ci a20*b05 - a22*b02 + a23*b01, 437cb93a386Sopenharmony_ci a10*b10 - a11*b08 + a13*b06, 438cb93a386Sopenharmony_ci a01*b08 - a00*b10 - a03*b06, 439cb93a386Sopenharmony_ci a30*b04 - a31*b02 + a33*b00, 440cb93a386Sopenharmony_ci a21*b02 - a20*b04 - a23*b00, 441cb93a386Sopenharmony_ci a11*b07 - a10*b09 - a12*b06, 442cb93a386Sopenharmony_ci a00*b09 - a01*b07 + a02*b06, 443cb93a386Sopenharmony_ci a31*b01 - a30*b03 - a32*b00, 444cb93a386Sopenharmony_ci a20*b03 - a21*b01 + a22*b00) * (1/det); 445cb93a386Sopenharmony_ci} 446cb93a386Sopenharmony_ci)"; 447cb93a386Sopenharmony_ci 448cb93a386Sopenharmony_ciString MetalCodeGenerator::getInversePolyfill(const ExpressionArray& arguments) { 449cb93a386Sopenharmony_ci // Only use polyfills for a function taking a single-argument square matrix. 450cb93a386Sopenharmony_ci if (arguments.size() == 1) { 451cb93a386Sopenharmony_ci const Type& type = arguments.front()->type(); 452cb93a386Sopenharmony_ci if (type.isMatrix() && type.rows() == type.columns()) { 453cb93a386Sopenharmony_ci // Inject the correct polyfill based on the matrix size. 454cb93a386Sopenharmony_ci auto name = String::printf("mat%d_inverse", type.columns()); 455cb93a386Sopenharmony_ci auto [iter, didInsert] = fWrittenIntrinsics.insert(name); 456cb93a386Sopenharmony_ci if (didInsert) { 457cb93a386Sopenharmony_ci switch (type.rows()) { 458cb93a386Sopenharmony_ci case 2: 459cb93a386Sopenharmony_ci fExtraFunctions.writeText(kInverse2x2); 460cb93a386Sopenharmony_ci break; 461cb93a386Sopenharmony_ci case 3: 462cb93a386Sopenharmony_ci fExtraFunctions.writeText(kInverse3x3); 463cb93a386Sopenharmony_ci break; 464cb93a386Sopenharmony_ci case 4: 465cb93a386Sopenharmony_ci fExtraFunctions.writeText(kInverse4x4); 466cb93a386Sopenharmony_ci break; 467cb93a386Sopenharmony_ci } 468cb93a386Sopenharmony_ci } 469cb93a386Sopenharmony_ci return name; 470cb93a386Sopenharmony_ci } 471cb93a386Sopenharmony_ci } 472cb93a386Sopenharmony_ci // This isn't the built-in `inverse`. We don't want to polyfill it at all. 473cb93a386Sopenharmony_ci return "inverse"; 474cb93a386Sopenharmony_ci} 475cb93a386Sopenharmony_ci 476cb93a386Sopenharmony_civoid MetalCodeGenerator::writeMatrixCompMult() { 477cb93a386Sopenharmony_ci static constexpr char kMatrixCompMult[] = R"( 478cb93a386Sopenharmony_citemplate <typename T, int C, int R> 479cb93a386Sopenharmony_cimatrix<T, C, R> matrixCompMult(matrix<T, C, R> a, const matrix<T, C, R> b) { 480cb93a386Sopenharmony_ci for (int c = 0; c < C; ++c) { 481cb93a386Sopenharmony_ci a[c] *= b[c]; 482cb93a386Sopenharmony_ci } 483cb93a386Sopenharmony_ci return a; 484cb93a386Sopenharmony_ci} 485cb93a386Sopenharmony_ci)"; 486cb93a386Sopenharmony_ci 487cb93a386Sopenharmony_ci String name = "matrixCompMult"; 488cb93a386Sopenharmony_ci if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) { 489cb93a386Sopenharmony_ci fWrittenIntrinsics.insert(name); 490cb93a386Sopenharmony_ci fExtraFunctions.writeText(kMatrixCompMult); 491cb93a386Sopenharmony_ci } 492cb93a386Sopenharmony_ci} 493cb93a386Sopenharmony_ci 494cb93a386Sopenharmony_civoid MetalCodeGenerator::writeOuterProduct() { 495cb93a386Sopenharmony_ci static constexpr char kOuterProduct[] = R"( 496cb93a386Sopenharmony_citemplate <typename T, int C, int R> 497cb93a386Sopenharmony_cimatrix<T, C, R> outerProduct(const vec<T, R> a, const vec<T, C> b) { 498cb93a386Sopenharmony_ci matrix<T, C, R> result; 499cb93a386Sopenharmony_ci for (int c = 0; c < C; ++c) { 500cb93a386Sopenharmony_ci result[c] = a * b[c]; 501cb93a386Sopenharmony_ci } 502cb93a386Sopenharmony_ci return result; 503cb93a386Sopenharmony_ci} 504cb93a386Sopenharmony_ci)"; 505cb93a386Sopenharmony_ci 506cb93a386Sopenharmony_ci String name = "outerProduct"; 507cb93a386Sopenharmony_ci if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) { 508cb93a386Sopenharmony_ci fWrittenIntrinsics.insert(name); 509cb93a386Sopenharmony_ci fExtraFunctions.writeText(kOuterProduct); 510cb93a386Sopenharmony_ci } 511cb93a386Sopenharmony_ci} 512cb93a386Sopenharmony_ci 513cb93a386Sopenharmony_ciString MetalCodeGenerator::getTempVariable(const Type& type) { 514cb93a386Sopenharmony_ci String tempVar = "_skTemp" + to_string(fVarCount++); 515cb93a386Sopenharmony_ci this->fFunctionHeader += " " + this->typeName(type) + " " + tempVar + ";\n"; 516cb93a386Sopenharmony_ci return tempVar; 517cb93a386Sopenharmony_ci} 518cb93a386Sopenharmony_ci 519cb93a386Sopenharmony_civoid MetalCodeGenerator::writeSimpleIntrinsic(const FunctionCall& c) { 520cb93a386Sopenharmony_ci // Write out an intrinsic function call exactly as-is. No muss no fuss. 521cb93a386Sopenharmony_ci this->write(c.function().name()); 522cb93a386Sopenharmony_ci this->writeArgumentList(c.arguments()); 523cb93a386Sopenharmony_ci} 524cb93a386Sopenharmony_ci 525cb93a386Sopenharmony_civoid MetalCodeGenerator::writeArgumentList(const ExpressionArray& arguments) { 526cb93a386Sopenharmony_ci this->write("("); 527cb93a386Sopenharmony_ci const char* separator = ""; 528cb93a386Sopenharmony_ci for (const std::unique_ptr<Expression>& arg : arguments) { 529cb93a386Sopenharmony_ci this->write(separator); 530cb93a386Sopenharmony_ci separator = ", "; 531cb93a386Sopenharmony_ci this->writeExpression(*arg, Precedence::kSequence); 532cb93a386Sopenharmony_ci } 533cb93a386Sopenharmony_ci this->write(")"); 534cb93a386Sopenharmony_ci} 535cb93a386Sopenharmony_ci 536cb93a386Sopenharmony_cibool MetalCodeGenerator::writeIntrinsicCall(const FunctionCall& c, IntrinsicKind kind) { 537cb93a386Sopenharmony_ci const ExpressionArray& arguments = c.arguments(); 538cb93a386Sopenharmony_ci switch (kind) { 539cb93a386Sopenharmony_ci case k_sample_IntrinsicKind: { 540cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 541cb93a386Sopenharmony_ci this->write(".sample("); 542cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 543cb93a386Sopenharmony_ci this->write(SAMPLER_SUFFIX); 544cb93a386Sopenharmony_ci this->write(", "); 545cb93a386Sopenharmony_ci const Type& arg1Type = arguments[1]->type(); 546cb93a386Sopenharmony_ci if (arg1Type.columns() == 3) { 547cb93a386Sopenharmony_ci // have to store the vector in a temp variable to avoid double evaluating it 548cb93a386Sopenharmony_ci String tmpVar = this->getTempVariable(arg1Type); 549cb93a386Sopenharmony_ci this->write("(" + tmpVar + " = "); 550cb93a386Sopenharmony_ci this->writeExpression(*arguments[1], Precedence::kSequence); 551cb93a386Sopenharmony_ci this->write(", " + tmpVar + ".xy / " + tmpVar + ".z))"); 552cb93a386Sopenharmony_ci } else { 553cb93a386Sopenharmony_ci SkASSERT(arg1Type.columns() == 2); 554cb93a386Sopenharmony_ci this->writeExpression(*arguments[1], Precedence::kSequence); 555cb93a386Sopenharmony_ci this->write(")"); 556cb93a386Sopenharmony_ci } 557cb93a386Sopenharmony_ci return true; 558cb93a386Sopenharmony_ci } 559cb93a386Sopenharmony_ci case k_mod_IntrinsicKind: { 560cb93a386Sopenharmony_ci // fmod(x, y) in metal calculates x - y * trunc(x / y) instead of x - y * floor(x / y) 561cb93a386Sopenharmony_ci String tmpX = this->getTempVariable(arguments[0]->type()); 562cb93a386Sopenharmony_ci String tmpY = this->getTempVariable(arguments[1]->type()); 563cb93a386Sopenharmony_ci this->write("(" + tmpX + " = "); 564cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 565cb93a386Sopenharmony_ci this->write(", " + tmpY + " = "); 566cb93a386Sopenharmony_ci this->writeExpression(*arguments[1], Precedence::kSequence); 567cb93a386Sopenharmony_ci this->write(", " + tmpX + " - " + tmpY + " * floor(" + tmpX + " / " + tmpY + "))"); 568cb93a386Sopenharmony_ci return true; 569cb93a386Sopenharmony_ci } 570cb93a386Sopenharmony_ci // GLSL declares scalar versions of most geometric intrinsics, but these don't exist in MSL 571cb93a386Sopenharmony_ci case k_distance_IntrinsicKind: { 572cb93a386Sopenharmony_ci if (arguments[0]->type().columns() == 1) { 573cb93a386Sopenharmony_ci this->write("abs("); 574cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kAdditive); 575cb93a386Sopenharmony_ci this->write(" - "); 576cb93a386Sopenharmony_ci this->writeExpression(*arguments[1], Precedence::kAdditive); 577cb93a386Sopenharmony_ci this->write(")"); 578cb93a386Sopenharmony_ci } else { 579cb93a386Sopenharmony_ci this->writeSimpleIntrinsic(c); 580cb93a386Sopenharmony_ci } 581cb93a386Sopenharmony_ci return true; 582cb93a386Sopenharmony_ci } 583cb93a386Sopenharmony_ci case k_dot_IntrinsicKind: { 584cb93a386Sopenharmony_ci if (arguments[0]->type().columns() == 1) { 585cb93a386Sopenharmony_ci this->write("("); 586cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kMultiplicative); 587cb93a386Sopenharmony_ci this->write(" * "); 588cb93a386Sopenharmony_ci this->writeExpression(*arguments[1], Precedence::kMultiplicative); 589cb93a386Sopenharmony_ci this->write(")"); 590cb93a386Sopenharmony_ci } else { 591cb93a386Sopenharmony_ci this->writeSimpleIntrinsic(c); 592cb93a386Sopenharmony_ci } 593cb93a386Sopenharmony_ci return true; 594cb93a386Sopenharmony_ci } 595cb93a386Sopenharmony_ci case k_faceforward_IntrinsicKind: { 596cb93a386Sopenharmony_ci if (arguments[0]->type().columns() == 1) { 597cb93a386Sopenharmony_ci // ((((Nref) * (I) < 0) ? 1 : -1) * (N)) 598cb93a386Sopenharmony_ci this->write("(((("); 599cb93a386Sopenharmony_ci this->writeExpression(*arguments[2], Precedence::kSequence); 600cb93a386Sopenharmony_ci this->write(") * ("); 601cb93a386Sopenharmony_ci this->writeExpression(*arguments[1], Precedence::kSequence); 602cb93a386Sopenharmony_ci this->write(") < 0) ? 1 : -1) * ("); 603cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 604cb93a386Sopenharmony_ci this->write("))"); 605cb93a386Sopenharmony_ci } else { 606cb93a386Sopenharmony_ci this->writeSimpleIntrinsic(c); 607cb93a386Sopenharmony_ci } 608cb93a386Sopenharmony_ci return true; 609cb93a386Sopenharmony_ci } 610cb93a386Sopenharmony_ci case k_length_IntrinsicKind: { 611cb93a386Sopenharmony_ci this->write(arguments[0]->type().columns() == 1 ? "abs(" : "length("); 612cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 613cb93a386Sopenharmony_ci this->write(")"); 614cb93a386Sopenharmony_ci return true; 615cb93a386Sopenharmony_ci } 616cb93a386Sopenharmony_ci case k_normalize_IntrinsicKind: { 617cb93a386Sopenharmony_ci this->write(arguments[0]->type().columns() == 1 ? "sign(" : "normalize("); 618cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 619cb93a386Sopenharmony_ci this->write(")"); 620cb93a386Sopenharmony_ci return true; 621cb93a386Sopenharmony_ci } 622cb93a386Sopenharmony_ci case k_packUnorm2x16_IntrinsicKind: { 623cb93a386Sopenharmony_ci this->write("pack_float_to_unorm2x16("); 624cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 625cb93a386Sopenharmony_ci this->write(")"); 626cb93a386Sopenharmony_ci return true; 627cb93a386Sopenharmony_ci } 628cb93a386Sopenharmony_ci case k_unpackUnorm2x16_IntrinsicKind: { 629cb93a386Sopenharmony_ci this->write("unpack_unorm2x16_to_float("); 630cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 631cb93a386Sopenharmony_ci this->write(")"); 632cb93a386Sopenharmony_ci return true; 633cb93a386Sopenharmony_ci } 634cb93a386Sopenharmony_ci case k_packSnorm2x16_IntrinsicKind: { 635cb93a386Sopenharmony_ci this->write("pack_float_to_snorm2x16("); 636cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 637cb93a386Sopenharmony_ci this->write(")"); 638cb93a386Sopenharmony_ci return true; 639cb93a386Sopenharmony_ci } 640cb93a386Sopenharmony_ci case k_unpackSnorm2x16_IntrinsicKind: { 641cb93a386Sopenharmony_ci this->write("unpack_snorm2x16_to_float("); 642cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 643cb93a386Sopenharmony_ci this->write(")"); 644cb93a386Sopenharmony_ci return true; 645cb93a386Sopenharmony_ci } 646cb93a386Sopenharmony_ci case k_packUnorm4x8_IntrinsicKind: { 647cb93a386Sopenharmony_ci this->write("pack_float_to_unorm4x8("); 648cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 649cb93a386Sopenharmony_ci this->write(")"); 650cb93a386Sopenharmony_ci return true; 651cb93a386Sopenharmony_ci } 652cb93a386Sopenharmony_ci case k_unpackUnorm4x8_IntrinsicKind: { 653cb93a386Sopenharmony_ci this->write("unpack_unorm4x8_to_float("); 654cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 655cb93a386Sopenharmony_ci this->write(")"); 656cb93a386Sopenharmony_ci return true; 657cb93a386Sopenharmony_ci } 658cb93a386Sopenharmony_ci case k_packSnorm4x8_IntrinsicKind: { 659cb93a386Sopenharmony_ci this->write("pack_float_to_snorm4x8("); 660cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 661cb93a386Sopenharmony_ci this->write(")"); 662cb93a386Sopenharmony_ci return true; 663cb93a386Sopenharmony_ci } 664cb93a386Sopenharmony_ci case k_unpackSnorm4x8_IntrinsicKind: { 665cb93a386Sopenharmony_ci this->write("unpack_snorm4x8_to_float("); 666cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 667cb93a386Sopenharmony_ci this->write(")"); 668cb93a386Sopenharmony_ci return true; 669cb93a386Sopenharmony_ci } 670cb93a386Sopenharmony_ci case k_packHalf2x16_IntrinsicKind: { 671cb93a386Sopenharmony_ci this->write("as_type<uint>(half2("); 672cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 673cb93a386Sopenharmony_ci this->write("))"); 674cb93a386Sopenharmony_ci return true; 675cb93a386Sopenharmony_ci } 676cb93a386Sopenharmony_ci case k_unpackHalf2x16_IntrinsicKind: { 677cb93a386Sopenharmony_ci this->write("float2(as_type<half2>("); 678cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 679cb93a386Sopenharmony_ci this->write("))"); 680cb93a386Sopenharmony_ci return true; 681cb93a386Sopenharmony_ci } 682cb93a386Sopenharmony_ci case k_floatBitsToInt_IntrinsicKind: 683cb93a386Sopenharmony_ci case k_floatBitsToUint_IntrinsicKind: 684cb93a386Sopenharmony_ci case k_intBitsToFloat_IntrinsicKind: 685cb93a386Sopenharmony_ci case k_uintBitsToFloat_IntrinsicKind: { 686cb93a386Sopenharmony_ci this->write(this->getBitcastIntrinsic(c.type())); 687cb93a386Sopenharmony_ci this->write("("); 688cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 689cb93a386Sopenharmony_ci this->write(")"); 690cb93a386Sopenharmony_ci return true; 691cb93a386Sopenharmony_ci } 692cb93a386Sopenharmony_ci case k_degrees_IntrinsicKind: { 693cb93a386Sopenharmony_ci this->write("(("); 694cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 695cb93a386Sopenharmony_ci this->write(") * 57.2957795)"); 696cb93a386Sopenharmony_ci return true; 697cb93a386Sopenharmony_ci } 698cb93a386Sopenharmony_ci case k_radians_IntrinsicKind: { 699cb93a386Sopenharmony_ci this->write("(("); 700cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 701cb93a386Sopenharmony_ci this->write(") * 0.0174532925)"); 702cb93a386Sopenharmony_ci return true; 703cb93a386Sopenharmony_ci } 704cb93a386Sopenharmony_ci case k_dFdx_IntrinsicKind: { 705cb93a386Sopenharmony_ci this->write("dfdx"); 706cb93a386Sopenharmony_ci this->writeArgumentList(c.arguments()); 707cb93a386Sopenharmony_ci return true; 708cb93a386Sopenharmony_ci } 709cb93a386Sopenharmony_ci case k_dFdy_IntrinsicKind: { 710cb93a386Sopenharmony_ci this->write("(" + fRTFlipName + ".y * dfdy"); 711cb93a386Sopenharmony_ci this->writeArgumentList(c.arguments()); 712cb93a386Sopenharmony_ci this->write(")"); 713cb93a386Sopenharmony_ci return true; 714cb93a386Sopenharmony_ci } 715cb93a386Sopenharmony_ci case k_inverse_IntrinsicKind: { 716cb93a386Sopenharmony_ci this->write(this->getInversePolyfill(arguments)); 717cb93a386Sopenharmony_ci this->writeArgumentList(c.arguments()); 718cb93a386Sopenharmony_ci return true; 719cb93a386Sopenharmony_ci } 720cb93a386Sopenharmony_ci case k_inversesqrt_IntrinsicKind: { 721cb93a386Sopenharmony_ci this->write("rsqrt"); 722cb93a386Sopenharmony_ci this->writeArgumentList(c.arguments()); 723cb93a386Sopenharmony_ci return true; 724cb93a386Sopenharmony_ci } 725cb93a386Sopenharmony_ci case k_atan_IntrinsicKind: { 726cb93a386Sopenharmony_ci this->write(c.arguments().size() == 2 ? "atan2" : "atan"); 727cb93a386Sopenharmony_ci this->writeArgumentList(c.arguments()); 728cb93a386Sopenharmony_ci return true; 729cb93a386Sopenharmony_ci } 730cb93a386Sopenharmony_ci case k_reflect_IntrinsicKind: { 731cb93a386Sopenharmony_ci if (arguments[0]->type().columns() == 1) { 732cb93a386Sopenharmony_ci // We need to synthesize `I - 2 * N * I * N`. 733cb93a386Sopenharmony_ci String tmpI = this->getTempVariable(arguments[0]->type()); 734cb93a386Sopenharmony_ci String tmpN = this->getTempVariable(arguments[1]->type()); 735cb93a386Sopenharmony_ci 736cb93a386Sopenharmony_ci // (_skTempI = ... 737cb93a386Sopenharmony_ci this->write("(" + tmpI + " = "); 738cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 739cb93a386Sopenharmony_ci 740cb93a386Sopenharmony_ci // , _skTempN = ... 741cb93a386Sopenharmony_ci this->write(", " + tmpN + " = "); 742cb93a386Sopenharmony_ci this->writeExpression(*arguments[1], Precedence::kSequence); 743cb93a386Sopenharmony_ci 744cb93a386Sopenharmony_ci // , _skTempI - 2 * _skTempN * _skTempI * _skTempN) 745cb93a386Sopenharmony_ci this->write(", " + tmpI + " - 2 * " + tmpN + " * " + tmpI + " * " + tmpN + ")"); 746cb93a386Sopenharmony_ci } else { 747cb93a386Sopenharmony_ci this->writeSimpleIntrinsic(c); 748cb93a386Sopenharmony_ci } 749cb93a386Sopenharmony_ci return true; 750cb93a386Sopenharmony_ci } 751cb93a386Sopenharmony_ci case k_refract_IntrinsicKind: { 752cb93a386Sopenharmony_ci if (arguments[0]->type().columns() == 1) { 753cb93a386Sopenharmony_ci // Metal does implement refract for vectors; rather than reimplementing refract from 754cb93a386Sopenharmony_ci // scratch, we can replace the call with `refract(float2(I,0), float2(N,0), eta).x`. 755cb93a386Sopenharmony_ci this->write("(refract(float2("); 756cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 757cb93a386Sopenharmony_ci this->write(", 0), float2("); 758cb93a386Sopenharmony_ci this->writeExpression(*arguments[1], Precedence::kSequence); 759cb93a386Sopenharmony_ci this->write(", 0), "); 760cb93a386Sopenharmony_ci this->writeExpression(*arguments[2], Precedence::kSequence); 761cb93a386Sopenharmony_ci this->write(").x)"); 762cb93a386Sopenharmony_ci } else { 763cb93a386Sopenharmony_ci this->writeSimpleIntrinsic(c); 764cb93a386Sopenharmony_ci } 765cb93a386Sopenharmony_ci return true; 766cb93a386Sopenharmony_ci } 767cb93a386Sopenharmony_ci case k_roundEven_IntrinsicKind: { 768cb93a386Sopenharmony_ci this->write("rint"); 769cb93a386Sopenharmony_ci this->writeArgumentList(c.arguments()); 770cb93a386Sopenharmony_ci return true; 771cb93a386Sopenharmony_ci } 772cb93a386Sopenharmony_ci case k_bitCount_IntrinsicKind: { 773cb93a386Sopenharmony_ci this->write("popcount("); 774cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 775cb93a386Sopenharmony_ci this->write(")"); 776cb93a386Sopenharmony_ci return true; 777cb93a386Sopenharmony_ci } 778cb93a386Sopenharmony_ci case k_findLSB_IntrinsicKind: { 779cb93a386Sopenharmony_ci // Create a temp variable to store the expression, to avoid double-evaluating it. 780cb93a386Sopenharmony_ci String skTemp = this->getTempVariable(arguments[0]->type()); 781cb93a386Sopenharmony_ci String exprType = this->typeName(arguments[0]->type()); 782cb93a386Sopenharmony_ci 783cb93a386Sopenharmony_ci // ctz returns numbits(type) on zero inputs; GLSL documents it as generating -1 instead. 784cb93a386Sopenharmony_ci // Use select to detect zero inputs and force a -1 result. 785cb93a386Sopenharmony_ci 786cb93a386Sopenharmony_ci // (_skTemp1 = (.....), select(ctz(_skTemp1), int4(-1), _skTemp1 == int4(0))) 787cb93a386Sopenharmony_ci this->write("("); 788cb93a386Sopenharmony_ci this->write(skTemp); 789cb93a386Sopenharmony_ci this->write(" = ("); 790cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 791cb93a386Sopenharmony_ci this->write("), select(ctz("); 792cb93a386Sopenharmony_ci this->write(skTemp); 793cb93a386Sopenharmony_ci this->write("), "); 794cb93a386Sopenharmony_ci this->write(exprType); 795cb93a386Sopenharmony_ci this->write("(-1), "); 796cb93a386Sopenharmony_ci this->write(skTemp); 797cb93a386Sopenharmony_ci this->write(" == "); 798cb93a386Sopenharmony_ci this->write(exprType); 799cb93a386Sopenharmony_ci this->write("(0)))"); 800cb93a386Sopenharmony_ci return true; 801cb93a386Sopenharmony_ci } 802cb93a386Sopenharmony_ci case k_findMSB_IntrinsicKind: { 803cb93a386Sopenharmony_ci // Create a temp variable to store the expression, to avoid double-evaluating it. 804cb93a386Sopenharmony_ci String skTemp1 = this->getTempVariable(arguments[0]->type()); 805cb93a386Sopenharmony_ci String exprType = this->typeName(arguments[0]->type()); 806cb93a386Sopenharmony_ci 807cb93a386Sopenharmony_ci // GLSL findMSB is actually quite different from Metal's clz: 808cb93a386Sopenharmony_ci // - For signed negative numbers, it returns the first zero bit, not the first one bit! 809cb93a386Sopenharmony_ci // - For an empty input (0/~0 depending on sign), findMSB gives -1; clz is numbits(type) 810cb93a386Sopenharmony_ci 811cb93a386Sopenharmony_ci // (_skTemp1 = (.....), 812cb93a386Sopenharmony_ci this->write("("); 813cb93a386Sopenharmony_ci this->write(skTemp1); 814cb93a386Sopenharmony_ci this->write(" = ("); 815cb93a386Sopenharmony_ci this->writeExpression(*arguments[0], Precedence::kSequence); 816cb93a386Sopenharmony_ci this->write("), "); 817cb93a386Sopenharmony_ci 818cb93a386Sopenharmony_ci // Signed input types might be negative; we need another helper variable to negate the 819cb93a386Sopenharmony_ci // input (since we can only find one bits, not zero bits). 820cb93a386Sopenharmony_ci String skTemp2; 821cb93a386Sopenharmony_ci if (arguments[0]->type().isSigned()) { 822cb93a386Sopenharmony_ci // ... _skTemp2 = (select(_skTemp1, ~_skTemp1, _skTemp1 < 0)), 823cb93a386Sopenharmony_ci skTemp2 = this->getTempVariable(arguments[0]->type()); 824cb93a386Sopenharmony_ci this->write(skTemp2); 825cb93a386Sopenharmony_ci this->write(" = (select("); 826cb93a386Sopenharmony_ci this->write(skTemp1); 827cb93a386Sopenharmony_ci this->write(", ~"); 828cb93a386Sopenharmony_ci this->write(skTemp1); 829cb93a386Sopenharmony_ci this->write(", "); 830cb93a386Sopenharmony_ci this->write(skTemp1); 831cb93a386Sopenharmony_ci this->write(" < 0)), "); 832cb93a386Sopenharmony_ci } else { 833cb93a386Sopenharmony_ci skTemp2 = skTemp1; 834cb93a386Sopenharmony_ci } 835cb93a386Sopenharmony_ci 836cb93a386Sopenharmony_ci // ... select(int4(clz(_skTemp2)), int4(-1), _skTemp2 == int4(0))) 837cb93a386Sopenharmony_ci this->write("select("); 838cb93a386Sopenharmony_ci this->write(this->typeName(c.type())); 839cb93a386Sopenharmony_ci this->write("(clz("); 840cb93a386Sopenharmony_ci this->write(skTemp2); 841cb93a386Sopenharmony_ci this->write(")), "); 842cb93a386Sopenharmony_ci this->write(this->typeName(c.type())); 843cb93a386Sopenharmony_ci this->write("(-1), "); 844cb93a386Sopenharmony_ci this->write(skTemp2); 845cb93a386Sopenharmony_ci this->write(" == "); 846cb93a386Sopenharmony_ci this->write(exprType); 847cb93a386Sopenharmony_ci this->write("(0)))"); 848cb93a386Sopenharmony_ci return true; 849cb93a386Sopenharmony_ci } 850cb93a386Sopenharmony_ci case k_matrixCompMult_IntrinsicKind: { 851cb93a386Sopenharmony_ci this->writeMatrixCompMult(); 852cb93a386Sopenharmony_ci this->writeSimpleIntrinsic(c); 853cb93a386Sopenharmony_ci return true; 854cb93a386Sopenharmony_ci } 855cb93a386Sopenharmony_ci case k_outerProduct_IntrinsicKind: { 856cb93a386Sopenharmony_ci this->writeOuterProduct(); 857cb93a386Sopenharmony_ci this->writeSimpleIntrinsic(c); 858cb93a386Sopenharmony_ci return true; 859cb93a386Sopenharmony_ci } 860cb93a386Sopenharmony_ci case k_mix_IntrinsicKind: { 861cb93a386Sopenharmony_ci SkASSERT(c.arguments().size() == 3); 862cb93a386Sopenharmony_ci if (arguments[2]->type().componentType().isBoolean()) { 863cb93a386Sopenharmony_ci // The Boolean forms of GLSL mix() use the select() intrinsic in Metal. 864cb93a386Sopenharmony_ci this->write("select"); 865cb93a386Sopenharmony_ci this->writeArgumentList(c.arguments()); 866cb93a386Sopenharmony_ci return true; 867cb93a386Sopenharmony_ci } 868cb93a386Sopenharmony_ci // The basic form of mix() is supported by Metal as-is. 869cb93a386Sopenharmony_ci this->writeSimpleIntrinsic(c); 870cb93a386Sopenharmony_ci return true; 871cb93a386Sopenharmony_ci } 872cb93a386Sopenharmony_ci case k_equal_IntrinsicKind: 873cb93a386Sopenharmony_ci case k_greaterThan_IntrinsicKind: 874cb93a386Sopenharmony_ci case k_greaterThanEqual_IntrinsicKind: 875cb93a386Sopenharmony_ci case k_lessThan_IntrinsicKind: 876cb93a386Sopenharmony_ci case k_lessThanEqual_IntrinsicKind: 877cb93a386Sopenharmony_ci case k_notEqual_IntrinsicKind: { 878cb93a386Sopenharmony_ci this->write("("); 879cb93a386Sopenharmony_ci this->writeExpression(*c.arguments()[0], Precedence::kRelational); 880cb93a386Sopenharmony_ci switch (kind) { 881cb93a386Sopenharmony_ci case k_equal_IntrinsicKind: 882cb93a386Sopenharmony_ci this->write(" == "); 883cb93a386Sopenharmony_ci break; 884cb93a386Sopenharmony_ci case k_notEqual_IntrinsicKind: 885cb93a386Sopenharmony_ci this->write(" != "); 886cb93a386Sopenharmony_ci break; 887cb93a386Sopenharmony_ci case k_lessThan_IntrinsicKind: 888cb93a386Sopenharmony_ci this->write(" < "); 889cb93a386Sopenharmony_ci break; 890cb93a386Sopenharmony_ci case k_lessThanEqual_IntrinsicKind: 891cb93a386Sopenharmony_ci this->write(" <= "); 892cb93a386Sopenharmony_ci break; 893cb93a386Sopenharmony_ci case k_greaterThan_IntrinsicKind: 894cb93a386Sopenharmony_ci this->write(" > "); 895cb93a386Sopenharmony_ci break; 896cb93a386Sopenharmony_ci case k_greaterThanEqual_IntrinsicKind: 897cb93a386Sopenharmony_ci this->write(" >= "); 898cb93a386Sopenharmony_ci break; 899cb93a386Sopenharmony_ci default: 900cb93a386Sopenharmony_ci SK_ABORT("unsupported comparison intrinsic kind"); 901cb93a386Sopenharmony_ci } 902cb93a386Sopenharmony_ci this->writeExpression(*c.arguments()[1], Precedence::kRelational); 903cb93a386Sopenharmony_ci this->write(")"); 904cb93a386Sopenharmony_ci return true; 905cb93a386Sopenharmony_ci } 906cb93a386Sopenharmony_ci default: 907cb93a386Sopenharmony_ci return false; 908cb93a386Sopenharmony_ci } 909cb93a386Sopenharmony_ci} 910cb93a386Sopenharmony_ci 911cb93a386Sopenharmony_ci// Assembles a matrix of type floatRxC by resizing another matrix named `x0`. 912cb93a386Sopenharmony_ci// Cells that don't exist in the source matrix will be populated with identity-matrix values. 913cb93a386Sopenharmony_civoid MetalCodeGenerator::assembleMatrixFromMatrix(const Type& sourceMatrix, int rows, int columns) { 914cb93a386Sopenharmony_ci SkASSERT(rows <= 4); 915cb93a386Sopenharmony_ci SkASSERT(columns <= 4); 916cb93a386Sopenharmony_ci 917cb93a386Sopenharmony_ci std::string matrixType = this->typeName(sourceMatrix.componentType()); 918cb93a386Sopenharmony_ci 919cb93a386Sopenharmony_ci const char* separator = ""; 920cb93a386Sopenharmony_ci for (int c = 0; c < columns; ++c) { 921cb93a386Sopenharmony_ci fExtraFunctions.printf("%s%s%d(", separator, matrixType.c_str(), rows); 922cb93a386Sopenharmony_ci separator = "), "; 923cb93a386Sopenharmony_ci 924cb93a386Sopenharmony_ci // Determine how many values to take from the source matrix for this row. 925cb93a386Sopenharmony_ci int swizzleLength = 0; 926cb93a386Sopenharmony_ci if (c < sourceMatrix.columns()) { 927cb93a386Sopenharmony_ci swizzleLength = std::min<>(rows, sourceMatrix.rows()); 928cb93a386Sopenharmony_ci } 929cb93a386Sopenharmony_ci 930cb93a386Sopenharmony_ci // Emit all the values from the source matrix row. 931cb93a386Sopenharmony_ci bool firstItem; 932cb93a386Sopenharmony_ci switch (swizzleLength) { 933cb93a386Sopenharmony_ci case 0: firstItem = true; break; 934cb93a386Sopenharmony_ci case 1: firstItem = false; fExtraFunctions.printf("x0[%d].x", c); break; 935cb93a386Sopenharmony_ci case 2: firstItem = false; fExtraFunctions.printf("x0[%d].xy", c); break; 936cb93a386Sopenharmony_ci case 3: firstItem = false; fExtraFunctions.printf("x0[%d].xyz", c); break; 937cb93a386Sopenharmony_ci case 4: firstItem = false; fExtraFunctions.printf("x0[%d].xyzw", c); break; 938cb93a386Sopenharmony_ci default: SkUNREACHABLE; 939cb93a386Sopenharmony_ci } 940cb93a386Sopenharmony_ci 941cb93a386Sopenharmony_ci // Emit the placeholder identity-matrix cells. 942cb93a386Sopenharmony_ci for (int r = swizzleLength; r < rows; ++r) { 943cb93a386Sopenharmony_ci fExtraFunctions.printf("%s%s", firstItem ? "" : ", ", (r == c) ? "1.0" : "0.0"); 944cb93a386Sopenharmony_ci firstItem = false; 945cb93a386Sopenharmony_ci } 946cb93a386Sopenharmony_ci } 947cb93a386Sopenharmony_ci 948cb93a386Sopenharmony_ci fExtraFunctions.writeText(")"); 949cb93a386Sopenharmony_ci} 950cb93a386Sopenharmony_ci 951cb93a386Sopenharmony_ci// Assembles a matrix of type floatCxR by concatenating an arbitrary mix of values, named `x0`, 952cb93a386Sopenharmony_ci// `x1`, etc. An error is written if the expression list don't contain exactly C*R scalars. 953cb93a386Sopenharmony_civoid MetalCodeGenerator::assembleMatrixFromExpressions(const AnyConstructor& ctor, 954cb93a386Sopenharmony_ci int columns, int rows) { 955cb93a386Sopenharmony_ci SkASSERT(rows <= 4); 956cb93a386Sopenharmony_ci SkASSERT(columns <= 4); 957cb93a386Sopenharmony_ci 958cb93a386Sopenharmony_ci std::string matrixType = this->typeName(ctor.type().componentType()); 959cb93a386Sopenharmony_ci size_t argIndex = 0; 960cb93a386Sopenharmony_ci int argPosition = 0; 961cb93a386Sopenharmony_ci auto args = ctor.argumentSpan(); 962cb93a386Sopenharmony_ci 963cb93a386Sopenharmony_ci static constexpr char kSwizzle[] = "xyzw"; 964cb93a386Sopenharmony_ci const char* separator = ""; 965cb93a386Sopenharmony_ci for (int c = 0; c < columns; ++c) { 966cb93a386Sopenharmony_ci fExtraFunctions.printf("%s%s%d(", separator, matrixType.c_str(), rows); 967cb93a386Sopenharmony_ci separator = "), "; 968cb93a386Sopenharmony_ci 969cb93a386Sopenharmony_ci const char* columnSeparator = ""; 970cb93a386Sopenharmony_ci for (int r = 0; r < rows;) { 971cb93a386Sopenharmony_ci fExtraFunctions.writeText(columnSeparator); 972cb93a386Sopenharmony_ci columnSeparator = ", "; 973cb93a386Sopenharmony_ci 974cb93a386Sopenharmony_ci if (argIndex < args.size()) { 975cb93a386Sopenharmony_ci const Type& argType = args[argIndex]->type(); 976cb93a386Sopenharmony_ci switch (argType.typeKind()) { 977cb93a386Sopenharmony_ci case Type::TypeKind::kScalar: { 978cb93a386Sopenharmony_ci fExtraFunctions.printf("x%zu", argIndex); 979cb93a386Sopenharmony_ci ++r; 980cb93a386Sopenharmony_ci ++argPosition; 981cb93a386Sopenharmony_ci break; 982cb93a386Sopenharmony_ci } 983cb93a386Sopenharmony_ci case Type::TypeKind::kVector: { 984cb93a386Sopenharmony_ci fExtraFunctions.printf("x%zu.", argIndex); 985cb93a386Sopenharmony_ci do { 986cb93a386Sopenharmony_ci fExtraFunctions.write8(kSwizzle[argPosition]); 987cb93a386Sopenharmony_ci ++r; 988cb93a386Sopenharmony_ci ++argPosition; 989cb93a386Sopenharmony_ci } while (r < rows && argPosition < argType.columns()); 990cb93a386Sopenharmony_ci break; 991cb93a386Sopenharmony_ci } 992cb93a386Sopenharmony_ci case Type::TypeKind::kMatrix: { 993cb93a386Sopenharmony_ci fExtraFunctions.printf("x%zu[%d].", argIndex, argPosition / argType.rows()); 994cb93a386Sopenharmony_ci do { 995cb93a386Sopenharmony_ci fExtraFunctions.write8(kSwizzle[argPosition]); 996cb93a386Sopenharmony_ci ++r; 997cb93a386Sopenharmony_ci ++argPosition; 998cb93a386Sopenharmony_ci } while (r < rows && (argPosition % argType.rows()) != 0); 999cb93a386Sopenharmony_ci break; 1000cb93a386Sopenharmony_ci } 1001cb93a386Sopenharmony_ci default: { 1002cb93a386Sopenharmony_ci SkDEBUGFAIL("incorrect type of argument for matrix constructor"); 1003cb93a386Sopenharmony_ci fExtraFunctions.writeText("<error>"); 1004cb93a386Sopenharmony_ci break; 1005cb93a386Sopenharmony_ci } 1006cb93a386Sopenharmony_ci } 1007cb93a386Sopenharmony_ci 1008cb93a386Sopenharmony_ci if (argPosition >= argType.columns() * argType.rows()) { 1009cb93a386Sopenharmony_ci ++argIndex; 1010cb93a386Sopenharmony_ci argPosition = 0; 1011cb93a386Sopenharmony_ci } 1012cb93a386Sopenharmony_ci } else { 1013cb93a386Sopenharmony_ci SkDEBUGFAIL("not enough arguments for matrix constructor"); 1014cb93a386Sopenharmony_ci fExtraFunctions.writeText("<error>"); 1015cb93a386Sopenharmony_ci } 1016cb93a386Sopenharmony_ci } 1017cb93a386Sopenharmony_ci } 1018cb93a386Sopenharmony_ci 1019cb93a386Sopenharmony_ci if (argPosition != 0 || argIndex != args.size()) { 1020cb93a386Sopenharmony_ci SkDEBUGFAIL("incorrect number of arguments for matrix constructor"); 1021cb93a386Sopenharmony_ci fExtraFunctions.writeText(", <error>"); 1022cb93a386Sopenharmony_ci } 1023cb93a386Sopenharmony_ci 1024cb93a386Sopenharmony_ci fExtraFunctions.writeText(")"); 1025cb93a386Sopenharmony_ci} 1026cb93a386Sopenharmony_ci 1027cb93a386Sopenharmony_ci// Generates a constructor for 'matrix' which reorganizes the input arguments into the proper shape. 1028cb93a386Sopenharmony_ci// Keeps track of previously generated constructors so that we won't generate more than one 1029cb93a386Sopenharmony_ci// constructor for any given permutation of input argument types. Returns the name of the 1030cb93a386Sopenharmony_ci// generated constructor method. 1031cb93a386Sopenharmony_ciString MetalCodeGenerator::getMatrixConstructHelper(const AnyConstructor& c) { 1032cb93a386Sopenharmony_ci const Type& type = c.type(); 1033cb93a386Sopenharmony_ci int columns = type.columns(); 1034cb93a386Sopenharmony_ci int rows = type.rows(); 1035cb93a386Sopenharmony_ci auto args = c.argumentSpan(); 1036cb93a386Sopenharmony_ci String typeName = this->typeName(type); 1037cb93a386Sopenharmony_ci 1038cb93a386Sopenharmony_ci // Create the helper-method name and use it as our lookup key. 1039cb93a386Sopenharmony_ci String name; 1040cb93a386Sopenharmony_ci name.appendf("%s_from", typeName.c_str()); 1041cb93a386Sopenharmony_ci for (const std::unique_ptr<Expression>& expr : args) { 1042cb93a386Sopenharmony_ci name.appendf("_%s", this->typeName(expr->type()).c_str()); 1043cb93a386Sopenharmony_ci } 1044cb93a386Sopenharmony_ci 1045cb93a386Sopenharmony_ci // If a helper-method has already been synthesized, we don't need to synthesize it again. 1046cb93a386Sopenharmony_ci auto [iter, newlyCreated] = fHelpers.insert(name); 1047cb93a386Sopenharmony_ci if (!newlyCreated) { 1048cb93a386Sopenharmony_ci return name; 1049cb93a386Sopenharmony_ci } 1050cb93a386Sopenharmony_ci 1051cb93a386Sopenharmony_ci // Unlike GLSL, Metal requires that matrices are initialized with exactly R vectors of C 1052cb93a386Sopenharmony_ci // components apiece. (In Metal 2.0, you can also supply R*C scalars, but you still cannot 1053cb93a386Sopenharmony_ci // supply a mixture of scalars and vectors.) 1054cb93a386Sopenharmony_ci fExtraFunctions.printf("%s %s(", typeName.c_str(), name.c_str()); 1055cb93a386Sopenharmony_ci 1056cb93a386Sopenharmony_ci size_t argIndex = 0; 1057cb93a386Sopenharmony_ci const char* argSeparator = ""; 1058cb93a386Sopenharmony_ci for (const std::unique_ptr<Expression>& expr : args) { 1059cb93a386Sopenharmony_ci fExtraFunctions.printf("%s%s x%zu", argSeparator, 1060cb93a386Sopenharmony_ci this->typeName(expr->type()).c_str(), argIndex++); 1061cb93a386Sopenharmony_ci argSeparator = ", "; 1062cb93a386Sopenharmony_ci } 1063cb93a386Sopenharmony_ci 1064cb93a386Sopenharmony_ci fExtraFunctions.printf(") {\n return %s(", typeName.c_str()); 1065cb93a386Sopenharmony_ci 1066cb93a386Sopenharmony_ci if (args.size() == 1 && args.front()->type().isMatrix()) { 1067cb93a386Sopenharmony_ci this->assembleMatrixFromMatrix(args.front()->type(), rows, columns); 1068cb93a386Sopenharmony_ci } else { 1069cb93a386Sopenharmony_ci this->assembleMatrixFromExpressions(c, columns, rows); 1070cb93a386Sopenharmony_ci } 1071cb93a386Sopenharmony_ci 1072cb93a386Sopenharmony_ci fExtraFunctions.writeText(");\n}\n"); 1073cb93a386Sopenharmony_ci return name; 1074cb93a386Sopenharmony_ci} 1075cb93a386Sopenharmony_ci 1076cb93a386Sopenharmony_cibool MetalCodeGenerator::matrixConstructHelperIsNeeded(const ConstructorCompound& c) { 1077cb93a386Sopenharmony_ci SkASSERT(c.type().isMatrix()); 1078cb93a386Sopenharmony_ci 1079cb93a386Sopenharmony_ci // GLSL is fairly free-form about inputs to its matrix constructors, but Metal is not; it 1080cb93a386Sopenharmony_ci // expects exactly R vectors of C components apiece. (Metal 2.0 also allows a list of R*C 1081cb93a386Sopenharmony_ci // scalars.) Some cases are simple to translate and so we handle those inline--e.g. a list of 1082cb93a386Sopenharmony_ci // scalars can be constructed trivially. In more complex cases, we generate a helper function 1083cb93a386Sopenharmony_ci // that converts our inputs into a properly-shaped matrix. 1084cb93a386Sopenharmony_ci // A matrix construct helper method is always used if any input argument is a matrix. 1085cb93a386Sopenharmony_ci // Helper methods are also necessary when any argument would span multiple rows. For instance: 1086cb93a386Sopenharmony_ci // 1087cb93a386Sopenharmony_ci // float2 x = (1, 2); 1088cb93a386Sopenharmony_ci // float3x2(x, 3, 4, 5, 6) = | 1 3 5 | = no helper needed; conversion can be done inline 1089cb93a386Sopenharmony_ci // | 2 4 6 | 1090cb93a386Sopenharmony_ci // 1091cb93a386Sopenharmony_ci // float2 x = (2, 3); 1092cb93a386Sopenharmony_ci // float3x2(1, x, 4, 5, 6) = | 1 3 5 | = x spans multiple rows; a helper method will be used 1093cb93a386Sopenharmony_ci // | 2 4 6 | 1094cb93a386Sopenharmony_ci // 1095cb93a386Sopenharmony_ci // float4 x = (1, 2, 3, 4); 1096cb93a386Sopenharmony_ci // float2x2(x) = | 1 3 | = x spans multiple rows; a helper method will be used 1097cb93a386Sopenharmony_ci // | 2 4 | 1098cb93a386Sopenharmony_ci // 1099cb93a386Sopenharmony_ci 1100cb93a386Sopenharmony_ci int position = 0; 1101cb93a386Sopenharmony_ci for (const std::unique_ptr<Expression>& expr : c.arguments()) { 1102cb93a386Sopenharmony_ci // If an input argument is a matrix, we need a helper function. 1103cb93a386Sopenharmony_ci if (expr->type().isMatrix()) { 1104cb93a386Sopenharmony_ci return true; 1105cb93a386Sopenharmony_ci } 1106cb93a386Sopenharmony_ci position += expr->type().columns(); 1107cb93a386Sopenharmony_ci if (position > c.type().rows()) { 1108cb93a386Sopenharmony_ci // An input argument would span multiple rows; a helper function is required. 1109cb93a386Sopenharmony_ci return true; 1110cb93a386Sopenharmony_ci } 1111cb93a386Sopenharmony_ci if (position == c.type().rows()) { 1112cb93a386Sopenharmony_ci // We've advanced to the end of a row. Wrap to the start of the next row. 1113cb93a386Sopenharmony_ci position = 0; 1114cb93a386Sopenharmony_ci } 1115cb93a386Sopenharmony_ci } 1116cb93a386Sopenharmony_ci 1117cb93a386Sopenharmony_ci return false; 1118cb93a386Sopenharmony_ci} 1119cb93a386Sopenharmony_ci 1120cb93a386Sopenharmony_civoid MetalCodeGenerator::writeConstructorMatrixResize(const ConstructorMatrixResize& c, 1121cb93a386Sopenharmony_ci Precedence parentPrecedence) { 1122cb93a386Sopenharmony_ci // Matrix-resize via casting doesn't natively exist in Metal at all, so we always need to use a 1123cb93a386Sopenharmony_ci // matrix-construct helper here. 1124cb93a386Sopenharmony_ci this->write(this->getMatrixConstructHelper(c)); 1125cb93a386Sopenharmony_ci this->write("("); 1126cb93a386Sopenharmony_ci this->writeExpression(*c.argument(), Precedence::kSequence); 1127cb93a386Sopenharmony_ci this->write(")"); 1128cb93a386Sopenharmony_ci} 1129cb93a386Sopenharmony_ci 1130cb93a386Sopenharmony_civoid MetalCodeGenerator::writeConstructorCompound(const ConstructorCompound& c, 1131cb93a386Sopenharmony_ci Precedence parentPrecedence) { 1132cb93a386Sopenharmony_ci if (c.type().isVector()) { 1133cb93a386Sopenharmony_ci this->writeConstructorCompoundVector(c, parentPrecedence); 1134cb93a386Sopenharmony_ci } else if (c.type().isMatrix()) { 1135cb93a386Sopenharmony_ci this->writeConstructorCompoundMatrix(c, parentPrecedence); 1136cb93a386Sopenharmony_ci } else { 1137cb93a386Sopenharmony_ci fContext.fErrors->error(c.fLine, "unsupported compound constructor"); 1138cb93a386Sopenharmony_ci } 1139cb93a386Sopenharmony_ci} 1140cb93a386Sopenharmony_ci 1141cb93a386Sopenharmony_civoid MetalCodeGenerator::writeConstructorArrayCast(const ConstructorArrayCast& c, 1142cb93a386Sopenharmony_ci Precedence parentPrecedence) { 1143cb93a386Sopenharmony_ci const Type& inType = c.argument()->type().componentType(); 1144cb93a386Sopenharmony_ci const Type& outType = c.type().componentType(); 1145cb93a386Sopenharmony_ci String inTypeName = this->typeName(inType); 1146cb93a386Sopenharmony_ci String outTypeName = this->typeName(outType); 1147cb93a386Sopenharmony_ci 1148cb93a386Sopenharmony_ci String name = "array_of_" + outTypeName + "_from_" + inTypeName; 1149cb93a386Sopenharmony_ci auto [iter, didInsert] = fHelpers.insert(name); 1150cb93a386Sopenharmony_ci if (didInsert) { 1151cb93a386Sopenharmony_ci fExtraFunctions.printf(R"( 1152cb93a386Sopenharmony_citemplate <size_t N> 1153cb93a386Sopenharmony_ciarray<%s, N> %s(thread const array<%s, N>& x) { 1154cb93a386Sopenharmony_ci array<%s, N> result; 1155cb93a386Sopenharmony_ci for (int i = 0; i < N; ++i) { 1156cb93a386Sopenharmony_ci result[i] = %s(x[i]); 1157cb93a386Sopenharmony_ci } 1158cb93a386Sopenharmony_ci return result; 1159cb93a386Sopenharmony_ci} 1160cb93a386Sopenharmony_ci)", 1161cb93a386Sopenharmony_ci outTypeName.c_str(), name.c_str(), inTypeName.c_str(), 1162cb93a386Sopenharmony_ci outTypeName.c_str(), 1163cb93a386Sopenharmony_ci outTypeName.c_str()); 1164cb93a386Sopenharmony_ci } 1165cb93a386Sopenharmony_ci 1166cb93a386Sopenharmony_ci this->write(name); 1167cb93a386Sopenharmony_ci this->write("("); 1168cb93a386Sopenharmony_ci this->writeExpression(*c.argument(), Precedence::kSequence); 1169cb93a386Sopenharmony_ci this->write(")"); 1170cb93a386Sopenharmony_ci} 1171cb93a386Sopenharmony_ci 1172cb93a386Sopenharmony_ciString MetalCodeGenerator::getVectorFromMat2x2ConstructorHelper(const Type& matrixType) { 1173cb93a386Sopenharmony_ci SkASSERT(matrixType.isMatrix()); 1174cb93a386Sopenharmony_ci SkASSERT(matrixType.rows() == 2); 1175cb93a386Sopenharmony_ci SkASSERT(matrixType.columns() == 2); 1176cb93a386Sopenharmony_ci 1177cb93a386Sopenharmony_ci String baseType = this->typeName(matrixType.componentType()); 1178cb93a386Sopenharmony_ci String name = String::printf("%s4_from_%s2x2", baseType.c_str(), baseType.c_str()); 1179cb93a386Sopenharmony_ci if (fHelpers.find(name) == fHelpers.end()) { 1180cb93a386Sopenharmony_ci fHelpers.insert(name); 1181cb93a386Sopenharmony_ci 1182cb93a386Sopenharmony_ci fExtraFunctions.printf(R"( 1183cb93a386Sopenharmony_ci%s4 %s(%s2x2 x) { 1184cb93a386Sopenharmony_ci return %s4(x[0].xy, x[1].xy); 1185cb93a386Sopenharmony_ci} 1186cb93a386Sopenharmony_ci)", baseType.c_str(), name.c_str(), baseType.c_str(), baseType.c_str()); 1187cb93a386Sopenharmony_ci } 1188cb93a386Sopenharmony_ci 1189cb93a386Sopenharmony_ci return name; 1190cb93a386Sopenharmony_ci} 1191cb93a386Sopenharmony_ci 1192cb93a386Sopenharmony_civoid MetalCodeGenerator::writeConstructorCompoundVector(const ConstructorCompound& c, 1193cb93a386Sopenharmony_ci Precedence parentPrecedence) { 1194cb93a386Sopenharmony_ci SkASSERT(c.type().isVector()); 1195cb93a386Sopenharmony_ci 1196cb93a386Sopenharmony_ci // Metal supports constructing vectors from a mix of scalars and vectors, but not matrices. 1197cb93a386Sopenharmony_ci // GLSL supports vec4(mat2x2), so we detect that case here and emit a helper function. 1198cb93a386Sopenharmony_ci if (c.type().columns() == 4 && c.argumentSpan().size() == 1) { 1199cb93a386Sopenharmony_ci const Expression& expr = *c.argumentSpan().front(); 1200cb93a386Sopenharmony_ci if (expr.type().isMatrix()) { 1201cb93a386Sopenharmony_ci this->write(this->getVectorFromMat2x2ConstructorHelper(expr.type())); 1202cb93a386Sopenharmony_ci this->write("("); 1203cb93a386Sopenharmony_ci this->writeExpression(expr, Precedence::kSequence); 1204cb93a386Sopenharmony_ci this->write(")"); 1205cb93a386Sopenharmony_ci return; 1206cb93a386Sopenharmony_ci } 1207cb93a386Sopenharmony_ci } 1208cb93a386Sopenharmony_ci 1209cb93a386Sopenharmony_ci this->writeAnyConstructor(c, "(", ")", parentPrecedence); 1210cb93a386Sopenharmony_ci} 1211cb93a386Sopenharmony_ci 1212cb93a386Sopenharmony_civoid MetalCodeGenerator::writeConstructorCompoundMatrix(const ConstructorCompound& c, 1213cb93a386Sopenharmony_ci Precedence parentPrecedence) { 1214cb93a386Sopenharmony_ci SkASSERT(c.type().isMatrix()); 1215cb93a386Sopenharmony_ci 1216cb93a386Sopenharmony_ci // Emit and invoke a matrix-constructor helper method if one is necessary. 1217cb93a386Sopenharmony_ci if (this->matrixConstructHelperIsNeeded(c)) { 1218cb93a386Sopenharmony_ci this->write(this->getMatrixConstructHelper(c)); 1219cb93a386Sopenharmony_ci this->write("("); 1220cb93a386Sopenharmony_ci const char* separator = ""; 1221cb93a386Sopenharmony_ci for (const std::unique_ptr<Expression>& expr : c.arguments()) { 1222cb93a386Sopenharmony_ci this->write(separator); 1223cb93a386Sopenharmony_ci separator = ", "; 1224cb93a386Sopenharmony_ci this->writeExpression(*expr, Precedence::kSequence); 1225cb93a386Sopenharmony_ci } 1226cb93a386Sopenharmony_ci this->write(")"); 1227cb93a386Sopenharmony_ci return; 1228cb93a386Sopenharmony_ci } 1229cb93a386Sopenharmony_ci 1230cb93a386Sopenharmony_ci // Metal doesn't allow creating matrices by passing in scalars and vectors in a jumble; it 1231cb93a386Sopenharmony_ci // requires your scalars to be grouped up into columns. Because `matrixConstructHelperIsNeeded` 1232cb93a386Sopenharmony_ci // returned false, we know that none of our scalars/vectors "wrap" across across a column, so we 1233cb93a386Sopenharmony_ci // can group our inputs up and synthesize a constructor for each column. 1234cb93a386Sopenharmony_ci const Type& matrixType = c.type(); 1235cb93a386Sopenharmony_ci const Type& columnType = matrixType.componentType().toCompound( 1236cb93a386Sopenharmony_ci fContext, /*columns=*/matrixType.rows(), /*rows=*/1); 1237cb93a386Sopenharmony_ci 1238cb93a386Sopenharmony_ci this->writeType(matrixType); 1239cb93a386Sopenharmony_ci this->write("("); 1240cb93a386Sopenharmony_ci const char* separator = ""; 1241cb93a386Sopenharmony_ci int scalarCount = 0; 1242cb93a386Sopenharmony_ci for (const std::unique_ptr<Expression>& arg : c.arguments()) { 1243cb93a386Sopenharmony_ci this->write(separator); 1244cb93a386Sopenharmony_ci separator = ", "; 1245cb93a386Sopenharmony_ci if (arg->type().columns() < matrixType.rows()) { 1246cb93a386Sopenharmony_ci // Write a `floatN(` constructor to group scalars and smaller vectors together. 1247cb93a386Sopenharmony_ci if (!scalarCount) { 1248cb93a386Sopenharmony_ci this->writeType(columnType); 1249cb93a386Sopenharmony_ci this->write("("); 1250cb93a386Sopenharmony_ci } 1251cb93a386Sopenharmony_ci scalarCount += arg->type().columns(); 1252cb93a386Sopenharmony_ci } 1253cb93a386Sopenharmony_ci this->writeExpression(*arg, Precedence::kSequence); 1254cb93a386Sopenharmony_ci if (scalarCount && scalarCount == matrixType.rows()) { 1255cb93a386Sopenharmony_ci // Close our `floatN(...` constructor block from above. 1256cb93a386Sopenharmony_ci this->write(")"); 1257cb93a386Sopenharmony_ci scalarCount = 0; 1258cb93a386Sopenharmony_ci } 1259cb93a386Sopenharmony_ci } 1260cb93a386Sopenharmony_ci this->write(")"); 1261cb93a386Sopenharmony_ci} 1262cb93a386Sopenharmony_ci 1263cb93a386Sopenharmony_civoid MetalCodeGenerator::writeAnyConstructor(const AnyConstructor& c, 1264cb93a386Sopenharmony_ci const char* leftBracket, 1265cb93a386Sopenharmony_ci const char* rightBracket, 1266cb93a386Sopenharmony_ci Precedence parentPrecedence) { 1267cb93a386Sopenharmony_ci this->writeType(c.type()); 1268cb93a386Sopenharmony_ci this->write(leftBracket); 1269cb93a386Sopenharmony_ci const char* separator = ""; 1270cb93a386Sopenharmony_ci for (const std::unique_ptr<Expression>& arg : c.argumentSpan()) { 1271cb93a386Sopenharmony_ci this->write(separator); 1272cb93a386Sopenharmony_ci separator = ", "; 1273cb93a386Sopenharmony_ci this->writeExpression(*arg, Precedence::kSequence); 1274cb93a386Sopenharmony_ci } 1275cb93a386Sopenharmony_ci this->write(rightBracket); 1276cb93a386Sopenharmony_ci} 1277cb93a386Sopenharmony_ci 1278cb93a386Sopenharmony_civoid MetalCodeGenerator::writeCastConstructor(const AnyConstructor& c, 1279cb93a386Sopenharmony_ci const char* leftBracket, 1280cb93a386Sopenharmony_ci const char* rightBracket, 1281cb93a386Sopenharmony_ci Precedence parentPrecedence) { 1282cb93a386Sopenharmony_ci return this->writeAnyConstructor(c, leftBracket, rightBracket, parentPrecedence); 1283cb93a386Sopenharmony_ci} 1284cb93a386Sopenharmony_ci 1285cb93a386Sopenharmony_civoid MetalCodeGenerator::writeFragCoord() { 1286cb93a386Sopenharmony_ci SkASSERT(fRTFlipName.length()); 1287cb93a386Sopenharmony_ci this->write("float4(_fragCoord.x, "); 1288cb93a386Sopenharmony_ci this->write(fRTFlipName.c_str()); 1289cb93a386Sopenharmony_ci this->write(".x + "); 1290cb93a386Sopenharmony_ci this->write(fRTFlipName.c_str()); 1291cb93a386Sopenharmony_ci this->write(".y * _fragCoord.y, 0.0, _fragCoord.w)"); 1292cb93a386Sopenharmony_ci} 1293cb93a386Sopenharmony_ci 1294cb93a386Sopenharmony_civoid MetalCodeGenerator::writeVariableReference(const VariableReference& ref) { 1295cb93a386Sopenharmony_ci // When assembling out-param helper functions, we copy variables into local clones with matching 1296cb93a386Sopenharmony_ci // names. We never want to prepend "_in." or "_globals." when writing these variables since 1297cb93a386Sopenharmony_ci // we're actually targeting the clones. 1298cb93a386Sopenharmony_ci if (fIgnoreVariableReferenceModifiers) { 1299cb93a386Sopenharmony_ci this->writeName(ref.variable()->name()); 1300cb93a386Sopenharmony_ci return; 1301cb93a386Sopenharmony_ci } 1302cb93a386Sopenharmony_ci 1303cb93a386Sopenharmony_ci switch (ref.variable()->modifiers().fLayout.fBuiltin) { 1304cb93a386Sopenharmony_ci case SK_FRAGCOLOR_BUILTIN: 1305cb93a386Sopenharmony_ci this->write("_out.sk_FragColor"); 1306cb93a386Sopenharmony_ci break; 1307cb93a386Sopenharmony_ci case SK_FRAGCOORD_BUILTIN: 1308cb93a386Sopenharmony_ci this->writeFragCoord(); 1309cb93a386Sopenharmony_ci break; 1310cb93a386Sopenharmony_ci case SK_VERTEXID_BUILTIN: 1311cb93a386Sopenharmony_ci this->write("sk_VertexID"); 1312cb93a386Sopenharmony_ci break; 1313cb93a386Sopenharmony_ci case SK_INSTANCEID_BUILTIN: 1314cb93a386Sopenharmony_ci this->write("sk_InstanceID"); 1315cb93a386Sopenharmony_ci break; 1316cb93a386Sopenharmony_ci case SK_CLOCKWISE_BUILTIN: 1317cb93a386Sopenharmony_ci // We'd set the front facing winding in the MTLRenderCommandEncoder to be counter 1318cb93a386Sopenharmony_ci // clockwise to match Skia convention. 1319cb93a386Sopenharmony_ci this->write("(" + fRTFlipName + ".y < 0 ? _frontFacing : !_frontFacing)"); 1320cb93a386Sopenharmony_ci break; 1321cb93a386Sopenharmony_ci default: 1322cb93a386Sopenharmony_ci const Variable& var = *ref.variable(); 1323cb93a386Sopenharmony_ci if (var.storage() == Variable::Storage::kGlobal) { 1324cb93a386Sopenharmony_ci if (var.modifiers().fFlags & Modifiers::kIn_Flag) { 1325cb93a386Sopenharmony_ci this->write("_in."); 1326cb93a386Sopenharmony_ci } else if (var.modifiers().fFlags & Modifiers::kOut_Flag) { 1327cb93a386Sopenharmony_ci this->write("_out."); 1328cb93a386Sopenharmony_ci } else if (var.modifiers().fFlags & Modifiers::kUniform_Flag && 1329cb93a386Sopenharmony_ci var.type().typeKind() != Type::TypeKind::kSampler) { 1330cb93a386Sopenharmony_ci this->write("_uniforms."); 1331cb93a386Sopenharmony_ci } else { 1332cb93a386Sopenharmony_ci this->write("_globals."); 1333cb93a386Sopenharmony_ci } 1334cb93a386Sopenharmony_ci } 1335cb93a386Sopenharmony_ci this->writeName(var.name()); 1336cb93a386Sopenharmony_ci } 1337cb93a386Sopenharmony_ci} 1338cb93a386Sopenharmony_ci 1339cb93a386Sopenharmony_civoid MetalCodeGenerator::writeIndexExpression(const IndexExpression& expr) { 1340cb93a386Sopenharmony_ci this->writeExpression(*expr.base(), Precedence::kPostfix); 1341cb93a386Sopenharmony_ci this->write("["); 1342cb93a386Sopenharmony_ci this->writeExpression(*expr.index(), Precedence::kTopLevel); 1343cb93a386Sopenharmony_ci this->write("]"); 1344cb93a386Sopenharmony_ci} 1345cb93a386Sopenharmony_ci 1346cb93a386Sopenharmony_civoid MetalCodeGenerator::writeFieldAccess(const FieldAccess& f) { 1347cb93a386Sopenharmony_ci const Type::Field* field = &f.base()->type().fields()[f.fieldIndex()]; 1348cb93a386Sopenharmony_ci if (FieldAccess::OwnerKind::kDefault == f.ownerKind()) { 1349cb93a386Sopenharmony_ci this->writeExpression(*f.base(), Precedence::kPostfix); 1350cb93a386Sopenharmony_ci this->write("."); 1351cb93a386Sopenharmony_ci } 1352cb93a386Sopenharmony_ci switch (field->fModifiers.fLayout.fBuiltin) { 1353cb93a386Sopenharmony_ci case SK_POSITION_BUILTIN: 1354cb93a386Sopenharmony_ci this->write("_out.sk_Position"); 1355cb93a386Sopenharmony_ci break; 1356cb93a386Sopenharmony_ci default: 1357cb93a386Sopenharmony_ci if (field->fName == "sk_PointSize") { 1358cb93a386Sopenharmony_ci this->write("_out.sk_PointSize"); 1359cb93a386Sopenharmony_ci } else { 1360cb93a386Sopenharmony_ci if (FieldAccess::OwnerKind::kAnonymousInterfaceBlock == f.ownerKind()) { 1361cb93a386Sopenharmony_ci this->write("_globals."); 1362cb93a386Sopenharmony_ci this->write(fInterfaceBlockNameMap[fInterfaceBlockMap[field]]); 1363cb93a386Sopenharmony_ci this->write("->"); 1364cb93a386Sopenharmony_ci } 1365cb93a386Sopenharmony_ci this->writeName(field->fName); 1366cb93a386Sopenharmony_ci } 1367cb93a386Sopenharmony_ci } 1368cb93a386Sopenharmony_ci} 1369cb93a386Sopenharmony_ci 1370cb93a386Sopenharmony_civoid MetalCodeGenerator::writeSwizzle(const Swizzle& swizzle) { 1371cb93a386Sopenharmony_ci this->writeExpression(*swizzle.base(), Precedence::kPostfix); 1372cb93a386Sopenharmony_ci this->write("."); 1373cb93a386Sopenharmony_ci for (int c : swizzle.components()) { 1374cb93a386Sopenharmony_ci SkASSERT(c >= 0 && c <= 3); 1375cb93a386Sopenharmony_ci this->write(&("x\0y\0z\0w\0"[c * 2])); 1376cb93a386Sopenharmony_ci } 1377cb93a386Sopenharmony_ci} 1378cb93a386Sopenharmony_ci 1379cb93a386Sopenharmony_civoid MetalCodeGenerator::writeMatrixTimesEqualHelper(const Type& left, const Type& right, 1380cb93a386Sopenharmony_ci const Type& result) { 1381cb93a386Sopenharmony_ci SkASSERT(left.isMatrix()); 1382cb93a386Sopenharmony_ci SkASSERT(right.isMatrix()); 1383cb93a386Sopenharmony_ci SkASSERT(result.isMatrix()); 1384cb93a386Sopenharmony_ci SkASSERT(left.rows() == right.rows()); 1385cb93a386Sopenharmony_ci SkASSERT(left.columns() == right.columns()); 1386cb93a386Sopenharmony_ci SkASSERT(left.rows() == result.rows()); 1387cb93a386Sopenharmony_ci SkASSERT(left.columns() == result.columns()); 1388cb93a386Sopenharmony_ci 1389cb93a386Sopenharmony_ci String key = "Matrix *= " + this->typeName(left) + ":" + this->typeName(right); 1390cb93a386Sopenharmony_ci 1391cb93a386Sopenharmony_ci auto [iter, wasInserted] = fHelpers.insert(key); 1392cb93a386Sopenharmony_ci if (wasInserted) { 1393cb93a386Sopenharmony_ci fExtraFunctions.printf("thread %s& operator*=(thread %s& left, thread const %s& right) {\n" 1394cb93a386Sopenharmony_ci " left = left * right;\n" 1395cb93a386Sopenharmony_ci " return left;\n" 1396cb93a386Sopenharmony_ci "}\n", 1397cb93a386Sopenharmony_ci this->typeName(result).c_str(), this->typeName(left).c_str(), 1398cb93a386Sopenharmony_ci this->typeName(right).c_str()); 1399cb93a386Sopenharmony_ci } 1400cb93a386Sopenharmony_ci} 1401cb93a386Sopenharmony_ci 1402cb93a386Sopenharmony_civoid MetalCodeGenerator::writeMatrixEqualityHelpers(const Type& left, const Type& right) { 1403cb93a386Sopenharmony_ci SkASSERT(left.isMatrix()); 1404cb93a386Sopenharmony_ci SkASSERT(right.isMatrix()); 1405cb93a386Sopenharmony_ci SkASSERT(left.rows() == right.rows()); 1406cb93a386Sopenharmony_ci SkASSERT(left.columns() == right.columns()); 1407cb93a386Sopenharmony_ci 1408cb93a386Sopenharmony_ci String key = "Matrix == " + this->typeName(left) + ":" + this->typeName(right); 1409cb93a386Sopenharmony_ci 1410cb93a386Sopenharmony_ci auto [iter, wasInserted] = fHelpers.insert(key); 1411cb93a386Sopenharmony_ci if (wasInserted) { 1412cb93a386Sopenharmony_ci fExtraFunctionPrototypes.printf(R"( 1413cb93a386Sopenharmony_cithread bool operator==(const %s left, const %s right); 1414cb93a386Sopenharmony_cithread bool operator!=(const %s left, const %s right); 1415cb93a386Sopenharmony_ci)", 1416cb93a386Sopenharmony_ci this->typeName(left).c_str(), 1417cb93a386Sopenharmony_ci this->typeName(right).c_str(), 1418cb93a386Sopenharmony_ci this->typeName(left).c_str(), 1419cb93a386Sopenharmony_ci this->typeName(right).c_str()); 1420cb93a386Sopenharmony_ci 1421cb93a386Sopenharmony_ci fExtraFunctions.printf( 1422cb93a386Sopenharmony_ci "thread bool operator==(const %s left, const %s right) {\n" 1423cb93a386Sopenharmony_ci " return ", 1424cb93a386Sopenharmony_ci this->typeName(left).c_str(), this->typeName(right).c_str()); 1425cb93a386Sopenharmony_ci 1426cb93a386Sopenharmony_ci const char* separator = ""; 1427cb93a386Sopenharmony_ci for (int index=0; index<left.columns(); ++index) { 1428cb93a386Sopenharmony_ci fExtraFunctions.printf("%sall(left[%d] == right[%d])", separator, index, index); 1429cb93a386Sopenharmony_ci separator = " &&\n "; 1430cb93a386Sopenharmony_ci } 1431cb93a386Sopenharmony_ci 1432cb93a386Sopenharmony_ci fExtraFunctions.printf( 1433cb93a386Sopenharmony_ci ";\n" 1434cb93a386Sopenharmony_ci "}\n" 1435cb93a386Sopenharmony_ci "thread bool operator!=(const %s left, const %s right) {\n" 1436cb93a386Sopenharmony_ci " return !(left == right);\n" 1437cb93a386Sopenharmony_ci "}\n", 1438cb93a386Sopenharmony_ci this->typeName(left).c_str(), this->typeName(right).c_str()); 1439cb93a386Sopenharmony_ci } 1440cb93a386Sopenharmony_ci} 1441cb93a386Sopenharmony_ci 1442cb93a386Sopenharmony_civoid MetalCodeGenerator::writeMatrixDivisionHelpers(const Type& type) { 1443cb93a386Sopenharmony_ci SkASSERT(type.isMatrix()); 1444cb93a386Sopenharmony_ci 1445cb93a386Sopenharmony_ci String key = "Matrix / " + this->typeName(type); 1446cb93a386Sopenharmony_ci 1447cb93a386Sopenharmony_ci auto [iter, wasInserted] = fHelpers.insert(key); 1448cb93a386Sopenharmony_ci if (wasInserted) { 1449cb93a386Sopenharmony_ci String typeName = this->typeName(type); 1450cb93a386Sopenharmony_ci 1451cb93a386Sopenharmony_ci fExtraFunctions.printf( 1452cb93a386Sopenharmony_ci "thread %s operator/(const %s left, const %s right) {\n" 1453cb93a386Sopenharmony_ci " return %s(", 1454cb93a386Sopenharmony_ci typeName.c_str(), typeName.c_str(), typeName.c_str(), typeName.c_str()); 1455cb93a386Sopenharmony_ci 1456cb93a386Sopenharmony_ci const char* separator = ""; 1457cb93a386Sopenharmony_ci for (int index=0; index<type.columns(); ++index) { 1458cb93a386Sopenharmony_ci fExtraFunctions.printf("%sleft[%d] / right[%d]", separator, index, index); 1459cb93a386Sopenharmony_ci separator = ", "; 1460cb93a386Sopenharmony_ci } 1461cb93a386Sopenharmony_ci 1462cb93a386Sopenharmony_ci fExtraFunctions.printf(");\n" 1463cb93a386Sopenharmony_ci "}\n" 1464cb93a386Sopenharmony_ci "thread %s& operator/=(thread %s& left, thread const %s& right) {\n" 1465cb93a386Sopenharmony_ci " left = left / right;\n" 1466cb93a386Sopenharmony_ci " return left;\n" 1467cb93a386Sopenharmony_ci "}\n", 1468cb93a386Sopenharmony_ci typeName.c_str(), typeName.c_str(), typeName.c_str()); 1469cb93a386Sopenharmony_ci } 1470cb93a386Sopenharmony_ci} 1471cb93a386Sopenharmony_ci 1472cb93a386Sopenharmony_civoid MetalCodeGenerator::writeArrayEqualityHelpers(const Type& type) { 1473cb93a386Sopenharmony_ci SkASSERT(type.isArray()); 1474cb93a386Sopenharmony_ci 1475cb93a386Sopenharmony_ci // If the array's component type needs a helper as well, we need to emit that one first. 1476cb93a386Sopenharmony_ci this->writeEqualityHelpers(type.componentType(), type.componentType()); 1477cb93a386Sopenharmony_ci 1478cb93a386Sopenharmony_ci auto [iter, wasInserted] = fHelpers.insert("ArrayEquality []"); 1479cb93a386Sopenharmony_ci if (wasInserted) { 1480cb93a386Sopenharmony_ci fExtraFunctionPrototypes.writeText(R"( 1481cb93a386Sopenharmony_citemplate <typename T1, typename T2, size_t N> 1482cb93a386Sopenharmony_cibool operator==(thread const array<T1, N>& left, thread const array<T2, N>& right); 1483cb93a386Sopenharmony_citemplate <typename T1, typename T2, size_t N> 1484cb93a386Sopenharmony_cibool operator!=(thread const array<T1, N>& left, thread const array<T2, N>& right); 1485cb93a386Sopenharmony_ci)"); 1486cb93a386Sopenharmony_ci fExtraFunctions.writeText(R"( 1487cb93a386Sopenharmony_citemplate <typename T1, typename T2, size_t N> 1488cb93a386Sopenharmony_cibool operator==(thread const array<T1, N>& left, thread const array<T2, N>& right) { 1489cb93a386Sopenharmony_ci for (size_t index = 0; index < N; ++index) { 1490cb93a386Sopenharmony_ci if (!all(left[index] == right[index])) { 1491cb93a386Sopenharmony_ci return false; 1492cb93a386Sopenharmony_ci } 1493cb93a386Sopenharmony_ci } 1494cb93a386Sopenharmony_ci return true; 1495cb93a386Sopenharmony_ci} 1496cb93a386Sopenharmony_ci 1497cb93a386Sopenharmony_citemplate <typename T1, typename T2, size_t N> 1498cb93a386Sopenharmony_cibool operator!=(thread const array<T1, N>& left, thread const array<T2, N>& right) { 1499cb93a386Sopenharmony_ci return !(left == right); 1500cb93a386Sopenharmony_ci} 1501cb93a386Sopenharmony_ci)"); 1502cb93a386Sopenharmony_ci } 1503cb93a386Sopenharmony_ci} 1504cb93a386Sopenharmony_ci 1505cb93a386Sopenharmony_civoid MetalCodeGenerator::writeStructEqualityHelpers(const Type& type) { 1506cb93a386Sopenharmony_ci SkASSERT(type.isStruct()); 1507cb93a386Sopenharmony_ci String key = "StructEquality " + this->typeName(type); 1508cb93a386Sopenharmony_ci 1509cb93a386Sopenharmony_ci auto [iter, wasInserted] = fHelpers.insert(key); 1510cb93a386Sopenharmony_ci if (wasInserted) { 1511cb93a386Sopenharmony_ci // If one of the struct's fields needs a helper as well, we need to emit that one first. 1512cb93a386Sopenharmony_ci for (const Type::Field& field : type.fields()) { 1513cb93a386Sopenharmony_ci this->writeEqualityHelpers(*field.fType, *field.fType); 1514cb93a386Sopenharmony_ci } 1515cb93a386Sopenharmony_ci 1516cb93a386Sopenharmony_ci // Write operator== and operator!= for this struct, since those are assumed to exist in SkSL 1517cb93a386Sopenharmony_ci // and GLSL but do not exist by default in Metal. 1518cb93a386Sopenharmony_ci fExtraFunctionPrototypes.printf(R"( 1519cb93a386Sopenharmony_cithread bool operator==(thread const %s& left, thread const %s& right); 1520cb93a386Sopenharmony_cithread bool operator!=(thread const %s& left, thread const %s& right); 1521cb93a386Sopenharmony_ci)", 1522cb93a386Sopenharmony_ci this->typeName(type).c_str(), 1523cb93a386Sopenharmony_ci this->typeName(type).c_str(), 1524cb93a386Sopenharmony_ci this->typeName(type).c_str(), 1525cb93a386Sopenharmony_ci this->typeName(type).c_str()); 1526cb93a386Sopenharmony_ci 1527cb93a386Sopenharmony_ci fExtraFunctions.printf( 1528cb93a386Sopenharmony_ci "thread bool operator==(thread const %s& left, thread const %s& right) {\n" 1529cb93a386Sopenharmony_ci " return ", 1530cb93a386Sopenharmony_ci this->typeName(type).c_str(), 1531cb93a386Sopenharmony_ci this->typeName(type).c_str()); 1532cb93a386Sopenharmony_ci 1533cb93a386Sopenharmony_ci const char* separator = ""; 1534cb93a386Sopenharmony_ci for (const Type::Field& field : type.fields()) { 1535cb93a386Sopenharmony_ci fExtraFunctions.printf("%sall(left.%.*s == right.%.*s)", 1536cb93a386Sopenharmony_ci separator, 1537cb93a386Sopenharmony_ci (int)field.fName.size(), field.fName.data(), 1538cb93a386Sopenharmony_ci (int)field.fName.size(), field.fName.data()); 1539cb93a386Sopenharmony_ci separator = " &&\n "; 1540cb93a386Sopenharmony_ci } 1541cb93a386Sopenharmony_ci fExtraFunctions.printf( 1542cb93a386Sopenharmony_ci ";\n" 1543cb93a386Sopenharmony_ci "}\n" 1544cb93a386Sopenharmony_ci "thread bool operator!=(thread const %s& left, thread const %s& right) {\n" 1545cb93a386Sopenharmony_ci " return !(left == right);\n" 1546cb93a386Sopenharmony_ci "}\n", 1547cb93a386Sopenharmony_ci this->typeName(type).c_str(), 1548cb93a386Sopenharmony_ci this->typeName(type).c_str()); 1549cb93a386Sopenharmony_ci } 1550cb93a386Sopenharmony_ci} 1551cb93a386Sopenharmony_ci 1552cb93a386Sopenharmony_civoid MetalCodeGenerator::writeEqualityHelpers(const Type& leftType, const Type& rightType) { 1553cb93a386Sopenharmony_ci if (leftType.isArray() && rightType.isArray()) { 1554cb93a386Sopenharmony_ci this->writeArrayEqualityHelpers(leftType); 1555cb93a386Sopenharmony_ci return; 1556cb93a386Sopenharmony_ci } 1557cb93a386Sopenharmony_ci if (leftType.isStruct() && rightType.isStruct()) { 1558cb93a386Sopenharmony_ci this->writeStructEqualityHelpers(leftType); 1559cb93a386Sopenharmony_ci return; 1560cb93a386Sopenharmony_ci } 1561cb93a386Sopenharmony_ci if (leftType.isMatrix() && rightType.isMatrix()) { 1562cb93a386Sopenharmony_ci this->writeMatrixEqualityHelpers(leftType, rightType); 1563cb93a386Sopenharmony_ci return; 1564cb93a386Sopenharmony_ci } 1565cb93a386Sopenharmony_ci} 1566cb93a386Sopenharmony_ci 1567cb93a386Sopenharmony_civoid MetalCodeGenerator::writeNumberAsMatrix(const Expression& expr, const Type& matrixType) { 1568cb93a386Sopenharmony_ci SkASSERT(expr.type().isNumber()); 1569cb93a386Sopenharmony_ci SkASSERT(matrixType.isMatrix()); 1570cb93a386Sopenharmony_ci 1571cb93a386Sopenharmony_ci // Componentwise multiply the scalar against a matrix of the desired size which contains all 1s. 1572cb93a386Sopenharmony_ci this->write("("); 1573cb93a386Sopenharmony_ci this->writeType(matrixType); 1574cb93a386Sopenharmony_ci this->write("("); 1575cb93a386Sopenharmony_ci 1576cb93a386Sopenharmony_ci const char* separator = ""; 1577cb93a386Sopenharmony_ci for (int index = matrixType.slotCount(); index--;) { 1578cb93a386Sopenharmony_ci this->write(separator); 1579cb93a386Sopenharmony_ci this->write("1.0"); 1580cb93a386Sopenharmony_ci separator = ", "; 1581cb93a386Sopenharmony_ci } 1582cb93a386Sopenharmony_ci 1583cb93a386Sopenharmony_ci this->write(") * "); 1584cb93a386Sopenharmony_ci this->writeExpression(expr, Precedence::kMultiplicative); 1585cb93a386Sopenharmony_ci this->write(")"); 1586cb93a386Sopenharmony_ci} 1587cb93a386Sopenharmony_ci 1588cb93a386Sopenharmony_civoid MetalCodeGenerator::writeBinaryExpression(const BinaryExpression& b, 1589cb93a386Sopenharmony_ci Precedence parentPrecedence) { 1590cb93a386Sopenharmony_ci const Expression& left = *b.left(); 1591cb93a386Sopenharmony_ci const Expression& right = *b.right(); 1592cb93a386Sopenharmony_ci const Type& leftType = left.type(); 1593cb93a386Sopenharmony_ci const Type& rightType = right.type(); 1594cb93a386Sopenharmony_ci Operator op = b.getOperator(); 1595cb93a386Sopenharmony_ci Precedence precedence = op.getBinaryPrecedence(); 1596cb93a386Sopenharmony_ci bool needParens = precedence >= parentPrecedence; 1597cb93a386Sopenharmony_ci switch (op.kind()) { 1598cb93a386Sopenharmony_ci case Token::Kind::TK_EQEQ: 1599cb93a386Sopenharmony_ci this->writeEqualityHelpers(leftType, rightType); 1600cb93a386Sopenharmony_ci if (leftType.isVector()) { 1601cb93a386Sopenharmony_ci this->write("all"); 1602cb93a386Sopenharmony_ci needParens = true; 1603cb93a386Sopenharmony_ci } 1604cb93a386Sopenharmony_ci break; 1605cb93a386Sopenharmony_ci case Token::Kind::TK_NEQ: 1606cb93a386Sopenharmony_ci this->writeEqualityHelpers(leftType, rightType); 1607cb93a386Sopenharmony_ci if (leftType.isVector()) { 1608cb93a386Sopenharmony_ci this->write("any"); 1609cb93a386Sopenharmony_ci needParens = true; 1610cb93a386Sopenharmony_ci } 1611cb93a386Sopenharmony_ci break; 1612cb93a386Sopenharmony_ci default: 1613cb93a386Sopenharmony_ci break; 1614cb93a386Sopenharmony_ci } 1615cb93a386Sopenharmony_ci if (leftType.isMatrix() && rightType.isMatrix() && op.kind() == Token::Kind::TK_STAREQ) { 1616cb93a386Sopenharmony_ci this->writeMatrixTimesEqualHelper(leftType, rightType, b.type()); 1617cb93a386Sopenharmony_ci } 1618cb93a386Sopenharmony_ci if (op.removeAssignment().kind() == Token::Kind::TK_SLASH && 1619cb93a386Sopenharmony_ci ((leftType.isMatrix() && rightType.isMatrix()) || 1620cb93a386Sopenharmony_ci (leftType.isScalar() && rightType.isMatrix()) || 1621cb93a386Sopenharmony_ci (leftType.isMatrix() && rightType.isScalar()))) { 1622cb93a386Sopenharmony_ci this->writeMatrixDivisionHelpers(leftType.isMatrix() ? leftType : rightType); 1623cb93a386Sopenharmony_ci } 1624cb93a386Sopenharmony_ci if (needParens) { 1625cb93a386Sopenharmony_ci this->write("("); 1626cb93a386Sopenharmony_ci } 1627cb93a386Sopenharmony_ci bool needMatrixSplatOnScalar = rightType.isMatrix() && leftType.isNumber() && 1628cb93a386Sopenharmony_ci op.isValidForMatrixOrVector() && 1629cb93a386Sopenharmony_ci op.removeAssignment().kind() != Token::Kind::TK_STAR; 1630cb93a386Sopenharmony_ci if (needMatrixSplatOnScalar) { 1631cb93a386Sopenharmony_ci this->writeNumberAsMatrix(left, rightType); 1632cb93a386Sopenharmony_ci } else { 1633cb93a386Sopenharmony_ci this->writeExpression(left, precedence); 1634cb93a386Sopenharmony_ci } 1635cb93a386Sopenharmony_ci if (op.kind() != Token::Kind::TK_EQ && op.isAssignment() && 1636cb93a386Sopenharmony_ci left.kind() == Expression::Kind::kSwizzle && !left.hasSideEffects()) { 1637cb93a386Sopenharmony_ci // This doesn't compile in Metal: 1638cb93a386Sopenharmony_ci // float4 x = float4(1); 1639cb93a386Sopenharmony_ci // x.xy *= float2x2(...); 1640cb93a386Sopenharmony_ci // with the error message "non-const reference cannot bind to vector element", 1641cb93a386Sopenharmony_ci // but switching it to x.xy = x.xy * float2x2(...) fixes it. We perform this tranformation 1642cb93a386Sopenharmony_ci // as long as the LHS has no side effects, and hope for the best otherwise. 1643cb93a386Sopenharmony_ci this->write(" = "); 1644cb93a386Sopenharmony_ci this->writeExpression(left, Precedence::kAssignment); 1645cb93a386Sopenharmony_ci this->write(" "); 1646cb93a386Sopenharmony_ci this->write(OperatorName(op.removeAssignment())); 1647cb93a386Sopenharmony_ci this->write(" "); 1648cb93a386Sopenharmony_ci } else { 1649cb93a386Sopenharmony_ci this->write(String(" ") + OperatorName(op) + " "); 1650cb93a386Sopenharmony_ci } 1651cb93a386Sopenharmony_ci 1652cb93a386Sopenharmony_ci needMatrixSplatOnScalar = leftType.isMatrix() && rightType.isNumber() && 1653cb93a386Sopenharmony_ci op.isValidForMatrixOrVector() && 1654cb93a386Sopenharmony_ci op.removeAssignment().kind() != Token::Kind::TK_STAR; 1655cb93a386Sopenharmony_ci if (needMatrixSplatOnScalar) { 1656cb93a386Sopenharmony_ci this->writeNumberAsMatrix(right, leftType); 1657cb93a386Sopenharmony_ci } else { 1658cb93a386Sopenharmony_ci this->writeExpression(right, precedence); 1659cb93a386Sopenharmony_ci } 1660cb93a386Sopenharmony_ci if (needParens) { 1661cb93a386Sopenharmony_ci this->write(")"); 1662cb93a386Sopenharmony_ci } 1663cb93a386Sopenharmony_ci} 1664cb93a386Sopenharmony_ci 1665cb93a386Sopenharmony_civoid MetalCodeGenerator::writeTernaryExpression(const TernaryExpression& t, 1666cb93a386Sopenharmony_ci Precedence parentPrecedence) { 1667cb93a386Sopenharmony_ci if (Precedence::kTernary >= parentPrecedence) { 1668cb93a386Sopenharmony_ci this->write("("); 1669cb93a386Sopenharmony_ci } 1670cb93a386Sopenharmony_ci this->writeExpression(*t.test(), Precedence::kTernary); 1671cb93a386Sopenharmony_ci this->write(" ? "); 1672cb93a386Sopenharmony_ci this->writeExpression(*t.ifTrue(), Precedence::kTernary); 1673cb93a386Sopenharmony_ci this->write(" : "); 1674cb93a386Sopenharmony_ci this->writeExpression(*t.ifFalse(), Precedence::kTernary); 1675cb93a386Sopenharmony_ci if (Precedence::kTernary >= parentPrecedence) { 1676cb93a386Sopenharmony_ci this->write(")"); 1677cb93a386Sopenharmony_ci } 1678cb93a386Sopenharmony_ci} 1679cb93a386Sopenharmony_ci 1680cb93a386Sopenharmony_civoid MetalCodeGenerator::writePrefixExpression(const PrefixExpression& p, 1681cb93a386Sopenharmony_ci Precedence parentPrecedence) { 1682cb93a386Sopenharmony_ci if (Precedence::kPrefix >= parentPrecedence) { 1683cb93a386Sopenharmony_ci this->write("("); 1684cb93a386Sopenharmony_ci } 1685cb93a386Sopenharmony_ci this->write(OperatorName(p.getOperator())); 1686cb93a386Sopenharmony_ci this->writeExpression(*p.operand(), Precedence::kPrefix); 1687cb93a386Sopenharmony_ci if (Precedence::kPrefix >= parentPrecedence) { 1688cb93a386Sopenharmony_ci this->write(")"); 1689cb93a386Sopenharmony_ci } 1690cb93a386Sopenharmony_ci} 1691cb93a386Sopenharmony_ci 1692cb93a386Sopenharmony_civoid MetalCodeGenerator::writePostfixExpression(const PostfixExpression& p, 1693cb93a386Sopenharmony_ci Precedence parentPrecedence) { 1694cb93a386Sopenharmony_ci if (Precedence::kPostfix >= parentPrecedence) { 1695cb93a386Sopenharmony_ci this->write("("); 1696cb93a386Sopenharmony_ci } 1697cb93a386Sopenharmony_ci this->writeExpression(*p.operand(), Precedence::kPostfix); 1698cb93a386Sopenharmony_ci this->write(OperatorName(p.getOperator())); 1699cb93a386Sopenharmony_ci if (Precedence::kPostfix >= parentPrecedence) { 1700cb93a386Sopenharmony_ci this->write(")"); 1701cb93a386Sopenharmony_ci } 1702cb93a386Sopenharmony_ci} 1703cb93a386Sopenharmony_ci 1704cb93a386Sopenharmony_civoid MetalCodeGenerator::writeLiteral(const Literal& l) { 1705cb93a386Sopenharmony_ci const Type& type = l.type(); 1706cb93a386Sopenharmony_ci if (type.isFloat()) { 1707cb93a386Sopenharmony_ci this->write(to_string(l.floatValue())); 1708cb93a386Sopenharmony_ci if (!l.type().highPrecision()) { 1709cb93a386Sopenharmony_ci this->write("h"); 1710cb93a386Sopenharmony_ci } 1711cb93a386Sopenharmony_ci return; 1712cb93a386Sopenharmony_ci } 1713cb93a386Sopenharmony_ci if (type.isInteger()) { 1714cb93a386Sopenharmony_ci if (type == *fContext.fTypes.fUInt) { 1715cb93a386Sopenharmony_ci this->write(to_string(l.intValue() & 0xffffffff)); 1716cb93a386Sopenharmony_ci this->write("u"); 1717cb93a386Sopenharmony_ci } else if (type == *fContext.fTypes.fUShort) { 1718cb93a386Sopenharmony_ci this->write(to_string(l.intValue() & 0xffff)); 1719cb93a386Sopenharmony_ci this->write("u"); 1720cb93a386Sopenharmony_ci } else { 1721cb93a386Sopenharmony_ci this->write(to_string(l.intValue())); 1722cb93a386Sopenharmony_ci } 1723cb93a386Sopenharmony_ci return; 1724cb93a386Sopenharmony_ci } 1725cb93a386Sopenharmony_ci SkASSERT(type.isBoolean()); 1726cb93a386Sopenharmony_ci this->write(l.boolValue() ? "true" : "false"); 1727cb93a386Sopenharmony_ci} 1728cb93a386Sopenharmony_ci 1729cb93a386Sopenharmony_civoid MetalCodeGenerator::writeSetting(const Setting& s) { 1730cb93a386Sopenharmony_ci SK_ABORT("internal error; setting was not folded to a constant during compilation\n"); 1731cb93a386Sopenharmony_ci} 1732cb93a386Sopenharmony_ci 1733cb93a386Sopenharmony_civoid MetalCodeGenerator::writeFunctionRequirementArgs(const FunctionDeclaration& f, 1734cb93a386Sopenharmony_ci const char*& separator) { 1735cb93a386Sopenharmony_ci Requirements requirements = this->requirements(f); 1736cb93a386Sopenharmony_ci if (requirements & kInputs_Requirement) { 1737cb93a386Sopenharmony_ci this->write(separator); 1738cb93a386Sopenharmony_ci this->write("_in"); 1739cb93a386Sopenharmony_ci separator = ", "; 1740cb93a386Sopenharmony_ci } 1741cb93a386Sopenharmony_ci if (requirements & kOutputs_Requirement) { 1742cb93a386Sopenharmony_ci this->write(separator); 1743cb93a386Sopenharmony_ci this->write("_out"); 1744cb93a386Sopenharmony_ci separator = ", "; 1745cb93a386Sopenharmony_ci } 1746cb93a386Sopenharmony_ci if (requirements & kUniforms_Requirement) { 1747cb93a386Sopenharmony_ci this->write(separator); 1748cb93a386Sopenharmony_ci this->write("_uniforms"); 1749cb93a386Sopenharmony_ci separator = ", "; 1750cb93a386Sopenharmony_ci } 1751cb93a386Sopenharmony_ci if (requirements & kGlobals_Requirement) { 1752cb93a386Sopenharmony_ci this->write(separator); 1753cb93a386Sopenharmony_ci this->write("_globals"); 1754cb93a386Sopenharmony_ci separator = ", "; 1755cb93a386Sopenharmony_ci } 1756cb93a386Sopenharmony_ci if (requirements & kFragCoord_Requirement) { 1757cb93a386Sopenharmony_ci this->write(separator); 1758cb93a386Sopenharmony_ci this->write("_fragCoord"); 1759cb93a386Sopenharmony_ci separator = ", "; 1760cb93a386Sopenharmony_ci } 1761cb93a386Sopenharmony_ci} 1762cb93a386Sopenharmony_ci 1763cb93a386Sopenharmony_civoid MetalCodeGenerator::writeFunctionRequirementParams(const FunctionDeclaration& f, 1764cb93a386Sopenharmony_ci const char*& separator) { 1765cb93a386Sopenharmony_ci Requirements requirements = this->requirements(f); 1766cb93a386Sopenharmony_ci if (requirements & kInputs_Requirement) { 1767cb93a386Sopenharmony_ci this->write(separator); 1768cb93a386Sopenharmony_ci this->write("Inputs _in"); 1769cb93a386Sopenharmony_ci separator = ", "; 1770cb93a386Sopenharmony_ci } 1771cb93a386Sopenharmony_ci if (requirements & kOutputs_Requirement) { 1772cb93a386Sopenharmony_ci this->write(separator); 1773cb93a386Sopenharmony_ci this->write("thread Outputs& _out"); 1774cb93a386Sopenharmony_ci separator = ", "; 1775cb93a386Sopenharmony_ci } 1776cb93a386Sopenharmony_ci if (requirements & kUniforms_Requirement) { 1777cb93a386Sopenharmony_ci this->write(separator); 1778cb93a386Sopenharmony_ci this->write("Uniforms _uniforms"); 1779cb93a386Sopenharmony_ci separator = ", "; 1780cb93a386Sopenharmony_ci } 1781cb93a386Sopenharmony_ci if (requirements & kGlobals_Requirement) { 1782cb93a386Sopenharmony_ci this->write(separator); 1783cb93a386Sopenharmony_ci this->write("thread Globals& _globals"); 1784cb93a386Sopenharmony_ci separator = ", "; 1785cb93a386Sopenharmony_ci } 1786cb93a386Sopenharmony_ci if (requirements & kFragCoord_Requirement) { 1787cb93a386Sopenharmony_ci this->write(separator); 1788cb93a386Sopenharmony_ci this->write("float4 _fragCoord"); 1789cb93a386Sopenharmony_ci separator = ", "; 1790cb93a386Sopenharmony_ci } 1791cb93a386Sopenharmony_ci} 1792cb93a386Sopenharmony_ci 1793cb93a386Sopenharmony_ciint MetalCodeGenerator::getUniformBinding(const Modifiers& m) { 1794cb93a386Sopenharmony_ci return (m.fLayout.fBinding >= 0) ? m.fLayout.fBinding 1795cb93a386Sopenharmony_ci : fProgram.fConfig->fSettings.fDefaultUniformBinding; 1796cb93a386Sopenharmony_ci} 1797cb93a386Sopenharmony_ci 1798cb93a386Sopenharmony_ciint MetalCodeGenerator::getUniformSet(const Modifiers& m) { 1799cb93a386Sopenharmony_ci return (m.fLayout.fSet >= 0) ? m.fLayout.fSet 1800cb93a386Sopenharmony_ci : fProgram.fConfig->fSettings.fDefaultUniformSet; 1801cb93a386Sopenharmony_ci} 1802cb93a386Sopenharmony_ci 1803cb93a386Sopenharmony_cibool MetalCodeGenerator::writeFunctionDeclaration(const FunctionDeclaration& f) { 1804cb93a386Sopenharmony_ci fRTFlipName = fProgram.fInputs.fUseFlipRTUniform 1805cb93a386Sopenharmony_ci ? "_globals._anonInterface0->" SKSL_RTFLIP_NAME 1806cb93a386Sopenharmony_ci : ""; 1807cb93a386Sopenharmony_ci const char* separator = ""; 1808cb93a386Sopenharmony_ci if (f.isMain()) { 1809cb93a386Sopenharmony_ci switch (fProgram.fConfig->fKind) { 1810cb93a386Sopenharmony_ci case ProgramKind::kFragment: 1811cb93a386Sopenharmony_ci this->write("fragment Outputs fragmentMain"); 1812cb93a386Sopenharmony_ci break; 1813cb93a386Sopenharmony_ci case ProgramKind::kVertex: 1814cb93a386Sopenharmony_ci this->write("vertex Outputs vertexMain"); 1815cb93a386Sopenharmony_ci break; 1816cb93a386Sopenharmony_ci default: 1817cb93a386Sopenharmony_ci fContext.fErrors->error(-1, "unsupported kind of program"); 1818cb93a386Sopenharmony_ci return false; 1819cb93a386Sopenharmony_ci } 1820cb93a386Sopenharmony_ci this->write("(Inputs _in [[stage_in]]"); 1821cb93a386Sopenharmony_ci if (-1 != fUniformBuffer) { 1822cb93a386Sopenharmony_ci this->write(", constant Uniforms& _uniforms [[buffer(" + 1823cb93a386Sopenharmony_ci to_string(fUniformBuffer) + ")]]"); 1824cb93a386Sopenharmony_ci } 1825cb93a386Sopenharmony_ci for (const ProgramElement* e : fProgram.elements()) { 1826cb93a386Sopenharmony_ci if (e->is<GlobalVarDeclaration>()) { 1827cb93a386Sopenharmony_ci const GlobalVarDeclaration& decls = e->as<GlobalVarDeclaration>(); 1828cb93a386Sopenharmony_ci const VarDeclaration& var = decls.declaration()->as<VarDeclaration>(); 1829cb93a386Sopenharmony_ci if (var.var().type().typeKind() == Type::TypeKind::kSampler) { 1830cb93a386Sopenharmony_ci if (var.var().modifiers().fLayout.fBinding < 0) { 1831cb93a386Sopenharmony_ci fContext.fErrors->error(decls.fLine, 1832cb93a386Sopenharmony_ci "Metal samplers must have 'layout(binding=...)'"); 1833cb93a386Sopenharmony_ci return false; 1834cb93a386Sopenharmony_ci } 1835cb93a386Sopenharmony_ci if (var.var().type().dimensions() != SpvDim2D) { 1836cb93a386Sopenharmony_ci // Not yet implemented--Skia currently only uses 2D textures. 1837cb93a386Sopenharmony_ci fContext.fErrors->error(decls.fLine, "Unsupported texture dimensions"); 1838cb93a386Sopenharmony_ci return false; 1839cb93a386Sopenharmony_ci } 1840cb93a386Sopenharmony_ci this->write(", texture2d<half> "); 1841cb93a386Sopenharmony_ci this->writeName(var.var().name()); 1842cb93a386Sopenharmony_ci this->write("[[texture("); 1843cb93a386Sopenharmony_ci this->write(to_string(var.var().modifiers().fLayout.fBinding)); 1844cb93a386Sopenharmony_ci this->write(")]]"); 1845cb93a386Sopenharmony_ci this->write(", sampler "); 1846cb93a386Sopenharmony_ci this->writeName(var.var().name()); 1847cb93a386Sopenharmony_ci this->write(SAMPLER_SUFFIX); 1848cb93a386Sopenharmony_ci this->write("[[sampler("); 1849cb93a386Sopenharmony_ci this->write(to_string(var.var().modifiers().fLayout.fBinding)); 1850cb93a386Sopenharmony_ci this->write(")]]"); 1851cb93a386Sopenharmony_ci } 1852cb93a386Sopenharmony_ci } else if (e->is<InterfaceBlock>()) { 1853cb93a386Sopenharmony_ci const InterfaceBlock& intf = e->as<InterfaceBlock>(); 1854cb93a386Sopenharmony_ci if (intf.typeName() == "sk_PerVertex") { 1855cb93a386Sopenharmony_ci continue; 1856cb93a386Sopenharmony_ci } 1857cb93a386Sopenharmony_ci this->write(", constant "); 1858cb93a386Sopenharmony_ci this->writeType(intf.variable().type()); 1859cb93a386Sopenharmony_ci this->write("& " ); 1860cb93a386Sopenharmony_ci this->write(fInterfaceBlockNameMap[&intf]); 1861cb93a386Sopenharmony_ci this->write(" [[buffer("); 1862cb93a386Sopenharmony_ci this->write(to_string(this->getUniformBinding(intf.variable().modifiers()))); 1863cb93a386Sopenharmony_ci this->write(")]]"); 1864cb93a386Sopenharmony_ci } 1865cb93a386Sopenharmony_ci } 1866cb93a386Sopenharmony_ci if (fProgram.fConfig->fKind == ProgramKind::kFragment) { 1867cb93a386Sopenharmony_ci if (fProgram.fInputs.fUseFlipRTUniform && fInterfaceBlockNameMap.empty()) { 1868cb93a386Sopenharmony_ci this->write(", constant sksl_synthetic_uniforms& _anonInterface0 [[buffer(1)]]"); 1869cb93a386Sopenharmony_ci fRTFlipName = "_anonInterface0." SKSL_RTFLIP_NAME; 1870cb93a386Sopenharmony_ci } 1871cb93a386Sopenharmony_ci this->write(", bool _frontFacing [[front_facing]]"); 1872cb93a386Sopenharmony_ci this->write(", float4 _fragCoord [[position]]"); 1873cb93a386Sopenharmony_ci } else if (fProgram.fConfig->fKind == ProgramKind::kVertex) { 1874cb93a386Sopenharmony_ci this->write(", uint sk_VertexID [[vertex_id]], uint sk_InstanceID [[instance_id]]"); 1875cb93a386Sopenharmony_ci } 1876cb93a386Sopenharmony_ci separator = ", "; 1877cb93a386Sopenharmony_ci } else { 1878cb93a386Sopenharmony_ci this->writeType(f.returnType()); 1879cb93a386Sopenharmony_ci this->write(" "); 1880cb93a386Sopenharmony_ci this->writeName(f.mangledName()); 1881cb93a386Sopenharmony_ci this->write("("); 1882cb93a386Sopenharmony_ci this->writeFunctionRequirementParams(f, separator); 1883cb93a386Sopenharmony_ci } 1884cb93a386Sopenharmony_ci for (const auto& param : f.parameters()) { 1885cb93a386Sopenharmony_ci if (f.isMain() && param->modifiers().fLayout.fBuiltin != -1) { 1886cb93a386Sopenharmony_ci continue; 1887cb93a386Sopenharmony_ci } 1888cb93a386Sopenharmony_ci this->write(separator); 1889cb93a386Sopenharmony_ci separator = ", "; 1890cb93a386Sopenharmony_ci this->writeModifiers(param->modifiers()); 1891cb93a386Sopenharmony_ci const Type* type = ¶m->type(); 1892cb93a386Sopenharmony_ci this->writeType(*type); 1893cb93a386Sopenharmony_ci if (param->modifiers().fFlags & Modifiers::kOut_Flag) { 1894cb93a386Sopenharmony_ci this->write("&"); 1895cb93a386Sopenharmony_ci } 1896cb93a386Sopenharmony_ci this->write(" "); 1897cb93a386Sopenharmony_ci this->writeName(param->name()); 1898cb93a386Sopenharmony_ci } 1899cb93a386Sopenharmony_ci this->write(")"); 1900cb93a386Sopenharmony_ci return true; 1901cb93a386Sopenharmony_ci} 1902cb93a386Sopenharmony_ci 1903cb93a386Sopenharmony_civoid MetalCodeGenerator::writeFunctionPrototype(const FunctionPrototype& f) { 1904cb93a386Sopenharmony_ci this->writeFunctionDeclaration(f.declaration()); 1905cb93a386Sopenharmony_ci this->writeLine(";"); 1906cb93a386Sopenharmony_ci} 1907cb93a386Sopenharmony_ci 1908cb93a386Sopenharmony_cistatic bool is_block_ending_with_return(const Statement* stmt) { 1909cb93a386Sopenharmony_ci // This function detects (potentially nested) blocks that end in a return statement. 1910cb93a386Sopenharmony_ci if (!stmt->is<Block>()) { 1911cb93a386Sopenharmony_ci return false; 1912cb93a386Sopenharmony_ci } 1913cb93a386Sopenharmony_ci const StatementArray& block = stmt->as<Block>().children(); 1914cb93a386Sopenharmony_ci for (int index = block.count(); index--; ) { 1915cb93a386Sopenharmony_ci stmt = block[index].get(); 1916cb93a386Sopenharmony_ci if (stmt->is<ReturnStatement>()) { 1917cb93a386Sopenharmony_ci return true; 1918cb93a386Sopenharmony_ci } 1919cb93a386Sopenharmony_ci if (stmt->is<Block>()) { 1920cb93a386Sopenharmony_ci return is_block_ending_with_return(stmt); 1921cb93a386Sopenharmony_ci } 1922cb93a386Sopenharmony_ci if (!stmt->is<Nop>()) { 1923cb93a386Sopenharmony_ci break; 1924cb93a386Sopenharmony_ci } 1925cb93a386Sopenharmony_ci } 1926cb93a386Sopenharmony_ci return false; 1927cb93a386Sopenharmony_ci} 1928cb93a386Sopenharmony_ci 1929cb93a386Sopenharmony_civoid MetalCodeGenerator::writeFunction(const FunctionDefinition& f) { 1930cb93a386Sopenharmony_ci SkASSERT(!fProgram.fConfig->fSettings.fFragColorIsInOut); 1931cb93a386Sopenharmony_ci 1932cb93a386Sopenharmony_ci if (!this->writeFunctionDeclaration(f.declaration())) { 1933cb93a386Sopenharmony_ci return; 1934cb93a386Sopenharmony_ci } 1935cb93a386Sopenharmony_ci 1936cb93a386Sopenharmony_ci fCurrentFunction = &f.declaration(); 1937cb93a386Sopenharmony_ci SkScopeExit clearCurrentFunction([&] { fCurrentFunction = nullptr; }); 1938cb93a386Sopenharmony_ci 1939cb93a386Sopenharmony_ci this->writeLine(" {"); 1940cb93a386Sopenharmony_ci 1941cb93a386Sopenharmony_ci if (f.declaration().isMain()) { 1942cb93a386Sopenharmony_ci this->writeGlobalInit(); 1943cb93a386Sopenharmony_ci this->writeLine(" Outputs _out;"); 1944cb93a386Sopenharmony_ci this->writeLine(" (void)_out;"); 1945cb93a386Sopenharmony_ci } 1946cb93a386Sopenharmony_ci 1947cb93a386Sopenharmony_ci fFunctionHeader.clear(); 1948cb93a386Sopenharmony_ci StringStream buffer; 1949cb93a386Sopenharmony_ci { 1950cb93a386Sopenharmony_ci AutoOutputStream outputToBuffer(this, &buffer); 1951cb93a386Sopenharmony_ci fIndentation++; 1952cb93a386Sopenharmony_ci for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) { 1953cb93a386Sopenharmony_ci if (!stmt->isEmpty()) { 1954cb93a386Sopenharmony_ci this->writeStatement(*stmt); 1955cb93a386Sopenharmony_ci this->finishLine(); 1956cb93a386Sopenharmony_ci } 1957cb93a386Sopenharmony_ci } 1958cb93a386Sopenharmony_ci if (f.declaration().isMain()) { 1959cb93a386Sopenharmony_ci // If the main function doesn't end with a return, we need to synthesize one here. 1960cb93a386Sopenharmony_ci if (!is_block_ending_with_return(f.body().get())) { 1961cb93a386Sopenharmony_ci this->writeReturnStatementFromMain(); 1962cb93a386Sopenharmony_ci this->finishLine(); 1963cb93a386Sopenharmony_ci } 1964cb93a386Sopenharmony_ci } 1965cb93a386Sopenharmony_ci fIndentation--; 1966cb93a386Sopenharmony_ci this->writeLine("}"); 1967cb93a386Sopenharmony_ci } 1968cb93a386Sopenharmony_ci this->write(fFunctionHeader); 1969cb93a386Sopenharmony_ci this->write(buffer.str()); 1970cb93a386Sopenharmony_ci} 1971cb93a386Sopenharmony_ci 1972cb93a386Sopenharmony_civoid MetalCodeGenerator::writeModifiers(const Modifiers& modifiers) { 1973cb93a386Sopenharmony_ci if (modifiers.fFlags & Modifiers::kOut_Flag) { 1974cb93a386Sopenharmony_ci this->write("thread "); 1975cb93a386Sopenharmony_ci } 1976cb93a386Sopenharmony_ci if (modifiers.fFlags & Modifiers::kConst_Flag) { 1977cb93a386Sopenharmony_ci this->write("const "); 1978cb93a386Sopenharmony_ci } 1979cb93a386Sopenharmony_ci} 1980cb93a386Sopenharmony_ci 1981cb93a386Sopenharmony_civoid MetalCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) { 1982cb93a386Sopenharmony_ci if ("sk_PerVertex" == intf.typeName()) { 1983cb93a386Sopenharmony_ci return; 1984cb93a386Sopenharmony_ci } 1985cb93a386Sopenharmony_ci this->writeModifiers(intf.variable().modifiers()); 1986cb93a386Sopenharmony_ci this->write("struct "); 1987cb93a386Sopenharmony_ci this->writeLine(intf.typeName() + " {"); 1988cb93a386Sopenharmony_ci const Type* structType = &intf.variable().type(); 1989cb93a386Sopenharmony_ci if (structType->isArray()) { 1990cb93a386Sopenharmony_ci structType = &structType->componentType(); 1991cb93a386Sopenharmony_ci } 1992cb93a386Sopenharmony_ci fIndentation++; 1993cb93a386Sopenharmony_ci this->writeFields(structType->fields(), structType->fLine, &intf); 1994cb93a386Sopenharmony_ci if (fProgram.fInputs.fUseFlipRTUniform) { 1995cb93a386Sopenharmony_ci this->writeLine("float2 " SKSL_RTFLIP_NAME ";"); 1996cb93a386Sopenharmony_ci } 1997cb93a386Sopenharmony_ci fIndentation--; 1998cb93a386Sopenharmony_ci this->write("}"); 1999cb93a386Sopenharmony_ci if (intf.instanceName().size()) { 2000cb93a386Sopenharmony_ci this->write(" "); 2001cb93a386Sopenharmony_ci this->write(intf.instanceName()); 2002cb93a386Sopenharmony_ci if (intf.arraySize() > 0) { 2003cb93a386Sopenharmony_ci this->write("["); 2004cb93a386Sopenharmony_ci this->write(to_string(intf.arraySize())); 2005cb93a386Sopenharmony_ci this->write("]"); 2006cb93a386Sopenharmony_ci } 2007cb93a386Sopenharmony_ci fInterfaceBlockNameMap[&intf] = intf.instanceName(); 2008cb93a386Sopenharmony_ci } else { 2009cb93a386Sopenharmony_ci fInterfaceBlockNameMap[&intf] = *fProgram.fSymbols->takeOwnershipOfString("_anonInterface" + 2010cb93a386Sopenharmony_ci to_string(fAnonInterfaceCount++)); 2011cb93a386Sopenharmony_ci } 2012cb93a386Sopenharmony_ci this->writeLine(";"); 2013cb93a386Sopenharmony_ci} 2014cb93a386Sopenharmony_ci 2015cb93a386Sopenharmony_civoid MetalCodeGenerator::writeFields(const std::vector<Type::Field>& fields, int parentLine, 2016cb93a386Sopenharmony_ci const InterfaceBlock* parentIntf) { 2017cb93a386Sopenharmony_ci MemoryLayout memoryLayout(MemoryLayout::kMetal_Standard); 2018cb93a386Sopenharmony_ci int currentOffset = 0; 2019cb93a386Sopenharmony_ci for (const Type::Field& field : fields) { 2020cb93a386Sopenharmony_ci int fieldOffset = field.fModifiers.fLayout.fOffset; 2021cb93a386Sopenharmony_ci const Type* fieldType = field.fType; 2022cb93a386Sopenharmony_ci if (!MemoryLayout::LayoutIsSupported(*fieldType)) { 2023cb93a386Sopenharmony_ci fContext.fErrors->error(parentLine, "type '" + fieldType->name() + 2024cb93a386Sopenharmony_ci "' is not permitted here"); 2025cb93a386Sopenharmony_ci return; 2026cb93a386Sopenharmony_ci } 2027cb93a386Sopenharmony_ci if (fieldOffset != -1) { 2028cb93a386Sopenharmony_ci if (currentOffset > fieldOffset) { 2029cb93a386Sopenharmony_ci fContext.fErrors->error(parentLine, 2030cb93a386Sopenharmony_ci "offset of field '" + field.fName + "' must be at least " + 2031cb93a386Sopenharmony_ci to_string((int) currentOffset)); 2032cb93a386Sopenharmony_ci return; 2033cb93a386Sopenharmony_ci } else if (currentOffset < fieldOffset) { 2034cb93a386Sopenharmony_ci this->write("char pad"); 2035cb93a386Sopenharmony_ci this->write(to_string(fPaddingCount++)); 2036cb93a386Sopenharmony_ci this->write("["); 2037cb93a386Sopenharmony_ci this->write(to_string(fieldOffset - currentOffset)); 2038cb93a386Sopenharmony_ci this->writeLine("];"); 2039cb93a386Sopenharmony_ci currentOffset = fieldOffset; 2040cb93a386Sopenharmony_ci } 2041cb93a386Sopenharmony_ci int alignment = memoryLayout.alignment(*fieldType); 2042cb93a386Sopenharmony_ci if (fieldOffset % alignment) { 2043cb93a386Sopenharmony_ci fContext.fErrors->error(parentLine, 2044cb93a386Sopenharmony_ci "offset of field '" + field.fName + "' must be a multiple of " + 2045cb93a386Sopenharmony_ci to_string((int) alignment)); 2046cb93a386Sopenharmony_ci return; 2047cb93a386Sopenharmony_ci } 2048cb93a386Sopenharmony_ci } 2049cb93a386Sopenharmony_ci size_t fieldSize = memoryLayout.size(*fieldType); 2050cb93a386Sopenharmony_ci if (fieldSize > static_cast<size_t>(std::numeric_limits<int>::max() - currentOffset)) { 2051cb93a386Sopenharmony_ci fContext.fErrors->error(parentLine, "field offset overflow"); 2052cb93a386Sopenharmony_ci return; 2053cb93a386Sopenharmony_ci } 2054cb93a386Sopenharmony_ci currentOffset += fieldSize; 2055cb93a386Sopenharmony_ci this->writeModifiers(field.fModifiers); 2056cb93a386Sopenharmony_ci this->writeType(*fieldType); 2057cb93a386Sopenharmony_ci this->write(" "); 2058cb93a386Sopenharmony_ci this->writeName(field.fName); 2059cb93a386Sopenharmony_ci this->writeLine(";"); 2060cb93a386Sopenharmony_ci if (parentIntf) { 2061cb93a386Sopenharmony_ci fInterfaceBlockMap[&field] = parentIntf; 2062cb93a386Sopenharmony_ci } 2063cb93a386Sopenharmony_ci } 2064cb93a386Sopenharmony_ci} 2065cb93a386Sopenharmony_ci 2066cb93a386Sopenharmony_civoid MetalCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) { 2067cb93a386Sopenharmony_ci this->writeExpression(value, Precedence::kTopLevel); 2068cb93a386Sopenharmony_ci} 2069cb93a386Sopenharmony_ci 2070cb93a386Sopenharmony_civoid MetalCodeGenerator::writeName(skstd::string_view name) { 2071cb93a386Sopenharmony_ci if (fReservedWords.find(name) != fReservedWords.end()) { 2072cb93a386Sopenharmony_ci this->write("_"); // adding underscore before name to avoid conflict with reserved words 2073cb93a386Sopenharmony_ci } 2074cb93a386Sopenharmony_ci this->write(name); 2075cb93a386Sopenharmony_ci} 2076cb93a386Sopenharmony_ci 2077cb93a386Sopenharmony_civoid MetalCodeGenerator::writeVarDeclaration(const VarDeclaration& varDecl) { 2078cb93a386Sopenharmony_ci this->writeModifiers(varDecl.var().modifiers()); 2079cb93a386Sopenharmony_ci this->writeType(varDecl.var().type()); 2080cb93a386Sopenharmony_ci this->write(" "); 2081cb93a386Sopenharmony_ci this->writeName(varDecl.var().name()); 2082cb93a386Sopenharmony_ci if (varDecl.value()) { 2083cb93a386Sopenharmony_ci this->write(" = "); 2084cb93a386Sopenharmony_ci this->writeVarInitializer(varDecl.var(), *varDecl.value()); 2085cb93a386Sopenharmony_ci } 2086cb93a386Sopenharmony_ci this->write(";"); 2087cb93a386Sopenharmony_ci} 2088cb93a386Sopenharmony_ci 2089cb93a386Sopenharmony_civoid MetalCodeGenerator::writeStatement(const Statement& s) { 2090cb93a386Sopenharmony_ci switch (s.kind()) { 2091cb93a386Sopenharmony_ci case Statement::Kind::kBlock: 2092cb93a386Sopenharmony_ci this->writeBlock(s.as<Block>()); 2093cb93a386Sopenharmony_ci break; 2094cb93a386Sopenharmony_ci case Statement::Kind::kExpression: 2095cb93a386Sopenharmony_ci this->writeExpression(*s.as<ExpressionStatement>().expression(), Precedence::kTopLevel); 2096cb93a386Sopenharmony_ci this->write(";"); 2097cb93a386Sopenharmony_ci break; 2098cb93a386Sopenharmony_ci case Statement::Kind::kReturn: 2099cb93a386Sopenharmony_ci this->writeReturnStatement(s.as<ReturnStatement>()); 2100cb93a386Sopenharmony_ci break; 2101cb93a386Sopenharmony_ci case Statement::Kind::kVarDeclaration: 2102cb93a386Sopenharmony_ci this->writeVarDeclaration(s.as<VarDeclaration>()); 2103cb93a386Sopenharmony_ci break; 2104cb93a386Sopenharmony_ci case Statement::Kind::kIf: 2105cb93a386Sopenharmony_ci this->writeIfStatement(s.as<IfStatement>()); 2106cb93a386Sopenharmony_ci break; 2107cb93a386Sopenharmony_ci case Statement::Kind::kFor: 2108cb93a386Sopenharmony_ci this->writeForStatement(s.as<ForStatement>()); 2109cb93a386Sopenharmony_ci break; 2110cb93a386Sopenharmony_ci case Statement::Kind::kDo: 2111cb93a386Sopenharmony_ci this->writeDoStatement(s.as<DoStatement>()); 2112cb93a386Sopenharmony_ci break; 2113cb93a386Sopenharmony_ci case Statement::Kind::kSwitch: 2114cb93a386Sopenharmony_ci this->writeSwitchStatement(s.as<SwitchStatement>()); 2115cb93a386Sopenharmony_ci break; 2116cb93a386Sopenharmony_ci case Statement::Kind::kBreak: 2117cb93a386Sopenharmony_ci this->write("break;"); 2118cb93a386Sopenharmony_ci break; 2119cb93a386Sopenharmony_ci case Statement::Kind::kContinue: 2120cb93a386Sopenharmony_ci this->write("continue;"); 2121cb93a386Sopenharmony_ci break; 2122cb93a386Sopenharmony_ci case Statement::Kind::kDiscard: 2123cb93a386Sopenharmony_ci this->write("discard_fragment();"); 2124cb93a386Sopenharmony_ci break; 2125cb93a386Sopenharmony_ci case Statement::Kind::kInlineMarker: 2126cb93a386Sopenharmony_ci case Statement::Kind::kNop: 2127cb93a386Sopenharmony_ci this->write(";"); 2128cb93a386Sopenharmony_ci break; 2129cb93a386Sopenharmony_ci default: 2130cb93a386Sopenharmony_ci SkDEBUGFAILF("unsupported statement: %s", s.description().c_str()); 2131cb93a386Sopenharmony_ci break; 2132cb93a386Sopenharmony_ci } 2133cb93a386Sopenharmony_ci} 2134cb93a386Sopenharmony_ci 2135cb93a386Sopenharmony_civoid MetalCodeGenerator::writeBlock(const Block& b) { 2136cb93a386Sopenharmony_ci // Write scope markers if this block is a scope, or if the block is empty (since we need to emit 2137cb93a386Sopenharmony_ci // something here to make the code valid). 2138cb93a386Sopenharmony_ci bool isScope = b.isScope() || b.isEmpty(); 2139cb93a386Sopenharmony_ci if (isScope) { 2140cb93a386Sopenharmony_ci this->writeLine("{"); 2141cb93a386Sopenharmony_ci fIndentation++; 2142cb93a386Sopenharmony_ci } 2143cb93a386Sopenharmony_ci for (const std::unique_ptr<Statement>& stmt : b.children()) { 2144cb93a386Sopenharmony_ci if (!stmt->isEmpty()) { 2145cb93a386Sopenharmony_ci this->writeStatement(*stmt); 2146cb93a386Sopenharmony_ci this->finishLine(); 2147cb93a386Sopenharmony_ci } 2148cb93a386Sopenharmony_ci } 2149cb93a386Sopenharmony_ci if (isScope) { 2150cb93a386Sopenharmony_ci fIndentation--; 2151cb93a386Sopenharmony_ci this->write("}"); 2152cb93a386Sopenharmony_ci } 2153cb93a386Sopenharmony_ci} 2154cb93a386Sopenharmony_ci 2155cb93a386Sopenharmony_civoid MetalCodeGenerator::writeIfStatement(const IfStatement& stmt) { 2156cb93a386Sopenharmony_ci this->write("if ("); 2157cb93a386Sopenharmony_ci this->writeExpression(*stmt.test(), Precedence::kTopLevel); 2158cb93a386Sopenharmony_ci this->write(") "); 2159cb93a386Sopenharmony_ci this->writeStatement(*stmt.ifTrue()); 2160cb93a386Sopenharmony_ci if (stmt.ifFalse()) { 2161cb93a386Sopenharmony_ci this->write(" else "); 2162cb93a386Sopenharmony_ci this->writeStatement(*stmt.ifFalse()); 2163cb93a386Sopenharmony_ci } 2164cb93a386Sopenharmony_ci} 2165cb93a386Sopenharmony_ci 2166cb93a386Sopenharmony_civoid MetalCodeGenerator::writeForStatement(const ForStatement& f) { 2167cb93a386Sopenharmony_ci // Emit loops of the form 'for(;test;)' as 'while(test)', which is probably how they started 2168cb93a386Sopenharmony_ci if (!f.initializer() && f.test() && !f.next()) { 2169cb93a386Sopenharmony_ci this->write("while ("); 2170cb93a386Sopenharmony_ci this->writeExpression(*f.test(), Precedence::kTopLevel); 2171cb93a386Sopenharmony_ci this->write(") "); 2172cb93a386Sopenharmony_ci this->writeStatement(*f.statement()); 2173cb93a386Sopenharmony_ci return; 2174cb93a386Sopenharmony_ci } 2175cb93a386Sopenharmony_ci 2176cb93a386Sopenharmony_ci this->write("for ("); 2177cb93a386Sopenharmony_ci if (f.initializer() && !f.initializer()->isEmpty()) { 2178cb93a386Sopenharmony_ci this->writeStatement(*f.initializer()); 2179cb93a386Sopenharmony_ci } else { 2180cb93a386Sopenharmony_ci this->write("; "); 2181cb93a386Sopenharmony_ci } 2182cb93a386Sopenharmony_ci if (f.test()) { 2183cb93a386Sopenharmony_ci this->writeExpression(*f.test(), Precedence::kTopLevel); 2184cb93a386Sopenharmony_ci } 2185cb93a386Sopenharmony_ci this->write("; "); 2186cb93a386Sopenharmony_ci if (f.next()) { 2187cb93a386Sopenharmony_ci this->writeExpression(*f.next(), Precedence::kTopLevel); 2188cb93a386Sopenharmony_ci } 2189cb93a386Sopenharmony_ci this->write(") "); 2190cb93a386Sopenharmony_ci this->writeStatement(*f.statement()); 2191cb93a386Sopenharmony_ci} 2192cb93a386Sopenharmony_ci 2193cb93a386Sopenharmony_civoid MetalCodeGenerator::writeDoStatement(const DoStatement& d) { 2194cb93a386Sopenharmony_ci this->write("do "); 2195cb93a386Sopenharmony_ci this->writeStatement(*d.statement()); 2196cb93a386Sopenharmony_ci this->write(" while ("); 2197cb93a386Sopenharmony_ci this->writeExpression(*d.test(), Precedence::kTopLevel); 2198cb93a386Sopenharmony_ci this->write(");"); 2199cb93a386Sopenharmony_ci} 2200cb93a386Sopenharmony_ci 2201cb93a386Sopenharmony_civoid MetalCodeGenerator::writeSwitchStatement(const SwitchStatement& s) { 2202cb93a386Sopenharmony_ci this->write("switch ("); 2203cb93a386Sopenharmony_ci this->writeExpression(*s.value(), Precedence::kTopLevel); 2204cb93a386Sopenharmony_ci this->writeLine(") {"); 2205cb93a386Sopenharmony_ci fIndentation++; 2206cb93a386Sopenharmony_ci for (const std::unique_ptr<Statement>& stmt : s.cases()) { 2207cb93a386Sopenharmony_ci const SwitchCase& c = stmt->as<SwitchCase>(); 2208cb93a386Sopenharmony_ci if (c.value()) { 2209cb93a386Sopenharmony_ci this->write("case "); 2210cb93a386Sopenharmony_ci this->writeExpression(*c.value(), Precedence::kTopLevel); 2211cb93a386Sopenharmony_ci this->writeLine(":"); 2212cb93a386Sopenharmony_ci } else { 2213cb93a386Sopenharmony_ci this->writeLine("default:"); 2214cb93a386Sopenharmony_ci } 2215cb93a386Sopenharmony_ci if (!c.statement()->isEmpty()) { 2216cb93a386Sopenharmony_ci fIndentation++; 2217cb93a386Sopenharmony_ci this->writeStatement(*c.statement()); 2218cb93a386Sopenharmony_ci this->finishLine(); 2219cb93a386Sopenharmony_ci fIndentation--; 2220cb93a386Sopenharmony_ci } 2221cb93a386Sopenharmony_ci } 2222cb93a386Sopenharmony_ci fIndentation--; 2223cb93a386Sopenharmony_ci this->write("}"); 2224cb93a386Sopenharmony_ci} 2225cb93a386Sopenharmony_ci 2226cb93a386Sopenharmony_civoid MetalCodeGenerator::writeReturnStatementFromMain() { 2227cb93a386Sopenharmony_ci // main functions in Metal return a magic _out parameter that doesn't exist in SkSL. 2228cb93a386Sopenharmony_ci switch (fProgram.fConfig->fKind) { 2229cb93a386Sopenharmony_ci case ProgramKind::kVertex: 2230cb93a386Sopenharmony_ci case ProgramKind::kFragment: 2231cb93a386Sopenharmony_ci this->write("return _out;"); 2232cb93a386Sopenharmony_ci break; 2233cb93a386Sopenharmony_ci default: 2234cb93a386Sopenharmony_ci SkDEBUGFAIL("unsupported kind of program"); 2235cb93a386Sopenharmony_ci } 2236cb93a386Sopenharmony_ci} 2237cb93a386Sopenharmony_ci 2238cb93a386Sopenharmony_civoid MetalCodeGenerator::writeReturnStatement(const ReturnStatement& r) { 2239cb93a386Sopenharmony_ci if (fCurrentFunction && fCurrentFunction->isMain()) { 2240cb93a386Sopenharmony_ci if (r.expression()) { 2241cb93a386Sopenharmony_ci if (r.expression()->type() == *fContext.fTypes.fHalf4) { 2242cb93a386Sopenharmony_ci this->write("_out.sk_FragColor = "); 2243cb93a386Sopenharmony_ci this->writeExpression(*r.expression(), Precedence::kTopLevel); 2244cb93a386Sopenharmony_ci this->writeLine(";"); 2245cb93a386Sopenharmony_ci } else { 2246cb93a386Sopenharmony_ci fContext.fErrors->error(r.fLine, 2247cb93a386Sopenharmony_ci "Metal does not support returning '" + 2248cb93a386Sopenharmony_ci r.expression()->type().description() + "' from main()"); 2249cb93a386Sopenharmony_ci } 2250cb93a386Sopenharmony_ci } 2251cb93a386Sopenharmony_ci this->writeReturnStatementFromMain(); 2252cb93a386Sopenharmony_ci return; 2253cb93a386Sopenharmony_ci } 2254cb93a386Sopenharmony_ci 2255cb93a386Sopenharmony_ci this->write("return"); 2256cb93a386Sopenharmony_ci if (r.expression()) { 2257cb93a386Sopenharmony_ci this->write(" "); 2258cb93a386Sopenharmony_ci this->writeExpression(*r.expression(), Precedence::kTopLevel); 2259cb93a386Sopenharmony_ci } 2260cb93a386Sopenharmony_ci this->write(";"); 2261cb93a386Sopenharmony_ci} 2262cb93a386Sopenharmony_ci 2263cb93a386Sopenharmony_civoid MetalCodeGenerator::writeHeader() { 2264cb93a386Sopenharmony_ci this->write("#include <metal_stdlib>\n"); 2265cb93a386Sopenharmony_ci this->write("#include <simd/simd.h>\n"); 2266cb93a386Sopenharmony_ci this->write("using namespace metal;\n"); 2267cb93a386Sopenharmony_ci} 2268cb93a386Sopenharmony_ci 2269cb93a386Sopenharmony_civoid MetalCodeGenerator::writeUniformStruct() { 2270cb93a386Sopenharmony_ci for (const ProgramElement* e : fProgram.elements()) { 2271cb93a386Sopenharmony_ci if (e->is<GlobalVarDeclaration>()) { 2272cb93a386Sopenharmony_ci const GlobalVarDeclaration& decls = e->as<GlobalVarDeclaration>(); 2273cb93a386Sopenharmony_ci const Variable& var = decls.declaration()->as<VarDeclaration>().var(); 2274cb93a386Sopenharmony_ci if (var.modifiers().fFlags & Modifiers::kUniform_Flag && 2275cb93a386Sopenharmony_ci var.type().typeKind() != Type::TypeKind::kSampler) { 2276cb93a386Sopenharmony_ci int uniformSet = this->getUniformSet(var.modifiers()); 2277cb93a386Sopenharmony_ci // Make sure that the program's uniform-set value is consistent throughout. 2278cb93a386Sopenharmony_ci if (-1 == fUniformBuffer) { 2279cb93a386Sopenharmony_ci this->write("struct Uniforms {\n"); 2280cb93a386Sopenharmony_ci fUniformBuffer = uniformSet; 2281cb93a386Sopenharmony_ci } else if (uniformSet != fUniformBuffer) { 2282cb93a386Sopenharmony_ci fContext.fErrors->error(decls.fLine, 2283cb93a386Sopenharmony_ci "Metal backend requires all uniforms to have the same " 2284cb93a386Sopenharmony_ci "'layout(set=...)'"); 2285cb93a386Sopenharmony_ci } 2286cb93a386Sopenharmony_ci this->write(" "); 2287cb93a386Sopenharmony_ci this->writeType(var.type()); 2288cb93a386Sopenharmony_ci this->write(" "); 2289cb93a386Sopenharmony_ci this->writeName(var.name()); 2290cb93a386Sopenharmony_ci this->write(";\n"); 2291cb93a386Sopenharmony_ci } 2292cb93a386Sopenharmony_ci } 2293cb93a386Sopenharmony_ci } 2294cb93a386Sopenharmony_ci if (-1 != fUniformBuffer) { 2295cb93a386Sopenharmony_ci this->write("};\n"); 2296cb93a386Sopenharmony_ci } 2297cb93a386Sopenharmony_ci} 2298cb93a386Sopenharmony_ci 2299cb93a386Sopenharmony_civoid MetalCodeGenerator::writeInputStruct() { 2300cb93a386Sopenharmony_ci this->write("struct Inputs {\n"); 2301cb93a386Sopenharmony_ci for (const ProgramElement* e : fProgram.elements()) { 2302cb93a386Sopenharmony_ci if (e->is<GlobalVarDeclaration>()) { 2303cb93a386Sopenharmony_ci const GlobalVarDeclaration& decls = e->as<GlobalVarDeclaration>(); 2304cb93a386Sopenharmony_ci const Variable& var = decls.declaration()->as<VarDeclaration>().var(); 2305cb93a386Sopenharmony_ci if (var.modifiers().fFlags & Modifiers::kIn_Flag && 2306cb93a386Sopenharmony_ci -1 == var.modifiers().fLayout.fBuiltin) { 2307cb93a386Sopenharmony_ci this->write(" "); 2308cb93a386Sopenharmony_ci this->writeType(var.type()); 2309cb93a386Sopenharmony_ci this->write(" "); 2310cb93a386Sopenharmony_ci this->writeName(var.name()); 2311cb93a386Sopenharmony_ci if (-1 != var.modifiers().fLayout.fLocation) { 2312cb93a386Sopenharmony_ci if (fProgram.fConfig->fKind == ProgramKind::kVertex) { 2313cb93a386Sopenharmony_ci this->write(" [[attribute(" + 2314cb93a386Sopenharmony_ci to_string(var.modifiers().fLayout.fLocation) + ")]]"); 2315cb93a386Sopenharmony_ci } else if (fProgram.fConfig->fKind == ProgramKind::kFragment) { 2316cb93a386Sopenharmony_ci this->write(" [[user(locn" + 2317cb93a386Sopenharmony_ci to_string(var.modifiers().fLayout.fLocation) + ")]]"); 2318cb93a386Sopenharmony_ci } 2319cb93a386Sopenharmony_ci } 2320cb93a386Sopenharmony_ci this->write(";\n"); 2321cb93a386Sopenharmony_ci } 2322cb93a386Sopenharmony_ci } 2323cb93a386Sopenharmony_ci } 2324cb93a386Sopenharmony_ci this->write("};\n"); 2325cb93a386Sopenharmony_ci} 2326cb93a386Sopenharmony_ci 2327cb93a386Sopenharmony_civoid MetalCodeGenerator::writeOutputStruct() { 2328cb93a386Sopenharmony_ci this->write("struct Outputs {\n"); 2329cb93a386Sopenharmony_ci if (fProgram.fConfig->fKind == ProgramKind::kVertex) { 2330cb93a386Sopenharmony_ci this->write(" float4 sk_Position [[position]];\n"); 2331cb93a386Sopenharmony_ci } else if (fProgram.fConfig->fKind == ProgramKind::kFragment) { 2332cb93a386Sopenharmony_ci this->write(" half4 sk_FragColor [[color(0)]];\n"); 2333cb93a386Sopenharmony_ci } 2334cb93a386Sopenharmony_ci for (const ProgramElement* e : fProgram.elements()) { 2335cb93a386Sopenharmony_ci if (e->is<GlobalVarDeclaration>()) { 2336cb93a386Sopenharmony_ci const GlobalVarDeclaration& decls = e->as<GlobalVarDeclaration>(); 2337cb93a386Sopenharmony_ci const Variable& var = decls.declaration()->as<VarDeclaration>().var(); 2338cb93a386Sopenharmony_ci if (var.modifiers().fFlags & Modifiers::kOut_Flag && 2339cb93a386Sopenharmony_ci -1 == var.modifiers().fLayout.fBuiltin) { 2340cb93a386Sopenharmony_ci this->write(" "); 2341cb93a386Sopenharmony_ci this->writeType(var.type()); 2342cb93a386Sopenharmony_ci this->write(" "); 2343cb93a386Sopenharmony_ci this->writeName(var.name()); 2344cb93a386Sopenharmony_ci 2345cb93a386Sopenharmony_ci int location = var.modifiers().fLayout.fLocation; 2346cb93a386Sopenharmony_ci if (location < 0) { 2347cb93a386Sopenharmony_ci fContext.fErrors->error(var.fLine, 2348cb93a386Sopenharmony_ci "Metal out variables must have 'layout(location=...)'"); 2349cb93a386Sopenharmony_ci } else if (fProgram.fConfig->fKind == ProgramKind::kVertex) { 2350cb93a386Sopenharmony_ci this->write(" [[user(locn" + to_string(location) + ")]]"); 2351cb93a386Sopenharmony_ci } else if (fProgram.fConfig->fKind == ProgramKind::kFragment) { 2352cb93a386Sopenharmony_ci this->write(" [[color(" + to_string(location) + ")"); 2353cb93a386Sopenharmony_ci int colorIndex = var.modifiers().fLayout.fIndex; 2354cb93a386Sopenharmony_ci if (colorIndex) { 2355cb93a386Sopenharmony_ci this->write(", index(" + to_string(colorIndex) + ")"); 2356cb93a386Sopenharmony_ci } 2357cb93a386Sopenharmony_ci this->write("]]"); 2358cb93a386Sopenharmony_ci } 2359cb93a386Sopenharmony_ci this->write(";\n"); 2360cb93a386Sopenharmony_ci } 2361cb93a386Sopenharmony_ci } 2362cb93a386Sopenharmony_ci } 2363cb93a386Sopenharmony_ci if (fProgram.fConfig->fKind == ProgramKind::kVertex) { 2364cb93a386Sopenharmony_ci this->write(" float sk_PointSize [[point_size]];\n"); 2365cb93a386Sopenharmony_ci } 2366cb93a386Sopenharmony_ci this->write("};\n"); 2367cb93a386Sopenharmony_ci} 2368cb93a386Sopenharmony_ci 2369cb93a386Sopenharmony_civoid MetalCodeGenerator::writeInterfaceBlocks() { 2370cb93a386Sopenharmony_ci bool wroteInterfaceBlock = false; 2371cb93a386Sopenharmony_ci for (const ProgramElement* e : fProgram.elements()) { 2372cb93a386Sopenharmony_ci if (e->is<InterfaceBlock>()) { 2373cb93a386Sopenharmony_ci this->writeInterfaceBlock(e->as<InterfaceBlock>()); 2374cb93a386Sopenharmony_ci wroteInterfaceBlock = true; 2375cb93a386Sopenharmony_ci } 2376cb93a386Sopenharmony_ci } 2377cb93a386Sopenharmony_ci if (!wroteInterfaceBlock && fProgram.fInputs.fUseFlipRTUniform) { 2378cb93a386Sopenharmony_ci this->writeLine("struct sksl_synthetic_uniforms {"); 2379cb93a386Sopenharmony_ci this->writeLine(" float2 " SKSL_RTFLIP_NAME ";"); 2380cb93a386Sopenharmony_ci this->writeLine("};"); 2381cb93a386Sopenharmony_ci } 2382cb93a386Sopenharmony_ci} 2383cb93a386Sopenharmony_ci 2384cb93a386Sopenharmony_civoid MetalCodeGenerator::writeStructDefinitions() { 2385cb93a386Sopenharmony_ci for (const ProgramElement* e : fProgram.elements()) { 2386cb93a386Sopenharmony_ci if (e->is<StructDefinition>()) { 2387cb93a386Sopenharmony_ci this->writeStructDefinition(e->as<StructDefinition>()); 2388cb93a386Sopenharmony_ci } 2389cb93a386Sopenharmony_ci } 2390cb93a386Sopenharmony_ci} 2391cb93a386Sopenharmony_ci 2392cb93a386Sopenharmony_civoid MetalCodeGenerator::visitGlobalStruct(GlobalStructVisitor* visitor) { 2393cb93a386Sopenharmony_ci // Visit the interface blocks. 2394cb93a386Sopenharmony_ci for (const auto& [interfaceType, interfaceName] : fInterfaceBlockNameMap) { 2395cb93a386Sopenharmony_ci visitor->visitInterfaceBlock(*interfaceType, interfaceName); 2396cb93a386Sopenharmony_ci } 2397cb93a386Sopenharmony_ci for (const ProgramElement* element : fProgram.elements()) { 2398cb93a386Sopenharmony_ci if (!element->is<GlobalVarDeclaration>()) { 2399cb93a386Sopenharmony_ci continue; 2400cb93a386Sopenharmony_ci } 2401cb93a386Sopenharmony_ci const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>(); 2402cb93a386Sopenharmony_ci const VarDeclaration& decl = global.declaration()->as<VarDeclaration>(); 2403cb93a386Sopenharmony_ci const Variable& var = decl.var(); 2404cb93a386Sopenharmony_ci if (var.type().typeKind() == Type::TypeKind::kSampler) { 2405cb93a386Sopenharmony_ci // Samplers are represented as a "texture/sampler" duo in the global struct. 2406cb93a386Sopenharmony_ci visitor->visitTexture(var.type(), var.name()); 2407cb93a386Sopenharmony_ci visitor->visitSampler(var.type(), var.name() + SAMPLER_SUFFIX); 2408cb93a386Sopenharmony_ci continue; 2409cb93a386Sopenharmony_ci } 2410cb93a386Sopenharmony_ci 2411cb93a386Sopenharmony_ci if (!(var.modifiers().fFlags & ~Modifiers::kConst_Flag) && 2412cb93a386Sopenharmony_ci -1 == var.modifiers().fLayout.fBuiltin) { 2413cb93a386Sopenharmony_ci // Visit a regular variable. 2414cb93a386Sopenharmony_ci visitor->visitVariable(var, decl.value().get()); 2415cb93a386Sopenharmony_ci } 2416cb93a386Sopenharmony_ci } 2417cb93a386Sopenharmony_ci} 2418cb93a386Sopenharmony_ci 2419cb93a386Sopenharmony_civoid MetalCodeGenerator::writeGlobalStruct() { 2420cb93a386Sopenharmony_ci class : public GlobalStructVisitor { 2421cb93a386Sopenharmony_ci public: 2422cb93a386Sopenharmony_ci void visitInterfaceBlock(const InterfaceBlock& block, 2423cb93a386Sopenharmony_ci skstd::string_view blockName) override { 2424cb93a386Sopenharmony_ci this->addElement(); 2425cb93a386Sopenharmony_ci fCodeGen->write(" constant "); 2426cb93a386Sopenharmony_ci fCodeGen->write(block.typeName()); 2427cb93a386Sopenharmony_ci fCodeGen->write("* "); 2428cb93a386Sopenharmony_ci fCodeGen->writeName(blockName); 2429cb93a386Sopenharmony_ci fCodeGen->write(";\n"); 2430cb93a386Sopenharmony_ci } 2431cb93a386Sopenharmony_ci void visitTexture(const Type& type, skstd::string_view name) override { 2432cb93a386Sopenharmony_ci this->addElement(); 2433cb93a386Sopenharmony_ci fCodeGen->write(" "); 2434cb93a386Sopenharmony_ci fCodeGen->writeType(type); 2435cb93a386Sopenharmony_ci fCodeGen->write(" "); 2436cb93a386Sopenharmony_ci fCodeGen->writeName(name); 2437cb93a386Sopenharmony_ci fCodeGen->write(";\n"); 2438cb93a386Sopenharmony_ci } 2439cb93a386Sopenharmony_ci void visitSampler(const Type&, skstd::string_view name) override { 2440cb93a386Sopenharmony_ci this->addElement(); 2441cb93a386Sopenharmony_ci fCodeGen->write(" sampler "); 2442cb93a386Sopenharmony_ci fCodeGen->writeName(name); 2443cb93a386Sopenharmony_ci fCodeGen->write(";\n"); 2444cb93a386Sopenharmony_ci } 2445cb93a386Sopenharmony_ci void visitVariable(const Variable& var, const Expression* value) override { 2446cb93a386Sopenharmony_ci this->addElement(); 2447cb93a386Sopenharmony_ci fCodeGen->write(" "); 2448cb93a386Sopenharmony_ci fCodeGen->writeModifiers(var.modifiers()); 2449cb93a386Sopenharmony_ci fCodeGen->writeType(var.type()); 2450cb93a386Sopenharmony_ci fCodeGen->write(" "); 2451cb93a386Sopenharmony_ci fCodeGen->writeName(var.name()); 2452cb93a386Sopenharmony_ci fCodeGen->write(";\n"); 2453cb93a386Sopenharmony_ci } 2454cb93a386Sopenharmony_ci void addElement() { 2455cb93a386Sopenharmony_ci if (fFirst) { 2456cb93a386Sopenharmony_ci fCodeGen->write("struct Globals {\n"); 2457cb93a386Sopenharmony_ci fFirst = false; 2458cb93a386Sopenharmony_ci } 2459cb93a386Sopenharmony_ci } 2460cb93a386Sopenharmony_ci void finish() { 2461cb93a386Sopenharmony_ci if (!fFirst) { 2462cb93a386Sopenharmony_ci fCodeGen->writeLine("};"); 2463cb93a386Sopenharmony_ci fFirst = true; 2464cb93a386Sopenharmony_ci } 2465cb93a386Sopenharmony_ci } 2466cb93a386Sopenharmony_ci 2467cb93a386Sopenharmony_ci MetalCodeGenerator* fCodeGen = nullptr; 2468cb93a386Sopenharmony_ci bool fFirst = true; 2469cb93a386Sopenharmony_ci } visitor; 2470cb93a386Sopenharmony_ci 2471cb93a386Sopenharmony_ci visitor.fCodeGen = this; 2472cb93a386Sopenharmony_ci this->visitGlobalStruct(&visitor); 2473cb93a386Sopenharmony_ci visitor.finish(); 2474cb93a386Sopenharmony_ci} 2475cb93a386Sopenharmony_ci 2476cb93a386Sopenharmony_civoid MetalCodeGenerator::writeGlobalInit() { 2477cb93a386Sopenharmony_ci class : public GlobalStructVisitor { 2478cb93a386Sopenharmony_ci public: 2479cb93a386Sopenharmony_ci void visitInterfaceBlock(const InterfaceBlock& blockType, 2480cb93a386Sopenharmony_ci skstd::string_view blockName) override { 2481cb93a386Sopenharmony_ci this->addElement(); 2482cb93a386Sopenharmony_ci fCodeGen->write("&"); 2483cb93a386Sopenharmony_ci fCodeGen->writeName(blockName); 2484cb93a386Sopenharmony_ci } 2485cb93a386Sopenharmony_ci void visitTexture(const Type&, skstd::string_view name) override { 2486cb93a386Sopenharmony_ci this->addElement(); 2487cb93a386Sopenharmony_ci fCodeGen->writeName(name); 2488cb93a386Sopenharmony_ci } 2489cb93a386Sopenharmony_ci void visitSampler(const Type&, skstd::string_view name) override { 2490cb93a386Sopenharmony_ci this->addElement(); 2491cb93a386Sopenharmony_ci fCodeGen->writeName(name); 2492cb93a386Sopenharmony_ci } 2493cb93a386Sopenharmony_ci void visitVariable(const Variable& var, const Expression* value) override { 2494cb93a386Sopenharmony_ci this->addElement(); 2495cb93a386Sopenharmony_ci if (value) { 2496cb93a386Sopenharmony_ci fCodeGen->writeVarInitializer(var, *value); 2497cb93a386Sopenharmony_ci } else { 2498cb93a386Sopenharmony_ci fCodeGen->write("{}"); 2499cb93a386Sopenharmony_ci } 2500cb93a386Sopenharmony_ci } 2501cb93a386Sopenharmony_ci void addElement() { 2502cb93a386Sopenharmony_ci if (fFirst) { 2503cb93a386Sopenharmony_ci fCodeGen->write(" Globals _globals{"); 2504cb93a386Sopenharmony_ci fFirst = false; 2505cb93a386Sopenharmony_ci } else { 2506cb93a386Sopenharmony_ci fCodeGen->write(", "); 2507cb93a386Sopenharmony_ci } 2508cb93a386Sopenharmony_ci } 2509cb93a386Sopenharmony_ci void finish() { 2510cb93a386Sopenharmony_ci if (!fFirst) { 2511cb93a386Sopenharmony_ci fCodeGen->writeLine("};"); 2512cb93a386Sopenharmony_ci fCodeGen->writeLine(" (void)_globals;"); 2513cb93a386Sopenharmony_ci } 2514cb93a386Sopenharmony_ci } 2515cb93a386Sopenharmony_ci MetalCodeGenerator* fCodeGen = nullptr; 2516cb93a386Sopenharmony_ci bool fFirst = true; 2517cb93a386Sopenharmony_ci } visitor; 2518cb93a386Sopenharmony_ci 2519cb93a386Sopenharmony_ci visitor.fCodeGen = this; 2520cb93a386Sopenharmony_ci this->visitGlobalStruct(&visitor); 2521cb93a386Sopenharmony_ci visitor.finish(); 2522cb93a386Sopenharmony_ci} 2523cb93a386Sopenharmony_ci 2524cb93a386Sopenharmony_civoid MetalCodeGenerator::writeProgramElement(const ProgramElement& e) { 2525cb93a386Sopenharmony_ci switch (e.kind()) { 2526cb93a386Sopenharmony_ci case ProgramElement::Kind::kExtension: 2527cb93a386Sopenharmony_ci break; 2528cb93a386Sopenharmony_ci case ProgramElement::Kind::kGlobalVar: 2529cb93a386Sopenharmony_ci break; 2530cb93a386Sopenharmony_ci case ProgramElement::Kind::kInterfaceBlock: 2531cb93a386Sopenharmony_ci // handled in writeInterfaceBlocks, do nothing 2532cb93a386Sopenharmony_ci break; 2533cb93a386Sopenharmony_ci case ProgramElement::Kind::kStructDefinition: 2534cb93a386Sopenharmony_ci // Handled in writeStructDefinitions. Do nothing. 2535cb93a386Sopenharmony_ci break; 2536cb93a386Sopenharmony_ci case ProgramElement::Kind::kFunction: 2537cb93a386Sopenharmony_ci this->writeFunction(e.as<FunctionDefinition>()); 2538cb93a386Sopenharmony_ci break; 2539cb93a386Sopenharmony_ci case ProgramElement::Kind::kFunctionPrototype: 2540cb93a386Sopenharmony_ci this->writeFunctionPrototype(e.as<FunctionPrototype>()); 2541cb93a386Sopenharmony_ci break; 2542cb93a386Sopenharmony_ci case ProgramElement::Kind::kModifiers: 2543cb93a386Sopenharmony_ci this->writeModifiers(e.as<ModifiersDeclaration>().modifiers()); 2544cb93a386Sopenharmony_ci this->writeLine(";"); 2545cb93a386Sopenharmony_ci break; 2546cb93a386Sopenharmony_ci default: 2547cb93a386Sopenharmony_ci SkDEBUGFAILF("unsupported program element: %s\n", e.description().c_str()); 2548cb93a386Sopenharmony_ci break; 2549cb93a386Sopenharmony_ci } 2550cb93a386Sopenharmony_ci} 2551cb93a386Sopenharmony_ci 2552cb93a386Sopenharmony_ciMetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const Expression* e) { 2553cb93a386Sopenharmony_ci if (!e) { 2554cb93a386Sopenharmony_ci return kNo_Requirements; 2555cb93a386Sopenharmony_ci } 2556cb93a386Sopenharmony_ci switch (e->kind()) { 2557cb93a386Sopenharmony_ci case Expression::Kind::kFunctionCall: { 2558cb93a386Sopenharmony_ci const FunctionCall& f = e->as<FunctionCall>(); 2559cb93a386Sopenharmony_ci Requirements result = this->requirements(f.function()); 2560cb93a386Sopenharmony_ci for (const auto& arg : f.arguments()) { 2561cb93a386Sopenharmony_ci result |= this->requirements(arg.get()); 2562cb93a386Sopenharmony_ci } 2563cb93a386Sopenharmony_ci return result; 2564cb93a386Sopenharmony_ci } 2565cb93a386Sopenharmony_ci case Expression::Kind::kConstructorCompound: 2566cb93a386Sopenharmony_ci case Expression::Kind::kConstructorCompoundCast: 2567cb93a386Sopenharmony_ci case Expression::Kind::kConstructorArray: 2568cb93a386Sopenharmony_ci case Expression::Kind::kConstructorArrayCast: 2569cb93a386Sopenharmony_ci case Expression::Kind::kConstructorDiagonalMatrix: 2570cb93a386Sopenharmony_ci case Expression::Kind::kConstructorScalarCast: 2571cb93a386Sopenharmony_ci case Expression::Kind::kConstructorSplat: 2572cb93a386Sopenharmony_ci case Expression::Kind::kConstructorStruct: { 2573cb93a386Sopenharmony_ci const AnyConstructor& c = e->asAnyConstructor(); 2574cb93a386Sopenharmony_ci Requirements result = kNo_Requirements; 2575cb93a386Sopenharmony_ci for (const auto& arg : c.argumentSpan()) { 2576cb93a386Sopenharmony_ci result |= this->requirements(arg.get()); 2577cb93a386Sopenharmony_ci } 2578cb93a386Sopenharmony_ci return result; 2579cb93a386Sopenharmony_ci } 2580cb93a386Sopenharmony_ci case Expression::Kind::kFieldAccess: { 2581cb93a386Sopenharmony_ci const FieldAccess& f = e->as<FieldAccess>(); 2582cb93a386Sopenharmony_ci if (FieldAccess::OwnerKind::kAnonymousInterfaceBlock == f.ownerKind()) { 2583cb93a386Sopenharmony_ci return kGlobals_Requirement; 2584cb93a386Sopenharmony_ci } 2585cb93a386Sopenharmony_ci return this->requirements(f.base().get()); 2586cb93a386Sopenharmony_ci } 2587cb93a386Sopenharmony_ci case Expression::Kind::kSwizzle: 2588cb93a386Sopenharmony_ci return this->requirements(e->as<Swizzle>().base().get()); 2589cb93a386Sopenharmony_ci case Expression::Kind::kBinary: { 2590cb93a386Sopenharmony_ci const BinaryExpression& bin = e->as<BinaryExpression>(); 2591cb93a386Sopenharmony_ci return this->requirements(bin.left().get()) | 2592cb93a386Sopenharmony_ci this->requirements(bin.right().get()); 2593cb93a386Sopenharmony_ci } 2594cb93a386Sopenharmony_ci case Expression::Kind::kIndex: { 2595cb93a386Sopenharmony_ci const IndexExpression& idx = e->as<IndexExpression>(); 2596cb93a386Sopenharmony_ci return this->requirements(idx.base().get()) | this->requirements(idx.index().get()); 2597cb93a386Sopenharmony_ci } 2598cb93a386Sopenharmony_ci case Expression::Kind::kPrefix: 2599cb93a386Sopenharmony_ci return this->requirements(e->as<PrefixExpression>().operand().get()); 2600cb93a386Sopenharmony_ci case Expression::Kind::kPostfix: 2601cb93a386Sopenharmony_ci return this->requirements(e->as<PostfixExpression>().operand().get()); 2602cb93a386Sopenharmony_ci case Expression::Kind::kTernary: { 2603cb93a386Sopenharmony_ci const TernaryExpression& t = e->as<TernaryExpression>(); 2604cb93a386Sopenharmony_ci return this->requirements(t.test().get()) | this->requirements(t.ifTrue().get()) | 2605cb93a386Sopenharmony_ci this->requirements(t.ifFalse().get()); 2606cb93a386Sopenharmony_ci } 2607cb93a386Sopenharmony_ci case Expression::Kind::kVariableReference: { 2608cb93a386Sopenharmony_ci const VariableReference& v = e->as<VariableReference>(); 2609cb93a386Sopenharmony_ci const Modifiers& modifiers = v.variable()->modifiers(); 2610cb93a386Sopenharmony_ci Requirements result = kNo_Requirements; 2611cb93a386Sopenharmony_ci if (modifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN) { 2612cb93a386Sopenharmony_ci result = kGlobals_Requirement | kFragCoord_Requirement; 2613cb93a386Sopenharmony_ci } else if (Variable::Storage::kGlobal == v.variable()->storage()) { 2614cb93a386Sopenharmony_ci if (modifiers.fFlags & Modifiers::kIn_Flag) { 2615cb93a386Sopenharmony_ci result = kInputs_Requirement; 2616cb93a386Sopenharmony_ci } else if (modifiers.fFlags & Modifiers::kOut_Flag) { 2617cb93a386Sopenharmony_ci result = kOutputs_Requirement; 2618cb93a386Sopenharmony_ci } else if (modifiers.fFlags & Modifiers::kUniform_Flag && 2619cb93a386Sopenharmony_ci v.variable()->type().typeKind() != Type::TypeKind::kSampler) { 2620cb93a386Sopenharmony_ci result = kUniforms_Requirement; 2621cb93a386Sopenharmony_ci } else { 2622cb93a386Sopenharmony_ci result = kGlobals_Requirement; 2623cb93a386Sopenharmony_ci } 2624cb93a386Sopenharmony_ci } 2625cb93a386Sopenharmony_ci return result; 2626cb93a386Sopenharmony_ci } 2627cb93a386Sopenharmony_ci default: 2628cb93a386Sopenharmony_ci return kNo_Requirements; 2629cb93a386Sopenharmony_ci } 2630cb93a386Sopenharmony_ci} 2631cb93a386Sopenharmony_ci 2632cb93a386Sopenharmony_ciMetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const Statement* s) { 2633cb93a386Sopenharmony_ci if (!s) { 2634cb93a386Sopenharmony_ci return kNo_Requirements; 2635cb93a386Sopenharmony_ci } 2636cb93a386Sopenharmony_ci switch (s->kind()) { 2637cb93a386Sopenharmony_ci case Statement::Kind::kBlock: { 2638cb93a386Sopenharmony_ci Requirements result = kNo_Requirements; 2639cb93a386Sopenharmony_ci for (const std::unique_ptr<Statement>& child : s->as<Block>().children()) { 2640cb93a386Sopenharmony_ci result |= this->requirements(child.get()); 2641cb93a386Sopenharmony_ci } 2642cb93a386Sopenharmony_ci return result; 2643cb93a386Sopenharmony_ci } 2644cb93a386Sopenharmony_ci case Statement::Kind::kVarDeclaration: { 2645cb93a386Sopenharmony_ci const VarDeclaration& var = s->as<VarDeclaration>(); 2646cb93a386Sopenharmony_ci return this->requirements(var.value().get()); 2647cb93a386Sopenharmony_ci } 2648cb93a386Sopenharmony_ci case Statement::Kind::kExpression: 2649cb93a386Sopenharmony_ci return this->requirements(s->as<ExpressionStatement>().expression().get()); 2650cb93a386Sopenharmony_ci case Statement::Kind::kReturn: { 2651cb93a386Sopenharmony_ci const ReturnStatement& r = s->as<ReturnStatement>(); 2652cb93a386Sopenharmony_ci return this->requirements(r.expression().get()); 2653cb93a386Sopenharmony_ci } 2654cb93a386Sopenharmony_ci case Statement::Kind::kIf: { 2655cb93a386Sopenharmony_ci const IfStatement& i = s->as<IfStatement>(); 2656cb93a386Sopenharmony_ci return this->requirements(i.test().get()) | 2657cb93a386Sopenharmony_ci this->requirements(i.ifTrue().get()) | 2658cb93a386Sopenharmony_ci this->requirements(i.ifFalse().get()); 2659cb93a386Sopenharmony_ci } 2660cb93a386Sopenharmony_ci case Statement::Kind::kFor: { 2661cb93a386Sopenharmony_ci const ForStatement& f = s->as<ForStatement>(); 2662cb93a386Sopenharmony_ci return this->requirements(f.initializer().get()) | 2663cb93a386Sopenharmony_ci this->requirements(f.test().get()) | 2664cb93a386Sopenharmony_ci this->requirements(f.next().get()) | 2665cb93a386Sopenharmony_ci this->requirements(f.statement().get()); 2666cb93a386Sopenharmony_ci } 2667cb93a386Sopenharmony_ci case Statement::Kind::kDo: { 2668cb93a386Sopenharmony_ci const DoStatement& d = s->as<DoStatement>(); 2669cb93a386Sopenharmony_ci return this->requirements(d.test().get()) | 2670cb93a386Sopenharmony_ci this->requirements(d.statement().get()); 2671cb93a386Sopenharmony_ci } 2672cb93a386Sopenharmony_ci case Statement::Kind::kSwitch: { 2673cb93a386Sopenharmony_ci const SwitchStatement& sw = s->as<SwitchStatement>(); 2674cb93a386Sopenharmony_ci Requirements result = this->requirements(sw.value().get()); 2675cb93a386Sopenharmony_ci for (const std::unique_ptr<Statement>& sc : sw.cases()) { 2676cb93a386Sopenharmony_ci result |= this->requirements(sc->as<SwitchCase>().statement().get()); 2677cb93a386Sopenharmony_ci } 2678cb93a386Sopenharmony_ci return result; 2679cb93a386Sopenharmony_ci } 2680cb93a386Sopenharmony_ci default: 2681cb93a386Sopenharmony_ci return kNo_Requirements; 2682cb93a386Sopenharmony_ci } 2683cb93a386Sopenharmony_ci} 2684cb93a386Sopenharmony_ci 2685cb93a386Sopenharmony_ciMetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const FunctionDeclaration& f) { 2686cb93a386Sopenharmony_ci if (f.isBuiltin()) { 2687cb93a386Sopenharmony_ci return kNo_Requirements; 2688cb93a386Sopenharmony_ci } 2689cb93a386Sopenharmony_ci auto found = fRequirements.find(&f); 2690cb93a386Sopenharmony_ci if (found == fRequirements.end()) { 2691cb93a386Sopenharmony_ci fRequirements[&f] = kNo_Requirements; 2692cb93a386Sopenharmony_ci for (const ProgramElement* e : fProgram.elements()) { 2693cb93a386Sopenharmony_ci if (e->is<FunctionDefinition>()) { 2694cb93a386Sopenharmony_ci const FunctionDefinition& def = e->as<FunctionDefinition>(); 2695cb93a386Sopenharmony_ci if (&def.declaration() == &f) { 2696cb93a386Sopenharmony_ci Requirements reqs = this->requirements(def.body().get()); 2697cb93a386Sopenharmony_ci fRequirements[&f] = reqs; 2698cb93a386Sopenharmony_ci return reqs; 2699cb93a386Sopenharmony_ci } 2700cb93a386Sopenharmony_ci } 2701cb93a386Sopenharmony_ci } 2702cb93a386Sopenharmony_ci // We never found a definition for this declared function, but it's legal to prototype a 2703cb93a386Sopenharmony_ci // function without ever giving a definition, as long as you don't call it. 2704cb93a386Sopenharmony_ci return kNo_Requirements; 2705cb93a386Sopenharmony_ci } 2706cb93a386Sopenharmony_ci return found->second; 2707cb93a386Sopenharmony_ci} 2708cb93a386Sopenharmony_ci 2709cb93a386Sopenharmony_cibool MetalCodeGenerator::generateCode() { 2710cb93a386Sopenharmony_ci StringStream header; 2711cb93a386Sopenharmony_ci { 2712cb93a386Sopenharmony_ci AutoOutputStream outputToHeader(this, &header, &fIndentation); 2713cb93a386Sopenharmony_ci this->writeHeader(); 2714cb93a386Sopenharmony_ci this->writeStructDefinitions(); 2715cb93a386Sopenharmony_ci this->writeUniformStruct(); 2716cb93a386Sopenharmony_ci this->writeInputStruct(); 2717cb93a386Sopenharmony_ci this->writeOutputStruct(); 2718cb93a386Sopenharmony_ci this->writeInterfaceBlocks(); 2719cb93a386Sopenharmony_ci this->writeGlobalStruct(); 2720cb93a386Sopenharmony_ci } 2721cb93a386Sopenharmony_ci StringStream body; 2722cb93a386Sopenharmony_ci { 2723cb93a386Sopenharmony_ci AutoOutputStream outputToBody(this, &body, &fIndentation); 2724cb93a386Sopenharmony_ci for (const ProgramElement* e : fProgram.elements()) { 2725cb93a386Sopenharmony_ci this->writeProgramElement(*e); 2726cb93a386Sopenharmony_ci } 2727cb93a386Sopenharmony_ci } 2728cb93a386Sopenharmony_ci write_stringstream(header, *fOut); 2729cb93a386Sopenharmony_ci write_stringstream(fExtraFunctionPrototypes, *fOut); 2730cb93a386Sopenharmony_ci write_stringstream(fExtraFunctions, *fOut); 2731cb93a386Sopenharmony_ci write_stringstream(body, *fOut); 2732cb93a386Sopenharmony_ci fContext.fErrors->reportPendingErrors(PositionInfo()); 2733cb93a386Sopenharmony_ci return fContext.fErrors->errorCount() == 0; 2734cb93a386Sopenharmony_ci} 2735cb93a386Sopenharmony_ci 2736cb93a386Sopenharmony_ci} // namespace SkSL 2737