blob: 65575018f01acf9ea60d5c66c60c39734feb0e00 [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 }
Olli Etuaho43364892017-02-13 16:00:12 +000075
76 if (IsOpaqueType(type.getBasicType()) && layoutQualifier.binding != -1)
77 {
78 return true;
79 }
80
Martin Radev2cc85b32016-08-05 16:22:53 +030081 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
82 {
83 return true;
84 }
85 return false;
86}
87
Olli Etuaho43364892017-02-13 16:00:12 +000088class CommaSeparatedListItemPrefixGenerator
89{
90 public:
91 CommaSeparatedListItemPrefixGenerator() : mFirst(true) {}
92 private:
93 bool mFirst;
94
95 friend TInfoSinkBase &operator<<(TInfoSinkBase &out,
96 CommaSeparatedListItemPrefixGenerator &gen);
97};
98
99TInfoSinkBase &operator<<(TInfoSinkBase &out, CommaSeparatedListItemPrefixGenerator &gen)
100{
101 if (gen.mFirst)
102 {
103 gen.mFirst = false;
104 }
105 else
106 {
107 out << ", ";
108 }
109 return out;
110}
111
zmo@google.com5601ea02011-06-10 18:23:25 +0000112} // namespace
113
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700114TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000115 ShArrayIndexClampingStrategy clampingStrategy,
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000116 ShHashFunction64 hashFunction,
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700117 NameMap &nameMap,
118 TSymbolTable &symbolTable,
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000119 sh::GLenum shaderType,
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800120 int shaderVersion,
Qiankun Miao705a9192016-08-29 10:05:27 +0800121 ShShaderOutput output,
122 ShCompileOptions compileOptions)
zmo@google.com5601ea02011-06-10 18:23:25 +0000123 : TIntermTraverser(true, true, true),
124 mObjSink(objSink),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000125 mDeclaringVariables(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000126 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000127 mHashFunction(hashFunction),
128 mNameMap(nameMap),
Jamie Madill02f20dd2013-09-12 12:07:42 -0400129 mSymbolTable(symbolTable),
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000130 mShaderType(shaderType),
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800131 mShaderVersion(shaderVersion),
Qiankun Miao705a9192016-08-29 10:05:27 +0800132 mOutput(output),
133 mCompileOptions(compileOptions)
zmo@google.com5601ea02011-06-10 18:23:25 +0000134{
135}
136
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800137void TOutputGLSLBase::writeInvariantQualifier(const TType &type)
138{
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000139 if (!sh::RemoveInvariant(mShaderType, mShaderVersion, mOutput, mCompileOptions))
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800140 {
141 TInfoSinkBase &out = objSink();
142 out << "invariant ";
143 }
144}
145
Olli Etuaho56a2f952016-12-08 12:16:27 +0000146void TOutputGLSLBase::writeFloat(TInfoSinkBase &out, float f)
147{
148 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300)
149 {
150 out << "uintBitsToFloat(" << gl::bitCast<uint32_t>(f) << "u)";
151 }
152 else
153 {
154 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
155 }
156}
157
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500158void TOutputGLSLBase::writeTriplet(Visit visit,
159 const char *preStr,
160 const char *inStr,
161 const char *postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000162{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700163 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000164 if (visit == PreVisit && preStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000165 out << preStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000166 else if (visit == InVisit && inStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000167 out << inStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000168 else if (visit == PostVisit && postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000169 out << postStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000170}
171
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500172void TOutputGLSLBase::writeBuiltInFunctionTriplet(Visit visit,
Olli Etuahoe1805592017-01-02 16:41:20 +0000173 TOperator op,
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500174 bool useEmulatedFunction)
zmo@google.com5601ea02011-06-10 18:23:25 +0000175{
Olli Etuahod68924e2017-01-02 17:34:40 +0000176 TInfoSinkBase &out = objSink();
177 if (visit == PreVisit)
Olli Etuahoe1805592017-01-02 16:41:20 +0000178 {
Olli Etuahod68924e2017-01-02 17:34:40 +0000179 const char *opStr(GetOperatorString(op));
180 if (useEmulatedFunction)
181 {
182 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
183 }
184 else
185 {
186 out << opStr;
187 }
188 out << "(";
Olli Etuahoe1805592017-01-02 16:41:20 +0000189 }
Olli Etuahod68924e2017-01-02 17:34:40 +0000190 else
191 {
192 writeTriplet(visit, nullptr, ", ", ")");
193 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700194}
195
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300196void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
197{
Martin Radev2cc85b32016-08-05 16:22:53 +0300198 if (!NeedsToWriteLayoutQualifier(type))
199 {
200 return;
201 }
202
203 TInfoSinkBase &out = objSink();
204 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
205 out << "layout(";
206
Olli Etuaho43364892017-02-13 16:00:12 +0000207 CommaSeparatedListItemPrefixGenerator listItemPrefix;
208
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300209 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
210 {
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300211 if (layoutQualifier.location >= 0)
212 {
Olli Etuaho43364892017-02-13 16:00:12 +0000213 out << listItemPrefix << "location = " << layoutQualifier.location;
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300214 }
215 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300216
Olli Etuaho43364892017-02-13 16:00:12 +0000217 if (IsOpaqueType(type.getBasicType()))
Martin Radev2cc85b32016-08-05 16:22:53 +0300218 {
Olli Etuaho43364892017-02-13 16:00:12 +0000219 if (layoutQualifier.binding >= 0)
220 {
221 out << listItemPrefix << "binding = " << layoutQualifier.binding;
222 }
223 }
224
225 if (IsImage(type.getBasicType()))
226 {
227 if (layoutQualifier.imageInternalFormat != EiifUnspecified)
228 {
229 ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
230 out << listItemPrefix
231 << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
232 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300233 }
234
235 out << ") ";
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300236}
237
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800238const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier)
239{
240 if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 &&
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000241 (mCompileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0)
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800242 {
243 switch (qualifier)
244 {
245 // The return string is consistent with sh::getQualifierString() from
246 // BaseTypes.h minus the "centroid" keyword.
247 case EvqCentroid:
248 return "";
249 case EvqCentroidIn:
250 return "smooth in";
251 case EvqCentroidOut:
252 return "smooth out";
253 default:
254 break;
255 }
256 }
257 if (sh::IsGLSL130OrNewer(mOutput))
258 {
259 switch (qualifier)
260 {
261 case EvqAttribute:
262 return "in";
263 case EvqVaryingIn:
264 return "in";
265 case EvqVaryingOut:
266 return "out";
267 default:
268 break;
269 }
270 }
271 return sh::getQualifierString(qualifier);
272}
273
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700274void TOutputGLSLBase::writeVariableType(const TType &type)
275{
Qiankun Miao705a9192016-08-29 10:05:27 +0800276 TQualifier qualifier = type.getQualifier();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500277 TInfoSinkBase &out = objSink();
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800278 if (type.isInvariant())
Olli Etuaho214c2d82015-04-27 14:49:13 +0300279 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800280 writeInvariantQualifier(type);
Olli Etuaho214c2d82015-04-27 14:49:13 +0300281 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400282 if (type.getBasicType() == EbtInterfaceBlock)
283 {
284 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
285 declareInterfaceBlockLayout(interfaceBlock);
286 }
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400287 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400288 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800289 const char *qualifierString = mapQualifierToString(qualifier);
290 if (qualifierString && qualifierString[0] != '\0')
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800291 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800292 out << qualifierString << " ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800293 }
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400294 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300295
296 const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
297 if (memoryQualifier.readonly)
298 {
299 ASSERT(IsImage(type.getBasicType()));
300 out << "readonly ";
301 }
302
303 if (memoryQualifier.writeonly)
304 {
305 ASSERT(IsImage(type.getBasicType()));
306 out << "writeonly ";
307 }
308
Martin Radev049edfa2016-11-11 14:35:37 +0200309 if (memoryQualifier.coherent)
310 {
311 ASSERT(IsImage(type.getBasicType()));
312 out << "coherent ";
313 }
314
315 if (memoryQualifier.restrictQualifier)
316 {
317 ASSERT(IsImage(type.getBasicType()));
318 out << "restrict ";
319 }
320
321 if (memoryQualifier.volatileQualifier)
322 {
323 ASSERT(IsImage(type.getBasicType()));
324 out << "volatile ";
325 }
326
zmo@google.com5601ea02011-06-10 18:23:25 +0000327 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700328 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000329 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400330 TStructure *structure = type.getStruct();
331
332 declareStruct(structure);
333
334 if (!structure->name().empty())
335 {
336 mDeclaredStructs.insert(structure->uniqueId());
337 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000338 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400339 else if (type.getBasicType() == EbtInterfaceBlock)
340 {
341 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
342 declareInterfaceBlock(interfaceBlock);
343 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000344 else
345 {
346 if (writeVariablePrecision(type.getPrecision()))
347 out << " ";
348 out << getTypeName(type);
349 }
350}
351
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700352void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000353{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700354 TInfoSinkBase &out = objSink();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500355 for (TIntermSequence::const_iterator iter = args.begin(); iter != args.end(); ++iter)
zmo@google.com5601ea02011-06-10 18:23:25 +0000356 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700357 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000358 ASSERT(arg != NULL);
359
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700360 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000361 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000362
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000363 if (!arg->getName().getString().empty())
364 out << " " << hashName(arg->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000365 if (type.isArray())
366 out << arrayBrackets(type);
367
368 // Put a comma if this is not the last argument.
369 if (iter != args.end() - 1)
370 out << ", ";
371 }
372}
373
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500374const TConstantUnion *TOutputGLSLBase::writeConstantUnion(const TType &type,
375 const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000376{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700377 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000378
379 if (type.getBasicType() == EbtStruct)
380 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700381 const TStructure *structure = type.getStruct();
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000382 out << hashName(TName(structure->name())) << "(";
Jamie Madill98493dd2013-07-08 14:39:03 -0400383
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700384 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400385 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000386 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700387 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000388 ASSERT(fieldType != NULL);
389 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700390 if (i != fields.size() - 1)
391 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000392 }
393 out << ")";
394 }
395 else
396 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500397 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000398 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700399 if (writeType)
400 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400401 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000402 {
403 switch (pConstUnion->getType())
404 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500405 case EbtFloat:
406 writeFloat(out, pConstUnion->getFConst());
407 break;
408 case EbtInt:
409 out << pConstUnion->getIConst();
410 break;
411 case EbtUInt:
412 out << pConstUnion->getUConst() << "u";
413 break;
414 case EbtBool:
415 out << pConstUnion->getBConst();
416 break;
417 default:
418 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000419 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700420 if (i != size - 1)
421 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000422 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700423 if (writeType)
424 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000425 }
426 return pConstUnion;
427}
428
Olli Etuahoe92507b2016-07-04 11:20:10 +0300429void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
Olli Etuahof40319e2015-03-10 14:33:00 +0200430{
431 TInfoSinkBase &out = objSink();
432 if (visit == PreVisit)
433 {
434 if (type.isArray())
435 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300436 out << getTypeName(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200437 out << arrayBrackets(type);
438 out << "(";
439 }
440 else
441 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300442 out << getTypeName(type) << "(";
Olli Etuahof40319e2015-03-10 14:33:00 +0200443 }
444 }
445 else
446 {
447 writeTriplet(visit, nullptr, ", ", ")");
448 }
449}
450
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700451void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000452{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700453 TInfoSinkBase &out = objSink();
Corentin Wallez1b896c62016-11-16 13:10:44 -0500454 out << hashVariableName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000455
456 if (mDeclaringVariables && node->getType().isArray())
457 out << arrayBrackets(node->getType());
458}
459
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700460void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000461{
462 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
463}
464
Olli Etuahob6fa0432016-09-28 16:28:05 +0100465bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
466{
467 TInfoSinkBase &out = objSink();
468 if (visit == PostVisit)
469 {
470 out << ".";
471 node->writeOffsetsAsXYZW(&out);
472 }
473 return true;
474}
475
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700476bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000477{
478 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700479 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000480 switch (node->getOp())
481 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100482 case EOpComma:
483 writeTriplet(visit, "(", ", ", ")");
484 break;
485 case EOpInitialize:
zmo@google.com5601ea02011-06-10 18:23:25 +0000486 if (visit == InVisit)
487 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100488 out << " = ";
489 // RHS of initialize is not being declared.
490 mDeclaringVariables = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000491 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100492 break;
493 case EOpAssign:
494 writeTriplet(visit, "(", " = ", ")");
495 break;
496 case EOpAddAssign:
497 writeTriplet(visit, "(", " += ", ")");
498 break;
499 case EOpSubAssign:
500 writeTriplet(visit, "(", " -= ", ")");
501 break;
502 case EOpDivAssign:
503 writeTriplet(visit, "(", " /= ", ")");
504 break;
505 case EOpIModAssign:
506 writeTriplet(visit, "(", " %= ", ")");
507 break;
508 // Notice the fall-through.
509 case EOpMulAssign:
510 case EOpVectorTimesMatrixAssign:
511 case EOpVectorTimesScalarAssign:
512 case EOpMatrixTimesScalarAssign:
513 case EOpMatrixTimesMatrixAssign:
514 writeTriplet(visit, "(", " *= ", ")");
515 break;
516 case EOpBitShiftLeftAssign:
517 writeTriplet(visit, "(", " <<= ", ")");
518 break;
519 case EOpBitShiftRightAssign:
520 writeTriplet(visit, "(", " >>= ", ")");
521 break;
522 case EOpBitwiseAndAssign:
523 writeTriplet(visit, "(", " &= ", ")");
524 break;
525 case EOpBitwiseXorAssign:
526 writeTriplet(visit, "(", " ^= ", ")");
527 break;
528 case EOpBitwiseOrAssign:
529 writeTriplet(visit, "(", " |= ", ")");
530 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000531
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100532 case EOpIndexDirect:
zmo@google.com5601ea02011-06-10 18:23:25 +0000533 writeTriplet(visit, NULL, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100534 break;
535 case EOpIndexIndirect:
536 if (node->getAddIndexClamp())
537 {
538 if (visit == InVisit)
539 {
540 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
541 out << "[int(clamp(float(";
542 else
543 out << "[webgl_int_clamp(";
544 }
545 else if (visit == PostVisit)
546 {
547 int maxSize;
548 TIntermTyped *left = node->getLeft();
549 TType leftType = left->getType();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700550
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100551 if (left->isArray())
552 {
553 // The shader will fail validation if the array length is not > 0.
554 maxSize = static_cast<int>(leftType.getArraySize()) - 1;
555 }
556 else
557 {
558 maxSize = leftType.getNominalSize() - 1;
559 }
560
561 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
562 out << "), 0.0, float(" << maxSize << ")))]";
563 else
564 out << ", 0, " << maxSize << ")]";
565 }
566 }
567 else
568 {
569 writeTriplet(visit, NULL, "[", "]");
570 }
571 break;
572 case EOpIndexDirectStruct:
573 if (visit == InVisit)
574 {
575 // Here we are writing out "foo.bar", where "foo" is struct
576 // and "bar" is field. In AST, it is represented as a binary
577 // node, where left child represents "foo" and right child "bar".
578 // The node itself represents ".". The struct field "bar" is
579 // actually stored as an index into TStructure::fields.
580 out << ".";
581 const TStructure *structure = node->getLeft()->getType().getStruct();
582 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
583 const TField *field = structure->fields()[index->getIConst(0)];
584
585 TString fieldName = field->name();
586 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000587 fieldName = hashName(TName(fieldName));
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100588
589 out << fieldName;
590 visitChildren = false;
591 }
592 break;
593 case EOpIndexDirectInterfaceBlock:
594 if (visit == InVisit)
595 {
596 out << ".";
597 const TInterfaceBlock *interfaceBlock =
598 node->getLeft()->getType().getInterfaceBlock();
599 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
600 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
601
602 TString fieldName = field->name();
603 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000604 fieldName = hashName(TName(fieldName));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700605
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100606 out << fieldName;
607 visitChildren = false;
608 }
609 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400610
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100611 case EOpAdd:
612 writeTriplet(visit, "(", " + ", ")");
613 break;
614 case EOpSub:
615 writeTriplet(visit, "(", " - ", ")");
616 break;
617 case EOpMul:
618 writeTriplet(visit, "(", " * ", ")");
619 break;
620 case EOpDiv:
621 writeTriplet(visit, "(", " / ", ")");
622 break;
623 case EOpIMod:
624 writeTriplet(visit, "(", " % ", ")");
625 break;
626 case EOpBitShiftLeft:
627 writeTriplet(visit, "(", " << ", ")");
628 break;
629 case EOpBitShiftRight:
630 writeTriplet(visit, "(", " >> ", ")");
631 break;
632 case EOpBitwiseAnd:
633 writeTriplet(visit, "(", " & ", ")");
634 break;
635 case EOpBitwiseXor:
636 writeTriplet(visit, "(", " ^ ", ")");
637 break;
638 case EOpBitwiseOr:
639 writeTriplet(visit, "(", " | ", ")");
640 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400641
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100642 case EOpEqual:
643 writeTriplet(visit, "(", " == ", ")");
644 break;
645 case EOpNotEqual:
646 writeTriplet(visit, "(", " != ", ")");
647 break;
648 case EOpLessThan:
649 writeTriplet(visit, "(", " < ", ")");
650 break;
651 case EOpGreaterThan:
652 writeTriplet(visit, "(", " > ", ")");
653 break;
654 case EOpLessThanEqual:
655 writeTriplet(visit, "(", " <= ", ")");
656 break;
657 case EOpGreaterThanEqual:
658 writeTriplet(visit, "(", " >= ", ")");
659 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000660
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100661 // Notice the fall-through.
662 case EOpVectorTimesScalar:
663 case EOpVectorTimesMatrix:
664 case EOpMatrixTimesVector:
665 case EOpMatrixTimesScalar:
666 case EOpMatrixTimesMatrix:
667 writeTriplet(visit, "(", " * ", ")");
668 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200669
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100670 case EOpLogicalOr:
671 writeTriplet(visit, "(", " || ", ")");
672 break;
673 case EOpLogicalXor:
674 writeTriplet(visit, "(", " ^^ ", ")");
675 break;
676 case EOpLogicalAnd:
677 writeTriplet(visit, "(", " && ", ")");
678 break;
679 default:
680 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000681 }
682
683 return visitChildren;
684}
685
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700686bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000687{
zmo@google.com32e97312011-08-24 01:03:11 +0000688 TString preString;
689 TString postString = ")";
690
zmo@google.com5601ea02011-06-10 18:23:25 +0000691 switch (node->getOp())
692 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500693 case EOpNegative:
694 preString = "(-";
695 break;
696 case EOpPositive:
697 preString = "(+";
698 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500699 case EOpLogicalNot:
700 preString = "(!";
701 break;
702 case EOpBitwiseNot:
703 preString = "(~";
704 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000705
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500706 case EOpPostIncrement:
707 preString = "(";
708 postString = "++)";
709 break;
710 case EOpPostDecrement:
711 preString = "(";
712 postString = "--)";
713 break;
714 case EOpPreIncrement:
715 preString = "(++";
716 break;
717 case EOpPreDecrement:
718 preString = "(--";
719 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000720
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500721 case EOpRadians:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500722 case EOpDegrees:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500723 case EOpSin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500724 case EOpCos:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500725 case EOpTan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500726 case EOpAsin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500727 case EOpAcos:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500728 case EOpAtan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500729 case EOpSinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500730 case EOpCosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500731 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500732 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500733 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500734 case EOpAtanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500735 case EOpExp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500736 case EOpLog:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500737 case EOpExp2:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500738 case EOpLog2:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500739 case EOpSqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500740 case EOpInverseSqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500741 case EOpAbs:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500742 case EOpSign:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500743 case EOpFloor:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500744 case EOpTrunc:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500745 case EOpRound:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500746 case EOpRoundEven:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500747 case EOpCeil:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500748 case EOpFract:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500749 case EOpIsNan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500750 case EOpIsInf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500751 case EOpFloatBitsToInt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500752 case EOpFloatBitsToUint:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500753 case EOpIntBitsToFloat:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500754 case EOpUintBitsToFloat:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500755 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500756 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500757 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500758 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500759 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500760 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800761 case EOpPackUnorm4x8:
762 case EOpPackSnorm4x8:
763 case EOpUnpackUnorm4x8:
764 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500765 case EOpLength:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500766 case EOpNormalize:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500767 case EOpDFdx:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500768 case EOpDFdy:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500769 case EOpFwidth:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500770 case EOpTranspose:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500771 case EOpDeterminant:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500772 case EOpInverse:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500773 case EOpAny:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500774 case EOpAll:
Olli Etuahod68924e2017-01-02 17:34:40 +0000775 case EOpLogicalNotComponentWise:
Olli Etuaho9250cb22017-01-21 10:51:27 +0000776 case EOpBitfieldReverse:
777 case EOpBitCount:
778 case EOpFindLSB:
779 case EOpFindMSB:
Olli Etuahod68924e2017-01-02 17:34:40 +0000780 writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
781 return true;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500782 default:
783 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000784 }
785
zmo@google.com32e97312011-08-24 01:03:11 +0000786 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
787
zmo@google.com5601ea02011-06-10 18:23:25 +0000788 return true;
789}
790
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300791bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
792{
793 TInfoSinkBase &out = objSink();
794 // Notice two brackets at the beginning and end. The outer ones
795 // encapsulate the whole ternary expression. This preserves the
796 // order of precedence when ternary expressions are used in a
797 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
798 out << "((";
799 node->getCondition()->traverse(this);
800 out << ") ? (";
801 node->getTrueExpression()->traverse(this);
802 out << ") : (";
803 node->getFalseExpression()->traverse(this);
804 out << "))";
805 return false;
806}
807
Olli Etuaho57961272016-09-14 13:57:46 +0300808bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000809{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700810 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000811
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300812 out << "if (";
813 node->getCondition()->traverse(this);
814 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000815
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300816 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000817
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300818 if (node->getFalseBlock())
819 {
820 out << "else\n";
821 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000822 }
823 return false;
824}
825
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200826bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200827{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200828 if (node->getStatementList())
829 {
830 writeTriplet(visit, "switch (", ") ", nullptr);
831 // The curly braces get written when visiting the statementList aggregate
832 }
833 else
834 {
835 // No statementList, so it won't output curly braces
836 writeTriplet(visit, "switch (", ") {", "}\n");
837 }
838 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200839}
840
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200841bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200842{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200843 if (node->hasCondition())
844 {
845 writeTriplet(visit, "case (", nullptr, "):\n");
846 return true;
847 }
848 else
849 {
850 TInfoSinkBase &out = objSink();
851 out << "default:\n";
852 return false;
853 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200854}
855
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100856bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
857{
858 TInfoSinkBase &out = objSink();
859 // Scope the blocks except when at the global scope.
860 if (mDepth > 0)
861 {
862 out << "{\n";
863 }
864
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100865 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
866 iter != node->getSequence()->end(); ++iter)
867 {
868 TIntermNode *curNode = *iter;
869 ASSERT(curNode != nullptr);
870 curNode->traverse(this);
871
872 if (isSingleStatement(curNode))
873 out << ";\n";
874 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100875
876 // Scope the blocks except when at the global scope.
877 if (mDepth > 0)
878 {
879 out << "}\n";
880 }
881 return false;
882}
883
Olli Etuaho336b1472016-10-05 16:37:55 +0100884bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
885{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000886 TIntermFunctionPrototype *prototype = node->getFunctionPrototype();
887 prototype->traverse(this);
Olli Etuaho336b1472016-10-05 16:37:55 +0100888 visitCodeBlock(node->getBody());
Olli Etuaho336b1472016-10-05 16:37:55 +0100889
890 // Fully processed; no need to visit children.
891 return false;
892}
893
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000894bool TOutputGLSLBase::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
895{
896 TInfoSinkBase &out = objSink();
897 ASSERT(visit == PreVisit);
898 const TIntermSymbol *symbol = node->getSymbol();
899 out << "invariant " << hashVariableName(symbol->getName());
900 return false;
901}
902
Olli Etuaho16c745a2017-01-16 17:02:27 +0000903bool TOutputGLSLBase::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
904{
905 TInfoSinkBase &out = objSink();
906 ASSERT(visit == PreVisit);
907
908 const TType &type = node->getType();
909 writeVariableType(type);
910 if (type.isArray())
911 out << arrayBrackets(type);
912
913 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
914
915 out << "(";
916 writeFunctionParameters(*(node->getSequence()));
917 out << ")";
918
919 return false;
920}
921
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700922bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000923{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500924 bool visitChildren = true;
925 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000926 switch (node->getOp())
927 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800928 case EOpCallFunctionInAST:
929 case EOpCallInternalRawFunction:
930 case EOpCallBuiltInFunction:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500931 // Function call.
932 if (visit == PreVisit)
933 out << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
934 else if (visit == InVisit)
935 out << ", ";
936 else
937 out << ")";
938 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500939 case EOpConstructFloat:
940 case EOpConstructVec2:
941 case EOpConstructVec3:
942 case EOpConstructVec4:
943 case EOpConstructBool:
944 case EOpConstructBVec2:
945 case EOpConstructBVec3:
946 case EOpConstructBVec4:
947 case EOpConstructInt:
948 case EOpConstructIVec2:
949 case EOpConstructIVec3:
950 case EOpConstructIVec4:
951 case EOpConstructUInt:
952 case EOpConstructUVec2:
953 case EOpConstructUVec3:
954 case EOpConstructUVec4:
955 case EOpConstructMat2:
956 case EOpConstructMat2x3:
957 case EOpConstructMat2x4:
958 case EOpConstructMat3x2:
959 case EOpConstructMat3:
960 case EOpConstructMat3x4:
961 case EOpConstructMat4x2:
962 case EOpConstructMat4x3:
963 case EOpConstructMat4:
964 case EOpConstructStruct:
965 writeConstructorTriplet(visit, node->getType());
966 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200967
Olli Etuahoe1805592017-01-02 16:41:20 +0000968 case EOpEqualComponentWise:
969 case EOpNotEqualComponentWise:
970 case EOpLessThanComponentWise:
971 case EOpGreaterThanComponentWise:
972 case EOpLessThanEqualComponentWise:
973 case EOpGreaterThanEqualComponentWise:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500974 case EOpMod:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500975 case EOpModf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500976 case EOpPow:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500977 case EOpAtan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500978 case EOpMin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500979 case EOpMax:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500980 case EOpClamp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500981 case EOpMix:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500982 case EOpStep:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500983 case EOpSmoothStep:
Olli Etuaho74da73f2017-02-01 15:37:48 +0000984 case EOpFrexp:
985 case EOpLdexp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500986 case EOpDistance:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500987 case EOpDot:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500988 case EOpCross:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500989 case EOpFaceForward:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500990 case EOpReflect:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500991 case EOpRefract:
Olli Etuahoe1805592017-01-02 16:41:20 +0000992 case EOpMulMatrixComponentWise:
993 case EOpOuterProduct:
Olli Etuaho9250cb22017-01-21 10:51:27 +0000994 case EOpBitfieldExtract:
995 case EOpBitfieldInsert:
996 case EOpUaddCarry:
997 case EOpUsubBorrow:
998 case EOpUmulExtended:
999 case EOpImulExtended:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001000 case EOpBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001001 case EOpMemoryBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001002 case EOpMemoryBarrierAtomicCounter:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001003 case EOpMemoryBarrierBuffer:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001004 case EOpMemoryBarrierImage:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001005 case EOpMemoryBarrierShared:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001006 case EOpGroupMemoryBarrier:
Olli Etuahod68924e2017-01-02 17:34:40 +00001007 writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001008 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001009 default:
1010 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001011 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001012 return visitChildren;
1013}
1014
Olli Etuaho13389b62016-10-16 11:48:18 +01001015bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
1016{
1017 TInfoSinkBase &out = objSink();
1018
1019 // Variable declaration.
1020 if (visit == PreVisit)
1021 {
1022 const TIntermSequence &sequence = *(node->getSequence());
1023 const TIntermTyped *variable = sequence.front()->getAsTyped();
1024 writeLayoutQualifier(variable->getType());
1025 writeVariableType(variable->getType());
1026 out << " ";
1027 mDeclaringVariables = true;
1028 }
1029 else if (visit == InVisit)
1030 {
1031 out << ", ";
1032 mDeclaringVariables = true;
1033 }
1034 else
1035 {
1036 mDeclaringVariables = false;
1037 }
1038 return true;
1039}
1040
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001041bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001042{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001043 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001044
zmo@google.com5601ea02011-06-10 18:23:25 +00001045 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001046
zmo@google.com5601ea02011-06-10 18:23:25 +00001047 if (loopType == ELoopFor) // for loop
1048 {
Corentin Wallez1b896c62016-11-16 13:10:44 -05001049 out << "for (";
1050 if (node->getInit())
1051 node->getInit()->traverse(this);
1052 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001053
Corentin Wallez1b896c62016-11-16 13:10:44 -05001054 if (node->getCondition())
1055 node->getCondition()->traverse(this);
1056 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001057
Corentin Wallez1b896c62016-11-16 13:10:44 -05001058 if (node->getExpression())
1059 node->getExpression()->traverse(this);
1060 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001061
Corentin Wallez1b896c62016-11-16 13:10:44 -05001062 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001063 }
1064 else if (loopType == ELoopWhile) // while loop
1065 {
1066 out << "while (";
1067 ASSERT(node->getCondition() != NULL);
1068 node->getCondition()->traverse(this);
1069 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001070
1071 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001072 }
1073 else // do-while loop
1074 {
1075 ASSERT(loopType == ELoopDoWhile);
1076 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001077
zmo@google.com5601ea02011-06-10 18:23:25 +00001078 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001079
zmo@google.com5601ea02011-06-10 18:23:25 +00001080 out << "while (";
1081 ASSERT(node->getCondition() != NULL);
1082 node->getCondition()->traverse(this);
1083 out << ");\n";
1084 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001085
zmo@google.com5601ea02011-06-10 18:23:25 +00001086 // No need to visit children. They have been already processed in
1087 // this function.
1088 return false;
1089}
1090
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001091bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001092{
1093 switch (node->getFlowOp())
1094 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001095 case EOpKill:
1096 writeTriplet(visit, "discard", NULL, NULL);
1097 break;
1098 case EOpBreak:
1099 writeTriplet(visit, "break", NULL, NULL);
1100 break;
1101 case EOpContinue:
1102 writeTriplet(visit, "continue", NULL, NULL);
1103 break;
1104 case EOpReturn:
1105 writeTriplet(visit, "return ", NULL, NULL);
1106 break;
1107 default:
1108 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001109 }
1110
1111 return true;
1112}
1113
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001114void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001115{
zmo@google.com5601ea02011-06-10 18:23:25 +00001116 TInfoSinkBase &out = objSink();
1117 if (node != NULL)
1118 {
1119 node->traverse(this);
1120 // Single statements not part of a sequence need to be terminated
1121 // with semi-colon.
1122 if (isSingleStatement(node))
1123 out << ";\n";
1124 }
1125 else
1126 {
1127 out << "{\n}\n"; // Empty code block.
1128 }
1129}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001130
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001131TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001132{
Olli Etuahoe92507b2016-07-04 11:20:10 +03001133 if (type.getBasicType() == EbtStruct)
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001134 return hashName(TName(type.getStruct()->name()));
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001135 else
Olli Etuahoe92507b2016-07-04 11:20:10 +03001136 return type.getBuiltInTypeNameString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001137}
1138
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001139TString TOutputGLSLBase::hashName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001140{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001141 if (name.getString().empty())
1142 {
1143 ASSERT(!name.isInternal());
1144 return name.getString();
1145 }
1146 if (name.isInternal())
1147 {
1148 // TODO(oetuaho): Would be nicer to prefix non-internal names with "_" instead, like is
1149 // done in the HLSL output, but that requires fairly complex changes elsewhere in the code
1150 // as well.
1151 // We need to use a prefix that is reserved in WebGL in order to guarantee that the internal
1152 // names don't conflict with user-defined names from WebGL.
1153 return "webgl_angle_" + name.getString();
1154 }
1155 if (mHashFunction == nullptr)
1156 {
1157 return name.getString();
1158 }
1159 NameMap::const_iterator it = mNameMap.find(name.getString().c_str());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001160 if (it != mNameMap.end())
1161 return it->second.c_str();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001162 TString hashedName = TIntermTraverser::hash(name.getString(), mHashFunction);
1163 mNameMap[name.getString().c_str()] = hashedName.c_str();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001164 return hashedName;
1165}
1166
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001167TString TOutputGLSLBase::hashVariableName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001168{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001169 if (mSymbolTable.findBuiltIn(name.getString(), mShaderVersion) != NULL)
Olli Etuaho09b04a22016-12-15 13:30:26 +00001170 {
1171 if (mCompileOptions & SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM &&
1172 name.getString() == "gl_ViewID_OVR")
1173 {
Olli Etuaho2f90a9b2017-01-10 12:27:56 +00001174 TName uniformName(TString("ViewID_OVR"));
Olli Etuaho09b04a22016-12-15 13:30:26 +00001175 uniformName.setInternal(true);
1176 return hashName(uniformName);
1177 }
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001178 return name.getString();
Olli Etuaho09b04a22016-12-15 13:30:26 +00001179 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001180 return hashName(name);
1181}
1182
Olli Etuaho59f9a642015-08-06 20:38:26 +03001183TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001184{
Olli Etuaho59f9a642015-08-06 20:38:26 +03001185 TString mangledStr = mangledName.getString();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001186 TString name = TFunction::unmangleName(mangledStr);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001187 if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001188 return translateTextureFunction(name);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001189 if (mangledName.isInternal())
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001190 {
1191 // Internal function names are outputted as-is - they may refer to functions manually added
1192 // to the output shader source that are not included in the AST at all.
Olli Etuaho59f9a642015-08-06 20:38:26 +03001193 return name;
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001194 }
Olli Etuaho59f9a642015-08-06 20:38:26 +03001195 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001196 {
1197 TName nameObj(name);
1198 return hashName(nameObj);
1199 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001200}
Jamie Madill98493dd2013-07-08 14:39:03 -04001201
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001202bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001203{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001204 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001205 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001206 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001207 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001208 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001209
1210 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001211}
1212
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001213void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001214{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001215 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001216
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001217 out << "struct " << hashName(TName(structure->name())) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001218 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001219 for (size_t i = 0; i < fields.size(); ++i)
1220 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001221 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001222 if (writeVariablePrecision(field->type()->getPrecision()))
1223 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001224 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Jamie Madill98493dd2013-07-08 14:39:03 -04001225 if (field->type()->isArray())
1226 out << arrayBrackets(*field->type());
1227 out << ";\n";
1228 }
1229 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001230}
Jamie Madill98493dd2013-07-08 14:39:03 -04001231
Geoff Langbdcc54a2015-09-02 13:09:48 -04001232void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1233{
1234 TInfoSinkBase &out = objSink();
1235
1236 out << "layout(";
1237
1238 switch (interfaceBlock->blockStorage())
1239 {
1240 case EbsUnspecified:
1241 case EbsShared:
1242 // Default block storage is shared.
1243 out << "shared";
1244 break;
1245
1246 case EbsPacked:
1247 out << "packed";
1248 break;
1249
1250 case EbsStd140:
1251 out << "std140";
1252 break;
1253
1254 default:
1255 UNREACHABLE();
1256 break;
1257 }
1258
1259 out << ", ";
1260
1261 switch (interfaceBlock->matrixPacking())
1262 {
1263 case EmpUnspecified:
1264 case EmpColumnMajor:
1265 // Default matrix packing is column major.
1266 out << "column_major";
1267 break;
1268
1269 case EmpRowMajor:
1270 out << "row_major";
1271 break;
1272
1273 default:
1274 UNREACHABLE();
1275 break;
1276 }
1277
1278 out << ") ";
1279}
1280
1281void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1282{
1283 TInfoSinkBase &out = objSink();
1284
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001285 out << hashName(TName(interfaceBlock->name())) << "{\n";
Geoff Langbdcc54a2015-09-02 13:09:48 -04001286 const TFieldList &fields = interfaceBlock->fields();
1287 for (size_t i = 0; i < fields.size(); ++i)
1288 {
1289 const TField *field = fields[i];
1290 if (writeVariablePrecision(field->type()->getPrecision()))
1291 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001292 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Geoff Langbdcc54a2015-09-02 13:09:48 -04001293 if (field->type()->isArray())
1294 out << arrayBrackets(*field->type());
1295 out << ";\n";
1296 }
1297 out << "}";
1298}
Jamie Madill45bcc782016-11-07 13:58:48 -05001299
1300} // namespace sh