blob: 6ef3b9b3daa793d7675f332e597933ceeeb22b45 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/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"
13#include "src/sksl/ir/SkSLExpressionStatement.h"
14#include "src/sksl/ir/SkSLExtension.h"
15#include "src/sksl/ir/SkSLIndexExpression.h"
16#include "src/sksl/ir/SkSLModifiersDeclaration.h"
17#include "src/sksl/ir/SkSLNop.h"
18#include "src/sksl/ir/SkSLVariableReference.h"
ethannicholasf789b382016-08-03 12:43:36 -070019
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -040020#ifndef SKSL_STANDALONE
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "include/private/SkOnce.h"
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -040022#endif
23
ethannicholasf789b382016-08-03 12:43:36 -070024namespace SkSL {
25
26void GLSLCodeGenerator::write(const char* s) {
27 if (s[0] == 0) {
28 return;
29 }
30 if (fAtLineStart) {
31 for (int i = 0; i < fIndentation; i++) {
Ethan Nicholas9e1138d2016-11-21 10:39:35 -050032 fOut->writeText(" ");
ethannicholasf789b382016-08-03 12:43:36 -070033 }
34 }
Ethan Nicholas9e1138d2016-11-21 10:39:35 -050035 fOut->writeText(s);
ethannicholasf789b382016-08-03 12:43:36 -070036 fAtLineStart = false;
37}
38
39void GLSLCodeGenerator::writeLine(const char* s) {
40 this->write(s);
Ethan Nicholas762466e2017-06-29 10:03:38 -040041 fOut->writeText(fLineEnding);
ethannicholasf789b382016-08-03 12:43:36 -070042 fAtLineStart = true;
43}
44
Ethan Nicholas0df1b042017-03-31 13:56:23 -040045void GLSLCodeGenerator::write(const String& s) {
ethannicholasf789b382016-08-03 12:43:36 -070046 this->write(s.c_str());
47}
48
Ethan Nicholas5b5f0962017-09-11 13:50:14 -070049void GLSLCodeGenerator::write(StringFragment s) {
50 if (!s.fLength) {
51 return;
52 }
53 if (fAtLineStart) {
54 for (int i = 0; i < fIndentation; i++) {
55 fOut->writeText(" ");
56 }
57 }
58 fOut->write(s.fChars, s.fLength);
59 fAtLineStart = false;
60}
61
Ethan Nicholas0df1b042017-03-31 13:56:23 -040062void GLSLCodeGenerator::writeLine(const String& s) {
ethannicholasf789b382016-08-03 12:43:36 -070063 this->writeLine(s.c_str());
64}
65
66void GLSLCodeGenerator::writeLine() {
67 this->writeLine("");
68}
69
Ethan Nicholas88f6d372018-07-27 10:03:46 -040070void GLSLCodeGenerator::writeExtension(const String& name) {
71 this->writeExtension(name, true);
72}
73
74void GLSLCodeGenerator::writeExtension(const String& name, bool require) {
75 fExtensions.writeText("#extension ");
76 fExtensions.write(name.c_str(), name.length());
77 fExtensions.writeText(require ? " : require\n" : " : enable\n");
ethannicholasf789b382016-08-03 12:43:36 -070078}
79
Ethan Nicholasf7b88202017-09-18 14:10:39 -040080bool GLSLCodeGenerator::usesPrecisionModifiers() const {
81 return fProgram.fSettings.fCaps->usesPrecisionModifiers();
82}
83
84String GLSLCodeGenerator::getTypeName(const Type& type) {
Ethan Nicholase6592142020-09-08 10:22:09 -040085 switch (type.typeKind()) {
86 case Type::TypeKind::kVector: {
Ethan Nicholasc18bb512020-07-28 14:46:53 -040087 const Type& component = type.componentType();
Ethan Nicholasf7b88202017-09-18 14:10:39 -040088 String result;
89 if (component == *fContext.fFloat_Type || component == *fContext.fHalf_Type) {
90 result = "vec";
91 }
Ethan Nicholase1f55022019-02-05 17:17:40 -050092 else if (component.isSigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -040093 result = "ivec";
94 }
Ethan Nicholase1f55022019-02-05 17:17:40 -050095 else if (component.isUnsigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -040096 result = "uvec";
97 }
98 else if (component == *fContext.fBool_Type) {
99 result = "bvec";
100 }
101 else {
102 ABORT("unsupported vector type");
103 }
104 result += to_string(type.columns());
105 return result;
106 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400107 case Type::TypeKind::kMatrix: {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400108 String result;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400109 const Type& component = type.componentType();
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400110 if (component == *fContext.fFloat_Type || component == *fContext.fHalf_Type) {
111 result = "mat";
112 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400113 else {
114 ABORT("unsupported matrix type");
115 }
116 result += to_string(type.columns());
117 if (type.columns() != type.rows()) {
118 result += "x";
119 result += to_string(type.rows());
120 }
121 return result;
122 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400123 case Type::TypeKind::kArray: {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400124 String result = this->getTypeName(type.componentType()) + "[";
125 if (type.columns() != -1) {
126 result += to_string(type.columns());
127 }
128 result += "]";
129 return result;
130 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400131 case Type::TypeKind::kScalar: {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400132 if (type == *fContext.fHalf_Type) {
133 return "float";
134 }
135 else if (type == *fContext.fShort_Type) {
136 return "int";
137 }
138 else if (type == *fContext.fUShort_Type) {
139 return "uint";
140 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400141 else if (type == *fContext.fByte_Type) {
142 return "int";
143 }
144 else if (type == *fContext.fUByte_Type) {
145 return "uint";
146 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400147 else {
148 return type.name();
149 }
150 break;
151 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400152 case Type::TypeKind::kEnum:
Ethan Nicholasdb80f692019-11-22 14:06:12 -0500153 return "int";
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400154 default:
155 return type.name();
156 }
157}
158
ethannicholasf789b382016-08-03 12:43:36 -0700159void GLSLCodeGenerator::writeType(const Type& type) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400160 if (type.typeKind() == Type::TypeKind::kStruct) {
ethannicholasf789b382016-08-03 12:43:36 -0700161 for (const Type* search : fWrittenStructs) {
162 if (*search == type) {
163 // already written
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700164 this->write(type.fName);
ethannicholasf789b382016-08-03 12:43:36 -0700165 return;
166 }
167 }
168 fWrittenStructs.push_back(&type);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700169 this->write("struct ");
170 this->write(type.fName);
171 this->writeLine(" {");
ethannicholasf789b382016-08-03 12:43:36 -0700172 fIndentation++;
173 for (const auto& f : type.fields()) {
ethannicholas5961bc92016-10-12 06:39:56 -0700174 this->writeModifiers(f.fModifiers, false);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -0400175 this->writeTypePrecision(*f.fType);
ethannicholasf789b382016-08-03 12:43:36 -0700176 // sizes (which must be static in structs) are part of the type name here
ethannicholas0730be72016-09-01 07:59:02 -0700177 this->writeType(*f.fType);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700178 this->write(" ");
179 this->write(f.fName);
180 this->writeLine(";");
ethannicholasf789b382016-08-03 12:43:36 -0700181 }
182 fIndentation--;
Ethan Nicholas19671772016-11-28 16:30:17 -0500183 this->write("}");
ethannicholasf789b382016-08-03 12:43:36 -0700184 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400185 this->write(this->getTypeName(type));
ethannicholasf789b382016-08-03 12:43:36 -0700186 }
187}
188
189void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence parentPrecedence) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400190 switch (expr.kind()) {
191 case Expression::Kind::kBinary:
John Stiles81365af2020-08-18 09:24:00 -0400192 this->writeBinaryExpression(expr.as<BinaryExpression>(), parentPrecedence);
ethannicholasf789b382016-08-03 12:43:36 -0700193 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400194 case Expression::Kind::kBoolLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400195 this->writeBoolLiteral(expr.as<BoolLiteral>());
ethannicholasf789b382016-08-03 12:43:36 -0700196 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400197 case Expression::Kind::kConstructor:
John Stiles81365af2020-08-18 09:24:00 -0400198 this->writeConstructor(expr.as<Constructor>(), parentPrecedence);
ethannicholasf789b382016-08-03 12:43:36 -0700199 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400200 case Expression::Kind::kIntLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400201 this->writeIntLiteral(expr.as<IntLiteral>());
ethannicholasf789b382016-08-03 12:43:36 -0700202 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400203 case Expression::Kind::kFieldAccess:
John Stiles81365af2020-08-18 09:24:00 -0400204 this->writeFieldAccess(expr.as<FieldAccess>());
ethannicholasf789b382016-08-03 12:43:36 -0700205 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400206 case Expression::Kind::kFloatLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400207 this->writeFloatLiteral(expr.as<FloatLiteral>());
ethannicholasf789b382016-08-03 12:43:36 -0700208 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400209 case Expression::Kind::kFunctionCall:
John Stiles81365af2020-08-18 09:24:00 -0400210 this->writeFunctionCall(expr.as<FunctionCall>());
ethannicholasf789b382016-08-03 12:43:36 -0700211 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400212 case Expression::Kind::kPrefix:
John Stiles81365af2020-08-18 09:24:00 -0400213 this->writePrefixExpression(expr.as<PrefixExpression>(), parentPrecedence);
ethannicholasf789b382016-08-03 12:43:36 -0700214 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400215 case Expression::Kind::kPostfix:
John Stiles81365af2020-08-18 09:24:00 -0400216 this->writePostfixExpression(expr.as<PostfixExpression>(), parentPrecedence);
ethannicholasf789b382016-08-03 12:43:36 -0700217 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400218 case Expression::Kind::kSetting:
John Stiles81365af2020-08-18 09:24:00 -0400219 this->writeSetting(expr.as<Setting>());
Ethan Nicholas762466e2017-06-29 10:03:38 -0400220 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400221 case Expression::Kind::kSwizzle:
John Stiles81365af2020-08-18 09:24:00 -0400222 this->writeSwizzle(expr.as<Swizzle>());
ethannicholasf789b382016-08-03 12:43:36 -0700223 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400224 case Expression::Kind::kVariableReference:
John Stiles81365af2020-08-18 09:24:00 -0400225 this->writeVariableReference(expr.as<VariableReference>());
ethannicholasf789b382016-08-03 12:43:36 -0700226 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400227 case Expression::Kind::kTernary:
John Stiles81365af2020-08-18 09:24:00 -0400228 this->writeTernaryExpression(expr.as<TernaryExpression>(), parentPrecedence);
ethannicholasf789b382016-08-03 12:43:36 -0700229 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400230 case Expression::Kind::kIndex:
John Stiles81365af2020-08-18 09:24:00 -0400231 this->writeIndexExpression(expr.as<IndexExpression>());
ethannicholasf789b382016-08-03 12:43:36 -0700232 break;
233 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500234#ifdef SK_DEBUG
ethannicholasf789b382016-08-03 12:43:36 -0700235 ABORT("unsupported expression: %s", expr.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500236#endif
237 break;
ethannicholasf789b382016-08-03 12:43:36 -0700238 }
239}
240
ethannicholas5961bc92016-10-12 06:39:56 -0700241static bool is_abs(Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400242 if (expr.kind() != Expression::Kind::kFunctionCall) {
ethannicholas5961bc92016-10-12 06:39:56 -0700243 return false;
244 }
John Stiles81365af2020-08-18 09:24:00 -0400245 return expr.as<FunctionCall>().fFunction.fName == "abs";
ethannicholas5961bc92016-10-12 06:39:56 -0700246}
247
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500248// turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a
ethannicholas5961bc92016-10-12 06:39:56 -0700249// Tegra3 compiler bug.
250void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400251 SkASSERT(!fProgram.fSettings.fCaps->canUseMinAndAbsTogether());
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400252 String tmpVar1 = "minAbsHackVar" + to_string(fVarCount++);
253 String tmpVar2 = "minAbsHackVar" + to_string(fVarCount++);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400254 this->fFunctionHeader += String(" ") + this->getTypePrecision(absExpr.type()) +
255 this->getTypeName(absExpr.type()) + " " + tmpVar1 + ";\n";
256 this->fFunctionHeader += String(" ") + this->getTypePrecision(otherExpr.type()) +
257 this->getTypeName(otherExpr.type()) + " " + tmpVar2 + ";\n";
ethannicholas5961bc92016-10-12 06:39:56 -0700258 this->write("((" + tmpVar1 + " = ");
259 this->writeExpression(absExpr, kTopLevel_Precedence);
260 this->write(") < (" + tmpVar2 + " = ");
261 this->writeExpression(otherExpr, kAssignment_Precedence);
262 this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")");
263}
264
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500265void GLSLCodeGenerator::writeInverseSqrtHack(const Expression& x) {
266 this->write("(1.0 / sqrt(");
267 this->writeExpression(x, kTopLevel_Precedence);
268 this->write("))");
269}
270
271void GLSLCodeGenerator::writeDeterminantHack(const Expression& mat) {
272 String name;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400273 const Type& type = mat.type();
274 if (type == *fContext.fFloat2x2_Type || type == *fContext.fHalf2x2_Type) {
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500275 name = "_determinant2";
276 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
277 fWrittenIntrinsics.insert(name);
278 fExtraFunctions.writeText((
279 "float " + name + "(mat2 m) {"
280 " return m[0][0] * m[1][1] - m[0][1] * m[1][0];"
281 "}"
282 ).c_str());
283 }
284 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400285 else if (type == *fContext.fFloat3x3_Type || type == *fContext.fHalf3x3_Type) {
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500286 name = "_determinant3";
287 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
288 fWrittenIntrinsics.insert(name);
289 fExtraFunctions.writeText((
290 "float " + name + "(mat3 m) {"
291 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
292 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
293 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
294 " float b01 = a22 * a11 - a12 * a21;"
295 " float b11 = -a22 * a10 + a12 * a20;"
296 " float b21 = a21 * a10 - a11 * a20;"
297 " return a00 * b01 + a01 * b11 + a02 * b21;"
298 "}"
299 ).c_str());
300 }
301 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400302 else if (type == *fContext.fFloat4x4_Type || type == *fContext.fHalf4x4_Type) {
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500303 name = "_determinant3";
304 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
305 fWrittenIntrinsics.insert(name);
306 fExtraFunctions.writeText((
307 "mat4 " + name + "(mat4 m) {"
308 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
309 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
310 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
311 " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
312 " float b00 = a00 * a11 - a01 * a10;"
313 " float b01 = a00 * a12 - a02 * a10;"
314 " float b02 = a00 * a13 - a03 * a10;"
315 " float b03 = a01 * a12 - a02 * a11;"
316 " float b04 = a01 * a13 - a03 * a11;"
317 " float b05 = a02 * a13 - a03 * a12;"
318 " float b06 = a20 * a31 - a21 * a30;"
319 " float b07 = a20 * a32 - a22 * a30;"
320 " float b08 = a20 * a33 - a23 * a30;"
321 " float b09 = a21 * a32 - a22 * a31;"
322 " float b10 = a21 * a33 - a23 * a31;"
323 " float b11 = a22 * a33 - a23 * a32;"
324 " return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;"
325 "}"
326 ).c_str());
327 }
328 }
329 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400330 SkASSERT(false);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500331 }
332 this->write(name + "(");
333 this->writeExpression(mat, kTopLevel_Precedence);
334 this->write(")");
335}
336
337void GLSLCodeGenerator::writeInverseHack(const Expression& mat) {
338 String name;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400339 const Type& type = mat.type();
340 if (type == *fContext.fFloat2x2_Type || type == *fContext.fHalf2x2_Type) {
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500341 name = "_inverse2";
342 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
343 fWrittenIntrinsics.insert(name);
344 fExtraFunctions.writeText((
345 "mat2 " + name + "(mat2 m) {"
346 " return mat2(m[1][1], -m[0][1], -m[1][0], m[0][0]) / "
347 "(m[0][0] * m[1][1] - m[0][1] * m[1][0]);"
348 "}"
349 ).c_str());
350 }
351 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400352 else if (type == *fContext.fFloat3x3_Type || type == *fContext.fHalf3x3_Type) {
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500353 name = "_inverse3";
354 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
355 fWrittenIntrinsics.insert(name);
356 fExtraFunctions.writeText((
357 "mat3 " + name + "(mat3 m) {"
358 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];"
359 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];"
360 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];"
361 " float b01 = a22 * a11 - a12 * a21;"
362 " float b11 = -a22 * a10 + a12 * a20;"
363 " float b21 = a21 * a10 - a11 * a20;"
364 " float det = a00 * b01 + a01 * b11 + a02 * b21;"
365 " return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),"
366 " b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),"
367 " b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;"
368 "}"
369 ).c_str());
370 }
371 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400372 else if (type == *fContext.fFloat4x4_Type || type == *fContext.fHalf4x4_Type) {
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500373 name = "_inverse4";
374 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
375 fWrittenIntrinsics.insert(name);
376 fExtraFunctions.writeText((
377 "mat4 " + name + "(mat4 m) {"
378 " float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3];"
379 " float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3];"
380 " float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3];"
381 " float a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3];"
382 " float b00 = a00 * a11 - a01 * a10;"
383 " float b01 = a00 * a12 - a02 * a10;"
384 " float b02 = a00 * a13 - a03 * a10;"
385 " float b03 = a01 * a12 - a02 * a11;"
386 " float b04 = a01 * a13 - a03 * a11;"
387 " float b05 = a02 * a13 - a03 * a12;"
388 " float b06 = a20 * a31 - a21 * a30;"
389 " float b07 = a20 * a32 - a22 * a30;"
390 " float b08 = a20 * a33 - a23 * a30;"
391 " float b09 = a21 * a32 - a22 * a31;"
392 " float b10 = a21 * a33 - a23 * a31;"
393 " float b11 = a22 * a33 - a23 * a32;"
394 " float det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - "
395 " b04 * b07 + b05 * b06;"
396 " return mat4("
397 " a11 * b11 - a12 * b10 + a13 * b09,"
398 " a02 * b10 - a01 * b11 - a03 * b09,"
399 " a31 * b05 - a32 * b04 + a33 * b03,"
400 " a22 * b04 - a21 * b05 - a23 * b03,"
401 " a12 * b08 - a10 * b11 - a13 * b07,"
402 " a00 * b11 - a02 * b08 + a03 * b07,"
403 " a32 * b02 - a30 * b05 - a33 * b01,"
404 " a20 * b05 - a22 * b02 + a23 * b01,"
405 " a10 * b10 - a11 * b08 + a13 * b06,"
406 " a01 * b08 - a00 * b10 - a03 * b06,"
407 " a30 * b04 - a31 * b02 + a33 * b00,"
408 " a21 * b02 - a20 * b04 - a23 * b00,"
409 " a11 * b07 - a10 * b09 - a12 * b06,"
410 " a00 * b09 - a01 * b07 + a02 * b06,"
411 " a31 * b01 - a30 * b03 - a32 * b00,"
412 " a20 * b03 - a21 * b01 + a22 * b00) / det;"
413 "}"
414 ).c_str());
415 }
416 }
417 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400418 SkASSERT(false);
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500419 }
420 this->write(name + "(");
421 this->writeExpression(mat, kTopLevel_Precedence);
422 this->write(")");
423}
424
425void GLSLCodeGenerator::writeTransposeHack(const Expression& mat) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400426 const Type& type = mat.type();
427 String name = "transpose" + to_string(type.columns()) + to_string(type.rows());
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500428 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
429 fWrittenIntrinsics.insert(name);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400430 String typeName = this->getTypeName(type);
431 const Type& base = type.componentType();
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500432 String transposed = this->getTypeName(base.toCompound(fContext,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400433 type.rows(),
434 type.columns()));
435 fExtraFunctions.writeText((transposed + " " + name + "(" + typeName + " m) {\nreturn " +
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500436 transposed + "(").c_str());
437 const char* separator = "";
Ethan Nicholas30d30222020-09-11 12:27:26 -0400438 for (int row = 0; row < type.rows(); ++row) {
439 for (int column = 0; column < type.columns(); ++column) {
Ethan Nicholas6e6525c2018-01-03 17:03:56 -0500440 fExtraFunctions.writeText(separator);
441 fExtraFunctions.writeText(("m[" + to_string(column) + "][" + to_string(row) +
442 "]").c_str());
443 separator = ", ";
444 }
445 }
446 fExtraFunctions.writeText("); }");
447 }
448 this->write(name + "(");
449 this->writeExpression(mat, kTopLevel_Precedence);
450 this->write(")");
451}
452
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400453std::unordered_map<StringFragment, GLSLCodeGenerator::FunctionClass>*
454 GLSLCodeGenerator::fFunctionClasses = nullptr;
455
ethannicholasf789b382016-08-03 12:43:36 -0700456void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400457#ifdef SKSL_STANDALONE
458 if (!fFunctionClasses) {
459#else
460 static SkOnce once;
461 once([] {
462#endif
463 fFunctionClasses = new std::unordered_map<StringFragment, FunctionClass>();
Adrienne Walker92b161f2018-08-22 10:41:52 -0700464 (*fFunctionClasses)["abs"] = FunctionClass::kAbs;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400465 (*fFunctionClasses)["atan"] = FunctionClass::kAtan;
466 (*fFunctionClasses)["determinant"] = FunctionClass::kDeterminant;
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700467 (*fFunctionClasses)["dFdx"] = FunctionClass::kDFdx;
468 (*fFunctionClasses)["dFdy"] = FunctionClass::kDFdy;
469 (*fFunctionClasses)["fwidth"] = FunctionClass::kFwidth;
Chris Daltona7086182018-11-16 09:33:43 -0500470 (*fFunctionClasses)["fma"] = FunctionClass::kFMA;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400471 (*fFunctionClasses)["fract"] = FunctionClass::kFract;
472 (*fFunctionClasses)["inverse"] = FunctionClass::kInverse;
473 (*fFunctionClasses)["inverseSqrt"] = FunctionClass::kInverseSqrt;
474 (*fFunctionClasses)["min"] = FunctionClass::kMin;
Adrienne Walker2f4c09b2018-08-22 16:04:57 -0700475 (*fFunctionClasses)["pow"] = FunctionClass::kPow;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400476 (*fFunctionClasses)["saturate"] = FunctionClass::kSaturate;
Ethan Nicholas13863662019-07-29 13:05:15 -0400477 (*fFunctionClasses)["sample"] = FunctionClass::kTexture;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400478 (*fFunctionClasses)["transpose"] = FunctionClass::kTranspose;
ethannicholas5961bc92016-10-12 06:39:56 -0700479 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400480#ifndef SKSL_STANDALONE
481 );
482#endif
483 const auto found = c.fFunction.fBuiltin ? fFunctionClasses->find(c.fFunction.fName) :
484 fFunctionClasses->end();
Brian Osman8a83ca42018-02-12 14:32:17 -0500485 bool isTextureFunctionWithBias = false;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400486 bool nameWritten = false;
487 if (found != fFunctionClasses->end()) {
488 switch (found->second) {
Adrienne Walker92b161f2018-08-22 10:41:52 -0700489 case FunctionClass::kAbs: {
490 if (!fProgram.fSettings.fCaps->emulateAbsIntFunction())
491 break;
492 SkASSERT(c.fArguments.size() == 1);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400493 if (c.fArguments[0]->type() != *fContext.fInt_Type)
Adrienne Walker92b161f2018-08-22 10:41:52 -0700494 break;
495 // abs(int) on Intel OSX is incorrect, so emulate it:
496 String name = "_absemulation";
497 this->write(name);
498 nameWritten = true;
499 if (fWrittenIntrinsics.find(name) == fWrittenIntrinsics.end()) {
500 fWrittenIntrinsics.insert(name);
501 fExtraFunctions.writeText((
502 "int " + name + "(int x) {\n"
503 " return x * sign(x);\n"
504 "}\n"
505 ).c_str());
506 }
507 break;
508 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400509 case FunctionClass::kAtan:
510 if (fProgram.fSettings.fCaps->mustForceNegatedAtanParamToFloat() &&
511 c.fArguments.size() == 2 &&
Ethan Nicholase6592142020-09-08 10:22:09 -0400512 c.fArguments[1]->kind() == Expression::Kind::kPrefix) {
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400513 const PrefixExpression& p = (PrefixExpression&) *c.fArguments[1];
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400514 if (p.fOperator == Token::Kind::TK_MINUS) {
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400515 this->write("atan(");
516 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
517 this->write(", -1.0 * ");
518 this->writeExpression(*p.fOperand, kMultiplicative_Precedence);
519 this->write(")");
520 return;
521 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500522 }
523 break;
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700524 case FunctionClass::kDFdy:
525 if (fProgram.fSettings.fFlipY) {
526 // Flipping Y also negates the Y derivatives.
527 this->write("-dFdy");
528 nameWritten = true;
529 }
John Stiles30212b72020-06-11 17:55:07 -0400530 [[fallthrough]];
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700531 case FunctionClass::kDFdx:
532 case FunctionClass::kFwidth:
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400533 if (!fFoundDerivatives &&
534 fProgram.fSettings.fCaps->shaderDerivativeExtensionString()) {
535 SkASSERT(fProgram.fSettings.fCaps->shaderDerivativeSupport());
536 this->writeExtension(fProgram.fSettings.fCaps->shaderDerivativeExtensionString());
537 fFoundDerivatives = true;
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500538 }
539 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400540 case FunctionClass::kDeterminant:
541 if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
542 SkASSERT(c.fArguments.size() == 1);
543 this->writeDeterminantHack(*c.fArguments[0]);
544 return;
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500545 }
546 break;
Chris Daltona7086182018-11-16 09:33:43 -0500547 case FunctionClass::kFMA:
548 if (!fProgram.fSettings.fCaps->builtinFMASupport()) {
549 SkASSERT(c.fArguments.size() == 3);
550 this->write("((");
551 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
552 this->write(") * (");
553 this->writeExpression(*c.fArguments[1], kSequence_Precedence);
554 this->write(") + (");
555 this->writeExpression(*c.fArguments[2], kSequence_Precedence);
556 this->write("))");
557 return;
558 }
559 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400560 case FunctionClass::kFract:
561 if (!fProgram.fSettings.fCaps->canUseFractForNegativeValues()) {
562 SkASSERT(c.fArguments.size() == 1);
563 this->write("(0.5 - sign(");
564 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
565 this->write(") * (0.5 - fract(abs(");
566 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
567 this->write("))))");
568 return;
569 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500570 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400571 case FunctionClass::kInverse:
572 if (fProgram.fSettings.fCaps->generation() < k140_GrGLSLGeneration) {
573 SkASSERT(c.fArguments.size() == 1);
574 this->writeInverseHack(*c.fArguments[0]);
575 return;
576 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500577 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400578 case FunctionClass::kInverseSqrt:
579 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
580 SkASSERT(c.fArguments.size() == 1);
581 this->writeInverseSqrtHack(*c.fArguments[0]);
582 return;
583 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500584 break;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400585 case FunctionClass::kMin:
586 if (!fProgram.fSettings.fCaps->canUseMinAndAbsTogether()) {
587 SkASSERT(c.fArguments.size() == 2);
588 if (is_abs(*c.fArguments[0])) {
589 this->writeMinAbsHack(*c.fArguments[0], *c.fArguments[1]);
590 return;
591 }
592 if (is_abs(*c.fArguments[1])) {
593 // note that this violates the GLSL left-to-right evaluation semantics.
594 // I doubt it will ever end up mattering, but it's worth calling out.
595 this->writeMinAbsHack(*c.fArguments[1], *c.fArguments[0]);
596 return;
597 }
598 }
599 break;
Adrienne Walker2f4c09b2018-08-22 16:04:57 -0700600 case FunctionClass::kPow:
601 if (!fProgram.fSettings.fCaps->removePowWithConstantExponent()) {
602 break;
603 }
604 // pow(x, y) on some NVIDIA drivers causes crashes if y is a
605 // constant. It's hard to tell what constitutes "constant" here
606 // so just replace in all cases.
607
608 // Change pow(x, y) into exp2(y * log2(x))
609 this->write("exp2(");
610 this->writeExpression(*c.fArguments[1], kMultiplicative_Precedence);
611 this->write(" * log2(");
612 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
613 this->write("))");
614 return;
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400615 case FunctionClass::kSaturate:
616 SkASSERT(c.fArguments.size() == 1);
617 this->write("clamp(");
618 this->writeExpression(*c.fArguments[0], kSequence_Precedence);
619 this->write(", 0.0, 1.0)");
620 return;
621 case FunctionClass::kTexture: {
622 const char* dim = "";
623 bool proj = false;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400624 const Type& arg0Type = c.fArguments[0]->type();
625 const Type& arg1Type = c.fArguments[1]->type();
626 switch (arg0Type.dimensions()) {
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400627 case SpvDim1D:
628 dim = "1D";
629 isTextureFunctionWithBias = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400630 if (arg1Type == *fContext.fFloat_Type) {
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400631 proj = false;
632 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400633 SkASSERT(arg1Type == *fContext.fFloat2_Type);
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400634 proj = true;
635 }
636 break;
637 case SpvDim2D:
638 dim = "2D";
Ethan Nicholas30d30222020-09-11 12:27:26 -0400639 if (arg0Type != *fContext.fSamplerExternalOES_Type) {
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400640 isTextureFunctionWithBias = true;
641 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400642 if (arg1Type == *fContext.fFloat2_Type) {
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400643 proj = false;
644 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400645 SkASSERT(arg1Type == *fContext.fFloat3_Type);
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400646 proj = true;
647 }
648 break;
649 case SpvDim3D:
650 dim = "3D";
651 isTextureFunctionWithBias = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400652 if (arg1Type == *fContext.fFloat3_Type) {
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400653 proj = false;
654 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400655 SkASSERT(arg1Type == *fContext.fFloat4_Type);
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400656 proj = true;
657 }
658 break;
659 case SpvDimCube:
660 dim = "Cube";
661 isTextureFunctionWithBias = true;
662 proj = false;
663 break;
664 case SpvDimRect:
Khushal Sagar2cb13152019-09-11 23:17:26 +0000665 dim = "2DRect";
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400666 proj = false;
667 break;
668 case SpvDimBuffer:
669 SkASSERT(false); // doesn't exist
670 dim = "Buffer";
671 proj = false;
672 break;
673 case SpvDimSubpassData:
674 SkASSERT(false); // doesn't exist
675 dim = "SubpassData";
676 proj = false;
677 break;
678 }
Ethan Nicholas13863662019-07-29 13:05:15 -0400679 if (fTextureFunctionOverride != "") {
680 this->write(fTextureFunctionOverride.c_str());
681 } else {
682 this->write("texture");
683 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
684 this->write(dim);
685 }
686 if (proj) {
687 this->write("Proj");
688 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400689 }
690 nameWritten = true;
691 break;
692 }
693 case FunctionClass::kTranspose:
694 if (fProgram.fSettings.fCaps->generation() < k130_GrGLSLGeneration) {
695 SkASSERT(c.fArguments.size() == 1);
696 this->writeTransposeHack(*c.fArguments[0]);
697 return;
698 }
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500699 break;
700 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400701 }
702 if (!nameWritten) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500703 this->write(c.fFunction.fName);
704 }
705 this->write("(");
ethannicholasf789b382016-08-03 12:43:36 -0700706 const char* separator = "";
707 for (const auto& arg : c.fArguments) {
708 this->write(separator);
709 separator = ", ";
710 this->writeExpression(*arg, kSequence_Precedence);
711 }
Brian Osman8a83ca42018-02-12 14:32:17 -0500712 if (fProgram.fSettings.fSharpenTextures && isTextureFunctionWithBias) {
713 this->write(", -0.5");
714 }
ethannicholasf789b382016-08-03 12:43:36 -0700715 this->write(")");
716}
717
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400718void GLSLCodeGenerator::writeConstructor(const Constructor& c, Precedence parentPrecedence) {
719 if (c.fArguments.size() == 1 &&
Ethan Nicholas30d30222020-09-11 12:27:26 -0400720 (this->getTypeName(c.type()) == this->getTypeName(c.fArguments[0]->type()) ||
721 (c.type().typeKind() == Type::TypeKind::kScalar &&
722 c.fArguments[0]->type() == *fContext.fFloatLiteral_Type))) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400723 // in cases like half(float), they're different types as far as SkSL is concerned but the
724 // same type as far as GLSL is concerned. We avoid a redundant float(float) by just writing
725 // out the inner expression here.
726 this->writeExpression(*c.fArguments[0], parentPrecedence);
727 return;
728 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400729 this->writeType(c.type());
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400730 this->write("(");
ethannicholasf789b382016-08-03 12:43:36 -0700731 const char* separator = "";
732 for (const auto& arg : c.fArguments) {
733 this->write(separator);
734 separator = ", ";
735 this->writeExpression(*arg, kSequence_Precedence);
736 }
737 this->write(")");
738}
739
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500740void GLSLCodeGenerator::writeFragCoord() {
Brian Osmancd3261a2018-01-16 13:52:29 +0000741 if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
Brian Salomondba65f92018-01-22 08:43:38 -0500742 if (!fSetupFragCoordWorkaround) {
743 const char* precision = usesPrecisionModifiers() ? "highp " : "";
744 fFunctionHeader += precision;
745 fFunctionHeader += " float sk_FragCoord_InvW = 1. / sk_FragCoord_Workaround.w;\n";
746 fFunctionHeader += precision;
747 fFunctionHeader += " vec4 sk_FragCoord_Resolved = "
748 "vec4(sk_FragCoord_Workaround.xyz * sk_FragCoord_InvW, sk_FragCoord_InvW);\n";
749 // Ensure that we get exact .5 values for x and y.
750 fFunctionHeader += " sk_FragCoord_Resolved.xy = floor(sk_FragCoord_Resolved.xy) + "
751 "vec2(.5);\n";
752 fSetupFragCoordWorkaround = true;
753 }
754 this->write("sk_FragCoord_Resolved");
Brian Osmancd3261a2018-01-16 13:52:29 +0000755 return;
756 }
757
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500758 // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
759 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
760 // declaration varies in earlier GLSL specs. So it is simpler to omit it.
761 if (!fProgram.fSettings.fFlipY) {
762 this->write("gl_FragCoord");
763 } else if (const char* extension =
Ethan Nicholascd700e92018-08-24 16:43:57 -0400764 fProgram.fSettings.fCaps->fragCoordConventionsExtensionString()) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500765 if (!fSetupFragPositionGlobal) {
766 if (fProgram.fSettings.fCaps->generation() < k150_GrGLSLGeneration) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -0400767 this->writeExtension(extension);
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500768 }
Ethan Nicholas88f6d372018-07-27 10:03:46 -0400769 fGlobals.writeText("layout(origin_upper_left) in vec4 gl_FragCoord;\n");
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500770 fSetupFragPositionGlobal = true;
Greg Daniele8e4a3e2016-12-12 17:20:42 +0000771 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500772 this->write("gl_FragCoord");
Greg Daniele8e4a3e2016-12-12 17:20:42 +0000773 } else {
Ethan Nicholascd700e92018-08-24 16:43:57 -0400774 if (!fSetupFragPositionLocal) {
Michael Ludwig5e1f6ea2018-12-03 15:14:50 -0500775 fFunctionHeader += usesPrecisionModifiers() ? "highp " : "";
Michael Ludwigf0b60442018-12-10 14:43:38 +0000776 fFunctionHeader += " vec4 sk_FragCoord = vec4(gl_FragCoord.x, " SKSL_RTHEIGHT_NAME
777 " - gl_FragCoord.y, gl_FragCoord.z, gl_FragCoord.w);\n";
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500778 fSetupFragPositionLocal = true;
779 }
780 this->write("sk_FragCoord");
781 }
782}
783
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500784void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
785 switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
786 case SK_FRAGCOLOR_BUILTIN:
787 if (fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
788 this->write("sk_FragColor");
789 } else {
790 this->write("gl_FragColor");
791 }
792 break;
793 case SK_FRAGCOORD_BUILTIN:
794 this->writeFragCoord();
795 break;
Ethan Nicholascd700e92018-08-24 16:43:57 -0400796 case SK_WIDTH_BUILTIN:
797 this->write("u_skRTWidth");
798 break;
799 case SK_HEIGHT_BUILTIN:
800 this->write("u_skRTHeight");
801 break;
Chris Dalton49d14e92018-07-27 12:38:35 -0600802 case SK_CLOCKWISE_BUILTIN:
Chris Daltonc8ece3d2018-07-30 15:03:45 -0600803 this->write(fProgram.fSettings.fFlipY ? "(!gl_FrontFacing)" : "gl_FrontFacing");
Chris Dalton49d14e92018-07-27 12:38:35 -0600804 break;
Chris Daltonb0fd4b12019-10-29 13:41:22 -0600805 case SK_SAMPLEMASK_BUILTIN:
Chris Dalton8a64a442019-10-29 18:54:58 -0600806 SkASSERT(fProgram.fSettings.fCaps->sampleMaskSupport());
Chris Daltonb0fd4b12019-10-29 13:41:22 -0600807 this->write("gl_SampleMask");
808 break;
Ethan Nicholasa51740c2017-02-07 14:53:32 -0500809 case SK_VERTEXID_BUILTIN:
810 this->write("gl_VertexID");
811 break;
Chris Dalton8580d512017-10-14 22:12:33 -0600812 case SK_INSTANCEID_BUILTIN:
813 this->write("gl_InstanceID");
814 break;
Ethan Nicholas67d64602017-02-09 10:15:25 -0500815 case SK_CLIPDISTANCE_BUILTIN:
816 this->write("gl_ClipDistance");
817 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -0500818 case SK_IN_BUILTIN:
819 this->write("gl_in");
820 break;
821 case SK_INVOCATIONID_BUILTIN:
822 this->write("gl_InvocationID");
823 break;
Ethan Nicholaseab2baa2018-04-13 15:16:27 -0400824 case SK_LASTFRAGCOLOR_BUILTIN:
825 this->write(fProgram.fSettings.fCaps->fbFetchColorName());
826 break;
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500827 default:
828 this->write(ref.fVariable.fName);
ethannicholas5961bc92016-10-12 06:39:56 -0700829 }
ethannicholasf789b382016-08-03 12:43:36 -0700830}
831
832void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
833 this->writeExpression(*expr.fBase, kPostfix_Precedence);
834 this->write("[");
835 this->writeExpression(*expr.fIndex, kTopLevel_Precedence);
836 this->write("]");
837}
838
Brian Osmancd3261a2018-01-16 13:52:29 +0000839bool is_sk_position(const FieldAccess& f) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400840 return "sk_Position" == f.fBase->type().fields()[f.fFieldIndex].fName;
Brian Osmancd3261a2018-01-16 13:52:29 +0000841}
842
ethannicholasf789b382016-08-03 12:43:36 -0700843void GLSLCodeGenerator::writeFieldAccess(const FieldAccess& f) {
844 if (f.fOwnerKind == FieldAccess::kDefault_OwnerKind) {
845 this->writeExpression(*f.fBase, kPostfix_Precedence);
846 this->write(".");
847 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400848 const Type& baseType = f.fBase->type();
849 switch (baseType.fields()[f.fFieldIndex].fModifiers.fLayout.fBuiltin) {
Ethan Nicholas67d64602017-02-09 10:15:25 -0500850 case SK_CLIPDISTANCE_BUILTIN:
851 this->write("gl_ClipDistance");
852 break;
853 default:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400854 StringFragment name = baseType.fields()[f.fFieldIndex].fName;
Ethan Nicholasbed683a2017-09-26 14:23:59 -0400855 if (name == "sk_Position") {
856 this->write("gl_Position");
857 } else if (name == "sk_PointSize") {
858 this->write("gl_PointSize");
859 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400860 this->write(baseType.fields()[f.fFieldIndex].fName);
Ethan Nicholasbed683a2017-09-26 14:23:59 -0400861 }
Ethan Nicholas67d64602017-02-09 10:15:25 -0500862 }
ethannicholasf789b382016-08-03 12:43:36 -0700863}
864
Brian Osman25647672020-09-15 15:16:56 -0400865void GLSLCodeGenerator::writeSwizzle(const Swizzle& swizzle) {
ethannicholasf789b382016-08-03 12:43:36 -0700866 this->writeExpression(*swizzle.fBase, kPostfix_Precedence);
867 this->write(".");
868 for (int c : swizzle.fComponents) {
Brian Osman25647672020-09-15 15:16:56 -0400869 SkASSERT(c >= 0 && c <= 3);
870 this->write(&("x\0y\0z\0w\0"[c * 2]));
ethannicholasf789b382016-08-03 12:43:36 -0700871 }
872}
873
Ethan Nicholas762466e2017-06-29 10:03:38 -0400874GLSLCodeGenerator::Precedence GLSLCodeGenerator::GetBinaryPrecedence(Token::Kind op) {
ethannicholasf789b382016-08-03 12:43:36 -0700875 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400876 case Token::Kind::TK_STAR: // fall through
877 case Token::Kind::TK_SLASH: // fall through
878 case Token::Kind::TK_PERCENT: return GLSLCodeGenerator::kMultiplicative_Precedence;
879 case Token::Kind::TK_PLUS: // fall through
880 case Token::Kind::TK_MINUS: return GLSLCodeGenerator::kAdditive_Precedence;
881 case Token::Kind::TK_SHL: // fall through
882 case Token::Kind::TK_SHR: return GLSLCodeGenerator::kShift_Precedence;
883 case Token::Kind::TK_LT: // fall through
884 case Token::Kind::TK_GT: // fall through
885 case Token::Kind::TK_LTEQ: // fall through
886 case Token::Kind::TK_GTEQ: return GLSLCodeGenerator::kRelational_Precedence;
887 case Token::Kind::TK_EQEQ: // fall through
888 case Token::Kind::TK_NEQ: return GLSLCodeGenerator::kEquality_Precedence;
889 case Token::Kind::TK_BITWISEAND: return GLSLCodeGenerator::kBitwiseAnd_Precedence;
890 case Token::Kind::TK_BITWISEXOR: return GLSLCodeGenerator::kBitwiseXor_Precedence;
891 case Token::Kind::TK_BITWISEOR: return GLSLCodeGenerator::kBitwiseOr_Precedence;
892 case Token::Kind::TK_LOGICALAND: return GLSLCodeGenerator::kLogicalAnd_Precedence;
893 case Token::Kind::TK_LOGICALXOR: return GLSLCodeGenerator::kLogicalXor_Precedence;
894 case Token::Kind::TK_LOGICALOR: return GLSLCodeGenerator::kLogicalOr_Precedence;
895 case Token::Kind::TK_EQ: // fall through
896 case Token::Kind::TK_PLUSEQ: // fall through
897 case Token::Kind::TK_MINUSEQ: // fall through
898 case Token::Kind::TK_STAREQ: // fall through
899 case Token::Kind::TK_SLASHEQ: // fall through
900 case Token::Kind::TK_PERCENTEQ: // fall through
901 case Token::Kind::TK_SHLEQ: // fall through
902 case Token::Kind::TK_SHREQ: // fall through
903 case Token::Kind::TK_LOGICALANDEQ: // fall through
904 case Token::Kind::TK_LOGICALXOREQ: // fall through
905 case Token::Kind::TK_LOGICALOREQ: // fall through
906 case Token::Kind::TK_BITWISEANDEQ: // fall through
907 case Token::Kind::TK_BITWISEXOREQ: // fall through
908 case Token::Kind::TK_BITWISEOREQ: return GLSLCodeGenerator::kAssignment_Precedence;
909 case Token::Kind::TK_COMMA: return GLSLCodeGenerator::kSequence_Precedence;
ethannicholasf789b382016-08-03 12:43:36 -0700910 default: ABORT("unsupported binary operator");
911 }
912}
913
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400914void GLSLCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
ethannicholasf789b382016-08-03 12:43:36 -0700915 Precedence parentPrecedence) {
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400916 const Expression& left = b.left();
917 const Expression& right = b.right();
918 Token::Kind op = b.getOperator();
Adrienne Walkerc02165f2018-08-21 11:08:11 -0700919 if (fProgram.fSettings.fCaps->unfoldShortCircuitAsTernary() &&
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400920 (op == Token::Kind::TK_LOGICALAND || op == Token::Kind::TK_LOGICALOR)) {
Adrienne Walkerc02165f2018-08-21 11:08:11 -0700921 this->writeShortCircuitWorkaroundExpression(b, parentPrecedence);
922 return;
923 }
924
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400925 Precedence precedence = GetBinaryPrecedence(op);
ethannicholasf789b382016-08-03 12:43:36 -0700926 if (precedence >= parentPrecedence) {
927 this->write("(");
928 }
Ethan Nicholas0b631962018-07-24 13:41:11 -0400929 bool positionWorkaround = fProgramKind == Program::Kind::kVertex_Kind &&
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400930 Compiler::IsAssignment(op) &&
931 left.kind() == Expression::Kind::kFieldAccess &&
932 is_sk_position((FieldAccess&) left) &&
933 !right.containsRTAdjust() &&
Brian Osmancd3261a2018-01-16 13:52:29 +0000934 !fProgram.fSettings.fCaps->canUseFragCoord();
935 if (positionWorkaround) {
936 this->write("sk_FragCoord_Workaround = (");
937 }
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400938 this->writeExpression(left, precedence);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700939 this->write(" ");
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400940 this->write(Compiler::OperatorName(op));
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700941 this->write(" ");
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400942 this->writeExpression(right, precedence);
Brian Osmancd3261a2018-01-16 13:52:29 +0000943 if (positionWorkaround) {
944 this->write(")");
945 }
ethannicholasf789b382016-08-03 12:43:36 -0700946 if (precedence >= parentPrecedence) {
947 this->write(")");
948 }
949}
950
Adrienne Walkerc02165f2018-08-21 11:08:11 -0700951void GLSLCodeGenerator::writeShortCircuitWorkaroundExpression(const BinaryExpression& b,
952 Precedence parentPrecedence) {
953 if (kTernary_Precedence >= parentPrecedence) {
954 this->write("(");
955 }
956
957 // Transform:
958 // a && b => a ? b : false
959 // a || b => a ? true : b
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400960 this->writeExpression(b.left(), kTernary_Precedence);
Adrienne Walkerc02165f2018-08-21 11:08:11 -0700961 this->write(" ? ");
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400962 if (b.getOperator() == Token::Kind::TK_LOGICALAND) {
963 this->writeExpression(b.right(), kTernary_Precedence);
Adrienne Walkerc02165f2018-08-21 11:08:11 -0700964 } else {
965 BoolLiteral boolTrue(fContext, -1, true);
966 this->writeBoolLiteral(boolTrue);
967 }
968 this->write(" : ");
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400969 if (b.getOperator() == Token::Kind::TK_LOGICALAND) {
Adrienne Walkerc02165f2018-08-21 11:08:11 -0700970 BoolLiteral boolFalse(fContext, -1, false);
971 this->writeBoolLiteral(boolFalse);
972 } else {
Ethan Nicholas1d3e0e02020-09-16 15:19:24 -0400973 this->writeExpression(b.right(), kTernary_Precedence);
Adrienne Walkerc02165f2018-08-21 11:08:11 -0700974 }
975 if (kTernary_Precedence >= parentPrecedence) {
976 this->write(")");
977 }
978}
979
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400980void GLSLCodeGenerator::writeTernaryExpression(const TernaryExpression& t,
ethannicholasf789b382016-08-03 12:43:36 -0700981 Precedence parentPrecedence) {
982 if (kTernary_Precedence >= parentPrecedence) {
983 this->write("(");
984 }
985 this->writeExpression(*t.fTest, kTernary_Precedence);
986 this->write(" ? ");
987 this->writeExpression(*t.fIfTrue, kTernary_Precedence);
988 this->write(" : ");
989 this->writeExpression(*t.fIfFalse, kTernary_Precedence);
990 if (kTernary_Precedence >= parentPrecedence) {
991 this->write(")");
992 }
993}
994
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400995void GLSLCodeGenerator::writePrefixExpression(const PrefixExpression& p,
ethannicholasf789b382016-08-03 12:43:36 -0700996 Precedence parentPrecedence) {
997 if (kPrefix_Precedence >= parentPrecedence) {
998 this->write("(");
999 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001000 this->write(Compiler::OperatorName(p.fOperator));
ethannicholasf789b382016-08-03 12:43:36 -07001001 this->writeExpression(*p.fOperand, kPrefix_Precedence);
1002 if (kPrefix_Precedence >= parentPrecedence) {
1003 this->write(")");
1004 }
1005}
1006
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001007void GLSLCodeGenerator::writePostfixExpression(const PostfixExpression& p,
ethannicholasf789b382016-08-03 12:43:36 -07001008 Precedence parentPrecedence) {
1009 if (kPostfix_Precedence >= parentPrecedence) {
1010 this->write("(");
1011 }
1012 this->writeExpression(*p.fOperand, kPostfix_Precedence);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001013 this->write(Compiler::OperatorName(p.fOperator));
ethannicholasf789b382016-08-03 12:43:36 -07001014 if (kPostfix_Precedence >= parentPrecedence) {
1015 this->write(")");
1016 }
1017}
1018
1019void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
1020 this->write(b.fValue ? "true" : "false");
1021}
1022
1023void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001024 const Type& type = i.type();
1025 if (type == *fContext.fUInt_Type) {
ethannicholas5961bc92016-10-12 06:39:56 -07001026 this->write(to_string(i.fValue & 0xffffffff) + "u");
Ethan Nicholas30d30222020-09-11 12:27:26 -04001027 } else if (type == *fContext.fUShort_Type) {
Ethan Nicholas58d56482017-12-19 09:29:22 -05001028 this->write(to_string(i.fValue & 0xffff) + "u");
Ethan Nicholas30d30222020-09-11 12:27:26 -04001029 } else if (type == *fContext.fUByte_Type) {
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001030 this->write(to_string(i.fValue & 0xff) + "u");
1031 } else {
ethannicholas5961bc92016-10-12 06:39:56 -07001032 this->write(to_string((int32_t) i.fValue));
1033 }
ethannicholasf789b382016-08-03 12:43:36 -07001034}
1035
1036void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
1037 this->write(to_string(f.fValue));
1038}
1039
Ethan Nicholas762466e2017-06-29 10:03:38 -04001040void GLSLCodeGenerator::writeSetting(const Setting& s) {
1041 ABORT("internal error; setting was not folded to a constant during compilation\n");
1042}
1043
ethannicholasf789b382016-08-03 12:43:36 -07001044void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
Ethan Nicholasc6dce5a2019-07-24 16:51:36 -04001045 fSetupFragPositionLocal = false;
1046 fSetupFragCoordWorkaround = false;
John Stilesfffe3842020-09-02 15:44:18 -04001047
1048 // The pipeline-stage code generator can't use functions written this way, so make sure we don't
1049 // accidentally end up here.
1050 SkASSERT(fProgramKind != Program::kPipelineStage_Kind);
1051
1052 this->writeTypePrecision(f.fDeclaration.fReturnType);
1053 this->writeType(f.fDeclaration.fReturnType);
1054 this->write(" " + f.fDeclaration.fName + "(");
1055 const char* separator = "";
1056 for (const auto& param : f.fDeclaration.fParameters) {
1057 this->write(separator);
1058 separator = ", ";
1059 this->writeModifiers(param->fModifiers, false);
1060 std::vector<int> sizes;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001061 const Type* type = &param->type();
Ethan Nicholase6592142020-09-08 10:22:09 -04001062 while (type->typeKind() == Type::TypeKind::kArray) {
John Stilesfffe3842020-09-02 15:44:18 -04001063 sizes.push_back(type->columns());
1064 type = &type->componentType();
1065 }
1066 this->writeTypePrecision(*type);
1067 this->writeType(*type);
1068 this->write(" " + param->fName);
1069 for (int s : sizes) {
1070 if (s <= 0) {
1071 this->write("[]");
1072 } else {
1073 this->write("[" + to_string(s) + "]");
ethannicholas5961bc92016-10-12 06:39:56 -07001074 }
1075 }
ethannicholasf789b382016-08-03 12:43:36 -07001076 }
John Stilesfffe3842020-09-02 15:44:18 -04001077 this->writeLine(") {");
1078 fIndentation++;
1079
ethannicholas5961bc92016-10-12 06:39:56 -07001080 fFunctionHeader = "";
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001081 OutputStream* oldOut = fOut;
1082 StringStream buffer;
ethannicholas5961bc92016-10-12 06:39:56 -07001083 fOut = &buffer;
John Stiles3dc0da62020-08-19 17:48:31 -04001084 this->writeStatements(f.fBody->as<Block>().fStatements);
John Stilesfffe3842020-09-02 15:44:18 -04001085
1086 fIndentation--;
1087 this->writeLine("}");
ethannicholas5961bc92016-10-12 06:39:56 -07001088
1089 fOut = oldOut;
1090 this->write(fFunctionHeader);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001091 this->write(buffer.str());
ethannicholasf789b382016-08-03 12:43:36 -07001092}
1093
Greg Daniel64773e62016-11-22 09:44:03 -05001094void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
ethannicholas5961bc92016-10-12 06:39:56 -07001095 bool globalContext) {
Brian Salomonf9f45122016-11-29 11:59:17 -05001096 if (modifiers.fFlags & Modifiers::kFlat_Flag) {
1097 this->write("flat ");
1098 }
ethannicholas5961bc92016-10-12 06:39:56 -07001099 if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
1100 this->write("noperspective ");
1101 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001102 String layout = modifiers.fLayout.description();
Ethan Nicholas8da9e942017-03-09 16:35:09 -05001103 if (layout.size()) {
1104 this->write(layout + " ");
1105 }
Brian Salomonf9f45122016-11-29 11:59:17 -05001106 if (modifiers.fFlags & Modifiers::kReadOnly_Flag) {
1107 this->write("readonly ");
1108 }
1109 if (modifiers.fFlags & Modifiers::kWriteOnly_Flag) {
1110 this->write("writeonly ");
1111 }
1112 if (modifiers.fFlags & Modifiers::kCoherent_Flag) {
1113 this->write("coherent ");
1114 }
1115 if (modifiers.fFlags & Modifiers::kVolatile_Flag) {
1116 this->write("volatile ");
1117 }
1118 if (modifiers.fFlags & Modifiers::kRestrict_Flag) {
1119 this->write("restrict ");
ethannicholas5961bc92016-10-12 06:39:56 -07001120 }
Greg Daniel64773e62016-11-22 09:44:03 -05001121 if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
ethannicholas5961bc92016-10-12 06:39:56 -07001122 (modifiers.fFlags & Modifiers::kOut_Flag)) {
1123 this->write("inout ");
1124 } else if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001125 if (globalContext &&
1126 fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
ethannicholas5961bc92016-10-12 06:39:56 -07001127 this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
1128 : "varying ");
1129 } else {
1130 this->write("in ");
1131 }
1132 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001133 if (globalContext &&
1134 fProgram.fSettings.fCaps->generation() < GrGLSLGeneration::k130_GrGLSLGeneration) {
ethannicholas5961bc92016-10-12 06:39:56 -07001135 this->write("varying ");
1136 } else {
1137 this->write("out ");
1138 }
1139 }
1140 if (modifiers.fFlags & Modifiers::kUniform_Flag) {
1141 this->write("uniform ");
1142 }
1143 if (modifiers.fFlags & Modifiers::kConst_Flag) {
1144 this->write("const ");
1145 }
Ethan Nicholasa7ceb502019-01-11 10:31:48 -05001146 if (modifiers.fFlags & Modifiers::kPLS_Flag) {
1147 this->write("__pixel_localEXT ");
1148 }
1149 if (modifiers.fFlags & Modifiers::kPLSIn_Flag) {
1150 this->write("__pixel_local_inEXT ");
1151 }
1152 if (modifiers.fFlags & Modifiers::kPLSOut_Flag) {
1153 this->write("__pixel_local_outEXT ");
1154 }
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001155 switch (modifiers.fLayout.fFormat) {
1156 case Layout::Format::kUnspecified:
1157 break;
Robert Phillipsebab03f2019-07-22 08:48:18 -04001158 case Layout::Format::kRGBA32F: // fall through
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001159 case Layout::Format::kR32F:
ethannicholas5961bc92016-10-12 06:39:56 -07001160 this->write("highp ");
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001161 break;
Robert Phillipsebab03f2019-07-22 08:48:18 -04001162 case Layout::Format::kRGBA16F: // fall through
1163 case Layout::Format::kR16F: // fall through
1164 case Layout::Format::kLUMINANCE16F: // fall through
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001165 case Layout::Format::kRG16F:
1166 this->write("mediump ");
1167 break;
Robert Phillipsebab03f2019-07-22 08:48:18 -04001168 case Layout::Format::kRGBA8: // fall through
1169 case Layout::Format::kR8: // fall through
1170 case Layout::Format::kRGBA8I: // fall through
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001171 case Layout::Format::kR8I:
1172 this->write("lowp ");
1173 break;
ethannicholas5961bc92016-10-12 06:39:56 -07001174 }
ethannicholasf789b382016-08-03 12:43:36 -07001175}
1176
1177void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
Ethan Nicholas52cad152017-02-16 16:37:32 -05001178 if (intf.fTypeName == "sk_PerVertex") {
ethannicholasf789b382016-08-03 12:43:36 -07001179 return;
1180 }
ethannicholas5961bc92016-10-12 06:39:56 -07001181 this->writeModifiers(intf.fVariable.fModifiers, true);
Ethan Nicholas50afc172017-02-16 14:49:57 -05001182 this->writeLine(intf.fTypeName + " {");
ethannicholasf789b382016-08-03 12:43:36 -07001183 fIndentation++;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001184 const Type* structType = &intf.fVariable.type();
Ethan Nicholase6592142020-09-08 10:22:09 -04001185 while (structType->typeKind() == Type::TypeKind::kArray) {
Ethan Nicholas50afc172017-02-16 14:49:57 -05001186 structType = &structType->componentType();
1187 }
1188 for (const auto& f : structType->fields()) {
ethannicholas5961bc92016-10-12 06:39:56 -07001189 this->writeModifiers(f.fModifiers, false);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001190 this->writeTypePrecision(*f.fType);
ethannicholas0730be72016-09-01 07:59:02 -07001191 this->writeType(*f.fType);
ethannicholasf789b382016-08-03 12:43:36 -07001192 this->writeLine(" " + f.fName + ";");
1193 }
1194 fIndentation--;
Ethan Nicholas50afc172017-02-16 14:49:57 -05001195 this->write("}");
1196 if (intf.fInstanceName.size()) {
1197 this->write(" ");
1198 this->write(intf.fInstanceName);
1199 for (const auto& size : intf.fSizes) {
1200 this->write("[");
1201 if (size) {
1202 this->writeExpression(*size, kTopLevel_Precedence);
1203 }
1204 this->write("]");
1205 }
1206 }
1207 this->writeLine(";");
ethannicholasf789b382016-08-03 12:43:36 -07001208}
1209
Ethan Nicholas762466e2017-06-29 10:03:38 -04001210void GLSLCodeGenerator::writeVarInitializer(const Variable& var, const Expression& value) {
1211 this->writeExpression(value, kTopLevel_Precedence);
1212}
1213
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001214const char* GLSLCodeGenerator::getTypePrecision(const Type& type) {
1215 if (usesPrecisionModifiers()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001216 switch (type.typeKind()) {
1217 case Type::TypeKind::kScalar:
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001218 if (type == *fContext.fShort_Type || type == *fContext.fUShort_Type ||
1219 type == *fContext.fByte_Type || type == *fContext.fUByte_Type) {
Chris Daltonc2d0dd62018-03-07 07:46:10 -07001220 if (fProgram.fSettings.fForceHighPrecision ||
1221 fProgram.fSettings.fCaps->incompleteShortIntPrecision()) {
1222 return "highp ";
1223 }
1224 return "mediump ";
1225 }
1226 if (type == *fContext.fHalf_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001227 return fProgram.fSettings.fForceHighPrecision ? "highp " : "mediump ";
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001228 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001229 if (type == *fContext.fFloat_Type || type == *fContext.fInt_Type ||
1230 type == *fContext.fUInt_Type) {
1231 return "highp ";
1232 }
1233 return "";
Ethan Nicholase6592142020-09-08 10:22:09 -04001234 case Type::TypeKind::kVector: // fall through
1235 case Type::TypeKind::kMatrix:
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001236 return this->getTypePrecision(type.componentType());
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001237 default:
1238 break;
1239 }
1240 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001241 return "";
1242}
1243
1244void GLSLCodeGenerator::writeTypePrecision(const Type& type) {
1245 this->write(this->getTypePrecision(type));
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001246}
1247
ethannicholas5961bc92016-10-12 06:39:56 -07001248void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
Ethan Nicholas14efcbf2017-11-07 09:23:38 -05001249 if (!decl.fVars.size()) {
1250 return;
1251 }
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001252 bool wroteType = false;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001253 for (const auto& stmt : decl.fVars) {
John Stiles3dc0da62020-08-19 17:48:31 -04001254 const VarDeclaration& var = stmt->as<VarDeclaration>();
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001255 if (wroteType) {
1256 this->write(", ");
1257 } else {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001258 this->writeModifiers(var.fVar->fModifiers, global);
Ethan Nicholasdcba08e2017-08-02 10:52:54 -04001259 this->writeTypePrecision(decl.fBaseType);
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001260 this->writeType(decl.fBaseType);
1261 this->write(" ");
1262 wroteType = true;
1263 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001264 this->write(var.fVar->fName);
1265 for (const auto& size : var.fSizes) {
ethannicholasf789b382016-08-03 12:43:36 -07001266 this->write("[");
ethannicholas5961bc92016-10-12 06:39:56 -07001267 if (size) {
1268 this->writeExpression(*size, kTopLevel_Precedence);
1269 }
ethannicholasf789b382016-08-03 12:43:36 -07001270 this->write("]");
1271 }
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001272 if (var.fValue) {
ethannicholasf789b382016-08-03 12:43:36 -07001273 this->write(" = ");
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001274 this->writeVarInitializer(*var.fVar, *var.fValue);
ethannicholasf789b382016-08-03 12:43:36 -07001275 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001276 if (!fFoundExternalSamplerDecl && var.fVar->type() == *fContext.fSamplerExternalOES_Type) {
Brian Osman4b2f9152018-04-17 11:19:57 -04001277 if (fProgram.fSettings.fCaps->externalTextureExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001278 this->writeExtension(fProgram.fSettings.fCaps->externalTextureExtensionString());
Brian Osman4b2f9152018-04-17 11:19:57 -04001279 }
Brian Osman061020e2018-04-17 14:22:15 -04001280 if (fProgram.fSettings.fCaps->secondExternalTextureExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001281 this->writeExtension(
1282 fProgram.fSettings.fCaps->secondExternalTextureExtensionString());
Brian Osman061020e2018-04-17 14:22:15 -04001283 }
Brian Osman4b2f9152018-04-17 11:19:57 -04001284 fFoundExternalSamplerDecl = true;
1285 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001286 if (!fFoundRectSamplerDecl && var.fVar->type() == *fContext.fSampler2DRect_Type) {
Brian Salomon67529b22019-08-13 15:31:04 -04001287 fFoundRectSamplerDecl = true;
1288 }
ethannicholasf789b382016-08-03 12:43:36 -07001289 }
Ethan Nicholasb4dc4192017-06-02 10:16:28 -04001290 if (wroteType) {
1291 this->write(";");
1292 }
ethannicholasf789b382016-08-03 12:43:36 -07001293}
1294
1295void GLSLCodeGenerator::writeStatement(const Statement& s) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001296 switch (s.kind()) {
1297 case Statement::Kind::kBlock:
John Stiles3dc0da62020-08-19 17:48:31 -04001298 this->writeBlock(s.as<Block>());
ethannicholasf789b382016-08-03 12:43:36 -07001299 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001300 case Statement::Kind::kExpression:
John Stiles26f98502020-08-18 09:30:51 -04001301 this->writeExpression(*s.as<ExpressionStatement>().fExpression, kTopLevel_Precedence);
ethannicholasf789b382016-08-03 12:43:36 -07001302 this->write(";");
1303 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001304 case Statement::Kind::kReturn:
John Stiles26f98502020-08-18 09:30:51 -04001305 this->writeReturnStatement(s.as<ReturnStatement>());
ethannicholasf789b382016-08-03 12:43:36 -07001306 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001307 case Statement::Kind::kVarDeclarations:
John Stiles26f98502020-08-18 09:30:51 -04001308 this->writeVarDeclarations(*s.as<VarDeclarationsStatement>().fDeclaration, false);
ethannicholasf789b382016-08-03 12:43:36 -07001309 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001310 case Statement::Kind::kIf:
John Stiles26f98502020-08-18 09:30:51 -04001311 this->writeIfStatement(s.as<IfStatement>());
ethannicholasf789b382016-08-03 12:43:36 -07001312 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001313 case Statement::Kind::kFor:
John Stiles26f98502020-08-18 09:30:51 -04001314 this->writeForStatement(s.as<ForStatement>());
ethannicholasf789b382016-08-03 12:43:36 -07001315 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001316 case Statement::Kind::kWhile:
John Stiles26f98502020-08-18 09:30:51 -04001317 this->writeWhileStatement(s.as<WhileStatement>());
ethannicholasf789b382016-08-03 12:43:36 -07001318 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001319 case Statement::Kind::kDo:
John Stiles26f98502020-08-18 09:30:51 -04001320 this->writeDoStatement(s.as<DoStatement>());
ethannicholasf789b382016-08-03 12:43:36 -07001321 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001322 case Statement::Kind::kSwitch:
John Stiles26f98502020-08-18 09:30:51 -04001323 this->writeSwitchStatement(s.as<SwitchStatement>());
Ethan Nicholasaf197692017-02-27 13:26:45 -05001324 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001325 case Statement::Kind::kBreak:
ethannicholasf789b382016-08-03 12:43:36 -07001326 this->write("break;");
1327 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001328 case Statement::Kind::kContinue:
ethannicholasf789b382016-08-03 12:43:36 -07001329 this->write("continue;");
1330 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001331 case Statement::Kind::kDiscard:
ethannicholasf789b382016-08-03 12:43:36 -07001332 this->write("discard;");
1333 break;
John Stiles98c1f822020-09-09 14:18:53 -04001334 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -04001335 case Statement::Kind::kNop:
Ethan Nicholascb670962017-04-20 19:31:52 -04001336 this->write(";");
1337 break;
ethannicholasf789b382016-08-03 12:43:36 -07001338 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001339#ifdef SK_DEBUG
ethannicholasf789b382016-08-03 12:43:36 -07001340 ABORT("unsupported statement: %s", s.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001341#endif
1342 break;
ethannicholasf789b382016-08-03 12:43:36 -07001343 }
1344}
1345
Ethan Nicholascb670962017-04-20 19:31:52 -04001346void GLSLCodeGenerator::writeStatements(const std::vector<std::unique_ptr<Statement>>& statements) {
1347 for (const auto& s : statements) {
1348 if (!s->isEmpty()) {
1349 this->writeStatement(*s);
1350 this->writeLine();
1351 }
1352 }
1353}
1354
ethannicholasf789b382016-08-03 12:43:36 -07001355void GLSLCodeGenerator::writeBlock(const Block& b) {
Ethan Nicholas70728ef2020-05-28 07:09:00 -04001356 if (b.fIsScope) {
1357 this->writeLine("{");
1358 fIndentation++;
1359 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001360 this->writeStatements(b.fStatements);
Ethan Nicholas70728ef2020-05-28 07:09:00 -04001361 if (b.fIsScope) {
1362 fIndentation--;
1363 this->write("}");
1364 }
ethannicholasf789b382016-08-03 12:43:36 -07001365}
1366
1367void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) {
1368 this->write("if (");
1369 this->writeExpression(*stmt.fTest, kTopLevel_Precedence);
1370 this->write(") ");
1371 this->writeStatement(*stmt.fIfTrue);
1372 if (stmt.fIfFalse) {
1373 this->write(" else ");
1374 this->writeStatement(*stmt.fIfFalse);
1375 }
1376}
1377
1378void GLSLCodeGenerator::writeForStatement(const ForStatement& f) {
1379 this->write("for (");
Ethan Nicholasb310fd52017-06-09 13:46:34 -04001380 if (f.fInitializer && !f.fInitializer->isEmpty()) {
ethannicholasf789b382016-08-03 12:43:36 -07001381 this->writeStatement(*f.fInitializer);
1382 } else {
1383 this->write("; ");
1384 }
1385 if (f.fTest) {
Adrienne Walkeree8295c2018-08-21 10:56:30 -07001386 if (fProgram.fSettings.fCaps->addAndTrueToLoopCondition()) {
1387 std::unique_ptr<Expression> and_true(new BinaryExpression(
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04001388 -1, f.fTest->clone(), Token::Kind::TK_LOGICALAND,
John Stilesfbd050b2020-08-03 13:21:46 -04001389 std::make_unique<BoolLiteral>(fContext, -1, true),
Ethan Nicholas30d30222020-09-11 12:27:26 -04001390 fContext.fBool_Type.get()));
Adrienne Walkeree8295c2018-08-21 10:56:30 -07001391 this->writeExpression(*and_true, kTopLevel_Precedence);
1392 } else {
1393 this->writeExpression(*f.fTest, kTopLevel_Precedence);
1394 }
ethannicholasf789b382016-08-03 12:43:36 -07001395 }
1396 this->write("; ");
1397 if (f.fNext) {
1398 this->writeExpression(*f.fNext, kTopLevel_Precedence);
1399 }
1400 this->write(") ");
1401 this->writeStatement(*f.fStatement);
1402}
1403
1404void GLSLCodeGenerator::writeWhileStatement(const WhileStatement& w) {
1405 this->write("while (");
1406 this->writeExpression(*w.fTest, kTopLevel_Precedence);
1407 this->write(") ");
1408 this->writeStatement(*w.fStatement);
1409}
1410
1411void GLSLCodeGenerator::writeDoStatement(const DoStatement& d) {
Adrienne Walker8b23ca62018-08-22 10:45:41 -07001412 if (!fProgram.fSettings.fCaps->rewriteDoWhileLoops()) {
1413 this->write("do ");
1414 this->writeStatement(*d.fStatement);
1415 this->write(" while (");
1416 this->writeExpression(*d.fTest, kTopLevel_Precedence);
1417 this->write(");");
1418 return;
1419 }
1420
1421 // Otherwise, do the do while loop workaround, to rewrite loops of the form:
1422 // do {
1423 // CODE;
1424 // } while (CONDITION)
1425 //
1426 // to loops of the form
1427 // bool temp = false;
1428 // while (true) {
1429 // if (temp) {
1430 // if (!CONDITION) {
1431 // break;
1432 // }
1433 // }
1434 // temp = true;
1435 // CODE;
1436 // }
1437 String tmpVar = "_tmpLoopSeenOnce" + to_string(fVarCount++);
1438 this->write("bool ");
1439 this->write(tmpVar);
1440 this->writeLine(" = false;");
1441 this->writeLine("while (true) {");
1442 fIndentation++;
1443 this->write("if (");
1444 this->write(tmpVar);
1445 this->writeLine(") {");
1446 fIndentation++;
1447 this->write("if (!");
1448 this->writeExpression(*d.fTest, kPrefix_Precedence);
1449 this->writeLine(") {");
1450 fIndentation++;
1451 this->writeLine("break;");
1452 fIndentation--;
1453 this->writeLine("}");
1454 fIndentation--;
1455 this->writeLine("}");
1456 this->write(tmpVar);
1457 this->writeLine(" = true;");
ethannicholasf789b382016-08-03 12:43:36 -07001458 this->writeStatement(*d.fStatement);
Adrienne Walker8b23ca62018-08-22 10:45:41 -07001459 this->writeLine();
1460 fIndentation--;
1461 this->write("}");
ethannicholasf789b382016-08-03 12:43:36 -07001462}
1463
Ethan Nicholasaf197692017-02-27 13:26:45 -05001464void GLSLCodeGenerator::writeSwitchStatement(const SwitchStatement& s) {
1465 this->write("switch (");
1466 this->writeExpression(*s.fValue, kTopLevel_Precedence);
1467 this->writeLine(") {");
1468 fIndentation++;
1469 for (const auto& c : s.fCases) {
1470 if (c->fValue) {
1471 this->write("case ");
1472 this->writeExpression(*c->fValue, kTopLevel_Precedence);
1473 this->writeLine(":");
1474 } else {
1475 this->writeLine("default:");
1476 }
1477 fIndentation++;
1478 for (const auto& stmt : c->fStatements) {
1479 this->writeStatement(*stmt);
1480 this->writeLine();
1481 }
1482 fIndentation--;
1483 }
1484 fIndentation--;
1485 this->write("}");
1486}
1487
ethannicholasf789b382016-08-03 12:43:36 -07001488void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
1489 this->write("return");
1490 if (r.fExpression) {
1491 this->write(" ");
1492 this->writeExpression(*r.fExpression, kTopLevel_Precedence);
1493 }
1494 this->write(";");
1495}
1496
Ethan Nicholas762466e2017-06-29 10:03:38 -04001497void GLSLCodeGenerator::writeHeader() {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001498 this->write(fProgram.fSettings.fCaps->versionDeclString());
ethannicholasf789b382016-08-03 12:43:36 -07001499 this->writeLine();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001500}
1501
Ethan Nicholas762466e2017-06-29 10:03:38 -04001502void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001503 switch (e.kind()) {
1504 case ProgramElement::Kind::kExtension:
John Stiles3dc0da62020-08-19 17:48:31 -04001505 this->writeExtension(e.as<Extension>().fName);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001506 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001507 case ProgramElement::Kind::kVar: {
John Stiles3dc0da62020-08-19 17:48:31 -04001508 const VarDeclarations& decl = e.as<VarDeclarations>();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001509 if (decl.fVars.size() > 0) {
John Stiles3dc0da62020-08-19 17:48:31 -04001510 int builtin = decl.fVars[0]->as<VarDeclaration>().fVar->fModifiers.fLayout.fBuiltin;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001511 if (builtin == -1) {
1512 // normal var
1513 this->writeVarDeclarations(decl, true);
1514 this->writeLine();
1515 } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
Ethan Nicholasa7ceb502019-01-11 10:31:48 -05001516 fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput() &&
John Stiles3dc0da62020-08-19 17:48:31 -04001517 decl.fVars[0]->as<VarDeclaration>().fVar->fWriteCount) {
Brian Salomondc092132018-04-04 10:14:16 -04001518 if (fProgram.fSettings.fFragColorIsInOut) {
1519 this->write("inout ");
1520 } else {
1521 this->write("out ");
1522 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001523 if (usesPrecisionModifiers()) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001524 this->write("mediump ");
Mike Klein5ce39722017-06-27 22:52:03 +00001525 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001526 this->writeLine("vec4 sk_FragColor;");
Mike Klein5ce39722017-06-27 22:52:03 +00001527 }
Mike Klein5ce39722017-06-27 22:52:03 +00001528 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001529 break;
Mike Klein5ce39722017-06-27 22:52:03 +00001530 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001531 case ProgramElement::Kind::kInterfaceBlock:
John Stiles3dc0da62020-08-19 17:48:31 -04001532 this->writeInterfaceBlock(e.as<InterfaceBlock>());
Ethan Nicholas762466e2017-06-29 10:03:38 -04001533 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001534 case ProgramElement::Kind::kFunction:
John Stiles3dc0da62020-08-19 17:48:31 -04001535 this->writeFunction(e.as<FunctionDefinition>());
Ethan Nicholas762466e2017-06-29 10:03:38 -04001536 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001537 case ProgramElement::Kind::kModifiers: {
John Stiles3dc0da62020-08-19 17:48:31 -04001538 const Modifiers& modifiers = e.as<ModifiersDeclaration>().fModifiers;
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001539 if (!fFoundGSInvocations && modifiers.fLayout.fInvocations >= 0) {
1540 if (fProgram.fSettings.fCaps->gsInvocationsExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001541 this->writeExtension(fProgram.fSettings.fCaps->gsInvocationsExtensionString());
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001542 }
1543 fFoundGSInvocations = true;
1544 }
1545 this->writeModifiers(modifiers, true);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001546 this->writeLine(";");
1547 break;
Chris Daltonf1b47bb2017-10-06 11:57:51 -06001548 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001549 case ProgramElement::Kind::kEnum:
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001550 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001551 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001552#ifdef SK_DEBUG
1553 printf("unsupported program element %s\n", e.description().c_str());
1554#endif
1555 SkASSERT(false);
Ethan Nicholasc0709392017-06-27 11:20:22 -04001556 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001557}
1558
Ethan Nicholascd700e92018-08-24 16:43:57 -04001559void GLSLCodeGenerator::writeInputVars() {
1560 if (fProgram.fInputs.fRTWidth) {
1561 const char* precision = usesPrecisionModifiers() ? "highp " : "";
1562 fGlobals.writeText("uniform ");
1563 fGlobals.writeText(precision);
1564 fGlobals.writeText("float " SKSL_RTWIDTH_NAME ";\n");
1565 }
1566 if (fProgram.fInputs.fRTHeight) {
1567 const char* precision = usesPrecisionModifiers() ? "highp " : "";
1568 fGlobals.writeText("uniform ");
1569 fGlobals.writeText(precision);
1570 fGlobals.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
1571 }
1572}
1573
Ethan Nicholas762466e2017-06-29 10:03:38 -04001574bool GLSLCodeGenerator::generateCode() {
John Stilesfffe3842020-09-02 15:44:18 -04001575 this->writeHeader();
Chris Dalton8fd79552018-01-11 00:46:14 -05001576 if (Program::kGeometry_Kind == fProgramKind &&
1577 fProgram.fSettings.fCaps->geometryShaderExtensionString()) {
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001578 this->writeExtension(fProgram.fSettings.fCaps->geometryShaderExtensionString());
Chris Dalton8fd79552018-01-11 00:46:14 -05001579 }
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001580 OutputStream* rawOut = fOut;
Ethan Nicholas762466e2017-06-29 10:03:38 -04001581 StringStream body;
1582 fOut = &body;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04001583 for (const auto& e : fProgram) {
1584 this->writeProgramElement(e);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001585 }
1586 fOut = rawOut;
ethannicholasddb37d62016-10-20 09:54:00 -07001587
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001588 write_stringstream(fExtensions, *rawOut);
Ethan Nicholascd700e92018-08-24 16:43:57 -04001589 this->writeInputVars();
Ethan Nicholas88f6d372018-07-27 10:03:46 -04001590 write_stringstream(fGlobals, *rawOut);
Brian Osmancc10d792018-07-20 13:09:45 -04001591
1592 if (!fProgram.fSettings.fCaps->canUseFragCoord()) {
1593 Layout layout;
1594 switch (fProgram.fKind) {
1595 case Program::kVertex_Kind: {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001596 Modifiers modifiers(layout, Modifiers::kOut_Flag);
Brian Osmancc10d792018-07-20 13:09:45 -04001597 this->writeModifiers(modifiers, true);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001598 if (this->usesPrecisionModifiers()) {
1599 this->write("highp ");
1600 }
Brian Osmancc10d792018-07-20 13:09:45 -04001601 this->write("vec4 sk_FragCoord_Workaround;\n");
1602 break;
1603 }
1604 case Program::kFragment_Kind: {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001605 Modifiers modifiers(layout, Modifiers::kIn_Flag);
Brian Osmancc10d792018-07-20 13:09:45 -04001606 this->writeModifiers(modifiers, true);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001607 if (this->usesPrecisionModifiers()) {
1608 this->write("highp ");
1609 }
Brian Osmancc10d792018-07-20 13:09:45 -04001610 this->write("vec4 sk_FragCoord_Workaround;\n");
1611 break;
1612 }
1613 default:
1614 break;
1615 }
1616 }
1617
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001618 if (this->usesPrecisionModifiers()) {
1619 this->writeLine("precision mediump float;");
Brian Salomon67529b22019-08-13 15:31:04 -04001620 this->writeLine("precision mediump sampler2D;");
Brian Salomon5a5f3e82019-08-16 15:05:40 -04001621 if (fFoundExternalSamplerDecl &&
1622 !fProgram.fSettings.fCaps->noDefaultPrecisionForExternalSamplers()) {
Brian Salomon67529b22019-08-13 15:31:04 -04001623 this->writeLine("precision mediump samplerExternalOES;");
1624 }
1625 if (fFoundRectSamplerDecl) {
1626 this->writeLine("precision mediump sampler2DRect;");
1627 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001628 }
Ethan Nicholas6e6525c2018-01-03 17:03:56 -05001629 write_stringstream(fExtraFunctions, *rawOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001630 write_stringstream(body, *rawOut);
Brian Osman3000d6b2020-07-31 15:57:28 -04001631 return 0 == fErrors.errorCount();
ethannicholasf789b382016-08-03 12:43:36 -07001632}
1633
John Stilesa6841be2020-08-06 14:11:56 -04001634} // namespace SkSL