blob: 6eaadd2562cbed4263f330379a11ef3c1446f6ef [file] [log] [blame]
zmo@google.com5601ea02011-06-10 18:23:25 +00001//
Jamie Madill02f20dd2013-09-12 12:07:42 -04002// Copyright (c) 2002-2013 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 EOpConvIntToBool:
406 case EOpConvFloatToBool:
407 switch (node->getOperand()->getType().getNominalSize())
408 {
409 case 1:
410 preString = "bool(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000411 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700412 case 2:
413 preString = "bvec2(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000414 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700415 case 3:
416 preString = "bvec3(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000417 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700418 case 4:
419 preString = "bvec4(";
420 break;
421 default:
422 UNREACHABLE();
423 }
424 break;
425 case EOpConvBoolToFloat:
426 case EOpConvIntToFloat:
427 switch (node->getOperand()->getType().getNominalSize())
428 {
429 case 1:
430 preString = "float(";
431 break;
432 case 2:
433 preString = "vec2(";
434 break;
435 case 3:
436 preString = "vec3(";
437 break;
438 case 4:
439 preString = "vec4(";
440 break;
441 default:
442 UNREACHABLE();
443 }
444 break;
445 case EOpConvFloatToInt:
446 case EOpConvBoolToInt:
447 switch (node->getOperand()->getType().getNominalSize())
448 {
449 case 1:
450 preString = "int(";
451 break;
452 case 2:
453 preString = "ivec2(";
454 break;
455 case 3:
456 preString = "ivec3(";
457 break;
458 case 4:
459 preString = "ivec4(";
460 break;
461 default:
462 UNREACHABLE();
463 }
464 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000465
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700466 case EOpRadians:
467 preString = "radians(";
468 break;
469 case EOpDegrees:
470 preString = "degrees(";
471 break;
472 case EOpSin:
473 preString = "sin(";
474 break;
475 case EOpCos:
476 preString = "cos(";
477 break;
478 case EOpTan:
479 preString = "tan(";
480 break;
481 case EOpAsin:
482 preString = "asin(";
483 break;
484 case EOpAcos:
485 preString = "acos(";
486 break;
487 case EOpAtan:
488 preString = "atan(";
489 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000490
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700491 case EOpExp:
492 preString = "exp(";
493 break;
494 case EOpLog:
495 preString = "log(";
496 break;
497 case EOpExp2:
498 preString = "exp2(";
499 break;
500 case EOpLog2:
501 preString = "log2(";
502 break;
503 case EOpSqrt:
504 preString = "sqrt(";
505 break;
506 case EOpInverseSqrt:
507 preString = "inversesqrt(";
508 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000509
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700510 case EOpAbs:
511 preString = "abs(";
512 break;
513 case EOpSign:
514 preString = "sign(";
515 break;
516 case EOpFloor:
517 preString = "floor(";
518 break;
519 case EOpCeil:
520 preString = "ceil(";
521 break;
522 case EOpFract:
523 preString = "fract(";
524 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000525
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700526 case EOpLength:
527 preString = "length(";
528 break;
529 case EOpNormalize:
530 preString = "normalize(";
531 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000532
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700533 case EOpDFdx:
534 preString = "dFdx(";
535 break;
536 case EOpDFdy:
537 preString = "dFdy(";
538 break;
539 case EOpFwidth:
540 preString = "fwidth(";
541 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000542
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700543 case EOpAny:
544 preString = "any(";
545 break;
546 case EOpAll:
547 preString = "all(";
548 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000549
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700550 default:
551 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000552 }
553
zmo@google.com32e97312011-08-24 01:03:11 +0000554 if (visit == PreVisit && node->getUseEmulatedFunction())
555 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
556 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
557
zmo@google.com5601ea02011-06-10 18:23:25 +0000558 return true;
559}
560
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700561bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000562{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700563 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000564
565 if (node->usesTernaryOperator())
566 {
567 // Notice two brackets at the beginning and end. The outer ones
568 // encapsulate the whole ternary expression. This preserves the
569 // order of precedence when ternary expressions are used in a
570 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
571 out << "((";
572 node->getCondition()->traverse(this);
573 out << ") ? (";
574 node->getTrueBlock()->traverse(this);
575 out << ") : (";
576 node->getFalseBlock()->traverse(this);
577 out << "))";
578 }
579 else
580 {
581 out << "if (";
582 node->getCondition()->traverse(this);
583 out << ")\n";
584
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700585 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000586 visitCodeBlock(node->getTrueBlock());
587
588 if (node->getFalseBlock())
589 {
590 out << "else\n";
591 visitCodeBlock(node->getFalseBlock());
592 }
593 decrementDepth();
594 }
595 return false;
596}
597
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700598bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000599{
600 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700601 TInfoSinkBase &out = objSink();
zmo@google.comf420c422011-09-12 18:27:59 +0000602 TString preString;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700603 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000604 switch (node->getOp())
605 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700606 case EOpSequence:
607 // Scope the sequences except when at the global scope.
608 if (depth > 0)
609 {
610 out << "{\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000611 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000612
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700613 incrementDepth(node);
614 for (TIntermSequence::const_iterator iter = node->getSequence().begin();
615 iter != node->getSequence().end(); ++iter)
616 {
617 TIntermNode *node = *iter;
618 ASSERT(node != NULL);
619 node->traverse(this);
620
621 if (isSingleStatement(node))
622 out << ";\n";
623 }
624 decrementDepth();
625
626 // Scope the sequences except when at the global scope.
627 if (depth > 0)
628 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700629 out << "}\n";
630 }
631 visitChildren = false;
632 break;
633 case EOpPrototype:
634 // Function declaration.
635 ASSERT(visit == PreVisit);
636 writeVariableType(node->getType());
637 out << " " << hashName(node->getName());
638
639 out << "(";
640 writeFunctionParameters(node->getSequence());
641 out << ")";
642
643 visitChildren = false;
644 break;
645 case EOpFunction: {
646 // Function definition.
647 ASSERT(visit == PreVisit);
648 writeVariableType(node->getType());
649 out << " " << hashFunctionName(node->getName());
650
651 incrementDepth(node);
652 // Function definition node contains one or two children nodes
653 // representing function parameters and function body. The latter
654 // is not present in case of empty function bodies.
655 const TIntermSequence &sequence = node->getSequence();
656 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
657 TIntermSequence::const_iterator seqIter = sequence.begin();
658
659 // Traverse function parameters.
660 TIntermAggregate *params = (*seqIter)->getAsAggregate();
661 ASSERT(params != NULL);
662 ASSERT(params->getOp() == EOpParameters);
663 params->traverse(this);
664
665 // Traverse function body.
666 TIntermAggregate *body = ++seqIter != sequence.end() ?
667 (*seqIter)->getAsAggregate() : NULL;
668 visitCodeBlock(body);
669 decrementDepth();
670
671 // Fully processed; no need to visit children.
672 visitChildren = false;
673 break;
674 }
675 case EOpFunctionCall:
676 // Function call.
677 if (visit == PreVisit)
678 out << hashFunctionName(node->getName()) << "(";
679 else if (visit == InVisit)
680 out << ", ";
681 else
zmo@google.com5601ea02011-06-10 18:23:25 +0000682 out << ")";
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700683 break;
684 case EOpParameters:
685 // Function parameters.
686 ASSERT(visit == PreVisit);
687 out << "(";
688 writeFunctionParameters(node->getSequence());
689 out << ")";
690 visitChildren = false;
691 break;
692 case EOpDeclaration:
693 // Variable declaration.
694 if (visit == PreVisit)
695 {
696 const TIntermSequence &sequence = node->getSequence();
697 const TIntermTyped *variable = sequence.front()->getAsTyped();
698 writeVariableType(variable->getType());
699 out << " ";
700 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000701 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700702 else if (visit == InVisit)
703 {
704 out << ", ";
705 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000706 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700707 else
708 {
709 mDeclaringVariables = false;
710 }
711 break;
712 case EOpConstructFloat:
713 writeTriplet(visit, "float(", NULL, ")");
714 break;
715 case EOpConstructVec2:
716 writeBuiltInFunctionTriplet(visit, "vec2(", false);
717 break;
718 case EOpConstructVec3:
719 writeBuiltInFunctionTriplet(visit, "vec3(", false);
720 break;
721 case EOpConstructVec4:
722 writeBuiltInFunctionTriplet(visit, "vec4(", false);
723 break;
724 case EOpConstructBool:
725 writeTriplet(visit, "bool(", NULL, ")");
726 break;
727 case EOpConstructBVec2:
728 writeBuiltInFunctionTriplet(visit, "bvec2(", false);
729 break;
730 case EOpConstructBVec3:
731 writeBuiltInFunctionTriplet(visit, "bvec3(", false);
732 break;
733 case EOpConstructBVec4:
734 writeBuiltInFunctionTriplet(visit, "bvec4(", false);
735 break;
736 case EOpConstructInt:
737 writeTriplet(visit, "int(", NULL, ")");
738 break;
739 case EOpConstructIVec2:
740 writeBuiltInFunctionTriplet(visit, "ivec2(", false);
741 break;
742 case EOpConstructIVec3:
743 writeBuiltInFunctionTriplet(visit, "ivec3(", false);
744 break;
745 case EOpConstructIVec4:
746 writeBuiltInFunctionTriplet(visit, "ivec4(", false);
747 break;
748 case EOpConstructMat2:
749 writeBuiltInFunctionTriplet(visit, "mat2(", false);
750 break;
751 case EOpConstructMat3:
752 writeBuiltInFunctionTriplet(visit, "mat3(", false);
753 break;
754 case EOpConstructMat4:
755 writeBuiltInFunctionTriplet(visit, "mat4(", false);
756 break;
757 case EOpConstructStruct:
758 if (visit == PreVisit)
759 {
760 const TType &type = node->getType();
761 ASSERT(type.getBasicType() == EbtStruct);
762 out << hashName(type.getStruct()->name()) << "(";
763 }
764 else if (visit == InVisit)
765 {
766 out << ", ";
767 }
768 else
769 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000770 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000771 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700772 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000773
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700774 case EOpLessThan:
775 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
776 break;
777 case EOpGreaterThan:
778 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
779 break;
780 case EOpLessThanEqual:
781 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
782 break;
783 case EOpGreaterThanEqual:
784 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
785 break;
786 case EOpVectorEqual:
787 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
788 break;
789 case EOpVectorNotEqual:
790 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
791 break;
792 case EOpComma:
793 writeTriplet(visit, NULL, ", ", NULL);
794 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000795
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700796 case EOpMod:
797 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
798 break;
799 case EOpPow:
800 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
801 break;
802 case EOpAtan:
803 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
804 break;
805 case EOpMin:
806 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
807 break;
808 case EOpMax:
809 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
810 break;
811 case EOpClamp:
812 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
813 break;
814 case EOpMix:
815 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
816 break;
817 case EOpStep:
818 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
819 break;
820 case EOpSmoothStep:
821 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
822 break;
823 case EOpDistance:
824 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
825 break;
826 case EOpDot:
827 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
828 break;
829 case EOpCross:
830 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
831 break;
832 case EOpFaceForward:
833 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
834 break;
835 case EOpReflect:
836 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
837 break;
838 case EOpRefract:
839 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
840 break;
841 case EOpMul:
842 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
843 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000844
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700845 default:
846 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000847 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000848 return visitChildren;
849}
850
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700851bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000852{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700853 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000854
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700855 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000856 // Loop header.
857 TLoopType loopType = node->getType();
858 if (loopType == ELoopFor) // for loop
859 {
Zhenyao Mo550c6002014-02-26 15:40:48 -0800860 if (!node->getUnrollFlag())
861 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000862 out << "for (";
863 if (node->getInit())
864 node->getInit()->traverse(this);
865 out << "; ";
866
867 if (node->getCondition())
868 node->getCondition()->traverse(this);
869 out << "; ";
870
871 if (node->getExpression())
872 node->getExpression()->traverse(this);
873 out << ")\n";
874 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800875 else
876 {
877 // Need to put a one-iteration loop here to handle break.
878 TIntermSequence &declSeq =
879 node->getInit()->getAsAggregate()->getSequence();
880 TIntermSymbol *indexSymbol =
881 declSeq[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
882 TString name = hashVariableName(indexSymbol->getSymbol());
883 out << "for (int " << name << " = 0; "
884 << name << " < 1; "
885 << "++" << name << ")\n";
886 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000887 }
888 else if (loopType == ELoopWhile) // while loop
889 {
890 out << "while (";
891 ASSERT(node->getCondition() != NULL);
892 node->getCondition()->traverse(this);
893 out << ")\n";
894 }
895 else // do-while loop
896 {
897 ASSERT(loopType == ELoopDoWhile);
898 out << "do\n";
899 }
900
901 // Loop body.
902 if (node->getUnrollFlag())
903 {
Zhenyao Mo550c6002014-02-26 15:40:48 -0800904 out << "{\n";
905 mLoopUnrollStack.push(node);
906 while (mLoopUnrollStack.satisfiesLoopCondition())
zmo@google.com5601ea02011-06-10 18:23:25 +0000907 {
908 visitCodeBlock(node->getBody());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800909 mLoopUnrollStack.step();
zmo@google.com5601ea02011-06-10 18:23:25 +0000910 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800911 mLoopUnrollStack.pop();
912 out << "}\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000913 }
914 else
915 {
916 visitCodeBlock(node->getBody());
917 }
918
919 // Loop footer.
920 if (loopType == ELoopDoWhile) // do-while loop
921 {
922 out << "while (";
923 ASSERT(node->getCondition() != NULL);
924 node->getCondition()->traverse(this);
925 out << ");\n";
926 }
927 decrementDepth();
928
929 // No need to visit children. They have been already processed in
930 // this function.
931 return false;
932}
933
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700934bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000935{
936 switch (node->getFlowOp())
937 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700938 case EOpKill:
939 writeTriplet(visit, "discard", NULL, NULL);
940 break;
941 case EOpBreak:
942 writeTriplet(visit, "break", NULL, NULL);
943 break;
944 case EOpContinue:
945 writeTriplet(visit, "continue", NULL, NULL);
946 break;
947 case EOpReturn:
948 writeTriplet(visit, "return ", NULL, NULL);
949 break;
950 default:
951 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000952 }
953
954 return true;
955}
956
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700957void TOutputGLSLBase::visitCodeBlock(TIntermNode *node)
958{
zmo@google.com5601ea02011-06-10 18:23:25 +0000959 TInfoSinkBase &out = objSink();
960 if (node != NULL)
961 {
962 node->traverse(this);
963 // Single statements not part of a sequence need to be terminated
964 // with semi-colon.
965 if (isSingleStatement(node))
966 out << ";\n";
967 }
968 else
969 {
970 out << "{\n}\n"; // Empty code block.
971 }
972}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000973
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700974TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000975{
976 TInfoSinkBase out;
977 if (type.isMatrix())
978 {
979 out << "mat";
980 out << type.getNominalSize();
981 }
982 else if (type.isVector())
983 {
984 switch (type.getBasicType())
985 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700986 case EbtFloat:
987 out << "vec";
988 break;
989 case EbtInt:
990 out << "ivec";
991 break;
992 case EbtBool:
993 out << "bvec";
994 break;
995 default:
996 UNREACHABLE();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000997 }
998 out << type.getNominalSize();
999 }
1000 else
1001 {
1002 if (type.getBasicType() == EbtStruct)
Jamie Madill98493dd2013-07-08 14:39:03 -04001003 out << hashName(type.getStruct()->name());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001004 else
1005 out << type.getBasicString();
1006 }
1007 return TString(out.c_str());
1008}
1009
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001010TString TOutputGLSLBase::hashName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001011{
1012 if (mHashFunction == NULL || name.empty())
1013 return name;
1014 NameMap::const_iterator it = mNameMap.find(name.c_str());
1015 if (it != mNameMap.end())
1016 return it->second.c_str();
1017 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
1018 mNameMap[name.c_str()] = hashedName.c_str();
1019 return hashedName;
1020}
1021
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001022TString TOutputGLSLBase::hashVariableName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001023{
Jamie Madill02f20dd2013-09-12 12:07:42 -04001024 if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001025 return name;
1026 return hashName(name);
1027}
1028
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001029TString TOutputGLSLBase::hashFunctionName(const TString &mangled_name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001030{
1031 TString name = TFunction::unmangleName(mangled_name);
Jamie Madill02f20dd2013-09-12 12:07:42 -04001032 if (mSymbolTable.findBuiltIn(mangled_name, mShaderVersion) != NULL || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001033 return translateTextureFunction(name);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001034 return hashName(name);
1035}
Jamie Madill98493dd2013-07-08 14:39:03 -04001036
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001037bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001038{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001039 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001040 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001041 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001042 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001043 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001044
1045 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001046}
1047
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001048void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001049{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001050 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001051
1052 out << "struct " << hashName(structure->name()) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001053 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001054 for (size_t i = 0; i < fields.size(); ++i)
1055 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001056 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001057 if (writeVariablePrecision(field->type()->getPrecision()))
1058 out << " ";
1059 out << getTypeName(*field->type()) << " " << hashName(field->name());
1060 if (field->type()->isArray())
1061 out << arrayBrackets(*field->type());
1062 out << ";\n";
1063 }
1064 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001065}
Jamie Madill98493dd2013-07-08 14:39:03 -04001066