Coverage Report

Created: 2021-08-22 09:07

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