blob: 964f1e25dacacee5a69778b9ffe8bcd8e083c9db [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,
Qiankun Miao89dd8f32016-11-09 12:59:30 +000088 sh::GLenum shaderType,
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080089 int shaderVersion,
Qiankun Miao705a9192016-08-29 10:05:27 +080090 ShShaderOutput output,
91 ShCompileOptions compileOptions)
zmo@google.com5601ea02011-06-10 18:23:25 +000092 : TIntermTraverser(true, true, true),
93 mObjSink(objSink),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000094 mDeclaringVariables(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000095 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000096 mHashFunction(hashFunction),
97 mNameMap(nameMap),
Jamie Madill02f20dd2013-09-12 12:07:42 -040098 mSymbolTable(symbolTable),
Qiankun Miao89dd8f32016-11-09 12:59:30 +000099 mShaderType(shaderType),
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800100 mShaderVersion(shaderVersion),
Qiankun Miao705a9192016-08-29 10:05:27 +0800101 mOutput(output),
102 mCompileOptions(compileOptions)
zmo@google.com5601ea02011-06-10 18:23:25 +0000103{
104}
105
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800106void TOutputGLSLBase::writeInvariantQualifier(const TType &type)
107{
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000108 if (!sh::RemoveInvariant(mShaderType, mShaderVersion, mOutput, mCompileOptions))
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800109 {
110 TInfoSinkBase &out = objSink();
111 out << "invariant ";
112 }
113}
114
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700115void TOutputGLSLBase::writeTriplet(
116 Visit visit, const char *preStr, const char *inStr, const char *postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000117{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700118 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000119 if (visit == PreVisit && preStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000120 out << preStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000121 else if (visit == InVisit && inStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000122 out << inStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000123 else if (visit == PostVisit && postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000124 out << postStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000125}
126
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700127void TOutputGLSLBase::writeBuiltInFunctionTriplet(
128 Visit visit, const char *preStr, bool useEmulatedFunction)
zmo@google.com5601ea02011-06-10 18:23:25 +0000129{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700130 TString preString = useEmulatedFunction ?
131 BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
132 writeTriplet(visit, preString.c_str(), ", ", ")");
133}
134
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300135void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
136{
Martin Radev2cc85b32016-08-05 16:22:53 +0300137 if (!NeedsToWriteLayoutQualifier(type))
138 {
139 return;
140 }
141
142 TInfoSinkBase &out = objSink();
143 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
144 out << "layout(";
145
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300146 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
147 {
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300148 if (layoutQualifier.location >= 0)
149 {
Martin Radev2cc85b32016-08-05 16:22:53 +0300150 out << "location = " << layoutQualifier.location;
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300151 }
152 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300153
154 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
155 {
156 ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
157 out << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
158 }
159
160 out << ") ";
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300161}
162
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800163const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier)
164{
165 if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 &&
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000166 (mCompileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0)
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800167 {
168 switch (qualifier)
169 {
170 // The return string is consistent with sh::getQualifierString() from
171 // BaseTypes.h minus the "centroid" keyword.
172 case EvqCentroid:
173 return "";
174 case EvqCentroidIn:
175 return "smooth in";
176 case EvqCentroidOut:
177 return "smooth out";
178 default:
179 break;
180 }
181 }
182 if (sh::IsGLSL130OrNewer(mOutput))
183 {
184 switch (qualifier)
185 {
186 case EvqAttribute:
187 return "in";
188 case EvqVaryingIn:
189 return "in";
190 case EvqVaryingOut:
191 return "out";
192 default:
193 break;
194 }
195 }
196 return sh::getQualifierString(qualifier);
197}
198
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700199void TOutputGLSLBase::writeVariableType(const TType &type)
200{
Qiankun Miao705a9192016-08-29 10:05:27 +0800201 TQualifier qualifier = type.getQualifier();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700202 TInfoSinkBase &out = objSink();
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800203 if (type.isInvariant())
Olli Etuaho214c2d82015-04-27 14:49:13 +0300204 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800205 writeInvariantQualifier(type);
Olli Etuaho214c2d82015-04-27 14:49:13 +0300206 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400207 if (type.getBasicType() == EbtInterfaceBlock)
208 {
209 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
210 declareInterfaceBlockLayout(interfaceBlock);
211 }
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400212 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400213 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800214 const char *qualifierString = mapQualifierToString(qualifier);
215 if (qualifierString && qualifierString[0] != '\0')
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800216 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800217 out << qualifierString << " ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800218 }
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400219 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300220
221 const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
222 if (memoryQualifier.readonly)
223 {
224 ASSERT(IsImage(type.getBasicType()));
225 out << "readonly ";
226 }
227
228 if (memoryQualifier.writeonly)
229 {
230 ASSERT(IsImage(type.getBasicType()));
231 out << "writeonly ";
232 }
233
zmo@google.com5601ea02011-06-10 18:23:25 +0000234 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700235 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000236 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400237 TStructure *structure = type.getStruct();
238
239 declareStruct(structure);
240
241 if (!structure->name().empty())
242 {
243 mDeclaredStructs.insert(structure->uniqueId());
244 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000245 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400246 else if (type.getBasicType() == EbtInterfaceBlock)
247 {
248 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
249 declareInterfaceBlock(interfaceBlock);
250 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000251 else
252 {
253 if (writeVariablePrecision(type.getPrecision()))
254 out << " ";
255 out << getTypeName(type);
256 }
257}
258
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700259void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000260{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700261 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000262 for (TIntermSequence::const_iterator iter = args.begin();
263 iter != args.end(); ++iter)
264 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700265 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000266 ASSERT(arg != NULL);
267
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700268 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000269 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000270
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000271 if (!arg->getName().getString().empty())
272 out << " " << hashName(arg->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000273 if (type.isArray())
274 out << arrayBrackets(type);
275
276 // Put a comma if this is not the last argument.
277 if (iter != args.end() - 1)
278 out << ", ";
279 }
280}
281
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400282const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
283 const TType &type, const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000284{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700285 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000286
287 if (type.getBasicType() == EbtStruct)
288 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700289 const TStructure *structure = type.getStruct();
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000290 out << hashName(TName(structure->name())) << "(";
Jamie Madill98493dd2013-07-08 14:39:03 -0400291
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700292 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400293 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000294 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700295 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000296 ASSERT(fieldType != NULL);
297 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700298 if (i != fields.size() - 1)
299 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000300 }
301 out << ")";
302 }
303 else
304 {
Jamie Madill94bf7f22013-07-08 13:31:15 -0400305 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000306 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700307 if (writeType)
308 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400309 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000310 {
311 switch (pConstUnion->getType())
312 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700313 case EbtFloat:
314 out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
315 break;
316 case EbtInt:
317 out << pConstUnion->getIConst();
318 break;
Olli Etuaho5321c802015-04-02 17:08:16 +0300319 case EbtUInt:
320 out << pConstUnion->getUConst() << "u";
321 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700322 case EbtBool:
323 out << pConstUnion->getBConst();
324 break;
325 default: UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000326 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700327 if (i != size - 1)
328 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000329 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700330 if (writeType)
331 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000332 }
333 return pConstUnion;
334}
335
Olli Etuahoe92507b2016-07-04 11:20:10 +0300336void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
Olli Etuahof40319e2015-03-10 14:33:00 +0200337{
338 TInfoSinkBase &out = objSink();
339 if (visit == PreVisit)
340 {
341 if (type.isArray())
342 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300343 out << getTypeName(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200344 out << arrayBrackets(type);
345 out << "(";
346 }
347 else
348 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300349 out << getTypeName(type) << "(";
Olli Etuahof40319e2015-03-10 14:33:00 +0200350 }
351 }
352 else
353 {
354 writeTriplet(visit, nullptr, ", ", ")");
355 }
356}
357
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700358void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000359{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700360 TInfoSinkBase &out = objSink();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800361 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
362 out << mLoopUnrollStack.getLoopIndexValue(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000363 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000364 out << hashVariableName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000365
366 if (mDeclaringVariables && node->getType().isArray())
367 out << arrayBrackets(node->getType());
368}
369
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700370void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000371{
372 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
373}
374
Olli Etuahob6fa0432016-09-28 16:28:05 +0100375bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
376{
377 TInfoSinkBase &out = objSink();
378 if (visit == PostVisit)
379 {
380 out << ".";
381 node->writeOffsetsAsXYZW(&out);
382 }
383 return true;
384}
385
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700386bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000387{
388 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700389 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000390 switch (node->getOp())
391 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100392 case EOpComma:
393 writeTriplet(visit, "(", ", ", ")");
394 break;
395 case EOpInitialize:
zmo@google.com5601ea02011-06-10 18:23:25 +0000396 if (visit == InVisit)
397 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100398 out << " = ";
399 // RHS of initialize is not being declared.
400 mDeclaringVariables = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000401 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100402 break;
403 case EOpAssign:
404 writeTriplet(visit, "(", " = ", ")");
405 break;
406 case EOpAddAssign:
407 writeTriplet(visit, "(", " += ", ")");
408 break;
409 case EOpSubAssign:
410 writeTriplet(visit, "(", " -= ", ")");
411 break;
412 case EOpDivAssign:
413 writeTriplet(visit, "(", " /= ", ")");
414 break;
415 case EOpIModAssign:
416 writeTriplet(visit, "(", " %= ", ")");
417 break;
418 // Notice the fall-through.
419 case EOpMulAssign:
420 case EOpVectorTimesMatrixAssign:
421 case EOpVectorTimesScalarAssign:
422 case EOpMatrixTimesScalarAssign:
423 case EOpMatrixTimesMatrixAssign:
424 writeTriplet(visit, "(", " *= ", ")");
425 break;
426 case EOpBitShiftLeftAssign:
427 writeTriplet(visit, "(", " <<= ", ")");
428 break;
429 case EOpBitShiftRightAssign:
430 writeTriplet(visit, "(", " >>= ", ")");
431 break;
432 case EOpBitwiseAndAssign:
433 writeTriplet(visit, "(", " &= ", ")");
434 break;
435 case EOpBitwiseXorAssign:
436 writeTriplet(visit, "(", " ^= ", ")");
437 break;
438 case EOpBitwiseOrAssign:
439 writeTriplet(visit, "(", " |= ", ")");
440 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000441
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100442 case EOpIndexDirect:
zmo@google.com5601ea02011-06-10 18:23:25 +0000443 writeTriplet(visit, NULL, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100444 break;
445 case EOpIndexIndirect:
446 if (node->getAddIndexClamp())
447 {
448 if (visit == InVisit)
449 {
450 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
451 out << "[int(clamp(float(";
452 else
453 out << "[webgl_int_clamp(";
454 }
455 else if (visit == PostVisit)
456 {
457 int maxSize;
458 TIntermTyped *left = node->getLeft();
459 TType leftType = left->getType();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700460
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100461 if (left->isArray())
462 {
463 // The shader will fail validation if the array length is not > 0.
464 maxSize = static_cast<int>(leftType.getArraySize()) - 1;
465 }
466 else
467 {
468 maxSize = leftType.getNominalSize() - 1;
469 }
470
471 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
472 out << "), 0.0, float(" << maxSize << ")))]";
473 else
474 out << ", 0, " << maxSize << ")]";
475 }
476 }
477 else
478 {
479 writeTriplet(visit, NULL, "[", "]");
480 }
481 break;
482 case EOpIndexDirectStruct:
483 if (visit == InVisit)
484 {
485 // Here we are writing out "foo.bar", where "foo" is struct
486 // and "bar" is field. In AST, it is represented as a binary
487 // node, where left child represents "foo" and right child "bar".
488 // The node itself represents ".". The struct field "bar" is
489 // actually stored as an index into TStructure::fields.
490 out << ".";
491 const TStructure *structure = node->getLeft()->getType().getStruct();
492 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
493 const TField *field = structure->fields()[index->getIConst(0)];
494
495 TString fieldName = field->name();
496 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000497 fieldName = hashName(TName(fieldName));
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100498
499 out << fieldName;
500 visitChildren = false;
501 }
502 break;
503 case EOpIndexDirectInterfaceBlock:
504 if (visit == InVisit)
505 {
506 out << ".";
507 const TInterfaceBlock *interfaceBlock =
508 node->getLeft()->getType().getInterfaceBlock();
509 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
510 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
511
512 TString fieldName = field->name();
513 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000514 fieldName = hashName(TName(fieldName));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700515
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100516 out << fieldName;
517 visitChildren = false;
518 }
519 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400520
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100521 case EOpAdd:
522 writeTriplet(visit, "(", " + ", ")");
523 break;
524 case EOpSub:
525 writeTriplet(visit, "(", " - ", ")");
526 break;
527 case EOpMul:
528 writeTriplet(visit, "(", " * ", ")");
529 break;
530 case EOpDiv:
531 writeTriplet(visit, "(", " / ", ")");
532 break;
533 case EOpIMod:
534 writeTriplet(visit, "(", " % ", ")");
535 break;
536 case EOpBitShiftLeft:
537 writeTriplet(visit, "(", " << ", ")");
538 break;
539 case EOpBitShiftRight:
540 writeTriplet(visit, "(", " >> ", ")");
541 break;
542 case EOpBitwiseAnd:
543 writeTriplet(visit, "(", " & ", ")");
544 break;
545 case EOpBitwiseXor:
546 writeTriplet(visit, "(", " ^ ", ")");
547 break;
548 case EOpBitwiseOr:
549 writeTriplet(visit, "(", " | ", ")");
550 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400551
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100552 case EOpEqual:
553 writeTriplet(visit, "(", " == ", ")");
554 break;
555 case EOpNotEqual:
556 writeTriplet(visit, "(", " != ", ")");
557 break;
558 case EOpLessThan:
559 writeTriplet(visit, "(", " < ", ")");
560 break;
561 case EOpGreaterThan:
562 writeTriplet(visit, "(", " > ", ")");
563 break;
564 case EOpLessThanEqual:
565 writeTriplet(visit, "(", " <= ", ")");
566 break;
567 case EOpGreaterThanEqual:
568 writeTriplet(visit, "(", " >= ", ")");
569 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000570
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100571 // Notice the fall-through.
572 case EOpVectorTimesScalar:
573 case EOpVectorTimesMatrix:
574 case EOpMatrixTimesVector:
575 case EOpMatrixTimesScalar:
576 case EOpMatrixTimesMatrix:
577 writeTriplet(visit, "(", " * ", ")");
578 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200579
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100580 case EOpLogicalOr:
581 writeTriplet(visit, "(", " || ", ")");
582 break;
583 case EOpLogicalXor:
584 writeTriplet(visit, "(", " ^^ ", ")");
585 break;
586 case EOpLogicalAnd:
587 writeTriplet(visit, "(", " && ", ")");
588 break;
589 default:
590 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000591 }
592
593 return visitChildren;
594}
595
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700596bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000597{
zmo@google.com32e97312011-08-24 01:03:11 +0000598 TString preString;
599 TString postString = ")";
600
zmo@google.com5601ea02011-06-10 18:23:25 +0000601 switch (node->getOp())
602 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700603 case EOpNegative: preString = "(-"; break;
Zhenyao Mode1e00e2014-10-09 16:55:32 -0700604 case EOpPositive: preString = "(+"; break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700605 case EOpVectorLogicalNot: preString = "not("; break;
606 case EOpLogicalNot: preString = "(!"; break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200607 case EOpBitwiseNot: preString = "(~"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000608
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700609 case EOpPostIncrement: preString = "("; postString = "++)"; break;
610 case EOpPostDecrement: preString = "("; postString = "--)"; break;
611 case EOpPreIncrement: preString = "(++"; break;
612 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000613
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700614 case EOpRadians:
615 preString = "radians(";
616 break;
617 case EOpDegrees:
618 preString = "degrees(";
619 break;
620 case EOpSin:
621 preString = "sin(";
622 break;
623 case EOpCos:
624 preString = "cos(";
625 break;
626 case EOpTan:
627 preString = "tan(";
628 break;
629 case EOpAsin:
630 preString = "asin(";
631 break;
632 case EOpAcos:
633 preString = "acos(";
634 break;
635 case EOpAtan:
636 preString = "atan(";
637 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000638
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200639 case EOpSinh:
640 preString = "sinh(";
641 break;
642 case EOpCosh:
643 preString = "cosh(";
644 break;
645 case EOpTanh:
646 preString = "tanh(";
647 break;
648 case EOpAsinh:
649 preString = "asinh(";
650 break;
651 case EOpAcosh:
652 preString = "acosh(";
653 break;
654 case EOpAtanh:
655 preString = "atanh(";
656 break;
657
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700658 case EOpExp:
659 preString = "exp(";
660 break;
661 case EOpLog:
662 preString = "log(";
663 break;
664 case EOpExp2:
665 preString = "exp2(";
666 break;
667 case EOpLog2:
668 preString = "log2(";
669 break;
670 case EOpSqrt:
671 preString = "sqrt(";
672 break;
673 case EOpInverseSqrt:
674 preString = "inversesqrt(";
675 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000676
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700677 case EOpAbs:
678 preString = "abs(";
679 break;
680 case EOpSign:
681 preString = "sign(";
682 break;
683 case EOpFloor:
684 preString = "floor(";
685 break;
Qingqing Deng5dbece52015-02-27 20:35:38 -0800686 case EOpTrunc:
687 preString = "trunc(";
688 break;
689 case EOpRound:
690 preString = "round(";
691 break;
692 case EOpRoundEven:
693 preString = "roundEven(";
694 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700695 case EOpCeil:
696 preString = "ceil(";
697 break;
698 case EOpFract:
699 preString = "fract(";
700 break;
Arun Patole0c1726e2015-02-18 14:35:02 +0530701 case EOpIsNan:
702 preString = "isnan(";
703 break;
704 case EOpIsInf:
705 preString = "isinf(";
706 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000707
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200708 case EOpFloatBitsToInt:
709 preString = "floatBitsToInt(";
710 break;
711 case EOpFloatBitsToUint:
712 preString = "floatBitsToUint(";
713 break;
714 case EOpIntBitsToFloat:
715 preString = "intBitsToFloat(";
716 break;
717 case EOpUintBitsToFloat:
718 preString = "uintBitsToFloat(";
719 break;
720
Olli Etuaho7700ff62015-01-15 12:16:29 +0200721 case EOpPackSnorm2x16:
722 preString = "packSnorm2x16(";
723 break;
724 case EOpPackUnorm2x16:
725 preString = "packUnorm2x16(";
726 break;
727 case EOpPackHalf2x16:
728 preString = "packHalf2x16(";
729 break;
730 case EOpUnpackSnorm2x16:
731 preString = "unpackSnorm2x16(";
732 break;
733 case EOpUnpackUnorm2x16:
734 preString = "unpackUnorm2x16(";
735 break;
736 case EOpUnpackHalf2x16:
737 preString = "unpackHalf2x16(";
738 break;
739
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700740 case EOpLength:
741 preString = "length(";
742 break;
743 case EOpNormalize:
744 preString = "normalize(";
745 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000746
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700747 case EOpDFdx:
748 preString = "dFdx(";
749 break;
750 case EOpDFdy:
751 preString = "dFdy(";
752 break;
753 case EOpFwidth:
754 preString = "fwidth(";
755 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000756
Olli Etuahoe39706d2014-12-30 16:40:36 +0200757 case EOpTranspose:
758 preString = "transpose(";
759 break;
760 case EOpDeterminant:
761 preString = "determinant(";
762 break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +0200763 case EOpInverse:
764 preString = "inverse(";
765 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200766
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700767 case EOpAny:
768 preString = "any(";
769 break;
770 case EOpAll:
771 preString = "all(";
772 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000773
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700774 default:
775 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000776 }
777
zmo@google.com32e97312011-08-24 01:03:11 +0000778 if (visit == PreVisit && node->getUseEmulatedFunction())
779 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
780 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
781
zmo@google.com5601ea02011-06-10 18:23:25 +0000782 return true;
783}
784
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300785bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
786{
787 TInfoSinkBase &out = objSink();
788 // Notice two brackets at the beginning and end. The outer ones
789 // encapsulate the whole ternary expression. This preserves the
790 // order of precedence when ternary expressions are used in a
791 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
792 out << "((";
793 node->getCondition()->traverse(this);
794 out << ") ? (";
795 node->getTrueExpression()->traverse(this);
796 out << ") : (";
797 node->getFalseExpression()->traverse(this);
798 out << "))";
799 return false;
800}
801
Olli Etuaho57961272016-09-14 13:57:46 +0300802bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000803{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700804 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000805
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300806 out << "if (";
807 node->getCondition()->traverse(this);
808 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000809
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300810 incrementDepth(node);
811 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000812
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300813 if (node->getFalseBlock())
814 {
815 out << "else\n";
816 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000817 }
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300818 decrementDepth();
zmo@google.com5601ea02011-06-10 18:23:25 +0000819 return false;
820}
821
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200822bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200823{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200824 if (node->getStatementList())
825 {
826 writeTriplet(visit, "switch (", ") ", nullptr);
827 // The curly braces get written when visiting the statementList aggregate
828 }
829 else
830 {
831 // No statementList, so it won't output curly braces
832 writeTriplet(visit, "switch (", ") {", "}\n");
833 }
834 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200835}
836
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200837bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200838{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200839 if (node->hasCondition())
840 {
841 writeTriplet(visit, "case (", nullptr, "):\n");
842 return true;
843 }
844 else
845 {
846 TInfoSinkBase &out = objSink();
847 out << "default:\n";
848 return false;
849 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200850}
851
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100852bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
853{
854 TInfoSinkBase &out = objSink();
855 // Scope the blocks except when at the global scope.
856 if (mDepth > 0)
857 {
858 out << "{\n";
859 }
860
861 incrementDepth(node);
862 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
863 iter != node->getSequence()->end(); ++iter)
864 {
865 TIntermNode *curNode = *iter;
866 ASSERT(curNode != nullptr);
867 curNode->traverse(this);
868
869 if (isSingleStatement(curNode))
870 out << ";\n";
871 }
872 decrementDepth();
873
874 // Scope the blocks except when at the global scope.
875 if (mDepth > 0)
876 {
877 out << "}\n";
878 }
879 return false;
880}
881
Olli Etuaho336b1472016-10-05 16:37:55 +0100882bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
883{
884 TInfoSinkBase &out = objSink();
885
886 ASSERT(visit == PreVisit);
887 {
888 const TType &type = node->getType();
889 writeVariableType(type);
890 if (type.isArray())
891 out << arrayBrackets(type);
892 }
893
894 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
895
896 incrementDepth(node);
897
898 // Traverse function parameters.
899 TIntermAggregate *params = node->getFunctionParameters()->getAsAggregate();
900 ASSERT(params->getOp() == EOpParameters);
901 params->traverse(this);
902
903 // Traverse function body.
904 visitCodeBlock(node->getBody());
905 decrementDepth();
906
907 // Fully processed; no need to visit children.
908 return false;
909}
910
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700911bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000912{
913 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700914 TInfoSinkBase &out = objSink();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700915 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000916 switch (node->getOp())
917 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700918 case EOpPrototype:
919 // Function declaration.
920 ASSERT(visit == PreVisit);
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300921 {
922 const TType &type = node->getType();
923 writeVariableType(type);
924 if (type.isArray())
925 out << arrayBrackets(type);
926 }
927
Olli Etuahobd674552016-10-06 13:28:42 +0100928 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700929
930 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700931 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700932 out << ")";
933
934 visitChildren = false;
935 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700936 case EOpFunctionCall:
937 // Function call.
938 if (visit == PreVisit)
Olli Etuahobd674552016-10-06 13:28:42 +0100939 out << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200940 else if (visit == InVisit)
941 out << ", ";
942 else
943 out << ")";
944 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700945 case EOpParameters:
946 // Function parameters.
947 ASSERT(visit == PreVisit);
948 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700949 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700950 out << ")";
951 visitChildren = false;
952 break;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700953 case EOpInvariantDeclaration:
954 // Invariant declaration.
955 ASSERT(visit == PreVisit);
956 {
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400957 const TIntermSequence *sequence = node->getSequence();
958 ASSERT(sequence && sequence->size() == 1);
959 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
960 ASSERT(symbol);
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000961 out << "invariant " << hashVariableName(symbol->getName());
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400962 }
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700963 visitChildren = false;
964 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700965 case EOpConstructFloat:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700966 case EOpConstructVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700967 case EOpConstructVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700968 case EOpConstructVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700969 case EOpConstructBool:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700970 case EOpConstructBVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700971 case EOpConstructBVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700972 case EOpConstructBVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700973 case EOpConstructInt:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700974 case EOpConstructIVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700975 case EOpConstructIVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700976 case EOpConstructIVec4:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400977 case EOpConstructUInt:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400978 case EOpConstructUVec2:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400979 case EOpConstructUVec3:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400980 case EOpConstructUVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700981 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400982 case EOpConstructMat2x3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400983 case EOpConstructMat2x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400984 case EOpConstructMat3x2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700985 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400986 case EOpConstructMat3x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400987 case EOpConstructMat4x2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400988 case EOpConstructMat4x3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700989 case EOpConstructMat4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700990 case EOpConstructStruct:
Olli Etuahoe92507b2016-07-04 11:20:10 +0300991 writeConstructorTriplet(visit, node->getType());
992 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000993
Olli Etuahoe39706d2014-12-30 16:40:36 +0200994 case EOpOuterProduct:
995 writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
996 break;
997
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700998 case EOpLessThan:
999 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
1000 break;
1001 case EOpGreaterThan:
1002 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
1003 break;
1004 case EOpLessThanEqual:
1005 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
1006 break;
1007 case EOpGreaterThanEqual:
1008 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
1009 break;
1010 case EOpVectorEqual:
1011 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
1012 break;
1013 case EOpVectorNotEqual:
1014 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
1015 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001016
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001017 case EOpMod:
1018 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
1019 break;
Olli Etuahob6e07a62015-02-16 12:22:10 +02001020 case EOpModf:
1021 writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
1022 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001023 case EOpPow:
1024 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
1025 break;
1026 case EOpAtan:
1027 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
1028 break;
1029 case EOpMin:
1030 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
1031 break;
1032 case EOpMax:
1033 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
1034 break;
1035 case EOpClamp:
1036 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
1037 break;
1038 case EOpMix:
1039 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
1040 break;
1041 case EOpStep:
1042 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
1043 break;
1044 case EOpSmoothStep:
1045 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
1046 break;
1047 case EOpDistance:
1048 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
1049 break;
1050 case EOpDot:
1051 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
1052 break;
1053 case EOpCross:
1054 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
1055 break;
1056 case EOpFaceForward:
1057 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
1058 break;
1059 case EOpReflect:
1060 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
1061 break;
1062 case EOpRefract:
1063 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
1064 break;
1065 case EOpMul:
1066 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
1067 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001068
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001069 default:
1070 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001071 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001072 return visitChildren;
1073}
1074
Olli Etuaho13389b62016-10-16 11:48:18 +01001075bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
1076{
1077 TInfoSinkBase &out = objSink();
1078
1079 // Variable declaration.
1080 if (visit == PreVisit)
1081 {
1082 const TIntermSequence &sequence = *(node->getSequence());
1083 const TIntermTyped *variable = sequence.front()->getAsTyped();
1084 writeLayoutQualifier(variable->getType());
1085 writeVariableType(variable->getType());
1086 out << " ";
1087 mDeclaringVariables = true;
1088 }
1089 else if (visit == InVisit)
1090 {
1091 out << ", ";
1092 mDeclaringVariables = true;
1093 }
1094 else
1095 {
1096 mDeclaringVariables = false;
1097 }
1098 return true;
1099}
1100
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001101bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001102{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001103 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001104
Zhenyao Mo7cab38b2013-10-15 12:59:30 -07001105 incrementDepth(node);
Corentin Wallez7258e302015-09-22 10:40:24 -07001106
zmo@google.com5601ea02011-06-10 18:23:25 +00001107 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001108
1109 // Only for loops can be unrolled
1110 ASSERT(!node->getUnrollFlag() || loopType == ELoopFor);
1111
zmo@google.com5601ea02011-06-10 18:23:25 +00001112 if (loopType == ELoopFor) // for loop
1113 {
Zhenyao Mo550c6002014-02-26 15:40:48 -08001114 if (!node->getUnrollFlag())
1115 {
zmo@google.com5601ea02011-06-10 18:23:25 +00001116 out << "for (";
1117 if (node->getInit())
1118 node->getInit()->traverse(this);
1119 out << "; ";
1120
1121 if (node->getCondition())
1122 node->getCondition()->traverse(this);
1123 out << "; ";
1124
1125 if (node->getExpression())
1126 node->getExpression()->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 }
Zhenyao Mo550c6002014-02-26 15:40:48 -08001131 else
1132 {
1133 // Need to put a one-iteration loop here to handle break.
Olli Etuaho13389b62016-10-16 11:48:18 +01001134 TIntermSequence *declSeq = node->getInit()->getAsDeclarationNode()->getSequence();
Zhenyao Mo550c6002014-02-26 15:40:48 -08001135 TIntermSymbol *indexSymbol =
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001136 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001137 TString name = hashVariableName(indexSymbol->getName());
Zhenyao Mo550c6002014-02-26 15:40:48 -08001138 out << "for (int " << name << " = 0; "
1139 << name << " < 1; "
1140 << "++" << name << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001141
1142 out << "{\n";
1143 mLoopUnrollStack.push(node);
1144 while (mLoopUnrollStack.satisfiesLoopCondition())
1145 {
1146 visitCodeBlock(node->getBody());
1147 mLoopUnrollStack.step();
1148 }
1149 mLoopUnrollStack.pop();
1150 out << "}\n";
Zhenyao Mo550c6002014-02-26 15:40:48 -08001151 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001152 }
1153 else if (loopType == ELoopWhile) // while loop
1154 {
1155 out << "while (";
1156 ASSERT(node->getCondition() != NULL);
1157 node->getCondition()->traverse(this);
1158 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001159
1160 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001161 }
1162 else // do-while loop
1163 {
1164 ASSERT(loopType == ELoopDoWhile);
1165 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001166
zmo@google.com5601ea02011-06-10 18:23:25 +00001167 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001168
zmo@google.com5601ea02011-06-10 18:23:25 +00001169 out << "while (";
1170 ASSERT(node->getCondition() != NULL);
1171 node->getCondition()->traverse(this);
1172 out << ");\n";
1173 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001174
zmo@google.com5601ea02011-06-10 18:23:25 +00001175 decrementDepth();
1176
1177 // No need to visit children. They have been already processed in
1178 // this function.
1179 return false;
1180}
1181
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001182bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001183{
1184 switch (node->getFlowOp())
1185 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001186 case EOpKill:
1187 writeTriplet(visit, "discard", NULL, NULL);
1188 break;
1189 case EOpBreak:
1190 writeTriplet(visit, "break", NULL, NULL);
1191 break;
1192 case EOpContinue:
1193 writeTriplet(visit, "continue", NULL, NULL);
1194 break;
1195 case EOpReturn:
1196 writeTriplet(visit, "return ", NULL, NULL);
1197 break;
1198 default:
1199 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001200 }
1201
1202 return true;
1203}
1204
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001205void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001206{
zmo@google.com5601ea02011-06-10 18:23:25 +00001207 TInfoSinkBase &out = objSink();
1208 if (node != NULL)
1209 {
1210 node->traverse(this);
1211 // Single statements not part of a sequence need to be terminated
1212 // with semi-colon.
1213 if (isSingleStatement(node))
1214 out << ";\n";
1215 }
1216 else
1217 {
1218 out << "{\n}\n"; // Empty code block.
1219 }
1220}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001221
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001222TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001223{
Olli Etuahoe92507b2016-07-04 11:20:10 +03001224 if (type.getBasicType() == EbtStruct)
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001225 return hashName(TName(type.getStruct()->name()));
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001226 else
Olli Etuahoe92507b2016-07-04 11:20:10 +03001227 return type.getBuiltInTypeNameString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001228}
1229
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001230TString TOutputGLSLBase::hashName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001231{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001232 if (name.getString().empty())
1233 {
1234 ASSERT(!name.isInternal());
1235 return name.getString();
1236 }
1237 if (name.isInternal())
1238 {
1239 // TODO(oetuaho): Would be nicer to prefix non-internal names with "_" instead, like is
1240 // done in the HLSL output, but that requires fairly complex changes elsewhere in the code
1241 // as well.
1242 // We need to use a prefix that is reserved in WebGL in order to guarantee that the internal
1243 // names don't conflict with user-defined names from WebGL.
1244 return "webgl_angle_" + name.getString();
1245 }
1246 if (mHashFunction == nullptr)
1247 {
1248 return name.getString();
1249 }
1250 NameMap::const_iterator it = mNameMap.find(name.getString().c_str());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001251 if (it != mNameMap.end())
1252 return it->second.c_str();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001253 TString hashedName = TIntermTraverser::hash(name.getString(), mHashFunction);
1254 mNameMap[name.getString().c_str()] = hashedName.c_str();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001255 return hashedName;
1256}
1257
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001258TString TOutputGLSLBase::hashVariableName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001259{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001260 if (mSymbolTable.findBuiltIn(name.getString(), mShaderVersion) != NULL)
1261 return name.getString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001262 return hashName(name);
1263}
1264
Olli Etuaho59f9a642015-08-06 20:38:26 +03001265TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001266{
Olli Etuaho59f9a642015-08-06 20:38:26 +03001267 TString mangledStr = mangledName.getString();
1268 TString name = TFunction::unmangleName(mangledStr);
1269 if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001270 return translateTextureFunction(name);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001271 if (mangledName.isInternal())
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001272 {
1273 // Internal function names are outputted as-is - they may refer to functions manually added
1274 // to the output shader source that are not included in the AST at all.
Olli Etuaho59f9a642015-08-06 20:38:26 +03001275 return name;
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001276 }
Olli Etuaho59f9a642015-08-06 20:38:26 +03001277 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001278 {
1279 TName nameObj(name);
1280 return hashName(nameObj);
1281 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001282}
Jamie Madill98493dd2013-07-08 14:39:03 -04001283
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001284bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001285{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001286 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001287 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001288 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001289 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001290 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001291
1292 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001293}
1294
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001295void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001296{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001297 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001298
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001299 out << "struct " << hashName(TName(structure->name())) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001300 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001301 for (size_t i = 0; i < fields.size(); ++i)
1302 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001303 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001304 if (writeVariablePrecision(field->type()->getPrecision()))
1305 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001306 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Jamie Madill98493dd2013-07-08 14:39:03 -04001307 if (field->type()->isArray())
1308 out << arrayBrackets(*field->type());
1309 out << ";\n";
1310 }
1311 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001312}
Jamie Madill98493dd2013-07-08 14:39:03 -04001313
Geoff Langbdcc54a2015-09-02 13:09:48 -04001314void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1315{
1316 TInfoSinkBase &out = objSink();
1317
1318 out << "layout(";
1319
1320 switch (interfaceBlock->blockStorage())
1321 {
1322 case EbsUnspecified:
1323 case EbsShared:
1324 // Default block storage is shared.
1325 out << "shared";
1326 break;
1327
1328 case EbsPacked:
1329 out << "packed";
1330 break;
1331
1332 case EbsStd140:
1333 out << "std140";
1334 break;
1335
1336 default:
1337 UNREACHABLE();
1338 break;
1339 }
1340
1341 out << ", ";
1342
1343 switch (interfaceBlock->matrixPacking())
1344 {
1345 case EmpUnspecified:
1346 case EmpColumnMajor:
1347 // Default matrix packing is column major.
1348 out << "column_major";
1349 break;
1350
1351 case EmpRowMajor:
1352 out << "row_major";
1353 break;
1354
1355 default:
1356 UNREACHABLE();
1357 break;
1358 }
1359
1360 out << ") ";
1361}
1362
1363void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1364{
1365 TInfoSinkBase &out = objSink();
1366
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001367 out << hashName(TName(interfaceBlock->name())) << "{\n";
Geoff Langbdcc54a2015-09-02 13:09:48 -04001368 const TFieldList &fields = interfaceBlock->fields();
1369 for (size_t i = 0; i < fields.size(); ++i)
1370 {
1371 const TField *field = fields[i];
1372 if (writeVariablePrecision(field->type()->getPrecision()))
1373 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001374 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Geoff Langbdcc54a2015-09-02 13:09:48 -04001375 if (field->type()->isArray())
1376 out << arrayBrackets(*field->type());
1377 out << ";\n";
1378 }
1379 out << "}";
1380}
Jamie Madill45bcc782016-11-07 13:58:48 -05001381
1382} // namespace sh