blob: e367a448766050c91f1b49d56c627869658b9052 [file] [log] [blame]
zmo@google.com5601ea02011-06-10 18:23:25 +00001//
Nicolas Capens16004fc2014-06-11 11:29:11 -04002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
zmo@google.com5601ea02011-06-10 18:23:25 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Geoff Lang17732822013-08-29 13:46:49 -04007#include "compiler/translator/OutputGLSLBase.h"
8#include "compiler/translator/compilerdebug.h"
zmo@google.com5601ea02011-06-10 18:23:25 +00009
daniel@transgaming.com773ff742013-01-11 04:12:51 +000010#include <cfloat>
daniel@transgaming.com6c1203f2013-01-11 04:12:43 +000011
zmo@google.com5601ea02011-06-10 18:23:25 +000012namespace
13{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070014TString arrayBrackets(const TType &type)
zmo@google.com5601ea02011-06-10 18:23:25 +000015{
16 ASSERT(type.isArray());
17 TInfoSinkBase out;
18 out << "[" << type.getArraySize() << "]";
19 return TString(out.c_str());
20}
21
Zhenyao Mo9eedea02014-05-12 16:02:35 -070022bool isSingleStatement(TIntermNode *node)
23{
24 if (const TIntermAggregate *aggregate = node->getAsAggregate())
zmo@google.com5601ea02011-06-10 18:23:25 +000025 {
26 return (aggregate->getOp() != EOpFunction) &&
27 (aggregate->getOp() != EOpSequence);
28 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -070029 else if (const TIntermSelection *selection = node->getAsSelectionNode())
zmo@google.com5601ea02011-06-10 18:23:25 +000030 {
31 // Ternary operators are usually part of an assignment operator.
32 // This handles those rare cases in which they are all by themselves.
33 return selection->usesTernaryOperator();
34 }
35 else if (node->getAsLoopNode())
36 {
37 return false;
38 }
39 return true;
40}
41} // namespace
42
Zhenyao Mo9eedea02014-05-12 16:02:35 -070043TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000044 ShArrayIndexClampingStrategy clampingStrategy,
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000045 ShHashFunction64 hashFunction,
Zhenyao Mo9eedea02014-05-12 16:02:35 -070046 NameMap &nameMap,
47 TSymbolTable &symbolTable,
Jamie Madill02f20dd2013-09-12 12:07:42 -040048 int shaderVersion)
zmo@google.com5601ea02011-06-10 18:23:25 +000049 : TIntermTraverser(true, true, true),
50 mObjSink(objSink),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000051 mDeclaringVariables(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000052 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000053 mHashFunction(hashFunction),
54 mNameMap(nameMap),
Jamie Madill02f20dd2013-09-12 12:07:42 -040055 mSymbolTable(symbolTable),
56 mShaderVersion(shaderVersion)
zmo@google.com5601ea02011-06-10 18:23:25 +000057{
58}
59
Zhenyao Mo9eedea02014-05-12 16:02:35 -070060void TOutputGLSLBase::writeTriplet(
61 Visit visit, const char *preStr, const char *inStr, const char *postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000062{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070063 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +000064 if (visit == PreVisit && preStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000065 out << preStr;
zmo@google.com5601ea02011-06-10 18:23:25 +000066 else if (visit == InVisit && inStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000067 out << inStr;
zmo@google.com5601ea02011-06-10 18:23:25 +000068 else if (visit == PostVisit && postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +000069 out << postStr;
zmo@google.com5601ea02011-06-10 18:23:25 +000070}
71
Zhenyao Mo9eedea02014-05-12 16:02:35 -070072void TOutputGLSLBase::writeBuiltInFunctionTriplet(
73 Visit visit, const char *preStr, bool useEmulatedFunction)
zmo@google.com5601ea02011-06-10 18:23:25 +000074{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070075 TString preString = useEmulatedFunction ?
76 BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
77 writeTriplet(visit, preString.c_str(), ", ", ")");
78}
79
80void TOutputGLSLBase::writeVariableType(const TType &type)
81{
82 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +000083 TQualifier qualifier = type.getQualifier();
Jamie Madill3b5c2da2014-08-19 15:23:32 -040084 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -040085 {
zmo@google.com5601ea02011-06-10 18:23:25 +000086 out << type.getQualifierString() << " ";
Jamie Madill1c28e1f2014-08-04 11:37:54 -040087 }
zmo@google.com5601ea02011-06-10 18:23:25 +000088 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -070089 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +000090 {
Jamie Madill01f85ac2014-06-06 11:55:04 -040091 TStructure *structure = type.getStruct();
92
93 declareStruct(structure);
94
95 if (!structure->name().empty())
96 {
97 mDeclaredStructs.insert(structure->uniqueId());
98 }
zmo@google.com5601ea02011-06-10 18:23:25 +000099 }
100 else
101 {
102 if (writeVariablePrecision(type.getPrecision()))
103 out << " ";
104 out << getTypeName(type);
105 }
106}
107
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700108void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000109{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700110 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000111 for (TIntermSequence::const_iterator iter = args.begin();
112 iter != args.end(); ++iter)
113 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700114 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000115 ASSERT(arg != NULL);
116
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700117 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000118 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000119
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700120 const TString &name = arg->getSymbol();
zmo@google.com5601ea02011-06-10 18:23:25 +0000121 if (!name.empty())
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000122 out << " " << hashName(name);
zmo@google.com5601ea02011-06-10 18:23:25 +0000123 if (type.isArray())
124 out << arrayBrackets(type);
125
126 // Put a comma if this is not the last argument.
127 if (iter != args.end() - 1)
128 out << ", ";
129 }
130}
131
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700132const ConstantUnion *TOutputGLSLBase::writeConstantUnion(
133 const TType &type, const ConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000134{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700135 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000136
137 if (type.getBasicType() == EbtStruct)
138 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700139 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -0400140 out << hashName(structure->name()) << "(";
141
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700142 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400143 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000144 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700145 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000146 ASSERT(fieldType != NULL);
147 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700148 if (i != fields.size() - 1)
149 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000150 }
151 out << ")";
152 }
153 else
154 {
Jamie Madill94bf7f22013-07-08 13:31:15 -0400155 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000156 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700157 if (writeType)
158 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400159 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000160 {
161 switch (pConstUnion->getType())
162 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700163 case EbtFloat:
164 out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
165 break;
166 case EbtInt:
167 out << pConstUnion->getIConst();
168 break;
169 case EbtBool:
170 out << pConstUnion->getBConst();
171 break;
172 default: UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000173 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700174 if (i != size - 1)
175 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000176 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700177 if (writeType)
178 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000179 }
180 return pConstUnion;
181}
182
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700183void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000184{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700185 TInfoSinkBase &out = objSink();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800186 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
187 out << mLoopUnrollStack.getLoopIndexValue(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000188 else
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000189 out << hashVariableName(node->getSymbol());
zmo@google.com5601ea02011-06-10 18:23:25 +0000190
191 if (mDeclaringVariables && node->getType().isArray())
192 out << arrayBrackets(node->getType());
193}
194
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700195void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000196{
197 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
198}
199
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700200bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000201{
202 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700203 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000204 switch (node->getOp())
205 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700206 case EOpInitialize:
207 if (visit == InVisit)
208 {
209 out << " = ";
210 // RHS of initialize is not being declared.
211 mDeclaringVariables = false;
212 }
213 break;
214 case EOpAssign:
215 writeTriplet(visit, "(", " = ", ")");
216 break;
217 case EOpAddAssign:
218 writeTriplet(visit, "(", " += ", ")");
219 break;
220 case EOpSubAssign:
221 writeTriplet(visit, "(", " -= ", ")");
222 break;
223 case EOpDivAssign:
224 writeTriplet(visit, "(", " /= ", ")");
225 break;
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000226 case EOpModAssign:
227 writeTriplet(visit, "(", " %= ", ")");
228 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700229 // Notice the fall-through.
230 case EOpMulAssign:
231 case EOpVectorTimesMatrixAssign:
232 case EOpVectorTimesScalarAssign:
233 case EOpMatrixTimesScalarAssign:
234 case EOpMatrixTimesMatrixAssign:
235 writeTriplet(visit, "(", " *= ", ")");
236 break;
237
238 case EOpIndexDirect:
239 writeTriplet(visit, NULL, "[", "]");
240 break;
241 case EOpIndexIndirect:
242 if (node->getAddIndexClamp())
243 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000244 if (visit == InVisit)
245 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700246 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
247 out << "[int(clamp(float(";
248 else
249 out << "[webgl_int_clamp(";
zmo@google.com5601ea02011-06-10 18:23:25 +0000250 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700251 else if (visit == PostVisit)
252 {
253 int maxSize;
254 TIntermTyped *left = node->getLeft();
255 TType leftType = left->getType();
zmo@google.com5601ea02011-06-10 18:23:25 +0000256
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700257 if (left->isArray())
258 {
259 // The shader will fail validation if the array length is not > 0.
260 maxSize = leftType.getArraySize() - 1;
261 }
262 else
263 {
264 maxSize = leftType.getNominalSize() - 1;
265 }
266
267 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
268 out << "), 0.0, float(" << maxSize << ")))]";
269 else
270 out << ", 0, " << maxSize << ")]";
271 }
272 }
273 else
274 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000275 writeTriplet(visit, NULL, "[", "]");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700276 }
277 break;
278 case EOpIndexDirectStruct:
279 if (visit == InVisit)
280 {
281 // Here we are writing out "foo.bar", where "foo" is struct
282 // and "bar" is field. In AST, it is represented as a binary
283 // node, where left child represents "foo" and right child "bar".
284 // The node itself represents ".". The struct field "bar" is
285 // actually stored as an index into TStructure::fields.
286 out << ".";
287 const TStructure *structure = node->getLeft()->getType().getStruct();
288 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
289 const TField *field = structure->fields()[index->getIConst(0)];
290
291 TString fieldName = field->name();
292 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
293 fieldName = hashName(fieldName);
294
295 out << fieldName;
296 visitChildren = false;
297 }
298 break;
299 case EOpVectorSwizzle:
300 if (visit == InVisit)
301 {
302 out << ".";
303 TIntermAggregate *rightChild = node->getRight()->getAsAggregate();
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700304 TIntermSequence *sequence = rightChild->getSequence();
305 for (TIntermSequence::iterator sit = sequence->begin(); sit != sequence->end(); ++sit)
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000306 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700307 TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
308 ASSERT(element->getBasicType() == EbtInt);
309 ASSERT(element->getNominalSize() == 1);
310 const ConstantUnion& data = element->getUnionArrayPointer()[0];
311 ASSERT(data.getType() == EbtInt);
312 switch (data.getIConst())
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000313 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700314 case 0:
315 out << "x";
316 break;
317 case 1:
318 out << "y";
319 break;
320 case 2:
321 out << "z";
322 break;
323 case 3:
324 out << "w";
325 break;
326 default:
327 UNREACHABLE();
daniel@transgaming.com4167cc92013-01-11 04:11:53 +0000328 }
329 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700330 visitChildren = false;
331 }
332 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000333
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700334 case EOpAdd:
335 writeTriplet(visit, "(", " + ", ")");
336 break;
337 case EOpSub:
338 writeTriplet(visit, "(", " - ", ")");
339 break;
340 case EOpMul:
341 writeTriplet(visit, "(", " * ", ")");
342 break;
343 case EOpDiv:
344 writeTriplet(visit, "(", " / ", ")");
345 break;
346 case EOpMod:
Gregoire Payen de La Garanderiebe954a22014-12-23 00:05:28 +0000347 writeTriplet(visit, "(", " % ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700348 break;
349 case EOpEqual:
350 writeTriplet(visit, "(", " == ", ")");
351 break;
352 case EOpNotEqual:
353 writeTriplet(visit, "(", " != ", ")");
354 break;
355 case EOpLessThan:
356 writeTriplet(visit, "(", " < ", ")");
357 break;
358 case EOpGreaterThan:
359 writeTriplet(visit, "(", " > ", ")");
360 break;
361 case EOpLessThanEqual:
362 writeTriplet(visit, "(", " <= ", ")");
363 break;
364 case EOpGreaterThanEqual:
365 writeTriplet(visit, "(", " >= ", ")");
366 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000367
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700368 // Notice the fall-through.
369 case EOpVectorTimesScalar:
370 case EOpVectorTimesMatrix:
371 case EOpMatrixTimesVector:
372 case EOpMatrixTimesScalar:
373 case EOpMatrixTimesMatrix:
374 writeTriplet(visit, "(", " * ", ")");
375 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000376
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700377 case EOpLogicalOr:
378 writeTriplet(visit, "(", " || ", ")");
379 break;
380 case EOpLogicalXor:
381 writeTriplet(visit, "(", " ^^ ", ")");
382 break;
383 case EOpLogicalAnd:
384 writeTriplet(visit, "(", " && ", ")");
385 break;
386 default:
387 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000388 }
389
390 return visitChildren;
391}
392
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700393bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000394{
zmo@google.com32e97312011-08-24 01:03:11 +0000395 TString preString;
396 TString postString = ")";
397
zmo@google.com5601ea02011-06-10 18:23:25 +0000398 switch (node->getOp())
399 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700400 case EOpNegative: preString = "(-"; break;
Zhenyao Mode1e00e2014-10-09 16:55:32 -0700401 case EOpPositive: preString = "(+"; break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700402 case EOpVectorLogicalNot: preString = "not("; break;
403 case EOpLogicalNot: preString = "(!"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000404
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700405 case EOpPostIncrement: preString = "("; postString = "++)"; break;
406 case EOpPostDecrement: preString = "("; postString = "--)"; break;
407 case EOpPreIncrement: preString = "(++"; break;
408 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000409
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700410 case EOpRadians:
411 preString = "radians(";
412 break;
413 case EOpDegrees:
414 preString = "degrees(";
415 break;
416 case EOpSin:
417 preString = "sin(";
418 break;
419 case EOpCos:
420 preString = "cos(";
421 break;
422 case EOpTan:
423 preString = "tan(";
424 break;
425 case EOpAsin:
426 preString = "asin(";
427 break;
428 case EOpAcos:
429 preString = "acos(";
430 break;
431 case EOpAtan:
432 preString = "atan(";
433 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000434
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200435 case EOpSinh:
436 preString = "sinh(";
437 break;
438 case EOpCosh:
439 preString = "cosh(";
440 break;
441 case EOpTanh:
442 preString = "tanh(";
443 break;
444 case EOpAsinh:
445 preString = "asinh(";
446 break;
447 case EOpAcosh:
448 preString = "acosh(";
449 break;
450 case EOpAtanh:
451 preString = "atanh(";
452 break;
453
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700454 case EOpExp:
455 preString = "exp(";
456 break;
457 case EOpLog:
458 preString = "log(";
459 break;
460 case EOpExp2:
461 preString = "exp2(";
462 break;
463 case EOpLog2:
464 preString = "log2(";
465 break;
466 case EOpSqrt:
467 preString = "sqrt(";
468 break;
469 case EOpInverseSqrt:
470 preString = "inversesqrt(";
471 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000472
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700473 case EOpAbs:
474 preString = "abs(";
475 break;
476 case EOpSign:
477 preString = "sign(";
478 break;
479 case EOpFloor:
480 preString = "floor(";
481 break;
482 case EOpCeil:
483 preString = "ceil(";
484 break;
485 case EOpFract:
486 preString = "fract(";
487 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000488
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200489 case EOpFloatBitsToInt:
490 preString = "floatBitsToInt(";
491 break;
492 case EOpFloatBitsToUint:
493 preString = "floatBitsToUint(";
494 break;
495 case EOpIntBitsToFloat:
496 preString = "intBitsToFloat(";
497 break;
498 case EOpUintBitsToFloat:
499 preString = "uintBitsToFloat(";
500 break;
501
Olli Etuaho7700ff62015-01-15 12:16:29 +0200502 case EOpPackSnorm2x16:
503 preString = "packSnorm2x16(";
504 break;
505 case EOpPackUnorm2x16:
506 preString = "packUnorm2x16(";
507 break;
508 case EOpPackHalf2x16:
509 preString = "packHalf2x16(";
510 break;
511 case EOpUnpackSnorm2x16:
512 preString = "unpackSnorm2x16(";
513 break;
514 case EOpUnpackUnorm2x16:
515 preString = "unpackUnorm2x16(";
516 break;
517 case EOpUnpackHalf2x16:
518 preString = "unpackHalf2x16(";
519 break;
520
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700521 case EOpLength:
522 preString = "length(";
523 break;
524 case EOpNormalize:
525 preString = "normalize(";
526 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000527
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700528 case EOpDFdx:
529 preString = "dFdx(";
530 break;
531 case EOpDFdy:
532 preString = "dFdy(";
533 break;
534 case EOpFwidth:
535 preString = "fwidth(";
536 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000537
Olli Etuahoe39706d2014-12-30 16:40:36 +0200538 case EOpTranspose:
539 preString = "transpose(";
540 break;
541 case EOpDeterminant:
542 preString = "determinant(";
543 break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +0200544 case EOpInverse:
545 preString = "inverse(";
546 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200547
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700548 case EOpAny:
549 preString = "any(";
550 break;
551 case EOpAll:
552 preString = "all(";
553 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000554
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700555 default:
556 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000557 }
558
zmo@google.com32e97312011-08-24 01:03:11 +0000559 if (visit == PreVisit && node->getUseEmulatedFunction())
560 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
561 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
562
zmo@google.com5601ea02011-06-10 18:23:25 +0000563 return true;
564}
565
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700566bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000567{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700568 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000569
570 if (node->usesTernaryOperator())
571 {
572 // Notice two brackets at the beginning and end. The outer ones
573 // encapsulate the whole ternary expression. This preserves the
574 // order of precedence when ternary expressions are used in a
575 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
576 out << "((";
577 node->getCondition()->traverse(this);
578 out << ") ? (";
579 node->getTrueBlock()->traverse(this);
580 out << ") : (";
581 node->getFalseBlock()->traverse(this);
582 out << "))";
583 }
584 else
585 {
586 out << "if (";
587 node->getCondition()->traverse(this);
588 out << ")\n";
589
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700590 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000591 visitCodeBlock(node->getTrueBlock());
592
593 if (node->getFalseBlock())
594 {
595 out << "else\n";
596 visitCodeBlock(node->getFalseBlock());
597 }
598 decrementDepth();
599 }
600 return false;
601}
602
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700603bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000604{
605 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700606 TInfoSinkBase &out = objSink();
zmo@google.comf420c422011-09-12 18:27:59 +0000607 TString preString;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700608 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000609 switch (node->getOp())
610 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700611 case EOpSequence:
612 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700613 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700614 {
615 out << "{\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000616 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000617
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700618 incrementDepth(node);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700619 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
620 iter != node->getSequence()->end(); ++iter)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700621 {
622 TIntermNode *node = *iter;
623 ASSERT(node != NULL);
624 node->traverse(this);
625
626 if (isSingleStatement(node))
627 out << ";\n";
628 }
629 decrementDepth();
630
631 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700632 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700633 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700634 out << "}\n";
635 }
636 visitChildren = false;
637 break;
638 case EOpPrototype:
639 // Function declaration.
640 ASSERT(visit == PreVisit);
641 writeVariableType(node->getType());
Olli Etuaho76acee82014-11-04 13:44:03 +0200642 out << " " << hashFunctionName(node->getName());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700643
644 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700645 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700646 out << ")";
647
648 visitChildren = false;
649 break;
650 case EOpFunction: {
651 // Function definition.
652 ASSERT(visit == PreVisit);
653 writeVariableType(node->getType());
654 out << " " << hashFunctionName(node->getName());
655
656 incrementDepth(node);
657 // Function definition node contains one or two children nodes
658 // representing function parameters and function body. The latter
659 // is not present in case of empty function bodies.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700660 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700661 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
662 TIntermSequence::const_iterator seqIter = sequence.begin();
663
664 // Traverse function parameters.
665 TIntermAggregate *params = (*seqIter)->getAsAggregate();
666 ASSERT(params != NULL);
667 ASSERT(params->getOp() == EOpParameters);
668 params->traverse(this);
669
670 // Traverse function body.
671 TIntermAggregate *body = ++seqIter != sequence.end() ?
672 (*seqIter)->getAsAggregate() : NULL;
673 visitCodeBlock(body);
674 decrementDepth();
675
676 // Fully processed; no need to visit children.
677 visitChildren = false;
678 break;
679 }
680 case EOpFunctionCall:
681 // Function call.
682 if (visit == PreVisit)
683 out << hashFunctionName(node->getName()) << "(";
684 else if (visit == InVisit)
685 out << ", ";
686 else
zmo@google.com5601ea02011-06-10 18:23:25 +0000687 out << ")";
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700688 break;
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200689 case EOpInternalFunctionCall:
690 // Function call to an internal helper function.
691 if (visit == PreVisit)
692 out << node->getName() << "(";
693 else if (visit == InVisit)
694 out << ", ";
695 else
696 out << ")";
697 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700698 case EOpParameters:
699 // Function parameters.
700 ASSERT(visit == PreVisit);
701 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700702 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700703 out << ")";
704 visitChildren = false;
705 break;
706 case EOpDeclaration:
707 // Variable declaration.
708 if (visit == PreVisit)
709 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700710 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700711 const TIntermTyped *variable = sequence.front()->getAsTyped();
712 writeVariableType(variable->getType());
713 out << " ";
714 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000715 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700716 else if (visit == InVisit)
717 {
718 out << ", ";
719 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000720 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700721 else
722 {
723 mDeclaringVariables = false;
724 }
725 break;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700726 case EOpInvariantDeclaration:
727 // Invariant declaration.
728 ASSERT(visit == PreVisit);
729 {
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400730 const TIntermSequence *sequence = node->getSequence();
731 ASSERT(sequence && sequence->size() == 1);
732 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
733 ASSERT(symbol);
Zhenyao Mo2a517272014-10-27 16:09:57 -0700734 out << "invariant " << hashVariableName(symbol->getSymbol());
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400735 }
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700736 visitChildren = false;
737 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700738 case EOpConstructFloat:
739 writeTriplet(visit, "float(", NULL, ")");
740 break;
741 case EOpConstructVec2:
742 writeBuiltInFunctionTriplet(visit, "vec2(", false);
743 break;
744 case EOpConstructVec3:
745 writeBuiltInFunctionTriplet(visit, "vec3(", false);
746 break;
747 case EOpConstructVec4:
748 writeBuiltInFunctionTriplet(visit, "vec4(", false);
749 break;
750 case EOpConstructBool:
751 writeTriplet(visit, "bool(", NULL, ")");
752 break;
753 case EOpConstructBVec2:
754 writeBuiltInFunctionTriplet(visit, "bvec2(", false);
755 break;
756 case EOpConstructBVec3:
757 writeBuiltInFunctionTriplet(visit, "bvec3(", false);
758 break;
759 case EOpConstructBVec4:
760 writeBuiltInFunctionTriplet(visit, "bvec4(", false);
761 break;
762 case EOpConstructInt:
763 writeTriplet(visit, "int(", NULL, ")");
764 break;
765 case EOpConstructIVec2:
766 writeBuiltInFunctionTriplet(visit, "ivec2(", false);
767 break;
768 case EOpConstructIVec3:
769 writeBuiltInFunctionTriplet(visit, "ivec3(", false);
770 break;
771 case EOpConstructIVec4:
772 writeBuiltInFunctionTriplet(visit, "ivec4(", false);
773 break;
774 case EOpConstructMat2:
775 writeBuiltInFunctionTriplet(visit, "mat2(", false);
776 break;
777 case EOpConstructMat3:
778 writeBuiltInFunctionTriplet(visit, "mat3(", false);
779 break;
780 case EOpConstructMat4:
781 writeBuiltInFunctionTriplet(visit, "mat4(", false);
782 break;
783 case EOpConstructStruct:
784 if (visit == PreVisit)
785 {
786 const TType &type = node->getType();
787 ASSERT(type.getBasicType() == EbtStruct);
788 out << hashName(type.getStruct()->name()) << "(";
789 }
790 else if (visit == InVisit)
791 {
792 out << ", ";
793 }
794 else
795 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000796 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000797 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700798 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000799
Olli Etuahoe39706d2014-12-30 16:40:36 +0200800 case EOpOuterProduct:
801 writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
802 break;
803
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700804 case EOpLessThan:
805 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
806 break;
807 case EOpGreaterThan:
808 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
809 break;
810 case EOpLessThanEqual:
811 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
812 break;
813 case EOpGreaterThanEqual:
814 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
815 break;
816 case EOpVectorEqual:
817 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
818 break;
819 case EOpVectorNotEqual:
820 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
821 break;
822 case EOpComma:
Zhenyao Mo0783efd2014-10-21 15:51:59 -0700823 writeTriplet(visit, "(", ", ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700824 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000825
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700826 case EOpMod:
827 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
828 break;
829 case EOpPow:
830 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
831 break;
832 case EOpAtan:
833 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
834 break;
835 case EOpMin:
836 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
837 break;
838 case EOpMax:
839 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
840 break;
841 case EOpClamp:
842 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
843 break;
844 case EOpMix:
845 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
846 break;
847 case EOpStep:
848 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
849 break;
850 case EOpSmoothStep:
851 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
852 break;
853 case EOpDistance:
854 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
855 break;
856 case EOpDot:
857 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
858 break;
859 case EOpCross:
860 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
861 break;
862 case EOpFaceForward:
863 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
864 break;
865 case EOpReflect:
866 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
867 break;
868 case EOpRefract:
869 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
870 break;
871 case EOpMul:
872 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
873 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000874
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700875 default:
876 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000877 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000878 return visitChildren;
879}
880
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700881bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000882{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700883 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000884
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700885 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000886 // Loop header.
887 TLoopType loopType = node->getType();
888 if (loopType == ELoopFor) // for loop
889 {
Zhenyao Mo550c6002014-02-26 15:40:48 -0800890 if (!node->getUnrollFlag())
891 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000892 out << "for (";
893 if (node->getInit())
894 node->getInit()->traverse(this);
895 out << "; ";
896
897 if (node->getCondition())
898 node->getCondition()->traverse(this);
899 out << "; ";
900
901 if (node->getExpression())
902 node->getExpression()->traverse(this);
903 out << ")\n";
904 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800905 else
906 {
907 // Need to put a one-iteration loop here to handle break.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700908 TIntermSequence *declSeq =
Zhenyao Mo550c6002014-02-26 15:40:48 -0800909 node->getInit()->getAsAggregate()->getSequence();
910 TIntermSymbol *indexSymbol =
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700911 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800912 TString name = hashVariableName(indexSymbol->getSymbol());
913 out << "for (int " << name << " = 0; "
914 << name << " < 1; "
915 << "++" << name << ")\n";
916 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000917 }
918 else if (loopType == ELoopWhile) // while loop
919 {
920 out << "while (";
921 ASSERT(node->getCondition() != NULL);
922 node->getCondition()->traverse(this);
923 out << ")\n";
924 }
925 else // do-while loop
926 {
927 ASSERT(loopType == ELoopDoWhile);
928 out << "do\n";
929 }
930
931 // Loop body.
932 if (node->getUnrollFlag())
933 {
Zhenyao Mo550c6002014-02-26 15:40:48 -0800934 out << "{\n";
935 mLoopUnrollStack.push(node);
936 while (mLoopUnrollStack.satisfiesLoopCondition())
zmo@google.com5601ea02011-06-10 18:23:25 +0000937 {
938 visitCodeBlock(node->getBody());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800939 mLoopUnrollStack.step();
zmo@google.com5601ea02011-06-10 18:23:25 +0000940 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800941 mLoopUnrollStack.pop();
942 out << "}\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000943 }
944 else
945 {
946 visitCodeBlock(node->getBody());
947 }
948
949 // Loop footer.
950 if (loopType == ELoopDoWhile) // do-while loop
951 {
952 out << "while (";
953 ASSERT(node->getCondition() != NULL);
954 node->getCondition()->traverse(this);
955 out << ");\n";
956 }
957 decrementDepth();
958
959 // No need to visit children. They have been already processed in
960 // this function.
961 return false;
962}
963
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700964bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000965{
966 switch (node->getFlowOp())
967 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700968 case EOpKill:
969 writeTriplet(visit, "discard", NULL, NULL);
970 break;
971 case EOpBreak:
972 writeTriplet(visit, "break", NULL, NULL);
973 break;
974 case EOpContinue:
975 writeTriplet(visit, "continue", NULL, NULL);
976 break;
977 case EOpReturn:
978 writeTriplet(visit, "return ", NULL, NULL);
979 break;
980 default:
981 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000982 }
983
984 return true;
985}
986
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700987void TOutputGLSLBase::visitCodeBlock(TIntermNode *node)
988{
zmo@google.com5601ea02011-06-10 18:23:25 +0000989 TInfoSinkBase &out = objSink();
990 if (node != NULL)
991 {
992 node->traverse(this);
993 // Single statements not part of a sequence need to be terminated
994 // with semi-colon.
995 if (isSingleStatement(node))
996 out << ";\n";
997 }
998 else
999 {
1000 out << "{\n}\n"; // Empty code block.
1001 }
1002}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001003
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001004TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001005{
1006 TInfoSinkBase out;
1007 if (type.isMatrix())
1008 {
1009 out << "mat";
1010 out << type.getNominalSize();
1011 }
1012 else if (type.isVector())
1013 {
1014 switch (type.getBasicType())
1015 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001016 case EbtFloat:
1017 out << "vec";
1018 break;
1019 case EbtInt:
1020 out << "ivec";
1021 break;
1022 case EbtBool:
1023 out << "bvec";
1024 break;
1025 default:
1026 UNREACHABLE();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001027 }
1028 out << type.getNominalSize();
1029 }
1030 else
1031 {
1032 if (type.getBasicType() == EbtStruct)
Jamie Madill98493dd2013-07-08 14:39:03 -04001033 out << hashName(type.getStruct()->name());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001034 else
1035 out << type.getBasicString();
1036 }
1037 return TString(out.c_str());
1038}
1039
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001040TString TOutputGLSLBase::hashName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001041{
1042 if (mHashFunction == NULL || name.empty())
1043 return name;
1044 NameMap::const_iterator it = mNameMap.find(name.c_str());
1045 if (it != mNameMap.end())
1046 return it->second.c_str();
1047 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
1048 mNameMap[name.c_str()] = hashedName.c_str();
1049 return hashedName;
1050}
1051
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001052TString TOutputGLSLBase::hashVariableName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001053{
Jamie Madill02f20dd2013-09-12 12:07:42 -04001054 if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001055 return name;
1056 return hashName(name);
1057}
1058
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001059TString TOutputGLSLBase::hashFunctionName(const TString &mangled_name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001060{
1061 TString name = TFunction::unmangleName(mangled_name);
Jamie Madill02f20dd2013-09-12 12:07:42 -04001062 if (mSymbolTable.findBuiltIn(mangled_name, mShaderVersion) != NULL || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001063 return translateTextureFunction(name);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001064 return hashName(name);
1065}
Jamie Madill98493dd2013-07-08 14:39:03 -04001066
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001067bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001068{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001069 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001070 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001071 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001072 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001073 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001074
1075 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001076}
1077
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001078void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001079{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001080 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001081
1082 out << "struct " << hashName(structure->name()) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001083 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001084 for (size_t i = 0; i < fields.size(); ++i)
1085 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001086 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001087 if (writeVariablePrecision(field->type()->getPrecision()))
1088 out << " ";
1089 out << getTypeName(*field->type()) << " " << hashName(field->name());
1090 if (field->type()->isArray())
1091 out << arrayBrackets(*field->type());
1092 out << ";\n";
1093 }
1094 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001095}
Jamie Madill98493dd2013-07-08 14:39:03 -04001096