blob: 1830b173a1252c3aa6d1bd0bf1151cfef439c288 [file] [log] [blame]
zmo@google.com5601ea02011-06-10 18:23:25 +00001//
Jamie Madill02f20dd2013-09-12 12:07:42 -04002// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
zmo@google.com5601ea02011-06-10 18:23:25 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Geoff Lang17732822013-08-29 13:46:49 -04007#include "compiler/translator/OutputGLSLBase.h"
8#include "compiler/translator/compilerdebug.h"
zmo@google.com5601ea02011-06-10 18:23:25 +00009
daniel@transgaming.com773ff742013-01-11 04:12:51 +000010#include <cfloat>
daniel@transgaming.com6c1203f2013-01-11 04:12:43 +000011
zmo@google.com5601ea02011-06-10 18:23:25 +000012namespace
13{
zmo@google.com5601ea02011-06-10 18:23:25 +000014TString arrayBrackets(const TType& type)
15{
16 ASSERT(type.isArray());
17 TInfoSinkBase out;
18 out << "[" << type.getArraySize() << "]";
19 return TString(out.c_str());
20}
21
22bool isSingleStatement(TIntermNode* node) {
23 if (const TIntermAggregate* aggregate = node->getAsAggregate())
24 {
25 return (aggregate->getOp() != EOpFunction) &&
26 (aggregate->getOp() != EOpSequence);
27 }
28 else if (const TIntermSelection* selection = node->getAsSelectionNode())
29 {
30 // Ternary operators are usually part of an assignment operator.
31 // This handles those rare cases in which they are all by themselves.
32 return selection->usesTernaryOperator();
33 }
34 else if (node->getAsLoopNode())
35 {
36 return false;
37 }
38 return true;
39}
40} // namespace
41
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000042TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase& objSink,
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000043 ShArrayIndexClampingStrategy clampingStrategy,
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000044 ShHashFunction64 hashFunction,
45 NameMap& nameMap,
Jamie Madill02f20dd2013-09-12 12:07:42 -040046 TSymbolTable& symbolTable,
47 int shaderVersion)
zmo@google.com5601ea02011-06-10 18:23:25 +000048 : TIntermTraverser(true, true, true),
49 mObjSink(objSink),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000050 mDeclaringVariables(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000051 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000052 mHashFunction(hashFunction),
53 mNameMap(nameMap),
Jamie Madill02f20dd2013-09-12 12:07:42 -040054 mSymbolTable(symbolTable),
55 mShaderVersion(shaderVersion)
zmo@google.com5601ea02011-06-10 18:23:25 +000056{
Zhenyao Mo904a9162014-05-09 14:07:45 -070057 // Set up global scope.
58 mDeclaredStructs.push_back(ScopedDeclaredStructs());
zmo@google.com5601ea02011-06-10 18:23:25 +000059}
60
61void TOutputGLSLBase::writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr)
62{
63 TInfoSinkBase& out = objSink();
64 if (visit == PreVisit && preStr)
65 {
66 out << preStr;
67 }
68 else if (visit == InVisit && inStr)
69 {
70 out << inStr;
71 }
72 else if (visit == PostVisit && postStr)
73 {
74 out << postStr;
75 }
76}
77
78void TOutputGLSLBase::writeVariableType(const TType& type)
79{
80 TInfoSinkBase& out = objSink();
81 TQualifier qualifier = type.getQualifier();
82 // TODO(alokp): Validate qualifier for variable declarations.
83 if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal))
84 out << type.getQualifierString() << " ";
85 // Declare the struct if we have not done so already.
Jamie Madill98493dd2013-07-08 14:39:03 -040086 if ((type.getBasicType() == EbtStruct) && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +000087 {
Jamie Madill98493dd2013-07-08 14:39:03 -040088 declareStruct(type.getStruct());
Zhenyao Mo904a9162014-05-09 14:07:45 -070089 mDeclaredStructs[mDeclaredStructs.size() - 1].push_back(type.getStruct());
zmo@google.com5601ea02011-06-10 18:23:25 +000090 }
91 else
92 {
93 if (writeVariablePrecision(type.getPrecision()))
94 out << " ";
95 out << getTypeName(type);
96 }
97}
98
99void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence& args)
100{
101 TInfoSinkBase& out = objSink();
102 for (TIntermSequence::const_iterator iter = args.begin();
103 iter != args.end(); ++iter)
104 {
105 const TIntermSymbol* arg = (*iter)->getAsSymbolNode();
106 ASSERT(arg != NULL);
107
108 const TType& type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000109 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000110
111 const TString& name = arg->getSymbol();
112 if (!name.empty())
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000113 out << " " << hashName(name);
zmo@google.com5601ea02011-06-10 18:23:25 +0000114 if (type.isArray())
115 out << arrayBrackets(type);
116
117 // Put a comma if this is not the last argument.
118 if (iter != args.end() - 1)
119 out << ", ";
120 }
121}
122
123const ConstantUnion* TOutputGLSLBase::writeConstantUnion(const TType& type,
124 const ConstantUnion* pConstUnion)
125{
126 TInfoSinkBase& out = objSink();
127
128 if (type.getBasicType() == EbtStruct)
129 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400130 const TStructure* structure = type.getStruct();
131 out << hashName(structure->name()) << "(";
132
133 const TFieldList& fields = structure->fields();
134 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000135 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400136 const TType* fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000137 ASSERT(fieldType != NULL);
138 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Jamie Madill98493dd2013-07-08 14:39:03 -0400139 if (i != fields.size() - 1) out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000140 }
141 out << ")";
142 }
143 else
144 {
Jamie Madill94bf7f22013-07-08 13:31:15 -0400145 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000146 bool writeType = size > 1;
147 if (writeType) out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400148 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000149 {
150 switch (pConstUnion->getType())
151 {
daniel@transgaming.com6c1203f2013-01-11 04:12:43 +0000152 case EbtFloat: out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst())); break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000153 case EbtInt: out << pConstUnion->getIConst(); break;
154 case EbtBool: out << pConstUnion->getBConst(); break;
155 default: UNREACHABLE();
156 }
157 if (i != size - 1) out << ", ";
158 }
159 if (writeType) out << ")";
160 }
161 return pConstUnion;
162}
163
164void TOutputGLSLBase::visitSymbol(TIntermSymbol* node)
165{
166 TInfoSinkBase& out = objSink();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800167 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
168 out << mLoopUnrollStack.getLoopIndexValue(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000169 else
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000170 out << hashVariableName(node->getSymbol());
zmo@google.com5601ea02011-06-10 18:23:25 +0000171
172 if (mDeclaringVariables && node->getType().isArray())
173 out << arrayBrackets(node->getType());
174}
175
176void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion* node)
177{
178 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
179}
180
181bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary* node)
182{
183 bool visitChildren = true;
184 TInfoSinkBase& out = objSink();
185 switch (node->getOp())
186 {
187 case EOpInitialize:
188 if (visit == InVisit)
189 {
190 out << " = ";
191 // RHS of initialize is not being declared.
192 mDeclaringVariables = false;
193 }
194 break;
195 case EOpAssign: writeTriplet(visit, "(", " = ", ")"); break;
196 case EOpAddAssign: writeTriplet(visit, "(", " += ", ")"); break;
197 case EOpSubAssign: writeTriplet(visit, "(", " -= ", ")"); break;
198 case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break;
199 // Notice the fall-through.
200 case EOpMulAssign:
201 case EOpVectorTimesMatrixAssign:
202 case EOpVectorTimesScalarAssign:
203 case EOpMatrixTimesScalarAssign:
204 case EOpMatrixTimesMatrixAssign:
205 writeTriplet(visit, "(", " *= ", ")");
206 break;
207
208 case EOpIndexDirect:
zmo@google.com5601ea02011-06-10 18:23:25 +0000209 writeTriplet(visit, NULL, "[", "]");
210 break;
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000211 case EOpIndexIndirect:
212 if (node->getAddIndexClamp())
213 {
214 if (visit == InVisit)
215 {
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000216 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) {
217 out << "[int(clamp(float(";
218 } else {
219 out << "[webgl_int_clamp(";
220 }
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000221 }
222 else if (visit == PostVisit)
223 {
224 int maxSize;
225 TIntermTyped *left = node->getLeft();
226 TType leftType = left->getType();
227
228 if (left->isArray())
229 {
230 // The shader will fail validation if the array length is not > 0.
231 maxSize = leftType.getArraySize() - 1;
232 }
233 else
234 {
235 maxSize = leftType.getNominalSize() - 1;
236 }
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000237
238 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC) {
239 out << "), 0.0, float(" << maxSize << ")))]";
240 } else {
241 out << ", 0, " << maxSize << ")]";
242 }
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000243 }
244 }
245 else
246 {
247 writeTriplet(visit, NULL, "[", "]");
248 }
249 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000250 case EOpIndexDirectStruct:
251 if (visit == InVisit)
252 {
Jamie Madill98493dd2013-07-08 14:39:03 -0400253 // Here we are writing out "foo.bar", where "foo" is struct
254 // and "bar" is field. In AST, it is represented as a binary
255 // node, where left child represents "foo" and right child "bar".
256 // The node itself represents ".". The struct field "bar" is
257 // actually stored as an index into TStructure::fields.
zmo@google.com5601ea02011-06-10 18:23:25 +0000258 out << ".";
Jamie Madill98493dd2013-07-08 14:39:03 -0400259 const TStructure* structure = node->getLeft()->getType().getStruct();
260 const TIntermConstantUnion* index = node->getRight()->getAsConstantUnion();
261 const TField* field = structure->fields()[index->getIConst(0)];
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000262
Jamie Madill98493dd2013-07-08 14:39:03 -0400263 TString fieldName = field->name();
Jamie Madill02f20dd2013-09-12 12:07:42 -0400264 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000265 fieldName = hashName(fieldName);
266
267 out << fieldName;
zmo@google.com5601ea02011-06-10 18:23:25 +0000268 visitChildren = false;
269 }
270 break;
271 case EOpVectorSwizzle:
272 if (visit == InVisit)
273 {
274 out << ".";
275 TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
276 TIntermSequence& sequence = rightChild->getSequence();
277 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
278 {
279 TIntermConstantUnion* element = (*sit)->getAsConstantUnion();
280 ASSERT(element->getBasicType() == EbtInt);
281 ASSERT(element->getNominalSize() == 1);
282 const ConstantUnion& data = element->getUnionArrayPointer()[0];
283 ASSERT(data.getType() == EbtInt);
284 switch (data.getIConst())
285 {
286 case 0: out << "x"; break;
287 case 1: out << "y"; break;
288 case 2: out << "z"; break;
289 case 3: out << "w"; break;
290 default: UNREACHABLE(); break;
291 }
292 }
293 visitChildren = false;
294 }
295 break;
296
297 case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break;
298 case EOpSub: writeTriplet(visit, "(", " - ", ")"); break;
299 case EOpMul: writeTriplet(visit, "(", " * ", ")"); break;
300 case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break;
301 case EOpMod: UNIMPLEMENTED(); break;
302 case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break;
303 case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break;
304 case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break;
305 case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break;
306 case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break;
307 case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break;
308
309 // Notice the fall-through.
310 case EOpVectorTimesScalar:
311 case EOpVectorTimesMatrix:
312 case EOpMatrixTimesVector:
313 case EOpMatrixTimesScalar:
314 case EOpMatrixTimesMatrix:
315 writeTriplet(visit, "(", " * ", ")");
316 break;
317
318 case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
319 case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break;
320 case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break;
321 default: UNREACHABLE(); break;
322 }
323
324 return visitChildren;
325}
326
327bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary* node)
328{
zmo@google.com32e97312011-08-24 01:03:11 +0000329 TString preString;
330 TString postString = ")";
331
zmo@google.com5601ea02011-06-10 18:23:25 +0000332 switch (node->getOp())
333 {
zmo@google.com32e97312011-08-24 01:03:11 +0000334 case EOpNegative: preString = "(-"; break;
335 case EOpVectorLogicalNot: preString = "not("; break;
336 case EOpLogicalNot: preString = "(!"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000337
zmo@google.com32e97312011-08-24 01:03:11 +0000338 case EOpPostIncrement: preString = "("; postString = "++)"; break;
339 case EOpPostDecrement: preString = "("; postString = "--)"; break;
340 case EOpPreIncrement: preString = "(++"; break;
341 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000342
343 case EOpConvIntToBool:
344 case EOpConvFloatToBool:
345 switch (node->getOperand()->getType().getNominalSize())
346 {
zmo@google.com32e97312011-08-24 01:03:11 +0000347 case 1: preString = "bool("; break;
348 case 2: preString = "bvec2("; break;
349 case 3: preString = "bvec3("; break;
350 case 4: preString = "bvec4("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000351 default: UNREACHABLE();
352 }
353 break;
354 case EOpConvBoolToFloat:
355 case EOpConvIntToFloat:
356 switch (node->getOperand()->getType().getNominalSize())
357 {
zmo@google.com32e97312011-08-24 01:03:11 +0000358 case 1: preString = "float("; break;
359 case 2: preString = "vec2("; break;
360 case 3: preString = "vec3("; break;
361 case 4: preString = "vec4("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000362 default: UNREACHABLE();
363 }
364 break;
365 case EOpConvFloatToInt:
366 case EOpConvBoolToInt:
367 switch (node->getOperand()->getType().getNominalSize())
368 {
zmo@google.com32e97312011-08-24 01:03:11 +0000369 case 1: preString = "int("; break;
370 case 2: preString = "ivec2("; break;
371 case 3: preString = "ivec3("; break;
372 case 4: preString = "ivec4("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000373 default: UNREACHABLE();
374 }
375 break;
376
zmo@google.com32e97312011-08-24 01:03:11 +0000377 case EOpRadians: preString = "radians("; break;
378 case EOpDegrees: preString = "degrees("; break;
379 case EOpSin: preString = "sin("; break;
380 case EOpCos: preString = "cos("; break;
381 case EOpTan: preString = "tan("; break;
382 case EOpAsin: preString = "asin("; break;
383 case EOpAcos: preString = "acos("; break;
384 case EOpAtan: preString = "atan("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000385
zmo@google.com32e97312011-08-24 01:03:11 +0000386 case EOpExp: preString = "exp("; break;
387 case EOpLog: preString = "log("; break;
388 case EOpExp2: preString = "exp2("; break;
389 case EOpLog2: preString = "log2("; break;
390 case EOpSqrt: preString = "sqrt("; break;
391 case EOpInverseSqrt: preString = "inversesqrt("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000392
zmo@google.com32e97312011-08-24 01:03:11 +0000393 case EOpAbs: preString = "abs("; break;
394 case EOpSign: preString = "sign("; break;
395 case EOpFloor: preString = "floor("; break;
396 case EOpCeil: preString = "ceil("; break;
397 case EOpFract: preString = "fract("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000398
zmo@google.com32e97312011-08-24 01:03:11 +0000399 case EOpLength: preString = "length("; break;
400 case EOpNormalize: preString = "normalize("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000401
zmo@google.com32e97312011-08-24 01:03:11 +0000402 case EOpDFdx: preString = "dFdx("; break;
403 case EOpDFdy: preString = "dFdy("; break;
404 case EOpFwidth: preString = "fwidth("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000405
zmo@google.com32e97312011-08-24 01:03:11 +0000406 case EOpAny: preString = "any("; break;
407 case EOpAll: preString = "all("; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000408
409 default: UNREACHABLE(); break;
410 }
411
zmo@google.com32e97312011-08-24 01:03:11 +0000412 if (visit == PreVisit && node->getUseEmulatedFunction())
413 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
414 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
415
zmo@google.com5601ea02011-06-10 18:23:25 +0000416 return true;
417}
418
419bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection* node)
420{
421 TInfoSinkBase& out = objSink();
422
423 if (node->usesTernaryOperator())
424 {
425 // Notice two brackets at the beginning and end. The outer ones
426 // encapsulate the whole ternary expression. This preserves the
427 // order of precedence when ternary expressions are used in a
428 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
429 out << "((";
430 node->getCondition()->traverse(this);
431 out << ") ? (";
432 node->getTrueBlock()->traverse(this);
433 out << ") : (";
434 node->getFalseBlock()->traverse(this);
435 out << "))";
436 }
437 else
438 {
439 out << "if (";
440 node->getCondition()->traverse(this);
441 out << ")\n";
442
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700443 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000444 visitCodeBlock(node->getTrueBlock());
445
446 if (node->getFalseBlock())
447 {
448 out << "else\n";
449 visitCodeBlock(node->getFalseBlock());
450 }
451 decrementDepth();
452 }
453 return false;
454}
455
456bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate* node)
457{
458 bool visitChildren = true;
459 TInfoSinkBase& out = objSink();
zmo@google.comf420c422011-09-12 18:27:59 +0000460 TString preString;
461 bool delayedWrite = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000462 switch (node->getOp())
463 {
464 case EOpSequence: {
465 // Scope the sequences except when at the global scope.
Zhenyao Mo904a9162014-05-09 14:07:45 -0700466 if (depth > 0)
467 {
468 out << "{\n";
469 pushDeclaredStructsScope();
470 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000471
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700472 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000473 const TIntermSequence& sequence = node->getSequence();
474 for (TIntermSequence::const_iterator iter = sequence.begin();
475 iter != sequence.end(); ++iter)
476 {
477 TIntermNode* node = *iter;
478 ASSERT(node != NULL);
479 node->traverse(this);
480
481 if (isSingleStatement(node))
482 out << ";\n";
483 }
484 decrementDepth();
485
486 // Scope the sequences except when at the global scope.
Zhenyao Mo904a9162014-05-09 14:07:45 -0700487 if (depth > 0)
488 {
489 popDeclaredStructsScope();
490 out << "}\n";
491 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000492 visitChildren = false;
493 break;
494 }
495 case EOpPrototype: {
496 // Function declaration.
497 ASSERT(visit == PreVisit);
kbr@chromium.org57f7ce02011-08-15 23:13:05 +0000498 writeVariableType(node->getType());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000499 out << " " << hashName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000500
501 out << "(";
502 writeFunctionParameters(node->getSequence());
503 out << ")";
504
505 visitChildren = false;
506 break;
507 }
508 case EOpFunction: {
509 // Function definition.
510 ASSERT(visit == PreVisit);
zmo@google.com189be2f2011-06-16 18:28:53 +0000511 writeVariableType(node->getType());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000512 out << " " << hashFunctionName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000513
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700514 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000515 // Function definition node contains one or two children nodes
516 // representing function parameters and function body. The latter
517 // is not present in case of empty function bodies.
518 const TIntermSequence& sequence = node->getSequence();
519 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
520 TIntermSequence::const_iterator seqIter = sequence.begin();
521
522 // Traverse function parameters.
523 TIntermAggregate* params = (*seqIter)->getAsAggregate();
524 ASSERT(params != NULL);
525 ASSERT(params->getOp() == EOpParameters);
526 params->traverse(this);
527
528 // Traverse function body.
529 TIntermAggregate* body = ++seqIter != sequence.end() ?
530 (*seqIter)->getAsAggregate() : NULL;
531 visitCodeBlock(body);
532 decrementDepth();
533
534 // Fully processed; no need to visit children.
535 visitChildren = false;
536 break;
537 }
538 case EOpFunctionCall:
539 // Function call.
540 if (visit == PreVisit)
541 {
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000542 out << hashFunctionName(node->getName()) << "(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000543 }
544 else if (visit == InVisit)
545 {
546 out << ", ";
547 }
548 else
549 {
550 out << ")";
551 }
552 break;
553 case EOpParameters: {
554 // Function parameters.
555 ASSERT(visit == PreVisit);
556 out << "(";
557 writeFunctionParameters(node->getSequence());
558 out << ")";
559 visitChildren = false;
560 break;
561 }
562 case EOpDeclaration: {
563 // Variable declaration.
564 if (visit == PreVisit)
565 {
566 const TIntermSequence& sequence = node->getSequence();
567 const TIntermTyped* variable = sequence.front()->getAsTyped();
568 writeVariableType(variable->getType());
569 out << " ";
570 mDeclaringVariables = true;
571 }
572 else if (visit == InVisit)
573 {
574 out << ", ";
575 mDeclaringVariables = true;
576 }
577 else
578 {
579 mDeclaringVariables = false;
580 }
581 break;
582 }
583 case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break;
584 case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
585 case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
586 case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
587 case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break;
588 case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break;
589 case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break;
590 case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break;
591 case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break;
592 case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break;
593 case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break;
594 case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break;
595 case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break;
596 case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break;
597 case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
598 case EOpConstructStruct:
599 if (visit == PreVisit)
600 {
601 const TType& type = node->getType();
602 ASSERT(type.getBasicType() == EbtStruct);
Jamie Madill98493dd2013-07-08 14:39:03 -0400603 out << hashName(type.getStruct()->name()) << "(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000604 }
605 else if (visit == InVisit)
606 {
607 out << ", ";
608 }
609 else
610 {
611 out << ")";
612 }
613 break;
614
zmo@google.comf420c422011-09-12 18:27:59 +0000615 case EOpLessThan: preString = "lessThan("; delayedWrite = true; break;
616 case EOpGreaterThan: preString = "greaterThan("; delayedWrite = true; break;
617 case EOpLessThanEqual: preString = "lessThanEqual("; delayedWrite = true; break;
618 case EOpGreaterThanEqual: preString = "greaterThanEqual("; delayedWrite = true; break;
619 case EOpVectorEqual: preString = "equal("; delayedWrite = true; break;
620 case EOpVectorNotEqual: preString = "notEqual("; delayedWrite = true; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000621 case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break;
622
zmo@google.comf420c422011-09-12 18:27:59 +0000623 case EOpMod: preString = "mod("; delayedWrite = true; break;
624 case EOpPow: preString = "pow("; delayedWrite = true; break;
625 case EOpAtan: preString = "atan("; delayedWrite = true; break;
626 case EOpMin: preString = "min("; delayedWrite = true; break;
627 case EOpMax: preString = "max("; delayedWrite = true; break;
628 case EOpClamp: preString = "clamp("; delayedWrite = true; break;
629 case EOpMix: preString = "mix("; delayedWrite = true; break;
630 case EOpStep: preString = "step("; delayedWrite = true; break;
631 case EOpSmoothStep: preString = "smoothstep("; delayedWrite = true; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000632
zmo@google.comf420c422011-09-12 18:27:59 +0000633 case EOpDistance: preString = "distance("; delayedWrite = true; break;
634 case EOpDot: preString = "dot("; delayedWrite = true; break;
635 case EOpCross: preString = "cross("; delayedWrite = true; break;
636 case EOpFaceForward: preString = "faceforward("; delayedWrite = true; break;
637 case EOpReflect: preString = "reflect("; delayedWrite = true; break;
638 case EOpRefract: preString = "refract("; delayedWrite = true; break;
639 case EOpMul: preString = "matrixCompMult("; delayedWrite = true; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000640
641 default: UNREACHABLE(); break;
642 }
zmo@google.comf420c422011-09-12 18:27:59 +0000643 if (delayedWrite && visit == PreVisit && node->getUseEmulatedFunction())
644 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
645 if (delayedWrite)
646 writeTriplet(visit, preString.c_str(), ", ", ")");
zmo@google.com5601ea02011-06-10 18:23:25 +0000647 return visitChildren;
648}
649
650bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node)
651{
652 TInfoSinkBase& out = objSink();
653
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700654 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000655 // Loop header.
656 TLoopType loopType = node->getType();
657 if (loopType == ELoopFor) // for loop
658 {
Zhenyao Mo550c6002014-02-26 15:40:48 -0800659 if (!node->getUnrollFlag())
660 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000661 out << "for (";
662 if (node->getInit())
663 node->getInit()->traverse(this);
664 out << "; ";
665
666 if (node->getCondition())
667 node->getCondition()->traverse(this);
668 out << "; ";
669
670 if (node->getExpression())
671 node->getExpression()->traverse(this);
672 out << ")\n";
673 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800674 else
675 {
676 // Need to put a one-iteration loop here to handle break.
677 TIntermSequence &declSeq =
678 node->getInit()->getAsAggregate()->getSequence();
679 TIntermSymbol *indexSymbol =
680 declSeq[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
681 TString name = hashVariableName(indexSymbol->getSymbol());
682 out << "for (int " << name << " = 0; "
683 << name << " < 1; "
684 << "++" << name << ")\n";
685 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000686 }
687 else if (loopType == ELoopWhile) // while loop
688 {
689 out << "while (";
690 ASSERT(node->getCondition() != NULL);
691 node->getCondition()->traverse(this);
692 out << ")\n";
693 }
694 else // do-while loop
695 {
696 ASSERT(loopType == ELoopDoWhile);
697 out << "do\n";
698 }
699
700 // Loop body.
701 if (node->getUnrollFlag())
702 {
Zhenyao Mo550c6002014-02-26 15:40:48 -0800703 out << "{\n";
704 mLoopUnrollStack.push(node);
705 while (mLoopUnrollStack.satisfiesLoopCondition())
zmo@google.com5601ea02011-06-10 18:23:25 +0000706 {
707 visitCodeBlock(node->getBody());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800708 mLoopUnrollStack.step();
zmo@google.com5601ea02011-06-10 18:23:25 +0000709 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800710 mLoopUnrollStack.pop();
711 out << "}\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000712 }
713 else
714 {
715 visitCodeBlock(node->getBody());
716 }
717
718 // Loop footer.
719 if (loopType == ELoopDoWhile) // do-while loop
720 {
721 out << "while (";
722 ASSERT(node->getCondition() != NULL);
723 node->getCondition()->traverse(this);
724 out << ");\n";
725 }
726 decrementDepth();
727
728 // No need to visit children. They have been already processed in
729 // this function.
730 return false;
731}
732
733bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch* node)
734{
735 switch (node->getFlowOp())
736 {
737 case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break;
738 case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break;
739 case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break;
740 case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break;
741 default: UNREACHABLE(); break;
742 }
743
744 return true;
745}
746
747void TOutputGLSLBase::visitCodeBlock(TIntermNode* node) {
748 TInfoSinkBase &out = objSink();
749 if (node != NULL)
750 {
751 node->traverse(this);
752 // Single statements not part of a sequence need to be terminated
753 // with semi-colon.
754 if (isSingleStatement(node))
755 out << ";\n";
756 }
757 else
758 {
759 out << "{\n}\n"; // Empty code block.
760 }
761}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000762
763TString TOutputGLSLBase::getTypeName(const TType& type)
764{
765 TInfoSinkBase out;
766 if (type.isMatrix())
767 {
768 out << "mat";
769 out << type.getNominalSize();
770 }
771 else if (type.isVector())
772 {
773 switch (type.getBasicType())
774 {
775 case EbtFloat: out << "vec"; break;
776 case EbtInt: out << "ivec"; break;
777 case EbtBool: out << "bvec"; break;
778 default: UNREACHABLE(); break;
779 }
780 out << type.getNominalSize();
781 }
782 else
783 {
784 if (type.getBasicType() == EbtStruct)
Jamie Madill98493dd2013-07-08 14:39:03 -0400785 out << hashName(type.getStruct()->name());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000786 else
787 out << type.getBasicString();
788 }
789 return TString(out.c_str());
790}
791
792TString TOutputGLSLBase::hashName(const TString& name)
793{
794 if (mHashFunction == NULL || name.empty())
795 return name;
796 NameMap::const_iterator it = mNameMap.find(name.c_str());
797 if (it != mNameMap.end())
798 return it->second.c_str();
799 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
800 mNameMap[name.c_str()] = hashedName.c_str();
801 return hashedName;
802}
803
804TString TOutputGLSLBase::hashVariableName(const TString& name)
805{
Jamie Madill02f20dd2013-09-12 12:07:42 -0400806 if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000807 return name;
808 return hashName(name);
809}
810
811TString TOutputGLSLBase::hashFunctionName(const TString& mangled_name)
812{
813 TString name = TFunction::unmangleName(mangled_name);
Jamie Madill02f20dd2013-09-12 12:07:42 -0400814 if (mSymbolTable.findBuiltIn(mangled_name, mShaderVersion) != NULL || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -0400815 {
816 return translateTextureFunction(name);
817 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000818 return hashName(name);
819}
Jamie Madill98493dd2013-07-08 14:39:03 -0400820
821bool TOutputGLSLBase::structDeclared(const TStructure* structure) const
822{
Zhenyao Mo904a9162014-05-09 14:07:45 -0700823 ASSERT(structure);
824 ASSERT(mDeclaredStructs.size() > 0);
825 for (size_t ii = mDeclaredStructs.size(); ii > 0; --ii)
826 {
827 const ScopedDeclaredStructs& scope = mDeclaredStructs[ii - 1];
828 for (size_t jj = 0; jj < scope.size(); ++jj)
829 {
830 if (scope[jj]->equals(*structure))
831 return true;
832 }
833 }
834 return false;
Jamie Madill98493dd2013-07-08 14:39:03 -0400835}
836
837void TOutputGLSLBase::declareStruct(const TStructure* structure)
838{
839 TInfoSinkBase& out = objSink();
840
841 out << "struct " << hashName(structure->name()) << "{\n";
842 const TFieldList& fields = structure->fields();
843 for (size_t i = 0; i < fields.size(); ++i)
844 {
845 const TField* field = fields[i];
846 if (writeVariablePrecision(field->type()->getPrecision()))
847 out << " ";
848 out << getTypeName(*field->type()) << " " << hashName(field->name());
849 if (field->type()->isArray())
850 out << arrayBrackets(*field->type());
851 out << ";\n";
852 }
853 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -0700854}
Jamie Madill98493dd2013-07-08 14:39:03 -0400855
Zhenyao Mo904a9162014-05-09 14:07:45 -0700856void TOutputGLSLBase::pushDeclaredStructsScope()
857{
858 mDeclaredStructs.push_back(ScopedDeclaredStructs());
859}
860
861void TOutputGLSLBase::popDeclaredStructsScope()
862{
863 // We should never pop the global scope.
864 ASSERT(mDeclaredStructs.size() >= 2);
865 mDeclaredStructs.pop_back();
Jamie Madill98493dd2013-07-08 14:39:03 -0400866}