blob: 47c75fd988b5faf1f9222d5b0fcb0008e29dfda9 [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"
Olli Etuaho56a2f952016-12-08 12:16:27 +000010#include "common/mathutil.h"
zmo@google.com5601ea02011-06-10 18:23:25 +000011
daniel@transgaming.com773ff742013-01-11 04:12:51 +000012#include <cfloat>
daniel@transgaming.com6c1203f2013-01-11 04:12:43 +000013
Jamie Madill45bcc782016-11-07 13:58:48 -050014namespace sh
15{
16
zmo@google.com5601ea02011-06-10 18:23:25 +000017namespace
18{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070019TString arrayBrackets(const TType &type)
zmo@google.com5601ea02011-06-10 18:23:25 +000020{
21 ASSERT(type.isArray());
22 TInfoSinkBase out;
23 out << "[" << type.getArraySize() << "]";
24 return TString(out.c_str());
25}
26
Zhenyao Mo9eedea02014-05-12 16:02:35 -070027bool isSingleStatement(TIntermNode *node)
28{
Olli Etuaho336b1472016-10-05 16:37:55 +010029 if (node->getAsFunctionDefinition())
zmo@google.com5601ea02011-06-10 18:23:25 +000030 {
Olli Etuaho336b1472016-10-05 16:37:55 +010031 return false;
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010032 }
33 else if (node->getAsBlock())
34 {
35 return false;
zmo@google.com5601ea02011-06-10 18:23:25 +000036 }
Olli Etuaho57961272016-09-14 13:57:46 +030037 else if (node->getAsIfElseNode())
zmo@google.com5601ea02011-06-10 18:23:25 +000038 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +030039 return false;
zmo@google.com5601ea02011-06-10 18:23:25 +000040 }
41 else if (node->getAsLoopNode())
42 {
43 return false;
44 }
Olli Etuaho01cd8af2015-02-20 10:39:20 +020045 else if (node->getAsSwitchNode())
46 {
47 return false;
48 }
49 else if (node->getAsCaseNode())
50 {
51 return false;
52 }
zmo@google.com5601ea02011-06-10 18:23:25 +000053 return true;
54}
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080055
Martin Radev2cc85b32016-08-05 16:22:53 +030056// If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
57// variables with specified layout qualifiers are copied. Additional checks are needed against the
58// type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
59// TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
60// NeedsToWriteLayoutQualifier.
61bool NeedsToWriteLayoutQualifier(const TType &type)
62{
63 if (type.getBasicType() == EbtInterfaceBlock)
64 {
65 return false;
66 }
67
68 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
69
70 if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn) &&
71 layoutQualifier.location >= 0)
72 {
73 return true;
74 }
75 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
76 {
77 return true;
78 }
79 return false;
80}
81
zmo@google.com5601ea02011-06-10 18:23:25 +000082} // namespace
83
Zhenyao Mo9eedea02014-05-12 16:02:35 -070084TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000085 ShArrayIndexClampingStrategy clampingStrategy,
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000086 ShHashFunction64 hashFunction,
Zhenyao Mo9eedea02014-05-12 16:02:35 -070087 NameMap &nameMap,
88 TSymbolTable &symbolTable,
Qiankun Miao89dd8f32016-11-09 12:59:30 +000089 sh::GLenum shaderType,
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080090 int shaderVersion,
Qiankun Miao705a9192016-08-29 10:05:27 +080091 ShShaderOutput output,
92 ShCompileOptions compileOptions)
zmo@google.com5601ea02011-06-10 18:23:25 +000093 : TIntermTraverser(true, true, true),
94 mObjSink(objSink),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000095 mDeclaringVariables(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000096 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000097 mHashFunction(hashFunction),
98 mNameMap(nameMap),
Jamie Madill02f20dd2013-09-12 12:07:42 -040099 mSymbolTable(symbolTable),
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000100 mShaderType(shaderType),
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800101 mShaderVersion(shaderVersion),
Qiankun Miao705a9192016-08-29 10:05:27 +0800102 mOutput(output),
103 mCompileOptions(compileOptions)
zmo@google.com5601ea02011-06-10 18:23:25 +0000104{
105}
106
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800107void TOutputGLSLBase::writeInvariantQualifier(const TType &type)
108{
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000109 if (!sh::RemoveInvariant(mShaderType, mShaderVersion, mOutput, mCompileOptions))
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800110 {
111 TInfoSinkBase &out = objSink();
112 out << "invariant ";
113 }
114}
115
Olli Etuaho56a2f952016-12-08 12:16:27 +0000116void TOutputGLSLBase::writeFloat(TInfoSinkBase &out, float f)
117{
118 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300)
119 {
120 out << "uintBitsToFloat(" << gl::bitCast<uint32_t>(f) << "u)";
121 }
122 else
123 {
124 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
125 }
126}
127
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700128void TOutputGLSLBase::writeTriplet(
129 Visit visit, const char *preStr, const char *inStr, const char *postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000130{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700131 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000132 if (visit == PreVisit && preStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000133 out << preStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000134 else if (visit == InVisit && inStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000135 out << inStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000136 else if (visit == PostVisit && postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000137 out << postStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000138}
139
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700140void TOutputGLSLBase::writeBuiltInFunctionTriplet(
141 Visit visit, const char *preStr, bool useEmulatedFunction)
zmo@google.com5601ea02011-06-10 18:23:25 +0000142{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700143 TString preString = useEmulatedFunction ?
144 BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
145 writeTriplet(visit, preString.c_str(), ", ", ")");
146}
147
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300148void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
149{
Martin Radev2cc85b32016-08-05 16:22:53 +0300150 if (!NeedsToWriteLayoutQualifier(type))
151 {
152 return;
153 }
154
155 TInfoSinkBase &out = objSink();
156 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
157 out << "layout(";
158
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300159 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
160 {
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300161 if (layoutQualifier.location >= 0)
162 {
Martin Radev2cc85b32016-08-05 16:22:53 +0300163 out << "location = " << layoutQualifier.location;
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300164 }
165 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300166
167 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
168 {
169 ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
170 out << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
171 }
172
173 out << ") ";
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300174}
175
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800176const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier)
177{
178 if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 &&
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000179 (mCompileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0)
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800180 {
181 switch (qualifier)
182 {
183 // The return string is consistent with sh::getQualifierString() from
184 // BaseTypes.h minus the "centroid" keyword.
185 case EvqCentroid:
186 return "";
187 case EvqCentroidIn:
188 return "smooth in";
189 case EvqCentroidOut:
190 return "smooth out";
191 default:
192 break;
193 }
194 }
195 if (sh::IsGLSL130OrNewer(mOutput))
196 {
197 switch (qualifier)
198 {
199 case EvqAttribute:
200 return "in";
201 case EvqVaryingIn:
202 return "in";
203 case EvqVaryingOut:
204 return "out";
205 default:
206 break;
207 }
208 }
209 return sh::getQualifierString(qualifier);
210}
211
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700212void TOutputGLSLBase::writeVariableType(const TType &type)
213{
Qiankun Miao705a9192016-08-29 10:05:27 +0800214 TQualifier qualifier = type.getQualifier();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700215 TInfoSinkBase &out = objSink();
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800216 if (type.isInvariant())
Olli Etuaho214c2d82015-04-27 14:49:13 +0300217 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800218 writeInvariantQualifier(type);
Olli Etuaho214c2d82015-04-27 14:49:13 +0300219 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400220 if (type.getBasicType() == EbtInterfaceBlock)
221 {
222 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
223 declareInterfaceBlockLayout(interfaceBlock);
224 }
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400225 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400226 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800227 const char *qualifierString = mapQualifierToString(qualifier);
228 if (qualifierString && qualifierString[0] != '\0')
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800229 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800230 out << qualifierString << " ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800231 }
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400232 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300233
234 const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
235 if (memoryQualifier.readonly)
236 {
237 ASSERT(IsImage(type.getBasicType()));
238 out << "readonly ";
239 }
240
241 if (memoryQualifier.writeonly)
242 {
243 ASSERT(IsImage(type.getBasicType()));
244 out << "writeonly ";
245 }
246
Martin Radev049edfa2016-11-11 14:35:37 +0200247 if (memoryQualifier.coherent)
248 {
249 ASSERT(IsImage(type.getBasicType()));
250 out << "coherent ";
251 }
252
253 if (memoryQualifier.restrictQualifier)
254 {
255 ASSERT(IsImage(type.getBasicType()));
256 out << "restrict ";
257 }
258
259 if (memoryQualifier.volatileQualifier)
260 {
261 ASSERT(IsImage(type.getBasicType()));
262 out << "volatile ";
263 }
264
zmo@google.com5601ea02011-06-10 18:23:25 +0000265 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700266 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000267 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400268 TStructure *structure = type.getStruct();
269
270 declareStruct(structure);
271
272 if (!structure->name().empty())
273 {
274 mDeclaredStructs.insert(structure->uniqueId());
275 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000276 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400277 else if (type.getBasicType() == EbtInterfaceBlock)
278 {
279 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
280 declareInterfaceBlock(interfaceBlock);
281 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000282 else
283 {
284 if (writeVariablePrecision(type.getPrecision()))
285 out << " ";
286 out << getTypeName(type);
287 }
288}
289
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700290void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000291{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700292 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000293 for (TIntermSequence::const_iterator iter = args.begin();
294 iter != args.end(); ++iter)
295 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700296 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000297 ASSERT(arg != NULL);
298
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700299 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000300 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000301
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000302 if (!arg->getName().getString().empty())
303 out << " " << hashName(arg->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000304 if (type.isArray())
305 out << arrayBrackets(type);
306
307 // Put a comma if this is not the last argument.
308 if (iter != args.end() - 1)
309 out << ", ";
310 }
311}
312
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400313const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
314 const TType &type, const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000315{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700316 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000317
318 if (type.getBasicType() == EbtStruct)
319 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700320 const TStructure *structure = type.getStruct();
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000321 out << hashName(TName(structure->name())) << "(";
Jamie Madill98493dd2013-07-08 14:39:03 -0400322
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700323 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400324 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000325 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700326 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000327 ASSERT(fieldType != NULL);
328 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700329 if (i != fields.size() - 1)
330 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000331 }
332 out << ")";
333 }
334 else
335 {
Jamie Madill94bf7f22013-07-08 13:31:15 -0400336 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000337 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700338 if (writeType)
339 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400340 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000341 {
342 switch (pConstUnion->getType())
343 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700344 case EbtFloat:
Olli Etuaho56a2f952016-12-08 12:16:27 +0000345 writeFloat(out, pConstUnion->getFConst());
346 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700347 case EbtInt:
348 out << pConstUnion->getIConst();
349 break;
Olli Etuaho5321c802015-04-02 17:08:16 +0300350 case EbtUInt:
351 out << pConstUnion->getUConst() << "u";
352 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700353 case EbtBool:
354 out << pConstUnion->getBConst();
355 break;
356 default: UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000357 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700358 if (i != size - 1)
359 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000360 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700361 if (writeType)
362 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000363 }
364 return pConstUnion;
365}
366
Olli Etuahoe92507b2016-07-04 11:20:10 +0300367void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
Olli Etuahof40319e2015-03-10 14:33:00 +0200368{
369 TInfoSinkBase &out = objSink();
370 if (visit == PreVisit)
371 {
372 if (type.isArray())
373 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300374 out << getTypeName(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200375 out << arrayBrackets(type);
376 out << "(";
377 }
378 else
379 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300380 out << getTypeName(type) << "(";
Olli Etuahof40319e2015-03-10 14:33:00 +0200381 }
382 }
383 else
384 {
385 writeTriplet(visit, nullptr, ", ", ")");
386 }
387}
388
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700389void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000390{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700391 TInfoSinkBase &out = objSink();
Corentin Wallez1b896c62016-11-16 13:10:44 -0500392 out << hashVariableName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000393
394 if (mDeclaringVariables && node->getType().isArray())
395 out << arrayBrackets(node->getType());
396}
397
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700398void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000399{
400 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
401}
402
Olli Etuahob6fa0432016-09-28 16:28:05 +0100403bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
404{
405 TInfoSinkBase &out = objSink();
406 if (visit == PostVisit)
407 {
408 out << ".";
409 node->writeOffsetsAsXYZW(&out);
410 }
411 return true;
412}
413
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700414bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000415{
416 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700417 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000418 switch (node->getOp())
419 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100420 case EOpComma:
421 writeTriplet(visit, "(", ", ", ")");
422 break;
423 case EOpInitialize:
zmo@google.com5601ea02011-06-10 18:23:25 +0000424 if (visit == InVisit)
425 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100426 out << " = ";
427 // RHS of initialize is not being declared.
428 mDeclaringVariables = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000429 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100430 break;
431 case EOpAssign:
432 writeTriplet(visit, "(", " = ", ")");
433 break;
434 case EOpAddAssign:
435 writeTriplet(visit, "(", " += ", ")");
436 break;
437 case EOpSubAssign:
438 writeTriplet(visit, "(", " -= ", ")");
439 break;
440 case EOpDivAssign:
441 writeTriplet(visit, "(", " /= ", ")");
442 break;
443 case EOpIModAssign:
444 writeTriplet(visit, "(", " %= ", ")");
445 break;
446 // Notice the fall-through.
447 case EOpMulAssign:
448 case EOpVectorTimesMatrixAssign:
449 case EOpVectorTimesScalarAssign:
450 case EOpMatrixTimesScalarAssign:
451 case EOpMatrixTimesMatrixAssign:
452 writeTriplet(visit, "(", " *= ", ")");
453 break;
454 case EOpBitShiftLeftAssign:
455 writeTriplet(visit, "(", " <<= ", ")");
456 break;
457 case EOpBitShiftRightAssign:
458 writeTriplet(visit, "(", " >>= ", ")");
459 break;
460 case EOpBitwiseAndAssign:
461 writeTriplet(visit, "(", " &= ", ")");
462 break;
463 case EOpBitwiseXorAssign:
464 writeTriplet(visit, "(", " ^= ", ")");
465 break;
466 case EOpBitwiseOrAssign:
467 writeTriplet(visit, "(", " |= ", ")");
468 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000469
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100470 case EOpIndexDirect:
zmo@google.com5601ea02011-06-10 18:23:25 +0000471 writeTriplet(visit, NULL, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100472 break;
473 case EOpIndexIndirect:
474 if (node->getAddIndexClamp())
475 {
476 if (visit == InVisit)
477 {
478 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
479 out << "[int(clamp(float(";
480 else
481 out << "[webgl_int_clamp(";
482 }
483 else if (visit == PostVisit)
484 {
485 int maxSize;
486 TIntermTyped *left = node->getLeft();
487 TType leftType = left->getType();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700488
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100489 if (left->isArray())
490 {
491 // The shader will fail validation if the array length is not > 0.
492 maxSize = static_cast<int>(leftType.getArraySize()) - 1;
493 }
494 else
495 {
496 maxSize = leftType.getNominalSize() - 1;
497 }
498
499 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
500 out << "), 0.0, float(" << maxSize << ")))]";
501 else
502 out << ", 0, " << maxSize << ")]";
503 }
504 }
505 else
506 {
507 writeTriplet(visit, NULL, "[", "]");
508 }
509 break;
510 case EOpIndexDirectStruct:
511 if (visit == InVisit)
512 {
513 // Here we are writing out "foo.bar", where "foo" is struct
514 // and "bar" is field. In AST, it is represented as a binary
515 // node, where left child represents "foo" and right child "bar".
516 // The node itself represents ".". The struct field "bar" is
517 // actually stored as an index into TStructure::fields.
518 out << ".";
519 const TStructure *structure = node->getLeft()->getType().getStruct();
520 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
521 const TField *field = structure->fields()[index->getIConst(0)];
522
523 TString fieldName = field->name();
524 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000525 fieldName = hashName(TName(fieldName));
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100526
527 out << fieldName;
528 visitChildren = false;
529 }
530 break;
531 case EOpIndexDirectInterfaceBlock:
532 if (visit == InVisit)
533 {
534 out << ".";
535 const TInterfaceBlock *interfaceBlock =
536 node->getLeft()->getType().getInterfaceBlock();
537 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
538 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
539
540 TString fieldName = field->name();
541 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000542 fieldName = hashName(TName(fieldName));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700543
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100544 out << fieldName;
545 visitChildren = false;
546 }
547 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400548
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100549 case EOpAdd:
550 writeTriplet(visit, "(", " + ", ")");
551 break;
552 case EOpSub:
553 writeTriplet(visit, "(", " - ", ")");
554 break;
555 case EOpMul:
556 writeTriplet(visit, "(", " * ", ")");
557 break;
558 case EOpDiv:
559 writeTriplet(visit, "(", " / ", ")");
560 break;
561 case EOpIMod:
562 writeTriplet(visit, "(", " % ", ")");
563 break;
564 case EOpBitShiftLeft:
565 writeTriplet(visit, "(", " << ", ")");
566 break;
567 case EOpBitShiftRight:
568 writeTriplet(visit, "(", " >> ", ")");
569 break;
570 case EOpBitwiseAnd:
571 writeTriplet(visit, "(", " & ", ")");
572 break;
573 case EOpBitwiseXor:
574 writeTriplet(visit, "(", " ^ ", ")");
575 break;
576 case EOpBitwiseOr:
577 writeTriplet(visit, "(", " | ", ")");
578 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400579
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100580 case EOpEqual:
581 writeTriplet(visit, "(", " == ", ")");
582 break;
583 case EOpNotEqual:
584 writeTriplet(visit, "(", " != ", ")");
585 break;
586 case EOpLessThan:
587 writeTriplet(visit, "(", " < ", ")");
588 break;
589 case EOpGreaterThan:
590 writeTriplet(visit, "(", " > ", ")");
591 break;
592 case EOpLessThanEqual:
593 writeTriplet(visit, "(", " <= ", ")");
594 break;
595 case EOpGreaterThanEqual:
596 writeTriplet(visit, "(", " >= ", ")");
597 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000598
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100599 // Notice the fall-through.
600 case EOpVectorTimesScalar:
601 case EOpVectorTimesMatrix:
602 case EOpMatrixTimesVector:
603 case EOpMatrixTimesScalar:
604 case EOpMatrixTimesMatrix:
605 writeTriplet(visit, "(", " * ", ")");
606 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200607
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100608 case EOpLogicalOr:
609 writeTriplet(visit, "(", " || ", ")");
610 break;
611 case EOpLogicalXor:
612 writeTriplet(visit, "(", " ^^ ", ")");
613 break;
614 case EOpLogicalAnd:
615 writeTriplet(visit, "(", " && ", ")");
616 break;
617 default:
618 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000619 }
620
621 return visitChildren;
622}
623
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700624bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000625{
zmo@google.com32e97312011-08-24 01:03:11 +0000626 TString preString;
627 TString postString = ")";
628
zmo@google.com5601ea02011-06-10 18:23:25 +0000629 switch (node->getOp())
630 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700631 case EOpNegative: preString = "(-"; break;
Zhenyao Mode1e00e2014-10-09 16:55:32 -0700632 case EOpPositive: preString = "(+"; break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700633 case EOpVectorLogicalNot: preString = "not("; break;
634 case EOpLogicalNot: preString = "(!"; break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200635 case EOpBitwiseNot: preString = "(~"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000636
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700637 case EOpPostIncrement: preString = "("; postString = "++)"; break;
638 case EOpPostDecrement: preString = "("; postString = "--)"; break;
639 case EOpPreIncrement: preString = "(++"; break;
640 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000641
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700642 case EOpRadians:
643 preString = "radians(";
644 break;
645 case EOpDegrees:
646 preString = "degrees(";
647 break;
648 case EOpSin:
649 preString = "sin(";
650 break;
651 case EOpCos:
652 preString = "cos(";
653 break;
654 case EOpTan:
655 preString = "tan(";
656 break;
657 case EOpAsin:
658 preString = "asin(";
659 break;
660 case EOpAcos:
661 preString = "acos(";
662 break;
663 case EOpAtan:
664 preString = "atan(";
665 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000666
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200667 case EOpSinh:
668 preString = "sinh(";
669 break;
670 case EOpCosh:
671 preString = "cosh(";
672 break;
673 case EOpTanh:
674 preString = "tanh(";
675 break;
676 case EOpAsinh:
677 preString = "asinh(";
678 break;
679 case EOpAcosh:
680 preString = "acosh(";
681 break;
682 case EOpAtanh:
683 preString = "atanh(";
684 break;
685
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700686 case EOpExp:
687 preString = "exp(";
688 break;
689 case EOpLog:
690 preString = "log(";
691 break;
692 case EOpExp2:
693 preString = "exp2(";
694 break;
695 case EOpLog2:
696 preString = "log2(";
697 break;
698 case EOpSqrt:
699 preString = "sqrt(";
700 break;
701 case EOpInverseSqrt:
702 preString = "inversesqrt(";
703 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000704
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700705 case EOpAbs:
706 preString = "abs(";
707 break;
708 case EOpSign:
709 preString = "sign(";
710 break;
711 case EOpFloor:
712 preString = "floor(";
713 break;
Qingqing Deng5dbece52015-02-27 20:35:38 -0800714 case EOpTrunc:
715 preString = "trunc(";
716 break;
717 case EOpRound:
718 preString = "round(";
719 break;
720 case EOpRoundEven:
721 preString = "roundEven(";
722 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700723 case EOpCeil:
724 preString = "ceil(";
725 break;
726 case EOpFract:
727 preString = "fract(";
728 break;
Arun Patole0c1726e2015-02-18 14:35:02 +0530729 case EOpIsNan:
730 preString = "isnan(";
731 break;
732 case EOpIsInf:
733 preString = "isinf(";
734 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000735
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200736 case EOpFloatBitsToInt:
737 preString = "floatBitsToInt(";
738 break;
739 case EOpFloatBitsToUint:
740 preString = "floatBitsToUint(";
741 break;
742 case EOpIntBitsToFloat:
743 preString = "intBitsToFloat(";
744 break;
745 case EOpUintBitsToFloat:
746 preString = "uintBitsToFloat(";
747 break;
748
Olli Etuaho7700ff62015-01-15 12:16:29 +0200749 case EOpPackSnorm2x16:
750 preString = "packSnorm2x16(";
751 break;
752 case EOpPackUnorm2x16:
753 preString = "packUnorm2x16(";
754 break;
755 case EOpPackHalf2x16:
756 preString = "packHalf2x16(";
757 break;
758 case EOpUnpackSnorm2x16:
759 preString = "unpackSnorm2x16(";
760 break;
761 case EOpUnpackUnorm2x16:
762 preString = "unpackUnorm2x16(";
763 break;
764 case EOpUnpackHalf2x16:
765 preString = "unpackHalf2x16(";
766 break;
767
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700768 case EOpLength:
769 preString = "length(";
770 break;
771 case EOpNormalize:
772 preString = "normalize(";
773 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000774
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700775 case EOpDFdx:
776 preString = "dFdx(";
777 break;
778 case EOpDFdy:
779 preString = "dFdy(";
780 break;
781 case EOpFwidth:
782 preString = "fwidth(";
783 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000784
Olli Etuahoe39706d2014-12-30 16:40:36 +0200785 case EOpTranspose:
786 preString = "transpose(";
787 break;
788 case EOpDeterminant:
789 preString = "determinant(";
790 break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +0200791 case EOpInverse:
792 preString = "inverse(";
793 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200794
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700795 case EOpAny:
796 preString = "any(";
797 break;
798 case EOpAll:
799 preString = "all(";
800 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000801
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700802 default:
803 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000804 }
805
zmo@google.com32e97312011-08-24 01:03:11 +0000806 if (visit == PreVisit && node->getUseEmulatedFunction())
807 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
808 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
809
zmo@google.com5601ea02011-06-10 18:23:25 +0000810 return true;
811}
812
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300813bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
814{
815 TInfoSinkBase &out = objSink();
816 // Notice two brackets at the beginning and end. The outer ones
817 // encapsulate the whole ternary expression. This preserves the
818 // order of precedence when ternary expressions are used in a
819 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
820 out << "((";
821 node->getCondition()->traverse(this);
822 out << ") ? (";
823 node->getTrueExpression()->traverse(this);
824 out << ") : (";
825 node->getFalseExpression()->traverse(this);
826 out << "))";
827 return false;
828}
829
Olli Etuaho57961272016-09-14 13:57:46 +0300830bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000831{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700832 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000833
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300834 out << "if (";
835 node->getCondition()->traverse(this);
836 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000837
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300838 incrementDepth(node);
839 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000840
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300841 if (node->getFalseBlock())
842 {
843 out << "else\n";
844 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000845 }
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300846 decrementDepth();
zmo@google.com5601ea02011-06-10 18:23:25 +0000847 return false;
848}
849
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200850bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200851{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200852 if (node->getStatementList())
853 {
854 writeTriplet(visit, "switch (", ") ", nullptr);
855 // The curly braces get written when visiting the statementList aggregate
856 }
857 else
858 {
859 // No statementList, so it won't output curly braces
860 writeTriplet(visit, "switch (", ") {", "}\n");
861 }
862 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200863}
864
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200865bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200866{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200867 if (node->hasCondition())
868 {
869 writeTriplet(visit, "case (", nullptr, "):\n");
870 return true;
871 }
872 else
873 {
874 TInfoSinkBase &out = objSink();
875 out << "default:\n";
876 return false;
877 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200878}
879
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100880bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
881{
882 TInfoSinkBase &out = objSink();
883 // Scope the blocks except when at the global scope.
884 if (mDepth > 0)
885 {
886 out << "{\n";
887 }
888
889 incrementDepth(node);
890 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
891 iter != node->getSequence()->end(); ++iter)
892 {
893 TIntermNode *curNode = *iter;
894 ASSERT(curNode != nullptr);
895 curNode->traverse(this);
896
897 if (isSingleStatement(curNode))
898 out << ";\n";
899 }
900 decrementDepth();
901
902 // Scope the blocks except when at the global scope.
903 if (mDepth > 0)
904 {
905 out << "}\n";
906 }
907 return false;
908}
909
Olli Etuaho336b1472016-10-05 16:37:55 +0100910bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
911{
912 TInfoSinkBase &out = objSink();
913
914 ASSERT(visit == PreVisit);
915 {
916 const TType &type = node->getType();
917 writeVariableType(type);
918 if (type.isArray())
919 out << arrayBrackets(type);
920 }
921
922 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
923
924 incrementDepth(node);
925
926 // Traverse function parameters.
927 TIntermAggregate *params = node->getFunctionParameters()->getAsAggregate();
928 ASSERT(params->getOp() == EOpParameters);
929 params->traverse(this);
930
931 // Traverse function body.
932 visitCodeBlock(node->getBody());
933 decrementDepth();
934
935 // Fully processed; no need to visit children.
936 return false;
937}
938
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700939bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000940{
941 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700942 TInfoSinkBase &out = objSink();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700943 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000944 switch (node->getOp())
945 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700946 case EOpPrototype:
947 // Function declaration.
948 ASSERT(visit == PreVisit);
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300949 {
950 const TType &type = node->getType();
951 writeVariableType(type);
952 if (type.isArray())
953 out << arrayBrackets(type);
954 }
955
Olli Etuahobd674552016-10-06 13:28:42 +0100956 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700957
958 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700959 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700960 out << ")";
961
962 visitChildren = false;
963 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700964 case EOpFunctionCall:
965 // Function call.
966 if (visit == PreVisit)
Olli Etuahobd674552016-10-06 13:28:42 +0100967 out << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200968 else if (visit == InVisit)
969 out << ", ";
970 else
971 out << ")";
972 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700973 case EOpParameters:
974 // Function parameters.
975 ASSERT(visit == PreVisit);
976 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700977 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700978 out << ")";
979 visitChildren = false;
980 break;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700981 case EOpInvariantDeclaration:
982 // Invariant declaration.
983 ASSERT(visit == PreVisit);
984 {
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400985 const TIntermSequence *sequence = node->getSequence();
986 ASSERT(sequence && sequence->size() == 1);
987 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
988 ASSERT(symbol);
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000989 out << "invariant " << hashVariableName(symbol->getName());
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400990 }
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700991 visitChildren = false;
992 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700993 case EOpConstructFloat:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700994 case EOpConstructVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700995 case EOpConstructVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700996 case EOpConstructVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700997 case EOpConstructBool:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700998 case EOpConstructBVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700999 case EOpConstructBVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001000 case EOpConstructBVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001001 case EOpConstructInt:
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001002 case EOpConstructIVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001003 case EOpConstructIVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001004 case EOpConstructIVec4:
Geoff Langc4c7442d2015-07-20 13:09:26 -04001005 case EOpConstructUInt:
Geoff Langc4c7442d2015-07-20 13:09:26 -04001006 case EOpConstructUVec2:
Geoff Langc4c7442d2015-07-20 13:09:26 -04001007 case EOpConstructUVec3:
Geoff Langc4c7442d2015-07-20 13:09:26 -04001008 case EOpConstructUVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001009 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -04001010 case EOpConstructMat2x3:
Alexis Hetu07e57df2015-06-16 16:55:52 -04001011 case EOpConstructMat2x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -04001012 case EOpConstructMat3x2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001013 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -04001014 case EOpConstructMat3x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -04001015 case EOpConstructMat4x2:
Alexis Hetu07e57df2015-06-16 16:55:52 -04001016 case EOpConstructMat4x3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001017 case EOpConstructMat4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001018 case EOpConstructStruct:
Olli Etuahoe92507b2016-07-04 11:20:10 +03001019 writeConstructorTriplet(visit, node->getType());
1020 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001021
Olli Etuahoe39706d2014-12-30 16:40:36 +02001022 case EOpOuterProduct:
1023 writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
1024 break;
1025
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001026 case EOpLessThan:
1027 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
1028 break;
1029 case EOpGreaterThan:
1030 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
1031 break;
1032 case EOpLessThanEqual:
1033 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
1034 break;
1035 case EOpGreaterThanEqual:
1036 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
1037 break;
1038 case EOpVectorEqual:
1039 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
1040 break;
1041 case EOpVectorNotEqual:
1042 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
1043 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001044
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001045 case EOpMod:
1046 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
1047 break;
Olli Etuahob6e07a62015-02-16 12:22:10 +02001048 case EOpModf:
1049 writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
1050 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001051 case EOpPow:
1052 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
1053 break;
1054 case EOpAtan:
1055 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
1056 break;
1057 case EOpMin:
1058 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
1059 break;
1060 case EOpMax:
1061 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
1062 break;
1063 case EOpClamp:
1064 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
1065 break;
1066 case EOpMix:
1067 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
1068 break;
1069 case EOpStep:
1070 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
1071 break;
1072 case EOpSmoothStep:
1073 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
1074 break;
1075 case EOpDistance:
1076 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
1077 break;
1078 case EOpDot:
1079 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
1080 break;
1081 case EOpCross:
1082 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
1083 break;
1084 case EOpFaceForward:
1085 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
1086 break;
1087 case EOpReflect:
1088 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
1089 break;
1090 case EOpRefract:
1091 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
1092 break;
1093 case EOpMul:
1094 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
1095 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001096
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001097 default:
1098 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001099 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001100 return visitChildren;
1101}
1102
Olli Etuaho13389b62016-10-16 11:48:18 +01001103bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
1104{
1105 TInfoSinkBase &out = objSink();
1106
1107 // Variable declaration.
1108 if (visit == PreVisit)
1109 {
1110 const TIntermSequence &sequence = *(node->getSequence());
1111 const TIntermTyped *variable = sequence.front()->getAsTyped();
1112 writeLayoutQualifier(variable->getType());
1113 writeVariableType(variable->getType());
1114 out << " ";
1115 mDeclaringVariables = true;
1116 }
1117 else if (visit == InVisit)
1118 {
1119 out << ", ";
1120 mDeclaringVariables = true;
1121 }
1122 else
1123 {
1124 mDeclaringVariables = false;
1125 }
1126 return true;
1127}
1128
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001129bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001130{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001131 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001132
Zhenyao Mo7cab38b2013-10-15 12:59:30 -07001133 incrementDepth(node);
Corentin Wallez7258e302015-09-22 10:40:24 -07001134
zmo@google.com5601ea02011-06-10 18:23:25 +00001135 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001136
zmo@google.com5601ea02011-06-10 18:23:25 +00001137 if (loopType == ELoopFor) // for loop
1138 {
Corentin Wallez1b896c62016-11-16 13:10:44 -05001139 out << "for (";
1140 if (node->getInit())
1141 node->getInit()->traverse(this);
1142 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001143
Corentin Wallez1b896c62016-11-16 13:10:44 -05001144 if (node->getCondition())
1145 node->getCondition()->traverse(this);
1146 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001147
Corentin Wallez1b896c62016-11-16 13:10:44 -05001148 if (node->getExpression())
1149 node->getExpression()->traverse(this);
1150 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001151
Corentin Wallez1b896c62016-11-16 13:10:44 -05001152 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001153 }
1154 else if (loopType == ELoopWhile) // while loop
1155 {
1156 out << "while (";
1157 ASSERT(node->getCondition() != NULL);
1158 node->getCondition()->traverse(this);
1159 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001160
1161 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001162 }
1163 else // do-while loop
1164 {
1165 ASSERT(loopType == ELoopDoWhile);
1166 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001167
zmo@google.com5601ea02011-06-10 18:23:25 +00001168 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001169
zmo@google.com5601ea02011-06-10 18:23:25 +00001170 out << "while (";
1171 ASSERT(node->getCondition() != NULL);
1172 node->getCondition()->traverse(this);
1173 out << ");\n";
1174 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001175
zmo@google.com5601ea02011-06-10 18:23:25 +00001176 decrementDepth();
1177
1178 // No need to visit children. They have been already processed in
1179 // this function.
1180 return false;
1181}
1182
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001183bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001184{
1185 switch (node->getFlowOp())
1186 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001187 case EOpKill:
1188 writeTriplet(visit, "discard", NULL, NULL);
1189 break;
1190 case EOpBreak:
1191 writeTriplet(visit, "break", NULL, NULL);
1192 break;
1193 case EOpContinue:
1194 writeTriplet(visit, "continue", NULL, NULL);
1195 break;
1196 case EOpReturn:
1197 writeTriplet(visit, "return ", NULL, NULL);
1198 break;
1199 default:
1200 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001201 }
1202
1203 return true;
1204}
1205
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001206void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001207{
zmo@google.com5601ea02011-06-10 18:23:25 +00001208 TInfoSinkBase &out = objSink();
1209 if (node != NULL)
1210 {
1211 node->traverse(this);
1212 // Single statements not part of a sequence need to be terminated
1213 // with semi-colon.
1214 if (isSingleStatement(node))
1215 out << ";\n";
1216 }
1217 else
1218 {
1219 out << "{\n}\n"; // Empty code block.
1220 }
1221}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001222
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001223TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001224{
Olli Etuahoe92507b2016-07-04 11:20:10 +03001225 if (type.getBasicType() == EbtStruct)
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001226 return hashName(TName(type.getStruct()->name()));
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001227 else
Olli Etuahoe92507b2016-07-04 11:20:10 +03001228 return type.getBuiltInTypeNameString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001229}
1230
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001231TString TOutputGLSLBase::hashName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001232{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001233 if (name.getString().empty())
1234 {
1235 ASSERT(!name.isInternal());
1236 return name.getString();
1237 }
1238 if (name.isInternal())
1239 {
1240 // TODO(oetuaho): Would be nicer to prefix non-internal names with "_" instead, like is
1241 // done in the HLSL output, but that requires fairly complex changes elsewhere in the code
1242 // as well.
1243 // We need to use a prefix that is reserved in WebGL in order to guarantee that the internal
1244 // names don't conflict with user-defined names from WebGL.
1245 return "webgl_angle_" + name.getString();
1246 }
1247 if (mHashFunction == nullptr)
1248 {
1249 return name.getString();
1250 }
1251 NameMap::const_iterator it = mNameMap.find(name.getString().c_str());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001252 if (it != mNameMap.end())
1253 return it->second.c_str();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001254 TString hashedName = TIntermTraverser::hash(name.getString(), mHashFunction);
1255 mNameMap[name.getString().c_str()] = hashedName.c_str();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001256 return hashedName;
1257}
1258
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001259TString TOutputGLSLBase::hashVariableName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001260{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001261 if (mSymbolTable.findBuiltIn(name.getString(), mShaderVersion) != NULL)
1262 return name.getString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001263 return hashName(name);
1264}
1265
Olli Etuaho59f9a642015-08-06 20:38:26 +03001266TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001267{
Olli Etuaho59f9a642015-08-06 20:38:26 +03001268 TString mangledStr = mangledName.getString();
1269 TString name = TFunction::unmangleName(mangledStr);
1270 if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001271 return translateTextureFunction(name);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001272 if (mangledName.isInternal())
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001273 {
1274 // Internal function names are outputted as-is - they may refer to functions manually added
1275 // to the output shader source that are not included in the AST at all.
Olli Etuaho59f9a642015-08-06 20:38:26 +03001276 return name;
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001277 }
Olli Etuaho59f9a642015-08-06 20:38:26 +03001278 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001279 {
1280 TName nameObj(name);
1281 return hashName(nameObj);
1282 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001283}
Jamie Madill98493dd2013-07-08 14:39:03 -04001284
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001285bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001286{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001287 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001288 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001289 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001290 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001291 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001292
1293 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001294}
1295
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001296void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001297{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001298 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001299
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001300 out << "struct " << hashName(TName(structure->name())) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001301 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001302 for (size_t i = 0; i < fields.size(); ++i)
1303 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001304 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001305 if (writeVariablePrecision(field->type()->getPrecision()))
1306 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001307 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Jamie Madill98493dd2013-07-08 14:39:03 -04001308 if (field->type()->isArray())
1309 out << arrayBrackets(*field->type());
1310 out << ";\n";
1311 }
1312 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001313}
Jamie Madill98493dd2013-07-08 14:39:03 -04001314
Geoff Langbdcc54a2015-09-02 13:09:48 -04001315void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1316{
1317 TInfoSinkBase &out = objSink();
1318
1319 out << "layout(";
1320
1321 switch (interfaceBlock->blockStorage())
1322 {
1323 case EbsUnspecified:
1324 case EbsShared:
1325 // Default block storage is shared.
1326 out << "shared";
1327 break;
1328
1329 case EbsPacked:
1330 out << "packed";
1331 break;
1332
1333 case EbsStd140:
1334 out << "std140";
1335 break;
1336
1337 default:
1338 UNREACHABLE();
1339 break;
1340 }
1341
1342 out << ", ";
1343
1344 switch (interfaceBlock->matrixPacking())
1345 {
1346 case EmpUnspecified:
1347 case EmpColumnMajor:
1348 // Default matrix packing is column major.
1349 out << "column_major";
1350 break;
1351
1352 case EmpRowMajor:
1353 out << "row_major";
1354 break;
1355
1356 default:
1357 UNREACHABLE();
1358 break;
1359 }
1360
1361 out << ") ";
1362}
1363
1364void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1365{
1366 TInfoSinkBase &out = objSink();
1367
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001368 out << hashName(TName(interfaceBlock->name())) << "{\n";
Geoff Langbdcc54a2015-09-02 13:09:48 -04001369 const TFieldList &fields = interfaceBlock->fields();
1370 for (size_t i = 0; i < fields.size(); ++i)
1371 {
1372 const TField *field = fields[i];
1373 if (writeVariablePrecision(field->type()->getPrecision()))
1374 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001375 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Geoff Langbdcc54a2015-09-02 13:09:48 -04001376 if (field->type()->isArray())
1377 out << arrayBrackets(*field->type());
1378 out << ";\n";
1379 }
1380 out << "}";
1381}
Jamie Madill45bcc782016-11-07 13:58:48 -05001382
1383} // namespace sh