blob: 66d40ecaae30a20ac7fe995c43f21dcf77bee6fb [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"
Olli Etuahod57e0db2015-04-24 15:05:08 +03008
9#include "common/debug.h"
zmo@google.com5601ea02011-06-10 18:23:25 +000010
daniel@transgaming.com773ff742013-01-11 04:12:51 +000011#include <cfloat>
daniel@transgaming.com6c1203f2013-01-11 04:12:43 +000012
zmo@google.com5601ea02011-06-10 18:23:25 +000013namespace
14{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070015TString arrayBrackets(const TType &type)
zmo@google.com5601ea02011-06-10 18:23:25 +000016{
17 ASSERT(type.isArray());
18 TInfoSinkBase out;
19 out << "[" << type.getArraySize() << "]";
20 return TString(out.c_str());
21}
22
Zhenyao Mo9eedea02014-05-12 16:02:35 -070023bool isSingleStatement(TIntermNode *node)
24{
Olli Etuaho336b1472016-10-05 16:37:55 +010025 if (node->getAsFunctionDefinition())
zmo@google.com5601ea02011-06-10 18:23:25 +000026 {
Olli Etuaho336b1472016-10-05 16:37:55 +010027 return false;
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010028 }
29 else if (node->getAsBlock())
30 {
31 return false;
zmo@google.com5601ea02011-06-10 18:23:25 +000032 }
Olli Etuaho57961272016-09-14 13:57:46 +030033 else if (node->getAsIfElseNode())
zmo@google.com5601ea02011-06-10 18:23:25 +000034 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +030035 return false;
zmo@google.com5601ea02011-06-10 18:23:25 +000036 }
37 else if (node->getAsLoopNode())
38 {
39 return false;
40 }
Olli Etuaho01cd8af2015-02-20 10:39:20 +020041 else if (node->getAsSwitchNode())
42 {
43 return false;
44 }
45 else if (node->getAsCaseNode())
46 {
47 return false;
48 }
zmo@google.com5601ea02011-06-10 18:23:25 +000049 return true;
50}
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080051
Martin Radev2cc85b32016-08-05 16:22:53 +030052// If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
53// variables with specified layout qualifiers are copied. Additional checks are needed against the
54// type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
55// TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
56// NeedsToWriteLayoutQualifier.
57bool NeedsToWriteLayoutQualifier(const TType &type)
58{
59 if (type.getBasicType() == EbtInterfaceBlock)
60 {
61 return false;
62 }
63
64 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
65
66 if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn) &&
67 layoutQualifier.location >= 0)
68 {
69 return true;
70 }
71 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
72 {
73 return true;
74 }
75 return false;
76}
77
zmo@google.com5601ea02011-06-10 18:23:25 +000078} // namespace
79
Zhenyao Mo9eedea02014-05-12 16:02:35 -070080TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000081 ShArrayIndexClampingStrategy clampingStrategy,
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000082 ShHashFunction64 hashFunction,
Zhenyao Mo9eedea02014-05-12 16:02:35 -070083 NameMap &nameMap,
84 TSymbolTable &symbolTable,
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080085 int shaderVersion,
Qiankun Miao705a9192016-08-29 10:05:27 +080086 ShShaderOutput output,
87 ShCompileOptions compileOptions)
zmo@google.com5601ea02011-06-10 18:23:25 +000088 : TIntermTraverser(true, true, true),
89 mObjSink(objSink),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000090 mDeclaringVariables(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000091 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000092 mHashFunction(hashFunction),
93 mNameMap(nameMap),
Jamie Madill02f20dd2013-09-12 12:07:42 -040094 mSymbolTable(symbolTable),
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080095 mShaderVersion(shaderVersion),
Qiankun Miao705a9192016-08-29 10:05:27 +080096 mOutput(output),
97 mCompileOptions(compileOptions)
zmo@google.com5601ea02011-06-10 18:23:25 +000098{
99}
100
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700101void TOutputGLSLBase::writeTriplet(
102 Visit visit, const char *preStr, const char *inStr, const char *postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000103{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700104 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000105 if (visit == PreVisit && preStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000106 out << preStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000107 else if (visit == InVisit && inStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000108 out << inStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000109 else if (visit == PostVisit && postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000110 out << postStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000111}
112
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700113void TOutputGLSLBase::writeBuiltInFunctionTriplet(
114 Visit visit, const char *preStr, bool useEmulatedFunction)
zmo@google.com5601ea02011-06-10 18:23:25 +0000115{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700116 TString preString = useEmulatedFunction ?
117 BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
118 writeTriplet(visit, preString.c_str(), ", ", ")");
119}
120
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300121void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
122{
Martin Radev2cc85b32016-08-05 16:22:53 +0300123 if (!NeedsToWriteLayoutQualifier(type))
124 {
125 return;
126 }
127
128 TInfoSinkBase &out = objSink();
129 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
130 out << "layout(";
131
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300132 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
133 {
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300134 if (layoutQualifier.location >= 0)
135 {
Martin Radev2cc85b32016-08-05 16:22:53 +0300136 out << "location = " << layoutQualifier.location;
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300137 }
138 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300139
140 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
141 {
142 ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
143 out << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
144 }
145
146 out << ") ";
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300147}
148
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700149void TOutputGLSLBase::writeVariableType(const TType &type)
150{
Qiankun Miao705a9192016-08-29 10:05:27 +0800151 TQualifier qualifier = type.getQualifier();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700152 TInfoSinkBase &out = objSink();
Qiankun Miao705a9192016-08-29 10:05:27 +0800153 bool removeInvariant = (qualifier == EvqVaryingIn && IsGLSL420OrNewer(mOutput) &&
154 !(mCompileOptions & SH_DONT_REMOVE_INVARIANT_FOR_FRAGMENT_INPUT));
155 if (type.isInvariant() && !removeInvariant)
Olli Etuaho214c2d82015-04-27 14:49:13 +0300156 {
157 out << "invariant ";
158 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400159 if (type.getBasicType() == EbtInterfaceBlock)
160 {
161 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
162 declareInterfaceBlockLayout(interfaceBlock);
163 }
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400164 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400165 {
Qingqing Dengad0d0792015-04-08 14:25:06 -0700166 if (IsGLSL130OrNewer(mOutput))
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800167 {
168 switch (qualifier)
169 {
170 case EvqAttribute:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300171 out << "in ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800172 break;
173 case EvqVaryingIn:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300174 out << "in ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800175 break;
176 case EvqVaryingOut:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300177 out << "out ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800178 break;
179 default:
180 out << type.getQualifierString() << " ";
181 break;
182 }
183 }
184 else
185 {
186 out << type.getQualifierString() << " ";
187 }
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400188 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300189
190 const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
191 if (memoryQualifier.readonly)
192 {
193 ASSERT(IsImage(type.getBasicType()));
194 out << "readonly ";
195 }
196
197 if (memoryQualifier.writeonly)
198 {
199 ASSERT(IsImage(type.getBasicType()));
200 out << "writeonly ";
201 }
202
zmo@google.com5601ea02011-06-10 18:23:25 +0000203 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700204 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000205 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400206 TStructure *structure = type.getStruct();
207
208 declareStruct(structure);
209
210 if (!structure->name().empty())
211 {
212 mDeclaredStructs.insert(structure->uniqueId());
213 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000214 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400215 else if (type.getBasicType() == EbtInterfaceBlock)
216 {
217 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
218 declareInterfaceBlock(interfaceBlock);
219 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000220 else
221 {
222 if (writeVariablePrecision(type.getPrecision()))
223 out << " ";
224 out << getTypeName(type);
225 }
226}
227
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700228void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000229{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700230 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000231 for (TIntermSequence::const_iterator iter = args.begin();
232 iter != args.end(); ++iter)
233 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700234 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000235 ASSERT(arg != NULL);
236
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700237 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000238 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000239
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700240 const TString &name = arg->getSymbol();
zmo@google.com5601ea02011-06-10 18:23:25 +0000241 if (!name.empty())
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000242 out << " " << hashName(name);
zmo@google.com5601ea02011-06-10 18:23:25 +0000243 if (type.isArray())
244 out << arrayBrackets(type);
245
246 // Put a comma if this is not the last argument.
247 if (iter != args.end() - 1)
248 out << ", ";
249 }
250}
251
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400252const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
253 const TType &type, const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000254{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700255 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000256
257 if (type.getBasicType() == EbtStruct)
258 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700259 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -0400260 out << hashName(structure->name()) << "(";
261
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700262 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400263 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000264 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700265 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000266 ASSERT(fieldType != NULL);
267 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700268 if (i != fields.size() - 1)
269 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000270 }
271 out << ")";
272 }
273 else
274 {
Jamie Madill94bf7f22013-07-08 13:31:15 -0400275 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000276 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700277 if (writeType)
278 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400279 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000280 {
281 switch (pConstUnion->getType())
282 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700283 case EbtFloat:
284 out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
285 break;
286 case EbtInt:
287 out << pConstUnion->getIConst();
288 break;
Olli Etuaho5321c802015-04-02 17:08:16 +0300289 case EbtUInt:
290 out << pConstUnion->getUConst() << "u";
291 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700292 case EbtBool:
293 out << pConstUnion->getBConst();
294 break;
295 default: UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000296 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700297 if (i != size - 1)
298 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000299 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700300 if (writeType)
301 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000302 }
303 return pConstUnion;
304}
305
Olli Etuahoe92507b2016-07-04 11:20:10 +0300306void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
Olli Etuahof40319e2015-03-10 14:33:00 +0200307{
308 TInfoSinkBase &out = objSink();
309 if (visit == PreVisit)
310 {
311 if (type.isArray())
312 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300313 out << getTypeName(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200314 out << arrayBrackets(type);
315 out << "(";
316 }
317 else
318 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300319 out << getTypeName(type) << "(";
Olli Etuahof40319e2015-03-10 14:33:00 +0200320 }
321 }
322 else
323 {
324 writeTriplet(visit, nullptr, ", ", ")");
325 }
326}
327
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700328void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000329{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700330 TInfoSinkBase &out = objSink();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800331 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
332 out << mLoopUnrollStack.getLoopIndexValue(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000333 else
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000334 out << hashVariableName(node->getSymbol());
zmo@google.com5601ea02011-06-10 18:23:25 +0000335
336 if (mDeclaringVariables && node->getType().isArray())
337 out << arrayBrackets(node->getType());
338}
339
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700340void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000341{
342 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
343}
344
Olli Etuahob6fa0432016-09-28 16:28:05 +0100345bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
346{
347 TInfoSinkBase &out = objSink();
348 if (visit == PostVisit)
349 {
350 out << ".";
351 node->writeOffsetsAsXYZW(&out);
352 }
353 return true;
354}
355
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700356bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000357{
358 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700359 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000360 switch (node->getOp())
361 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100362 case EOpComma:
363 writeTriplet(visit, "(", ", ", ")");
364 break;
365 case EOpInitialize:
zmo@google.com5601ea02011-06-10 18:23:25 +0000366 if (visit == InVisit)
367 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100368 out << " = ";
369 // RHS of initialize is not being declared.
370 mDeclaringVariables = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000371 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100372 break;
373 case EOpAssign:
374 writeTriplet(visit, "(", " = ", ")");
375 break;
376 case EOpAddAssign:
377 writeTriplet(visit, "(", " += ", ")");
378 break;
379 case EOpSubAssign:
380 writeTriplet(visit, "(", " -= ", ")");
381 break;
382 case EOpDivAssign:
383 writeTriplet(visit, "(", " /= ", ")");
384 break;
385 case EOpIModAssign:
386 writeTriplet(visit, "(", " %= ", ")");
387 break;
388 // Notice the fall-through.
389 case EOpMulAssign:
390 case EOpVectorTimesMatrixAssign:
391 case EOpVectorTimesScalarAssign:
392 case EOpMatrixTimesScalarAssign:
393 case EOpMatrixTimesMatrixAssign:
394 writeTriplet(visit, "(", " *= ", ")");
395 break;
396 case EOpBitShiftLeftAssign:
397 writeTriplet(visit, "(", " <<= ", ")");
398 break;
399 case EOpBitShiftRightAssign:
400 writeTriplet(visit, "(", " >>= ", ")");
401 break;
402 case EOpBitwiseAndAssign:
403 writeTriplet(visit, "(", " &= ", ")");
404 break;
405 case EOpBitwiseXorAssign:
406 writeTriplet(visit, "(", " ^= ", ")");
407 break;
408 case EOpBitwiseOrAssign:
409 writeTriplet(visit, "(", " |= ", ")");
410 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000411
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100412 case EOpIndexDirect:
zmo@google.com5601ea02011-06-10 18:23:25 +0000413 writeTriplet(visit, NULL, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100414 break;
415 case EOpIndexIndirect:
416 if (node->getAddIndexClamp())
417 {
418 if (visit == InVisit)
419 {
420 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
421 out << "[int(clamp(float(";
422 else
423 out << "[webgl_int_clamp(";
424 }
425 else if (visit == PostVisit)
426 {
427 int maxSize;
428 TIntermTyped *left = node->getLeft();
429 TType leftType = left->getType();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700430
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100431 if (left->isArray())
432 {
433 // The shader will fail validation if the array length is not > 0.
434 maxSize = static_cast<int>(leftType.getArraySize()) - 1;
435 }
436 else
437 {
438 maxSize = leftType.getNominalSize() - 1;
439 }
440
441 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
442 out << "), 0.0, float(" << maxSize << ")))]";
443 else
444 out << ", 0, " << maxSize << ")]";
445 }
446 }
447 else
448 {
449 writeTriplet(visit, NULL, "[", "]");
450 }
451 break;
452 case EOpIndexDirectStruct:
453 if (visit == InVisit)
454 {
455 // Here we are writing out "foo.bar", where "foo" is struct
456 // and "bar" is field. In AST, it is represented as a binary
457 // node, where left child represents "foo" and right child "bar".
458 // The node itself represents ".". The struct field "bar" is
459 // actually stored as an index into TStructure::fields.
460 out << ".";
461 const TStructure *structure = node->getLeft()->getType().getStruct();
462 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
463 const TField *field = structure->fields()[index->getIConst(0)];
464
465 TString fieldName = field->name();
466 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
467 fieldName = hashName(fieldName);
468
469 out << fieldName;
470 visitChildren = false;
471 }
472 break;
473 case EOpIndexDirectInterfaceBlock:
474 if (visit == InVisit)
475 {
476 out << ".";
477 const TInterfaceBlock *interfaceBlock =
478 node->getLeft()->getType().getInterfaceBlock();
479 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
480 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
481
482 TString fieldName = field->name();
483 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700484 fieldName = hashName(fieldName);
485
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100486 out << fieldName;
487 visitChildren = false;
488 }
489 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400490
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100491 case EOpAdd:
492 writeTriplet(visit, "(", " + ", ")");
493 break;
494 case EOpSub:
495 writeTriplet(visit, "(", " - ", ")");
496 break;
497 case EOpMul:
498 writeTriplet(visit, "(", " * ", ")");
499 break;
500 case EOpDiv:
501 writeTriplet(visit, "(", " / ", ")");
502 break;
503 case EOpIMod:
504 writeTriplet(visit, "(", " % ", ")");
505 break;
506 case EOpBitShiftLeft:
507 writeTriplet(visit, "(", " << ", ")");
508 break;
509 case EOpBitShiftRight:
510 writeTriplet(visit, "(", " >> ", ")");
511 break;
512 case EOpBitwiseAnd:
513 writeTriplet(visit, "(", " & ", ")");
514 break;
515 case EOpBitwiseXor:
516 writeTriplet(visit, "(", " ^ ", ")");
517 break;
518 case EOpBitwiseOr:
519 writeTriplet(visit, "(", " | ", ")");
520 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400521
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100522 case EOpEqual:
523 writeTriplet(visit, "(", " == ", ")");
524 break;
525 case EOpNotEqual:
526 writeTriplet(visit, "(", " != ", ")");
527 break;
528 case EOpLessThan:
529 writeTriplet(visit, "(", " < ", ")");
530 break;
531 case EOpGreaterThan:
532 writeTriplet(visit, "(", " > ", ")");
533 break;
534 case EOpLessThanEqual:
535 writeTriplet(visit, "(", " <= ", ")");
536 break;
537 case EOpGreaterThanEqual:
538 writeTriplet(visit, "(", " >= ", ")");
539 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000540
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100541 // Notice the fall-through.
542 case EOpVectorTimesScalar:
543 case EOpVectorTimesMatrix:
544 case EOpMatrixTimesVector:
545 case EOpMatrixTimesScalar:
546 case EOpMatrixTimesMatrix:
547 writeTriplet(visit, "(", " * ", ")");
548 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200549
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100550 case EOpLogicalOr:
551 writeTriplet(visit, "(", " || ", ")");
552 break;
553 case EOpLogicalXor:
554 writeTriplet(visit, "(", " ^^ ", ")");
555 break;
556 case EOpLogicalAnd:
557 writeTriplet(visit, "(", " && ", ")");
558 break;
559 default:
560 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000561 }
562
563 return visitChildren;
564}
565
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700566bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000567{
zmo@google.com32e97312011-08-24 01:03:11 +0000568 TString preString;
569 TString postString = ")";
570
zmo@google.com5601ea02011-06-10 18:23:25 +0000571 switch (node->getOp())
572 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700573 case EOpNegative: preString = "(-"; break;
Zhenyao Mode1e00e2014-10-09 16:55:32 -0700574 case EOpPositive: preString = "(+"; break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700575 case EOpVectorLogicalNot: preString = "not("; break;
576 case EOpLogicalNot: preString = "(!"; break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200577 case EOpBitwiseNot: preString = "(~"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000578
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700579 case EOpPostIncrement: preString = "("; postString = "++)"; break;
580 case EOpPostDecrement: preString = "("; postString = "--)"; break;
581 case EOpPreIncrement: preString = "(++"; break;
582 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000583
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700584 case EOpRadians:
585 preString = "radians(";
586 break;
587 case EOpDegrees:
588 preString = "degrees(";
589 break;
590 case EOpSin:
591 preString = "sin(";
592 break;
593 case EOpCos:
594 preString = "cos(";
595 break;
596 case EOpTan:
597 preString = "tan(";
598 break;
599 case EOpAsin:
600 preString = "asin(";
601 break;
602 case EOpAcos:
603 preString = "acos(";
604 break;
605 case EOpAtan:
606 preString = "atan(";
607 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000608
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200609 case EOpSinh:
610 preString = "sinh(";
611 break;
612 case EOpCosh:
613 preString = "cosh(";
614 break;
615 case EOpTanh:
616 preString = "tanh(";
617 break;
618 case EOpAsinh:
619 preString = "asinh(";
620 break;
621 case EOpAcosh:
622 preString = "acosh(";
623 break;
624 case EOpAtanh:
625 preString = "atanh(";
626 break;
627
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700628 case EOpExp:
629 preString = "exp(";
630 break;
631 case EOpLog:
632 preString = "log(";
633 break;
634 case EOpExp2:
635 preString = "exp2(";
636 break;
637 case EOpLog2:
638 preString = "log2(";
639 break;
640 case EOpSqrt:
641 preString = "sqrt(";
642 break;
643 case EOpInverseSqrt:
644 preString = "inversesqrt(";
645 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000646
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700647 case EOpAbs:
648 preString = "abs(";
649 break;
650 case EOpSign:
651 preString = "sign(";
652 break;
653 case EOpFloor:
654 preString = "floor(";
655 break;
Qingqing Deng5dbece52015-02-27 20:35:38 -0800656 case EOpTrunc:
657 preString = "trunc(";
658 break;
659 case EOpRound:
660 preString = "round(";
661 break;
662 case EOpRoundEven:
663 preString = "roundEven(";
664 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700665 case EOpCeil:
666 preString = "ceil(";
667 break;
668 case EOpFract:
669 preString = "fract(";
670 break;
Arun Patole0c1726e2015-02-18 14:35:02 +0530671 case EOpIsNan:
672 preString = "isnan(";
673 break;
674 case EOpIsInf:
675 preString = "isinf(";
676 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000677
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200678 case EOpFloatBitsToInt:
679 preString = "floatBitsToInt(";
680 break;
681 case EOpFloatBitsToUint:
682 preString = "floatBitsToUint(";
683 break;
684 case EOpIntBitsToFloat:
685 preString = "intBitsToFloat(";
686 break;
687 case EOpUintBitsToFloat:
688 preString = "uintBitsToFloat(";
689 break;
690
Olli Etuaho7700ff62015-01-15 12:16:29 +0200691 case EOpPackSnorm2x16:
692 preString = "packSnorm2x16(";
693 break;
694 case EOpPackUnorm2x16:
695 preString = "packUnorm2x16(";
696 break;
697 case EOpPackHalf2x16:
698 preString = "packHalf2x16(";
699 break;
700 case EOpUnpackSnorm2x16:
701 preString = "unpackSnorm2x16(";
702 break;
703 case EOpUnpackUnorm2x16:
704 preString = "unpackUnorm2x16(";
705 break;
706 case EOpUnpackHalf2x16:
707 preString = "unpackHalf2x16(";
708 break;
709
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700710 case EOpLength:
711 preString = "length(";
712 break;
713 case EOpNormalize:
714 preString = "normalize(";
715 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000716
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700717 case EOpDFdx:
718 preString = "dFdx(";
719 break;
720 case EOpDFdy:
721 preString = "dFdy(";
722 break;
723 case EOpFwidth:
724 preString = "fwidth(";
725 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000726
Olli Etuahoe39706d2014-12-30 16:40:36 +0200727 case EOpTranspose:
728 preString = "transpose(";
729 break;
730 case EOpDeterminant:
731 preString = "determinant(";
732 break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +0200733 case EOpInverse:
734 preString = "inverse(";
735 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200736
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700737 case EOpAny:
738 preString = "any(";
739 break;
740 case EOpAll:
741 preString = "all(";
742 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000743
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700744 default:
745 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000746 }
747
zmo@google.com32e97312011-08-24 01:03:11 +0000748 if (visit == PreVisit && node->getUseEmulatedFunction())
749 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
750 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
751
zmo@google.com5601ea02011-06-10 18:23:25 +0000752 return true;
753}
754
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300755bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
756{
757 TInfoSinkBase &out = objSink();
758 // Notice two brackets at the beginning and end. The outer ones
759 // encapsulate the whole ternary expression. This preserves the
760 // order of precedence when ternary expressions are used in a
761 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
762 out << "((";
763 node->getCondition()->traverse(this);
764 out << ") ? (";
765 node->getTrueExpression()->traverse(this);
766 out << ") : (";
767 node->getFalseExpression()->traverse(this);
768 out << "))";
769 return false;
770}
771
Olli Etuaho57961272016-09-14 13:57:46 +0300772bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000773{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700774 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000775
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300776 out << "if (";
777 node->getCondition()->traverse(this);
778 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000779
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300780 incrementDepth(node);
781 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000782
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300783 if (node->getFalseBlock())
784 {
785 out << "else\n";
786 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000787 }
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300788 decrementDepth();
zmo@google.com5601ea02011-06-10 18:23:25 +0000789 return false;
790}
791
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200792bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200793{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200794 if (node->getStatementList())
795 {
796 writeTriplet(visit, "switch (", ") ", nullptr);
797 // The curly braces get written when visiting the statementList aggregate
798 }
799 else
800 {
801 // No statementList, so it won't output curly braces
802 writeTriplet(visit, "switch (", ") {", "}\n");
803 }
804 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200805}
806
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200807bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200808{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200809 if (node->hasCondition())
810 {
811 writeTriplet(visit, "case (", nullptr, "):\n");
812 return true;
813 }
814 else
815 {
816 TInfoSinkBase &out = objSink();
817 out << "default:\n";
818 return false;
819 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200820}
821
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100822bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
823{
824 TInfoSinkBase &out = objSink();
825 // Scope the blocks except when at the global scope.
826 if (mDepth > 0)
827 {
828 out << "{\n";
829 }
830
831 incrementDepth(node);
832 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
833 iter != node->getSequence()->end(); ++iter)
834 {
835 TIntermNode *curNode = *iter;
836 ASSERT(curNode != nullptr);
837 curNode->traverse(this);
838
839 if (isSingleStatement(curNode))
840 out << ";\n";
841 }
842 decrementDepth();
843
844 // Scope the blocks except when at the global scope.
845 if (mDepth > 0)
846 {
847 out << "}\n";
848 }
849 return false;
850}
851
Olli Etuaho336b1472016-10-05 16:37:55 +0100852bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
853{
854 TInfoSinkBase &out = objSink();
855
856 ASSERT(visit == PreVisit);
857 {
858 const TType &type = node->getType();
859 writeVariableType(type);
860 if (type.isArray())
861 out << arrayBrackets(type);
862 }
863
864 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
865
866 incrementDepth(node);
867
868 // Traverse function parameters.
869 TIntermAggregate *params = node->getFunctionParameters()->getAsAggregate();
870 ASSERT(params->getOp() == EOpParameters);
871 params->traverse(this);
872
873 // Traverse function body.
874 visitCodeBlock(node->getBody());
875 decrementDepth();
876
877 // Fully processed; no need to visit children.
878 return false;
879}
880
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700881bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000882{
883 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700884 TInfoSinkBase &out = objSink();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700885 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000886 switch (node->getOp())
887 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700888 case EOpPrototype:
889 // Function declaration.
890 ASSERT(visit == PreVisit);
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300891 {
892 const TType &type = node->getType();
893 writeVariableType(type);
894 if (type.isArray())
895 out << arrayBrackets(type);
896 }
897
Olli Etuahobd674552016-10-06 13:28:42 +0100898 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700899
900 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700901 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700902 out << ")";
903
904 visitChildren = false;
905 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700906 case EOpFunctionCall:
907 // Function call.
908 if (visit == PreVisit)
Olli Etuahobd674552016-10-06 13:28:42 +0100909 out << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200910 else if (visit == InVisit)
911 out << ", ";
912 else
913 out << ")";
914 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700915 case EOpParameters:
916 // Function parameters.
917 ASSERT(visit == PreVisit);
918 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700919 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700920 out << ")";
921 visitChildren = false;
922 break;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700923 case EOpInvariantDeclaration:
924 // Invariant declaration.
925 ASSERT(visit == PreVisit);
926 {
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400927 const TIntermSequence *sequence = node->getSequence();
928 ASSERT(sequence && sequence->size() == 1);
929 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
930 ASSERT(symbol);
Zhenyao Mo2a517272014-10-27 16:09:57 -0700931 out << "invariant " << hashVariableName(symbol->getSymbol());
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400932 }
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700933 visitChildren = false;
934 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700935 case EOpConstructFloat:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700936 case EOpConstructVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700937 case EOpConstructVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700938 case EOpConstructVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700939 case EOpConstructBool:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700940 case EOpConstructBVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700941 case EOpConstructBVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700942 case EOpConstructBVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700943 case EOpConstructInt:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700944 case EOpConstructIVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700945 case EOpConstructIVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700946 case EOpConstructIVec4:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400947 case EOpConstructUInt:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400948 case EOpConstructUVec2:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400949 case EOpConstructUVec3:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400950 case EOpConstructUVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700951 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400952 case EOpConstructMat2x3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400953 case EOpConstructMat2x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400954 case EOpConstructMat3x2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700955 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400956 case EOpConstructMat3x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400957 case EOpConstructMat4x2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400958 case EOpConstructMat4x3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700959 case EOpConstructMat4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700960 case EOpConstructStruct:
Olli Etuahoe92507b2016-07-04 11:20:10 +0300961 writeConstructorTriplet(visit, node->getType());
962 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000963
Olli Etuahoe39706d2014-12-30 16:40:36 +0200964 case EOpOuterProduct:
965 writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
966 break;
967
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700968 case EOpLessThan:
969 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
970 break;
971 case EOpGreaterThan:
972 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
973 break;
974 case EOpLessThanEqual:
975 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
976 break;
977 case EOpGreaterThanEqual:
978 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
979 break;
980 case EOpVectorEqual:
981 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
982 break;
983 case EOpVectorNotEqual:
984 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
985 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000986
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700987 case EOpMod:
988 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
989 break;
Olli Etuahob6e07a62015-02-16 12:22:10 +0200990 case EOpModf:
991 writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
992 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700993 case EOpPow:
994 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
995 break;
996 case EOpAtan:
997 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
998 break;
999 case EOpMin:
1000 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
1001 break;
1002 case EOpMax:
1003 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
1004 break;
1005 case EOpClamp:
1006 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
1007 break;
1008 case EOpMix:
1009 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
1010 break;
1011 case EOpStep:
1012 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
1013 break;
1014 case EOpSmoothStep:
1015 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
1016 break;
1017 case EOpDistance:
1018 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
1019 break;
1020 case EOpDot:
1021 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
1022 break;
1023 case EOpCross:
1024 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
1025 break;
1026 case EOpFaceForward:
1027 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
1028 break;
1029 case EOpReflect:
1030 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
1031 break;
1032 case EOpRefract:
1033 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
1034 break;
1035 case EOpMul:
1036 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
1037 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001038
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001039 default:
1040 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001041 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001042 return visitChildren;
1043}
1044
Olli Etuaho13389b62016-10-16 11:48:18 +01001045bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
1046{
1047 TInfoSinkBase &out = objSink();
1048
1049 // Variable declaration.
1050 if (visit == PreVisit)
1051 {
1052 const TIntermSequence &sequence = *(node->getSequence());
1053 const TIntermTyped *variable = sequence.front()->getAsTyped();
1054 writeLayoutQualifier(variable->getType());
1055 writeVariableType(variable->getType());
1056 out << " ";
1057 mDeclaringVariables = true;
1058 }
1059 else if (visit == InVisit)
1060 {
1061 out << ", ";
1062 mDeclaringVariables = true;
1063 }
1064 else
1065 {
1066 mDeclaringVariables = false;
1067 }
1068 return true;
1069}
1070
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001071bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001072{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001073 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001074
Zhenyao Mo7cab38b2013-10-15 12:59:30 -07001075 incrementDepth(node);
Corentin Wallez7258e302015-09-22 10:40:24 -07001076
zmo@google.com5601ea02011-06-10 18:23:25 +00001077 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001078
1079 // Only for loops can be unrolled
1080 ASSERT(!node->getUnrollFlag() || loopType == ELoopFor);
1081
zmo@google.com5601ea02011-06-10 18:23:25 +00001082 if (loopType == ELoopFor) // for loop
1083 {
Zhenyao Mo550c6002014-02-26 15:40:48 -08001084 if (!node->getUnrollFlag())
1085 {
zmo@google.com5601ea02011-06-10 18:23:25 +00001086 out << "for (";
1087 if (node->getInit())
1088 node->getInit()->traverse(this);
1089 out << "; ";
1090
1091 if (node->getCondition())
1092 node->getCondition()->traverse(this);
1093 out << "; ";
1094
1095 if (node->getExpression())
1096 node->getExpression()->traverse(this);
1097 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001098
1099 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001100 }
Zhenyao Mo550c6002014-02-26 15:40:48 -08001101 else
1102 {
1103 // Need to put a one-iteration loop here to handle break.
Olli Etuaho13389b62016-10-16 11:48:18 +01001104 TIntermSequence *declSeq = node->getInit()->getAsDeclarationNode()->getSequence();
Zhenyao Mo550c6002014-02-26 15:40:48 -08001105 TIntermSymbol *indexSymbol =
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001106 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -08001107 TString name = hashVariableName(indexSymbol->getSymbol());
1108 out << "for (int " << name << " = 0; "
1109 << name << " < 1; "
1110 << "++" << name << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001111
1112 out << "{\n";
1113 mLoopUnrollStack.push(node);
1114 while (mLoopUnrollStack.satisfiesLoopCondition())
1115 {
1116 visitCodeBlock(node->getBody());
1117 mLoopUnrollStack.step();
1118 }
1119 mLoopUnrollStack.pop();
1120 out << "}\n";
Zhenyao Mo550c6002014-02-26 15:40:48 -08001121 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001122 }
1123 else if (loopType == ELoopWhile) // while loop
1124 {
1125 out << "while (";
1126 ASSERT(node->getCondition() != NULL);
1127 node->getCondition()->traverse(this);
1128 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001129
1130 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001131 }
1132 else // do-while loop
1133 {
1134 ASSERT(loopType == ELoopDoWhile);
1135 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001136
zmo@google.com5601ea02011-06-10 18:23:25 +00001137 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001138
zmo@google.com5601ea02011-06-10 18:23:25 +00001139 out << "while (";
1140 ASSERT(node->getCondition() != NULL);
1141 node->getCondition()->traverse(this);
1142 out << ");\n";
1143 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001144
zmo@google.com5601ea02011-06-10 18:23:25 +00001145 decrementDepth();
1146
1147 // No need to visit children. They have been already processed in
1148 // this function.
1149 return false;
1150}
1151
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001152bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001153{
1154 switch (node->getFlowOp())
1155 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001156 case EOpKill:
1157 writeTriplet(visit, "discard", NULL, NULL);
1158 break;
1159 case EOpBreak:
1160 writeTriplet(visit, "break", NULL, NULL);
1161 break;
1162 case EOpContinue:
1163 writeTriplet(visit, "continue", NULL, NULL);
1164 break;
1165 case EOpReturn:
1166 writeTriplet(visit, "return ", NULL, NULL);
1167 break;
1168 default:
1169 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001170 }
1171
1172 return true;
1173}
1174
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001175void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001176{
zmo@google.com5601ea02011-06-10 18:23:25 +00001177 TInfoSinkBase &out = objSink();
1178 if (node != NULL)
1179 {
1180 node->traverse(this);
1181 // Single statements not part of a sequence need to be terminated
1182 // with semi-colon.
1183 if (isSingleStatement(node))
1184 out << ";\n";
1185 }
1186 else
1187 {
1188 out << "{\n}\n"; // Empty code block.
1189 }
1190}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001191
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001192TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001193{
Olli Etuahoe92507b2016-07-04 11:20:10 +03001194 if (type.getBasicType() == EbtStruct)
1195 return hashName(type.getStruct()->name());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001196 else
Olli Etuahoe92507b2016-07-04 11:20:10 +03001197 return type.getBuiltInTypeNameString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001198}
1199
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001200TString TOutputGLSLBase::hashName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001201{
1202 if (mHashFunction == NULL || name.empty())
1203 return name;
1204 NameMap::const_iterator it = mNameMap.find(name.c_str());
1205 if (it != mNameMap.end())
1206 return it->second.c_str();
1207 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
1208 mNameMap[name.c_str()] = hashedName.c_str();
1209 return hashedName;
1210}
1211
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001212TString TOutputGLSLBase::hashVariableName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001213{
Jamie Madill02f20dd2013-09-12 12:07:42 -04001214 if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001215 return name;
1216 return hashName(name);
1217}
1218
Olli Etuaho59f9a642015-08-06 20:38:26 +03001219TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001220{
Olli Etuaho59f9a642015-08-06 20:38:26 +03001221 TString mangledStr = mangledName.getString();
1222 TString name = TFunction::unmangleName(mangledStr);
1223 if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001224 return translateTextureFunction(name);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001225 if (mangledName.isInternal())
1226 return name;
1227 else
1228 return hashName(name);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001229}
Jamie Madill98493dd2013-07-08 14:39:03 -04001230
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001231bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001232{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001233 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001234 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001235 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001236 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001237 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001238
1239 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001240}
1241
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001242void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001243{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001244 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001245
1246 out << "struct " << hashName(structure->name()) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001247 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001248 for (size_t i = 0; i < fields.size(); ++i)
1249 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001250 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001251 if (writeVariablePrecision(field->type()->getPrecision()))
1252 out << " ";
1253 out << getTypeName(*field->type()) << " " << hashName(field->name());
1254 if (field->type()->isArray())
1255 out << arrayBrackets(*field->type());
1256 out << ";\n";
1257 }
1258 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001259}
Jamie Madill98493dd2013-07-08 14:39:03 -04001260
Geoff Langbdcc54a2015-09-02 13:09:48 -04001261void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1262{
1263 TInfoSinkBase &out = objSink();
1264
1265 out << "layout(";
1266
1267 switch (interfaceBlock->blockStorage())
1268 {
1269 case EbsUnspecified:
1270 case EbsShared:
1271 // Default block storage is shared.
1272 out << "shared";
1273 break;
1274
1275 case EbsPacked:
1276 out << "packed";
1277 break;
1278
1279 case EbsStd140:
1280 out << "std140";
1281 break;
1282
1283 default:
1284 UNREACHABLE();
1285 break;
1286 }
1287
1288 out << ", ";
1289
1290 switch (interfaceBlock->matrixPacking())
1291 {
1292 case EmpUnspecified:
1293 case EmpColumnMajor:
1294 // Default matrix packing is column major.
1295 out << "column_major";
1296 break;
1297
1298 case EmpRowMajor:
1299 out << "row_major";
1300 break;
1301
1302 default:
1303 UNREACHABLE();
1304 break;
1305 }
1306
1307 out << ") ";
1308}
1309
1310void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1311{
1312 TInfoSinkBase &out = objSink();
1313
1314 out << hashName(interfaceBlock->name()) << "{\n";
1315 const TFieldList &fields = interfaceBlock->fields();
1316 for (size_t i = 0; i < fields.size(); ++i)
1317 {
1318 const TField *field = fields[i];
1319 if (writeVariablePrecision(field->type()->getPrecision()))
1320 out << " ";
1321 out << getTypeName(*field->type()) << " " << hashName(field->name());
1322 if (field->type()->isArray())
1323 out << arrayBrackets(*field->type());
1324 out << ";\n";
1325 }
1326 out << "}";
1327}