blob: 2720baf202fb681c0cc7b78c7bc82a3b8a1dbe29 [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
Olli Etuahof40319e2015-03-10 14:33:00 +0200224void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type, const char *constructorBaseType)
225{
226 TInfoSinkBase &out = objSink();
227 if (visit == PreVisit)
228 {
229 if (type.isArray())
230 {
231 out << constructorBaseType;
232 out << arrayBrackets(type);
233 out << "(";
234 }
235 else
236 {
237 out << constructorBaseType << "(";
238 }
239 }
240 else
241 {
242 writeTriplet(visit, nullptr, ", ", ")");
243 }
244}
245
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700246void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000247{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700248 TInfoSinkBase &out = objSink();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800249 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
250 out << mLoopUnrollStack.getLoopIndexValue(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000251 else
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000252 out << hashVariableName(node->getSymbol());
zmo@google.com5601ea02011-06-10 18:23:25 +0000253
254 if (mDeclaringVariables && node->getType().isArray())
255 out << arrayBrackets(node->getType());
256}
257
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700258void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000259{
260 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
261}
262
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700263bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000264{
265 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700266 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000267 switch (node->getOp())
268 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700269 case EOpInitialize:
270 if (visit == InVisit)
271 {
272 out << " = ";
273 // RHS of initialize is not being declared.
274 mDeclaringVariables = false;
275 }
276 break;
277 case EOpAssign:
278 writeTriplet(visit, "(", " = ", ")");
279 break;
280 case EOpAddAssign:
281 writeTriplet(visit, "(", " += ", ")");
282 break;
283 case EOpSubAssign:
284 writeTriplet(visit, "(", " -= ", ")");
285 break;
286 case EOpDivAssign:
287 writeTriplet(visit, "(", " /= ", ")");
288 break;
Olli Etuahoff805cc2015-02-13 10:59:34 +0200289 case EOpIModAssign:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000290 writeTriplet(visit, "(", " %= ", ")");
291 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700292 // Notice the fall-through.
293 case EOpMulAssign:
294 case EOpVectorTimesMatrixAssign:
295 case EOpVectorTimesScalarAssign:
296 case EOpMatrixTimesScalarAssign:
297 case EOpMatrixTimesMatrixAssign:
298 writeTriplet(visit, "(", " *= ", ")");
299 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200300 case EOpBitShiftLeftAssign:
301 writeTriplet(visit, "(", " <<= ", ")");
302 break;
303 case EOpBitShiftRightAssign:
304 writeTriplet(visit, "(", " >>= ", ")");
305 break;
306 case EOpBitwiseAndAssign:
307 writeTriplet(visit, "(", " &= ", ")");
308 break;
309 case EOpBitwiseXorAssign:
310 writeTriplet(visit, "(", " ^= ", ")");
311 break;
312 case EOpBitwiseOrAssign:
313 writeTriplet(visit, "(", " |= ", ")");
314 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700315
316 case EOpIndexDirect:
317 writeTriplet(visit, NULL, "[", "]");
318 break;
319 case EOpIndexIndirect:
320 if (node->getAddIndexClamp())
321 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000322 if (visit == InVisit)
323 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700324 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
325 out << "[int(clamp(float(";
326 else
327 out << "[webgl_int_clamp(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000328 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700329 else if (visit == PostVisit)
330 {
331 int maxSize;
332 TIntermTyped *left = node->getLeft();
333 TType leftType = left->getType();
zmo@google.com5601ea02011-06-10 18:23:25 +0000334
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700335 if (left->isArray())
336 {
337 // The shader will fail validation if the array length is not > 0.
338 maxSize = leftType.getArraySize() - 1;
339 }
340 else
341 {
342 maxSize = leftType.getNominalSize() - 1;
343 }
344
345 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
346 out << "), 0.0, float(" << maxSize << ")))]";
347 else
348 out << ", 0, " << maxSize << ")]";
349 }
350 }
351 else
352 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000353 writeTriplet(visit, NULL, "[", "]");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700354 }
355 break;
356 case EOpIndexDirectStruct:
357 if (visit == InVisit)
358 {
359 // Here we are writing out "foo.bar", where "foo" is struct
360 // and "bar" is field. In AST, it is represented as a binary
361 // node, where left child represents "foo" and right child "bar".
362 // The node itself represents ".". The struct field "bar" is
363 // actually stored as an index into TStructure::fields.
364 out << ".";
365 const TStructure *structure = node->getLeft()->getType().getStruct();
366 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
367 const TField *field = structure->fields()[index->getIConst(0)];
368
369 TString fieldName = field->name();
370 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
371 fieldName = hashName(fieldName);
372
373 out << fieldName;
374 visitChildren = false;
375 }
376 break;
377 case EOpVectorSwizzle:
378 if (visit == InVisit)
379 {
380 out << ".";
381 TIntermAggregate *rightChild = node->getRight()->getAsAggregate();
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700382 TIntermSequence *sequence = rightChild->getSequence();
383 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); ++sit)
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000384 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700385 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
386 ASSERT(element->getBasicType() == EbtInt);
387 ASSERT(element->getNominalSize() == 1);
388 const ConstantUnion& data = element->getUnionArrayPointer()[0];
389 ASSERT(data.getType() == EbtInt);
390 switch (data.getIConst())
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000391 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700392 case 0:
393 out << "x";
394 break;
395 case 1:
396 out << "y";
397 break;
398 case 2:
399 out << "z";
400 break;
401 case 3:
402 out << "w";
403 break;
404 default:
405 UNREACHABLE();
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000406 }
407 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700408 visitChildren = false;
409 }
410 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000411
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700412 case EOpAdd:
413 writeTriplet(visit, "(", " + ", ")");
414 break;
415 case EOpSub:
416 writeTriplet(visit, "(", " - ", ")");
417 break;
418 case EOpMul:
419 writeTriplet(visit, "(", " * ", ")");
420 break;
421 case EOpDiv:
422 writeTriplet(visit, "(", " / ", ")");
423 break;
Olli Etuahoff805cc2015-02-13 10:59:34 +0200424 case EOpIMod:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000425 writeTriplet(visit, "(", " % ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700426 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200427 case EOpBitShiftLeft:
428 writeTriplet(visit, "(", " << ", ")");
429 break;
430 case EOpBitShiftRight:
431 writeTriplet(visit, "(", " >> ", ")");
432 break;
433 case EOpBitwiseAnd:
434 writeTriplet(visit, "(", " & ", ")");
435 break;
436 case EOpBitwiseXor:
437 writeTriplet(visit, "(", " ^ ", ")");
438 break;
439 case EOpBitwiseOr:
440 writeTriplet(visit, "(", " | ", ")");
441 break;
442
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700443 case EOpEqual:
444 writeTriplet(visit, "(", " == ", ")");
445 break;
446 case EOpNotEqual:
447 writeTriplet(visit, "(", " != ", ")");
448 break;
449 case EOpLessThan:
450 writeTriplet(visit, "(", " < ", ")");
451 break;
452 case EOpGreaterThan:
453 writeTriplet(visit, "(", " > ", ")");
454 break;
455 case EOpLessThanEqual:
456 writeTriplet(visit, "(", " <= ", ")");
457 break;
458 case EOpGreaterThanEqual:
459 writeTriplet(visit, "(", " >= ", ")");
460 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000461
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700462 // Notice the fall-through.
463 case EOpVectorTimesScalar:
464 case EOpVectorTimesMatrix:
465 case EOpMatrixTimesVector:
466 case EOpMatrixTimesScalar:
467 case EOpMatrixTimesMatrix:
468 writeTriplet(visit, "(", " * ", ")");
469 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000470
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700471 case EOpLogicalOr:
472 writeTriplet(visit, "(", " || ", ")");
473 break;
474 case EOpLogicalXor:
475 writeTriplet(visit, "(", " ^^ ", ")");
476 break;
477 case EOpLogicalAnd:
478 writeTriplet(visit, "(", " && ", ")");
479 break;
480 default:
481 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000482 }
483
484 return visitChildren;
485}
486
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700487bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000488{
zmo@google.com32e97312011-08-24 01:03:11 +0000489 TString preString;
490 TString postString = ")";
491
zmo@google.com5601ea02011-06-10 18:23:25 +0000492 switch (node->getOp())
493 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700494 case EOpNegative: preString = "(-"; break;
Zhenyao Mode1e00e2014-10-09 16:55:32 -0700495 case EOpPositive: preString = "(+"; break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700496 case EOpVectorLogicalNot: preString = "not("; break;
497 case EOpLogicalNot: preString = "(!"; break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200498 case EOpBitwiseNot: preString = "(~"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000499
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700500 case EOpPostIncrement: preString = "("; postString = "++)"; break;
501 case EOpPostDecrement: preString = "("; postString = "--)"; break;
502 case EOpPreIncrement: preString = "(++"; break;
503 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000504
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700505 case EOpRadians:
506 preString = "radians(";
507 break;
508 case EOpDegrees:
509 preString = "degrees(";
510 break;
511 case EOpSin:
512 preString = "sin(";
513 break;
514 case EOpCos:
515 preString = "cos(";
516 break;
517 case EOpTan:
518 preString = "tan(";
519 break;
520 case EOpAsin:
521 preString = "asin(";
522 break;
523 case EOpAcos:
524 preString = "acos(";
525 break;
526 case EOpAtan:
527 preString = "atan(";
528 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000529
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200530 case EOpSinh:
531 preString = "sinh(";
532 break;
533 case EOpCosh:
534 preString = "cosh(";
535 break;
536 case EOpTanh:
537 preString = "tanh(";
538 break;
539 case EOpAsinh:
540 preString = "asinh(";
541 break;
542 case EOpAcosh:
543 preString = "acosh(";
544 break;
545 case EOpAtanh:
546 preString = "atanh(";
547 break;
548
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700549 case EOpExp:
550 preString = "exp(";
551 break;
552 case EOpLog:
553 preString = "log(";
554 break;
555 case EOpExp2:
556 preString = "exp2(";
557 break;
558 case EOpLog2:
559 preString = "log2(";
560 break;
561 case EOpSqrt:
562 preString = "sqrt(";
563 break;
564 case EOpInverseSqrt:
565 preString = "inversesqrt(";
566 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000567
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700568 case EOpAbs:
569 preString = "abs(";
570 break;
571 case EOpSign:
572 preString = "sign(";
573 break;
574 case EOpFloor:
575 preString = "floor(";
576 break;
Qingqing Deng5dbece52015-02-27 20:35:38 -0800577 case EOpTrunc:
578 preString = "trunc(";
579 break;
580 case EOpRound:
581 preString = "round(";
582 break;
583 case EOpRoundEven:
584 preString = "roundEven(";
585 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700586 case EOpCeil:
587 preString = "ceil(";
588 break;
589 case EOpFract:
590 preString = "fract(";
591 break;
Arun Patole0c1726e2015-02-18 14:35:02 +0530592 case EOpIsNan:
593 preString = "isnan(";
594 break;
595 case EOpIsInf:
596 preString = "isinf(";
597 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000598
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200599 case EOpFloatBitsToInt:
600 preString = "floatBitsToInt(";
601 break;
602 case EOpFloatBitsToUint:
603 preString = "floatBitsToUint(";
604 break;
605 case EOpIntBitsToFloat:
606 preString = "intBitsToFloat(";
607 break;
608 case EOpUintBitsToFloat:
609 preString = "uintBitsToFloat(";
610 break;
611
Olli Etuaho7700ff62015-01-15 12:16:29 +0200612 case EOpPackSnorm2x16:
613 preString = "packSnorm2x16(";
614 break;
615 case EOpPackUnorm2x16:
616 preString = "packUnorm2x16(";
617 break;
618 case EOpPackHalf2x16:
619 preString = "packHalf2x16(";
620 break;
621 case EOpUnpackSnorm2x16:
622 preString = "unpackSnorm2x16(";
623 break;
624 case EOpUnpackUnorm2x16:
625 preString = "unpackUnorm2x16(";
626 break;
627 case EOpUnpackHalf2x16:
628 preString = "unpackHalf2x16(";
629 break;
630
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700631 case EOpLength:
632 preString = "length(";
633 break;
634 case EOpNormalize:
635 preString = "normalize(";
636 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000637
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700638 case EOpDFdx:
639 preString = "dFdx(";
640 break;
641 case EOpDFdy:
642 preString = "dFdy(";
643 break;
644 case EOpFwidth:
645 preString = "fwidth(";
646 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000647
Olli Etuahoe39706d2014-12-30 16:40:36 +0200648 case EOpTranspose:
649 preString = "transpose(";
650 break;
651 case EOpDeterminant:
652 preString = "determinant(";
653 break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +0200654 case EOpInverse:
655 preString = "inverse(";
656 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200657
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700658 case EOpAny:
659 preString = "any(";
660 break;
661 case EOpAll:
662 preString = "all(";
663 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000664
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700665 default:
666 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000667 }
668
zmo@google.com32e97312011-08-24 01:03:11 +0000669 if (visit == PreVisit && node->getUseEmulatedFunction())
670 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
671 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
672
zmo@google.com5601ea02011-06-10 18:23:25 +0000673 return true;
674}
675
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700676bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000677{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700678 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000679
680 if (node->usesTernaryOperator())
681 {
682 // Notice two brackets at the beginning and end. The outer ones
683 // encapsulate the whole ternary expression. This preserves the
684 // order of precedence when ternary expressions are used in a
685 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
686 out << "((";
687 node->getCondition()->traverse(this);
688 out << ") ? (";
689 node->getTrueBlock()->traverse(this);
690 out << ") : (";
691 node->getFalseBlock()->traverse(this);
692 out << "))";
693 }
694 else
695 {
696 out << "if (";
697 node->getCondition()->traverse(this);
698 out << ")\n";
699
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700700 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000701 visitCodeBlock(node->getTrueBlock());
702
703 if (node->getFalseBlock())
704 {
705 out << "else\n";
706 visitCodeBlock(node->getFalseBlock());
707 }
708 decrementDepth();
709 }
710 return false;
711}
712
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200713bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200714{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200715 if (node->getStatementList())
716 {
717 writeTriplet(visit, "switch (", ") ", nullptr);
718 // The curly braces get written when visiting the statementList aggregate
719 }
720 else
721 {
722 // No statementList, so it won't output curly braces
723 writeTriplet(visit, "switch (", ") {", "}\n");
724 }
725 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200726}
727
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200728bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200729{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200730 if (node->hasCondition())
731 {
732 writeTriplet(visit, "case (", nullptr, "):\n");
733 return true;
734 }
735 else
736 {
737 TInfoSinkBase &out = objSink();
738 out << "default:\n";
739 return false;
740 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200741}
742
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700743bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000744{
745 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700746 TInfoSinkBase &out = objSink();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700747 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000748 switch (node->getOp())
749 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700750 case EOpSequence:
751 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700752 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700753 {
754 out << "{\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000755 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000756
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700757 incrementDepth(node);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700758 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
759 iter != node->getSequence()->end(); ++iter)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700760 {
Austin Kinross3ae64652015-01-26 15:51:39 -0800761 TIntermNode *curNode = *iter;
762 ASSERT(curNode != NULL);
763 curNode->traverse(this);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700764
Austin Kinross3ae64652015-01-26 15:51:39 -0800765 if (isSingleStatement(curNode))
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700766 out << ";\n";
767 }
768 decrementDepth();
769
770 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700771 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700772 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700773 out << "}\n";
774 }
775 visitChildren = false;
776 break;
777 case EOpPrototype:
778 // Function declaration.
779 ASSERT(visit == PreVisit);
780 writeVariableType(node->getType());
Olli Etuaho76acee82014-11-04 13:44:03 +0200781 out << " " << hashFunctionName(node->getName());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700782
783 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700784 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700785 out << ")";
786
787 visitChildren = false;
788 break;
789 case EOpFunction: {
790 // Function definition.
791 ASSERT(visit == PreVisit);
792 writeVariableType(node->getType());
793 out << " " << hashFunctionName(node->getName());
794
795 incrementDepth(node);
796 // Function definition node contains one or two children nodes
797 // representing function parameters and function body. The latter
798 // is not present in case of empty function bodies.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700799 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700800 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
801 TIntermSequence::const_iterator seqIter = sequence.begin();
802
803 // Traverse function parameters.
804 TIntermAggregate *params = (*seqIter)->getAsAggregate();
805 ASSERT(params != NULL);
806 ASSERT(params->getOp() == EOpParameters);
807 params->traverse(this);
808
809 // Traverse function body.
810 TIntermAggregate *body = ++seqIter != sequence.end() ?
811 (*seqIter)->getAsAggregate() : NULL;
812 visitCodeBlock(body);
813 decrementDepth();
814
815 // Fully processed; no need to visit children.
816 visitChildren = false;
817 break;
818 }
819 case EOpFunctionCall:
820 // Function call.
821 if (visit == PreVisit)
822 out << hashFunctionName(node->getName()) << "(";
823 else if (visit == InVisit)
824 out << ", ";
825 else
zmo@google.com5601ea02011-06-10 18:23:25 +0000826 out << ")";
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700827 break;
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200828 case EOpInternalFunctionCall:
829 // Function call to an internal helper function.
830 if (visit == PreVisit)
831 out << node->getName() << "(";
832 else if (visit == InVisit)
833 out << ", ";
834 else
835 out << ")";
836 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700837 case EOpParameters:
838 // Function parameters.
839 ASSERT(visit == PreVisit);
840 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700841 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700842 out << ")";
843 visitChildren = false;
844 break;
845 case EOpDeclaration:
846 // Variable declaration.
847 if (visit == PreVisit)
848 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700849 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700850 const TIntermTyped *variable = sequence.front()->getAsTyped();
851 writeVariableType(variable->getType());
852 out << " ";
853 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000854 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700855 else if (visit == InVisit)
856 {
857 out << ", ";
858 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000859 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700860 else
861 {
862 mDeclaringVariables = false;
863 }
864 break;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700865 case EOpInvariantDeclaration:
866 // Invariant declaration.
867 ASSERT(visit == PreVisit);
868 {
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400869 const TIntermSequence *sequence = node->getSequence();
870 ASSERT(sequence && sequence->size() == 1);
871 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
872 ASSERT(symbol);
Zhenyao Mo2a517272014-10-27 16:09:57 -0700873 out << "invariant " << hashVariableName(symbol->getSymbol());
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400874 }
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700875 visitChildren = false;
876 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700877 case EOpConstructFloat:
Olli Etuahof40319e2015-03-10 14:33:00 +0200878 writeConstructorTriplet(visit, node->getType(), "float");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700879 break;
880 case EOpConstructVec2:
Olli Etuahof40319e2015-03-10 14:33:00 +0200881 writeConstructorTriplet(visit, node->getType(), "vec2");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700882 break;
883 case EOpConstructVec3:
Olli Etuahof40319e2015-03-10 14:33:00 +0200884 writeConstructorTriplet(visit, node->getType(), "vec3");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700885 break;
886 case EOpConstructVec4:
Olli Etuahof40319e2015-03-10 14:33:00 +0200887 writeConstructorTriplet(visit, node->getType(), "vec4");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700888 break;
889 case EOpConstructBool:
Olli Etuahof40319e2015-03-10 14:33:00 +0200890 writeConstructorTriplet(visit, node->getType(), "bool");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700891 break;
892 case EOpConstructBVec2:
Olli Etuahof40319e2015-03-10 14:33:00 +0200893 writeConstructorTriplet(visit, node->getType(), "bvec2");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700894 break;
895 case EOpConstructBVec3:
Olli Etuahof40319e2015-03-10 14:33:00 +0200896 writeConstructorTriplet(visit, node->getType(), "bvec3");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700897 break;
898 case EOpConstructBVec4:
Olli Etuahof40319e2015-03-10 14:33:00 +0200899 writeConstructorTriplet(visit, node->getType(), "bvec4");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700900 break;
901 case EOpConstructInt:
Olli Etuahof40319e2015-03-10 14:33:00 +0200902 writeConstructorTriplet(visit, node->getType(), "int");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700903 break;
904 case EOpConstructIVec2:
Olli Etuahof40319e2015-03-10 14:33:00 +0200905 writeConstructorTriplet(visit, node->getType(), "ivec2");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700906 break;
907 case EOpConstructIVec3:
Olli Etuahof40319e2015-03-10 14:33:00 +0200908 writeConstructorTriplet(visit, node->getType(), "ivec3");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700909 break;
910 case EOpConstructIVec4:
Olli Etuahof40319e2015-03-10 14:33:00 +0200911 writeConstructorTriplet(visit, node->getType(), "ivec4");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700912 break;
913 case EOpConstructMat2:
Olli Etuahof40319e2015-03-10 14:33:00 +0200914 writeConstructorTriplet(visit, node->getType(), "mat2");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700915 break;
916 case EOpConstructMat3:
Olli Etuahof40319e2015-03-10 14:33:00 +0200917 writeConstructorTriplet(visit, node->getType(), "mat3");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700918 break;
919 case EOpConstructMat4:
Olli Etuahof40319e2015-03-10 14:33:00 +0200920 writeConstructorTriplet(visit, node->getType(), "mat4");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700921 break;
922 case EOpConstructStruct:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700923 {
924 const TType &type = node->getType();
925 ASSERT(type.getBasicType() == EbtStruct);
Olli Etuahof40319e2015-03-10 14:33:00 +0200926 TString constructorName = hashName(type.getStruct()->name());
927 writeConstructorTriplet(visit, node->getType(), constructorName.c_str());
928 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700929 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000930
Olli Etuahoe39706d2014-12-30 16:40:36 +0200931 case EOpOuterProduct:
932 writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
933 break;
934
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700935 case EOpLessThan:
936 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
937 break;
938 case EOpGreaterThan:
939 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
940 break;
941 case EOpLessThanEqual:
942 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
943 break;
944 case EOpGreaterThanEqual:
945 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
946 break;
947 case EOpVectorEqual:
948 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
949 break;
950 case EOpVectorNotEqual:
951 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
952 break;
953 case EOpComma:
Zhenyao Mo0783efd2014-10-21 15:51:59 -0700954 writeTriplet(visit, "(", ", ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700955 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000956
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700957 case EOpMod:
958 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
959 break;
Olli Etuahob6e07a62015-02-16 12:22:10 +0200960 case EOpModf:
961 writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
962 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700963 case EOpPow:
964 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
965 break;
966 case EOpAtan:
967 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
968 break;
969 case EOpMin:
970 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
971 break;
972 case EOpMax:
973 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
974 break;
975 case EOpClamp:
976 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
977 break;
978 case EOpMix:
979 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
980 break;
981 case EOpStep:
982 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
983 break;
984 case EOpSmoothStep:
985 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
986 break;
987 case EOpDistance:
988 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
989 break;
990 case EOpDot:
991 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
992 break;
993 case EOpCross:
994 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
995 break;
996 case EOpFaceForward:
997 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
998 break;
999 case EOpReflect:
1000 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
1001 break;
1002 case EOpRefract:
1003 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
1004 break;
1005 case EOpMul:
1006 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
1007 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001008
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001009 default:
1010 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001011 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001012 return visitChildren;
1013}
1014
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001015bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001016{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001017 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001018
Zhenyao Mo7cab38b2013-10-15 12:59:30 -07001019 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +00001020 // Loop header.
1021 TLoopType loopType = node->getType();
1022 if (loopType == ELoopFor) // for loop
1023 {
Zhenyao Mo550c6002014-02-26 15:40:48 -08001024 if (!node->getUnrollFlag())
1025 {
zmo@google.com5601ea02011-06-10 18:23:25 +00001026 out << "for (";
1027 if (node->getInit())
1028 node->getInit()->traverse(this);
1029 out << "; ";
1030
1031 if (node->getCondition())
1032 node->getCondition()->traverse(this);
1033 out << "; ";
1034
1035 if (node->getExpression())
1036 node->getExpression()->traverse(this);
1037 out << ")\n";
1038 }
Zhenyao Mo550c6002014-02-26 15:40:48 -08001039 else
1040 {
1041 // Need to put a one-iteration loop here to handle break.
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001042 TIntermSequence *declSeq =
Zhenyao Mo550c6002014-02-26 15:40:48 -08001043 node->getInit()->getAsAggregate()->getSequence();
1044 TIntermSymbol *indexSymbol =
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001045 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -08001046 TString name = hashVariableName(indexSymbol->getSymbol());
1047 out << "for (int " << name << " = 0; "
1048 << name << " < 1; "
1049 << "++" << name << ")\n";
1050 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001051 }
1052 else if (loopType == ELoopWhile) // while loop
1053 {
1054 out << "while (";
1055 ASSERT(node->getCondition() != NULL);
1056 node->getCondition()->traverse(this);
1057 out << ")\n";
1058 }
1059 else // do-while loop
1060 {
1061 ASSERT(loopType == ELoopDoWhile);
1062 out << "do\n";
1063 }
1064
1065 // Loop body.
1066 if (node->getUnrollFlag())
1067 {
Zhenyao Mo550c6002014-02-26 15:40:48 -08001068 out << "{\n";
1069 mLoopUnrollStack.push(node);
1070 while (mLoopUnrollStack.satisfiesLoopCondition())
zmo@google.com5601ea02011-06-10 18:23:25 +00001071 {
1072 visitCodeBlock(node->getBody());
Zhenyao Mo550c6002014-02-26 15:40:48 -08001073 mLoopUnrollStack.step();
zmo@google.com5601ea02011-06-10 18:23:25 +00001074 }
Zhenyao Mo550c6002014-02-26 15:40:48 -08001075 mLoopUnrollStack.pop();
1076 out << "}\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001077 }
1078 else
1079 {
1080 visitCodeBlock(node->getBody());
1081 }
1082
1083 // Loop footer.
1084 if (loopType == ELoopDoWhile) // do-while loop
1085 {
1086 out << "while (";
1087 ASSERT(node->getCondition() != NULL);
1088 node->getCondition()->traverse(this);
1089 out << ");\n";
1090 }
1091 decrementDepth();
1092
1093 // No need to visit children. They have been already processed in
1094 // this function.
1095 return false;
1096}
1097
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001098bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001099{
1100 switch (node->getFlowOp())
1101 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001102 case EOpKill:
1103 writeTriplet(visit, "discard", NULL, NULL);
1104 break;
1105 case EOpBreak:
1106 writeTriplet(visit, "break", NULL, NULL);
1107 break;
1108 case EOpContinue:
1109 writeTriplet(visit, "continue", NULL, NULL);
1110 break;
1111 case EOpReturn:
1112 writeTriplet(visit, "return ", NULL, NULL);
1113 break;
1114 default:
1115 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001116 }
1117
1118 return true;
1119}
1120
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001121void TOutputGLSLBase::visitCodeBlock(TIntermNode *node)
1122{
zmo@google.com5601ea02011-06-10 18:23:25 +00001123 TInfoSinkBase &out = objSink();
1124 if (node != NULL)
1125 {
1126 node->traverse(this);
1127 // Single statements not part of a sequence need to be terminated
1128 // with semi-colon.
1129 if (isSingleStatement(node))
1130 out << ";\n";
1131 }
1132 else
1133 {
1134 out << "{\n}\n"; // Empty code block.
1135 }
1136}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001137
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001138TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001139{
1140 TInfoSinkBase out;
1141 if (type.isMatrix())
1142 {
1143 out << "mat";
1144 out << type.getNominalSize();
1145 }
1146 else if (type.isVector())
1147 {
1148 switch (type.getBasicType())
1149 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001150 case EbtFloat:
1151 out << "vec";
1152 break;
1153 case EbtInt:
1154 out << "ivec";
1155 break;
1156 case EbtBool:
1157 out << "bvec";
1158 break;
1159 default:
1160 UNREACHABLE();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001161 }
1162 out << type.getNominalSize();
1163 }
1164 else
1165 {
1166 if (type.getBasicType() == EbtStruct)
Jamie Madill98493dd2013-07-08 14:39:03 -04001167 out << hashName(type.getStruct()->name());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001168 else
1169 out << type.getBasicString();
1170 }
1171 return TString(out.c_str());
1172}
1173
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001174TString TOutputGLSLBase::hashName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001175{
1176 if (mHashFunction == NULL || name.empty())
1177 return name;
1178 NameMap::const_iterator it = mNameMap.find(name.c_str());
1179 if (it != mNameMap.end())
1180 return it->second.c_str();
1181 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
1182 mNameMap[name.c_str()] = hashedName.c_str();
1183 return hashedName;
1184}
1185
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001186TString TOutputGLSLBase::hashVariableName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001187{
Jamie Madill02f20dd2013-09-12 12:07:42 -04001188 if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001189 return name;
1190 return hashName(name);
1191}
1192
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001193TString TOutputGLSLBase::hashFunctionName(const TString &mangled_name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001194{
1195 TString name = TFunction::unmangleName(mangled_name);
Jamie Madill02f20dd2013-09-12 12:07:42 -04001196 if (mSymbolTable.findBuiltIn(mangled_name, mShaderVersion) != NULL || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001197 return translateTextureFunction(name);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001198 return hashName(name);
1199}
Jamie Madill98493dd2013-07-08 14:39:03 -04001200
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001201bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001202{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001203 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001204 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001205 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001206 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001207 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001208
1209 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001210}
1211
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001212void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001213{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001214 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001215
1216 out << "struct " << hashName(structure->name()) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001217 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001218 for (size_t i = 0; i < fields.size(); ++i)
1219 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001220 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001221 if (writeVariablePrecision(field->type()->getPrecision()))
1222 out << " ";
1223 out << getTypeName(*field->type()) << " " << hashName(field->name());
1224 if (field->type()->isArray())
1225 out << arrayBrackets(*field->type());
1226 out << ";\n";
1227 }
1228 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001229}
Jamie Madill98493dd2013-07-08 14:39:03 -04001230