blob: 785eaed0b1ae85473239d4d4acf84285984343b7 [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
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500128void TOutputGLSLBase::writeTriplet(Visit visit,
129 const char *preStr,
130 const char *inStr,
131 const char *postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000132{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700133 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000134 if (visit == PreVisit && preStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000135 out << preStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000136 else if (visit == InVisit && inStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000137 out << inStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000138 else if (visit == PostVisit && postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000139 out << postStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000140}
141
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500142void TOutputGLSLBase::writeBuiltInFunctionTriplet(Visit visit,
Olli Etuahoe1805592017-01-02 16:41:20 +0000143 TOperator op,
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500144 bool useEmulatedFunction)
zmo@google.com5601ea02011-06-10 18:23:25 +0000145{
Olli Etuahod68924e2017-01-02 17:34:40 +0000146 TInfoSinkBase &out = objSink();
147 if (visit == PreVisit)
Olli Etuahoe1805592017-01-02 16:41:20 +0000148 {
Olli Etuahod68924e2017-01-02 17:34:40 +0000149 const char *opStr(GetOperatorString(op));
150 if (useEmulatedFunction)
151 {
152 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
153 }
154 else
155 {
156 out << opStr;
157 }
158 out << "(";
Olli Etuahoe1805592017-01-02 16:41:20 +0000159 }
Olli Etuahod68924e2017-01-02 17:34:40 +0000160 else
161 {
162 writeTriplet(visit, nullptr, ", ", ")");
163 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700164}
165
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300166void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
167{
Martin Radev2cc85b32016-08-05 16:22:53 +0300168 if (!NeedsToWriteLayoutQualifier(type))
169 {
170 return;
171 }
172
173 TInfoSinkBase &out = objSink();
174 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
175 out << "layout(";
176
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300177 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
178 {
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300179 if (layoutQualifier.location >= 0)
180 {
Martin Radev2cc85b32016-08-05 16:22:53 +0300181 out << "location = " << layoutQualifier.location;
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300182 }
183 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300184
185 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
186 {
187 ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
188 out << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
189 }
190
191 out << ") ";
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300192}
193
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800194const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier)
195{
196 if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 &&
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000197 (mCompileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0)
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800198 {
199 switch (qualifier)
200 {
201 // The return string is consistent with sh::getQualifierString() from
202 // BaseTypes.h minus the "centroid" keyword.
203 case EvqCentroid:
204 return "";
205 case EvqCentroidIn:
206 return "smooth in";
207 case EvqCentroidOut:
208 return "smooth out";
209 default:
210 break;
211 }
212 }
213 if (sh::IsGLSL130OrNewer(mOutput))
214 {
215 switch (qualifier)
216 {
217 case EvqAttribute:
218 return "in";
219 case EvqVaryingIn:
220 return "in";
221 case EvqVaryingOut:
222 return "out";
223 default:
224 break;
225 }
226 }
227 return sh::getQualifierString(qualifier);
228}
229
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700230void TOutputGLSLBase::writeVariableType(const TType &type)
231{
Qiankun Miao705a9192016-08-29 10:05:27 +0800232 TQualifier qualifier = type.getQualifier();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500233 TInfoSinkBase &out = objSink();
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800234 if (type.isInvariant())
Olli Etuaho214c2d82015-04-27 14:49:13 +0300235 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800236 writeInvariantQualifier(type);
Olli Etuaho214c2d82015-04-27 14:49:13 +0300237 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400238 if (type.getBasicType() == EbtInterfaceBlock)
239 {
240 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
241 declareInterfaceBlockLayout(interfaceBlock);
242 }
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400243 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400244 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800245 const char *qualifierString = mapQualifierToString(qualifier);
246 if (qualifierString && qualifierString[0] != '\0')
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800247 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800248 out << qualifierString << " ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800249 }
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400250 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300251
252 const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
253 if (memoryQualifier.readonly)
254 {
255 ASSERT(IsImage(type.getBasicType()));
256 out << "readonly ";
257 }
258
259 if (memoryQualifier.writeonly)
260 {
261 ASSERT(IsImage(type.getBasicType()));
262 out << "writeonly ";
263 }
264
Martin Radev049edfa2016-11-11 14:35:37 +0200265 if (memoryQualifier.coherent)
266 {
267 ASSERT(IsImage(type.getBasicType()));
268 out << "coherent ";
269 }
270
271 if (memoryQualifier.restrictQualifier)
272 {
273 ASSERT(IsImage(type.getBasicType()));
274 out << "restrict ";
275 }
276
277 if (memoryQualifier.volatileQualifier)
278 {
279 ASSERT(IsImage(type.getBasicType()));
280 out << "volatile ";
281 }
282
zmo@google.com5601ea02011-06-10 18:23:25 +0000283 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700284 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000285 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400286 TStructure *structure = type.getStruct();
287
288 declareStruct(structure);
289
290 if (!structure->name().empty())
291 {
292 mDeclaredStructs.insert(structure->uniqueId());
293 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000294 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400295 else if (type.getBasicType() == EbtInterfaceBlock)
296 {
297 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
298 declareInterfaceBlock(interfaceBlock);
299 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000300 else
301 {
302 if (writeVariablePrecision(type.getPrecision()))
303 out << " ";
304 out << getTypeName(type);
305 }
306}
307
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700308void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000309{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700310 TInfoSinkBase &out = objSink();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500311 for (TIntermSequence::const_iterator iter = args.begin(); iter != args.end(); ++iter)
zmo@google.com5601ea02011-06-10 18:23:25 +0000312 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700313 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000314 ASSERT(arg != NULL);
315
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700316 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000317 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000318
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000319 if (!arg->getName().getString().empty())
320 out << " " << hashName(arg->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000321 if (type.isArray())
322 out << arrayBrackets(type);
323
324 // Put a comma if this is not the last argument.
325 if (iter != args.end() - 1)
326 out << ", ";
327 }
328}
329
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500330const TConstantUnion *TOutputGLSLBase::writeConstantUnion(const TType &type,
331 const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000332{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700333 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000334
335 if (type.getBasicType() == EbtStruct)
336 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700337 const TStructure *structure = type.getStruct();
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000338 out << hashName(TName(structure->name())) << "(";
Jamie Madill98493dd2013-07-08 14:39:03 -0400339
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700340 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400341 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000342 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700343 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000344 ASSERT(fieldType != NULL);
345 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700346 if (i != fields.size() - 1)
347 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000348 }
349 out << ")";
350 }
351 else
352 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500353 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000354 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700355 if (writeType)
356 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400357 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000358 {
359 switch (pConstUnion->getType())
360 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500361 case EbtFloat:
362 writeFloat(out, pConstUnion->getFConst());
363 break;
364 case EbtInt:
365 out << pConstUnion->getIConst();
366 break;
367 case EbtUInt:
368 out << pConstUnion->getUConst() << "u";
369 break;
370 case EbtBool:
371 out << pConstUnion->getBConst();
372 break;
373 default:
374 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000375 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700376 if (i != size - 1)
377 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000378 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700379 if (writeType)
380 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000381 }
382 return pConstUnion;
383}
384
Olli Etuahoe92507b2016-07-04 11:20:10 +0300385void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
Olli Etuahof40319e2015-03-10 14:33:00 +0200386{
387 TInfoSinkBase &out = objSink();
388 if (visit == PreVisit)
389 {
390 if (type.isArray())
391 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300392 out << getTypeName(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200393 out << arrayBrackets(type);
394 out << "(";
395 }
396 else
397 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300398 out << getTypeName(type) << "(";
Olli Etuahof40319e2015-03-10 14:33:00 +0200399 }
400 }
401 else
402 {
403 writeTriplet(visit, nullptr, ", ", ")");
404 }
405}
406
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700407void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000408{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700409 TInfoSinkBase &out = objSink();
Corentin Wallez1b896c62016-11-16 13:10:44 -0500410 out << hashVariableName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000411
412 if (mDeclaringVariables && node->getType().isArray())
413 out << arrayBrackets(node->getType());
414}
415
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700416void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000417{
418 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
419}
420
Olli Etuahob6fa0432016-09-28 16:28:05 +0100421bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
422{
423 TInfoSinkBase &out = objSink();
424 if (visit == PostVisit)
425 {
426 out << ".";
427 node->writeOffsetsAsXYZW(&out);
428 }
429 return true;
430}
431
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700432bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000433{
434 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700435 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000436 switch (node->getOp())
437 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100438 case EOpComma:
439 writeTriplet(visit, "(", ", ", ")");
440 break;
441 case EOpInitialize:
zmo@google.com5601ea02011-06-10 18:23:25 +0000442 if (visit == InVisit)
443 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100444 out << " = ";
445 // RHS of initialize is not being declared.
446 mDeclaringVariables = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000447 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100448 break;
449 case EOpAssign:
450 writeTriplet(visit, "(", " = ", ")");
451 break;
452 case EOpAddAssign:
453 writeTriplet(visit, "(", " += ", ")");
454 break;
455 case EOpSubAssign:
456 writeTriplet(visit, "(", " -= ", ")");
457 break;
458 case EOpDivAssign:
459 writeTriplet(visit, "(", " /= ", ")");
460 break;
461 case EOpIModAssign:
462 writeTriplet(visit, "(", " %= ", ")");
463 break;
464 // Notice the fall-through.
465 case EOpMulAssign:
466 case EOpVectorTimesMatrixAssign:
467 case EOpVectorTimesScalarAssign:
468 case EOpMatrixTimesScalarAssign:
469 case EOpMatrixTimesMatrixAssign:
470 writeTriplet(visit, "(", " *= ", ")");
471 break;
472 case EOpBitShiftLeftAssign:
473 writeTriplet(visit, "(", " <<= ", ")");
474 break;
475 case EOpBitShiftRightAssign:
476 writeTriplet(visit, "(", " >>= ", ")");
477 break;
478 case EOpBitwiseAndAssign:
479 writeTriplet(visit, "(", " &= ", ")");
480 break;
481 case EOpBitwiseXorAssign:
482 writeTriplet(visit, "(", " ^= ", ")");
483 break;
484 case EOpBitwiseOrAssign:
485 writeTriplet(visit, "(", " |= ", ")");
486 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000487
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100488 case EOpIndexDirect:
zmo@google.com5601ea02011-06-10 18:23:25 +0000489 writeTriplet(visit, NULL, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100490 break;
491 case EOpIndexIndirect:
492 if (node->getAddIndexClamp())
493 {
494 if (visit == InVisit)
495 {
496 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
497 out << "[int(clamp(float(";
498 else
499 out << "[webgl_int_clamp(";
500 }
501 else if (visit == PostVisit)
502 {
503 int maxSize;
504 TIntermTyped *left = node->getLeft();
505 TType leftType = left->getType();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700506
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100507 if (left->isArray())
508 {
509 // The shader will fail validation if the array length is not > 0.
510 maxSize = static_cast<int>(leftType.getArraySize()) - 1;
511 }
512 else
513 {
514 maxSize = leftType.getNominalSize() - 1;
515 }
516
517 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
518 out << "), 0.0, float(" << maxSize << ")))]";
519 else
520 out << ", 0, " << maxSize << ")]";
521 }
522 }
523 else
524 {
525 writeTriplet(visit, NULL, "[", "]");
526 }
527 break;
528 case EOpIndexDirectStruct:
529 if (visit == InVisit)
530 {
531 // Here we are writing out "foo.bar", where "foo" is struct
532 // and "bar" is field. In AST, it is represented as a binary
533 // node, where left child represents "foo" and right child "bar".
534 // The node itself represents ".". The struct field "bar" is
535 // actually stored as an index into TStructure::fields.
536 out << ".";
537 const TStructure *structure = node->getLeft()->getType().getStruct();
538 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
539 const TField *field = structure->fields()[index->getIConst(0)];
540
541 TString fieldName = field->name();
542 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000543 fieldName = hashName(TName(fieldName));
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100544
545 out << fieldName;
546 visitChildren = false;
547 }
548 break;
549 case EOpIndexDirectInterfaceBlock:
550 if (visit == InVisit)
551 {
552 out << ".";
553 const TInterfaceBlock *interfaceBlock =
554 node->getLeft()->getType().getInterfaceBlock();
555 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
556 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
557
558 TString fieldName = field->name();
559 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000560 fieldName = hashName(TName(fieldName));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700561
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100562 out << fieldName;
563 visitChildren = false;
564 }
565 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400566
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100567 case EOpAdd:
568 writeTriplet(visit, "(", " + ", ")");
569 break;
570 case EOpSub:
571 writeTriplet(visit, "(", " - ", ")");
572 break;
573 case EOpMul:
574 writeTriplet(visit, "(", " * ", ")");
575 break;
576 case EOpDiv:
577 writeTriplet(visit, "(", " / ", ")");
578 break;
579 case EOpIMod:
580 writeTriplet(visit, "(", " % ", ")");
581 break;
582 case EOpBitShiftLeft:
583 writeTriplet(visit, "(", " << ", ")");
584 break;
585 case EOpBitShiftRight:
586 writeTriplet(visit, "(", " >> ", ")");
587 break;
588 case EOpBitwiseAnd:
589 writeTriplet(visit, "(", " & ", ")");
590 break;
591 case EOpBitwiseXor:
592 writeTriplet(visit, "(", " ^ ", ")");
593 break;
594 case EOpBitwiseOr:
595 writeTriplet(visit, "(", " | ", ")");
596 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400597
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100598 case EOpEqual:
599 writeTriplet(visit, "(", " == ", ")");
600 break;
601 case EOpNotEqual:
602 writeTriplet(visit, "(", " != ", ")");
603 break;
604 case EOpLessThan:
605 writeTriplet(visit, "(", " < ", ")");
606 break;
607 case EOpGreaterThan:
608 writeTriplet(visit, "(", " > ", ")");
609 break;
610 case EOpLessThanEqual:
611 writeTriplet(visit, "(", " <= ", ")");
612 break;
613 case EOpGreaterThanEqual:
614 writeTriplet(visit, "(", " >= ", ")");
615 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000616
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100617 // Notice the fall-through.
618 case EOpVectorTimesScalar:
619 case EOpVectorTimesMatrix:
620 case EOpMatrixTimesVector:
621 case EOpMatrixTimesScalar:
622 case EOpMatrixTimesMatrix:
623 writeTriplet(visit, "(", " * ", ")");
624 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200625
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100626 case EOpLogicalOr:
627 writeTriplet(visit, "(", " || ", ")");
628 break;
629 case EOpLogicalXor:
630 writeTriplet(visit, "(", " ^^ ", ")");
631 break;
632 case EOpLogicalAnd:
633 writeTriplet(visit, "(", " && ", ")");
634 break;
635 default:
636 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000637 }
638
639 return visitChildren;
640}
641
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700642bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000643{
zmo@google.com32e97312011-08-24 01:03:11 +0000644 TString preString;
645 TString postString = ")";
646
zmo@google.com5601ea02011-06-10 18:23:25 +0000647 switch (node->getOp())
648 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500649 case EOpNegative:
650 preString = "(-";
651 break;
652 case EOpPositive:
653 preString = "(+";
654 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500655 case EOpLogicalNot:
656 preString = "(!";
657 break;
658 case EOpBitwiseNot:
659 preString = "(~";
660 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000661
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500662 case EOpPostIncrement:
663 preString = "(";
664 postString = "++)";
665 break;
666 case EOpPostDecrement:
667 preString = "(";
668 postString = "--)";
669 break;
670 case EOpPreIncrement:
671 preString = "(++";
672 break;
673 case EOpPreDecrement:
674 preString = "(--";
675 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000676
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500677 case EOpRadians:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500678 case EOpDegrees:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500679 case EOpSin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500680 case EOpCos:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500681 case EOpTan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500682 case EOpAsin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500683 case EOpAcos:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500684 case EOpAtan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500685 case EOpSinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500686 case EOpCosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500687 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500688 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500689 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500690 case EOpAtanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500691 case EOpExp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500692 case EOpLog:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500693 case EOpExp2:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500694 case EOpLog2:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500695 case EOpSqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500696 case EOpInverseSqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500697 case EOpAbs:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500698 case EOpSign:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500699 case EOpFloor:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500700 case EOpTrunc:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500701 case EOpRound:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500702 case EOpRoundEven:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500703 case EOpCeil:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500704 case EOpFract:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500705 case EOpIsNan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500706 case EOpIsInf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500707 case EOpFloatBitsToInt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500708 case EOpFloatBitsToUint:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500709 case EOpIntBitsToFloat:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500710 case EOpUintBitsToFloat:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500711 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500712 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500713 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500714 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500715 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500716 case EOpUnpackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500717 case EOpLength:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500718 case EOpNormalize:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500719 case EOpDFdx:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500720 case EOpDFdy:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500721 case EOpFwidth:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500722 case EOpTranspose:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500723 case EOpDeterminant:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500724 case EOpInverse:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500725 case EOpAny:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500726 case EOpAll:
Olli Etuahod68924e2017-01-02 17:34:40 +0000727 case EOpLogicalNotComponentWise:
728 writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
729 return true;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500730 default:
731 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000732 }
733
zmo@google.com32e97312011-08-24 01:03:11 +0000734 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
735
zmo@google.com5601ea02011-06-10 18:23:25 +0000736 return true;
737}
738
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300739bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
740{
741 TInfoSinkBase &out = objSink();
742 // Notice two brackets at the beginning and end. The outer ones
743 // encapsulate the whole ternary expression. This preserves the
744 // order of precedence when ternary expressions are used in a
745 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
746 out << "((";
747 node->getCondition()->traverse(this);
748 out << ") ? (";
749 node->getTrueExpression()->traverse(this);
750 out << ") : (";
751 node->getFalseExpression()->traverse(this);
752 out << "))";
753 return false;
754}
755
Olli Etuaho57961272016-09-14 13:57:46 +0300756bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000757{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700758 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000759
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300760 out << "if (";
761 node->getCondition()->traverse(this);
762 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000763
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300764 incrementDepth(node);
765 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000766
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300767 if (node->getFalseBlock())
768 {
769 out << "else\n";
770 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000771 }
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300772 decrementDepth();
zmo@google.com5601ea02011-06-10 18:23:25 +0000773 return false;
774}
775
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200776bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200777{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200778 if (node->getStatementList())
779 {
780 writeTriplet(visit, "switch (", ") ", nullptr);
781 // The curly braces get written when visiting the statementList aggregate
782 }
783 else
784 {
785 // No statementList, so it won't output curly braces
786 writeTriplet(visit, "switch (", ") {", "}\n");
787 }
788 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200789}
790
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200791bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200792{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200793 if (node->hasCondition())
794 {
795 writeTriplet(visit, "case (", nullptr, "):\n");
796 return true;
797 }
798 else
799 {
800 TInfoSinkBase &out = objSink();
801 out << "default:\n";
802 return false;
803 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200804}
805
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100806bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
807{
808 TInfoSinkBase &out = objSink();
809 // Scope the blocks except when at the global scope.
810 if (mDepth > 0)
811 {
812 out << "{\n";
813 }
814
815 incrementDepth(node);
816 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
817 iter != node->getSequence()->end(); ++iter)
818 {
819 TIntermNode *curNode = *iter;
820 ASSERT(curNode != nullptr);
821 curNode->traverse(this);
822
823 if (isSingleStatement(curNode))
824 out << ";\n";
825 }
826 decrementDepth();
827
828 // Scope the blocks except when at the global scope.
829 if (mDepth > 0)
830 {
831 out << "}\n";
832 }
833 return false;
834}
835
Olli Etuaho336b1472016-10-05 16:37:55 +0100836bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
837{
838 TInfoSinkBase &out = objSink();
839
840 ASSERT(visit == PreVisit);
841 {
842 const TType &type = node->getType();
843 writeVariableType(type);
844 if (type.isArray())
845 out << arrayBrackets(type);
846 }
847
848 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
849
850 incrementDepth(node);
851
852 // Traverse function parameters.
853 TIntermAggregate *params = node->getFunctionParameters()->getAsAggregate();
854 ASSERT(params->getOp() == EOpParameters);
855 params->traverse(this);
856
857 // Traverse function body.
858 visitCodeBlock(node->getBody());
859 decrementDepth();
860
861 // Fully processed; no need to visit children.
862 return false;
863}
864
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000865bool TOutputGLSLBase::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
866{
867 TInfoSinkBase &out = objSink();
868 ASSERT(visit == PreVisit);
869 const TIntermSymbol *symbol = node->getSymbol();
870 out << "invariant " << hashVariableName(symbol->getName());
871 return false;
872}
873
Olli Etuaho16c745a2017-01-16 17:02:27 +0000874bool TOutputGLSLBase::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
875{
876 TInfoSinkBase &out = objSink();
877 ASSERT(visit == PreVisit);
878
879 const TType &type = node->getType();
880 writeVariableType(type);
881 if (type.isArray())
882 out << arrayBrackets(type);
883
884 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
885
886 out << "(";
887 writeFunctionParameters(*(node->getSequence()));
888 out << ")";
889
890 return false;
891}
892
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700893bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000894{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500895 bool visitChildren = true;
896 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000897 switch (node->getOp())
898 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500899 case EOpFunctionCall:
900 // Function call.
901 if (visit == PreVisit)
902 out << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
903 else if (visit == InVisit)
904 out << ", ";
905 else
906 out << ")";
907 break;
908 case EOpParameters:
909 // Function parameters.
910 ASSERT(visit == PreVisit);
911 out << "(";
912 writeFunctionParameters(*(node->getSequence()));
913 out << ")";
914 visitChildren = false;
915 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500916 case EOpConstructFloat:
917 case EOpConstructVec2:
918 case EOpConstructVec3:
919 case EOpConstructVec4:
920 case EOpConstructBool:
921 case EOpConstructBVec2:
922 case EOpConstructBVec3:
923 case EOpConstructBVec4:
924 case EOpConstructInt:
925 case EOpConstructIVec2:
926 case EOpConstructIVec3:
927 case EOpConstructIVec4:
928 case EOpConstructUInt:
929 case EOpConstructUVec2:
930 case EOpConstructUVec3:
931 case EOpConstructUVec4:
932 case EOpConstructMat2:
933 case EOpConstructMat2x3:
934 case EOpConstructMat2x4:
935 case EOpConstructMat3x2:
936 case EOpConstructMat3:
937 case EOpConstructMat3x4:
938 case EOpConstructMat4x2:
939 case EOpConstructMat4x3:
940 case EOpConstructMat4:
941 case EOpConstructStruct:
942 writeConstructorTriplet(visit, node->getType());
943 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200944
Olli Etuahoe1805592017-01-02 16:41:20 +0000945 case EOpEqualComponentWise:
946 case EOpNotEqualComponentWise:
947 case EOpLessThanComponentWise:
948 case EOpGreaterThanComponentWise:
949 case EOpLessThanEqualComponentWise:
950 case EOpGreaterThanEqualComponentWise:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500951 case EOpMod:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500952 case EOpModf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500953 case EOpPow:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500954 case EOpAtan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500955 case EOpMin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500956 case EOpMax:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500957 case EOpClamp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500958 case EOpMix:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500959 case EOpStep:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500960 case EOpSmoothStep:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500961 case EOpDistance:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500962 case EOpDot:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500963 case EOpCross:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500964 case EOpFaceForward:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500965 case EOpReflect:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500966 case EOpRefract:
Olli Etuahoe1805592017-01-02 16:41:20 +0000967 case EOpMulMatrixComponentWise:
968 case EOpOuterProduct:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300969 case EOpBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300970 case EOpMemoryBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300971 case EOpMemoryBarrierAtomicCounter:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300972 case EOpMemoryBarrierBuffer:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300973 case EOpMemoryBarrierImage:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300974 case EOpMemoryBarrierShared:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300975 case EOpGroupMemoryBarrier:
Olli Etuahod68924e2017-01-02 17:34:40 +0000976 writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300977 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500978 default:
979 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000980 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000981 return visitChildren;
982}
983
Olli Etuaho13389b62016-10-16 11:48:18 +0100984bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
985{
986 TInfoSinkBase &out = objSink();
987
988 // Variable declaration.
989 if (visit == PreVisit)
990 {
991 const TIntermSequence &sequence = *(node->getSequence());
992 const TIntermTyped *variable = sequence.front()->getAsTyped();
993 writeLayoutQualifier(variable->getType());
994 writeVariableType(variable->getType());
995 out << " ";
996 mDeclaringVariables = true;
997 }
998 else if (visit == InVisit)
999 {
1000 out << ", ";
1001 mDeclaringVariables = true;
1002 }
1003 else
1004 {
1005 mDeclaringVariables = false;
1006 }
1007 return true;
1008}
1009
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001010bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001011{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001012 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001013
Zhenyao Mo7cab38b2013-10-15 12:59:30 -07001014 incrementDepth(node);
Corentin Wallez7258e302015-09-22 10:40:24 -07001015
zmo@google.com5601ea02011-06-10 18:23:25 +00001016 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001017
zmo@google.com5601ea02011-06-10 18:23:25 +00001018 if (loopType == ELoopFor) // for loop
1019 {
Corentin Wallez1b896c62016-11-16 13:10:44 -05001020 out << "for (";
1021 if (node->getInit())
1022 node->getInit()->traverse(this);
1023 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001024
Corentin Wallez1b896c62016-11-16 13:10:44 -05001025 if (node->getCondition())
1026 node->getCondition()->traverse(this);
1027 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001028
Corentin Wallez1b896c62016-11-16 13:10:44 -05001029 if (node->getExpression())
1030 node->getExpression()->traverse(this);
1031 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001032
Corentin Wallez1b896c62016-11-16 13:10:44 -05001033 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001034 }
1035 else if (loopType == ELoopWhile) // while loop
1036 {
1037 out << "while (";
1038 ASSERT(node->getCondition() != NULL);
1039 node->getCondition()->traverse(this);
1040 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001041
1042 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001043 }
1044 else // do-while loop
1045 {
1046 ASSERT(loopType == ELoopDoWhile);
1047 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001048
zmo@google.com5601ea02011-06-10 18:23:25 +00001049 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001050
zmo@google.com5601ea02011-06-10 18:23:25 +00001051 out << "while (";
1052 ASSERT(node->getCondition() != NULL);
1053 node->getCondition()->traverse(this);
1054 out << ");\n";
1055 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001056
zmo@google.com5601ea02011-06-10 18:23:25 +00001057 decrementDepth();
1058
1059 // No need to visit children. They have been already processed in
1060 // this function.
1061 return false;
1062}
1063
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001064bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001065{
1066 switch (node->getFlowOp())
1067 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001068 case EOpKill:
1069 writeTriplet(visit, "discard", NULL, NULL);
1070 break;
1071 case EOpBreak:
1072 writeTriplet(visit, "break", NULL, NULL);
1073 break;
1074 case EOpContinue:
1075 writeTriplet(visit, "continue", NULL, NULL);
1076 break;
1077 case EOpReturn:
1078 writeTriplet(visit, "return ", NULL, NULL);
1079 break;
1080 default:
1081 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001082 }
1083
1084 return true;
1085}
1086
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001087void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001088{
zmo@google.com5601ea02011-06-10 18:23:25 +00001089 TInfoSinkBase &out = objSink();
1090 if (node != NULL)
1091 {
1092 node->traverse(this);
1093 // Single statements not part of a sequence need to be terminated
1094 // with semi-colon.
1095 if (isSingleStatement(node))
1096 out << ";\n";
1097 }
1098 else
1099 {
1100 out << "{\n}\n"; // Empty code block.
1101 }
1102}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001103
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001104TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001105{
Olli Etuahoe92507b2016-07-04 11:20:10 +03001106 if (type.getBasicType() == EbtStruct)
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001107 return hashName(TName(type.getStruct()->name()));
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001108 else
Olli Etuahoe92507b2016-07-04 11:20:10 +03001109 return type.getBuiltInTypeNameString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001110}
1111
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001112TString TOutputGLSLBase::hashName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001113{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001114 if (name.getString().empty())
1115 {
1116 ASSERT(!name.isInternal());
1117 return name.getString();
1118 }
1119 if (name.isInternal())
1120 {
1121 // TODO(oetuaho): Would be nicer to prefix non-internal names with "_" instead, like is
1122 // done in the HLSL output, but that requires fairly complex changes elsewhere in the code
1123 // as well.
1124 // We need to use a prefix that is reserved in WebGL in order to guarantee that the internal
1125 // names don't conflict with user-defined names from WebGL.
1126 return "webgl_angle_" + name.getString();
1127 }
1128 if (mHashFunction == nullptr)
1129 {
1130 return name.getString();
1131 }
1132 NameMap::const_iterator it = mNameMap.find(name.getString().c_str());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001133 if (it != mNameMap.end())
1134 return it->second.c_str();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001135 TString hashedName = TIntermTraverser::hash(name.getString(), mHashFunction);
1136 mNameMap[name.getString().c_str()] = hashedName.c_str();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001137 return hashedName;
1138}
1139
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001140TString TOutputGLSLBase::hashVariableName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001141{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001142 if (mSymbolTable.findBuiltIn(name.getString(), mShaderVersion) != NULL)
Olli Etuaho09b04a22016-12-15 13:30:26 +00001143 {
1144 if (mCompileOptions & SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM &&
1145 name.getString() == "gl_ViewID_OVR")
1146 {
Olli Etuaho2f90a9b2017-01-10 12:27:56 +00001147 TName uniformName(TString("ViewID_OVR"));
Olli Etuaho09b04a22016-12-15 13:30:26 +00001148 uniformName.setInternal(true);
1149 return hashName(uniformName);
1150 }
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001151 return name.getString();
Olli Etuaho09b04a22016-12-15 13:30:26 +00001152 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001153 return hashName(name);
1154}
1155
Olli Etuaho59f9a642015-08-06 20:38:26 +03001156TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001157{
Olli Etuaho59f9a642015-08-06 20:38:26 +03001158 TString mangledStr = mangledName.getString();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001159 TString name = TFunction::unmangleName(mangledStr);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001160 if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001161 return translateTextureFunction(name);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001162 if (mangledName.isInternal())
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001163 {
1164 // Internal function names are outputted as-is - they may refer to functions manually added
1165 // to the output shader source that are not included in the AST at all.
Olli Etuaho59f9a642015-08-06 20:38:26 +03001166 return name;
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001167 }
Olli Etuaho59f9a642015-08-06 20:38:26 +03001168 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001169 {
1170 TName nameObj(name);
1171 return hashName(nameObj);
1172 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001173}
Jamie Madill98493dd2013-07-08 14:39:03 -04001174
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001175bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001176{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001177 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001178 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001179 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001180 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001181 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001182
1183 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001184}
1185
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001186void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001187{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001188 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001189
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001190 out << "struct " << hashName(TName(structure->name())) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001191 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001192 for (size_t i = 0; i < fields.size(); ++i)
1193 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001194 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001195 if (writeVariablePrecision(field->type()->getPrecision()))
1196 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001197 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Jamie Madill98493dd2013-07-08 14:39:03 -04001198 if (field->type()->isArray())
1199 out << arrayBrackets(*field->type());
1200 out << ";\n";
1201 }
1202 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001203}
Jamie Madill98493dd2013-07-08 14:39:03 -04001204
Geoff Langbdcc54a2015-09-02 13:09:48 -04001205void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1206{
1207 TInfoSinkBase &out = objSink();
1208
1209 out << "layout(";
1210
1211 switch (interfaceBlock->blockStorage())
1212 {
1213 case EbsUnspecified:
1214 case EbsShared:
1215 // Default block storage is shared.
1216 out << "shared";
1217 break;
1218
1219 case EbsPacked:
1220 out << "packed";
1221 break;
1222
1223 case EbsStd140:
1224 out << "std140";
1225 break;
1226
1227 default:
1228 UNREACHABLE();
1229 break;
1230 }
1231
1232 out << ", ";
1233
1234 switch (interfaceBlock->matrixPacking())
1235 {
1236 case EmpUnspecified:
1237 case EmpColumnMajor:
1238 // Default matrix packing is column major.
1239 out << "column_major";
1240 break;
1241
1242 case EmpRowMajor:
1243 out << "row_major";
1244 break;
1245
1246 default:
1247 UNREACHABLE();
1248 break;
1249 }
1250
1251 out << ") ";
1252}
1253
1254void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1255{
1256 TInfoSinkBase &out = objSink();
1257
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001258 out << hashName(TName(interfaceBlock->name())) << "{\n";
Geoff Langbdcc54a2015-09-02 13:09:48 -04001259 const TFieldList &fields = interfaceBlock->fields();
1260 for (size_t i = 0; i < fields.size(); ++i)
1261 {
1262 const TField *field = fields[i];
1263 if (writeVariablePrecision(field->type()->getPrecision()))
1264 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001265 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Geoff Langbdcc54a2015-09-02 13:09:48 -04001266 if (field->type()->isArray())
1267 out << arrayBrackets(*field->type());
1268 out << ";\n";
1269 }
1270 out << "}";
1271}
Jamie Madill45bcc782016-11-07 13:58:48 -05001272
1273} // namespace sh