blob: 790a1bf44884bb131fe7dd4bbabb740acde3b5c0 [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 Etuahoe1805592017-01-02 16:41:20 +0000146 TString opStr(GetOperatorString(op));
147 opStr += "(";
148 if (useEmulatedFunction)
149 {
150 opStr = BuiltInFunctionEmulator::GetEmulatedFunctionName(opStr);
151 }
152 writeTriplet(visit, opStr.c_str(), ", ", ")");
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700153}
154
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300155void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
156{
Martin Radev2cc85b32016-08-05 16:22:53 +0300157 if (!NeedsToWriteLayoutQualifier(type))
158 {
159 return;
160 }
161
162 TInfoSinkBase &out = objSink();
163 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
164 out << "layout(";
165
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300166 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
167 {
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300168 if (layoutQualifier.location >= 0)
169 {
Martin Radev2cc85b32016-08-05 16:22:53 +0300170 out << "location = " << layoutQualifier.location;
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300171 }
172 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300173
174 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
175 {
176 ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
177 out << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
178 }
179
180 out << ") ";
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300181}
182
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800183const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier)
184{
185 if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 &&
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000186 (mCompileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0)
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800187 {
188 switch (qualifier)
189 {
190 // The return string is consistent with sh::getQualifierString() from
191 // BaseTypes.h minus the "centroid" keyword.
192 case EvqCentroid:
193 return "";
194 case EvqCentroidIn:
195 return "smooth in";
196 case EvqCentroidOut:
197 return "smooth out";
198 default:
199 break;
200 }
201 }
202 if (sh::IsGLSL130OrNewer(mOutput))
203 {
204 switch (qualifier)
205 {
206 case EvqAttribute:
207 return "in";
208 case EvqVaryingIn:
209 return "in";
210 case EvqVaryingOut:
211 return "out";
212 default:
213 break;
214 }
215 }
216 return sh::getQualifierString(qualifier);
217}
218
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700219void TOutputGLSLBase::writeVariableType(const TType &type)
220{
Qiankun Miao705a9192016-08-29 10:05:27 +0800221 TQualifier qualifier = type.getQualifier();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500222 TInfoSinkBase &out = objSink();
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800223 if (type.isInvariant())
Olli Etuaho214c2d82015-04-27 14:49:13 +0300224 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800225 writeInvariantQualifier(type);
Olli Etuaho214c2d82015-04-27 14:49:13 +0300226 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400227 if (type.getBasicType() == EbtInterfaceBlock)
228 {
229 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
230 declareInterfaceBlockLayout(interfaceBlock);
231 }
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400232 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400233 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800234 const char *qualifierString = mapQualifierToString(qualifier);
235 if (qualifierString && qualifierString[0] != '\0')
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800236 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800237 out << qualifierString << " ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800238 }
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400239 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300240
241 const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
242 if (memoryQualifier.readonly)
243 {
244 ASSERT(IsImage(type.getBasicType()));
245 out << "readonly ";
246 }
247
248 if (memoryQualifier.writeonly)
249 {
250 ASSERT(IsImage(type.getBasicType()));
251 out << "writeonly ";
252 }
253
Martin Radev049edfa2016-11-11 14:35:37 +0200254 if (memoryQualifier.coherent)
255 {
256 ASSERT(IsImage(type.getBasicType()));
257 out << "coherent ";
258 }
259
260 if (memoryQualifier.restrictQualifier)
261 {
262 ASSERT(IsImage(type.getBasicType()));
263 out << "restrict ";
264 }
265
266 if (memoryQualifier.volatileQualifier)
267 {
268 ASSERT(IsImage(type.getBasicType()));
269 out << "volatile ";
270 }
271
zmo@google.com5601ea02011-06-10 18:23:25 +0000272 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700273 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000274 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400275 TStructure *structure = type.getStruct();
276
277 declareStruct(structure);
278
279 if (!structure->name().empty())
280 {
281 mDeclaredStructs.insert(structure->uniqueId());
282 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000283 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400284 else if (type.getBasicType() == EbtInterfaceBlock)
285 {
286 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
287 declareInterfaceBlock(interfaceBlock);
288 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000289 else
290 {
291 if (writeVariablePrecision(type.getPrecision()))
292 out << " ";
293 out << getTypeName(type);
294 }
295}
296
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700297void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000298{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700299 TInfoSinkBase &out = objSink();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500300 for (TIntermSequence::const_iterator iter = args.begin(); iter != args.end(); ++iter)
zmo@google.com5601ea02011-06-10 18:23:25 +0000301 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700302 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000303 ASSERT(arg != NULL);
304
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700305 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000306 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000307
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000308 if (!arg->getName().getString().empty())
309 out << " " << hashName(arg->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000310 if (type.isArray())
311 out << arrayBrackets(type);
312
313 // Put a comma if this is not the last argument.
314 if (iter != args.end() - 1)
315 out << ", ";
316 }
317}
318
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500319const TConstantUnion *TOutputGLSLBase::writeConstantUnion(const TType &type,
320 const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000321{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700322 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000323
324 if (type.getBasicType() == EbtStruct)
325 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700326 const TStructure *structure = type.getStruct();
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000327 out << hashName(TName(structure->name())) << "(";
Jamie Madill98493dd2013-07-08 14:39:03 -0400328
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700329 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400330 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000331 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700332 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000333 ASSERT(fieldType != NULL);
334 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700335 if (i != fields.size() - 1)
336 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000337 }
338 out << ")";
339 }
340 else
341 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500342 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000343 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700344 if (writeType)
345 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400346 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000347 {
348 switch (pConstUnion->getType())
349 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500350 case EbtFloat:
351 writeFloat(out, pConstUnion->getFConst());
352 break;
353 case EbtInt:
354 out << pConstUnion->getIConst();
355 break;
356 case EbtUInt:
357 out << pConstUnion->getUConst() << "u";
358 break;
359 case EbtBool:
360 out << pConstUnion->getBConst();
361 break;
362 default:
363 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000364 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700365 if (i != size - 1)
366 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000367 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700368 if (writeType)
369 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000370 }
371 return pConstUnion;
372}
373
Olli Etuahoe92507b2016-07-04 11:20:10 +0300374void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
Olli Etuahof40319e2015-03-10 14:33:00 +0200375{
376 TInfoSinkBase &out = objSink();
377 if (visit == PreVisit)
378 {
379 if (type.isArray())
380 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300381 out << getTypeName(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200382 out << arrayBrackets(type);
383 out << "(";
384 }
385 else
386 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300387 out << getTypeName(type) << "(";
Olli Etuahof40319e2015-03-10 14:33:00 +0200388 }
389 }
390 else
391 {
392 writeTriplet(visit, nullptr, ", ", ")");
393 }
394}
395
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700396void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000397{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700398 TInfoSinkBase &out = objSink();
Corentin Wallez1b896c62016-11-16 13:10:44 -0500399 out << hashVariableName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000400
401 if (mDeclaringVariables && node->getType().isArray())
402 out << arrayBrackets(node->getType());
403}
404
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700405void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000406{
407 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
408}
409
Olli Etuahob6fa0432016-09-28 16:28:05 +0100410bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
411{
412 TInfoSinkBase &out = objSink();
413 if (visit == PostVisit)
414 {
415 out << ".";
416 node->writeOffsetsAsXYZW(&out);
417 }
418 return true;
419}
420
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700421bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000422{
423 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700424 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000425 switch (node->getOp())
426 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100427 case EOpComma:
428 writeTriplet(visit, "(", ", ", ")");
429 break;
430 case EOpInitialize:
zmo@google.com5601ea02011-06-10 18:23:25 +0000431 if (visit == InVisit)
432 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100433 out << " = ";
434 // RHS of initialize is not being declared.
435 mDeclaringVariables = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000436 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100437 break;
438 case EOpAssign:
439 writeTriplet(visit, "(", " = ", ")");
440 break;
441 case EOpAddAssign:
442 writeTriplet(visit, "(", " += ", ")");
443 break;
444 case EOpSubAssign:
445 writeTriplet(visit, "(", " -= ", ")");
446 break;
447 case EOpDivAssign:
448 writeTriplet(visit, "(", " /= ", ")");
449 break;
450 case EOpIModAssign:
451 writeTriplet(visit, "(", " %= ", ")");
452 break;
453 // Notice the fall-through.
454 case EOpMulAssign:
455 case EOpVectorTimesMatrixAssign:
456 case EOpVectorTimesScalarAssign:
457 case EOpMatrixTimesScalarAssign:
458 case EOpMatrixTimesMatrixAssign:
459 writeTriplet(visit, "(", " *= ", ")");
460 break;
461 case EOpBitShiftLeftAssign:
462 writeTriplet(visit, "(", " <<= ", ")");
463 break;
464 case EOpBitShiftRightAssign:
465 writeTriplet(visit, "(", " >>= ", ")");
466 break;
467 case EOpBitwiseAndAssign:
468 writeTriplet(visit, "(", " &= ", ")");
469 break;
470 case EOpBitwiseXorAssign:
471 writeTriplet(visit, "(", " ^= ", ")");
472 break;
473 case EOpBitwiseOrAssign:
474 writeTriplet(visit, "(", " |= ", ")");
475 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000476
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100477 case EOpIndexDirect:
zmo@google.com5601ea02011-06-10 18:23:25 +0000478 writeTriplet(visit, NULL, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100479 break;
480 case EOpIndexIndirect:
481 if (node->getAddIndexClamp())
482 {
483 if (visit == InVisit)
484 {
485 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
486 out << "[int(clamp(float(";
487 else
488 out << "[webgl_int_clamp(";
489 }
490 else if (visit == PostVisit)
491 {
492 int maxSize;
493 TIntermTyped *left = node->getLeft();
494 TType leftType = left->getType();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700495
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100496 if (left->isArray())
497 {
498 // The shader will fail validation if the array length is not > 0.
499 maxSize = static_cast<int>(leftType.getArraySize()) - 1;
500 }
501 else
502 {
503 maxSize = leftType.getNominalSize() - 1;
504 }
505
506 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
507 out << "), 0.0, float(" << maxSize << ")))]";
508 else
509 out << ", 0, " << maxSize << ")]";
510 }
511 }
512 else
513 {
514 writeTriplet(visit, NULL, "[", "]");
515 }
516 break;
517 case EOpIndexDirectStruct:
518 if (visit == InVisit)
519 {
520 // Here we are writing out "foo.bar", where "foo" is struct
521 // and "bar" is field. In AST, it is represented as a binary
522 // node, where left child represents "foo" and right child "bar".
523 // The node itself represents ".". The struct field "bar" is
524 // actually stored as an index into TStructure::fields.
525 out << ".";
526 const TStructure *structure = node->getLeft()->getType().getStruct();
527 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
528 const TField *field = structure->fields()[index->getIConst(0)];
529
530 TString fieldName = field->name();
531 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000532 fieldName = hashName(TName(fieldName));
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100533
534 out << fieldName;
535 visitChildren = false;
536 }
537 break;
538 case EOpIndexDirectInterfaceBlock:
539 if (visit == InVisit)
540 {
541 out << ".";
542 const TInterfaceBlock *interfaceBlock =
543 node->getLeft()->getType().getInterfaceBlock();
544 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
545 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
546
547 TString fieldName = field->name();
548 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000549 fieldName = hashName(TName(fieldName));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700550
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100551 out << fieldName;
552 visitChildren = false;
553 }
554 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400555
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100556 case EOpAdd:
557 writeTriplet(visit, "(", " + ", ")");
558 break;
559 case EOpSub:
560 writeTriplet(visit, "(", " - ", ")");
561 break;
562 case EOpMul:
563 writeTriplet(visit, "(", " * ", ")");
564 break;
565 case EOpDiv:
566 writeTriplet(visit, "(", " / ", ")");
567 break;
568 case EOpIMod:
569 writeTriplet(visit, "(", " % ", ")");
570 break;
571 case EOpBitShiftLeft:
572 writeTriplet(visit, "(", " << ", ")");
573 break;
574 case EOpBitShiftRight:
575 writeTriplet(visit, "(", " >> ", ")");
576 break;
577 case EOpBitwiseAnd:
578 writeTriplet(visit, "(", " & ", ")");
579 break;
580 case EOpBitwiseXor:
581 writeTriplet(visit, "(", " ^ ", ")");
582 break;
583 case EOpBitwiseOr:
584 writeTriplet(visit, "(", " | ", ")");
585 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400586
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100587 case EOpEqual:
588 writeTriplet(visit, "(", " == ", ")");
589 break;
590 case EOpNotEqual:
591 writeTriplet(visit, "(", " != ", ")");
592 break;
593 case EOpLessThan:
594 writeTriplet(visit, "(", " < ", ")");
595 break;
596 case EOpGreaterThan:
597 writeTriplet(visit, "(", " > ", ")");
598 break;
599 case EOpLessThanEqual:
600 writeTriplet(visit, "(", " <= ", ")");
601 break;
602 case EOpGreaterThanEqual:
603 writeTriplet(visit, "(", " >= ", ")");
604 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000605
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100606 // Notice the fall-through.
607 case EOpVectorTimesScalar:
608 case EOpVectorTimesMatrix:
609 case EOpMatrixTimesVector:
610 case EOpMatrixTimesScalar:
611 case EOpMatrixTimesMatrix:
612 writeTriplet(visit, "(", " * ", ")");
613 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200614
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100615 case EOpLogicalOr:
616 writeTriplet(visit, "(", " || ", ")");
617 break;
618 case EOpLogicalXor:
619 writeTriplet(visit, "(", " ^^ ", ")");
620 break;
621 case EOpLogicalAnd:
622 writeTriplet(visit, "(", " && ", ")");
623 break;
624 default:
625 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000626 }
627
628 return visitChildren;
629}
630
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700631bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000632{
zmo@google.com32e97312011-08-24 01:03:11 +0000633 TString preString;
634 TString postString = ")";
635
zmo@google.com5601ea02011-06-10 18:23:25 +0000636 switch (node->getOp())
637 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500638 case EOpNegative:
639 preString = "(-";
640 break;
641 case EOpPositive:
642 preString = "(+";
643 break;
644 case EOpVectorLogicalNot:
645 preString = "not(";
646 break;
647 case EOpLogicalNot:
648 preString = "(!";
649 break;
650 case EOpBitwiseNot:
651 preString = "(~";
652 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000653
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500654 case EOpPostIncrement:
655 preString = "(";
656 postString = "++)";
657 break;
658 case EOpPostDecrement:
659 preString = "(";
660 postString = "--)";
661 break;
662 case EOpPreIncrement:
663 preString = "(++";
664 break;
665 case EOpPreDecrement:
666 preString = "(--";
667 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000668
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500669 case EOpRadians:
670 preString = "radians(";
671 break;
672 case EOpDegrees:
673 preString = "degrees(";
674 break;
675 case EOpSin:
676 preString = "sin(";
677 break;
678 case EOpCos:
679 preString = "cos(";
680 break;
681 case EOpTan:
682 preString = "tan(";
683 break;
684 case EOpAsin:
685 preString = "asin(";
686 break;
687 case EOpAcos:
688 preString = "acos(";
689 break;
690 case EOpAtan:
691 preString = "atan(";
692 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000693
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500694 case EOpSinh:
695 preString = "sinh(";
696 break;
697 case EOpCosh:
698 preString = "cosh(";
699 break;
700 case EOpTanh:
701 preString = "tanh(";
702 break;
703 case EOpAsinh:
704 preString = "asinh(";
705 break;
706 case EOpAcosh:
707 preString = "acosh(";
708 break;
709 case EOpAtanh:
710 preString = "atanh(";
711 break;
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200712
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500713 case EOpExp:
714 preString = "exp(";
715 break;
716 case EOpLog:
717 preString = "log(";
718 break;
719 case EOpExp2:
720 preString = "exp2(";
721 break;
722 case EOpLog2:
723 preString = "log2(";
724 break;
725 case EOpSqrt:
726 preString = "sqrt(";
727 break;
728 case EOpInverseSqrt:
729 preString = "inversesqrt(";
730 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000731
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500732 case EOpAbs:
733 preString = "abs(";
734 break;
735 case EOpSign:
736 preString = "sign(";
737 break;
738 case EOpFloor:
739 preString = "floor(";
740 break;
741 case EOpTrunc:
742 preString = "trunc(";
743 break;
744 case EOpRound:
745 preString = "round(";
746 break;
747 case EOpRoundEven:
748 preString = "roundEven(";
749 break;
750 case EOpCeil:
751 preString = "ceil(";
752 break;
753 case EOpFract:
754 preString = "fract(";
755 break;
756 case EOpIsNan:
757 preString = "isnan(";
758 break;
759 case EOpIsInf:
760 preString = "isinf(";
761 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000762
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500763 case EOpFloatBitsToInt:
764 preString = "floatBitsToInt(";
765 break;
766 case EOpFloatBitsToUint:
767 preString = "floatBitsToUint(";
768 break;
769 case EOpIntBitsToFloat:
770 preString = "intBitsToFloat(";
771 break;
772 case EOpUintBitsToFloat:
773 preString = "uintBitsToFloat(";
774 break;
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200775
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500776 case EOpPackSnorm2x16:
777 preString = "packSnorm2x16(";
778 break;
779 case EOpPackUnorm2x16:
780 preString = "packUnorm2x16(";
781 break;
782 case EOpPackHalf2x16:
783 preString = "packHalf2x16(";
784 break;
785 case EOpUnpackSnorm2x16:
786 preString = "unpackSnorm2x16(";
787 break;
788 case EOpUnpackUnorm2x16:
789 preString = "unpackUnorm2x16(";
790 break;
791 case EOpUnpackHalf2x16:
792 preString = "unpackHalf2x16(";
793 break;
Olli Etuaho7700ff62015-01-15 12:16:29 +0200794
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500795 case EOpLength:
796 preString = "length(";
797 break;
798 case EOpNormalize:
799 preString = "normalize(";
800 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000801
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500802 case EOpDFdx:
803 preString = "dFdx(";
804 break;
805 case EOpDFdy:
806 preString = "dFdy(";
807 break;
808 case EOpFwidth:
809 preString = "fwidth(";
810 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000811
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500812 case EOpTranspose:
813 preString = "transpose(";
814 break;
815 case EOpDeterminant:
816 preString = "determinant(";
817 break;
818 case EOpInverse:
819 preString = "inverse(";
820 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200821
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500822 case EOpAny:
823 preString = "any(";
824 break;
825 case EOpAll:
826 preString = "all(";
827 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000828
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500829 default:
830 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000831 }
832
zmo@google.com32e97312011-08-24 01:03:11 +0000833 if (visit == PreVisit && node->getUseEmulatedFunction())
834 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
835 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
836
zmo@google.com5601ea02011-06-10 18:23:25 +0000837 return true;
838}
839
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300840bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
841{
842 TInfoSinkBase &out = objSink();
843 // Notice two brackets at the beginning and end. The outer ones
844 // encapsulate the whole ternary expression. This preserves the
845 // order of precedence when ternary expressions are used in a
846 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
847 out << "((";
848 node->getCondition()->traverse(this);
849 out << ") ? (";
850 node->getTrueExpression()->traverse(this);
851 out << ") : (";
852 node->getFalseExpression()->traverse(this);
853 out << "))";
854 return false;
855}
856
Olli Etuaho57961272016-09-14 13:57:46 +0300857bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000858{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700859 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000860
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300861 out << "if (";
862 node->getCondition()->traverse(this);
863 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000864
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300865 incrementDepth(node);
866 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000867
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300868 if (node->getFalseBlock())
869 {
870 out << "else\n";
871 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000872 }
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300873 decrementDepth();
zmo@google.com5601ea02011-06-10 18:23:25 +0000874 return false;
875}
876
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200877bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200878{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200879 if (node->getStatementList())
880 {
881 writeTriplet(visit, "switch (", ") ", nullptr);
882 // The curly braces get written when visiting the statementList aggregate
883 }
884 else
885 {
886 // No statementList, so it won't output curly braces
887 writeTriplet(visit, "switch (", ") {", "}\n");
888 }
889 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200890}
891
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200892bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200893{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200894 if (node->hasCondition())
895 {
896 writeTriplet(visit, "case (", nullptr, "):\n");
897 return true;
898 }
899 else
900 {
901 TInfoSinkBase &out = objSink();
902 out << "default:\n";
903 return false;
904 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200905}
906
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100907bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
908{
909 TInfoSinkBase &out = objSink();
910 // Scope the blocks except when at the global scope.
911 if (mDepth > 0)
912 {
913 out << "{\n";
914 }
915
916 incrementDepth(node);
917 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
918 iter != node->getSequence()->end(); ++iter)
919 {
920 TIntermNode *curNode = *iter;
921 ASSERT(curNode != nullptr);
922 curNode->traverse(this);
923
924 if (isSingleStatement(curNode))
925 out << ";\n";
926 }
927 decrementDepth();
928
929 // Scope the blocks except when at the global scope.
930 if (mDepth > 0)
931 {
932 out << "}\n";
933 }
934 return false;
935}
936
Olli Etuaho336b1472016-10-05 16:37:55 +0100937bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
938{
939 TInfoSinkBase &out = objSink();
940
941 ASSERT(visit == PreVisit);
942 {
943 const TType &type = node->getType();
944 writeVariableType(type);
945 if (type.isArray())
946 out << arrayBrackets(type);
947 }
948
949 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
950
951 incrementDepth(node);
952
953 // Traverse function parameters.
954 TIntermAggregate *params = node->getFunctionParameters()->getAsAggregate();
955 ASSERT(params->getOp() == EOpParameters);
956 params->traverse(this);
957
958 // Traverse function body.
959 visitCodeBlock(node->getBody());
960 decrementDepth();
961
962 // Fully processed; no need to visit children.
963 return false;
964}
965
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000966bool TOutputGLSLBase::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
967{
968 TInfoSinkBase &out = objSink();
969 ASSERT(visit == PreVisit);
970 const TIntermSymbol *symbol = node->getSymbol();
971 out << "invariant " << hashVariableName(symbol->getName());
972 return false;
973}
974
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700975bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000976{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500977 bool visitChildren = true;
978 TInfoSinkBase &out = objSink();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700979 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000980 switch (node->getOp())
981 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500982 case EOpPrototype:
983 // Function declaration.
984 ASSERT(visit == PreVisit);
985 {
986 const TType &type = node->getType();
987 writeVariableType(type);
988 if (type.isArray())
989 out << arrayBrackets(type);
990 }
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300991
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500992 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700993
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500994 out << "(";
995 writeFunctionParameters(*(node->getSequence()));
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200996 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000997
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500998 visitChildren = false;
999 break;
1000 case EOpFunctionCall:
1001 // Function call.
1002 if (visit == PreVisit)
1003 out << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
1004 else if (visit == InVisit)
1005 out << ", ";
1006 else
1007 out << ")";
1008 break;
1009 case EOpParameters:
1010 // Function parameters.
1011 ASSERT(visit == PreVisit);
1012 out << "(";
1013 writeFunctionParameters(*(node->getSequence()));
1014 out << ")";
1015 visitChildren = false;
1016 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001017 case EOpConstructFloat:
1018 case EOpConstructVec2:
1019 case EOpConstructVec3:
1020 case EOpConstructVec4:
1021 case EOpConstructBool:
1022 case EOpConstructBVec2:
1023 case EOpConstructBVec3:
1024 case EOpConstructBVec4:
1025 case EOpConstructInt:
1026 case EOpConstructIVec2:
1027 case EOpConstructIVec3:
1028 case EOpConstructIVec4:
1029 case EOpConstructUInt:
1030 case EOpConstructUVec2:
1031 case EOpConstructUVec3:
1032 case EOpConstructUVec4:
1033 case EOpConstructMat2:
1034 case EOpConstructMat2x3:
1035 case EOpConstructMat2x4:
1036 case EOpConstructMat3x2:
1037 case EOpConstructMat3:
1038 case EOpConstructMat3x4:
1039 case EOpConstructMat4x2:
1040 case EOpConstructMat4x3:
1041 case EOpConstructMat4:
1042 case EOpConstructStruct:
1043 writeConstructorTriplet(visit, node->getType());
1044 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001045
Olli Etuahoe1805592017-01-02 16:41:20 +00001046 case EOpEqualComponentWise:
1047 case EOpNotEqualComponentWise:
1048 case EOpLessThanComponentWise:
1049 case EOpGreaterThanComponentWise:
1050 case EOpLessThanEqualComponentWise:
1051 case EOpGreaterThanEqualComponentWise:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001052 case EOpMod:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001053 case EOpModf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001054 case EOpPow:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001055 case EOpAtan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001056 case EOpMin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001057 case EOpMax:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001058 case EOpClamp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001059 case EOpMix:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001060 case EOpStep:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001061 case EOpSmoothStep:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001062 case EOpDistance:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001063 case EOpDot:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001064 case EOpCross:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001065 case EOpFaceForward:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001066 case EOpReflect:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001067 case EOpRefract:
Olli Etuahoe1805592017-01-02 16:41:20 +00001068 case EOpMulMatrixComponentWise:
1069 case EOpOuterProduct:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001070 case EOpBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001071 case EOpMemoryBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001072 case EOpMemoryBarrierAtomicCounter:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001073 case EOpMemoryBarrierBuffer:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001074 case EOpMemoryBarrierImage:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001075 case EOpMemoryBarrierShared:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001076 case EOpGroupMemoryBarrier:
Olli Etuahoe1805592017-01-02 16:41:20 +00001077 writeBuiltInFunctionTriplet(visit, node->getOp(), useEmulatedFunction);
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001078 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001079 default:
1080 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001081 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001082 return visitChildren;
1083}
1084
Olli Etuaho13389b62016-10-16 11:48:18 +01001085bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
1086{
1087 TInfoSinkBase &out = objSink();
1088
1089 // Variable declaration.
1090 if (visit == PreVisit)
1091 {
1092 const TIntermSequence &sequence = *(node->getSequence());
1093 const TIntermTyped *variable = sequence.front()->getAsTyped();
1094 writeLayoutQualifier(variable->getType());
1095 writeVariableType(variable->getType());
1096 out << " ";
1097 mDeclaringVariables = true;
1098 }
1099 else if (visit == InVisit)
1100 {
1101 out << ", ";
1102 mDeclaringVariables = true;
1103 }
1104 else
1105 {
1106 mDeclaringVariables = false;
1107 }
1108 return true;
1109}
1110
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001111bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001112{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001113 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001114
Zhenyao Mo7cab38b2013-10-15 12:59:30 -07001115 incrementDepth(node);
Corentin Wallez7258e302015-09-22 10:40:24 -07001116
zmo@google.com5601ea02011-06-10 18:23:25 +00001117 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001118
zmo@google.com5601ea02011-06-10 18:23:25 +00001119 if (loopType == ELoopFor) // for loop
1120 {
Corentin Wallez1b896c62016-11-16 13:10:44 -05001121 out << "for (";
1122 if (node->getInit())
1123 node->getInit()->traverse(this);
1124 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001125
Corentin Wallez1b896c62016-11-16 13:10:44 -05001126 if (node->getCondition())
1127 node->getCondition()->traverse(this);
1128 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001129
Corentin Wallez1b896c62016-11-16 13:10:44 -05001130 if (node->getExpression())
1131 node->getExpression()->traverse(this);
1132 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001133
Corentin Wallez1b896c62016-11-16 13:10:44 -05001134 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001135 }
1136 else if (loopType == ELoopWhile) // while loop
1137 {
1138 out << "while (";
1139 ASSERT(node->getCondition() != NULL);
1140 node->getCondition()->traverse(this);
1141 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001142
1143 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001144 }
1145 else // do-while loop
1146 {
1147 ASSERT(loopType == ELoopDoWhile);
1148 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001149
zmo@google.com5601ea02011-06-10 18:23:25 +00001150 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001151
zmo@google.com5601ea02011-06-10 18:23:25 +00001152 out << "while (";
1153 ASSERT(node->getCondition() != NULL);
1154 node->getCondition()->traverse(this);
1155 out << ");\n";
1156 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001157
zmo@google.com5601ea02011-06-10 18:23:25 +00001158 decrementDepth();
1159
1160 // No need to visit children. They have been already processed in
1161 // this function.
1162 return false;
1163}
1164
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001165bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001166{
1167 switch (node->getFlowOp())
1168 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001169 case EOpKill:
1170 writeTriplet(visit, "discard", NULL, NULL);
1171 break;
1172 case EOpBreak:
1173 writeTriplet(visit, "break", NULL, NULL);
1174 break;
1175 case EOpContinue:
1176 writeTriplet(visit, "continue", NULL, NULL);
1177 break;
1178 case EOpReturn:
1179 writeTriplet(visit, "return ", NULL, NULL);
1180 break;
1181 default:
1182 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001183 }
1184
1185 return true;
1186}
1187
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001188void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001189{
zmo@google.com5601ea02011-06-10 18:23:25 +00001190 TInfoSinkBase &out = objSink();
1191 if (node != NULL)
1192 {
1193 node->traverse(this);
1194 // Single statements not part of a sequence need to be terminated
1195 // with semi-colon.
1196 if (isSingleStatement(node))
1197 out << ";\n";
1198 }
1199 else
1200 {
1201 out << "{\n}\n"; // Empty code block.
1202 }
1203}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001204
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001205TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001206{
Olli Etuahoe92507b2016-07-04 11:20:10 +03001207 if (type.getBasicType() == EbtStruct)
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001208 return hashName(TName(type.getStruct()->name()));
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001209 else
Olli Etuahoe92507b2016-07-04 11:20:10 +03001210 return type.getBuiltInTypeNameString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001211}
1212
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001213TString TOutputGLSLBase::hashName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001214{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001215 if (name.getString().empty())
1216 {
1217 ASSERT(!name.isInternal());
1218 return name.getString();
1219 }
1220 if (name.isInternal())
1221 {
1222 // TODO(oetuaho): Would be nicer to prefix non-internal names with "_" instead, like is
1223 // done in the HLSL output, but that requires fairly complex changes elsewhere in the code
1224 // as well.
1225 // We need to use a prefix that is reserved in WebGL in order to guarantee that the internal
1226 // names don't conflict with user-defined names from WebGL.
1227 return "webgl_angle_" + name.getString();
1228 }
1229 if (mHashFunction == nullptr)
1230 {
1231 return name.getString();
1232 }
1233 NameMap::const_iterator it = mNameMap.find(name.getString().c_str());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001234 if (it != mNameMap.end())
1235 return it->second.c_str();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001236 TString hashedName = TIntermTraverser::hash(name.getString(), mHashFunction);
1237 mNameMap[name.getString().c_str()] = hashedName.c_str();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001238 return hashedName;
1239}
1240
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001241TString TOutputGLSLBase::hashVariableName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001242{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001243 if (mSymbolTable.findBuiltIn(name.getString(), mShaderVersion) != NULL)
Olli Etuaho09b04a22016-12-15 13:30:26 +00001244 {
1245 if (mCompileOptions & SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM &&
1246 name.getString() == "gl_ViewID_OVR")
1247 {
1248 TName uniformName(TString("ViewId_OVR"));
1249 uniformName.setInternal(true);
1250 return hashName(uniformName);
1251 }
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001252 return name.getString();
Olli Etuaho09b04a22016-12-15 13:30:26 +00001253 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001254 return hashName(name);
1255}
1256
Olli Etuaho59f9a642015-08-06 20:38:26 +03001257TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001258{
Olli Etuaho59f9a642015-08-06 20:38:26 +03001259 TString mangledStr = mangledName.getString();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001260 TString name = TFunction::unmangleName(mangledStr);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001261 if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001262 return translateTextureFunction(name);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001263 if (mangledName.isInternal())
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001264 {
1265 // Internal function names are outputted as-is - they may refer to functions manually added
1266 // to the output shader source that are not included in the AST at all.
Olli Etuaho59f9a642015-08-06 20:38:26 +03001267 return name;
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001268 }
Olli Etuaho59f9a642015-08-06 20:38:26 +03001269 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001270 {
1271 TName nameObj(name);
1272 return hashName(nameObj);
1273 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001274}
Jamie Madill98493dd2013-07-08 14:39:03 -04001275
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001276bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001277{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001278 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001279 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001280 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001281 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001282 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001283
1284 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001285}
1286
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001287void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001288{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001289 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001290
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001291 out << "struct " << hashName(TName(structure->name())) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001292 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001293 for (size_t i = 0; i < fields.size(); ++i)
1294 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001295 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001296 if (writeVariablePrecision(field->type()->getPrecision()))
1297 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001298 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Jamie Madill98493dd2013-07-08 14:39:03 -04001299 if (field->type()->isArray())
1300 out << arrayBrackets(*field->type());
1301 out << ";\n";
1302 }
1303 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001304}
Jamie Madill98493dd2013-07-08 14:39:03 -04001305
Geoff Langbdcc54a2015-09-02 13:09:48 -04001306void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1307{
1308 TInfoSinkBase &out = objSink();
1309
1310 out << "layout(";
1311
1312 switch (interfaceBlock->blockStorage())
1313 {
1314 case EbsUnspecified:
1315 case EbsShared:
1316 // Default block storage is shared.
1317 out << "shared";
1318 break;
1319
1320 case EbsPacked:
1321 out << "packed";
1322 break;
1323
1324 case EbsStd140:
1325 out << "std140";
1326 break;
1327
1328 default:
1329 UNREACHABLE();
1330 break;
1331 }
1332
1333 out << ", ";
1334
1335 switch (interfaceBlock->matrixPacking())
1336 {
1337 case EmpUnspecified:
1338 case EmpColumnMajor:
1339 // Default matrix packing is column major.
1340 out << "column_major";
1341 break;
1342
1343 case EmpRowMajor:
1344 out << "row_major";
1345 break;
1346
1347 default:
1348 UNREACHABLE();
1349 break;
1350 }
1351
1352 out << ") ";
1353}
1354
1355void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1356{
1357 TInfoSinkBase &out = objSink();
1358
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001359 out << hashName(TName(interfaceBlock->name())) << "{\n";
Geoff Langbdcc54a2015-09-02 13:09:48 -04001360 const TFieldList &fields = interfaceBlock->fields();
1361 for (size_t i = 0; i < fields.size(); ++i)
1362 {
1363 const TField *field = fields[i];
1364 if (writeVariablePrecision(field->type()->getPrecision()))
1365 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001366 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Geoff Langbdcc54a2015-09-02 13:09:48 -04001367 if (field->type()->isArray())
1368 out << arrayBrackets(*field->type());
1369 out << ";\n";
1370 }
1371 out << "}";
1372}
Jamie Madill45bcc782016-11-07 13:58:48 -05001373
1374} // namespace sh