blob: 63b28133c76516505549067eca83daf0601d63b1 [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 }
zmo@google.com5601ea02011-06-10 18:23:25 +000099 TQualifier qualifier = type.getQualifier();
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400100 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400101 {
Qingqing Dengad0d0792015-04-08 14:25:06 -0700102 if (IsGLSL130OrNewer(mOutput))
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800103 {
104 switch (qualifier)
105 {
106 case EvqAttribute:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300107 out << "in ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800108 break;
109 case EvqVaryingIn:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300110 out << "in ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800111 break;
112 case EvqVaryingOut:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300113 out << "out ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800114 break;
115 default:
116 out << type.getQualifierString() << " ";
117 break;
118 }
119 }
120 else
121 {
122 out << type.getQualifierString() << " ";
123 }
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400124 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000125 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700126 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000127 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400128 TStructure *structure = type.getStruct();
129
130 declareStruct(structure);
131
132 if (!structure->name().empty())
133 {
134 mDeclaredStructs.insert(structure->uniqueId());
135 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000136 }
137 else
138 {
139 if (writeVariablePrecision(type.getPrecision()))
140 out << " ";
141 out << getTypeName(type);
142 }
143}
144
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700145void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000146{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700147 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000148 for (TIntermSequence::const_iterator iter = args.begin();
149 iter != args.end(); ++iter)
150 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700151 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000152 ASSERT(arg != NULL);
153
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700154 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000155 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000156
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700157 const TString &name = arg->getSymbol();
zmo@google.com5601ea02011-06-10 18:23:25 +0000158 if (!name.empty())
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000159 out << " " << hashName(name);
zmo@google.com5601ea02011-06-10 18:23:25 +0000160 if (type.isArray())
161 out << arrayBrackets(type);
162
163 // Put a comma if this is not the last argument.
164 if (iter != args.end() - 1)
165 out << ", ";
166 }
167}
168
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400169const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
170 const TType &type, const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000171{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700172 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000173
174 if (type.getBasicType() == EbtStruct)
175 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700176 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -0400177 out << hashName(structure->name()) << "(";
178
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700179 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400180 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000181 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700182 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000183 ASSERT(fieldType != NULL);
184 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700185 if (i != fields.size() - 1)
186 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000187 }
188 out << ")";
189 }
190 else
191 {
Jamie Madill94bf7f22013-07-08 13:31:15 -0400192 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000193 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700194 if (writeType)
195 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400196 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000197 {
198 switch (pConstUnion->getType())
199 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700200 case EbtFloat:
201 out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
202 break;
203 case EbtInt:
204 out << pConstUnion->getIConst();
205 break;
Olli Etuaho5321c802015-04-02 17:08:16 +0300206 case EbtUInt:
207 out << pConstUnion->getUConst() << "u";
208 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700209 case EbtBool:
210 out << pConstUnion->getBConst();
211 break;
212 default: UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000213 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700214 if (i != size - 1)
215 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000216 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700217 if (writeType)
218 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000219 }
220 return pConstUnion;
221}
222
Olli Etuahof40319e2015-03-10 14:33:00 +0200223void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type, const char *constructorBaseType)
224{
225 TInfoSinkBase &out = objSink();
226 if (visit == PreVisit)
227 {
228 if (type.isArray())
229 {
230 out << constructorBaseType;
231 out << arrayBrackets(type);
232 out << "(";
233 }
234 else
235 {
236 out << constructorBaseType << "(";
237 }
238 }
239 else
240 {
241 writeTriplet(visit, nullptr, ", ", ")");
242 }
243}
244
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700245void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000246{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700247 TInfoSinkBase &out = objSink();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800248 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
249 out << mLoopUnrollStack.getLoopIndexValue(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000250 else
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000251 out << hashVariableName(node->getSymbol());
zmo@google.com5601ea02011-06-10 18:23:25 +0000252
253 if (mDeclaringVariables && node->getType().isArray())
254 out << arrayBrackets(node->getType());
255}
256
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700257void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000258{
259 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
260}
261
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700262bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000263{
264 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700265 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000266 switch (node->getOp())
267 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700268 case EOpInitialize:
269 if (visit == InVisit)
270 {
271 out << " = ";
272 // RHS of initialize is not being declared.
273 mDeclaringVariables = false;
274 }
275 break;
276 case EOpAssign:
277 writeTriplet(visit, "(", " = ", ")");
278 break;
279 case EOpAddAssign:
280 writeTriplet(visit, "(", " += ", ")");
281 break;
282 case EOpSubAssign:
283 writeTriplet(visit, "(", " -= ", ")");
284 break;
285 case EOpDivAssign:
286 writeTriplet(visit, "(", " /= ", ")");
287 break;
Olli Etuahoff805cc2015-02-13 10:59:34 +0200288 case EOpIModAssign:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000289 writeTriplet(visit, "(", " %= ", ")");
290 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700291 // Notice the fall-through.
292 case EOpMulAssign:
293 case EOpVectorTimesMatrixAssign:
294 case EOpVectorTimesScalarAssign:
295 case EOpMatrixTimesScalarAssign:
296 case EOpMatrixTimesMatrixAssign:
297 writeTriplet(visit, "(", " *= ", ")");
298 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200299 case EOpBitShiftLeftAssign:
300 writeTriplet(visit, "(", " <<= ", ")");
301 break;
302 case EOpBitShiftRightAssign:
303 writeTriplet(visit, "(", " >>= ", ")");
304 break;
305 case EOpBitwiseAndAssign:
306 writeTriplet(visit, "(", " &= ", ")");
307 break;
308 case EOpBitwiseXorAssign:
309 writeTriplet(visit, "(", " ^= ", ")");
310 break;
311 case EOpBitwiseOrAssign:
312 writeTriplet(visit, "(", " |= ", ")");
313 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700314
315 case EOpIndexDirect:
316 writeTriplet(visit, NULL, "[", "]");
317 break;
318 case EOpIndexIndirect:
319 if (node->getAddIndexClamp())
320 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000321 if (visit == InVisit)
322 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700323 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
324 out << "[int(clamp(float(";
325 else
326 out << "[webgl_int_clamp(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000327 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700328 else if (visit == PostVisit)
329 {
330 int maxSize;
331 TIntermTyped *left = node->getLeft();
332 TType leftType = left->getType();
zmo@google.com5601ea02011-06-10 18:23:25 +0000333
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700334 if (left->isArray())
335 {
336 // The shader will fail validation if the array length is not > 0.
337 maxSize = leftType.getArraySize() - 1;
338 }
339 else
340 {
341 maxSize = leftType.getNominalSize() - 1;
342 }
343
344 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
345 out << "), 0.0, float(" << maxSize << ")))]";
346 else
347 out << ", 0, " << maxSize << ")]";
348 }
349 }
350 else
351 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000352 writeTriplet(visit, NULL, "[", "]");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700353 }
354 break;
355 case EOpIndexDirectStruct:
356 if (visit == InVisit)
357 {
358 // Here we are writing out "foo.bar", where "foo" is struct
359 // and "bar" is field. In AST, it is represented as a binary
360 // node, where left child represents "foo" and right child "bar".
361 // The node itself represents ".". The struct field "bar" is
362 // actually stored as an index into TStructure::fields.
363 out << ".";
364 const TStructure *structure = node->getLeft()->getType().getStruct();
365 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
366 const TField *field = structure->fields()[index->getIConst(0)];
367
368 TString fieldName = field->name();
369 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
370 fieldName = hashName(fieldName);
371
372 out << fieldName;
373 visitChildren = false;
374 }
375 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400376 case EOpIndexDirectInterfaceBlock:
377 if (visit == InVisit)
378 {
379 out << ".";
380 const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
381 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
382 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
383
384 TString fieldName = field->name();
385 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
386 fieldName = hashName(fieldName);
387
388 out << fieldName;
389 visitChildren = false;
390 }
391 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700392 case EOpVectorSwizzle:
393 if (visit == InVisit)
394 {
395 out << ".";
396 TIntermAggregate *rightChild = node->getRight()->getAsAggregate();
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700397 TIntermSequence *sequence = rightChild->getSequence();
398 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); ++sit)
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000399 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700400 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
401 ASSERT(element->getBasicType() == EbtInt);
402 ASSERT(element->getNominalSize() == 1);
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400403 const TConstantUnion& data = element->getUnionArrayPointer()[0];
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700404 ASSERT(data.getType() == EbtInt);
405 switch (data.getIConst())
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000406 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700407 case 0:
408 out << "x";
409 break;
410 case 1:
411 out << "y";
412 break;
413 case 2:
414 out << "z";
415 break;
416 case 3:
417 out << "w";
418 break;
419 default:
420 UNREACHABLE();
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000421 }
422 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700423 visitChildren = false;
424 }
425 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000426
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700427 case EOpAdd:
428 writeTriplet(visit, "(", " + ", ")");
429 break;
430 case EOpSub:
431 writeTriplet(visit, "(", " - ", ")");
432 break;
433 case EOpMul:
434 writeTriplet(visit, "(", " * ", ")");
435 break;
436 case EOpDiv:
437 writeTriplet(visit, "(", " / ", ")");
438 break;
Olli Etuahoff805cc2015-02-13 10:59:34 +0200439 case EOpIMod:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000440 writeTriplet(visit, "(", " % ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700441 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200442 case EOpBitShiftLeft:
443 writeTriplet(visit, "(", " << ", ")");
444 break;
445 case EOpBitShiftRight:
446 writeTriplet(visit, "(", " >> ", ")");
447 break;
448 case EOpBitwiseAnd:
449 writeTriplet(visit, "(", " & ", ")");
450 break;
451 case EOpBitwiseXor:
452 writeTriplet(visit, "(", " ^ ", ")");
453 break;
454 case EOpBitwiseOr:
455 writeTriplet(visit, "(", " | ", ")");
456 break;
457
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700458 case EOpEqual:
459 writeTriplet(visit, "(", " == ", ")");
460 break;
461 case EOpNotEqual:
462 writeTriplet(visit, "(", " != ", ")");
463 break;
464 case EOpLessThan:
465 writeTriplet(visit, "(", " < ", ")");
466 break;
467 case EOpGreaterThan:
468 writeTriplet(visit, "(", " > ", ")");
469 break;
470 case EOpLessThanEqual:
471 writeTriplet(visit, "(", " <= ", ")");
472 break;
473 case EOpGreaterThanEqual:
474 writeTriplet(visit, "(", " >= ", ")");
475 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000476
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700477 // Notice the fall-through.
478 case EOpVectorTimesScalar:
479 case EOpVectorTimesMatrix:
480 case EOpMatrixTimesVector:
481 case EOpMatrixTimesScalar:
482 case EOpMatrixTimesMatrix:
483 writeTriplet(visit, "(", " * ", ")");
484 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000485
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700486 case EOpLogicalOr:
487 writeTriplet(visit, "(", " || ", ")");
488 break;
489 case EOpLogicalXor:
490 writeTriplet(visit, "(", " ^^ ", ")");
491 break;
492 case EOpLogicalAnd:
493 writeTriplet(visit, "(", " && ", ")");
494 break;
495 default:
496 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000497 }
498
499 return visitChildren;
500}
501
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700502bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000503{
zmo@google.com32e97312011-08-24 01:03:11 +0000504 TString preString;
505 TString postString = ")";
506
zmo@google.com5601ea02011-06-10 18:23:25 +0000507 switch (node->getOp())
508 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700509 case EOpNegative: preString = "(-"; break;
Zhenyao Mode1e00e2014-10-09 16:55:32 -0700510 case EOpPositive: preString = "(+"; break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700511 case EOpVectorLogicalNot: preString = "not("; break;
512 case EOpLogicalNot: preString = "(!"; break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200513 case EOpBitwiseNot: preString = "(~"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000514
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700515 case EOpPostIncrement: preString = "("; postString = "++)"; break;
516 case EOpPostDecrement: preString = "("; postString = "--)"; break;
517 case EOpPreIncrement: preString = "(++"; break;
518 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000519
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700520 case EOpRadians:
521 preString = "radians(";
522 break;
523 case EOpDegrees:
524 preString = "degrees(";
525 break;
526 case EOpSin:
527 preString = "sin(";
528 break;
529 case EOpCos:
530 preString = "cos(";
531 break;
532 case EOpTan:
533 preString = "tan(";
534 break;
535 case EOpAsin:
536 preString = "asin(";
537 break;
538 case EOpAcos:
539 preString = "acos(";
540 break;
541 case EOpAtan:
542 preString = "atan(";
543 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000544
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200545 case EOpSinh:
546 preString = "sinh(";
547 break;
548 case EOpCosh:
549 preString = "cosh(";
550 break;
551 case EOpTanh:
552 preString = "tanh(";
553 break;
554 case EOpAsinh:
555 preString = "asinh(";
556 break;
557 case EOpAcosh:
558 preString = "acosh(";
559 break;
560 case EOpAtanh:
561 preString = "atanh(";
562 break;
563
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700564 case EOpExp:
565 preString = "exp(";
566 break;
567 case EOpLog:
568 preString = "log(";
569 break;
570 case EOpExp2:
571 preString = "exp2(";
572 break;
573 case EOpLog2:
574 preString = "log2(";
575 break;
576 case EOpSqrt:
577 preString = "sqrt(";
578 break;
579 case EOpInverseSqrt:
580 preString = "inversesqrt(";
581 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000582
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700583 case EOpAbs:
584 preString = "abs(";
585 break;
586 case EOpSign:
587 preString = "sign(";
588 break;
589 case EOpFloor:
590 preString = "floor(";
591 break;
Qingqing Deng5dbece52015-02-27 20:35:38 -0800592 case EOpTrunc:
593 preString = "trunc(";
594 break;
595 case EOpRound:
596 preString = "round(";
597 break;
598 case EOpRoundEven:
599 preString = "roundEven(";
600 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700601 case EOpCeil:
602 preString = "ceil(";
603 break;
604 case EOpFract:
605 preString = "fract(";
606 break;
Arun Patole0c1726e2015-02-18 14:35:02 +0530607 case EOpIsNan:
608 preString = "isnan(";
609 break;
610 case EOpIsInf:
611 preString = "isinf(";
612 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000613
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200614 case EOpFloatBitsToInt:
615 preString = "floatBitsToInt(";
616 break;
617 case EOpFloatBitsToUint:
618 preString = "floatBitsToUint(";
619 break;
620 case EOpIntBitsToFloat:
621 preString = "intBitsToFloat(";
622 break;
623 case EOpUintBitsToFloat:
624 preString = "uintBitsToFloat(";
625 break;
626
Olli Etuaho7700ff62015-01-15 12:16:29 +0200627 case EOpPackSnorm2x16:
628 preString = "packSnorm2x16(";
629 break;
630 case EOpPackUnorm2x16:
631 preString = "packUnorm2x16(";
632 break;
633 case EOpPackHalf2x16:
634 preString = "packHalf2x16(";
635 break;
636 case EOpUnpackSnorm2x16:
637 preString = "unpackSnorm2x16(";
638 break;
639 case EOpUnpackUnorm2x16:
640 preString = "unpackUnorm2x16(";
641 break;
642 case EOpUnpackHalf2x16:
643 preString = "unpackHalf2x16(";
644 break;
645
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700646 case EOpLength:
647 preString = "length(";
648 break;
649 case EOpNormalize:
650 preString = "normalize(";
651 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000652
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700653 case EOpDFdx:
654 preString = "dFdx(";
655 break;
656 case EOpDFdy:
657 preString = "dFdy(";
658 break;
659 case EOpFwidth:
660 preString = "fwidth(";
661 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000662
Olli Etuahoe39706d2014-12-30 16:40:36 +0200663 case EOpTranspose:
664 preString = "transpose(";
665 break;
666 case EOpDeterminant:
667 preString = "determinant(";
668 break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +0200669 case EOpInverse:
670 preString = "inverse(";
671 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200672
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700673 case EOpAny:
674 preString = "any(";
675 break;
676 case EOpAll:
677 preString = "all(";
678 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000679
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700680 default:
681 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000682 }
683
zmo@google.com32e97312011-08-24 01:03:11 +0000684 if (visit == PreVisit && node->getUseEmulatedFunction())
685 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
686 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
687
zmo@google.com5601ea02011-06-10 18:23:25 +0000688 return true;
689}
690
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700691bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000692{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700693 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000694
695 if (node->usesTernaryOperator())
696 {
697 // Notice two brackets at the beginning and end. The outer ones
698 // encapsulate the whole ternary expression. This preserves the
699 // order of precedence when ternary expressions are used in a
700 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
701 out << "((";
702 node->getCondition()->traverse(this);
703 out << ") ? (";
704 node->getTrueBlock()->traverse(this);
705 out << ") : (";
706 node->getFalseBlock()->traverse(this);
707 out << "))";
708 }
709 else
710 {
711 out << "if (";
712 node->getCondition()->traverse(this);
713 out << ")\n";
714
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700715 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000716 visitCodeBlock(node->getTrueBlock());
717
718 if (node->getFalseBlock())
719 {
720 out << "else\n";
721 visitCodeBlock(node->getFalseBlock());
722 }
723 decrementDepth();
724 }
725 return false;
726}
727
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200728bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200729{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200730 if (node->getStatementList())
731 {
732 writeTriplet(visit, "switch (", ") ", nullptr);
733 // The curly braces get written when visiting the statementList aggregate
734 }
735 else
736 {
737 // No statementList, so it won't output curly braces
738 writeTriplet(visit, "switch (", ") {", "}\n");
739 }
740 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200741}
742
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200743bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200744{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200745 if (node->hasCondition())
746 {
747 writeTriplet(visit, "case (", nullptr, "):\n");
748 return true;
749 }
750 else
751 {
752 TInfoSinkBase &out = objSink();
753 out << "default:\n";
754 return false;
755 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200756}
757
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700758bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000759{
760 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700761 TInfoSinkBase &out = objSink();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700762 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000763 switch (node->getOp())
764 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700765 case EOpSequence:
766 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700767 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700768 {
769 out << "{\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000770 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000771
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700772 incrementDepth(node);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700773 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
774 iter != node->getSequence()->end(); ++iter)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700775 {
Austin Kinross3ae64652015-01-26 15:51:39 -0800776 TIntermNode *curNode = *iter;
777 ASSERT(curNode != NULL);
778 curNode->traverse(this);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700779
Austin Kinross3ae64652015-01-26 15:51:39 -0800780 if (isSingleStatement(curNode))
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700781 out << ";\n";
782 }
783 decrementDepth();
784
785 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700786 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700787 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700788 out << "}\n";
789 }
790 visitChildren = false;
791 break;
792 case EOpPrototype:
793 // Function declaration.
794 ASSERT(visit == PreVisit);
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300795 {
796 const TType &type = node->getType();
797 writeVariableType(type);
798 if (type.isArray())
799 out << arrayBrackets(type);
800 }
801
Olli Etuaho59f9a642015-08-06 20:38:26 +0300802 out << " " << hashFunctionNameIfNeeded(node->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700803
804 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700805 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700806 out << ")";
807
808 visitChildren = false;
809 break;
810 case EOpFunction: {
811 // Function definition.
812 ASSERT(visit == PreVisit);
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300813 {
814 const TType &type = node->getType();
815 writeVariableType(type);
816 if (type.isArray())
817 out << arrayBrackets(type);
818 }
819
Olli Etuaho59f9a642015-08-06 20:38:26 +0300820 out << " " << hashFunctionNameIfNeeded(node->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700821
822 incrementDepth(node);
823 // Function definition node contains one or two children nodes
824 // representing function parameters and function body. The latter
825 // is not present in case of empty function bodies.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700826 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700827 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
828 TIntermSequence::const_iterator seqIter = sequence.begin();
829
830 // Traverse function parameters.
831 TIntermAggregate *params = (*seqIter)->getAsAggregate();
832 ASSERT(params != NULL);
833 ASSERT(params->getOp() == EOpParameters);
834 params->traverse(this);
835
836 // Traverse function body.
837 TIntermAggregate *body = ++seqIter != sequence.end() ?
838 (*seqIter)->getAsAggregate() : NULL;
839 visitCodeBlock(body);
840 decrementDepth();
841
842 // Fully processed; no need to visit children.
843 visitChildren = false;
844 break;
845 }
846 case EOpFunctionCall:
847 // Function call.
848 if (visit == PreVisit)
Olli Etuaho59f9a642015-08-06 20:38:26 +0300849 out << hashFunctionNameIfNeeded(node->getNameObj()) << "(";
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200850 else if (visit == InVisit)
851 out << ", ";
852 else
853 out << ")";
854 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700855 case EOpParameters:
856 // Function parameters.
857 ASSERT(visit == PreVisit);
858 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700859 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700860 out << ")";
861 visitChildren = false;
862 break;
863 case EOpDeclaration:
864 // Variable declaration.
865 if (visit == PreVisit)
866 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700867 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700868 const TIntermTyped *variable = sequence.front()->getAsTyped();
869 writeVariableType(variable->getType());
870 out << " ";
871 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000872 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700873 else if (visit == InVisit)
874 {
875 out << ", ";
876 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000877 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700878 else
879 {
880 mDeclaringVariables = false;
881 }
882 break;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700883 case EOpInvariantDeclaration:
884 // Invariant declaration.
885 ASSERT(visit == PreVisit);
886 {
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400887 const TIntermSequence *sequence = node->getSequence();
888 ASSERT(sequence && sequence->size() == 1);
889 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
890 ASSERT(symbol);
Zhenyao Mo2a517272014-10-27 16:09:57 -0700891 out << "invariant " << hashVariableName(symbol->getSymbol());
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400892 }
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700893 visitChildren = false;
894 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700895 case EOpConstructFloat:
Olli Etuahof40319e2015-03-10 14:33:00 +0200896 writeConstructorTriplet(visit, node->getType(), "float");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700897 break;
898 case EOpConstructVec2:
Olli Etuahof40319e2015-03-10 14:33:00 +0200899 writeConstructorTriplet(visit, node->getType(), "vec2");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700900 break;
901 case EOpConstructVec3:
Olli Etuahof40319e2015-03-10 14:33:00 +0200902 writeConstructorTriplet(visit, node->getType(), "vec3");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700903 break;
904 case EOpConstructVec4:
Olli Etuahof40319e2015-03-10 14:33:00 +0200905 writeConstructorTriplet(visit, node->getType(), "vec4");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700906 break;
907 case EOpConstructBool:
Olli Etuahof40319e2015-03-10 14:33:00 +0200908 writeConstructorTriplet(visit, node->getType(), "bool");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700909 break;
910 case EOpConstructBVec2:
Olli Etuahof40319e2015-03-10 14:33:00 +0200911 writeConstructorTriplet(visit, node->getType(), "bvec2");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700912 break;
913 case EOpConstructBVec3:
Olli Etuahof40319e2015-03-10 14:33:00 +0200914 writeConstructorTriplet(visit, node->getType(), "bvec3");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700915 break;
916 case EOpConstructBVec4:
Olli Etuahof40319e2015-03-10 14:33:00 +0200917 writeConstructorTriplet(visit, node->getType(), "bvec4");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700918 break;
919 case EOpConstructInt:
Olli Etuahof40319e2015-03-10 14:33:00 +0200920 writeConstructorTriplet(visit, node->getType(), "int");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700921 break;
922 case EOpConstructIVec2:
Olli Etuahof40319e2015-03-10 14:33:00 +0200923 writeConstructorTriplet(visit, node->getType(), "ivec2");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700924 break;
925 case EOpConstructIVec3:
Olli Etuahof40319e2015-03-10 14:33:00 +0200926 writeConstructorTriplet(visit, node->getType(), "ivec3");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700927 break;
928 case EOpConstructIVec4:
Olli Etuahof40319e2015-03-10 14:33:00 +0200929 writeConstructorTriplet(visit, node->getType(), "ivec4");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700930 break;
Geoff Langc4c7442d2015-07-20 13:09:26 -0400931 case EOpConstructUInt:
932 writeConstructorTriplet(visit, node->getType(), "uint");
933 break;
934 case EOpConstructUVec2:
935 writeConstructorTriplet(visit, node->getType(), "uvec2");
936 break;
937 case EOpConstructUVec3:
938 writeConstructorTriplet(visit, node->getType(), "uvec3");
939 break;
940 case EOpConstructUVec4:
941 writeConstructorTriplet(visit, node->getType(), "uvec4");
942 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700943 case EOpConstructMat2:
Olli Etuahof40319e2015-03-10 14:33:00 +0200944 writeConstructorTriplet(visit, node->getType(), "mat2");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700945 break;
Alexis Hetu07e57df2015-06-16 16:55:52 -0400946 case EOpConstructMat2x3:
947 writeConstructorTriplet(visit, node->getType(), "mat2x3");
948 break;
949 case EOpConstructMat2x4:
950 writeConstructorTriplet(visit, node->getType(), "mat2x4");
951 break;
952 case EOpConstructMat3x2:
953 writeConstructorTriplet(visit, node->getType(), "mat3x2");
954 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700955 case EOpConstructMat3:
Olli Etuahof40319e2015-03-10 14:33:00 +0200956 writeConstructorTriplet(visit, node->getType(), "mat3");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700957 break;
Alexis Hetu07e57df2015-06-16 16:55:52 -0400958 case EOpConstructMat3x4:
959 writeConstructorTriplet(visit, node->getType(), "mat3x4");
960 break;
961 case EOpConstructMat4x2:
962 writeConstructorTriplet(visit, node->getType(), "mat4x2");
963 break;
964 case EOpConstructMat4x3:
965 writeConstructorTriplet(visit, node->getType(), "mat4x3");
966 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700967 case EOpConstructMat4:
Olli Etuahof40319e2015-03-10 14:33:00 +0200968 writeConstructorTriplet(visit, node->getType(), "mat4");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700969 break;
970 case EOpConstructStruct:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700971 {
972 const TType &type = node->getType();
973 ASSERT(type.getBasicType() == EbtStruct);
Olli Etuahof40319e2015-03-10 14:33:00 +0200974 TString constructorName = hashName(type.getStruct()->name());
975 writeConstructorTriplet(visit, node->getType(), constructorName.c_str());
976 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700977 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000978
Olli Etuahoe39706d2014-12-30 16:40:36 +0200979 case EOpOuterProduct:
980 writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
981 break;
982
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700983 case EOpLessThan:
984 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
985 break;
986 case EOpGreaterThan:
987 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
988 break;
989 case EOpLessThanEqual:
990 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
991 break;
992 case EOpGreaterThanEqual:
993 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
994 break;
995 case EOpVectorEqual:
996 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
997 break;
998 case EOpVectorNotEqual:
999 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
1000 break;
1001 case EOpComma:
Zhenyao Mo0783efd2014-10-21 15:51:59 -07001002 writeTriplet(visit, "(", ", ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001003 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001004
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001005 case EOpMod:
1006 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
1007 break;
Olli Etuahob6e07a62015-02-16 12:22:10 +02001008 case EOpModf:
1009 writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
1010 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001011 case EOpPow:
1012 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
1013 break;
1014 case EOpAtan:
1015 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
1016 break;
1017 case EOpMin:
1018 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
1019 break;
1020 case EOpMax:
1021 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
1022 break;
1023 case EOpClamp:
1024 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
1025 break;
1026 case EOpMix:
1027 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
1028 break;
1029 case EOpStep:
1030 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
1031 break;
1032 case EOpSmoothStep:
1033 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
1034 break;
1035 case EOpDistance:
1036 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
1037 break;
1038 case EOpDot:
1039 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
1040 break;
1041 case EOpCross:
1042 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
1043 break;
1044 case EOpFaceForward:
1045 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
1046 break;
1047 case EOpReflect:
1048 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
1049 break;
1050 case EOpRefract:
1051 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
1052 break;
1053 case EOpMul:
1054 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
1055 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001056
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001057 default:
1058 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001059 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001060 return visitChildren;
1061}
1062
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001063bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001064{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001065 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001066
Zhenyao Mo7cab38b2013-10-15 12:59:30 -07001067 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +00001068 // Loop header.
1069 TLoopType loopType = node->getType();
1070 if (loopType == ELoopFor) // for loop
1071 {
Zhenyao Mo550c6002014-02-26 15:40:48 -08001072 if (!node->getUnrollFlag())
1073 {
zmo@google.com5601ea02011-06-10 18:23:25 +00001074 out << "for (";
1075 if (node->getInit())
1076 node->getInit()->traverse(this);
1077 out << "; ";
1078
1079 if (node->getCondition())
1080 node->getCondition()->traverse(this);
1081 out << "; ";
1082
1083 if (node->getExpression())
1084 node->getExpression()->traverse(this);
1085 out << ")\n";
1086 }
Zhenyao Mo550c6002014-02-26 15:40:48 -08001087 else
1088 {
1089 // Need to put a one-iteration loop here to handle break.
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001090 TIntermSequence *declSeq =
Zhenyao Mo550c6002014-02-26 15:40:48 -08001091 node->getInit()->getAsAggregate()->getSequence();
1092 TIntermSymbol *indexSymbol =
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001093 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -08001094 TString name = hashVariableName(indexSymbol->getSymbol());
1095 out << "for (int " << name << " = 0; "
1096 << name << " < 1; "
1097 << "++" << name << ")\n";
1098 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001099 }
1100 else if (loopType == ELoopWhile) // while loop
1101 {
1102 out << "while (";
1103 ASSERT(node->getCondition() != NULL);
1104 node->getCondition()->traverse(this);
1105 out << ")\n";
1106 }
1107 else // do-while loop
1108 {
1109 ASSERT(loopType == ELoopDoWhile);
1110 out << "do\n";
1111 }
1112
1113 // Loop body.
1114 if (node->getUnrollFlag())
1115 {
Zhenyao Mo550c6002014-02-26 15:40:48 -08001116 out << "{\n";
1117 mLoopUnrollStack.push(node);
1118 while (mLoopUnrollStack.satisfiesLoopCondition())
zmo@google.com5601ea02011-06-10 18:23:25 +00001119 {
1120 visitCodeBlock(node->getBody());
Zhenyao Mo550c6002014-02-26 15:40:48 -08001121 mLoopUnrollStack.step();
zmo@google.com5601ea02011-06-10 18:23:25 +00001122 }
Zhenyao Mo550c6002014-02-26 15:40:48 -08001123 mLoopUnrollStack.pop();
1124 out << "}\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001125 }
1126 else
1127 {
1128 visitCodeBlock(node->getBody());
1129 }
1130
1131 // Loop footer.
1132 if (loopType == ELoopDoWhile) // do-while loop
1133 {
1134 out << "while (";
1135 ASSERT(node->getCondition() != NULL);
1136 node->getCondition()->traverse(this);
1137 out << ");\n";
1138 }
1139 decrementDepth();
1140
1141 // No need to visit children. They have been already processed in
1142 // this function.
1143 return false;
1144}
1145
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001146bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001147{
1148 switch (node->getFlowOp())
1149 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001150 case EOpKill:
1151 writeTriplet(visit, "discard", NULL, NULL);
1152 break;
1153 case EOpBreak:
1154 writeTriplet(visit, "break", NULL, NULL);
1155 break;
1156 case EOpContinue:
1157 writeTriplet(visit, "continue", NULL, NULL);
1158 break;
1159 case EOpReturn:
1160 writeTriplet(visit, "return ", NULL, NULL);
1161 break;
1162 default:
1163 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001164 }
1165
1166 return true;
1167}
1168
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001169void TOutputGLSLBase::visitCodeBlock(TIntermNode *node)
1170{
zmo@google.com5601ea02011-06-10 18:23:25 +00001171 TInfoSinkBase &out = objSink();
1172 if (node != NULL)
1173 {
1174 node->traverse(this);
1175 // Single statements not part of a sequence need to be terminated
1176 // with semi-colon.
1177 if (isSingleStatement(node))
1178 out << ";\n";
1179 }
1180 else
1181 {
1182 out << "{\n}\n"; // Empty code block.
1183 }
1184}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001185
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001186TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001187{
1188 TInfoSinkBase out;
1189 if (type.isMatrix())
1190 {
1191 out << "mat";
1192 out << type.getNominalSize();
Geoff Langd8edb512015-09-02 11:52:56 -04001193 if (type.getSecondarySize() != type.getNominalSize())
1194 {
1195 out << "x" << type.getSecondarySize();
1196 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001197 }
1198 else if (type.isVector())
1199 {
1200 switch (type.getBasicType())
1201 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001202 case EbtFloat:
1203 out << "vec";
1204 break;
1205 case EbtInt:
1206 out << "ivec";
1207 break;
1208 case EbtBool:
1209 out << "bvec";
1210 break;
Geoff Langc4c7442d2015-07-20 13:09:26 -04001211 case EbtUInt:
1212 out << "uvec";
1213 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001214 default:
1215 UNREACHABLE();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001216 }
1217 out << type.getNominalSize();
1218 }
1219 else
1220 {
1221 if (type.getBasicType() == EbtStruct)
Jamie Madill98493dd2013-07-08 14:39:03 -04001222 out << hashName(type.getStruct()->name());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001223 else
1224 out << type.getBasicString();
1225 }
1226 return TString(out.c_str());
1227}
1228
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001229TString TOutputGLSLBase::hashName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001230{
1231 if (mHashFunction == NULL || name.empty())
1232 return name;
1233 NameMap::const_iterator it = mNameMap.find(name.c_str());
1234 if (it != mNameMap.end())
1235 return it->second.c_str();
1236 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
1237 mNameMap[name.c_str()] = hashedName.c_str();
1238 return hashedName;
1239}
1240
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001241TString TOutputGLSLBase::hashVariableName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001242{
Jamie Madill02f20dd2013-09-12 12:07:42 -04001243 if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001244 return name;
1245 return hashName(name);
1246}
1247
Olli Etuaho59f9a642015-08-06 20:38:26 +03001248TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001249{
Olli Etuaho59f9a642015-08-06 20:38:26 +03001250 TString mangledStr = mangledName.getString();
1251 TString name = TFunction::unmangleName(mangledStr);
1252 if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001253 return translateTextureFunction(name);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001254 if (mangledName.isInternal())
1255 return name;
1256 else
1257 return hashName(name);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001258}
Jamie Madill98493dd2013-07-08 14:39:03 -04001259
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001260bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001261{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001262 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001263 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001264 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001265 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001266 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001267
1268 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001269}
1270
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001271void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001272{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001273 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001274
1275 out << "struct " << hashName(structure->name()) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001276 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001277 for (size_t i = 0; i < fields.size(); ++i)
1278 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001279 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001280 if (writeVariablePrecision(field->type()->getPrecision()))
1281 out << " ";
1282 out << getTypeName(*field->type()) << " " << hashName(field->name());
1283 if (field->type()->isArray())
1284 out << arrayBrackets(*field->type());
1285 out << ";\n";
1286 }
1287 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001288}
Jamie Madill98493dd2013-07-08 14:39:03 -04001289