blob: d14c70dc43e1915c02134c649e878adf8717fac2 [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();
84 // TODO(alokp): Validate qualifier for variable declarations.
Zhenyao Mo9eedea02014-05-12 16:02:35 -070085 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
zmo@google.com5601ea02011-06-10 18:23:25 +000086 out << type.getQualifierString() << " ";
87 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -070088 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +000089 {
Jamie Madill01f85ac2014-06-06 11:55:04 -040090 TStructure *structure = type.getStruct();
91
92 declareStruct(structure);
93
94 if (!structure->name().empty())
95 {
96 mDeclaredStructs.insert(structure->uniqueId());
97 }
zmo@google.com5601ea02011-06-10 18:23:25 +000098 }
99 else
100 {
101 if (writeVariablePrecision(type.getPrecision()))
102 out << " ";
103 out << getTypeName(type);
104 }
105}
106
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700107void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000108{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700109 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000110 for (TIntermSequence::const_iterator iter = args.begin();
111 iter != args.end(); ++iter)
112 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700113 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000114 ASSERT(arg != NULL);
115
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700116 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000117 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000118
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700119 const TString &name = arg->getSymbol();
zmo@google.com5601ea02011-06-10 18:23:25 +0000120 if (!name.empty())
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000121 out << " " << hashName(name);
zmo@google.com5601ea02011-06-10 18:23:25 +0000122 if (type.isArray())
123 out << arrayBrackets(type);
124
125 // Put a comma if this is not the last argument.
126 if (iter != args.end() - 1)
127 out << ", ";
128 }
129}
130
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700131const ConstantUnion *TOutputGLSLBase::writeConstantUnion(
132 const TType &type, const ConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000133{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700134 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000135
136 if (type.getBasicType() == EbtStruct)
137 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700138 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -0400139 out << hashName(structure->name()) << "(";
140
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700141 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400142 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000143 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700144 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000145 ASSERT(fieldType != NULL);
146 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700147 if (i != fields.size() - 1)
148 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000149 }
150 out << ")";
151 }
152 else
153 {
Jamie Madill94bf7f22013-07-08 13:31:15 -0400154 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000155 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700156 if (writeType)
157 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400158 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000159 {
160 switch (pConstUnion->getType())
161 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700162 case EbtFloat:
163 out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
164 break;
165 case EbtInt:
166 out << pConstUnion->getIConst();
167 break;
168 case EbtBool:
169 out << pConstUnion->getBConst();
170 break;
171 default: UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000172 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700173 if (i != size - 1)
174 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000175 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700176 if (writeType)
177 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000178 }
179 return pConstUnion;
180}
181
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700182void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000183{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700184 TInfoSinkBase &out = objSink();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800185 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
186 out << mLoopUnrollStack.getLoopIndexValue(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000187 else
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000188 out << hashVariableName(node->getSymbol());
zmo@google.com5601ea02011-06-10 18:23:25 +0000189
190 if (mDeclaringVariables && node->getType().isArray())
191 out << arrayBrackets(node->getType());
192}
193
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700194void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000195{
196 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
197}
198
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700199bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000200{
201 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700202 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000203 switch (node->getOp())
204 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700205 case EOpInitialize:
206 if (visit == InVisit)
207 {
208 out << " = ";
209 // RHS of initialize is not being declared.
210 mDeclaringVariables = false;
211 }
212 break;
213 case EOpAssign:
214 writeTriplet(visit, "(", " = ", ")");
215 break;
216 case EOpAddAssign:
217 writeTriplet(visit, "(", " += ", ")");
218 break;
219 case EOpSubAssign:
220 writeTriplet(visit, "(", " -= ", ")");
221 break;
222 case EOpDivAssign:
223 writeTriplet(visit, "(", " /= ", ")");
224 break;
225 // Notice the fall-through.
226 case EOpMulAssign:
227 case EOpVectorTimesMatrixAssign:
228 case EOpVectorTimesScalarAssign:
229 case EOpMatrixTimesScalarAssign:
230 case EOpMatrixTimesMatrixAssign:
231 writeTriplet(visit, "(", " *= ", ")");
232 break;
233
234 case EOpIndexDirect:
235 writeTriplet(visit, NULL, "[", "]");
236 break;
237 case EOpIndexIndirect:
238 if (node->getAddIndexClamp())
239 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000240 if (visit == InVisit)
241 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700242 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
243 out << "[int(clamp(float(";
244 else
245 out << "[webgl_int_clamp(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000246 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700247 else if (visit == PostVisit)
248 {
249 int maxSize;
250 TIntermTyped *left = node->getLeft();
251 TType leftType = left->getType();
zmo@google.com5601ea02011-06-10 18:23:25 +0000252
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700253 if (left->isArray())
254 {
255 // The shader will fail validation if the array length is not > 0.
256 maxSize = leftType.getArraySize() - 1;
257 }
258 else
259 {
260 maxSize = leftType.getNominalSize() - 1;
261 }
262
263 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
264 out << "), 0.0, float(" << maxSize << ")))]";
265 else
266 out << ", 0, " << maxSize << ")]";
267 }
268 }
269 else
270 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000271 writeTriplet(visit, NULL, "[", "]");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700272 }
273 break;
274 case EOpIndexDirectStruct:
275 if (visit == InVisit)
276 {
277 // Here we are writing out "foo.bar", where "foo" is struct
278 // and "bar" is field. In AST, it is represented as a binary
279 // node, where left child represents "foo" and right child "bar".
280 // The node itself represents ".". The struct field "bar" is
281 // actually stored as an index into TStructure::fields.
282 out << ".";
283 const TStructure *structure = node->getLeft()->getType().getStruct();
284 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
285 const TField *field = structure->fields()[index->getIConst(0)];
286
287 TString fieldName = field->name();
288 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
289 fieldName = hashName(fieldName);
290
291 out << fieldName;
292 visitChildren = false;
293 }
294 break;
295 case EOpVectorSwizzle:
296 if (visit == InVisit)
297 {
298 out << ".";
299 TIntermAggregate *rightChild = node->getRight()->getAsAggregate();
300 TIntermSequence &sequence = rightChild->getSequence();
301 for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000302 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700303 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
304 ASSERT(element->getBasicType() == EbtInt);
305 ASSERT(element->getNominalSize() == 1);
306 const ConstantUnion& data = element->getUnionArrayPointer()[0];
307 ASSERT(data.getType() == EbtInt);
308 switch (data.getIConst())
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000309 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700310 case 0:
311 out << "x";
312 break;
313 case 1:
314 out << "y";
315 break;
316 case 2:
317 out << "z";
318 break;
319 case 3:
320 out << "w";
321 break;
322 default:
323 UNREACHABLE();
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000324 }
325 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700326 visitChildren = false;
327 }
328 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000329
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700330 case EOpAdd:
331 writeTriplet(visit, "(", " + ", ")");
332 break;
333 case EOpSub:
334 writeTriplet(visit, "(", " - ", ")");
335 break;
336 case EOpMul:
337 writeTriplet(visit, "(", " * ", ")");
338 break;
339 case EOpDiv:
340 writeTriplet(visit, "(", " / ", ")");
341 break;
342 case EOpMod:
343 UNIMPLEMENTED();
344 break;
345 case EOpEqual:
346 writeTriplet(visit, "(", " == ", ")");
347 break;
348 case EOpNotEqual:
349 writeTriplet(visit, "(", " != ", ")");
350 break;
351 case EOpLessThan:
352 writeTriplet(visit, "(", " < ", ")");
353 break;
354 case EOpGreaterThan:
355 writeTriplet(visit, "(", " > ", ")");
356 break;
357 case EOpLessThanEqual:
358 writeTriplet(visit, "(", " <= ", ")");
359 break;
360 case EOpGreaterThanEqual:
361 writeTriplet(visit, "(", " >= ", ")");
362 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000363
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700364 // Notice the fall-through.
365 case EOpVectorTimesScalar:
366 case EOpVectorTimesMatrix:
367 case EOpMatrixTimesVector:
368 case EOpMatrixTimesScalar:
369 case EOpMatrixTimesMatrix:
370 writeTriplet(visit, "(", " * ", ")");
371 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000372
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700373 case EOpLogicalOr:
374 writeTriplet(visit, "(", " || ", ")");
375 break;
376 case EOpLogicalXor:
377 writeTriplet(visit, "(", " ^^ ", ")");
378 break;
379 case EOpLogicalAnd:
380 writeTriplet(visit, "(", " && ", ")");
381 break;
382 default:
383 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000384 }
385
386 return visitChildren;
387}
388
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700389bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000390{
zmo@google.com32e97312011-08-24 01:03:11 +0000391 TString preString;
392 TString postString = ")";
393
zmo@google.com5601ea02011-06-10 18:23:25 +0000394 switch (node->getOp())
395 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700396 case EOpNegative: preString = "(-"; break;
397 case EOpVectorLogicalNot: preString = "not("; break;
398 case EOpLogicalNot: preString = "(!"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000399
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700400 case EOpPostIncrement: preString = "("; postString = "++)"; break;
401 case EOpPostDecrement: preString = "("; postString = "--)"; break;
402 case EOpPreIncrement: preString = "(++"; break;
403 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000404
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700405 case EOpRadians:
406 preString = "radians(";
407 break;
408 case EOpDegrees:
409 preString = "degrees(";
410 break;
411 case EOpSin:
412 preString = "sin(";
413 break;
414 case EOpCos:
415 preString = "cos(";
416 break;
417 case EOpTan:
418 preString = "tan(";
419 break;
420 case EOpAsin:
421 preString = "asin(";
422 break;
423 case EOpAcos:
424 preString = "acos(";
425 break;
426 case EOpAtan:
427 preString = "atan(";
428 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000429
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700430 case EOpExp:
431 preString = "exp(";
432 break;
433 case EOpLog:
434 preString = "log(";
435 break;
436 case EOpExp2:
437 preString = "exp2(";
438 break;
439 case EOpLog2:
440 preString = "log2(";
441 break;
442 case EOpSqrt:
443 preString = "sqrt(";
444 break;
445 case EOpInverseSqrt:
446 preString = "inversesqrt(";
447 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000448
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700449 case EOpAbs:
450 preString = "abs(";
451 break;
452 case EOpSign:
453 preString = "sign(";
454 break;
455 case EOpFloor:
456 preString = "floor(";
457 break;
458 case EOpCeil:
459 preString = "ceil(";
460 break;
461 case EOpFract:
462 preString = "fract(";
463 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000464
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700465 case EOpLength:
466 preString = "length(";
467 break;
468 case EOpNormalize:
469 preString = "normalize(";
470 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000471
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700472 case EOpDFdx:
473 preString = "dFdx(";
474 break;
475 case EOpDFdy:
476 preString = "dFdy(";
477 break;
478 case EOpFwidth:
479 preString = "fwidth(";
480 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000481
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700482 case EOpAny:
483 preString = "any(";
484 break;
485 case EOpAll:
486 preString = "all(";
487 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000488
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700489 default:
490 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000491 }
492
zmo@google.com32e97312011-08-24 01:03:11 +0000493 if (visit == PreVisit && node->getUseEmulatedFunction())
494 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
495 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
496
zmo@google.com5601ea02011-06-10 18:23:25 +0000497 return true;
498}
499
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700500bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000501{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700502 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000503
504 if (node->usesTernaryOperator())
505 {
506 // Notice two brackets at the beginning and end. The outer ones
507 // encapsulate the whole ternary expression. This preserves the
508 // order of precedence when ternary expressions are used in a
509 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
510 out << "((";
511 node->getCondition()->traverse(this);
512 out << ") ? (";
513 node->getTrueBlock()->traverse(this);
514 out << ") : (";
515 node->getFalseBlock()->traverse(this);
516 out << "))";
517 }
518 else
519 {
520 out << "if (";
521 node->getCondition()->traverse(this);
522 out << ")\n";
523
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700524 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000525 visitCodeBlock(node->getTrueBlock());
526
527 if (node->getFalseBlock())
528 {
529 out << "else\n";
530 visitCodeBlock(node->getFalseBlock());
531 }
532 decrementDepth();
533 }
534 return false;
535}
536
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700537bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000538{
539 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700540 TInfoSinkBase &out = objSink();
zmo@google.comf420c422011-09-12 18:27:59 +0000541 TString preString;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700542 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000543 switch (node->getOp())
544 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700545 case EOpSequence:
546 // Scope the sequences except when at the global scope.
547 if (depth > 0)
548 {
549 out << "{\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000550 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000551
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700552 incrementDepth(node);
553 for (TIntermSequence::const_iterator iter = node->getSequence().begin();
554 iter != node->getSequence().end(); ++iter)
555 {
556 TIntermNode *node = *iter;
557 ASSERT(node != NULL);
558 node->traverse(this);
559
560 if (isSingleStatement(node))
561 out << ";\n";
562 }
563 decrementDepth();
564
565 // Scope the sequences except when at the global scope.
566 if (depth > 0)
567 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700568 out << "}\n";
569 }
570 visitChildren = false;
571 break;
572 case EOpPrototype:
573 // Function declaration.
574 ASSERT(visit == PreVisit);
575 writeVariableType(node->getType());
576 out << " " << hashName(node->getName());
577
578 out << "(";
579 writeFunctionParameters(node->getSequence());
580 out << ")";
581
582 visitChildren = false;
583 break;
584 case EOpFunction: {
585 // Function definition.
586 ASSERT(visit == PreVisit);
587 writeVariableType(node->getType());
588 out << " " << hashFunctionName(node->getName());
589
590 incrementDepth(node);
591 // Function definition node contains one or two children nodes
592 // representing function parameters and function body. The latter
593 // is not present in case of empty function bodies.
594 const TIntermSequence &sequence = node->getSequence();
595 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
596 TIntermSequence::const_iterator seqIter = sequence.begin();
597
598 // Traverse function parameters.
599 TIntermAggregate *params = (*seqIter)->getAsAggregate();
600 ASSERT(params != NULL);
601 ASSERT(params->getOp() == EOpParameters);
602 params->traverse(this);
603
604 // Traverse function body.
605 TIntermAggregate *body = ++seqIter != sequence.end() ?
606 (*seqIter)->getAsAggregate() : NULL;
607 visitCodeBlock(body);
608 decrementDepth();
609
610 // Fully processed; no need to visit children.
611 visitChildren = false;
612 break;
613 }
614 case EOpFunctionCall:
615 // Function call.
616 if (visit == PreVisit)
617 out << hashFunctionName(node->getName()) << "(";
618 else if (visit == InVisit)
619 out << ", ";
620 else
zmo@google.com5601ea02011-06-10 18:23:25 +0000621 out << ")";
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700622 break;
623 case EOpParameters:
624 // Function parameters.
625 ASSERT(visit == PreVisit);
626 out << "(";
627 writeFunctionParameters(node->getSequence());
628 out << ")";
629 visitChildren = false;
630 break;
631 case EOpDeclaration:
632 // Variable declaration.
633 if (visit == PreVisit)
634 {
635 const TIntermSequence &sequence = node->getSequence();
636 const TIntermTyped *variable = sequence.front()->getAsTyped();
637 writeVariableType(variable->getType());
638 out << " ";
639 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000640 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700641 else if (visit == InVisit)
642 {
643 out << ", ";
644 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000645 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700646 else
647 {
648 mDeclaringVariables = false;
649 }
650 break;
651 case EOpConstructFloat:
652 writeTriplet(visit, "float(", NULL, ")");
653 break;
654 case EOpConstructVec2:
655 writeBuiltInFunctionTriplet(visit, "vec2(", false);
656 break;
657 case EOpConstructVec3:
658 writeBuiltInFunctionTriplet(visit, "vec3(", false);
659 break;
660 case EOpConstructVec4:
661 writeBuiltInFunctionTriplet(visit, "vec4(", false);
662 break;
663 case EOpConstructBool:
664 writeTriplet(visit, "bool(", NULL, ")");
665 break;
666 case EOpConstructBVec2:
667 writeBuiltInFunctionTriplet(visit, "bvec2(", false);
668 break;
669 case EOpConstructBVec3:
670 writeBuiltInFunctionTriplet(visit, "bvec3(", false);
671 break;
672 case EOpConstructBVec4:
673 writeBuiltInFunctionTriplet(visit, "bvec4(", false);
674 break;
675 case EOpConstructInt:
676 writeTriplet(visit, "int(", NULL, ")");
677 break;
678 case EOpConstructIVec2:
679 writeBuiltInFunctionTriplet(visit, "ivec2(", false);
680 break;
681 case EOpConstructIVec3:
682 writeBuiltInFunctionTriplet(visit, "ivec3(", false);
683 break;
684 case EOpConstructIVec4:
685 writeBuiltInFunctionTriplet(visit, "ivec4(", false);
686 break;
687 case EOpConstructMat2:
688 writeBuiltInFunctionTriplet(visit, "mat2(", false);
689 break;
690 case EOpConstructMat3:
691 writeBuiltInFunctionTriplet(visit, "mat3(", false);
692 break;
693 case EOpConstructMat4:
694 writeBuiltInFunctionTriplet(visit, "mat4(", false);
695 break;
696 case EOpConstructStruct:
697 if (visit == PreVisit)
698 {
699 const TType &type = node->getType();
700 ASSERT(type.getBasicType() == EbtStruct);
701 out << hashName(type.getStruct()->name()) << "(";
702 }
703 else if (visit == InVisit)
704 {
705 out << ", ";
706 }
707 else
708 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000709 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000710 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700711 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000712
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700713 case EOpLessThan:
714 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
715 break;
716 case EOpGreaterThan:
717 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
718 break;
719 case EOpLessThanEqual:
720 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
721 break;
722 case EOpGreaterThanEqual:
723 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
724 break;
725 case EOpVectorEqual:
726 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
727 break;
728 case EOpVectorNotEqual:
729 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
730 break;
731 case EOpComma:
732 writeTriplet(visit, NULL, ", ", NULL);
733 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000734
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700735 case EOpMod:
736 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
737 break;
738 case EOpPow:
739 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
740 break;
741 case EOpAtan:
742 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
743 break;
744 case EOpMin:
745 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
746 break;
747 case EOpMax:
748 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
749 break;
750 case EOpClamp:
751 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
752 break;
753 case EOpMix:
754 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
755 break;
756 case EOpStep:
757 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
758 break;
759 case EOpSmoothStep:
760 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
761 break;
762 case EOpDistance:
763 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
764 break;
765 case EOpDot:
766 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
767 break;
768 case EOpCross:
769 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
770 break;
771 case EOpFaceForward:
772 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
773 break;
774 case EOpReflect:
775 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
776 break;
777 case EOpRefract:
778 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
779 break;
780 case EOpMul:
781 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
782 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000783
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700784 default:
785 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000786 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000787 return visitChildren;
788}
789
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700790bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000791{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700792 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000793
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700794 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000795 // Loop header.
796 TLoopType loopType = node->getType();
797 if (loopType == ELoopFor) // for loop
798 {
Zhenyao Mo550c6002014-02-26 15:40:48 -0800799 if (!node->getUnrollFlag())
800 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000801 out << "for (";
802 if (node->getInit())
803 node->getInit()->traverse(this);
804 out << "; ";
805
806 if (node->getCondition())
807 node->getCondition()->traverse(this);
808 out << "; ";
809
810 if (node->getExpression())
811 node->getExpression()->traverse(this);
812 out << ")\n";
813 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800814 else
815 {
816 // Need to put a one-iteration loop here to handle break.
817 TIntermSequence &declSeq =
818 node->getInit()->getAsAggregate()->getSequence();
819 TIntermSymbol *indexSymbol =
820 declSeq[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
821 TString name = hashVariableName(indexSymbol->getSymbol());
822 out << "for (int " << name << " = 0; "
823 << name << " < 1; "
824 << "++" << name << ")\n";
825 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000826 }
827 else if (loopType == ELoopWhile) // while loop
828 {
829 out << "while (";
830 ASSERT(node->getCondition() != NULL);
831 node->getCondition()->traverse(this);
832 out << ")\n";
833 }
834 else // do-while loop
835 {
836 ASSERT(loopType == ELoopDoWhile);
837 out << "do\n";
838 }
839
840 // Loop body.
841 if (node->getUnrollFlag())
842 {
Zhenyao Mo550c6002014-02-26 15:40:48 -0800843 out << "{\n";
844 mLoopUnrollStack.push(node);
845 while (mLoopUnrollStack.satisfiesLoopCondition())
zmo@google.com5601ea02011-06-10 18:23:25 +0000846 {
847 visitCodeBlock(node->getBody());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800848 mLoopUnrollStack.step();
zmo@google.com5601ea02011-06-10 18:23:25 +0000849 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800850 mLoopUnrollStack.pop();
851 out << "}\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000852 }
853 else
854 {
855 visitCodeBlock(node->getBody());
856 }
857
858 // Loop footer.
859 if (loopType == ELoopDoWhile) // do-while loop
860 {
861 out << "while (";
862 ASSERT(node->getCondition() != NULL);
863 node->getCondition()->traverse(this);
864 out << ");\n";
865 }
866 decrementDepth();
867
868 // No need to visit children. They have been already processed in
869 // this function.
870 return false;
871}
872
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700873bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000874{
875 switch (node->getFlowOp())
876 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700877 case EOpKill:
878 writeTriplet(visit, "discard", NULL, NULL);
879 break;
880 case EOpBreak:
881 writeTriplet(visit, "break", NULL, NULL);
882 break;
883 case EOpContinue:
884 writeTriplet(visit, "continue", NULL, NULL);
885 break;
886 case EOpReturn:
887 writeTriplet(visit, "return ", NULL, NULL);
888 break;
889 default:
890 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000891 }
892
893 return true;
894}
895
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700896void TOutputGLSLBase::visitCodeBlock(TIntermNode *node)
897{
zmo@google.com5601ea02011-06-10 18:23:25 +0000898 TInfoSinkBase &out = objSink();
899 if (node != NULL)
900 {
901 node->traverse(this);
902 // Single statements not part of a sequence need to be terminated
903 // with semi-colon.
904 if (isSingleStatement(node))
905 out << ";\n";
906 }
907 else
908 {
909 out << "{\n}\n"; // Empty code block.
910 }
911}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000912
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700913TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000914{
915 TInfoSinkBase out;
916 if (type.isMatrix())
917 {
918 out << "mat";
919 out << type.getNominalSize();
920 }
921 else if (type.isVector())
922 {
923 switch (type.getBasicType())
924 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700925 case EbtFloat:
926 out << "vec";
927 break;
928 case EbtInt:
929 out << "ivec";
930 break;
931 case EbtBool:
932 out << "bvec";
933 break;
934 default:
935 UNREACHABLE();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000936 }
937 out << type.getNominalSize();
938 }
939 else
940 {
941 if (type.getBasicType() == EbtStruct)
Jamie Madill98493dd2013-07-08 14:39:03 -0400942 out << hashName(type.getStruct()->name());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000943 else
944 out << type.getBasicString();
945 }
946 return TString(out.c_str());
947}
948
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700949TString TOutputGLSLBase::hashName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000950{
951 if (mHashFunction == NULL || name.empty())
952 return name;
953 NameMap::const_iterator it = mNameMap.find(name.c_str());
954 if (it != mNameMap.end())
955 return it->second.c_str();
956 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
957 mNameMap[name.c_str()] = hashedName.c_str();
958 return hashedName;
959}
960
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700961TString TOutputGLSLBase::hashVariableName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000962{
Jamie Madill02f20dd2013-09-12 12:07:42 -0400963 if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000964 return name;
965 return hashName(name);
966}
967
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700968TString TOutputGLSLBase::hashFunctionName(const TString &mangled_name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000969{
970 TString name = TFunction::unmangleName(mangled_name);
Jamie Madill02f20dd2013-09-12 12:07:42 -0400971 if (mSymbolTable.findBuiltIn(mangled_name, mShaderVersion) != NULL || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -0400972 return translateTextureFunction(name);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000973 return hashName(name);
974}
Jamie Madill98493dd2013-07-08 14:39:03 -0400975
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700976bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -0400977{
Zhenyao Mo904a9162014-05-09 14:07:45 -0700978 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -0400979 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -0700980 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400981 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -0700982 }
Jamie Madill01f85ac2014-06-06 11:55:04 -0400983
984 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -0400985}
986
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700987void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -0400988{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700989 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -0400990
991 out << "struct " << hashName(structure->name()) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700992 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400993 for (size_t i = 0; i < fields.size(); ++i)
994 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700995 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -0400996 if (writeVariablePrecision(field->type()->getPrecision()))
997 out << " ";
998 out << getTypeName(*field->type()) << " " << hashName(field->name());
999 if (field->type()->isArray())
1000 out << arrayBrackets(*field->type());
1001 out << ";\n";
1002 }
1003 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001004}
Jamie Madill98493dd2013-07-08 14:39:03 -04001005