blob: 09f7ad9b7d24b1a99e3b5344895239a97d56a4ce [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 Madill1c28e1f2014-08-04 11:37:54 -040084 if (qualifier != EvqTemporary && qualifier != EvqGlobal &&
85 type.getBasicType() != EbtInvariant)
86 {
zmo@google.com5601ea02011-06-10 18:23:25 +000087 out << type.getQualifierString() << " ";
Jamie Madill1c28e1f2014-08-04 11:37:54 -040088 }
zmo@google.com5601ea02011-06-10 18:23:25 +000089 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -070090 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +000091 {
Jamie Madill01f85ac2014-06-06 11:55:04 -040092 TStructure *structure = type.getStruct();
93
94 declareStruct(structure);
95
96 if (!structure->name().empty())
97 {
98 mDeclaredStructs.insert(structure->uniqueId());
99 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000100 }
101 else
102 {
103 if (writeVariablePrecision(type.getPrecision()))
104 out << " ";
105 out << getTypeName(type);
106 }
107}
108
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700109void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000110{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700111 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000112 for (TIntermSequence::const_iterator iter = args.begin();
113 iter != args.end(); ++iter)
114 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700115 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000116 ASSERT(arg != NULL);
117
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700118 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000119 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000120
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700121 const TString &name = arg->getSymbol();
zmo@google.com5601ea02011-06-10 18:23:25 +0000122 if (!name.empty())
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000123 out << " " << hashName(name);
zmo@google.com5601ea02011-06-10 18:23:25 +0000124 if (type.isArray())
125 out << arrayBrackets(type);
126
127 // Put a comma if this is not the last argument.
128 if (iter != args.end() - 1)
129 out << ", ";
130 }
131}
132
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700133const ConstantUnion *TOutputGLSLBase::writeConstantUnion(
134 const TType &type, const ConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000135{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700136 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000137
138 if (type.getBasicType() == EbtStruct)
139 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700140 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -0400141 out << hashName(structure->name()) << "(";
142
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700143 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400144 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000145 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700146 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000147 ASSERT(fieldType != NULL);
148 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700149 if (i != fields.size() - 1)
150 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000151 }
152 out << ")";
153 }
154 else
155 {
Jamie Madill94bf7f22013-07-08 13:31:15 -0400156 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000157 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700158 if (writeType)
159 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400160 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000161 {
162 switch (pConstUnion->getType())
163 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700164 case EbtFloat:
165 out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
166 break;
167 case EbtInt:
168 out << pConstUnion->getIConst();
169 break;
170 case EbtBool:
171 out << pConstUnion->getBConst();
172 break;
173 default: UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000174 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700175 if (i != size - 1)
176 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000177 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700178 if (writeType)
179 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000180 }
181 return pConstUnion;
182}
183
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700184void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000185{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700186 TInfoSinkBase &out = objSink();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800187 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
188 out << mLoopUnrollStack.getLoopIndexValue(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000189 else
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000190 out << hashVariableName(node->getSymbol());
zmo@google.com5601ea02011-06-10 18:23:25 +0000191
192 if (mDeclaringVariables && node->getType().isArray())
193 out << arrayBrackets(node->getType());
194}
195
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700196void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000197{
198 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
199}
200
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700201bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000202{
203 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700204 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000205 switch (node->getOp())
206 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700207 case EOpInitialize:
208 if (visit == InVisit)
209 {
210 out << " = ";
211 // RHS of initialize is not being declared.
212 mDeclaringVariables = false;
213 }
214 break;
215 case EOpAssign:
216 writeTriplet(visit, "(", " = ", ")");
217 break;
218 case EOpAddAssign:
219 writeTriplet(visit, "(", " += ", ")");
220 break;
221 case EOpSubAssign:
222 writeTriplet(visit, "(", " -= ", ")");
223 break;
224 case EOpDivAssign:
225 writeTriplet(visit, "(", " /= ", ")");
226 break;
227 // Notice the fall-through.
228 case EOpMulAssign:
229 case EOpVectorTimesMatrixAssign:
230 case EOpVectorTimesScalarAssign:
231 case EOpMatrixTimesScalarAssign:
232 case EOpMatrixTimesMatrixAssign:
233 writeTriplet(visit, "(", " *= ", ")");
234 break;
235
236 case EOpIndexDirect:
237 writeTriplet(visit, NULL, "[", "]");
238 break;
239 case EOpIndexIndirect:
240 if (node->getAddIndexClamp())
241 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000242 if (visit == InVisit)
243 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700244 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
245 out << "[int(clamp(float(";
246 else
247 out << "[webgl_int_clamp(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000248 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700249 else if (visit == PostVisit)
250 {
251 int maxSize;
252 TIntermTyped *left = node->getLeft();
253 TType leftType = left->getType();
zmo@google.com5601ea02011-06-10 18:23:25 +0000254
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700255 if (left->isArray())
256 {
257 // The shader will fail validation if the array length is not > 0.
258 maxSize = leftType.getArraySize() - 1;
259 }
260 else
261 {
262 maxSize = leftType.getNominalSize() - 1;
263 }
264
265 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
266 out << "), 0.0, float(" << maxSize << ")))]";
267 else
268 out << ", 0, " << maxSize << ")]";
269 }
270 }
271 else
272 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000273 writeTriplet(visit, NULL, "[", "]");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700274 }
275 break;
276 case EOpIndexDirectStruct:
277 if (visit == InVisit)
278 {
279 // Here we are writing out "foo.bar", where "foo" is struct
280 // and "bar" is field. In AST, it is represented as a binary
281 // node, where left child represents "foo" and right child "bar".
282 // The node itself represents ".". The struct field "bar" is
283 // actually stored as an index into TStructure::fields.
284 out << ".";
285 const TStructure *structure = node->getLeft()->getType().getStruct();
286 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
287 const TField *field = structure->fields()[index->getIConst(0)];
288
289 TString fieldName = field->name();
290 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
291 fieldName = hashName(fieldName);
292
293 out << fieldName;
294 visitChildren = false;
295 }
296 break;
297 case EOpVectorSwizzle:
298 if (visit == InVisit)
299 {
300 out << ".";
301 TIntermAggregate *rightChild = node->getRight()->getAsAggregate();
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700302 TIntermSequence *sequence = rightChild->getSequence();
303 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); ++sit)
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000304 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700305 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
306 ASSERT(element->getBasicType() == EbtInt);
307 ASSERT(element->getNominalSize() == 1);
308 const ConstantUnion& data = element->getUnionArrayPointer()[0];
309 ASSERT(data.getType() == EbtInt);
310 switch (data.getIConst())
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000311 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700312 case 0:
313 out << "x";
314 break;
315 case 1:
316 out << "y";
317 break;
318 case 2:
319 out << "z";
320 break;
321 case 3:
322 out << "w";
323 break;
324 default:
325 UNREACHABLE();
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000326 }
327 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700328 visitChildren = false;
329 }
330 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000331
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700332 case EOpAdd:
333 writeTriplet(visit, "(", " + ", ")");
334 break;
335 case EOpSub:
336 writeTriplet(visit, "(", " - ", ")");
337 break;
338 case EOpMul:
339 writeTriplet(visit, "(", " * ", ")");
340 break;
341 case EOpDiv:
342 writeTriplet(visit, "(", " / ", ")");
343 break;
344 case EOpMod:
345 UNIMPLEMENTED();
346 break;
347 case EOpEqual:
348 writeTriplet(visit, "(", " == ", ")");
349 break;
350 case EOpNotEqual:
351 writeTriplet(visit, "(", " != ", ")");
352 break;
353 case EOpLessThan:
354 writeTriplet(visit, "(", " < ", ")");
355 break;
356 case EOpGreaterThan:
357 writeTriplet(visit, "(", " > ", ")");
358 break;
359 case EOpLessThanEqual:
360 writeTriplet(visit, "(", " <= ", ")");
361 break;
362 case EOpGreaterThanEqual:
363 writeTriplet(visit, "(", " >= ", ")");
364 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000365
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700366 // Notice the fall-through.
367 case EOpVectorTimesScalar:
368 case EOpVectorTimesMatrix:
369 case EOpMatrixTimesVector:
370 case EOpMatrixTimesScalar:
371 case EOpMatrixTimesMatrix:
372 writeTriplet(visit, "(", " * ", ")");
373 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000374
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700375 case EOpLogicalOr:
376 writeTriplet(visit, "(", " || ", ")");
377 break;
378 case EOpLogicalXor:
379 writeTriplet(visit, "(", " ^^ ", ")");
380 break;
381 case EOpLogicalAnd:
382 writeTriplet(visit, "(", " && ", ")");
383 break;
384 default:
385 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000386 }
387
388 return visitChildren;
389}
390
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700391bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000392{
zmo@google.com32e97312011-08-24 01:03:11 +0000393 TString preString;
394 TString postString = ")";
395
zmo@google.com5601ea02011-06-10 18:23:25 +0000396 switch (node->getOp())
397 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700398 case EOpNegative: preString = "(-"; break;
399 case EOpVectorLogicalNot: preString = "not("; break;
400 case EOpLogicalNot: preString = "(!"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000401
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700402 case EOpPostIncrement: preString = "("; postString = "++)"; break;
403 case EOpPostDecrement: preString = "("; postString = "--)"; break;
404 case EOpPreIncrement: preString = "(++"; break;
405 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000406
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700407 case EOpRadians:
408 preString = "radians(";
409 break;
410 case EOpDegrees:
411 preString = "degrees(";
412 break;
413 case EOpSin:
414 preString = "sin(";
415 break;
416 case EOpCos:
417 preString = "cos(";
418 break;
419 case EOpTan:
420 preString = "tan(";
421 break;
422 case EOpAsin:
423 preString = "asin(";
424 break;
425 case EOpAcos:
426 preString = "acos(";
427 break;
428 case EOpAtan:
429 preString = "atan(";
430 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000431
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700432 case EOpExp:
433 preString = "exp(";
434 break;
435 case EOpLog:
436 preString = "log(";
437 break;
438 case EOpExp2:
439 preString = "exp2(";
440 break;
441 case EOpLog2:
442 preString = "log2(";
443 break;
444 case EOpSqrt:
445 preString = "sqrt(";
446 break;
447 case EOpInverseSqrt:
448 preString = "inversesqrt(";
449 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000450
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700451 case EOpAbs:
452 preString = "abs(";
453 break;
454 case EOpSign:
455 preString = "sign(";
456 break;
457 case EOpFloor:
458 preString = "floor(";
459 break;
460 case EOpCeil:
461 preString = "ceil(";
462 break;
463 case EOpFract:
464 preString = "fract(";
465 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000466
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700467 case EOpLength:
468 preString = "length(";
469 break;
470 case EOpNormalize:
471 preString = "normalize(";
472 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000473
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700474 case EOpDFdx:
475 preString = "dFdx(";
476 break;
477 case EOpDFdy:
478 preString = "dFdy(";
479 break;
480 case EOpFwidth:
481 preString = "fwidth(";
482 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000483
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700484 case EOpAny:
485 preString = "any(";
486 break;
487 case EOpAll:
488 preString = "all(";
489 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000490
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700491 default:
492 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000493 }
494
zmo@google.com32e97312011-08-24 01:03:11 +0000495 if (visit == PreVisit && node->getUseEmulatedFunction())
496 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
497 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
498
zmo@google.com5601ea02011-06-10 18:23:25 +0000499 return true;
500}
501
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700502bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000503{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700504 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000505
506 if (node->usesTernaryOperator())
507 {
508 // Notice two brackets at the beginning and end. The outer ones
509 // encapsulate the whole ternary expression. This preserves the
510 // order of precedence when ternary expressions are used in a
511 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
512 out << "((";
513 node->getCondition()->traverse(this);
514 out << ") ? (";
515 node->getTrueBlock()->traverse(this);
516 out << ") : (";
517 node->getFalseBlock()->traverse(this);
518 out << "))";
519 }
520 else
521 {
522 out << "if (";
523 node->getCondition()->traverse(this);
524 out << ")\n";
525
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700526 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000527 visitCodeBlock(node->getTrueBlock());
528
529 if (node->getFalseBlock())
530 {
531 out << "else\n";
532 visitCodeBlock(node->getFalseBlock());
533 }
534 decrementDepth();
535 }
536 return false;
537}
538
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700539bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000540{
541 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700542 TInfoSinkBase &out = objSink();
zmo@google.comf420c422011-09-12 18:27:59 +0000543 TString preString;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700544 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000545 switch (node->getOp())
546 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700547 case EOpSequence:
548 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700549 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700550 {
551 out << "{\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000552 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000553
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700554 incrementDepth(node);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700555 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
556 iter != node->getSequence()->end(); ++iter)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700557 {
558 TIntermNode *node = *iter;
559 ASSERT(node != NULL);
560 node->traverse(this);
561
562 if (isSingleStatement(node))
563 out << ";\n";
564 }
565 decrementDepth();
566
567 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700568 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700569 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700570 out << "}\n";
571 }
572 visitChildren = false;
573 break;
574 case EOpPrototype:
575 // Function declaration.
576 ASSERT(visit == PreVisit);
577 writeVariableType(node->getType());
578 out << " " << hashName(node->getName());
579
580 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700581 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700582 out << ")";
583
584 visitChildren = false;
585 break;
586 case EOpFunction: {
587 // Function definition.
588 ASSERT(visit == PreVisit);
589 writeVariableType(node->getType());
590 out << " " << hashFunctionName(node->getName());
591
592 incrementDepth(node);
593 // Function definition node contains one or two children nodes
594 // representing function parameters and function body. The latter
595 // is not present in case of empty function bodies.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700596 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700597 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
598 TIntermSequence::const_iterator seqIter = sequence.begin();
599
600 // Traverse function parameters.
601 TIntermAggregate *params = (*seqIter)->getAsAggregate();
602 ASSERT(params != NULL);
603 ASSERT(params->getOp() == EOpParameters);
604 params->traverse(this);
605
606 // Traverse function body.
607 TIntermAggregate *body = ++seqIter != sequence.end() ?
608 (*seqIter)->getAsAggregate() : NULL;
609 visitCodeBlock(body);
610 decrementDepth();
611
612 // Fully processed; no need to visit children.
613 visitChildren = false;
614 break;
615 }
616 case EOpFunctionCall:
617 // Function call.
618 if (visit == PreVisit)
619 out << hashFunctionName(node->getName()) << "(";
620 else if (visit == InVisit)
621 out << ", ";
622 else
zmo@google.com5601ea02011-06-10 18:23:25 +0000623 out << ")";
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700624 break;
625 case EOpParameters:
626 // Function parameters.
627 ASSERT(visit == PreVisit);
628 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700629 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700630 out << ")";
631 visitChildren = false;
632 break;
633 case EOpDeclaration:
634 // Variable declaration.
635 if (visit == PreVisit)
636 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700637 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700638 const TIntermTyped *variable = sequence.front()->getAsTyped();
639 writeVariableType(variable->getType());
640 out << " ";
641 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000642 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700643 else if (visit == InVisit)
644 {
645 out << ", ";
646 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000647 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700648 else
649 {
650 mDeclaringVariables = false;
651 }
652 break;
653 case EOpConstructFloat:
654 writeTriplet(visit, "float(", NULL, ")");
655 break;
656 case EOpConstructVec2:
657 writeBuiltInFunctionTriplet(visit, "vec2(", false);
658 break;
659 case EOpConstructVec3:
660 writeBuiltInFunctionTriplet(visit, "vec3(", false);
661 break;
662 case EOpConstructVec4:
663 writeBuiltInFunctionTriplet(visit, "vec4(", false);
664 break;
665 case EOpConstructBool:
666 writeTriplet(visit, "bool(", NULL, ")");
667 break;
668 case EOpConstructBVec2:
669 writeBuiltInFunctionTriplet(visit, "bvec2(", false);
670 break;
671 case EOpConstructBVec3:
672 writeBuiltInFunctionTriplet(visit, "bvec3(", false);
673 break;
674 case EOpConstructBVec4:
675 writeBuiltInFunctionTriplet(visit, "bvec4(", false);
676 break;
677 case EOpConstructInt:
678 writeTriplet(visit, "int(", NULL, ")");
679 break;
680 case EOpConstructIVec2:
681 writeBuiltInFunctionTriplet(visit, "ivec2(", false);
682 break;
683 case EOpConstructIVec3:
684 writeBuiltInFunctionTriplet(visit, "ivec3(", false);
685 break;
686 case EOpConstructIVec4:
687 writeBuiltInFunctionTriplet(visit, "ivec4(", false);
688 break;
689 case EOpConstructMat2:
690 writeBuiltInFunctionTriplet(visit, "mat2(", false);
691 break;
692 case EOpConstructMat3:
693 writeBuiltInFunctionTriplet(visit, "mat3(", false);
694 break;
695 case EOpConstructMat4:
696 writeBuiltInFunctionTriplet(visit, "mat4(", false);
697 break;
698 case EOpConstructStruct:
699 if (visit == PreVisit)
700 {
701 const TType &type = node->getType();
702 ASSERT(type.getBasicType() == EbtStruct);
703 out << hashName(type.getStruct()->name()) << "(";
704 }
705 else if (visit == InVisit)
706 {
707 out << ", ";
708 }
709 else
710 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000711 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000712 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700713 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000714
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700715 case EOpLessThan:
716 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
717 break;
718 case EOpGreaterThan:
719 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
720 break;
721 case EOpLessThanEqual:
722 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
723 break;
724 case EOpGreaterThanEqual:
725 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
726 break;
727 case EOpVectorEqual:
728 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
729 break;
730 case EOpVectorNotEqual:
731 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
732 break;
733 case EOpComma:
734 writeTriplet(visit, NULL, ", ", NULL);
735 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000736
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700737 case EOpMod:
738 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
739 break;
740 case EOpPow:
741 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
742 break;
743 case EOpAtan:
744 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
745 break;
746 case EOpMin:
747 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
748 break;
749 case EOpMax:
750 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
751 break;
752 case EOpClamp:
753 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
754 break;
755 case EOpMix:
756 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
757 break;
758 case EOpStep:
759 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
760 break;
761 case EOpSmoothStep:
762 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
763 break;
764 case EOpDistance:
765 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
766 break;
767 case EOpDot:
768 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
769 break;
770 case EOpCross:
771 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
772 break;
773 case EOpFaceForward:
774 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
775 break;
776 case EOpReflect:
777 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
778 break;
779 case EOpRefract:
780 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
781 break;
782 case EOpMul:
783 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
784 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000785
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700786 default:
787 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000788 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000789 return visitChildren;
790}
791
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700792bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000793{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700794 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000795
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700796 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000797 // Loop header.
798 TLoopType loopType = node->getType();
799 if (loopType == ELoopFor) // for loop
800 {
Zhenyao Mo550c6002014-02-26 15:40:48 -0800801 if (!node->getUnrollFlag())
802 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000803 out << "for (";
804 if (node->getInit())
805 node->getInit()->traverse(this);
806 out << "; ";
807
808 if (node->getCondition())
809 node->getCondition()->traverse(this);
810 out << "; ";
811
812 if (node->getExpression())
813 node->getExpression()->traverse(this);
814 out << ")\n";
815 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800816 else
817 {
818 // Need to put a one-iteration loop here to handle break.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700819 TIntermSequence *declSeq =
Zhenyao Mo550c6002014-02-26 15:40:48 -0800820 node->getInit()->getAsAggregate()->getSequence();
821 TIntermSymbol *indexSymbol =
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700822 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800823 TString name = hashVariableName(indexSymbol->getSymbol());
824 out << "for (int " << name << " = 0; "
825 << name << " < 1; "
826 << "++" << name << ")\n";
827 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000828 }
829 else if (loopType == ELoopWhile) // while loop
830 {
831 out << "while (";
832 ASSERT(node->getCondition() != NULL);
833 node->getCondition()->traverse(this);
834 out << ")\n";
835 }
836 else // do-while loop
837 {
838 ASSERT(loopType == ELoopDoWhile);
839 out << "do\n";
840 }
841
842 // Loop body.
843 if (node->getUnrollFlag())
844 {
Zhenyao Mo550c6002014-02-26 15:40:48 -0800845 out << "{\n";
846 mLoopUnrollStack.push(node);
847 while (mLoopUnrollStack.satisfiesLoopCondition())
zmo@google.com5601ea02011-06-10 18:23:25 +0000848 {
849 visitCodeBlock(node->getBody());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800850 mLoopUnrollStack.step();
zmo@google.com5601ea02011-06-10 18:23:25 +0000851 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800852 mLoopUnrollStack.pop();
853 out << "}\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000854 }
855 else
856 {
857 visitCodeBlock(node->getBody());
858 }
859
860 // Loop footer.
861 if (loopType == ELoopDoWhile) // do-while loop
862 {
863 out << "while (";
864 ASSERT(node->getCondition() != NULL);
865 node->getCondition()->traverse(this);
866 out << ");\n";
867 }
868 decrementDepth();
869
870 // No need to visit children. They have been already processed in
871 // this function.
872 return false;
873}
874
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700875bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000876{
877 switch (node->getFlowOp())
878 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700879 case EOpKill:
880 writeTriplet(visit, "discard", NULL, NULL);
881 break;
882 case EOpBreak:
883 writeTriplet(visit, "break", NULL, NULL);
884 break;
885 case EOpContinue:
886 writeTriplet(visit, "continue", NULL, NULL);
887 break;
888 case EOpReturn:
889 writeTriplet(visit, "return ", NULL, NULL);
890 break;
891 default:
892 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000893 }
894
895 return true;
896}
897
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700898void TOutputGLSLBase::visitCodeBlock(TIntermNode *node)
899{
zmo@google.com5601ea02011-06-10 18:23:25 +0000900 TInfoSinkBase &out = objSink();
901 if (node != NULL)
902 {
903 node->traverse(this);
904 // Single statements not part of a sequence need to be terminated
905 // with semi-colon.
906 if (isSingleStatement(node))
907 out << ";\n";
908 }
909 else
910 {
911 out << "{\n}\n"; // Empty code block.
912 }
913}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000914
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700915TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000916{
917 TInfoSinkBase out;
918 if (type.isMatrix())
919 {
920 out << "mat";
921 out << type.getNominalSize();
922 }
923 else if (type.isVector())
924 {
925 switch (type.getBasicType())
926 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700927 case EbtFloat:
928 out << "vec";
929 break;
930 case EbtInt:
931 out << "ivec";
932 break;
933 case EbtBool:
934 out << "bvec";
935 break;
936 default:
937 UNREACHABLE();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000938 }
939 out << type.getNominalSize();
940 }
941 else
942 {
943 if (type.getBasicType() == EbtStruct)
Jamie Madill98493dd2013-07-08 14:39:03 -0400944 out << hashName(type.getStruct()->name());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000945 else
946 out << type.getBasicString();
947 }
948 return TString(out.c_str());
949}
950
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700951TString TOutputGLSLBase::hashName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000952{
953 if (mHashFunction == NULL || name.empty())
954 return name;
955 NameMap::const_iterator it = mNameMap.find(name.c_str());
956 if (it != mNameMap.end())
957 return it->second.c_str();
958 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
959 mNameMap[name.c_str()] = hashedName.c_str();
960 return hashedName;
961}
962
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700963TString TOutputGLSLBase::hashVariableName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000964{
Jamie Madill02f20dd2013-09-12 12:07:42 -0400965 if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000966 return name;
967 return hashName(name);
968}
969
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700970TString TOutputGLSLBase::hashFunctionName(const TString &mangled_name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000971{
972 TString name = TFunction::unmangleName(mangled_name);
Jamie Madill02f20dd2013-09-12 12:07:42 -0400973 if (mSymbolTable.findBuiltIn(mangled_name, mShaderVersion) != NULL || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -0400974 return translateTextureFunction(name);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000975 return hashName(name);
976}
Jamie Madill98493dd2013-07-08 14:39:03 -0400977
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700978bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -0400979{
Zhenyao Mo904a9162014-05-09 14:07:45 -0700980 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -0400981 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -0700982 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400983 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -0700984 }
Jamie Madill01f85ac2014-06-06 11:55:04 -0400985
986 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -0400987}
988
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700989void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -0400990{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700991 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -0400992
993 out << "struct " << hashName(structure->name()) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700994 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400995 for (size_t i = 0; i < fields.size(); ++i)
996 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700997 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -0400998 if (writeVariablePrecision(field->type()->getPrecision()))
999 out << " ";
1000 out << getTypeName(*field->type()) << " " << hashName(field->name());
1001 if (field->type()->isArray())
1002 out << arrayBrackets(*field->type());
1003 out << ";\n";
1004 }
1005 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001006}
Jamie Madill98493dd2013-07-08 14:39:03 -04001007