blob: 4bb6305d051ece673f8333f0e00b7f4f56ce50c5 [file] [log] [blame]
zmo@google.com5601ea02011-06-10 18:23:25 +00001//
Nicolas Capens16004fc2014-06-11 11:29:11 -04002// Copyright (c) 2002-2014 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{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070014TString arrayBrackets(const TType &type)
zmo@google.com5601ea02011-06-10 18:23:25 +000015{
16 ASSERT(type.isArray());
17 TInfoSinkBase out;
18 out << "[" << type.getArraySize() << "]";
19 return TString(out.c_str());
20}
21
Zhenyao Mo9eedea02014-05-12 16:02:35 -070022bool isSingleStatement(TIntermNode *node)
23{
24 if (const TIntermAggregate *aggregate = node->getAsAggregate())
zmo@google.com5601ea02011-06-10 18:23:25 +000025 {
26 return (aggregate->getOp() != EOpFunction) &&
27 (aggregate->getOp() != EOpSequence);
28 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -070029 else if (const TIntermSelection *selection = node->getAsSelectionNode())
zmo@google.com5601ea02011-06-10 18:23:25 +000030 {
31 // Ternary operators are usually part of an assignment operator.
32 // This handles those rare cases in which they are all by themselves.
33 return selection->usesTernaryOperator();
34 }
35 else if (node->getAsLoopNode())
36 {
37 return false;
38 }
Olli Etuaho01cd8af2015-02-20 10:39:20 +020039 else if (node->getAsSwitchNode())
40 {
41 return false;
42 }
43 else if (node->getAsCaseNode())
44 {
45 return false;
46 }
zmo@google.com5601ea02011-06-10 18:23:25 +000047 return true;
48}
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080049
zmo@google.com5601ea02011-06-10 18:23:25 +000050} // namespace
51
Zhenyao Mo9eedea02014-05-12 16:02:35 -070052TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000053 ShArrayIndexClampingStrategy clampingStrategy,
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000054 ShHashFunction64 hashFunction,
Zhenyao Mo9eedea02014-05-12 16:02:35 -070055 NameMap &nameMap,
56 TSymbolTable &symbolTable,
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080057 int shaderVersion,
58 ShShaderOutput output)
zmo@google.com5601ea02011-06-10 18:23:25 +000059 : TIntermTraverser(true, true, true),
60 mObjSink(objSink),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000061 mDeclaringVariables(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000062 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000063 mHashFunction(hashFunction),
64 mNameMap(nameMap),
Jamie Madill02f20dd2013-09-12 12:07:42 -040065 mSymbolTable(symbolTable),
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080066 mShaderVersion(shaderVersion),
67 mOutput(output)
zmo@google.com5601ea02011-06-10 18:23:25 +000068{
69}
70
Zhenyao Mo9eedea02014-05-12 16:02:35 -070071void TOutputGLSLBase::writeTriplet(
72 Visit visit, const char *preStr, const char *inStr, const char *postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000073{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070074 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +000075 if (visit == PreVisit && preStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000076 out << preStr;
zmo@google.com5601ea02011-06-10 18:23:25 +000077 else if (visit == InVisit && inStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000078 out << inStr;
zmo@google.com5601ea02011-06-10 18:23:25 +000079 else if (visit == PostVisit && postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000080 out << postStr;
zmo@google.com5601ea02011-06-10 18:23:25 +000081}
82
Zhenyao Mo9eedea02014-05-12 16:02:35 -070083void TOutputGLSLBase::writeBuiltInFunctionTriplet(
84 Visit visit, const char *preStr, bool useEmulatedFunction)
zmo@google.com5601ea02011-06-10 18:23:25 +000085{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070086 TString preString = useEmulatedFunction ?
87 BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
88 writeTriplet(visit, preString.c_str(), ", ", ")");
89}
90
91void TOutputGLSLBase::writeVariableType(const TType &type)
92{
93 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +000094 TQualifier qualifier = type.getQualifier();
Jamie Madill3b5c2da2014-08-19 15:23:32 -040095 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -040096 {
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080097 if (mOutput == SH_GLSL_CORE_OUTPUT)
98 {
99 switch (qualifier)
100 {
101 case EvqAttribute:
102 out << "in" << " ";
103 break;
104 case EvqVaryingIn:
105 out << "in" << " ";
106 break;
107 case EvqVaryingOut:
108 out << "out" << " ";
109 break;
110 case EvqInvariantVaryingIn:
111 out << "invariant in" << " ";
112 break;
113 case EvqInvariantVaryingOut:
114 out << "invariant out" << " ";
115 break;
116 default:
117 out << type.getQualifierString() << " ";
118 break;
119 }
120 }
121 else
122 {
123 out << type.getQualifierString() << " ";
124 }
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400125 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000126 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700127 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000128 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400129 TStructure *structure = type.getStruct();
130
131 declareStruct(structure);
132
133 if (!structure->name().empty())
134 {
135 mDeclaredStructs.insert(structure->uniqueId());
136 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000137 }
138 else
139 {
140 if (writeVariablePrecision(type.getPrecision()))
141 out << " ";
142 out << getTypeName(type);
143 }
144}
145
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700146void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000147{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700148 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000149 for (TIntermSequence::const_iterator iter = args.begin();
150 iter != args.end(); ++iter)
151 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700152 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000153 ASSERT(arg != NULL);
154
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700155 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000156 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000157
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700158 const TString &name = arg->getSymbol();
zmo@google.com5601ea02011-06-10 18:23:25 +0000159 if (!name.empty())
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000160 out << " " << hashName(name);
zmo@google.com5601ea02011-06-10 18:23:25 +0000161 if (type.isArray())
162 out << arrayBrackets(type);
163
164 // Put a comma if this is not the last argument.
165 if (iter != args.end() - 1)
166 out << ", ";
167 }
168}
169
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700170const ConstantUnion *TOutputGLSLBase::writeConstantUnion(
171 const TType &type, const ConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000172{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700173 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000174
175 if (type.getBasicType() == EbtStruct)
176 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700177 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -0400178 out << hashName(structure->name()) << "(";
179
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700180 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400181 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000182 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700183 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000184 ASSERT(fieldType != NULL);
185 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700186 if (i != fields.size() - 1)
187 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000188 }
189 out << ")";
190 }
191 else
192 {
Jamie Madill94bf7f22013-07-08 13:31:15 -0400193 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000194 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700195 if (writeType)
196 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400197 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000198 {
199 switch (pConstUnion->getType())
200 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700201 case EbtFloat:
202 out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
203 break;
204 case EbtInt:
205 out << pConstUnion->getIConst();
206 break;
Olli Etuaho5321c802015-04-02 17:08:16 +0300207 case EbtUInt:
208 out << pConstUnion->getUConst() << "u";
209 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700210 case EbtBool:
211 out << pConstUnion->getBConst();
212 break;
213 default: UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000214 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700215 if (i != size - 1)
216 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000217 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700218 if (writeType)
219 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000220 }
221 return pConstUnion;
222}
223
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700224void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000225{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700226 TInfoSinkBase &out = objSink();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800227 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
228 out << mLoopUnrollStack.getLoopIndexValue(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000229 else
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000230 out << hashVariableName(node->getSymbol());
zmo@google.com5601ea02011-06-10 18:23:25 +0000231
232 if (mDeclaringVariables && node->getType().isArray())
233 out << arrayBrackets(node->getType());
234}
235
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700236void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000237{
238 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
239}
240
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700241bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000242{
243 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700244 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000245 switch (node->getOp())
246 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700247 case EOpInitialize:
248 if (visit == InVisit)
249 {
250 out << " = ";
251 // RHS of initialize is not being declared.
252 mDeclaringVariables = false;
253 }
254 break;
255 case EOpAssign:
256 writeTriplet(visit, "(", " = ", ")");
257 break;
258 case EOpAddAssign:
259 writeTriplet(visit, "(", " += ", ")");
260 break;
261 case EOpSubAssign:
262 writeTriplet(visit, "(", " -= ", ")");
263 break;
264 case EOpDivAssign:
265 writeTriplet(visit, "(", " /= ", ")");
266 break;
Olli Etuahoff805cc2015-02-13 10:59:34 +0200267 case EOpIModAssign:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000268 writeTriplet(visit, "(", " %= ", ")");
269 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700270 // Notice the fall-through.
271 case EOpMulAssign:
272 case EOpVectorTimesMatrixAssign:
273 case EOpVectorTimesScalarAssign:
274 case EOpMatrixTimesScalarAssign:
275 case EOpMatrixTimesMatrixAssign:
276 writeTriplet(visit, "(", " *= ", ")");
277 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200278 case EOpBitShiftLeftAssign:
279 writeTriplet(visit, "(", " <<= ", ")");
280 break;
281 case EOpBitShiftRightAssign:
282 writeTriplet(visit, "(", " >>= ", ")");
283 break;
284 case EOpBitwiseAndAssign:
285 writeTriplet(visit, "(", " &= ", ")");
286 break;
287 case EOpBitwiseXorAssign:
288 writeTriplet(visit, "(", " ^= ", ")");
289 break;
290 case EOpBitwiseOrAssign:
291 writeTriplet(visit, "(", " |= ", ")");
292 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700293
294 case EOpIndexDirect:
295 writeTriplet(visit, NULL, "[", "]");
296 break;
297 case EOpIndexIndirect:
298 if (node->getAddIndexClamp())
299 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000300 if (visit == InVisit)
301 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700302 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
303 out << "[int(clamp(float(";
304 else
305 out << "[webgl_int_clamp(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000306 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700307 else if (visit == PostVisit)
308 {
309 int maxSize;
310 TIntermTyped *left = node->getLeft();
311 TType leftType = left->getType();
zmo@google.com5601ea02011-06-10 18:23:25 +0000312
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700313 if (left->isArray())
314 {
315 // The shader will fail validation if the array length is not > 0.
316 maxSize = leftType.getArraySize() - 1;
317 }
318 else
319 {
320 maxSize = leftType.getNominalSize() - 1;
321 }
322
323 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
324 out << "), 0.0, float(" << maxSize << ")))]";
325 else
326 out << ", 0, " << maxSize << ")]";
327 }
328 }
329 else
330 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000331 writeTriplet(visit, NULL, "[", "]");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700332 }
333 break;
334 case EOpIndexDirectStruct:
335 if (visit == InVisit)
336 {
337 // Here we are writing out "foo.bar", where "foo" is struct
338 // and "bar" is field. In AST, it is represented as a binary
339 // node, where left child represents "foo" and right child "bar".
340 // The node itself represents ".". The struct field "bar" is
341 // actually stored as an index into TStructure::fields.
342 out << ".";
343 const TStructure *structure = node->getLeft()->getType().getStruct();
344 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
345 const TField *field = structure->fields()[index->getIConst(0)];
346
347 TString fieldName = field->name();
348 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
349 fieldName = hashName(fieldName);
350
351 out << fieldName;
352 visitChildren = false;
353 }
354 break;
355 case EOpVectorSwizzle:
356 if (visit == InVisit)
357 {
358 out << ".";
359 TIntermAggregate *rightChild = node->getRight()->getAsAggregate();
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700360 TIntermSequence *sequence = rightChild->getSequence();
361 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); ++sit)
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000362 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700363 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
364 ASSERT(element->getBasicType() == EbtInt);
365 ASSERT(element->getNominalSize() == 1);
366 const ConstantUnion& data = element->getUnionArrayPointer()[0];
367 ASSERT(data.getType() == EbtInt);
368 switch (data.getIConst())
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000369 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700370 case 0:
371 out << "x";
372 break;
373 case 1:
374 out << "y";
375 break;
376 case 2:
377 out << "z";
378 break;
379 case 3:
380 out << "w";
381 break;
382 default:
383 UNREACHABLE();
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000384 }
385 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700386 visitChildren = false;
387 }
388 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000389
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700390 case EOpAdd:
391 writeTriplet(visit, "(", " + ", ")");
392 break;
393 case EOpSub:
394 writeTriplet(visit, "(", " - ", ")");
395 break;
396 case EOpMul:
397 writeTriplet(visit, "(", " * ", ")");
398 break;
399 case EOpDiv:
400 writeTriplet(visit, "(", " / ", ")");
401 break;
Olli Etuahoff805cc2015-02-13 10:59:34 +0200402 case EOpIMod:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000403 writeTriplet(visit, "(", " % ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700404 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200405 case EOpBitShiftLeft:
406 writeTriplet(visit, "(", " << ", ")");
407 break;
408 case EOpBitShiftRight:
409 writeTriplet(visit, "(", " >> ", ")");
410 break;
411 case EOpBitwiseAnd:
412 writeTriplet(visit, "(", " & ", ")");
413 break;
414 case EOpBitwiseXor:
415 writeTriplet(visit, "(", " ^ ", ")");
416 break;
417 case EOpBitwiseOr:
418 writeTriplet(visit, "(", " | ", ")");
419 break;
420
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700421 case EOpEqual:
422 writeTriplet(visit, "(", " == ", ")");
423 break;
424 case EOpNotEqual:
425 writeTriplet(visit, "(", " != ", ")");
426 break;
427 case EOpLessThan:
428 writeTriplet(visit, "(", " < ", ")");
429 break;
430 case EOpGreaterThan:
431 writeTriplet(visit, "(", " > ", ")");
432 break;
433 case EOpLessThanEqual:
434 writeTriplet(visit, "(", " <= ", ")");
435 break;
436 case EOpGreaterThanEqual:
437 writeTriplet(visit, "(", " >= ", ")");
438 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000439
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700440 // Notice the fall-through.
441 case EOpVectorTimesScalar:
442 case EOpVectorTimesMatrix:
443 case EOpMatrixTimesVector:
444 case EOpMatrixTimesScalar:
445 case EOpMatrixTimesMatrix:
446 writeTriplet(visit, "(", " * ", ")");
447 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000448
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700449 case EOpLogicalOr:
450 writeTriplet(visit, "(", " || ", ")");
451 break;
452 case EOpLogicalXor:
453 writeTriplet(visit, "(", " ^^ ", ")");
454 break;
455 case EOpLogicalAnd:
456 writeTriplet(visit, "(", " && ", ")");
457 break;
458 default:
459 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000460 }
461
462 return visitChildren;
463}
464
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700465bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000466{
zmo@google.com32e97312011-08-24 01:03:11 +0000467 TString preString;
468 TString postString = ")";
469
zmo@google.com5601ea02011-06-10 18:23:25 +0000470 switch (node->getOp())
471 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700472 case EOpNegative: preString = "(-"; break;
Zhenyao Mode1e00e2014-10-09 16:55:32 -0700473 case EOpPositive: preString = "(+"; break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700474 case EOpVectorLogicalNot: preString = "not("; break;
475 case EOpLogicalNot: preString = "(!"; break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200476 case EOpBitwiseNot: preString = "(~"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000477
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700478 case EOpPostIncrement: preString = "("; postString = "++)"; break;
479 case EOpPostDecrement: preString = "("; postString = "--)"; break;
480 case EOpPreIncrement: preString = "(++"; break;
481 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000482
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700483 case EOpRadians:
484 preString = "radians(";
485 break;
486 case EOpDegrees:
487 preString = "degrees(";
488 break;
489 case EOpSin:
490 preString = "sin(";
491 break;
492 case EOpCos:
493 preString = "cos(";
494 break;
495 case EOpTan:
496 preString = "tan(";
497 break;
498 case EOpAsin:
499 preString = "asin(";
500 break;
501 case EOpAcos:
502 preString = "acos(";
503 break;
504 case EOpAtan:
505 preString = "atan(";
506 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000507
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200508 case EOpSinh:
509 preString = "sinh(";
510 break;
511 case EOpCosh:
512 preString = "cosh(";
513 break;
514 case EOpTanh:
515 preString = "tanh(";
516 break;
517 case EOpAsinh:
518 preString = "asinh(";
519 break;
520 case EOpAcosh:
521 preString = "acosh(";
522 break;
523 case EOpAtanh:
524 preString = "atanh(";
525 break;
526
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700527 case EOpExp:
528 preString = "exp(";
529 break;
530 case EOpLog:
531 preString = "log(";
532 break;
533 case EOpExp2:
534 preString = "exp2(";
535 break;
536 case EOpLog2:
537 preString = "log2(";
538 break;
539 case EOpSqrt:
540 preString = "sqrt(";
541 break;
542 case EOpInverseSqrt:
543 preString = "inversesqrt(";
544 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000545
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700546 case EOpAbs:
547 preString = "abs(";
548 break;
549 case EOpSign:
550 preString = "sign(";
551 break;
552 case EOpFloor:
553 preString = "floor(";
554 break;
Qingqing Deng5dbece52015-02-27 20:35:38 -0800555 case EOpTrunc:
556 preString = "trunc(";
557 break;
558 case EOpRound:
559 preString = "round(";
560 break;
561 case EOpRoundEven:
562 preString = "roundEven(";
563 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700564 case EOpCeil:
565 preString = "ceil(";
566 break;
567 case EOpFract:
568 preString = "fract(";
569 break;
Arun Patole0c1726e2015-02-18 14:35:02 +0530570 case EOpIsNan:
571 preString = "isnan(";
572 break;
573 case EOpIsInf:
574 preString = "isinf(";
575 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000576
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200577 case EOpFloatBitsToInt:
578 preString = "floatBitsToInt(";
579 break;
580 case EOpFloatBitsToUint:
581 preString = "floatBitsToUint(";
582 break;
583 case EOpIntBitsToFloat:
584 preString = "intBitsToFloat(";
585 break;
586 case EOpUintBitsToFloat:
587 preString = "uintBitsToFloat(";
588 break;
589
Olli Etuaho7700ff62015-01-15 12:16:29 +0200590 case EOpPackSnorm2x16:
591 preString = "packSnorm2x16(";
592 break;
593 case EOpPackUnorm2x16:
594 preString = "packUnorm2x16(";
595 break;
596 case EOpPackHalf2x16:
597 preString = "packHalf2x16(";
598 break;
599 case EOpUnpackSnorm2x16:
600 preString = "unpackSnorm2x16(";
601 break;
602 case EOpUnpackUnorm2x16:
603 preString = "unpackUnorm2x16(";
604 break;
605 case EOpUnpackHalf2x16:
606 preString = "unpackHalf2x16(";
607 break;
608
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700609 case EOpLength:
610 preString = "length(";
611 break;
612 case EOpNormalize:
613 preString = "normalize(";
614 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000615
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700616 case EOpDFdx:
617 preString = "dFdx(";
618 break;
619 case EOpDFdy:
620 preString = "dFdy(";
621 break;
622 case EOpFwidth:
623 preString = "fwidth(";
624 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000625
Olli Etuahoe39706d2014-12-30 16:40:36 +0200626 case EOpTranspose:
627 preString = "transpose(";
628 break;
629 case EOpDeterminant:
630 preString = "determinant(";
631 break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +0200632 case EOpInverse:
633 preString = "inverse(";
634 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200635
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700636 case EOpAny:
637 preString = "any(";
638 break;
639 case EOpAll:
640 preString = "all(";
641 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000642
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700643 default:
644 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000645 }
646
zmo@google.com32e97312011-08-24 01:03:11 +0000647 if (visit == PreVisit && node->getUseEmulatedFunction())
648 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
649 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
650
zmo@google.com5601ea02011-06-10 18:23:25 +0000651 return true;
652}
653
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700654bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000655{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700656 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000657
658 if (node->usesTernaryOperator())
659 {
660 // Notice two brackets at the beginning and end. The outer ones
661 // encapsulate the whole ternary expression. This preserves the
662 // order of precedence when ternary expressions are used in a
663 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
664 out << "((";
665 node->getCondition()->traverse(this);
666 out << ") ? (";
667 node->getTrueBlock()->traverse(this);
668 out << ") : (";
669 node->getFalseBlock()->traverse(this);
670 out << "))";
671 }
672 else
673 {
674 out << "if (";
675 node->getCondition()->traverse(this);
676 out << ")\n";
677
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700678 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000679 visitCodeBlock(node->getTrueBlock());
680
681 if (node->getFalseBlock())
682 {
683 out << "else\n";
684 visitCodeBlock(node->getFalseBlock());
685 }
686 decrementDepth();
687 }
688 return false;
689}
690
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200691bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200692{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200693 if (node->getStatementList())
694 {
695 writeTriplet(visit, "switch (", ") ", nullptr);
696 // The curly braces get written when visiting the statementList aggregate
697 }
698 else
699 {
700 // No statementList, so it won't output curly braces
701 writeTriplet(visit, "switch (", ") {", "}\n");
702 }
703 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200704}
705
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200706bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200707{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200708 if (node->hasCondition())
709 {
710 writeTriplet(visit, "case (", nullptr, "):\n");
711 return true;
712 }
713 else
714 {
715 TInfoSinkBase &out = objSink();
716 out << "default:\n";
717 return false;
718 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200719}
720
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700721bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000722{
723 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700724 TInfoSinkBase &out = objSink();
zmo@google.comf420c422011-09-12 18:27:59 +0000725 TString preString;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700726 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000727 switch (node->getOp())
728 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700729 case EOpSequence:
730 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700731 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700732 {
733 out << "{\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000734 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000735
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700736 incrementDepth(node);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700737 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
738 iter != node->getSequence()->end(); ++iter)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700739 {
Austin Kinross3ae64652015-01-26 15:51:39 -0800740 TIntermNode *curNode = *iter;
741 ASSERT(curNode != NULL);
742 curNode->traverse(this);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700743
Austin Kinross3ae64652015-01-26 15:51:39 -0800744 if (isSingleStatement(curNode))
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700745 out << ";\n";
746 }
747 decrementDepth();
748
749 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700750 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700751 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700752 out << "}\n";
753 }
754 visitChildren = false;
755 break;
756 case EOpPrototype:
757 // Function declaration.
758 ASSERT(visit == PreVisit);
759 writeVariableType(node->getType());
Olli Etuaho76acee82014-11-04 13:44:03 +0200760 out << " " << hashFunctionName(node->getName());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700761
762 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700763 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700764 out << ")";
765
766 visitChildren = false;
767 break;
768 case EOpFunction: {
769 // Function definition.
770 ASSERT(visit == PreVisit);
771 writeVariableType(node->getType());
772 out << " " << hashFunctionName(node->getName());
773
774 incrementDepth(node);
775 // Function definition node contains one or two children nodes
776 // representing function parameters and function body. The latter
777 // is not present in case of empty function bodies.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700778 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700779 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
780 TIntermSequence::const_iterator seqIter = sequence.begin();
781
782 // Traverse function parameters.
783 TIntermAggregate *params = (*seqIter)->getAsAggregate();
784 ASSERT(params != NULL);
785 ASSERT(params->getOp() == EOpParameters);
786 params->traverse(this);
787
788 // Traverse function body.
789 TIntermAggregate *body = ++seqIter != sequence.end() ?
790 (*seqIter)->getAsAggregate() : NULL;
791 visitCodeBlock(body);
792 decrementDepth();
793
794 // Fully processed; no need to visit children.
795 visitChildren = false;
796 break;
797 }
798 case EOpFunctionCall:
799 // Function call.
800 if (visit == PreVisit)
801 out << hashFunctionName(node->getName()) << "(";
802 else if (visit == InVisit)
803 out << ", ";
804 else
zmo@google.com5601ea02011-06-10 18:23:25 +0000805 out << ")";
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700806 break;
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200807 case EOpInternalFunctionCall:
808 // Function call to an internal helper function.
809 if (visit == PreVisit)
810 out << node->getName() << "(";
811 else if (visit == InVisit)
812 out << ", ";
813 else
814 out << ")";
815 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700816 case EOpParameters:
817 // Function parameters.
818 ASSERT(visit == PreVisit);
819 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700820 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700821 out << ")";
822 visitChildren = false;
823 break;
824 case EOpDeclaration:
825 // Variable declaration.
826 if (visit == PreVisit)
827 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700828 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700829 const TIntermTyped *variable = sequence.front()->getAsTyped();
830 writeVariableType(variable->getType());
831 out << " ";
832 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000833 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700834 else if (visit == InVisit)
835 {
836 out << ", ";
837 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000838 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700839 else
840 {
841 mDeclaringVariables = false;
842 }
843 break;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700844 case EOpInvariantDeclaration:
845 // Invariant declaration.
846 ASSERT(visit == PreVisit);
847 {
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400848 const TIntermSequence *sequence = node->getSequence();
849 ASSERT(sequence && sequence->size() == 1);
850 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
851 ASSERT(symbol);
Zhenyao Mo2a517272014-10-27 16:09:57 -0700852 out << "invariant " << hashVariableName(symbol->getSymbol());
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400853 }
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700854 visitChildren = false;
855 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700856 case EOpConstructFloat:
857 writeTriplet(visit, "float(", NULL, ")");
858 break;
859 case EOpConstructVec2:
860 writeBuiltInFunctionTriplet(visit, "vec2(", false);
861 break;
862 case EOpConstructVec3:
863 writeBuiltInFunctionTriplet(visit, "vec3(", false);
864 break;
865 case EOpConstructVec4:
866 writeBuiltInFunctionTriplet(visit, "vec4(", false);
867 break;
868 case EOpConstructBool:
869 writeTriplet(visit, "bool(", NULL, ")");
870 break;
871 case EOpConstructBVec2:
872 writeBuiltInFunctionTriplet(visit, "bvec2(", false);
873 break;
874 case EOpConstructBVec3:
875 writeBuiltInFunctionTriplet(visit, "bvec3(", false);
876 break;
877 case EOpConstructBVec4:
878 writeBuiltInFunctionTriplet(visit, "bvec4(", false);
879 break;
880 case EOpConstructInt:
881 writeTriplet(visit, "int(", NULL, ")");
882 break;
883 case EOpConstructIVec2:
884 writeBuiltInFunctionTriplet(visit, "ivec2(", false);
885 break;
886 case EOpConstructIVec3:
887 writeBuiltInFunctionTriplet(visit, "ivec3(", false);
888 break;
889 case EOpConstructIVec4:
890 writeBuiltInFunctionTriplet(visit, "ivec4(", false);
891 break;
892 case EOpConstructMat2:
893 writeBuiltInFunctionTriplet(visit, "mat2(", false);
894 break;
895 case EOpConstructMat3:
896 writeBuiltInFunctionTriplet(visit, "mat3(", false);
897 break;
898 case EOpConstructMat4:
899 writeBuiltInFunctionTriplet(visit, "mat4(", false);
900 break;
901 case EOpConstructStruct:
902 if (visit == PreVisit)
903 {
904 const TType &type = node->getType();
905 ASSERT(type.getBasicType() == EbtStruct);
906 out << hashName(type.getStruct()->name()) << "(";
907 }
908 else if (visit == InVisit)
909 {
910 out << ", ";
911 }
912 else
913 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000914 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000915 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700916 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000917
Olli Etuahoe39706d2014-12-30 16:40:36 +0200918 case EOpOuterProduct:
919 writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
920 break;
921
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700922 case EOpLessThan:
923 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
924 break;
925 case EOpGreaterThan:
926 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
927 break;
928 case EOpLessThanEqual:
929 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
930 break;
931 case EOpGreaterThanEqual:
932 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
933 break;
934 case EOpVectorEqual:
935 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
936 break;
937 case EOpVectorNotEqual:
938 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
939 break;
940 case EOpComma:
Zhenyao Mo0783efd2014-10-21 15:51:59 -0700941 writeTriplet(visit, "(", ", ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700942 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000943
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700944 case EOpMod:
945 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
946 break;
Olli Etuahob6e07a62015-02-16 12:22:10 +0200947 case EOpModf:
948 writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
949 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700950 case EOpPow:
951 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
952 break;
953 case EOpAtan:
954 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
955 break;
956 case EOpMin:
957 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
958 break;
959 case EOpMax:
960 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
961 break;
962 case EOpClamp:
963 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
964 break;
965 case EOpMix:
966 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
967 break;
968 case EOpStep:
969 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
970 break;
971 case EOpSmoothStep:
972 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
973 break;
974 case EOpDistance:
975 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
976 break;
977 case EOpDot:
978 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
979 break;
980 case EOpCross:
981 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
982 break;
983 case EOpFaceForward:
984 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
985 break;
986 case EOpReflect:
987 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
988 break;
989 case EOpRefract:
990 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
991 break;
992 case EOpMul:
993 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
994 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000995
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700996 default:
997 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000998 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000999 return visitChildren;
1000}
1001
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001002bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001003{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001004 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001005
Zhenyao Mo7cab38b2013-10-15 12:59:30 -07001006 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +00001007 // Loop header.
1008 TLoopType loopType = node->getType();
1009 if (loopType == ELoopFor) // for loop
1010 {
Zhenyao Mo550c6002014-02-26 15:40:48 -08001011 if (!node->getUnrollFlag())
1012 {
zmo@google.com5601ea02011-06-10 18:23:25 +00001013 out << "for (";
1014 if (node->getInit())
1015 node->getInit()->traverse(this);
1016 out << "; ";
1017
1018 if (node->getCondition())
1019 node->getCondition()->traverse(this);
1020 out << "; ";
1021
1022 if (node->getExpression())
1023 node->getExpression()->traverse(this);
1024 out << ")\n";
1025 }
Zhenyao Mo550c6002014-02-26 15:40:48 -08001026 else
1027 {
1028 // Need to put a one-iteration loop here to handle break.
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001029 TIntermSequence *declSeq =
Zhenyao Mo550c6002014-02-26 15:40:48 -08001030 node->getInit()->getAsAggregate()->getSequence();
1031 TIntermSymbol *indexSymbol =
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001032 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -08001033 TString name = hashVariableName(indexSymbol->getSymbol());
1034 out << "for (int " << name << " = 0; "
1035 << name << " < 1; "
1036 << "++" << name << ")\n";
1037 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001038 }
1039 else if (loopType == ELoopWhile) // while loop
1040 {
1041 out << "while (";
1042 ASSERT(node->getCondition() != NULL);
1043 node->getCondition()->traverse(this);
1044 out << ")\n";
1045 }
1046 else // do-while loop
1047 {
1048 ASSERT(loopType == ELoopDoWhile);
1049 out << "do\n";
1050 }
1051
1052 // Loop body.
1053 if (node->getUnrollFlag())
1054 {
Zhenyao Mo550c6002014-02-26 15:40:48 -08001055 out << "{\n";
1056 mLoopUnrollStack.push(node);
1057 while (mLoopUnrollStack.satisfiesLoopCondition())
zmo@google.com5601ea02011-06-10 18:23:25 +00001058 {
1059 visitCodeBlock(node->getBody());
Zhenyao Mo550c6002014-02-26 15:40:48 -08001060 mLoopUnrollStack.step();
zmo@google.com5601ea02011-06-10 18:23:25 +00001061 }
Zhenyao Mo550c6002014-02-26 15:40:48 -08001062 mLoopUnrollStack.pop();
1063 out << "}\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001064 }
1065 else
1066 {
1067 visitCodeBlock(node->getBody());
1068 }
1069
1070 // Loop footer.
1071 if (loopType == ELoopDoWhile) // do-while loop
1072 {
1073 out << "while (";
1074 ASSERT(node->getCondition() != NULL);
1075 node->getCondition()->traverse(this);
1076 out << ");\n";
1077 }
1078 decrementDepth();
1079
1080 // No need to visit children. They have been already processed in
1081 // this function.
1082 return false;
1083}
1084
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001085bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001086{
1087 switch (node->getFlowOp())
1088 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001089 case EOpKill:
1090 writeTriplet(visit, "discard", NULL, NULL);
1091 break;
1092 case EOpBreak:
1093 writeTriplet(visit, "break", NULL, NULL);
1094 break;
1095 case EOpContinue:
1096 writeTriplet(visit, "continue", NULL, NULL);
1097 break;
1098 case EOpReturn:
1099 writeTriplet(visit, "return ", NULL, NULL);
1100 break;
1101 default:
1102 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001103 }
1104
1105 return true;
1106}
1107
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001108void TOutputGLSLBase::visitCodeBlock(TIntermNode *node)
1109{
zmo@google.com5601ea02011-06-10 18:23:25 +00001110 TInfoSinkBase &out = objSink();
1111 if (node != NULL)
1112 {
1113 node->traverse(this);
1114 // Single statements not part of a sequence need to be terminated
1115 // with semi-colon.
1116 if (isSingleStatement(node))
1117 out << ";\n";
1118 }
1119 else
1120 {
1121 out << "{\n}\n"; // Empty code block.
1122 }
1123}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001124
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001125TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001126{
1127 TInfoSinkBase out;
1128 if (type.isMatrix())
1129 {
1130 out << "mat";
1131 out << type.getNominalSize();
1132 }
1133 else if (type.isVector())
1134 {
1135 switch (type.getBasicType())
1136 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001137 case EbtFloat:
1138 out << "vec";
1139 break;
1140 case EbtInt:
1141 out << "ivec";
1142 break;
1143 case EbtBool:
1144 out << "bvec";
1145 break;
1146 default:
1147 UNREACHABLE();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001148 }
1149 out << type.getNominalSize();
1150 }
1151 else
1152 {
1153 if (type.getBasicType() == EbtStruct)
Jamie Madill98493dd2013-07-08 14:39:03 -04001154 out << hashName(type.getStruct()->name());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001155 else
1156 out << type.getBasicString();
1157 }
1158 return TString(out.c_str());
1159}
1160
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001161TString TOutputGLSLBase::hashName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001162{
1163 if (mHashFunction == NULL || name.empty())
1164 return name;
1165 NameMap::const_iterator it = mNameMap.find(name.c_str());
1166 if (it != mNameMap.end())
1167 return it->second.c_str();
1168 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
1169 mNameMap[name.c_str()] = hashedName.c_str();
1170 return hashedName;
1171}
1172
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001173TString TOutputGLSLBase::hashVariableName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001174{
Jamie Madill02f20dd2013-09-12 12:07:42 -04001175 if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001176 return name;
1177 return hashName(name);
1178}
1179
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001180TString TOutputGLSLBase::hashFunctionName(const TString &mangled_name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001181{
1182 TString name = TFunction::unmangleName(mangled_name);
Jamie Madill02f20dd2013-09-12 12:07:42 -04001183 if (mSymbolTable.findBuiltIn(mangled_name, mShaderVersion) != NULL || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001184 return translateTextureFunction(name);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001185 return hashName(name);
1186}
Jamie Madill98493dd2013-07-08 14:39:03 -04001187
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001188bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001189{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001190 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001191 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001192 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001193 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001194 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001195
1196 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001197}
1198
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001199void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001200{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001201 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001202
1203 out << "struct " << hashName(structure->name()) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001204 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001205 for (size_t i = 0; i < fields.size(); ++i)
1206 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001207 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001208 if (writeVariablePrecision(field->type()->getPrecision()))
1209 out << " ";
1210 out << getTypeName(*field->type()) << " " << hashName(field->name());
1211 if (field->type()->isArray())
1212 out << arrayBrackets(*field->type());
1213 out << ";\n";
1214 }
1215 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001216}
Jamie Madill98493dd2013-07-08 14:39:03 -04001217