blob: f048b050b7ebbd9100e958878d7fe17592d3f8df [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 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -070030 else if (const TIntermSelection *selection = node->getAsSelectionNode())
zmo@google.com5601ea02011-06-10 18:23:25 +000031 {
32 // Ternary operators are usually part of an assignment operator.
33 // This handles those rare cases in which they are all by themselves.
34 return selection->usesTernaryOperator();
35 }
36 else if (node->getAsLoopNode())
37 {
38 return false;
39 }
Olli Etuaho01cd8af2015-02-20 10:39:20 +020040 else if (node->getAsSwitchNode())
41 {
42 return false;
43 }
44 else if (node->getAsCaseNode())
45 {
46 return false;
47 }
zmo@google.com5601ea02011-06-10 18:23:25 +000048 return true;
49}
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080050
zmo@google.com5601ea02011-06-10 18:23:25 +000051} // namespace
52
Zhenyao Mo9eedea02014-05-12 16:02:35 -070053TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000054 ShArrayIndexClampingStrategy clampingStrategy,
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000055 ShHashFunction64 hashFunction,
Zhenyao Mo9eedea02014-05-12 16:02:35 -070056 NameMap &nameMap,
57 TSymbolTable &symbolTable,
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080058 int shaderVersion,
59 ShShaderOutput output)
zmo@google.com5601ea02011-06-10 18:23:25 +000060 : TIntermTraverser(true, true, true),
61 mObjSink(objSink),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000062 mDeclaringVariables(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000063 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000064 mHashFunction(hashFunction),
65 mNameMap(nameMap),
Jamie Madill02f20dd2013-09-12 12:07:42 -040066 mSymbolTable(symbolTable),
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080067 mShaderVersion(shaderVersion),
68 mOutput(output)
zmo@google.com5601ea02011-06-10 18:23:25 +000069{
70}
71
Zhenyao Mo9eedea02014-05-12 16:02:35 -070072void TOutputGLSLBase::writeTriplet(
73 Visit visit, const char *preStr, const char *inStr, const char *postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000074{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070075 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +000076 if (visit == PreVisit && preStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000077 out << preStr;
zmo@google.com5601ea02011-06-10 18:23:25 +000078 else if (visit == InVisit && inStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000079 out << inStr;
zmo@google.com5601ea02011-06-10 18:23:25 +000080 else if (visit == PostVisit && postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000081 out << postStr;
zmo@google.com5601ea02011-06-10 18:23:25 +000082}
83
Zhenyao Mo9eedea02014-05-12 16:02:35 -070084void TOutputGLSLBase::writeBuiltInFunctionTriplet(
85 Visit visit, const char *preStr, bool useEmulatedFunction)
zmo@google.com5601ea02011-06-10 18:23:25 +000086{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070087 TString preString = useEmulatedFunction ?
88 BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
89 writeTriplet(visit, preString.c_str(), ", ", ")");
90}
91
Olli Etuahoae69d7e2015-10-07 17:19:50 +030092void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
93{
94 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
95 {
96 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
97 if (layoutQualifier.location >= 0)
98 {
99 TInfoSinkBase &out = objSink();
100 out << "layout(location = " << layoutQualifier.location << ") ";
101 }
102 }
103}
104
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700105void TOutputGLSLBase::writeVariableType(const TType &type)
106{
107 TInfoSinkBase &out = objSink();
Olli Etuaho214c2d82015-04-27 14:49:13 +0300108 if (type.isInvariant())
109 {
110 out << "invariant ";
111 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400112 if (type.getBasicType() == EbtInterfaceBlock)
113 {
114 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
115 declareInterfaceBlockLayout(interfaceBlock);
116 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000117 TQualifier qualifier = type.getQualifier();
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400118 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400119 {
Qingqing Dengad0d0792015-04-08 14:25:06 -0700120 if (IsGLSL130OrNewer(mOutput))
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800121 {
122 switch (qualifier)
123 {
124 case EvqAttribute:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300125 out << "in ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800126 break;
127 case EvqVaryingIn:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300128 out << "in ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800129 break;
130 case EvqVaryingOut:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300131 out << "out ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800132 break;
133 default:
134 out << type.getQualifierString() << " ";
135 break;
136 }
137 }
138 else
139 {
140 out << type.getQualifierString() << " ";
141 }
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400142 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000143 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700144 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000145 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400146 TStructure *structure = type.getStruct();
147
148 declareStruct(structure);
149
150 if (!structure->name().empty())
151 {
152 mDeclaredStructs.insert(structure->uniqueId());
153 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000154 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400155 else if (type.getBasicType() == EbtInterfaceBlock)
156 {
157 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
158 declareInterfaceBlock(interfaceBlock);
159 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000160 else
161 {
162 if (writeVariablePrecision(type.getPrecision()))
163 out << " ";
164 out << getTypeName(type);
165 }
166}
167
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700168void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000169{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700170 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000171 for (TIntermSequence::const_iterator iter = args.begin();
172 iter != args.end(); ++iter)
173 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700174 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000175 ASSERT(arg != NULL);
176
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700177 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000178 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000179
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700180 const TString &name = arg->getSymbol();
zmo@google.com5601ea02011-06-10 18:23:25 +0000181 if (!name.empty())
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000182 out << " " << hashName(name);
zmo@google.com5601ea02011-06-10 18:23:25 +0000183 if (type.isArray())
184 out << arrayBrackets(type);
185
186 // Put a comma if this is not the last argument.
187 if (iter != args.end() - 1)
188 out << ", ";
189 }
190}
191
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400192const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
193 const TType &type, const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000194{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700195 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000196
197 if (type.getBasicType() == EbtStruct)
198 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700199 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -0400200 out << hashName(structure->name()) << "(";
201
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700202 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400203 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000204 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700205 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000206 ASSERT(fieldType != NULL);
207 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700208 if (i != fields.size() - 1)
209 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000210 }
211 out << ")";
212 }
213 else
214 {
Jamie Madill94bf7f22013-07-08 13:31:15 -0400215 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000216 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700217 if (writeType)
218 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400219 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000220 {
221 switch (pConstUnion->getType())
222 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700223 case EbtFloat:
224 out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
225 break;
226 case EbtInt:
227 out << pConstUnion->getIConst();
228 break;
Olli Etuaho5321c802015-04-02 17:08:16 +0300229 case EbtUInt:
230 out << pConstUnion->getUConst() << "u";
231 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700232 case EbtBool:
233 out << pConstUnion->getBConst();
234 break;
235 default: UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000236 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700237 if (i != size - 1)
238 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000239 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700240 if (writeType)
241 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000242 }
243 return pConstUnion;
244}
245
Olli Etuahof40319e2015-03-10 14:33:00 +0200246void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type, const char *constructorBaseType)
247{
248 TInfoSinkBase &out = objSink();
249 if (visit == PreVisit)
250 {
251 if (type.isArray())
252 {
253 out << constructorBaseType;
254 out << arrayBrackets(type);
255 out << "(";
256 }
257 else
258 {
259 out << constructorBaseType << "(";
260 }
261 }
262 else
263 {
264 writeTriplet(visit, nullptr, ", ", ")");
265 }
266}
267
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700268void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000269{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700270 TInfoSinkBase &out = objSink();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800271 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
272 out << mLoopUnrollStack.getLoopIndexValue(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000273 else
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000274 out << hashVariableName(node->getSymbol());
zmo@google.com5601ea02011-06-10 18:23:25 +0000275
276 if (mDeclaringVariables && node->getType().isArray())
277 out << arrayBrackets(node->getType());
278}
279
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700280void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000281{
282 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
283}
284
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700285bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000286{
287 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700288 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000289 switch (node->getOp())
290 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700291 case EOpInitialize:
292 if (visit == InVisit)
293 {
294 out << " = ";
295 // RHS of initialize is not being declared.
296 mDeclaringVariables = false;
297 }
298 break;
299 case EOpAssign:
300 writeTriplet(visit, "(", " = ", ")");
301 break;
302 case EOpAddAssign:
303 writeTriplet(visit, "(", " += ", ")");
304 break;
305 case EOpSubAssign:
306 writeTriplet(visit, "(", " -= ", ")");
307 break;
308 case EOpDivAssign:
309 writeTriplet(visit, "(", " /= ", ")");
310 break;
Olli Etuahoff805cc2015-02-13 10:59:34 +0200311 case EOpIModAssign:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000312 writeTriplet(visit, "(", " %= ", ")");
313 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700314 // Notice the fall-through.
315 case EOpMulAssign:
316 case EOpVectorTimesMatrixAssign:
317 case EOpVectorTimesScalarAssign:
318 case EOpMatrixTimesScalarAssign:
319 case EOpMatrixTimesMatrixAssign:
320 writeTriplet(visit, "(", " *= ", ")");
321 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200322 case EOpBitShiftLeftAssign:
323 writeTriplet(visit, "(", " <<= ", ")");
324 break;
325 case EOpBitShiftRightAssign:
326 writeTriplet(visit, "(", " >>= ", ")");
327 break;
328 case EOpBitwiseAndAssign:
329 writeTriplet(visit, "(", " &= ", ")");
330 break;
331 case EOpBitwiseXorAssign:
332 writeTriplet(visit, "(", " ^= ", ")");
333 break;
334 case EOpBitwiseOrAssign:
335 writeTriplet(visit, "(", " |= ", ")");
336 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700337
338 case EOpIndexDirect:
339 writeTriplet(visit, NULL, "[", "]");
340 break;
341 case EOpIndexIndirect:
342 if (node->getAddIndexClamp())
343 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000344 if (visit == InVisit)
345 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700346 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
347 out << "[int(clamp(float(";
348 else
349 out << "[webgl_int_clamp(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000350 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700351 else if (visit == PostVisit)
352 {
353 int maxSize;
354 TIntermTyped *left = node->getLeft();
355 TType leftType = left->getType();
zmo@google.com5601ea02011-06-10 18:23:25 +0000356
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700357 if (left->isArray())
358 {
359 // The shader will fail validation if the array length is not > 0.
360 maxSize = leftType.getArraySize() - 1;
361 }
362 else
363 {
364 maxSize = leftType.getNominalSize() - 1;
365 }
366
367 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
368 out << "), 0.0, float(" << maxSize << ")))]";
369 else
370 out << ", 0, " << maxSize << ")]";
371 }
372 }
373 else
374 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000375 writeTriplet(visit, NULL, "[", "]");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700376 }
377 break;
378 case EOpIndexDirectStruct:
379 if (visit == InVisit)
380 {
381 // Here we are writing out "foo.bar", where "foo" is struct
382 // and "bar" is field. In AST, it is represented as a binary
383 // node, where left child represents "foo" and right child "bar".
384 // The node itself represents ".". The struct field "bar" is
385 // actually stored as an index into TStructure::fields.
386 out << ".";
387 const TStructure *structure = node->getLeft()->getType().getStruct();
388 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
389 const TField *field = structure->fields()[index->getIConst(0)];
390
391 TString fieldName = field->name();
392 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
393 fieldName = hashName(fieldName);
394
395 out << fieldName;
396 visitChildren = false;
397 }
398 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400399 case EOpIndexDirectInterfaceBlock:
400 if (visit == InVisit)
401 {
402 out << ".";
403 const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
404 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
405 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
406
407 TString fieldName = field->name();
408 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
409 fieldName = hashName(fieldName);
410
411 out << fieldName;
412 visitChildren = false;
413 }
414 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700415 case EOpVectorSwizzle:
416 if (visit == InVisit)
417 {
418 out << ".";
419 TIntermAggregate *rightChild = node->getRight()->getAsAggregate();
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700420 TIntermSequence *sequence = rightChild->getSequence();
421 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); ++sit)
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000422 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700423 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
424 ASSERT(element->getBasicType() == EbtInt);
425 ASSERT(element->getNominalSize() == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400426 const TConstantUnion& data = element->getUnionArrayPointer()[0];
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700427 ASSERT(data.getType() == EbtInt);
428 switch (data.getIConst())
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000429 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700430 case 0:
431 out << "x";
432 break;
433 case 1:
434 out << "y";
435 break;
436 case 2:
437 out << "z";
438 break;
439 case 3:
440 out << "w";
441 break;
442 default:
443 UNREACHABLE();
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000444 }
445 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700446 visitChildren = false;
447 }
448 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000449
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700450 case EOpAdd:
451 writeTriplet(visit, "(", " + ", ")");
452 break;
453 case EOpSub:
454 writeTriplet(visit, "(", " - ", ")");
455 break;
456 case EOpMul:
457 writeTriplet(visit, "(", " * ", ")");
458 break;
459 case EOpDiv:
460 writeTriplet(visit, "(", " / ", ")");
461 break;
Olli Etuahoff805cc2015-02-13 10:59:34 +0200462 case EOpIMod:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000463 writeTriplet(visit, "(", " % ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700464 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200465 case EOpBitShiftLeft:
466 writeTriplet(visit, "(", " << ", ")");
467 break;
468 case EOpBitShiftRight:
469 writeTriplet(visit, "(", " >> ", ")");
470 break;
471 case EOpBitwiseAnd:
472 writeTriplet(visit, "(", " & ", ")");
473 break;
474 case EOpBitwiseXor:
475 writeTriplet(visit, "(", " ^ ", ")");
476 break;
477 case EOpBitwiseOr:
478 writeTriplet(visit, "(", " | ", ")");
479 break;
480
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700481 case EOpEqual:
482 writeTriplet(visit, "(", " == ", ")");
483 break;
484 case EOpNotEqual:
485 writeTriplet(visit, "(", " != ", ")");
486 break;
487 case EOpLessThan:
488 writeTriplet(visit, "(", " < ", ")");
489 break;
490 case EOpGreaterThan:
491 writeTriplet(visit, "(", " > ", ")");
492 break;
493 case EOpLessThanEqual:
494 writeTriplet(visit, "(", " <= ", ")");
495 break;
496 case EOpGreaterThanEqual:
497 writeTriplet(visit, "(", " >= ", ")");
498 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000499
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700500 // Notice the fall-through.
501 case EOpVectorTimesScalar:
502 case EOpVectorTimesMatrix:
503 case EOpMatrixTimesVector:
504 case EOpMatrixTimesScalar:
505 case EOpMatrixTimesMatrix:
506 writeTriplet(visit, "(", " * ", ")");
507 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000508
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700509 case EOpLogicalOr:
510 writeTriplet(visit, "(", " || ", ")");
511 break;
512 case EOpLogicalXor:
513 writeTriplet(visit, "(", " ^^ ", ")");
514 break;
515 case EOpLogicalAnd:
516 writeTriplet(visit, "(", " && ", ")");
517 break;
518 default:
519 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000520 }
521
522 return visitChildren;
523}
524
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700525bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000526{
zmo@google.com32e97312011-08-24 01:03:11 +0000527 TString preString;
528 TString postString = ")";
529
zmo@google.com5601ea02011-06-10 18:23:25 +0000530 switch (node->getOp())
531 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700532 case EOpNegative: preString = "(-"; break;
Zhenyao Mode1e00e2014-10-09 16:55:32 -0700533 case EOpPositive: preString = "(+"; break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700534 case EOpVectorLogicalNot: preString = "not("; break;
535 case EOpLogicalNot: preString = "(!"; break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200536 case EOpBitwiseNot: preString = "(~"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000537
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700538 case EOpPostIncrement: preString = "("; postString = "++)"; break;
539 case EOpPostDecrement: preString = "("; postString = "--)"; break;
540 case EOpPreIncrement: preString = "(++"; break;
541 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000542
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700543 case EOpRadians:
544 preString = "radians(";
545 break;
546 case EOpDegrees:
547 preString = "degrees(";
548 break;
549 case EOpSin:
550 preString = "sin(";
551 break;
552 case EOpCos:
553 preString = "cos(";
554 break;
555 case EOpTan:
556 preString = "tan(";
557 break;
558 case EOpAsin:
559 preString = "asin(";
560 break;
561 case EOpAcos:
562 preString = "acos(";
563 break;
564 case EOpAtan:
565 preString = "atan(";
566 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000567
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200568 case EOpSinh:
569 preString = "sinh(";
570 break;
571 case EOpCosh:
572 preString = "cosh(";
573 break;
574 case EOpTanh:
575 preString = "tanh(";
576 break;
577 case EOpAsinh:
578 preString = "asinh(";
579 break;
580 case EOpAcosh:
581 preString = "acosh(";
582 break;
583 case EOpAtanh:
584 preString = "atanh(";
585 break;
586
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700587 case EOpExp:
588 preString = "exp(";
589 break;
590 case EOpLog:
591 preString = "log(";
592 break;
593 case EOpExp2:
594 preString = "exp2(";
595 break;
596 case EOpLog2:
597 preString = "log2(";
598 break;
599 case EOpSqrt:
600 preString = "sqrt(";
601 break;
602 case EOpInverseSqrt:
603 preString = "inversesqrt(";
604 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000605
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700606 case EOpAbs:
607 preString = "abs(";
608 break;
609 case EOpSign:
610 preString = "sign(";
611 break;
612 case EOpFloor:
613 preString = "floor(";
614 break;
Qingqing Deng5dbece52015-02-27 20:35:38 -0800615 case EOpTrunc:
616 preString = "trunc(";
617 break;
618 case EOpRound:
619 preString = "round(";
620 break;
621 case EOpRoundEven:
622 preString = "roundEven(";
623 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700624 case EOpCeil:
625 preString = "ceil(";
626 break;
627 case EOpFract:
628 preString = "fract(";
629 break;
Arun Patole0c1726e2015-02-18 14:35:02 +0530630 case EOpIsNan:
631 preString = "isnan(";
632 break;
633 case EOpIsInf:
634 preString = "isinf(";
635 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000636
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200637 case EOpFloatBitsToInt:
638 preString = "floatBitsToInt(";
639 break;
640 case EOpFloatBitsToUint:
641 preString = "floatBitsToUint(";
642 break;
643 case EOpIntBitsToFloat:
644 preString = "intBitsToFloat(";
645 break;
646 case EOpUintBitsToFloat:
647 preString = "uintBitsToFloat(";
648 break;
649
Olli Etuaho7700ff62015-01-15 12:16:29 +0200650 case EOpPackSnorm2x16:
651 preString = "packSnorm2x16(";
652 break;
653 case EOpPackUnorm2x16:
654 preString = "packUnorm2x16(";
655 break;
656 case EOpPackHalf2x16:
657 preString = "packHalf2x16(";
658 break;
659 case EOpUnpackSnorm2x16:
660 preString = "unpackSnorm2x16(";
661 break;
662 case EOpUnpackUnorm2x16:
663 preString = "unpackUnorm2x16(";
664 break;
665 case EOpUnpackHalf2x16:
666 preString = "unpackHalf2x16(";
667 break;
668
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700669 case EOpLength:
670 preString = "length(";
671 break;
672 case EOpNormalize:
673 preString = "normalize(";
674 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000675
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700676 case EOpDFdx:
677 preString = "dFdx(";
678 break;
679 case EOpDFdy:
680 preString = "dFdy(";
681 break;
682 case EOpFwidth:
683 preString = "fwidth(";
684 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000685
Olli Etuahoe39706d2014-12-30 16:40:36 +0200686 case EOpTranspose:
687 preString = "transpose(";
688 break;
689 case EOpDeterminant:
690 preString = "determinant(";
691 break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +0200692 case EOpInverse:
693 preString = "inverse(";
694 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200695
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700696 case EOpAny:
697 preString = "any(";
698 break;
699 case EOpAll:
700 preString = "all(";
701 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000702
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700703 default:
704 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000705 }
706
zmo@google.com32e97312011-08-24 01:03:11 +0000707 if (visit == PreVisit && node->getUseEmulatedFunction())
708 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
709 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
710
zmo@google.com5601ea02011-06-10 18:23:25 +0000711 return true;
712}
713
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700714bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000715{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700716 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000717
718 if (node->usesTernaryOperator())
719 {
720 // Notice two brackets at the beginning and end. The outer ones
721 // encapsulate the whole ternary expression. This preserves the
722 // order of precedence when ternary expressions are used in a
723 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
724 out << "((";
725 node->getCondition()->traverse(this);
726 out << ") ? (";
727 node->getTrueBlock()->traverse(this);
728 out << ") : (";
729 node->getFalseBlock()->traverse(this);
730 out << "))";
731 }
732 else
733 {
734 out << "if (";
735 node->getCondition()->traverse(this);
736 out << ")\n";
737
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700738 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000739 visitCodeBlock(node->getTrueBlock());
740
741 if (node->getFalseBlock())
742 {
743 out << "else\n";
744 visitCodeBlock(node->getFalseBlock());
745 }
746 decrementDepth();
747 }
748 return false;
749}
750
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200751bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200752{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200753 if (node->getStatementList())
754 {
755 writeTriplet(visit, "switch (", ") ", nullptr);
756 // The curly braces get written when visiting the statementList aggregate
757 }
758 else
759 {
760 // No statementList, so it won't output curly braces
761 writeTriplet(visit, "switch (", ") {", "}\n");
762 }
763 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200764}
765
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200766bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200767{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200768 if (node->hasCondition())
769 {
770 writeTriplet(visit, "case (", nullptr, "):\n");
771 return true;
772 }
773 else
774 {
775 TInfoSinkBase &out = objSink();
776 out << "default:\n";
777 return false;
778 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200779}
780
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700781bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000782{
783 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700784 TInfoSinkBase &out = objSink();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700785 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000786 switch (node->getOp())
787 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700788 case EOpSequence:
789 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700790 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700791 {
792 out << "{\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000793 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000794
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700795 incrementDepth(node);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700796 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
797 iter != node->getSequence()->end(); ++iter)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700798 {
Austin Kinross3ae64652015-01-26 15:51:39 -0800799 TIntermNode *curNode = *iter;
800 ASSERT(curNode != NULL);
801 curNode->traverse(this);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700802
Austin Kinross3ae64652015-01-26 15:51:39 -0800803 if (isSingleStatement(curNode))
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700804 out << ";\n";
805 }
806 decrementDepth();
807
808 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700809 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700810 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700811 out << "}\n";
812 }
813 visitChildren = false;
814 break;
815 case EOpPrototype:
816 // Function declaration.
817 ASSERT(visit == PreVisit);
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300818 {
819 const TType &type = node->getType();
820 writeVariableType(type);
821 if (type.isArray())
822 out << arrayBrackets(type);
823 }
824
Olli Etuaho59f9a642015-08-06 20:38:26 +0300825 out << " " << hashFunctionNameIfNeeded(node->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700826
827 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700828 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700829 out << ")";
830
831 visitChildren = false;
832 break;
833 case EOpFunction: {
834 // Function definition.
835 ASSERT(visit == PreVisit);
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300836 {
837 const TType &type = node->getType();
838 writeVariableType(type);
839 if (type.isArray())
840 out << arrayBrackets(type);
841 }
842
Olli Etuaho59f9a642015-08-06 20:38:26 +0300843 out << " " << hashFunctionNameIfNeeded(node->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700844
845 incrementDepth(node);
846 // Function definition node contains one or two children nodes
847 // representing function parameters and function body. The latter
848 // is not present in case of empty function bodies.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700849 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700850 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
851 TIntermSequence::const_iterator seqIter = sequence.begin();
852
853 // Traverse function parameters.
854 TIntermAggregate *params = (*seqIter)->getAsAggregate();
855 ASSERT(params != NULL);
856 ASSERT(params->getOp() == EOpParameters);
857 params->traverse(this);
858
859 // Traverse function body.
860 TIntermAggregate *body = ++seqIter != sequence.end() ?
861 (*seqIter)->getAsAggregate() : NULL;
862 visitCodeBlock(body);
863 decrementDepth();
864
865 // Fully processed; no need to visit children.
866 visitChildren = false;
867 break;
868 }
869 case EOpFunctionCall:
870 // Function call.
871 if (visit == PreVisit)
Olli Etuaho59f9a642015-08-06 20:38:26 +0300872 out << hashFunctionNameIfNeeded(node->getNameObj()) << "(";
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200873 else if (visit == InVisit)
874 out << ", ";
875 else
876 out << ")";
877 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700878 case EOpParameters:
879 // Function parameters.
880 ASSERT(visit == PreVisit);
881 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700882 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700883 out << ")";
884 visitChildren = false;
885 break;
886 case EOpDeclaration:
887 // Variable declaration.
888 if (visit == PreVisit)
889 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700890 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700891 const TIntermTyped *variable = sequence.front()->getAsTyped();
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300892 writeLayoutQualifier(variable->getType());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700893 writeVariableType(variable->getType());
894 out << " ";
895 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000896 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700897 else if (visit == InVisit)
898 {
899 out << ", ";
900 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000901 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700902 else
903 {
904 mDeclaringVariables = false;
905 }
906 break;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700907 case EOpInvariantDeclaration:
908 // Invariant declaration.
909 ASSERT(visit == PreVisit);
910 {
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400911 const TIntermSequence *sequence = node->getSequence();
912 ASSERT(sequence && sequence->size() == 1);
913 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
914 ASSERT(symbol);
Zhenyao Mo2a517272014-10-27 16:09:57 -0700915 out << "invariant " << hashVariableName(symbol->getSymbol());
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400916 }
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700917 visitChildren = false;
918 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700919 case EOpConstructFloat:
Olli Etuahof40319e2015-03-10 14:33:00 +0200920 writeConstructorTriplet(visit, node->getType(), "float");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700921 break;
922 case EOpConstructVec2:
Olli Etuahof40319e2015-03-10 14:33:00 +0200923 writeConstructorTriplet(visit, node->getType(), "vec2");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700924 break;
925 case EOpConstructVec3:
Olli Etuahof40319e2015-03-10 14:33:00 +0200926 writeConstructorTriplet(visit, node->getType(), "vec3");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700927 break;
928 case EOpConstructVec4:
Olli Etuahof40319e2015-03-10 14:33:00 +0200929 writeConstructorTriplet(visit, node->getType(), "vec4");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700930 break;
931 case EOpConstructBool:
Olli Etuahof40319e2015-03-10 14:33:00 +0200932 writeConstructorTriplet(visit, node->getType(), "bool");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700933 break;
934 case EOpConstructBVec2:
Olli Etuahof40319e2015-03-10 14:33:00 +0200935 writeConstructorTriplet(visit, node->getType(), "bvec2");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700936 break;
937 case EOpConstructBVec3:
Olli Etuahof40319e2015-03-10 14:33:00 +0200938 writeConstructorTriplet(visit, node->getType(), "bvec3");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700939 break;
940 case EOpConstructBVec4:
Olli Etuahof40319e2015-03-10 14:33:00 +0200941 writeConstructorTriplet(visit, node->getType(), "bvec4");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700942 break;
943 case EOpConstructInt:
Olli Etuahof40319e2015-03-10 14:33:00 +0200944 writeConstructorTriplet(visit, node->getType(), "int");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700945 break;
946 case EOpConstructIVec2:
Olli Etuahof40319e2015-03-10 14:33:00 +0200947 writeConstructorTriplet(visit, node->getType(), "ivec2");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700948 break;
949 case EOpConstructIVec3:
Olli Etuahof40319e2015-03-10 14:33:00 +0200950 writeConstructorTriplet(visit, node->getType(), "ivec3");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700951 break;
952 case EOpConstructIVec4:
Olli Etuahof40319e2015-03-10 14:33:00 +0200953 writeConstructorTriplet(visit, node->getType(), "ivec4");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700954 break;
Geoff Langc4c7442d2015-07-20 13:09:26 -0400955 case EOpConstructUInt:
956 writeConstructorTriplet(visit, node->getType(), "uint");
957 break;
958 case EOpConstructUVec2:
959 writeConstructorTriplet(visit, node->getType(), "uvec2");
960 break;
961 case EOpConstructUVec3:
962 writeConstructorTriplet(visit, node->getType(), "uvec3");
963 break;
964 case EOpConstructUVec4:
965 writeConstructorTriplet(visit, node->getType(), "uvec4");
966 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700967 case EOpConstructMat2:
Olli Etuahof40319e2015-03-10 14:33:00 +0200968 writeConstructorTriplet(visit, node->getType(), "mat2");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700969 break;
Alexis Hetu07e57df2015-06-16 16:55:52 -0400970 case EOpConstructMat2x3:
971 writeConstructorTriplet(visit, node->getType(), "mat2x3");
972 break;
973 case EOpConstructMat2x4:
974 writeConstructorTriplet(visit, node->getType(), "mat2x4");
975 break;
976 case EOpConstructMat3x2:
977 writeConstructorTriplet(visit, node->getType(), "mat3x2");
978 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700979 case EOpConstructMat3:
Olli Etuahof40319e2015-03-10 14:33:00 +0200980 writeConstructorTriplet(visit, node->getType(), "mat3");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700981 break;
Alexis Hetu07e57df2015-06-16 16:55:52 -0400982 case EOpConstructMat3x4:
983 writeConstructorTriplet(visit, node->getType(), "mat3x4");
984 break;
985 case EOpConstructMat4x2:
986 writeConstructorTriplet(visit, node->getType(), "mat4x2");
987 break;
988 case EOpConstructMat4x3:
989 writeConstructorTriplet(visit, node->getType(), "mat4x3");
990 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700991 case EOpConstructMat4:
Olli Etuahof40319e2015-03-10 14:33:00 +0200992 writeConstructorTriplet(visit, node->getType(), "mat4");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700993 break;
994 case EOpConstructStruct:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700995 {
996 const TType &type = node->getType();
997 ASSERT(type.getBasicType() == EbtStruct);
Olli Etuahof40319e2015-03-10 14:33:00 +0200998 TString constructorName = hashName(type.getStruct()->name());
999 writeConstructorTriplet(visit, node->getType(), constructorName.c_str());
1000 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001001 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001002
Olli Etuahoe39706d2014-12-30 16:40:36 +02001003 case EOpOuterProduct:
1004 writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
1005 break;
1006
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001007 case EOpLessThan:
1008 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
1009 break;
1010 case EOpGreaterThan:
1011 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
1012 break;
1013 case EOpLessThanEqual:
1014 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
1015 break;
1016 case EOpGreaterThanEqual:
1017 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
1018 break;
1019 case EOpVectorEqual:
1020 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
1021 break;
1022 case EOpVectorNotEqual:
1023 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
1024 break;
1025 case EOpComma:
Zhenyao Mo0783efd2014-10-21 15:51:59 -07001026 writeTriplet(visit, "(", ", ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001027 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001028
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001029 case EOpMod:
1030 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
1031 break;
Olli Etuahob6e07a62015-02-16 12:22:10 +02001032 case EOpModf:
1033 writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
1034 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001035 case EOpPow:
1036 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
1037 break;
1038 case EOpAtan:
1039 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
1040 break;
1041 case EOpMin:
1042 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
1043 break;
1044 case EOpMax:
1045 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
1046 break;
1047 case EOpClamp:
1048 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
1049 break;
1050 case EOpMix:
1051 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
1052 break;
1053 case EOpStep:
1054 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
1055 break;
1056 case EOpSmoothStep:
1057 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
1058 break;
1059 case EOpDistance:
1060 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
1061 break;
1062 case EOpDot:
1063 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
1064 break;
1065 case EOpCross:
1066 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
1067 break;
1068 case EOpFaceForward:
1069 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
1070 break;
1071 case EOpReflect:
1072 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
1073 break;
1074 case EOpRefract:
1075 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
1076 break;
1077 case EOpMul:
1078 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
1079 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001080
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001081 default:
1082 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001083 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001084 return visitChildren;
1085}
1086
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001087bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001088{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001089 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001090
Zhenyao Mo7cab38b2013-10-15 12:59:30 -07001091 incrementDepth(node);
Corentin Wallez7258e302015-09-22 10:40:24 -07001092
zmo@google.com5601ea02011-06-10 18:23:25 +00001093 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001094
1095 // Only for loops can be unrolled
1096 ASSERT(!node->getUnrollFlag() || loopType == ELoopFor);
1097
zmo@google.com5601ea02011-06-10 18:23:25 +00001098 if (loopType == ELoopFor) // for loop
1099 {
Zhenyao Mo550c6002014-02-26 15:40:48 -08001100 if (!node->getUnrollFlag())
1101 {
zmo@google.com5601ea02011-06-10 18:23:25 +00001102 out << "for (";
1103 if (node->getInit())
1104 node->getInit()->traverse(this);
1105 out << "; ";
1106
1107 if (node->getCondition())
1108 node->getCondition()->traverse(this);
1109 out << "; ";
1110
1111 if (node->getExpression())
1112 node->getExpression()->traverse(this);
1113 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001114
1115 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001116 }
Zhenyao Mo550c6002014-02-26 15:40:48 -08001117 else
1118 {
1119 // Need to put a one-iteration loop here to handle break.
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001120 TIntermSequence *declSeq =
Zhenyao Mo550c6002014-02-26 15:40:48 -08001121 node->getInit()->getAsAggregate()->getSequence();
1122 TIntermSymbol *indexSymbol =
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001123 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -08001124 TString name = hashVariableName(indexSymbol->getSymbol());
1125 out << "for (int " << name << " = 0; "
1126 << name << " < 1; "
1127 << "++" << name << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001128
1129 out << "{\n";
1130 mLoopUnrollStack.push(node);
1131 while (mLoopUnrollStack.satisfiesLoopCondition())
1132 {
1133 visitCodeBlock(node->getBody());
1134 mLoopUnrollStack.step();
1135 }
1136 mLoopUnrollStack.pop();
1137 out << "}\n";
Zhenyao Mo550c6002014-02-26 15:40:48 -08001138 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001139 }
1140 else if (loopType == ELoopWhile) // while loop
1141 {
1142 out << "while (";
1143 ASSERT(node->getCondition() != NULL);
1144 node->getCondition()->traverse(this);
1145 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001146
1147 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001148 }
1149 else // do-while loop
1150 {
1151 ASSERT(loopType == ELoopDoWhile);
1152 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001153
zmo@google.com5601ea02011-06-10 18:23:25 +00001154 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001155
zmo@google.com5601ea02011-06-10 18:23:25 +00001156 out << "while (";
1157 ASSERT(node->getCondition() != NULL);
1158 node->getCondition()->traverse(this);
1159 out << ");\n";
1160 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001161
zmo@google.com5601ea02011-06-10 18:23:25 +00001162 decrementDepth();
1163
1164 // No need to visit children. They have been already processed in
1165 // this function.
1166 return false;
1167}
1168
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001169bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001170{
1171 switch (node->getFlowOp())
1172 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001173 case EOpKill:
1174 writeTriplet(visit, "discard", NULL, NULL);
1175 break;
1176 case EOpBreak:
1177 writeTriplet(visit, "break", NULL, NULL);
1178 break;
1179 case EOpContinue:
1180 writeTriplet(visit, "continue", NULL, NULL);
1181 break;
1182 case EOpReturn:
1183 writeTriplet(visit, "return ", NULL, NULL);
1184 break;
1185 default:
1186 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001187 }
1188
1189 return true;
1190}
1191
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001192void TOutputGLSLBase::visitCodeBlock(TIntermNode *node)
1193{
zmo@google.com5601ea02011-06-10 18:23:25 +00001194 TInfoSinkBase &out = objSink();
1195 if (node != NULL)
1196 {
1197 node->traverse(this);
1198 // Single statements not part of a sequence need to be terminated
1199 // with semi-colon.
1200 if (isSingleStatement(node))
1201 out << ";\n";
1202 }
1203 else
1204 {
1205 out << "{\n}\n"; // Empty code block.
1206 }
1207}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001208
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001209TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001210{
1211 TInfoSinkBase out;
1212 if (type.isMatrix())
1213 {
1214 out << "mat";
1215 out << type.getNominalSize();
Geoff Langd8edb512015-09-02 11:52:56 -04001216 if (type.getSecondarySize() != type.getNominalSize())
1217 {
1218 out << "x" << type.getSecondarySize();
1219 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001220 }
1221 else if (type.isVector())
1222 {
1223 switch (type.getBasicType())
1224 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001225 case EbtFloat:
1226 out << "vec";
1227 break;
1228 case EbtInt:
1229 out << "ivec";
1230 break;
1231 case EbtBool:
1232 out << "bvec";
1233 break;
Geoff Langc4c7442d2015-07-20 13:09:26 -04001234 case EbtUInt:
1235 out << "uvec";
1236 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001237 default:
1238 UNREACHABLE();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001239 }
1240 out << type.getNominalSize();
1241 }
1242 else
1243 {
1244 if (type.getBasicType() == EbtStruct)
Jamie Madill98493dd2013-07-08 14:39:03 -04001245 out << hashName(type.getStruct()->name());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001246 else
1247 out << type.getBasicString();
1248 }
1249 return TString(out.c_str());
1250}
1251
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001252TString TOutputGLSLBase::hashName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001253{
1254 if (mHashFunction == NULL || name.empty())
1255 return name;
1256 NameMap::const_iterator it = mNameMap.find(name.c_str());
1257 if (it != mNameMap.end())
1258 return it->second.c_str();
1259 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
1260 mNameMap[name.c_str()] = hashedName.c_str();
1261 return hashedName;
1262}
1263
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001264TString TOutputGLSLBase::hashVariableName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001265{
Jamie Madill02f20dd2013-09-12 12:07:42 -04001266 if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001267 return name;
1268 return hashName(name);
1269}
1270
Olli Etuaho59f9a642015-08-06 20:38:26 +03001271TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001272{
Olli Etuaho59f9a642015-08-06 20:38:26 +03001273 TString mangledStr = mangledName.getString();
1274 TString name = TFunction::unmangleName(mangledStr);
1275 if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001276 return translateTextureFunction(name);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001277 if (mangledName.isInternal())
1278 return name;
1279 else
1280 return hashName(name);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001281}
Jamie Madill98493dd2013-07-08 14:39:03 -04001282
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001283bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001284{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001285 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001286 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001287 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001288 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001289 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001290
1291 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001292}
1293
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001294void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001295{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001296 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001297
1298 out << "struct " << hashName(structure->name()) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001299 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001300 for (size_t i = 0; i < fields.size(); ++i)
1301 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001302 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001303 if (writeVariablePrecision(field->type()->getPrecision()))
1304 out << " ";
1305 out << getTypeName(*field->type()) << " " << hashName(field->name());
1306 if (field->type()->isArray())
1307 out << arrayBrackets(*field->type());
1308 out << ";\n";
1309 }
1310 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001311}
Jamie Madill98493dd2013-07-08 14:39:03 -04001312
Geoff Langbdcc54a2015-09-02 13:09:48 -04001313void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1314{
1315 TInfoSinkBase &out = objSink();
1316
1317 out << "layout(";
1318
1319 switch (interfaceBlock->blockStorage())
1320 {
1321 case EbsUnspecified:
1322 case EbsShared:
1323 // Default block storage is shared.
1324 out << "shared";
1325 break;
1326
1327 case EbsPacked:
1328 out << "packed";
1329 break;
1330
1331 case EbsStd140:
1332 out << "std140";
1333 break;
1334
1335 default:
1336 UNREACHABLE();
1337 break;
1338 }
1339
1340 out << ", ";
1341
1342 switch (interfaceBlock->matrixPacking())
1343 {
1344 case EmpUnspecified:
1345 case EmpColumnMajor:
1346 // Default matrix packing is column major.
1347 out << "column_major";
1348 break;
1349
1350 case EmpRowMajor:
1351 out << "row_major";
1352 break;
1353
1354 default:
1355 UNREACHABLE();
1356 break;
1357 }
1358
1359 out << ") ";
1360}
1361
1362void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1363{
1364 TInfoSinkBase &out = objSink();
1365
1366 out << hashName(interfaceBlock->name()) << "{\n";
1367 const TFieldList &fields = interfaceBlock->fields();
1368 for (size_t i = 0; i < fields.size(); ++i)
1369 {
1370 const TField *field = fields[i];
1371 if (writeVariablePrecision(field->type()->getPrecision()))
1372 out << " ";
1373 out << getTypeName(*field->type()) << " " << hashName(field->name());
1374 if (field->type()->isArray())
1375 out << arrayBrackets(*field->type());
1376 out << ";\n";
1377 }
1378 out << "}";
1379}