blob: a81f154cdab7fb08f80de5147b4b3a8bffbd4aff [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
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000240 if (!arg->getName().getString().empty())
241 out << " " << hashName(arg->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000242 if (type.isArray())
243 out << arrayBrackets(type);
244
245 // Put a comma if this is not the last argument.
246 if (iter != args.end() - 1)
247 out << ", ";
248 }
249}
250
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400251const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
252 const TType &type, const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000253{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700254 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000255
256 if (type.getBasicType() == EbtStruct)
257 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700258 const TStructure *structure = type.getStruct();
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000259 out << hashName(TName(structure->name())) << "(";
Jamie Madill98493dd2013-07-08 14:39:03 -0400260
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700261 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400262 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000263 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700264 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000265 ASSERT(fieldType != NULL);
266 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700267 if (i != fields.size() - 1)
268 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000269 }
270 out << ")";
271 }
272 else
273 {
Jamie Madill94bf7f22013-07-08 13:31:15 -0400274 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000275 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700276 if (writeType)
277 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400278 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000279 {
280 switch (pConstUnion->getType())
281 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700282 case EbtFloat:
283 out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
284 break;
285 case EbtInt:
286 out << pConstUnion->getIConst();
287 break;
Olli Etuaho5321c802015-04-02 17:08:16 +0300288 case EbtUInt:
289 out << pConstUnion->getUConst() << "u";
290 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700291 case EbtBool:
292 out << pConstUnion->getBConst();
293 break;
294 default: UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000295 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700296 if (i != size - 1)
297 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000298 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700299 if (writeType)
300 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000301 }
302 return pConstUnion;
303}
304
Olli Etuahoe92507b2016-07-04 11:20:10 +0300305void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
Olli Etuahof40319e2015-03-10 14:33:00 +0200306{
307 TInfoSinkBase &out = objSink();
308 if (visit == PreVisit)
309 {
310 if (type.isArray())
311 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300312 out << getTypeName(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200313 out << arrayBrackets(type);
314 out << "(";
315 }
316 else
317 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300318 out << getTypeName(type) << "(";
Olli Etuahof40319e2015-03-10 14:33:00 +0200319 }
320 }
321 else
322 {
323 writeTriplet(visit, nullptr, ", ", ")");
324 }
325}
326
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700327void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000328{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700329 TInfoSinkBase &out = objSink();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800330 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
331 out << mLoopUnrollStack.getLoopIndexValue(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000332 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000333 out << hashVariableName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000334
335 if (mDeclaringVariables && node->getType().isArray())
336 out << arrayBrackets(node->getType());
337}
338
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700339void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000340{
341 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
342}
343
Olli Etuahob6fa0432016-09-28 16:28:05 +0100344bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
345{
346 TInfoSinkBase &out = objSink();
347 if (visit == PostVisit)
348 {
349 out << ".";
350 node->writeOffsetsAsXYZW(&out);
351 }
352 return true;
353}
354
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700355bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000356{
357 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700358 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000359 switch (node->getOp())
360 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100361 case EOpComma:
362 writeTriplet(visit, "(", ", ", ")");
363 break;
364 case EOpInitialize:
zmo@google.com5601ea02011-06-10 18:23:25 +0000365 if (visit == InVisit)
366 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100367 out << " = ";
368 // RHS of initialize is not being declared.
369 mDeclaringVariables = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000370 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100371 break;
372 case EOpAssign:
373 writeTriplet(visit, "(", " = ", ")");
374 break;
375 case EOpAddAssign:
376 writeTriplet(visit, "(", " += ", ")");
377 break;
378 case EOpSubAssign:
379 writeTriplet(visit, "(", " -= ", ")");
380 break;
381 case EOpDivAssign:
382 writeTriplet(visit, "(", " /= ", ")");
383 break;
384 case EOpIModAssign:
385 writeTriplet(visit, "(", " %= ", ")");
386 break;
387 // Notice the fall-through.
388 case EOpMulAssign:
389 case EOpVectorTimesMatrixAssign:
390 case EOpVectorTimesScalarAssign:
391 case EOpMatrixTimesScalarAssign:
392 case EOpMatrixTimesMatrixAssign:
393 writeTriplet(visit, "(", " *= ", ")");
394 break;
395 case EOpBitShiftLeftAssign:
396 writeTriplet(visit, "(", " <<= ", ")");
397 break;
398 case EOpBitShiftRightAssign:
399 writeTriplet(visit, "(", " >>= ", ")");
400 break;
401 case EOpBitwiseAndAssign:
402 writeTriplet(visit, "(", " &= ", ")");
403 break;
404 case EOpBitwiseXorAssign:
405 writeTriplet(visit, "(", " ^= ", ")");
406 break;
407 case EOpBitwiseOrAssign:
408 writeTriplet(visit, "(", " |= ", ")");
409 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000410
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100411 case EOpIndexDirect:
zmo@google.com5601ea02011-06-10 18:23:25 +0000412 writeTriplet(visit, NULL, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100413 break;
414 case EOpIndexIndirect:
415 if (node->getAddIndexClamp())
416 {
417 if (visit == InVisit)
418 {
419 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
420 out << "[int(clamp(float(";
421 else
422 out << "[webgl_int_clamp(";
423 }
424 else if (visit == PostVisit)
425 {
426 int maxSize;
427 TIntermTyped *left = node->getLeft();
428 TType leftType = left->getType();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700429
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100430 if (left->isArray())
431 {
432 // The shader will fail validation if the array length is not > 0.
433 maxSize = static_cast<int>(leftType.getArraySize()) - 1;
434 }
435 else
436 {
437 maxSize = leftType.getNominalSize() - 1;
438 }
439
440 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
441 out << "), 0.0, float(" << maxSize << ")))]";
442 else
443 out << ", 0, " << maxSize << ")]";
444 }
445 }
446 else
447 {
448 writeTriplet(visit, NULL, "[", "]");
449 }
450 break;
451 case EOpIndexDirectStruct:
452 if (visit == InVisit)
453 {
454 // Here we are writing out "foo.bar", where "foo" is struct
455 // and "bar" is field. In AST, it is represented as a binary
456 // node, where left child represents "foo" and right child "bar".
457 // The node itself represents ".". The struct field "bar" is
458 // actually stored as an index into TStructure::fields.
459 out << ".";
460 const TStructure *structure = node->getLeft()->getType().getStruct();
461 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
462 const TField *field = structure->fields()[index->getIConst(0)];
463
464 TString fieldName = field->name();
465 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000466 fieldName = hashName(TName(fieldName));
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100467
468 out << fieldName;
469 visitChildren = false;
470 }
471 break;
472 case EOpIndexDirectInterfaceBlock:
473 if (visit == InVisit)
474 {
475 out << ".";
476 const TInterfaceBlock *interfaceBlock =
477 node->getLeft()->getType().getInterfaceBlock();
478 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
479 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
480
481 TString fieldName = field->name();
482 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000483 fieldName = hashName(TName(fieldName));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700484
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100485 out << fieldName;
486 visitChildren = false;
487 }
488 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400489
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100490 case EOpAdd:
491 writeTriplet(visit, "(", " + ", ")");
492 break;
493 case EOpSub:
494 writeTriplet(visit, "(", " - ", ")");
495 break;
496 case EOpMul:
497 writeTriplet(visit, "(", " * ", ")");
498 break;
499 case EOpDiv:
500 writeTriplet(visit, "(", " / ", ")");
501 break;
502 case EOpIMod:
503 writeTriplet(visit, "(", " % ", ")");
504 break;
505 case EOpBitShiftLeft:
506 writeTriplet(visit, "(", " << ", ")");
507 break;
508 case EOpBitShiftRight:
509 writeTriplet(visit, "(", " >> ", ")");
510 break;
511 case EOpBitwiseAnd:
512 writeTriplet(visit, "(", " & ", ")");
513 break;
514 case EOpBitwiseXor:
515 writeTriplet(visit, "(", " ^ ", ")");
516 break;
517 case EOpBitwiseOr:
518 writeTriplet(visit, "(", " | ", ")");
519 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400520
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100521 case EOpEqual:
522 writeTriplet(visit, "(", " == ", ")");
523 break;
524 case EOpNotEqual:
525 writeTriplet(visit, "(", " != ", ")");
526 break;
527 case EOpLessThan:
528 writeTriplet(visit, "(", " < ", ")");
529 break;
530 case EOpGreaterThan:
531 writeTriplet(visit, "(", " > ", ")");
532 break;
533 case EOpLessThanEqual:
534 writeTriplet(visit, "(", " <= ", ")");
535 break;
536 case EOpGreaterThanEqual:
537 writeTriplet(visit, "(", " >= ", ")");
538 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000539
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100540 // Notice the fall-through.
541 case EOpVectorTimesScalar:
542 case EOpVectorTimesMatrix:
543 case EOpMatrixTimesVector:
544 case EOpMatrixTimesScalar:
545 case EOpMatrixTimesMatrix:
546 writeTriplet(visit, "(", " * ", ")");
547 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200548
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100549 case EOpLogicalOr:
550 writeTriplet(visit, "(", " || ", ")");
551 break;
552 case EOpLogicalXor:
553 writeTriplet(visit, "(", " ^^ ", ")");
554 break;
555 case EOpLogicalAnd:
556 writeTriplet(visit, "(", " && ", ")");
557 break;
558 default:
559 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000560 }
561
562 return visitChildren;
563}
564
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700565bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000566{
zmo@google.com32e97312011-08-24 01:03:11 +0000567 TString preString;
568 TString postString = ")";
569
zmo@google.com5601ea02011-06-10 18:23:25 +0000570 switch (node->getOp())
571 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700572 case EOpNegative: preString = "(-"; break;
Zhenyao Mode1e00e2014-10-09 16:55:32 -0700573 case EOpPositive: preString = "(+"; break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700574 case EOpVectorLogicalNot: preString = "not("; break;
575 case EOpLogicalNot: preString = "(!"; break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200576 case EOpBitwiseNot: preString = "(~"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000577
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700578 case EOpPostIncrement: preString = "("; postString = "++)"; break;
579 case EOpPostDecrement: preString = "("; postString = "--)"; break;
580 case EOpPreIncrement: preString = "(++"; break;
581 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000582
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700583 case EOpRadians:
584 preString = "radians(";
585 break;
586 case EOpDegrees:
587 preString = "degrees(";
588 break;
589 case EOpSin:
590 preString = "sin(";
591 break;
592 case EOpCos:
593 preString = "cos(";
594 break;
595 case EOpTan:
596 preString = "tan(";
597 break;
598 case EOpAsin:
599 preString = "asin(";
600 break;
601 case EOpAcos:
602 preString = "acos(";
603 break;
604 case EOpAtan:
605 preString = "atan(";
606 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000607
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200608 case EOpSinh:
609 preString = "sinh(";
610 break;
611 case EOpCosh:
612 preString = "cosh(";
613 break;
614 case EOpTanh:
615 preString = "tanh(";
616 break;
617 case EOpAsinh:
618 preString = "asinh(";
619 break;
620 case EOpAcosh:
621 preString = "acosh(";
622 break;
623 case EOpAtanh:
624 preString = "atanh(";
625 break;
626
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700627 case EOpExp:
628 preString = "exp(";
629 break;
630 case EOpLog:
631 preString = "log(";
632 break;
633 case EOpExp2:
634 preString = "exp2(";
635 break;
636 case EOpLog2:
637 preString = "log2(";
638 break;
639 case EOpSqrt:
640 preString = "sqrt(";
641 break;
642 case EOpInverseSqrt:
643 preString = "inversesqrt(";
644 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000645
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700646 case EOpAbs:
647 preString = "abs(";
648 break;
649 case EOpSign:
650 preString = "sign(";
651 break;
652 case EOpFloor:
653 preString = "floor(";
654 break;
Qingqing Deng5dbece52015-02-27 20:35:38 -0800655 case EOpTrunc:
656 preString = "trunc(";
657 break;
658 case EOpRound:
659 preString = "round(";
660 break;
661 case EOpRoundEven:
662 preString = "roundEven(";
663 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700664 case EOpCeil:
665 preString = "ceil(";
666 break;
667 case EOpFract:
668 preString = "fract(";
669 break;
Arun Patole0c1726e2015-02-18 14:35:02 +0530670 case EOpIsNan:
671 preString = "isnan(";
672 break;
673 case EOpIsInf:
674 preString = "isinf(";
675 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000676
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200677 case EOpFloatBitsToInt:
678 preString = "floatBitsToInt(";
679 break;
680 case EOpFloatBitsToUint:
681 preString = "floatBitsToUint(";
682 break;
683 case EOpIntBitsToFloat:
684 preString = "intBitsToFloat(";
685 break;
686 case EOpUintBitsToFloat:
687 preString = "uintBitsToFloat(";
688 break;
689
Olli Etuaho7700ff62015-01-15 12:16:29 +0200690 case EOpPackSnorm2x16:
691 preString = "packSnorm2x16(";
692 break;
693 case EOpPackUnorm2x16:
694 preString = "packUnorm2x16(";
695 break;
696 case EOpPackHalf2x16:
697 preString = "packHalf2x16(";
698 break;
699 case EOpUnpackSnorm2x16:
700 preString = "unpackSnorm2x16(";
701 break;
702 case EOpUnpackUnorm2x16:
703 preString = "unpackUnorm2x16(";
704 break;
705 case EOpUnpackHalf2x16:
706 preString = "unpackHalf2x16(";
707 break;
708
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700709 case EOpLength:
710 preString = "length(";
711 break;
712 case EOpNormalize:
713 preString = "normalize(";
714 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000715
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700716 case EOpDFdx:
717 preString = "dFdx(";
718 break;
719 case EOpDFdy:
720 preString = "dFdy(";
721 break;
722 case EOpFwidth:
723 preString = "fwidth(";
724 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000725
Olli Etuahoe39706d2014-12-30 16:40:36 +0200726 case EOpTranspose:
727 preString = "transpose(";
728 break;
729 case EOpDeterminant:
730 preString = "determinant(";
731 break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +0200732 case EOpInverse:
733 preString = "inverse(";
734 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200735
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700736 case EOpAny:
737 preString = "any(";
738 break;
739 case EOpAll:
740 preString = "all(";
741 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000742
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700743 default:
744 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000745 }
746
zmo@google.com32e97312011-08-24 01:03:11 +0000747 if (visit == PreVisit && node->getUseEmulatedFunction())
748 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
749 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
750
zmo@google.com5601ea02011-06-10 18:23:25 +0000751 return true;
752}
753
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300754bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
755{
756 TInfoSinkBase &out = objSink();
757 // Notice two brackets at the beginning and end. The outer ones
758 // encapsulate the whole ternary expression. This preserves the
759 // order of precedence when ternary expressions are used in a
760 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
761 out << "((";
762 node->getCondition()->traverse(this);
763 out << ") ? (";
764 node->getTrueExpression()->traverse(this);
765 out << ") : (";
766 node->getFalseExpression()->traverse(this);
767 out << "))";
768 return false;
769}
770
Olli Etuaho57961272016-09-14 13:57:46 +0300771bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000772{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700773 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000774
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300775 out << "if (";
776 node->getCondition()->traverse(this);
777 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000778
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300779 incrementDepth(node);
780 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000781
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300782 if (node->getFalseBlock())
783 {
784 out << "else\n";
785 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000786 }
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300787 decrementDepth();
zmo@google.com5601ea02011-06-10 18:23:25 +0000788 return false;
789}
790
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200791bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200792{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200793 if (node->getStatementList())
794 {
795 writeTriplet(visit, "switch (", ") ", nullptr);
796 // The curly braces get written when visiting the statementList aggregate
797 }
798 else
799 {
800 // No statementList, so it won't output curly braces
801 writeTriplet(visit, "switch (", ") {", "}\n");
802 }
803 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200804}
805
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200806bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200807{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200808 if (node->hasCondition())
809 {
810 writeTriplet(visit, "case (", nullptr, "):\n");
811 return true;
812 }
813 else
814 {
815 TInfoSinkBase &out = objSink();
816 out << "default:\n";
817 return false;
818 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200819}
820
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100821bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
822{
823 TInfoSinkBase &out = objSink();
824 // Scope the blocks except when at the global scope.
825 if (mDepth > 0)
826 {
827 out << "{\n";
828 }
829
830 incrementDepth(node);
831 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
832 iter != node->getSequence()->end(); ++iter)
833 {
834 TIntermNode *curNode = *iter;
835 ASSERT(curNode != nullptr);
836 curNode->traverse(this);
837
838 if (isSingleStatement(curNode))
839 out << ";\n";
840 }
841 decrementDepth();
842
843 // Scope the blocks except when at the global scope.
844 if (mDepth > 0)
845 {
846 out << "}\n";
847 }
848 return false;
849}
850
Olli Etuaho336b1472016-10-05 16:37:55 +0100851bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
852{
853 TInfoSinkBase &out = objSink();
854
855 ASSERT(visit == PreVisit);
856 {
857 const TType &type = node->getType();
858 writeVariableType(type);
859 if (type.isArray())
860 out << arrayBrackets(type);
861 }
862
863 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
864
865 incrementDepth(node);
866
867 // Traverse function parameters.
868 TIntermAggregate *params = node->getFunctionParameters()->getAsAggregate();
869 ASSERT(params->getOp() == EOpParameters);
870 params->traverse(this);
871
872 // Traverse function body.
873 visitCodeBlock(node->getBody());
874 decrementDepth();
875
876 // Fully processed; no need to visit children.
877 return false;
878}
879
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700880bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000881{
882 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700883 TInfoSinkBase &out = objSink();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700884 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000885 switch (node->getOp())
886 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700887 case EOpPrototype:
888 // Function declaration.
889 ASSERT(visit == PreVisit);
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300890 {
891 const TType &type = node->getType();
892 writeVariableType(type);
893 if (type.isArray())
894 out << arrayBrackets(type);
895 }
896
Olli Etuahobd674552016-10-06 13:28:42 +0100897 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700898
899 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700900 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700901 out << ")";
902
903 visitChildren = false;
904 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700905 case EOpFunctionCall:
906 // Function call.
907 if (visit == PreVisit)
Olli Etuahobd674552016-10-06 13:28:42 +0100908 out << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200909 else if (visit == InVisit)
910 out << ", ";
911 else
912 out << ")";
913 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700914 case EOpParameters:
915 // Function parameters.
916 ASSERT(visit == PreVisit);
917 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700918 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700919 out << ")";
920 visitChildren = false;
921 break;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700922 case EOpInvariantDeclaration:
923 // Invariant declaration.
924 ASSERT(visit == PreVisit);
925 {
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400926 const TIntermSequence *sequence = node->getSequence();
927 ASSERT(sequence && sequence->size() == 1);
928 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
929 ASSERT(symbol);
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000930 out << "invariant " << hashVariableName(symbol->getName());
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400931 }
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700932 visitChildren = false;
933 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700934 case EOpConstructFloat:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700935 case EOpConstructVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700936 case EOpConstructVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700937 case EOpConstructVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700938 case EOpConstructBool:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700939 case EOpConstructBVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700940 case EOpConstructBVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700941 case EOpConstructBVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700942 case EOpConstructInt:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700943 case EOpConstructIVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700944 case EOpConstructIVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700945 case EOpConstructIVec4:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400946 case EOpConstructUInt:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400947 case EOpConstructUVec2:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400948 case EOpConstructUVec3:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400949 case EOpConstructUVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700950 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400951 case EOpConstructMat2x3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400952 case EOpConstructMat2x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400953 case EOpConstructMat3x2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700954 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400955 case EOpConstructMat3x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400956 case EOpConstructMat4x2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400957 case EOpConstructMat4x3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700958 case EOpConstructMat4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700959 case EOpConstructStruct:
Olli Etuahoe92507b2016-07-04 11:20:10 +0300960 writeConstructorTriplet(visit, node->getType());
961 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000962
Olli Etuahoe39706d2014-12-30 16:40:36 +0200963 case EOpOuterProduct:
964 writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
965 break;
966
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700967 case EOpLessThan:
968 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
969 break;
970 case EOpGreaterThan:
971 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
972 break;
973 case EOpLessThanEqual:
974 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
975 break;
976 case EOpGreaterThanEqual:
977 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
978 break;
979 case EOpVectorEqual:
980 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
981 break;
982 case EOpVectorNotEqual:
983 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
984 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000985
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700986 case EOpMod:
987 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
988 break;
Olli Etuahob6e07a62015-02-16 12:22:10 +0200989 case EOpModf:
990 writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
991 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700992 case EOpPow:
993 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
994 break;
995 case EOpAtan:
996 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
997 break;
998 case EOpMin:
999 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
1000 break;
1001 case EOpMax:
1002 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
1003 break;
1004 case EOpClamp:
1005 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
1006 break;
1007 case EOpMix:
1008 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
1009 break;
1010 case EOpStep:
1011 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
1012 break;
1013 case EOpSmoothStep:
1014 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
1015 break;
1016 case EOpDistance:
1017 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
1018 break;
1019 case EOpDot:
1020 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
1021 break;
1022 case EOpCross:
1023 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
1024 break;
1025 case EOpFaceForward:
1026 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
1027 break;
1028 case EOpReflect:
1029 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
1030 break;
1031 case EOpRefract:
1032 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
1033 break;
1034 case EOpMul:
1035 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
1036 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001037
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001038 default:
1039 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001040 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001041 return visitChildren;
1042}
1043
Olli Etuaho13389b62016-10-16 11:48:18 +01001044bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
1045{
1046 TInfoSinkBase &out = objSink();
1047
1048 // Variable declaration.
1049 if (visit == PreVisit)
1050 {
1051 const TIntermSequence &sequence = *(node->getSequence());
1052 const TIntermTyped *variable = sequence.front()->getAsTyped();
1053 writeLayoutQualifier(variable->getType());
1054 writeVariableType(variable->getType());
1055 out << " ";
1056 mDeclaringVariables = true;
1057 }
1058 else if (visit == InVisit)
1059 {
1060 out << ", ";
1061 mDeclaringVariables = true;
1062 }
1063 else
1064 {
1065 mDeclaringVariables = false;
1066 }
1067 return true;
1068}
1069
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001070bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001071{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001072 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001073
Zhenyao Mo7cab38b2013-10-15 12:59:30 -07001074 incrementDepth(node);
Corentin Wallez7258e302015-09-22 10:40:24 -07001075
zmo@google.com5601ea02011-06-10 18:23:25 +00001076 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001077
1078 // Only for loops can be unrolled
1079 ASSERT(!node->getUnrollFlag() || loopType == ELoopFor);
1080
zmo@google.com5601ea02011-06-10 18:23:25 +00001081 if (loopType == ELoopFor) // for loop
1082 {
Zhenyao Mo550c6002014-02-26 15:40:48 -08001083 if (!node->getUnrollFlag())
1084 {
zmo@google.com5601ea02011-06-10 18:23:25 +00001085 out << "for (";
1086 if (node->getInit())
1087 node->getInit()->traverse(this);
1088 out << "; ";
1089
1090 if (node->getCondition())
1091 node->getCondition()->traverse(this);
1092 out << "; ";
1093
1094 if (node->getExpression())
1095 node->getExpression()->traverse(this);
1096 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001097
1098 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001099 }
Zhenyao Mo550c6002014-02-26 15:40:48 -08001100 else
1101 {
1102 // Need to put a one-iteration loop here to handle break.
Olli Etuaho13389b62016-10-16 11:48:18 +01001103 TIntermSequence *declSeq = node->getInit()->getAsDeclarationNode()->getSequence();
Zhenyao Mo550c6002014-02-26 15:40:48 -08001104 TIntermSymbol *indexSymbol =
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001105 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001106 TString name = hashVariableName(indexSymbol->getName());
Zhenyao Mo550c6002014-02-26 15:40:48 -08001107 out << "for (int " << name << " = 0; "
1108 << name << " < 1; "
1109 << "++" << name << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001110
1111 out << "{\n";
1112 mLoopUnrollStack.push(node);
1113 while (mLoopUnrollStack.satisfiesLoopCondition())
1114 {
1115 visitCodeBlock(node->getBody());
1116 mLoopUnrollStack.step();
1117 }
1118 mLoopUnrollStack.pop();
1119 out << "}\n";
Zhenyao Mo550c6002014-02-26 15:40:48 -08001120 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001121 }
1122 else if (loopType == ELoopWhile) // while loop
1123 {
1124 out << "while (";
1125 ASSERT(node->getCondition() != NULL);
1126 node->getCondition()->traverse(this);
1127 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001128
1129 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001130 }
1131 else // do-while loop
1132 {
1133 ASSERT(loopType == ELoopDoWhile);
1134 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001135
zmo@google.com5601ea02011-06-10 18:23:25 +00001136 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001137
zmo@google.com5601ea02011-06-10 18:23:25 +00001138 out << "while (";
1139 ASSERT(node->getCondition() != NULL);
1140 node->getCondition()->traverse(this);
1141 out << ");\n";
1142 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001143
zmo@google.com5601ea02011-06-10 18:23:25 +00001144 decrementDepth();
1145
1146 // No need to visit children. They have been already processed in
1147 // this function.
1148 return false;
1149}
1150
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001151bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001152{
1153 switch (node->getFlowOp())
1154 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001155 case EOpKill:
1156 writeTriplet(visit, "discard", NULL, NULL);
1157 break;
1158 case EOpBreak:
1159 writeTriplet(visit, "break", NULL, NULL);
1160 break;
1161 case EOpContinue:
1162 writeTriplet(visit, "continue", NULL, NULL);
1163 break;
1164 case EOpReturn:
1165 writeTriplet(visit, "return ", NULL, NULL);
1166 break;
1167 default:
1168 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001169 }
1170
1171 return true;
1172}
1173
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001174void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001175{
zmo@google.com5601ea02011-06-10 18:23:25 +00001176 TInfoSinkBase &out = objSink();
1177 if (node != NULL)
1178 {
1179 node->traverse(this);
1180 // Single statements not part of a sequence need to be terminated
1181 // with semi-colon.
1182 if (isSingleStatement(node))
1183 out << ";\n";
1184 }
1185 else
1186 {
1187 out << "{\n}\n"; // Empty code block.
1188 }
1189}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001190
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001191TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001192{
Olli Etuahoe92507b2016-07-04 11:20:10 +03001193 if (type.getBasicType() == EbtStruct)
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001194 return hashName(TName(type.getStruct()->name()));
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001195 else
Olli Etuahoe92507b2016-07-04 11:20:10 +03001196 return type.getBuiltInTypeNameString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001197}
1198
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001199TString TOutputGLSLBase::hashName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001200{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001201 if (name.getString().empty())
1202 {
1203 ASSERT(!name.isInternal());
1204 return name.getString();
1205 }
1206 if (name.isInternal())
1207 {
1208 // TODO(oetuaho): Would be nicer to prefix non-internal names with "_" instead, like is
1209 // done in the HLSL output, but that requires fairly complex changes elsewhere in the code
1210 // as well.
1211 // We need to use a prefix that is reserved in WebGL in order to guarantee that the internal
1212 // names don't conflict with user-defined names from WebGL.
1213 return "webgl_angle_" + name.getString();
1214 }
1215 if (mHashFunction == nullptr)
1216 {
1217 return name.getString();
1218 }
1219 NameMap::const_iterator it = mNameMap.find(name.getString().c_str());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001220 if (it != mNameMap.end())
1221 return it->second.c_str();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001222 TString hashedName = TIntermTraverser::hash(name.getString(), mHashFunction);
1223 mNameMap[name.getString().c_str()] = hashedName.c_str();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001224 return hashedName;
1225}
1226
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001227TString TOutputGLSLBase::hashVariableName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001228{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001229 if (mSymbolTable.findBuiltIn(name.getString(), mShaderVersion) != NULL)
1230 return name.getString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001231 return hashName(name);
1232}
1233
Olli Etuaho59f9a642015-08-06 20:38:26 +03001234TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001235{
Olli Etuaho59f9a642015-08-06 20:38:26 +03001236 TString mangledStr = mangledName.getString();
1237 TString name = TFunction::unmangleName(mangledStr);
1238 if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001239 return translateTextureFunction(name);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001240 if (mangledName.isInternal())
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001241 {
1242 // Internal function names are outputted as-is - they may refer to functions manually added
1243 // to the output shader source that are not included in the AST at all.
Olli Etuaho59f9a642015-08-06 20:38:26 +03001244 return name;
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001245 }
Olli Etuaho59f9a642015-08-06 20:38:26 +03001246 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001247 {
1248 TName nameObj(name);
1249 return hashName(nameObj);
1250 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001251}
Jamie Madill98493dd2013-07-08 14:39:03 -04001252
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001253bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001254{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001255 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001256 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001257 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001258 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001259 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001260
1261 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001262}
1263
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001264void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001265{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001266 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001267
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001268 out << "struct " << hashName(TName(structure->name())) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001269 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001270 for (size_t i = 0; i < fields.size(); ++i)
1271 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001272 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001273 if (writeVariablePrecision(field->type()->getPrecision()))
1274 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001275 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Jamie Madill98493dd2013-07-08 14:39:03 -04001276 if (field->type()->isArray())
1277 out << arrayBrackets(*field->type());
1278 out << ";\n";
1279 }
1280 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001281}
Jamie Madill98493dd2013-07-08 14:39:03 -04001282
Geoff Langbdcc54a2015-09-02 13:09:48 -04001283void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1284{
1285 TInfoSinkBase &out = objSink();
1286
1287 out << "layout(";
1288
1289 switch (interfaceBlock->blockStorage())
1290 {
1291 case EbsUnspecified:
1292 case EbsShared:
1293 // Default block storage is shared.
1294 out << "shared";
1295 break;
1296
1297 case EbsPacked:
1298 out << "packed";
1299 break;
1300
1301 case EbsStd140:
1302 out << "std140";
1303 break;
1304
1305 default:
1306 UNREACHABLE();
1307 break;
1308 }
1309
1310 out << ", ";
1311
1312 switch (interfaceBlock->matrixPacking())
1313 {
1314 case EmpUnspecified:
1315 case EmpColumnMajor:
1316 // Default matrix packing is column major.
1317 out << "column_major";
1318 break;
1319
1320 case EmpRowMajor:
1321 out << "row_major";
1322 break;
1323
1324 default:
1325 UNREACHABLE();
1326 break;
1327 }
1328
1329 out << ") ";
1330}
1331
1332void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1333{
1334 TInfoSinkBase &out = objSink();
1335
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001336 out << hashName(TName(interfaceBlock->name())) << "{\n";
Geoff Langbdcc54a2015-09-02 13:09:48 -04001337 const TFieldList &fields = interfaceBlock->fields();
1338 for (size_t i = 0; i < fields.size(); ++i)
1339 {
1340 const TField *field = fields[i];
1341 if (writeVariablePrecision(field->type()->getPrecision()))
1342 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001343 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Geoff Langbdcc54a2015-09-02 13:09:48 -04001344 if (field->type()->isArray())
1345 out << arrayBrackets(*field->type());
1346 out << ";\n";
1347 }
1348 out << "}";
1349}