blob: 95dc947bbdfc7db6a2f2507267581c64211c8765 [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
Shaob5cc1192017-07-06 10:47:20 +08009#include "angle_gl.h"
Olli Etuahod57e0db2015-04-24 15:05:08 +030010#include "common/debug.h"
Olli Etuaho56a2f952016-12-08 12:16:27 +000011#include "common/mathutil.h"
Olli Etuahocccf2b02017-07-05 14:50:54 +030012#include "compiler/translator/Compiler.h"
Olli Etuaho96f6adf2017-08-16 11:18:54 +030013#include "compiler/translator/util.h"
zmo@google.com5601ea02011-06-10 18:23:25 +000014
daniel@transgaming.com773ff742013-01-11 04:12:51 +000015#include <cfloat>
daniel@transgaming.com6c1203f2013-01-11 04:12:43 +000016
Jamie Madill45bcc782016-11-07 13:58:48 -050017namespace sh
18{
19
zmo@google.com5601ea02011-06-10 18:23:25 +000020namespace
21{
zmo@google.com5601ea02011-06-10 18:23:25 +000022
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
Jiawei Shao4cc89e22017-08-31 14:25:54 +080066 if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn ||
67 IsVarying(type.getQualifier())) &&
Martin Radev2cc85b32016-08-05 16:22:53 +030068 layoutQualifier.location >= 0)
69 {
70 return true;
71 }
Olli Etuaho43364892017-02-13 16:00:12 +000072
Andrei Volykhina5527072017-03-22 16:46:30 +030073 if (type.getQualifier() == EvqFragmentOut && layoutQualifier.yuv == true)
74 {
75 return true;
76 }
77
Olli Etuaho43364892017-02-13 16:00:12 +000078 if (IsOpaqueType(type.getBasicType()) && layoutQualifier.binding != -1)
79 {
80 return true;
81 }
82
Martin Radev2cc85b32016-08-05 16:22:53 +030083 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
84 {
85 return true;
86 }
87 return false;
88}
89
Olli Etuaho43364892017-02-13 16:00:12 +000090class CommaSeparatedListItemPrefixGenerator
91{
92 public:
93 CommaSeparatedListItemPrefixGenerator() : mFirst(true) {}
94 private:
95 bool mFirst;
96
97 friend TInfoSinkBase &operator<<(TInfoSinkBase &out,
98 CommaSeparatedListItemPrefixGenerator &gen);
99};
100
101TInfoSinkBase &operator<<(TInfoSinkBase &out, CommaSeparatedListItemPrefixGenerator &gen)
102{
103 if (gen.mFirst)
104 {
105 gen.mFirst = false;
106 }
107 else
108 {
109 out << ", ";
110 }
111 return out;
112}
113
zmo@google.com5601ea02011-06-10 18:23:25 +0000114} // namespace
115
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700116TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000117 ShArrayIndexClampingStrategy clampingStrategy,
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000118 ShHashFunction64 hashFunction,
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700119 NameMap &nameMap,
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300120 TSymbolTable *symbolTable,
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000121 sh::GLenum shaderType,
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800122 int shaderVersion,
Qiankun Miao705a9192016-08-29 10:05:27 +0800123 ShShaderOutput output,
124 ShCompileOptions compileOptions)
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300125 : TIntermTraverser(true, true, true, symbolTable),
zmo@google.com5601ea02011-06-10 18:23:25 +0000126 mObjSink(objSink),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000127 mDeclaringVariables(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000128 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000129 mHashFunction(hashFunction),
130 mNameMap(nameMap),
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000131 mShaderType(shaderType),
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800132 mShaderVersion(shaderVersion),
Qiankun Miao705a9192016-08-29 10:05:27 +0800133 mOutput(output),
134 mCompileOptions(compileOptions)
zmo@google.com5601ea02011-06-10 18:23:25 +0000135{
136}
137
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800138void TOutputGLSLBase::writeInvariantQualifier(const TType &type)
139{
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000140 if (!sh::RemoveInvariant(mShaderType, mShaderVersion, mOutput, mCompileOptions))
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800141 {
142 TInfoSinkBase &out = objSink();
143 out << "invariant ";
144 }
145}
146
Olli Etuaho56a2f952016-12-08 12:16:27 +0000147void TOutputGLSLBase::writeFloat(TInfoSinkBase &out, float f)
148{
149 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300)
150 {
151 out << "uintBitsToFloat(" << gl::bitCast<uint32_t>(f) << "u)";
152 }
153 else
154 {
155 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
156 }
157}
158
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500159void TOutputGLSLBase::writeTriplet(Visit visit,
160 const char *preStr,
161 const char *inStr,
162 const char *postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000163{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700164 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000165 if (visit == PreVisit && preStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000166 out << preStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000167 else if (visit == InVisit && inStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000168 out << inStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000169 else if (visit == PostVisit && postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000170 out << postStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000171}
172
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500173void TOutputGLSLBase::writeBuiltInFunctionTriplet(Visit visit,
Olli Etuahoe1805592017-01-02 16:41:20 +0000174 TOperator op,
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500175 bool useEmulatedFunction)
zmo@google.com5601ea02011-06-10 18:23:25 +0000176{
Olli Etuahod68924e2017-01-02 17:34:40 +0000177 TInfoSinkBase &out = objSink();
178 if (visit == PreVisit)
Olli Etuahoe1805592017-01-02 16:41:20 +0000179 {
Olli Etuahod68924e2017-01-02 17:34:40 +0000180 const char *opStr(GetOperatorString(op));
181 if (useEmulatedFunction)
182 {
183 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
184 }
185 else
186 {
187 out << opStr;
188 }
189 out << "(";
Olli Etuahoe1805592017-01-02 16:41:20 +0000190 }
Olli Etuahod68924e2017-01-02 17:34:40 +0000191 else
192 {
193 writeTriplet(visit, nullptr, ", ", ")");
194 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700195}
196
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300197void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
198{
Martin Radev2cc85b32016-08-05 16:22:53 +0300199 if (!NeedsToWriteLayoutQualifier(type))
200 {
201 return;
202 }
203
204 TInfoSinkBase &out = objSink();
205 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
206 out << "layout(";
207
Olli Etuaho43364892017-02-13 16:00:12 +0000208 CommaSeparatedListItemPrefixGenerator listItemPrefix;
209
Jiawei Shao4cc89e22017-08-31 14:25:54 +0800210 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn ||
211 IsVarying(type.getQualifier()))
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300212 {
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300213 if (layoutQualifier.location >= 0)
214 {
Olli Etuaho43364892017-02-13 16:00:12 +0000215 out << listItemPrefix << "location = " << layoutQualifier.location;
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300216 }
217 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300218
Andrei Volykhina5527072017-03-22 16:46:30 +0300219 if (type.getQualifier() == EvqFragmentOut)
220 {
221 if (layoutQualifier.yuv == true)
222 {
223 out << listItemPrefix << "yuv";
224 }
225 }
226
Olli Etuaho43364892017-02-13 16:00:12 +0000227 if (IsOpaqueType(type.getBasicType()))
Martin Radev2cc85b32016-08-05 16:22:53 +0300228 {
Olli Etuaho43364892017-02-13 16:00:12 +0000229 if (layoutQualifier.binding >= 0)
230 {
231 out << listItemPrefix << "binding = " << layoutQualifier.binding;
232 }
233 }
234
235 if (IsImage(type.getBasicType()))
236 {
237 if (layoutQualifier.imageInternalFormat != EiifUnspecified)
238 {
239 ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
240 out << listItemPrefix
241 << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
242 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300243 }
244
jchen1005c31da2017-07-18 16:11:39 +0800245 if (IsAtomicCounter(type.getBasicType()))
246 {
247 out << listItemPrefix << "offset = " << layoutQualifier.offset;
248 }
249
Martin Radev2cc85b32016-08-05 16:22:53 +0300250 out << ") ";
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300251}
252
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800253const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier)
254{
255 if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 &&
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000256 (mCompileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0)
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800257 {
258 switch (qualifier)
259 {
260 // The return string is consistent with sh::getQualifierString() from
261 // BaseTypes.h minus the "centroid" keyword.
262 case EvqCentroid:
263 return "";
264 case EvqCentroidIn:
265 return "smooth in";
266 case EvqCentroidOut:
267 return "smooth out";
268 default:
269 break;
270 }
271 }
272 if (sh::IsGLSL130OrNewer(mOutput))
273 {
274 switch (qualifier)
275 {
276 case EvqAttribute:
277 return "in";
278 case EvqVaryingIn:
279 return "in";
280 case EvqVaryingOut:
281 return "out";
282 default:
283 break;
284 }
285 }
286 return sh::getQualifierString(qualifier);
287}
288
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700289void TOutputGLSLBase::writeVariableType(const TType &type)
290{
Qiankun Miao705a9192016-08-29 10:05:27 +0800291 TQualifier qualifier = type.getQualifier();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500292 TInfoSinkBase &out = objSink();
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800293 if (type.isInvariant())
Olli Etuaho214c2d82015-04-27 14:49:13 +0300294 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800295 writeInvariantQualifier(type);
Olli Etuaho214c2d82015-04-27 14:49:13 +0300296 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400297 if (type.getBasicType() == EbtInterfaceBlock)
298 {
299 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
300 declareInterfaceBlockLayout(interfaceBlock);
301 }
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400302 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400303 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800304 const char *qualifierString = mapQualifierToString(qualifier);
305 if (qualifierString && qualifierString[0] != '\0')
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800306 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800307 out << qualifierString << " ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800308 }
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400309 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300310
311 const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
312 if (memoryQualifier.readonly)
313 {
314 ASSERT(IsImage(type.getBasicType()));
315 out << "readonly ";
316 }
317
318 if (memoryQualifier.writeonly)
319 {
320 ASSERT(IsImage(type.getBasicType()));
321 out << "writeonly ";
322 }
323
Martin Radev049edfa2016-11-11 14:35:37 +0200324 if (memoryQualifier.coherent)
325 {
326 ASSERT(IsImage(type.getBasicType()));
327 out << "coherent ";
328 }
329
330 if (memoryQualifier.restrictQualifier)
331 {
332 ASSERT(IsImage(type.getBasicType()));
333 out << "restrict ";
334 }
335
336 if (memoryQualifier.volatileQualifier)
337 {
338 ASSERT(IsImage(type.getBasicType()));
339 out << "volatile ";
340 }
341
zmo@google.com5601ea02011-06-10 18:23:25 +0000342 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700343 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000344 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400345 TStructure *structure = type.getStruct();
346
347 declareStruct(structure);
348
349 if (!structure->name().empty())
350 {
351 mDeclaredStructs.insert(structure->uniqueId());
352 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000353 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400354 else if (type.getBasicType() == EbtInterfaceBlock)
355 {
356 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
357 declareInterfaceBlock(interfaceBlock);
358 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000359 else
360 {
361 if (writeVariablePrecision(type.getPrecision()))
362 out << " ";
363 out << getTypeName(type);
364 }
365}
366
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700367void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000368{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700369 TInfoSinkBase &out = objSink();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500370 for (TIntermSequence::const_iterator iter = args.begin(); iter != args.end(); ++iter)
zmo@google.com5601ea02011-06-10 18:23:25 +0000371 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700372 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
Yunchao He4f285442017-04-21 12:15:49 +0800373 ASSERT(arg != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +0000374
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700375 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000376 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000377
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000378 if (!arg->getName().getString().empty())
379 out << " " << hashName(arg->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000380 if (type.isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300381 out << ArrayString(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000382
383 // Put a comma if this is not the last argument.
384 if (iter != args.end() - 1)
385 out << ", ";
386 }
387}
388
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500389const TConstantUnion *TOutputGLSLBase::writeConstantUnion(const TType &type,
390 const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000391{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700392 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000393
394 if (type.getBasicType() == EbtStruct)
395 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700396 const TStructure *structure = type.getStruct();
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000397 out << hashName(TName(structure->name())) << "(";
Jamie Madill98493dd2013-07-08 14:39:03 -0400398
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700399 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400400 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000401 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700402 const TType *fieldType = fields[i]->type();
Yunchao He4f285442017-04-21 12:15:49 +0800403 ASSERT(fieldType != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +0000404 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700405 if (i != fields.size() - 1)
406 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000407 }
408 out << ")";
409 }
410 else
411 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500412 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000413 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700414 if (writeType)
415 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400416 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000417 {
418 switch (pConstUnion->getType())
419 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500420 case EbtFloat:
421 writeFloat(out, pConstUnion->getFConst());
422 break;
423 case EbtInt:
424 out << pConstUnion->getIConst();
425 break;
426 case EbtUInt:
427 out << pConstUnion->getUConst() << "u";
428 break;
429 case EbtBool:
430 out << pConstUnion->getBConst();
431 break;
Andrei Volykhina5527072017-03-22 16:46:30 +0300432 case EbtYuvCscStandardEXT:
433 out << getYuvCscStandardEXTString(pConstUnion->getYuvCscStandardEXTConst());
434 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500435 default:
436 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000437 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700438 if (i != size - 1)
439 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000440 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700441 if (writeType)
442 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000443 }
444 return pConstUnion;
445}
446
Olli Etuahoe92507b2016-07-04 11:20:10 +0300447void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
Olli Etuahof40319e2015-03-10 14:33:00 +0200448{
449 TInfoSinkBase &out = objSink();
450 if (visit == PreVisit)
451 {
452 if (type.isArray())
453 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300454 out << getTypeName(type);
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300455 out << ArrayString(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200456 out << "(";
457 }
458 else
459 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300460 out << getTypeName(type) << "(";
Olli Etuahof40319e2015-03-10 14:33:00 +0200461 }
462 }
463 else
464 {
465 writeTriplet(visit, nullptr, ", ", ")");
466 }
467}
468
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700469void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000470{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700471 TInfoSinkBase &out = objSink();
Corentin Wallez1b896c62016-11-16 13:10:44 -0500472 out << hashVariableName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000473
474 if (mDeclaringVariables && node->getType().isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300475 out << ArrayString(node->getType());
zmo@google.com5601ea02011-06-10 18:23:25 +0000476}
477
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700478void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000479{
480 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
481}
482
Olli Etuahob6fa0432016-09-28 16:28:05 +0100483bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
484{
485 TInfoSinkBase &out = objSink();
486 if (visit == PostVisit)
487 {
488 out << ".";
489 node->writeOffsetsAsXYZW(&out);
490 }
491 return true;
492}
493
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700494bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000495{
496 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700497 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000498 switch (node->getOp())
499 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100500 case EOpComma:
501 writeTriplet(visit, "(", ", ", ")");
502 break;
503 case EOpInitialize:
zmo@google.com5601ea02011-06-10 18:23:25 +0000504 if (visit == InVisit)
505 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100506 out << " = ";
507 // RHS of initialize is not being declared.
508 mDeclaringVariables = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000509 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100510 break;
511 case EOpAssign:
512 writeTriplet(visit, "(", " = ", ")");
513 break;
514 case EOpAddAssign:
515 writeTriplet(visit, "(", " += ", ")");
516 break;
517 case EOpSubAssign:
518 writeTriplet(visit, "(", " -= ", ")");
519 break;
520 case EOpDivAssign:
521 writeTriplet(visit, "(", " /= ", ")");
522 break;
523 case EOpIModAssign:
524 writeTriplet(visit, "(", " %= ", ")");
525 break;
526 // Notice the fall-through.
527 case EOpMulAssign:
528 case EOpVectorTimesMatrixAssign:
529 case EOpVectorTimesScalarAssign:
530 case EOpMatrixTimesScalarAssign:
531 case EOpMatrixTimesMatrixAssign:
532 writeTriplet(visit, "(", " *= ", ")");
533 break;
534 case EOpBitShiftLeftAssign:
535 writeTriplet(visit, "(", " <<= ", ")");
536 break;
537 case EOpBitShiftRightAssign:
538 writeTriplet(visit, "(", " >>= ", ")");
539 break;
540 case EOpBitwiseAndAssign:
541 writeTriplet(visit, "(", " &= ", ")");
542 break;
543 case EOpBitwiseXorAssign:
544 writeTriplet(visit, "(", " ^= ", ")");
545 break;
546 case EOpBitwiseOrAssign:
547 writeTriplet(visit, "(", " |= ", ")");
548 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000549
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100550 case EOpIndexDirect:
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800551 writeTriplet(visit, nullptr, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100552 break;
553 case EOpIndexIndirect:
554 if (node->getAddIndexClamp())
555 {
556 if (visit == InVisit)
557 {
558 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
559 out << "[int(clamp(float(";
560 else
561 out << "[webgl_int_clamp(";
562 }
563 else if (visit == PostVisit)
564 {
565 int maxSize;
566 TIntermTyped *left = node->getLeft();
567 TType leftType = left->getType();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700568
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100569 if (left->isArray())
570 {
571 // The shader will fail validation if the array length is not > 0.
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300572 maxSize = static_cast<int>(leftType.getOutermostArraySize()) - 1;
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100573 }
574 else
575 {
576 maxSize = leftType.getNominalSize() - 1;
577 }
578
579 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
580 out << "), 0.0, float(" << maxSize << ")))]";
581 else
582 out << ", 0, " << maxSize << ")]";
583 }
584 }
585 else
586 {
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800587 writeTriplet(visit, nullptr, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100588 }
589 break;
590 case EOpIndexDirectStruct:
591 if (visit == InVisit)
592 {
593 // Here we are writing out "foo.bar", where "foo" is struct
594 // and "bar" is field. In AST, it is represented as a binary
595 // node, where left child represents "foo" and right child "bar".
596 // The node itself represents ".". The struct field "bar" is
597 // actually stored as an index into TStructure::fields.
598 out << ".";
599 const TStructure *structure = node->getLeft()->getType().getStruct();
600 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
601 const TField *field = structure->fields()[index->getIConst(0)];
602
603 TString fieldName = field->name();
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300604 if (!mSymbolTable->findBuiltIn(structure->name(), mShaderVersion))
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000605 fieldName = hashName(TName(fieldName));
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100606
607 out << fieldName;
608 visitChildren = false;
609 }
610 break;
611 case EOpIndexDirectInterfaceBlock:
612 if (visit == InVisit)
613 {
614 out << ".";
615 const TInterfaceBlock *interfaceBlock =
616 node->getLeft()->getType().getInterfaceBlock();
617 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
618 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
619
620 TString fieldName = field->name();
Jiawei Shaod8105a02017-08-08 09:54:36 +0800621 ASSERT(!mSymbolTable->findBuiltIn(interfaceBlock->name(), mShaderVersion) ||
622 interfaceBlock->name() == "gl_PerVertex");
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000623 fieldName = hashName(TName(fieldName));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700624
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100625 out << fieldName;
626 visitChildren = false;
627 }
628 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400629
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100630 case EOpAdd:
631 writeTriplet(visit, "(", " + ", ")");
632 break;
633 case EOpSub:
634 writeTriplet(visit, "(", " - ", ")");
635 break;
636 case EOpMul:
637 writeTriplet(visit, "(", " * ", ")");
638 break;
639 case EOpDiv:
640 writeTriplet(visit, "(", " / ", ")");
641 break;
642 case EOpIMod:
643 writeTriplet(visit, "(", " % ", ")");
644 break;
645 case EOpBitShiftLeft:
646 writeTriplet(visit, "(", " << ", ")");
647 break;
648 case EOpBitShiftRight:
649 writeTriplet(visit, "(", " >> ", ")");
650 break;
651 case EOpBitwiseAnd:
652 writeTriplet(visit, "(", " & ", ")");
653 break;
654 case EOpBitwiseXor:
655 writeTriplet(visit, "(", " ^ ", ")");
656 break;
657 case EOpBitwiseOr:
658 writeTriplet(visit, "(", " | ", ")");
659 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400660
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100661 case EOpEqual:
662 writeTriplet(visit, "(", " == ", ")");
663 break;
664 case EOpNotEqual:
665 writeTriplet(visit, "(", " != ", ")");
666 break;
667 case EOpLessThan:
668 writeTriplet(visit, "(", " < ", ")");
669 break;
670 case EOpGreaterThan:
671 writeTriplet(visit, "(", " > ", ")");
672 break;
673 case EOpLessThanEqual:
674 writeTriplet(visit, "(", " <= ", ")");
675 break;
676 case EOpGreaterThanEqual:
677 writeTriplet(visit, "(", " >= ", ")");
678 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000679
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100680 // Notice the fall-through.
681 case EOpVectorTimesScalar:
682 case EOpVectorTimesMatrix:
683 case EOpMatrixTimesVector:
684 case EOpMatrixTimesScalar:
685 case EOpMatrixTimesMatrix:
686 writeTriplet(visit, "(", " * ", ")");
687 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200688
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100689 case EOpLogicalOr:
690 writeTriplet(visit, "(", " || ", ")");
691 break;
692 case EOpLogicalXor:
693 writeTriplet(visit, "(", " ^^ ", ")");
694 break;
695 case EOpLogicalAnd:
696 writeTriplet(visit, "(", " && ", ")");
697 break;
698 default:
699 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000700 }
701
702 return visitChildren;
703}
704
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700705bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000706{
zmo@google.com32e97312011-08-24 01:03:11 +0000707 TString preString;
708 TString postString = ")";
709
zmo@google.com5601ea02011-06-10 18:23:25 +0000710 switch (node->getOp())
711 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500712 case EOpNegative:
713 preString = "(-";
714 break;
715 case EOpPositive:
716 preString = "(+";
717 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500718 case EOpLogicalNot:
719 preString = "(!";
720 break;
721 case EOpBitwiseNot:
722 preString = "(~";
723 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000724
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500725 case EOpPostIncrement:
726 preString = "(";
727 postString = "++)";
728 break;
729 case EOpPostDecrement:
730 preString = "(";
731 postString = "--)";
732 break;
733 case EOpPreIncrement:
734 preString = "(++";
735 break;
736 case EOpPreDecrement:
737 preString = "(--";
738 break;
Olli Etuahobb5a7e22017-08-30 13:03:12 +0300739 case EOpArrayLength:
740 preString = "((";
741 postString = ").length())";
742 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000743
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500744 case EOpRadians:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500745 case EOpDegrees:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500746 case EOpSin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500747 case EOpCos:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500748 case EOpTan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500749 case EOpAsin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500750 case EOpAcos:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500751 case EOpAtan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500752 case EOpSinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500753 case EOpCosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500754 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500755 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500756 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500757 case EOpAtanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500758 case EOpExp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500759 case EOpLog:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500760 case EOpExp2:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500761 case EOpLog2:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500762 case EOpSqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500763 case EOpInverseSqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500764 case EOpAbs:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500765 case EOpSign:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500766 case EOpFloor:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500767 case EOpTrunc:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500768 case EOpRound:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500769 case EOpRoundEven:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500770 case EOpCeil:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500771 case EOpFract:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500772 case EOpIsNan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500773 case EOpIsInf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500774 case EOpFloatBitsToInt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500775 case EOpFloatBitsToUint:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500776 case EOpIntBitsToFloat:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500777 case EOpUintBitsToFloat:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500778 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500779 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500780 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500781 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500782 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500783 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800784 case EOpPackUnorm4x8:
785 case EOpPackSnorm4x8:
786 case EOpUnpackUnorm4x8:
787 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500788 case EOpLength:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500789 case EOpNormalize:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500790 case EOpDFdx:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500791 case EOpDFdy:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500792 case EOpFwidth:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500793 case EOpTranspose:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500794 case EOpDeterminant:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500795 case EOpInverse:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500796 case EOpAny:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500797 case EOpAll:
Olli Etuahod68924e2017-01-02 17:34:40 +0000798 case EOpLogicalNotComponentWise:
Olli Etuaho9250cb22017-01-21 10:51:27 +0000799 case EOpBitfieldReverse:
800 case EOpBitCount:
801 case EOpFindLSB:
802 case EOpFindMSB:
Olli Etuahod68924e2017-01-02 17:34:40 +0000803 writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
804 return true;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500805 default:
806 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000807 }
808
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800809 writeTriplet(visit, preString.c_str(), nullptr, postString.c_str());
zmo@google.com32e97312011-08-24 01:03:11 +0000810
zmo@google.com5601ea02011-06-10 18:23:25 +0000811 return true;
812}
813
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300814bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
815{
816 TInfoSinkBase &out = objSink();
817 // Notice two brackets at the beginning and end. The outer ones
818 // encapsulate the whole ternary expression. This preserves the
819 // order of precedence when ternary expressions are used in a
820 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
821 out << "((";
822 node->getCondition()->traverse(this);
823 out << ") ? (";
824 node->getTrueExpression()->traverse(this);
825 out << ") : (";
826 node->getFalseExpression()->traverse(this);
827 out << "))";
828 return false;
829}
830
Olli Etuaho57961272016-09-14 13:57:46 +0300831bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000832{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700833 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000834
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300835 out << "if (";
836 node->getCondition()->traverse(this);
837 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000838
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300839 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000840
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300841 if (node->getFalseBlock())
842 {
843 out << "else\n";
844 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000845 }
846 return false;
847}
848
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200849bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200850{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200851 if (node->getStatementList())
852 {
853 writeTriplet(visit, "switch (", ") ", nullptr);
854 // The curly braces get written when visiting the statementList aggregate
855 }
856 else
857 {
858 // No statementList, so it won't output curly braces
859 writeTriplet(visit, "switch (", ") {", "}\n");
860 }
861 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200862}
863
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200864bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200865{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200866 if (node->hasCondition())
867 {
868 writeTriplet(visit, "case (", nullptr, "):\n");
869 return true;
870 }
871 else
872 {
873 TInfoSinkBase &out = objSink();
874 out << "default:\n";
875 return false;
876 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200877}
878
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100879bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
880{
881 TInfoSinkBase &out = objSink();
882 // Scope the blocks except when at the global scope.
883 if (mDepth > 0)
884 {
885 out << "{\n";
886 }
887
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100888 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
889 iter != node->getSequence()->end(); ++iter)
890 {
891 TIntermNode *curNode = *iter;
892 ASSERT(curNode != nullptr);
893 curNode->traverse(this);
894
895 if (isSingleStatement(curNode))
896 out << ";\n";
897 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100898
899 // Scope the blocks except when at the global scope.
900 if (mDepth > 0)
901 {
902 out << "}\n";
903 }
904 return false;
905}
906
Olli Etuaho336b1472016-10-05 16:37:55 +0100907bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
908{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000909 TIntermFunctionPrototype *prototype = node->getFunctionPrototype();
910 prototype->traverse(this);
Olli Etuaho336b1472016-10-05 16:37:55 +0100911 visitCodeBlock(node->getBody());
Olli Etuaho336b1472016-10-05 16:37:55 +0100912
913 // Fully processed; no need to visit children.
914 return false;
915}
916
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000917bool TOutputGLSLBase::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
918{
919 TInfoSinkBase &out = objSink();
920 ASSERT(visit == PreVisit);
921 const TIntermSymbol *symbol = node->getSymbol();
922 out << "invariant " << hashVariableName(symbol->getName());
923 return false;
924}
925
Olli Etuaho16c745a2017-01-16 17:02:27 +0000926bool TOutputGLSLBase::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
927{
928 TInfoSinkBase &out = objSink();
929 ASSERT(visit == PreVisit);
930
931 const TType &type = node->getType();
932 writeVariableType(type);
933 if (type.isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300934 out << ArrayString(type);
Olli Etuaho16c745a2017-01-16 17:02:27 +0000935
Olli Etuahoec9232b2017-03-27 17:01:37 +0300936 out << " " << hashFunctionNameIfNeeded(*node->getFunctionSymbolInfo());
Olli Etuaho16c745a2017-01-16 17:02:27 +0000937
938 out << "(";
939 writeFunctionParameters(*(node->getSequence()));
940 out << ")";
941
942 return false;
943}
944
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700945bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000946{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500947 bool visitChildren = true;
948 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000949 switch (node->getOp())
950 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800951 case EOpCallFunctionInAST:
952 case EOpCallInternalRawFunction:
953 case EOpCallBuiltInFunction:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500954 // Function call.
955 if (visit == PreVisit)
Olli Etuahoec9232b2017-03-27 17:01:37 +0300956 {
957 if (node->getOp() == EOpCallBuiltInFunction)
958 {
959 out << translateTextureFunction(node->getFunctionSymbolInfo()->getName());
960 }
961 else
962 {
963 out << hashFunctionNameIfNeeded(*node->getFunctionSymbolInfo());
964 }
965 out << "(";
966 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500967 else if (visit == InVisit)
968 out << ", ";
969 else
970 out << ")";
971 break;
Olli Etuaho8fab3202017-05-08 18:22:22 +0300972 case EOpConstruct:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500973 writeConstructorTriplet(visit, node->getType());
974 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200975
Olli Etuahoe1805592017-01-02 16:41:20 +0000976 case EOpEqualComponentWise:
977 case EOpNotEqualComponentWise:
978 case EOpLessThanComponentWise:
979 case EOpGreaterThanComponentWise:
980 case EOpLessThanEqualComponentWise:
981 case EOpGreaterThanEqualComponentWise:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500982 case EOpMod:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500983 case EOpModf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500984 case EOpPow:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500985 case EOpAtan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500986 case EOpMin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500987 case EOpMax:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500988 case EOpClamp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500989 case EOpMix:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500990 case EOpStep:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500991 case EOpSmoothStep:
Olli Etuaho74da73f2017-02-01 15:37:48 +0000992 case EOpFrexp:
993 case EOpLdexp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500994 case EOpDistance:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500995 case EOpDot:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500996 case EOpCross:
Jamie Madille72595b2017-06-06 15:12:26 -0400997 case EOpFaceforward:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500998 case EOpReflect:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500999 case EOpRefract:
Olli Etuahoe1805592017-01-02 16:41:20 +00001000 case EOpMulMatrixComponentWise:
1001 case EOpOuterProduct:
Olli Etuaho9250cb22017-01-21 10:51:27 +00001002 case EOpBitfieldExtract:
1003 case EOpBitfieldInsert:
1004 case EOpUaddCarry:
1005 case EOpUsubBorrow:
1006 case EOpUmulExtended:
1007 case EOpImulExtended:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001008 case EOpBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001009 case EOpMemoryBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001010 case EOpMemoryBarrierAtomicCounter:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001011 case EOpMemoryBarrierBuffer:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001012 case EOpMemoryBarrierImage:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001013 case EOpMemoryBarrierShared:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001014 case EOpGroupMemoryBarrier:
Jiawei Shaod27f5c82017-08-23 09:38:08 +08001015 case EOpEmitVertex:
1016 case EOpEndPrimitive:
Olli Etuahod68924e2017-01-02 17:34:40 +00001017 writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001018 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001019 default:
1020 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001021 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001022 return visitChildren;
1023}
1024
Olli Etuaho13389b62016-10-16 11:48:18 +01001025bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
1026{
1027 TInfoSinkBase &out = objSink();
1028
1029 // Variable declaration.
1030 if (visit == PreVisit)
1031 {
1032 const TIntermSequence &sequence = *(node->getSequence());
1033 const TIntermTyped *variable = sequence.front()->getAsTyped();
1034 writeLayoutQualifier(variable->getType());
1035 writeVariableType(variable->getType());
1036 out << " ";
1037 mDeclaringVariables = true;
1038 }
1039 else if (visit == InVisit)
1040 {
1041 out << ", ";
1042 mDeclaringVariables = true;
1043 }
1044 else
1045 {
1046 mDeclaringVariables = false;
1047 }
1048 return true;
1049}
1050
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001051bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001052{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001053 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001054
zmo@google.com5601ea02011-06-10 18:23:25 +00001055 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001056
zmo@google.com5601ea02011-06-10 18:23:25 +00001057 if (loopType == ELoopFor) // for loop
1058 {
Corentin Wallez1b896c62016-11-16 13:10:44 -05001059 out << "for (";
1060 if (node->getInit())
1061 node->getInit()->traverse(this);
1062 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001063
Corentin Wallez1b896c62016-11-16 13:10:44 -05001064 if (node->getCondition())
1065 node->getCondition()->traverse(this);
1066 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001067
Corentin Wallez1b896c62016-11-16 13:10:44 -05001068 if (node->getExpression())
1069 node->getExpression()->traverse(this);
1070 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001071
Corentin Wallez1b896c62016-11-16 13:10:44 -05001072 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001073 }
1074 else if (loopType == ELoopWhile) // while loop
1075 {
1076 out << "while (";
Yunchao He4f285442017-04-21 12:15:49 +08001077 ASSERT(node->getCondition() != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +00001078 node->getCondition()->traverse(this);
1079 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001080
1081 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001082 }
1083 else // do-while loop
1084 {
1085 ASSERT(loopType == ELoopDoWhile);
1086 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001087
zmo@google.com5601ea02011-06-10 18:23:25 +00001088 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001089
zmo@google.com5601ea02011-06-10 18:23:25 +00001090 out << "while (";
Yunchao He4f285442017-04-21 12:15:49 +08001091 ASSERT(node->getCondition() != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +00001092 node->getCondition()->traverse(this);
1093 out << ");\n";
1094 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001095
zmo@google.com5601ea02011-06-10 18:23:25 +00001096 // No need to visit children. They have been already processed in
1097 // this function.
1098 return false;
1099}
1100
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001101bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001102{
1103 switch (node->getFlowOp())
1104 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001105 case EOpKill:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001106 writeTriplet(visit, "discard", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001107 break;
1108 case EOpBreak:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001109 writeTriplet(visit, "break", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001110 break;
1111 case EOpContinue:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001112 writeTriplet(visit, "continue", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001113 break;
1114 case EOpReturn:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001115 writeTriplet(visit, "return ", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001116 break;
1117 default:
1118 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001119 }
1120
1121 return true;
1122}
1123
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001124void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001125{
zmo@google.com5601ea02011-06-10 18:23:25 +00001126 TInfoSinkBase &out = objSink();
Yunchao He4f285442017-04-21 12:15:49 +08001127 if (node != nullptr)
zmo@google.com5601ea02011-06-10 18:23:25 +00001128 {
1129 node->traverse(this);
1130 // Single statements not part of a sequence need to be terminated
1131 // with semi-colon.
1132 if (isSingleStatement(node))
1133 out << ";\n";
1134 }
1135 else
1136 {
1137 out << "{\n}\n"; // Empty code block.
1138 }
1139}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001140
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001141TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001142{
Olli Etuahoe92507b2016-07-04 11:20:10 +03001143 if (type.getBasicType() == EbtStruct)
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001144 return hashName(TName(type.getStruct()->name()));
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001145 else
Olli Etuahoe92507b2016-07-04 11:20:10 +03001146 return type.getBuiltInTypeNameString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001147}
1148
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001149TString TOutputGLSLBase::hashName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001150{
Olli Etuaho855d9642017-05-17 14:05:06 +03001151 return HashName(name, mHashFunction, &mNameMap);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001152}
1153
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001154TString TOutputGLSLBase::hashVariableName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001155{
Olli Etuaho855d9642017-05-17 14:05:06 +03001156 if (mSymbolTable->findBuiltIn(name.getString(), mShaderVersion) != nullptr ||
1157 name.getString().substr(0, 3) == "gl_")
Olli Etuaho09b04a22016-12-15 13:30:26 +00001158 {
1159 if (mCompileOptions & SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM &&
1160 name.getString() == "gl_ViewID_OVR")
1161 {
Olli Etuaho2f90a9b2017-01-10 12:27:56 +00001162 TName uniformName(TString("ViewID_OVR"));
Olli Etuaho09b04a22016-12-15 13:30:26 +00001163 uniformName.setInternal(true);
1164 return hashName(uniformName);
1165 }
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001166 return name.getString();
Olli Etuaho09b04a22016-12-15 13:30:26 +00001167 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001168 return hashName(name);
1169}
1170
Olli Etuahoec9232b2017-03-27 17:01:37 +03001171TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TFunctionSymbolInfo &info)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001172{
Olli Etuaho855d9642017-05-17 14:05:06 +03001173 if (info.isMain())
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001174 {
Olli Etuahoec9232b2017-03-27 17:01:37 +03001175 return info.getName();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001176 }
Olli Etuaho59f9a642015-08-06 20:38:26 +03001177 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001178 {
Olli Etuahoec9232b2017-03-27 17:01:37 +03001179 return hashName(info.getNameObj());
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001180 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001181}
Jamie Madill98493dd2013-07-08 14:39:03 -04001182
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001183bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001184{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001185 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001186 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001187 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001188 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001189 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001190
1191 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001192}
1193
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001194void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001195{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001196 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001197
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001198 out << "struct " << hashName(TName(structure->name())) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001199 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001200 for (size_t i = 0; i < fields.size(); ++i)
1201 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001202 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001203 if (writeVariablePrecision(field->type()->getPrecision()))
1204 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001205 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Jamie Madill98493dd2013-07-08 14:39:03 -04001206 if (field->type()->isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001207 out << ArrayString(*field->type());
Jamie Madill98493dd2013-07-08 14:39:03 -04001208 out << ";\n";
1209 }
1210 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001211}
Jamie Madill98493dd2013-07-08 14:39:03 -04001212
Geoff Langbdcc54a2015-09-02 13:09:48 -04001213void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1214{
1215 TInfoSinkBase &out = objSink();
1216
1217 out << "layout(";
1218
1219 switch (interfaceBlock->blockStorage())
1220 {
1221 case EbsUnspecified:
1222 case EbsShared:
1223 // Default block storage is shared.
1224 out << "shared";
1225 break;
1226
1227 case EbsPacked:
1228 out << "packed";
1229 break;
1230
1231 case EbsStd140:
1232 out << "std140";
1233 break;
1234
1235 default:
1236 UNREACHABLE();
1237 break;
1238 }
1239
1240 out << ", ";
1241
Jiajia Qin729b2c62017-08-14 09:36:11 +08001242 if (interfaceBlock->blockBinding() > 0)
1243 {
1244 out << "binding = " << interfaceBlock->blockBinding();
1245 out << ", ";
1246 }
1247
Geoff Langbdcc54a2015-09-02 13:09:48 -04001248 switch (interfaceBlock->matrixPacking())
1249 {
1250 case EmpUnspecified:
1251 case EmpColumnMajor:
1252 // Default matrix packing is column major.
1253 out << "column_major";
1254 break;
1255
1256 case EmpRowMajor:
1257 out << "row_major";
1258 break;
1259
1260 default:
1261 UNREACHABLE();
1262 break;
1263 }
1264
1265 out << ") ";
1266}
1267
1268void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1269{
1270 TInfoSinkBase &out = objSink();
1271
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001272 out << hashName(TName(interfaceBlock->name())) << "{\n";
Geoff Langbdcc54a2015-09-02 13:09:48 -04001273 const TFieldList &fields = interfaceBlock->fields();
1274 for (size_t i = 0; i < fields.size(); ++i)
1275 {
1276 const TField *field = fields[i];
1277 if (writeVariablePrecision(field->type()->getPrecision()))
1278 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001279 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Geoff Langbdcc54a2015-09-02 13:09:48 -04001280 if (field->type()->isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001281 out << ArrayString(*field->type());
Geoff Langbdcc54a2015-09-02 13:09:48 -04001282 out << ";\n";
1283 }
1284 out << "}";
1285}
Jamie Madill45bcc782016-11-07 13:58:48 -05001286
Shaob5cc1192017-07-06 10:47:20 +08001287void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out,
1288 sh::TLayoutPrimitiveType inputPrimitive,
1289 int invocations,
1290 sh::TLayoutPrimitiveType outputPrimitive,
1291 int maxVertices)
1292{
1293 // Omit 'invocations = 1'
1294 if (inputPrimitive != EptUndefined || invocations > 1)
1295 {
1296 out << "layout (";
1297
1298 if (inputPrimitive != EptUndefined)
1299 {
1300 out << getGeometryShaderPrimitiveTypeString(inputPrimitive);
1301 }
1302
1303 if (invocations > 1)
1304 {
1305 if (inputPrimitive != EptUndefined)
1306 {
1307 out << ", ";
1308 }
1309 out << "invocations = " << invocations;
1310 }
1311 out << ") in;\n";
1312 }
1313
1314 if (outputPrimitive != EptUndefined || maxVertices != -1)
1315 {
1316 out << "layout (";
1317
1318 if (outputPrimitive != EptUndefined)
1319 {
1320 out << getGeometryShaderPrimitiveTypeString(outputPrimitive);
1321 }
1322
1323 if (maxVertices != -1)
1324 {
1325 if (outputPrimitive != EptUndefined)
1326 {
1327 out << ", ";
1328 }
1329 out << "max_vertices = " << maxVertices;
1330 }
1331 out << ") out;\n";
1332 }
1333}
1334
Jamie Madill45bcc782016-11-07 13:58:48 -05001335} // namespace sh