blob: 2c32b2ea5cec3260d9317d0633ba4de35f0ec461 [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
Martin Radev049edfa2016-11-11 14:35:37 +0200234 if (memoryQualifier.coherent)
235 {
236 ASSERT(IsImage(type.getBasicType()));
237 out << "coherent ";
238 }
239
240 if (memoryQualifier.restrictQualifier)
241 {
242 ASSERT(IsImage(type.getBasicType()));
243 out << "restrict ";
244 }
245
246 if (memoryQualifier.volatileQualifier)
247 {
248 ASSERT(IsImage(type.getBasicType()));
249 out << "volatile ";
250 }
251
zmo@google.com5601ea02011-06-10 18:23:25 +0000252 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700253 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000254 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400255 TStructure *structure = type.getStruct();
256
257 declareStruct(structure);
258
259 if (!structure->name().empty())
260 {
261 mDeclaredStructs.insert(structure->uniqueId());
262 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000263 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400264 else if (type.getBasicType() == EbtInterfaceBlock)
265 {
266 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
267 declareInterfaceBlock(interfaceBlock);
268 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000269 else
270 {
271 if (writeVariablePrecision(type.getPrecision()))
272 out << " ";
273 out << getTypeName(type);
274 }
275}
276
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700277void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000278{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700279 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000280 for (TIntermSequence::const_iterator iter = args.begin();
281 iter != args.end(); ++iter)
282 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700283 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000284 ASSERT(arg != NULL);
285
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700286 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000287 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000288
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000289 if (!arg->getName().getString().empty())
290 out << " " << hashName(arg->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000291 if (type.isArray())
292 out << arrayBrackets(type);
293
294 // Put a comma if this is not the last argument.
295 if (iter != args.end() - 1)
296 out << ", ";
297 }
298}
299
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400300const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
301 const TType &type, const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000302{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700303 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000304
305 if (type.getBasicType() == EbtStruct)
306 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700307 const TStructure *structure = type.getStruct();
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000308 out << hashName(TName(structure->name())) << "(";
Jamie Madill98493dd2013-07-08 14:39:03 -0400309
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700310 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400311 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000312 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700313 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000314 ASSERT(fieldType != NULL);
315 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700316 if (i != fields.size() - 1)
317 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000318 }
319 out << ")";
320 }
321 else
322 {
Jamie Madill94bf7f22013-07-08 13:31:15 -0400323 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000324 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700325 if (writeType)
326 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400327 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000328 {
329 switch (pConstUnion->getType())
330 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700331 case EbtFloat:
332 out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
333 break;
334 case EbtInt:
335 out << pConstUnion->getIConst();
336 break;
Olli Etuaho5321c802015-04-02 17:08:16 +0300337 case EbtUInt:
338 out << pConstUnion->getUConst() << "u";
339 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700340 case EbtBool:
341 out << pConstUnion->getBConst();
342 break;
343 default: UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000344 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700345 if (i != size - 1)
346 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000347 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700348 if (writeType)
349 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000350 }
351 return pConstUnion;
352}
353
Olli Etuahoe92507b2016-07-04 11:20:10 +0300354void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
Olli Etuahof40319e2015-03-10 14:33:00 +0200355{
356 TInfoSinkBase &out = objSink();
357 if (visit == PreVisit)
358 {
359 if (type.isArray())
360 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300361 out << getTypeName(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200362 out << arrayBrackets(type);
363 out << "(";
364 }
365 else
366 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300367 out << getTypeName(type) << "(";
Olli Etuahof40319e2015-03-10 14:33:00 +0200368 }
369 }
370 else
371 {
372 writeTriplet(visit, nullptr, ", ", ")");
373 }
374}
375
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700376void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000377{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700378 TInfoSinkBase &out = objSink();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800379 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
380 out << mLoopUnrollStack.getLoopIndexValue(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000381 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000382 out << hashVariableName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000383
384 if (mDeclaringVariables && node->getType().isArray())
385 out << arrayBrackets(node->getType());
386}
387
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700388void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000389{
390 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
391}
392
Olli Etuahob6fa0432016-09-28 16:28:05 +0100393bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
394{
395 TInfoSinkBase &out = objSink();
396 if (visit == PostVisit)
397 {
398 out << ".";
399 node->writeOffsetsAsXYZW(&out);
400 }
401 return true;
402}
403
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700404bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000405{
406 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700407 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000408 switch (node->getOp())
409 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100410 case EOpComma:
411 writeTriplet(visit, "(", ", ", ")");
412 break;
413 case EOpInitialize:
zmo@google.com5601ea02011-06-10 18:23:25 +0000414 if (visit == InVisit)
415 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100416 out << " = ";
417 // RHS of initialize is not being declared.
418 mDeclaringVariables = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000419 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100420 break;
421 case EOpAssign:
422 writeTriplet(visit, "(", " = ", ")");
423 break;
424 case EOpAddAssign:
425 writeTriplet(visit, "(", " += ", ")");
426 break;
427 case EOpSubAssign:
428 writeTriplet(visit, "(", " -= ", ")");
429 break;
430 case EOpDivAssign:
431 writeTriplet(visit, "(", " /= ", ")");
432 break;
433 case EOpIModAssign:
434 writeTriplet(visit, "(", " %= ", ")");
435 break;
436 // Notice the fall-through.
437 case EOpMulAssign:
438 case EOpVectorTimesMatrixAssign:
439 case EOpVectorTimesScalarAssign:
440 case EOpMatrixTimesScalarAssign:
441 case EOpMatrixTimesMatrixAssign:
442 writeTriplet(visit, "(", " *= ", ")");
443 break;
444 case EOpBitShiftLeftAssign:
445 writeTriplet(visit, "(", " <<= ", ")");
446 break;
447 case EOpBitShiftRightAssign:
448 writeTriplet(visit, "(", " >>= ", ")");
449 break;
450 case EOpBitwiseAndAssign:
451 writeTriplet(visit, "(", " &= ", ")");
452 break;
453 case EOpBitwiseXorAssign:
454 writeTriplet(visit, "(", " ^= ", ")");
455 break;
456 case EOpBitwiseOrAssign:
457 writeTriplet(visit, "(", " |= ", ")");
458 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000459
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100460 case EOpIndexDirect:
zmo@google.com5601ea02011-06-10 18:23:25 +0000461 writeTriplet(visit, NULL, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100462 break;
463 case EOpIndexIndirect:
464 if (node->getAddIndexClamp())
465 {
466 if (visit == InVisit)
467 {
468 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
469 out << "[int(clamp(float(";
470 else
471 out << "[webgl_int_clamp(";
472 }
473 else if (visit == PostVisit)
474 {
475 int maxSize;
476 TIntermTyped *left = node->getLeft();
477 TType leftType = left->getType();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700478
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100479 if (left->isArray())
480 {
481 // The shader will fail validation if the array length is not > 0.
482 maxSize = static_cast<int>(leftType.getArraySize()) - 1;
483 }
484 else
485 {
486 maxSize = leftType.getNominalSize() - 1;
487 }
488
489 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
490 out << "), 0.0, float(" << maxSize << ")))]";
491 else
492 out << ", 0, " << maxSize << ")]";
493 }
494 }
495 else
496 {
497 writeTriplet(visit, NULL, "[", "]");
498 }
499 break;
500 case EOpIndexDirectStruct:
501 if (visit == InVisit)
502 {
503 // Here we are writing out "foo.bar", where "foo" is struct
504 // and "bar" is field. In AST, it is represented as a binary
505 // node, where left child represents "foo" and right child "bar".
506 // The node itself represents ".". The struct field "bar" is
507 // actually stored as an index into TStructure::fields.
508 out << ".";
509 const TStructure *structure = node->getLeft()->getType().getStruct();
510 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
511 const TField *field = structure->fields()[index->getIConst(0)];
512
513 TString fieldName = field->name();
514 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000515 fieldName = hashName(TName(fieldName));
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100516
517 out << fieldName;
518 visitChildren = false;
519 }
520 break;
521 case EOpIndexDirectInterfaceBlock:
522 if (visit == InVisit)
523 {
524 out << ".";
525 const TInterfaceBlock *interfaceBlock =
526 node->getLeft()->getType().getInterfaceBlock();
527 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
528 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
529
530 TString fieldName = field->name();
531 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000532 fieldName = hashName(TName(fieldName));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700533
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100534 out << fieldName;
535 visitChildren = false;
536 }
537 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400538
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100539 case EOpAdd:
540 writeTriplet(visit, "(", " + ", ")");
541 break;
542 case EOpSub:
543 writeTriplet(visit, "(", " - ", ")");
544 break;
545 case EOpMul:
546 writeTriplet(visit, "(", " * ", ")");
547 break;
548 case EOpDiv:
549 writeTriplet(visit, "(", " / ", ")");
550 break;
551 case EOpIMod:
552 writeTriplet(visit, "(", " % ", ")");
553 break;
554 case EOpBitShiftLeft:
555 writeTriplet(visit, "(", " << ", ")");
556 break;
557 case EOpBitShiftRight:
558 writeTriplet(visit, "(", " >> ", ")");
559 break;
560 case EOpBitwiseAnd:
561 writeTriplet(visit, "(", " & ", ")");
562 break;
563 case EOpBitwiseXor:
564 writeTriplet(visit, "(", " ^ ", ")");
565 break;
566 case EOpBitwiseOr:
567 writeTriplet(visit, "(", " | ", ")");
568 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400569
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100570 case EOpEqual:
571 writeTriplet(visit, "(", " == ", ")");
572 break;
573 case EOpNotEqual:
574 writeTriplet(visit, "(", " != ", ")");
575 break;
576 case EOpLessThan:
577 writeTriplet(visit, "(", " < ", ")");
578 break;
579 case EOpGreaterThan:
580 writeTriplet(visit, "(", " > ", ")");
581 break;
582 case EOpLessThanEqual:
583 writeTriplet(visit, "(", " <= ", ")");
584 break;
585 case EOpGreaterThanEqual:
586 writeTriplet(visit, "(", " >= ", ")");
587 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000588
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100589 // Notice the fall-through.
590 case EOpVectorTimesScalar:
591 case EOpVectorTimesMatrix:
592 case EOpMatrixTimesVector:
593 case EOpMatrixTimesScalar:
594 case EOpMatrixTimesMatrix:
595 writeTriplet(visit, "(", " * ", ")");
596 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200597
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100598 case EOpLogicalOr:
599 writeTriplet(visit, "(", " || ", ")");
600 break;
601 case EOpLogicalXor:
602 writeTriplet(visit, "(", " ^^ ", ")");
603 break;
604 case EOpLogicalAnd:
605 writeTriplet(visit, "(", " && ", ")");
606 break;
607 default:
608 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000609 }
610
611 return visitChildren;
612}
613
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700614bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000615{
zmo@google.com32e97312011-08-24 01:03:11 +0000616 TString preString;
617 TString postString = ")";
618
zmo@google.com5601ea02011-06-10 18:23:25 +0000619 switch (node->getOp())
620 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700621 case EOpNegative: preString = "(-"; break;
Zhenyao Mode1e00e2014-10-09 16:55:32 -0700622 case EOpPositive: preString = "(+"; break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700623 case EOpVectorLogicalNot: preString = "not("; break;
624 case EOpLogicalNot: preString = "(!"; break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200625 case EOpBitwiseNot: preString = "(~"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000626
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700627 case EOpPostIncrement: preString = "("; postString = "++)"; break;
628 case EOpPostDecrement: preString = "("; postString = "--)"; break;
629 case EOpPreIncrement: preString = "(++"; break;
630 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000631
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700632 case EOpRadians:
633 preString = "radians(";
634 break;
635 case EOpDegrees:
636 preString = "degrees(";
637 break;
638 case EOpSin:
639 preString = "sin(";
640 break;
641 case EOpCos:
642 preString = "cos(";
643 break;
644 case EOpTan:
645 preString = "tan(";
646 break;
647 case EOpAsin:
648 preString = "asin(";
649 break;
650 case EOpAcos:
651 preString = "acos(";
652 break;
653 case EOpAtan:
654 preString = "atan(";
655 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000656
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200657 case EOpSinh:
658 preString = "sinh(";
659 break;
660 case EOpCosh:
661 preString = "cosh(";
662 break;
663 case EOpTanh:
664 preString = "tanh(";
665 break;
666 case EOpAsinh:
667 preString = "asinh(";
668 break;
669 case EOpAcosh:
670 preString = "acosh(";
671 break;
672 case EOpAtanh:
673 preString = "atanh(";
674 break;
675
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700676 case EOpExp:
677 preString = "exp(";
678 break;
679 case EOpLog:
680 preString = "log(";
681 break;
682 case EOpExp2:
683 preString = "exp2(";
684 break;
685 case EOpLog2:
686 preString = "log2(";
687 break;
688 case EOpSqrt:
689 preString = "sqrt(";
690 break;
691 case EOpInverseSqrt:
692 preString = "inversesqrt(";
693 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000694
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700695 case EOpAbs:
696 preString = "abs(";
697 break;
698 case EOpSign:
699 preString = "sign(";
700 break;
701 case EOpFloor:
702 preString = "floor(";
703 break;
Qingqing Deng5dbece52015-02-27 20:35:38 -0800704 case EOpTrunc:
705 preString = "trunc(";
706 break;
707 case EOpRound:
708 preString = "round(";
709 break;
710 case EOpRoundEven:
711 preString = "roundEven(";
712 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700713 case EOpCeil:
714 preString = "ceil(";
715 break;
716 case EOpFract:
717 preString = "fract(";
718 break;
Arun Patole0c1726e2015-02-18 14:35:02 +0530719 case EOpIsNan:
720 preString = "isnan(";
721 break;
722 case EOpIsInf:
723 preString = "isinf(";
724 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000725
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200726 case EOpFloatBitsToInt:
727 preString = "floatBitsToInt(";
728 break;
729 case EOpFloatBitsToUint:
730 preString = "floatBitsToUint(";
731 break;
732 case EOpIntBitsToFloat:
733 preString = "intBitsToFloat(";
734 break;
735 case EOpUintBitsToFloat:
736 preString = "uintBitsToFloat(";
737 break;
738
Olli Etuaho7700ff62015-01-15 12:16:29 +0200739 case EOpPackSnorm2x16:
740 preString = "packSnorm2x16(";
741 break;
742 case EOpPackUnorm2x16:
743 preString = "packUnorm2x16(";
744 break;
745 case EOpPackHalf2x16:
746 preString = "packHalf2x16(";
747 break;
748 case EOpUnpackSnorm2x16:
749 preString = "unpackSnorm2x16(";
750 break;
751 case EOpUnpackUnorm2x16:
752 preString = "unpackUnorm2x16(";
753 break;
754 case EOpUnpackHalf2x16:
755 preString = "unpackHalf2x16(";
756 break;
757
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700758 case EOpLength:
759 preString = "length(";
760 break;
761 case EOpNormalize:
762 preString = "normalize(";
763 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000764
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700765 case EOpDFdx:
766 preString = "dFdx(";
767 break;
768 case EOpDFdy:
769 preString = "dFdy(";
770 break;
771 case EOpFwidth:
772 preString = "fwidth(";
773 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000774
Olli Etuahoe39706d2014-12-30 16:40:36 +0200775 case EOpTranspose:
776 preString = "transpose(";
777 break;
778 case EOpDeterminant:
779 preString = "determinant(";
780 break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +0200781 case EOpInverse:
782 preString = "inverse(";
783 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200784
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700785 case EOpAny:
786 preString = "any(";
787 break;
788 case EOpAll:
789 preString = "all(";
790 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000791
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700792 default:
793 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000794 }
795
zmo@google.com32e97312011-08-24 01:03:11 +0000796 if (visit == PreVisit && node->getUseEmulatedFunction())
797 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
798 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
799
zmo@google.com5601ea02011-06-10 18:23:25 +0000800 return true;
801}
802
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300803bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
804{
805 TInfoSinkBase &out = objSink();
806 // Notice two brackets at the beginning and end. The outer ones
807 // encapsulate the whole ternary expression. This preserves the
808 // order of precedence when ternary expressions are used in a
809 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
810 out << "((";
811 node->getCondition()->traverse(this);
812 out << ") ? (";
813 node->getTrueExpression()->traverse(this);
814 out << ") : (";
815 node->getFalseExpression()->traverse(this);
816 out << "))";
817 return false;
818}
819
Olli Etuaho57961272016-09-14 13:57:46 +0300820bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000821{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700822 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000823
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300824 out << "if (";
825 node->getCondition()->traverse(this);
826 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000827
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300828 incrementDepth(node);
829 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000830
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300831 if (node->getFalseBlock())
832 {
833 out << "else\n";
834 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000835 }
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300836 decrementDepth();
zmo@google.com5601ea02011-06-10 18:23:25 +0000837 return false;
838}
839
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200840bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200841{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200842 if (node->getStatementList())
843 {
844 writeTriplet(visit, "switch (", ") ", nullptr);
845 // The curly braces get written when visiting the statementList aggregate
846 }
847 else
848 {
849 // No statementList, so it won't output curly braces
850 writeTriplet(visit, "switch (", ") {", "}\n");
851 }
852 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200853}
854
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200855bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200856{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200857 if (node->hasCondition())
858 {
859 writeTriplet(visit, "case (", nullptr, "):\n");
860 return true;
861 }
862 else
863 {
864 TInfoSinkBase &out = objSink();
865 out << "default:\n";
866 return false;
867 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200868}
869
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100870bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
871{
872 TInfoSinkBase &out = objSink();
873 // Scope the blocks except when at the global scope.
874 if (mDepth > 0)
875 {
876 out << "{\n";
877 }
878
879 incrementDepth(node);
880 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
881 iter != node->getSequence()->end(); ++iter)
882 {
883 TIntermNode *curNode = *iter;
884 ASSERT(curNode != nullptr);
885 curNode->traverse(this);
886
887 if (isSingleStatement(curNode))
888 out << ";\n";
889 }
890 decrementDepth();
891
892 // Scope the blocks except when at the global scope.
893 if (mDepth > 0)
894 {
895 out << "}\n";
896 }
897 return false;
898}
899
Olli Etuaho336b1472016-10-05 16:37:55 +0100900bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
901{
902 TInfoSinkBase &out = objSink();
903
904 ASSERT(visit == PreVisit);
905 {
906 const TType &type = node->getType();
907 writeVariableType(type);
908 if (type.isArray())
909 out << arrayBrackets(type);
910 }
911
912 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
913
914 incrementDepth(node);
915
916 // Traverse function parameters.
917 TIntermAggregate *params = node->getFunctionParameters()->getAsAggregate();
918 ASSERT(params->getOp() == EOpParameters);
919 params->traverse(this);
920
921 // Traverse function body.
922 visitCodeBlock(node->getBody());
923 decrementDepth();
924
925 // Fully processed; no need to visit children.
926 return false;
927}
928
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700929bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000930{
931 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700932 TInfoSinkBase &out = objSink();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700933 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000934 switch (node->getOp())
935 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700936 case EOpPrototype:
937 // Function declaration.
938 ASSERT(visit == PreVisit);
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300939 {
940 const TType &type = node->getType();
941 writeVariableType(type);
942 if (type.isArray())
943 out << arrayBrackets(type);
944 }
945
Olli Etuahobd674552016-10-06 13:28:42 +0100946 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700947
948 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700949 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700950 out << ")";
951
952 visitChildren = false;
953 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700954 case EOpFunctionCall:
955 // Function call.
956 if (visit == PreVisit)
Olli Etuahobd674552016-10-06 13:28:42 +0100957 out << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200958 else if (visit == InVisit)
959 out << ", ";
960 else
961 out << ")";
962 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700963 case EOpParameters:
964 // Function parameters.
965 ASSERT(visit == PreVisit);
966 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700967 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700968 out << ")";
969 visitChildren = false;
970 break;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700971 case EOpInvariantDeclaration:
972 // Invariant declaration.
973 ASSERT(visit == PreVisit);
974 {
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400975 const TIntermSequence *sequence = node->getSequence();
976 ASSERT(sequence && sequence->size() == 1);
977 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
978 ASSERT(symbol);
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000979 out << "invariant " << hashVariableName(symbol->getName());
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400980 }
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700981 visitChildren = false;
982 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700983 case EOpConstructFloat:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700984 case EOpConstructVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700985 case EOpConstructVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700986 case EOpConstructVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700987 case EOpConstructBool:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700988 case EOpConstructBVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700989 case EOpConstructBVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700990 case EOpConstructBVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700991 case EOpConstructInt:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700992 case EOpConstructIVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700993 case EOpConstructIVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700994 case EOpConstructIVec4:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400995 case EOpConstructUInt:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400996 case EOpConstructUVec2:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400997 case EOpConstructUVec3:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400998 case EOpConstructUVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700999 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -04001000 case EOpConstructMat2x3:
Alexis Hetu07e57df2015-06-16 16:55:52 -04001001 case EOpConstructMat2x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -04001002 case EOpConstructMat3x2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001003 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -04001004 case EOpConstructMat3x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -04001005 case EOpConstructMat4x2:
Alexis Hetu07e57df2015-06-16 16:55:52 -04001006 case EOpConstructMat4x3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001007 case EOpConstructMat4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001008 case EOpConstructStruct:
Olli Etuahoe92507b2016-07-04 11:20:10 +03001009 writeConstructorTriplet(visit, node->getType());
1010 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001011
Olli Etuahoe39706d2014-12-30 16:40:36 +02001012 case EOpOuterProduct:
1013 writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
1014 break;
1015
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001016 case EOpLessThan:
1017 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
1018 break;
1019 case EOpGreaterThan:
1020 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
1021 break;
1022 case EOpLessThanEqual:
1023 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
1024 break;
1025 case EOpGreaterThanEqual:
1026 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
1027 break;
1028 case EOpVectorEqual:
1029 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
1030 break;
1031 case EOpVectorNotEqual:
1032 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
1033 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001034
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001035 case EOpMod:
1036 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
1037 break;
Olli Etuahob6e07a62015-02-16 12:22:10 +02001038 case EOpModf:
1039 writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
1040 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001041 case EOpPow:
1042 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
1043 break;
1044 case EOpAtan:
1045 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
1046 break;
1047 case EOpMin:
1048 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
1049 break;
1050 case EOpMax:
1051 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
1052 break;
1053 case EOpClamp:
1054 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
1055 break;
1056 case EOpMix:
1057 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
1058 break;
1059 case EOpStep:
1060 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
1061 break;
1062 case EOpSmoothStep:
1063 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
1064 break;
1065 case EOpDistance:
1066 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
1067 break;
1068 case EOpDot:
1069 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
1070 break;
1071 case EOpCross:
1072 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
1073 break;
1074 case EOpFaceForward:
1075 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
1076 break;
1077 case EOpReflect:
1078 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
1079 break;
1080 case EOpRefract:
1081 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
1082 break;
1083 case EOpMul:
1084 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
1085 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001086
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001087 default:
1088 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001089 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001090 return visitChildren;
1091}
1092
Olli Etuaho13389b62016-10-16 11:48:18 +01001093bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
1094{
1095 TInfoSinkBase &out = objSink();
1096
1097 // Variable declaration.
1098 if (visit == PreVisit)
1099 {
1100 const TIntermSequence &sequence = *(node->getSequence());
1101 const TIntermTyped *variable = sequence.front()->getAsTyped();
1102 writeLayoutQualifier(variable->getType());
1103 writeVariableType(variable->getType());
1104 out << " ";
1105 mDeclaringVariables = true;
1106 }
1107 else if (visit == InVisit)
1108 {
1109 out << ", ";
1110 mDeclaringVariables = true;
1111 }
1112 else
1113 {
1114 mDeclaringVariables = false;
1115 }
1116 return true;
1117}
1118
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001119bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001120{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001121 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001122
Zhenyao Mo7cab38b2013-10-15 12:59:30 -07001123 incrementDepth(node);
Corentin Wallez7258e302015-09-22 10:40:24 -07001124
zmo@google.com5601ea02011-06-10 18:23:25 +00001125 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001126
1127 // Only for loops can be unrolled
1128 ASSERT(!node->getUnrollFlag() || loopType == ELoopFor);
1129
zmo@google.com5601ea02011-06-10 18:23:25 +00001130 if (loopType == ELoopFor) // for loop
1131 {
Zhenyao Mo550c6002014-02-26 15:40:48 -08001132 if (!node->getUnrollFlag())
1133 {
zmo@google.com5601ea02011-06-10 18:23:25 +00001134 out << "for (";
1135 if (node->getInit())
1136 node->getInit()->traverse(this);
1137 out << "; ";
1138
1139 if (node->getCondition())
1140 node->getCondition()->traverse(this);
1141 out << "; ";
1142
1143 if (node->getExpression())
1144 node->getExpression()->traverse(this);
1145 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001146
1147 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001148 }
Zhenyao Mo550c6002014-02-26 15:40:48 -08001149 else
1150 {
1151 // Need to put a one-iteration loop here to handle break.
Olli Etuaho13389b62016-10-16 11:48:18 +01001152 TIntermSequence *declSeq = node->getInit()->getAsDeclarationNode()->getSequence();
Zhenyao Mo550c6002014-02-26 15:40:48 -08001153 TIntermSymbol *indexSymbol =
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001154 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001155 TString name = hashVariableName(indexSymbol->getName());
Zhenyao Mo550c6002014-02-26 15:40:48 -08001156 out << "for (int " << name << " = 0; "
1157 << name << " < 1; "
1158 << "++" << name << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001159
1160 out << "{\n";
1161 mLoopUnrollStack.push(node);
1162 while (mLoopUnrollStack.satisfiesLoopCondition())
1163 {
1164 visitCodeBlock(node->getBody());
1165 mLoopUnrollStack.step();
1166 }
1167 mLoopUnrollStack.pop();
1168 out << "}\n";
Zhenyao Mo550c6002014-02-26 15:40:48 -08001169 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001170 }
1171 else if (loopType == ELoopWhile) // while loop
1172 {
1173 out << "while (";
1174 ASSERT(node->getCondition() != NULL);
1175 node->getCondition()->traverse(this);
1176 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001177
1178 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001179 }
1180 else // do-while loop
1181 {
1182 ASSERT(loopType == ELoopDoWhile);
1183 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001184
zmo@google.com5601ea02011-06-10 18:23:25 +00001185 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001186
zmo@google.com5601ea02011-06-10 18:23:25 +00001187 out << "while (";
1188 ASSERT(node->getCondition() != NULL);
1189 node->getCondition()->traverse(this);
1190 out << ");\n";
1191 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001192
zmo@google.com5601ea02011-06-10 18:23:25 +00001193 decrementDepth();
1194
1195 // No need to visit children. They have been already processed in
1196 // this function.
1197 return false;
1198}
1199
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001200bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001201{
1202 switch (node->getFlowOp())
1203 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001204 case EOpKill:
1205 writeTriplet(visit, "discard", NULL, NULL);
1206 break;
1207 case EOpBreak:
1208 writeTriplet(visit, "break", NULL, NULL);
1209 break;
1210 case EOpContinue:
1211 writeTriplet(visit, "continue", NULL, NULL);
1212 break;
1213 case EOpReturn:
1214 writeTriplet(visit, "return ", NULL, NULL);
1215 break;
1216 default:
1217 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001218 }
1219
1220 return true;
1221}
1222
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001223void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001224{
zmo@google.com5601ea02011-06-10 18:23:25 +00001225 TInfoSinkBase &out = objSink();
1226 if (node != NULL)
1227 {
1228 node->traverse(this);
1229 // Single statements not part of a sequence need to be terminated
1230 // with semi-colon.
1231 if (isSingleStatement(node))
1232 out << ";\n";
1233 }
1234 else
1235 {
1236 out << "{\n}\n"; // Empty code block.
1237 }
1238}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001239
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001240TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001241{
Olli Etuahoe92507b2016-07-04 11:20:10 +03001242 if (type.getBasicType() == EbtStruct)
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001243 return hashName(TName(type.getStruct()->name()));
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001244 else
Olli Etuahoe92507b2016-07-04 11:20:10 +03001245 return type.getBuiltInTypeNameString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001246}
1247
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001248TString TOutputGLSLBase::hashName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001249{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001250 if (name.getString().empty())
1251 {
1252 ASSERT(!name.isInternal());
1253 return name.getString();
1254 }
1255 if (name.isInternal())
1256 {
1257 // TODO(oetuaho): Would be nicer to prefix non-internal names with "_" instead, like is
1258 // done in the HLSL output, but that requires fairly complex changes elsewhere in the code
1259 // as well.
1260 // We need to use a prefix that is reserved in WebGL in order to guarantee that the internal
1261 // names don't conflict with user-defined names from WebGL.
1262 return "webgl_angle_" + name.getString();
1263 }
1264 if (mHashFunction == nullptr)
1265 {
1266 return name.getString();
1267 }
1268 NameMap::const_iterator it = mNameMap.find(name.getString().c_str());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001269 if (it != mNameMap.end())
1270 return it->second.c_str();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001271 TString hashedName = TIntermTraverser::hash(name.getString(), mHashFunction);
1272 mNameMap[name.getString().c_str()] = hashedName.c_str();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001273 return hashedName;
1274}
1275
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001276TString TOutputGLSLBase::hashVariableName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001277{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001278 if (mSymbolTable.findBuiltIn(name.getString(), mShaderVersion) != NULL)
1279 return name.getString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001280 return hashName(name);
1281}
1282
Olli Etuaho59f9a642015-08-06 20:38:26 +03001283TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001284{
Olli Etuaho59f9a642015-08-06 20:38:26 +03001285 TString mangledStr = mangledName.getString();
1286 TString name = TFunction::unmangleName(mangledStr);
1287 if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001288 return translateTextureFunction(name);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001289 if (mangledName.isInternal())
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001290 {
1291 // Internal function names are outputted as-is - they may refer to functions manually added
1292 // to the output shader source that are not included in the AST at all.
Olli Etuaho59f9a642015-08-06 20:38:26 +03001293 return name;
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001294 }
Olli Etuaho59f9a642015-08-06 20:38:26 +03001295 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001296 {
1297 TName nameObj(name);
1298 return hashName(nameObj);
1299 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001300}
Jamie Madill98493dd2013-07-08 14:39:03 -04001301
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001302bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001303{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001304 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001305 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001306 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001307 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001308 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001309
1310 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001311}
1312
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001313void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001314{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001315 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001316
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001317 out << "struct " << hashName(TName(structure->name())) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001318 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001319 for (size_t i = 0; i < fields.size(); ++i)
1320 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001321 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001322 if (writeVariablePrecision(field->type()->getPrecision()))
1323 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001324 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Jamie Madill98493dd2013-07-08 14:39:03 -04001325 if (field->type()->isArray())
1326 out << arrayBrackets(*field->type());
1327 out << ";\n";
1328 }
1329 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001330}
Jamie Madill98493dd2013-07-08 14:39:03 -04001331
Geoff Langbdcc54a2015-09-02 13:09:48 -04001332void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1333{
1334 TInfoSinkBase &out = objSink();
1335
1336 out << "layout(";
1337
1338 switch (interfaceBlock->blockStorage())
1339 {
1340 case EbsUnspecified:
1341 case EbsShared:
1342 // Default block storage is shared.
1343 out << "shared";
1344 break;
1345
1346 case EbsPacked:
1347 out << "packed";
1348 break;
1349
1350 case EbsStd140:
1351 out << "std140";
1352 break;
1353
1354 default:
1355 UNREACHABLE();
1356 break;
1357 }
1358
1359 out << ", ";
1360
1361 switch (interfaceBlock->matrixPacking())
1362 {
1363 case EmpUnspecified:
1364 case EmpColumnMajor:
1365 // Default matrix packing is column major.
1366 out << "column_major";
1367 break;
1368
1369 case EmpRowMajor:
1370 out << "row_major";
1371 break;
1372
1373 default:
1374 UNREACHABLE();
1375 break;
1376 }
1377
1378 out << ") ";
1379}
1380
1381void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1382{
1383 TInfoSinkBase &out = objSink();
1384
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001385 out << hashName(TName(interfaceBlock->name())) << "{\n";
Geoff Langbdcc54a2015-09-02 13:09:48 -04001386 const TFieldList &fields = interfaceBlock->fields();
1387 for (size_t i = 0; i < fields.size(); ++i)
1388 {
1389 const TField *field = fields[i];
1390 if (writeVariablePrecision(field->type()->getPrecision()))
1391 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001392 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Geoff Langbdcc54a2015-09-02 13:09:48 -04001393 if (field->type()->isArray())
1394 out << arrayBrackets(*field->type());
1395 out << ";\n";
1396 }
1397 out << "}";
1398}
Jamie Madill45bcc782016-11-07 13:58:48 -05001399
1400} // namespace sh