blob: 6860edc6972854d727a0bb598957978a53e1e173 [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();
Corentin Wallez1b896c62016-11-16 13:10:44 -0500379 out << hashVariableName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000380
381 if (mDeclaringVariables && node->getType().isArray())
382 out << arrayBrackets(node->getType());
383}
384
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700385void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000386{
387 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
388}
389
Olli Etuahob6fa0432016-09-28 16:28:05 +0100390bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
391{
392 TInfoSinkBase &out = objSink();
393 if (visit == PostVisit)
394 {
395 out << ".";
396 node->writeOffsetsAsXYZW(&out);
397 }
398 return true;
399}
400
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700401bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000402{
403 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700404 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000405 switch (node->getOp())
406 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100407 case EOpComma:
408 writeTriplet(visit, "(", ", ", ")");
409 break;
410 case EOpInitialize:
zmo@google.com5601ea02011-06-10 18:23:25 +0000411 if (visit == InVisit)
412 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100413 out << " = ";
414 // RHS of initialize is not being declared.
415 mDeclaringVariables = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000416 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100417 break;
418 case EOpAssign:
419 writeTriplet(visit, "(", " = ", ")");
420 break;
421 case EOpAddAssign:
422 writeTriplet(visit, "(", " += ", ")");
423 break;
424 case EOpSubAssign:
425 writeTriplet(visit, "(", " -= ", ")");
426 break;
427 case EOpDivAssign:
428 writeTriplet(visit, "(", " /= ", ")");
429 break;
430 case EOpIModAssign:
431 writeTriplet(visit, "(", " %= ", ")");
432 break;
433 // Notice the fall-through.
434 case EOpMulAssign:
435 case EOpVectorTimesMatrixAssign:
436 case EOpVectorTimesScalarAssign:
437 case EOpMatrixTimesScalarAssign:
438 case EOpMatrixTimesMatrixAssign:
439 writeTriplet(visit, "(", " *= ", ")");
440 break;
441 case EOpBitShiftLeftAssign:
442 writeTriplet(visit, "(", " <<= ", ")");
443 break;
444 case EOpBitShiftRightAssign:
445 writeTriplet(visit, "(", " >>= ", ")");
446 break;
447 case EOpBitwiseAndAssign:
448 writeTriplet(visit, "(", " &= ", ")");
449 break;
450 case EOpBitwiseXorAssign:
451 writeTriplet(visit, "(", " ^= ", ")");
452 break;
453 case EOpBitwiseOrAssign:
454 writeTriplet(visit, "(", " |= ", ")");
455 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000456
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100457 case EOpIndexDirect:
zmo@google.com5601ea02011-06-10 18:23:25 +0000458 writeTriplet(visit, NULL, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100459 break;
460 case EOpIndexIndirect:
461 if (node->getAddIndexClamp())
462 {
463 if (visit == InVisit)
464 {
465 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
466 out << "[int(clamp(float(";
467 else
468 out << "[webgl_int_clamp(";
469 }
470 else if (visit == PostVisit)
471 {
472 int maxSize;
473 TIntermTyped *left = node->getLeft();
474 TType leftType = left->getType();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700475
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100476 if (left->isArray())
477 {
478 // The shader will fail validation if the array length is not > 0.
479 maxSize = static_cast<int>(leftType.getArraySize()) - 1;
480 }
481 else
482 {
483 maxSize = leftType.getNominalSize() - 1;
484 }
485
486 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
487 out << "), 0.0, float(" << maxSize << ")))]";
488 else
489 out << ", 0, " << maxSize << ")]";
490 }
491 }
492 else
493 {
494 writeTriplet(visit, NULL, "[", "]");
495 }
496 break;
497 case EOpIndexDirectStruct:
498 if (visit == InVisit)
499 {
500 // Here we are writing out "foo.bar", where "foo" is struct
501 // and "bar" is field. In AST, it is represented as a binary
502 // node, where left child represents "foo" and right child "bar".
503 // The node itself represents ".". The struct field "bar" is
504 // actually stored as an index into TStructure::fields.
505 out << ".";
506 const TStructure *structure = node->getLeft()->getType().getStruct();
507 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
508 const TField *field = structure->fields()[index->getIConst(0)];
509
510 TString fieldName = field->name();
511 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000512 fieldName = hashName(TName(fieldName));
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100513
514 out << fieldName;
515 visitChildren = false;
516 }
517 break;
518 case EOpIndexDirectInterfaceBlock:
519 if (visit == InVisit)
520 {
521 out << ".";
522 const TInterfaceBlock *interfaceBlock =
523 node->getLeft()->getType().getInterfaceBlock();
524 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
525 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
526
527 TString fieldName = field->name();
528 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000529 fieldName = hashName(TName(fieldName));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700530
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100531 out << fieldName;
532 visitChildren = false;
533 }
534 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400535
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100536 case EOpAdd:
537 writeTriplet(visit, "(", " + ", ")");
538 break;
539 case EOpSub:
540 writeTriplet(visit, "(", " - ", ")");
541 break;
542 case EOpMul:
543 writeTriplet(visit, "(", " * ", ")");
544 break;
545 case EOpDiv:
546 writeTriplet(visit, "(", " / ", ")");
547 break;
548 case EOpIMod:
549 writeTriplet(visit, "(", " % ", ")");
550 break;
551 case EOpBitShiftLeft:
552 writeTriplet(visit, "(", " << ", ")");
553 break;
554 case EOpBitShiftRight:
555 writeTriplet(visit, "(", " >> ", ")");
556 break;
557 case EOpBitwiseAnd:
558 writeTriplet(visit, "(", " & ", ")");
559 break;
560 case EOpBitwiseXor:
561 writeTriplet(visit, "(", " ^ ", ")");
562 break;
563 case EOpBitwiseOr:
564 writeTriplet(visit, "(", " | ", ")");
565 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400566
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100567 case EOpEqual:
568 writeTriplet(visit, "(", " == ", ")");
569 break;
570 case EOpNotEqual:
571 writeTriplet(visit, "(", " != ", ")");
572 break;
573 case EOpLessThan:
574 writeTriplet(visit, "(", " < ", ")");
575 break;
576 case EOpGreaterThan:
577 writeTriplet(visit, "(", " > ", ")");
578 break;
579 case EOpLessThanEqual:
580 writeTriplet(visit, "(", " <= ", ")");
581 break;
582 case EOpGreaterThanEqual:
583 writeTriplet(visit, "(", " >= ", ")");
584 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000585
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100586 // Notice the fall-through.
587 case EOpVectorTimesScalar:
588 case EOpVectorTimesMatrix:
589 case EOpMatrixTimesVector:
590 case EOpMatrixTimesScalar:
591 case EOpMatrixTimesMatrix:
592 writeTriplet(visit, "(", " * ", ")");
593 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200594
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100595 case EOpLogicalOr:
596 writeTriplet(visit, "(", " || ", ")");
597 break;
598 case EOpLogicalXor:
599 writeTriplet(visit, "(", " ^^ ", ")");
600 break;
601 case EOpLogicalAnd:
602 writeTriplet(visit, "(", " && ", ")");
603 break;
604 default:
605 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000606 }
607
608 return visitChildren;
609}
610
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700611bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000612{
zmo@google.com32e97312011-08-24 01:03:11 +0000613 TString preString;
614 TString postString = ")";
615
zmo@google.com5601ea02011-06-10 18:23:25 +0000616 switch (node->getOp())
617 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700618 case EOpNegative: preString = "(-"; break;
Zhenyao Mode1e00e2014-10-09 16:55:32 -0700619 case EOpPositive: preString = "(+"; break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700620 case EOpVectorLogicalNot: preString = "not("; break;
621 case EOpLogicalNot: preString = "(!"; break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200622 case EOpBitwiseNot: preString = "(~"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000623
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700624 case EOpPostIncrement: preString = "("; postString = "++)"; break;
625 case EOpPostDecrement: preString = "("; postString = "--)"; break;
626 case EOpPreIncrement: preString = "(++"; break;
627 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000628
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700629 case EOpRadians:
630 preString = "radians(";
631 break;
632 case EOpDegrees:
633 preString = "degrees(";
634 break;
635 case EOpSin:
636 preString = "sin(";
637 break;
638 case EOpCos:
639 preString = "cos(";
640 break;
641 case EOpTan:
642 preString = "tan(";
643 break;
644 case EOpAsin:
645 preString = "asin(";
646 break;
647 case EOpAcos:
648 preString = "acos(";
649 break;
650 case EOpAtan:
651 preString = "atan(";
652 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000653
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200654 case EOpSinh:
655 preString = "sinh(";
656 break;
657 case EOpCosh:
658 preString = "cosh(";
659 break;
660 case EOpTanh:
661 preString = "tanh(";
662 break;
663 case EOpAsinh:
664 preString = "asinh(";
665 break;
666 case EOpAcosh:
667 preString = "acosh(";
668 break;
669 case EOpAtanh:
670 preString = "atanh(";
671 break;
672
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700673 case EOpExp:
674 preString = "exp(";
675 break;
676 case EOpLog:
677 preString = "log(";
678 break;
679 case EOpExp2:
680 preString = "exp2(";
681 break;
682 case EOpLog2:
683 preString = "log2(";
684 break;
685 case EOpSqrt:
686 preString = "sqrt(";
687 break;
688 case EOpInverseSqrt:
689 preString = "inversesqrt(";
690 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000691
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700692 case EOpAbs:
693 preString = "abs(";
694 break;
695 case EOpSign:
696 preString = "sign(";
697 break;
698 case EOpFloor:
699 preString = "floor(";
700 break;
Qingqing Deng5dbece52015-02-27 20:35:38 -0800701 case EOpTrunc:
702 preString = "trunc(";
703 break;
704 case EOpRound:
705 preString = "round(";
706 break;
707 case EOpRoundEven:
708 preString = "roundEven(";
709 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700710 case EOpCeil:
711 preString = "ceil(";
712 break;
713 case EOpFract:
714 preString = "fract(";
715 break;
Arun Patole0c1726e2015-02-18 14:35:02 +0530716 case EOpIsNan:
717 preString = "isnan(";
718 break;
719 case EOpIsInf:
720 preString = "isinf(";
721 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000722
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200723 case EOpFloatBitsToInt:
724 preString = "floatBitsToInt(";
725 break;
726 case EOpFloatBitsToUint:
727 preString = "floatBitsToUint(";
728 break;
729 case EOpIntBitsToFloat:
730 preString = "intBitsToFloat(";
731 break;
732 case EOpUintBitsToFloat:
733 preString = "uintBitsToFloat(";
734 break;
735
Olli Etuaho7700ff62015-01-15 12:16:29 +0200736 case EOpPackSnorm2x16:
737 preString = "packSnorm2x16(";
738 break;
739 case EOpPackUnorm2x16:
740 preString = "packUnorm2x16(";
741 break;
742 case EOpPackHalf2x16:
743 preString = "packHalf2x16(";
744 break;
745 case EOpUnpackSnorm2x16:
746 preString = "unpackSnorm2x16(";
747 break;
748 case EOpUnpackUnorm2x16:
749 preString = "unpackUnorm2x16(";
750 break;
751 case EOpUnpackHalf2x16:
752 preString = "unpackHalf2x16(";
753 break;
754
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700755 case EOpLength:
756 preString = "length(";
757 break;
758 case EOpNormalize:
759 preString = "normalize(";
760 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000761
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700762 case EOpDFdx:
763 preString = "dFdx(";
764 break;
765 case EOpDFdy:
766 preString = "dFdy(";
767 break;
768 case EOpFwidth:
769 preString = "fwidth(";
770 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000771
Olli Etuahoe39706d2014-12-30 16:40:36 +0200772 case EOpTranspose:
773 preString = "transpose(";
774 break;
775 case EOpDeterminant:
776 preString = "determinant(";
777 break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +0200778 case EOpInverse:
779 preString = "inverse(";
780 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200781
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700782 case EOpAny:
783 preString = "any(";
784 break;
785 case EOpAll:
786 preString = "all(";
787 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000788
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700789 default:
790 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000791 }
792
zmo@google.com32e97312011-08-24 01:03:11 +0000793 if (visit == PreVisit && node->getUseEmulatedFunction())
794 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
795 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
796
zmo@google.com5601ea02011-06-10 18:23:25 +0000797 return true;
798}
799
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300800bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
801{
802 TInfoSinkBase &out = objSink();
803 // Notice two brackets at the beginning and end. The outer ones
804 // encapsulate the whole ternary expression. This preserves the
805 // order of precedence when ternary expressions are used in a
806 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
807 out << "((";
808 node->getCondition()->traverse(this);
809 out << ") ? (";
810 node->getTrueExpression()->traverse(this);
811 out << ") : (";
812 node->getFalseExpression()->traverse(this);
813 out << "))";
814 return false;
815}
816
Olli Etuaho57961272016-09-14 13:57:46 +0300817bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000818{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700819 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000820
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300821 out << "if (";
822 node->getCondition()->traverse(this);
823 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000824
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300825 incrementDepth(node);
826 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000827
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300828 if (node->getFalseBlock())
829 {
830 out << "else\n";
831 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000832 }
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300833 decrementDepth();
zmo@google.com5601ea02011-06-10 18:23:25 +0000834 return false;
835}
836
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200837bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200838{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200839 if (node->getStatementList())
840 {
841 writeTriplet(visit, "switch (", ") ", nullptr);
842 // The curly braces get written when visiting the statementList aggregate
843 }
844 else
845 {
846 // No statementList, so it won't output curly braces
847 writeTriplet(visit, "switch (", ") {", "}\n");
848 }
849 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200850}
851
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200852bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200853{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200854 if (node->hasCondition())
855 {
856 writeTriplet(visit, "case (", nullptr, "):\n");
857 return true;
858 }
859 else
860 {
861 TInfoSinkBase &out = objSink();
862 out << "default:\n";
863 return false;
864 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200865}
866
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100867bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
868{
869 TInfoSinkBase &out = objSink();
870 // Scope the blocks except when at the global scope.
871 if (mDepth > 0)
872 {
873 out << "{\n";
874 }
875
876 incrementDepth(node);
877 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
878 iter != node->getSequence()->end(); ++iter)
879 {
880 TIntermNode *curNode = *iter;
881 ASSERT(curNode != nullptr);
882 curNode->traverse(this);
883
884 if (isSingleStatement(curNode))
885 out << ";\n";
886 }
887 decrementDepth();
888
889 // Scope the blocks except when at the global scope.
890 if (mDepth > 0)
891 {
892 out << "}\n";
893 }
894 return false;
895}
896
Olli Etuaho336b1472016-10-05 16:37:55 +0100897bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
898{
899 TInfoSinkBase &out = objSink();
900
901 ASSERT(visit == PreVisit);
902 {
903 const TType &type = node->getType();
904 writeVariableType(type);
905 if (type.isArray())
906 out << arrayBrackets(type);
907 }
908
909 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
910
911 incrementDepth(node);
912
913 // Traverse function parameters.
914 TIntermAggregate *params = node->getFunctionParameters()->getAsAggregate();
915 ASSERT(params->getOp() == EOpParameters);
916 params->traverse(this);
917
918 // Traverse function body.
919 visitCodeBlock(node->getBody());
920 decrementDepth();
921
922 // Fully processed; no need to visit children.
923 return false;
924}
925
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700926bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000927{
928 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700929 TInfoSinkBase &out = objSink();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700930 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000931 switch (node->getOp())
932 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700933 case EOpPrototype:
934 // Function declaration.
935 ASSERT(visit == PreVisit);
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300936 {
937 const TType &type = node->getType();
938 writeVariableType(type);
939 if (type.isArray())
940 out << arrayBrackets(type);
941 }
942
Olli Etuahobd674552016-10-06 13:28:42 +0100943 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700944
945 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700946 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700947 out << ")";
948
949 visitChildren = false;
950 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700951 case EOpFunctionCall:
952 // Function call.
953 if (visit == PreVisit)
Olli Etuahobd674552016-10-06 13:28:42 +0100954 out << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200955 else if (visit == InVisit)
956 out << ", ";
957 else
958 out << ")";
959 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700960 case EOpParameters:
961 // Function parameters.
962 ASSERT(visit == PreVisit);
963 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700964 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700965 out << ")";
966 visitChildren = false;
967 break;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700968 case EOpInvariantDeclaration:
969 // Invariant declaration.
970 ASSERT(visit == PreVisit);
971 {
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400972 const TIntermSequence *sequence = node->getSequence();
973 ASSERT(sequence && sequence->size() == 1);
974 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
975 ASSERT(symbol);
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000976 out << "invariant " << hashVariableName(symbol->getName());
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400977 }
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700978 visitChildren = false;
979 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700980 case EOpConstructFloat:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700981 case EOpConstructVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700982 case EOpConstructVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700983 case EOpConstructVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700984 case EOpConstructBool:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700985 case EOpConstructBVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700986 case EOpConstructBVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700987 case EOpConstructBVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700988 case EOpConstructInt:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700989 case EOpConstructIVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700990 case EOpConstructIVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700991 case EOpConstructIVec4:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400992 case EOpConstructUInt:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400993 case EOpConstructUVec2:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400994 case EOpConstructUVec3:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400995 case EOpConstructUVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700996 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400997 case EOpConstructMat2x3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400998 case EOpConstructMat2x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400999 case EOpConstructMat3x2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001000 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -04001001 case EOpConstructMat3x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -04001002 case EOpConstructMat4x2:
Alexis Hetu07e57df2015-06-16 16:55:52 -04001003 case EOpConstructMat4x3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001004 case EOpConstructMat4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001005 case EOpConstructStruct:
Olli Etuahoe92507b2016-07-04 11:20:10 +03001006 writeConstructorTriplet(visit, node->getType());
1007 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001008
Olli Etuahoe39706d2014-12-30 16:40:36 +02001009 case EOpOuterProduct:
1010 writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
1011 break;
1012
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001013 case EOpLessThan:
1014 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
1015 break;
1016 case EOpGreaterThan:
1017 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
1018 break;
1019 case EOpLessThanEqual:
1020 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
1021 break;
1022 case EOpGreaterThanEqual:
1023 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
1024 break;
1025 case EOpVectorEqual:
1026 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
1027 break;
1028 case EOpVectorNotEqual:
1029 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
1030 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001031
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001032 case EOpMod:
1033 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
1034 break;
Olli Etuahob6e07a62015-02-16 12:22:10 +02001035 case EOpModf:
1036 writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
1037 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001038 case EOpPow:
1039 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
1040 break;
1041 case EOpAtan:
1042 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
1043 break;
1044 case EOpMin:
1045 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
1046 break;
1047 case EOpMax:
1048 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
1049 break;
1050 case EOpClamp:
1051 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
1052 break;
1053 case EOpMix:
1054 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
1055 break;
1056 case EOpStep:
1057 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
1058 break;
1059 case EOpSmoothStep:
1060 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
1061 break;
1062 case EOpDistance:
1063 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
1064 break;
1065 case EOpDot:
1066 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
1067 break;
1068 case EOpCross:
1069 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
1070 break;
1071 case EOpFaceForward:
1072 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
1073 break;
1074 case EOpReflect:
1075 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
1076 break;
1077 case EOpRefract:
1078 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
1079 break;
1080 case EOpMul:
1081 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
1082 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001083
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001084 default:
1085 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001086 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001087 return visitChildren;
1088}
1089
Olli Etuaho13389b62016-10-16 11:48:18 +01001090bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
1091{
1092 TInfoSinkBase &out = objSink();
1093
1094 // Variable declaration.
1095 if (visit == PreVisit)
1096 {
1097 const TIntermSequence &sequence = *(node->getSequence());
1098 const TIntermTyped *variable = sequence.front()->getAsTyped();
1099 writeLayoutQualifier(variable->getType());
1100 writeVariableType(variable->getType());
1101 out << " ";
1102 mDeclaringVariables = true;
1103 }
1104 else if (visit == InVisit)
1105 {
1106 out << ", ";
1107 mDeclaringVariables = true;
1108 }
1109 else
1110 {
1111 mDeclaringVariables = false;
1112 }
1113 return true;
1114}
1115
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001116bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001117{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001118 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001119
Zhenyao Mo7cab38b2013-10-15 12:59:30 -07001120 incrementDepth(node);
Corentin Wallez7258e302015-09-22 10:40:24 -07001121
zmo@google.com5601ea02011-06-10 18:23:25 +00001122 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001123
zmo@google.com5601ea02011-06-10 18:23:25 +00001124 if (loopType == ELoopFor) // for loop
1125 {
Corentin Wallez1b896c62016-11-16 13:10:44 -05001126 out << "for (";
1127 if (node->getInit())
1128 node->getInit()->traverse(this);
1129 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001130
Corentin Wallez1b896c62016-11-16 13:10:44 -05001131 if (node->getCondition())
1132 node->getCondition()->traverse(this);
1133 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001134
Corentin Wallez1b896c62016-11-16 13:10:44 -05001135 if (node->getExpression())
1136 node->getExpression()->traverse(this);
1137 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001138
Corentin Wallez1b896c62016-11-16 13:10:44 -05001139 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001140 }
1141 else if (loopType == ELoopWhile) // while loop
1142 {
1143 out << "while (";
1144 ASSERT(node->getCondition() != NULL);
1145 node->getCondition()->traverse(this);
1146 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001147
1148 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001149 }
1150 else // do-while loop
1151 {
1152 ASSERT(loopType == ELoopDoWhile);
1153 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001154
zmo@google.com5601ea02011-06-10 18:23:25 +00001155 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001156
zmo@google.com5601ea02011-06-10 18:23:25 +00001157 out << "while (";
1158 ASSERT(node->getCondition() != NULL);
1159 node->getCondition()->traverse(this);
1160 out << ");\n";
1161 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001162
zmo@google.com5601ea02011-06-10 18:23:25 +00001163 decrementDepth();
1164
1165 // No need to visit children. They have been already processed in
1166 // this function.
1167 return false;
1168}
1169
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001170bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001171{
1172 switch (node->getFlowOp())
1173 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001174 case EOpKill:
1175 writeTriplet(visit, "discard", NULL, NULL);
1176 break;
1177 case EOpBreak:
1178 writeTriplet(visit, "break", NULL, NULL);
1179 break;
1180 case EOpContinue:
1181 writeTriplet(visit, "continue", NULL, NULL);
1182 break;
1183 case EOpReturn:
1184 writeTriplet(visit, "return ", NULL, NULL);
1185 break;
1186 default:
1187 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001188 }
1189
1190 return true;
1191}
1192
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001193void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001194{
zmo@google.com5601ea02011-06-10 18:23:25 +00001195 TInfoSinkBase &out = objSink();
1196 if (node != NULL)
1197 {
1198 node->traverse(this);
1199 // Single statements not part of a sequence need to be terminated
1200 // with semi-colon.
1201 if (isSingleStatement(node))
1202 out << ";\n";
1203 }
1204 else
1205 {
1206 out << "{\n}\n"; // Empty code block.
1207 }
1208}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001209
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001210TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001211{
Olli Etuahoe92507b2016-07-04 11:20:10 +03001212 if (type.getBasicType() == EbtStruct)
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001213 return hashName(TName(type.getStruct()->name()));
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001214 else
Olli Etuahoe92507b2016-07-04 11:20:10 +03001215 return type.getBuiltInTypeNameString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001216}
1217
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001218TString TOutputGLSLBase::hashName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001219{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001220 if (name.getString().empty())
1221 {
1222 ASSERT(!name.isInternal());
1223 return name.getString();
1224 }
1225 if (name.isInternal())
1226 {
1227 // TODO(oetuaho): Would be nicer to prefix non-internal names with "_" instead, like is
1228 // done in the HLSL output, but that requires fairly complex changes elsewhere in the code
1229 // as well.
1230 // We need to use a prefix that is reserved in WebGL in order to guarantee that the internal
1231 // names don't conflict with user-defined names from WebGL.
1232 return "webgl_angle_" + name.getString();
1233 }
1234 if (mHashFunction == nullptr)
1235 {
1236 return name.getString();
1237 }
1238 NameMap::const_iterator it = mNameMap.find(name.getString().c_str());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001239 if (it != mNameMap.end())
1240 return it->second.c_str();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001241 TString hashedName = TIntermTraverser::hash(name.getString(), mHashFunction);
1242 mNameMap[name.getString().c_str()] = hashedName.c_str();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001243 return hashedName;
1244}
1245
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001246TString TOutputGLSLBase::hashVariableName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001247{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001248 if (mSymbolTable.findBuiltIn(name.getString(), mShaderVersion) != NULL)
1249 return name.getString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001250 return hashName(name);
1251}
1252
Olli Etuaho59f9a642015-08-06 20:38:26 +03001253TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001254{
Olli Etuaho59f9a642015-08-06 20:38:26 +03001255 TString mangledStr = mangledName.getString();
1256 TString name = TFunction::unmangleName(mangledStr);
1257 if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001258 return translateTextureFunction(name);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001259 if (mangledName.isInternal())
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001260 {
1261 // Internal function names are outputted as-is - they may refer to functions manually added
1262 // to the output shader source that are not included in the AST at all.
Olli Etuaho59f9a642015-08-06 20:38:26 +03001263 return name;
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001264 }
Olli Etuaho59f9a642015-08-06 20:38:26 +03001265 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001266 {
1267 TName nameObj(name);
1268 return hashName(nameObj);
1269 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001270}
Jamie Madill98493dd2013-07-08 14:39:03 -04001271
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001272bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001273{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001274 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001275 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001276 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001277 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001278 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001279
1280 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001281}
1282
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001283void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001284{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001285 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001286
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001287 out << "struct " << hashName(TName(structure->name())) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001288 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001289 for (size_t i = 0; i < fields.size(); ++i)
1290 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001291 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001292 if (writeVariablePrecision(field->type()->getPrecision()))
1293 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001294 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Jamie Madill98493dd2013-07-08 14:39:03 -04001295 if (field->type()->isArray())
1296 out << arrayBrackets(*field->type());
1297 out << ";\n";
1298 }
1299 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001300}
Jamie Madill98493dd2013-07-08 14:39:03 -04001301
Geoff Langbdcc54a2015-09-02 13:09:48 -04001302void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1303{
1304 TInfoSinkBase &out = objSink();
1305
1306 out << "layout(";
1307
1308 switch (interfaceBlock->blockStorage())
1309 {
1310 case EbsUnspecified:
1311 case EbsShared:
1312 // Default block storage is shared.
1313 out << "shared";
1314 break;
1315
1316 case EbsPacked:
1317 out << "packed";
1318 break;
1319
1320 case EbsStd140:
1321 out << "std140";
1322 break;
1323
1324 default:
1325 UNREACHABLE();
1326 break;
1327 }
1328
1329 out << ", ";
1330
1331 switch (interfaceBlock->matrixPacking())
1332 {
1333 case EmpUnspecified:
1334 case EmpColumnMajor:
1335 // Default matrix packing is column major.
1336 out << "column_major";
1337 break;
1338
1339 case EmpRowMajor:
1340 out << "row_major";
1341 break;
1342
1343 default:
1344 UNREACHABLE();
1345 break;
1346 }
1347
1348 out << ") ";
1349}
1350
1351void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1352{
1353 TInfoSinkBase &out = objSink();
1354
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001355 out << hashName(TName(interfaceBlock->name())) << "{\n";
Geoff Langbdcc54a2015-09-02 13:09:48 -04001356 const TFieldList &fields = interfaceBlock->fields();
1357 for (size_t i = 0; i < fields.size(); ++i)
1358 {
1359 const TField *field = fields[i];
1360 if (writeVariablePrecision(field->type()->getPrecision()))
1361 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001362 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Geoff Langbdcc54a2015-09-02 13:09:48 -04001363 if (field->type()->isArray())
1364 out << arrayBrackets(*field->type());
1365 out << ";\n";
1366 }
1367 out << "}";
1368}
Jamie Madill45bcc782016-11-07 13:58:48 -05001369
1370} // namespace sh