blob: a041cfa28612d6437d110a3d4b66345384fea5ff [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
zmo@google.com5601ea02011-06-10 18:23:25 +000013namespace
14{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070015TString arrayBrackets(const TType &type)
zmo@google.com5601ea02011-06-10 18:23:25 +000016{
17 ASSERT(type.isArray());
18 TInfoSinkBase out;
19 out << "[" << type.getArraySize() << "]";
20 return TString(out.c_str());
21}
22
Zhenyao Mo9eedea02014-05-12 16:02:35 -070023bool isSingleStatement(TIntermNode *node)
24{
Olli Etuaho336b1472016-10-05 16:37:55 +010025 if (node->getAsFunctionDefinition())
zmo@google.com5601ea02011-06-10 18:23:25 +000026 {
Olli Etuaho336b1472016-10-05 16:37:55 +010027 return false;
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010028 }
29 else if (node->getAsBlock())
30 {
31 return false;
zmo@google.com5601ea02011-06-10 18:23:25 +000032 }
Olli Etuaho57961272016-09-14 13:57:46 +030033 else if (node->getAsIfElseNode())
zmo@google.com5601ea02011-06-10 18:23:25 +000034 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +030035 return false;
zmo@google.com5601ea02011-06-10 18:23:25 +000036 }
37 else if (node->getAsLoopNode())
38 {
39 return false;
40 }
Olli Etuaho01cd8af2015-02-20 10:39:20 +020041 else if (node->getAsSwitchNode())
42 {
43 return false;
44 }
45 else if (node->getAsCaseNode())
46 {
47 return false;
48 }
zmo@google.com5601ea02011-06-10 18:23:25 +000049 return true;
50}
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080051
Martin Radev2cc85b32016-08-05 16:22:53 +030052// If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
53// variables with specified layout qualifiers are copied. Additional checks are needed against the
54// type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
55// TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
56// NeedsToWriteLayoutQualifier.
57bool NeedsToWriteLayoutQualifier(const TType &type)
58{
59 if (type.getBasicType() == EbtInterfaceBlock)
60 {
61 return false;
62 }
63
64 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
65
66 if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn) &&
67 layoutQualifier.location >= 0)
68 {
69 return true;
70 }
71 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
72 {
73 return true;
74 }
75 return false;
76}
77
zmo@google.com5601ea02011-06-10 18:23:25 +000078} // namespace
79
Zhenyao Mo9eedea02014-05-12 16:02:35 -070080TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000081 ShArrayIndexClampingStrategy clampingStrategy,
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000082 ShHashFunction64 hashFunction,
Zhenyao Mo9eedea02014-05-12 16:02:35 -070083 NameMap &nameMap,
84 TSymbolTable &symbolTable,
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080085 int shaderVersion,
86 ShShaderOutput output)
zmo@google.com5601ea02011-06-10 18:23:25 +000087 : TIntermTraverser(true, true, true),
88 mObjSink(objSink),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000089 mDeclaringVariables(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000090 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000091 mHashFunction(hashFunction),
92 mNameMap(nameMap),
Jamie Madill02f20dd2013-09-12 12:07:42 -040093 mSymbolTable(symbolTable),
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080094 mShaderVersion(shaderVersion),
95 mOutput(output)
zmo@google.com5601ea02011-06-10 18:23:25 +000096{
97}
98
Zhenyao Mo9eedea02014-05-12 16:02:35 -070099void TOutputGLSLBase::writeTriplet(
100 Visit visit, const char *preStr, const char *inStr, const char *postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000101{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700102 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000103 if (visit == PreVisit && preStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000104 out << preStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000105 else if (visit == InVisit && inStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000106 out << inStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000107 else if (visit == PostVisit && postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000108 out << postStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000109}
110
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700111void TOutputGLSLBase::writeBuiltInFunctionTriplet(
112 Visit visit, const char *preStr, bool useEmulatedFunction)
zmo@google.com5601ea02011-06-10 18:23:25 +0000113{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700114 TString preString = useEmulatedFunction ?
115 BuiltInFunctionEmulator::GetEmulatedFunctionName(preStr) : preStr;
116 writeTriplet(visit, preString.c_str(), ", ", ")");
117}
118
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300119void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
120{
Martin Radev2cc85b32016-08-05 16:22:53 +0300121 if (!NeedsToWriteLayoutQualifier(type))
122 {
123 return;
124 }
125
126 TInfoSinkBase &out = objSink();
127 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
128 out << "layout(";
129
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300130 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
131 {
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300132 if (layoutQualifier.location >= 0)
133 {
Martin Radev2cc85b32016-08-05 16:22:53 +0300134 out << "location = " << layoutQualifier.location;
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300135 }
136 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300137
138 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
139 {
140 ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
141 out << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
142 }
143
144 out << ") ";
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300145}
146
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700147void TOutputGLSLBase::writeVariableType(const TType &type)
148{
Qiankun Miaod842a6b2016-08-29 10:05:27 +0800149 TQualifier qualifier = type.getQualifier();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700150 TInfoSinkBase &out = objSink();
Qiankun Miaod842a6b2016-08-29 10:05:27 +0800151 if (type.isInvariant() && qualifier != EvqFragmentIn && !IsGLSL420OrNewer(mOutput))
Olli Etuaho214c2d82015-04-27 14:49:13 +0300152 {
153 out << "invariant ";
154 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400155 if (type.getBasicType() == EbtInterfaceBlock)
156 {
157 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
158 declareInterfaceBlockLayout(interfaceBlock);
159 }
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400160 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400161 {
Qingqing Dengad0d0792015-04-08 14:25:06 -0700162 if (IsGLSL130OrNewer(mOutput))
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800163 {
164 switch (qualifier)
165 {
166 case EvqAttribute:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300167 out << "in ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800168 break;
169 case EvqVaryingIn:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300170 out << "in ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800171 break;
172 case EvqVaryingOut:
Olli Etuaho214c2d82015-04-27 14:49:13 +0300173 out << "out ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800174 break;
175 default:
176 out << type.getQualifierString() << " ";
177 break;
178 }
179 }
180 else
181 {
182 out << type.getQualifierString() << " ";
183 }
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400184 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300185
186 const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
187 if (memoryQualifier.readonly)
188 {
189 ASSERT(IsImage(type.getBasicType()));
190 out << "readonly ";
191 }
192
193 if (memoryQualifier.writeonly)
194 {
195 ASSERT(IsImage(type.getBasicType()));
196 out << "writeonly ";
197 }
198
zmo@google.com5601ea02011-06-10 18:23:25 +0000199 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700200 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000201 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400202 TStructure *structure = type.getStruct();
203
204 declareStruct(structure);
205
206 if (!structure->name().empty())
207 {
208 mDeclaredStructs.insert(structure->uniqueId());
209 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000210 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400211 else if (type.getBasicType() == EbtInterfaceBlock)
212 {
213 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
214 declareInterfaceBlock(interfaceBlock);
215 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000216 else
217 {
218 if (writeVariablePrecision(type.getPrecision()))
219 out << " ";
220 out << getTypeName(type);
221 }
222}
223
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700224void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000225{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700226 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000227 for (TIntermSequence::const_iterator iter = args.begin();
228 iter != args.end(); ++iter)
229 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700230 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000231 ASSERT(arg != NULL);
232
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700233 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000234 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000235
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700236 const TString &name = arg->getSymbol();
zmo@google.com5601ea02011-06-10 18:23:25 +0000237 if (!name.empty())
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000238 out << " " << hashName(name);
zmo@google.com5601ea02011-06-10 18:23:25 +0000239 if (type.isArray())
240 out << arrayBrackets(type);
241
242 // Put a comma if this is not the last argument.
243 if (iter != args.end() - 1)
244 out << ", ";
245 }
246}
247
Jamie Madill6ba6ead2015-05-04 14:21:21 -0400248const TConstantUnion *TOutputGLSLBase::writeConstantUnion(
249 const TType &type, const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000250{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700251 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000252
253 if (type.getBasicType() == EbtStruct)
254 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700255 const TStructure *structure = type.getStruct();
Jamie Madill98493dd2013-07-08 14:39:03 -0400256 out << hashName(structure->name()) << "(";
257
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700258 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400259 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000260 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700261 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000262 ASSERT(fieldType != NULL);
263 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700264 if (i != fields.size() - 1)
265 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000266 }
267 out << ")";
268 }
269 else
270 {
Jamie Madill94bf7f22013-07-08 13:31:15 -0400271 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000272 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700273 if (writeType)
274 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400275 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000276 {
277 switch (pConstUnion->getType())
278 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700279 case EbtFloat:
280 out << std::min(FLT_MAX, std::max(-FLT_MAX, pConstUnion->getFConst()));
281 break;
282 case EbtInt:
283 out << pConstUnion->getIConst();
284 break;
Olli Etuaho5321c802015-04-02 17:08:16 +0300285 case EbtUInt:
286 out << pConstUnion->getUConst() << "u";
287 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700288 case EbtBool:
289 out << pConstUnion->getBConst();
290 break;
291 default: UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000292 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700293 if (i != size - 1)
294 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000295 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700296 if (writeType)
297 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000298 }
299 return pConstUnion;
300}
301
Olli Etuahoe92507b2016-07-04 11:20:10 +0300302void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
Olli Etuahof40319e2015-03-10 14:33:00 +0200303{
304 TInfoSinkBase &out = objSink();
305 if (visit == PreVisit)
306 {
307 if (type.isArray())
308 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300309 out << getTypeName(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200310 out << arrayBrackets(type);
311 out << "(";
312 }
313 else
314 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300315 out << getTypeName(type) << "(";
Olli Etuahof40319e2015-03-10 14:33:00 +0200316 }
317 }
318 else
319 {
320 writeTriplet(visit, nullptr, ", ", ")");
321 }
322}
323
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700324void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000325{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700326 TInfoSinkBase &out = objSink();
Zhenyao Mo550c6002014-02-26 15:40:48 -0800327 if (mLoopUnrollStack.needsToReplaceSymbolWithValue(node))
328 out << mLoopUnrollStack.getLoopIndexValue(node);
zmo@google.com5601ea02011-06-10 18:23:25 +0000329 else
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000330 out << hashVariableName(node->getSymbol());
zmo@google.com5601ea02011-06-10 18:23:25 +0000331
332 if (mDeclaringVariables && node->getType().isArray())
333 out << arrayBrackets(node->getType());
334}
335
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700336void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000337{
338 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
339}
340
Olli Etuahob6fa0432016-09-28 16:28:05 +0100341bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
342{
343 TInfoSinkBase &out = objSink();
344 if (visit == PostVisit)
345 {
346 out << ".";
347 node->writeOffsetsAsXYZW(&out);
348 }
349 return true;
350}
351
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700352bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000353{
354 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700355 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000356 switch (node->getOp())
357 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100358 case EOpComma:
359 writeTriplet(visit, "(", ", ", ")");
360 break;
361 case EOpInitialize:
zmo@google.com5601ea02011-06-10 18:23:25 +0000362 if (visit == InVisit)
363 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100364 out << " = ";
365 // RHS of initialize is not being declared.
366 mDeclaringVariables = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000367 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100368 break;
369 case EOpAssign:
370 writeTriplet(visit, "(", " = ", ")");
371 break;
372 case EOpAddAssign:
373 writeTriplet(visit, "(", " += ", ")");
374 break;
375 case EOpSubAssign:
376 writeTriplet(visit, "(", " -= ", ")");
377 break;
378 case EOpDivAssign:
379 writeTriplet(visit, "(", " /= ", ")");
380 break;
381 case EOpIModAssign:
382 writeTriplet(visit, "(", " %= ", ")");
383 break;
384 // Notice the fall-through.
385 case EOpMulAssign:
386 case EOpVectorTimesMatrixAssign:
387 case EOpVectorTimesScalarAssign:
388 case EOpMatrixTimesScalarAssign:
389 case EOpMatrixTimesMatrixAssign:
390 writeTriplet(visit, "(", " *= ", ")");
391 break;
392 case EOpBitShiftLeftAssign:
393 writeTriplet(visit, "(", " <<= ", ")");
394 break;
395 case EOpBitShiftRightAssign:
396 writeTriplet(visit, "(", " >>= ", ")");
397 break;
398 case EOpBitwiseAndAssign:
399 writeTriplet(visit, "(", " &= ", ")");
400 break;
401 case EOpBitwiseXorAssign:
402 writeTriplet(visit, "(", " ^= ", ")");
403 break;
404 case EOpBitwiseOrAssign:
405 writeTriplet(visit, "(", " |= ", ")");
406 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000407
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100408 case EOpIndexDirect:
zmo@google.com5601ea02011-06-10 18:23:25 +0000409 writeTriplet(visit, NULL, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100410 break;
411 case EOpIndexIndirect:
412 if (node->getAddIndexClamp())
413 {
414 if (visit == InVisit)
415 {
416 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
417 out << "[int(clamp(float(";
418 else
419 out << "[webgl_int_clamp(";
420 }
421 else if (visit == PostVisit)
422 {
423 int maxSize;
424 TIntermTyped *left = node->getLeft();
425 TType leftType = left->getType();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700426
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100427 if (left->isArray())
428 {
429 // The shader will fail validation if the array length is not > 0.
430 maxSize = static_cast<int>(leftType.getArraySize()) - 1;
431 }
432 else
433 {
434 maxSize = leftType.getNominalSize() - 1;
435 }
436
437 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
438 out << "), 0.0, float(" << maxSize << ")))]";
439 else
440 out << ", 0, " << maxSize << ")]";
441 }
442 }
443 else
444 {
445 writeTriplet(visit, NULL, "[", "]");
446 }
447 break;
448 case EOpIndexDirectStruct:
449 if (visit == InVisit)
450 {
451 // Here we are writing out "foo.bar", where "foo" is struct
452 // and "bar" is field. In AST, it is represented as a binary
453 // node, where left child represents "foo" and right child "bar".
454 // The node itself represents ".". The struct field "bar" is
455 // actually stored as an index into TStructure::fields.
456 out << ".";
457 const TStructure *structure = node->getLeft()->getType().getStruct();
458 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
459 const TField *field = structure->fields()[index->getIConst(0)];
460
461 TString fieldName = field->name();
462 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
463 fieldName = hashName(fieldName);
464
465 out << fieldName;
466 visitChildren = false;
467 }
468 break;
469 case EOpIndexDirectInterfaceBlock:
470 if (visit == InVisit)
471 {
472 out << ".";
473 const TInterfaceBlock *interfaceBlock =
474 node->getLeft()->getType().getInterfaceBlock();
475 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
476 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
477
478 TString fieldName = field->name();
479 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700480 fieldName = hashName(fieldName);
481
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100482 out << fieldName;
483 visitChildren = false;
484 }
485 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400486
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100487 case EOpAdd:
488 writeTriplet(visit, "(", " + ", ")");
489 break;
490 case EOpSub:
491 writeTriplet(visit, "(", " - ", ")");
492 break;
493 case EOpMul:
494 writeTriplet(visit, "(", " * ", ")");
495 break;
496 case EOpDiv:
497 writeTriplet(visit, "(", " / ", ")");
498 break;
499 case EOpIMod:
500 writeTriplet(visit, "(", " % ", ")");
501 break;
502 case EOpBitShiftLeft:
503 writeTriplet(visit, "(", " << ", ")");
504 break;
505 case EOpBitShiftRight:
506 writeTriplet(visit, "(", " >> ", ")");
507 break;
508 case EOpBitwiseAnd:
509 writeTriplet(visit, "(", " & ", ")");
510 break;
511 case EOpBitwiseXor:
512 writeTriplet(visit, "(", " ^ ", ")");
513 break;
514 case EOpBitwiseOr:
515 writeTriplet(visit, "(", " | ", ")");
516 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400517
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100518 case EOpEqual:
519 writeTriplet(visit, "(", " == ", ")");
520 break;
521 case EOpNotEqual:
522 writeTriplet(visit, "(", " != ", ")");
523 break;
524 case EOpLessThan:
525 writeTriplet(visit, "(", " < ", ")");
526 break;
527 case EOpGreaterThan:
528 writeTriplet(visit, "(", " > ", ")");
529 break;
530 case EOpLessThanEqual:
531 writeTriplet(visit, "(", " <= ", ")");
532 break;
533 case EOpGreaterThanEqual:
534 writeTriplet(visit, "(", " >= ", ")");
535 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000536
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100537 // Notice the fall-through.
538 case EOpVectorTimesScalar:
539 case EOpVectorTimesMatrix:
540 case EOpMatrixTimesVector:
541 case EOpMatrixTimesScalar:
542 case EOpMatrixTimesMatrix:
543 writeTriplet(visit, "(", " * ", ")");
544 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200545
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100546 case EOpLogicalOr:
547 writeTriplet(visit, "(", " || ", ")");
548 break;
549 case EOpLogicalXor:
550 writeTriplet(visit, "(", " ^^ ", ")");
551 break;
552 case EOpLogicalAnd:
553 writeTriplet(visit, "(", " && ", ")");
554 break;
555 default:
556 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000557 }
558
559 return visitChildren;
560}
561
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700562bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000563{
zmo@google.com32e97312011-08-24 01:03:11 +0000564 TString preString;
565 TString postString = ")";
566
zmo@google.com5601ea02011-06-10 18:23:25 +0000567 switch (node->getOp())
568 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700569 case EOpNegative: preString = "(-"; break;
Zhenyao Mode1e00e2014-10-09 16:55:32 -0700570 case EOpPositive: preString = "(+"; break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700571 case EOpVectorLogicalNot: preString = "not("; break;
572 case EOpLogicalNot: preString = "(!"; break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200573 case EOpBitwiseNot: preString = "(~"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000574
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700575 case EOpPostIncrement: preString = "("; postString = "++)"; break;
576 case EOpPostDecrement: preString = "("; postString = "--)"; break;
577 case EOpPreIncrement: preString = "(++"; break;
578 case EOpPreDecrement: preString = "(--"; break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000579
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700580 case EOpRadians:
581 preString = "radians(";
582 break;
583 case EOpDegrees:
584 preString = "degrees(";
585 break;
586 case EOpSin:
587 preString = "sin(";
588 break;
589 case EOpCos:
590 preString = "cos(";
591 break;
592 case EOpTan:
593 preString = "tan(";
594 break;
595 case EOpAsin:
596 preString = "asin(";
597 break;
598 case EOpAcos:
599 preString = "acos(";
600 break;
601 case EOpAtan:
602 preString = "atan(";
603 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000604
Olli Etuaho5c9cd3d2014-12-18 13:04:25 +0200605 case EOpSinh:
606 preString = "sinh(";
607 break;
608 case EOpCosh:
609 preString = "cosh(";
610 break;
611 case EOpTanh:
612 preString = "tanh(";
613 break;
614 case EOpAsinh:
615 preString = "asinh(";
616 break;
617 case EOpAcosh:
618 preString = "acosh(";
619 break;
620 case EOpAtanh:
621 preString = "atanh(";
622 break;
623
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700624 case EOpExp:
625 preString = "exp(";
626 break;
627 case EOpLog:
628 preString = "log(";
629 break;
630 case EOpExp2:
631 preString = "exp2(";
632 break;
633 case EOpLog2:
634 preString = "log2(";
635 break;
636 case EOpSqrt:
637 preString = "sqrt(";
638 break;
639 case EOpInverseSqrt:
640 preString = "inversesqrt(";
641 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000642
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700643 case EOpAbs:
644 preString = "abs(";
645 break;
646 case EOpSign:
647 preString = "sign(";
648 break;
649 case EOpFloor:
650 preString = "floor(";
651 break;
Qingqing Deng5dbece52015-02-27 20:35:38 -0800652 case EOpTrunc:
653 preString = "trunc(";
654 break;
655 case EOpRound:
656 preString = "round(";
657 break;
658 case EOpRoundEven:
659 preString = "roundEven(";
660 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700661 case EOpCeil:
662 preString = "ceil(";
663 break;
664 case EOpFract:
665 preString = "fract(";
666 break;
Arun Patole0c1726e2015-02-18 14:35:02 +0530667 case EOpIsNan:
668 preString = "isnan(";
669 break;
670 case EOpIsInf:
671 preString = "isinf(";
672 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000673
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200674 case EOpFloatBitsToInt:
675 preString = "floatBitsToInt(";
676 break;
677 case EOpFloatBitsToUint:
678 preString = "floatBitsToUint(";
679 break;
680 case EOpIntBitsToFloat:
681 preString = "intBitsToFloat(";
682 break;
683 case EOpUintBitsToFloat:
684 preString = "uintBitsToFloat(";
685 break;
686
Olli Etuaho7700ff62015-01-15 12:16:29 +0200687 case EOpPackSnorm2x16:
688 preString = "packSnorm2x16(";
689 break;
690 case EOpPackUnorm2x16:
691 preString = "packUnorm2x16(";
692 break;
693 case EOpPackHalf2x16:
694 preString = "packHalf2x16(";
695 break;
696 case EOpUnpackSnorm2x16:
697 preString = "unpackSnorm2x16(";
698 break;
699 case EOpUnpackUnorm2x16:
700 preString = "unpackUnorm2x16(";
701 break;
702 case EOpUnpackHalf2x16:
703 preString = "unpackHalf2x16(";
704 break;
705
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700706 case EOpLength:
707 preString = "length(";
708 break;
709 case EOpNormalize:
710 preString = "normalize(";
711 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000712
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700713 case EOpDFdx:
714 preString = "dFdx(";
715 break;
716 case EOpDFdy:
717 preString = "dFdy(";
718 break;
719 case EOpFwidth:
720 preString = "fwidth(";
721 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000722
Olli Etuahoe39706d2014-12-30 16:40:36 +0200723 case EOpTranspose:
724 preString = "transpose(";
725 break;
726 case EOpDeterminant:
727 preString = "determinant(";
728 break;
Olli Etuahoabf6dad2015-01-14 14:45:16 +0200729 case EOpInverse:
730 preString = "inverse(";
731 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200732
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700733 case EOpAny:
734 preString = "any(";
735 break;
736 case EOpAll:
737 preString = "all(";
738 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000739
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700740 default:
741 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000742 }
743
zmo@google.com32e97312011-08-24 01:03:11 +0000744 if (visit == PreVisit && node->getUseEmulatedFunction())
745 preString = BuiltInFunctionEmulator::GetEmulatedFunctionName(preString);
746 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
747
zmo@google.com5601ea02011-06-10 18:23:25 +0000748 return true;
749}
750
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300751bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
752{
753 TInfoSinkBase &out = objSink();
754 // Notice two brackets at the beginning and end. The outer ones
755 // encapsulate the whole ternary expression. This preserves the
756 // order of precedence when ternary expressions are used in a
757 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
758 out << "((";
759 node->getCondition()->traverse(this);
760 out << ") ? (";
761 node->getTrueExpression()->traverse(this);
762 out << ") : (";
763 node->getFalseExpression()->traverse(this);
764 out << "))";
765 return false;
766}
767
Olli Etuaho57961272016-09-14 13:57:46 +0300768bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000769{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700770 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000771
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300772 out << "if (";
773 node->getCondition()->traverse(this);
774 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000775
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300776 incrementDepth(node);
777 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000778
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300779 if (node->getFalseBlock())
780 {
781 out << "else\n";
782 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000783 }
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300784 decrementDepth();
zmo@google.com5601ea02011-06-10 18:23:25 +0000785 return false;
786}
787
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200788bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200789{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200790 if (node->getStatementList())
791 {
792 writeTriplet(visit, "switch (", ") ", nullptr);
793 // The curly braces get written when visiting the statementList aggregate
794 }
795 else
796 {
797 // No statementList, so it won't output curly braces
798 writeTriplet(visit, "switch (", ") {", "}\n");
799 }
800 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200801}
802
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200803bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200804{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200805 if (node->hasCondition())
806 {
807 writeTriplet(visit, "case (", nullptr, "):\n");
808 return true;
809 }
810 else
811 {
812 TInfoSinkBase &out = objSink();
813 out << "default:\n";
814 return false;
815 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200816}
817
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100818bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
819{
820 TInfoSinkBase &out = objSink();
821 // Scope the blocks except when at the global scope.
822 if (mDepth > 0)
823 {
824 out << "{\n";
825 }
826
827 incrementDepth(node);
828 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
829 iter != node->getSequence()->end(); ++iter)
830 {
831 TIntermNode *curNode = *iter;
832 ASSERT(curNode != nullptr);
833 curNode->traverse(this);
834
835 if (isSingleStatement(curNode))
836 out << ";\n";
837 }
838 decrementDepth();
839
840 // Scope the blocks except when at the global scope.
841 if (mDepth > 0)
842 {
843 out << "}\n";
844 }
845 return false;
846}
847
Olli Etuaho336b1472016-10-05 16:37:55 +0100848bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
849{
850 TInfoSinkBase &out = objSink();
851
852 ASSERT(visit == PreVisit);
853 {
854 const TType &type = node->getType();
855 writeVariableType(type);
856 if (type.isArray())
857 out << arrayBrackets(type);
858 }
859
860 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
861
862 incrementDepth(node);
863
864 // Traverse function parameters.
865 TIntermAggregate *params = node->getFunctionParameters()->getAsAggregate();
866 ASSERT(params->getOp() == EOpParameters);
867 params->traverse(this);
868
869 // Traverse function body.
870 visitCodeBlock(node->getBody());
871 decrementDepth();
872
873 // Fully processed; no need to visit children.
874 return false;
875}
876
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700877bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000878{
879 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700880 TInfoSinkBase &out = objSink();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700881 bool useEmulatedFunction = (visit == PreVisit && node->getUseEmulatedFunction());
zmo@google.com5601ea02011-06-10 18:23:25 +0000882 switch (node->getOp())
883 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700884 case EOpPrototype:
885 // Function declaration.
886 ASSERT(visit == PreVisit);
Olli Etuahoab6fc6a2015-04-13 12:10:20 +0300887 {
888 const TType &type = node->getType();
889 writeVariableType(type);
890 if (type.isArray())
891 out << arrayBrackets(type);
892 }
893
Olli Etuahobd674552016-10-06 13:28:42 +0100894 out << " " << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700895
896 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700897 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700898 out << ")";
899
900 visitChildren = false;
901 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700902 case EOpFunctionCall:
903 // Function call.
904 if (visit == PreVisit)
Olli Etuahobd674552016-10-06 13:28:42 +0100905 out << hashFunctionNameIfNeeded(node->getFunctionSymbolInfo()->getNameObj()) << "(";
Olli Etuaho853dc1a2014-11-06 17:25:48 +0200906 else if (visit == InVisit)
907 out << ", ";
908 else
909 out << ")";
910 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700911 case EOpParameters:
912 // Function parameters.
913 ASSERT(visit == PreVisit);
914 out << "(";
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700915 writeFunctionParameters(*(node->getSequence()));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700916 out << ")";
917 visitChildren = false;
918 break;
919 case EOpDeclaration:
920 // Variable declaration.
921 if (visit == PreVisit)
922 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700923 const TIntermSequence &sequence = *(node->getSequence());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700924 const TIntermTyped *variable = sequence.front()->getAsTyped();
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300925 writeLayoutQualifier(variable->getType());
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700926 writeVariableType(variable->getType());
927 out << " ";
928 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000929 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700930 else if (visit == InVisit)
931 {
932 out << ", ";
933 mDeclaringVariables = true;
zmo@google.com5601ea02011-06-10 18:23:25 +0000934 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700935 else
936 {
937 mDeclaringVariables = false;
938 }
939 break;
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700940 case EOpInvariantDeclaration:
941 // Invariant declaration.
942 ASSERT(visit == PreVisit);
943 {
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400944 const TIntermSequence *sequence = node->getSequence();
945 ASSERT(sequence && sequence->size() == 1);
946 const TIntermSymbol *symbol = sequence->front()->getAsSymbolNode();
947 ASSERT(symbol);
Zhenyao Mo2a517272014-10-27 16:09:57 -0700948 out << "invariant " << hashVariableName(symbol->getSymbol());
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400949 }
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700950 visitChildren = false;
951 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700952 case EOpConstructFloat:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700953 case EOpConstructVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700954 case EOpConstructVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700955 case EOpConstructVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700956 case EOpConstructBool:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700957 case EOpConstructBVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700958 case EOpConstructBVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700959 case EOpConstructBVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700960 case EOpConstructInt:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700961 case EOpConstructIVec2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700962 case EOpConstructIVec3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700963 case EOpConstructIVec4:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400964 case EOpConstructUInt:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400965 case EOpConstructUVec2:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400966 case EOpConstructUVec3:
Geoff Langc4c7442d2015-07-20 13:09:26 -0400967 case EOpConstructUVec4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700968 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400969 case EOpConstructMat2x3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400970 case EOpConstructMat2x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400971 case EOpConstructMat3x2:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700972 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400973 case EOpConstructMat3x4:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400974 case EOpConstructMat4x2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400975 case EOpConstructMat4x3:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700976 case EOpConstructMat4:
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700977 case EOpConstructStruct:
Olli Etuahoe92507b2016-07-04 11:20:10 +0300978 writeConstructorTriplet(visit, node->getType());
979 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000980
Olli Etuahoe39706d2014-12-30 16:40:36 +0200981 case EOpOuterProduct:
982 writeBuiltInFunctionTriplet(visit, "outerProduct(", useEmulatedFunction);
983 break;
984
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700985 case EOpLessThan:
986 writeBuiltInFunctionTriplet(visit, "lessThan(", useEmulatedFunction);
987 break;
988 case EOpGreaterThan:
989 writeBuiltInFunctionTriplet(visit, "greaterThan(", useEmulatedFunction);
990 break;
991 case EOpLessThanEqual:
992 writeBuiltInFunctionTriplet(visit, "lessThanEqual(", useEmulatedFunction);
993 break;
994 case EOpGreaterThanEqual:
995 writeBuiltInFunctionTriplet(visit, "greaterThanEqual(", useEmulatedFunction);
996 break;
997 case EOpVectorEqual:
998 writeBuiltInFunctionTriplet(visit, "equal(", useEmulatedFunction);
999 break;
1000 case EOpVectorNotEqual:
1001 writeBuiltInFunctionTriplet(visit, "notEqual(", useEmulatedFunction);
1002 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001003
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001004 case EOpMod:
1005 writeBuiltInFunctionTriplet(visit, "mod(", useEmulatedFunction);
1006 break;
Olli Etuahob6e07a62015-02-16 12:22:10 +02001007 case EOpModf:
1008 writeBuiltInFunctionTriplet(visit, "modf(", useEmulatedFunction);
1009 break;
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001010 case EOpPow:
1011 writeBuiltInFunctionTriplet(visit, "pow(", useEmulatedFunction);
1012 break;
1013 case EOpAtan:
1014 writeBuiltInFunctionTriplet(visit, "atan(", useEmulatedFunction);
1015 break;
1016 case EOpMin:
1017 writeBuiltInFunctionTriplet(visit, "min(", useEmulatedFunction);
1018 break;
1019 case EOpMax:
1020 writeBuiltInFunctionTriplet(visit, "max(", useEmulatedFunction);
1021 break;
1022 case EOpClamp:
1023 writeBuiltInFunctionTriplet(visit, "clamp(", useEmulatedFunction);
1024 break;
1025 case EOpMix:
1026 writeBuiltInFunctionTriplet(visit, "mix(", useEmulatedFunction);
1027 break;
1028 case EOpStep:
1029 writeBuiltInFunctionTriplet(visit, "step(", useEmulatedFunction);
1030 break;
1031 case EOpSmoothStep:
1032 writeBuiltInFunctionTriplet(visit, "smoothstep(", useEmulatedFunction);
1033 break;
1034 case EOpDistance:
1035 writeBuiltInFunctionTriplet(visit, "distance(", useEmulatedFunction);
1036 break;
1037 case EOpDot:
1038 writeBuiltInFunctionTriplet(visit, "dot(", useEmulatedFunction);
1039 break;
1040 case EOpCross:
1041 writeBuiltInFunctionTriplet(visit, "cross(", useEmulatedFunction);
1042 break;
1043 case EOpFaceForward:
1044 writeBuiltInFunctionTriplet(visit, "faceforward(", useEmulatedFunction);
1045 break;
1046 case EOpReflect:
1047 writeBuiltInFunctionTriplet(visit, "reflect(", useEmulatedFunction);
1048 break;
1049 case EOpRefract:
1050 writeBuiltInFunctionTriplet(visit, "refract(", useEmulatedFunction);
1051 break;
1052 case EOpMul:
1053 writeBuiltInFunctionTriplet(visit, "matrixCompMult(", useEmulatedFunction);
1054 break;
zmo@google.com5601ea02011-06-10 18:23:25 +00001055
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001056 default:
1057 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001058 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001059 return visitChildren;
1060}
1061
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001062bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001063{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001064 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001065
Zhenyao Mo7cab38b2013-10-15 12:59:30 -07001066 incrementDepth(node);
Corentin Wallez7258e302015-09-22 10:40:24 -07001067
zmo@google.com5601ea02011-06-10 18:23:25 +00001068 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001069
1070 // Only for loops can be unrolled
1071 ASSERT(!node->getUnrollFlag() || loopType == ELoopFor);
1072
zmo@google.com5601ea02011-06-10 18:23:25 +00001073 if (loopType == ELoopFor) // for loop
1074 {
Zhenyao Mo550c6002014-02-26 15:40:48 -08001075 if (!node->getUnrollFlag())
1076 {
zmo@google.com5601ea02011-06-10 18:23:25 +00001077 out << "for (";
1078 if (node->getInit())
1079 node->getInit()->traverse(this);
1080 out << "; ";
1081
1082 if (node->getCondition())
1083 node->getCondition()->traverse(this);
1084 out << "; ";
1085
1086 if (node->getExpression())
1087 node->getExpression()->traverse(this);
1088 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001089
1090 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001091 }
Zhenyao Mo550c6002014-02-26 15:40:48 -08001092 else
1093 {
1094 // Need to put a one-iteration loop here to handle break.
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001095 TIntermSequence *declSeq =
Zhenyao Mo550c6002014-02-26 15:40:48 -08001096 node->getInit()->getAsAggregate()->getSequence();
1097 TIntermSymbol *indexSymbol =
Zhenyao Moe40d1e92014-07-16 17:40:36 -07001098 (*declSeq)[0]->getAsBinaryNode()->getLeft()->getAsSymbolNode();
Zhenyao Mo550c6002014-02-26 15:40:48 -08001099 TString name = hashVariableName(indexSymbol->getSymbol());
1100 out << "for (int " << name << " = 0; "
1101 << name << " < 1; "
1102 << "++" << name << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001103
1104 out << "{\n";
1105 mLoopUnrollStack.push(node);
1106 while (mLoopUnrollStack.satisfiesLoopCondition())
1107 {
1108 visitCodeBlock(node->getBody());
1109 mLoopUnrollStack.step();
1110 }
1111 mLoopUnrollStack.pop();
1112 out << "}\n";
Zhenyao Mo550c6002014-02-26 15:40:48 -08001113 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001114 }
1115 else if (loopType == ELoopWhile) // while loop
1116 {
1117 out << "while (";
1118 ASSERT(node->getCondition() != NULL);
1119 node->getCondition()->traverse(this);
1120 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001121
1122 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001123 }
1124 else // do-while loop
1125 {
1126 ASSERT(loopType == ELoopDoWhile);
1127 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001128
zmo@google.com5601ea02011-06-10 18:23:25 +00001129 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001130
zmo@google.com5601ea02011-06-10 18:23:25 +00001131 out << "while (";
1132 ASSERT(node->getCondition() != NULL);
1133 node->getCondition()->traverse(this);
1134 out << ");\n";
1135 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001136
zmo@google.com5601ea02011-06-10 18:23:25 +00001137 decrementDepth();
1138
1139 // No need to visit children. They have been already processed in
1140 // this function.
1141 return false;
1142}
1143
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001144bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001145{
1146 switch (node->getFlowOp())
1147 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001148 case EOpKill:
1149 writeTriplet(visit, "discard", NULL, NULL);
1150 break;
1151 case EOpBreak:
1152 writeTriplet(visit, "break", NULL, NULL);
1153 break;
1154 case EOpContinue:
1155 writeTriplet(visit, "continue", NULL, NULL);
1156 break;
1157 case EOpReturn:
1158 writeTriplet(visit, "return ", NULL, NULL);
1159 break;
1160 default:
1161 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001162 }
1163
1164 return true;
1165}
1166
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001167void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001168{
zmo@google.com5601ea02011-06-10 18:23:25 +00001169 TInfoSinkBase &out = objSink();
1170 if (node != NULL)
1171 {
1172 node->traverse(this);
1173 // Single statements not part of a sequence need to be terminated
1174 // with semi-colon.
1175 if (isSingleStatement(node))
1176 out << ";\n";
1177 }
1178 else
1179 {
1180 out << "{\n}\n"; // Empty code block.
1181 }
1182}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001183
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001184TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001185{
Olli Etuahoe92507b2016-07-04 11:20:10 +03001186 if (type.getBasicType() == EbtStruct)
1187 return hashName(type.getStruct()->name());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001188 else
Olli Etuahoe92507b2016-07-04 11:20:10 +03001189 return type.getBuiltInTypeNameString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001190}
1191
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001192TString TOutputGLSLBase::hashName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001193{
1194 if (mHashFunction == NULL || name.empty())
1195 return name;
1196 NameMap::const_iterator it = mNameMap.find(name.c_str());
1197 if (it != mNameMap.end())
1198 return it->second.c_str();
1199 TString hashedName = TIntermTraverser::hash(name, mHashFunction);
1200 mNameMap[name.c_str()] = hashedName.c_str();
1201 return hashedName;
1202}
1203
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001204TString TOutputGLSLBase::hashVariableName(const TString &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001205{
Jamie Madill02f20dd2013-09-12 12:07:42 -04001206 if (mSymbolTable.findBuiltIn(name, mShaderVersion) != NULL)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001207 return name;
1208 return hashName(name);
1209}
1210
Olli Etuaho59f9a642015-08-06 20:38:26 +03001211TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TName &mangledName)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001212{
Olli Etuaho59f9a642015-08-06 20:38:26 +03001213 TString mangledStr = mangledName.getString();
1214 TString name = TFunction::unmangleName(mangledStr);
1215 if (mSymbolTable.findBuiltIn(mangledStr, mShaderVersion) != nullptr || name == "main")
Nicolas Capens46485082014-04-15 13:12:50 -04001216 return translateTextureFunction(name);
Olli Etuaho59f9a642015-08-06 20:38:26 +03001217 if (mangledName.isInternal())
1218 return name;
1219 else
1220 return hashName(name);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001221}
Jamie Madill98493dd2013-07-08 14:39:03 -04001222
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001223bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001224{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001225 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001226 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001227 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001228 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001229 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001230
1231 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001232}
1233
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001234void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001235{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001236 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001237
1238 out << "struct " << hashName(structure->name()) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001239 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001240 for (size_t i = 0; i < fields.size(); ++i)
1241 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001242 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001243 if (writeVariablePrecision(field->type()->getPrecision()))
1244 out << " ";
1245 out << getTypeName(*field->type()) << " " << hashName(field->name());
1246 if (field->type()->isArray())
1247 out << arrayBrackets(*field->type());
1248 out << ";\n";
1249 }
1250 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001251}
Jamie Madill98493dd2013-07-08 14:39:03 -04001252
Geoff Langbdcc54a2015-09-02 13:09:48 -04001253void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1254{
1255 TInfoSinkBase &out = objSink();
1256
1257 out << "layout(";
1258
1259 switch (interfaceBlock->blockStorage())
1260 {
1261 case EbsUnspecified:
1262 case EbsShared:
1263 // Default block storage is shared.
1264 out << "shared";
1265 break;
1266
1267 case EbsPacked:
1268 out << "packed";
1269 break;
1270
1271 case EbsStd140:
1272 out << "std140";
1273 break;
1274
1275 default:
1276 UNREACHABLE();
1277 break;
1278 }
1279
1280 out << ", ";
1281
1282 switch (interfaceBlock->matrixPacking())
1283 {
1284 case EmpUnspecified:
1285 case EmpColumnMajor:
1286 // Default matrix packing is column major.
1287 out << "column_major";
1288 break;
1289
1290 case EmpRowMajor:
1291 out << "row_major";
1292 break;
1293
1294 default:
1295 UNREACHABLE();
1296 break;
1297 }
1298
1299 out << ") ";
1300}
1301
1302void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1303{
1304 TInfoSinkBase &out = objSink();
1305
1306 out << hashName(interfaceBlock->name()) << "{\n";
1307 const TFieldList &fields = interfaceBlock->fields();
1308 for (size_t i = 0; i < fields.size(); ++i)
1309 {
1310 const TField *field = fields[i];
1311 if (writeVariablePrecision(field->type()->getPrecision()))
1312 out << " ";
1313 out << getTypeName(*field->type()) << " " << hashName(field->name());
1314 if (field->type()->isArray())
1315 out << arrayBrackets(*field->type());
1316 out << ";\n";
1317 }
1318 out << "}";
1319}