blob: d4479db19bde58341b0d43619846ec552486690e [file] [log] [blame]
ethannicholasf789b382016-08-03 12:43:36 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Greg Daniel64773e62016-11-22 09:44:03 -05007
John Stiles3738ef52021-04-13 10:41:57 -04008#include "src/sksl/codegen/SkSLGLSLCodeGenerator.h"
ethannicholasf789b382016-08-03 12:43:36 -07009
John Stilesfbd050b2020-08-03 13:21:46 -040010#include <memory>
11
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "src/sksl/SkSLCompiler.h"
John Stilese3ae9682021-08-05 10:35:01 -040013#include "src/sksl/ir/SkSLConstructorArrayCast.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/sksl/ir/SkSLExpressionStatement.h"
15#include "src/sksl/ir/SkSLExtension.h"
16#include "src/sksl/ir/SkSLIndexExpression.h"
17#include "src/sksl/ir/SkSLModifiersDeclaration.h"
18#include "src/sksl/ir/SkSLNop.h"
John Stilesdc75a972020-11-25 16:24:55 -050019#include "src/sksl/ir/SkSLStructDefinition.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "src/sksl/ir/SkSLVariableReference.h"
ethannicholasf789b382016-08-03 12:43:36 -070021
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -040022#ifndef SKSL_STANDALONE
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "include/private/SkOnce.h"
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -040024#endif
25
ethannicholasf789b382016-08-03 12:43:36 -070026namespace SkSL {
27
Ethan Nicholas962dec42021-06-10 13:06:39 -040028void GLSLCodeGenerator::write(skstd::string_view s) {
Ethan Nicholasd2e09602021-06-10 11:21:59 -040029 if (!s.length()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -070030 return;
31 }
32 if (fAtLineStart) {
33 for (int i = 0; i < fIndentation; i++) {
34 fOut->writeText(" ");
35 }
36 }
Ethan Nicholasd2e09602021-06-10 11:21:59 -040037 fOut->write(s.data(), s.length());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -070038 fAtLineStart = false;
39}
40
Ethan Nicholas962dec42021-06-10 13:06:39 -040041void GLSLCodeGenerator::writeLine(skstd::string_view s) {
Ethan Nicholasd2e09602021-06-10 11:21:59 -040042 this->write(s);
John Stilese8b5a732021-03-12 13:25:52 -050043 fOut->writeText(fLineEnding);
44 fAtLineStart = true;
45}
46
47void GLSLCodeGenerator::finishLine() {
48 if (!fAtLineStart) {
49 this->writeLine();
50 }
ethannicholasf789b382016-08-03 12:43:36 -070051}
52
Ethan Nicholas962dec42021-06-10 13:06:39 -040053void GLSLCodeGenerator::writeExtension(skstd::string_view name, bool require) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -040054 fExtensions.writeText("#extension ");
Ethan Nicholasd2e09602021-06-10 11:21:59 -040055 fExtensions.write(name.data(), name.length());
Ethan Nicholas88f6d372018-07-27 10:03:46 -040056 fExtensions.writeText(require ? " : require\n" : " : enable\n");
ethannicholasf789b382016-08-03 12:43:36 -070057}
58
Ethan Nicholasf7b88202017-09-18 14:10:39 -040059bool GLSLCodeGenerator::usesPrecisionModifiers() const {
John Stilesc1a98b82021-02-24 13:35:02 -050060 return this->caps().usesPrecisionModifiers();
Ethan Nicholasf7b88202017-09-18 14:10:39 -040061}
62
Brian Osman8e756f32021-02-10 10:19:27 -050063// Returns the name of the type with array dimensions, e.g. `float[2]`.
Ethan Nicholasf7b88202017-09-18 14:10:39 -040064String GLSLCodeGenerator::getTypeName(const Type& type) {
Ethan Nicholase6592142020-09-08 10:22:09 -040065 switch (type.typeKind()) {
66 case Type::TypeKind::kVector: {
Ethan Nicholasc18bb512020-07-28 14:46:53 -040067 const Type& component = type.componentType();
Ethan Nicholasf7b88202017-09-18 14:10:39 -040068 String result;
John Stiles54e7c052021-01-11 14:22:36 -050069 if (component == *fContext.fTypes.fFloat || component == *fContext.fTypes.fHalf) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -040070 result = "vec";
71 }
Ethan Nicholase1f55022019-02-05 17:17:40 -050072 else if (component.isSigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -040073 result = "ivec";
74 }
Ethan Nicholase1f55022019-02-05 17:17:40 -050075 else if (component.isUnsigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -040076 result = "uvec";
77 }
John Stiles54e7c052021-01-11 14:22:36 -050078 else if (component == *fContext.fTypes.fBool) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -040079 result = "bvec";
80 }
81 else {
John Stilesf57207b2021-02-02 17:50:34 -050082 SK_ABORT("unsupported vector type");
Ethan Nicholasf7b88202017-09-18 14:10:39 -040083 }
84 result += to_string(type.columns());
85 return result;
86 }
Ethan Nicholase6592142020-09-08 10:22:09 -040087 case Type::TypeKind::kMatrix: {
Ethan Nicholasf7b88202017-09-18 14:10:39 -040088 String result;
Ethan Nicholasc18bb512020-07-28 14:46:53 -040089 const Type& component = type.componentType();
John Stiles54e7c052021-01-11 14:22:36 -050090 if (component == *fContext.fTypes.fFloat || component == *fContext.fTypes.fHalf) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -040091 result = "mat";
92 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -040093 else {
John Stilesf57207b2021-02-02 17:50:34 -050094 SK_ABORT("unsupported matrix type");
Ethan Nicholasf7b88202017-09-18 14:10:39 -040095 }
96 result += to_string(type.columns());
97 if (type.columns() != type.rows()) {
98 result += "x";
99 result += to_string(type.rows());
100 }
101 return result;
102 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400103 case Type::TypeKind::kArray: {
John Stilesbb43b7e2020-12-03 17:36:32 -0500104 String baseTypeName = this->getTypeName(type.componentType());
Brian Osmanb42c3832021-08-27 15:19:03 -0400105 return String::printf("%s[%d]", baseTypeName.c_str(), type.columns());
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400106 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400107 case Type::TypeKind::kScalar: {
John Stiles54e7c052021-01-11 14:22:36 -0500108 if (type == *fContext.fTypes.fHalf) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400109 return "float";
110 }
John Stiles54e7c052021-01-11 14:22:36 -0500111 else if (type == *fContext.fTypes.fShort) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400112 return "int";
113 }
John Stiles54e7c052021-01-11 14:22:36 -0500114 else if (type == *fContext.fTypes.fUShort) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400115 return "uint";
116 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400117 else {
Ethan Nicholasd2e09602021-06-10 11:21:59 -0400118 return String(type.name());
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400119 }
120 break;
121 }
122 default:
Ethan Nicholasd2e09602021-06-10 11:21:59 -0400123 return String(type.name());
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400124 }
125}
126
Brian Osman02bc5222021-01-28 11:00:20 -0500127void GLSLCodeGenerator::writeStructDefinition(const StructDefinition& s) {
128 const Type& type = s.type();
John Stilesdc75a972020-11-25 16:24:55 -0500129 this->write("struct ");
130 this->write(type.name());
131 this->writeLine(" {");
132 fIndentation++;
133 for (const auto& f : type.fields()) {
134 this->writeModifiers(f.fModifiers, false);
135 this->writeTypePrecision(*f.fType);
Brian Osman8e756f32021-02-10 10:19:27 -0500136 const Type& baseType = f.fType->isArray() ? f.fType->componentType() : *f.fType;
137 this->writeType(baseType);
John Stilesdc75a972020-11-25 16:24:55 -0500138 this->write(" ");
139 this->write(f.fName);
Brian Osman8e756f32021-02-10 10:19:27 -0500140 if (f.fType->isArray()) {
141 this->write("[" + to_string(f.fType->columns()) + "]");
142 }
John Stilesdc75a972020-11-25 16:24:55 -0500143 this->writeLine(";");
144 }
145 fIndentation--;
Brian Osman02bc5222021-01-28 11:00:20 -0500146 this->writeLine("};");
John Stilesdc75a972020-11-25 16:24:55 -0500147}
148
ethannicholasf789b382016-08-03 12:43:36 -0700149void GLSLCodeGenerator::writeType(const Type& type) {
Brian Osman02bc5222021-01-28 11:00:20 -0500150 this->write(this->getTypeName(type));
ethannicholasf789b382016-08-03 12:43:36 -0700151}
152
153void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400154 switch (expr.kind()) {
155 case Expression::Kind::kBinary:
John Stiles81365af2020-08-18 09:24:00 -0400156 this->writeBinaryExpression(expr.as<BinaryExpression>(), parentPrecedence);
ethannicholasf789b382016-08-03 12:43:36 -0700157 break;
John Stiles3c74a532021-05-18 17:31:48 -0400158 case Expression::Kind::kConstructorDiagonalMatrix:
159 this->writeConstructorDiagonalMatrix(expr.as<ConstructorDiagonalMatrix>(),
160 parentPrecedence);
161 break;
John Stilese3ae9682021-08-05 10:35:01 -0400162 case Expression::Kind::kConstructorArrayCast:
163 this->writeExpression(*expr.as<ConstructorArrayCast>().argument(), parentPrecedence);
164 break;
John Stiles7384b372021-04-01 13:48:15 -0400165 case Expression::Kind::kConstructorArray:
John Stiles8cad6372021-04-07 12:31:13 -0400166 case Expression::Kind::kConstructorCompound:
John Stiles5abb9e12021-04-06 13:47:19 -0400167 case Expression::Kind::kConstructorMatrixResize:
John Stiles2938eea2021-04-01 18:58:25 -0400168 case Expression::Kind::kConstructorSplat:
John Stilesd47330f2021-04-08 23:25:52 -0400169 case Expression::Kind::kConstructorStruct:
John Stiles7384b372021-04-01 13:48:15 -0400170 this->writeAnyConstructor(expr.asAnyConstructor(), parentPrecedence);
John Stilese1182782021-03-30 22:09:37 -0400171 break;
John Stilesb14a8192021-04-05 11:40:46 -0400172 case Expression::Kind::kConstructorScalarCast:
John Stiles8cad6372021-04-07 12:31:13 -0400173 case Expression::Kind::kConstructorCompoundCast:
John Stilesb14a8192021-04-05 11:40:46 -0400174 this->writeCastConstructor(expr.asAnyConstructor(), parentPrecedence);
175 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400176 case Expression::Kind::kFieldAccess:
John Stiles81365af2020-08-18 09:24:00 -0400177 this->writeFieldAccess(expr.as<FieldAccess>());
ethannicholasf789b382016-08-03 12:43:36 -0700178 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400179 case Expression::Kind::kFunctionCall:
John Stiles81365af2020-08-18 09:24:00 -0400180 this->writeFunctionCall(expr.as<FunctionCall>());
ethannicholasf789b382016-08-03 12:43:36 -0700181 break;
John Stiles7591d4b2021-09-13 13:32:06 -0400182 case Expression::Kind::kLiteral:
183 this->writeLiteral(expr.as<Literal>());
184 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400185 case Expression::Kind::kPrefix:
John Stiles81365af2020-08-18 09:24:00 -0400186 this->writePrefixExpression(expr.as<PrefixExpression>(), parentPrecedence);
ethannicholasf789b382016-08-03 12:43:36 -0700187 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400188 case Expression::Kind::kPostfix:
John Stiles81365af2020-08-18 09:24:00 -0400189 this->writePostfixExpression(expr.as<PostfixExpression>(), parentPrecedence);
ethannicholasf789b382016-08-03 12:43:36 -0700190 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400191 case Expression::Kind::kSetting:
John Stiles81365af2020-08-18 09:24:00 -0400192 this->writeSetting(expr.as<Setting>());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400193 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400194 case Expression::Kind::kSwizzle:
John Stiles81365af2020-08-18 09:24:00 -0400195 this->writeSwizzle(expr.as<Swizzle>());
ethannicholasf789b382016-08-03 12:43:36 -0700196 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400197 case Expression::Kind::kVariableReference:
John Stiles81365af2020-08-18 09:24:00 -0400198 this->writeVariableReference(expr.as<VariableReference>());
ethannicholasf789b382016-08-03 12:43:36 -0700199 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400200 case Expression::Kind::kTernary:
John Stiles81365af2020-08-18 09:24:00 -0400201 this->writeTernaryExpression(expr.as<TernaryExpression>(), parentPrecedence);
ethannicholasf789b382016-08-03 12:43:36 -0700202 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400203 case Expression::Kind::kIndex:
John Stiles81365af2020-08-18 09:24:00 -0400204 this->writeIndexExpression(expr.as<IndexExpression>());
ethannicholasf789b382016-08-03 12:43:36 -0700205 break;
206 default:
John Stileseada7bc2021-02-02 16:29:32 -0500207 SkDEBUGFAILF("unsupported expression: %s", expr.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500208 break;
ethannicholasf789b382016-08-03 12:43:36 -0700209 }
210}
211
ethannicholas5961bc92016-10-12 06:39:56 -0700212static bool is_abs(Expression& expr) {
John Stilesa5569ac2021-05-18 17:06:33 -0400213 return expr.is<FunctionCall>() &&
214 expr.as<FunctionCall>().function().intrinsicKind() == k_abs_IntrinsicKind;
ethannicholas5961bc92016-10-12 06:39:56 -0700215}
216
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500217// turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a
ethannicholas5961bc92016-10-12 06:39:56 -0700218// Tegra3 compiler bug.
219void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
John Stilesc1a98b82021-02-24 13:35:02 -0500220 SkASSERT(!this->caps().canUseMinAndAbsTogether());
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400221 String tmpVar1 = "minAbsHackVar" + to_string(fVarCount++);
222 String tmpVar2 = "minAbsHackVar" + to_string(fVarCount++);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400223 this->fFunctionHeader += String(" ") + this->getTypePrecision(absExpr.type()) +
224 this->getTypeName(absExpr.type()) + " " + tmpVar1 + ";\n";
225 this->fFunctionHeader += String(" ") + this->getTypePrecision(otherExpr.type()) +
226 this->getTypeName(otherExpr.type()) + " " + tmpVar2 + ";\n";
ethannicholas5961bc92016-10-12 06:39:56 -0700227 this->write("((" + tmpVar1 + " = ");
Brian Osman00185012021-02-04 16:07:11 -0500228 this->writeExpression(absExpr, Precedence::kTopLevel);
ethannicholas5961bc92016-10-12 06:39:56 -0700229 this->write(") < (" + tmpVar2 + " = ");
Brian Osman00185012021-02-04 16:07:11 -0500230 this->writeExpression(otherExpr, Precedence::kAssignment);
ethannicholas5961bc92016-10-12 06:39:56 -0700231 this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")");
232}
233
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500234void GLSLCodeGenerator::writeInverseSqrtHack(const Expression& x) {
235 this->write("(1.0 / sqrt(");
Brian Osman00185012021-02-04 16:07:11 -0500236 this->writeExpression(x, Precedence::kTopLevel);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500237 this->write("))");
238}
239
240void GLSLCodeGenerator::writeDeterminantHack(const Expression& mat) {
241 String name;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400242 const Type& type = mat.type();
John Stiles54e7c052021-01-11 14:22:36 -0500243 if (type == *fContext.fTypes.fFloat2x2 || type == *fContext.fTypes.fHalf2x2) {
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500244 name = "_determinant2";
245 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
246 fWrittenIntrinsics.insert(name);
247 fExtraFunctions.writeText((
248 "float " + name + "(mat2 m) {"
249 " return m[0][0] * m[1][1] - m[0][1] * m[1][0];"
250 "}"
251 ).c_str());
252 }
253 }
John Stiles54e7c052021-01-11 14:22:36 -0500254 else if (type == *fContext.fTypes.fFloat3x3 || type == *fContext.fTypes.fHalf3x3) {
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500255 name = "_determinant3";
256 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
257 fWrittenIntrinsics.insert(name);
258 fExtraFunctions.writeText((
259 "float " + name + "(mat3 m) {"
260 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
261 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
262 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
263 " float b01 = a22 * a11 - a12 * a21;"
264 " float b11 = -a22 * a10 + a12 * a20;"
265 " float b21 = a21 * a10 - a11 * a20;"
266 " return a00 * b01 + a01 * b11 + a02 * b21;"
267 "}"
268 ).c_str());
269 }
270 }
John Stiles54e7c052021-01-11 14:22:36 -0500271 else if (type == *fContext.fTypes.fFloat4x4 || type == *fContext.fTypes.fHalf4x4) {
John Stiles6f3015a2020-10-08 14:55:36 -0400272 name = "_determinant4";
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500273 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
274 fWrittenIntrinsics.insert(name);
275 fExtraFunctions.writeText((
276 "mat4 " + name + "(mat4 m) {"
277 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
278 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
279 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
280 " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
281 " float b00 = a00 * a11 - a01 * a10;"
282 " float b01 = a00 * a12 - a02 * a10;"
283 " float b02 = a00 * a13 - a03 * a10;"
284 " float b03 = a01 * a12 - a02 * a11;"
285 " float b04 = a01 * a13 - a03 * a11;"
286 " float b05 = a02 * a13 - a03 * a12;"
287 " float b06 = a20 * a31 - a21 * a30;"
288 " float b07 = a20 * a32 - a22 * a30;"
289 " float b08 = a20 * a33 - a23 * a30;"
290 " float b09 = a21 * a32 - a22 * a31;"
291 " float b10 = a21 * a33 - a23 * a31;"
292 " float b11 = a22 * a33 - a23 * a32;"
293 " return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;"
294 "}"
295 ).c_str());
296 }
297 }
298 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400299 SkASSERT(false);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500300 }
301 this->write(name + "(");
Brian Osman00185012021-02-04 16:07:11 -0500302 this->writeExpression(mat, Precedence::kTopLevel);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500303 this->write(")");
304}
305
306void GLSLCodeGenerator::writeInverseHack(const Expression& mat) {
307 String name;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400308 const Type& type = mat.type();
John Stiles54e7c052021-01-11 14:22:36 -0500309 if (type == *fContext.fTypes.fFloat2x2 || type == *fContext.fTypes.fHalf2x2) {
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500310 name = "_inverse2";
311 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
312 fWrittenIntrinsics.insert(name);
313 fExtraFunctions.writeText((
314 "mat2 " + name + "(mat2 m) {"
315 " return mat2(m[1][1], -m[0][1], -m[1][0], m[0][0]) / "
316 "(m[0][0] * m[1][1] - m[0][1] * m[1][0]);"
317 "}"
318 ).c_str());
319 }
320 }
John Stiles54e7c052021-01-11 14:22:36 -0500321 else if (type == *fContext.fTypes.fFloat3x3 || type == *fContext.fTypes.fHalf3x3) {
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500322 name = "_inverse3";
323 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
324 fWrittenIntrinsics.insert(name);
325 fExtraFunctions.writeText((
326 "mat3 " + name + "(mat3 m) {"
327 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
328 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
329 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
330 " float b01 = a22 * a11 - a12 * a21;"
331 " float b11 = -a22 * a10 + a12 * a20;"
332 " float b21 = a21 * a10 - a11 * a20;"
333 " float det = a00 * b01 + a01 * b11 + a02 * b21;"
334 " return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),"
335 " b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),"
336 " b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;"
337 "}"
338 ).c_str());
339 }
340 }
John Stiles54e7c052021-01-11 14:22:36 -0500341 else if (type == *fContext.fTypes.fFloat4x4 || type == *fContext.fTypes.fHalf4x4) {
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500342 name = "_inverse4";
343 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
344 fWrittenIntrinsics.insert(name);
345 fExtraFunctions.writeText((
346 "mat4 " + name + "(mat4 m) {"
347 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
348 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
349 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
350 " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
351 " float b00 = a00 * a11 - a01 * a10;"
352 " float b01 = a00 * a12 - a02 * a10;"
353 " float b02 = a00 * a13 - a03 * a10;"
354 " float b03 = a01 * a12 - a02 * a11;"
355 " float b04 = a01 * a13 - a03 * a11;"
356 " float b05 = a02 * a13 - a03 * a12;"
357 " float b06 = a20 * a31 - a21 * a30;"
358 " float b07 = a20 * a32 - a22 * a30;"
359 " float b08 = a20 * a33 - a23 * a30;"
360 " float b09 = a21 * a32 - a22 * a31;"
361 " float b10 = a21 * a33 - a23 * a31;"
362 " float b11 = a22 * a33 - a23 * a32;"
363 " float det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - "
364 " b04 * b07 + b05 * b06;"
365 " return mat4("
366 " a11 * b11 - a12 * b10 + a13 * b09,"
367 " a02 * b10 - a01 * b11 - a03 * b09,"
368 " a31 * b05 - a32 * b04 + a33 * b03,"
369 " a22 * b04 - a21 * b05 - a23 * b03,"
370 " a12 * b08 - a10 * b11 - a13 * b07,"
371 " a00 * b11 - a02 * b08 + a03 * b07,"
372 " a32 * b02 - a30 * b05 - a33 * b01,"
373 " a20 * b05 - a22 * b02 + a23 * b01,"
374 " a10 * b10 - a11 * b08 + a13 * b06,"
375 " a01 * b08 - a00 * b10 - a03 * b06,"
376 " a30 * b04 - a31 * b02 + a33 * b00,"
377 " a21 * b02 - a20 * b04 - a23 * b00,"
378 " a11 * b07 - a10 * b09 - a12 * b06,"
379 " a00 * b09 - a01 * b07 + a02 * b06,"
380 " a31 * b01 - a30 * b03 - a32 * b00,"
381 " a20 * b03 - a21 * b01 + a22 * b00) / det;"
382 "}"
383 ).c_str());
384 }
385 }
386 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400387 SkASSERT(false);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500388 }
389 this->write(name + "(");
Brian Osman00185012021-02-04 16:07:11 -0500390 this->writeExpression(mat, Precedence::kTopLevel);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500391 this->write(")");
392}
393
394void GLSLCodeGenerator::writeTransposeHack(const Expression& mat) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400395 const Type& type = mat.type();
396 String name = "transpose" + to_string(type.columns()) + to_string(type.rows());
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500397 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
398 fWrittenIntrinsics.insert(name);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400399 String typeName = this->getTypeName(type);
400 const Type& base = type.componentType();
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500401 String transposed = this->getTypeName(base.toCompound(fContext,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400402 type.rows(),
403 type.columns()));
404 fExtraFunctions.writeText((transposed + " " + name + "(" + typeName + " m) {\nreturn " +
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500405 transposed + "(").c_str());
406 const char* separator = "";
Ethan Nicholas30d30222020-09-11 12:27:26 -0400407 for (int row = 0; row < type.rows(); ++row) {
408 for (int column = 0; column < type.columns(); ++column) {
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500409 fExtraFunctions.writeText(separator);
410 fExtraFunctions.writeText(("m[" + to_string(column) + "][" + to_string(row) +
411 "]").c_str());
412 separator = ", ";
413 }
414 }
415 fExtraFunctions.writeText("); }");
416 }
417 this->write(name + "(");
Brian Osman00185012021-02-04 16:07:11 -0500418 this->writeExpression(mat, Precedence::kTopLevel);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500419 this->write(")");
420}
421
ethannicholasf789b382016-08-03 12:43:36 -0700422void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400423 const FunctionDeclaration& function = c.function();
John Stiles8e3b6be2020-10-13 11:14:08 -0400424 const ExpressionArray& arguments = c.arguments();
Brian Osman8a83ca42018-02-12 14:32:17 -0500425 bool isTextureFunctionWithBias = false;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400426 bool nameWritten = false;
John Stilesf96cb712021-05-05 22:17:04 -0400427 switch (c.function().intrinsicKind()) {
428 case k_abs_IntrinsicKind: {
429 if (!this->caps().emulateAbsIntFunction())
430 break;
431 SkASSERT(arguments.size() == 1);
432 if (arguments[0]->type() != *fContext.fTypes.fInt) {
Adrienne Walker92b161f2018-08-22 10:41:52 -0700433 break;
434 }
John Stilesf96cb712021-05-05 22:17:04 -0400435 // abs(int) on Intel OSX is incorrect, so emulate it:
436 String name = "_absemulation";
437 this->write(name);
438 nameWritten = true;
439 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
440 fWrittenIntrinsics.insert(name);
441 fExtraFunctions.writeText((
442 "int " + name + "(int x) {\n"
443 " return x * sign(x);\n"
444 "}\n"
445 ).c_str());
446 }
447 break;
448 }
449 case k_atan_IntrinsicKind:
450 if (this->caps().mustForceNegatedAtanParamToFloat() &&
451 arguments.size() == 2 &&
452 arguments[1]->kind() == Expression::Kind::kPrefix) {
453 const PrefixExpression& p = (PrefixExpression&) *arguments[1];
454 if (p.getOperator().kind() == Token::Kind::TK_MINUS) {
455 this->write("atan(");
Brian Osman00185012021-02-04 16:07:11 -0500456 this->writeExpression(*arguments[0], Precedence::kSequence);
John Stilesf96cb712021-05-05 22:17:04 -0400457 this->write(", -1.0 * ");
458 this->writeExpression(*p.operand(), Precedence::kMultiplicative);
459 this->write(")");
Chris Daltona7086182018-11-16 09:33:43 -0500460 return;
461 }
John Stilesf96cb712021-05-05 22:17:04 -0400462 }
463 break;
Chris Dalton155c33c2021-06-07 18:51:42 -0600464 case k_ldexp_IntrinsicKind:
465 if (this->caps().mustForceNegatedLdexpParamToMultiply() &&
466 arguments.size() == 2 &&
467 arguments[1]->is<PrefixExpression>()) {
468 const PrefixExpression& p = arguments[1]->as<PrefixExpression>();
469 if (p.getOperator().kind() == Token::Kind::TK_MINUS) {
470 this->write("ldexp(");
471 this->writeExpression(*arguments[0], Precedence::kSequence);
472 this->write(", ");
473 this->writeExpression(*p.operand(), Precedence::kMultiplicative);
474 this->write(" * -1)");
475 return;
476 }
477 }
478 break;
John Stilesf96cb712021-05-05 22:17:04 -0400479 case k_dFdy_IntrinsicKind:
Brian Salomond8d85b92021-07-07 09:41:17 -0400480 // Flipping Y also negates the Y derivatives.
481 this->write(SKSL_RTFLIP_NAME ".y * dFdy");
482 nameWritten = true;
John Stilesf96cb712021-05-05 22:17:04 -0400483 [[fallthrough]];
484 case k_dFdx_IntrinsicKind:
485 case k_fwidth_IntrinsicKind:
486 if (!fFoundDerivatives &&
487 this->caps().shaderDerivativeExtensionString()) {
488 this->writeExtension(this->caps().shaderDerivativeExtensionString());
489 fFoundDerivatives = true;
490 }
491 break;
492 case k_determinant_IntrinsicKind:
493 if (!this->caps().builtinDeterminantSupport()) {
494 SkASSERT(arguments.size() == 1);
495 this->writeDeterminantHack(*arguments[0]);
496 return;
497 }
498 break;
499 case k_fma_IntrinsicKind:
500 if (!this->caps().builtinFMASupport()) {
501 SkASSERT(arguments.size() == 3);
502 this->write("((");
Brian Osman00185012021-02-04 16:07:11 -0500503 this->writeExpression(*arguments[0], Precedence::kSequence);
John Stilesf96cb712021-05-05 22:17:04 -0400504 this->write(") * (");
505 this->writeExpression(*arguments[1], Precedence::kSequence);
506 this->write(") + (");
507 this->writeExpression(*arguments[2], Precedence::kSequence);
Adrienne Walker2f4c09b2018-08-22 16:04:57 -0700508 this->write("))");
509 return;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400510 }
John Stilesf96cb712021-05-05 22:17:04 -0400511 break;
512 case k_fract_IntrinsicKind:
513 if (!this->caps().canUseFractForNegativeValues()) {
514 SkASSERT(arguments.size() == 1);
515 this->write("(0.5 - sign(");
516 this->writeExpression(*arguments[0], Precedence::kSequence);
517 this->write(") * (0.5 - fract(abs(");
518 this->writeExpression(*arguments[0], Precedence::kSequence);
519 this->write("))))");
520 return;
521 }
522 break;
523 case k_inverse_IntrinsicKind:
524 if (this->caps().generation() < k140_GrGLSLGeneration) {
525 SkASSERT(arguments.size() == 1);
526 this->writeInverseHack(*arguments[0]);
527 return;
528 }
529 break;
530 case k_inversesqrt_IntrinsicKind:
531 if (this->caps().generation() < k130_GrGLSLGeneration) {
532 SkASSERT(arguments.size() == 1);
533 this->writeInverseSqrtHack(*arguments[0]);
534 return;
535 }
536 break;
537 case k_min_IntrinsicKind:
538 if (!this->caps().canUseMinAndAbsTogether()) {
539 SkASSERT(arguments.size() == 2);
540 if (is_abs(*arguments[0])) {
541 this->writeMinAbsHack(*arguments[0], *arguments[1]);
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400542 return;
543 }
John Stilesf96cb712021-05-05 22:17:04 -0400544 if (is_abs(*arguments[1])) {
545 // note that this violates the GLSL left-to-right evaluation semantics.
546 // I doubt it will ever end up mattering, but it's worth calling out.
547 this->writeMinAbsHack(*arguments[1], *arguments[0]);
548 return;
549 }
550 }
551 break;
552 case k_pow_IntrinsicKind:
553 if (!this->caps().removePowWithConstantExponent()) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500554 break;
John Stilesf96cb712021-05-05 22:17:04 -0400555 }
556 // pow(x, y) on some NVIDIA drivers causes crashes if y is a
557 // constant. It's hard to tell what constitutes "constant" here
558 // so just replace in all cases.
559
560 // Change pow(x, y) into exp2(y * log2(x))
561 this->write("exp2(");
562 this->writeExpression(*arguments[1], Precedence::kMultiplicative);
563 this->write(" * log2(");
564 this->writeExpression(*arguments[0], Precedence::kSequence);
565 this->write("))");
566 return;
567 case k_saturate_IntrinsicKind:
568 SkASSERT(arguments.size() == 1);
569 this->write("clamp(");
570 this->writeExpression(*arguments[0], Precedence::kSequence);
571 this->write(", 0.0, 1.0)");
572 return;
573 case k_sample_IntrinsicKind: {
574 const char* dim = "";
575 bool proj = false;
576 const Type& arg0Type = arguments[0]->type();
577 const Type& arg1Type = arguments[1]->type();
578 switch (arg0Type.dimensions()) {
579 case SpvDim1D:
580 dim = "1D";
581 isTextureFunctionWithBias = true;
582 if (arg1Type == *fContext.fTypes.fFloat) {
583 proj = false;
584 } else {
585 SkASSERT(arg1Type == *fContext.fTypes.fFloat2);
586 proj = true;
587 }
588 break;
589 case SpvDim2D:
590 dim = "2D";
591 if (arg0Type != *fContext.fTypes.fSamplerExternalOES) {
592 isTextureFunctionWithBias = true;
593 }
594 if (arg1Type == *fContext.fTypes.fFloat2) {
595 proj = false;
596 } else {
597 SkASSERT(arg1Type == *fContext.fTypes.fFloat3);
598 proj = true;
599 }
600 break;
601 case SpvDim3D:
602 dim = "3D";
603 isTextureFunctionWithBias = true;
604 if (arg1Type == *fContext.fTypes.fFloat3) {
605 proj = false;
606 } else {
607 SkASSERT(arg1Type == *fContext.fTypes.fFloat4);
608 proj = true;
609 }
610 break;
611 case SpvDimCube:
612 dim = "Cube";
613 isTextureFunctionWithBias = true;
614 proj = false;
615 break;
616 case SpvDimRect:
617 dim = "2DRect";
618 proj = false;
619 break;
620 case SpvDimBuffer:
621 SkASSERT(false); // doesn't exist
622 dim = "Buffer";
623 proj = false;
624 break;
625 case SpvDimSubpassData:
626 SkASSERT(false); // doesn't exist
627 dim = "SubpassData";
628 proj = false;
629 break;
630 }
631 if (!fTextureFunctionOverride.empty()) {
632 this->write(fTextureFunctionOverride.c_str());
633 } else {
634 this->write("texture");
635 if (this->caps().generation() < k130_GrGLSLGeneration) {
636 this->write(dim);
637 }
638 if (proj) {
639 this->write("Proj");
640 }
641 }
642 nameWritten = true;
643 break;
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500644 }
John Stilesf96cb712021-05-05 22:17:04 -0400645 case k_transpose_IntrinsicKind:
646 if (this->caps().generation() < k130_GrGLSLGeneration) {
647 SkASSERT(arguments.size() == 1);
648 this->writeTransposeHack(*arguments[0]);
649 return;
650 }
651 break;
652 default:
653 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400654 }
John Stilesf96cb712021-05-05 22:17:04 -0400655
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400656 if (!nameWritten) {
John Stilesece1d792021-03-22 11:43:11 -0400657 this->write(function.mangledName());
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500658 }
659 this->write("(");
ethannicholasf789b382016-08-03 12:43:36 -0700660 const char* separator = "";
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400661 for (const auto& arg : arguments) {
ethannicholasf789b382016-08-03 12:43:36 -0700662 this->write(separator);
663 separator = ", ";
Brian Osman00185012021-02-04 16:07:11 -0500664 this->writeExpression(*arg, Precedence::kSequence);
ethannicholasf789b382016-08-03 12:43:36 -0700665 }
John Stiles270cec22021-02-17 12:59:36 -0500666 if (fProgram.fConfig->fSettings.fSharpenTextures && isTextureFunctionWithBias) {
Brian Osman8a83ca42018-02-12 14:32:17 -0500667 this->write(", -0.5");
668 }
ethannicholasf789b382016-08-03 12:43:36 -0700669 this->write(")");
670}
671
John Stiles3c74a532021-05-18 17:31:48 -0400672void GLSLCodeGenerator::writeConstructorDiagonalMatrix(const ConstructorDiagonalMatrix& c,
673 Precedence parentPrecedence) {
674 if (c.type().columns() == 4 && c.type().rows() == 2) {
675 // Due to a longstanding bug in glslang and Mesa, several GPU drivers generate diagonal 4x2
676 // matrices incorrectly. (skia:12003, https://github.com/KhronosGroup/glslang/pull/2646)
677 // We can work around this issue by multiplying a scalar by the identity matrix.
678 // In practice, this doesn't come up naturally in real code and we don't know every affected
679 // driver, so we just apply this workaround everywhere.
680 this->write("(");
681 this->writeType(c.type());
682 this->write("(1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0) * ");
683 this->writeExpression(*c.argument(), Precedence::kMultiplicative);
684 this->write(")");
685 return;
686 }
687 this->writeAnyConstructor(c, parentPrecedence);
688}
689
John Stilesb14a8192021-04-05 11:40:46 -0400690void GLSLCodeGenerator::writeCastConstructor(const AnyConstructor& c, Precedence parentPrecedence) {
John Stilesfd7252f2021-04-04 22:24:40 -0400691 const auto arguments = c.argumentSpan();
John Stilesb14a8192021-04-05 11:40:46 -0400692 SkASSERT(arguments.size() == 1);
693
694 const Expression& argument = *arguments.front();
695 if ((this->getTypeName(c.type()) == this->getTypeName(argument.type()) ||
696 (argument.type() == *fContext.fTypes.fFloatLiteral))) {
John Stilesfd7252f2021-04-04 22:24:40 -0400697 // In cases like half(float), they're different types as far as SkSL is concerned but
698 // the same type as far as GLSL is concerned. We avoid a redundant float(float) by just
699 // writing out the inner expression here.
John Stilesb14a8192021-04-05 11:40:46 -0400700 this->writeExpression(argument, parentPrecedence);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400701 return;
702 }
John Stilesb14a8192021-04-05 11:40:46 -0400703
John Stilesfd7252f2021-04-04 22:24:40 -0400704 // This cast should be emitted as-is.
John Stilesd8eb8752021-04-01 11:49:10 -0400705 return this->writeAnyConstructor(c, parentPrecedence);
John Stiles626b62e2021-03-31 22:06:07 -0400706}
707
John Stilesd8eb8752021-04-01 11:49:10 -0400708void GLSLCodeGenerator::writeAnyConstructor(const AnyConstructor& c, Precedence parentPrecedence) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400709 this->writeType(c.type());
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400710 this->write("(");
ethannicholasf789b382016-08-03 12:43:36 -0700711 const char* separator = "";
John Stilesd8eb8752021-04-01 11:49:10 -0400712 for (const auto& arg : c.argumentSpan()) {
ethannicholasf789b382016-08-03 12:43:36 -0700713 this->write(separator);
714 separator = ", ";
Brian Osman00185012021-02-04 16:07:11 -0500715 this->writeExpression(*arg, Precedence::kSequence);
ethannicholasf789b382016-08-03 12:43:36 -0700716 }
717 this->write(")");
718}
719
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500720void GLSLCodeGenerator::writeFragCoord() {
John Stilesc1a98b82021-02-24 13:35:02 -0500721 if (!this->caps().canUseFragCoord()) {
Brian Salomondba65f92018-01-22 08:43:38 -0500722 if (!fSetupFragCoordWorkaround) {
723 const char* precision = usesPrecisionModifiers() ? "highp " : "";
724 fFunctionHeader += precision;
725 fFunctionHeader += " float sk_FragCoord_InvW = 1. / sk_FragCoord_Workaround.w;\n";
726 fFunctionHeader += precision;
727 fFunctionHeader += " vec4 sk_FragCoord_Resolved = "
728 "vec4(sk_FragCoord_Workaround.xyz * sk_FragCoord_InvW, sk_FragCoord_InvW);\n";
729 // Ensure that we get exact .5 values for x and y.
730 fFunctionHeader += " sk_FragCoord_Resolved.xy = floor(sk_FragCoord_Resolved.xy) + "
731 "vec2(.5);\n";
732 fSetupFragCoordWorkaround = true;
733 }
734 this->write("sk_FragCoord_Resolved");
Brian Osmancd3261a2018-01-16 13:52:29 +0000735 return;
736 }
737
Brian Salomond8d85b92021-07-07 09:41:17 -0400738 if (!fSetupFragPosition) {
739 fFunctionHeader += usesPrecisionModifiers() ? "highp " : "";
740 fFunctionHeader += " vec4 sk_FragCoord = vec4("
741 "gl_FragCoord.x, "
742 SKSL_RTFLIP_NAME ".x + " SKSL_RTFLIP_NAME ".y * gl_FragCoord.y, "
743 "gl_FragCoord.z, "
744 "gl_FragCoord.w);\n";
745 fSetupFragPosition = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500746 }
Brian Salomond8d85b92021-07-07 09:41:17 -0400747 this->write("sk_FragCoord");
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500748}
749
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500750void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
Ethan Nicholas78686922020-10-08 06:46:27 -0400751 switch (ref.variable()->modifiers().fLayout.fBuiltin) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500752 case SK_FRAGCOLOR_BUILTIN:
John Stilesc1a98b82021-02-24 13:35:02 -0500753 if (this->caps().mustDeclareFragmentShaderOutput()) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500754 this->write("sk_FragColor");
755 } else {
756 this->write("gl_FragColor");
757 }
758 break;
759 case SK_FRAGCOORD_BUILTIN:
760 this->writeFragCoord();
761 break;
Chris Dalton49d14e92018-07-27 12:38:35 -0600762 case SK_CLOCKWISE_BUILTIN:
Brian Salomond8d85b92021-07-07 09:41:17 -0400763 if (!fSetupClockwise) {
764 fFunctionHeader +=
765 " bool sk_Clockwise = gl_FrontFacing;\n"
766 " if (" SKSL_RTFLIP_NAME ".y < 0.0) {\n"
767 " sk_Clockwise = !sk_Clockwise;\n"
768 " }\n";
769 fSetupClockwise = true;
770 }
771 this->write("sk_Clockwise");
Chris Dalton49d14e92018-07-27 12:38:35 -0600772 break;
Ethan Nicholasa51740c2017-02-07 14:53:32 -0500773 case SK_VERTEXID_BUILTIN:
774 this->write("gl_VertexID");
775 break;
Chris Dalton8580d512017-10-14 22:12:33 -0600776 case SK_INSTANCEID_BUILTIN:
777 this->write("gl_InstanceID");
778 break;
Ethan Nicholaseab2baa2018-04-13 15:16:27 -0400779 case SK_LASTFRAGCOLOR_BUILTIN:
Brian Osmana81e7e22021-09-15 10:28:27 -0400780 if (this->caps().fbFetchSupport()) {
781 this->write(this->caps().fbFetchColorName());
782 } else {
783 fContext.fErrors->error(ref.fOffset,
784 "sk_LastFragColor requires framebuffer fetch support");
785 }
Ethan Nicholaseab2baa2018-04-13 15:16:27 -0400786 break;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500787 default:
Ethan Nicholas78686922020-10-08 06:46:27 -0400788 this->write(ref.variable()->name());
Ethan Nicholasb13f3692021-09-10 16:49:42 -0400789 break;
ethannicholas5961bc92016-10-12 06:39:56 -0700790 }
ethannicholasf789b382016-08-03 12:43:36 -0700791}
792
793void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
Brian Osman00185012021-02-04 16:07:11 -0500794 this->writeExpression(*expr.base(), Precedence::kPostfix);
ethannicholasf789b382016-08-03 12:43:36 -0700795 this->write("[");
Brian Osman00185012021-02-04 16:07:11 -0500796 this->writeExpression(*expr.index(), Precedence::kTopLevel);
ethannicholasf789b382016-08-03 12:43:36 -0700797 this->write("]");
798}
799
Brian Osmancd3261a2018-01-16 13:52:29 +0000800bool is_sk_position(const FieldAccess& f) {
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400801 return "sk_Position" == f.base()->type().fields()[f.fieldIndex()].fName;
Brian Osmancd3261a2018-01-16 13:52:29 +0000802}
803
ethannicholasf789b382016-08-03 12:43:36 -0700804void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400805 if (f.ownerKind() == FieldAccess::OwnerKind::kDefault) {
Brian Osman00185012021-02-04 16:07:11 -0500806 this->writeExpression(*f.base(), Precedence::kPostfix);
ethannicholasf789b382016-08-03 12:43:36 -0700807 this->write(".");
808 }
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400809 const Type& baseType = f.base()->type();
Ethan Nicholas962dec42021-06-10 13:06:39 -0400810 skstd::string_view name = baseType.fields()[f.fieldIndex()].fName;
John Stilesba385882020-09-25 14:49:37 -0400811 if (name == "sk_Position") {
812 this->write("gl_Position");
813 } else if (name == "sk_PointSize") {
814 this->write("gl_PointSize");
815 } else {
Ethan Nicholas7a95b202020-10-09 11:55:40 -0400816 this->write(baseType.fields()[f.fieldIndex()].fName);
Ethan Nicholas67d64602017-02-09 10:15:25 -0500817 }
ethannicholasf789b382016-08-03 12:43:36 -0700818}
819
Brian Osman25647672020-09-15 15:16:56 -0400820void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
Brian Osman00185012021-02-04 16:07:11 -0500821 this->writeExpression(*swizzle.base(), Precedence::kPostfix);
ethannicholasf789b382016-08-03 12:43:36 -0700822 this->write(".");
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400823 for (int c : swizzle.components()) {
Brian Osman25647672020-09-15 15:16:56 -0400824 SkASSERT(c >= 0 && c <= 3);
825 this->write(&("x\0y\0z\0w\0"[c * 2]));
ethannicholasf789b382016-08-03 12:43:36 -0700826 }
827}
828
John Stilesf061c592021-05-21 23:34:42 -0400829void GLSLCodeGenerator::writeMatrixComparisonWorkaround(const BinaryExpression& b) {
830 const Expression& left = *b.left();
831 const Expression& right = *b.right();
832 Operator op = b.getOperator();
833
834 SkASSERT(op.kind() == Token::Kind::TK_EQEQ || op.kind() == Token::Kind::TK_NEQ);
835 SkASSERT(left.type().isMatrix());
836 SkASSERT(right.type().isMatrix());
837
838 String tempMatrix1 = "_tempMatrix" + to_string(fVarCount++);
839 String tempMatrix2 = "_tempMatrix" + to_string(fVarCount++);
840
841 this->fFunctionHeader += String(" ") + this->getTypePrecision(left.type()) +
842 this->getTypeName(left.type()) + " " + tempMatrix1 + ";\n " +
843 this->getTypePrecision(right.type()) +
844 this->getTypeName(right.type()) + " " + tempMatrix2 + ";\n";
845 this->write("((" + tempMatrix1 + " = ");
846 this->writeExpression(left, Precedence::kAssignment);
847 this->write("), (" + tempMatrix2 + " = ");
848 this->writeExpression(right, Precedence::kAssignment);
849 this->write("), (" + tempMatrix1 + " ");
850 this->write(op.operatorName());
851 this->write(" " + tempMatrix2 + "))");
852}
853
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400854void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
ethannicholasf789b382016-08-03 12:43:36 -0700855 Precedence parentPrecedence) {
John Stiles2d4f9592020-10-30 10:29:12 -0400856 const Expression& left = *b.left();
857 const Expression& right = *b.right();
John Stiles45990502021-02-16 10:55:27 -0500858 Operator op = b.getOperator();
John Stilesc1a98b82021-02-24 13:35:02 -0500859 if (this->caps().unfoldShortCircuitAsTernary() &&
John Stiles45990502021-02-16 10:55:27 -0500860 (op.kind() == Token::Kind::TK_LOGICALAND || op.kind() == Token::Kind::TK_LOGICALOR)) {
Adrienne Walkerc02165f2018-08-21 11:08:11 -0700861 this->writeShortCircuitWorkaroundExpression(b, parentPrecedence);
862 return;
863 }
864
John Stilesf061c592021-05-21 23:34:42 -0400865 if (this->caps().rewriteMatrixComparisons() &&
866 left.type().isMatrix() && right.type().isMatrix() &&
867 (op.kind() == Token::Kind::TK_EQEQ || op.kind() == Token::Kind::TK_NEQ)) {
868 this->writeMatrixComparisonWorkaround(b);
869 return;
870 }
871
John Stiles45990502021-02-16 10:55:27 -0500872 Precedence precedence = op.getBinaryPrecedence();
ethannicholasf789b382016-08-03 12:43:36 -0700873 if (precedence >= parentPrecedence) {
874 this->write("(");
875 }
John Stiles270cec22021-02-17 12:59:36 -0500876 bool positionWorkaround = fProgram.fConfig->fKind == ProgramKind::kVertex &&
John Stiles45990502021-02-16 10:55:27 -0500877 op.isAssignment() &&
878 left.is<FieldAccess>() &&
879 is_sk_position(left.as<FieldAccess>()) &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400880 !right.containsRTAdjust() &&
John Stilesc1a98b82021-02-24 13:35:02 -0500881 !this->caps().canUseFragCoord();
Brian Osmancd3261a2018-01-16 13:52:29 +0000882 if (positionWorkaround) {
883 this->write("sk_FragCoord_Workaround = (");
884 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400885 this->writeExpression(left, precedence);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700886 this->write(" ");
John Stiles45990502021-02-16 10:55:27 -0500887 this->write(op.operatorName());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700888 this->write(" ");
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400889 this->writeExpression(right, precedence);
Brian Osmancd3261a2018-01-16 13:52:29 +0000890 if (positionWorkaround) {
891 this->write(")");
892 }
ethannicholasf789b382016-08-03 12:43:36 -0700893 if (precedence >= parentPrecedence) {
894 this->write(")");
895 }
896}
897
Adrienne Walkerc02165f2018-08-21 11:08:11 -0700898void GLSLCodeGenerator::writeShortCircuitWorkaroundExpression(const BinaryExpression& b,
899 Precedence parentPrecedence) {
Brian Osman00185012021-02-04 16:07:11 -0500900 if (Precedence::kTernary >= parentPrecedence) {
Adrienne Walkerc02165f2018-08-21 11:08:11 -0700901 this->write("(");
902 }
903
904 // Transform:
905 // a && b => a ? b : false
906 // a || b => a ? true : b
Brian Osman00185012021-02-04 16:07:11 -0500907 this->writeExpression(*b.left(), Precedence::kTernary);
Adrienne Walkerc02165f2018-08-21 11:08:11 -0700908 this->write(" ? ");
John Stiles45990502021-02-16 10:55:27 -0500909 if (b.getOperator().kind() == Token::Kind::TK_LOGICALAND) {
Brian Osman00185012021-02-04 16:07:11 -0500910 this->writeExpression(*b.right(), Precedence::kTernary);
Adrienne Walkerc02165f2018-08-21 11:08:11 -0700911 } else {
John Stiles7591d4b2021-09-13 13:32:06 -0400912 Literal boolTrue(/*offset=*/-1, /*value=*/1, fContext.fTypes.fBool.get());
913 this->writeLiteral(boolTrue);
Adrienne Walkerc02165f2018-08-21 11:08:11 -0700914 }
915 this->write(" : ");
John Stiles45990502021-02-16 10:55:27 -0500916 if (b.getOperator().kind() == Token::Kind::TK_LOGICALAND) {
John Stiles7591d4b2021-09-13 13:32:06 -0400917 Literal boolFalse(/*offset=*/-1, /*value=*/0, fContext.fTypes.fBool.get());
918 this->writeLiteral(boolFalse);
Adrienne Walkerc02165f2018-08-21 11:08:11 -0700919 } else {
Brian Osman00185012021-02-04 16:07:11 -0500920 this->writeExpression(*b.right(), Precedence::kTernary);
Adrienne Walkerc02165f2018-08-21 11:08:11 -0700921 }
Brian Osman00185012021-02-04 16:07:11 -0500922 if (Precedence::kTernary >= parentPrecedence) {
Adrienne Walkerc02165f2018-08-21 11:08:11 -0700923 this->write(")");
924 }
925}
926
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400927void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
ethannicholasf789b382016-08-03 12:43:36 -0700928 Precedence parentPrecedence) {
Brian Osman00185012021-02-04 16:07:11 -0500929 if (Precedence::kTernary >= parentPrecedence) {
ethannicholasf789b382016-08-03 12:43:36 -0700930 this->write("(");
931 }
Brian Osman00185012021-02-04 16:07:11 -0500932 this->writeExpression(*t.test(), Precedence::kTernary);
ethannicholasf789b382016-08-03 12:43:36 -0700933 this->write(" ? ");
Brian Osman00185012021-02-04 16:07:11 -0500934 this->writeExpression(*t.ifTrue(), Precedence::kTernary);
ethannicholasf789b382016-08-03 12:43:36 -0700935 this->write(" : ");
Brian Osman00185012021-02-04 16:07:11 -0500936 this->writeExpression(*t.ifFalse(), Precedence::kTernary);
937 if (Precedence::kTernary >= parentPrecedence) {
ethannicholasf789b382016-08-03 12:43:36 -0700938 this->write(")");
939 }
940}
941
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400942void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
ethannicholasf789b382016-08-03 12:43:36 -0700943 Precedence parentPrecedence) {
Brian Osman00185012021-02-04 16:07:11 -0500944 if (Precedence::kPrefix >= parentPrecedence) {
ethannicholasf789b382016-08-03 12:43:36 -0700945 this->write("(");
946 }
John Stiles45990502021-02-16 10:55:27 -0500947 this->write(p.getOperator().operatorName());
Brian Osman00185012021-02-04 16:07:11 -0500948 this->writeExpression(*p.operand(), Precedence::kPrefix);
949 if (Precedence::kPrefix >= parentPrecedence) {
ethannicholasf789b382016-08-03 12:43:36 -0700950 this->write(")");
951 }
952}
953
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400954void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
ethannicholasf789b382016-08-03 12:43:36 -0700955 Precedence parentPrecedence) {
Brian Osman00185012021-02-04 16:07:11 -0500956 if (Precedence::kPostfix >= parentPrecedence) {
ethannicholasf789b382016-08-03 12:43:36 -0700957 this->write("(");
958 }
Brian Osman00185012021-02-04 16:07:11 -0500959 this->writeExpression(*p.operand(), Precedence::kPostfix);
John Stiles45990502021-02-16 10:55:27 -0500960 this->write(p.getOperator().operatorName());
Brian Osman00185012021-02-04 16:07:11 -0500961 if (Precedence::kPostfix >= parentPrecedence) {
ethannicholasf789b382016-08-03 12:43:36 -0700962 this->write(")");
963 }
964}
965
John Stiles7591d4b2021-09-13 13:32:06 -0400966void GLSLCodeGenerator::writeLiteral(const Literal& l) {
967 const Type& type = l.type();
968 if (type.isFloat()) {
969 this->write(to_string(l.floatValue()));
970 return;
ethannicholas5961bc92016-10-12 06:39:56 -0700971 }
John Stiles7591d4b2021-09-13 13:32:06 -0400972 if (type.isInteger()) {
973 if (type == *fContext.fTypes.fUInt) {
974 this->write(to_string(l.intValue() & 0xffffffff) + "u");
975 } else if (type == *fContext.fTypes.fUShort) {
976 this->write(to_string(l.intValue() & 0xffff) + "u");
977 } else {
978 this->write(to_string(l.intValue()));
979 }
980 return;
981 }
982 SkASSERT(type.isBoolean());
983 this->write(l.boolValue() ? "true" : "false");
ethannicholasf789b382016-08-03 12:43:36 -0700984}
985
Ethan Nicholas762466e2017-06-29 10:03:38 -0400986void GLSLCodeGenerator::writeSetting(const Setting& s) {
John Stilesf57207b2021-02-02 17:50:34 -0500987 SK_ABORT("internal error; setting was not folded to a constant during compilation\n");
Ethan Nicholas762466e2017-06-29 10:03:38 -0400988}
989
John Stiles569249b2020-11-03 12:18:22 -0500990void GLSLCodeGenerator::writeFunctionDeclaration(const FunctionDeclaration& f) {
991 this->writeTypePrecision(f.returnType());
992 this->writeType(f.returnType());
John Stilesece1d792021-03-22 11:43:11 -0400993 this->write(" " + f.mangledName() + "(");
John Stilesfffe3842020-09-02 15:44:18 -0400994 const char* separator = "";
John Stiles569249b2020-11-03 12:18:22 -0500995 for (const auto& param : f.parameters()) {
Brian Osman716aeb92021-04-21 13:20:00 -0400996 // This is a workaround for our test files. They use the runtime effect signature, so main
997 // takes a coords parameter. The IR generator tags those with a builtin ID (sk_FragCoord),
998 // and we omit them from the declaration here, so the function is valid GLSL.
999 if (f.isMain() && param->modifiers().fLayout.fBuiltin != -1) {
1000 continue;
1001 }
John Stilesfffe3842020-09-02 15:44:18 -04001002 this->write(separator);
1003 separator = ", ";
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001004 this->writeModifiers(param->modifiers(), false);
John Stilesfffe3842020-09-02 15:44:18 -04001005 std::vector<int> sizes;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001006 const Type* type = &param->type();
John Stilesbb43b7e2020-12-03 17:36:32 -05001007 if (type->isArray()) {
John Stilesfffe3842020-09-02 15:44:18 -04001008 sizes.push_back(type->columns());
1009 type = &type->componentType();
1010 }
1011 this->writeTypePrecision(*type);
1012 this->writeType(*type);
Ethan Nicholase2c49992020-10-05 11:49:11 -04001013 this->write(" " + param->name());
John Stilesfffe3842020-09-02 15:44:18 -04001014 for (int s : sizes) {
Brian Osmanb42c3832021-08-27 15:19:03 -04001015 this->write("[" + to_string(s) + "]");
ethannicholas5961bc92016-10-12 06:39:56 -07001016 }
ethannicholasf789b382016-08-03 12:43:36 -07001017 }
John Stiles569249b2020-11-03 12:18:22 -05001018 this->write(")");
1019}
1020
1021void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
Brian Salomond8d85b92021-07-07 09:41:17 -04001022 fSetupFragPosition = false;
John Stiles569249b2020-11-03 12:18:22 -05001023 fSetupFragCoordWorkaround = false;
1024
John Stiles569249b2020-11-03 12:18:22 -05001025 this->writeFunctionDeclaration(f.declaration());
1026 this->writeLine(" {");
John Stilesfffe3842020-09-02 15:44:18 -04001027 fIndentation++;
1028
John Stiles95680232021-04-22 15:05:20 -04001029 fFunctionHeader.clear();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001030 OutputStream* oldOut = fOut;
1031 StringStream buffer;
ethannicholas5961bc92016-10-12 06:39:56 -07001032 fOut = &buffer;
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001033 for (const std::unique_ptr<Statement>& stmt : f.body()->as<Block>().children()) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001034 if (!stmt->isEmpty()) {
1035 this->writeStatement(*stmt);
John Stilese8b5a732021-03-12 13:25:52 -05001036 this->finishLine();
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001037 }
1038 }
John Stilesfffe3842020-09-02 15:44:18 -04001039
1040 fIndentation--;
1041 this->writeLine("}");
ethannicholas5961bc92016-10-12 06:39:56 -07001042
1043 fOut = oldOut;
1044 this->write(fFunctionHeader);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001045 this->write(buffer.str());
ethannicholasf789b382016-08-03 12:43:36 -07001046}
1047
John Stiles569249b2020-11-03 12:18:22 -05001048void GLSLCodeGenerator::writeFunctionPrototype(const FunctionPrototype& f) {
1049 this->writeFunctionDeclaration(f.declaration());
1050 this->writeLine(";");
1051}
1052
Greg Daniel64773e62016-11-22 09:44:03 -05001053void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
ethannicholas5961bc92016-10-12 06:39:56 -07001054 bool globalContext) {
Brian Salomonf9f45122016-11-29 11:59:17 -05001055 if (modifiers.fFlags & Modifiers::kFlat_Flag) {
1056 this->write("flat ");
1057 }
ethannicholas5961bc92016-10-12 06:39:56 -07001058 if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
1059 this->write("noperspective ");
1060 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001061 String layout = modifiers.fLayout.description();
Ethan Nicholas8da9e942017-03-09 16:35:09 -05001062 if (layout.size()) {
1063 this->write(layout + " ");
1064 }
Greg Daniel64773e62016-11-22 09:44:03 -05001065 if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
ethannicholas5961bc92016-10-12 06:39:56 -07001066 (modifiers.fFlags & Modifiers::kOut_Flag)) {
1067 this->write("inout ");
1068 } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001069 if (globalContext &&
John Stilesc1a98b82021-02-24 13:35:02 -05001070 this->caps().generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
John Stiles270cec22021-02-17 12:59:36 -05001071 this->write(fProgram.fConfig->fKind == ProgramKind::kVertex ? "attribute "
1072 : "varying ");
ethannicholas5961bc92016-10-12 06:39:56 -07001073 } else {
1074 this->write("in ");
1075 }
1076 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001077 if (globalContext &&
John Stilesc1a98b82021-02-24 13:35:02 -05001078 this->caps().generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
ethannicholas5961bc92016-10-12 06:39:56 -07001079 this->write("varying ");
1080 } else {
1081 this->write("out ");
1082 }
1083 }
1084 if (modifiers.fFlags & Modifiers::kUniform_Flag) {
1085 this->write("uniform ");
1086 }
1087 if (modifiers.fFlags & Modifiers::kConst_Flag) {
1088 this->write("const ");
1089 }
ethannicholasf789b382016-08-03 12:43:36 -07001090}
1091
1092void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
Ethan Nicholaseaf47882020-10-15 10:10:08 -04001093 if (intf.typeName() == "sk_PerVertex") {
ethannicholasf789b382016-08-03 12:43:36 -07001094 return;
1095 }
Ethan Nicholaseaf47882020-10-15 10:10:08 -04001096 this->writeModifiers(intf.variable().modifiers(), true);
1097 this->writeLine(intf.typeName() + " {");
ethannicholasf789b382016-08-03 12:43:36 -07001098 fIndentation++;
Ethan Nicholaseaf47882020-10-15 10:10:08 -04001099 const Type* structType = &intf.variable().type();
John Stilesbb43b7e2020-12-03 17:36:32 -05001100 if (structType->isArray()) {
Ethan Nicholas50afc172017-02-16 14:49:57 -05001101 structType = &structType->componentType();
1102 }
1103 for (const auto& f : structType->fields()) {
ethannicholas5961bc92016-10-12 06:39:56 -07001104 this->writeModifiers(f.fModifiers, false);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001105 this->writeTypePrecision(*f.fType);
ethannicholas0730be72016-09-01 07:59:02 -07001106 this->writeType(*f.fType);
ethannicholasf789b382016-08-03 12:43:36 -07001107 this->writeLine(" " + f.fName + ";");
1108 }
1109 fIndentation--;
Ethan Nicholas50afc172017-02-16 14:49:57 -05001110 this->write("}");
Ethan Nicholaseaf47882020-10-15 10:10:08 -04001111 if (intf.instanceName().size()) {
Ethan Nicholas50afc172017-02-16 14:49:57 -05001112 this->write(" ");
Ethan Nicholaseaf47882020-10-15 10:10:08 -04001113 this->write(intf.instanceName());
John Stilesd39aec02020-12-03 10:42:26 -05001114 if (intf.arraySize() > 0) {
Ethan Nicholas50afc172017-02-16 14:49:57 -05001115 this->write("[");
John Stilesd39aec02020-12-03 10:42:26 -05001116 this->write(to_string(intf.arraySize()));
Ethan Nicholas50afc172017-02-16 14:49:57 -05001117 this->write("]");
1118 }
1119 }
1120 this->writeLine(";");
ethannicholasf789b382016-08-03 12:43:36 -07001121}
1122
Ethan Nicholas762466e2017-06-29 10:03:38 -04001123void GLSLCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
Brian Osman00185012021-02-04 16:07:11 -05001124 this->writeExpression(value, Precedence::kTopLevel);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001125}
1126
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001127const char* GLSLCodeGenerator::getTypePrecision(const Type& type) {
1128 if (usesPrecisionModifiers()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001129 switch (type.typeKind()) {
1130 case Type::TypeKind::kScalar:
Ethan Nicholas722c83e2021-05-04 11:39:30 -04001131 if (type == *fContext.fTypes.fShort || type == *fContext.fTypes.fUShort) {
John Stiles270cec22021-02-17 12:59:36 -05001132 if (fProgram.fConfig->fSettings.fForceHighPrecision ||
John Stilesc1a98b82021-02-24 13:35:02 -05001133 this->caps().incompleteShortIntPrecision()) {
Chris Daltonc2d0dd62018-03-07 07:46:10 -07001134 return "highp ";
1135 }
1136 return "mediump ";
1137 }
John Stiles54e7c052021-01-11 14:22:36 -05001138 if (type == *fContext.fTypes.fHalf) {
John Stiles270cec22021-02-17 12:59:36 -05001139 return fProgram.fConfig->fSettings.fForceHighPrecision ? "highp " : "mediump ";
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001140 }
John Stiles54e7c052021-01-11 14:22:36 -05001141 if (type == *fContext.fTypes.fFloat || type == *fContext.fTypes.fInt ||
1142 type == *fContext.fTypes.fUInt) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001143 return "highp ";
1144 }
1145 return "";
Ethan Nicholase6592142020-09-08 10:22:09 -04001146 case Type::TypeKind::kVector: // fall through
1147 case Type::TypeKind::kMatrix:
Brian Osman8e756f32021-02-10 10:19:27 -05001148 case Type::TypeKind::kArray:
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001149 return this->getTypePrecision(type.componentType());
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001150 default:
1151 break;
1152 }
1153 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001154 return "";
1155}
1156
1157void GLSLCodeGenerator::writeTypePrecision(const Type& type) {
1158 this->write(this->getTypePrecision(type));
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001159}
1160
Brian Osmanc0213602020-10-06 14:43:32 -04001161void GLSLCodeGenerator::writeVarDeclaration(const VarDeclaration& var, bool global) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001162 this->writeModifiers(var.var().modifiers(), global);
1163 this->writeTypePrecision(var.baseType());
1164 this->writeType(var.baseType());
Brian Osmanc0213602020-10-06 14:43:32 -04001165 this->write(" ");
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001166 this->write(var.var().name());
John Stiles62a56462020-12-03 10:41:58 -05001167 if (var.arraySize() > 0) {
Brian Osmanc0213602020-10-06 14:43:32 -04001168 this->write("[");
John Stiles62a56462020-12-03 10:41:58 -05001169 this->write(to_string(var.arraySize()));
Brian Osmanc0213602020-10-06 14:43:32 -04001170 this->write("]");
Ethan Nicholas14efcbf2017-11-07 09:23:38 -05001171 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001172 if (var.value()) {
Brian Osmanc0213602020-10-06 14:43:32 -04001173 this->write(" = ");
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001174 this->writeVarInitializer(var.var(), *var.value());
ethannicholasf789b382016-08-03 12:43:36 -07001175 }
John Stiles54e7c052021-01-11 14:22:36 -05001176 if (!fFoundExternalSamplerDecl && var.var().type() == *fContext.fTypes.fSamplerExternalOES) {
John Stilesc1a98b82021-02-24 13:35:02 -05001177 if (this->caps().externalTextureExtensionString()) {
1178 this->writeExtension(this->caps().externalTextureExtensionString());
Brian Osmanc0213602020-10-06 14:43:32 -04001179 }
John Stilesc1a98b82021-02-24 13:35:02 -05001180 if (this->caps().secondExternalTextureExtensionString()) {
1181 this->writeExtension(this->caps().secondExternalTextureExtensionString());
Brian Osmanc0213602020-10-06 14:43:32 -04001182 }
1183 fFoundExternalSamplerDecl = true;
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001184 }
John Stiles54e7c052021-01-11 14:22:36 -05001185 if (!fFoundRectSamplerDecl && var.var().type() == *fContext.fTypes.fSampler2DRect) {
Brian Osmanc0213602020-10-06 14:43:32 -04001186 fFoundRectSamplerDecl = true;
1187 }
1188 this->write(";");
ethannicholasf789b382016-08-03 12:43:36 -07001189}
1190
1191void GLSLCodeGenerator::writeStatement(const Statement& s) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001192 switch (s.kind()) {
1193 case Statement::Kind::kBlock:
John Stiles3dc0da62020-08-19 17:48:31 -04001194 this->writeBlock(s.as<Block>());
ethannicholasf789b382016-08-03 12:43:36 -07001195 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001196 case Statement::Kind::kExpression:
Brian Osman00185012021-02-04 16:07:11 -05001197 this->writeExpression(*s.as<ExpressionStatement>().expression(), Precedence::kTopLevel);
ethannicholasf789b382016-08-03 12:43:36 -07001198 this->write(";");
1199 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001200 case Statement::Kind::kReturn:
John Stiles26f98502020-08-18 09:30:51 -04001201 this->writeReturnStatement(s.as<ReturnStatement>());
ethannicholasf789b382016-08-03 12:43:36 -07001202 break;
Brian Osmanc0213602020-10-06 14:43:32 -04001203 case Statement::Kind::kVarDeclaration:
1204 this->writeVarDeclaration(s.as<VarDeclaration>(), false);
ethannicholasf789b382016-08-03 12:43:36 -07001205 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001206 case Statement::Kind::kIf:
John Stiles26f98502020-08-18 09:30:51 -04001207 this->writeIfStatement(s.as<IfStatement>());
ethannicholasf789b382016-08-03 12:43:36 -07001208 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001209 case Statement::Kind::kFor:
John Stiles26f98502020-08-18 09:30:51 -04001210 this->writeForStatement(s.as<ForStatement>());
ethannicholasf789b382016-08-03 12:43:36 -07001211 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001212 case Statement::Kind::kDo:
John Stiles26f98502020-08-18 09:30:51 -04001213 this->writeDoStatement(s.as<DoStatement>());
ethannicholasf789b382016-08-03 12:43:36 -07001214 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001215 case Statement::Kind::kSwitch:
John Stiles26f98502020-08-18 09:30:51 -04001216 this->writeSwitchStatement(s.as<SwitchStatement>());
Ethan Nicholasaf197692017-02-27 13:26:45 -05001217 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001218 case Statement::Kind::kBreak:
ethannicholasf789b382016-08-03 12:43:36 -07001219 this->write("break;");
1220 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001221 case Statement::Kind::kContinue:
ethannicholasf789b382016-08-03 12:43:36 -07001222 this->write("continue;");
1223 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001224 case Statement::Kind::kDiscard:
ethannicholasf789b382016-08-03 12:43:36 -07001225 this->write("discard;");
1226 break;
John Stiles98c1f822020-09-09 14:18:53 -04001227 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -04001228 case Statement::Kind::kNop:
Ethan Nicholascb670962017-04-20 19:31:52 -04001229 this->write(";");
1230 break;
ethannicholasf789b382016-08-03 12:43:36 -07001231 default:
John Stileseada7bc2021-02-02 16:29:32 -05001232 SkDEBUGFAILF("unsupported statement: %s", s.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001233 break;
ethannicholasf789b382016-08-03 12:43:36 -07001234 }
1235}
1236
1237void GLSLCodeGenerator::writeBlock(const Block& b) {
John Stiles3744bd62021-01-26 13:49:43 -05001238 // Write scope markers if this block is a scope, or if the block is empty (since we need to emit
1239 // something here to make the code valid).
1240 bool isScope = b.isScope() || b.isEmpty();
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001241 if (isScope) {
Ethan Nicholas70728ef2020-05-28 07:09:00 -04001242 this->writeLine("{");
1243 fIndentation++;
1244 }
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001245 for (const std::unique_ptr<Statement>& stmt : b.children()) {
1246 if (!stmt->isEmpty()) {
1247 this->writeStatement(*stmt);
John Stilese8b5a732021-03-12 13:25:52 -05001248 this->finishLine();
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001249 }
1250 }
1251 if (isScope) {
Ethan Nicholas70728ef2020-05-28 07:09:00 -04001252 fIndentation--;
1253 this->write("}");
1254 }
ethannicholasf789b382016-08-03 12:43:36 -07001255}
1256
1257void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
1258 this->write("if (");
Brian Osman00185012021-02-04 16:07:11 -05001259 this->writeExpression(*stmt.test(), Precedence::kTopLevel);
ethannicholasf789b382016-08-03 12:43:36 -07001260 this->write(") ");
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001261 this->writeStatement(*stmt.ifTrue());
1262 if (stmt.ifFalse()) {
ethannicholasf789b382016-08-03 12:43:36 -07001263 this->write(" else ");
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001264 this->writeStatement(*stmt.ifFalse());
ethannicholasf789b382016-08-03 12:43:36 -07001265 }
1266}
1267
1268void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
Brian Osmand6f23382020-12-15 17:08:59 -05001269 // Emit loops of the form 'for(;test;)' as 'while(test)', which is probably how they started
1270 if (!f.initializer() && f.test() && !f.next()) {
1271 this->write("while (");
Brian Osman00185012021-02-04 16:07:11 -05001272 this->writeExpression(*f.test(), Precedence::kTopLevel);
Brian Osmand6f23382020-12-15 17:08:59 -05001273 this->write(") ");
1274 this->writeStatement(*f.statement());
1275 return;
1276 }
1277
John Stilesb1992c22021-04-19 14:57:04 -04001278 this->write("for (");
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04001279 if (f.initializer() && !f.initializer()->isEmpty()) {
John Stilesb1992c22021-04-19 14:57:04 -04001280 this->writeStatement(*f.initializer());
ethannicholasf789b382016-08-03 12:43:36 -07001281 } else {
John Stilesb1992c22021-04-19 14:57:04 -04001282 this->write("; ");
ethannicholasf789b382016-08-03 12:43:36 -07001283 }
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04001284 if (f.test()) {
John Stilesc1a98b82021-02-24 13:35:02 -05001285 if (this->caps().addAndTrueToLoopCondition()) {
Adrienne Walkeree8295c2018-08-21 10:56:30 -07001286 std::unique_ptr<Expression> and_true(new BinaryExpression(
John Stiles45990502021-02-16 10:55:27 -05001287 /*offset=*/-1, f.test()->clone(), Token::Kind::TK_LOGICALAND,
John Stiles7591d4b2021-09-13 13:32:06 -04001288 Literal::MakeBool(fContext, /*offset=*/-1, /*value=*/true),
John Stiles54e7c052021-01-11 14:22:36 -05001289 fContext.fTypes.fBool.get()));
Brian Osman00185012021-02-04 16:07:11 -05001290 this->writeExpression(*and_true, Precedence::kTopLevel);
Adrienne Walkeree8295c2018-08-21 10:56:30 -07001291 } else {
Brian Osman00185012021-02-04 16:07:11 -05001292 this->writeExpression(*f.test(), Precedence::kTopLevel);
Adrienne Walkeree8295c2018-08-21 10:56:30 -07001293 }
ethannicholasf789b382016-08-03 12:43:36 -07001294 }
1295 this->write("; ");
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04001296 if (f.next()) {
Brian Osman00185012021-02-04 16:07:11 -05001297 this->writeExpression(*f.next(), Precedence::kTopLevel);
ethannicholasf789b382016-08-03 12:43:36 -07001298 }
1299 this->write(") ");
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04001300 this->writeStatement(*f.statement());
ethannicholasf789b382016-08-03 12:43:36 -07001301}
1302
ethannicholasf789b382016-08-03 12:43:36 -07001303void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
John Stilesc1a98b82021-02-24 13:35:02 -05001304 if (!this->caps().rewriteDoWhileLoops()) {
Adrienne Walker8b23ca62018-08-22 10:45:41 -07001305 this->write("do ");
Ethan Nicholas1fd61162020-09-28 13:14:19 -04001306 this->writeStatement(*d.statement());
Adrienne Walker8b23ca62018-08-22 10:45:41 -07001307 this->write(" while (");
Brian Osman00185012021-02-04 16:07:11 -05001308 this->writeExpression(*d.test(), Precedence::kTopLevel);
Adrienne Walker8b23ca62018-08-22 10:45:41 -07001309 this->write(");");
1310 return;
1311 }
1312
1313 // Otherwise, do the do while loop workaround, to rewrite loops of the form:
1314 // do {
1315 // CODE;
1316 // } while (CONDITION)
1317 //
1318 // to loops of the form
1319 // bool temp = false;
1320 // while (true) {
1321 // if (temp) {
1322 // if (!CONDITION) {
1323 // break;
1324 // }
1325 // }
1326 // temp = true;
1327 // CODE;
1328 // }
1329 String tmpVar = "_tmpLoopSeenOnce" + to_string(fVarCount++);
1330 this->write("bool ");
1331 this->write(tmpVar);
1332 this->writeLine(" = false;");
1333 this->writeLine("while (true) {");
1334 fIndentation++;
1335 this->write("if (");
1336 this->write(tmpVar);
1337 this->writeLine(") {");
1338 fIndentation++;
1339 this->write("if (!");
Brian Osman00185012021-02-04 16:07:11 -05001340 this->writeExpression(*d.test(), Precedence::kPrefix);
Adrienne Walker8b23ca62018-08-22 10:45:41 -07001341 this->writeLine(") {");
1342 fIndentation++;
1343 this->writeLine("break;");
1344 fIndentation--;
1345 this->writeLine("}");
1346 fIndentation--;
1347 this->writeLine("}");
1348 this->write(tmpVar);
1349 this->writeLine(" = true;");
Ethan Nicholas1fd61162020-09-28 13:14:19 -04001350 this->writeStatement(*d.statement());
John Stilese8b5a732021-03-12 13:25:52 -05001351 this->finishLine();
Adrienne Walker8b23ca62018-08-22 10:45:41 -07001352 fIndentation--;
1353 this->write("}");
ethannicholasf789b382016-08-03 12:43:36 -07001354}
1355
Ethan Nicholasaf197692017-02-27 13:26:45 -05001356void GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
John Stilescb400082021-09-23 11:07:32 -04001357 if (fProgram.fConfig->strictES2Mode()) {
1358 // TODO(skia:12450): write switch compatibility code
1359 fContext.fErrors->error(s.fOffset, "switch statements are not supported");
1360 }
1361
Ethan Nicholasaf197692017-02-27 13:26:45 -05001362 this->write("switch (");
Brian Osman00185012021-02-04 16:07:11 -05001363 this->writeExpression(*s.value(), Precedence::kTopLevel);
Ethan Nicholasaf197692017-02-27 13:26:45 -05001364 this->writeLine(") {");
1365 fIndentation++;
John Stilesb8f16512021-09-21 09:24:09 -04001366 // If a switch contains only a `default` case and nothing else, this confuses some drivers and
1367 // can lead to a crash. Adding a real case before the default seems to work around the bug,
John Stiles408f38e2021-09-21 11:20:11 -04001368 // and doesn't change the meaning of the switch. (skia:12465)
John Stilesb8f16512021-09-21 09:24:09 -04001369 if (s.cases().size() == 1 && !s.cases().front()->as<SwitchCase>().value()) {
1370 this->writeLine("case 0:");
1371 }
John Stilesb23a64b2021-03-11 08:27:59 -05001372 for (const std::unique_ptr<Statement>& stmt : s.cases()) {
1373 const SwitchCase& c = stmt->as<SwitchCase>();
1374 if (c.value()) {
Ethan Nicholasaf197692017-02-27 13:26:45 -05001375 this->write("case ");
John Stilesb23a64b2021-03-11 08:27:59 -05001376 this->writeExpression(*c.value(), Precedence::kTopLevel);
Ethan Nicholasaf197692017-02-27 13:26:45 -05001377 this->writeLine(":");
1378 } else {
1379 this->writeLine("default:");
1380 }
John Stilesb23a64b2021-03-11 08:27:59 -05001381 if (!c.statement()->isEmpty()) {
John Stilesc3ce43b2021-03-09 15:37:01 -05001382 fIndentation++;
John Stilesb23a64b2021-03-11 08:27:59 -05001383 this->writeStatement(*c.statement());
John Stilese8b5a732021-03-12 13:25:52 -05001384 this->finishLine();
John Stilesc3ce43b2021-03-09 15:37:01 -05001385 fIndentation--;
Ethan Nicholasaf197692017-02-27 13:26:45 -05001386 }
Ethan Nicholasaf197692017-02-27 13:26:45 -05001387 }
1388 fIndentation--;
John Stilesbf16b6c2021-03-12 19:24:31 -05001389 this->finishLine();
Ethan Nicholasaf197692017-02-27 13:26:45 -05001390 this->write("}");
1391}
1392
ethannicholasf789b382016-08-03 12:43:36 -07001393void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1394 this->write("return");
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001395 if (r.expression()) {
ethannicholasf789b382016-08-03 12:43:36 -07001396 this->write(" ");
Brian Osman00185012021-02-04 16:07:11 -05001397 this->writeExpression(*r.expression(), Precedence::kTopLevel);
ethannicholasf789b382016-08-03 12:43:36 -07001398 }
1399 this->write(";");
1400}
1401
Ethan Nicholas762466e2017-06-29 10:03:38 -04001402void GLSLCodeGenerator::writeHeader() {
John Stilesc1a98b82021-02-24 13:35:02 -05001403 if (this->caps().versionDeclString()) {
1404 this->write(this->caps().versionDeclString());
John Stilese8b5a732021-03-12 13:25:52 -05001405 this->finishLine();
Ethan Nicholasba9a04f2020-11-06 09:28:04 -05001406 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001407}
1408
Ethan Nicholas762466e2017-06-29 10:03:38 -04001409void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001410 switch (e.kind()) {
1411 case ProgramElement::Kind::kExtension:
Ethan Nicholasefb09e22020-09-30 10:17:00 -04001412 this->writeExtension(e.as<Extension>().name());
Ethan Nicholas762466e2017-06-29 10:03:38 -04001413 break;
Brian Osmanc0213602020-10-06 14:43:32 -04001414 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001415 const VarDeclaration& decl =
1416 e.as<GlobalVarDeclaration>().declaration()->as<VarDeclaration>();
1417 int builtin = decl.var().modifiers().fLayout.fBuiltin;
Brian Osmanc0213602020-10-06 14:43:32 -04001418 if (builtin == -1) {
1419 // normal var
1420 this->writeVarDeclaration(decl, true);
John Stilese8b5a732021-03-12 13:25:52 -05001421 this->finishLine();
Brian Osmanc0213602020-10-06 14:43:32 -04001422 } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
John Stilesc1a98b82021-02-24 13:35:02 -05001423 this->caps().mustDeclareFragmentShaderOutput()) {
John Stiles270cec22021-02-17 12:59:36 -05001424 if (fProgram.fConfig->fSettings.fFragColorIsInOut) {
Brian Osmanc0213602020-10-06 14:43:32 -04001425 this->write("inout ");
1426 } else {
1427 this->write("out ");
Mike Klein5ce39722017-06-27 22:52:03 +00001428 }
Brian Osmanc0213602020-10-06 14:43:32 -04001429 if (usesPrecisionModifiers()) {
1430 this->write("mediump ");
1431 }
1432 this->writeLine("vec4 sk_FragColor;");
Mike Klein5ce39722017-06-27 22:52:03 +00001433 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001434 break;
Mike Klein5ce39722017-06-27 22:52:03 +00001435 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001436 case ProgramElement::Kind::kInterfaceBlock:
John Stiles3dc0da62020-08-19 17:48:31 -04001437 this->writeInterfaceBlock(e.as<InterfaceBlock>());
Ethan Nicholas762466e2017-06-29 10:03:38 -04001438 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001439 case ProgramElement::Kind::kFunction:
John Stiles3dc0da62020-08-19 17:48:31 -04001440 this->writeFunction(e.as<FunctionDefinition>());
Ethan Nicholas762466e2017-06-29 10:03:38 -04001441 break;
John Stiles569249b2020-11-03 12:18:22 -05001442 case ProgramElement::Kind::kFunctionPrototype:
1443 this->writeFunctionPrototype(e.as<FunctionPrototype>());
1444 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001445 case ProgramElement::Kind::kModifiers: {
Ethan Nicholas077050b2020-10-13 10:30:20 -04001446 const Modifiers& modifiers = e.as<ModifiersDeclaration>().modifiers();
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001447 this->writeModifiers(modifiers, true);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001448 this->writeLine(";");
1449 break;
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001450 }
John Stilesdc75a972020-11-25 16:24:55 -05001451 case ProgramElement::Kind::kStructDefinition:
Brian Osman02bc5222021-01-28 11:00:20 -05001452 this->writeStructDefinition(e.as<StructDefinition>());
John Stilesdc75a972020-11-25 16:24:55 -05001453 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001454 default:
John Stiles569249b2020-11-03 12:18:22 -05001455 SkDEBUGFAILF("unsupported program element %s\n", e.description().c_str());
1456 break;
Ethan Nicholasc0709392017-06-27 11:20:22 -04001457 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001458}
1459
Ethan Nicholascd700e92018-08-24 16:43:57 -04001460void GLSLCodeGenerator::writeInputVars() {
Brian Salomond8d85b92021-07-07 09:41:17 -04001461 if (fProgram.fInputs.fUseFlipRTUniform) {
Ethan Nicholascd700e92018-08-24 16:43:57 -04001462 const char* precision = usesPrecisionModifiers() ? "highp " : "";
1463 fGlobals.writeText("uniform ");
1464 fGlobals.writeText(precision);
Brian Salomond8d85b92021-07-07 09:41:17 -04001465 fGlobals.writeText("vec2 " SKSL_RTFLIP_NAME ";\n");
Ethan Nicholascd700e92018-08-24 16:43:57 -04001466 }
1467}
1468
Ethan Nicholas762466e2017-06-29 10:03:38 -04001469bool GLSLCodeGenerator::generateCode() {
John Stilesfffe3842020-09-02 15:44:18 -04001470 this->writeHeader();
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001471 OutputStream* rawOut = fOut;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001472 StringStream body;
1473 fOut = &body;
John Stiles9d7aa412021-01-15 15:54:02 -05001474 // Write all the program elements except for functions.
Brian Osman133724c2020-10-28 14:14:39 -04001475 for (const ProgramElement* e : fProgram.elements()) {
John Stiles9d7aa412021-01-15 15:54:02 -05001476 if (!e->is<FunctionDefinition>()) {
1477 this->writeProgramElement(*e);
1478 }
1479 }
1480 // Write the functions last.
1481 // Why don't we write things in their original order? Because the Inliner likes to move function
1482 // bodies around. After inlining, code can inadvertently move upwards, above ProgramElements
1483 // that the code relies on.
1484 for (const ProgramElement* e : fProgram.elements()) {
1485 if (e->is<FunctionDefinition>()) {
1486 this->writeProgramElement(*e);
1487 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001488 }
1489 fOut = rawOut;
ethannicholasddb37d62016-10-20 09:54:00 -07001490
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001491 write_stringstream(fExtensions, *rawOut);
Ethan Nicholascd700e92018-08-24 16:43:57 -04001492 this->writeInputVars();
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001493 write_stringstream(fGlobals, *rawOut);
Brian Osmancc10d792018-07-20 13:09:45 -04001494
John Stilesc1a98b82021-02-24 13:35:02 -05001495 if (!this->caps().canUseFragCoord()) {
Brian Osmancc10d792018-07-20 13:09:45 -04001496 Layout layout;
John Stiles270cec22021-02-17 12:59:36 -05001497 switch (fProgram.fConfig->fKind) {
John Stilesdbd4e6f2021-02-16 13:29:15 -05001498 case ProgramKind::kVertex: {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001499 Modifiers modifiers(layout, Modifiers::kOut_Flag);
Brian Osmancc10d792018-07-20 13:09:45 -04001500 this->writeModifiers(modifiers, true);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001501 if (this->usesPrecisionModifiers()) {
1502 this->write("highp ");
1503 }
Brian Osmancc10d792018-07-20 13:09:45 -04001504 this->write("vec4 sk_FragCoord_Workaround;\n");
1505 break;
1506 }
John Stilesdbd4e6f2021-02-16 13:29:15 -05001507 case ProgramKind::kFragment: {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001508 Modifiers modifiers(layout, Modifiers::kIn_Flag);
Brian Osmancc10d792018-07-20 13:09:45 -04001509 this->writeModifiers(modifiers, true);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001510 if (this->usesPrecisionModifiers()) {
1511 this->write("highp ");
1512 }
Brian Osmancc10d792018-07-20 13:09:45 -04001513 this->write("vec4 sk_FragCoord_Workaround;\n");
1514 break;
1515 }
1516 default:
1517 break;
1518 }
1519 }
1520
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001521 if (this->usesPrecisionModifiers()) {
Brian Osmanf6005202021-07-02 17:12:59 -04001522 const char* precision =
1523 fProgram.fConfig->fSettings.fForceHighPrecision ? "highp" : "mediump";
1524 this->write(String::printf("precision %s float;\n", precision));
1525 this->write(String::printf("precision %s sampler2D;\n", precision));
1526 if (fFoundExternalSamplerDecl && !this->caps().noDefaultPrecisionForExternalSamplers()) {
1527 this->write(String::printf("precision %s samplerExternalOES;\n", precision));
Brian Salomon67529b22019-08-13 15:31:04 -04001528 }
1529 if (fFoundRectSamplerDecl) {
Brian Osmanf6005202021-07-02 17:12:59 -04001530 this->write(String::printf("precision %s sampler2DRect;\n", precision));
Brian Salomon67529b22019-08-13 15:31:04 -04001531 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001532 }
Ethan Nicholas6e6525c2018-01-03 17:03:56 -05001533 write_stringstream(fExtraFunctions, *rawOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001534 write_stringstream(body, *rawOut);
Ethan Nicholas39f6da42021-08-23 13:10:07 -04001535 return fContext.fErrors->errorCount() == 0;
ethannicholasf789b382016-08-03 12:43:36 -07001536}
1537
John Stilesa6841be2020-08-06 14:11:56 -04001538} // namespace SkSL