blob: 0924e9254b376ca3949d5903b473ea87fbe5b1c5 [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
92void TOutputGLSLBase::writeVariableType(const TType &type)
93{
94 TInfoSinkBase &out = objSink();
Olli Etuaho214c2d82015-04-27 14:49:13 +030095 if (type.isInvariant())
96 {
97 out << "invariant ";
98 }
Geoff Langbdcc54a2015-09-02 13:09:48 -040099 if (type.getBasicType() == EbtInterfaceBlock)
100 {
101 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
102 declareInterfaceBlockLayout(interfaceBlock);
103 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000104 TQualifier qualifier = type.getQualifier();
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400105 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400106 {
Qingqing Dengad0d0792015-04-08 14:25:06 -0700107 if (IsGLSL130OrNewer(mOutput))
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800108 {
109 switch (qualifier)
110 {
111 case EvqAttribute:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300112 out << "in ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800113 break;
114 case EvqVaryingIn:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300115 out << "in ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800116 break;
117 case EvqVaryingOut:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300118 out << "out ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800119 break;
120 default:
121 out << type.getQualifierString() << " ";
122 break;
123 }
124 }
125 else
126 {
127 out << type.getQualifierString() << " ";
128 }
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400129 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000130 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700131 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000132 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400133 TStructure *structure = type.getStruct();
134
135 declareStruct(structure);
136
137 if (!structure->name().empty())
138 {
139 mDeclaredStructs.insert(structure->uniqueId());
140 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000141 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400142 else if (type.getBasicType() == EbtInterfaceBlock)
143 {
144 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
145 declareInterfaceBlock(interfaceBlock);
146 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000147 else
148 {
149 if (writeVariablePrecision(type.getPrecision()))
150 out << " ";
151 out << getTypeName(type);
152 }
153}
154
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700155void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000156{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700157 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000158 for (TIntermSequence::const_iterator iter = args.begin();
159 iter != args.end(); ++iter)
160 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700161 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000162 ASSERT(arg != NULL);
163
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700164 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000165 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000166
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700167 const TString &name = arg->getSymbol();
zmo@google.com5601ea02011-06-10 18:23:25 +0000168 if (!name.empty())
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000169 out << " " << hashName(name);
zmo@google.com5601ea02011-06-10 18:23:25 +0000170 if (type.isArray())
171 out << arrayBrackets(type);
172
173 // Put a comma if this is not the last argument.
174 if (iter != args.end() - 1)
175 out << ", ";
176 }
177}
178
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400179const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
180 const TType &type, const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000181{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700182 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000183
184 if (type.getBasicType() == EbtStruct)
185 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700186 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -0400187 out << hashName(structure->name()) << "(";
188
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700189 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400190 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000191 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700192 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000193 ASSERT(fieldType != NULL);
194 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700195 if (i != fields.size() - 1)
196 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000197 }
198 out << ")";
199 }
200 else
201 {
Jamie Madill94bf7f22013-07-08 13:31:15 -0400202 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000203 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700204 if (writeType)
205 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400206 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000207 {
208 switch (pConstUnion->getType())
209 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700210 case EbtFloat:
211 out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
212 break;
213 case EbtInt:
214 out << pConstUnion->getIConst();
215 break;
Olli Etuaho5321c802015-04-02 17:08:16 +0300216 case EbtUInt:
217 out << pConstUnion->getUConst() << "u";
218 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700219 case EbtBool:
220 out << pConstUnion->getBConst();
221 break;
222 default: UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000223 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700224 if (i != size - 1)
225 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000226 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700227 if (writeType)
228 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000229 }
230 return pConstUnion;
231}
232
Olli Etuahof40319e2015-03-10 14:33:00 +0200233void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type, const char *constructorBaseType)
234{
235 TInfoSinkBase &out = objSink();
236 if (visit == PreVisit)
237 {
238 if (type.isArray())
239 {
240 out << constructorBaseType;
241 out << arrayBrackets(type);
242 out << "(";
243 }
244 else
245 {
246 out << constructorBaseType << "(";
247 }
248 }
249 else
250 {
251 writeTriplet(visit, nullptr, ", ", ")");
252 }
253}
254
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700255void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000256{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700257 TInfoSinkBase &out = objSink();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800258 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
259 out << mLoopUnrollStack.getLoopIndexValue(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000260 else
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000261 out << hashVariableName(node->getSymbol());
zmo@google.com5601ea02011-06-10 18:23:25 +0000262
263 if (mDeclaringVariables && node->getType().isArray())
264 out << arrayBrackets(node->getType());
265}
266
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700267void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000268{
269 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
270}
271
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700272bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000273{
274 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700275 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000276 switch (node->getOp())
277 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700278 case EOpInitialize:
279 if (visit == InVisit)
280 {
281 out << " = ";
282 // RHS of initialize is not being declared.
283 mDeclaringVariables = false;
284 }
285 break;
286 case EOpAssign:
287 writeTriplet(visit, "(", " = ", ")");
288 break;
289 case EOpAddAssign:
290 writeTriplet(visit, "(", " += ", ")");
291 break;
292 case EOpSubAssign:
293 writeTriplet(visit, "(", " -= ", ")");
294 break;
295 case EOpDivAssign:
296 writeTriplet(visit, "(", " /= ", ")");
297 break;
Olli Etuahoff805cc2015-02-13 10:59:34 +0200298 case EOpIModAssign:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000299 writeTriplet(visit, "(", " %= ", ")");
300 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700301 // Notice the fall-through.
302 case EOpMulAssign:
303 case EOpVectorTimesMatrixAssign:
304 case EOpVectorTimesScalarAssign:
305 case EOpMatrixTimesScalarAssign:
306 case EOpMatrixTimesMatrixAssign:
307 writeTriplet(visit, "(", " *= ", ")");
308 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200309 case EOpBitShiftLeftAssign:
310 writeTriplet(visit, "(", " <<= ", ")");
311 break;
312 case EOpBitShiftRightAssign:
313 writeTriplet(visit, "(", " >>= ", ")");
314 break;
315 case EOpBitwiseAndAssign:
316 writeTriplet(visit, "(", " &= ", ")");
317 break;
318 case EOpBitwiseXorAssign:
319 writeTriplet(visit, "(", " ^= ", ")");
320 break;
321 case EOpBitwiseOrAssign:
322 writeTriplet(visit, "(", " |= ", ")");
323 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700324
325 case EOpIndexDirect:
326 writeTriplet(visit, NULL, "[", "]");
327 break;
328 case EOpIndexIndirect:
329 if (node->getAddIndexClamp())
330 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000331 if (visit == InVisit)
332 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700333 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
334 out << "[int(clamp(float(";
335 else
336 out << "[webgl_int_clamp(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000337 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700338 else if (visit == PostVisit)
339 {
340 int maxSize;
341 TIntermTyped *left = node->getLeft();
342 TType leftType = left->getType();
zmo@google.com5601ea02011-06-10 18:23:25 +0000343
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700344 if (left->isArray())
345 {
346 // The shader will fail validation if the array length is not > 0.
347 maxSize = leftType.getArraySize() - 1;
348 }
349 else
350 {
351 maxSize = leftType.getNominalSize() - 1;
352 }
353
354 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
355 out << "), 0.0, float(" << maxSize << ")))]";
356 else
357 out << ", 0, " << maxSize << ")]";
358 }
359 }
360 else
361 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000362 writeTriplet(visit, NULL, "[", "]");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700363 }
364 break;
365 case EOpIndexDirectStruct:
366 if (visit == InVisit)
367 {
368 // Here we are writing out "foo.bar", where "foo" is struct
369 // and "bar" is field. In AST, it is represented as a binary
370 // node, where left child represents "foo" and right child "bar".
371 // The node itself represents ".". The struct field "bar" is
372 // actually stored as an index into TStructure::fields.
373 out << ".";
374 const TStructure *structure = node->getLeft()->getType().getStruct();
375 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
376 const TField *field = structure->fields()[index->getIConst(0)];
377
378 TString fieldName = field->name();
379 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
380 fieldName = hashName(fieldName);
381
382 out << fieldName;
383 visitChildren = false;
384 }
385 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400386 case EOpIndexDirectInterfaceBlock:
387 if (visit == InVisit)
388 {
389 out << ".";
390 const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
391 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
392 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
393
394 TString fieldName = field->name();
395 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
396 fieldName = hashName(fieldName);
397
398 out << fieldName;
399 visitChildren = false;
400 }
401 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700402 case EOpVectorSwizzle:
403 if (visit == InVisit)
404 {
405 out << ".";
406 TIntermAggregate *rightChild = node->getRight()->getAsAggregate();
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700407 TIntermSequence *sequence = rightChild->getSequence();
408 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); ++sit)
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000409 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700410 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
411 ASSERT(element->getBasicType() == EbtInt);
412 ASSERT(element->getNominalSize() == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400413 const TConstantUnion& data = element->getUnionArrayPointer()[0];
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700414 ASSERT(data.getType() == EbtInt);
415 switch (data.getIConst())
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000416 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700417 case 0:
418 out << "x";
419 break;
420 case 1:
421 out << "y";
422 break;
423 case 2:
424 out << "z";
425 break;
426 case 3:
427 out << "w";
428 break;
429 default:
430 UNREACHABLE();
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000431 }
432 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700433 visitChildren = false;
434 }
435 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000436
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700437 case EOpAdd:
438 writeTriplet(visit, "(", " + ", ")");
439 break;
440 case EOpSub:
441 writeTriplet(visit, "(", " - ", ")");
442 break;
443 case EOpMul:
444 writeTriplet(visit, "(", " * ", ")");
445 break;
446 case EOpDiv:
447 writeTriplet(visit, "(", " / ", ")");
448 break;
Olli Etuahoff805cc2015-02-13 10:59:34 +0200449 case EOpIMod:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000450 writeTriplet(visit, "(", " % ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700451 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200452 case EOpBitShiftLeft:
453 writeTriplet(visit, "(", " << ", ")");
454 break;
455 case EOpBitShiftRight:
456 writeTriplet(visit, "(", " >> ", ")");
457 break;
458 case EOpBitwiseAnd:
459 writeTriplet(visit, "(", " & ", ")");
460 break;
461 case EOpBitwiseXor:
462 writeTriplet(visit, "(", " ^ ", ")");
463 break;
464 case EOpBitwiseOr:
465 writeTriplet(visit, "(", " | ", ")");
466 break;
467
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700468 case EOpEqual:
469 writeTriplet(visit, "(", " == ", ")");
470 break;
471 case EOpNotEqual:
472 writeTriplet(visit, "(", " != ", ")");
473 break;
474 case EOpLessThan:
475 writeTriplet(visit, "(", " < ", ")");
476 break;
477 case EOpGreaterThan:
478 writeTriplet(visit, "(", " > ", ")");
479 break;
480 case EOpLessThanEqual:
481 writeTriplet(visit, "(", " <= ", ")");
482 break;
483 case EOpGreaterThanEqual:
484 writeTriplet(visit, "(", " >= ", ")");
485 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000486
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700487 // Notice the fall-through.
488 case EOpVectorTimesScalar:
489 case EOpVectorTimesMatrix:
490 case EOpMatrixTimesVector:
491 case EOpMatrixTimesScalar:
492 case EOpMatrixTimesMatrix:
493 writeTriplet(visit, "(", " * ", ")");
494 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000495
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700496 case EOpLogicalOr:
497 writeTriplet(visit, "(", " || ", ")");
498 break;
499 case EOpLogicalXor:
500 writeTriplet(visit, "(", " ^^ ", ")");
501 break;
502 case EOpLogicalAnd:
503 writeTriplet(visit, "(", " && ", ")");
504 break;
505 default:
506 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000507 }
508
509 return visitChildren;
510}
511
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700512bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000513{
zmo@google.com32e97312011-08-24 01:03:11 +0000514 TString preString;
515 TString postString = ")";
516
zmo@google.com5601ea02011-06-10 18:23:25 +0000517 switch (node->getOp())
518 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700519 case EOpNegative: preString = "(-"; break;
Zhenyao Mode1e00e2014-10-09 16:55:32 -0700520 case EOpPositive: preString = "(+"; break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700521 case EOpVectorLogicalNot: preString = "not("; break;
522 case EOpLogicalNot: preString = "(!"; break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200523 case EOpBitwiseNot: preString = "(~"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000524
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700525 case EOpPostIncrement: preString = "("; postString = "++)"; break;
526 case EOpPostDecrement: preString = "("; postString = "--)"; break;
527 case EOpPreIncrement: preString = "(++"; break;
528 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000529
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700530 case EOpRadians:
531 preString = "radians(";
532 break;
533 case EOpDegrees:
534 preString = "degrees(";
535 break;
536 case EOpSin:
537 preString = "sin(";
538 break;
539 case EOpCos:
540 preString = "cos(";
541 break;
542 case EOpTan:
543 preString = "tan(";
544 break;
545 case EOpAsin:
546 preString = "asin(";
547 break;
548 case EOpAcos:
549 preString = "acos(";
550 break;
551 case EOpAtan:
552 preString = "atan(";
553 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000554
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200555 case EOpSinh:
556 preString = "sinh(";
557 break;
558 case EOpCosh:
559 preString = "cosh(";
560 break;
561 case EOpTanh:
562 preString = "tanh(";
563 break;
564 case EOpAsinh:
565 preString = "asinh(";
566 break;
567 case EOpAcosh:
568 preString = "acosh(";
569 break;
570 case EOpAtanh:
571 preString = "atanh(";
572 break;
573
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700574 case EOpExp:
575 preString = "exp(";
576 break;
577 case EOpLog:
578 preString = "log(";
579 break;
580 case EOpExp2:
581 preString = "exp2(";
582 break;
583 case EOpLog2:
584 preString = "log2(";
585 break;
586 case EOpSqrt:
587 preString = "sqrt(";
588 break;
589 case EOpInverseSqrt:
590 preString = "inversesqrt(";
591 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000592
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700593 case EOpAbs:
594 preString = "abs(";
595 break;
596 case EOpSign:
597 preString = "sign(";
598 break;
599 case EOpFloor:
600 preString = "floor(";
601 break;
Qingqing Deng5dbece52015-02-27 20:35:38 -0800602 case EOpTrunc:
603 preString = "trunc(";
604 break;
605 case EOpRound:
606 preString = "round(";
607 break;
608 case EOpRoundEven:
609 preString = "roundEven(";
610 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700611 case EOpCeil:
612 preString = "ceil(";
613 break;
614 case EOpFract:
615 preString = "fract(";
616 break;
Arun Patole0c1726e2015-02-18 14:35:02 +0530617 case EOpIsNan:
618 preString = "isnan(";
619 break;
620 case EOpIsInf:
621 preString = "isinf(";
622 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000623
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200624 case EOpFloatBitsToInt:
625 preString = "floatBitsToInt(";
626 break;
627 case EOpFloatBitsToUint:
628 preString = "floatBitsToUint(";
629 break;
630 case EOpIntBitsToFloat:
631 preString = "intBitsToFloat(";
632 break;
633 case EOpUintBitsToFloat:
634 preString = "uintBitsToFloat(";
635 break;
636
Olli Etuaho7700ff62015-01-15 12:16:29 +0200637 case EOpPackSnorm2x16:
638 preString = "packSnorm2x16(";
639 break;
640 case EOpPackUnorm2x16:
641 preString = "packUnorm2x16(";
642 break;
643 case EOpPackHalf2x16:
644 preString = "packHalf2x16(";
645 break;
646 case EOpUnpackSnorm2x16:
647 preString = "unpackSnorm2x16(";
648 break;
649 case EOpUnpackUnorm2x16:
650 preString = "unpackUnorm2x16(";
651 break;
652 case EOpUnpackHalf2x16:
653 preString = "unpackHalf2x16(";
654 break;
655
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700656 case EOpLength:
657 preString = "length(";
658 break;
659 case EOpNormalize:
660 preString = "normalize(";
661 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000662
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700663 case EOpDFdx:
664 preString = "dFdx(";
665 break;
666 case EOpDFdy:
667 preString = "dFdy(";
668 break;
669 case EOpFwidth:
670 preString = "fwidth(";
671 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000672
Olli Etuahoe39706d2014-12-30 16:40:36 +0200673 case EOpTranspose:
674 preString = "transpose(";
675 break;
676 case EOpDeterminant:
677 preString = "determinant(";
678 break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +0200679 case EOpInverse:
680 preString = "inverse(";
681 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200682
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700683 case EOpAny:
684 preString = "any(";
685 break;
686 case EOpAll:
687 preString = "all(";
688 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000689
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700690 default:
691 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000692 }
693
zmo@google.com32e97312011-08-24 01:03:11 +0000694 if (visit == PreVisit && node->getUseEmulatedFunction())
695 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
696 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
697
zmo@google.com5601ea02011-06-10 18:23:25 +0000698 return true;
699}
700
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700701bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000702{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700703 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000704
705 if (node->usesTernaryOperator())
706 {
707 // Notice two brackets at the beginning and end. The outer ones
708 // encapsulate the whole ternary expression. This preserves the
709 // order of precedence when ternary expressions are used in a
710 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
711 out << "((";
712 node->getCondition()->traverse(this);
713 out << ") ? (";
714 node->getTrueBlock()->traverse(this);
715 out << ") : (";
716 node->getFalseBlock()->traverse(this);
717 out << "))";
718 }
719 else
720 {
721 out << "if (";
722 node->getCondition()->traverse(this);
723 out << ")\n";
724
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700725 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000726 visitCodeBlock(node->getTrueBlock());
727
728 if (node->getFalseBlock())
729 {
730 out << "else\n";
731 visitCodeBlock(node->getFalseBlock());
732 }
733 decrementDepth();
734 }
735 return false;
736}
737
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200738bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200739{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200740 if (node->getStatementList())
741 {
742 writeTriplet(visit, "switch (", ") ", nullptr);
743 // The curly braces get written when visiting the statementList aggregate
744 }
745 else
746 {
747 // No statementList, so it won't output curly braces
748 writeTriplet(visit, "switch (", ") {", "}\n");
749 }
750 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200751}
752
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200753bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200754{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200755 if (node->hasCondition())
756 {
757 writeTriplet(visit, "case (", nullptr, "):\n");
758 return true;
759 }
760 else
761 {
762 TInfoSinkBase &out = objSink();
763 out << "default:\n";
764 return false;
765 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200766}
767
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700768bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000769{
770 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700771 TInfoSinkBase &out = objSink();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700772 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000773 switch (node->getOp())
774 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700775 case EOpSequence:
776 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700777 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700778 {
779 out << "{\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000780 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000781
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700782 incrementDepth(node);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700783 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
784 iter != node->getSequence()->end(); ++iter)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700785 {
Austin Kinross3ae64652015-01-26 15:51:39 -0800786 TIntermNode *curNode = *iter;
787 ASSERT(curNode != NULL);
788 curNode->traverse(this);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700789
Austin Kinross3ae64652015-01-26 15:51:39 -0800790 if (isSingleStatement(curNode))
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700791 out << ";\n";
792 }
793 decrementDepth();
794
795 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700796 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700797 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700798 out << "}\n";
799 }
800 visitChildren = false;
801 break;
802 case EOpPrototype:
803 // Function declaration.
804 ASSERT(visit == PreVisit);
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300805 {
806 const TType &type = node->getType();
807 writeVariableType(type);
808 if (type.isArray())
809 out << arrayBrackets(type);
810 }
811
Olli Etuaho59f9a642015-08-06 20:38:26 +0300812 out << " " << hashFunctionNameIfNeeded(node->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700813
814 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700815 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700816 out << ")";
817
818 visitChildren = false;
819 break;
820 case EOpFunction: {
821 // Function definition.
822 ASSERT(visit == PreVisit);
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300823 {
824 const TType &type = node->getType();
825 writeVariableType(type);
826 if (type.isArray())
827 out << arrayBrackets(type);
828 }
829
Olli Etuaho59f9a642015-08-06 20:38:26 +0300830 out << " " << hashFunctionNameIfNeeded(node->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700831
832 incrementDepth(node);
833 // Function definition node contains one or two children nodes
834 // representing function parameters and function body. The latter
835 // is not present in case of empty function bodies.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700836 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700837 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
838 TIntermSequence::const_iterator seqIter = sequence.begin();
839
840 // Traverse function parameters.
841 TIntermAggregate *params = (*seqIter)->getAsAggregate();
842 ASSERT(params != NULL);
843 ASSERT(params->getOp() == EOpParameters);
844 params->traverse(this);
845
846 // Traverse function body.
847 TIntermAggregate *body = ++seqIter != sequence.end() ?
848 (*seqIter)->getAsAggregate() : NULL;
849 visitCodeBlock(body);
850 decrementDepth();
851
852 // Fully processed; no need to visit children.
853 visitChildren = false;
854 break;
855 }
856 case EOpFunctionCall:
857 // Function call.
858 if (visit == PreVisit)
Olli Etuaho59f9a642015-08-06 20:38:26 +0300859 out << hashFunctionNameIfNeeded(node->getNameObj()) << "(";
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200860 else if (visit == InVisit)
861 out << ", ";
862 else
863 out << ")";
864 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700865 case EOpParameters:
866 // Function parameters.
867 ASSERT(visit == PreVisit);
868 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700869 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700870 out << ")";
871 visitChildren = false;
872 break;
873 case EOpDeclaration:
874 // Variable declaration.
875 if (visit == PreVisit)
876 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700877 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700878 const TIntermTyped *variable = sequence.front()->getAsTyped();
879 writeVariableType(variable->getType());
880 out << " ";
881 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000882 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700883 else if (visit == InVisit)
884 {
885 out << ", ";
886 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000887 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700888 else
889 {
890 mDeclaringVariables = false;
891 }
892 break;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700893 case EOpInvariantDeclaration:
894 // Invariant declaration.
895 ASSERT(visit == PreVisit);
896 {
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400897 const TIntermSequence *sequence = node->getSequence();
898 ASSERT(sequence && sequence->size() == 1);
899 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
900 ASSERT(symbol);
Zhenyao Mo2a517272014-10-27 16:09:57 -0700901 out << "invariant " << hashVariableName(symbol->getSymbol());
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400902 }
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700903 visitChildren = false;
904 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700905 case EOpConstructFloat:
Olli Etuahof40319e2015-03-10 14:33:00 +0200906 writeConstructorTriplet(visit, node->getType(), "float");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700907 break;
908 case EOpConstructVec2:
Olli Etuahof40319e2015-03-10 14:33:00 +0200909 writeConstructorTriplet(visit, node->getType(), "vec2");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700910 break;
911 case EOpConstructVec3:
Olli Etuahof40319e2015-03-10 14:33:00 +0200912 writeConstructorTriplet(visit, node->getType(), "vec3");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700913 break;
914 case EOpConstructVec4:
Olli Etuahof40319e2015-03-10 14:33:00 +0200915 writeConstructorTriplet(visit, node->getType(), "vec4");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700916 break;
917 case EOpConstructBool:
Olli Etuahof40319e2015-03-10 14:33:00 +0200918 writeConstructorTriplet(visit, node->getType(), "bool");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700919 break;
920 case EOpConstructBVec2:
Olli Etuahof40319e2015-03-10 14:33:00 +0200921 writeConstructorTriplet(visit, node->getType(), "bvec2");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700922 break;
923 case EOpConstructBVec3:
Olli Etuahof40319e2015-03-10 14:33:00 +0200924 writeConstructorTriplet(visit, node->getType(), "bvec3");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700925 break;
926 case EOpConstructBVec4:
Olli Etuahof40319e2015-03-10 14:33:00 +0200927 writeConstructorTriplet(visit, node->getType(), "bvec4");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700928 break;
929 case EOpConstructInt:
Olli Etuahof40319e2015-03-10 14:33:00 +0200930 writeConstructorTriplet(visit, node->getType(), "int");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700931 break;
932 case EOpConstructIVec2:
Olli Etuahof40319e2015-03-10 14:33:00 +0200933 writeConstructorTriplet(visit, node->getType(), "ivec2");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700934 break;
935 case EOpConstructIVec3:
Olli Etuahof40319e2015-03-10 14:33:00 +0200936 writeConstructorTriplet(visit, node->getType(), "ivec3");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700937 break;
938 case EOpConstructIVec4:
Olli Etuahof40319e2015-03-10 14:33:00 +0200939 writeConstructorTriplet(visit, node->getType(), "ivec4");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700940 break;
Geoff Langc4c7442d2015-07-20 13:09:26 -0400941 case EOpConstructUInt:
942 writeConstructorTriplet(visit, node->getType(), "uint");
943 break;
944 case EOpConstructUVec2:
945 writeConstructorTriplet(visit, node->getType(), "uvec2");
946 break;
947 case EOpConstructUVec3:
948 writeConstructorTriplet(visit, node->getType(), "uvec3");
949 break;
950 case EOpConstructUVec4:
951 writeConstructorTriplet(visit, node->getType(), "uvec4");
952 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700953 case EOpConstructMat2:
Olli Etuahof40319e2015-03-10 14:33:00 +0200954 writeConstructorTriplet(visit, node->getType(), "mat2");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700955 break;
Alexis Hetu07e57df2015-06-16 16:55:52 -0400956 case EOpConstructMat2x3:
957 writeConstructorTriplet(visit, node->getType(), "mat2x3");
958 break;
959 case EOpConstructMat2x4:
960 writeConstructorTriplet(visit, node->getType(), "mat2x4");
961 break;
962 case EOpConstructMat3x2:
963 writeConstructorTriplet(visit, node->getType(), "mat3x2");
964 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700965 case EOpConstructMat3:
Olli Etuahof40319e2015-03-10 14:33:00 +0200966 writeConstructorTriplet(visit, node->getType(), "mat3");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700967 break;
Alexis Hetu07e57df2015-06-16 16:55:52 -0400968 case EOpConstructMat3x4:
969 writeConstructorTriplet(visit, node->getType(), "mat3x4");
970 break;
971 case EOpConstructMat4x2:
972 writeConstructorTriplet(visit, node->getType(), "mat4x2");
973 break;
974 case EOpConstructMat4x3:
975 writeConstructorTriplet(visit, node->getType(), "mat4x3");
976 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700977 case EOpConstructMat4:
Olli Etuahof40319e2015-03-10 14:33:00 +0200978 writeConstructorTriplet(visit, node->getType(), "mat4");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700979 break;
980 case EOpConstructStruct:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700981 {
982 const TType &type = node->getType();
983 ASSERT(type.getBasicType() == EbtStruct);
Olli Etuahof40319e2015-03-10 14:33:00 +0200984 TString constructorName = hashName(type.getStruct()->name());
985 writeConstructorTriplet(visit, node->getType(), constructorName.c_str());
986 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700987 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000988
Olli Etuahoe39706d2014-12-30 16:40:36 +0200989 case EOpOuterProduct:
990 writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
991 break;
992
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700993 case EOpLessThan:
994 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
995 break;
996 case EOpGreaterThan:
997 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
998 break;
999 case EOpLessThanEqual:
1000 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
1001 break;
1002 case EOpGreaterThanEqual:
1003 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
1004 break;
1005 case EOpVectorEqual:
1006 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
1007 break;
1008 case EOpVectorNotEqual:
1009 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
1010 break;
1011 case EOpComma:
Zhenyao Mo0783efd2014-10-21 15:51:59 -07001012 writeTriplet(visit, "(", ", ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001013 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001014
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001015 case EOpMod:
1016 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
1017 break;
Olli Etuahob6e07a62015-02-16 12:22:10 +02001018 case EOpModf:
1019 writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
1020 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001021 case EOpPow:
1022 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
1023 break;
1024 case EOpAtan:
1025 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
1026 break;
1027 case EOpMin:
1028 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
1029 break;
1030 case EOpMax:
1031 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
1032 break;
1033 case EOpClamp:
1034 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
1035 break;
1036 case EOpMix:
1037 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
1038 break;
1039 case EOpStep:
1040 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
1041 break;
1042 case EOpSmoothStep:
1043 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
1044 break;
1045 case EOpDistance:
1046 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
1047 break;
1048 case EOpDot:
1049 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
1050 break;
1051 case EOpCross:
1052 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
1053 break;
1054 case EOpFaceForward:
1055 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
1056 break;
1057 case EOpReflect:
1058 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
1059 break;
1060 case EOpRefract:
1061 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
1062 break;
1063 case EOpMul:
1064 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
1065 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001066
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001067 default:
1068 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001069 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001070 return visitChildren;
1071}
1072
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001073bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001074{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001075 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001076
Zhenyao Mo7cab38b2013-10-15 12:59:30 -07001077 incrementDepth(node);
Corentin Wallez7258e302015-09-22 10:40:24 -07001078
zmo@google.com5601ea02011-06-10 18:23:25 +00001079 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001080
1081 // Only for loops can be unrolled
1082 ASSERT(!node->getUnrollFlag() || loopType == ELoopFor);
1083
zmo@google.com5601ea02011-06-10 18:23:25 +00001084 if (loopType == ELoopFor) // for loop
1085 {
Zhenyao Mo550c6002014-02-26 15:40:48 -08001086 if (!node->getUnrollFlag())
1087 {
zmo@google.com5601ea02011-06-10 18:23:25 +00001088 out << "for (";
1089 if (node->getInit())
1090 node->getInit()->traverse(this);
1091 out << "; ";
1092
1093 if (node->getCondition())
1094 node->getCondition()->traverse(this);
1095 out << "; ";
1096
1097 if (node->getExpression())
1098 node->getExpression()->traverse(this);
1099 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001100
1101 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001102 }
Zhenyao Mo550c6002014-02-26 15:40:48 -08001103 else
1104 {
1105 // Need to put a one-iteration loop here to handle break.
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001106 TIntermSequence *declSeq =
Zhenyao Mo550c6002014-02-26 15:40:48 -08001107 node->getInit()->getAsAggregate()->getSequence();
1108 TIntermSymbol *indexSymbol =
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001109 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -08001110 TString name = hashVariableName(indexSymbol->getSymbol());
1111 out << "for (int " << name << " = 0; "
1112 << name << " < 1; "
1113 << "++" << name << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001114
1115 out << "{\n";
1116 mLoopUnrollStack.push(node);
1117 while (mLoopUnrollStack.satisfiesLoopCondition())
1118 {
1119 visitCodeBlock(node->getBody());
1120 mLoopUnrollStack.step();
1121 }
1122 mLoopUnrollStack.pop();
1123 out << "}\n";
Zhenyao Mo550c6002014-02-26 15:40:48 -08001124 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001125 }
1126 else if (loopType == ELoopWhile) // while loop
1127 {
1128 out << "while (";
1129 ASSERT(node->getCondition() != NULL);
1130 node->getCondition()->traverse(this);
1131 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001132
1133 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001134 }
1135 else // do-while loop
1136 {
1137 ASSERT(loopType == ELoopDoWhile);
1138 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001139
zmo@google.com5601ea02011-06-10 18:23:25 +00001140 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001141
zmo@google.com5601ea02011-06-10 18:23:25 +00001142 out << "while (";
1143 ASSERT(node->getCondition() != NULL);
1144 node->getCondition()->traverse(this);
1145 out << ");\n";
1146 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001147
zmo@google.com5601ea02011-06-10 18:23:25 +00001148 decrementDepth();
1149
1150 // No need to visit children. They have been already processed in
1151 // this function.
1152 return false;
1153}
1154
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001155bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001156{
1157 switch (node->getFlowOp())
1158 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001159 case EOpKill:
1160 writeTriplet(visit, "discard", NULL, NULL);
1161 break;
1162 case EOpBreak:
1163 writeTriplet(visit, "break", NULL, NULL);
1164 break;
1165 case EOpContinue:
1166 writeTriplet(visit, "continue", NULL, NULL);
1167 break;
1168 case EOpReturn:
1169 writeTriplet(visit, "return ", NULL, NULL);
1170 break;
1171 default:
1172 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001173 }
1174
1175 return true;
1176}
1177
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001178void TOutputGLSLBase::visitCodeBlock(TIntermNode *node)
1179{
zmo@google.com5601ea02011-06-10 18:23:25 +00001180 TInfoSinkBase &out = objSink();
1181 if (node != NULL)
1182 {
1183 node->traverse(this);
1184 // Single statements not part of a sequence need to be terminated
1185 // with semi-colon.
1186 if (isSingleStatement(node))
1187 out << ";\n";
1188 }
1189 else
1190 {
1191 out << "{\n}\n"; // Empty code block.
1192 }
1193}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001194
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001195TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001196{
1197 TInfoSinkBase out;
1198 if (type.isMatrix())
1199 {
1200 out << "mat";
1201 out << type.getNominalSize();
Geoff Langd8edb512015-09-02 11:52:56 -04001202 if (type.getSecondarySize() != type.getNominalSize())
1203 {
1204 out << "x" << type.getSecondarySize();
1205 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001206 }
1207 else if (type.isVector())
1208 {
1209 switch (type.getBasicType())
1210 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001211 case EbtFloat:
1212 out << "vec";
1213 break;
1214 case EbtInt:
1215 out << "ivec";
1216 break;
1217 case EbtBool:
1218 out << "bvec";
1219 break;
Geoff Langc4c7442d2015-07-20 13:09:26 -04001220 case EbtUInt:
1221 out << "uvec";
1222 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001223 default:
1224 UNREACHABLE();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001225 }
1226 out << type.getNominalSize();
1227 }
1228 else
1229 {
1230 if (type.getBasicType() == EbtStruct)
Jamie Madill98493dd2013-07-08 14:39:03 -04001231 out << hashName(type.getStruct()->name());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001232 else
1233 out << type.getBasicString();
1234 }
1235 return TString(out.c_str());
1236}
1237
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001238TString TOutputGLSLBase::hashName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001239{
1240 if (mHashFunction == NULL || name.empty())
1241 return name;
1242 NameMap::const_iterator it = mNameMap.find(name.c_str());
1243 if (it != mNameMap.end())
1244 return it->second.c_str();
1245 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
1246 mNameMap[name.c_str()] = hashedName.c_str();
1247 return hashedName;
1248}
1249
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001250TString TOutputGLSLBase::hashVariableName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001251{
Jamie Madill02f20dd2013-09-12 12:07:42 -04001252 if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001253 return name;
1254 return hashName(name);
1255}
1256
Olli Etuaho59f9a642015-08-06 20:38:26 +03001257TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001258{
Olli Etuaho59f9a642015-08-06 20:38:26 +03001259 TString mangledStr = mangledName.getString();
1260 TString name = TFunction::unmangleName(mangledStr);
1261 if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001262 return translateTextureFunction(name);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001263 if (mangledName.isInternal())
1264 return name;
1265 else
1266 return hashName(name);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001267}
Jamie Madill98493dd2013-07-08 14:39:03 -04001268
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001269bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001270{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001271 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001272 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001273 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001274 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001275 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001276
1277 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001278}
1279
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001280void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001281{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001282 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001283
1284 out << "struct " << hashName(structure->name()) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001285 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001286 for (size_t i = 0; i < fields.size(); ++i)
1287 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001288 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001289 if (writeVariablePrecision(field->type()->getPrecision()))
1290 out << " ";
1291 out << getTypeName(*field->type()) << " " << hashName(field->name());
1292 if (field->type()->isArray())
1293 out << arrayBrackets(*field->type());
1294 out << ";\n";
1295 }
1296 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001297}
Jamie Madill98493dd2013-07-08 14:39:03 -04001298
Geoff Langbdcc54a2015-09-02 13:09:48 -04001299void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1300{
1301 TInfoSinkBase &out = objSink();
1302
1303 out << "layout(";
1304
1305 switch (interfaceBlock->blockStorage())
1306 {
1307 case EbsUnspecified:
1308 case EbsShared:
1309 // Default block storage is shared.
1310 out << "shared";
1311 break;
1312
1313 case EbsPacked:
1314 out << "packed";
1315 break;
1316
1317 case EbsStd140:
1318 out << "std140";
1319 break;
1320
1321 default:
1322 UNREACHABLE();
1323 break;
1324 }
1325
1326 out << ", ";
1327
1328 switch (interfaceBlock->matrixPacking())
1329 {
1330 case EmpUnspecified:
1331 case EmpColumnMajor:
1332 // Default matrix packing is column major.
1333 out << "column_major";
1334 break;
1335
1336 case EmpRowMajor:
1337 out << "row_major";
1338 break;
1339
1340 default:
1341 UNREACHABLE();
1342 break;
1343 }
1344
1345 out << ") ";
1346}
1347
1348void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1349{
1350 TInfoSinkBase &out = objSink();
1351
1352 out << hashName(interfaceBlock->name()) << "{\n";
1353 const TFieldList &fields = interfaceBlock->fields();
1354 for (size_t i = 0; i < fields.size(); ++i)
1355 {
1356 const TField *field = fields[i];
1357 if (writeVariablePrecision(field->type()->getPrecision()))
1358 out << " ";
1359 out << getTypeName(*field->type()) << " " << hashName(field->name());
1360 if (field->type()->isArray())
1361 out << arrayBrackets(*field->type());
1362 out << ";\n";
1363 }
1364 out << "}";
1365}