blob: 899b16679573d52cfcc13fb9fad52125989a8978 [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"
Olli Etuahod57e0db2015-04-24 15:05:08 +03008
9#include "common/debug.h"
zmo@google.com5601ea02011-06-10 18:23:25 +000010
daniel@transgaming.com773ff742013-01-11 04:12:51 +000011#include <cfloat>
daniel@transgaming.com6c1203f2013-01-11 04:12:43 +000012
zmo@google.com5601ea02011-06-10 18:23:25 +000013namespace
14{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070015TString arrayBrackets(const TType &type)
zmo@google.com5601ea02011-06-10 18:23:25 +000016{
17 ASSERT(type.isArray());
18 TInfoSinkBase out;
19 out << "[" << type.getArraySize() << "]";
20 return TString(out.c_str());
21}
22
Zhenyao Mo9eedea02014-05-12 16:02:35 -070023bool isSingleStatement(TIntermNode *node)
24{
25 if (const TIntermAggregate *aggregate = node->getAsAggregate())
zmo@google.com5601ea02011-06-10 18:23:25 +000026 {
27 return (aggregate->getOp() != EOpFunction) &&
28 (aggregate->getOp() != EOpSequence);
29 }
Olli Etuaho57961272016-09-14 13:57:46 +030030 else if (node->getAsIfElseNode())
zmo@google.com5601ea02011-06-10 18:23:25 +000031 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +030032 return false;
zmo@google.com5601ea02011-06-10 18:23:25 +000033 }
34 else if (node->getAsLoopNode())
35 {
36 return false;
37 }
Olli Etuaho01cd8af2015-02-20 10:39:20 +020038 else if (node->getAsSwitchNode())
39 {
40 return false;
41 }
42 else if (node->getAsCaseNode())
43 {
44 return false;
45 }
zmo@google.com5601ea02011-06-10 18:23:25 +000046 return true;
47}
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080048
zmo@google.com5601ea02011-06-10 18:23:25 +000049} // 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,
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080056 int shaderVersion,
57 ShShaderOutput output)
zmo@google.com5601ea02011-06-10 18:23:25 +000058 : TIntermTraverser(true, true, true),
59 mObjSink(objSink),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000060 mDeclaringVariables(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000061 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000062 mHashFunction(hashFunction),
63 mNameMap(nameMap),
Jamie Madill02f20dd2013-09-12 12:07:42 -040064 mSymbolTable(symbolTable),
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080065 mShaderVersion(shaderVersion),
66 mOutput(output)
zmo@google.com5601ea02011-06-10 18:23:25 +000067{
68}
69
Zhenyao Mo9eedea02014-05-12 16:02:35 -070070void TOutputGLSLBase::writeTriplet(
71 Visit visit, const char *preStr, const char *inStr, const char *postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000072{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070073 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +000074 if (visit == PreVisit && preStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000075 out << preStr;
zmo@google.com5601ea02011-06-10 18:23:25 +000076 else if (visit == InVisit && inStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000077 out << inStr;
zmo@google.com5601ea02011-06-10 18:23:25 +000078 else if (visit == PostVisit && postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000079 out << postStr;
zmo@google.com5601ea02011-06-10 18:23:25 +000080}
81
Zhenyao Mo9eedea02014-05-12 16:02:35 -070082void TOutputGLSLBase::writeBuiltInFunctionTriplet(
83 Visit visit, const char *preStr, bool useEmulatedFunction)
zmo@google.com5601ea02011-06-10 18:23:25 +000084{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070085 TString preString = useEmulatedFunction ?
86 BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
87 writeTriplet(visit, preString.c_str(), ", ", ")");
88}
89
Olli Etuahoae69d7e2015-10-07 17:19:50 +030090void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
91{
92 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
93 {
94 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
95 if (layoutQualifier.location >= 0)
96 {
97 TInfoSinkBase &out = objSink();
98 out << "layout(location = " << layoutQualifier.location << ") ";
99 }
100 }
101}
102
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700103void TOutputGLSLBase::writeVariableType(const TType &type)
104{
105 TInfoSinkBase &out = objSink();
Olli Etuaho214c2d82015-04-27 14:49:13 +0300106 if (type.isInvariant())
107 {
108 out << "invariant ";
109 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400110 if (type.getBasicType() == EbtInterfaceBlock)
111 {
112 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
113 declareInterfaceBlockLayout(interfaceBlock);
114 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000115 TQualifier qualifier = type.getQualifier();
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400116 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400117 {
Qingqing Dengad0d0792015-04-08 14:25:06 -0700118 if (IsGLSL130OrNewer(mOutput))
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800119 {
120 switch (qualifier)
121 {
122 case EvqAttribute:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300123 out << "in ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800124 break;
125 case EvqVaryingIn:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300126 out << "in ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800127 break;
128 case EvqVaryingOut:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300129 out << "out ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800130 break;
131 default:
132 out << type.getQualifierString() << " ";
133 break;
134 }
135 }
136 else
137 {
138 out << type.getQualifierString() << " ";
139 }
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400140 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000141 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700142 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000143 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400144 TStructure *structure = type.getStruct();
145
146 declareStruct(structure);
147
148 if (!structure->name().empty())
149 {
150 mDeclaredStructs.insert(structure->uniqueId());
151 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000152 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400153 else if (type.getBasicType() == EbtInterfaceBlock)
154 {
155 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
156 declareInterfaceBlock(interfaceBlock);
157 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000158 else
159 {
160 if (writeVariablePrecision(type.getPrecision()))
161 out << " ";
162 out << getTypeName(type);
163 }
164}
165
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700166void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000167{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700168 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000169 for (TIntermSequence::const_iterator iter = args.begin();
170 iter != args.end(); ++iter)
171 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700172 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000173 ASSERT(arg != NULL);
174
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700175 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000176 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000177
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700178 const TString &name = arg->getSymbol();
zmo@google.com5601ea02011-06-10 18:23:25 +0000179 if (!name.empty())
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000180 out << " " << hashName(name);
zmo@google.com5601ea02011-06-10 18:23:25 +0000181 if (type.isArray())
182 out << arrayBrackets(type);
183
184 // Put a comma if this is not the last argument.
185 if (iter != args.end() - 1)
186 out << ", ";
187 }
188}
189
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400190const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
191 const TType &type, const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000192{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700193 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000194
195 if (type.getBasicType() == EbtStruct)
196 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700197 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -0400198 out << hashName(structure->name()) << "(";
199
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700200 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400201 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000202 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700203 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000204 ASSERT(fieldType != NULL);
205 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700206 if (i != fields.size() - 1)
207 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000208 }
209 out << ")";
210 }
211 else
212 {
Jamie Madill94bf7f22013-07-08 13:31:15 -0400213 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000214 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700215 if (writeType)
216 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400217 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000218 {
219 switch (pConstUnion->getType())
220 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700221 case EbtFloat:
222 out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
223 break;
224 case EbtInt:
225 out << pConstUnion->getIConst();
226 break;
Olli Etuaho5321c802015-04-02 17:08:16 +0300227 case EbtUInt:
228 out << pConstUnion->getUConst() << "u";
229 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700230 case EbtBool:
231 out << pConstUnion->getBConst();
232 break;
233 default: UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000234 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700235 if (i != size - 1)
236 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000237 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700238 if (writeType)
239 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000240 }
241 return pConstUnion;
242}
243
Olli Etuahoe92507b2016-07-04 11:20:10 +0300244void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
Olli Etuahof40319e2015-03-10 14:33:00 +0200245{
246 TInfoSinkBase &out = objSink();
247 if (visit == PreVisit)
248 {
249 if (type.isArray())
250 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300251 out << getTypeName(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200252 out << arrayBrackets(type);
253 out << "(";
254 }
255 else
256 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300257 out << getTypeName(type) << "(";
Olli Etuahof40319e2015-03-10 14:33:00 +0200258 }
259 }
260 else
261 {
262 writeTriplet(visit, nullptr, ", ", ")");
263 }
264}
265
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700266void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000267{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700268 TInfoSinkBase &out = objSink();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800269 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
270 out << mLoopUnrollStack.getLoopIndexValue(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000271 else
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000272 out << hashVariableName(node->getSymbol());
zmo@google.com5601ea02011-06-10 18:23:25 +0000273
274 if (mDeclaringVariables && node->getType().isArray())
275 out << arrayBrackets(node->getType());
276}
277
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700278void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000279{
280 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
281}
282
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700283bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000284{
285 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700286 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000287 switch (node->getOp())
288 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700289 case EOpInitialize:
290 if (visit == InVisit)
291 {
292 out << " = ";
293 // RHS of initialize is not being declared.
294 mDeclaringVariables = false;
295 }
296 break;
297 case EOpAssign:
298 writeTriplet(visit, "(", " = ", ")");
299 break;
300 case EOpAddAssign:
301 writeTriplet(visit, "(", " += ", ")");
302 break;
303 case EOpSubAssign:
304 writeTriplet(visit, "(", " -= ", ")");
305 break;
306 case EOpDivAssign:
307 writeTriplet(visit, "(", " /= ", ")");
308 break;
Olli Etuahoff805cc2015-02-13 10:59:34 +0200309 case EOpIModAssign:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000310 writeTriplet(visit, "(", " %= ", ")");
311 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700312 // Notice the fall-through.
313 case EOpMulAssign:
314 case EOpVectorTimesMatrixAssign:
315 case EOpVectorTimesScalarAssign:
316 case EOpMatrixTimesScalarAssign:
317 case EOpMatrixTimesMatrixAssign:
318 writeTriplet(visit, "(", " *= ", ")");
319 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200320 case EOpBitShiftLeftAssign:
321 writeTriplet(visit, "(", " <<= ", ")");
322 break;
323 case EOpBitShiftRightAssign:
324 writeTriplet(visit, "(", " >>= ", ")");
325 break;
326 case EOpBitwiseAndAssign:
327 writeTriplet(visit, "(", " &= ", ")");
328 break;
329 case EOpBitwiseXorAssign:
330 writeTriplet(visit, "(", " ^= ", ")");
331 break;
332 case EOpBitwiseOrAssign:
333 writeTriplet(visit, "(", " |= ", ")");
334 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700335
336 case EOpIndexDirect:
337 writeTriplet(visit, NULL, "[", "]");
338 break;
339 case EOpIndexIndirect:
340 if (node->getAddIndexClamp())
341 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000342 if (visit == InVisit)
343 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700344 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
345 out << "[int(clamp(float(";
346 else
347 out << "[webgl_int_clamp(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000348 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700349 else if (visit == PostVisit)
350 {
351 int maxSize;
352 TIntermTyped *left = node->getLeft();
353 TType leftType = left->getType();
zmo@google.com5601ea02011-06-10 18:23:25 +0000354
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700355 if (left->isArray())
356 {
357 // The shader will fail validation if the array length is not > 0.
Olli Etuaho856c4972016-08-08 11:38:39 +0300358 maxSize = static_cast<int>(leftType.getArraySize()) - 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700359 }
360 else
361 {
362 maxSize = leftType.getNominalSize() - 1;
363 }
364
365 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
366 out << "), 0.0, float(" << maxSize << ")))]";
367 else
368 out << ", 0, " << maxSize << ")]";
369 }
370 }
371 else
372 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000373 writeTriplet(visit, NULL, "[", "]");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700374 }
375 break;
376 case EOpIndexDirectStruct:
377 if (visit == InVisit)
378 {
379 // Here we are writing out "foo.bar", where "foo" is struct
380 // and "bar" is field. In AST, it is represented as a binary
381 // node, where left child represents "foo" and right child "bar".
382 // The node itself represents ".". The struct field "bar" is
383 // actually stored as an index into TStructure::fields.
384 out << ".";
385 const TStructure *structure = node->getLeft()->getType().getStruct();
386 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
387 const TField *field = structure->fields()[index->getIConst(0)];
388
389 TString fieldName = field->name();
390 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
391 fieldName = hashName(fieldName);
392
393 out << fieldName;
394 visitChildren = false;
395 }
396 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400397 case EOpIndexDirectInterfaceBlock:
398 if (visit == InVisit)
399 {
400 out << ".";
401 const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
402 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
403 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
404
405 TString fieldName = field->name();
406 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
407 fieldName = hashName(fieldName);
408
409 out << fieldName;
410 visitChildren = false;
411 }
412 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700413 case EOpVectorSwizzle:
414 if (visit == InVisit)
415 {
416 out << ".";
417 TIntermAggregate *rightChild = node->getRight()->getAsAggregate();
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700418 TIntermSequence *sequence = rightChild->getSequence();
419 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); ++sit)
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000420 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700421 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
422 ASSERT(element->getBasicType() == EbtInt);
423 ASSERT(element->getNominalSize() == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400424 const TConstantUnion& data = element->getUnionArrayPointer()[0];
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700425 ASSERT(data.getType() == EbtInt);
426 switch (data.getIConst())
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000427 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700428 case 0:
429 out << "x";
430 break;
431 case 1:
432 out << "y";
433 break;
434 case 2:
435 out << "z";
436 break;
437 case 3:
438 out << "w";
439 break;
440 default:
441 UNREACHABLE();
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000442 }
443 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700444 visitChildren = false;
445 }
446 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000447
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700448 case EOpAdd:
449 writeTriplet(visit, "(", " + ", ")");
450 break;
451 case EOpSub:
452 writeTriplet(visit, "(", " - ", ")");
453 break;
454 case EOpMul:
455 writeTriplet(visit, "(", " * ", ")");
456 break;
457 case EOpDiv:
458 writeTriplet(visit, "(", " / ", ")");
459 break;
Olli Etuahoff805cc2015-02-13 10:59:34 +0200460 case EOpIMod:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000461 writeTriplet(visit, "(", " % ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700462 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200463 case EOpBitShiftLeft:
464 writeTriplet(visit, "(", " << ", ")");
465 break;
466 case EOpBitShiftRight:
467 writeTriplet(visit, "(", " >> ", ")");
468 break;
469 case EOpBitwiseAnd:
470 writeTriplet(visit, "(", " & ", ")");
471 break;
472 case EOpBitwiseXor:
473 writeTriplet(visit, "(", " ^ ", ")");
474 break;
475 case EOpBitwiseOr:
476 writeTriplet(visit, "(", " | ", ")");
477 break;
478
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700479 case EOpEqual:
480 writeTriplet(visit, "(", " == ", ")");
481 break;
482 case EOpNotEqual:
483 writeTriplet(visit, "(", " != ", ")");
484 break;
485 case EOpLessThan:
486 writeTriplet(visit, "(", " < ", ")");
487 break;
488 case EOpGreaterThan:
489 writeTriplet(visit, "(", " > ", ")");
490 break;
491 case EOpLessThanEqual:
492 writeTriplet(visit, "(", " <= ", ")");
493 break;
494 case EOpGreaterThanEqual:
495 writeTriplet(visit, "(", " >= ", ")");
496 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000497
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700498 // Notice the fall-through.
499 case EOpVectorTimesScalar:
500 case EOpVectorTimesMatrix:
501 case EOpMatrixTimesVector:
502 case EOpMatrixTimesScalar:
503 case EOpMatrixTimesMatrix:
504 writeTriplet(visit, "(", " * ", ")");
505 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000506
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700507 case EOpLogicalOr:
508 writeTriplet(visit, "(", " || ", ")");
509 break;
510 case EOpLogicalXor:
511 writeTriplet(visit, "(", " ^^ ", ")");
512 break;
513 case EOpLogicalAnd:
514 writeTriplet(visit, "(", " && ", ")");
515 break;
516 default:
517 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000518 }
519
520 return visitChildren;
521}
522
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700523bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000524{
zmo@google.com32e97312011-08-24 01:03:11 +0000525 TString preString;
526 TString postString = ")";
527
zmo@google.com5601ea02011-06-10 18:23:25 +0000528 switch (node->getOp())
529 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700530 case EOpNegative: preString = "(-"; break;
Zhenyao Mode1e00e2014-10-09 16:55:32 -0700531 case EOpPositive: preString = "(+"; break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700532 case EOpVectorLogicalNot: preString = "not("; break;
533 case EOpLogicalNot: preString = "(!"; break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200534 case EOpBitwiseNot: preString = "(~"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000535
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700536 case EOpPostIncrement: preString = "("; postString = "++)"; break;
537 case EOpPostDecrement: preString = "("; postString = "--)"; break;
538 case EOpPreIncrement: preString = "(++"; break;
539 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000540
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700541 case EOpRadians:
542 preString = "radians(";
543 break;
544 case EOpDegrees:
545 preString = "degrees(";
546 break;
547 case EOpSin:
548 preString = "sin(";
549 break;
550 case EOpCos:
551 preString = "cos(";
552 break;
553 case EOpTan:
554 preString = "tan(";
555 break;
556 case EOpAsin:
557 preString = "asin(";
558 break;
559 case EOpAcos:
560 preString = "acos(";
561 break;
562 case EOpAtan:
563 preString = "atan(";
564 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000565
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200566 case EOpSinh:
567 preString = "sinh(";
568 break;
569 case EOpCosh:
570 preString = "cosh(";
571 break;
572 case EOpTanh:
573 preString = "tanh(";
574 break;
575 case EOpAsinh:
576 preString = "asinh(";
577 break;
578 case EOpAcosh:
579 preString = "acosh(";
580 break;
581 case EOpAtanh:
582 preString = "atanh(";
583 break;
584
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700585 case EOpExp:
586 preString = "exp(";
587 break;
588 case EOpLog:
589 preString = "log(";
590 break;
591 case EOpExp2:
592 preString = "exp2(";
593 break;
594 case EOpLog2:
595 preString = "log2(";
596 break;
597 case EOpSqrt:
598 preString = "sqrt(";
599 break;
600 case EOpInverseSqrt:
601 preString = "inversesqrt(";
602 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000603
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700604 case EOpAbs:
605 preString = "abs(";
606 break;
607 case EOpSign:
608 preString = "sign(";
609 break;
610 case EOpFloor:
611 preString = "floor(";
612 break;
Qingqing Deng5dbece52015-02-27 20:35:38 -0800613 case EOpTrunc:
614 preString = "trunc(";
615 break;
616 case EOpRound:
617 preString = "round(";
618 break;
619 case EOpRoundEven:
620 preString = "roundEven(";
621 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700622 case EOpCeil:
623 preString = "ceil(";
624 break;
625 case EOpFract:
626 preString = "fract(";
627 break;
Arun Patole0c1726e2015-02-18 14:35:02 +0530628 case EOpIsNan:
629 preString = "isnan(";
630 break;
631 case EOpIsInf:
632 preString = "isinf(";
633 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000634
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200635 case EOpFloatBitsToInt:
636 preString = "floatBitsToInt(";
637 break;
638 case EOpFloatBitsToUint:
639 preString = "floatBitsToUint(";
640 break;
641 case EOpIntBitsToFloat:
642 preString = "intBitsToFloat(";
643 break;
644 case EOpUintBitsToFloat:
645 preString = "uintBitsToFloat(";
646 break;
647
Olli Etuaho7700ff62015-01-15 12:16:29 +0200648 case EOpPackSnorm2x16:
649 preString = "packSnorm2x16(";
650 break;
651 case EOpPackUnorm2x16:
652 preString = "packUnorm2x16(";
653 break;
654 case EOpPackHalf2x16:
655 preString = "packHalf2x16(";
656 break;
657 case EOpUnpackSnorm2x16:
658 preString = "unpackSnorm2x16(";
659 break;
660 case EOpUnpackUnorm2x16:
661 preString = "unpackUnorm2x16(";
662 break;
663 case EOpUnpackHalf2x16:
664 preString = "unpackHalf2x16(";
665 break;
666
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700667 case EOpLength:
668 preString = "length(";
669 break;
670 case EOpNormalize:
671 preString = "normalize(";
672 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000673
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700674 case EOpDFdx:
675 preString = "dFdx(";
676 break;
677 case EOpDFdy:
678 preString = "dFdy(";
679 break;
680 case EOpFwidth:
681 preString = "fwidth(";
682 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000683
Olli Etuahoe39706d2014-12-30 16:40:36 +0200684 case EOpTranspose:
685 preString = "transpose(";
686 break;
687 case EOpDeterminant:
688 preString = "determinant(";
689 break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +0200690 case EOpInverse:
691 preString = "inverse(";
692 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200693
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700694 case EOpAny:
695 preString = "any(";
696 break;
697 case EOpAll:
698 preString = "all(";
699 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000700
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700701 default:
702 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000703 }
704
zmo@google.com32e97312011-08-24 01:03:11 +0000705 if (visit == PreVisit && node->getUseEmulatedFunction())
706 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
707 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
708
zmo@google.com5601ea02011-06-10 18:23:25 +0000709 return true;
710}
711
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300712bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
713{
714 TInfoSinkBase &out = objSink();
715 // Notice two brackets at the beginning and end. The outer ones
716 // encapsulate the whole ternary expression. This preserves the
717 // order of precedence when ternary expressions are used in a
718 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
719 out << "((";
720 node->getCondition()->traverse(this);
721 out << ") ? (";
722 node->getTrueExpression()->traverse(this);
723 out << ") : (";
724 node->getFalseExpression()->traverse(this);
725 out << "))";
726 return false;
727}
728
Olli Etuaho57961272016-09-14 13:57:46 +0300729bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000730{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700731 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000732
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300733 out << "if (";
734 node->getCondition()->traverse(this);
735 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000736
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300737 incrementDepth(node);
738 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000739
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300740 if (node->getFalseBlock())
741 {
742 out << "else\n";
743 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000744 }
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300745 decrementDepth();
zmo@google.com5601ea02011-06-10 18:23:25 +0000746 return false;
747}
748
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200749bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200750{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200751 if (node->getStatementList())
752 {
753 writeTriplet(visit, "switch (", ") ", nullptr);
754 // The curly braces get written when visiting the statementList aggregate
755 }
756 else
757 {
758 // No statementList, so it won't output curly braces
759 writeTriplet(visit, "switch (", ") {", "}\n");
760 }
761 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200762}
763
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200764bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200765{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200766 if (node->hasCondition())
767 {
768 writeTriplet(visit, "case (", nullptr, "):\n");
769 return true;
770 }
771 else
772 {
773 TInfoSinkBase &out = objSink();
774 out << "default:\n";
775 return false;
776 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200777}
778
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700779bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000780{
781 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700782 TInfoSinkBase &out = objSink();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700783 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000784 switch (node->getOp())
785 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700786 case EOpSequence:
787 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700788 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700789 {
790 out << "{\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000791 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000792
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700793 incrementDepth(node);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700794 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
795 iter != node->getSequence()->end(); ++iter)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700796 {
Austin Kinross3ae64652015-01-26 15:51:39 -0800797 TIntermNode *curNode = *iter;
798 ASSERT(curNode != NULL);
799 curNode->traverse(this);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700800
Austin Kinross3ae64652015-01-26 15:51:39 -0800801 if (isSingleStatement(curNode))
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700802 out << ";\n";
803 }
804 decrementDepth();
805
806 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700807 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700808 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700809 out << "}\n";
810 }
811 visitChildren = false;
812 break;
813 case EOpPrototype:
814 // Function declaration.
815 ASSERT(visit == PreVisit);
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300816 {
817 const TType &type = node->getType();
818 writeVariableType(type);
819 if (type.isArray())
820 out << arrayBrackets(type);
821 }
822
Olli Etuaho59f9a642015-08-06 20:38:26 +0300823 out << " " << hashFunctionNameIfNeeded(node->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700824
825 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700826 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700827 out << ")";
828
829 visitChildren = false;
830 break;
831 case EOpFunction: {
832 // Function definition.
833 ASSERT(visit == PreVisit);
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300834 {
835 const TType &type = node->getType();
836 writeVariableType(type);
837 if (type.isArray())
838 out << arrayBrackets(type);
839 }
840
Olli Etuaho59f9a642015-08-06 20:38:26 +0300841 out << " " << hashFunctionNameIfNeeded(node->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700842
843 incrementDepth(node);
844 // Function definition node contains one or two children nodes
845 // representing function parameters and function body. The latter
846 // is not present in case of empty function bodies.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700847 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700848 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
849 TIntermSequence::const_iterator seqIter = sequence.begin();
850
851 // Traverse function parameters.
852 TIntermAggregate *params = (*seqIter)->getAsAggregate();
853 ASSERT(params != NULL);
854 ASSERT(params->getOp() == EOpParameters);
855 params->traverse(this);
856
857 // Traverse function body.
858 TIntermAggregate *body = ++seqIter != sequence.end() ?
859 (*seqIter)->getAsAggregate() : NULL;
860 visitCodeBlock(body);
861 decrementDepth();
862
863 // Fully processed; no need to visit children.
864 visitChildren = false;
865 break;
866 }
867 case EOpFunctionCall:
868 // Function call.
869 if (visit == PreVisit)
Olli Etuaho59f9a642015-08-06 20:38:26 +0300870 out << hashFunctionNameIfNeeded(node->getNameObj()) << "(";
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200871 else if (visit == InVisit)
872 out << ", ";
873 else
874 out << ")";
875 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700876 case EOpParameters:
877 // Function parameters.
878 ASSERT(visit == PreVisit);
879 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700880 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700881 out << ")";
882 visitChildren = false;
883 break;
884 case EOpDeclaration:
885 // Variable declaration.
886 if (visit == PreVisit)
887 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700888 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700889 const TIntermTyped *variable = sequence.front()->getAsTyped();
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300890 writeLayoutQualifier(variable->getType());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700891 writeVariableType(variable->getType());
892 out << " ";
893 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000894 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700895 else if (visit == InVisit)
896 {
897 out << ", ";
898 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000899 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700900 else
901 {
902 mDeclaringVariables = false;
903 }
904 break;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700905 case EOpInvariantDeclaration:
906 // Invariant declaration.
907 ASSERT(visit == PreVisit);
908 {
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400909 const TIntermSequence *sequence = node->getSequence();
910 ASSERT(sequence && sequence->size() == 1);
911 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
912 ASSERT(symbol);
Zhenyao Mo2a517272014-10-27 16:09:57 -0700913 out << "invariant " << hashVariableName(symbol->getSymbol());
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400914 }
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700915 visitChildren = false;
916 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700917 case EOpConstructFloat:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700918 case EOpConstructVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700919 case EOpConstructVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700920 case EOpConstructVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700921 case EOpConstructBool:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700922 case EOpConstructBVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700923 case EOpConstructBVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700924 case EOpConstructBVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700925 case EOpConstructInt:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700926 case EOpConstructIVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700927 case EOpConstructIVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700928 case EOpConstructIVec4:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400929 case EOpConstructUInt:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400930 case EOpConstructUVec2:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400931 case EOpConstructUVec3:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400932 case EOpConstructUVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700933 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400934 case EOpConstructMat2x3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400935 case EOpConstructMat2x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400936 case EOpConstructMat3x2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700937 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400938 case EOpConstructMat3x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400939 case EOpConstructMat4x2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400940 case EOpConstructMat4x3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700941 case EOpConstructMat4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700942 case EOpConstructStruct:
Olli Etuahoe92507b2016-07-04 11:20:10 +0300943 writeConstructorTriplet(visit, node->getType());
944 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000945
Olli Etuahoe39706d2014-12-30 16:40:36 +0200946 case EOpOuterProduct:
947 writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
948 break;
949
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700950 case EOpLessThan:
951 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
952 break;
953 case EOpGreaterThan:
954 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
955 break;
956 case EOpLessThanEqual:
957 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
958 break;
959 case EOpGreaterThanEqual:
960 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
961 break;
962 case EOpVectorEqual:
963 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
964 break;
965 case EOpVectorNotEqual:
966 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
967 break;
968 case EOpComma:
Zhenyao Mo0783efd2014-10-21 15:51:59 -0700969 writeTriplet(visit, "(", ", ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700970 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000971
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700972 case EOpMod:
973 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
974 break;
Olli Etuahob6e07a62015-02-16 12:22:10 +0200975 case EOpModf:
976 writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
977 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700978 case EOpPow:
979 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
980 break;
981 case EOpAtan:
982 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
983 break;
984 case EOpMin:
985 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
986 break;
987 case EOpMax:
988 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
989 break;
990 case EOpClamp:
991 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
992 break;
993 case EOpMix:
994 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
995 break;
996 case EOpStep:
997 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
998 break;
999 case EOpSmoothStep:
1000 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
1001 break;
1002 case EOpDistance:
1003 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
1004 break;
1005 case EOpDot:
1006 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
1007 break;
1008 case EOpCross:
1009 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
1010 break;
1011 case EOpFaceForward:
1012 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
1013 break;
1014 case EOpReflect:
1015 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
1016 break;
1017 case EOpRefract:
1018 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
1019 break;
1020 case EOpMul:
1021 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
1022 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001023
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001024 default:
1025 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001026 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001027 return visitChildren;
1028}
1029
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001030bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001031{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001032 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001033
Zhenyao Mo7cab38b2013-10-15 12:59:30 -07001034 incrementDepth(node);
Corentin Wallez7258e302015-09-22 10:40:24 -07001035
zmo@google.com5601ea02011-06-10 18:23:25 +00001036 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001037
1038 // Only for loops can be unrolled
1039 ASSERT(!node->getUnrollFlag() || loopType == ELoopFor);
1040
zmo@google.com5601ea02011-06-10 18:23:25 +00001041 if (loopType == ELoopFor) // for loop
1042 {
Zhenyao Mo550c6002014-02-26 15:40:48 -08001043 if (!node->getUnrollFlag())
1044 {
zmo@google.com5601ea02011-06-10 18:23:25 +00001045 out << "for (";
1046 if (node->getInit())
1047 node->getInit()->traverse(this);
1048 out << "; ";
1049
1050 if (node->getCondition())
1051 node->getCondition()->traverse(this);
1052 out << "; ";
1053
1054 if (node->getExpression())
1055 node->getExpression()->traverse(this);
1056 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001057
1058 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001059 }
Zhenyao Mo550c6002014-02-26 15:40:48 -08001060 else
1061 {
1062 // Need to put a one-iteration loop here to handle break.
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001063 TIntermSequence *declSeq =
Zhenyao Mo550c6002014-02-26 15:40:48 -08001064 node->getInit()->getAsAggregate()->getSequence();
1065 TIntermSymbol *indexSymbol =
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001066 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -08001067 TString name = hashVariableName(indexSymbol->getSymbol());
1068 out << "for (int " << name << " = 0; "
1069 << name << " < 1; "
1070 << "++" << name << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001071
1072 out << "{\n";
1073 mLoopUnrollStack.push(node);
1074 while (mLoopUnrollStack.satisfiesLoopCondition())
1075 {
1076 visitCodeBlock(node->getBody());
1077 mLoopUnrollStack.step();
1078 }
1079 mLoopUnrollStack.pop();
1080 out << "}\n";
Zhenyao Mo550c6002014-02-26 15:40:48 -08001081 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001082 }
1083 else if (loopType == ELoopWhile) // while loop
1084 {
1085 out << "while (";
1086 ASSERT(node->getCondition() != NULL);
1087 node->getCondition()->traverse(this);
1088 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001089
1090 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001091 }
1092 else // do-while loop
1093 {
1094 ASSERT(loopType == ELoopDoWhile);
1095 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001096
zmo@google.com5601ea02011-06-10 18:23:25 +00001097 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001098
zmo@google.com5601ea02011-06-10 18:23:25 +00001099 out << "while (";
1100 ASSERT(node->getCondition() != NULL);
1101 node->getCondition()->traverse(this);
1102 out << ");\n";
1103 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001104
zmo@google.com5601ea02011-06-10 18:23:25 +00001105 decrementDepth();
1106
1107 // No need to visit children. They have been already processed in
1108 // this function.
1109 return false;
1110}
1111
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001112bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001113{
1114 switch (node->getFlowOp())
1115 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001116 case EOpKill:
1117 writeTriplet(visit, "discard", NULL, NULL);
1118 break;
1119 case EOpBreak:
1120 writeTriplet(visit, "break", NULL, NULL);
1121 break;
1122 case EOpContinue:
1123 writeTriplet(visit, "continue", NULL, NULL);
1124 break;
1125 case EOpReturn:
1126 writeTriplet(visit, "return ", NULL, NULL);
1127 break;
1128 default:
1129 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001130 }
1131
1132 return true;
1133}
1134
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001135void TOutputGLSLBase::visitCodeBlock(TIntermNode *node)
1136{
zmo@google.com5601ea02011-06-10 18:23:25 +00001137 TInfoSinkBase &out = objSink();
1138 if (node != NULL)
1139 {
1140 node->traverse(this);
1141 // Single statements not part of a sequence need to be terminated
1142 // with semi-colon.
1143 if (isSingleStatement(node))
1144 out << ";\n";
1145 }
1146 else
1147 {
1148 out << "{\n}\n"; // Empty code block.
1149 }
1150}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001151
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001152TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001153{
Olli Etuahoe92507b2016-07-04 11:20:10 +03001154 if (type.getBasicType() == EbtStruct)
1155 return hashName(type.getStruct()->name());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001156 else
Olli Etuahoe92507b2016-07-04 11:20:10 +03001157 return type.getBuiltInTypeNameString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001158}
1159
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001160TString TOutputGLSLBase::hashName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001161{
1162 if (mHashFunction == NULL || name.empty())
1163 return name;
1164 NameMap::const_iterator it = mNameMap.find(name.c_str());
1165 if (it != mNameMap.end())
1166 return it->second.c_str();
1167 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
1168 mNameMap[name.c_str()] = hashedName.c_str();
1169 return hashedName;
1170}
1171
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001172TString TOutputGLSLBase::hashVariableName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001173{
Jamie Madill02f20dd2013-09-12 12:07:42 -04001174 if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001175 return name;
1176 return hashName(name);
1177}
1178
Olli Etuaho59f9a642015-08-06 20:38:26 +03001179TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001180{
Olli Etuaho59f9a642015-08-06 20:38:26 +03001181 TString mangledStr = mangledName.getString();
1182 TString name = TFunction::unmangleName(mangledStr);
1183 if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001184 return translateTextureFunction(name);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001185 if (mangledName.isInternal())
1186 return name;
1187 else
1188 return hashName(name);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001189}
Jamie Madill98493dd2013-07-08 14:39:03 -04001190
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001191bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001192{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001193 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001194 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001195 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001196 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001197 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001198
1199 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001200}
1201
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001202void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001203{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001204 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001205
1206 out << "struct " << hashName(structure->name()) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001207 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001208 for (size_t i = 0; i < fields.size(); ++i)
1209 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001210 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001211 if (writeVariablePrecision(field->type()->getPrecision()))
1212 out << " ";
1213 out << getTypeName(*field->type()) << " " << hashName(field->name());
1214 if (field->type()->isArray())
1215 out << arrayBrackets(*field->type());
1216 out << ";\n";
1217 }
1218 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001219}
Jamie Madill98493dd2013-07-08 14:39:03 -04001220
Geoff Langbdcc54a2015-09-02 13:09:48 -04001221void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1222{
1223 TInfoSinkBase &out = objSink();
1224
1225 out << "layout(";
1226
1227 switch (interfaceBlock->blockStorage())
1228 {
1229 case EbsUnspecified:
1230 case EbsShared:
1231 // Default block storage is shared.
1232 out << "shared";
1233 break;
1234
1235 case EbsPacked:
1236 out << "packed";
1237 break;
1238
1239 case EbsStd140:
1240 out << "std140";
1241 break;
1242
1243 default:
1244 UNREACHABLE();
1245 break;
1246 }
1247
1248 out << ", ";
1249
1250 switch (interfaceBlock->matrixPacking())
1251 {
1252 case EmpUnspecified:
1253 case EmpColumnMajor:
1254 // Default matrix packing is column major.
1255 out << "column_major";
1256 break;
1257
1258 case EmpRowMajor:
1259 out << "row_major";
1260 break;
1261
1262 default:
1263 UNREACHABLE();
1264 break;
1265 }
1266
1267 out << ") ";
1268}
1269
1270void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1271{
1272 TInfoSinkBase &out = objSink();
1273
1274 out << hashName(interfaceBlock->name()) << "{\n";
1275 const TFieldList &fields = interfaceBlock->fields();
1276 for (size_t i = 0; i < fields.size(); ++i)
1277 {
1278 const TField *field = fields[i];
1279 if (writeVariablePrecision(field->type()->getPrecision()))
1280 out << " ";
1281 out << getTypeName(*field->type()) << " " << hashName(field->name());
1282 if (field->type()->isArray())
1283 out << arrayBrackets(*field->type());
1284 out << ";\n";
1285 }
1286 out << "}";
1287}