blob: fee3836316c7b5d1e9535a49b91009f4fe0abfd1 [file] [log] [blame]
zmo@google.com5601ea02011-06-10 18:23:25 +00001//
Nicolas Capens16004fc2014-06-11 11:29:11 -04002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
zmo@google.com5601ea02011-06-10 18:23:25 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Geoff Lang17732822013-08-29 13:46:49 -04007#include "compiler/translator/OutputGLSLBase.h"
Olli Etuahod57e0db2015-04-24 15:05:08 +03008
9#include "common/debug.h"
Olli Etuaho56a2f952016-12-08 12:16:27 +000010#include "common/mathutil.h"
zmo@google.com5601ea02011-06-10 18:23:25 +000011
daniel@transgaming.com773ff742013-01-11 04:12:51 +000012#include <cfloat>
daniel@transgaming.com6c1203f2013-01-11 04:12:43 +000013
Jamie Madill45bcc782016-11-07 13:58:48 -050014namespace sh
15{
16
zmo@google.com5601ea02011-06-10 18:23:25 +000017namespace
18{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070019TString arrayBrackets(const TType &type)
zmo@google.com5601ea02011-06-10 18:23:25 +000020{
21 ASSERT(type.isArray());
22 TInfoSinkBase out;
23 out << "[" << type.getArraySize() << "]";
24 return TString(out.c_str());
25}
26
Zhenyao Mo9eedea02014-05-12 16:02:35 -070027bool isSingleStatement(TIntermNode *node)
28{
Olli Etuaho336b1472016-10-05 16:37:55 +010029 if (node->getAsFunctionDefinition())
zmo@google.com5601ea02011-06-10 18:23:25 +000030 {
Olli Etuaho336b1472016-10-05 16:37:55 +010031 return false;
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010032 }
33 else if (node->getAsBlock())
34 {
35 return false;
zmo@google.com5601ea02011-06-10 18:23:25 +000036 }
Olli Etuaho57961272016-09-14 13:57:46 +030037 else if (node->getAsIfElseNode())
zmo@google.com5601ea02011-06-10 18:23:25 +000038 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +030039 return false;
zmo@google.com5601ea02011-06-10 18:23:25 +000040 }
41 else if (node->getAsLoopNode())
42 {
43 return false;
44 }
Olli Etuaho01cd8af2015-02-20 10:39:20 +020045 else if (node->getAsSwitchNode())
46 {
47 return false;
48 }
49 else if (node->getAsCaseNode())
50 {
51 return false;
52 }
zmo@google.com5601ea02011-06-10 18:23:25 +000053 return true;
54}
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080055
Martin Radev2cc85b32016-08-05 16:22:53 +030056// If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
57// variables with specified layout qualifiers are copied. Additional checks are needed against the
58// type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
59// TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
60// NeedsToWriteLayoutQualifier.
61bool NeedsToWriteLayoutQualifier(const TType &type)
62{
63 if (type.getBasicType() == EbtInterfaceBlock)
64 {
65 return false;
66 }
67
68 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
69
70 if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn) &&
71 layoutQualifier.location >= 0)
72 {
73 return true;
74 }
Olli Etuaho43364892017-02-13 16:00:12 +000075
Andrei Volykhina5527072017-03-22 16:46:30 +030076 if (type.getQualifier() == EvqFragmentOut && layoutQualifier.yuv == true)
77 {
78 return true;
79 }
80
Olli Etuaho43364892017-02-13 16:00:12 +000081 if (IsOpaqueType(type.getBasicType()) && layoutQualifier.binding != -1)
82 {
83 return true;
84 }
85
Martin Radev2cc85b32016-08-05 16:22:53 +030086 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
87 {
88 return true;
89 }
90 return false;
91}
92
Olli Etuaho43364892017-02-13 16:00:12 +000093class CommaSeparatedListItemPrefixGenerator
94{
95 public:
96 CommaSeparatedListItemPrefixGenerator() : mFirst(true) {}
97 private:
98 bool mFirst;
99
100 friend TInfoSinkBase &operator<<(TInfoSinkBase &out,
101 CommaSeparatedListItemPrefixGenerator &gen);
102};
103
104TInfoSinkBase &operator<<(TInfoSinkBase &out, CommaSeparatedListItemPrefixGenerator &gen)
105{
106 if (gen.mFirst)
107 {
108 gen.mFirst = false;
109 }
110 else
111 {
112 out << ", ";
113 }
114 return out;
115}
116
zmo@google.com5601ea02011-06-10 18:23:25 +0000117} // namespace
118
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700119TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000120 ShArrayIndexClampingStrategy clampingStrategy,
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000121 ShHashFunction64 hashFunction,
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700122 NameMap &nameMap,
123 TSymbolTable &symbolTable,
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000124 sh::GLenum shaderType,
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800125 int shaderVersion,
Qiankun Miao705a9192016-08-29 10:05:27 +0800126 ShShaderOutput output,
127 ShCompileOptions compileOptions)
zmo@google.com5601ea02011-06-10 18:23:25 +0000128 : TIntermTraverser(true, true, true),
129 mObjSink(objSink),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000130 mDeclaringVariables(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000131 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000132 mHashFunction(hashFunction),
133 mNameMap(nameMap),
Jamie Madill02f20dd2013-09-12 12:07:42 -0400134 mSymbolTable(symbolTable),
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000135 mShaderType(shaderType),
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800136 mShaderVersion(shaderVersion),
Qiankun Miao705a9192016-08-29 10:05:27 +0800137 mOutput(output),
138 mCompileOptions(compileOptions)
zmo@google.com5601ea02011-06-10 18:23:25 +0000139{
140}
141
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800142void TOutputGLSLBase::writeInvariantQualifier(const TType &type)
143{
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000144 if (!sh::RemoveInvariant(mShaderType, mShaderVersion, mOutput, mCompileOptions))
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800145 {
146 TInfoSinkBase &out = objSink();
147 out << "invariant ";
148 }
149}
150
Olli Etuaho56a2f952016-12-08 12:16:27 +0000151void TOutputGLSLBase::writeFloat(TInfoSinkBase &out, float f)
152{
153 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300)
154 {
155 out << "uintBitsToFloat(" << gl::bitCast<uint32_t>(f) << "u)";
156 }
157 else
158 {
159 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
160 }
161}
162
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500163void TOutputGLSLBase::writeTriplet(Visit visit,
164 const char *preStr,
165 const char *inStr,
166 const char *postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000167{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700168 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000169 if (visit == PreVisit && preStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000170 out << preStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000171 else if (visit == InVisit && inStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000172 out << inStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000173 else if (visit == PostVisit && postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000174 out << postStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000175}
176
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500177void TOutputGLSLBase::writeBuiltInFunctionTriplet(Visit visit,
Olli Etuahoe1805592017-01-02 16:41:20 +0000178 TOperator op,
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500179 bool useEmulatedFunction)
zmo@google.com5601ea02011-06-10 18:23:25 +0000180{
Olli Etuahod68924e2017-01-02 17:34:40 +0000181 TInfoSinkBase &out = objSink();
182 if (visit == PreVisit)
Olli Etuahoe1805592017-01-02 16:41:20 +0000183 {
Olli Etuahod68924e2017-01-02 17:34:40 +0000184 const char *opStr(GetOperatorString(op));
185 if (useEmulatedFunction)
186 {
187 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
188 }
189 else
190 {
191 out << opStr;
192 }
193 out << "(";
Olli Etuahoe1805592017-01-02 16:41:20 +0000194 }
Olli Etuahod68924e2017-01-02 17:34:40 +0000195 else
196 {
197 writeTriplet(visit, nullptr, ", ", ")");
198 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700199}
200
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300201void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
202{
Martin Radev2cc85b32016-08-05 16:22:53 +0300203 if (!NeedsToWriteLayoutQualifier(type))
204 {
205 return;
206 }
207
208 TInfoSinkBase &out = objSink();
209 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
210 out << "layout(";
211
Olli Etuaho43364892017-02-13 16:00:12 +0000212 CommaSeparatedListItemPrefixGenerator listItemPrefix;
213
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300214 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
215 {
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300216 if (layoutQualifier.location >= 0)
217 {
Olli Etuaho43364892017-02-13 16:00:12 +0000218 out << listItemPrefix << "location = " << layoutQualifier.location;
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300219 }
220 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300221
Andrei Volykhina5527072017-03-22 16:46:30 +0300222 if (type.getQualifier() == EvqFragmentOut)
223 {
224 if (layoutQualifier.yuv == true)
225 {
226 out << listItemPrefix << "yuv";
227 }
228 }
229
Olli Etuaho43364892017-02-13 16:00:12 +0000230 if (IsOpaqueType(type.getBasicType()))
Martin Radev2cc85b32016-08-05 16:22:53 +0300231 {
Olli Etuaho43364892017-02-13 16:00:12 +0000232 if (layoutQualifier.binding >= 0)
233 {
234 out << listItemPrefix << "binding = " << layoutQualifier.binding;
235 }
236 }
237
238 if (IsImage(type.getBasicType()))
239 {
240 if (layoutQualifier.imageInternalFormat != EiifUnspecified)
241 {
242 ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
243 out << listItemPrefix
244 << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
245 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300246 }
247
248 out << ") ";
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300249}
250
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800251const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier)
252{
253 if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 &&
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000254 (mCompileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0)
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800255 {
256 switch (qualifier)
257 {
258 // The return string is consistent with sh::getQualifierString() from
259 // BaseTypes.h minus the "centroid" keyword.
260 case EvqCentroid:
261 return "";
262 case EvqCentroidIn:
263 return "smooth in";
264 case EvqCentroidOut:
265 return "smooth out";
266 default:
267 break;
268 }
269 }
270 if (sh::IsGLSL130OrNewer(mOutput))
271 {
272 switch (qualifier)
273 {
274 case EvqAttribute:
275 return "in";
276 case EvqVaryingIn:
277 return "in";
278 case EvqVaryingOut:
279 return "out";
280 default:
281 break;
282 }
283 }
284 return sh::getQualifierString(qualifier);
285}
286
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700287void TOutputGLSLBase::writeVariableType(const TType &type)
288{
Qiankun Miao705a9192016-08-29 10:05:27 +0800289 TQualifier qualifier = type.getQualifier();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500290 TInfoSinkBase &out = objSink();
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800291 if (type.isInvariant())
Olli Etuaho214c2d82015-04-27 14:49:13 +0300292 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800293 writeInvariantQualifier(type);
Olli Etuaho214c2d82015-04-27 14:49:13 +0300294 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400295 if (type.getBasicType() == EbtInterfaceBlock)
296 {
297 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
298 declareInterfaceBlockLayout(interfaceBlock);
299 }
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400300 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400301 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800302 const char *qualifierString = mapQualifierToString(qualifier);
303 if (qualifierString && qualifierString[0] != '\0')
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800304 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800305 out << qualifierString << " ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800306 }
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400307 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300308
309 const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
310 if (memoryQualifier.readonly)
311 {
312 ASSERT(IsImage(type.getBasicType()));
313 out << "readonly ";
314 }
315
316 if (memoryQualifier.writeonly)
317 {
318 ASSERT(IsImage(type.getBasicType()));
319 out << "writeonly ";
320 }
321
Martin Radev049edfa2016-11-11 14:35:37 +0200322 if (memoryQualifier.coherent)
323 {
324 ASSERT(IsImage(type.getBasicType()));
325 out << "coherent ";
326 }
327
328 if (memoryQualifier.restrictQualifier)
329 {
330 ASSERT(IsImage(type.getBasicType()));
331 out << "restrict ";
332 }
333
334 if (memoryQualifier.volatileQualifier)
335 {
336 ASSERT(IsImage(type.getBasicType()));
337 out << "volatile ";
338 }
339
zmo@google.com5601ea02011-06-10 18:23:25 +0000340 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700341 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000342 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400343 TStructure *structure = type.getStruct();
344
345 declareStruct(structure);
346
347 if (!structure->name().empty())
348 {
349 mDeclaredStructs.insert(structure->uniqueId());
350 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000351 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400352 else if (type.getBasicType() == EbtInterfaceBlock)
353 {
354 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
355 declareInterfaceBlock(interfaceBlock);
356 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000357 else
358 {
359 if (writeVariablePrecision(type.getPrecision()))
360 out << " ";
361 out << getTypeName(type);
362 }
363}
364
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700365void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000366{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700367 TInfoSinkBase &out = objSink();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500368 for (TIntermSequence::const_iterator iter = args.begin(); iter != args.end(); ++iter)
zmo@google.com5601ea02011-06-10 18:23:25 +0000369 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700370 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
zmo@google.com5601ea02011-06-10 18:23:25 +0000371 ASSERT(arg != NULL);
372
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700373 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000374 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000375
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000376 if (!arg->getName().getString().empty())
377 out << " " << hashName(arg->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000378 if (type.isArray())
379 out << arrayBrackets(type);
380
381 // Put a comma if this is not the last argument.
382 if (iter != args.end() - 1)
383 out << ", ";
384 }
385}
386
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500387const TConstantUnion *TOutputGLSLBase::writeConstantUnion(const TType &type,
388 const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000389{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700390 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000391
392 if (type.getBasicType() == EbtStruct)
393 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700394 const TStructure *structure = type.getStruct();
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000395 out << hashName(TName(structure->name())) << "(";
Jamie Madill98493dd2013-07-08 14:39:03 -0400396
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700397 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400398 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000399 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700400 const TType *fieldType = fields[i]->type();
zmo@google.com5601ea02011-06-10 18:23:25 +0000401 ASSERT(fieldType != NULL);
402 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700403 if (i != fields.size() - 1)
404 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000405 }
406 out << ")";
407 }
408 else
409 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500410 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000411 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700412 if (writeType)
413 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400414 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000415 {
416 switch (pConstUnion->getType())
417 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500418 case EbtFloat:
419 writeFloat(out, pConstUnion->getFConst());
420 break;
421 case EbtInt:
422 out << pConstUnion->getIConst();
423 break;
424 case EbtUInt:
425 out << pConstUnion->getUConst() << "u";
426 break;
427 case EbtBool:
428 out << pConstUnion->getBConst();
429 break;
Andrei Volykhina5527072017-03-22 16:46:30 +0300430 case EbtYuvCscStandardEXT:
431 out << getYuvCscStandardEXTString(pConstUnion->getYuvCscStandardEXTConst());
432 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500433 default:
434 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000435 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700436 if (i != size - 1)
437 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000438 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700439 if (writeType)
440 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000441 }
442 return pConstUnion;
443}
444
Olli Etuahoe92507b2016-07-04 11:20:10 +0300445void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
Olli Etuahof40319e2015-03-10 14:33:00 +0200446{
447 TInfoSinkBase &out = objSink();
448 if (visit == PreVisit)
449 {
450 if (type.isArray())
451 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300452 out << getTypeName(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200453 out << arrayBrackets(type);
454 out << "(";
455 }
456 else
457 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300458 out << getTypeName(type) << "(";
Olli Etuahof40319e2015-03-10 14:33:00 +0200459 }
460 }
461 else
462 {
463 writeTriplet(visit, nullptr, ", ", ")");
464 }
465}
466
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700467void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000468{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700469 TInfoSinkBase &out = objSink();
Corentin Wallez1b896c62016-11-16 13:10:44 -0500470 out << hashVariableName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000471
472 if (mDeclaringVariables && node->getType().isArray())
473 out << arrayBrackets(node->getType());
474}
475
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700476void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000477{
478 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
479}
480
Olli Etuahob6fa0432016-09-28 16:28:05 +0100481bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
482{
483 TInfoSinkBase &out = objSink();
484 if (visit == PostVisit)
485 {
486 out << ".";
487 node->writeOffsetsAsXYZW(&out);
488 }
489 return true;
490}
491
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700492bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000493{
494 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700495 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000496 switch (node->getOp())
497 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100498 case EOpComma:
499 writeTriplet(visit, "(", ", ", ")");
500 break;
501 case EOpInitialize:
zmo@google.com5601ea02011-06-10 18:23:25 +0000502 if (visit == InVisit)
503 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100504 out << " = ";
505 // RHS of initialize is not being declared.
506 mDeclaringVariables = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000507 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100508 break;
509 case EOpAssign:
510 writeTriplet(visit, "(", " = ", ")");
511 break;
512 case EOpAddAssign:
513 writeTriplet(visit, "(", " += ", ")");
514 break;
515 case EOpSubAssign:
516 writeTriplet(visit, "(", " -= ", ")");
517 break;
518 case EOpDivAssign:
519 writeTriplet(visit, "(", " /= ", ")");
520 break;
521 case EOpIModAssign:
522 writeTriplet(visit, "(", " %= ", ")");
523 break;
524 // Notice the fall-through.
525 case EOpMulAssign:
526 case EOpVectorTimesMatrixAssign:
527 case EOpVectorTimesScalarAssign:
528 case EOpMatrixTimesScalarAssign:
529 case EOpMatrixTimesMatrixAssign:
530 writeTriplet(visit, "(", " *= ", ")");
531 break;
532 case EOpBitShiftLeftAssign:
533 writeTriplet(visit, "(", " <<= ", ")");
534 break;
535 case EOpBitShiftRightAssign:
536 writeTriplet(visit, "(", " >>= ", ")");
537 break;
538 case EOpBitwiseAndAssign:
539 writeTriplet(visit, "(", " &= ", ")");
540 break;
541 case EOpBitwiseXorAssign:
542 writeTriplet(visit, "(", " ^= ", ")");
543 break;
544 case EOpBitwiseOrAssign:
545 writeTriplet(visit, "(", " |= ", ")");
546 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000547
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100548 case EOpIndexDirect:
zmo@google.com5601ea02011-06-10 18:23:25 +0000549 writeTriplet(visit, NULL, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100550 break;
551 case EOpIndexIndirect:
552 if (node->getAddIndexClamp())
553 {
554 if (visit == InVisit)
555 {
556 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
557 out << "[int(clamp(float(";
558 else
559 out << "[webgl_int_clamp(";
560 }
561 else if (visit == PostVisit)
562 {
563 int maxSize;
564 TIntermTyped *left = node->getLeft();
565 TType leftType = left->getType();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700566
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100567 if (left->isArray())
568 {
569 // The shader will fail validation if the array length is not > 0.
570 maxSize = static_cast<int>(leftType.getArraySize()) - 1;
571 }
572 else
573 {
574 maxSize = leftType.getNominalSize() - 1;
575 }
576
577 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
578 out << "), 0.0, float(" << maxSize << ")))]";
579 else
580 out << ", 0, " << maxSize << ")]";
581 }
582 }
583 else
584 {
585 writeTriplet(visit, NULL, "[", "]");
586 }
587 break;
588 case EOpIndexDirectStruct:
589 if (visit == InVisit)
590 {
591 // Here we are writing out "foo.bar", where "foo" is struct
592 // and "bar" is field. In AST, it is represented as a binary
593 // node, where left child represents "foo" and right child "bar".
594 // The node itself represents ".". The struct field "bar" is
595 // actually stored as an index into TStructure::fields.
596 out << ".";
597 const TStructure *structure = node->getLeft()->getType().getStruct();
598 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
599 const TField *field = structure->fields()[index->getIConst(0)];
600
601 TString fieldName = field->name();
602 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000603 fieldName = hashName(TName(fieldName));
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100604
605 out << fieldName;
606 visitChildren = false;
607 }
608 break;
609 case EOpIndexDirectInterfaceBlock:
610 if (visit == InVisit)
611 {
612 out << ".";
613 const TInterfaceBlock *interfaceBlock =
614 node->getLeft()->getType().getInterfaceBlock();
615 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
616 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
617
618 TString fieldName = field->name();
619 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000620 fieldName = hashName(TName(fieldName));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700621
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100622 out << fieldName;
623 visitChildren = false;
624 }
625 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400626
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100627 case EOpAdd:
628 writeTriplet(visit, "(", " + ", ")");
629 break;
630 case EOpSub:
631 writeTriplet(visit, "(", " - ", ")");
632 break;
633 case EOpMul:
634 writeTriplet(visit, "(", " * ", ")");
635 break;
636 case EOpDiv:
637 writeTriplet(visit, "(", " / ", ")");
638 break;
639 case EOpIMod:
640 writeTriplet(visit, "(", " % ", ")");
641 break;
642 case EOpBitShiftLeft:
643 writeTriplet(visit, "(", " << ", ")");
644 break;
645 case EOpBitShiftRight:
646 writeTriplet(visit, "(", " >> ", ")");
647 break;
648 case EOpBitwiseAnd:
649 writeTriplet(visit, "(", " & ", ")");
650 break;
651 case EOpBitwiseXor:
652 writeTriplet(visit, "(", " ^ ", ")");
653 break;
654 case EOpBitwiseOr:
655 writeTriplet(visit, "(", " | ", ")");
656 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400657
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100658 case EOpEqual:
659 writeTriplet(visit, "(", " == ", ")");
660 break;
661 case EOpNotEqual:
662 writeTriplet(visit, "(", " != ", ")");
663 break;
664 case EOpLessThan:
665 writeTriplet(visit, "(", " < ", ")");
666 break;
667 case EOpGreaterThan:
668 writeTriplet(visit, "(", " > ", ")");
669 break;
670 case EOpLessThanEqual:
671 writeTriplet(visit, "(", " <= ", ")");
672 break;
673 case EOpGreaterThanEqual:
674 writeTriplet(visit, "(", " >= ", ")");
675 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000676
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100677 // Notice the fall-through.
678 case EOpVectorTimesScalar:
679 case EOpVectorTimesMatrix:
680 case EOpMatrixTimesVector:
681 case EOpMatrixTimesScalar:
682 case EOpMatrixTimesMatrix:
683 writeTriplet(visit, "(", " * ", ")");
684 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200685
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100686 case EOpLogicalOr:
687 writeTriplet(visit, "(", " || ", ")");
688 break;
689 case EOpLogicalXor:
690 writeTriplet(visit, "(", " ^^ ", ")");
691 break;
692 case EOpLogicalAnd:
693 writeTriplet(visit, "(", " && ", ")");
694 break;
695 default:
696 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000697 }
698
699 return visitChildren;
700}
701
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700702bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000703{
zmo@google.com32e97312011-08-24 01:03:11 +0000704 TString preString;
705 TString postString = ")";
706
zmo@google.com5601ea02011-06-10 18:23:25 +0000707 switch (node->getOp())
708 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500709 case EOpNegative:
710 preString = "(-";
711 break;
712 case EOpPositive:
713 preString = "(+";
714 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500715 case EOpLogicalNot:
716 preString = "(!";
717 break;
718 case EOpBitwiseNot:
719 preString = "(~";
720 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000721
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500722 case EOpPostIncrement:
723 preString = "(";
724 postString = "++)";
725 break;
726 case EOpPostDecrement:
727 preString = "(";
728 postString = "--)";
729 break;
730 case EOpPreIncrement:
731 preString = "(++";
732 break;
733 case EOpPreDecrement:
734 preString = "(--";
735 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000736
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500737 case EOpRadians:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500738 case EOpDegrees:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500739 case EOpSin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500740 case EOpCos:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500741 case EOpTan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500742 case EOpAsin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500743 case EOpAcos:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500744 case EOpAtan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500745 case EOpSinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500746 case EOpCosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500747 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500748 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500749 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500750 case EOpAtanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500751 case EOpExp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500752 case EOpLog:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500753 case EOpExp2:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500754 case EOpLog2:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500755 case EOpSqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500756 case EOpInverseSqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500757 case EOpAbs:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500758 case EOpSign:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500759 case EOpFloor:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500760 case EOpTrunc:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500761 case EOpRound:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500762 case EOpRoundEven:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500763 case EOpCeil:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500764 case EOpFract:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500765 case EOpIsNan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500766 case EOpIsInf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500767 case EOpFloatBitsToInt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500768 case EOpFloatBitsToUint:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500769 case EOpIntBitsToFloat:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500770 case EOpUintBitsToFloat:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500771 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500772 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500773 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500774 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500775 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500776 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800777 case EOpPackUnorm4x8:
778 case EOpPackSnorm4x8:
779 case EOpUnpackUnorm4x8:
780 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500781 case EOpLength:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500782 case EOpNormalize:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500783 case EOpDFdx:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500784 case EOpDFdy:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500785 case EOpFwidth:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500786 case EOpTranspose:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500787 case EOpDeterminant:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500788 case EOpInverse:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500789 case EOpAny:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500790 case EOpAll:
Olli Etuahod68924e2017-01-02 17:34:40 +0000791 case EOpLogicalNotComponentWise:
Olli Etuaho9250cb22017-01-21 10:51:27 +0000792 case EOpBitfieldReverse:
793 case EOpBitCount:
794 case EOpFindLSB:
795 case EOpFindMSB:
Olli Etuahod68924e2017-01-02 17:34:40 +0000796 writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
797 return true;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500798 default:
799 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000800 }
801
zmo@google.com32e97312011-08-24 01:03:11 +0000802 writeTriplet(visit, preString.c_str(), NULL, postString.c_str());
803
zmo@google.com5601ea02011-06-10 18:23:25 +0000804 return true;
805}
806
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300807bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
808{
809 TInfoSinkBase &out = objSink();
810 // Notice two brackets at the beginning and end. The outer ones
811 // encapsulate the whole ternary expression. This preserves the
812 // order of precedence when ternary expressions are used in a
813 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
814 out << "((";
815 node->getCondition()->traverse(this);
816 out << ") ? (";
817 node->getTrueExpression()->traverse(this);
818 out << ") : (";
819 node->getFalseExpression()->traverse(this);
820 out << "))";
821 return false;
822}
823
Olli Etuaho57961272016-09-14 13:57:46 +0300824bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000825{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700826 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000827
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300828 out << "if (";
829 node->getCondition()->traverse(this);
830 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000831
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300832 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000833
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300834 if (node->getFalseBlock())
835 {
836 out << "else\n";
837 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000838 }
839 return false;
840}
841
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200842bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200843{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200844 if (node->getStatementList())
845 {
846 writeTriplet(visit, "switch (", ") ", nullptr);
847 // The curly braces get written when visiting the statementList aggregate
848 }
849 else
850 {
851 // No statementList, so it won't output curly braces
852 writeTriplet(visit, "switch (", ") {", "}\n");
853 }
854 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200855}
856
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200857bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200858{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200859 if (node->hasCondition())
860 {
861 writeTriplet(visit, "case (", nullptr, "):\n");
862 return true;
863 }
864 else
865 {
866 TInfoSinkBase &out = objSink();
867 out << "default:\n";
868 return false;
869 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200870}
871
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100872bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
873{
874 TInfoSinkBase &out = objSink();
875 // Scope the blocks except when at the global scope.
876 if (mDepth > 0)
877 {
878 out << "{\n";
879 }
880
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100881 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
882 iter != node->getSequence()->end(); ++iter)
883 {
884 TIntermNode *curNode = *iter;
885 ASSERT(curNode != nullptr);
886 curNode->traverse(this);
887
888 if (isSingleStatement(curNode))
889 out << ";\n";
890 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100891
892 // Scope the blocks except when at the global scope.
893 if (mDepth > 0)
894 {
895 out << "}\n";
896 }
897 return false;
898}
899
Olli Etuaho336b1472016-10-05 16:37:55 +0100900bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
901{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000902 TIntermFunctionPrototype *prototype = node->getFunctionPrototype();
903 prototype->traverse(this);
Olli Etuaho336b1472016-10-05 16:37:55 +0100904 visitCodeBlock(node->getBody());
Olli Etuaho336b1472016-10-05 16:37:55 +0100905
906 // Fully processed; no need to visit children.
907 return false;
908}
909
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000910bool TOutputGLSLBase::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
911{
912 TInfoSinkBase &out = objSink();
913 ASSERT(visit == PreVisit);
914 const TIntermSymbol *symbol = node->getSymbol();
915 out << "invariant " << hashVariableName(symbol->getName());
916 return false;
917}
918
Olli Etuaho16c745a2017-01-16 17:02:27 +0000919bool TOutputGLSLBase::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
920{
921 TInfoSinkBase &out = objSink();
922 ASSERT(visit == PreVisit);
923
924 const TType &type = node->getType();
925 writeVariableType(type);
926 if (type.isArray())
927 out << arrayBrackets(type);
928
Olli Etuahoec9232b2017-03-27 17:01:37 +0300929 out << " " << hashFunctionNameIfNeeded(*node->getFunctionSymbolInfo());
Olli Etuaho16c745a2017-01-16 17:02:27 +0000930
931 out << "(";
932 writeFunctionParameters(*(node->getSequence()));
933 out << ")";
934
935 return false;
936}
937
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700938bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000939{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500940 bool visitChildren = true;
941 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000942 switch (node->getOp())
943 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800944 case EOpCallFunctionInAST:
945 case EOpCallInternalRawFunction:
946 case EOpCallBuiltInFunction:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500947 // Function call.
948 if (visit == PreVisit)
Olli Etuahoec9232b2017-03-27 17:01:37 +0300949 {
950 if (node->getOp() == EOpCallBuiltInFunction)
951 {
952 out << translateTextureFunction(node->getFunctionSymbolInfo()->getName());
953 }
954 else
955 {
956 out << hashFunctionNameIfNeeded(*node->getFunctionSymbolInfo());
957 }
958 out << "(";
959 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500960 else if (visit == InVisit)
961 out << ", ";
962 else
963 out << ")";
964 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500965 case EOpConstructFloat:
966 case EOpConstructVec2:
967 case EOpConstructVec3:
968 case EOpConstructVec4:
969 case EOpConstructBool:
970 case EOpConstructBVec2:
971 case EOpConstructBVec3:
972 case EOpConstructBVec4:
973 case EOpConstructInt:
974 case EOpConstructIVec2:
975 case EOpConstructIVec3:
976 case EOpConstructIVec4:
977 case EOpConstructUInt:
978 case EOpConstructUVec2:
979 case EOpConstructUVec3:
980 case EOpConstructUVec4:
981 case EOpConstructMat2:
982 case EOpConstructMat2x3:
983 case EOpConstructMat2x4:
984 case EOpConstructMat3x2:
985 case EOpConstructMat3:
986 case EOpConstructMat3x4:
987 case EOpConstructMat4x2:
988 case EOpConstructMat4x3:
989 case EOpConstructMat4:
990 case EOpConstructStruct:
991 writeConstructorTriplet(visit, node->getType());
992 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200993
Olli Etuahoe1805592017-01-02 16:41:20 +0000994 case EOpEqualComponentWise:
995 case EOpNotEqualComponentWise:
996 case EOpLessThanComponentWise:
997 case EOpGreaterThanComponentWise:
998 case EOpLessThanEqualComponentWise:
999 case EOpGreaterThanEqualComponentWise:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001000 case EOpMod:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001001 case EOpModf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001002 case EOpPow:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001003 case EOpAtan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001004 case EOpMin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001005 case EOpMax:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001006 case EOpClamp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001007 case EOpMix:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001008 case EOpStep:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001009 case EOpSmoothStep:
Olli Etuaho74da73f2017-02-01 15:37:48 +00001010 case EOpFrexp:
1011 case EOpLdexp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001012 case EOpDistance:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001013 case EOpDot:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001014 case EOpCross:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001015 case EOpFaceForward:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001016 case EOpReflect:
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001017 case EOpRefract:
Olli Etuahoe1805592017-01-02 16:41:20 +00001018 case EOpMulMatrixComponentWise:
1019 case EOpOuterProduct:
Olli Etuaho9250cb22017-01-21 10:51:27 +00001020 case EOpBitfieldExtract:
1021 case EOpBitfieldInsert:
1022 case EOpUaddCarry:
1023 case EOpUsubBorrow:
1024 case EOpUmulExtended:
1025 case EOpImulExtended:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001026 case EOpBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001027 case EOpMemoryBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001028 case EOpMemoryBarrierAtomicCounter:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001029 case EOpMemoryBarrierBuffer:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001030 case EOpMemoryBarrierImage:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001031 case EOpMemoryBarrierShared:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001032 case EOpGroupMemoryBarrier:
Olli Etuahod68924e2017-01-02 17:34:40 +00001033 writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001034 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001035 default:
1036 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001037 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001038 return visitChildren;
1039}
1040
Olli Etuaho13389b62016-10-16 11:48:18 +01001041bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
1042{
1043 TInfoSinkBase &out = objSink();
1044
1045 // Variable declaration.
1046 if (visit == PreVisit)
1047 {
1048 const TIntermSequence &sequence = *(node->getSequence());
1049 const TIntermTyped *variable = sequence.front()->getAsTyped();
1050 writeLayoutQualifier(variable->getType());
1051 writeVariableType(variable->getType());
1052 out << " ";
1053 mDeclaringVariables = true;
1054 }
1055 else if (visit == InVisit)
1056 {
1057 out << ", ";
1058 mDeclaringVariables = true;
1059 }
1060 else
1061 {
1062 mDeclaringVariables = false;
1063 }
1064 return true;
1065}
1066
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001067bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001068{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001069 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001070
zmo@google.com5601ea02011-06-10 18:23:25 +00001071 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001072
zmo@google.com5601ea02011-06-10 18:23:25 +00001073 if (loopType == ELoopFor) // for loop
1074 {
Corentin Wallez1b896c62016-11-16 13:10:44 -05001075 out << "for (";
1076 if (node->getInit())
1077 node->getInit()->traverse(this);
1078 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001079
Corentin Wallez1b896c62016-11-16 13:10:44 -05001080 if (node->getCondition())
1081 node->getCondition()->traverse(this);
1082 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001083
Corentin Wallez1b896c62016-11-16 13:10:44 -05001084 if (node->getExpression())
1085 node->getExpression()->traverse(this);
1086 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001087
Corentin Wallez1b896c62016-11-16 13:10:44 -05001088 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001089 }
1090 else if (loopType == ELoopWhile) // while loop
1091 {
1092 out << "while (";
1093 ASSERT(node->getCondition() != NULL);
1094 node->getCondition()->traverse(this);
1095 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001096
1097 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001098 }
1099 else // do-while loop
1100 {
1101 ASSERT(loopType == ELoopDoWhile);
1102 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001103
zmo@google.com5601ea02011-06-10 18:23:25 +00001104 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001105
zmo@google.com5601ea02011-06-10 18:23:25 +00001106 out << "while (";
1107 ASSERT(node->getCondition() != NULL);
1108 node->getCondition()->traverse(this);
1109 out << ");\n";
1110 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001111
zmo@google.com5601ea02011-06-10 18:23:25 +00001112 // No need to visit children. They have been already processed in
1113 // this function.
1114 return false;
1115}
1116
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001117bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001118{
1119 switch (node->getFlowOp())
1120 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001121 case EOpKill:
1122 writeTriplet(visit, "discard", NULL, NULL);
1123 break;
1124 case EOpBreak:
1125 writeTriplet(visit, "break", NULL, NULL);
1126 break;
1127 case EOpContinue:
1128 writeTriplet(visit, "continue", NULL, NULL);
1129 break;
1130 case EOpReturn:
1131 writeTriplet(visit, "return ", NULL, NULL);
1132 break;
1133 default:
1134 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001135 }
1136
1137 return true;
1138}
1139
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001140void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001141{
zmo@google.com5601ea02011-06-10 18:23:25 +00001142 TInfoSinkBase &out = objSink();
1143 if (node != NULL)
1144 {
1145 node->traverse(this);
1146 // Single statements not part of a sequence need to be terminated
1147 // with semi-colon.
1148 if (isSingleStatement(node))
1149 out << ";\n";
1150 }
1151 else
1152 {
1153 out << "{\n}\n"; // Empty code block.
1154 }
1155}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001156
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001157TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001158{
Olli Etuahoe92507b2016-07-04 11:20:10 +03001159 if (type.getBasicType() == EbtStruct)
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001160 return hashName(TName(type.getStruct()->name()));
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001161 else
Olli Etuahoe92507b2016-07-04 11:20:10 +03001162 return type.getBuiltInTypeNameString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001163}
1164
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001165TString TOutputGLSLBase::hashName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001166{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001167 if (name.getString().empty())
1168 {
1169 ASSERT(!name.isInternal());
1170 return name.getString();
1171 }
1172 if (name.isInternal())
1173 {
1174 // TODO(oetuaho): Would be nicer to prefix non-internal names with "_" instead, like is
1175 // done in the HLSL output, but that requires fairly complex changes elsewhere in the code
1176 // as well.
1177 // We need to use a prefix that is reserved in WebGL in order to guarantee that the internal
1178 // names don't conflict with user-defined names from WebGL.
1179 return "webgl_angle_" + name.getString();
1180 }
1181 if (mHashFunction == nullptr)
1182 {
1183 return name.getString();
1184 }
1185 NameMap::const_iterator it = mNameMap.find(name.getString().c_str());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001186 if (it != mNameMap.end())
1187 return it->second.c_str();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001188 TString hashedName = TIntermTraverser::hash(name.getString(), mHashFunction);
1189 mNameMap[name.getString().c_str()] = hashedName.c_str();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001190 return hashedName;
1191}
1192
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001193TString TOutputGLSLBase::hashVariableName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001194{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001195 if (mSymbolTable.findBuiltIn(name.getString(), mShaderVersion) != NULL)
Olli Etuaho09b04a22016-12-15 13:30:26 +00001196 {
1197 if (mCompileOptions & SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM &&
1198 name.getString() == "gl_ViewID_OVR")
1199 {
Olli Etuaho2f90a9b2017-01-10 12:27:56 +00001200 TName uniformName(TString("ViewID_OVR"));
Olli Etuaho09b04a22016-12-15 13:30:26 +00001201 uniformName.setInternal(true);
1202 return hashName(uniformName);
1203 }
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001204 return name.getString();
Olli Etuaho09b04a22016-12-15 13:30:26 +00001205 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001206 return hashName(name);
1207}
1208
Olli Etuahoec9232b2017-03-27 17:01:37 +03001209TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TFunctionSymbolInfo &info)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001210{
Olli Etuahoec9232b2017-03-27 17:01:37 +03001211 if (info.isMain() || info.getNameObj().isInternal())
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001212 {
1213 // Internal function names are outputted as-is - they may refer to functions manually added
1214 // to the output shader source that are not included in the AST at all.
Olli Etuahoec9232b2017-03-27 17:01:37 +03001215 return info.getName();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001216 }
Olli Etuaho59f9a642015-08-06 20:38:26 +03001217 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001218 {
Olli Etuahoec9232b2017-03-27 17:01:37 +03001219 return hashName(info.getNameObj());
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001220 }
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
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001238 out << "struct " << hashName(TName(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 << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001245 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Jamie Madill98493dd2013-07-08 14:39:03 -04001246 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
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001306 out << hashName(TName(interfaceBlock->name())) << "{\n";
Geoff Langbdcc54a2015-09-02 13:09:48 -04001307 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 << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001313 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Geoff Langbdcc54a2015-09-02 13:09:48 -04001314 if (field->type()->isArray())
1315 out << arrayBrackets(*field->type());
1316 out << ";\n";
1317 }
1318 out << "}";
1319}
Jamie Madill45bcc782016-11-07 13:58:48 -05001320
1321} // namespace sh