blob: 9256faa5a12bfe4f757c05dfb5f02361c245acc5 [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,
143 const char *preStr,
144 bool useEmulatedFunction)
zmo@google.com5601ea02011-06-10 18:23:25 +0000145{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500146 TString preString =
147 useEmulatedFunction ? BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700148 writeTriplet(visit, preString.c_str(), ", ", ")");
149}
150
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300151void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
152{
Martin Radev2cc85b32016-08-05 16:22:53 +0300153 if (!NeedsToWriteLayoutQualifier(type))
154 {
155 return;
156 }
157
158 TInfoSinkBase &out = objSink();
159 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
160 out << "layout(";
161
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300162 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
163 {
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300164 if (layoutQualifier.location >= 0)
165 {
Martin Radev2cc85b32016-08-05 16:22:53 +0300166 out << "location = " << layoutQualifier.location;
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300167 }
168 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300169
170 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
171 {
172 ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
173 out << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
174 }
175
176 out << ") ";
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300177}
178
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800179const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier)
180{
181 if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 &&
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000182 (mCompileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0)
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800183 {
184 switch (qualifier)
185 {
186 // The return string is consistent with sh::getQualifierString() from
187 // BaseTypes.h minus the "centroid" keyword.
188 case EvqCentroid:
189 return "";
190 case EvqCentroidIn:
191 return "smooth in";
192 case EvqCentroidOut:
193 return "smooth out";
194 default:
195 break;
196 }
197 }
198 if (sh::IsGLSL130OrNewer(mOutput))
199 {
200 switch (qualifier)
201 {
202 case EvqAttribute:
203 return "in";
204 case EvqVaryingIn:
205 return "in";
206 case EvqVaryingOut:
207 return "out";
208 default:
209 break;
210 }
211 }
212 return sh::getQualifierString(qualifier);
213}
214
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700215void TOutputGLSLBase::writeVariableType(const TType &type)
216{
Qiankun Miao705a9192016-08-29 10:05:27 +0800217 TQualifier qualifier = type.getQualifier();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500218 TInfoSinkBase &out = objSink();
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800219 if (type.isInvariant())
Olli Etuaho214c2d82015-04-27 14:49:13 +0300220 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800221 writeInvariantQualifier(type);
Olli Etuaho214c2d82015-04-27 14:49:13 +0300222 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400223 if (type.getBasicType() == EbtInterfaceBlock)
224 {
225 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
226 declareInterfaceBlockLayout(interfaceBlock);
227 }
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400228 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400229 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800230 const char *qualifierString = mapQualifierToString(qualifier);
231 if (qualifierString && qualifierString[0] != '\0')
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800232 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800233 out << qualifierString << " ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800234 }
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400235 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300236
237 const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
238 if (memoryQualifier.readonly)
239 {
240 ASSERT(IsImage(type.getBasicType()));
241 out << "readonly ";
242 }
243
244 if (memoryQualifier.writeonly)
245 {
246 ASSERT(IsImage(type.getBasicType()));
247 out << "writeonly ";
248 }
249
Martin Radev049edfa2016-11-11 14:35:37 +0200250 if (memoryQualifier.coherent)
251 {
252 ASSERT(IsImage(type.getBasicType()));
253 out << "coherent ";
254 }
255
256 if (memoryQualifier.restrictQualifier)
257 {
258 ASSERT(IsImage(type.getBasicType()));
259 out << "restrict ";
260 }
261
262 if (memoryQualifier.volatileQualifier)
263 {
264 ASSERT(IsImage(type.getBasicType()));
265 out << "volatile ";
266 }
267
zmo@google.com5601ea02011-06-10 18:23:25 +0000268 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700269 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000270 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400271 TStructure *structure = type.getStruct();
272
273 declareStruct(structure);
274
275 if (!structure->name().empty())
276 {
277 mDeclaredStructs.insert(structure->uniqueId());
278 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000279 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400280 else if (type.getBasicType() == EbtInterfaceBlock)
281 {
282 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
283 declareInterfaceBlock(interfaceBlock);
284 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000285 else
286 {
287 if (writeVariablePrecision(type.getPrecision()))
288 out << " ";
289 out << getTypeName(type);
290 }
291}
292
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700293void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000294{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700295 TInfoSinkBase &out = objSink();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500296 for (TIntermSequence::const_iterator iter = args.begin(); iter != args.end(); ++iter)
zmo@google.com5601ea02011-06-10 18:23:25 +0000297 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700298 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000299 ASSERT(arg != NULL);
300
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700301 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000302 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000303
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000304 if (!arg->getName().getString().empty())
305 out << " " << hashName(arg->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000306 if (type.isArray())
307 out << arrayBrackets(type);
308
309 // Put a comma if this is not the last argument.
310 if (iter != args.end() - 1)
311 out << ", ";
312 }
313}
314
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500315const TConstantUnion *TOutputGLSLBase::writeConstantUnion(const TType &type,
316 const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000317{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700318 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000319
320 if (type.getBasicType() == EbtStruct)
321 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700322 const TStructure *structure = type.getStruct();
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000323 out << hashName(TName(structure->name())) << "(";
Jamie Madill98493dd2013-07-08 14:39:03 -0400324
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700325 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400326 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000327 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700328 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000329 ASSERT(fieldType != NULL);
330 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700331 if (i != fields.size() - 1)
332 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000333 }
334 out << ")";
335 }
336 else
337 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500338 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000339 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700340 if (writeType)
341 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400342 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000343 {
344 switch (pConstUnion->getType())
345 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500346 case EbtFloat:
347 writeFloat(out, pConstUnion->getFConst());
348 break;
349 case EbtInt:
350 out << pConstUnion->getIConst();
351 break;
352 case EbtUInt:
353 out << pConstUnion->getUConst() << "u";
354 break;
355 case EbtBool:
356 out << pConstUnion->getBConst();
357 break;
358 default:
359 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000360 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700361 if (i != size - 1)
362 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000363 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700364 if (writeType)
365 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000366 }
367 return pConstUnion;
368}
369
Olli Etuahoe92507b2016-07-04 11:20:10 +0300370void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
Olli Etuahof40319e2015-03-10 14:33:00 +0200371{
372 TInfoSinkBase &out = objSink();
373 if (visit == PreVisit)
374 {
375 if (type.isArray())
376 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300377 out << getTypeName(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200378 out << arrayBrackets(type);
379 out << "(";
380 }
381 else
382 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300383 out << getTypeName(type) << "(";
Olli Etuahof40319e2015-03-10 14:33:00 +0200384 }
385 }
386 else
387 {
388 writeTriplet(visit, nullptr, ", ", ")");
389 }
390}
391
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700392void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000393{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700394 TInfoSinkBase &out = objSink();
Corentin Wallez1b896c62016-11-16 13:10:44 -0500395 out << hashVariableName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000396
397 if (mDeclaringVariables && node->getType().isArray())
398 out << arrayBrackets(node->getType());
399}
400
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700401void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000402{
403 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
404}
405
Olli Etuahob6fa0432016-09-28 16:28:05 +0100406bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
407{
408 TInfoSinkBase &out = objSink();
409 if (visit == PostVisit)
410 {
411 out << ".";
412 node->writeOffsetsAsXYZW(&out);
413 }
414 return true;
415}
416
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700417bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000418{
419 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700420 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000421 switch (node->getOp())
422 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100423 case EOpComma:
424 writeTriplet(visit, "(", ", ", ")");
425 break;
426 case EOpInitialize:
zmo@google.com5601ea02011-06-10 18:23:25 +0000427 if (visit == InVisit)
428 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100429 out << " = ";
430 // RHS of initialize is not being declared.
431 mDeclaringVariables = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000432 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100433 break;
434 case EOpAssign:
435 writeTriplet(visit, "(", " = ", ")");
436 break;
437 case EOpAddAssign:
438 writeTriplet(visit, "(", " += ", ")");
439 break;
440 case EOpSubAssign:
441 writeTriplet(visit, "(", " -= ", ")");
442 break;
443 case EOpDivAssign:
444 writeTriplet(visit, "(", " /= ", ")");
445 break;
446 case EOpIModAssign:
447 writeTriplet(visit, "(", " %= ", ")");
448 break;
449 // Notice the fall-through.
450 case EOpMulAssign:
451 case EOpVectorTimesMatrixAssign:
452 case EOpVectorTimesScalarAssign:
453 case EOpMatrixTimesScalarAssign:
454 case EOpMatrixTimesMatrixAssign:
455 writeTriplet(visit, "(", " *= ", ")");
456 break;
457 case EOpBitShiftLeftAssign:
458 writeTriplet(visit, "(", " <<= ", ")");
459 break;
460 case EOpBitShiftRightAssign:
461 writeTriplet(visit, "(", " >>= ", ")");
462 break;
463 case EOpBitwiseAndAssign:
464 writeTriplet(visit, "(", " &= ", ")");
465 break;
466 case EOpBitwiseXorAssign:
467 writeTriplet(visit, "(", " ^= ", ")");
468 break;
469 case EOpBitwiseOrAssign:
470 writeTriplet(visit, "(", " |= ", ")");
471 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000472
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100473 case EOpIndexDirect:
zmo@google.com5601ea02011-06-10 18:23:25 +0000474 writeTriplet(visit, NULL, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100475 break;
476 case EOpIndexIndirect:
477 if (node->getAddIndexClamp())
478 {
479 if (visit == InVisit)
480 {
481 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
482 out << "[int(clamp(float(";
483 else
484 out << "[webgl_int_clamp(";
485 }
486 else if (visit == PostVisit)
487 {
488 int maxSize;
489 TIntermTyped *left = node->getLeft();
490 TType leftType = left->getType();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700491
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100492 if (left->isArray())
493 {
494 // The shader will fail validation if the array length is not > 0.
495 maxSize = static_cast<int>(leftType.getArraySize()) - 1;
496 }
497 else
498 {
499 maxSize = leftType.getNominalSize() - 1;
500 }
501
502 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
503 out << "), 0.0, float(" << maxSize << ")))]";
504 else
505 out << ", 0, " << maxSize << ")]";
506 }
507 }
508 else
509 {
510 writeTriplet(visit, NULL, "[", "]");
511 }
512 break;
513 case EOpIndexDirectStruct:
514 if (visit == InVisit)
515 {
516 // Here we are writing out "foo.bar", where "foo" is struct
517 // and "bar" is field. In AST, it is represented as a binary
518 // node, where left child represents "foo" and right child "bar".
519 // The node itself represents ".". The struct field "bar" is
520 // actually stored as an index into TStructure::fields.
521 out << ".";
522 const TStructure *structure = node->getLeft()->getType().getStruct();
523 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
524 const TField *field = structure->fields()[index->getIConst(0)];
525
526 TString fieldName = field->name();
527 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000528 fieldName = hashName(TName(fieldName));
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100529
530 out << fieldName;
531 visitChildren = false;
532 }
533 break;
534 case EOpIndexDirectInterfaceBlock:
535 if (visit == InVisit)
536 {
537 out << ".";
538 const TInterfaceBlock *interfaceBlock =
539 node->getLeft()->getType().getInterfaceBlock();
540 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
541 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
542
543 TString fieldName = field->name();
544 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000545 fieldName = hashName(TName(fieldName));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700546
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100547 out << fieldName;
548 visitChildren = false;
549 }
550 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400551
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100552 case EOpAdd:
553 writeTriplet(visit, "(", " + ", ")");
554 break;
555 case EOpSub:
556 writeTriplet(visit, "(", " - ", ")");
557 break;
558 case EOpMul:
559 writeTriplet(visit, "(", " * ", ")");
560 break;
561 case EOpDiv:
562 writeTriplet(visit, "(", " / ", ")");
563 break;
564 case EOpIMod:
565 writeTriplet(visit, "(", " % ", ")");
566 break;
567 case EOpBitShiftLeft:
568 writeTriplet(visit, "(", " << ", ")");
569 break;
570 case EOpBitShiftRight:
571 writeTriplet(visit, "(", " >> ", ")");
572 break;
573 case EOpBitwiseAnd:
574 writeTriplet(visit, "(", " & ", ")");
575 break;
576 case EOpBitwiseXor:
577 writeTriplet(visit, "(", " ^ ", ")");
578 break;
579 case EOpBitwiseOr:
580 writeTriplet(visit, "(", " | ", ")");
581 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400582
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100583 case EOpEqual:
584 writeTriplet(visit, "(", " == ", ")");
585 break;
586 case EOpNotEqual:
587 writeTriplet(visit, "(", " != ", ")");
588 break;
589 case EOpLessThan:
590 writeTriplet(visit, "(", " < ", ")");
591 break;
592 case EOpGreaterThan:
593 writeTriplet(visit, "(", " > ", ")");
594 break;
595 case EOpLessThanEqual:
596 writeTriplet(visit, "(", " <= ", ")");
597 break;
598 case EOpGreaterThanEqual:
599 writeTriplet(visit, "(", " >= ", ")");
600 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000601
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100602 // Notice the fall-through.
603 case EOpVectorTimesScalar:
604 case EOpVectorTimesMatrix:
605 case EOpMatrixTimesVector:
606 case EOpMatrixTimesScalar:
607 case EOpMatrixTimesMatrix:
608 writeTriplet(visit, "(", " * ", ")");
609 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200610
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100611 case EOpLogicalOr:
612 writeTriplet(visit, "(", " || ", ")");
613 break;
614 case EOpLogicalXor:
615 writeTriplet(visit, "(", " ^^ ", ")");
616 break;
617 case EOpLogicalAnd:
618 writeTriplet(visit, "(", " && ", ")");
619 break;
620 default:
621 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000622 }
623
624 return visitChildren;
625}
626
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700627bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000628{
zmo@google.com32e97312011-08-24 01:03:11 +0000629 TString preString;
630 TString postString = ")";
631
zmo@google.com5601ea02011-06-10 18:23:25 +0000632 switch (node->getOp())
633 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500634 case EOpNegative:
635 preString = "(-";
636 break;
637 case EOpPositive:
638 preString = "(+";
639 break;
640 case EOpVectorLogicalNot:
641 preString = "not(";
642 break;
643 case EOpLogicalNot:
644 preString = "(!";
645 break;
646 case EOpBitwiseNot:
647 preString = "(~";
648 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000649
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500650 case EOpPostIncrement:
651 preString = "(";
652 postString = "++)";
653 break;
654 case EOpPostDecrement:
655 preString = "(";
656 postString = "--)";
657 break;
658 case EOpPreIncrement:
659 preString = "(++";
660 break;
661 case EOpPreDecrement:
662 preString = "(--";
663 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000664
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500665 case EOpRadians:
666 preString = "radians(";
667 break;
668 case EOpDegrees:
669 preString = "degrees(";
670 break;
671 case EOpSin:
672 preString = "sin(";
673 break;
674 case EOpCos:
675 preString = "cos(";
676 break;
677 case EOpTan:
678 preString = "tan(";
679 break;
680 case EOpAsin:
681 preString = "asin(";
682 break;
683 case EOpAcos:
684 preString = "acos(";
685 break;
686 case EOpAtan:
687 preString = "atan(";
688 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000689
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500690 case EOpSinh:
691 preString = "sinh(";
692 break;
693 case EOpCosh:
694 preString = "cosh(";
695 break;
696 case EOpTanh:
697 preString = "tanh(";
698 break;
699 case EOpAsinh:
700 preString = "asinh(";
701 break;
702 case EOpAcosh:
703 preString = "acosh(";
704 break;
705 case EOpAtanh:
706 preString = "atanh(";
707 break;
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200708
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500709 case EOpExp:
710 preString = "exp(";
711 break;
712 case EOpLog:
713 preString = "log(";
714 break;
715 case EOpExp2:
716 preString = "exp2(";
717 break;
718 case EOpLog2:
719 preString = "log2(";
720 break;
721 case EOpSqrt:
722 preString = "sqrt(";
723 break;
724 case EOpInverseSqrt:
725 preString = "inversesqrt(";
726 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000727
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500728 case EOpAbs:
729 preString = "abs(";
730 break;
731 case EOpSign:
732 preString = "sign(";
733 break;
734 case EOpFloor:
735 preString = "floor(";
736 break;
737 case EOpTrunc:
738 preString = "trunc(";
739 break;
740 case EOpRound:
741 preString = "round(";
742 break;
743 case EOpRoundEven:
744 preString = "roundEven(";
745 break;
746 case EOpCeil:
747 preString = "ceil(";
748 break;
749 case EOpFract:
750 preString = "fract(";
751 break;
752 case EOpIsNan:
753 preString = "isnan(";
754 break;
755 case EOpIsInf:
756 preString = "isinf(";
757 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000758
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500759 case EOpFloatBitsToInt:
760 preString = "floatBitsToInt(";
761 break;
762 case EOpFloatBitsToUint:
763 preString = "floatBitsToUint(";
764 break;
765 case EOpIntBitsToFloat:
766 preString = "intBitsToFloat(";
767 break;
768 case EOpUintBitsToFloat:
769 preString = "uintBitsToFloat(";
770 break;
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200771
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500772 case EOpPackSnorm2x16:
773 preString = "packSnorm2x16(";
774 break;
775 case EOpPackUnorm2x16:
776 preString = "packUnorm2x16(";
777 break;
778 case EOpPackHalf2x16:
779 preString = "packHalf2x16(";
780 break;
781 case EOpUnpackSnorm2x16:
782 preString = "unpackSnorm2x16(";
783 break;
784 case EOpUnpackUnorm2x16:
785 preString = "unpackUnorm2x16(";
786 break;
787 case EOpUnpackHalf2x16:
788 preString = "unpackHalf2x16(";
789 break;
Olli Etuaho7700ff62015-01-15 12:16:29 +0200790
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500791 case EOpLength:
792 preString = "length(";
793 break;
794 case EOpNormalize:
795 preString = "normalize(";
796 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000797
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500798 case EOpDFdx:
799 preString = "dFdx(";
800 break;
801 case EOpDFdy:
802 preString = "dFdy(";
803 break;
804 case EOpFwidth:
805 preString = "fwidth(";
806 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000807
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500808 case EOpTranspose:
809 preString = "transpose(";
810 break;
811 case EOpDeterminant:
812 preString = "determinant(";
813 break;
814 case EOpInverse:
815 preString = "inverse(";
816 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200817
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500818 case EOpAny:
819 preString = "any(";
820 break;
821 case EOpAll:
822 preString = "all(";
823 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000824
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500825 default:
826 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000827 }
828
zmo@google.com32e97312011-08-24 01:03:11 +0000829 if (visit == PreVisit && node->getUseEmulatedFunction())
830 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
831 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
832
zmo@google.com5601ea02011-06-10 18:23:25 +0000833 return true;
834}
835
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300836bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
837{
838 TInfoSinkBase &out = objSink();
839 // Notice two brackets at the beginning and end. The outer ones
840 // encapsulate the whole ternary expression. This preserves the
841 // order of precedence when ternary expressions are used in a
842 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
843 out << "((";
844 node->getCondition()->traverse(this);
845 out << ") ? (";
846 node->getTrueExpression()->traverse(this);
847 out << ") : (";
848 node->getFalseExpression()->traverse(this);
849 out << "))";
850 return false;
851}
852
Olli Etuaho57961272016-09-14 13:57:46 +0300853bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000854{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700855 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000856
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300857 out << "if (";
858 node->getCondition()->traverse(this);
859 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000860
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300861 incrementDepth(node);
862 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000863
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300864 if (node->getFalseBlock())
865 {
866 out << "else\n";
867 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000868 }
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300869 decrementDepth();
zmo@google.com5601ea02011-06-10 18:23:25 +0000870 return false;
871}
872
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200873bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200874{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200875 if (node->getStatementList())
876 {
877 writeTriplet(visit, "switch (", ") ", nullptr);
878 // The curly braces get written when visiting the statementList aggregate
879 }
880 else
881 {
882 // No statementList, so it won't output curly braces
883 writeTriplet(visit, "switch (", ") {", "}\n");
884 }
885 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200886}
887
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200888bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200889{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200890 if (node->hasCondition())
891 {
892 writeTriplet(visit, "case (", nullptr, "):\n");
893 return true;
894 }
895 else
896 {
897 TInfoSinkBase &out = objSink();
898 out << "default:\n";
899 return false;
900 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200901}
902
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100903bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
904{
905 TInfoSinkBase &out = objSink();
906 // Scope the blocks except when at the global scope.
907 if (mDepth > 0)
908 {
909 out << "{\n";
910 }
911
912 incrementDepth(node);
913 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
914 iter != node->getSequence()->end(); ++iter)
915 {
916 TIntermNode *curNode = *iter;
917 ASSERT(curNode != nullptr);
918 curNode->traverse(this);
919
920 if (isSingleStatement(curNode))
921 out << ";\n";
922 }
923 decrementDepth();
924
925 // Scope the blocks except when at the global scope.
926 if (mDepth > 0)
927 {
928 out << "}\n";
929 }
930 return false;
931}
932
Olli Etuaho336b1472016-10-05 16:37:55 +0100933bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
934{
935 TInfoSinkBase &out = objSink();
936
937 ASSERT(visit == PreVisit);
938 {
939 const TType &type = node->getType();
940 writeVariableType(type);
941 if (type.isArray())
942 out << arrayBrackets(type);
943 }
944
945 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
946
947 incrementDepth(node);
948
949 // Traverse function parameters.
950 TIntermAggregate *params = node->getFunctionParameters()->getAsAggregate();
951 ASSERT(params->getOp() == EOpParameters);
952 params->traverse(this);
953
954 // Traverse function body.
955 visitCodeBlock(node->getBody());
956 decrementDepth();
957
958 // Fully processed; no need to visit children.
959 return false;
960}
961
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000962bool TOutputGLSLBase::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
963{
964 TInfoSinkBase &out = objSink();
965 ASSERT(visit == PreVisit);
966 const TIntermSymbol *symbol = node->getSymbol();
967 out << "invariant " << hashVariableName(symbol->getName());
968 return false;
969}
970
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700971bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000972{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500973 bool visitChildren = true;
974 TInfoSinkBase &out = objSink();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700975 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000976 switch (node->getOp())
977 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500978 case EOpPrototype:
979 // Function declaration.
980 ASSERT(visit == PreVisit);
981 {
982 const TType &type = node->getType();
983 writeVariableType(type);
984 if (type.isArray())
985 out << arrayBrackets(type);
986 }
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300987
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500988 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700989
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500990 out << "(";
991 writeFunctionParameters(*(node->getSequence()));
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200992 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000993
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500994 visitChildren = false;
995 break;
996 case EOpFunctionCall:
997 // Function call.
998 if (visit == PreVisit)
999 out << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
1000 else if (visit == InVisit)
1001 out << ", ";
1002 else
1003 out << ")";
1004 break;
1005 case EOpParameters:
1006 // Function parameters.
1007 ASSERT(visit == PreVisit);
1008 out << "(";
1009 writeFunctionParameters(*(node->getSequence()));
1010 out << ")";
1011 visitChildren = false;
1012 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001013 case EOpConstructFloat:
1014 case EOpConstructVec2:
1015 case EOpConstructVec3:
1016 case EOpConstructVec4:
1017 case EOpConstructBool:
1018 case EOpConstructBVec2:
1019 case EOpConstructBVec3:
1020 case EOpConstructBVec4:
1021 case EOpConstructInt:
1022 case EOpConstructIVec2:
1023 case EOpConstructIVec3:
1024 case EOpConstructIVec4:
1025 case EOpConstructUInt:
1026 case EOpConstructUVec2:
1027 case EOpConstructUVec3:
1028 case EOpConstructUVec4:
1029 case EOpConstructMat2:
1030 case EOpConstructMat2x3:
1031 case EOpConstructMat2x4:
1032 case EOpConstructMat3x2:
1033 case EOpConstructMat3:
1034 case EOpConstructMat3x4:
1035 case EOpConstructMat4x2:
1036 case EOpConstructMat4x3:
1037 case EOpConstructMat4:
1038 case EOpConstructStruct:
1039 writeConstructorTriplet(visit, node->getType());
1040 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +02001041
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001042 case EOpOuterProduct:
1043 writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
1044 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001045
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001046 case EOpLessThan:
1047 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
1048 break;
1049 case EOpGreaterThan:
1050 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
1051 break;
1052 case EOpLessThanEqual:
1053 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
1054 break;
1055 case EOpGreaterThanEqual:
1056 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
1057 break;
1058 case EOpVectorEqual:
1059 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
1060 break;
1061 case EOpVectorNotEqual:
1062 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
1063 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001064
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001065 case EOpMod:
1066 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
1067 break;
1068 case EOpModf:
1069 writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
1070 break;
1071 case EOpPow:
1072 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
1073 break;
1074 case EOpAtan:
1075 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
1076 break;
1077 case EOpMin:
1078 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
1079 break;
1080 case EOpMax:
1081 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
1082 break;
1083 case EOpClamp:
1084 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
1085 break;
1086 case EOpMix:
1087 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
1088 break;
1089 case EOpStep:
1090 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
1091 break;
1092 case EOpSmoothStep:
1093 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
1094 break;
1095 case EOpDistance:
1096 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
1097 break;
1098 case EOpDot:
1099 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
1100 break;
1101 case EOpCross:
1102 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
1103 break;
1104 case EOpFaceForward:
1105 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
1106 break;
1107 case EOpReflect:
1108 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
1109 break;
1110 case EOpRefract:
1111 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
1112 break;
1113 case EOpMul:
1114 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
1115 break;
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001116 case EOpBarrier:
1117 writeBuiltInFunctionTriplet(visit, "barrier(", useEmulatedFunction);
1118 break;
1119 case EOpMemoryBarrier:
1120 writeBuiltInFunctionTriplet(visit, "memoryBarrier(", useEmulatedFunction);
1121 break;
1122 case EOpMemoryBarrierAtomicCounter:
1123 writeBuiltInFunctionTriplet(visit, "memoryBarrierAtomicCounter(", useEmulatedFunction);
1124 break;
1125 case EOpMemoryBarrierBuffer:
1126 writeBuiltInFunctionTriplet(visit, "memoryBarrierBuffer(", useEmulatedFunction);
1127 break;
1128 case EOpMemoryBarrierImage:
1129 writeBuiltInFunctionTriplet(visit, "memoryBarrierImage(", useEmulatedFunction);
1130 break;
1131 case EOpMemoryBarrierShared:
1132 writeBuiltInFunctionTriplet(visit, "memoryBarrierShared(", useEmulatedFunction);
1133 break;
1134 case EOpGroupMemoryBarrier:
1135 writeBuiltInFunctionTriplet(visit, "groupMemoryBarrier(", useEmulatedFunction);
1136 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001137 default:
1138 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001139 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001140 return visitChildren;
1141}
1142
Olli Etuaho13389b62016-10-16 11:48:18 +01001143bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
1144{
1145 TInfoSinkBase &out = objSink();
1146
1147 // Variable declaration.
1148 if (visit == PreVisit)
1149 {
1150 const TIntermSequence &sequence = *(node->getSequence());
1151 const TIntermTyped *variable = sequence.front()->getAsTyped();
1152 writeLayoutQualifier(variable->getType());
1153 writeVariableType(variable->getType());
1154 out << " ";
1155 mDeclaringVariables = true;
1156 }
1157 else if (visit == InVisit)
1158 {
1159 out << ", ";
1160 mDeclaringVariables = true;
1161 }
1162 else
1163 {
1164 mDeclaringVariables = false;
1165 }
1166 return true;
1167}
1168
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001169bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001170{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001171 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001172
Zhenyao Mo7cab38b2013-10-15 12:59:30 -07001173 incrementDepth(node);
Corentin Wallez7258e302015-09-22 10:40:24 -07001174
zmo@google.com5601ea02011-06-10 18:23:25 +00001175 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001176
zmo@google.com5601ea02011-06-10 18:23:25 +00001177 if (loopType == ELoopFor) // for loop
1178 {
Corentin Wallez1b896c62016-11-16 13:10:44 -05001179 out << "for (";
1180 if (node->getInit())
1181 node->getInit()->traverse(this);
1182 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001183
Corentin Wallez1b896c62016-11-16 13:10:44 -05001184 if (node->getCondition())
1185 node->getCondition()->traverse(this);
1186 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001187
Corentin Wallez1b896c62016-11-16 13:10:44 -05001188 if (node->getExpression())
1189 node->getExpression()->traverse(this);
1190 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001191
Corentin Wallez1b896c62016-11-16 13:10:44 -05001192 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001193 }
1194 else if (loopType == ELoopWhile) // while loop
1195 {
1196 out << "while (";
1197 ASSERT(node->getCondition() != NULL);
1198 node->getCondition()->traverse(this);
1199 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001200
1201 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001202 }
1203 else // do-while loop
1204 {
1205 ASSERT(loopType == ELoopDoWhile);
1206 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001207
zmo@google.com5601ea02011-06-10 18:23:25 +00001208 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001209
zmo@google.com5601ea02011-06-10 18:23:25 +00001210 out << "while (";
1211 ASSERT(node->getCondition() != NULL);
1212 node->getCondition()->traverse(this);
1213 out << ");\n";
1214 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001215
zmo@google.com5601ea02011-06-10 18:23:25 +00001216 decrementDepth();
1217
1218 // No need to visit children. They have been already processed in
1219 // this function.
1220 return false;
1221}
1222
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001223bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001224{
1225 switch (node->getFlowOp())
1226 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001227 case EOpKill:
1228 writeTriplet(visit, "discard", NULL, NULL);
1229 break;
1230 case EOpBreak:
1231 writeTriplet(visit, "break", NULL, NULL);
1232 break;
1233 case EOpContinue:
1234 writeTriplet(visit, "continue", NULL, NULL);
1235 break;
1236 case EOpReturn:
1237 writeTriplet(visit, "return ", NULL, NULL);
1238 break;
1239 default:
1240 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001241 }
1242
1243 return true;
1244}
1245
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001246void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001247{
zmo@google.com5601ea02011-06-10 18:23:25 +00001248 TInfoSinkBase &out = objSink();
1249 if (node != NULL)
1250 {
1251 node->traverse(this);
1252 // Single statements not part of a sequence need to be terminated
1253 // with semi-colon.
1254 if (isSingleStatement(node))
1255 out << ";\n";
1256 }
1257 else
1258 {
1259 out << "{\n}\n"; // Empty code block.
1260 }
1261}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001262
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001263TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001264{
Olli Etuahoe92507b2016-07-04 11:20:10 +03001265 if (type.getBasicType() == EbtStruct)
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001266 return hashName(TName(type.getStruct()->name()));
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001267 else
Olli Etuahoe92507b2016-07-04 11:20:10 +03001268 return type.getBuiltInTypeNameString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001269}
1270
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001271TString TOutputGLSLBase::hashName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001272{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001273 if (name.getString().empty())
1274 {
1275 ASSERT(!name.isInternal());
1276 return name.getString();
1277 }
1278 if (name.isInternal())
1279 {
1280 // TODO(oetuaho): Would be nicer to prefix non-internal names with "_" instead, like is
1281 // done in the HLSL output, but that requires fairly complex changes elsewhere in the code
1282 // as well.
1283 // We need to use a prefix that is reserved in WebGL in order to guarantee that the internal
1284 // names don't conflict with user-defined names from WebGL.
1285 return "webgl_angle_" + name.getString();
1286 }
1287 if (mHashFunction == nullptr)
1288 {
1289 return name.getString();
1290 }
1291 NameMap::const_iterator it = mNameMap.find(name.getString().c_str());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001292 if (it != mNameMap.end())
1293 return it->second.c_str();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001294 TString hashedName = TIntermTraverser::hash(name.getString(), mHashFunction);
1295 mNameMap[name.getString().c_str()] = hashedName.c_str();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001296 return hashedName;
1297}
1298
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001299TString TOutputGLSLBase::hashVariableName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001300{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001301 if (mSymbolTable.findBuiltIn(name.getString(), mShaderVersion) != NULL)
Olli Etuaho09b04a22016-12-15 13:30:26 +00001302 {
1303 if (mCompileOptions & SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM &&
1304 name.getString() == "gl_ViewID_OVR")
1305 {
1306 TName uniformName(TString("ViewId_OVR"));
1307 uniformName.setInternal(true);
1308 return hashName(uniformName);
1309 }
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001310 return name.getString();
Olli Etuaho09b04a22016-12-15 13:30:26 +00001311 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001312 return hashName(name);
1313}
1314
Olli Etuaho59f9a642015-08-06 20:38:26 +03001315TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001316{
Olli Etuaho59f9a642015-08-06 20:38:26 +03001317 TString mangledStr = mangledName.getString();
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001318 TString name = TFunction::unmangleName(mangledStr);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001319 if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001320 return translateTextureFunction(name);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001321 if (mangledName.isInternal())
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001322 {
1323 // Internal function names are outputted as-is - they may refer to functions manually added
1324 // to the output shader source that are not included in the AST at all.
Olli Etuaho59f9a642015-08-06 20:38:26 +03001325 return name;
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001326 }
Olli Etuaho59f9a642015-08-06 20:38:26 +03001327 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001328 {
1329 TName nameObj(name);
1330 return hashName(nameObj);
1331 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001332}
Jamie Madill98493dd2013-07-08 14:39:03 -04001333
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001334bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001335{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001336 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001337 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001338 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001339 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001340 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001341
1342 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001343}
1344
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001345void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001346{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001347 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001348
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001349 out << "struct " << hashName(TName(structure->name())) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001350 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001351 for (size_t i = 0; i < fields.size(); ++i)
1352 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001353 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001354 if (writeVariablePrecision(field->type()->getPrecision()))
1355 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001356 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Jamie Madill98493dd2013-07-08 14:39:03 -04001357 if (field->type()->isArray())
1358 out << arrayBrackets(*field->type());
1359 out << ";\n";
1360 }
1361 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001362}
Jamie Madill98493dd2013-07-08 14:39:03 -04001363
Geoff Langbdcc54a2015-09-02 13:09:48 -04001364void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1365{
1366 TInfoSinkBase &out = objSink();
1367
1368 out << "layout(";
1369
1370 switch (interfaceBlock->blockStorage())
1371 {
1372 case EbsUnspecified:
1373 case EbsShared:
1374 // Default block storage is shared.
1375 out << "shared";
1376 break;
1377
1378 case EbsPacked:
1379 out << "packed";
1380 break;
1381
1382 case EbsStd140:
1383 out << "std140";
1384 break;
1385
1386 default:
1387 UNREACHABLE();
1388 break;
1389 }
1390
1391 out << ", ";
1392
1393 switch (interfaceBlock->matrixPacking())
1394 {
1395 case EmpUnspecified:
1396 case EmpColumnMajor:
1397 // Default matrix packing is column major.
1398 out << "column_major";
1399 break;
1400
1401 case EmpRowMajor:
1402 out << "row_major";
1403 break;
1404
1405 default:
1406 UNREACHABLE();
1407 break;
1408 }
1409
1410 out << ") ";
1411}
1412
1413void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1414{
1415 TInfoSinkBase &out = objSink();
1416
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001417 out << hashName(TName(interfaceBlock->name())) << "{\n";
Geoff Langbdcc54a2015-09-02 13:09:48 -04001418 const TFieldList &fields = interfaceBlock->fields();
1419 for (size_t i = 0; i < fields.size(); ++i)
1420 {
1421 const TField *field = fields[i];
1422 if (writeVariablePrecision(field->type()->getPrecision()))
1423 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001424 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Geoff Langbdcc54a2015-09-02 13:09:48 -04001425 if (field->type()->isArray())
1426 out << arrayBrackets(*field->type());
1427 out << ";\n";
1428 }
1429 out << "}";
1430}
Jamie Madill45bcc782016-11-07 13:58:48 -05001431
1432} // namespace sh