blob: 14cb16b543e955be9f13c53c76867eda53e9cc31 [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"
zmo@google.com5601ea02011-06-10 18:23:25 +000010
daniel@transgaming.com773ff742013-01-11 04:12:51 +000011#include <cfloat>
daniel@transgaming.com6c1203f2013-01-11 04:12:43 +000012
Jamie Madill45bcc782016-11-07 13:58:48 -050013namespace sh
14{
15
zmo@google.com5601ea02011-06-10 18:23:25 +000016namespace
17{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070018TString arrayBrackets(const TType &type)
zmo@google.com5601ea02011-06-10 18:23:25 +000019{
20 ASSERT(type.isArray());
21 TInfoSinkBase out;
22 out << "[" << type.getArraySize() << "]";
23 return TString(out.c_str());
24}
25
Zhenyao Mo9eedea02014-05-12 16:02:35 -070026bool isSingleStatement(TIntermNode *node)
27{
Olli Etuaho336b1472016-10-05 16:37:55 +010028 if (node->getAsFunctionDefinition())
zmo@google.com5601ea02011-06-10 18:23:25 +000029 {
Olli Etuaho336b1472016-10-05 16:37:55 +010030 return false;
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010031 }
32 else if (node->getAsBlock())
33 {
34 return false;
zmo@google.com5601ea02011-06-10 18:23:25 +000035 }
Olli Etuaho57961272016-09-14 13:57:46 +030036 else if (node->getAsIfElseNode())
zmo@google.com5601ea02011-06-10 18:23:25 +000037 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +030038 return false;
zmo@google.com5601ea02011-06-10 18:23:25 +000039 }
40 else if (node->getAsLoopNode())
41 {
42 return false;
43 }
Olli Etuaho01cd8af2015-02-20 10:39:20 +020044 else if (node->getAsSwitchNode())
45 {
46 return false;
47 }
48 else if (node->getAsCaseNode())
49 {
50 return false;
51 }
zmo@google.com5601ea02011-06-10 18:23:25 +000052 return true;
53}
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080054
Martin Radev2cc85b32016-08-05 16:22:53 +030055// If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
56// variables with specified layout qualifiers are copied. Additional checks are needed against the
57// type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
58// TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
59// NeedsToWriteLayoutQualifier.
60bool NeedsToWriteLayoutQualifier(const TType &type)
61{
62 if (type.getBasicType() == EbtInterfaceBlock)
63 {
64 return false;
65 }
66
67 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
68
69 if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn) &&
70 layoutQualifier.location >= 0)
71 {
72 return true;
73 }
74 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
75 {
76 return true;
77 }
78 return false;
79}
80
zmo@google.com5601ea02011-06-10 18:23:25 +000081} // namespace
82
Zhenyao Mo9eedea02014-05-12 16:02:35 -070083TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000084 ShArrayIndexClampingStrategy clampingStrategy,
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000085 ShHashFunction64 hashFunction,
Zhenyao Mo9eedea02014-05-12 16:02:35 -070086 NameMap &nameMap,
87 TSymbolTable &symbolTable,
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080088 int shaderVersion,
Qiankun Miao705a9192016-08-29 10:05:27 +080089 ShShaderOutput output,
90 ShCompileOptions compileOptions)
zmo@google.com5601ea02011-06-10 18:23:25 +000091 : TIntermTraverser(true, true, true),
92 mObjSink(objSink),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000093 mDeclaringVariables(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000094 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000095 mHashFunction(hashFunction),
96 mNameMap(nameMap),
Jamie Madill02f20dd2013-09-12 12:07:42 -040097 mSymbolTable(symbolTable),
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080098 mShaderVersion(shaderVersion),
Qiankun Miao705a9192016-08-29 10:05:27 +080099 mOutput(output),
100 mCompileOptions(compileOptions)
zmo@google.com5601ea02011-06-10 18:23:25 +0000101{
102}
103
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800104void TOutputGLSLBase::writeInvariantQualifier(const TType &type)
105{
106 bool removeInvariant = ((type.getQualifier() == EvqVaryingIn && sh::IsGLSL420OrNewer(mOutput) &&
107 !(mCompileOptions & SH_DONT_REMOVE_INVARIANT_FOR_FRAGMENT_INPUT)) ||
108 (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 &&
109 !!(mCompileOptions & SH_REMOVE_INVARIANT_FOR_ESSL3)));
110 if (!removeInvariant)
111 {
112 TInfoSinkBase &out = objSink();
113 out << "invariant ";
114 }
115}
116
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700117void TOutputGLSLBase::writeTriplet(
118 Visit visit, const char *preStr, const char *inStr, const char *postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000119{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700120 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000121 if (visit == PreVisit && preStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000122 out << preStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000123 else if (visit == InVisit && inStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000124 out << inStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000125 else if (visit == PostVisit && postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000126 out << postStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000127}
128
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700129void TOutputGLSLBase::writeBuiltInFunctionTriplet(
130 Visit visit, const char *preStr, bool useEmulatedFunction)
zmo@google.com5601ea02011-06-10 18:23:25 +0000131{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700132 TString preString = useEmulatedFunction ?
133 BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
134 writeTriplet(visit, preString.c_str(), ", ", ")");
135}
136
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300137void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
138{
Martin Radev2cc85b32016-08-05 16:22:53 +0300139 if (!NeedsToWriteLayoutQualifier(type))
140 {
141 return;
142 }
143
144 TInfoSinkBase &out = objSink();
145 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
146 out << "layout(";
147
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300148 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
149 {
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300150 if (layoutQualifier.location >= 0)
151 {
Martin Radev2cc85b32016-08-05 16:22:53 +0300152 out << "location = " << layoutQualifier.location;
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300153 }
154 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300155
156 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
157 {
158 ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
159 out << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
160 }
161
162 out << ") ";
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300163}
164
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800165const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier)
166{
167 if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 &&
168 !!(mCompileOptions & SH_REMOVE_CENTROID_FOR_ESSL3))
169 {
170 switch (qualifier)
171 {
172 // The return string is consistent with sh::getQualifierString() from
173 // BaseTypes.h minus the "centroid" keyword.
174 case EvqCentroid:
175 return "";
176 case EvqCentroidIn:
177 return "smooth in";
178 case EvqCentroidOut:
179 return "smooth out";
180 default:
181 break;
182 }
183 }
184 if (sh::IsGLSL130OrNewer(mOutput))
185 {
186 switch (qualifier)
187 {
188 case EvqAttribute:
189 return "in";
190 case EvqVaryingIn:
191 return "in";
192 case EvqVaryingOut:
193 return "out";
194 default:
195 break;
196 }
197 }
198 return sh::getQualifierString(qualifier);
199}
200
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700201void TOutputGLSLBase::writeVariableType(const TType &type)
202{
Qiankun Miao705a9192016-08-29 10:05:27 +0800203 TQualifier qualifier = type.getQualifier();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700204 TInfoSinkBase &out = objSink();
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800205 if (type.isInvariant())
Olli Etuaho214c2d82015-04-27 14:49:13 +0300206 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800207 writeInvariantQualifier(type);
Olli Etuaho214c2d82015-04-27 14:49:13 +0300208 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400209 if (type.getBasicType() == EbtInterfaceBlock)
210 {
211 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
212 declareInterfaceBlockLayout(interfaceBlock);
213 }
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400214 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400215 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800216 const char *qualifierString = mapQualifierToString(qualifier);
217 if (qualifierString && qualifierString[0] != '\0')
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800218 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800219 out << qualifierString << " ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800220 }
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400221 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300222
223 const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
224 if (memoryQualifier.readonly)
225 {
226 ASSERT(IsImage(type.getBasicType()));
227 out << "readonly ";
228 }
229
230 if (memoryQualifier.writeonly)
231 {
232 ASSERT(IsImage(type.getBasicType()));
233 out << "writeonly ";
234 }
235
zmo@google.com5601ea02011-06-10 18:23:25 +0000236 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700237 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000238 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400239 TStructure *structure = type.getStruct();
240
241 declareStruct(structure);
242
243 if (!structure->name().empty())
244 {
245 mDeclaredStructs.insert(structure->uniqueId());
246 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000247 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400248 else if (type.getBasicType() == EbtInterfaceBlock)
249 {
250 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
251 declareInterfaceBlock(interfaceBlock);
252 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000253 else
254 {
255 if (writeVariablePrecision(type.getPrecision()))
256 out << " ";
257 out << getTypeName(type);
258 }
259}
260
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700261void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000262{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700263 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000264 for (TIntermSequence::const_iterator iter = args.begin();
265 iter != args.end(); ++iter)
266 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700267 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000268 ASSERT(arg != NULL);
269
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700270 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000271 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000272
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000273 if (!arg->getName().getString().empty())
274 out << " " << hashName(arg->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000275 if (type.isArray())
276 out << arrayBrackets(type);
277
278 // Put a comma if this is not the last argument.
279 if (iter != args.end() - 1)
280 out << ", ";
281 }
282}
283
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400284const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
285 const TType &type, const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000286{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700287 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000288
289 if (type.getBasicType() == EbtStruct)
290 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700291 const TStructure *structure = type.getStruct();
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000292 out << hashName(TName(structure->name())) << "(";
Jamie Madill98493dd2013-07-08 14:39:03 -0400293
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700294 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400295 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000296 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700297 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000298 ASSERT(fieldType != NULL);
299 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700300 if (i != fields.size() - 1)
301 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000302 }
303 out << ")";
304 }
305 else
306 {
Jamie Madill94bf7f22013-07-08 13:31:15 -0400307 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000308 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700309 if (writeType)
310 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400311 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000312 {
313 switch (pConstUnion->getType())
314 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700315 case EbtFloat:
316 out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
317 break;
318 case EbtInt:
319 out << pConstUnion->getIConst();
320 break;
Olli Etuaho5321c802015-04-02 17:08:16 +0300321 case EbtUInt:
322 out << pConstUnion->getUConst() << "u";
323 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700324 case EbtBool:
325 out << pConstUnion->getBConst();
326 break;
327 default: UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000328 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700329 if (i != size - 1)
330 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000331 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700332 if (writeType)
333 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000334 }
335 return pConstUnion;
336}
337
Olli Etuahoe92507b2016-07-04 11:20:10 +0300338void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
Olli Etuahof40319e2015-03-10 14:33:00 +0200339{
340 TInfoSinkBase &out = objSink();
341 if (visit == PreVisit)
342 {
343 if (type.isArray())
344 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300345 out << getTypeName(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200346 out << arrayBrackets(type);
347 out << "(";
348 }
349 else
350 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300351 out << getTypeName(type) << "(";
Olli Etuahof40319e2015-03-10 14:33:00 +0200352 }
353 }
354 else
355 {
356 writeTriplet(visit, nullptr, ", ", ")");
357 }
358}
359
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700360void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000361{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700362 TInfoSinkBase &out = objSink();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800363 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
364 out << mLoopUnrollStack.getLoopIndexValue(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000365 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000366 out << hashVariableName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000367
368 if (mDeclaringVariables && node->getType().isArray())
369 out << arrayBrackets(node->getType());
370}
371
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700372void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000373{
374 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
375}
376
Olli Etuahob6fa0432016-09-28 16:28:05 +0100377bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
378{
379 TInfoSinkBase &out = objSink();
380 if (visit == PostVisit)
381 {
382 out << ".";
383 node->writeOffsetsAsXYZW(&out);
384 }
385 return true;
386}
387
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700388bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000389{
390 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700391 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000392 switch (node->getOp())
393 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100394 case EOpComma:
395 writeTriplet(visit, "(", ", ", ")");
396 break;
397 case EOpInitialize:
zmo@google.com5601ea02011-06-10 18:23:25 +0000398 if (visit == InVisit)
399 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100400 out << " = ";
401 // RHS of initialize is not being declared.
402 mDeclaringVariables = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000403 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100404 break;
405 case EOpAssign:
406 writeTriplet(visit, "(", " = ", ")");
407 break;
408 case EOpAddAssign:
409 writeTriplet(visit, "(", " += ", ")");
410 break;
411 case EOpSubAssign:
412 writeTriplet(visit, "(", " -= ", ")");
413 break;
414 case EOpDivAssign:
415 writeTriplet(visit, "(", " /= ", ")");
416 break;
417 case EOpIModAssign:
418 writeTriplet(visit, "(", " %= ", ")");
419 break;
420 // Notice the fall-through.
421 case EOpMulAssign:
422 case EOpVectorTimesMatrixAssign:
423 case EOpVectorTimesScalarAssign:
424 case EOpMatrixTimesScalarAssign:
425 case EOpMatrixTimesMatrixAssign:
426 writeTriplet(visit, "(", " *= ", ")");
427 break;
428 case EOpBitShiftLeftAssign:
429 writeTriplet(visit, "(", " <<= ", ")");
430 break;
431 case EOpBitShiftRightAssign:
432 writeTriplet(visit, "(", " >>= ", ")");
433 break;
434 case EOpBitwiseAndAssign:
435 writeTriplet(visit, "(", " &= ", ")");
436 break;
437 case EOpBitwiseXorAssign:
438 writeTriplet(visit, "(", " ^= ", ")");
439 break;
440 case EOpBitwiseOrAssign:
441 writeTriplet(visit, "(", " |= ", ")");
442 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000443
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100444 case EOpIndexDirect:
zmo@google.com5601ea02011-06-10 18:23:25 +0000445 writeTriplet(visit, NULL, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100446 break;
447 case EOpIndexIndirect:
448 if (node->getAddIndexClamp())
449 {
450 if (visit == InVisit)
451 {
452 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
453 out << "[int(clamp(float(";
454 else
455 out << "[webgl_int_clamp(";
456 }
457 else if (visit == PostVisit)
458 {
459 int maxSize;
460 TIntermTyped *left = node->getLeft();
461 TType leftType = left->getType();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700462
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100463 if (left->isArray())
464 {
465 // The shader will fail validation if the array length is not > 0.
466 maxSize = static_cast<int>(leftType.getArraySize()) - 1;
467 }
468 else
469 {
470 maxSize = leftType.getNominalSize() - 1;
471 }
472
473 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
474 out << "), 0.0, float(" << maxSize << ")))]";
475 else
476 out << ", 0, " << maxSize << ")]";
477 }
478 }
479 else
480 {
481 writeTriplet(visit, NULL, "[", "]");
482 }
483 break;
484 case EOpIndexDirectStruct:
485 if (visit == InVisit)
486 {
487 // Here we are writing out "foo.bar", where "foo" is struct
488 // and "bar" is field. In AST, it is represented as a binary
489 // node, where left child represents "foo" and right child "bar".
490 // The node itself represents ".". The struct field "bar" is
491 // actually stored as an index into TStructure::fields.
492 out << ".";
493 const TStructure *structure = node->getLeft()->getType().getStruct();
494 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
495 const TField *field = structure->fields()[index->getIConst(0)];
496
497 TString fieldName = field->name();
498 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000499 fieldName = hashName(TName(fieldName));
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100500
501 out << fieldName;
502 visitChildren = false;
503 }
504 break;
505 case EOpIndexDirectInterfaceBlock:
506 if (visit == InVisit)
507 {
508 out << ".";
509 const TInterfaceBlock *interfaceBlock =
510 node->getLeft()->getType().getInterfaceBlock();
511 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
512 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
513
514 TString fieldName = field->name();
515 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000516 fieldName = hashName(TName(fieldName));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700517
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100518 out << fieldName;
519 visitChildren = false;
520 }
521 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400522
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100523 case EOpAdd:
524 writeTriplet(visit, "(", " + ", ")");
525 break;
526 case EOpSub:
527 writeTriplet(visit, "(", " - ", ")");
528 break;
529 case EOpMul:
530 writeTriplet(visit, "(", " * ", ")");
531 break;
532 case EOpDiv:
533 writeTriplet(visit, "(", " / ", ")");
534 break;
535 case EOpIMod:
536 writeTriplet(visit, "(", " % ", ")");
537 break;
538 case EOpBitShiftLeft:
539 writeTriplet(visit, "(", " << ", ")");
540 break;
541 case EOpBitShiftRight:
542 writeTriplet(visit, "(", " >> ", ")");
543 break;
544 case EOpBitwiseAnd:
545 writeTriplet(visit, "(", " & ", ")");
546 break;
547 case EOpBitwiseXor:
548 writeTriplet(visit, "(", " ^ ", ")");
549 break;
550 case EOpBitwiseOr:
551 writeTriplet(visit, "(", " | ", ")");
552 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400553
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100554 case EOpEqual:
555 writeTriplet(visit, "(", " == ", ")");
556 break;
557 case EOpNotEqual:
558 writeTriplet(visit, "(", " != ", ")");
559 break;
560 case EOpLessThan:
561 writeTriplet(visit, "(", " < ", ")");
562 break;
563 case EOpGreaterThan:
564 writeTriplet(visit, "(", " > ", ")");
565 break;
566 case EOpLessThanEqual:
567 writeTriplet(visit, "(", " <= ", ")");
568 break;
569 case EOpGreaterThanEqual:
570 writeTriplet(visit, "(", " >= ", ")");
571 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000572
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100573 // Notice the fall-through.
574 case EOpVectorTimesScalar:
575 case EOpVectorTimesMatrix:
576 case EOpMatrixTimesVector:
577 case EOpMatrixTimesScalar:
578 case EOpMatrixTimesMatrix:
579 writeTriplet(visit, "(", " * ", ")");
580 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200581
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100582 case EOpLogicalOr:
583 writeTriplet(visit, "(", " || ", ")");
584 break;
585 case EOpLogicalXor:
586 writeTriplet(visit, "(", " ^^ ", ")");
587 break;
588 case EOpLogicalAnd:
589 writeTriplet(visit, "(", " && ", ")");
590 break;
591 default:
592 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000593 }
594
595 return visitChildren;
596}
597
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700598bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000599{
zmo@google.com32e97312011-08-24 01:03:11 +0000600 TString preString;
601 TString postString = ")";
602
zmo@google.com5601ea02011-06-10 18:23:25 +0000603 switch (node->getOp())
604 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700605 case EOpNegative: preString = "(-"; break;
Zhenyao Mode1e00e2014-10-09 16:55:32 -0700606 case EOpPositive: preString = "(+"; break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700607 case EOpVectorLogicalNot: preString = "not("; break;
608 case EOpLogicalNot: preString = "(!"; break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200609 case EOpBitwiseNot: preString = "(~"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000610
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700611 case EOpPostIncrement: preString = "("; postString = "++)"; break;
612 case EOpPostDecrement: preString = "("; postString = "--)"; break;
613 case EOpPreIncrement: preString = "(++"; break;
614 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000615
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700616 case EOpRadians:
617 preString = "radians(";
618 break;
619 case EOpDegrees:
620 preString = "degrees(";
621 break;
622 case EOpSin:
623 preString = "sin(";
624 break;
625 case EOpCos:
626 preString = "cos(";
627 break;
628 case EOpTan:
629 preString = "tan(";
630 break;
631 case EOpAsin:
632 preString = "asin(";
633 break;
634 case EOpAcos:
635 preString = "acos(";
636 break;
637 case EOpAtan:
638 preString = "atan(";
639 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000640
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200641 case EOpSinh:
642 preString = "sinh(";
643 break;
644 case EOpCosh:
645 preString = "cosh(";
646 break;
647 case EOpTanh:
648 preString = "tanh(";
649 break;
650 case EOpAsinh:
651 preString = "asinh(";
652 break;
653 case EOpAcosh:
654 preString = "acosh(";
655 break;
656 case EOpAtanh:
657 preString = "atanh(";
658 break;
659
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700660 case EOpExp:
661 preString = "exp(";
662 break;
663 case EOpLog:
664 preString = "log(";
665 break;
666 case EOpExp2:
667 preString = "exp2(";
668 break;
669 case EOpLog2:
670 preString = "log2(";
671 break;
672 case EOpSqrt:
673 preString = "sqrt(";
674 break;
675 case EOpInverseSqrt:
676 preString = "inversesqrt(";
677 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000678
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700679 case EOpAbs:
680 preString = "abs(";
681 break;
682 case EOpSign:
683 preString = "sign(";
684 break;
685 case EOpFloor:
686 preString = "floor(";
687 break;
Qingqing Deng5dbece52015-02-27 20:35:38 -0800688 case EOpTrunc:
689 preString = "trunc(";
690 break;
691 case EOpRound:
692 preString = "round(";
693 break;
694 case EOpRoundEven:
695 preString = "roundEven(";
696 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700697 case EOpCeil:
698 preString = "ceil(";
699 break;
700 case EOpFract:
701 preString = "fract(";
702 break;
Arun Patole0c1726e2015-02-18 14:35:02 +0530703 case EOpIsNan:
704 preString = "isnan(";
705 break;
706 case EOpIsInf:
707 preString = "isinf(";
708 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000709
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200710 case EOpFloatBitsToInt:
711 preString = "floatBitsToInt(";
712 break;
713 case EOpFloatBitsToUint:
714 preString = "floatBitsToUint(";
715 break;
716 case EOpIntBitsToFloat:
717 preString = "intBitsToFloat(";
718 break;
719 case EOpUintBitsToFloat:
720 preString = "uintBitsToFloat(";
721 break;
722
Olli Etuaho7700ff62015-01-15 12:16:29 +0200723 case EOpPackSnorm2x16:
724 preString = "packSnorm2x16(";
725 break;
726 case EOpPackUnorm2x16:
727 preString = "packUnorm2x16(";
728 break;
729 case EOpPackHalf2x16:
730 preString = "packHalf2x16(";
731 break;
732 case EOpUnpackSnorm2x16:
733 preString = "unpackSnorm2x16(";
734 break;
735 case EOpUnpackUnorm2x16:
736 preString = "unpackUnorm2x16(";
737 break;
738 case EOpUnpackHalf2x16:
739 preString = "unpackHalf2x16(";
740 break;
741
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700742 case EOpLength:
743 preString = "length(";
744 break;
745 case EOpNormalize:
746 preString = "normalize(";
747 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000748
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700749 case EOpDFdx:
750 preString = "dFdx(";
751 break;
752 case EOpDFdy:
753 preString = "dFdy(";
754 break;
755 case EOpFwidth:
756 preString = "fwidth(";
757 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000758
Olli Etuahoe39706d2014-12-30 16:40:36 +0200759 case EOpTranspose:
760 preString = "transpose(";
761 break;
762 case EOpDeterminant:
763 preString = "determinant(";
764 break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +0200765 case EOpInverse:
766 preString = "inverse(";
767 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200768
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700769 case EOpAny:
770 preString = "any(";
771 break;
772 case EOpAll:
773 preString = "all(";
774 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000775
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700776 default:
777 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000778 }
779
zmo@google.com32e97312011-08-24 01:03:11 +0000780 if (visit == PreVisit && node->getUseEmulatedFunction())
781 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
782 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
783
zmo@google.com5601ea02011-06-10 18:23:25 +0000784 return true;
785}
786
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300787bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
788{
789 TInfoSinkBase &out = objSink();
790 // Notice two brackets at the beginning and end. The outer ones
791 // encapsulate the whole ternary expression. This preserves the
792 // order of precedence when ternary expressions are used in a
793 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
794 out << "((";
795 node->getCondition()->traverse(this);
796 out << ") ? (";
797 node->getTrueExpression()->traverse(this);
798 out << ") : (";
799 node->getFalseExpression()->traverse(this);
800 out << "))";
801 return false;
802}
803
Olli Etuaho57961272016-09-14 13:57:46 +0300804bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000805{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700806 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000807
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300808 out << "if (";
809 node->getCondition()->traverse(this);
810 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000811
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300812 incrementDepth(node);
813 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000814
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300815 if (node->getFalseBlock())
816 {
817 out << "else\n";
818 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000819 }
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300820 decrementDepth();
zmo@google.com5601ea02011-06-10 18:23:25 +0000821 return false;
822}
823
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200824bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200825{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200826 if (node->getStatementList())
827 {
828 writeTriplet(visit, "switch (", ") ", nullptr);
829 // The curly braces get written when visiting the statementList aggregate
830 }
831 else
832 {
833 // No statementList, so it won't output curly braces
834 writeTriplet(visit, "switch (", ") {", "}\n");
835 }
836 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200837}
838
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200839bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200840{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200841 if (node->hasCondition())
842 {
843 writeTriplet(visit, "case (", nullptr, "):\n");
844 return true;
845 }
846 else
847 {
848 TInfoSinkBase &out = objSink();
849 out << "default:\n";
850 return false;
851 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200852}
853
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100854bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
855{
856 TInfoSinkBase &out = objSink();
857 // Scope the blocks except when at the global scope.
858 if (mDepth > 0)
859 {
860 out << "{\n";
861 }
862
863 incrementDepth(node);
864 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
865 iter != node->getSequence()->end(); ++iter)
866 {
867 TIntermNode *curNode = *iter;
868 ASSERT(curNode != nullptr);
869 curNode->traverse(this);
870
871 if (isSingleStatement(curNode))
872 out << ";\n";
873 }
874 decrementDepth();
875
876 // Scope the blocks except when at the global scope.
877 if (mDepth > 0)
878 {
879 out << "}\n";
880 }
881 return false;
882}
883
Olli Etuaho336b1472016-10-05 16:37:55 +0100884bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
885{
886 TInfoSinkBase &out = objSink();
887
888 ASSERT(visit == PreVisit);
889 {
890 const TType &type = node->getType();
891 writeVariableType(type);
892 if (type.isArray())
893 out << arrayBrackets(type);
894 }
895
896 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
897
898 incrementDepth(node);
899
900 // Traverse function parameters.
901 TIntermAggregate *params = node->getFunctionParameters()->getAsAggregate();
902 ASSERT(params->getOp() == EOpParameters);
903 params->traverse(this);
904
905 // Traverse function body.
906 visitCodeBlock(node->getBody());
907 decrementDepth();
908
909 // Fully processed; no need to visit children.
910 return false;
911}
912
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700913bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000914{
915 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700916 TInfoSinkBase &out = objSink();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700917 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000918 switch (node->getOp())
919 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700920 case EOpPrototype:
921 // Function declaration.
922 ASSERT(visit == PreVisit);
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300923 {
924 const TType &type = node->getType();
925 writeVariableType(type);
926 if (type.isArray())
927 out << arrayBrackets(type);
928 }
929
Olli Etuahobd674552016-10-06 13:28:42 +0100930 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700931
932 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700933 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700934 out << ")";
935
936 visitChildren = false;
937 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700938 case EOpFunctionCall:
939 // Function call.
940 if (visit == PreVisit)
Olli Etuahobd674552016-10-06 13:28:42 +0100941 out << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200942 else if (visit == InVisit)
943 out << ", ";
944 else
945 out << ")";
946 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700947 case EOpParameters:
948 // Function parameters.
949 ASSERT(visit == PreVisit);
950 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700951 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700952 out << ")";
953 visitChildren = false;
954 break;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700955 case EOpInvariantDeclaration:
956 // Invariant declaration.
957 ASSERT(visit == PreVisit);
958 {
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400959 const TIntermSequence *sequence = node->getSequence();
960 ASSERT(sequence && sequence->size() == 1);
961 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
962 ASSERT(symbol);
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800963 writeInvariantQualifier(symbol->getType());
964 out << hashVariableName(symbol->getName());
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400965 }
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700966 visitChildren = false;
967 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700968 case EOpConstructFloat:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700969 case EOpConstructVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700970 case EOpConstructVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700971 case EOpConstructVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700972 case EOpConstructBool:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700973 case EOpConstructBVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700974 case EOpConstructBVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700975 case EOpConstructBVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700976 case EOpConstructInt:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700977 case EOpConstructIVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700978 case EOpConstructIVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700979 case EOpConstructIVec4:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400980 case EOpConstructUInt:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400981 case EOpConstructUVec2:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400982 case EOpConstructUVec3:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400983 case EOpConstructUVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700984 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400985 case EOpConstructMat2x3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400986 case EOpConstructMat2x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400987 case EOpConstructMat3x2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700988 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400989 case EOpConstructMat3x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400990 case EOpConstructMat4x2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400991 case EOpConstructMat4x3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700992 case EOpConstructMat4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700993 case EOpConstructStruct:
Olli Etuahoe92507b2016-07-04 11:20:10 +0300994 writeConstructorTriplet(visit, node->getType());
995 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000996
Olli Etuahoe39706d2014-12-30 16:40:36 +0200997 case EOpOuterProduct:
998 writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
999 break;
1000
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001001 case EOpLessThan:
1002 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
1003 break;
1004 case EOpGreaterThan:
1005 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
1006 break;
1007 case EOpLessThanEqual:
1008 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
1009 break;
1010 case EOpGreaterThanEqual:
1011 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
1012 break;
1013 case EOpVectorEqual:
1014 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
1015 break;
1016 case EOpVectorNotEqual:
1017 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
1018 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001019
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001020 case EOpMod:
1021 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
1022 break;
Olli Etuahob6e07a62015-02-16 12:22:10 +02001023 case EOpModf:
1024 writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
1025 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001026 case EOpPow:
1027 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
1028 break;
1029 case EOpAtan:
1030 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
1031 break;
1032 case EOpMin:
1033 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
1034 break;
1035 case EOpMax:
1036 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
1037 break;
1038 case EOpClamp:
1039 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
1040 break;
1041 case EOpMix:
1042 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
1043 break;
1044 case EOpStep:
1045 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
1046 break;
1047 case EOpSmoothStep:
1048 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
1049 break;
1050 case EOpDistance:
1051 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
1052 break;
1053 case EOpDot:
1054 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
1055 break;
1056 case EOpCross:
1057 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
1058 break;
1059 case EOpFaceForward:
1060 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
1061 break;
1062 case EOpReflect:
1063 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
1064 break;
1065 case EOpRefract:
1066 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
1067 break;
1068 case EOpMul:
1069 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
1070 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001071
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001072 default:
1073 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001074 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001075 return visitChildren;
1076}
1077
Olli Etuaho13389b62016-10-16 11:48:18 +01001078bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
1079{
1080 TInfoSinkBase &out = objSink();
1081
1082 // Variable declaration.
1083 if (visit == PreVisit)
1084 {
1085 const TIntermSequence &sequence = *(node->getSequence());
1086 const TIntermTyped *variable = sequence.front()->getAsTyped();
1087 writeLayoutQualifier(variable->getType());
1088 writeVariableType(variable->getType());
1089 out << " ";
1090 mDeclaringVariables = true;
1091 }
1092 else if (visit == InVisit)
1093 {
1094 out << ", ";
1095 mDeclaringVariables = true;
1096 }
1097 else
1098 {
1099 mDeclaringVariables = false;
1100 }
1101 return true;
1102}
1103
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001104bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001105{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001106 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001107
Zhenyao Mo7cab38b2013-10-15 12:59:30 -07001108 incrementDepth(node);
Corentin Wallez7258e302015-09-22 10:40:24 -07001109
zmo@google.com5601ea02011-06-10 18:23:25 +00001110 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001111
1112 // Only for loops can be unrolled
1113 ASSERT(!node->getUnrollFlag() || loopType == ELoopFor);
1114
zmo@google.com5601ea02011-06-10 18:23:25 +00001115 if (loopType == ELoopFor) // for loop
1116 {
Zhenyao Mo550c6002014-02-26 15:40:48 -08001117 if (!node->getUnrollFlag())
1118 {
zmo@google.com5601ea02011-06-10 18:23:25 +00001119 out << "for (";
1120 if (node->getInit())
1121 node->getInit()->traverse(this);
1122 out << "; ";
1123
1124 if (node->getCondition())
1125 node->getCondition()->traverse(this);
1126 out << "; ";
1127
1128 if (node->getExpression())
1129 node->getExpression()->traverse(this);
1130 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001131
1132 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001133 }
Zhenyao Mo550c6002014-02-26 15:40:48 -08001134 else
1135 {
1136 // Need to put a one-iteration loop here to handle break.
Olli Etuaho13389b62016-10-16 11:48:18 +01001137 TIntermSequence *declSeq = node->getInit()->getAsDeclarationNode()->getSequence();
Zhenyao Mo550c6002014-02-26 15:40:48 -08001138 TIntermSymbol *indexSymbol =
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001139 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001140 TString name = hashVariableName(indexSymbol->getName());
Zhenyao Mo550c6002014-02-26 15:40:48 -08001141 out << "for (int " << name << " = 0; "
1142 << name << " < 1; "
1143 << "++" << name << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001144
1145 out << "{\n";
1146 mLoopUnrollStack.push(node);
1147 while (mLoopUnrollStack.satisfiesLoopCondition())
1148 {
1149 visitCodeBlock(node->getBody());
1150 mLoopUnrollStack.step();
1151 }
1152 mLoopUnrollStack.pop();
1153 out << "}\n";
Zhenyao Mo550c6002014-02-26 15:40:48 -08001154 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001155 }
1156 else if (loopType == ELoopWhile) // while loop
1157 {
1158 out << "while (";
1159 ASSERT(node->getCondition() != NULL);
1160 node->getCondition()->traverse(this);
1161 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001162
1163 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001164 }
1165 else // do-while loop
1166 {
1167 ASSERT(loopType == ELoopDoWhile);
1168 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001169
zmo@google.com5601ea02011-06-10 18:23:25 +00001170 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001171
zmo@google.com5601ea02011-06-10 18:23:25 +00001172 out << "while (";
1173 ASSERT(node->getCondition() != NULL);
1174 node->getCondition()->traverse(this);
1175 out << ");\n";
1176 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001177
zmo@google.com5601ea02011-06-10 18:23:25 +00001178 decrementDepth();
1179
1180 // No need to visit children. They have been already processed in
1181 // this function.
1182 return false;
1183}
1184
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001185bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001186{
1187 switch (node->getFlowOp())
1188 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001189 case EOpKill:
1190 writeTriplet(visit, "discard", NULL, NULL);
1191 break;
1192 case EOpBreak:
1193 writeTriplet(visit, "break", NULL, NULL);
1194 break;
1195 case EOpContinue:
1196 writeTriplet(visit, "continue", NULL, NULL);
1197 break;
1198 case EOpReturn:
1199 writeTriplet(visit, "return ", NULL, NULL);
1200 break;
1201 default:
1202 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001203 }
1204
1205 return true;
1206}
1207
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001208void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001209{
zmo@google.com5601ea02011-06-10 18:23:25 +00001210 TInfoSinkBase &out = objSink();
1211 if (node != NULL)
1212 {
1213 node->traverse(this);
1214 // Single statements not part of a sequence need to be terminated
1215 // with semi-colon.
1216 if (isSingleStatement(node))
1217 out << ";\n";
1218 }
1219 else
1220 {
1221 out << "{\n}\n"; // Empty code block.
1222 }
1223}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001224
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001225TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001226{
Olli Etuahoe92507b2016-07-04 11:20:10 +03001227 if (type.getBasicType() == EbtStruct)
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001228 return hashName(TName(type.getStruct()->name()));
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001229 else
Olli Etuahoe92507b2016-07-04 11:20:10 +03001230 return type.getBuiltInTypeNameString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001231}
1232
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001233TString TOutputGLSLBase::hashName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001234{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001235 if (name.getString().empty())
1236 {
1237 ASSERT(!name.isInternal());
1238 return name.getString();
1239 }
1240 if (name.isInternal())
1241 {
1242 // TODO(oetuaho): Would be nicer to prefix non-internal names with "_" instead, like is
1243 // done in the HLSL output, but that requires fairly complex changes elsewhere in the code
1244 // as well.
1245 // We need to use a prefix that is reserved in WebGL in order to guarantee that the internal
1246 // names don't conflict with user-defined names from WebGL.
1247 return "webgl_angle_" + name.getString();
1248 }
1249 if (mHashFunction == nullptr)
1250 {
1251 return name.getString();
1252 }
1253 NameMap::const_iterator it = mNameMap.find(name.getString().c_str());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001254 if (it != mNameMap.end())
1255 return it->second.c_str();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001256 TString hashedName = TIntermTraverser::hash(name.getString(), mHashFunction);
1257 mNameMap[name.getString().c_str()] = hashedName.c_str();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001258 return hashedName;
1259}
1260
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001261TString TOutputGLSLBase::hashVariableName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001262{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001263 if (mSymbolTable.findBuiltIn(name.getString(), mShaderVersion) != NULL)
1264 return name.getString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001265 return hashName(name);
1266}
1267
Olli Etuaho59f9a642015-08-06 20:38:26 +03001268TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001269{
Olli Etuaho59f9a642015-08-06 20:38:26 +03001270 TString mangledStr = mangledName.getString();
1271 TString name = TFunction::unmangleName(mangledStr);
1272 if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001273 return translateTextureFunction(name);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001274 if (mangledName.isInternal())
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001275 {
1276 // Internal function names are outputted as-is - they may refer to functions manually added
1277 // to the output shader source that are not included in the AST at all.
Olli Etuaho59f9a642015-08-06 20:38:26 +03001278 return name;
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001279 }
Olli Etuaho59f9a642015-08-06 20:38:26 +03001280 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001281 {
1282 TName nameObj(name);
1283 return hashName(nameObj);
1284 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001285}
Jamie Madill98493dd2013-07-08 14:39:03 -04001286
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001287bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001288{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001289 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001290 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001291 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001292 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001293 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001294
1295 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001296}
1297
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001298void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001299{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001300 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001301
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001302 out << "struct " << hashName(TName(structure->name())) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001303 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001304 for (size_t i = 0; i < fields.size(); ++i)
1305 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001306 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001307 if (writeVariablePrecision(field->type()->getPrecision()))
1308 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001309 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Jamie Madill98493dd2013-07-08 14:39:03 -04001310 if (field->type()->isArray())
1311 out << arrayBrackets(*field->type());
1312 out << ";\n";
1313 }
1314 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001315}
Jamie Madill98493dd2013-07-08 14:39:03 -04001316
Geoff Langbdcc54a2015-09-02 13:09:48 -04001317void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1318{
1319 TInfoSinkBase &out = objSink();
1320
1321 out << "layout(";
1322
1323 switch (interfaceBlock->blockStorage())
1324 {
1325 case EbsUnspecified:
1326 case EbsShared:
1327 // Default block storage is shared.
1328 out << "shared";
1329 break;
1330
1331 case EbsPacked:
1332 out << "packed";
1333 break;
1334
1335 case EbsStd140:
1336 out << "std140";
1337 break;
1338
1339 default:
1340 UNREACHABLE();
1341 break;
1342 }
1343
1344 out << ", ";
1345
1346 switch (interfaceBlock->matrixPacking())
1347 {
1348 case EmpUnspecified:
1349 case EmpColumnMajor:
1350 // Default matrix packing is column major.
1351 out << "column_major";
1352 break;
1353
1354 case EmpRowMajor:
1355 out << "row_major";
1356 break;
1357
1358 default:
1359 UNREACHABLE();
1360 break;
1361 }
1362
1363 out << ") ";
1364}
1365
1366void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1367{
1368 TInfoSinkBase &out = objSink();
1369
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001370 out << hashName(TName(interfaceBlock->name())) << "{\n";
Geoff Langbdcc54a2015-09-02 13:09:48 -04001371 const TFieldList &fields = interfaceBlock->fields();
1372 for (size_t i = 0; i < fields.size(); ++i)
1373 {
1374 const TField *field = fields[i];
1375 if (writeVariablePrecision(field->type()->getPrecision()))
1376 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001377 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Geoff Langbdcc54a2015-09-02 13:09:48 -04001378 if (field->type()->isArray())
1379 out << arrayBrackets(*field->type());
1380 out << ";\n";
1381 }
1382 out << "}";
1383}
Jamie Madill45bcc782016-11-07 13:58:48 -05001384
1385} // namespace sh