blob: 6d07cccc04fc252fb1029ccd14ce52f1cc79192d [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"
8#include "compiler/translator/compilerdebug.h"
zmo@google.com5601ea02011-06-10 18:23:25 +00009
daniel@transgaming.com773ff742013-01-11 04:12:51 +000010#include <cfloat>
daniel@transgaming.com6c1203f2013-01-11 04:12:43 +000011
zmo@google.com5601ea02011-06-10 18:23:25 +000012namespace
13{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070014TString arrayBrackets(const TType &type)
zmo@google.com5601ea02011-06-10 18:23:25 +000015{
16 ASSERT(type.isArray());
17 TInfoSinkBase out;
18 out << "[" << type.getArraySize() << "]";
19 return TString(out.c_str());
20}
21
Zhenyao Mo9eedea02014-05-12 16:02:35 -070022bool isSingleStatement(TIntermNode *node)
23{
24 if (const TIntermAggregate *aggregate = node->getAsAggregate())
zmo@google.com5601ea02011-06-10 18:23:25 +000025 {
26 return (aggregate->getOp() != EOpFunction) &&
27 (aggregate->getOp() != EOpSequence);
28 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -070029 else if (const TIntermSelection *selection = node->getAsSelectionNode())
zmo@google.com5601ea02011-06-10 18:23:25 +000030 {
31 // Ternary operators are usually part of an assignment operator.
32 // This handles those rare cases in which they are all by themselves.
33 return selection->usesTernaryOperator();
34 }
35 else if (node->getAsLoopNode())
36 {
37 return false;
38 }
39 return true;
40}
41} // namespace
42
Zhenyao Mo9eedea02014-05-12 16:02:35 -070043TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000044 ShArrayIndexClampingStrategy clampingStrategy,
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000045 ShHashFunction64 hashFunction,
Zhenyao Mo9eedea02014-05-12 16:02:35 -070046 NameMap &nameMap,
47 TSymbolTable &symbolTable,
Jamie Madill02f20dd2013-09-12 12:07:42 -040048 int shaderVersion)
zmo@google.com5601ea02011-06-10 18:23:25 +000049 : TIntermTraverser(true, true, true),
50 mObjSink(objSink),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000051 mDeclaringVariables(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000052 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000053 mHashFunction(hashFunction),
54 mNameMap(nameMap),
Jamie Madill02f20dd2013-09-12 12:07:42 -040055 mSymbolTable(symbolTable),
56 mShaderVersion(shaderVersion)
zmo@google.com5601ea02011-06-10 18:23:25 +000057{
58}
59
Zhenyao Mo9eedea02014-05-12 16:02:35 -070060void TOutputGLSLBase::writeTriplet(
61 Visit visit, const char *preStr, const char *inStr, const char *postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000062{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070063 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +000064 if (visit == PreVisit && preStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000065 out << preStr;
zmo@google.com5601ea02011-06-10 18:23:25 +000066 else if (visit == InVisit && inStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000067 out << inStr;
zmo@google.com5601ea02011-06-10 18:23:25 +000068 else if (visit == PostVisit && postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000069 out << postStr;
zmo@google.com5601ea02011-06-10 18:23:25 +000070}
71
Zhenyao Mo9eedea02014-05-12 16:02:35 -070072void TOutputGLSLBase::writeBuiltInFunctionTriplet(
73 Visit visit, const char *preStr, bool useEmulatedFunction)
zmo@google.com5601ea02011-06-10 18:23:25 +000074{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070075 TString preString = useEmulatedFunction ?
76 BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
77 writeTriplet(visit, preString.c_str(), ", ", ")");
78}
79
80void TOutputGLSLBase::writeVariableType(const TType &type)
81{
82 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +000083 TQualifier qualifier = type.getQualifier();
Jamie Madill3b5c2da2014-08-19 15:23:32 -040084 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -040085 {
zmo@google.com5601ea02011-06-10 18:23:25 +000086 out << type.getQualifierString() << " ";
Jamie Madill1c28e1f2014-08-04 11:37:54 -040087 }
zmo@google.com5601ea02011-06-10 18:23:25 +000088 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -070089 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +000090 {
Jamie Madill01f85ac2014-06-06 11:55:04 -040091 TStructure *structure = type.getStruct();
92
93 declareStruct(structure);
94
95 if (!structure->name().empty())
96 {
97 mDeclaredStructs.insert(structure->uniqueId());
98 }
zmo@google.com5601ea02011-06-10 18:23:25 +000099 }
100 else
101 {
102 if (writeVariablePrecision(type.getPrecision()))
103 out << " ";
104 out << getTypeName(type);
105 }
106}
107
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700108void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000109{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700110 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000111 for (TIntermSequence::const_iterator iter = args.begin();
112 iter != args.end(); ++iter)
113 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700114 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000115 ASSERT(arg != NULL);
116
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700117 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000118 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000119
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700120 const TString &name = arg->getSymbol();
zmo@google.com5601ea02011-06-10 18:23:25 +0000121 if (!name.empty())
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000122 out << " " << hashName(name);
zmo@google.com5601ea02011-06-10 18:23:25 +0000123 if (type.isArray())
124 out << arrayBrackets(type);
125
126 // Put a comma if this is not the last argument.
127 if (iter != args.end() - 1)
128 out << ", ";
129 }
130}
131
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700132const ConstantUnion *TOutputGLSLBase::writeConstantUnion(
133 const TType &type, const ConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000134{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700135 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000136
137 if (type.getBasicType() == EbtStruct)
138 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700139 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -0400140 out << hashName(structure->name()) << "(";
141
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700142 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400143 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000144 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700145 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000146 ASSERT(fieldType != NULL);
147 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700148 if (i != fields.size() - 1)
149 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000150 }
151 out << ")";
152 }
153 else
154 {
Jamie Madill94bf7f22013-07-08 13:31:15 -0400155 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000156 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700157 if (writeType)
158 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400159 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000160 {
161 switch (pConstUnion->getType())
162 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700163 case EbtFloat:
164 out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
165 break;
166 case EbtInt:
167 out << pConstUnion->getIConst();
168 break;
169 case EbtBool:
170 out << pConstUnion->getBConst();
171 break;
172 default: UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000173 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700174 if (i != size - 1)
175 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000176 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700177 if (writeType)
178 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000179 }
180 return pConstUnion;
181}
182
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700183void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000184{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700185 TInfoSinkBase &out = objSink();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800186 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
187 out << mLoopUnrollStack.getLoopIndexValue(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000188 else
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000189 out << hashVariableName(node->getSymbol());
zmo@google.com5601ea02011-06-10 18:23:25 +0000190
191 if (mDeclaringVariables && node->getType().isArray())
192 out << arrayBrackets(node->getType());
193}
194
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700195void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000196{
197 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
198}
199
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700200bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000201{
202 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700203 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000204 switch (node->getOp())
205 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700206 case EOpInitialize:
207 if (visit == InVisit)
208 {
209 out << " = ";
210 // RHS of initialize is not being declared.
211 mDeclaringVariables = false;
212 }
213 break;
214 case EOpAssign:
215 writeTriplet(visit, "(", " = ", ")");
216 break;
217 case EOpAddAssign:
218 writeTriplet(visit, "(", " += ", ")");
219 break;
220 case EOpSubAssign:
221 writeTriplet(visit, "(", " -= ", ")");
222 break;
223 case EOpDivAssign:
224 writeTriplet(visit, "(", " /= ", ")");
225 break;
226 // Notice the fall-through.
227 case EOpMulAssign:
228 case EOpVectorTimesMatrixAssign:
229 case EOpVectorTimesScalarAssign:
230 case EOpMatrixTimesScalarAssign:
231 case EOpMatrixTimesMatrixAssign:
232 writeTriplet(visit, "(", " *= ", ")");
233 break;
234
235 case EOpIndexDirect:
236 writeTriplet(visit, NULL, "[", "]");
237 break;
238 case EOpIndexIndirect:
239 if (node->getAddIndexClamp())
240 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000241 if (visit == InVisit)
242 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700243 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
244 out << "[int(clamp(float(";
245 else
246 out << "[webgl_int_clamp(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000247 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700248 else if (visit == PostVisit)
249 {
250 int maxSize;
251 TIntermTyped *left = node->getLeft();
252 TType leftType = left->getType();
zmo@google.com5601ea02011-06-10 18:23:25 +0000253
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700254 if (left->isArray())
255 {
256 // The shader will fail validation if the array length is not > 0.
257 maxSize = leftType.getArraySize() - 1;
258 }
259 else
260 {
261 maxSize = leftType.getNominalSize() - 1;
262 }
263
264 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
265 out << "), 0.0, float(" << maxSize << ")))]";
266 else
267 out << ", 0, " << maxSize << ")]";
268 }
269 }
270 else
271 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000272 writeTriplet(visit, NULL, "[", "]");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700273 }
274 break;
275 case EOpIndexDirectStruct:
276 if (visit == InVisit)
277 {
278 // Here we are writing out "foo.bar", where "foo" is struct
279 // and "bar" is field. In AST, it is represented as a binary
280 // node, where left child represents "foo" and right child "bar".
281 // The node itself represents ".". The struct field "bar" is
282 // actually stored as an index into TStructure::fields.
283 out << ".";
284 const TStructure *structure = node->getLeft()->getType().getStruct();
285 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
286 const TField *field = structure->fields()[index->getIConst(0)];
287
288 TString fieldName = field->name();
289 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
290 fieldName = hashName(fieldName);
291
292 out << fieldName;
293 visitChildren = false;
294 }
295 break;
296 case EOpVectorSwizzle:
297 if (visit == InVisit)
298 {
299 out << ".";
300 TIntermAggregate *rightChild = node->getRight()->getAsAggregate();
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700301 TIntermSequence *sequence = rightChild->getSequence();
302 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); ++sit)
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000303 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700304 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
305 ASSERT(element->getBasicType() == EbtInt);
306 ASSERT(element->getNominalSize() == 1);
307 const ConstantUnion& data = element->getUnionArrayPointer()[0];
308 ASSERT(data.getType() == EbtInt);
309 switch (data.getIConst())
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000310 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700311 case 0:
312 out << "x";
313 break;
314 case 1:
315 out << "y";
316 break;
317 case 2:
318 out << "z";
319 break;
320 case 3:
321 out << "w";
322 break;
323 default:
324 UNREACHABLE();
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000325 }
326 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700327 visitChildren = false;
328 }
329 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000330
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700331 case EOpAdd:
332 writeTriplet(visit, "(", " + ", ")");
333 break;
334 case EOpSub:
335 writeTriplet(visit, "(", " - ", ")");
336 break;
337 case EOpMul:
338 writeTriplet(visit, "(", " * ", ")");
339 break;
340 case EOpDiv:
341 writeTriplet(visit, "(", " / ", ")");
342 break;
343 case EOpMod:
344 UNIMPLEMENTED();
345 break;
346 case EOpEqual:
347 writeTriplet(visit, "(", " == ", ")");
348 break;
349 case EOpNotEqual:
350 writeTriplet(visit, "(", " != ", ")");
351 break;
352 case EOpLessThan:
353 writeTriplet(visit, "(", " < ", ")");
354 break;
355 case EOpGreaterThan:
356 writeTriplet(visit, "(", " > ", ")");
357 break;
358 case EOpLessThanEqual:
359 writeTriplet(visit, "(", " <= ", ")");
360 break;
361 case EOpGreaterThanEqual:
362 writeTriplet(visit, "(", " >= ", ")");
363 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000364
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700365 // Notice the fall-through.
366 case EOpVectorTimesScalar:
367 case EOpVectorTimesMatrix:
368 case EOpMatrixTimesVector:
369 case EOpMatrixTimesScalar:
370 case EOpMatrixTimesMatrix:
371 writeTriplet(visit, "(", " * ", ")");
372 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000373
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700374 case EOpLogicalOr:
375 writeTriplet(visit, "(", " || ", ")");
376 break;
377 case EOpLogicalXor:
378 writeTriplet(visit, "(", " ^^ ", ")");
379 break;
380 case EOpLogicalAnd:
381 writeTriplet(visit, "(", " && ", ")");
382 break;
383 default:
384 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000385 }
386
387 return visitChildren;
388}
389
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700390bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000391{
zmo@google.com32e97312011-08-24 01:03:11 +0000392 TString preString;
393 TString postString = ")";
394
zmo@google.com5601ea02011-06-10 18:23:25 +0000395 switch (node->getOp())
396 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700397 case EOpNegative: preString = "(-"; break;
398 case EOpVectorLogicalNot: preString = "not("; break;
399 case EOpLogicalNot: preString = "(!"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000400
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700401 case EOpPostIncrement: preString = "("; postString = "++)"; break;
402 case EOpPostDecrement: preString = "("; postString = "--)"; break;
403 case EOpPreIncrement: preString = "(++"; break;
404 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000405
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700406 case EOpRadians:
407 preString = "radians(";
408 break;
409 case EOpDegrees:
410 preString = "degrees(";
411 break;
412 case EOpSin:
413 preString = "sin(";
414 break;
415 case EOpCos:
416 preString = "cos(";
417 break;
418 case EOpTan:
419 preString = "tan(";
420 break;
421 case EOpAsin:
422 preString = "asin(";
423 break;
424 case EOpAcos:
425 preString = "acos(";
426 break;
427 case EOpAtan:
428 preString = "atan(";
429 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000430
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700431 case EOpExp:
432 preString = "exp(";
433 break;
434 case EOpLog:
435 preString = "log(";
436 break;
437 case EOpExp2:
438 preString = "exp2(";
439 break;
440 case EOpLog2:
441 preString = "log2(";
442 break;
443 case EOpSqrt:
444 preString = "sqrt(";
445 break;
446 case EOpInverseSqrt:
447 preString = "inversesqrt(";
448 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000449
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700450 case EOpAbs:
451 preString = "abs(";
452 break;
453 case EOpSign:
454 preString = "sign(";
455 break;
456 case EOpFloor:
457 preString = "floor(";
458 break;
459 case EOpCeil:
460 preString = "ceil(";
461 break;
462 case EOpFract:
463 preString = "fract(";
464 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000465
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700466 case EOpLength:
467 preString = "length(";
468 break;
469 case EOpNormalize:
470 preString = "normalize(";
471 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000472
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700473 case EOpDFdx:
474 preString = "dFdx(";
475 break;
476 case EOpDFdy:
477 preString = "dFdy(";
478 break;
479 case EOpFwidth:
480 preString = "fwidth(";
481 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000482
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700483 case EOpAny:
484 preString = "any(";
485 break;
486 case EOpAll:
487 preString = "all(";
488 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000489
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700490 default:
491 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000492 }
493
zmo@google.com32e97312011-08-24 01:03:11 +0000494 if (visit == PreVisit && node->getUseEmulatedFunction())
495 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
496 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
497
zmo@google.com5601ea02011-06-10 18:23:25 +0000498 return true;
499}
500
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700501bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000502{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700503 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000504
505 if (node->usesTernaryOperator())
506 {
507 // Notice two brackets at the beginning and end. The outer ones
508 // encapsulate the whole ternary expression. This preserves the
509 // order of precedence when ternary expressions are used in a
510 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
511 out << "((";
512 node->getCondition()->traverse(this);
513 out << ") ? (";
514 node->getTrueBlock()->traverse(this);
515 out << ") : (";
516 node->getFalseBlock()->traverse(this);
517 out << "))";
518 }
519 else
520 {
521 out << "if (";
522 node->getCondition()->traverse(this);
523 out << ")\n";
524
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700525 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000526 visitCodeBlock(node->getTrueBlock());
527
528 if (node->getFalseBlock())
529 {
530 out << "else\n";
531 visitCodeBlock(node->getFalseBlock());
532 }
533 decrementDepth();
534 }
535 return false;
536}
537
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700538bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000539{
540 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700541 TInfoSinkBase &out = objSink();
zmo@google.comf420c422011-09-12 18:27:59 +0000542 TString preString;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700543 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000544 switch (node->getOp())
545 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700546 case EOpSequence:
547 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700548 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700549 {
550 out << "{\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000551 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000552
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700553 incrementDepth(node);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700554 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
555 iter != node->getSequence()->end(); ++iter)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700556 {
557 TIntermNode *node = *iter;
558 ASSERT(node != NULL);
559 node->traverse(this);
560
561 if (isSingleStatement(node))
562 out << ";\n";
563 }
564 decrementDepth();
565
566 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700567 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700568 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700569 out << "}\n";
570 }
571 visitChildren = false;
572 break;
573 case EOpPrototype:
574 // Function declaration.
575 ASSERT(visit == PreVisit);
576 writeVariableType(node->getType());
577 out << " " << hashName(node->getName());
578
579 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700580 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700581 out << ")";
582
583 visitChildren = false;
584 break;
585 case EOpFunction: {
586 // Function definition.
587 ASSERT(visit == PreVisit);
588 writeVariableType(node->getType());
589 out << " " << hashFunctionName(node->getName());
590
591 incrementDepth(node);
592 // Function definition node contains one or two children nodes
593 // representing function parameters and function body. The latter
594 // is not present in case of empty function bodies.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700595 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700596 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
597 TIntermSequence::const_iterator seqIter = sequence.begin();
598
599 // Traverse function parameters.
600 TIntermAggregate *params = (*seqIter)->getAsAggregate();
601 ASSERT(params != NULL);
602 ASSERT(params->getOp() == EOpParameters);
603 params->traverse(this);
604
605 // Traverse function body.
606 TIntermAggregate *body = ++seqIter != sequence.end() ?
607 (*seqIter)->getAsAggregate() : NULL;
608 visitCodeBlock(body);
609 decrementDepth();
610
611 // Fully processed; no need to visit children.
612 visitChildren = false;
613 break;
614 }
615 case EOpFunctionCall:
616 // Function call.
617 if (visit == PreVisit)
618 out << hashFunctionName(node->getName()) << "(";
619 else if (visit == InVisit)
620 out << ", ";
621 else
zmo@google.com5601ea02011-06-10 18:23:25 +0000622 out << ")";
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700623 break;
624 case EOpParameters:
625 // Function parameters.
626 ASSERT(visit == PreVisit);
627 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700628 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700629 out << ")";
630 visitChildren = false;
631 break;
632 case EOpDeclaration:
633 // Variable declaration.
634 if (visit == PreVisit)
635 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700636 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700637 const TIntermTyped *variable = sequence.front()->getAsTyped();
638 writeVariableType(variable->getType());
639 out << " ";
640 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000641 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700642 else if (visit == InVisit)
643 {
644 out << ", ";
645 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000646 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700647 else
648 {
649 mDeclaringVariables = false;
650 }
651 break;
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400652 case EOpInvariantDeclaration: {
653 // Invariant declaration.
654 ASSERT(visit == PreVisit);
655 const TIntermSequence *sequence = node->getSequence();
656 ASSERT(sequence && sequence->size() == 1);
657 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
658 ASSERT(symbol);
659 out << "invariant " << symbol->getSymbol() << ";";
660 visitChildren = false;
661 break;
662 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700663 case EOpConstructFloat:
664 writeTriplet(visit, "float(", NULL, ")");
665 break;
666 case EOpConstructVec2:
667 writeBuiltInFunctionTriplet(visit, "vec2(", false);
668 break;
669 case EOpConstructVec3:
670 writeBuiltInFunctionTriplet(visit, "vec3(", false);
671 break;
672 case EOpConstructVec4:
673 writeBuiltInFunctionTriplet(visit, "vec4(", false);
674 break;
675 case EOpConstructBool:
676 writeTriplet(visit, "bool(", NULL, ")");
677 break;
678 case EOpConstructBVec2:
679 writeBuiltInFunctionTriplet(visit, "bvec2(", false);
680 break;
681 case EOpConstructBVec3:
682 writeBuiltInFunctionTriplet(visit, "bvec3(", false);
683 break;
684 case EOpConstructBVec4:
685 writeBuiltInFunctionTriplet(visit, "bvec4(", false);
686 break;
687 case EOpConstructInt:
688 writeTriplet(visit, "int(", NULL, ")");
689 break;
690 case EOpConstructIVec2:
691 writeBuiltInFunctionTriplet(visit, "ivec2(", false);
692 break;
693 case EOpConstructIVec3:
694 writeBuiltInFunctionTriplet(visit, "ivec3(", false);
695 break;
696 case EOpConstructIVec4:
697 writeBuiltInFunctionTriplet(visit, "ivec4(", false);
698 break;
699 case EOpConstructMat2:
700 writeBuiltInFunctionTriplet(visit, "mat2(", false);
701 break;
702 case EOpConstructMat3:
703 writeBuiltInFunctionTriplet(visit, "mat3(", false);
704 break;
705 case EOpConstructMat4:
706 writeBuiltInFunctionTriplet(visit, "mat4(", false);
707 break;
708 case EOpConstructStruct:
709 if (visit == PreVisit)
710 {
711 const TType &type = node->getType();
712 ASSERT(type.getBasicType() == EbtStruct);
713 out << hashName(type.getStruct()->name()) << "(";
714 }
715 else if (visit == InVisit)
716 {
717 out << ", ";
718 }
719 else
720 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000721 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000722 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700723 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000724
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700725 case EOpLessThan:
726 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
727 break;
728 case EOpGreaterThan:
729 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
730 break;
731 case EOpLessThanEqual:
732 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
733 break;
734 case EOpGreaterThanEqual:
735 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
736 break;
737 case EOpVectorEqual:
738 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
739 break;
740 case EOpVectorNotEqual:
741 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
742 break;
743 case EOpComma:
744 writeTriplet(visit, NULL, ", ", NULL);
745 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000746
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700747 case EOpMod:
748 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
749 break;
750 case EOpPow:
751 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
752 break;
753 case EOpAtan:
754 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
755 break;
756 case EOpMin:
757 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
758 break;
759 case EOpMax:
760 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
761 break;
762 case EOpClamp:
763 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
764 break;
765 case EOpMix:
766 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
767 break;
768 case EOpStep:
769 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
770 break;
771 case EOpSmoothStep:
772 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
773 break;
774 case EOpDistance:
775 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
776 break;
777 case EOpDot:
778 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
779 break;
780 case EOpCross:
781 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
782 break;
783 case EOpFaceForward:
784 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
785 break;
786 case EOpReflect:
787 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
788 break;
789 case EOpRefract:
790 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
791 break;
792 case EOpMul:
793 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
794 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000795
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700796 default:
797 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000798 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000799 return visitChildren;
800}
801
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700802bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000803{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700804 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000805
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700806 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000807 // Loop header.
808 TLoopType loopType = node->getType();
809 if (loopType == ELoopFor) // for loop
810 {
Zhenyao Mo550c6002014-02-26 15:40:48 -0800811 if (!node->getUnrollFlag())
812 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000813 out << "for (";
814 if (node->getInit())
815 node->getInit()->traverse(this);
816 out << "; ";
817
818 if (node->getCondition())
819 node->getCondition()->traverse(this);
820 out << "; ";
821
822 if (node->getExpression())
823 node->getExpression()->traverse(this);
824 out << ")\n";
825 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800826 else
827 {
828 // Need to put a one-iteration loop here to handle break.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700829 TIntermSequence *declSeq =
Zhenyao Mo550c6002014-02-26 15:40:48 -0800830 node->getInit()->getAsAggregate()->getSequence();
831 TIntermSymbol *indexSymbol =
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700832 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800833 TString name = hashVariableName(indexSymbol->getSymbol());
834 out << "for (int " << name << " = 0; "
835 << name << " < 1; "
836 << "++" << name << ")\n";
837 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000838 }
839 else if (loopType == ELoopWhile) // while loop
840 {
841 out << "while (";
842 ASSERT(node->getCondition() != NULL);
843 node->getCondition()->traverse(this);
844 out << ")\n";
845 }
846 else // do-while loop
847 {
848 ASSERT(loopType == ELoopDoWhile);
849 out << "do\n";
850 }
851
852 // Loop body.
853 if (node->getUnrollFlag())
854 {
Zhenyao Mo550c6002014-02-26 15:40:48 -0800855 out << "{\n";
856 mLoopUnrollStack.push(node);
857 while (mLoopUnrollStack.satisfiesLoopCondition())
zmo@google.com5601ea02011-06-10 18:23:25 +0000858 {
859 visitCodeBlock(node->getBody());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800860 mLoopUnrollStack.step();
zmo@google.com5601ea02011-06-10 18:23:25 +0000861 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800862 mLoopUnrollStack.pop();
863 out << "}\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000864 }
865 else
866 {
867 visitCodeBlock(node->getBody());
868 }
869
870 // Loop footer.
871 if (loopType == ELoopDoWhile) // do-while loop
872 {
873 out << "while (";
874 ASSERT(node->getCondition() != NULL);
875 node->getCondition()->traverse(this);
876 out << ");\n";
877 }
878 decrementDepth();
879
880 // No need to visit children. They have been already processed in
881 // this function.
882 return false;
883}
884
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700885bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000886{
887 switch (node->getFlowOp())
888 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700889 case EOpKill:
890 writeTriplet(visit, "discard", NULL, NULL);
891 break;
892 case EOpBreak:
893 writeTriplet(visit, "break", NULL, NULL);
894 break;
895 case EOpContinue:
896 writeTriplet(visit, "continue", NULL, NULL);
897 break;
898 case EOpReturn:
899 writeTriplet(visit, "return ", NULL, NULL);
900 break;
901 default:
902 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000903 }
904
905 return true;
906}
907
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700908void TOutputGLSLBase::visitCodeBlock(TIntermNode *node)
909{
zmo@google.com5601ea02011-06-10 18:23:25 +0000910 TInfoSinkBase &out = objSink();
911 if (node != NULL)
912 {
913 node->traverse(this);
914 // Single statements not part of a sequence need to be terminated
915 // with semi-colon.
916 if (isSingleStatement(node))
917 out << ";\n";
918 }
919 else
920 {
921 out << "{\n}\n"; // Empty code block.
922 }
923}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000924
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700925TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000926{
927 TInfoSinkBase out;
928 if (type.isMatrix())
929 {
930 out << "mat";
931 out << type.getNominalSize();
932 }
933 else if (type.isVector())
934 {
935 switch (type.getBasicType())
936 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700937 case EbtFloat:
938 out << "vec";
939 break;
940 case EbtInt:
941 out << "ivec";
942 break;
943 case EbtBool:
944 out << "bvec";
945 break;
946 default:
947 UNREACHABLE();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000948 }
949 out << type.getNominalSize();
950 }
951 else
952 {
953 if (type.getBasicType() == EbtStruct)
Jamie Madill98493dd2013-07-08 14:39:03 -0400954 out << hashName(type.getStruct()->name());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000955 else
956 out << type.getBasicString();
957 }
958 return TString(out.c_str());
959}
960
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700961TString TOutputGLSLBase::hashName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000962{
963 if (mHashFunction == NULL || name.empty())
964 return name;
965 NameMap::const_iterator it = mNameMap.find(name.c_str());
966 if (it != mNameMap.end())
967 return it->second.c_str();
968 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
969 mNameMap[name.c_str()] = hashedName.c_str();
970 return hashedName;
971}
972
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700973TString TOutputGLSLBase::hashVariableName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000974{
Jamie Madill02f20dd2013-09-12 12:07:42 -0400975 if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000976 return name;
977 return hashName(name);
978}
979
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700980TString TOutputGLSLBase::hashFunctionName(const TString &mangled_name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000981{
982 TString name = TFunction::unmangleName(mangled_name);
Jamie Madill02f20dd2013-09-12 12:07:42 -0400983 if (mSymbolTable.findBuiltIn(mangled_name, mShaderVersion) != NULL || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -0400984 return translateTextureFunction(name);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000985 return hashName(name);
986}
Jamie Madill98493dd2013-07-08 14:39:03 -0400987
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700988bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -0400989{
Zhenyao Mo904a9162014-05-09 14:07:45 -0700990 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -0400991 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -0700992 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400993 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -0700994 }
Jamie Madill01f85ac2014-06-06 11:55:04 -0400995
996 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -0400997}
998
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700999void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001000{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001001 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001002
1003 out << "struct " << hashName(structure->name()) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001004 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001005 for (size_t i = 0; i < fields.size(); ++i)
1006 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001007 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001008 if (writeVariablePrecision(field->type()->getPrecision()))
1009 out << " ";
1010 out << getTypeName(*field->type()) << " " << hashName(field->name());
1011 if (field->type()->isArray())
1012 out << arrayBrackets(*field->type());
1013 out << ";\n";
1014 }
1015 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001016}
Jamie Madill98493dd2013-07-08 14:39:03 -04001017