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