1/* 2 * Copyright 2016 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "src/sksl/codegen/SkSLGLSLCodeGenerator.h" 9 10#include <memory> 11 12#include "src/sksl/SkSLCompiler.h" 13#include "src/sksl/ir/SkSLBinaryExpression.h" 14#include "src/sksl/ir/SkSLConstructorArrayCast.h" 15#include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h" 16#include "src/sksl/ir/SkSLDoStatement.h" 17#include "src/sksl/ir/SkSLExpressionStatement.h" 18#include "src/sksl/ir/SkSLExtension.h" 19#include "src/sksl/ir/SkSLFieldAccess.h" 20#include "src/sksl/ir/SkSLForStatement.h" 21#include "src/sksl/ir/SkSLFunctionCall.h" 22#include "src/sksl/ir/SkSLFunctionDefinition.h" 23#include "src/sksl/ir/SkSLFunctionPrototype.h" 24#include "src/sksl/ir/SkSLIfStatement.h" 25#include "src/sksl/ir/SkSLIndexExpression.h" 26#include "src/sksl/ir/SkSLInterfaceBlock.h" 27#include "src/sksl/ir/SkSLModifiersDeclaration.h" 28#include "src/sksl/ir/SkSLNop.h" 29#include "src/sksl/ir/SkSLPostfixExpression.h" 30#include "src/sksl/ir/SkSLPrefixExpression.h" 31#include "src/sksl/ir/SkSLReturnStatement.h" 32#include "src/sksl/ir/SkSLSetting.h" 33#include "src/sksl/ir/SkSLStructDefinition.h" 34#include "src/sksl/ir/SkSLSwitchCase.h" 35#include "src/sksl/ir/SkSLSwitchStatement.h" 36#include "src/sksl/ir/SkSLSwizzle.h" 37#include "src/sksl/ir/SkSLVariableReference.h" 38 39#ifndef SKSL_STANDALONE 40#include "include/private/SkOnce.h" 41#endif 42 43namespace SkSL { 44 45void GLSLCodeGenerator::write(skstd::string_view s) { 46 if (!s.length()) { 47 return; 48 } 49 if (fAtLineStart) { 50 for (int i = 0; i < fIndentation; i++) { 51 fOut->writeText(" "); 52 } 53 } 54 fOut->write(s.data(), s.length()); 55 fAtLineStart = false; 56} 57 58void GLSLCodeGenerator::writeLine(skstd::string_view s) { 59 this->write(s); 60 fOut->writeText(fLineEnding); 61 fAtLineStart = true; 62} 63 64void GLSLCodeGenerator::finishLine() { 65 if (!fAtLineStart) { 66 this->writeLine(); 67 } 68} 69 70void GLSLCodeGenerator::writeExtension(skstd::string_view name, bool require) { 71 fExtensions.writeText("#extension "); 72 fExtensions.write(name.data(), name.length()); 73 fExtensions.writeText(require ? " : require\n" : " : enable\n"); 74} 75 76bool GLSLCodeGenerator::usesPrecisionModifiers() const { 77 return this->caps().usesPrecisionModifiers(); 78} 79 80// Returns the name of the type with array dimensions, e.g. `float[2]`. 81String GLSLCodeGenerator::getTypeName(const Type& type) { 82 switch (type.typeKind()) { 83 case Type::TypeKind::kVector: { 84 const Type& component = type.componentType(); 85 String result; 86 if (component == *fContext.fTypes.fFloat || component == *fContext.fTypes.fHalf) { 87 result = "vec"; 88 } 89 else if (component.isSigned()) { 90 result = "ivec"; 91 } 92 else if (component.isUnsigned()) { 93 result = "uvec"; 94 } 95 else if (component == *fContext.fTypes.fBool) { 96 result = "bvec"; 97 } 98 else { 99 SK_ABORT("unsupported vector type"); 100 } 101 result += to_string(type.columns()); 102 return result; 103 } 104 case Type::TypeKind::kMatrix: { 105 String result; 106 const Type& component = type.componentType(); 107 if (component == *fContext.fTypes.fFloat || component == *fContext.fTypes.fHalf) { 108 result = "mat"; 109 } 110 else { 111 SK_ABORT("unsupported matrix type"); 112 } 113 result += to_string(type.columns()); 114 if (type.columns() != type.rows()) { 115 result += "x"; 116 result += to_string(type.rows()); 117 } 118 return result; 119 } 120 case Type::TypeKind::kArray: { 121 String baseTypeName = this->getTypeName(type.componentType()); 122 return String::printf("%s[%d]", baseTypeName.c_str(), type.columns()); 123 } 124 case Type::TypeKind::kScalar: { 125 if (type == *fContext.fTypes.fHalf) { 126 return "float"; 127 } 128 else if (type == *fContext.fTypes.fShort) { 129 return "int"; 130 } 131 else if (type == *fContext.fTypes.fUShort) { 132 return "uint"; 133 } 134 else { 135 return String(type.name()); 136 } 137 break; 138 } 139 default: 140 return String(type.name()); 141 } 142} 143 144void GLSLCodeGenerator::writeStructDefinition(const StructDefinition& s) { 145 const Type& type = s.type(); 146 this->write("struct "); 147 this->write(type.name()); 148 this->writeLine(" {"); 149 fIndentation++; 150 for (const auto& f : type.fields()) { 151 this->writeModifiers(f.fModifiers, false); 152 this->writeTypePrecision(*f.fType); 153 const Type& baseType = f.fType->isArray() ? f.fType->componentType() : *f.fType; 154 this->writeType(baseType); 155 this->write(" "); 156 this->write(f.fName); 157 if (f.fType->isArray()) { 158 this->write("[" + to_string(f.fType->columns()) + "]"); 159 } 160 this->writeLine(";"); 161 } 162 fIndentation--; 163 this->writeLine("};"); 164} 165 166void GLSLCodeGenerator::writeType(const Type& type) { 167 this->write(this->getTypeName(type)); 168} 169 170void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) { 171 switch (expr.kind()) { 172 case Expression::Kind::kBinary: 173 this->writeBinaryExpression(expr.as<BinaryExpression>(), parentPrecedence); 174 break; 175 case Expression::Kind::kConstructorDiagonalMatrix: 176 this->writeConstructorDiagonalMatrix(expr.as<ConstructorDiagonalMatrix>(), 177 parentPrecedence); 178 break; 179 case Expression::Kind::kConstructorArrayCast: 180 this->writeExpression(*expr.as<ConstructorArrayCast>().argument(), parentPrecedence); 181 break; 182 case Expression::Kind::kConstructorArray: 183 case Expression::Kind::kConstructorCompound: 184 case Expression::Kind::kConstructorMatrixResize: 185 case Expression::Kind::kConstructorSplat: 186 case Expression::Kind::kConstructorStruct: 187 this->writeAnyConstructor(expr.asAnyConstructor(), parentPrecedence); 188 break; 189 case Expression::Kind::kConstructorScalarCast: 190 case Expression::Kind::kConstructorCompoundCast: 191 this->writeCastConstructor(expr.asAnyConstructor(), parentPrecedence); 192 break; 193 case Expression::Kind::kFieldAccess: 194 this->writeFieldAccess(expr.as<FieldAccess>()); 195 break; 196 case Expression::Kind::kFunctionCall: 197 this->writeFunctionCall(expr.as<FunctionCall>()); 198 break; 199 case Expression::Kind::kLiteral: 200 this->writeLiteral(expr.as<Literal>()); 201 break; 202 case Expression::Kind::kPrefix: 203 this->writePrefixExpression(expr.as<PrefixExpression>(), parentPrecedence); 204 break; 205 case Expression::Kind::kPostfix: 206 this->writePostfixExpression(expr.as<PostfixExpression>(), parentPrecedence); 207 break; 208 case Expression::Kind::kSetting: 209 this->writeSetting(expr.as<Setting>()); 210 break; 211 case Expression::Kind::kSwizzle: 212 this->writeSwizzle(expr.as<Swizzle>()); 213 break; 214 case Expression::Kind::kVariableReference: 215 this->writeVariableReference(expr.as<VariableReference>()); 216 break; 217 case Expression::Kind::kTernary: 218 this->writeTernaryExpression(expr.as<TernaryExpression>(), parentPrecedence); 219 break; 220 case Expression::Kind::kIndex: 221 this->writeIndexExpression(expr.as<IndexExpression>()); 222 break; 223 default: 224 SkDEBUGFAILF("unsupported expression: %s", expr.description().c_str()); 225 break; 226 } 227} 228 229static bool is_abs(Expression& expr) { 230 return expr.is<FunctionCall>() && 231 expr.as<FunctionCall>().function().intrinsicKind() == k_abs_IntrinsicKind; 232} 233 234// turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a 235// Tegra3 compiler bug. 236void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) { 237 SkASSERT(!this->caps().canUseMinAndAbsTogether()); 238 String tmpVar1 = "minAbsHackVar" + to_string(fVarCount++); 239 String tmpVar2 = "minAbsHackVar" + to_string(fVarCount++); 240 this->fFunctionHeader += String(" ") + this->getTypePrecision(absExpr.type()) + 241 this->getTypeName(absExpr.type()) + " " + tmpVar1 + ";\n"; 242 this->fFunctionHeader += String(" ") + this->getTypePrecision(otherExpr.type()) + 243 this->getTypeName(otherExpr.type()) + " " + tmpVar2 + ";\n"; 244 this->write("((" + tmpVar1 + " = "); 245 this->writeExpression(absExpr, Precedence::kTopLevel); 246 this->write(") < (" + tmpVar2 + " = "); 247 this->writeExpression(otherExpr, Precedence::kAssignment); 248 this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")"); 249} 250 251void GLSLCodeGenerator::writeInverseSqrtHack(const Expression& x) { 252 this->write("(1.0 / sqrt("); 253 this->writeExpression(x, Precedence::kTopLevel); 254 this->write("))"); 255} 256 257void GLSLCodeGenerator::writeDeterminantHack(const Expression& mat) { 258 String name; 259 const Type& type = mat.type(); 260 if (type == *fContext.fTypes.fFloat2x2 || type == *fContext.fTypes.fHalf2x2) { 261 name = "_determinant2"; 262 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) { 263 fWrittenIntrinsics.insert(name); 264 fExtraFunctions.writeText(( 265 "float " + name + "(mat2 m) {" 266 " return m[0][0] * m[1][1] - m[0][1] * m[1][0];" 267 "}" 268 ).c_str()); 269 } 270 } 271 else if (type == *fContext.fTypes.fFloat3x3 || type == *fContext.fTypes.fHalf3x3) { 272 name = "_determinant3"; 273 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) { 274 fWrittenIntrinsics.insert(name); 275 fExtraFunctions.writeText(( 276 "float " + name + "(mat3 m) {" 277 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];" 278 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];" 279 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];" 280 " float b01 = a22 * a11 - a12 * a21;" 281 " float b11 = -a22 * a10 + a12 * a20;" 282 " float b21 = a21 * a10 - a11 * a20;" 283 " return a00 * b01 + a01 * b11 + a02 * b21;" 284 "}" 285 ).c_str()); 286 } 287 } 288 else if (type == *fContext.fTypes.fFloat4x4 || type == *fContext.fTypes.fHalf4x4) { 289 name = "_determinant4"; 290 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) { 291 fWrittenIntrinsics.insert(name); 292 fExtraFunctions.writeText(( 293 "mat4 " + name + "(mat4 m) {" 294 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];" 295 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];" 296 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];" 297 " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];" 298 " float b00 = a00 * a11 - a01 * a10;" 299 " float b01 = a00 * a12 - a02 * a10;" 300 " float b02 = a00 * a13 - a03 * a10;" 301 " float b03 = a01 * a12 - a02 * a11;" 302 " float b04 = a01 * a13 - a03 * a11;" 303 " float b05 = a02 * a13 - a03 * a12;" 304 " float b06 = a20 * a31 - a21 * a30;" 305 " float b07 = a20 * a32 - a22 * a30;" 306 " float b08 = a20 * a33 - a23 * a30;" 307 " float b09 = a21 * a32 - a22 * a31;" 308 " float b10 = a21 * a33 - a23 * a31;" 309 " float b11 = a22 * a33 - a23 * a32;" 310 " return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;" 311 "}" 312 ).c_str()); 313 } 314 } 315 else { 316 SkASSERT(false); 317 } 318 this->write(name + "("); 319 this->writeExpression(mat, Precedence::kTopLevel); 320 this->write(")"); 321} 322 323void GLSLCodeGenerator::writeInverseHack(const Expression& mat) { 324 String name; 325 const Type& type = mat.type(); 326 if (type == *fContext.fTypes.fFloat2x2 || type == *fContext.fTypes.fHalf2x2) { 327 name = "_inverse2"; 328 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) { 329 fWrittenIntrinsics.insert(name); 330 fExtraFunctions.writeText(( 331 "mat2 " + name + "(mat2 m) {" 332 " return mat2(m[1][1], -m[0][1], -m[1][0], m[0][0]) / " 333 "(m[0][0] * m[1][1] - m[0][1] * m[1][0]);" 334 "}" 335 ).c_str()); 336 } 337 } 338 else if (type == *fContext.fTypes.fFloat3x3 || type == *fContext.fTypes.fHalf3x3) { 339 name = "_inverse3"; 340 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) { 341 fWrittenIntrinsics.insert(name); 342 fExtraFunctions.writeText(( 343 "mat3 " + name + "(mat3 m) {" 344 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];" 345 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];" 346 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];" 347 " float b01 = a22 * a11 - a12 * a21;" 348 " float b11 = -a22 * a10 + a12 * a20;" 349 " float b21 = a21 * a10 - a11 * a20;" 350 " float det = a00 * b01 + a01 * b11 + a02 * b21;" 351 " return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11)," 352 " b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10)," 353 " b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;" 354 "}" 355 ).c_str()); 356 } 357 } 358 else if (type == *fContext.fTypes.fFloat4x4 || type == *fContext.fTypes.fHalf4x4) { 359 name = "_inverse4"; 360 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) { 361 fWrittenIntrinsics.insert(name); 362 fExtraFunctions.writeText(( 363 "mat4 " + name + "(mat4 m) {" 364 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];" 365 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];" 366 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];" 367 " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];" 368 " float b00 = a00 * a11 - a01 * a10;" 369 " float b01 = a00 * a12 - a02 * a10;" 370 " float b02 = a00 * a13 - a03 * a10;" 371 " float b03 = a01 * a12 - a02 * a11;" 372 " float b04 = a01 * a13 - a03 * a11;" 373 " float b05 = a02 * a13 - a03 * a12;" 374 " float b06 = a20 * a31 - a21 * a30;" 375 " float b07 = a20 * a32 - a22 * a30;" 376 " float b08 = a20 * a33 - a23 * a30;" 377 " float b09 = a21 * a32 - a22 * a31;" 378 " float b10 = a21 * a33 - a23 * a31;" 379 " float b11 = a22 * a33 - a23 * a32;" 380 " float det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - " 381 " b04 * b07 + b05 * b06;" 382 " return mat4(" 383 " a11 * b11 - a12 * b10 + a13 * b09," 384 " a02 * b10 - a01 * b11 - a03 * b09," 385 " a31 * b05 - a32 * b04 + a33 * b03," 386 " a22 * b04 - a21 * b05 - a23 * b03," 387 " a12 * b08 - a10 * b11 - a13 * b07," 388 " a00 * b11 - a02 * b08 + a03 * b07," 389 " a32 * b02 - a30 * b05 - a33 * b01," 390 " a20 * b05 - a22 * b02 + a23 * b01," 391 " a10 * b10 - a11 * b08 + a13 * b06," 392 " a01 * b08 - a00 * b10 - a03 * b06," 393 " a30 * b04 - a31 * b02 + a33 * b00," 394 " a21 * b02 - a20 * b04 - a23 * b00," 395 " a11 * b07 - a10 * b09 - a12 * b06," 396 " a00 * b09 - a01 * b07 + a02 * b06," 397 " a31 * b01 - a30 * b03 - a32 * b00," 398 " a20 * b03 - a21 * b01 + a22 * b00) / det;" 399 "}" 400 ).c_str()); 401 } 402 } 403 else { 404 SkASSERT(false); 405 } 406 this->write(name + "("); 407 this->writeExpression(mat, Precedence::kTopLevel); 408 this->write(")"); 409} 410 411void GLSLCodeGenerator::writeTransposeHack(const Expression& mat) { 412 const Type& type = mat.type(); 413 String name = "transpose" + to_string(type.columns()) + to_string(type.rows()); 414 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) { 415 fWrittenIntrinsics.insert(name); 416 String typeName = this->getTypeName(type); 417 const Type& base = type.componentType(); 418 String transposed = this->getTypeName(base.toCompound(fContext, 419 type.rows(), 420 type.columns())); 421 fExtraFunctions.writeText((transposed + " " + name + "(" + typeName + " m) {\nreturn " + 422 transposed + "(").c_str()); 423 const char* separator = ""; 424 for (int row = 0; row < type.rows(); ++row) { 425 for (int column = 0; column < type.columns(); ++column) { 426 fExtraFunctions.writeText(separator); 427 fExtraFunctions.writeText(("m[" + to_string(column) + "][" + to_string(row) + 428 "]").c_str()); 429 separator = ", "; 430 } 431 } 432 fExtraFunctions.writeText("); }"); 433 } 434 this->write(name + "("); 435 this->writeExpression(mat, Precedence::kTopLevel); 436 this->write(")"); 437} 438 439void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) { 440 const FunctionDeclaration& function = c.function(); 441 const ExpressionArray& arguments = c.arguments(); 442 bool isTextureFunctionWithBias = false; 443 bool nameWritten = false; 444 const char* closingParen = ")"; 445 switch (c.function().intrinsicKind()) { 446 case k_abs_IntrinsicKind: { 447 if (!this->caps().emulateAbsIntFunction()) 448 break; 449 SkASSERT(arguments.size() == 1); 450 if (arguments[0]->type() != *fContext.fTypes.fInt) { 451 break; 452 } 453 // abs(int) on Intel OSX is incorrect, so emulate it: 454 String name = "_absemulation"; 455 this->write(name); 456 nameWritten = true; 457 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) { 458 fWrittenIntrinsics.insert(name); 459 fExtraFunctions.writeText(( 460 "int " + name + "(int x) {\n" 461 " return x * sign(x);\n" 462 "}\n" 463 ).c_str()); 464 } 465 break; 466 } 467 case k_atan_IntrinsicKind: 468 if (this->caps().mustForceNegatedAtanParamToFloat() && 469 arguments.size() == 2 && 470 arguments[1]->kind() == Expression::Kind::kPrefix) { 471 const PrefixExpression& p = (PrefixExpression&) *arguments[1]; 472 if (p.getOperator().kind() == Token::Kind::TK_MINUS) { 473 this->write("atan("); 474 this->writeExpression(*arguments[0], Precedence::kSequence); 475 this->write(", -1.0 * "); 476 this->writeExpression(*p.operand(), Precedence::kMultiplicative); 477 this->write(")"); 478 return; 479 } 480 } 481 break; 482 case k_ldexp_IntrinsicKind: 483 if (this->caps().mustForceNegatedLdexpParamToMultiply() && 484 arguments.size() == 2 && 485 arguments[1]->is<PrefixExpression>()) { 486 const PrefixExpression& p = arguments[1]->as<PrefixExpression>(); 487 if (p.getOperator().kind() == Token::Kind::TK_MINUS) { 488 this->write("ldexp("); 489 this->writeExpression(*arguments[0], Precedence::kSequence); 490 this->write(", "); 491 this->writeExpression(*p.operand(), Precedence::kMultiplicative); 492 this->write(" * -1)"); 493 return; 494 } 495 } 496 break; 497 case k_dFdy_IntrinsicKind: 498 // Flipping Y also negates the Y derivatives. 499 closingParen = "))"; 500 this->write("(" SKSL_RTFLIP_NAME ".y * dFdy"); 501 nameWritten = true; 502 [[fallthrough]]; 503 case k_dFdx_IntrinsicKind: 504 case k_fwidth_IntrinsicKind: 505 if (!fFoundDerivatives && 506 this->caps().shaderDerivativeExtensionString()) { 507 this->writeExtension(this->caps().shaderDerivativeExtensionString()); 508 fFoundDerivatives = true; 509 } 510 break; 511 case k_determinant_IntrinsicKind: 512 if (!this->caps().builtinDeterminantSupport()) { 513 SkASSERT(arguments.size() == 1); 514 this->writeDeterminantHack(*arguments[0]); 515 return; 516 } 517 break; 518 case k_fma_IntrinsicKind: 519 if (!this->caps().builtinFMASupport()) { 520 SkASSERT(arguments.size() == 3); 521 this->write("(("); 522 this->writeExpression(*arguments[0], Precedence::kSequence); 523 this->write(") * ("); 524 this->writeExpression(*arguments[1], Precedence::kSequence); 525 this->write(") + ("); 526 this->writeExpression(*arguments[2], Precedence::kSequence); 527 this->write("))"); 528 return; 529 } 530 break; 531 case k_fract_IntrinsicKind: 532 if (!this->caps().canUseFractForNegativeValues()) { 533 SkASSERT(arguments.size() == 1); 534 this->write("(0.5 - sign("); 535 this->writeExpression(*arguments[0], Precedence::kSequence); 536 this->write(") * (0.5 - fract(abs("); 537 this->writeExpression(*arguments[0], Precedence::kSequence); 538 this->write("))))"); 539 return; 540 } 541 break; 542 case k_inverse_IntrinsicKind: 543 if (this->caps().generation() < k140_GrGLSLGeneration) { 544 SkASSERT(arguments.size() == 1); 545 this->writeInverseHack(*arguments[0]); 546 return; 547 } 548 break; 549 case k_inversesqrt_IntrinsicKind: 550 if (this->caps().generation() < k130_GrGLSLGeneration) { 551 SkASSERT(arguments.size() == 1); 552 this->writeInverseSqrtHack(*arguments[0]); 553 return; 554 } 555 break; 556 case k_min_IntrinsicKind: 557 if (!this->caps().canUseMinAndAbsTogether()) { 558 SkASSERT(arguments.size() == 2); 559 if (is_abs(*arguments[0])) { 560 this->writeMinAbsHack(*arguments[0], *arguments[1]); 561 return; 562 } 563 if (is_abs(*arguments[1])) { 564 // note that this violates the GLSL left-to-right evaluation semantics. 565 // I doubt it will ever end up mattering, but it's worth calling out. 566 this->writeMinAbsHack(*arguments[1], *arguments[0]); 567 return; 568 } 569 } 570 break; 571 case k_pow_IntrinsicKind: 572 if (!this->caps().removePowWithConstantExponent()) { 573 break; 574 } 575 // pow(x, y) on some NVIDIA drivers causes crashes if y is a 576 // constant. It's hard to tell what constitutes "constant" here 577 // so just replace in all cases. 578 579 // Change pow(x, y) into exp2(y * log2(x)) 580 this->write("exp2("); 581 this->writeExpression(*arguments[1], Precedence::kMultiplicative); 582 this->write(" * log2("); 583 this->writeExpression(*arguments[0], Precedence::kSequence); 584 this->write("))"); 585 return; 586 case k_saturate_IntrinsicKind: 587 SkASSERT(arguments.size() == 1); 588 this->write("clamp("); 589 this->writeExpression(*arguments[0], Precedence::kSequence); 590 this->write(", 0.0, 1.0)"); 591 return; 592 case k_sample_IntrinsicKind: { 593 const char* dim = ""; 594 bool proj = false; 595 const Type& arg0Type = arguments[0]->type(); 596 const Type& arg1Type = arguments[1]->type(); 597 switch (arg0Type.dimensions()) { 598 case SpvDim1D: 599 dim = "1D"; 600 isTextureFunctionWithBias = true; 601 if (arg1Type == *fContext.fTypes.fFloat) { 602 proj = false; 603 } else { 604 SkASSERT(arg1Type == *fContext.fTypes.fFloat2); 605 proj = true; 606 } 607 break; 608 case SpvDim2D: 609 dim = "2D"; 610 if (arg0Type != *fContext.fTypes.fSamplerExternalOES) { 611 isTextureFunctionWithBias = true; 612 } 613 if (arg1Type == *fContext.fTypes.fFloat2) { 614 proj = false; 615 } else { 616 SkASSERT(arg1Type == *fContext.fTypes.fFloat3); 617 proj = true; 618 } 619 break; 620 case SpvDim3D: 621 dim = "3D"; 622 isTextureFunctionWithBias = true; 623 if (arg1Type == *fContext.fTypes.fFloat3) { 624 proj = false; 625 } else { 626 SkASSERT(arg1Type == *fContext.fTypes.fFloat4); 627 proj = true; 628 } 629 break; 630 case SpvDimCube: 631 dim = "Cube"; 632 isTextureFunctionWithBias = true; 633 proj = false; 634 break; 635 case SpvDimRect: 636 dim = "2DRect"; 637 proj = false; 638 break; 639 case SpvDimBuffer: 640 SkASSERT(false); // doesn't exist 641 dim = "Buffer"; 642 proj = false; 643 break; 644 case SpvDimSubpassData: 645 SkASSERT(false); // doesn't exist 646 dim = "SubpassData"; 647 proj = false; 648 break; 649 } 650 if (!fTextureFunctionOverride.empty()) { 651 this->write(fTextureFunctionOverride.c_str()); 652 } else { 653 this->write("texture"); 654 if (this->caps().generation() < k130_GrGLSLGeneration) { 655 this->write(dim); 656 } 657 if (proj) { 658 this->write("Proj"); 659 } 660 } 661 nameWritten = true; 662 break; 663 } 664 case k_transpose_IntrinsicKind: 665 if (this->caps().generation() < k130_GrGLSLGeneration) { 666 SkASSERT(arguments.size() == 1); 667 this->writeTransposeHack(*arguments[0]); 668 return; 669 } 670 break; 671 default: 672 break; 673 } 674 675 if (!nameWritten) { 676 this->write(function.mangledName()); 677 } 678 this->write("("); 679 const char* separator = ""; 680 for (const auto& arg : arguments) { 681 this->write(separator); 682 separator = ", "; 683 this->writeExpression(*arg, Precedence::kSequence); 684 } 685 if (fProgram.fConfig->fSettings.fSharpenTextures && isTextureFunctionWithBias) { 686 this->write(", -0.5"); 687 } 688 this->write(closingParen); 689} 690 691void GLSLCodeGenerator::writeConstructorDiagonalMatrix(const ConstructorDiagonalMatrix& c, 692 Precedence parentPrecedence) { 693 if (c.type().columns() == 4 && c.type().rows() == 2) { 694 // Due to a longstanding bug in glslang and Mesa, several GPU drivers generate diagonal 4x2 695 // matrices incorrectly. (skia:12003, https://github.com/KhronosGroup/glslang/pull/2646) 696 // We can work around this issue by multiplying a scalar by the identity matrix. 697 // In practice, this doesn't come up naturally in real code and we don't know every affected 698 // driver, so we just apply this workaround everywhere. 699 this->write("("); 700 this->writeType(c.type()); 701 this->write("(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) * "); 702 this->writeExpression(*c.argument(), Precedence::kMultiplicative); 703 this->write(")"); 704 return; 705 } 706 this->writeAnyConstructor(c, parentPrecedence); 707} 708 709void GLSLCodeGenerator::writeCastConstructor(const AnyConstructor& c, Precedence parentPrecedence) { 710 const auto arguments = c.argumentSpan(); 711 SkASSERT(arguments.size() == 1); 712 713 const Expression& argument = *arguments.front(); 714 if ((this->getTypeName(c.type()) == this->getTypeName(argument.type()) || 715 (argument.type() == *fContext.fTypes.fFloatLiteral))) { 716 // In cases like half(float), they're different types as far as SkSL is concerned but 717 // the same type as far as GLSL is concerned. We avoid a redundant float(float) by just 718 // writing out the inner expression here. 719 this->writeExpression(argument, parentPrecedence); 720 return; 721 } 722 723 // This cast should be emitted as-is. 724 return this->writeAnyConstructor(c, parentPrecedence); 725} 726 727void GLSLCodeGenerator::writeAnyConstructor(const AnyConstructor& c, Precedence parentPrecedence) { 728 this->writeType(c.type()); 729 this->write("("); 730 const char* separator = ""; 731 for (const auto& arg : c.argumentSpan()) { 732 this->write(separator); 733 separator = ", "; 734 this->writeExpression(*arg, Precedence::kSequence); 735 } 736 this->write(")"); 737} 738 739void GLSLCodeGenerator::writeFragCoord() { 740 if (!this->caps().canUseFragCoord()) { 741 if (!fSetupFragCoordWorkaround) { 742 const char* precision = usesPrecisionModifiers() ? "highp " : ""; 743 fFunctionHeader += precision; 744 fFunctionHeader += " float sk_FragCoord_InvW = 1. / sk_FragCoord_Workaround.w;\n"; 745 fFunctionHeader += precision; 746 fFunctionHeader += " vec4 sk_FragCoord_Resolved = " 747 "vec4(sk_FragCoord_Workaround.xyz * sk_FragCoord_InvW, sk_FragCoord_InvW);\n"; 748 // Ensure that we get exact .5 values for x and y. 749 fFunctionHeader += " sk_FragCoord_Resolved.xy = floor(sk_FragCoord_Resolved.xy) + " 750 "vec2(.5);\n"; 751 fSetupFragCoordWorkaround = true; 752 } 753 this->write("sk_FragCoord_Resolved"); 754 return; 755 } 756 757 if (!fSetupFragPosition) { 758 fFunctionHeader += usesPrecisionModifiers() ? "highp " : ""; 759 fFunctionHeader += " vec4 sk_FragCoord = vec4(" 760 "gl_FragCoord.x, " 761 SKSL_RTFLIP_NAME ".x + " SKSL_RTFLIP_NAME ".y * gl_FragCoord.y, " 762 "gl_FragCoord.z, " 763 "gl_FragCoord.w);\n"; 764 fSetupFragPosition = true; 765 } 766 this->write("sk_FragCoord"); 767} 768 769void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) { 770 switch (ref.variable()->modifiers().fLayout.fBuiltin) { 771 case SK_FRAGCOLOR_BUILTIN: 772 if (this->caps().mustDeclareFragmentShaderOutput()) { 773 this->write("sk_FragColor"); 774 } else { 775 this->write("gl_FragColor"); 776 } 777 break; 778 case SK_SECONDARYFRAGCOLOR_BUILTIN: 779 this->write("gl_SecondaryFragColorEXT"); 780 break; 781 case SK_FRAGCOORD_BUILTIN: 782 this->writeFragCoord(); 783 break; 784 case SK_CLOCKWISE_BUILTIN: 785 if (!fSetupClockwise) { 786 fFunctionHeader += 787 " bool sk_Clockwise = gl_FrontFacing;\n" 788 " if (" SKSL_RTFLIP_NAME ".y < 0.0) {\n" 789 " sk_Clockwise = !sk_Clockwise;\n" 790 " }\n"; 791 fSetupClockwise = true; 792 } 793 this->write("sk_Clockwise"); 794 break; 795 case SK_VERTEXID_BUILTIN: 796 this->write("gl_VertexID"); 797 break; 798 case SK_INSTANCEID_BUILTIN: 799 this->write("gl_InstanceID"); 800 break; 801 case SK_LASTFRAGCOLOR_BUILTIN: 802 if (this->caps().fbFetchSupport()) { 803 this->write(this->caps().fbFetchColorName()); 804 } else { 805 fContext.fErrors->error(ref.fLine, 806 "sk_LastFragColor requires framebuffer fetch support"); 807 } 808 break; 809 default: 810 this->write(ref.variable()->name()); 811 break; 812 } 813} 814 815void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) { 816 this->writeExpression(*expr.base(), Precedence::kPostfix); 817 this->write("["); 818 this->writeExpression(*expr.index(), Precedence::kTopLevel); 819 this->write("]"); 820} 821 822bool is_sk_position(const FieldAccess& f) { 823 return "sk_Position" == f.base()->type().fields()[f.fieldIndex()].fName; 824} 825 826void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) { 827 if (f.ownerKind() == FieldAccess::OwnerKind::kDefault) { 828 this->writeExpression(*f.base(), Precedence::kPostfix); 829 this->write("."); 830 } 831 const Type& baseType = f.base()->type(); 832 skstd::string_view name = baseType.fields()[f.fieldIndex()].fName; 833 if (name == "sk_Position") { 834 this->write("gl_Position"); 835 } else if (name == "sk_PointSize") { 836 this->write("gl_PointSize"); 837 } else { 838 this->write(baseType.fields()[f.fieldIndex()].fName); 839 } 840} 841 842void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) { 843 this->writeExpression(*swizzle.base(), Precedence::kPostfix); 844 this->write("."); 845 for (int c : swizzle.components()) { 846 SkASSERT(c >= 0 && c <= 3); 847 this->write(&("x\0y\0z\0w\0"[c * 2])); 848 } 849} 850 851void GLSLCodeGenerator::writeMatrixComparisonWorkaround(const BinaryExpression& b) { 852 const Expression& left = *b.left(); 853 const Expression& right = *b.right(); 854 Operator op = b.getOperator(); 855 856 SkASSERT(op.kind() == Token::Kind::TK_EQEQ || op.kind() == Token::Kind::TK_NEQ); 857 SkASSERT(left.type().isMatrix()); 858 SkASSERT(right.type().isMatrix()); 859 860 String tempMatrix1 = "_tempMatrix" + to_string(fVarCount++); 861 String tempMatrix2 = "_tempMatrix" + to_string(fVarCount++); 862 863 this->fFunctionHeader += String(" ") + this->getTypePrecision(left.type()) + 864 this->getTypeName(left.type()) + " " + tempMatrix1 + ";\n " + 865 this->getTypePrecision(right.type()) + 866 this->getTypeName(right.type()) + " " + tempMatrix2 + ";\n"; 867 this->write("((" + tempMatrix1 + " = "); 868 this->writeExpression(left, Precedence::kAssignment); 869 this->write("), (" + tempMatrix2 + " = "); 870 this->writeExpression(right, Precedence::kAssignment); 871 this->write("), (" + tempMatrix1 + " "); 872 this->write(op.operatorName()); 873 this->write(" " + tempMatrix2 + "))"); 874} 875 876void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b, 877 Precedence parentPrecedence) { 878 const Expression& left = *b.left(); 879 const Expression& right = *b.right(); 880 Operator op = b.getOperator(); 881 if (this->caps().unfoldShortCircuitAsTernary() && 882 (op.kind() == Token::Kind::TK_LOGICALAND || op.kind() == Token::Kind::TK_LOGICALOR)) { 883 this->writeShortCircuitWorkaroundExpression(b, parentPrecedence); 884 return; 885 } 886 887 if (this->caps().rewriteMatrixComparisons() && 888 left.type().isMatrix() && right.type().isMatrix() && 889 (op.kind() == Token::Kind::TK_EQEQ || op.kind() == Token::Kind::TK_NEQ)) { 890 this->writeMatrixComparisonWorkaround(b); 891 return; 892 } 893 894 Precedence precedence = op.getBinaryPrecedence(); 895 if (precedence >= parentPrecedence) { 896 this->write("("); 897 } 898 bool positionWorkaround = fProgram.fConfig->fKind == ProgramKind::kVertex && 899 op.isAssignment() && 900 left.is<FieldAccess>() && 901 is_sk_position(left.as<FieldAccess>()) && 902 !right.containsRTAdjust() && 903 !this->caps().canUseFragCoord(); 904 if (positionWorkaround) { 905 this->write("sk_FragCoord_Workaround = ("); 906 } 907 this->writeExpression(left, precedence); 908 this->write(" "); 909 this->write(op.operatorName()); 910 this->write(" "); 911 this->writeExpression(right, precedence); 912 if (positionWorkaround) { 913 this->write(")"); 914 } 915 if (precedence >= parentPrecedence) { 916 this->write(")"); 917 } 918} 919 920void GLSLCodeGenerator::writeShortCircuitWorkaroundExpression(const BinaryExpression& b, 921 Precedence parentPrecedence) { 922 if (Precedence::kTernary >= parentPrecedence) { 923 this->write("("); 924 } 925 926 // Transform: 927 // a && b => a ? b : false 928 // a || b => a ? true : b 929 this->writeExpression(*b.left(), Precedence::kTernary); 930 this->write(" ? "); 931 if (b.getOperator().kind() == Token::Kind::TK_LOGICALAND) { 932 this->writeExpression(*b.right(), Precedence::kTernary); 933 } else { 934 Literal boolTrue(/*line=*/-1, /*value=*/1, fContext.fTypes.fBool.get()); 935 this->writeLiteral(boolTrue); 936 } 937 this->write(" : "); 938 if (b.getOperator().kind() == Token::Kind::TK_LOGICALAND) { 939 Literal boolFalse(/*line=*/-1, /*value=*/0, fContext.fTypes.fBool.get()); 940 this->writeLiteral(boolFalse); 941 } else { 942 this->writeExpression(*b.right(), Precedence::kTernary); 943 } 944 if (Precedence::kTernary >= parentPrecedence) { 945 this->write(")"); 946 } 947} 948 949void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t, 950 Precedence parentPrecedence) { 951 if (Precedence::kTernary >= parentPrecedence) { 952 this->write("("); 953 } 954 this->writeExpression(*t.test(), Precedence::kTernary); 955 this->write(" ? "); 956 this->writeExpression(*t.ifTrue(), Precedence::kTernary); 957 this->write(" : "); 958 this->writeExpression(*t.ifFalse(), Precedence::kTernary); 959 if (Precedence::kTernary >= parentPrecedence) { 960 this->write(")"); 961 } 962} 963 964void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p, 965 Precedence parentPrecedence) { 966 if (Precedence::kPrefix >= parentPrecedence) { 967 this->write("("); 968 } 969 this->write(p.getOperator().operatorName()); 970 this->writeExpression(*p.operand(), Precedence::kPrefix); 971 if (Precedence::kPrefix >= parentPrecedence) { 972 this->write(")"); 973 } 974} 975 976void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p, 977 Precedence parentPrecedence) { 978 if (Precedence::kPostfix >= parentPrecedence) { 979 this->write("("); 980 } 981 this->writeExpression(*p.operand(), Precedence::kPostfix); 982 this->write(p.getOperator().operatorName()); 983 if (Precedence::kPostfix >= parentPrecedence) { 984 this->write(")"); 985 } 986} 987 988void GLSLCodeGenerator::writeLiteral(const Literal& l) { 989 const Type& type = l.type(); 990 if (type.isFloat()) { 991 this->write(to_string(l.floatValue())); 992 return; 993 } 994 if (type.isInteger()) { 995 if (type == *fContext.fTypes.fUInt) { 996 this->write(to_string(l.intValue() & 0xffffffff) + "u"); 997 } else if (type == *fContext.fTypes.fUShort) { 998 this->write(to_string(l.intValue() & 0xffff) + "u"); 999 } else { 1000 this->write(to_string(l.intValue())); 1001 } 1002 return; 1003 } 1004 SkASSERT(type.isBoolean()); 1005 this->write(l.boolValue() ? "true" : "false"); 1006} 1007 1008void GLSLCodeGenerator::writeSetting(const Setting& s) { 1009 SK_ABORT("internal error; setting was not folded to a constant during compilation\n"); 1010} 1011 1012void GLSLCodeGenerator::writeFunctionDeclaration(const FunctionDeclaration& f) { 1013 this->writeTypePrecision(f.returnType()); 1014 this->writeType(f.returnType()); 1015 this->write(" " + f.mangledName() + "("); 1016 const char* separator = ""; 1017 for (const auto& param : f.parameters()) { 1018 // This is a workaround for our test files. They use the runtime effect signature, so main 1019 // takes a coords parameter. The IR generator tags those with a builtin ID (sk_FragCoord), 1020 // and we omit them from the declaration here, so the function is valid GLSL. 1021 if (f.isMain() && param->modifiers().fLayout.fBuiltin != -1) { 1022 continue; 1023 } 1024 this->write(separator); 1025 separator = ", "; 1026 this->writeModifiers(param->modifiers(), false); 1027 std::vector<int> sizes; 1028 const Type* type = ¶m->type(); 1029 if (type->isArray()) { 1030 sizes.push_back(type->columns()); 1031 type = &type->componentType(); 1032 } 1033 this->writeTypePrecision(*type); 1034 this->writeType(*type); 1035 this->write(" " + param->name()); 1036 for (int s : sizes) { 1037 this->write("[" + to_string(s) + "]"); 1038 } 1039 } 1040 this->write(")"); 1041} 1042 1043void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) { 1044 fSetupFragPosition = false; 1045 fSetupFragCoordWorkaround = false; 1046 1047 this->writeFunctionDeclaration(f.declaration()); 1048 this->writeLine(" {"); 1049 fIndentation++; 1050 1051 fFunctionHeader.clear(); 1052 OutputStream* oldOut = fOut; 1053 StringStream buffer; 1054 fOut = &buffer; 1055 for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) { 1056 if (!stmt->isEmpty()) { 1057 this->writeStatement(*stmt); 1058 this->finishLine(); 1059 } 1060 } 1061 1062 fIndentation--; 1063 this->writeLine("}"); 1064 1065 fOut = oldOut; 1066 this->write(fFunctionHeader); 1067 this->write(buffer.str()); 1068} 1069 1070void GLSLCodeGenerator::writeFunctionPrototype(const FunctionPrototype& f) { 1071 this->writeFunctionDeclaration(f.declaration()); 1072 this->writeLine(";"); 1073} 1074 1075void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers, 1076 bool globalContext) { 1077 String layout = modifiers.fLayout.description(); 1078 if (layout.size()) { 1079 this->write(layout + " "); 1080 } 1081 1082 // For GLSL 4.1 and below, qualifier-order matters! These are written out in Modifier-bit order. 1083 if (modifiers.fFlags & Modifiers::kFlat_Flag) { 1084 this->write("flat "); 1085 } 1086 if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) { 1087 this->write("noperspective "); 1088 } 1089 1090 if (modifiers.fFlags & Modifiers::kConst_Flag) { 1091 this->write("const "); 1092 } 1093 if (modifiers.fFlags & Modifiers::kUniform_Flag) { 1094 this->write("uniform "); 1095 } 1096 if ((modifiers.fFlags & Modifiers::kIn_Flag) && 1097 (modifiers.fFlags & Modifiers::kOut_Flag)) { 1098 this->write("inout "); 1099 } else if (modifiers.fFlags & Modifiers::kIn_Flag) { 1100 if (globalContext && 1101 this->caps().generation() < GrGLSLGeneration::k130_GrGLSLGeneration) { 1102 this->write(fProgram.fConfig->fKind == ProgramKind::kVertex ? "attribute " 1103 : "varying "); 1104 } else { 1105 this->write("in "); 1106 } 1107 } else if (modifiers.fFlags & Modifiers::kOut_Flag) { 1108 if (globalContext && 1109 this->caps().generation() < GrGLSLGeneration::k130_GrGLSLGeneration) { 1110 this->write("varying "); 1111 } else { 1112 this->write("out "); 1113 } 1114 } 1115 1116} 1117 1118void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) { 1119 if (intf.typeName() == "sk_PerVertex") { 1120 return; 1121 } 1122 this->writeModifiers(intf.variable().modifiers(), true); 1123 this->writeLine(intf.typeName() + " {"); 1124 fIndentation++; 1125 const Type* structType = &intf.variable().type(); 1126 if (structType->isArray()) { 1127 structType = &structType->componentType(); 1128 } 1129 for (const auto& f : structType->fields()) { 1130 this->writeModifiers(f.fModifiers, false); 1131 this->writeTypePrecision(*f.fType); 1132 this->writeType(*f.fType); 1133 this->writeLine(" " + f.fName + ";"); 1134 } 1135 fIndentation--; 1136 this->write("}"); 1137 if (intf.instanceName().size()) { 1138 this->write(" "); 1139 this->write(intf.instanceName()); 1140 if (intf.arraySize() > 0) { 1141 this->write("["); 1142 this->write(to_string(intf.arraySize())); 1143 this->write("]"); 1144 } 1145 } 1146 this->writeLine(";"); 1147} 1148 1149void GLSLCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) { 1150 this->writeExpression(value, Precedence::kTopLevel); 1151} 1152 1153const char* GLSLCodeGenerator::getTypePrecision(const Type& type) { 1154 if (usesPrecisionModifiers()) { 1155 switch (type.typeKind()) { 1156 case Type::TypeKind::kScalar: 1157 if (type == *fContext.fTypes.fShort || type == *fContext.fTypes.fUShort) { 1158 if (fProgram.fConfig->fSettings.fForceHighPrecision || 1159 this->caps().incompleteShortIntPrecision()) { 1160 return "highp "; 1161 } 1162 return "mediump "; 1163 } 1164 if (type == *fContext.fTypes.fHalf) { 1165 return fProgram.fConfig->fSettings.fForceHighPrecision ? "highp " : "mediump "; 1166 } 1167 if (type == *fContext.fTypes.fFloat || type == *fContext.fTypes.fInt || 1168 type == *fContext.fTypes.fUInt) { 1169 return "highp "; 1170 } 1171 return ""; 1172 case Type::TypeKind::kVector: // fall through 1173 case Type::TypeKind::kMatrix: 1174 case Type::TypeKind::kArray: 1175 return this->getTypePrecision(type.componentType()); 1176 default: 1177 break; 1178 } 1179 } 1180 return ""; 1181} 1182 1183void GLSLCodeGenerator::writeTypePrecision(const Type& type) { 1184 this->write(this->getTypePrecision(type)); 1185} 1186 1187void GLSLCodeGenerator::writeVarDeclaration(const VarDeclaration& var, bool global) { 1188 this->writeModifiers(var.var().modifiers(), global); 1189 this->writeTypePrecision(var.baseType()); 1190 this->writeType(var.baseType()); 1191 this->write(" "); 1192 this->write(var.var().name()); 1193 if (var.arraySize() > 0) { 1194 this->write("["); 1195 this->write(to_string(var.arraySize())); 1196 this->write("]"); 1197 } 1198 if (var.value()) { 1199 this->write(" = "); 1200 this->writeVarInitializer(var.var(), *var.value()); 1201 } 1202 if (!fFoundExternalSamplerDecl && var.var().type() == *fContext.fTypes.fSamplerExternalOES) { 1203 if (this->caps().externalTextureExtensionString()) { 1204 this->writeExtension(this->caps().externalTextureExtensionString()); 1205 } 1206 if (this->caps().secondExternalTextureExtensionString()) { 1207 this->writeExtension(this->caps().secondExternalTextureExtensionString()); 1208 } 1209 fFoundExternalSamplerDecl = true; 1210 } 1211 if (!fFoundRectSamplerDecl && var.var().type() == *fContext.fTypes.fSampler2DRect) { 1212 fFoundRectSamplerDecl = true; 1213 } 1214 this->write(";"); 1215} 1216 1217void GLSLCodeGenerator::writeStatement(const Statement& s) { 1218 switch (s.kind()) { 1219 case Statement::Kind::kBlock: 1220 this->writeBlock(s.as<Block>()); 1221 break; 1222 case Statement::Kind::kExpression: 1223 this->writeExpression(*s.as<ExpressionStatement>().expression(), Precedence::kTopLevel); 1224 this->write(";"); 1225 break; 1226 case Statement::Kind::kReturn: 1227 this->writeReturnStatement(s.as<ReturnStatement>()); 1228 break; 1229 case Statement::Kind::kVarDeclaration: 1230 this->writeVarDeclaration(s.as<VarDeclaration>(), false); 1231 break; 1232 case Statement::Kind::kIf: 1233 this->writeIfStatement(s.as<IfStatement>()); 1234 break; 1235 case Statement::Kind::kFor: 1236 this->writeForStatement(s.as<ForStatement>()); 1237 break; 1238 case Statement::Kind::kDo: 1239 this->writeDoStatement(s.as<DoStatement>()); 1240 break; 1241 case Statement::Kind::kSwitch: 1242 this->writeSwitchStatement(s.as<SwitchStatement>()); 1243 break; 1244 case Statement::Kind::kBreak: 1245 this->write("break;"); 1246 break; 1247 case Statement::Kind::kContinue: 1248 this->write("continue;"); 1249 break; 1250 case Statement::Kind::kDiscard: 1251 this->write("discard;"); 1252 break; 1253 case Statement::Kind::kInlineMarker: 1254 case Statement::Kind::kNop: 1255 this->write(";"); 1256 break; 1257 default: 1258 SkDEBUGFAILF("unsupported statement: %s", s.description().c_str()); 1259 break; 1260 } 1261} 1262 1263void GLSLCodeGenerator::writeBlock(const Block& b) { 1264 // Write scope markers if this block is a scope, or if the block is empty (since we need to emit 1265 // something here to make the code valid). 1266 bool isScope = b.isScope() || b.isEmpty(); 1267 if (isScope) { 1268 this->writeLine("{"); 1269 fIndentation++; 1270 } 1271 for (const std::unique_ptr<Statement>& stmt : b.children()) { 1272 if (!stmt->isEmpty()) { 1273 this->writeStatement(*stmt); 1274 this->finishLine(); 1275 } 1276 } 1277 if (isScope) { 1278 fIndentation--; 1279 this->write("}"); 1280 } 1281} 1282 1283void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) { 1284 this->write("if ("); 1285 this->writeExpression(*stmt.test(), Precedence::kTopLevel); 1286 this->write(") "); 1287 this->writeStatement(*stmt.ifTrue()); 1288 if (stmt.ifFalse()) { 1289 this->write(" else "); 1290 this->writeStatement(*stmt.ifFalse()); 1291 } 1292} 1293 1294void GLSLCodeGenerator::writeForStatement(const ForStatement& f) { 1295 // Emit loops of the form 'for(;test;)' as 'while(test)', which is probably how they started 1296 if (!f.initializer() && f.test() && !f.next()) { 1297 this->write("while ("); 1298 this->writeExpression(*f.test(), Precedence::kTopLevel); 1299 this->write(") "); 1300 this->writeStatement(*f.statement()); 1301 return; 1302 } 1303 1304 this->write("for ("); 1305 if (f.initializer() && !f.initializer()->isEmpty()) { 1306 this->writeStatement(*f.initializer()); 1307 } else { 1308 this->write("; "); 1309 } 1310 if (f.test()) { 1311 if (this->caps().addAndTrueToLoopCondition()) { 1312 std::unique_ptr<Expression> and_true(new BinaryExpression( 1313 /*line=*/-1, f.test()->clone(), Token::Kind::TK_LOGICALAND, 1314 Literal::MakeBool(fContext, /*line=*/-1, /*value=*/true), 1315 fContext.fTypes.fBool.get())); 1316 this->writeExpression(*and_true, Precedence::kTopLevel); 1317 } else { 1318 this->writeExpression(*f.test(), Precedence::kTopLevel); 1319 } 1320 } 1321 this->write("; "); 1322 if (f.next()) { 1323 this->writeExpression(*f.next(), Precedence::kTopLevel); 1324 } 1325 this->write(") "); 1326 this->writeStatement(*f.statement()); 1327} 1328 1329void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) { 1330 if (!this->caps().rewriteDoWhileLoops()) { 1331 this->write("do "); 1332 this->writeStatement(*d.statement()); 1333 this->write(" while ("); 1334 this->writeExpression(*d.test(), Precedence::kTopLevel); 1335 this->write(");"); 1336 return; 1337 } 1338 1339 // Otherwise, do the do while loop workaround, to rewrite loops of the form: 1340 // do { 1341 // CODE; 1342 // } while (CONDITION) 1343 // 1344 // to loops of the form 1345 // bool temp = false; 1346 // while (true) { 1347 // if (temp) { 1348 // if (!CONDITION) { 1349 // break; 1350 // } 1351 // } 1352 // temp = true; 1353 // CODE; 1354 // } 1355 String tmpVar = "_tmpLoopSeenOnce" + to_string(fVarCount++); 1356 this->write("bool "); 1357 this->write(tmpVar); 1358 this->writeLine(" = false;"); 1359 this->writeLine("while (true) {"); 1360 fIndentation++; 1361 this->write("if ("); 1362 this->write(tmpVar); 1363 this->writeLine(") {"); 1364 fIndentation++; 1365 this->write("if (!"); 1366 this->writeExpression(*d.test(), Precedence::kPrefix); 1367 this->writeLine(") {"); 1368 fIndentation++; 1369 this->writeLine("break;"); 1370 fIndentation--; 1371 this->writeLine("}"); 1372 fIndentation--; 1373 this->writeLine("}"); 1374 this->write(tmpVar); 1375 this->writeLine(" = true;"); 1376 this->writeStatement(*d.statement()); 1377 this->finishLine(); 1378 fIndentation--; 1379 this->write("}"); 1380} 1381 1382void GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) { 1383 if (this->caps().rewriteSwitchStatements()) { 1384 String fallthroughVar = "_tmpSwitchFallthrough" + to_string(fVarCount++); 1385 String valueVar = "_tmpSwitchValue" + to_string(fVarCount++); 1386 String loopVar = "_tmpSwitchLoop" + to_string(fVarCount++); 1387 this->write("int "); 1388 this->write(valueVar); 1389 this->write(" = "); 1390 this->writeExpression(*s.value(), Precedence::kAssignment); 1391 this->write(", "); 1392 this->write(fallthroughVar); 1393 this->writeLine(" = 0;"); 1394 this->write("for (int "); 1395 this->write(loopVar); 1396 this->write(" = 0; "); 1397 this->write(loopVar); 1398 this->write(" < 1; "); 1399 this->write(loopVar); 1400 this->writeLine("++) {"); 1401 fIndentation++; 1402 1403 bool firstCase = true; 1404 for (const std::unique_ptr<Statement>& stmt : s.cases()) { 1405 const SwitchCase& c = stmt->as<SwitchCase>(); 1406 if (c.value()) { 1407 this->write("if (("); 1408 if (firstCase) { 1409 firstCase = false; 1410 } else { 1411 this->write(fallthroughVar); 1412 this->write(" > 0) || ("); 1413 } 1414 this->write(valueVar); 1415 this->write(" == "); 1416 this->writeExpression(*c.value(), Precedence::kEquality); 1417 this->writeLine(")) {"); 1418 fIndentation++; 1419 1420 // We write the entire case-block statement here, and then set `switchFallthrough` 1421 // to 1. If the case-block had a break statement in it, we break out of the outer 1422 // for-loop entirely, meaning the `switchFallthrough` assignment never occurs, nor 1423 // does any code after it inside the switch. We've forbidden `continue` statements 1424 // inside switch case-blocks entirely, so we don't need to consider their effect on 1425 // control flow; see the Finalizer in FunctionDefinition::Convert. 1426 this->writeStatement(*c.statement()); 1427 this->finishLine(); 1428 this->write(fallthroughVar); 1429 this->write(" = 1;"); 1430 this->writeLine(); 1431 1432 fIndentation--; 1433 this->writeLine("}"); 1434 } else { 1435 // This is the default case. Since it's always last, we can just dump in the code. 1436 this->writeStatement(*c.statement()); 1437 this->finishLine(); 1438 } 1439 } 1440 1441 fIndentation--; 1442 this->writeLine("}"); 1443 return; 1444 } 1445 1446 this->write("switch ("); 1447 this->writeExpression(*s.value(), Precedence::kTopLevel); 1448 this->writeLine(") {"); 1449 fIndentation++; 1450 // If a switch contains only a `default` case and nothing else, this confuses some drivers and 1451 // can lead to a crash. Adding a real case before the default seems to work around the bug, 1452 // and doesn't change the meaning of the switch. (skia:12465) 1453 if (s.cases().size() == 1 && !s.cases().front()->as<SwitchCase>().value()) { 1454 this->writeLine("case 0:"); 1455 } 1456 for (const std::unique_ptr<Statement>& stmt : s.cases()) { 1457 const SwitchCase& c = stmt->as<SwitchCase>(); 1458 if (c.value()) { 1459 this->write("case "); 1460 this->writeExpression(*c.value(), Precedence::kTopLevel); 1461 this->writeLine(":"); 1462 } else { 1463 this->writeLine("default:"); 1464 } 1465 if (!c.statement()->isEmpty()) { 1466 fIndentation++; 1467 this->writeStatement(*c.statement()); 1468 this->finishLine(); 1469 fIndentation--; 1470 } 1471 } 1472 fIndentation--; 1473 this->finishLine(); 1474 this->write("}"); 1475} 1476 1477void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) { 1478 this->write("return"); 1479 if (r.expression()) { 1480 this->write(" "); 1481 this->writeExpression(*r.expression(), Precedence::kTopLevel); 1482 } 1483 this->write(";"); 1484} 1485 1486void GLSLCodeGenerator::writeHeader() { 1487 if (this->caps().versionDeclString()) { 1488 this->write(this->caps().versionDeclString()); 1489 this->finishLine(); 1490 } 1491} 1492 1493void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) { 1494 switch (e.kind()) { 1495 case ProgramElement::Kind::kExtension: 1496 this->writeExtension(e.as<Extension>().name()); 1497 break; 1498 case ProgramElement::Kind::kGlobalVar: { 1499 const VarDeclaration& decl = 1500 e.as<GlobalVarDeclaration>().declaration()->as<VarDeclaration>(); 1501 int builtin = decl.var().modifiers().fLayout.fBuiltin; 1502 if (builtin == -1) { 1503 // normal var 1504 this->writeVarDeclaration(decl, true); 1505 this->finishLine(); 1506 } else if (builtin == SK_FRAGCOLOR_BUILTIN && 1507 this->caps().mustDeclareFragmentShaderOutput()) { 1508 if (fProgram.fConfig->fSettings.fFragColorIsInOut) { 1509 this->write("inout "); 1510 } else { 1511 this->write("out "); 1512 } 1513 if (usesPrecisionModifiers()) { 1514 this->write("mediump "); 1515 } 1516 this->writeLine("vec4 sk_FragColor;"); 1517 } 1518 break; 1519 } 1520 case ProgramElement::Kind::kInterfaceBlock: 1521 this->writeInterfaceBlock(e.as<InterfaceBlock>()); 1522 break; 1523 case ProgramElement::Kind::kFunction: 1524 this->writeFunction(e.as<FunctionDefinition>()); 1525 break; 1526 case ProgramElement::Kind::kFunctionPrototype: 1527 this->writeFunctionPrototype(e.as<FunctionPrototype>()); 1528 break; 1529 case ProgramElement::Kind::kModifiers: { 1530 const Modifiers& modifiers = e.as<ModifiersDeclaration>().modifiers(); 1531 this->writeModifiers(modifiers, true); 1532 this->writeLine(";"); 1533 break; 1534 } 1535 case ProgramElement::Kind::kStructDefinition: 1536 this->writeStructDefinition(e.as<StructDefinition>()); 1537 break; 1538 default: 1539 SkDEBUGFAILF("unsupported program element %s\n", e.description().c_str()); 1540 break; 1541 } 1542} 1543 1544void GLSLCodeGenerator::writeInputVars() { 1545 if (fProgram.fInputs.fUseFlipRTUniform) { 1546 const char* precision = usesPrecisionModifiers() ? "highp " : ""; 1547 fGlobals.writeText("uniform "); 1548 fGlobals.writeText(precision); 1549 fGlobals.writeText("vec2 " SKSL_RTFLIP_NAME ";\n"); 1550 } 1551} 1552 1553bool GLSLCodeGenerator::generateCode() { 1554 this->writeHeader(); 1555 OutputStream* rawOut = fOut; 1556 StringStream body; 1557 fOut = &body; 1558 // Write all the program elements except for functions. 1559 for (const ProgramElement* e : fProgram.elements()) { 1560 if (!e->is<FunctionDefinition>()) { 1561 this->writeProgramElement(*e); 1562 } 1563 } 1564 // Write the functions last. 1565 // Why don't we write things in their original order? Because the Inliner likes to move function 1566 // bodies around. After inlining, code can inadvertently move upwards, above ProgramElements 1567 // that the code relies on. 1568 for (const ProgramElement* e : fProgram.elements()) { 1569 if (e->is<FunctionDefinition>()) { 1570 this->writeProgramElement(*e); 1571 } 1572 } 1573 fOut = rawOut; 1574 1575 write_stringstream(fExtensions, *rawOut); 1576 this->writeInputVars(); 1577 write_stringstream(fGlobals, *rawOut); 1578 1579 if (!this->caps().canUseFragCoord()) { 1580 Layout layout; 1581 switch (fProgram.fConfig->fKind) { 1582 case ProgramKind::kVertex: { 1583 Modifiers modifiers(layout, Modifiers::kOut_Flag); 1584 this->writeModifiers(modifiers, true); 1585 if (this->usesPrecisionModifiers()) { 1586 this->write("highp "); 1587 } 1588 this->write("vec4 sk_FragCoord_Workaround;\n"); 1589 break; 1590 } 1591 case ProgramKind::kFragment: { 1592 Modifiers modifiers(layout, Modifiers::kIn_Flag); 1593 this->writeModifiers(modifiers, true); 1594 if (this->usesPrecisionModifiers()) { 1595 this->write("highp "); 1596 } 1597 this->write("vec4 sk_FragCoord_Workaround;\n"); 1598 break; 1599 } 1600 default: 1601 break; 1602 } 1603 } 1604 1605 if (this->usesPrecisionModifiers()) { 1606 const char* precision = 1607 fProgram.fConfig->fSettings.fForceHighPrecision ? "highp" : "mediump"; 1608 this->write(String::printf("precision %s float;\n", precision)); 1609 this->write(String::printf("precision %s sampler2D;\n", precision)); 1610 if (fFoundExternalSamplerDecl && !this->caps().noDefaultPrecisionForExternalSamplers()) { 1611 this->write(String::printf("precision %s samplerExternalOES;\n", precision)); 1612 } 1613 if (fFoundRectSamplerDecl) { 1614 this->write(String::printf("precision %s sampler2DRect;\n", precision)); 1615 } 1616 } 1617 write_stringstream(fExtraFunctions, *rawOut); 1618 write_stringstream(body, *rawOut); 1619 return fContext.fErrors->errorCount() == 0; 1620} 1621 1622} // namespace SkSL 1623