blob: 86eb3d3ee87c4c6e73583536d68903ac1d07139c [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
Jamie Madill45bcc782016-11-07 13:58:48 -050013namespace sh
14{
15
zmo@google.com5601ea02011-06-10 18:23:25 +000016namespace
17{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070018TString arrayBrackets(const TType &type)
zmo@google.com5601ea02011-06-10 18:23:25 +000019{
20 ASSERT(type.isArray());
21 TInfoSinkBase out;
22 out << "[" << type.getArraySize() << "]";
23 return TString(out.c_str());
24}
25
Zhenyao Mo9eedea02014-05-12 16:02:35 -070026bool isSingleStatement(TIntermNode *node)
27{
Olli Etuaho336b1472016-10-05 16:37:55 +010028 if (node->getAsFunctionDefinition())
zmo@google.com5601ea02011-06-10 18:23:25 +000029 {
Olli Etuaho336b1472016-10-05 16:37:55 +010030 return false;
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010031 }
32 else if (node->getAsBlock())
33 {
34 return false;
zmo@google.com5601ea02011-06-10 18:23:25 +000035 }
Olli Etuaho57961272016-09-14 13:57:46 +030036 else if (node->getAsIfElseNode())
zmo@google.com5601ea02011-06-10 18:23:25 +000037 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +030038 return false;
zmo@google.com5601ea02011-06-10 18:23:25 +000039 }
40 else if (node->getAsLoopNode())
41 {
42 return false;
43 }
Olli Etuaho01cd8af2015-02-20 10:39:20 +020044 else if (node->getAsSwitchNode())
45 {
46 return false;
47 }
48 else if (node->getAsCaseNode())
49 {
50 return false;
51 }
zmo@google.com5601ea02011-06-10 18:23:25 +000052 return true;
53}
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080054
Martin Radev2cc85b32016-08-05 16:22:53 +030055// If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
56// variables with specified layout qualifiers are copied. Additional checks are needed against the
57// type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
58// TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
59// NeedsToWriteLayoutQualifier.
60bool NeedsToWriteLayoutQualifier(const TType &type)
61{
62 if (type.getBasicType() == EbtInterfaceBlock)
63 {
64 return false;
65 }
66
67 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
68
69 if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn) &&
70 layoutQualifier.location >= 0)
71 {
72 return true;
73 }
74 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
75 {
76 return true;
77 }
78 return false;
79}
80
zmo@google.com5601ea02011-06-10 18:23:25 +000081} // namespace
82
Zhenyao Mo9eedea02014-05-12 16:02:35 -070083TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000084 ShArrayIndexClampingStrategy clampingStrategy,
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000085 ShHashFunction64 hashFunction,
Zhenyao Mo9eedea02014-05-12 16:02:35 -070086 NameMap &nameMap,
87 TSymbolTable &symbolTable,
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080088 int shaderVersion,
Qiankun Miao705a9192016-08-29 10:05:27 +080089 ShShaderOutput output,
90 ShCompileOptions compileOptions)
zmo@google.com5601ea02011-06-10 18:23:25 +000091 : TIntermTraverser(true, true, true),
92 mObjSink(objSink),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000093 mDeclaringVariables(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000094 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000095 mHashFunction(hashFunction),
96 mNameMap(nameMap),
Jamie Madill02f20dd2013-09-12 12:07:42 -040097 mSymbolTable(symbolTable),
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080098 mShaderVersion(shaderVersion),
Qiankun Miao705a9192016-08-29 10:05:27 +080099 mOutput(output),
100 mCompileOptions(compileOptions)
zmo@google.com5601ea02011-06-10 18:23:25 +0000101{
102}
103
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700104void TOutputGLSLBase::writeTriplet(
105 Visit visit, const char *preStr, const char *inStr, const char *postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000106{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700107 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000108 if (visit == PreVisit && preStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000109 out << preStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000110 else if (visit == InVisit && inStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000111 out << inStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000112 else if (visit == PostVisit && postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000113 out << postStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000114}
115
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700116void TOutputGLSLBase::writeBuiltInFunctionTriplet(
117 Visit visit, const char *preStr, bool useEmulatedFunction)
zmo@google.com5601ea02011-06-10 18:23:25 +0000118{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700119 TString preString = useEmulatedFunction ?
120 BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
121 writeTriplet(visit, preString.c_str(), ", ", ")");
122}
123
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300124void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
125{
Martin Radev2cc85b32016-08-05 16:22:53 +0300126 if (!NeedsToWriteLayoutQualifier(type))
127 {
128 return;
129 }
130
131 TInfoSinkBase &out = objSink();
132 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
133 out << "layout(";
134
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300135 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
136 {
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300137 if (layoutQualifier.location >= 0)
138 {
Martin Radev2cc85b32016-08-05 16:22:53 +0300139 out << "location = " << layoutQualifier.location;
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300140 }
141 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300142
143 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
144 {
145 ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
146 out << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
147 }
148
149 out << ") ";
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300150}
151
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700152void TOutputGLSLBase::writeVariableType(const TType &type)
153{
Qiankun Miao705a9192016-08-29 10:05:27 +0800154 TQualifier qualifier = type.getQualifier();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700155 TInfoSinkBase &out = objSink();
Jamie Madillacb4b812016-11-07 13:50:29 -0500156 bool removeInvariant = (qualifier == EvqVaryingIn && sh::IsGLSL420OrNewer(mOutput) &&
Qiankun Miao705a9192016-08-29 10:05:27 +0800157 !(mCompileOptions & SH_DONT_REMOVE_INVARIANT_FOR_FRAGMENT_INPUT));
158 if (type.isInvariant() && !removeInvariant)
Olli Etuaho214c2d82015-04-27 14:49:13 +0300159 {
160 out << "invariant ";
161 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400162 if (type.getBasicType() == EbtInterfaceBlock)
163 {
164 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
165 declareInterfaceBlockLayout(interfaceBlock);
166 }
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400167 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400168 {
Jamie Madillacb4b812016-11-07 13:50:29 -0500169 if (sh::IsGLSL130OrNewer(mOutput))
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800170 {
171 switch (qualifier)
172 {
173 case EvqAttribute:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300174 out << "in ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800175 break;
176 case EvqVaryingIn:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300177 out << "in ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800178 break;
179 case EvqVaryingOut:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300180 out << "out ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800181 break;
182 default:
183 out << type.getQualifierString() << " ";
184 break;
185 }
186 }
187 else
188 {
189 out << type.getQualifierString() << " ";
190 }
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400191 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300192
193 const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
194 if (memoryQualifier.readonly)
195 {
196 ASSERT(IsImage(type.getBasicType()));
197 out << "readonly ";
198 }
199
200 if (memoryQualifier.writeonly)
201 {
202 ASSERT(IsImage(type.getBasicType()));
203 out << "writeonly ";
204 }
205
zmo@google.com5601ea02011-06-10 18:23:25 +0000206 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700207 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000208 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400209 TStructure *structure = type.getStruct();
210
211 declareStruct(structure);
212
213 if (!structure->name().empty())
214 {
215 mDeclaredStructs.insert(structure->uniqueId());
216 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000217 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400218 else if (type.getBasicType() == EbtInterfaceBlock)
219 {
220 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
221 declareInterfaceBlock(interfaceBlock);
222 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000223 else
224 {
225 if (writeVariablePrecision(type.getPrecision()))
226 out << " ";
227 out << getTypeName(type);
228 }
229}
230
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700231void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000232{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700233 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000234 for (TIntermSequence::const_iterator iter = args.begin();
235 iter != args.end(); ++iter)
236 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700237 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000238 ASSERT(arg != NULL);
239
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700240 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000241 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000242
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000243 if (!arg->getName().getString().empty())
244 out << " " << hashName(arg->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000245 if (type.isArray())
246 out << arrayBrackets(type);
247
248 // Put a comma if this is not the last argument.
249 if (iter != args.end() - 1)
250 out << ", ";
251 }
252}
253
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400254const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
255 const TType &type, const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000256{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700257 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000258
259 if (type.getBasicType() == EbtStruct)
260 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700261 const TStructure *structure = type.getStruct();
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000262 out << hashName(TName(structure->name())) << "(";
Jamie Madill98493dd2013-07-08 14:39:03 -0400263
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700264 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400265 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000266 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700267 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000268 ASSERT(fieldType != NULL);
269 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700270 if (i != fields.size() - 1)
271 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000272 }
273 out << ")";
274 }
275 else
276 {
Jamie Madill94bf7f22013-07-08 13:31:15 -0400277 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000278 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700279 if (writeType)
280 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400281 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000282 {
283 switch (pConstUnion->getType())
284 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700285 case EbtFloat:
286 out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
287 break;
288 case EbtInt:
289 out << pConstUnion->getIConst();
290 break;
Olli Etuaho5321c802015-04-02 17:08:16 +0300291 case EbtUInt:
292 out << pConstUnion->getUConst() << "u";
293 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700294 case EbtBool:
295 out << pConstUnion->getBConst();
296 break;
297 default: UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000298 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700299 if (i != size - 1)
300 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000301 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700302 if (writeType)
303 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000304 }
305 return pConstUnion;
306}
307
Olli Etuahoe92507b2016-07-04 11:20:10 +0300308void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
Olli Etuahof40319e2015-03-10 14:33:00 +0200309{
310 TInfoSinkBase &out = objSink();
311 if (visit == PreVisit)
312 {
313 if (type.isArray())
314 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300315 out << getTypeName(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200316 out << arrayBrackets(type);
317 out << "(";
318 }
319 else
320 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300321 out << getTypeName(type) << "(";
Olli Etuahof40319e2015-03-10 14:33:00 +0200322 }
323 }
324 else
325 {
326 writeTriplet(visit, nullptr, ", ", ")");
327 }
328}
329
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700330void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000331{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700332 TInfoSinkBase &out = objSink();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800333 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
334 out << mLoopUnrollStack.getLoopIndexValue(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000335 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000336 out << hashVariableName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000337
338 if (mDeclaringVariables && node->getType().isArray())
339 out << arrayBrackets(node->getType());
340}
341
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700342void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000343{
344 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
345}
346
Olli Etuahob6fa0432016-09-28 16:28:05 +0100347bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
348{
349 TInfoSinkBase &out = objSink();
350 if (visit == PostVisit)
351 {
352 out << ".";
353 node->writeOffsetsAsXYZW(&out);
354 }
355 return true;
356}
357
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700358bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000359{
360 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700361 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000362 switch (node->getOp())
363 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100364 case EOpComma:
365 writeTriplet(visit, "(", ", ", ")");
366 break;
367 case EOpInitialize:
zmo@google.com5601ea02011-06-10 18:23:25 +0000368 if (visit == InVisit)
369 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100370 out << " = ";
371 // RHS of initialize is not being declared.
372 mDeclaringVariables = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000373 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100374 break;
375 case EOpAssign:
376 writeTriplet(visit, "(", " = ", ")");
377 break;
378 case EOpAddAssign:
379 writeTriplet(visit, "(", " += ", ")");
380 break;
381 case EOpSubAssign:
382 writeTriplet(visit, "(", " -= ", ")");
383 break;
384 case EOpDivAssign:
385 writeTriplet(visit, "(", " /= ", ")");
386 break;
387 case EOpIModAssign:
388 writeTriplet(visit, "(", " %= ", ")");
389 break;
390 // Notice the fall-through.
391 case EOpMulAssign:
392 case EOpVectorTimesMatrixAssign:
393 case EOpVectorTimesScalarAssign:
394 case EOpMatrixTimesScalarAssign:
395 case EOpMatrixTimesMatrixAssign:
396 writeTriplet(visit, "(", " *= ", ")");
397 break;
398 case EOpBitShiftLeftAssign:
399 writeTriplet(visit, "(", " <<= ", ")");
400 break;
401 case EOpBitShiftRightAssign:
402 writeTriplet(visit, "(", " >>= ", ")");
403 break;
404 case EOpBitwiseAndAssign:
405 writeTriplet(visit, "(", " &= ", ")");
406 break;
407 case EOpBitwiseXorAssign:
408 writeTriplet(visit, "(", " ^= ", ")");
409 break;
410 case EOpBitwiseOrAssign:
411 writeTriplet(visit, "(", " |= ", ")");
412 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000413
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100414 case EOpIndexDirect:
zmo@google.com5601ea02011-06-10 18:23:25 +0000415 writeTriplet(visit, NULL, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100416 break;
417 case EOpIndexIndirect:
418 if (node->getAddIndexClamp())
419 {
420 if (visit == InVisit)
421 {
422 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
423 out << "[int(clamp(float(";
424 else
425 out << "[webgl_int_clamp(";
426 }
427 else if (visit == PostVisit)
428 {
429 int maxSize;
430 TIntermTyped *left = node->getLeft();
431 TType leftType = left->getType();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700432
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100433 if (left->isArray())
434 {
435 // The shader will fail validation if the array length is not > 0.
436 maxSize = static_cast<int>(leftType.getArraySize()) - 1;
437 }
438 else
439 {
440 maxSize = leftType.getNominalSize() - 1;
441 }
442
443 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
444 out << "), 0.0, float(" << maxSize << ")))]";
445 else
446 out << ", 0, " << maxSize << ")]";
447 }
448 }
449 else
450 {
451 writeTriplet(visit, NULL, "[", "]");
452 }
453 break;
454 case EOpIndexDirectStruct:
455 if (visit == InVisit)
456 {
457 // Here we are writing out "foo.bar", where "foo" is struct
458 // and "bar" is field. In AST, it is represented as a binary
459 // node, where left child represents "foo" and right child "bar".
460 // The node itself represents ".". The struct field "bar" is
461 // actually stored as an index into TStructure::fields.
462 out << ".";
463 const TStructure *structure = node->getLeft()->getType().getStruct();
464 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
465 const TField *field = structure->fields()[index->getIConst(0)];
466
467 TString fieldName = field->name();
468 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000469 fieldName = hashName(TName(fieldName));
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100470
471 out << fieldName;
472 visitChildren = false;
473 }
474 break;
475 case EOpIndexDirectInterfaceBlock:
476 if (visit == InVisit)
477 {
478 out << ".";
479 const TInterfaceBlock *interfaceBlock =
480 node->getLeft()->getType().getInterfaceBlock();
481 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
482 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
483
484 TString fieldName = field->name();
485 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000486 fieldName = hashName(TName(fieldName));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700487
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100488 out << fieldName;
489 visitChildren = false;
490 }
491 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400492
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100493 case EOpAdd:
494 writeTriplet(visit, "(", " + ", ")");
495 break;
496 case EOpSub:
497 writeTriplet(visit, "(", " - ", ")");
498 break;
499 case EOpMul:
500 writeTriplet(visit, "(", " * ", ")");
501 break;
502 case EOpDiv:
503 writeTriplet(visit, "(", " / ", ")");
504 break;
505 case EOpIMod:
506 writeTriplet(visit, "(", " % ", ")");
507 break;
508 case EOpBitShiftLeft:
509 writeTriplet(visit, "(", " << ", ")");
510 break;
511 case EOpBitShiftRight:
512 writeTriplet(visit, "(", " >> ", ")");
513 break;
514 case EOpBitwiseAnd:
515 writeTriplet(visit, "(", " & ", ")");
516 break;
517 case EOpBitwiseXor:
518 writeTriplet(visit, "(", " ^ ", ")");
519 break;
520 case EOpBitwiseOr:
521 writeTriplet(visit, "(", " | ", ")");
522 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400523
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100524 case EOpEqual:
525 writeTriplet(visit, "(", " == ", ")");
526 break;
527 case EOpNotEqual:
528 writeTriplet(visit, "(", " != ", ")");
529 break;
530 case EOpLessThan:
531 writeTriplet(visit, "(", " < ", ")");
532 break;
533 case EOpGreaterThan:
534 writeTriplet(visit, "(", " > ", ")");
535 break;
536 case EOpLessThanEqual:
537 writeTriplet(visit, "(", " <= ", ")");
538 break;
539 case EOpGreaterThanEqual:
540 writeTriplet(visit, "(", " >= ", ")");
541 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000542
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100543 // Notice the fall-through.
544 case EOpVectorTimesScalar:
545 case EOpVectorTimesMatrix:
546 case EOpMatrixTimesVector:
547 case EOpMatrixTimesScalar:
548 case EOpMatrixTimesMatrix:
549 writeTriplet(visit, "(", " * ", ")");
550 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200551
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100552 case EOpLogicalOr:
553 writeTriplet(visit, "(", " || ", ")");
554 break;
555 case EOpLogicalXor:
556 writeTriplet(visit, "(", " ^^ ", ")");
557 break;
558 case EOpLogicalAnd:
559 writeTriplet(visit, "(", " && ", ")");
560 break;
561 default:
562 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000563 }
564
565 return visitChildren;
566}
567
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700568bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000569{
zmo@google.com32e97312011-08-24 01:03:11 +0000570 TString preString;
571 TString postString = ")";
572
zmo@google.com5601ea02011-06-10 18:23:25 +0000573 switch (node->getOp())
574 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700575 case EOpNegative: preString = "(-"; break;
Zhenyao Mode1e00e2014-10-09 16:55:32 -0700576 case EOpPositive: preString = "(+"; break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700577 case EOpVectorLogicalNot: preString = "not("; break;
578 case EOpLogicalNot: preString = "(!"; break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200579 case EOpBitwiseNot: preString = "(~"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000580
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700581 case EOpPostIncrement: preString = "("; postString = "++)"; break;
582 case EOpPostDecrement: preString = "("; postString = "--)"; break;
583 case EOpPreIncrement: preString = "(++"; break;
584 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000585
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700586 case EOpRadians:
587 preString = "radians(";
588 break;
589 case EOpDegrees:
590 preString = "degrees(";
591 break;
592 case EOpSin:
593 preString = "sin(";
594 break;
595 case EOpCos:
596 preString = "cos(";
597 break;
598 case EOpTan:
599 preString = "tan(";
600 break;
601 case EOpAsin:
602 preString = "asin(";
603 break;
604 case EOpAcos:
605 preString = "acos(";
606 break;
607 case EOpAtan:
608 preString = "atan(";
609 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000610
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200611 case EOpSinh:
612 preString = "sinh(";
613 break;
614 case EOpCosh:
615 preString = "cosh(";
616 break;
617 case EOpTanh:
618 preString = "tanh(";
619 break;
620 case EOpAsinh:
621 preString = "asinh(";
622 break;
623 case EOpAcosh:
624 preString = "acosh(";
625 break;
626 case EOpAtanh:
627 preString = "atanh(";
628 break;
629
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700630 case EOpExp:
631 preString = "exp(";
632 break;
633 case EOpLog:
634 preString = "log(";
635 break;
636 case EOpExp2:
637 preString = "exp2(";
638 break;
639 case EOpLog2:
640 preString = "log2(";
641 break;
642 case EOpSqrt:
643 preString = "sqrt(";
644 break;
645 case EOpInverseSqrt:
646 preString = "inversesqrt(";
647 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000648
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700649 case EOpAbs:
650 preString = "abs(";
651 break;
652 case EOpSign:
653 preString = "sign(";
654 break;
655 case EOpFloor:
656 preString = "floor(";
657 break;
Qingqing Deng5dbece52015-02-27 20:35:38 -0800658 case EOpTrunc:
659 preString = "trunc(";
660 break;
661 case EOpRound:
662 preString = "round(";
663 break;
664 case EOpRoundEven:
665 preString = "roundEven(";
666 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700667 case EOpCeil:
668 preString = "ceil(";
669 break;
670 case EOpFract:
671 preString = "fract(";
672 break;
Arun Patole0c1726e2015-02-18 14:35:02 +0530673 case EOpIsNan:
674 preString = "isnan(";
675 break;
676 case EOpIsInf:
677 preString = "isinf(";
678 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000679
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200680 case EOpFloatBitsToInt:
681 preString = "floatBitsToInt(";
682 break;
683 case EOpFloatBitsToUint:
684 preString = "floatBitsToUint(";
685 break;
686 case EOpIntBitsToFloat:
687 preString = "intBitsToFloat(";
688 break;
689 case EOpUintBitsToFloat:
690 preString = "uintBitsToFloat(";
691 break;
692
Olli Etuaho7700ff62015-01-15 12:16:29 +0200693 case EOpPackSnorm2x16:
694 preString = "packSnorm2x16(";
695 break;
696 case EOpPackUnorm2x16:
697 preString = "packUnorm2x16(";
698 break;
699 case EOpPackHalf2x16:
700 preString = "packHalf2x16(";
701 break;
702 case EOpUnpackSnorm2x16:
703 preString = "unpackSnorm2x16(";
704 break;
705 case EOpUnpackUnorm2x16:
706 preString = "unpackUnorm2x16(";
707 break;
708 case EOpUnpackHalf2x16:
709 preString = "unpackHalf2x16(";
710 break;
711
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700712 case EOpLength:
713 preString = "length(";
714 break;
715 case EOpNormalize:
716 preString = "normalize(";
717 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000718
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700719 case EOpDFdx:
720 preString = "dFdx(";
721 break;
722 case EOpDFdy:
723 preString = "dFdy(";
724 break;
725 case EOpFwidth:
726 preString = "fwidth(";
727 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000728
Olli Etuahoe39706d2014-12-30 16:40:36 +0200729 case EOpTranspose:
730 preString = "transpose(";
731 break;
732 case EOpDeterminant:
733 preString = "determinant(";
734 break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +0200735 case EOpInverse:
736 preString = "inverse(";
737 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200738
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700739 case EOpAny:
740 preString = "any(";
741 break;
742 case EOpAll:
743 preString = "all(";
744 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000745
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700746 default:
747 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000748 }
749
zmo@google.com32e97312011-08-24 01:03:11 +0000750 if (visit == PreVisit && node->getUseEmulatedFunction())
751 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
752 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
753
zmo@google.com5601ea02011-06-10 18:23:25 +0000754 return true;
755}
756
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300757bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
758{
759 TInfoSinkBase &out = objSink();
760 // Notice two brackets at the beginning and end. The outer ones
761 // encapsulate the whole ternary expression. This preserves the
762 // order of precedence when ternary expressions are used in a
763 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
764 out << "((";
765 node->getCondition()->traverse(this);
766 out << ") ? (";
767 node->getTrueExpression()->traverse(this);
768 out << ") : (";
769 node->getFalseExpression()->traverse(this);
770 out << "))";
771 return false;
772}
773
Olli Etuaho57961272016-09-14 13:57:46 +0300774bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000775{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700776 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000777
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300778 out << "if (";
779 node->getCondition()->traverse(this);
780 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000781
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300782 incrementDepth(node);
783 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000784
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300785 if (node->getFalseBlock())
786 {
787 out << "else\n";
788 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000789 }
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300790 decrementDepth();
zmo@google.com5601ea02011-06-10 18:23:25 +0000791 return false;
792}
793
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200794bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200795{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200796 if (node->getStatementList())
797 {
798 writeTriplet(visit, "switch (", ") ", nullptr);
799 // The curly braces get written when visiting the statementList aggregate
800 }
801 else
802 {
803 // No statementList, so it won't output curly braces
804 writeTriplet(visit, "switch (", ") {", "}\n");
805 }
806 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200807}
808
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200809bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200810{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200811 if (node->hasCondition())
812 {
813 writeTriplet(visit, "case (", nullptr, "):\n");
814 return true;
815 }
816 else
817 {
818 TInfoSinkBase &out = objSink();
819 out << "default:\n";
820 return false;
821 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200822}
823
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100824bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
825{
826 TInfoSinkBase &out = objSink();
827 // Scope the blocks except when at the global scope.
828 if (mDepth > 0)
829 {
830 out << "{\n";
831 }
832
833 incrementDepth(node);
834 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
835 iter != node->getSequence()->end(); ++iter)
836 {
837 TIntermNode *curNode = *iter;
838 ASSERT(curNode != nullptr);
839 curNode->traverse(this);
840
841 if (isSingleStatement(curNode))
842 out << ";\n";
843 }
844 decrementDepth();
845
846 // Scope the blocks except when at the global scope.
847 if (mDepth > 0)
848 {
849 out << "}\n";
850 }
851 return false;
852}
853
Olli Etuaho336b1472016-10-05 16:37:55 +0100854bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
855{
856 TInfoSinkBase &out = objSink();
857
858 ASSERT(visit == PreVisit);
859 {
860 const TType &type = node->getType();
861 writeVariableType(type);
862 if (type.isArray())
863 out << arrayBrackets(type);
864 }
865
866 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
867
868 incrementDepth(node);
869
870 // Traverse function parameters.
871 TIntermAggregate *params = node->getFunctionParameters()->getAsAggregate();
872 ASSERT(params->getOp() == EOpParameters);
873 params->traverse(this);
874
875 // Traverse function body.
876 visitCodeBlock(node->getBody());
877 decrementDepth();
878
879 // Fully processed; no need to visit children.
880 return false;
881}
882
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700883bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000884{
885 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700886 TInfoSinkBase &out = objSink();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700887 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000888 switch (node->getOp())
889 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700890 case EOpPrototype:
891 // Function declaration.
892 ASSERT(visit == PreVisit);
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300893 {
894 const TType &type = node->getType();
895 writeVariableType(type);
896 if (type.isArray())
897 out << arrayBrackets(type);
898 }
899
Olli Etuahobd674552016-10-06 13:28:42 +0100900 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700901
902 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700903 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700904 out << ")";
905
906 visitChildren = false;
907 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700908 case EOpFunctionCall:
909 // Function call.
910 if (visit == PreVisit)
Olli Etuahobd674552016-10-06 13:28:42 +0100911 out << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200912 else if (visit == InVisit)
913 out << ", ";
914 else
915 out << ")";
916 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700917 case EOpParameters:
918 // Function parameters.
919 ASSERT(visit == PreVisit);
920 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700921 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700922 out << ")";
923 visitChildren = false;
924 break;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700925 case EOpInvariantDeclaration:
926 // Invariant declaration.
927 ASSERT(visit == PreVisit);
928 {
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400929 const TIntermSequence *sequence = node->getSequence();
930 ASSERT(sequence && sequence->size() == 1);
931 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
932 ASSERT(symbol);
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000933 out << "invariant " << hashVariableName(symbol->getName());
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400934 }
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700935 visitChildren = false;
936 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700937 case EOpConstructFloat:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700938 case EOpConstructVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700939 case EOpConstructVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700940 case EOpConstructVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700941 case EOpConstructBool:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700942 case EOpConstructBVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700943 case EOpConstructBVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700944 case EOpConstructBVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700945 case EOpConstructInt:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700946 case EOpConstructIVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700947 case EOpConstructIVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700948 case EOpConstructIVec4:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400949 case EOpConstructUInt:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400950 case EOpConstructUVec2:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400951 case EOpConstructUVec3:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400952 case EOpConstructUVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700953 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400954 case EOpConstructMat2x3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400955 case EOpConstructMat2x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400956 case EOpConstructMat3x2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700957 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400958 case EOpConstructMat3x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400959 case EOpConstructMat4x2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400960 case EOpConstructMat4x3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700961 case EOpConstructMat4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700962 case EOpConstructStruct:
Olli Etuahoe92507b2016-07-04 11:20:10 +0300963 writeConstructorTriplet(visit, node->getType());
964 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000965
Olli Etuahoe39706d2014-12-30 16:40:36 +0200966 case EOpOuterProduct:
967 writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
968 break;
969
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700970 case EOpLessThan:
971 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
972 break;
973 case EOpGreaterThan:
974 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
975 break;
976 case EOpLessThanEqual:
977 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
978 break;
979 case EOpGreaterThanEqual:
980 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
981 break;
982 case EOpVectorEqual:
983 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
984 break;
985 case EOpVectorNotEqual:
986 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
987 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000988
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700989 case EOpMod:
990 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
991 break;
Olli Etuahob6e07a62015-02-16 12:22:10 +0200992 case EOpModf:
993 writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
994 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700995 case EOpPow:
996 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
997 break;
998 case EOpAtan:
999 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
1000 break;
1001 case EOpMin:
1002 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
1003 break;
1004 case EOpMax:
1005 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
1006 break;
1007 case EOpClamp:
1008 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
1009 break;
1010 case EOpMix:
1011 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
1012 break;
1013 case EOpStep:
1014 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
1015 break;
1016 case EOpSmoothStep:
1017 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
1018 break;
1019 case EOpDistance:
1020 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
1021 break;
1022 case EOpDot:
1023 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
1024 break;
1025 case EOpCross:
1026 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
1027 break;
1028 case EOpFaceForward:
1029 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
1030 break;
1031 case EOpReflect:
1032 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
1033 break;
1034 case EOpRefract:
1035 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
1036 break;
1037 case EOpMul:
1038 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
1039 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001040
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001041 default:
1042 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001043 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001044 return visitChildren;
1045}
1046
Olli Etuaho13389b62016-10-16 11:48:18 +01001047bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
1048{
1049 TInfoSinkBase &out = objSink();
1050
1051 // Variable declaration.
1052 if (visit == PreVisit)
1053 {
1054 const TIntermSequence &sequence = *(node->getSequence());
1055 const TIntermTyped *variable = sequence.front()->getAsTyped();
1056 writeLayoutQualifier(variable->getType());
1057 writeVariableType(variable->getType());
1058 out << " ";
1059 mDeclaringVariables = true;
1060 }
1061 else if (visit == InVisit)
1062 {
1063 out << ", ";
1064 mDeclaringVariables = true;
1065 }
1066 else
1067 {
1068 mDeclaringVariables = false;
1069 }
1070 return true;
1071}
1072
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001073bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001074{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001075 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001076
Zhenyao Mo7cab38b2013-10-15 12:59:30 -07001077 incrementDepth(node);
Corentin Wallez7258e302015-09-22 10:40:24 -07001078
zmo@google.com5601ea02011-06-10 18:23:25 +00001079 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001080
1081 // Only for loops can be unrolled
1082 ASSERT(!node->getUnrollFlag() || loopType == ELoopFor);
1083
zmo@google.com5601ea02011-06-10 18:23:25 +00001084 if (loopType == ELoopFor) // for loop
1085 {
Zhenyao Mo550c6002014-02-26 15:40:48 -08001086 if (!node->getUnrollFlag())
1087 {
zmo@google.com5601ea02011-06-10 18:23:25 +00001088 out << "for (";
1089 if (node->getInit())
1090 node->getInit()->traverse(this);
1091 out << "; ";
1092
1093 if (node->getCondition())
1094 node->getCondition()->traverse(this);
1095 out << "; ";
1096
1097 if (node->getExpression())
1098 node->getExpression()->traverse(this);
1099 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001100
1101 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001102 }
Zhenyao Mo550c6002014-02-26 15:40:48 -08001103 else
1104 {
1105 // Need to put a one-iteration loop here to handle break.
Olli Etuaho13389b62016-10-16 11:48:18 +01001106 TIntermSequence *declSeq = node->getInit()->getAsDeclarationNode()->getSequence();
Zhenyao Mo550c6002014-02-26 15:40:48 -08001107 TIntermSymbol *indexSymbol =
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001108 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001109 TString name = hashVariableName(indexSymbol->getName());
Zhenyao Mo550c6002014-02-26 15:40:48 -08001110 out << "for (int " << name << " = 0; "
1111 << name << " < 1; "
1112 << "++" << name << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001113
1114 out << "{\n";
1115 mLoopUnrollStack.push(node);
1116 while (mLoopUnrollStack.satisfiesLoopCondition())
1117 {
1118 visitCodeBlock(node->getBody());
1119 mLoopUnrollStack.step();
1120 }
1121 mLoopUnrollStack.pop();
1122 out << "}\n";
Zhenyao Mo550c6002014-02-26 15:40:48 -08001123 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001124 }
1125 else if (loopType == ELoopWhile) // while loop
1126 {
1127 out << "while (";
1128 ASSERT(node->getCondition() != NULL);
1129 node->getCondition()->traverse(this);
1130 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001131
1132 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001133 }
1134 else // do-while loop
1135 {
1136 ASSERT(loopType == ELoopDoWhile);
1137 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001138
zmo@google.com5601ea02011-06-10 18:23:25 +00001139 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001140
zmo@google.com5601ea02011-06-10 18:23:25 +00001141 out << "while (";
1142 ASSERT(node->getCondition() != NULL);
1143 node->getCondition()->traverse(this);
1144 out << ");\n";
1145 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001146
zmo@google.com5601ea02011-06-10 18:23:25 +00001147 decrementDepth();
1148
1149 // No need to visit children. They have been already processed in
1150 // this function.
1151 return false;
1152}
1153
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001154bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001155{
1156 switch (node->getFlowOp())
1157 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001158 case EOpKill:
1159 writeTriplet(visit, "discard", NULL, NULL);
1160 break;
1161 case EOpBreak:
1162 writeTriplet(visit, "break", NULL, NULL);
1163 break;
1164 case EOpContinue:
1165 writeTriplet(visit, "continue", NULL, NULL);
1166 break;
1167 case EOpReturn:
1168 writeTriplet(visit, "return ", NULL, NULL);
1169 break;
1170 default:
1171 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001172 }
1173
1174 return true;
1175}
1176
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001177void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001178{
zmo@google.com5601ea02011-06-10 18:23:25 +00001179 TInfoSinkBase &out = objSink();
1180 if (node != NULL)
1181 {
1182 node->traverse(this);
1183 // Single statements not part of a sequence need to be terminated
1184 // with semi-colon.
1185 if (isSingleStatement(node))
1186 out << ";\n";
1187 }
1188 else
1189 {
1190 out << "{\n}\n"; // Empty code block.
1191 }
1192}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001193
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001194TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001195{
Olli Etuahoe92507b2016-07-04 11:20:10 +03001196 if (type.getBasicType() == EbtStruct)
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001197 return hashName(TName(type.getStruct()->name()));
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001198 else
Olli Etuahoe92507b2016-07-04 11:20:10 +03001199 return type.getBuiltInTypeNameString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001200}
1201
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001202TString TOutputGLSLBase::hashName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001203{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001204 if (name.getString().empty())
1205 {
1206 ASSERT(!name.isInternal());
1207 return name.getString();
1208 }
1209 if (name.isInternal())
1210 {
1211 // TODO(oetuaho): Would be nicer to prefix non-internal names with "_" instead, like is
1212 // done in the HLSL output, but that requires fairly complex changes elsewhere in the code
1213 // as well.
1214 // We need to use a prefix that is reserved in WebGL in order to guarantee that the internal
1215 // names don't conflict with user-defined names from WebGL.
1216 return "webgl_angle_" + name.getString();
1217 }
1218 if (mHashFunction == nullptr)
1219 {
1220 return name.getString();
1221 }
1222 NameMap::const_iterator it = mNameMap.find(name.getString().c_str());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001223 if (it != mNameMap.end())
1224 return it->second.c_str();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001225 TString hashedName = TIntermTraverser::hash(name.getString(), mHashFunction);
1226 mNameMap[name.getString().c_str()] = hashedName.c_str();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001227 return hashedName;
1228}
1229
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001230TString TOutputGLSLBase::hashVariableName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001231{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001232 if (mSymbolTable.findBuiltIn(name.getString(), mShaderVersion) != NULL)
1233 return name.getString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001234 return hashName(name);
1235}
1236
Olli Etuaho59f9a642015-08-06 20:38:26 +03001237TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001238{
Olli Etuaho59f9a642015-08-06 20:38:26 +03001239 TString mangledStr = mangledName.getString();
1240 TString name = TFunction::unmangleName(mangledStr);
1241 if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001242 return translateTextureFunction(name);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001243 if (mangledName.isInternal())
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001244 {
1245 // Internal function names are outputted as-is - they may refer to functions manually added
1246 // to the output shader source that are not included in the AST at all.
Olli Etuaho59f9a642015-08-06 20:38:26 +03001247 return name;
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001248 }
Olli Etuaho59f9a642015-08-06 20:38:26 +03001249 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001250 {
1251 TName nameObj(name);
1252 return hashName(nameObj);
1253 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001254}
Jamie Madill98493dd2013-07-08 14:39:03 -04001255
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001256bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001257{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001258 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001259 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001260 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001261 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001262 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001263
1264 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001265}
1266
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001267void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001268{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001269 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001270
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001271 out << "struct " << hashName(TName(structure->name())) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001272 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001273 for (size_t i = 0; i < fields.size(); ++i)
1274 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001275 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001276 if (writeVariablePrecision(field->type()->getPrecision()))
1277 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001278 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Jamie Madill98493dd2013-07-08 14:39:03 -04001279 if (field->type()->isArray())
1280 out << arrayBrackets(*field->type());
1281 out << ";\n";
1282 }
1283 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001284}
Jamie Madill98493dd2013-07-08 14:39:03 -04001285
Geoff Langbdcc54a2015-09-02 13:09:48 -04001286void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1287{
1288 TInfoSinkBase &out = objSink();
1289
1290 out << "layout(";
1291
1292 switch (interfaceBlock->blockStorage())
1293 {
1294 case EbsUnspecified:
1295 case EbsShared:
1296 // Default block storage is shared.
1297 out << "shared";
1298 break;
1299
1300 case EbsPacked:
1301 out << "packed";
1302 break;
1303
1304 case EbsStd140:
1305 out << "std140";
1306 break;
1307
1308 default:
1309 UNREACHABLE();
1310 break;
1311 }
1312
1313 out << ", ";
1314
1315 switch (interfaceBlock->matrixPacking())
1316 {
1317 case EmpUnspecified:
1318 case EmpColumnMajor:
1319 // Default matrix packing is column major.
1320 out << "column_major";
1321 break;
1322
1323 case EmpRowMajor:
1324 out << "row_major";
1325 break;
1326
1327 default:
1328 UNREACHABLE();
1329 break;
1330 }
1331
1332 out << ") ";
1333}
1334
1335void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1336{
1337 TInfoSinkBase &out = objSink();
1338
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001339 out << hashName(TName(interfaceBlock->name())) << "{\n";
Geoff Langbdcc54a2015-09-02 13:09:48 -04001340 const TFieldList &fields = interfaceBlock->fields();
1341 for (size_t i = 0; i < fields.size(); ++i)
1342 {
1343 const TField *field = fields[i];
1344 if (writeVariablePrecision(field->type()->getPrecision()))
1345 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001346 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Geoff Langbdcc54a2015-09-02 13:09:48 -04001347 if (field->type()->isArray())
1348 out << arrayBrackets(*field->type());
1349 out << ";\n";
1350 }
1351 out << "}";
1352}
Jamie Madill45bcc782016-11-07 13:58:48 -05001353
1354} // namespace sh