blob: ecd47fa8574a53c4997ceab5e9165b3e3f188321 [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 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010027 return (aggregate->getOp() != EOpFunction);
28 }
29 else if (node->getAsBlock())
30 {
31 return false;
zmo@google.com5601ea02011-06-10 18:23:25 +000032 }
Olli Etuaho57961272016-09-14 13:57:46 +030033 else if (node->getAsIfElseNode())
zmo@google.com5601ea02011-06-10 18:23:25 +000034 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +030035 return false;
zmo@google.com5601ea02011-06-10 18:23:25 +000036 }
37 else if (node->getAsLoopNode())
38 {
39 return false;
40 }
Olli Etuaho01cd8af2015-02-20 10:39:20 +020041 else if (node->getAsSwitchNode())
42 {
43 return false;
44 }
45 else if (node->getAsCaseNode())
46 {
47 return false;
48 }
zmo@google.com5601ea02011-06-10 18:23:25 +000049 return true;
50}
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080051
zmo@google.com5601ea02011-06-10 18:23:25 +000052} // namespace
53
Zhenyao Mo9eedea02014-05-12 16:02:35 -070054TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000055 ShArrayIndexClampingStrategy clampingStrategy,
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000056 ShHashFunction64 hashFunction,
Zhenyao Mo9eedea02014-05-12 16:02:35 -070057 NameMap &nameMap,
58 TSymbolTable &symbolTable,
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080059 int shaderVersion,
60 ShShaderOutput output)
zmo@google.com5601ea02011-06-10 18:23:25 +000061 : TIntermTraverser(true, true, true),
62 mObjSink(objSink),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000063 mDeclaringVariables(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000064 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000065 mHashFunction(hashFunction),
66 mNameMap(nameMap),
Jamie Madill02f20dd2013-09-12 12:07:42 -040067 mSymbolTable(symbolTable),
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080068 mShaderVersion(shaderVersion),
69 mOutput(output)
zmo@google.com5601ea02011-06-10 18:23:25 +000070{
71}
72
Zhenyao Mo9eedea02014-05-12 16:02:35 -070073void TOutputGLSLBase::writeTriplet(
74 Visit visit, const char *preStr, const char *inStr, const char *postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000075{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070076 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +000077 if (visit == PreVisit && preStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000078 out << preStr;
zmo@google.com5601ea02011-06-10 18:23:25 +000079 else if (visit == InVisit && inStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000080 out << inStr;
zmo@google.com5601ea02011-06-10 18:23:25 +000081 else if (visit == PostVisit && postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000082 out << postStr;
zmo@google.com5601ea02011-06-10 18:23:25 +000083}
84
Zhenyao Mo9eedea02014-05-12 16:02:35 -070085void TOutputGLSLBase::writeBuiltInFunctionTriplet(
86 Visit visit, const char *preStr, bool useEmulatedFunction)
zmo@google.com5601ea02011-06-10 18:23:25 +000087{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070088 TString preString = useEmulatedFunction ?
89 BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
90 writeTriplet(visit, preString.c_str(), ", ", ")");
91}
92
Olli Etuahoae69d7e2015-10-07 17:19:50 +030093void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
94{
95 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
96 {
97 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
98 if (layoutQualifier.location >= 0)
99 {
100 TInfoSinkBase &out = objSink();
101 out << "layout(location = " << layoutQualifier.location << ") ";
102 }
103 }
104}
105
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700106void TOutputGLSLBase::writeVariableType(const TType &type)
107{
108 TInfoSinkBase &out = objSink();
Olli Etuaho214c2d82015-04-27 14:49:13 +0300109 if (type.isInvariant())
110 {
111 out << "invariant ";
112 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400113 if (type.getBasicType() == EbtInterfaceBlock)
114 {
115 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
116 declareInterfaceBlockLayout(interfaceBlock);
117 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000118 TQualifier qualifier = type.getQualifier();
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400119 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400120 {
Qingqing Dengad0d0792015-04-08 14:25:06 -0700121 if (IsGLSL130OrNewer(mOutput))
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800122 {
123 switch (qualifier)
124 {
125 case EvqAttribute:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300126 out << "in ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800127 break;
128 case EvqVaryingIn:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300129 out << "in ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800130 break;
131 case EvqVaryingOut:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300132 out << "out ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800133 break;
134 default:
135 out << type.getQualifierString() << " ";
136 break;
137 }
138 }
139 else
140 {
141 out << type.getQualifierString() << " ";
142 }
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400143 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000144 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700145 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000146 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400147 TStructure *structure = type.getStruct();
148
149 declareStruct(structure);
150
151 if (!structure->name().empty())
152 {
153 mDeclaredStructs.insert(structure->uniqueId());
154 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000155 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400156 else if (type.getBasicType() == EbtInterfaceBlock)
157 {
158 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
159 declareInterfaceBlock(interfaceBlock);
160 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000161 else
162 {
163 if (writeVariablePrecision(type.getPrecision()))
164 out << " ";
165 out << getTypeName(type);
166 }
167}
168
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700169void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000170{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700171 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000172 for (TIntermSequence::const_iterator iter = args.begin();
173 iter != args.end(); ++iter)
174 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700175 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000176 ASSERT(arg != NULL);
177
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700178 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000179 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000180
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700181 const TString &name = arg->getSymbol();
zmo@google.com5601ea02011-06-10 18:23:25 +0000182 if (!name.empty())
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000183 out << " " << hashName(name);
zmo@google.com5601ea02011-06-10 18:23:25 +0000184 if (type.isArray())
185 out << arrayBrackets(type);
186
187 // Put a comma if this is not the last argument.
188 if (iter != args.end() - 1)
189 out << ", ";
190 }
191}
192
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400193const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
194 const TType &type, const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000195{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700196 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000197
198 if (type.getBasicType() == EbtStruct)
199 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700200 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -0400201 out << hashName(structure->name()) << "(";
202
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700203 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400204 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000205 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700206 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000207 ASSERT(fieldType != NULL);
208 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700209 if (i != fields.size() - 1)
210 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000211 }
212 out << ")";
213 }
214 else
215 {
Jamie Madill94bf7f22013-07-08 13:31:15 -0400216 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000217 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700218 if (writeType)
219 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400220 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000221 {
222 switch (pConstUnion->getType())
223 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700224 case EbtFloat:
225 out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
226 break;
227 case EbtInt:
228 out << pConstUnion->getIConst();
229 break;
Olli Etuaho5321c802015-04-02 17:08:16 +0300230 case EbtUInt:
231 out << pConstUnion->getUConst() << "u";
232 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700233 case EbtBool:
234 out << pConstUnion->getBConst();
235 break;
236 default: UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000237 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700238 if (i != size - 1)
239 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000240 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700241 if (writeType)
242 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000243 }
244 return pConstUnion;
245}
246
Olli Etuahoe92507b2016-07-04 11:20:10 +0300247void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
Olli Etuahof40319e2015-03-10 14:33:00 +0200248{
249 TInfoSinkBase &out = objSink();
250 if (visit == PreVisit)
251 {
252 if (type.isArray())
253 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300254 out << getTypeName(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200255 out << arrayBrackets(type);
256 out << "(";
257 }
258 else
259 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300260 out << getTypeName(type) << "(";
Olli Etuahof40319e2015-03-10 14:33:00 +0200261 }
262 }
263 else
264 {
265 writeTriplet(visit, nullptr, ", ", ")");
266 }
267}
268
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700269void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000270{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700271 TInfoSinkBase &out = objSink();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800272 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
273 out << mLoopUnrollStack.getLoopIndexValue(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000274 else
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000275 out << hashVariableName(node->getSymbol());
zmo@google.com5601ea02011-06-10 18:23:25 +0000276
277 if (mDeclaringVariables && node->getType().isArray())
278 out << arrayBrackets(node->getType());
279}
280
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700281void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000282{
283 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
284}
285
Olli Etuahob6fa0432016-09-28 16:28:05 +0100286bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
287{
288 TInfoSinkBase &out = objSink();
289 if (visit == PostVisit)
290 {
291 out << ".";
292 node->writeOffsetsAsXYZW(&out);
293 }
294 return true;
295}
296
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700297bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000298{
299 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700300 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000301 switch (node->getOp())
302 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700303 case EOpInitialize:
304 if (visit == InVisit)
305 {
306 out << " = ";
307 // RHS of initialize is not being declared.
308 mDeclaringVariables = false;
309 }
310 break;
311 case EOpAssign:
312 writeTriplet(visit, "(", " = ", ")");
313 break;
314 case EOpAddAssign:
315 writeTriplet(visit, "(", " += ", ")");
316 break;
317 case EOpSubAssign:
318 writeTriplet(visit, "(", " -= ", ")");
319 break;
320 case EOpDivAssign:
321 writeTriplet(visit, "(", " /= ", ")");
322 break;
Olli Etuahoff805cc2015-02-13 10:59:34 +0200323 case EOpIModAssign:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000324 writeTriplet(visit, "(", " %= ", ")");
325 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700326 // Notice the fall-through.
327 case EOpMulAssign:
328 case EOpVectorTimesMatrixAssign:
329 case EOpVectorTimesScalarAssign:
330 case EOpMatrixTimesScalarAssign:
331 case EOpMatrixTimesMatrixAssign:
332 writeTriplet(visit, "(", " *= ", ")");
333 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200334 case EOpBitShiftLeftAssign:
335 writeTriplet(visit, "(", " <<= ", ")");
336 break;
337 case EOpBitShiftRightAssign:
338 writeTriplet(visit, "(", " >>= ", ")");
339 break;
340 case EOpBitwiseAndAssign:
341 writeTriplet(visit, "(", " &= ", ")");
342 break;
343 case EOpBitwiseXorAssign:
344 writeTriplet(visit, "(", " ^= ", ")");
345 break;
346 case EOpBitwiseOrAssign:
347 writeTriplet(visit, "(", " |= ", ")");
348 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700349
350 case EOpIndexDirect:
351 writeTriplet(visit, NULL, "[", "]");
352 break;
353 case EOpIndexIndirect:
354 if (node->getAddIndexClamp())
355 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000356 if (visit == InVisit)
357 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700358 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
359 out << "[int(clamp(float(";
360 else
361 out << "[webgl_int_clamp(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000362 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700363 else if (visit == PostVisit)
364 {
365 int maxSize;
366 TIntermTyped *left = node->getLeft();
367 TType leftType = left->getType();
zmo@google.com5601ea02011-06-10 18:23:25 +0000368
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700369 if (left->isArray())
370 {
371 // The shader will fail validation if the array length is not > 0.
Olli Etuaho856c4972016-08-08 11:38:39 +0300372 maxSize = static_cast<int>(leftType.getArraySize()) - 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700373 }
374 else
375 {
376 maxSize = leftType.getNominalSize() - 1;
377 }
378
379 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
380 out << "), 0.0, float(" << maxSize << ")))]";
381 else
382 out << ", 0, " << maxSize << ")]";
383 }
384 }
385 else
386 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000387 writeTriplet(visit, NULL, "[", "]");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700388 }
389 break;
390 case EOpIndexDirectStruct:
391 if (visit == InVisit)
392 {
393 // Here we are writing out "foo.bar", where "foo" is struct
394 // and "bar" is field. In AST, it is represented as a binary
395 // node, where left child represents "foo" and right child "bar".
396 // The node itself represents ".". The struct field "bar" is
397 // actually stored as an index into TStructure::fields.
398 out << ".";
399 const TStructure *structure = node->getLeft()->getType().getStruct();
400 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
401 const TField *field = structure->fields()[index->getIConst(0)];
402
403 TString fieldName = field->name();
404 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
405 fieldName = hashName(fieldName);
406
407 out << fieldName;
408 visitChildren = false;
409 }
410 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400411 case EOpIndexDirectInterfaceBlock:
412 if (visit == InVisit)
413 {
414 out << ".";
415 const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
416 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
417 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
418
419 TString fieldName = field->name();
420 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
421 fieldName = hashName(fieldName);
422
423 out << fieldName;
424 visitChildren = false;
425 }
426 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000427
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700428 case EOpAdd:
429 writeTriplet(visit, "(", " + ", ")");
430 break;
431 case EOpSub:
432 writeTriplet(visit, "(", " - ", ")");
433 break;
434 case EOpMul:
435 writeTriplet(visit, "(", " * ", ")");
436 break;
437 case EOpDiv:
438 writeTriplet(visit, "(", " / ", ")");
439 break;
Olli Etuahoff805cc2015-02-13 10:59:34 +0200440 case EOpIMod:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000441 writeTriplet(visit, "(", " % ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700442 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200443 case EOpBitShiftLeft:
444 writeTriplet(visit, "(", " << ", ")");
445 break;
446 case EOpBitShiftRight:
447 writeTriplet(visit, "(", " >> ", ")");
448 break;
449 case EOpBitwiseAnd:
450 writeTriplet(visit, "(", " & ", ")");
451 break;
452 case EOpBitwiseXor:
453 writeTriplet(visit, "(", " ^ ", ")");
454 break;
455 case EOpBitwiseOr:
456 writeTriplet(visit, "(", " | ", ")");
457 break;
458
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700459 case EOpEqual:
460 writeTriplet(visit, "(", " == ", ")");
461 break;
462 case EOpNotEqual:
463 writeTriplet(visit, "(", " != ", ")");
464 break;
465 case EOpLessThan:
466 writeTriplet(visit, "(", " < ", ")");
467 break;
468 case EOpGreaterThan:
469 writeTriplet(visit, "(", " > ", ")");
470 break;
471 case EOpLessThanEqual:
472 writeTriplet(visit, "(", " <= ", ")");
473 break;
474 case EOpGreaterThanEqual:
475 writeTriplet(visit, "(", " >= ", ")");
476 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000477
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700478 // Notice the fall-through.
479 case EOpVectorTimesScalar:
480 case EOpVectorTimesMatrix:
481 case EOpMatrixTimesVector:
482 case EOpMatrixTimesScalar:
483 case EOpMatrixTimesMatrix:
484 writeTriplet(visit, "(", " * ", ")");
485 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000486
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700487 case EOpLogicalOr:
488 writeTriplet(visit, "(", " || ", ")");
489 break;
490 case EOpLogicalXor:
491 writeTriplet(visit, "(", " ^^ ", ")");
492 break;
493 case EOpLogicalAnd:
494 writeTriplet(visit, "(", " && ", ")");
495 break;
496 default:
497 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000498 }
499
500 return visitChildren;
501}
502
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700503bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000504{
zmo@google.com32e97312011-08-24 01:03:11 +0000505 TString preString;
506 TString postString = ")";
507
zmo@google.com5601ea02011-06-10 18:23:25 +0000508 switch (node->getOp())
509 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700510 case EOpNegative: preString = "(-"; break;
Zhenyao Mode1e00e2014-10-09 16:55:32 -0700511 case EOpPositive: preString = "(+"; break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700512 case EOpVectorLogicalNot: preString = "not("; break;
513 case EOpLogicalNot: preString = "(!"; break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200514 case EOpBitwiseNot: preString = "(~"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000515
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700516 case EOpPostIncrement: preString = "("; postString = "++)"; break;
517 case EOpPostDecrement: preString = "("; postString = "--)"; break;
518 case EOpPreIncrement: preString = "(++"; break;
519 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000520
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700521 case EOpRadians:
522 preString = "radians(";
523 break;
524 case EOpDegrees:
525 preString = "degrees(";
526 break;
527 case EOpSin:
528 preString = "sin(";
529 break;
530 case EOpCos:
531 preString = "cos(";
532 break;
533 case EOpTan:
534 preString = "tan(";
535 break;
536 case EOpAsin:
537 preString = "asin(";
538 break;
539 case EOpAcos:
540 preString = "acos(";
541 break;
542 case EOpAtan:
543 preString = "atan(";
544 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000545
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200546 case EOpSinh:
547 preString = "sinh(";
548 break;
549 case EOpCosh:
550 preString = "cosh(";
551 break;
552 case EOpTanh:
553 preString = "tanh(";
554 break;
555 case EOpAsinh:
556 preString = "asinh(";
557 break;
558 case EOpAcosh:
559 preString = "acosh(";
560 break;
561 case EOpAtanh:
562 preString = "atanh(";
563 break;
564
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700565 case EOpExp:
566 preString = "exp(";
567 break;
568 case EOpLog:
569 preString = "log(";
570 break;
571 case EOpExp2:
572 preString = "exp2(";
573 break;
574 case EOpLog2:
575 preString = "log2(";
576 break;
577 case EOpSqrt:
578 preString = "sqrt(";
579 break;
580 case EOpInverseSqrt:
581 preString = "inversesqrt(";
582 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000583
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700584 case EOpAbs:
585 preString = "abs(";
586 break;
587 case EOpSign:
588 preString = "sign(";
589 break;
590 case EOpFloor:
591 preString = "floor(";
592 break;
Qingqing Deng5dbece52015-02-27 20:35:38 -0800593 case EOpTrunc:
594 preString = "trunc(";
595 break;
596 case EOpRound:
597 preString = "round(";
598 break;
599 case EOpRoundEven:
600 preString = "roundEven(";
601 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700602 case EOpCeil:
603 preString = "ceil(";
604 break;
605 case EOpFract:
606 preString = "fract(";
607 break;
Arun Patole0c1726e2015-02-18 14:35:02 +0530608 case EOpIsNan:
609 preString = "isnan(";
610 break;
611 case EOpIsInf:
612 preString = "isinf(";
613 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000614
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200615 case EOpFloatBitsToInt:
616 preString = "floatBitsToInt(";
617 break;
618 case EOpFloatBitsToUint:
619 preString = "floatBitsToUint(";
620 break;
621 case EOpIntBitsToFloat:
622 preString = "intBitsToFloat(";
623 break;
624 case EOpUintBitsToFloat:
625 preString = "uintBitsToFloat(";
626 break;
627
Olli Etuaho7700ff62015-01-15 12:16:29 +0200628 case EOpPackSnorm2x16:
629 preString = "packSnorm2x16(";
630 break;
631 case EOpPackUnorm2x16:
632 preString = "packUnorm2x16(";
633 break;
634 case EOpPackHalf2x16:
635 preString = "packHalf2x16(";
636 break;
637 case EOpUnpackSnorm2x16:
638 preString = "unpackSnorm2x16(";
639 break;
640 case EOpUnpackUnorm2x16:
641 preString = "unpackUnorm2x16(";
642 break;
643 case EOpUnpackHalf2x16:
644 preString = "unpackHalf2x16(";
645 break;
646
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700647 case EOpLength:
648 preString = "length(";
649 break;
650 case EOpNormalize:
651 preString = "normalize(";
652 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000653
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700654 case EOpDFdx:
655 preString = "dFdx(";
656 break;
657 case EOpDFdy:
658 preString = "dFdy(";
659 break;
660 case EOpFwidth:
661 preString = "fwidth(";
662 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000663
Olli Etuahoe39706d2014-12-30 16:40:36 +0200664 case EOpTranspose:
665 preString = "transpose(";
666 break;
667 case EOpDeterminant:
668 preString = "determinant(";
669 break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +0200670 case EOpInverse:
671 preString = "inverse(";
672 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200673
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700674 case EOpAny:
675 preString = "any(";
676 break;
677 case EOpAll:
678 preString = "all(";
679 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000680
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700681 default:
682 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000683 }
684
zmo@google.com32e97312011-08-24 01:03:11 +0000685 if (visit == PreVisit && node->getUseEmulatedFunction())
686 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
687 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
688
zmo@google.com5601ea02011-06-10 18:23:25 +0000689 return true;
690}
691
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300692bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
693{
694 TInfoSinkBase &out = objSink();
695 // Notice two brackets at the beginning and end. The outer ones
696 // encapsulate the whole ternary expression. This preserves the
697 // order of precedence when ternary expressions are used in a
698 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
699 out << "((";
700 node->getCondition()->traverse(this);
701 out << ") ? (";
702 node->getTrueExpression()->traverse(this);
703 out << ") : (";
704 node->getFalseExpression()->traverse(this);
705 out << "))";
706 return false;
707}
708
Olli Etuaho57961272016-09-14 13:57:46 +0300709bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000710{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700711 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000712
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300713 out << "if (";
714 node->getCondition()->traverse(this);
715 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000716
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300717 incrementDepth(node);
718 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000719
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300720 if (node->getFalseBlock())
721 {
722 out << "else\n";
723 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000724 }
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300725 decrementDepth();
zmo@google.com5601ea02011-06-10 18:23:25 +0000726 return false;
727}
728
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200729bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200730{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200731 if (node->getStatementList())
732 {
733 writeTriplet(visit, "switch (", ") ", nullptr);
734 // The curly braces get written when visiting the statementList aggregate
735 }
736 else
737 {
738 // No statementList, so it won't output curly braces
739 writeTriplet(visit, "switch (", ") {", "}\n");
740 }
741 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200742}
743
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200744bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200745{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200746 if (node->hasCondition())
747 {
748 writeTriplet(visit, "case (", nullptr, "):\n");
749 return true;
750 }
751 else
752 {
753 TInfoSinkBase &out = objSink();
754 out << "default:\n";
755 return false;
756 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200757}
758
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100759bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
760{
761 TInfoSinkBase &out = objSink();
762 // Scope the blocks except when at the global scope.
763 if (mDepth > 0)
764 {
765 out << "{\n";
766 }
767
768 incrementDepth(node);
769 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
770 iter != node->getSequence()->end(); ++iter)
771 {
772 TIntermNode *curNode = *iter;
773 ASSERT(curNode != nullptr);
774 curNode->traverse(this);
775
776 if (isSingleStatement(curNode))
777 out << ";\n";
778 }
779 decrementDepth();
780
781 // Scope the blocks except when at the global scope.
782 if (mDepth > 0)
783 {
784 out << "}\n";
785 }
786 return false;
787}
788
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700789bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000790{
791 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700792 TInfoSinkBase &out = objSink();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700793 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000794 switch (node->getOp())
795 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700796 case EOpPrototype:
797 // Function declaration.
798 ASSERT(visit == PreVisit);
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300799 {
800 const TType &type = node->getType();
801 writeVariableType(type);
802 if (type.isArray())
803 out << arrayBrackets(type);
804 }
805
Olli Etuaho59f9a642015-08-06 20:38:26 +0300806 out << " " << hashFunctionNameIfNeeded(node->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700807
808 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700809 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700810 out << ")";
811
812 visitChildren = false;
813 break;
814 case EOpFunction: {
815 // Function definition.
816 ASSERT(visit == PreVisit);
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300817 {
818 const TType &type = node->getType();
819 writeVariableType(type);
820 if (type.isArray())
821 out << arrayBrackets(type);
822 }
823
Olli Etuaho59f9a642015-08-06 20:38:26 +0300824 out << " " << hashFunctionNameIfNeeded(node->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700825
826 incrementDepth(node);
Olli Etuahof51fdd22016-10-03 10:03:40 +0100827 // Function definition node contains two child nodes representing the function parameters
828 // and the function body.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700829 const TIntermSequence &sequence = *(node->getSequence());
Olli Etuahof51fdd22016-10-03 10:03:40 +0100830 ASSERT(sequence.size() == 2);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700831
832 // Traverse function parameters.
Olli Etuahof51fdd22016-10-03 10:03:40 +0100833 TIntermAggregate *params = sequence[0]->getAsAggregate();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700834 ASSERT(params != NULL);
835 ASSERT(params->getOp() == EOpParameters);
836 params->traverse(this);
837
838 // Traverse function body.
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100839 TIntermBlock *body = sequence[1]->getAsBlock();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700840 visitCodeBlock(body);
841 decrementDepth();
842
843 // Fully processed; no need to visit children.
844 visitChildren = false;
845 break;
846 }
847 case EOpFunctionCall:
848 // Function call.
849 if (visit == PreVisit)
Olli Etuaho59f9a642015-08-06 20:38:26 +0300850 out << hashFunctionNameIfNeeded(node->getNameObj()) << "(";
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200851 else if (visit == InVisit)
852 out << ", ";
853 else
854 out << ")";
855 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700856 case EOpParameters:
857 // Function parameters.
858 ASSERT(visit == PreVisit);
859 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700860 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700861 out << ")";
862 visitChildren = false;
863 break;
864 case EOpDeclaration:
865 // Variable declaration.
866 if (visit == PreVisit)
867 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700868 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700869 const TIntermTyped *variable = sequence.front()->getAsTyped();
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300870 writeLayoutQualifier(variable->getType());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700871 writeVariableType(variable->getType());
872 out << " ";
873 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000874 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700875 else if (visit == InVisit)
876 {
877 out << ", ";
878 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000879 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700880 else
881 {
882 mDeclaringVariables = false;
883 }
884 break;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700885 case EOpInvariantDeclaration:
886 // Invariant declaration.
887 ASSERT(visit == PreVisit);
888 {
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400889 const TIntermSequence *sequence = node->getSequence();
890 ASSERT(sequence && sequence->size() == 1);
891 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
892 ASSERT(symbol);
Zhenyao Mo2a517272014-10-27 16:09:57 -0700893 out << "invariant " << hashVariableName(symbol->getSymbol());
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400894 }
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700895 visitChildren = false;
896 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700897 case EOpConstructFloat:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700898 case EOpConstructVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700899 case EOpConstructVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700900 case EOpConstructVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700901 case EOpConstructBool:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700902 case EOpConstructBVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700903 case EOpConstructBVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700904 case EOpConstructBVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700905 case EOpConstructInt:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700906 case EOpConstructIVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700907 case EOpConstructIVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700908 case EOpConstructIVec4:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400909 case EOpConstructUInt:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400910 case EOpConstructUVec2:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400911 case EOpConstructUVec3:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400912 case EOpConstructUVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700913 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400914 case EOpConstructMat2x3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400915 case EOpConstructMat2x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400916 case EOpConstructMat3x2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700917 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400918 case EOpConstructMat3x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400919 case EOpConstructMat4x2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400920 case EOpConstructMat4x3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700921 case EOpConstructMat4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700922 case EOpConstructStruct:
Olli Etuahoe92507b2016-07-04 11:20:10 +0300923 writeConstructorTriplet(visit, node->getType());
924 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000925
Olli Etuahoe39706d2014-12-30 16:40:36 +0200926 case EOpOuterProduct:
927 writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
928 break;
929
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700930 case EOpLessThan:
931 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
932 break;
933 case EOpGreaterThan:
934 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
935 break;
936 case EOpLessThanEqual:
937 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
938 break;
939 case EOpGreaterThanEqual:
940 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
941 break;
942 case EOpVectorEqual:
943 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
944 break;
945 case EOpVectorNotEqual:
946 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
947 break;
948 case EOpComma:
Zhenyao Mo0783efd2014-10-21 15:51:59 -0700949 writeTriplet(visit, "(", ", ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700950 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000951
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700952 case EOpMod:
953 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
954 break;
Olli Etuahob6e07a62015-02-16 12:22:10 +0200955 case EOpModf:
956 writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
957 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700958 case EOpPow:
959 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
960 break;
961 case EOpAtan:
962 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
963 break;
964 case EOpMin:
965 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
966 break;
967 case EOpMax:
968 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
969 break;
970 case EOpClamp:
971 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
972 break;
973 case EOpMix:
974 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
975 break;
976 case EOpStep:
977 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
978 break;
979 case EOpSmoothStep:
980 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
981 break;
982 case EOpDistance:
983 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
984 break;
985 case EOpDot:
986 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
987 break;
988 case EOpCross:
989 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
990 break;
991 case EOpFaceForward:
992 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
993 break;
994 case EOpReflect:
995 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
996 break;
997 case EOpRefract:
998 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
999 break;
1000 case EOpMul:
1001 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
1002 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001003
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001004 default:
1005 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001006 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001007 return visitChildren;
1008}
1009
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001010bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001011{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001012 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001013
Zhenyao Mo7cab38b2013-10-15 12:59:30 -07001014 incrementDepth(node);
Corentin Wallez7258e302015-09-22 10:40:24 -07001015
zmo@google.com5601ea02011-06-10 18:23:25 +00001016 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001017
1018 // Only for loops can be unrolled
1019 ASSERT(!node->getUnrollFlag() || loopType == ELoopFor);
1020
zmo@google.com5601ea02011-06-10 18:23:25 +00001021 if (loopType == ELoopFor) // for loop
1022 {
Zhenyao Mo550c6002014-02-26 15:40:48 -08001023 if (!node->getUnrollFlag())
1024 {
zmo@google.com5601ea02011-06-10 18:23:25 +00001025 out << "for (";
1026 if (node->getInit())
1027 node->getInit()->traverse(this);
1028 out << "; ";
1029
1030 if (node->getCondition())
1031 node->getCondition()->traverse(this);
1032 out << "; ";
1033
1034 if (node->getExpression())
1035 node->getExpression()->traverse(this);
1036 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001037
1038 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001039 }
Zhenyao Mo550c6002014-02-26 15:40:48 -08001040 else
1041 {
1042 // Need to put a one-iteration loop here to handle break.
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001043 TIntermSequence *declSeq =
Zhenyao Mo550c6002014-02-26 15:40:48 -08001044 node->getInit()->getAsAggregate()->getSequence();
1045 TIntermSymbol *indexSymbol =
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001046 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -08001047 TString name = hashVariableName(indexSymbol->getSymbol());
1048 out << "for (int " << name << " = 0; "
1049 << name << " < 1; "
1050 << "++" << name << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001051
1052 out << "{\n";
1053 mLoopUnrollStack.push(node);
1054 while (mLoopUnrollStack.satisfiesLoopCondition())
1055 {
1056 visitCodeBlock(node->getBody());
1057 mLoopUnrollStack.step();
1058 }
1059 mLoopUnrollStack.pop();
1060 out << "}\n";
Zhenyao Mo550c6002014-02-26 15:40:48 -08001061 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001062 }
1063 else if (loopType == ELoopWhile) // while loop
1064 {
1065 out << "while (";
1066 ASSERT(node->getCondition() != NULL);
1067 node->getCondition()->traverse(this);
1068 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001069
1070 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001071 }
1072 else // do-while loop
1073 {
1074 ASSERT(loopType == ELoopDoWhile);
1075 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001076
zmo@google.com5601ea02011-06-10 18:23:25 +00001077 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001078
zmo@google.com5601ea02011-06-10 18:23:25 +00001079 out << "while (";
1080 ASSERT(node->getCondition() != NULL);
1081 node->getCondition()->traverse(this);
1082 out << ");\n";
1083 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001084
zmo@google.com5601ea02011-06-10 18:23:25 +00001085 decrementDepth();
1086
1087 // No need to visit children. They have been already processed in
1088 // this function.
1089 return false;
1090}
1091
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001092bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001093{
1094 switch (node->getFlowOp())
1095 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001096 case EOpKill:
1097 writeTriplet(visit, "discard", NULL, NULL);
1098 break;
1099 case EOpBreak:
1100 writeTriplet(visit, "break", NULL, NULL);
1101 break;
1102 case EOpContinue:
1103 writeTriplet(visit, "continue", NULL, NULL);
1104 break;
1105 case EOpReturn:
1106 writeTriplet(visit, "return ", NULL, NULL);
1107 break;
1108 default:
1109 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001110 }
1111
1112 return true;
1113}
1114
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001115void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001116{
zmo@google.com5601ea02011-06-10 18:23:25 +00001117 TInfoSinkBase &out = objSink();
1118 if (node != NULL)
1119 {
1120 node->traverse(this);
1121 // Single statements not part of a sequence need to be terminated
1122 // with semi-colon.
1123 if (isSingleStatement(node))
1124 out << ";\n";
1125 }
1126 else
1127 {
1128 out << "{\n}\n"; // Empty code block.
1129 }
1130}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001131
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001132TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001133{
Olli Etuahoe92507b2016-07-04 11:20:10 +03001134 if (type.getBasicType() == EbtStruct)
1135 return hashName(type.getStruct()->name());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001136 else
Olli Etuahoe92507b2016-07-04 11:20:10 +03001137 return type.getBuiltInTypeNameString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001138}
1139
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001140TString TOutputGLSLBase::hashName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001141{
1142 if (mHashFunction == NULL || name.empty())
1143 return name;
1144 NameMap::const_iterator it = mNameMap.find(name.c_str());
1145 if (it != mNameMap.end())
1146 return it->second.c_str();
1147 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
1148 mNameMap[name.c_str()] = hashedName.c_str();
1149 return hashedName;
1150}
1151
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001152TString TOutputGLSLBase::hashVariableName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001153{
Jamie Madill02f20dd2013-09-12 12:07:42 -04001154 if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001155 return name;
1156 return hashName(name);
1157}
1158
Olli Etuaho59f9a642015-08-06 20:38:26 +03001159TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001160{
Olli Etuaho59f9a642015-08-06 20:38:26 +03001161 TString mangledStr = mangledName.getString();
1162 TString name = TFunction::unmangleName(mangledStr);
1163 if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001164 return translateTextureFunction(name);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001165 if (mangledName.isInternal())
1166 return name;
1167 else
1168 return hashName(name);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001169}
Jamie Madill98493dd2013-07-08 14:39:03 -04001170
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001171bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001172{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001173 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001174 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001175 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001176 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001177 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001178
1179 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001180}
1181
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001182void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001183{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001184 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001185
1186 out << "struct " << hashName(structure->name()) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001187 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001188 for (size_t i = 0; i < fields.size(); ++i)
1189 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001190 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001191 if (writeVariablePrecision(field->type()->getPrecision()))
1192 out << " ";
1193 out << getTypeName(*field->type()) << " " << hashName(field->name());
1194 if (field->type()->isArray())
1195 out << arrayBrackets(*field->type());
1196 out << ";\n";
1197 }
1198 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001199}
Jamie Madill98493dd2013-07-08 14:39:03 -04001200
Geoff Langbdcc54a2015-09-02 13:09:48 -04001201void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1202{
1203 TInfoSinkBase &out = objSink();
1204
1205 out << "layout(";
1206
1207 switch (interfaceBlock->blockStorage())
1208 {
1209 case EbsUnspecified:
1210 case EbsShared:
1211 // Default block storage is shared.
1212 out << "shared";
1213 break;
1214
1215 case EbsPacked:
1216 out << "packed";
1217 break;
1218
1219 case EbsStd140:
1220 out << "std140";
1221 break;
1222
1223 default:
1224 UNREACHABLE();
1225 break;
1226 }
1227
1228 out << ", ";
1229
1230 switch (interfaceBlock->matrixPacking())
1231 {
1232 case EmpUnspecified:
1233 case EmpColumnMajor:
1234 // Default matrix packing is column major.
1235 out << "column_major";
1236 break;
1237
1238 case EmpRowMajor:
1239 out << "row_major";
1240 break;
1241
1242 default:
1243 UNREACHABLE();
1244 break;
1245 }
1246
1247 out << ") ";
1248}
1249
1250void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1251{
1252 TInfoSinkBase &out = objSink();
1253
1254 out << hashName(interfaceBlock->name()) << "{\n";
1255 const TFieldList &fields = interfaceBlock->fields();
1256 for (size_t i = 0; i < fields.size(); ++i)
1257 {
1258 const TField *field = fields[i];
1259 if (writeVariablePrecision(field->type()->getPrecision()))
1260 out << " ";
1261 out << getTypeName(*field->type()) << " " << hashName(field->name());
1262 if (field->type()->isArray())
1263 out << arrayBrackets(*field->type());
1264 out << ";\n";
1265 }
1266 out << "}";
1267}