2 * Copyright 2016 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "src/sksl/codegen/SkSLGLSLCodeGenerator.h"
10 #include "include/core/SkSpan.h"
11 #include "include/core/SkTypes.h"
12 #include "include/private/SkSLDefines.h"
13 #include "include/private/SkSLLayout.h"
14 #include "include/private/SkSLModifiers.h"
15 #include "include/private/SkSLProgramElement.h"
16 #include "include/private/SkSLStatement.h"
17 #include "include/private/SkSLString.h"
18 #include "include/private/SkTArray.h"
19 #include "include/sksl/SkSLErrorReporter.h"
20 #include "include/sksl/SkSLPosition.h"
21 #include "src/sksl/SkSLBuiltinTypes.h"
22 #include "src/sksl/SkSLCompiler.h"
23 #include "src/sksl/SkSLGLSL.h"
24 #include "src/sksl/SkSLOutputStream.h"
25 #include "src/sksl/SkSLProgramSettings.h"
26 #include "src/sksl/SkSLUtil.h"
27 #include "src/sksl/ir/SkSLBinaryExpression.h"
28 #include "src/sksl/ir/SkSLBlock.h"
29 #include "src/sksl/ir/SkSLConstructor.h"
30 #include "src/sksl/ir/SkSLConstructorArrayCast.h"
31 #include "src/sksl/ir/SkSLConstructorDiagonalMatrix.h"
32 #include "src/sksl/ir/SkSLDoStatement.h"
33 #include "src/sksl/ir/SkSLExpression.h"
34 #include "src/sksl/ir/SkSLExpressionStatement.h"
35 #include "src/sksl/ir/SkSLExtension.h"
36 #include "src/sksl/ir/SkSLFieldAccess.h"
37 #include "src/sksl/ir/SkSLForStatement.h"
38 #include "src/sksl/ir/SkSLFunctionCall.h"
39 #include "src/sksl/ir/SkSLFunctionDeclaration.h"
40 #include "src/sksl/ir/SkSLFunctionDefinition.h"
41 #include "src/sksl/ir/SkSLFunctionPrototype.h"
42 #include "src/sksl/ir/SkSLIfStatement.h"
43 #include "src/sksl/ir/SkSLIndexExpression.h"
44 #include "src/sksl/ir/SkSLInterfaceBlock.h"
45 #include "src/sksl/ir/SkSLLiteral.h"
46 #include "src/sksl/ir/SkSLModifiersDeclaration.h"
47 #include "src/sksl/ir/SkSLPostfixExpression.h"
48 #include "src/sksl/ir/SkSLPrefixExpression.h"
49 #include "src/sksl/ir/SkSLProgram.h"
50 #include "src/sksl/ir/SkSLReturnStatement.h"
51 #include "src/sksl/ir/SkSLSetting.h"
52 #include "src/sksl/ir/SkSLStructDefinition.h"
53 #include "src/sksl/ir/SkSLSwitchCase.h"
54 #include "src/sksl/ir/SkSLSwitchStatement.h"
55 #include "src/sksl/ir/SkSLSwizzle.h"
56 #include "src/sksl/ir/SkSLTernaryExpression.h"
57 #include "src/sksl/ir/SkSLType.h"
58 #include "src/sksl/ir/SkSLVarDeclarations.h"
59 #include "src/sksl/ir/SkSLVariable.h"
60 #include "src/sksl/ir/SkSLVariableReference.h"
61 #include "src/sksl/spirv.h"
68 void GLSLCodeGenerator::write(std::string_view s) {
73 for (int i = 0; i < fIndentation; i++) {
77 fOut->write(s.data(), s.length());
81 void GLSLCodeGenerator::writeLine(std::string_view s) {
83 fOut->writeText("\n");
87 void GLSLCodeGenerator::finishLine() {
93 void GLSLCodeGenerator::writeExtension(std::string_view name, bool require) {
94 fExtensions.writeText("#extension ");
95 fExtensions.write(name.data(), name.length());
96 fExtensions.writeText(require ? " : require\n" : " : enable\n");
99 bool GLSLCodeGenerator::usesPrecisionModifiers() const {
100 return this->caps().usesPrecisionModifiers();
103 // Returns the name of the type with array dimensions, e.g. `float[2]`.
104 std::string GLSLCodeGenerator::getTypeName(const Type& raw) {
105 const Type& type = raw.resolve();
106 switch (type.typeKind()) {
107 case Type::TypeKind::kVector: {
108 const Type& component = type.componentType();
110 if (component.matches(*fContext.fTypes.fFloat) ||
111 component.matches(*fContext.fTypes.fHalf)) {
114 else if (component.isSigned()) {
117 else if (component.isUnsigned()) {
120 else if (component.matches(*fContext.fTypes.fBool)) {
124 SK_ABORT("unsupported vector type");
126 result += std::to_string(type.columns());
129 case Type::TypeKind::kMatrix: {
131 const Type& component = type.componentType();
132 if (component.matches(*fContext.fTypes.fFloat) ||
133 component.matches(*fContext.fTypes.fHalf)) {
137 SK_ABORT("unsupported matrix type");
139 result += std::to_string(type.columns());
140 if (type.columns() != type.rows()) {
142 result += std::to_string(type.rows());
146 case Type::TypeKind::kArray: {
147 std::string baseTypeName = this->getTypeName(type.componentType());
148 return String::printf("%s[%d]", baseTypeName.c_str(), type.columns());
150 case Type::TypeKind::kScalar: {
151 if (type.matches(*fContext.fTypes.fHalf)) {
154 else if (type.matches(*fContext.fTypes.fShort)) {
157 else if (type.matches(*fContext.fTypes.fUShort)) {
161 return std::string(type.name());
166 return std::string(type.name());
170 void GLSLCodeGenerator::writeStructDefinition(const StructDefinition& s) {
171 const Type& type = s.type();
172 this->write("struct ");
173 this->write(type.name());
174 this->writeLine(" {");
176 for (const auto& f : type.fields()) {
177 this->writeModifiers(f.fModifiers, false);
178 this->writeTypePrecision(*f.fType);
179 const Type& baseType = f.fType->isArray() ? f.fType->componentType() : *f.fType;
180 this->writeType(baseType);
182 this->write(f.fName);
183 if (f.fType->isArray()) {
184 this->write("[" + std::to_string(f.fType->columns()) + "]");
186 this->writeLine(";");
189 this->writeLine("};");
192 void GLSLCodeGenerator::writeType(const Type& type) {
193 this->write(this->getTypeName(type));
196 void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
197 switch (expr.kind()) {
198 case Expression::Kind::kBinary:
199 this->writeBinaryExpression(expr.as<BinaryExpression>(), parentPrecedence);
201 case Expression::Kind::kConstructorDiagonalMatrix:
202 this->writeConstructorDiagonalMatrix(expr.as<ConstructorDiagonalMatrix>(),
205 case Expression::Kind::kConstructorArrayCast:
206 this->writeExpression(*expr.as<ConstructorArrayCast>().argument(), parentPrecedence);
208 case Expression::Kind::kConstructorArray:
209 case Expression::Kind::kConstructorCompound:
210 case Expression::Kind::kConstructorMatrixResize:
211 case Expression::Kind::kConstructorSplat:
212 case Expression::Kind::kConstructorStruct:
213 this->writeAnyConstructor(expr.asAnyConstructor(), parentPrecedence);
215 case Expression::Kind::kConstructorScalarCast:
216 case Expression::Kind::kConstructorCompoundCast:
217 this->writeCastConstructor(expr.asAnyConstructor(), parentPrecedence);
219 case Expression::Kind::kFieldAccess:
220 this->writeFieldAccess(expr.as<FieldAccess>());
222 case Expression::Kind::kFunctionCall:
223 this->writeFunctionCall(expr.as<FunctionCall>());
225 case Expression::Kind::kLiteral:
226 this->writeLiteral(expr.as<Literal>());
228 case Expression::Kind::kPrefix:
229 this->writePrefixExpression(expr.as<PrefixExpression>(), parentPrecedence);
231 case Expression::Kind::kPostfix:
232 this->writePostfixExpression(expr.as<PostfixExpression>(), parentPrecedence);
234 case Expression::Kind::kSetting:
235 this->writeSetting(expr.as<Setting>());
237 case Expression::Kind::kSwizzle:
238 this->writeSwizzle(expr.as<Swizzle>());
240 case Expression::Kind::kVariableReference:
241 this->writeVariableReference(expr.as<VariableReference>());
243 case Expression::Kind::kTernary:
244 this->writeTernaryExpression(expr.as<TernaryExpression>(), parentPrecedence);
246 case Expression::Kind::kIndex:
247 this->writeIndexExpression(expr.as<IndexExpression>());
250 SkDEBUGFAILF("unsupported expression: %s", expr.description().c_str());
255 static bool is_abs(Expression& expr) {
256 return expr.is<FunctionCall>() &&
257 expr.as<FunctionCall>().function().intrinsicKind() == k_abs_IntrinsicKind;
260 // turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a
261 // Tegra3 compiler bug.
262 void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
263 SkASSERT(!this->caps().canUseMinAndAbsTogether());
264 std::string tmpVar1 = "minAbsHackVar" + std::to_string(fVarCount++);
265 std::string tmpVar2 = "minAbsHackVar" + std::to_string(fVarCount++);
266 this->fFunctionHeader += std::string(" ") + this->getTypePrecision(absExpr.type()) +
267 this->getTypeName(absExpr.type()) + " " + tmpVar1 + ";\n";
268 this->fFunctionHeader += std::string(" ") + this->getTypePrecision(otherExpr.type()) +
269 this->getTypeName(otherExpr.type()) + " " + tmpVar2 + ";\n";
270 this->write("((" + tmpVar1 + " = ");
271 this->writeExpression(absExpr, Precedence::kTopLevel);
272 this->write(") < (" + tmpVar2 + " = ");
273 this->writeExpression(otherExpr, Precedence::kAssignment);
274 this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")");
277 void GLSLCodeGenerator::writeInverseSqrtHack(const Expression& x) {
278 this->write("(1.0 / sqrt(");
279 this->writeExpression(x, Precedence::kTopLevel);
283 void GLSLCodeGenerator::writeDeterminantHack(const Expression& mat) {
285 const Type& type = mat.type();
286 if (type.matches(*fContext.fTypes.fFloat2x2) || type.matches(*fContext.fTypes.fHalf2x2)) {
287 name = "_determinant2";
288 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
289 fWrittenIntrinsics.insert(name);
290 fExtraFunctions.writeText((
291 "float " + name + "(mat2 m) {"
292 " return m[0][0] * m[1][1] - m[0][1] * m[1][0];"
297 else if (type.matches(*fContext.fTypes.fFloat3x3) || type.matches(*fContext.fTypes.fHalf3x3)) {
298 name = "_determinant3";
299 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
300 fWrittenIntrinsics.insert(name);
301 fExtraFunctions.writeText((
302 "float " + name + "(mat3 m) {"
303 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
304 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
305 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
306 " float b01 = a22 * a11 - a12 * a21;"
307 " float b11 = -a22 * a10 + a12 * a20;"
308 " float b21 = a21 * a10 - a11 * a20;"
309 " return a00 * b01 + a01 * b11 + a02 * b21;"
314 else if (type.matches(*fContext.fTypes.fFloat4x4) || type.matches(*fContext.fTypes.fHalf4x4)) {
315 name = "_determinant4";
316 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
317 fWrittenIntrinsics.insert(name);
318 fExtraFunctions.writeText((
319 "mat4 " + name + "(mat4 m) {"
320 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
321 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
322 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
323 " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
324 " float b00 = a00 * a11 - a01 * a10;"
325 " float b01 = a00 * a12 - a02 * a10;"
326 " float b02 = a00 * a13 - a03 * a10;"
327 " float b03 = a01 * a12 - a02 * a11;"
328 " float b04 = a01 * a13 - a03 * a11;"
329 " float b05 = a02 * a13 - a03 * a12;"
330 " float b06 = a20 * a31 - a21 * a30;"
331 " float b07 = a20 * a32 - a22 * a30;"
332 " float b08 = a20 * a33 - a23 * a30;"
333 " float b09 = a21 * a32 - a22 * a31;"
334 " float b10 = a21 * a33 - a23 * a31;"
335 " float b11 = a22 * a33 - a23 * a32;"
336 " return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;"
344 this->write(name + "(");
345 this->writeExpression(mat, Precedence::kTopLevel);
349 void GLSLCodeGenerator::writeInverseHack(const Expression& mat) {
351 const Type& type = mat.type();
352 if (type.matches(*fContext.fTypes.fFloat2x2) || type.matches(*fContext.fTypes.fHalf2x2)) {
354 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
355 fWrittenIntrinsics.insert(name);
356 fExtraFunctions.writeText((
357 "mat2 " + name + "(mat2 m) {"
358 " return mat2(m[1][1], -m[0][1], -m[1][0], m[0][0]) / "
359 "(m[0][0] * m[1][1] - m[0][1] * m[1][0]);"
364 else if (type.matches(*fContext.fTypes.fFloat3x3) || type.matches(*fContext.fTypes.fHalf3x3)) {
366 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
367 fWrittenIntrinsics.insert(name);
368 fExtraFunctions.writeText((
369 "mat3 " + name + "(mat3 m) {"
370 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
371 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
372 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
373 " float b01 = a22 * a11 - a12 * a21;"
374 " float b11 = -a22 * a10 + a12 * a20;"
375 " float b21 = a21 * a10 - a11 * a20;"
376 " float det = a00 * b01 + a01 * b11 + a02 * b21;"
377 " return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),"
378 " b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),"
379 " b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;"
384 else if (type.matches(*fContext.fTypes.fFloat4x4) || type.matches(*fContext.fTypes.fHalf4x4)) {
386 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
387 fWrittenIntrinsics.insert(name);
388 fExtraFunctions.writeText((
389 "mat4 " + name + "(mat4 m) {"
390 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
391 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
392 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
393 " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
394 " float b00 = a00 * a11 - a01 * a10;"
395 " float b01 = a00 * a12 - a02 * a10;"
396 " float b02 = a00 * a13 - a03 * a10;"
397 " float b03 = a01 * a12 - a02 * a11;"
398 " float b04 = a01 * a13 - a03 * a11;"
399 " float b05 = a02 * a13 - a03 * a12;"
400 " float b06 = a20 * a31 - a21 * a30;"
401 " float b07 = a20 * a32 - a22 * a30;"
402 " float b08 = a20 * a33 - a23 * a30;"
403 " float b09 = a21 * a32 - a22 * a31;"
404 " float b10 = a21 * a33 - a23 * a31;"
405 " float b11 = a22 * a33 - a23 * a32;"
406 " float det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - "
407 " b04 * b07 + b05 * b06;"
409 " a11 * b11 - a12 * b10 + a13 * b09,"
410 " a02 * b10 - a01 * b11 - a03 * b09,"
411 " a31 * b05 - a32 * b04 + a33 * b03,"
412 " a22 * b04 - a21 * b05 - a23 * b03,"
413 " a12 * b08 - a10 * b11 - a13 * b07,"
414 " a00 * b11 - a02 * b08 + a03 * b07,"
415 " a32 * b02 - a30 * b05 - a33 * b01,"
416 " a20 * b05 - a22 * b02 + a23 * b01,"
417 " a10 * b10 - a11 * b08 + a13 * b06,"
418 " a01 * b08 - a00 * b10 - a03 * b06,"
419 " a30 * b04 - a31 * b02 + a33 * b00,"
420 " a21 * b02 - a20 * b04 - a23 * b00,"
421 " a11 * b07 - a10 * b09 - a12 * b06,"
422 " a00 * b09 - a01 * b07 + a02 * b06,"
423 " a31 * b01 - a30 * b03 - a32 * b00,"
424 " a20 * b03 - a21 * b01 + a22 * b00) / det;"
432 this->write(name + "(");
433 this->writeExpression(mat, Precedence::kTopLevel);
437 void GLSLCodeGenerator::writeTransposeHack(const Expression& mat) {
438 const Type& type = mat.type();
439 std::string name = "transpose" + std::to_string(type.columns()) + std::to_string(type.rows());
440 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
441 fWrittenIntrinsics.insert(name);
442 std::string typeName = this->getTypeName(type);
443 const Type& base = type.componentType();
444 std::string transposed = this->getTypeName(base.toCompound(fContext,
447 fExtraFunctions.writeText((transposed + " " + name + "(" + typeName + " m) {\nreturn " +
448 transposed + "(").c_str());
449 const char* separator = "";
450 for (int row = 0; row < type.rows(); ++row) {
451 for (int column = 0; column < type.columns(); ++column) {
452 fExtraFunctions.writeText(separator);
453 fExtraFunctions.writeText(("m[" + std::to_string(column) + "][" +
454 std::to_string(row) + "]").c_str());
458 fExtraFunctions.writeText("); }");
460 this->write(name + "(");
461 this->writeExpression(mat, Precedence::kTopLevel);
465 void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
466 const FunctionDeclaration& function = c.function();
467 const ExpressionArray& arguments = c.arguments();
468 bool isTextureFunctionWithBias = false;
469 bool nameWritten = false;
470 const char* closingParen = ")";
471 switch (c.function().intrinsicKind()) {
472 case k_abs_IntrinsicKind: {
473 if (!this->caps().emulateAbsIntFunction())
475 SkASSERT(arguments.size() == 1);
476 if (!arguments[0]->type().matches(*fContext.fTypes.fInt)) {
479 // abs(int) on Intel OSX is incorrect, so emulate it:
480 std::string name = "_absemulation";
483 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
484 fWrittenIntrinsics.insert(name);
485 fExtraFunctions.writeText((
486 "int " + name + "(int x) {\n"
487 " return x * sign(x);\n"
493 case k_atan_IntrinsicKind:
494 if (this->caps().mustForceNegatedAtanParamToFloat() &&
495 arguments.size() == 2 &&
496 arguments[1]->kind() == Expression::Kind::kPrefix) {
497 const PrefixExpression& p = (PrefixExpression&) *arguments[1];
498 if (p.getOperator().kind() == Operator::Kind::MINUS) {
499 this->write("atan(");
500 this->writeExpression(*arguments[0], Precedence::kSequence);
501 this->write(", -1.0 * ");
502 this->writeExpression(*p.operand(), Precedence::kMultiplicative);
508 case k_ldexp_IntrinsicKind:
509 if (this->caps().mustForceNegatedLdexpParamToMultiply() &&
510 arguments.size() == 2 &&
511 arguments[1]->is<PrefixExpression>()) {
512 const PrefixExpression& p = arguments[1]->as<PrefixExpression>();
513 if (p.getOperator().kind() == Operator::Kind::MINUS) {
514 this->write("ldexp(");
515 this->writeExpression(*arguments[0], Precedence::kSequence);
517 this->writeExpression(*p.operand(), Precedence::kMultiplicative);
518 this->write(" * -1)");
523 case k_dFdy_IntrinsicKind:
524 // Flipping Y also negates the Y derivatives.
527 if (!fProgram.fConfig->fSettings.fForceNoRTFlip) {
528 this->write(SKSL_RTFLIP_NAME ".y * ");
533 case k_dFdx_IntrinsicKind:
534 case k_fwidth_IntrinsicKind:
535 if (!fFoundDerivatives &&
536 this->caps().shaderDerivativeExtensionString()) {
537 this->writeExtension(this->caps().shaderDerivativeExtensionString());
538 fFoundDerivatives = true;
541 case k_determinant_IntrinsicKind:
542 if (!this->caps().builtinDeterminantSupport()) {
543 SkASSERT(arguments.size() == 1);
544 this->writeDeterminantHack(*arguments[0]);
548 case k_fma_IntrinsicKind:
549 if (!this->caps().builtinFMASupport()) {
550 SkASSERT(arguments.size() == 3);
552 this->writeExpression(*arguments[0], Precedence::kSequence);
553 this->write(") * (");
554 this->writeExpression(*arguments[1], Precedence::kSequence);
555 this->write(") + (");
556 this->writeExpression(*arguments[2], Precedence::kSequence);
561 case k_fract_IntrinsicKind:
562 if (!this->caps().canUseFractForNegativeValues()) {
563 SkASSERT(arguments.size() == 1);
564 this->write("(0.5 - sign(");
565 this->writeExpression(*arguments[0], Precedence::kSequence);
566 this->write(") * (0.5 - fract(abs(");
567 this->writeExpression(*arguments[0], Precedence::kSequence);
572 case k_inverse_IntrinsicKind:
573 if (this->caps().generation() < SkSL::GLSLGeneration::k140) {
574 SkASSERT(arguments.size() == 1);
575 this->writeInverseHack(*arguments[0]);
579 case k_inversesqrt_IntrinsicKind:
580 if (this->caps().generation() < SkSL::GLSLGeneration::k130) {
581 SkASSERT(arguments.size() == 1);
582 this->writeInverseSqrtHack(*arguments[0]);
586 case k_min_IntrinsicKind:
587 if (!this->caps().canUseMinAndAbsTogether()) {
588 SkASSERT(arguments.size() == 2);
589 if (is_abs(*arguments[0])) {
590 this->writeMinAbsHack(*arguments[0], *arguments[1]);
593 if (is_abs(*arguments[1])) {
594 // note that this violates the GLSL left-to-right evaluation semantics.
595 // I doubt it will ever end up mattering, but it's worth calling out.
596 this->writeMinAbsHack(*arguments[1], *arguments[0]);
601 case k_pow_IntrinsicKind:
602 if (!this->caps().removePowWithConstantExponent()) {
605 // pow(x, y) on some NVIDIA drivers causes crashes if y is a
606 // constant. It's hard to tell what constitutes "constant" here
607 // so just replace in all cases.
609 // Change pow(x, y) into exp2(y * log2(x))
610 this->write("exp2(");
611 this->writeExpression(*arguments[1], Precedence::kMultiplicative);
612 this->write(" * log2(");
613 this->writeExpression(*arguments[0], Precedence::kSequence);
616 case k_saturate_IntrinsicKind:
617 SkASSERT(arguments.size() == 1);
618 this->write("clamp(");
619 this->writeExpression(*arguments[0], Precedence::kSequence);
620 this->write(", 0.0, 1.0)");
622 case k_sample_IntrinsicKind: {
623 const char* dim = "";
625 const Type& arg0Type = arguments[0]->type();
626 const Type& arg1Type = arguments[1]->type();
627 switch (arg0Type.dimensions()) {
630 isTextureFunctionWithBias = true;
631 if (arg1Type.matches(*fContext.fTypes.fFloat)) {
634 SkASSERT(arg1Type.matches(*fContext.fTypes.fFloat2));
640 if (!arg0Type.matches(*fContext.fTypes.fSamplerExternalOES)) {
641 isTextureFunctionWithBias = true;
643 if (arg1Type.matches(*fContext.fTypes.fFloat2)) {
646 SkASSERT(arg1Type.matches(*fContext.fTypes.fFloat3));
652 isTextureFunctionWithBias = true;
653 if (arg1Type.matches(*fContext.fTypes.fFloat3)) {
656 SkASSERT(arg1Type.matches(*fContext.fTypes.fFloat4));
662 isTextureFunctionWithBias = true;
670 SkASSERT(false); // doesn't exist
674 case SpvDimSubpassData:
675 SkASSERT(false); // doesn't exist
680 this->write("texture");
681 if (this->caps().generation() < SkSL::GLSLGeneration::k130) {
690 case k_transpose_IntrinsicKind:
691 if (this->caps().generation() < SkSL::GLSLGeneration::k130) {
692 SkASSERT(arguments.size() == 1);
693 this->writeTransposeHack(*arguments[0]);
702 this->write(function.mangledName());
705 const char* separator = "";
706 for (const auto& arg : arguments) {
707 this->write(separator);
709 this->writeExpression(*arg, Precedence::kSequence);
711 if (fProgram.fConfig->fSettings.fSharpenTextures && isTextureFunctionWithBias) {
712 this->write(String::printf(", %g", kSharpenTexturesBias));
714 this->write(closingParen);
717 void GLSLCodeGenerator::writeConstructorDiagonalMatrix(const ConstructorDiagonalMatrix& c,
718 Precedence parentPrecedence) {
719 if (c.type().columns() == 4 && c.type().rows() == 2) {
720 // Due to a longstanding bug in glslang and Mesa, several GPU drivers generate diagonal 4x2
721 // matrices incorrectly. (skia:12003, https://github.com/KhronosGroup/glslang/pull/2646)
722 // We can work around this issue by multiplying a scalar by the identity matrix.
723 // In practice, this doesn't come up naturally in real code and we don't know every affected
724 // driver, so we just apply this workaround everywhere.
726 this->writeType(c.type());
727 this->write("(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) * ");
728 this->writeExpression(*c.argument(), Precedence::kMultiplicative);
732 this->writeAnyConstructor(c, parentPrecedence);
735 void GLSLCodeGenerator::writeCastConstructor(const AnyConstructor& c, Precedence parentPrecedence) {
736 const auto arguments = c.argumentSpan();
737 SkASSERT(arguments.size() == 1);
739 const Expression& argument = *arguments.front();
740 if ((this->getTypeName(c.type()) == this->getTypeName(argument.type()) ||
741 (argument.type().matches(*fContext.fTypes.fFloatLiteral)))) {
742 // In cases like half(float), they're different types as far as SkSL is concerned but
743 // the same type as far as GLSL is concerned. We avoid a redundant float(float) by just
744 // writing out the inner expression here.
745 this->writeExpression(argument, parentPrecedence);
749 // This cast should be emitted as-is.
750 return this->writeAnyConstructor(c, parentPrecedence);
753 void GLSLCodeGenerator::writeAnyConstructor(const AnyConstructor& c, Precedence parentPrecedence) {
754 this->writeType(c.type());
756 const char* separator = "";
757 for (const auto& arg : c.argumentSpan()) {
758 this->write(separator);
760 this->writeExpression(*arg, Precedence::kSequence);
765 void GLSLCodeGenerator::writeFragCoord() {
766 if (!this->caps().canUseFragCoord()) {
767 if (!fSetupFragCoordWorkaround) {
768 const char* precision = usesPrecisionModifiers() ? "highp " : "";
769 fFunctionHeader += precision;
770 fFunctionHeader += " float sk_FragCoord_InvW = 1. / sk_FragCoord_Workaround.w;\n";
771 fFunctionHeader += precision;
772 fFunctionHeader += " vec4 sk_FragCoord_Resolved = "
773 "vec4(sk_FragCoord_Workaround.xyz * sk_FragCoord_InvW, sk_FragCoord_InvW);\n";
774 // Ensure that we get exact .5 values for x and y.
775 fFunctionHeader += " sk_FragCoord_Resolved.xy = floor(sk_FragCoord_Resolved.xy) + "
777 fSetupFragCoordWorkaround = true;
779 this->write("sk_FragCoord_Resolved");
783 if (!fSetupFragPosition) {
784 fFunctionHeader += this->usesPrecisionModifiers() ? "highp " : "";
785 fFunctionHeader += " vec4 sk_FragCoord = vec4("
787 if (fProgram.fConfig->fSettings.fForceNoRTFlip) {
788 fFunctionHeader += "gl_FragCoord.y, ";
790 fFunctionHeader += SKSL_RTFLIP_NAME ".x + " SKSL_RTFLIP_NAME ".y * gl_FragCoord.y, ";
794 "gl_FragCoord.w);\n";
795 fSetupFragPosition = true;
797 this->write("sk_FragCoord");
800 void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
801 switch (ref.variable()->modifiers().fLayout.fBuiltin) {
802 case SK_FRAGCOLOR_BUILTIN:
803 if (this->caps().mustDeclareFragmentShaderOutput()) {
804 this->write("sk_FragColor");
806 this->write("gl_FragColor");
809 case SK_SECONDARYFRAGCOLOR_BUILTIN:
810 this->write("gl_SecondaryFragColorEXT");
812 case SK_FRAGCOORD_BUILTIN:
813 this->writeFragCoord();
815 case SK_CLOCKWISE_BUILTIN:
816 if (!fSetupClockwise) {
817 fFunctionHeader += " bool sk_Clockwise = gl_FrontFacing;\n";
818 if (!fProgram.fConfig->fSettings.fForceNoRTFlip) {
819 fFunctionHeader += " if (" SKSL_RTFLIP_NAME ".y < 0.0) {\n"
820 " sk_Clockwise = !sk_Clockwise;\n"
823 fSetupClockwise = true;
825 this->write("sk_Clockwise");
827 case SK_VERTEXID_BUILTIN:
828 this->write("gl_VertexID");
830 case SK_INSTANCEID_BUILTIN:
831 this->write("gl_InstanceID");
833 case SK_LASTFRAGCOLOR_BUILTIN:
834 if (this->caps().fbFetchSupport()) {
835 this->write(this->caps().fbFetchColorName());
837 fContext.fErrors->error(ref.fPosition,
838 "sk_LastFragColor requires framebuffer fetch support");
842 this->write(ref.variable()->name());
847 void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
848 this->writeExpression(*expr.base(), Precedence::kPostfix);
850 this->writeExpression(*expr.index(), Precedence::kTopLevel);
854 bool is_sk_position(const FieldAccess& f) {
855 return f.base()->type().fields()[f.fieldIndex()].fModifiers.fLayout.fBuiltin ==
859 void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
860 if (f.ownerKind() == FieldAccess::OwnerKind::kDefault) {
861 this->writeExpression(*f.base(), Precedence::kPostfix);
864 const Type& baseType = f.base()->type();
865 int builtin = baseType.fields()[f.fieldIndex()].fModifiers.fLayout.fBuiltin;
866 if (builtin == SK_POSITION_BUILTIN) {
867 this->write("gl_Position");
868 } else if (builtin == SK_POINTSIZE_BUILTIN) {
869 this->write("gl_PointSize");
871 this->write(baseType.fields()[f.fieldIndex()].fName);
875 void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
876 this->writeExpression(*swizzle.base(), Precedence::kPostfix);
878 for (int c : swizzle.components()) {
879 SkASSERT(c >= 0 && c <= 3);
880 this->write(&("x\0y\0z\0w\0"[c * 2]));
884 void GLSLCodeGenerator::writeMatrixComparisonWorkaround(const BinaryExpression& b) {
885 const Expression& left = *b.left();
886 const Expression& right = *b.right();
887 Operator op = b.getOperator();
889 SkASSERT(op.kind() == Operator::Kind::EQEQ || op.kind() == Operator::Kind::NEQ);
890 SkASSERT(left.type().isMatrix());
891 SkASSERT(right.type().isMatrix());
893 std::string tempMatrix1 = "_tempMatrix" + std::to_string(fVarCount++);
894 std::string tempMatrix2 = "_tempMatrix" + std::to_string(fVarCount++);
896 this->fFunctionHeader += std::string(" ") + this->getTypePrecision(left.type()) +
897 this->getTypeName(left.type()) + " " + tempMatrix1 + ";\n " +
898 this->getTypePrecision(right.type()) +
899 this->getTypeName(right.type()) + " " + tempMatrix2 + ";\n";
900 this->write("((" + tempMatrix1 + " = ");
901 this->writeExpression(left, Precedence::kAssignment);
902 this->write("), (" + tempMatrix2 + " = ");
903 this->writeExpression(right, Precedence::kAssignment);
904 this->write("), (" + tempMatrix1);
905 this->write(op.operatorName());
906 this->write(tempMatrix2 + "))");
909 void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
910 Precedence parentPrecedence) {
911 const Expression& left = *b.left();
912 const Expression& right = *b.right();
913 Operator op = b.getOperator();
914 if (this->caps().unfoldShortCircuitAsTernary() &&
915 (op.kind() == Operator::Kind::LOGICALAND || op.kind() == Operator::Kind::LOGICALOR)) {
916 this->writeShortCircuitWorkaroundExpression(b, parentPrecedence);
920 if (this->caps().rewriteMatrixComparisons() &&
921 left.type().isMatrix() && right.type().isMatrix() &&
922 (op.kind() == Operator::Kind::EQEQ || op.kind() == Operator::Kind::NEQ)) {
923 this->writeMatrixComparisonWorkaround(b);
927 Precedence precedence = op.getBinaryPrecedence();
928 if (precedence >= parentPrecedence) {
931 bool positionWorkaround = ProgramConfig::IsVertex(fProgram.fConfig->fKind) &&
933 left.is<FieldAccess>() &&
934 is_sk_position(left.as<FieldAccess>()) &&
935 !right.containsRTAdjust() &&
936 !this->caps().canUseFragCoord();
937 if (positionWorkaround) {
938 this->write("sk_FragCoord_Workaround = (");
940 this->writeExpression(left, precedence);
941 this->write(op.operatorName());
942 this->writeExpression(right, precedence);
943 if (positionWorkaround) {
946 if (precedence >= parentPrecedence) {
951 void GLSLCodeGenerator::writeShortCircuitWorkaroundExpression(const BinaryExpression& b,
952 Precedence parentPrecedence) {
953 if (Precedence::kTernary >= parentPrecedence) {
958 // a && b => a ? b : false
959 // a || b => a ? true : b
960 this->writeExpression(*b.left(), Precedence::kTernary);
962 if (b.getOperator().kind() == Operator::Kind::LOGICALAND) {
963 this->writeExpression(*b.right(), Precedence::kTernary);
965 Literal boolTrue(Position(), /*value=*/1, fContext.fTypes.fBool.get());
966 this->writeLiteral(boolTrue);
969 if (b.getOperator().kind() == Operator::Kind::LOGICALAND) {
970 Literal boolFalse(Position(), /*value=*/0, fContext.fTypes.fBool.get());
971 this->writeLiteral(boolFalse);
973 this->writeExpression(*b.right(), Precedence::kTernary);
975 if (Precedence::kTernary >= parentPrecedence) {
980 void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
981 Precedence parentPrecedence) {
982 if (Precedence::kTernary >= parentPrecedence) {
985 this->writeExpression(*t.test(), Precedence::kTernary);
987 this->writeExpression(*t.ifTrue(), Precedence::kTernary);
989 this->writeExpression(*t.ifFalse(), Precedence::kTernary);
990 if (Precedence::kTernary >= parentPrecedence) {
995 void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
996 Precedence parentPrecedence) {
997 if (Precedence::kPrefix >= parentPrecedence) {
1000 this->write(p.getOperator().tightOperatorName());
1001 this->writeExpression(*p.operand(), Precedence::kPrefix);
1002 if (Precedence::kPrefix >= parentPrecedence) {
1007 void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
1008 Precedence parentPrecedence) {
1009 if (Precedence::kPostfix >= parentPrecedence) {
1012 this->writeExpression(*p.operand(), Precedence::kPostfix);
1013 this->write(p.getOperator().tightOperatorName());
1014 if (Precedence::kPostfix >= parentPrecedence) {
1019 void GLSLCodeGenerator::writeLiteral(const Literal& l) {
1020 const Type& type = l.type();
1021 if (type.isFloat()) {
1022 this->write(skstd::to_string(l.floatValue()));
1025 if (type.isInteger()) {
1026 if (type.matches(*fContext.fTypes.fUInt)) {
1027 this->write(std::to_string(l.intValue() & 0xffffffff) + "u");
1028 } else if (type.matches(*fContext.fTypes.fUShort)) {
1029 this->write(std::to_string(l.intValue() & 0xffff) + "u");
1031 this->write(std::to_string(l.intValue()));
1035 SkASSERT(type.isBoolean());
1036 this->write(l.boolValue() ? "true" : "false");
1039 void GLSLCodeGenerator::writeSetting(const Setting& s) {
1040 SK_ABORT("internal error; setting was not folded to a constant during compilation\n");
1043 void GLSLCodeGenerator::writeFunctionDeclaration(const FunctionDeclaration& f) {
1044 this->writeTypePrecision(f.returnType());
1045 this->writeType(f.returnType());
1046 this->write(" " + f.mangledName() + "(");
1047 const char* separator = "";
1048 for (const auto& param : f.parameters()) {
1049 // This is a workaround for our test files. They use the runtime effect signature, so main
1050 // takes a coords parameter. The IR generator tags those with a builtin ID (sk_FragCoord),
1051 // and we omit them from the declaration here, so the function is valid GLSL.
1052 if (f.isMain() && param->modifiers().fLayout.fBuiltin != -1) {
1055 this->write(separator);
1057 this->writeModifiers(param->modifiers(), false);
1058 std::vector<int> sizes;
1059 const Type* type = ¶m->type();
1060 if (type->isArray()) {
1061 sizes.push_back(type->columns());
1062 type = &type->componentType();
1064 this->writeTypePrecision(*type);
1065 this->writeType(*type);
1066 this->write(" " + std::string(param->name()));
1067 for (int s : sizes) {
1068 this->write("[" + std::to_string(s) + "]");
1074 void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
1075 fSetupFragPosition = false;
1076 fSetupFragCoordWorkaround = false;
1078 this->writeFunctionDeclaration(f.declaration());
1079 this->writeLine(" {");
1082 fFunctionHeader.clear();
1083 OutputStream* oldOut = fOut;
1084 StringStream buffer;
1086 for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) {
1087 if (!stmt->isEmpty()) {
1088 this->writeStatement(*stmt);
1094 this->writeLine("}");
1097 this->write(fFunctionHeader);
1098 this->write(buffer.str());
1101 void GLSLCodeGenerator::writeFunctionPrototype(const FunctionPrototype& f) {
1102 this->writeFunctionDeclaration(f.declaration());
1103 this->writeLine(";");
1106 void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
1107 bool globalContext) {
1108 std::string layout = modifiers.fLayout.description();
1109 if (layout.size()) {
1110 this->write(layout + " ");
1113 // For GLSL 4.1 and below, qualifier-order matters! These are written out in Modifier-bit order.
1114 if (modifiers.fFlags & Modifiers::kFlat_Flag) {
1115 this->write("flat ");
1117 if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
1118 this->write("noperspective ");
1121 if (modifiers.fFlags & Modifiers::kConst_Flag) {
1122 this->write("const ");
1124 if (modifiers.fFlags & Modifiers::kUniform_Flag) {
1125 this->write("uniform ");
1127 if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
1128 (modifiers.fFlags & Modifiers::kOut_Flag)) {
1129 this->write("inout ");
1130 } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
1131 if (globalContext && this->caps().generation() < SkSL::GLSLGeneration::k130) {
1132 this->write(ProgramConfig::IsVertex(fProgram.fConfig->fKind) ? "attribute "
1137 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
1138 if (globalContext &&
1139 this->caps().generation() < SkSL::GLSLGeneration::k130) {
1140 this->write("varying ");
1142 this->write("out ");
1148 void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
1149 if (intf.typeName() == "sk_PerVertex") {
1152 this->writeModifiers(intf.variable().modifiers(), true);
1153 this->writeLine(std::string(intf.typeName()) + " {");
1155 const Type* structType = &intf.variable().type();
1156 if (structType->isArray()) {
1157 structType = &structType->componentType();
1159 for (const auto& f : structType->fields()) {
1160 this->writeModifiers(f.fModifiers, false);
1161 this->writeTypePrecision(*f.fType);
1162 this->writeType(*f.fType);
1163 this->writeLine(" " + std::string(f.fName) + ";");
1167 if (intf.instanceName().size()) {
1169 this->write(intf.instanceName());
1170 if (intf.arraySize() > 0) {
1172 this->write(std::to_string(intf.arraySize()));
1176 this->writeLine(";");
1179 void GLSLCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
1180 this->writeExpression(value, Precedence::kTopLevel);
1183 const char* GLSLCodeGenerator::getTypePrecision(const Type& type) {
1184 if (usesPrecisionModifiers()) {
1185 switch (type.typeKind()) {
1186 case Type::TypeKind::kScalar:
1187 if (type.matches(*fContext.fTypes.fShort) ||
1188 type.matches(*fContext.fTypes.fUShort)) {
1189 if (fProgram.fConfig->fSettings.fForceHighPrecision ||
1190 this->caps().incompleteShortIntPrecision()) {
1195 if (type.matches(*fContext.fTypes.fHalf)) {
1196 return fProgram.fConfig->fSettings.fForceHighPrecision ? "highp " : "mediump ";
1198 if (type.matches(*fContext.fTypes.fFloat) || type.matches(*fContext.fTypes.fInt) ||
1199 type.matches(*fContext.fTypes.fUInt)) {
1203 case Type::TypeKind::kVector: // fall through
1204 case Type::TypeKind::kMatrix:
1205 case Type::TypeKind::kArray:
1206 return this->getTypePrecision(type.componentType());
1214 void GLSLCodeGenerator::writeTypePrecision(const Type& type) {
1215 this->write(this->getTypePrecision(type));
1218 void GLSLCodeGenerator::writeVarDeclaration(const VarDeclaration& var, bool global) {
1219 this->writeModifiers(var.var().modifiers(), global);
1220 this->writeTypePrecision(var.baseType());
1221 this->writeType(var.baseType());
1223 this->write(var.var().name());
1224 if (var.arraySize() > 0) {
1226 this->write(std::to_string(var.arraySize()));
1231 this->writeVarInitializer(var.var(), *var.value());
1233 if (!fFoundExternalSamplerDecl &&
1234 var.var().type().matches(*fContext.fTypes.fSamplerExternalOES)) {
1235 if (this->caps().externalTextureExtensionString()) {
1236 this->writeExtension(this->caps().externalTextureExtensionString());
1238 if (this->caps().secondExternalTextureExtensionString()) {
1239 this->writeExtension(this->caps().secondExternalTextureExtensionString());
1241 fFoundExternalSamplerDecl = true;
1243 if (!fFoundRectSamplerDecl && var.var().type().matches(*fContext.fTypes.fSampler2DRect)) {
1244 fFoundRectSamplerDecl = true;
1249 void GLSLCodeGenerator::writeStatement(const Statement& s) {
1251 case Statement::Kind::kBlock:
1252 this->writeBlock(s.as<Block>());
1254 case Statement::Kind::kExpression:
1255 this->writeExpressionStatement(s.as<ExpressionStatement>());
1257 case Statement::Kind::kReturn:
1258 this->writeReturnStatement(s.as<ReturnStatement>());
1260 case Statement::Kind::kVarDeclaration:
1261 this->writeVarDeclaration(s.as<VarDeclaration>(), false);
1263 case Statement::Kind::kIf:
1264 this->writeIfStatement(s.as<IfStatement>());
1266 case Statement::Kind::kFor:
1267 this->writeForStatement(s.as<ForStatement>());
1269 case Statement::Kind::kDo:
1270 this->writeDoStatement(s.as<DoStatement>());
1272 case Statement::Kind::kSwitch:
1273 this->writeSwitchStatement(s.as<SwitchStatement>());
1275 case Statement::Kind::kBreak:
1276 this->write("break;");
1278 case Statement::Kind::kContinue:
1279 this->write("continue;");
1281 case Statement::Kind::kDiscard:
1282 this->write("discard;");
1284 case Statement::Kind::kNop:
1288 SkDEBUGFAILF("unsupported statement: %s", s.description().c_str());
1293 void GLSLCodeGenerator::writeBlock(const Block& b) {
1294 // Write scope markers if this block is a scope, or if the block is empty (since we need to emit
1295 // something here to make the code valid).
1296 bool isScope = b.isScope() || b.isEmpty();
1298 this->writeLine("{");
1301 for (const std::unique_ptr<Statement>& stmt : b.children()) {
1302 if (!stmt->isEmpty()) {
1303 this->writeStatement(*stmt);
1313 void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
1314 this->write("if (");
1315 this->writeExpression(*stmt.test(), Precedence::kTopLevel);
1317 this->writeStatement(*stmt.ifTrue());
1318 if (stmt.ifFalse()) {
1319 this->write(" else ");
1320 this->writeStatement(*stmt.ifFalse());
1324 void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
1325 // Emit loops of the form 'for(;test;)' as 'while(test)', which is probably how they started
1326 if (!f.initializer() && f.test() && !f.next()) {
1327 this->write("while (");
1328 this->writeExpression(*f.test(), Precedence::kTopLevel);
1330 this->writeStatement(*f.statement());
1334 this->write("for (");
1335 if (f.initializer() && !f.initializer()->isEmpty()) {
1336 this->writeStatement(*f.initializer());
1341 if (this->caps().addAndTrueToLoopCondition()) {
1342 std::unique_ptr<Expression> and_true(new BinaryExpression(
1343 Position(), f.test()->clone(), Operator::Kind::LOGICALAND,
1344 Literal::MakeBool(fContext, Position(), /*value=*/true),
1345 fContext.fTypes.fBool.get()));
1346 this->writeExpression(*and_true, Precedence::kTopLevel);
1348 this->writeExpression(*f.test(), Precedence::kTopLevel);
1353 this->writeExpression(*f.next(), Precedence::kTopLevel);
1356 this->writeStatement(*f.statement());
1359 void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
1360 if (!this->caps().rewriteDoWhileLoops()) {
1362 this->writeStatement(*d.statement());
1363 this->write(" while (");
1364 this->writeExpression(*d.test(), Precedence::kTopLevel);
1369 // Otherwise, do the do while loop workaround, to rewrite loops of the form:
1372 // } while (CONDITION)
1374 // to loops of the form
1375 // bool temp = false;
1378 // if (!CONDITION) {
1385 std::string tmpVar = "_tmpLoopSeenOnce" + std::to_string(fVarCount++);
1386 this->write("bool ");
1387 this->write(tmpVar);
1388 this->writeLine(" = false;");
1389 this->writeLine("while (true) {");
1391 this->write("if (");
1392 this->write(tmpVar);
1393 this->writeLine(") {");
1395 this->write("if (!");
1396 this->writeExpression(*d.test(), Precedence::kPrefix);
1397 this->writeLine(") {");
1399 this->writeLine("break;");
1401 this->writeLine("}");
1403 this->writeLine("}");
1404 this->write(tmpVar);
1405 this->writeLine(" = true;");
1406 this->writeStatement(*d.statement());
1412 void GLSLCodeGenerator::writeExpressionStatement(const ExpressionStatement& s) {
1413 if (fProgram.fConfig->fSettings.fOptimize && !s.expression()->hasSideEffects()) {
1414 // Don't emit dead expressions.
1417 this->writeExpression(*s.expression(), Precedence::kTopLevel);
1421 void GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
1422 if (this->caps().rewriteSwitchStatements()) {
1423 std::string fallthroughVar = "_tmpSwitchFallthrough" + std::to_string(fVarCount++);
1424 std::string valueVar = "_tmpSwitchValue" + std::to_string(fVarCount++);
1425 std::string loopVar = "_tmpSwitchLoop" + std::to_string(fVarCount++);
1426 this->write("int ");
1427 this->write(valueVar);
1429 this->writeExpression(*s.value(), Precedence::kAssignment);
1431 this->write(fallthroughVar);
1432 this->writeLine(" = 0;");
1433 this->write("for (int ");
1434 this->write(loopVar);
1435 this->write(" = 0; ");
1436 this->write(loopVar);
1437 this->write(" < 1; ");
1438 this->write(loopVar);
1439 this->writeLine("++) {");
1442 bool firstCase = true;
1443 for (const std::unique_ptr<Statement>& stmt : s.cases()) {
1444 const SwitchCase& c = stmt->as<SwitchCase>();
1445 if (!c.isDefault()) {
1446 this->write("if ((");
1450 this->write(fallthroughVar);
1451 this->write(" > 0) || (");
1453 this->write(valueVar);
1454 this->write(" == ");
1455 this->write(std::to_string(c.value()));
1456 this->writeLine(")) {");
1459 // We write the entire case-block statement here, and then set `switchFallthrough`
1460 // to 1. If the case-block had a break statement in it, we break out of the outer
1461 // for-loop entirely, meaning the `switchFallthrough` assignment never occurs, nor
1462 // does any code after it inside the switch. We've forbidden `continue` statements
1463 // inside switch case-blocks entirely, so we don't need to consider their effect on
1464 // control flow; see the Finalizer in FunctionDefinition::Convert.
1465 this->writeStatement(*c.statement());
1467 this->write(fallthroughVar);
1468 this->write(" = 1;");
1472 this->writeLine("}");
1474 // This is the default case. Since it's always last, we can just dump in the code.
1475 this->writeStatement(*c.statement());
1481 this->writeLine("}");
1485 this->write("switch (");
1486 this->writeExpression(*s.value(), Precedence::kTopLevel);
1487 this->writeLine(") {");
1489 // If a switch contains only a `default` case and nothing else, this confuses some drivers and
1490 // can lead to a crash. Adding a real case before the default seems to work around the bug,
1491 // and doesn't change the meaning of the switch. (skia:12465)
1492 if (s.cases().size() == 1 && s.cases().front()->as<SwitchCase>().isDefault()) {
1493 this->writeLine("case 0:");
1495 for (const std::unique_ptr<Statement>& stmt : s.cases()) {
1496 const SwitchCase& c = stmt->as<SwitchCase>();
1497 if (c.isDefault()) {
1498 this->writeLine("default:");
1500 this->write("case ");
1501 this->write(std::to_string(c.value()));
1502 this->writeLine(":");
1504 if (!c.statement()->isEmpty()) {
1506 this->writeStatement(*c.statement());
1516 void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1517 this->write("return");
1518 if (r.expression()) {
1520 this->writeExpression(*r.expression(), Precedence::kTopLevel);
1525 void GLSLCodeGenerator::writeHeader() {
1526 if (this->caps().versionDeclString()) {
1527 this->write(this->caps().versionDeclString());
1532 void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
1534 case ProgramElement::Kind::kExtension:
1535 this->writeExtension(e.as<Extension>().name());
1537 case ProgramElement::Kind::kGlobalVar: {
1538 const VarDeclaration& decl =
1539 e.as<GlobalVarDeclaration>().declaration()->as<VarDeclaration>();
1540 int builtin = decl.var().modifiers().fLayout.fBuiltin;
1541 if (builtin == -1) {
1543 this->writeVarDeclaration(decl, true);
1545 } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
1546 this->caps().mustDeclareFragmentShaderOutput()) {
1547 if (fProgram.fConfig->fSettings.fFragColorIsInOut) {
1548 this->write("inout ");
1550 this->write("out ");
1552 if (usesPrecisionModifiers()) {
1553 this->write("mediump ");
1555 this->writeLine("vec4 sk_FragColor;");
1559 case ProgramElement::Kind::kInterfaceBlock:
1560 this->writeInterfaceBlock(e.as<InterfaceBlock>());
1562 case ProgramElement::Kind::kFunction:
1563 this->writeFunction(e.as<FunctionDefinition>());
1565 case ProgramElement::Kind::kFunctionPrototype:
1566 this->writeFunctionPrototype(e.as<FunctionPrototype>());
1568 case ProgramElement::Kind::kModifiers: {
1569 const Modifiers& modifiers = e.as<ModifiersDeclaration>().modifiers();
1570 this->writeModifiers(modifiers, true);
1571 this->writeLine(";");
1574 case ProgramElement::Kind::kStructDefinition:
1575 this->writeStructDefinition(e.as<StructDefinition>());
1578 SkDEBUGFAILF("unsupported program element %s\n", e.description().c_str());
1583 void GLSLCodeGenerator::writeInputVars() {
1584 if (fProgram.fInputs.fUseFlipRTUniform) {
1585 const char* precision = usesPrecisionModifiers() ? "highp " : "";
1586 fGlobals.writeText("uniform ");
1587 fGlobals.writeText(precision);
1588 fGlobals.writeText("vec2 " SKSL_RTFLIP_NAME ";\n");
1592 bool GLSLCodeGenerator::generateCode() {
1593 this->writeHeader();
1594 OutputStream* rawOut = fOut;
1597 // Write all the program elements except for functions.
1598 for (const ProgramElement* e : fProgram.elements()) {
1599 if (!e->is<FunctionDefinition>()) {
1600 this->writeProgramElement(*e);
1603 // Write the functions last.
1604 // Why don't we write things in their original order? Because the Inliner likes to move function
1605 // bodies around. After inlining, code can inadvertently move upwards, above ProgramElements
1606 // that the code relies on.
1607 for (const ProgramElement* e : fProgram.elements()) {
1608 if (e->is<FunctionDefinition>()) {
1609 this->writeProgramElement(*e);
1614 write_stringstream(fExtensions, *rawOut);
1615 this->writeInputVars();
1616 write_stringstream(fGlobals, *rawOut);
1618 if (!this->caps().canUseFragCoord()) {
1620 if (ProgramConfig::IsVertex(fProgram.fConfig->fKind)) {
1621 Modifiers modifiers(layout, Modifiers::kOut_Flag);
1622 this->writeModifiers(modifiers, true);
1623 if (this->usesPrecisionModifiers()) {
1624 this->write("highp ");
1626 this->write("vec4 sk_FragCoord_Workaround;\n");
1627 } else if (ProgramConfig::IsFragment(fProgram.fConfig->fKind)) {
1628 Modifiers modifiers(layout, Modifiers::kIn_Flag);
1629 this->writeModifiers(modifiers, true);
1630 if (this->usesPrecisionModifiers()) {
1631 this->write("highp ");
1633 this->write("vec4 sk_FragCoord_Workaround;\n");
1637 if (this->usesPrecisionModifiers()) {
1638 const char* precision =
1639 fProgram.fConfig->fSettings.fForceHighPrecision ? "highp" : "mediump";
1640 this->write(String::printf("precision %s float;\n", precision));
1641 this->write(String::printf("precision %s sampler2D;\n", precision));
1642 if (fFoundExternalSamplerDecl && !this->caps().noDefaultPrecisionForExternalSamplers()) {
1643 this->write(String::printf("precision %s samplerExternalOES;\n", precision));
1645 if (fFoundRectSamplerDecl) {
1646 this->write(String::printf("precision %s sampler2DRect;\n", precision));
1649 write_stringstream(fExtraFunctions, *rawOut);
1650 write_stringstream(body, *rawOut);
1651 return fContext.fErrors->errorCount() == 0;