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