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