blob: b769d2884242150fa84b1f89e705e7ad6756d7a9 [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}
49} // namespace
50
Zhenyao Mo9eedea02014-05-12 16:02:35 -070051TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000052 ShArrayIndexClampingStrategy clampingStrategy,
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000053 ShHashFunction64 hashFunction,
Zhenyao Mo9eedea02014-05-12 16:02:35 -070054 NameMap &nameMap,
55 TSymbolTable &symbolTable,
Jamie Madill02f20dd2013-09-12 12:07:42 -040056 int shaderVersion)
zmo@google.com5601ea02011-06-10 18:23:25 +000057 : TIntermTraverser(true, true, true),
58 mObjSink(objSink),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000059 mDeclaringVariables(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000060 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000061 mHashFunction(hashFunction),
62 mNameMap(nameMap),
Jamie Madill02f20dd2013-09-12 12:07:42 -040063 mSymbolTable(symbolTable),
64 mShaderVersion(shaderVersion)
zmo@google.com5601ea02011-06-10 18:23:25 +000065{
66}
67
Zhenyao Mo9eedea02014-05-12 16:02:35 -070068void TOutputGLSLBase::writeTriplet(
69 Visit visit, const char *preStr, const char *inStr, const char *postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000070{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070071 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +000072 if (visit == PreVisit && preStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000073 out << preStr;
zmo@google.com5601ea02011-06-10 18:23:25 +000074 else if (visit == InVisit && inStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000075 out << inStr;
zmo@google.com5601ea02011-06-10 18:23:25 +000076 else if (visit == PostVisit && postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000077 out << postStr;
zmo@google.com5601ea02011-06-10 18:23:25 +000078}
79
Zhenyao Mo9eedea02014-05-12 16:02:35 -070080void TOutputGLSLBase::writeBuiltInFunctionTriplet(
81 Visit visit, const char *preStr, bool useEmulatedFunction)
zmo@google.com5601ea02011-06-10 18:23:25 +000082{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070083 TString preString = useEmulatedFunction ?
84 BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
85 writeTriplet(visit, preString.c_str(), ", ", ")");
86}
87
88void TOutputGLSLBase::writeVariableType(const TType &type)
89{
90 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +000091 TQualifier qualifier = type.getQualifier();
Jamie Madill3b5c2da2014-08-19 15:23:32 -040092 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -040093 {
zmo@google.com5601ea02011-06-10 18:23:25 +000094 out << type.getQualifierString() << " ";
Jamie Madill1c28e1f2014-08-04 11:37:54 -040095 }
zmo@google.com5601ea02011-06-10 18:23:25 +000096 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -070097 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +000098 {
Jamie Madill01f85ac2014-06-06 11:55:04 -040099 TStructure *structure = type.getStruct();
100
101 declareStruct(structure);
102
103 if (!structure->name().empty())
104 {
105 mDeclaredStructs.insert(structure->uniqueId());
106 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000107 }
108 else
109 {
110 if (writeVariablePrecision(type.getPrecision()))
111 out << " ";
112 out << getTypeName(type);
113 }
114}
115
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700116void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000117{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700118 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000119 for (TIntermSequence::const_iterator iter = args.begin();
120 iter != args.end(); ++iter)
121 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700122 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000123 ASSERT(arg != NULL);
124
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700125 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000126 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000127
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700128 const TString &name = arg->getSymbol();
zmo@google.com5601ea02011-06-10 18:23:25 +0000129 if (!name.empty())
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000130 out << " " << hashName(name);
zmo@google.com5601ea02011-06-10 18:23:25 +0000131 if (type.isArray())
132 out << arrayBrackets(type);
133
134 // Put a comma if this is not the last argument.
135 if (iter != args.end() - 1)
136 out << ", ";
137 }
138}
139
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700140const ConstantUnion *TOutputGLSLBase::writeConstantUnion(
141 const TType &type, const ConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000142{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700143 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000144
145 if (type.getBasicType() == EbtStruct)
146 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700147 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -0400148 out << hashName(structure->name()) << "(";
149
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700150 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400151 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000152 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700153 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000154 ASSERT(fieldType != NULL);
155 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700156 if (i != fields.size() - 1)
157 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000158 }
159 out << ")";
160 }
161 else
162 {
Jamie Madill94bf7f22013-07-08 13:31:15 -0400163 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000164 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700165 if (writeType)
166 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400167 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000168 {
169 switch (pConstUnion->getType())
170 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700171 case EbtFloat:
172 out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
173 break;
174 case EbtInt:
175 out << pConstUnion->getIConst();
176 break;
177 case EbtBool:
178 out << pConstUnion->getBConst();
179 break;
180 default: UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000181 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700182 if (i != size - 1)
183 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000184 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700185 if (writeType)
186 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000187 }
188 return pConstUnion;
189}
190
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700191void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000192{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700193 TInfoSinkBase &out = objSink();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800194 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
195 out << mLoopUnrollStack.getLoopIndexValue(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000196 else
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000197 out << hashVariableName(node->getSymbol());
zmo@google.com5601ea02011-06-10 18:23:25 +0000198
199 if (mDeclaringVariables && node->getType().isArray())
200 out << arrayBrackets(node->getType());
201}
202
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700203void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000204{
205 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
206}
207
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700208bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000209{
210 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700211 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000212 switch (node->getOp())
213 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700214 case EOpInitialize:
215 if (visit == InVisit)
216 {
217 out << " = ";
218 // RHS of initialize is not being declared.
219 mDeclaringVariables = false;
220 }
221 break;
222 case EOpAssign:
223 writeTriplet(visit, "(", " = ", ")");
224 break;
225 case EOpAddAssign:
226 writeTriplet(visit, "(", " += ", ")");
227 break;
228 case EOpSubAssign:
229 writeTriplet(visit, "(", " -= ", ")");
230 break;
231 case EOpDivAssign:
232 writeTriplet(visit, "(", " /= ", ")");
233 break;
Olli Etuahoff805cc2015-02-13 10:59:34 +0200234 case EOpIModAssign:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000235 writeTriplet(visit, "(", " %= ", ")");
236 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700237 // Notice the fall-through.
238 case EOpMulAssign:
239 case EOpVectorTimesMatrixAssign:
240 case EOpVectorTimesScalarAssign:
241 case EOpMatrixTimesScalarAssign:
242 case EOpMatrixTimesMatrixAssign:
243 writeTriplet(visit, "(", " *= ", ")");
244 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200245 case EOpBitShiftLeftAssign:
246 writeTriplet(visit, "(", " <<= ", ")");
247 break;
248 case EOpBitShiftRightAssign:
249 writeTriplet(visit, "(", " >>= ", ")");
250 break;
251 case EOpBitwiseAndAssign:
252 writeTriplet(visit, "(", " &= ", ")");
253 break;
254 case EOpBitwiseXorAssign:
255 writeTriplet(visit, "(", " ^= ", ")");
256 break;
257 case EOpBitwiseOrAssign:
258 writeTriplet(visit, "(", " |= ", ")");
259 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700260
261 case EOpIndexDirect:
262 writeTriplet(visit, NULL, "[", "]");
263 break;
264 case EOpIndexIndirect:
265 if (node->getAddIndexClamp())
266 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000267 if (visit == InVisit)
268 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700269 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
270 out << "[int(clamp(float(";
271 else
272 out << "[webgl_int_clamp(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000273 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700274 else if (visit == PostVisit)
275 {
276 int maxSize;
277 TIntermTyped *left = node->getLeft();
278 TType leftType = left->getType();
zmo@google.com5601ea02011-06-10 18:23:25 +0000279
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700280 if (left->isArray())
281 {
282 // The shader will fail validation if the array length is not > 0.
283 maxSize = leftType.getArraySize() - 1;
284 }
285 else
286 {
287 maxSize = leftType.getNominalSize() - 1;
288 }
289
290 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
291 out << "), 0.0, float(" << maxSize << ")))]";
292 else
293 out << ", 0, " << maxSize << ")]";
294 }
295 }
296 else
297 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000298 writeTriplet(visit, NULL, "[", "]");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700299 }
300 break;
301 case EOpIndexDirectStruct:
302 if (visit == InVisit)
303 {
304 // Here we are writing out "foo.bar", where "foo" is struct
305 // and "bar" is field. In AST, it is represented as a binary
306 // node, where left child represents "foo" and right child "bar".
307 // The node itself represents ".". The struct field "bar" is
308 // actually stored as an index into TStructure::fields.
309 out << ".";
310 const TStructure *structure = node->getLeft()->getType().getStruct();
311 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
312 const TField *field = structure->fields()[index->getIConst(0)];
313
314 TString fieldName = field->name();
315 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
316 fieldName = hashName(fieldName);
317
318 out << fieldName;
319 visitChildren = false;
320 }
321 break;
322 case EOpVectorSwizzle:
323 if (visit == InVisit)
324 {
325 out << ".";
326 TIntermAggregate *rightChild = node->getRight()->getAsAggregate();
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700327 TIntermSequence *sequence = rightChild->getSequence();
328 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); ++sit)
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000329 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700330 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
331 ASSERT(element->getBasicType() == EbtInt);
332 ASSERT(element->getNominalSize() == 1);
333 const ConstantUnion& data = element->getUnionArrayPointer()[0];
334 ASSERT(data.getType() == EbtInt);
335 switch (data.getIConst())
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000336 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700337 case 0:
338 out << "x";
339 break;
340 case 1:
341 out << "y";
342 break;
343 case 2:
344 out << "z";
345 break;
346 case 3:
347 out << "w";
348 break;
349 default:
350 UNREACHABLE();
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000351 }
352 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700353 visitChildren = false;
354 }
355 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000356
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700357 case EOpAdd:
358 writeTriplet(visit, "(", " + ", ")");
359 break;
360 case EOpSub:
361 writeTriplet(visit, "(", " - ", ")");
362 break;
363 case EOpMul:
364 writeTriplet(visit, "(", " * ", ")");
365 break;
366 case EOpDiv:
367 writeTriplet(visit, "(", " / ", ")");
368 break;
Olli Etuahoff805cc2015-02-13 10:59:34 +0200369 case EOpIMod:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000370 writeTriplet(visit, "(", " % ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700371 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200372 case EOpBitShiftLeft:
373 writeTriplet(visit, "(", " << ", ")");
374 break;
375 case EOpBitShiftRight:
376 writeTriplet(visit, "(", " >> ", ")");
377 break;
378 case EOpBitwiseAnd:
379 writeTriplet(visit, "(", " & ", ")");
380 break;
381 case EOpBitwiseXor:
382 writeTriplet(visit, "(", " ^ ", ")");
383 break;
384 case EOpBitwiseOr:
385 writeTriplet(visit, "(", " | ", ")");
386 break;
387
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700388 case EOpEqual:
389 writeTriplet(visit, "(", " == ", ")");
390 break;
391 case EOpNotEqual:
392 writeTriplet(visit, "(", " != ", ")");
393 break;
394 case EOpLessThan:
395 writeTriplet(visit, "(", " < ", ")");
396 break;
397 case EOpGreaterThan:
398 writeTriplet(visit, "(", " > ", ")");
399 break;
400 case EOpLessThanEqual:
401 writeTriplet(visit, "(", " <= ", ")");
402 break;
403 case EOpGreaterThanEqual:
404 writeTriplet(visit, "(", " >= ", ")");
405 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000406
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700407 // Notice the fall-through.
408 case EOpVectorTimesScalar:
409 case EOpVectorTimesMatrix:
410 case EOpMatrixTimesVector:
411 case EOpMatrixTimesScalar:
412 case EOpMatrixTimesMatrix:
413 writeTriplet(visit, "(", " * ", ")");
414 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000415
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700416 case EOpLogicalOr:
417 writeTriplet(visit, "(", " || ", ")");
418 break;
419 case EOpLogicalXor:
420 writeTriplet(visit, "(", " ^^ ", ")");
421 break;
422 case EOpLogicalAnd:
423 writeTriplet(visit, "(", " && ", ")");
424 break;
425 default:
426 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000427 }
428
429 return visitChildren;
430}
431
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700432bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000433{
zmo@google.com32e97312011-08-24 01:03:11 +0000434 TString preString;
435 TString postString = ")";
436
zmo@google.com5601ea02011-06-10 18:23:25 +0000437 switch (node->getOp())
438 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700439 case EOpNegative: preString = "(-"; break;
Zhenyao Mode1e00e2014-10-09 16:55:32 -0700440 case EOpPositive: preString = "(+"; break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700441 case EOpVectorLogicalNot: preString = "not("; break;
442 case EOpLogicalNot: preString = "(!"; break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200443 case EOpBitwiseNot: preString = "(~"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000444
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700445 case EOpPostIncrement: preString = "("; postString = "++)"; break;
446 case EOpPostDecrement: preString = "("; postString = "--)"; break;
447 case EOpPreIncrement: preString = "(++"; break;
448 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000449
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700450 case EOpRadians:
451 preString = "radians(";
452 break;
453 case EOpDegrees:
454 preString = "degrees(";
455 break;
456 case EOpSin:
457 preString = "sin(";
458 break;
459 case EOpCos:
460 preString = "cos(";
461 break;
462 case EOpTan:
463 preString = "tan(";
464 break;
465 case EOpAsin:
466 preString = "asin(";
467 break;
468 case EOpAcos:
469 preString = "acos(";
470 break;
471 case EOpAtan:
472 preString = "atan(";
473 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000474
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200475 case EOpSinh:
476 preString = "sinh(";
477 break;
478 case EOpCosh:
479 preString = "cosh(";
480 break;
481 case EOpTanh:
482 preString = "tanh(";
483 break;
484 case EOpAsinh:
485 preString = "asinh(";
486 break;
487 case EOpAcosh:
488 preString = "acosh(";
489 break;
490 case EOpAtanh:
491 preString = "atanh(";
492 break;
493
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700494 case EOpExp:
495 preString = "exp(";
496 break;
497 case EOpLog:
498 preString = "log(";
499 break;
500 case EOpExp2:
501 preString = "exp2(";
502 break;
503 case EOpLog2:
504 preString = "log2(";
505 break;
506 case EOpSqrt:
507 preString = "sqrt(";
508 break;
509 case EOpInverseSqrt:
510 preString = "inversesqrt(";
511 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000512
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700513 case EOpAbs:
514 preString = "abs(";
515 break;
516 case EOpSign:
517 preString = "sign(";
518 break;
519 case EOpFloor:
520 preString = "floor(";
521 break;
522 case EOpCeil:
523 preString = "ceil(";
524 break;
525 case EOpFract:
526 preString = "fract(";
527 break;
Arun Patole0c1726e2015-02-18 14:35:02 +0530528 case EOpIsNan:
529 preString = "isnan(";
530 break;
531 case EOpIsInf:
532 preString = "isinf(";
533 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000534
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200535 case EOpFloatBitsToInt:
536 preString = "floatBitsToInt(";
537 break;
538 case EOpFloatBitsToUint:
539 preString = "floatBitsToUint(";
540 break;
541 case EOpIntBitsToFloat:
542 preString = "intBitsToFloat(";
543 break;
544 case EOpUintBitsToFloat:
545 preString = "uintBitsToFloat(";
546 break;
547
Olli Etuaho7700ff62015-01-15 12:16:29 +0200548 case EOpPackSnorm2x16:
549 preString = "packSnorm2x16(";
550 break;
551 case EOpPackUnorm2x16:
552 preString = "packUnorm2x16(";
553 break;
554 case EOpPackHalf2x16:
555 preString = "packHalf2x16(";
556 break;
557 case EOpUnpackSnorm2x16:
558 preString = "unpackSnorm2x16(";
559 break;
560 case EOpUnpackUnorm2x16:
561 preString = "unpackUnorm2x16(";
562 break;
563 case EOpUnpackHalf2x16:
564 preString = "unpackHalf2x16(";
565 break;
566
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700567 case EOpLength:
568 preString = "length(";
569 break;
570 case EOpNormalize:
571 preString = "normalize(";
572 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000573
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700574 case EOpDFdx:
575 preString = "dFdx(";
576 break;
577 case EOpDFdy:
578 preString = "dFdy(";
579 break;
580 case EOpFwidth:
581 preString = "fwidth(";
582 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000583
Olli Etuahoe39706d2014-12-30 16:40:36 +0200584 case EOpTranspose:
585 preString = "transpose(";
586 break;
587 case EOpDeterminant:
588 preString = "determinant(";
589 break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +0200590 case EOpInverse:
591 preString = "inverse(";
592 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200593
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700594 case EOpAny:
595 preString = "any(";
596 break;
597 case EOpAll:
598 preString = "all(";
599 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000600
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700601 default:
602 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000603 }
604
zmo@google.com32e97312011-08-24 01:03:11 +0000605 if (visit == PreVisit && node->getUseEmulatedFunction())
606 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
607 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
608
zmo@google.com5601ea02011-06-10 18:23:25 +0000609 return true;
610}
611
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700612bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000613{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700614 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000615
616 if (node->usesTernaryOperator())
617 {
618 // Notice two brackets at the beginning and end. The outer ones
619 // encapsulate the whole ternary expression. This preserves the
620 // order of precedence when ternary expressions are used in a
621 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
622 out << "((";
623 node->getCondition()->traverse(this);
624 out << ") ? (";
625 node->getTrueBlock()->traverse(this);
626 out << ") : (";
627 node->getFalseBlock()->traverse(this);
628 out << "))";
629 }
630 else
631 {
632 out << "if (";
633 node->getCondition()->traverse(this);
634 out << ")\n";
635
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700636 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000637 visitCodeBlock(node->getTrueBlock());
638
639 if (node->getFalseBlock())
640 {
641 out << "else\n";
642 visitCodeBlock(node->getFalseBlock());
643 }
644 decrementDepth();
645 }
646 return false;
647}
648
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200649bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200650{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200651 if (node->getStatementList())
652 {
653 writeTriplet(visit, "switch (", ") ", nullptr);
654 // The curly braces get written when visiting the statementList aggregate
655 }
656 else
657 {
658 // No statementList, so it won't output curly braces
659 writeTriplet(visit, "switch (", ") {", "}\n");
660 }
661 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200662}
663
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200664bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200665{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200666 if (node->hasCondition())
667 {
668 writeTriplet(visit, "case (", nullptr, "):\n");
669 return true;
670 }
671 else
672 {
673 TInfoSinkBase &out = objSink();
674 out << "default:\n";
675 return false;
676 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200677}
678
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700679bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000680{
681 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700682 TInfoSinkBase &out = objSink();
zmo@google.comf420c422011-09-12 18:27:59 +0000683 TString preString;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700684 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000685 switch (node->getOp())
686 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700687 case EOpSequence:
688 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700689 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700690 {
691 out << "{\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000692 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000693
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700694 incrementDepth(node);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700695 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
696 iter != node->getSequence()->end(); ++iter)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700697 {
Austin Kinross3ae64652015-01-26 15:51:39 -0800698 TIntermNode *curNode = *iter;
699 ASSERT(curNode != NULL);
700 curNode->traverse(this);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700701
Austin Kinross3ae64652015-01-26 15:51:39 -0800702 if (isSingleStatement(curNode))
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700703 out << ";\n";
704 }
705 decrementDepth();
706
707 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700708 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700709 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700710 out << "}\n";
711 }
712 visitChildren = false;
713 break;
714 case EOpPrototype:
715 // Function declaration.
716 ASSERT(visit == PreVisit);
717 writeVariableType(node->getType());
Olli Etuaho76acee82014-11-04 13:44:03 +0200718 out << " " << hashFunctionName(node->getName());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700719
720 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700721 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700722 out << ")";
723
724 visitChildren = false;
725 break;
726 case EOpFunction: {
727 // Function definition.
728 ASSERT(visit == PreVisit);
729 writeVariableType(node->getType());
730 out << " " << hashFunctionName(node->getName());
731
732 incrementDepth(node);
733 // Function definition node contains one or two children nodes
734 // representing function parameters and function body. The latter
735 // is not present in case of empty function bodies.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700736 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700737 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
738 TIntermSequence::const_iterator seqIter = sequence.begin();
739
740 // Traverse function parameters.
741 TIntermAggregate *params = (*seqIter)->getAsAggregate();
742 ASSERT(params != NULL);
743 ASSERT(params->getOp() == EOpParameters);
744 params->traverse(this);
745
746 // Traverse function body.
747 TIntermAggregate *body = ++seqIter != sequence.end() ?
748 (*seqIter)->getAsAggregate() : NULL;
749 visitCodeBlock(body);
750 decrementDepth();
751
752 // Fully processed; no need to visit children.
753 visitChildren = false;
754 break;
755 }
756 case EOpFunctionCall:
757 // Function call.
758 if (visit == PreVisit)
759 out << hashFunctionName(node->getName()) << "(";
760 else if (visit == InVisit)
761 out << ", ";
762 else
zmo@google.com5601ea02011-06-10 18:23:25 +0000763 out << ")";
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700764 break;
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200765 case EOpInternalFunctionCall:
766 // Function call to an internal helper function.
767 if (visit == PreVisit)
768 out << node->getName() << "(";
769 else if (visit == InVisit)
770 out << ", ";
771 else
772 out << ")";
773 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700774 case EOpParameters:
775 // Function parameters.
776 ASSERT(visit == PreVisit);
777 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700778 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700779 out << ")";
780 visitChildren = false;
781 break;
782 case EOpDeclaration:
783 // Variable declaration.
784 if (visit == PreVisit)
785 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700786 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700787 const TIntermTyped *variable = sequence.front()->getAsTyped();
788 writeVariableType(variable->getType());
789 out << " ";
790 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000791 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700792 else if (visit == InVisit)
793 {
794 out << ", ";
795 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000796 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700797 else
798 {
799 mDeclaringVariables = false;
800 }
801 break;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700802 case EOpInvariantDeclaration:
803 // Invariant declaration.
804 ASSERT(visit == PreVisit);
805 {
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400806 const TIntermSequence *sequence = node->getSequence();
807 ASSERT(sequence && sequence->size() == 1);
808 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
809 ASSERT(symbol);
Zhenyao Mo2a517272014-10-27 16:09:57 -0700810 out << "invariant " << hashVariableName(symbol->getSymbol());
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400811 }
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700812 visitChildren = false;
813 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700814 case EOpConstructFloat:
815 writeTriplet(visit, "float(", NULL, ")");
816 break;
817 case EOpConstructVec2:
818 writeBuiltInFunctionTriplet(visit, "vec2(", false);
819 break;
820 case EOpConstructVec3:
821 writeBuiltInFunctionTriplet(visit, "vec3(", false);
822 break;
823 case EOpConstructVec4:
824 writeBuiltInFunctionTriplet(visit, "vec4(", false);
825 break;
826 case EOpConstructBool:
827 writeTriplet(visit, "bool(", NULL, ")");
828 break;
829 case EOpConstructBVec2:
830 writeBuiltInFunctionTriplet(visit, "bvec2(", false);
831 break;
832 case EOpConstructBVec3:
833 writeBuiltInFunctionTriplet(visit, "bvec3(", false);
834 break;
835 case EOpConstructBVec4:
836 writeBuiltInFunctionTriplet(visit, "bvec4(", false);
837 break;
838 case EOpConstructInt:
839 writeTriplet(visit, "int(", NULL, ")");
840 break;
841 case EOpConstructIVec2:
842 writeBuiltInFunctionTriplet(visit, "ivec2(", false);
843 break;
844 case EOpConstructIVec3:
845 writeBuiltInFunctionTriplet(visit, "ivec3(", false);
846 break;
847 case EOpConstructIVec4:
848 writeBuiltInFunctionTriplet(visit, "ivec4(", false);
849 break;
850 case EOpConstructMat2:
851 writeBuiltInFunctionTriplet(visit, "mat2(", false);
852 break;
853 case EOpConstructMat3:
854 writeBuiltInFunctionTriplet(visit, "mat3(", false);
855 break;
856 case EOpConstructMat4:
857 writeBuiltInFunctionTriplet(visit, "mat4(", false);
858 break;
859 case EOpConstructStruct:
860 if (visit == PreVisit)
861 {
862 const TType &type = node->getType();
863 ASSERT(type.getBasicType() == EbtStruct);
864 out << hashName(type.getStruct()->name()) << "(";
865 }
866 else if (visit == InVisit)
867 {
868 out << ", ";
869 }
870 else
871 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000872 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000873 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700874 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000875
Olli Etuahoe39706d2014-12-30 16:40:36 +0200876 case EOpOuterProduct:
877 writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
878 break;
879
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700880 case EOpLessThan:
881 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
882 break;
883 case EOpGreaterThan:
884 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
885 break;
886 case EOpLessThanEqual:
887 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
888 break;
889 case EOpGreaterThanEqual:
890 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
891 break;
892 case EOpVectorEqual:
893 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
894 break;
895 case EOpVectorNotEqual:
896 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
897 break;
898 case EOpComma:
Zhenyao Mo0783efd2014-10-21 15:51:59 -0700899 writeTriplet(visit, "(", ", ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700900 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000901
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700902 case EOpMod:
903 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
904 break;
Olli Etuahob6e07a62015-02-16 12:22:10 +0200905 case EOpModf:
906 writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
907 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700908 case EOpPow:
909 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
910 break;
911 case EOpAtan:
912 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
913 break;
914 case EOpMin:
915 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
916 break;
917 case EOpMax:
918 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
919 break;
920 case EOpClamp:
921 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
922 break;
923 case EOpMix:
924 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
925 break;
926 case EOpStep:
927 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
928 break;
929 case EOpSmoothStep:
930 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
931 break;
932 case EOpDistance:
933 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
934 break;
935 case EOpDot:
936 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
937 break;
938 case EOpCross:
939 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
940 break;
941 case EOpFaceForward:
942 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
943 break;
944 case EOpReflect:
945 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
946 break;
947 case EOpRefract:
948 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
949 break;
950 case EOpMul:
951 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
952 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000953
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700954 default:
955 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000956 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000957 return visitChildren;
958}
959
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700960bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000961{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700962 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000963
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700964 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000965 // Loop header.
966 TLoopType loopType = node->getType();
967 if (loopType == ELoopFor) // for loop
968 {
Zhenyao Mo550c6002014-02-26 15:40:48 -0800969 if (!node->getUnrollFlag())
970 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000971 out << "for (";
972 if (node->getInit())
973 node->getInit()->traverse(this);
974 out << "; ";
975
976 if (node->getCondition())
977 node->getCondition()->traverse(this);
978 out << "; ";
979
980 if (node->getExpression())
981 node->getExpression()->traverse(this);
982 out << ")\n";
983 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800984 else
985 {
986 // Need to put a one-iteration loop here to handle break.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700987 TIntermSequence *declSeq =
Zhenyao Mo550c6002014-02-26 15:40:48 -0800988 node->getInit()->getAsAggregate()->getSequence();
989 TIntermSymbol *indexSymbol =
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700990 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800991 TString name = hashVariableName(indexSymbol->getSymbol());
992 out << "for (int " << name << " = 0; "
993 << name << " < 1; "
994 << "++" << name << ")\n";
995 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000996 }
997 else if (loopType == ELoopWhile) // while loop
998 {
999 out << "while (";
1000 ASSERT(node->getCondition() != NULL);
1001 node->getCondition()->traverse(this);
1002 out << ")\n";
1003 }
1004 else // do-while loop
1005 {
1006 ASSERT(loopType == ELoopDoWhile);
1007 out << "do\n";
1008 }
1009
1010 // Loop body.
1011 if (node->getUnrollFlag())
1012 {
Zhenyao Mo550c6002014-02-26 15:40:48 -08001013 out << "{\n";
1014 mLoopUnrollStack.push(node);
1015 while (mLoopUnrollStack.satisfiesLoopCondition())
zmo@google.com5601ea02011-06-10 18:23:25 +00001016 {
1017 visitCodeBlock(node->getBody());
Zhenyao Mo550c6002014-02-26 15:40:48 -08001018 mLoopUnrollStack.step();
zmo@google.com5601ea02011-06-10 18:23:25 +00001019 }
Zhenyao Mo550c6002014-02-26 15:40:48 -08001020 mLoopUnrollStack.pop();
1021 out << "}\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001022 }
1023 else
1024 {
1025 visitCodeBlock(node->getBody());
1026 }
1027
1028 // Loop footer.
1029 if (loopType == ELoopDoWhile) // do-while loop
1030 {
1031 out << "while (";
1032 ASSERT(node->getCondition() != NULL);
1033 node->getCondition()->traverse(this);
1034 out << ");\n";
1035 }
1036 decrementDepth();
1037
1038 // No need to visit children. They have been already processed in
1039 // this function.
1040 return false;
1041}
1042
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001043bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001044{
1045 switch (node->getFlowOp())
1046 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001047 case EOpKill:
1048 writeTriplet(visit, "discard", NULL, NULL);
1049 break;
1050 case EOpBreak:
1051 writeTriplet(visit, "break", NULL, NULL);
1052 break;
1053 case EOpContinue:
1054 writeTriplet(visit, "continue", NULL, NULL);
1055 break;
1056 case EOpReturn:
1057 writeTriplet(visit, "return ", NULL, NULL);
1058 break;
1059 default:
1060 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001061 }
1062
1063 return true;
1064}
1065
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001066void TOutputGLSLBase::visitCodeBlock(TIntermNode *node)
1067{
zmo@google.com5601ea02011-06-10 18:23:25 +00001068 TInfoSinkBase &out = objSink();
1069 if (node != NULL)
1070 {
1071 node->traverse(this);
1072 // Single statements not part of a sequence need to be terminated
1073 // with semi-colon.
1074 if (isSingleStatement(node))
1075 out << ";\n";
1076 }
1077 else
1078 {
1079 out << "{\n}\n"; // Empty code block.
1080 }
1081}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001082
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001083TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001084{
1085 TInfoSinkBase out;
1086 if (type.isMatrix())
1087 {
1088 out << "mat";
1089 out << type.getNominalSize();
1090 }
1091 else if (type.isVector())
1092 {
1093 switch (type.getBasicType())
1094 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001095 case EbtFloat:
1096 out << "vec";
1097 break;
1098 case EbtInt:
1099 out << "ivec";
1100 break;
1101 case EbtBool:
1102 out << "bvec";
1103 break;
1104 default:
1105 UNREACHABLE();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001106 }
1107 out << type.getNominalSize();
1108 }
1109 else
1110 {
1111 if (type.getBasicType() == EbtStruct)
Jamie Madill98493dd2013-07-08 14:39:03 -04001112 out << hashName(type.getStruct()->name());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001113 else
1114 out << type.getBasicString();
1115 }
1116 return TString(out.c_str());
1117}
1118
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001119TString TOutputGLSLBase::hashName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001120{
1121 if (mHashFunction == NULL || name.empty())
1122 return name;
1123 NameMap::const_iterator it = mNameMap.find(name.c_str());
1124 if (it != mNameMap.end())
1125 return it->second.c_str();
1126 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
1127 mNameMap[name.c_str()] = hashedName.c_str();
1128 return hashedName;
1129}
1130
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001131TString TOutputGLSLBase::hashVariableName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001132{
Jamie Madill02f20dd2013-09-12 12:07:42 -04001133 if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001134 return name;
1135 return hashName(name);
1136}
1137
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001138TString TOutputGLSLBase::hashFunctionName(const TString &mangled_name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001139{
1140 TString name = TFunction::unmangleName(mangled_name);
Jamie Madill02f20dd2013-09-12 12:07:42 -04001141 if (mSymbolTable.findBuiltIn(mangled_name, mShaderVersion) != NULL || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001142 return translateTextureFunction(name);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001143 return hashName(name);
1144}
Jamie Madill98493dd2013-07-08 14:39:03 -04001145
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001146bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001147{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001148 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001149 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001150 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001151 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001152 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001153
1154 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001155}
1156
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001157void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001158{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001159 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001160
1161 out << "struct " << hashName(structure->name()) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001162 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001163 for (size_t i = 0; i < fields.size(); ++i)
1164 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001165 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001166 if (writeVariablePrecision(field->type()->getPrecision()))
1167 out << " ";
1168 out << getTypeName(*field->type()) << " " << hashName(field->name());
1169 if (field->type()->isArray())
1170 out << arrayBrackets(*field->type());
1171 out << ";\n";
1172 }
1173 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001174}
Jamie Madill98493dd2013-07-08 14:39:03 -04001175