blob: e5743d2190834611ab8dfb92bf385e9f2b02d3c6 [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
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700502 case EOpLength:
503 preString = "length(";
504 break;
505 case EOpNormalize:
506 preString = "normalize(";
507 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000508
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700509 case EOpDFdx:
510 preString = "dFdx(";
511 break;
512 case EOpDFdy:
513 preString = "dFdy(";
514 break;
515 case EOpFwidth:
516 preString = "fwidth(";
517 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000518
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700519 case EOpAny:
520 preString = "any(";
521 break;
522 case EOpAll:
523 preString = "all(";
524 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000525
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700526 default:
527 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000528 }
529
zmo@google.com32e97312011-08-24 01:03:11 +0000530 if (visit == PreVisit && node->getUseEmulatedFunction())
531 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
532 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
533
zmo@google.com5601ea02011-06-10 18:23:25 +0000534 return true;
535}
536
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700537bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000538{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700539 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000540
541 if (node->usesTernaryOperator())
542 {
543 // Notice two brackets at the beginning and end. The outer ones
544 // encapsulate the whole ternary expression. This preserves the
545 // order of precedence when ternary expressions are used in a
546 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
547 out << "((";
548 node->getCondition()->traverse(this);
549 out << ") ? (";
550 node->getTrueBlock()->traverse(this);
551 out << ") : (";
552 node->getFalseBlock()->traverse(this);
553 out << "))";
554 }
555 else
556 {
557 out << "if (";
558 node->getCondition()->traverse(this);
559 out << ")\n";
560
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700561 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000562 visitCodeBlock(node->getTrueBlock());
563
564 if (node->getFalseBlock())
565 {
566 out << "else\n";
567 visitCodeBlock(node->getFalseBlock());
568 }
569 decrementDepth();
570 }
571 return false;
572}
573
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700574bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000575{
576 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700577 TInfoSinkBase &out = objSink();
zmo@google.comf420c422011-09-12 18:27:59 +0000578 TString preString;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700579 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000580 switch (node->getOp())
581 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700582 case EOpSequence:
583 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700584 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700585 {
586 out << "{\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000587 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000588
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700589 incrementDepth(node);
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700590 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
591 iter != node->getSequence()->end(); ++iter)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700592 {
593 TIntermNode *node = *iter;
594 ASSERT(node != NULL);
595 node->traverse(this);
596
597 if (isSingleStatement(node))
598 out << ";\n";
599 }
600 decrementDepth();
601
602 // Scope the sequences except when at the global scope.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700603 if (mDepth > 0)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700604 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700605 out << "}\n";
606 }
607 visitChildren = false;
608 break;
609 case EOpPrototype:
610 // Function declaration.
611 ASSERT(visit == PreVisit);
612 writeVariableType(node->getType());
Olli Etuaho76acee82014-11-04 13:44:03 +0200613 out << " " << hashFunctionName(node->getName());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700614
615 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700616 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700617 out << ")";
618
619 visitChildren = false;
620 break;
621 case EOpFunction: {
622 // Function definition.
623 ASSERT(visit == PreVisit);
624 writeVariableType(node->getType());
625 out << " " << hashFunctionName(node->getName());
626
627 incrementDepth(node);
628 // Function definition node contains one or two children nodes
629 // representing function parameters and function body. The latter
630 // is not present in case of empty function bodies.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700631 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700632 ASSERT((sequence.size() == 1) || (sequence.size() == 2));
633 TIntermSequence::const_iterator seqIter = sequence.begin();
634
635 // Traverse function parameters.
636 TIntermAggregate *params = (*seqIter)->getAsAggregate();
637 ASSERT(params != NULL);
638 ASSERT(params->getOp() == EOpParameters);
639 params->traverse(this);
640
641 // Traverse function body.
642 TIntermAggregate *body = ++seqIter != sequence.end() ?
643 (*seqIter)->getAsAggregate() : NULL;
644 visitCodeBlock(body);
645 decrementDepth();
646
647 // Fully processed; no need to visit children.
648 visitChildren = false;
649 break;
650 }
651 case EOpFunctionCall:
652 // Function call.
653 if (visit == PreVisit)
654 out << hashFunctionName(node->getName()) << "(";
655 else if (visit == InVisit)
656 out << ", ";
657 else
zmo@google.com5601ea02011-06-10 18:23:25 +0000658 out << ")";
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700659 break;
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200660 case EOpInternalFunctionCall:
661 // Function call to an internal helper function.
662 if (visit == PreVisit)
663 out << node->getName() << "(";
664 else if (visit == InVisit)
665 out << ", ";
666 else
667 out << ")";
668 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700669 case EOpParameters:
670 // Function parameters.
671 ASSERT(visit == PreVisit);
672 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700673 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700674 out << ")";
675 visitChildren = false;
676 break;
677 case EOpDeclaration:
678 // Variable declaration.
679 if (visit == PreVisit)
680 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700681 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700682 const TIntermTyped *variable = sequence.front()->getAsTyped();
683 writeVariableType(variable->getType());
684 out << " ";
685 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000686 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700687 else if (visit == InVisit)
688 {
689 out << ", ";
690 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000691 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700692 else
693 {
694 mDeclaringVariables = false;
695 }
696 break;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700697 case EOpInvariantDeclaration:
698 // Invariant declaration.
699 ASSERT(visit == PreVisit);
700 {
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400701 const TIntermSequence *sequence = node->getSequence();
702 ASSERT(sequence && sequence->size() == 1);
703 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
704 ASSERT(symbol);
Zhenyao Mo2a517272014-10-27 16:09:57 -0700705 out << "invariant " << hashVariableName(symbol->getSymbol());
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400706 }
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700707 visitChildren = false;
708 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700709 case EOpConstructFloat:
710 writeTriplet(visit, "float(", NULL, ")");
711 break;
712 case EOpConstructVec2:
713 writeBuiltInFunctionTriplet(visit, "vec2(", false);
714 break;
715 case EOpConstructVec3:
716 writeBuiltInFunctionTriplet(visit, "vec3(", false);
717 break;
718 case EOpConstructVec4:
719 writeBuiltInFunctionTriplet(visit, "vec4(", false);
720 break;
721 case EOpConstructBool:
722 writeTriplet(visit, "bool(", NULL, ")");
723 break;
724 case EOpConstructBVec2:
725 writeBuiltInFunctionTriplet(visit, "bvec2(", false);
726 break;
727 case EOpConstructBVec3:
728 writeBuiltInFunctionTriplet(visit, "bvec3(", false);
729 break;
730 case EOpConstructBVec4:
731 writeBuiltInFunctionTriplet(visit, "bvec4(", false);
732 break;
733 case EOpConstructInt:
734 writeTriplet(visit, "int(", NULL, ")");
735 break;
736 case EOpConstructIVec2:
737 writeBuiltInFunctionTriplet(visit, "ivec2(", false);
738 break;
739 case EOpConstructIVec3:
740 writeBuiltInFunctionTriplet(visit, "ivec3(", false);
741 break;
742 case EOpConstructIVec4:
743 writeBuiltInFunctionTriplet(visit, "ivec4(", false);
744 break;
745 case EOpConstructMat2:
746 writeBuiltInFunctionTriplet(visit, "mat2(", false);
747 break;
748 case EOpConstructMat3:
749 writeBuiltInFunctionTriplet(visit, "mat3(", false);
750 break;
751 case EOpConstructMat4:
752 writeBuiltInFunctionTriplet(visit, "mat4(", false);
753 break;
754 case EOpConstructStruct:
755 if (visit == PreVisit)
756 {
757 const TType &type = node->getType();
758 ASSERT(type.getBasicType() == EbtStruct);
759 out << hashName(type.getStruct()->name()) << "(";
760 }
761 else if (visit == InVisit)
762 {
763 out << ", ";
764 }
765 else
766 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000767 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000768 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700769 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000770
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700771 case EOpLessThan:
772 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
773 break;
774 case EOpGreaterThan:
775 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
776 break;
777 case EOpLessThanEqual:
778 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
779 break;
780 case EOpGreaterThanEqual:
781 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
782 break;
783 case EOpVectorEqual:
784 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
785 break;
786 case EOpVectorNotEqual:
787 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
788 break;
789 case EOpComma:
Zhenyao Mo0783efd2014-10-21 15:51:59 -0700790 writeTriplet(visit, "(", ", ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700791 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000792
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700793 case EOpMod:
794 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
795 break;
796 case EOpPow:
797 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
798 break;
799 case EOpAtan:
800 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
801 break;
802 case EOpMin:
803 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
804 break;
805 case EOpMax:
806 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
807 break;
808 case EOpClamp:
809 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
810 break;
811 case EOpMix:
812 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
813 break;
814 case EOpStep:
815 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
816 break;
817 case EOpSmoothStep:
818 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
819 break;
820 case EOpDistance:
821 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
822 break;
823 case EOpDot:
824 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
825 break;
826 case EOpCross:
827 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
828 break;
829 case EOpFaceForward:
830 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
831 break;
832 case EOpReflect:
833 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
834 break;
835 case EOpRefract:
836 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
837 break;
838 case EOpMul:
839 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
840 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000841
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700842 default:
843 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000844 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000845 return visitChildren;
846}
847
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700848bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000849{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700850 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000851
Zhenyao Mo7cab38b2013-10-15 12:59:30 -0700852 incrementDepth(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000853 // Loop header.
854 TLoopType loopType = node->getType();
855 if (loopType == ELoopFor) // for loop
856 {
Zhenyao Mo550c6002014-02-26 15:40:48 -0800857 if (!node->getUnrollFlag())
858 {
zmo@google.com5601ea02011-06-10 18:23:25 +0000859 out << "for (";
860 if (node->getInit())
861 node->getInit()->traverse(this);
862 out << "; ";
863
864 if (node->getCondition())
865 node->getCondition()->traverse(this);
866 out << "; ";
867
868 if (node->getExpression())
869 node->getExpression()->traverse(this);
870 out << ")\n";
871 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800872 else
873 {
874 // Need to put a one-iteration loop here to handle break.
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700875 TIntermSequence *declSeq =
Zhenyao Mo550c6002014-02-26 15:40:48 -0800876 node->getInit()->getAsAggregate()->getSequence();
877 TIntermSymbol *indexSymbol =
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700878 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800879 TString name = hashVariableName(indexSymbol->getSymbol());
880 out << "for (int " << name << " = 0; "
881 << name << " < 1; "
882 << "++" << name << ")\n";
883 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000884 }
885 else if (loopType == ELoopWhile) // while loop
886 {
887 out << "while (";
888 ASSERT(node->getCondition() != NULL);
889 node->getCondition()->traverse(this);
890 out << ")\n";
891 }
892 else // do-while loop
893 {
894 ASSERT(loopType == ELoopDoWhile);
895 out << "do\n";
896 }
897
898 // Loop body.
899 if (node->getUnrollFlag())
900 {
Zhenyao Mo550c6002014-02-26 15:40:48 -0800901 out << "{\n";
902 mLoopUnrollStack.push(node);
903 while (mLoopUnrollStack.satisfiesLoopCondition())
zmo@google.com5601ea02011-06-10 18:23:25 +0000904 {
905 visitCodeBlock(node->getBody());
Zhenyao Mo550c6002014-02-26 15:40:48 -0800906 mLoopUnrollStack.step();
zmo@google.com5601ea02011-06-10 18:23:25 +0000907 }
Zhenyao Mo550c6002014-02-26 15:40:48 -0800908 mLoopUnrollStack.pop();
909 out << "}\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000910 }
911 else
912 {
913 visitCodeBlock(node->getBody());
914 }
915
916 // Loop footer.
917 if (loopType == ELoopDoWhile) // do-while loop
918 {
919 out << "while (";
920 ASSERT(node->getCondition() != NULL);
921 node->getCondition()->traverse(this);
922 out << ");\n";
923 }
924 decrementDepth();
925
926 // No need to visit children. They have been already processed in
927 // this function.
928 return false;
929}
930
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700931bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000932{
933 switch (node->getFlowOp())
934 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700935 case EOpKill:
936 writeTriplet(visit, "discard", NULL, NULL);
937 break;
938 case EOpBreak:
939 writeTriplet(visit, "break", NULL, NULL);
940 break;
941 case EOpContinue:
942 writeTriplet(visit, "continue", NULL, NULL);
943 break;
944 case EOpReturn:
945 writeTriplet(visit, "return ", NULL, NULL);
946 break;
947 default:
948 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000949 }
950
951 return true;
952}
953
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700954void TOutputGLSLBase::visitCodeBlock(TIntermNode *node)
955{
zmo@google.com5601ea02011-06-10 18:23:25 +0000956 TInfoSinkBase &out = objSink();
957 if (node != NULL)
958 {
959 node->traverse(this);
960 // Single statements not part of a sequence need to be terminated
961 // with semi-colon.
962 if (isSingleStatement(node))
963 out << ";\n";
964 }
965 else
966 {
967 out << "{\n}\n"; // Empty code block.
968 }
969}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000970
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700971TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000972{
973 TInfoSinkBase out;
974 if (type.isMatrix())
975 {
976 out << "mat";
977 out << type.getNominalSize();
978 }
979 else if (type.isVector())
980 {
981 switch (type.getBasicType())
982 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700983 case EbtFloat:
984 out << "vec";
985 break;
986 case EbtInt:
987 out << "ivec";
988 break;
989 case EbtBool:
990 out << "bvec";
991 break;
992 default:
993 UNREACHABLE();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000994 }
995 out << type.getNominalSize();
996 }
997 else
998 {
999 if (type.getBasicType() == EbtStruct)
Jamie Madill98493dd2013-07-08 14:39:03 -04001000 out << hashName(type.getStruct()->name());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001001 else
1002 out << type.getBasicString();
1003 }
1004 return TString(out.c_str());
1005}
1006
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001007TString TOutputGLSLBase::hashName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001008{
1009 if (mHashFunction == NULL || name.empty())
1010 return name;
1011 NameMap::const_iterator it = mNameMap.find(name.c_str());
1012 if (it != mNameMap.end())
1013 return it->second.c_str();
1014 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
1015 mNameMap[name.c_str()] = hashedName.c_str();
1016 return hashedName;
1017}
1018
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001019TString TOutputGLSLBase::hashVariableName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001020{
Jamie Madill02f20dd2013-09-12 12:07:42 -04001021 if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001022 return name;
1023 return hashName(name);
1024}
1025
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001026TString TOutputGLSLBase::hashFunctionName(const TString &mangled_name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001027{
1028 TString name = TFunction::unmangleName(mangled_name);
Jamie Madill02f20dd2013-09-12 12:07:42 -04001029 if (mSymbolTable.findBuiltIn(mangled_name, mShaderVersion) != NULL || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001030 return translateTextureFunction(name);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001031 return hashName(name);
1032}
Jamie Madill98493dd2013-07-08 14:39:03 -04001033
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001034bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001035{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001036 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001037 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001038 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001039 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001040 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001041
1042 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001043}
1044
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001045void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001046{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001047 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001048
1049 out << "struct " << hashName(structure->name()) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001050 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001051 for (size_t i = 0; i < fields.size(); ++i)
1052 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001053 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001054 if (writeVariablePrecision(field->type()->getPrecision()))
1055 out << " ";
1056 out << getTypeName(*field->type()) << " " << hashName(field->name());
1057 if (field->type()->isArray())
1058 out << arrayBrackets(*field->type());
1059 out << ";\n";
1060 }
1061 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001062}
Jamie Madill98493dd2013-07-08 14:39:03 -04001063