blob: 32db9de24f04c08ab29daf79863beef6680d261e [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
Olli Etuahob6fa0432016-09-28 16:28:05 +0100283bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
284{
285 TInfoSinkBase &out = objSink();
286 if (visit == PostVisit)
287 {
288 out << ".";
289 node->writeOffsetsAsXYZW(&out);
290 }
291 return true;
292}
293
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700294bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000295{
296 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700297 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000298 switch (node->getOp())
299 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700300 case EOpInitialize:
301 if (visit == InVisit)
302 {
303 out << " = ";
304 // RHS of initialize is not being declared.
305 mDeclaringVariables = false;
306 }
307 break;
308 case EOpAssign:
309 writeTriplet(visit, "(", " = ", ")");
310 break;
311 case EOpAddAssign:
312 writeTriplet(visit, "(", " += ", ")");
313 break;
314 case EOpSubAssign:
315 writeTriplet(visit, "(", " -= ", ")");
316 break;
317 case EOpDivAssign:
318 writeTriplet(visit, "(", " /= ", ")");
319 break;
Olli Etuahoff805cc2015-02-13 10:59:34 +0200320 case EOpIModAssign:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000321 writeTriplet(visit, "(", " %= ", ")");
322 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700323 // Notice the fall-through.
324 case EOpMulAssign:
325 case EOpVectorTimesMatrixAssign:
326 case EOpVectorTimesScalarAssign:
327 case EOpMatrixTimesScalarAssign:
328 case EOpMatrixTimesMatrixAssign:
329 writeTriplet(visit, "(", " *= ", ")");
330 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200331 case EOpBitShiftLeftAssign:
332 writeTriplet(visit, "(", " <<= ", ")");
333 break;
334 case EOpBitShiftRightAssign:
335 writeTriplet(visit, "(", " >>= ", ")");
336 break;
337 case EOpBitwiseAndAssign:
338 writeTriplet(visit, "(", " &= ", ")");
339 break;
340 case EOpBitwiseXorAssign:
341 writeTriplet(visit, "(", " ^= ", ")");
342 break;
343 case EOpBitwiseOrAssign:
344 writeTriplet(visit, "(", " |= ", ")");
345 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700346
347 case EOpIndexDirect:
348 writeTriplet(visit, NULL, "[", "]");
349 break;
350 case EOpIndexIndirect:
351 if (node->getAddIndexClamp())
352 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000353 if (visit == InVisit)
354 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700355 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
356 out << "[int(clamp(float(";
357 else
358 out << "[webgl_int_clamp(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000359 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700360 else if (visit == PostVisit)
361 {
362 int maxSize;
363 TIntermTyped *left = node->getLeft();
364 TType leftType = left->getType();
zmo@google.com5601ea02011-06-10 18:23:25 +0000365
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700366 if (left->isArray())
367 {
368 // The shader will fail validation if the array length is not > 0.
Olli Etuaho856c4972016-08-08 11:38:39 +0300369 maxSize = static_cast<int>(leftType.getArraySize()) - 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700370 }
371 else
372 {
373 maxSize = leftType.getNominalSize() - 1;
374 }
375
376 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
377 out << "), 0.0, float(" << maxSize << ")))]";
378 else
379 out << ", 0, " << maxSize << ")]";
380 }
381 }
382 else
383 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000384 writeTriplet(visit, NULL, "[", "]");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700385 }
386 break;
387 case EOpIndexDirectStruct:
388 if (visit == InVisit)
389 {
390 // Here we are writing out "foo.bar", where "foo" is struct
391 // and "bar" is field. In AST, it is represented as a binary
392 // node, where left child represents "foo" and right child "bar".
393 // The node itself represents ".". The struct field "bar" is
394 // actually stored as an index into TStructure::fields.
395 out << ".";
396 const TStructure *structure = node->getLeft()->getType().getStruct();
397 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
398 const TField *field = structure->fields()[index->getIConst(0)];
399
400 TString fieldName = field->name();
401 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
402 fieldName = hashName(fieldName);
403
404 out << fieldName;
405 visitChildren = false;
406 }
407 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400408 case EOpIndexDirectInterfaceBlock:
409 if (visit == InVisit)
410 {
411 out << ".";
412 const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
413 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
414 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
415
416 TString fieldName = field->name();
417 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
418 fieldName = hashName(fieldName);
419
420 out << fieldName;
421 visitChildren = false;
422 }
423 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000424
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700425 case EOpAdd:
426 writeTriplet(visit, "(", " + ", ")");
427 break;
428 case EOpSub:
429 writeTriplet(visit, "(", " - ", ")");
430 break;
431 case EOpMul:
432 writeTriplet(visit, "(", " * ", ")");
433 break;
434 case EOpDiv:
435 writeTriplet(visit, "(", " / ", ")");
436 break;
Olli Etuahoff805cc2015-02-13 10:59:34 +0200437 case EOpIMod:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000438 writeTriplet(visit, "(", " % ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700439 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200440 case EOpBitShiftLeft:
441 writeTriplet(visit, "(", " << ", ")");
442 break;
443 case EOpBitShiftRight:
444 writeTriplet(visit, "(", " >> ", ")");
445 break;
446 case EOpBitwiseAnd:
447 writeTriplet(visit, "(", " & ", ")");
448 break;
449 case EOpBitwiseXor:
450 writeTriplet(visit, "(", " ^ ", ")");
451 break;
452 case EOpBitwiseOr:
453 writeTriplet(visit, "(", " | ", ")");
454 break;
455
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700456 case EOpEqual:
457 writeTriplet(visit, "(", " == ", ")");
458 break;
459 case EOpNotEqual:
460 writeTriplet(visit, "(", " != ", ")");
461 break;
462 case EOpLessThan:
463 writeTriplet(visit, "(", " < ", ")");
464 break;
465 case EOpGreaterThan:
466 writeTriplet(visit, "(", " > ", ")");
467 break;
468 case EOpLessThanEqual:
469 writeTriplet(visit, "(", " <= ", ")");
470 break;
471 case EOpGreaterThanEqual:
472 writeTriplet(visit, "(", " >= ", ")");
473 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000474
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700475 // Notice the fall-through.
476 case EOpVectorTimesScalar:
477 case EOpVectorTimesMatrix:
478 case EOpMatrixTimesVector:
479 case EOpMatrixTimesScalar:
480 case EOpMatrixTimesMatrix:
481 writeTriplet(visit, "(", " * ", ")");
482 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000483
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700484 case EOpLogicalOr:
485 writeTriplet(visit, "(", " || ", ")");
486 break;
487 case EOpLogicalXor:
488 writeTriplet(visit, "(", " ^^ ", ")");
489 break;
490 case EOpLogicalAnd:
491 writeTriplet(visit, "(", " && ", ")");
492 break;
493 default:
494 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000495 }
496
497 return visitChildren;
498}
499
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700500bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000501{
zmo@google.com32e97312011-08-24 01:03:11 +0000502 TString preString;
503 TString postString = ")";
504
zmo@google.com5601ea02011-06-10 18:23:25 +0000505 switch (node->getOp())
506 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700507 case EOpNegative: preString = "(-"; break;
Zhenyao Mode1e00e2014-10-09 16:55:32 -0700508 case EOpPositive: preString = "(+"; break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700509 case EOpVectorLogicalNot: preString = "not("; break;
510 case EOpLogicalNot: preString = "(!"; break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200511 case EOpBitwiseNot: preString = "(~"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000512
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700513 case EOpPostIncrement: preString = "("; postString = "++)"; break;
514 case EOpPostDecrement: preString = "("; postString = "--)"; break;
515 case EOpPreIncrement: preString = "(++"; break;
516 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000517
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700518 case EOpRadians:
519 preString = "radians(";
520 break;
521 case EOpDegrees:
522 preString = "degrees(";
523 break;
524 case EOpSin:
525 preString = "sin(";
526 break;
527 case EOpCos:
528 preString = "cos(";
529 break;
530 case EOpTan:
531 preString = "tan(";
532 break;
533 case EOpAsin:
534 preString = "asin(";
535 break;
536 case EOpAcos:
537 preString = "acos(";
538 break;
539 case EOpAtan:
540 preString = "atan(";
541 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000542
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200543 case EOpSinh:
544 preString = "sinh(";
545 break;
546 case EOpCosh:
547 preString = "cosh(";
548 break;
549 case EOpTanh:
550 preString = "tanh(";
551 break;
552 case EOpAsinh:
553 preString = "asinh(";
554 break;
555 case EOpAcosh:
556 preString = "acosh(";
557 break;
558 case EOpAtanh:
559 preString = "atanh(";
560 break;
561
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700562 case EOpExp:
563 preString = "exp(";
564 break;
565 case EOpLog:
566 preString = "log(";
567 break;
568 case EOpExp2:
569 preString = "exp2(";
570 break;
571 case EOpLog2:
572 preString = "log2(";
573 break;
574 case EOpSqrt:
575 preString = "sqrt(";
576 break;
577 case EOpInverseSqrt:
578 preString = "inversesqrt(";
579 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000580
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700581 case EOpAbs:
582 preString = "abs(";
583 break;
584 case EOpSign:
585 preString = "sign(";
586 break;
587 case EOpFloor:
588 preString = "floor(";
589 break;
Qingqing Deng5dbece52015-02-27 20:35:38 -0800590 case EOpTrunc:
591 preString = "trunc(";
592 break;
593 case EOpRound:
594 preString = "round(";
595 break;
596 case EOpRoundEven:
597 preString = "roundEven(";
598 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700599 case EOpCeil:
600 preString = "ceil(";
601 break;
602 case EOpFract:
603 preString = "fract(";
604 break;
Arun Patole0c1726e2015-02-18 14:35:02 +0530605 case EOpIsNan:
606 preString = "isnan(";
607 break;
608 case EOpIsInf:
609 preString = "isinf(";
610 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000611
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200612 case EOpFloatBitsToInt:
613 preString = "floatBitsToInt(";
614 break;
615 case EOpFloatBitsToUint:
616 preString = "floatBitsToUint(";
617 break;
618 case EOpIntBitsToFloat:
619 preString = "intBitsToFloat(";
620 break;
621 case EOpUintBitsToFloat:
622 preString = "uintBitsToFloat(";
623 break;
624
Olli Etuaho7700ff62015-01-15 12:16:29 +0200625 case EOpPackSnorm2x16:
626 preString = "packSnorm2x16(";
627 break;
628 case EOpPackUnorm2x16:
629 preString = "packUnorm2x16(";
630 break;
631 case EOpPackHalf2x16:
632 preString = "packHalf2x16(";
633 break;
634 case EOpUnpackSnorm2x16:
635 preString = "unpackSnorm2x16(";
636 break;
637 case EOpUnpackUnorm2x16:
638 preString = "unpackUnorm2x16(";
639 break;
640 case EOpUnpackHalf2x16:
641 preString = "unpackHalf2x16(";
642 break;
643
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700644 case EOpLength:
645 preString = "length(";
646 break;
647 case EOpNormalize:
648 preString = "normalize(";
649 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000650
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700651 case EOpDFdx:
652 preString = "dFdx(";
653 break;
654 case EOpDFdy:
655 preString = "dFdy(";
656 break;
657 case EOpFwidth:
658 preString = "fwidth(";
659 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000660
Olli Etuahoe39706d2014-12-30 16:40:36 +0200661 case EOpTranspose:
662 preString = "transpose(";
663 break;
664 case EOpDeterminant:
665 preString = "determinant(";
666 break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +0200667 case EOpInverse:
668 preString = "inverse(";
669 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200670
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700671 case EOpAny:
672 preString = "any(";
673 break;
674 case EOpAll:
675 preString = "all(";
676 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000677
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700678 default:
679 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000680 }
681
zmo@google.com32e97312011-08-24 01:03:11 +0000682 if (visit == PreVisit && node->getUseEmulatedFunction())
683 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
684 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
685
zmo@google.com5601ea02011-06-10 18:23:25 +0000686 return true;
687}
688
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300689bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
690{
691 TInfoSinkBase &out = objSink();
692 // Notice two brackets at the beginning and end. The outer ones
693 // encapsulate the whole ternary expression. This preserves the
694 // order of precedence when ternary expressions are used in a
695 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
696 out << "((";
697 node->getCondition()->traverse(this);
698 out << ") ? (";
699 node->getTrueExpression()->traverse(this);
700 out << ") : (";
701 node->getFalseExpression()->traverse(this);
702 out << "))";
703 return false;
704}
705
Olli Etuaho57961272016-09-14 13:57:46 +0300706bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000707{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700708 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000709
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300710 out << "if (";
711 node->getCondition()->traverse(this);
712 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000713
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300714 incrementDepth(node);
715 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000716
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300717 if (node->getFalseBlock())
718 {
719 out << "else\n";
720 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000721 }
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300722 decrementDepth();
zmo@google.com5601ea02011-06-10 18:23:25 +0000723 return false;
724}
725
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200726bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200727{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200728 if (node->getStatementList())
729 {
730 writeTriplet(visit, "switch (", ") ", nullptr);
731 // The curly braces get written when visiting the statementList aggregate
732 }
733 else
734 {
735 // No statementList, so it won't output curly braces
736 writeTriplet(visit, "switch (", ") {", "}\n");
737 }
738 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200739}
740
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200741bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200742{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200743 if (node->hasCondition())
744 {
745 writeTriplet(visit, "case (", nullptr, "):\n");
746 return true;
747 }
748 else
749 {
750 TInfoSinkBase &out = objSink();
751 out << "default:\n";
752 return false;
753 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200754}
755
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700756bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000757{
758 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700759 TInfoSinkBase &out = objSink();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700760 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000761 switch (node->getOp())
762 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700763 case EOpSequence:
764 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700765 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700766 {
767 out << "{\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000768 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000769
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700770 incrementDepth(node);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700771 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
772 iter != node->getSequence()->end(); ++iter)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700773 {
Austin Kinross3ae64652015-01-26 15:51:39 -0800774 TIntermNode *curNode = *iter;
775 ASSERT(curNode != NULL);
776 curNode->traverse(this);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700777
Austin Kinross3ae64652015-01-26 15:51:39 -0800778 if (isSingleStatement(curNode))
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700779 out << ";\n";
780 }
781 decrementDepth();
782
783 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700784 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700785 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700786 out << "}\n";
787 }
788 visitChildren = false;
789 break;
790 case EOpPrototype:
791 // Function declaration.
792 ASSERT(visit == PreVisit);
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300793 {
794 const TType &type = node->getType();
795 writeVariableType(type);
796 if (type.isArray())
797 out << arrayBrackets(type);
798 }
799
Olli Etuaho59f9a642015-08-06 20:38:26 +0300800 out << " " << hashFunctionNameIfNeeded(node->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700801
802 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700803 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700804 out << ")";
805
806 visitChildren = false;
807 break;
808 case EOpFunction: {
809 // Function definition.
810 ASSERT(visit == PreVisit);
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300811 {
812 const TType &type = node->getType();
813 writeVariableType(type);
814 if (type.isArray())
815 out << arrayBrackets(type);
816 }
817
Olli Etuaho59f9a642015-08-06 20:38:26 +0300818 out << " " << hashFunctionNameIfNeeded(node->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700819
820 incrementDepth(node);
Olli Etuahof51fdd22016-10-03 10:03:40 +0100821 // Function definition node contains two child nodes representing the function parameters
822 // and the function body.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700823 const TIntermSequence &sequence = *(node->getSequence());
Olli Etuahof51fdd22016-10-03 10:03:40 +0100824 ASSERT(sequence.size() == 2);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700825
826 // Traverse function parameters.
Olli Etuahof51fdd22016-10-03 10:03:40 +0100827 TIntermAggregate *params = sequence[0]->getAsAggregate();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700828 ASSERT(params != NULL);
829 ASSERT(params->getOp() == EOpParameters);
830 params->traverse(this);
831
832 // Traverse function body.
Olli Etuahof51fdd22016-10-03 10:03:40 +0100833 TIntermAggregate *body = sequence[1]->getAsAggregate();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700834 visitCodeBlock(body);
835 decrementDepth();
836
837 // Fully processed; no need to visit children.
838 visitChildren = false;
839 break;
840 }
841 case EOpFunctionCall:
842 // Function call.
843 if (visit == PreVisit)
Olli Etuaho59f9a642015-08-06 20:38:26 +0300844 out << hashFunctionNameIfNeeded(node->getNameObj()) << "(";
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200845 else if (visit == InVisit)
846 out << ", ";
847 else
848 out << ")";
849 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700850 case EOpParameters:
851 // Function parameters.
852 ASSERT(visit == PreVisit);
853 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700854 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700855 out << ")";
856 visitChildren = false;
857 break;
858 case EOpDeclaration:
859 // Variable declaration.
860 if (visit == PreVisit)
861 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700862 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700863 const TIntermTyped *variable = sequence.front()->getAsTyped();
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300864 writeLayoutQualifier(variable->getType());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700865 writeVariableType(variable->getType());
866 out << " ";
867 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000868 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700869 else if (visit == InVisit)
870 {
871 out << ", ";
872 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000873 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700874 else
875 {
876 mDeclaringVariables = false;
877 }
878 break;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700879 case EOpInvariantDeclaration:
880 // Invariant declaration.
881 ASSERT(visit == PreVisit);
882 {
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400883 const TIntermSequence *sequence = node->getSequence();
884 ASSERT(sequence && sequence->size() == 1);
885 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
886 ASSERT(symbol);
Zhenyao Mo2a517272014-10-27 16:09:57 -0700887 out << "invariant " << hashVariableName(symbol->getSymbol());
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400888 }
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700889 visitChildren = false;
890 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700891 case EOpConstructFloat:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700892 case EOpConstructVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700893 case EOpConstructVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700894 case EOpConstructVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700895 case EOpConstructBool:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700896 case EOpConstructBVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700897 case EOpConstructBVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700898 case EOpConstructBVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700899 case EOpConstructInt:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700900 case EOpConstructIVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700901 case EOpConstructIVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700902 case EOpConstructIVec4:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400903 case EOpConstructUInt:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400904 case EOpConstructUVec2:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400905 case EOpConstructUVec3:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400906 case EOpConstructUVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700907 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400908 case EOpConstructMat2x3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400909 case EOpConstructMat2x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400910 case EOpConstructMat3x2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700911 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400912 case EOpConstructMat3x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400913 case EOpConstructMat4x2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400914 case EOpConstructMat4x3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700915 case EOpConstructMat4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700916 case EOpConstructStruct:
Olli Etuahoe92507b2016-07-04 11:20:10 +0300917 writeConstructorTriplet(visit, node->getType());
918 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000919
Olli Etuahoe39706d2014-12-30 16:40:36 +0200920 case EOpOuterProduct:
921 writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
922 break;
923
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700924 case EOpLessThan:
925 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
926 break;
927 case EOpGreaterThan:
928 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
929 break;
930 case EOpLessThanEqual:
931 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
932 break;
933 case EOpGreaterThanEqual:
934 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
935 break;
936 case EOpVectorEqual:
937 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
938 break;
939 case EOpVectorNotEqual:
940 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
941 break;
942 case EOpComma:
Zhenyao Mo0783efd2014-10-21 15:51:59 -0700943 writeTriplet(visit, "(", ", ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700944 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000945
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700946 case EOpMod:
947 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
948 break;
Olli Etuahob6e07a62015-02-16 12:22:10 +0200949 case EOpModf:
950 writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
951 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700952 case EOpPow:
953 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
954 break;
955 case EOpAtan:
956 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
957 break;
958 case EOpMin:
959 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
960 break;
961 case EOpMax:
962 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
963 break;
964 case EOpClamp:
965 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
966 break;
967 case EOpMix:
968 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
969 break;
970 case EOpStep:
971 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
972 break;
973 case EOpSmoothStep:
974 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
975 break;
976 case EOpDistance:
977 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
978 break;
979 case EOpDot:
980 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
981 break;
982 case EOpCross:
983 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
984 break;
985 case EOpFaceForward:
986 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
987 break;
988 case EOpReflect:
989 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
990 break;
991 case EOpRefract:
992 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
993 break;
994 case EOpMul:
995 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
996 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000997
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700998 default:
999 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001000 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001001 return visitChildren;
1002}
1003
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001004bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001005{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001006 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001007
Zhenyao Mo7cab38b2013-10-15 12:59:30 -07001008 incrementDepth(node);
Corentin Wallez7258e302015-09-22 10:40:24 -07001009
zmo@google.com5601ea02011-06-10 18:23:25 +00001010 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001011
1012 // Only for loops can be unrolled
1013 ASSERT(!node->getUnrollFlag() || loopType == ELoopFor);
1014
zmo@google.com5601ea02011-06-10 18:23:25 +00001015 if (loopType == ELoopFor) // for loop
1016 {
Zhenyao Mo550c6002014-02-26 15:40:48 -08001017 if (!node->getUnrollFlag())
1018 {
zmo@google.com5601ea02011-06-10 18:23:25 +00001019 out << "for (";
1020 if (node->getInit())
1021 node->getInit()->traverse(this);
1022 out << "; ";
1023
1024 if (node->getCondition())
1025 node->getCondition()->traverse(this);
1026 out << "; ";
1027
1028 if (node->getExpression())
1029 node->getExpression()->traverse(this);
1030 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001031
1032 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001033 }
Zhenyao Mo550c6002014-02-26 15:40:48 -08001034 else
1035 {
1036 // Need to put a one-iteration loop here to handle break.
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001037 TIntermSequence *declSeq =
Zhenyao Mo550c6002014-02-26 15:40:48 -08001038 node->getInit()->getAsAggregate()->getSequence();
1039 TIntermSymbol *indexSymbol =
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001040 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -08001041 TString name = hashVariableName(indexSymbol->getSymbol());
1042 out << "for (int " << name << " = 0; "
1043 << name << " < 1; "
1044 << "++" << name << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001045
1046 out << "{\n";
1047 mLoopUnrollStack.push(node);
1048 while (mLoopUnrollStack.satisfiesLoopCondition())
1049 {
1050 visitCodeBlock(node->getBody());
1051 mLoopUnrollStack.step();
1052 }
1053 mLoopUnrollStack.pop();
1054 out << "}\n";
Zhenyao Mo550c6002014-02-26 15:40:48 -08001055 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001056 }
1057 else if (loopType == ELoopWhile) // while loop
1058 {
1059 out << "while (";
1060 ASSERT(node->getCondition() != NULL);
1061 node->getCondition()->traverse(this);
1062 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001063
1064 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001065 }
1066 else // do-while loop
1067 {
1068 ASSERT(loopType == ELoopDoWhile);
1069 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001070
zmo@google.com5601ea02011-06-10 18:23:25 +00001071 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001072
zmo@google.com5601ea02011-06-10 18:23:25 +00001073 out << "while (";
1074 ASSERT(node->getCondition() != NULL);
1075 node->getCondition()->traverse(this);
1076 out << ");\n";
1077 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001078
zmo@google.com5601ea02011-06-10 18:23:25 +00001079 decrementDepth();
1080
1081 // No need to visit children. They have been already processed in
1082 // this function.
1083 return false;
1084}
1085
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001086bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001087{
1088 switch (node->getFlowOp())
1089 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001090 case EOpKill:
1091 writeTriplet(visit, "discard", NULL, NULL);
1092 break;
1093 case EOpBreak:
1094 writeTriplet(visit, "break", NULL, NULL);
1095 break;
1096 case EOpContinue:
1097 writeTriplet(visit, "continue", NULL, NULL);
1098 break;
1099 case EOpReturn:
1100 writeTriplet(visit, "return ", NULL, NULL);
1101 break;
1102 default:
1103 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001104 }
1105
1106 return true;
1107}
1108
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001109void TOutputGLSLBase::visitCodeBlock(TIntermNode *node)
1110{
zmo@google.com5601ea02011-06-10 18:23:25 +00001111 TInfoSinkBase &out = objSink();
1112 if (node != NULL)
1113 {
1114 node->traverse(this);
1115 // Single statements not part of a sequence need to be terminated
1116 // with semi-colon.
1117 if (isSingleStatement(node))
1118 out << ";\n";
1119 }
1120 else
1121 {
1122 out << "{\n}\n"; // Empty code block.
1123 }
1124}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001125
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001126TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001127{
Olli Etuahoe92507b2016-07-04 11:20:10 +03001128 if (type.getBasicType() == EbtStruct)
1129 return hashName(type.getStruct()->name());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001130 else
Olli Etuahoe92507b2016-07-04 11:20:10 +03001131 return type.getBuiltInTypeNameString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001132}
1133
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001134TString TOutputGLSLBase::hashName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001135{
1136 if (mHashFunction == NULL || name.empty())
1137 return name;
1138 NameMap::const_iterator it = mNameMap.find(name.c_str());
1139 if (it != mNameMap.end())
1140 return it->second.c_str();
1141 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
1142 mNameMap[name.c_str()] = hashedName.c_str();
1143 return hashedName;
1144}
1145
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001146TString TOutputGLSLBase::hashVariableName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001147{
Jamie Madill02f20dd2013-09-12 12:07:42 -04001148 if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001149 return name;
1150 return hashName(name);
1151}
1152
Olli Etuaho59f9a642015-08-06 20:38:26 +03001153TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001154{
Olli Etuaho59f9a642015-08-06 20:38:26 +03001155 TString mangledStr = mangledName.getString();
1156 TString name = TFunction::unmangleName(mangledStr);
1157 if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001158 return translateTextureFunction(name);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001159 if (mangledName.isInternal())
1160 return name;
1161 else
1162 return hashName(name);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001163}
Jamie Madill98493dd2013-07-08 14:39:03 -04001164
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001165bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001166{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001167 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001168 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001169 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001170 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001171 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001172
1173 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001174}
1175
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001176void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001177{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001178 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001179
1180 out << "struct " << hashName(structure->name()) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001181 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001182 for (size_t i = 0; i < fields.size(); ++i)
1183 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001184 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001185 if (writeVariablePrecision(field->type()->getPrecision()))
1186 out << " ";
1187 out << getTypeName(*field->type()) << " " << hashName(field->name());
1188 if (field->type()->isArray())
1189 out << arrayBrackets(*field->type());
1190 out << ";\n";
1191 }
1192 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001193}
Jamie Madill98493dd2013-07-08 14:39:03 -04001194
Geoff Langbdcc54a2015-09-02 13:09:48 -04001195void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1196{
1197 TInfoSinkBase &out = objSink();
1198
1199 out << "layout(";
1200
1201 switch (interfaceBlock->blockStorage())
1202 {
1203 case EbsUnspecified:
1204 case EbsShared:
1205 // Default block storage is shared.
1206 out << "shared";
1207 break;
1208
1209 case EbsPacked:
1210 out << "packed";
1211 break;
1212
1213 case EbsStd140:
1214 out << "std140";
1215 break;
1216
1217 default:
1218 UNREACHABLE();
1219 break;
1220 }
1221
1222 out << ", ";
1223
1224 switch (interfaceBlock->matrixPacking())
1225 {
1226 case EmpUnspecified:
1227 case EmpColumnMajor:
1228 // Default matrix packing is column major.
1229 out << "column_major";
1230 break;
1231
1232 case EmpRowMajor:
1233 out << "row_major";
1234 break;
1235
1236 default:
1237 UNREACHABLE();
1238 break;
1239 }
1240
1241 out << ") ";
1242}
1243
1244void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1245{
1246 TInfoSinkBase &out = objSink();
1247
1248 out << hashName(interfaceBlock->name()) << "{\n";
1249 const TFieldList &fields = interfaceBlock->fields();
1250 for (size_t i = 0; i < fields.size(); ++i)
1251 {
1252 const TField *field = fields[i];
1253 if (writeVariablePrecision(field->type()->getPrecision()))
1254 out << " ";
1255 out << getTypeName(*field->type()) << " " << hashName(field->name());
1256 if (field->type()->isArray())
1257 out << arrayBrackets(*field->type());
1258 out << ";\n";
1259 }
1260 out << "}";
1261}