blob: 4d3f098dcc8a66384b0194379b25002e439d3f0c [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
66 if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn) &&
67 layoutQualifier.location >= 0)
68 {
69 return true;
70 }
Olli Etuaho43364892017-02-13 16:00:12 +000071
Andrei Volykhina5527072017-03-22 16:46:30 +030072 if (type.getQualifier() == EvqFragmentOut && layoutQualifier.yuv == true)
73 {
74 return true;
75 }
76
Olli Etuaho43364892017-02-13 16:00:12 +000077 if (IsOpaqueType(type.getBasicType()) && layoutQualifier.binding != -1)
78 {
79 return true;
80 }
81
Martin Radev2cc85b32016-08-05 16:22:53 +030082 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
83 {
84 return true;
85 }
86 return false;
87}
88
Olli Etuaho43364892017-02-13 16:00:12 +000089class CommaSeparatedListItemPrefixGenerator
90{
91 public:
92 CommaSeparatedListItemPrefixGenerator() : mFirst(true) {}
93 private:
94 bool mFirst;
95
96 friend TInfoSinkBase &operator<<(TInfoSinkBase &out,
97 CommaSeparatedListItemPrefixGenerator &gen);
98};
99
100TInfoSinkBase &operator<<(TInfoSinkBase &out, CommaSeparatedListItemPrefixGenerator &gen)
101{
102 if (gen.mFirst)
103 {
104 gen.mFirst = false;
105 }
106 else
107 {
108 out << ", ";
109 }
110 return out;
111}
112
zmo@google.com5601ea02011-06-10 18:23:25 +0000113} // namespace
114
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700115TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000116 ShArrayIndexClampingStrategy clampingStrategy,
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000117 ShHashFunction64 hashFunction,
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700118 NameMap &nameMap,
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300119 TSymbolTable *symbolTable,
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000120 sh::GLenum shaderType,
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800121 int shaderVersion,
Qiankun Miao705a9192016-08-29 10:05:27 +0800122 ShShaderOutput output,
123 ShCompileOptions compileOptions)
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300124 : TIntermTraverser(true, true, true, symbolTable),
zmo@google.com5601ea02011-06-10 18:23:25 +0000125 mObjSink(objSink),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000126 mDeclaringVariables(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000127 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000128 mHashFunction(hashFunction),
129 mNameMap(nameMap),
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000130 mShaderType(shaderType),
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800131 mShaderVersion(shaderVersion),
Qiankun Miao705a9192016-08-29 10:05:27 +0800132 mOutput(output),
133 mCompileOptions(compileOptions)
zmo@google.com5601ea02011-06-10 18:23:25 +0000134{
135}
136
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800137void TOutputGLSLBase::writeInvariantQualifier(const TType &type)
138{
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000139 if (!sh::RemoveInvariant(mShaderType, mShaderVersion, mOutput, mCompileOptions))
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800140 {
141 TInfoSinkBase &out = objSink();
142 out << "invariant ";
143 }
144}
145
Olli Etuaho56a2f952016-12-08 12:16:27 +0000146void TOutputGLSLBase::writeFloat(TInfoSinkBase &out, float f)
147{
148 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300)
149 {
150 out << "uintBitsToFloat(" << gl::bitCast<uint32_t>(f) << "u)";
151 }
152 else
153 {
154 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
155 }
156}
157
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500158void TOutputGLSLBase::writeTriplet(Visit visit,
159 const char *preStr,
160 const char *inStr,
161 const char *postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000162{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700163 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000164 if (visit == PreVisit && preStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000165 out << preStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000166 else if (visit == InVisit && inStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000167 out << inStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000168 else if (visit == PostVisit && postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000169 out << postStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000170}
171
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500172void TOutputGLSLBase::writeBuiltInFunctionTriplet(Visit visit,
Olli Etuahoe1805592017-01-02 16:41:20 +0000173 TOperator op,
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500174 bool useEmulatedFunction)
zmo@google.com5601ea02011-06-10 18:23:25 +0000175{
Olli Etuahod68924e2017-01-02 17:34:40 +0000176 TInfoSinkBase &out = objSink();
177 if (visit == PreVisit)
Olli Etuahoe1805592017-01-02 16:41:20 +0000178 {
Olli Etuahod68924e2017-01-02 17:34:40 +0000179 const char *opStr(GetOperatorString(op));
180 if (useEmulatedFunction)
181 {
182 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
183 }
184 else
185 {
186 out << opStr;
187 }
188 out << "(";
Olli Etuahoe1805592017-01-02 16:41:20 +0000189 }
Olli Etuahod68924e2017-01-02 17:34:40 +0000190 else
191 {
192 writeTriplet(visit, nullptr, ", ", ")");
193 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700194}
195
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300196void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
197{
Martin Radev2cc85b32016-08-05 16:22:53 +0300198 if (!NeedsToWriteLayoutQualifier(type))
199 {
200 return;
201 }
202
203 TInfoSinkBase &out = objSink();
204 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
205 out << "layout(";
206
Olli Etuaho43364892017-02-13 16:00:12 +0000207 CommaSeparatedListItemPrefixGenerator listItemPrefix;
208
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300209 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
210 {
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300211 if (layoutQualifier.location >= 0)
212 {
Olli Etuaho43364892017-02-13 16:00:12 +0000213 out << listItemPrefix << "location = " << layoutQualifier.location;
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300214 }
215 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300216
Andrei Volykhina5527072017-03-22 16:46:30 +0300217 if (type.getQualifier() == EvqFragmentOut)
218 {
219 if (layoutQualifier.yuv == true)
220 {
221 out << listItemPrefix << "yuv";
222 }
223 }
224
Olli Etuaho43364892017-02-13 16:00:12 +0000225 if (IsOpaqueType(type.getBasicType()))
Martin Radev2cc85b32016-08-05 16:22:53 +0300226 {
Olli Etuaho43364892017-02-13 16:00:12 +0000227 if (layoutQualifier.binding >= 0)
228 {
229 out << listItemPrefix << "binding = " << layoutQualifier.binding;
230 }
231 }
232
233 if (IsImage(type.getBasicType()))
234 {
235 if (layoutQualifier.imageInternalFormat != EiifUnspecified)
236 {
237 ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
238 out << listItemPrefix
239 << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
240 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300241 }
242
jchen1005c31da2017-07-18 16:11:39 +0800243 if (IsAtomicCounter(type.getBasicType()))
244 {
245 out << listItemPrefix << "offset = " << layoutQualifier.offset;
246 }
247
Martin Radev2cc85b32016-08-05 16:22:53 +0300248 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();
Yunchao He4f285442017-04-21 12:15:49 +0800371 ASSERT(arg != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +0000372
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())
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300379 out << ArrayString(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000380
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();
Yunchao He4f285442017-04-21 12:15:49 +0800401 ASSERT(fieldType != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +0000402 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 Etuaho96f6adf2017-08-16 11:18:54 +0300453 out << ArrayString(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200454 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())
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300473 out << ArrayString(node->getType());
zmo@google.com5601ea02011-06-10 18:23:25 +0000474}
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:
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800549 writeTriplet(visit, nullptr, "[", "]");
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.
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300570 maxSize = static_cast<int>(leftType.getOutermostArraySize()) - 1;
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100571 }
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 {
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800585 writeTriplet(visit, nullptr, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100586 }
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();
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300602 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();
Jiawei Shaod8105a02017-08-08 09:54:36 +0800619 ASSERT(!mSymbolTable->findBuiltIn(interfaceBlock->name(), mShaderVersion) ||
620 interfaceBlock->name() == "gl_PerVertex");
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000621 fieldName = hashName(TName(fieldName));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700622
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100623 out << fieldName;
624 visitChildren = false;
625 }
626 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400627
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100628 case EOpAdd:
629 writeTriplet(visit, "(", " + ", ")");
630 break;
631 case EOpSub:
632 writeTriplet(visit, "(", " - ", ")");
633 break;
634 case EOpMul:
635 writeTriplet(visit, "(", " * ", ")");
636 break;
637 case EOpDiv:
638 writeTriplet(visit, "(", " / ", ")");
639 break;
640 case EOpIMod:
641 writeTriplet(visit, "(", " % ", ")");
642 break;
643 case EOpBitShiftLeft:
644 writeTriplet(visit, "(", " << ", ")");
645 break;
646 case EOpBitShiftRight:
647 writeTriplet(visit, "(", " >> ", ")");
648 break;
649 case EOpBitwiseAnd:
650 writeTriplet(visit, "(", " & ", ")");
651 break;
652 case EOpBitwiseXor:
653 writeTriplet(visit, "(", " ^ ", ")");
654 break;
655 case EOpBitwiseOr:
656 writeTriplet(visit, "(", " | ", ")");
657 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400658
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100659 case EOpEqual:
660 writeTriplet(visit, "(", " == ", ")");
661 break;
662 case EOpNotEqual:
663 writeTriplet(visit, "(", " != ", ")");
664 break;
665 case EOpLessThan:
666 writeTriplet(visit, "(", " < ", ")");
667 break;
668 case EOpGreaterThan:
669 writeTriplet(visit, "(", " > ", ")");
670 break;
671 case EOpLessThanEqual:
672 writeTriplet(visit, "(", " <= ", ")");
673 break;
674 case EOpGreaterThanEqual:
675 writeTriplet(visit, "(", " >= ", ")");
676 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000677
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100678 // Notice the fall-through.
679 case EOpVectorTimesScalar:
680 case EOpVectorTimesMatrix:
681 case EOpMatrixTimesVector:
682 case EOpMatrixTimesScalar:
683 case EOpMatrixTimesMatrix:
684 writeTriplet(visit, "(", " * ", ")");
685 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200686
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100687 case EOpLogicalOr:
688 writeTriplet(visit, "(", " || ", ")");
689 break;
690 case EOpLogicalXor:
691 writeTriplet(visit, "(", " ^^ ", ")");
692 break;
693 case EOpLogicalAnd:
694 writeTriplet(visit, "(", " && ", ")");
695 break;
696 default:
697 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000698 }
699
700 return visitChildren;
701}
702
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700703bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000704{
zmo@google.com32e97312011-08-24 01:03:11 +0000705 TString preString;
706 TString postString = ")";
707
zmo@google.com5601ea02011-06-10 18:23:25 +0000708 switch (node->getOp())
709 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500710 case EOpNegative:
711 preString = "(-";
712 break;
713 case EOpPositive:
714 preString = "(+";
715 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500716 case EOpLogicalNot:
717 preString = "(!";
718 break;
719 case EOpBitwiseNot:
720 preString = "(~";
721 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000722
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500723 case EOpPostIncrement:
724 preString = "(";
725 postString = "++)";
726 break;
727 case EOpPostDecrement:
728 preString = "(";
729 postString = "--)";
730 break;
731 case EOpPreIncrement:
732 preString = "(++";
733 break;
734 case EOpPreDecrement:
735 preString = "(--";
736 break;
Olli Etuahobb5a7e22017-08-30 13:03:12 +0300737 case EOpArrayLength:
738 preString = "((";
739 postString = ").length())";
740 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000741
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500742 case EOpRadians:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500743 case EOpDegrees:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500744 case EOpSin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500745 case EOpCos:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500746 case EOpTan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500747 case EOpAsin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500748 case EOpAcos:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500749 case EOpAtan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500750 case EOpSinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500751 case EOpCosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500752 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500753 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500754 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500755 case EOpAtanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500756 case EOpExp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500757 case EOpLog:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500758 case EOpExp2:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500759 case EOpLog2:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500760 case EOpSqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500761 case EOpInverseSqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500762 case EOpAbs:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500763 case EOpSign:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500764 case EOpFloor:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500765 case EOpTrunc:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500766 case EOpRound:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500767 case EOpRoundEven:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500768 case EOpCeil:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500769 case EOpFract:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500770 case EOpIsNan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500771 case EOpIsInf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500772 case EOpFloatBitsToInt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500773 case EOpFloatBitsToUint:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500774 case EOpIntBitsToFloat:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500775 case EOpUintBitsToFloat:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500776 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500777 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500778 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500779 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500780 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500781 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800782 case EOpPackUnorm4x8:
783 case EOpPackSnorm4x8:
784 case EOpUnpackUnorm4x8:
785 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500786 case EOpLength:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500787 case EOpNormalize:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500788 case EOpDFdx:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500789 case EOpDFdy:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500790 case EOpFwidth:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500791 case EOpTranspose:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500792 case EOpDeterminant:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500793 case EOpInverse:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500794 case EOpAny:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500795 case EOpAll:
Olli Etuahod68924e2017-01-02 17:34:40 +0000796 case EOpLogicalNotComponentWise:
Olli Etuaho9250cb22017-01-21 10:51:27 +0000797 case EOpBitfieldReverse:
798 case EOpBitCount:
799 case EOpFindLSB:
800 case EOpFindMSB:
Olli Etuahod68924e2017-01-02 17:34:40 +0000801 writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
802 return true;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500803 default:
804 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000805 }
806
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800807 writeTriplet(visit, preString.c_str(), nullptr, postString.c_str());
zmo@google.com32e97312011-08-24 01:03:11 +0000808
zmo@google.com5601ea02011-06-10 18:23:25 +0000809 return true;
810}
811
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300812bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
813{
814 TInfoSinkBase &out = objSink();
815 // Notice two brackets at the beginning and end. The outer ones
816 // encapsulate the whole ternary expression. This preserves the
817 // order of precedence when ternary expressions are used in a
818 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
819 out << "((";
820 node->getCondition()->traverse(this);
821 out << ") ? (";
822 node->getTrueExpression()->traverse(this);
823 out << ") : (";
824 node->getFalseExpression()->traverse(this);
825 out << "))";
826 return false;
827}
828
Olli Etuaho57961272016-09-14 13:57:46 +0300829bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000830{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700831 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000832
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300833 out << "if (";
834 node->getCondition()->traverse(this);
835 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000836
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300837 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000838
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300839 if (node->getFalseBlock())
840 {
841 out << "else\n";
842 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000843 }
844 return false;
845}
846
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200847bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200848{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200849 if (node->getStatementList())
850 {
851 writeTriplet(visit, "switch (", ") ", nullptr);
852 // The curly braces get written when visiting the statementList aggregate
853 }
854 else
855 {
856 // No statementList, so it won't output curly braces
857 writeTriplet(visit, "switch (", ") {", "}\n");
858 }
859 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200860}
861
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200862bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200863{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200864 if (node->hasCondition())
865 {
866 writeTriplet(visit, "case (", nullptr, "):\n");
867 return true;
868 }
869 else
870 {
871 TInfoSinkBase &out = objSink();
872 out << "default:\n";
873 return false;
874 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200875}
876
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100877bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
878{
879 TInfoSinkBase &out = objSink();
880 // Scope the blocks except when at the global scope.
881 if (mDepth > 0)
882 {
883 out << "{\n";
884 }
885
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100886 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
887 iter != node->getSequence()->end(); ++iter)
888 {
889 TIntermNode *curNode = *iter;
890 ASSERT(curNode != nullptr);
891 curNode->traverse(this);
892
893 if (isSingleStatement(curNode))
894 out << ";\n";
895 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100896
897 // Scope the blocks except when at the global scope.
898 if (mDepth > 0)
899 {
900 out << "}\n";
901 }
902 return false;
903}
904
Olli Etuaho336b1472016-10-05 16:37:55 +0100905bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
906{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000907 TIntermFunctionPrototype *prototype = node->getFunctionPrototype();
908 prototype->traverse(this);
Olli Etuaho336b1472016-10-05 16:37:55 +0100909 visitCodeBlock(node->getBody());
Olli Etuaho336b1472016-10-05 16:37:55 +0100910
911 // Fully processed; no need to visit children.
912 return false;
913}
914
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000915bool TOutputGLSLBase::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
916{
917 TInfoSinkBase &out = objSink();
918 ASSERT(visit == PreVisit);
919 const TIntermSymbol *symbol = node->getSymbol();
920 out << "invariant " << hashVariableName(symbol->getName());
921 return false;
922}
923
Olli Etuaho16c745a2017-01-16 17:02:27 +0000924bool TOutputGLSLBase::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
925{
926 TInfoSinkBase &out = objSink();
927 ASSERT(visit == PreVisit);
928
929 const TType &type = node->getType();
930 writeVariableType(type);
931 if (type.isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300932 out << ArrayString(type);
Olli Etuaho16c745a2017-01-16 17:02:27 +0000933
Olli Etuahoec9232b2017-03-27 17:01:37 +0300934 out << " " << hashFunctionNameIfNeeded(*node->getFunctionSymbolInfo());
Olli Etuaho16c745a2017-01-16 17:02:27 +0000935
936 out << "(";
937 writeFunctionParameters(*(node->getSequence()));
938 out << ")";
939
940 return false;
941}
942
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700943bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000944{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500945 bool visitChildren = true;
946 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000947 switch (node->getOp())
948 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800949 case EOpCallFunctionInAST:
950 case EOpCallInternalRawFunction:
951 case EOpCallBuiltInFunction:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500952 // Function call.
953 if (visit == PreVisit)
Olli Etuahoec9232b2017-03-27 17:01:37 +0300954 {
955 if (node->getOp() == EOpCallBuiltInFunction)
956 {
957 out << translateTextureFunction(node->getFunctionSymbolInfo()->getName());
958 }
959 else
960 {
961 out << hashFunctionNameIfNeeded(*node->getFunctionSymbolInfo());
962 }
963 out << "(";
964 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500965 else if (visit == InVisit)
966 out << ", ";
967 else
968 out << ")";
969 break;
Olli Etuaho8fab3202017-05-08 18:22:22 +0300970 case EOpConstruct:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500971 writeConstructorTriplet(visit, node->getType());
972 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200973
Olli Etuahoe1805592017-01-02 16:41:20 +0000974 case EOpEqualComponentWise:
975 case EOpNotEqualComponentWise:
976 case EOpLessThanComponentWise:
977 case EOpGreaterThanComponentWise:
978 case EOpLessThanEqualComponentWise:
979 case EOpGreaterThanEqualComponentWise:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500980 case EOpMod:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500981 case EOpModf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500982 case EOpPow:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500983 case EOpAtan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500984 case EOpMin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500985 case EOpMax:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500986 case EOpClamp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500987 case EOpMix:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500988 case EOpStep:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500989 case EOpSmoothStep:
Olli Etuaho74da73f2017-02-01 15:37:48 +0000990 case EOpFrexp:
991 case EOpLdexp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500992 case EOpDistance:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500993 case EOpDot:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500994 case EOpCross:
Jamie Madille72595b2017-06-06 15:12:26 -0400995 case EOpFaceforward:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500996 case EOpReflect:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500997 case EOpRefract:
Olli Etuahoe1805592017-01-02 16:41:20 +0000998 case EOpMulMatrixComponentWise:
999 case EOpOuterProduct:
Olli Etuaho9250cb22017-01-21 10:51:27 +00001000 case EOpBitfieldExtract:
1001 case EOpBitfieldInsert:
1002 case EOpUaddCarry:
1003 case EOpUsubBorrow:
1004 case EOpUmulExtended:
1005 case EOpImulExtended:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001006 case EOpBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001007 case EOpMemoryBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001008 case EOpMemoryBarrierAtomicCounter:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001009 case EOpMemoryBarrierBuffer:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001010 case EOpMemoryBarrierImage:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001011 case EOpMemoryBarrierShared:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001012 case EOpGroupMemoryBarrier:
Jiawei Shaod27f5c82017-08-23 09:38:08 +08001013 case EOpEmitVertex:
1014 case EOpEndPrimitive:
Olli Etuahod68924e2017-01-02 17:34:40 +00001015 writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001016 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001017 default:
1018 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001019 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001020 return visitChildren;
1021}
1022
Olli Etuaho13389b62016-10-16 11:48:18 +01001023bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
1024{
1025 TInfoSinkBase &out = objSink();
1026
1027 // Variable declaration.
1028 if (visit == PreVisit)
1029 {
1030 const TIntermSequence &sequence = *(node->getSequence());
1031 const TIntermTyped *variable = sequence.front()->getAsTyped();
1032 writeLayoutQualifier(variable->getType());
1033 writeVariableType(variable->getType());
1034 out << " ";
1035 mDeclaringVariables = true;
1036 }
1037 else if (visit == InVisit)
1038 {
1039 out << ", ";
1040 mDeclaringVariables = true;
1041 }
1042 else
1043 {
1044 mDeclaringVariables = false;
1045 }
1046 return true;
1047}
1048
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001049bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001050{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001051 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001052
zmo@google.com5601ea02011-06-10 18:23:25 +00001053 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001054
zmo@google.com5601ea02011-06-10 18:23:25 +00001055 if (loopType == ELoopFor) // for loop
1056 {
Corentin Wallez1b896c62016-11-16 13:10:44 -05001057 out << "for (";
1058 if (node->getInit())
1059 node->getInit()->traverse(this);
1060 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001061
Corentin Wallez1b896c62016-11-16 13:10:44 -05001062 if (node->getCondition())
1063 node->getCondition()->traverse(this);
1064 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001065
Corentin Wallez1b896c62016-11-16 13:10:44 -05001066 if (node->getExpression())
1067 node->getExpression()->traverse(this);
1068 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001069
Corentin Wallez1b896c62016-11-16 13:10:44 -05001070 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001071 }
1072 else if (loopType == ELoopWhile) // while loop
1073 {
1074 out << "while (";
Yunchao He4f285442017-04-21 12:15:49 +08001075 ASSERT(node->getCondition() != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +00001076 node->getCondition()->traverse(this);
1077 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001078
1079 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001080 }
1081 else // do-while loop
1082 {
1083 ASSERT(loopType == ELoopDoWhile);
1084 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001085
zmo@google.com5601ea02011-06-10 18:23:25 +00001086 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001087
zmo@google.com5601ea02011-06-10 18:23:25 +00001088 out << "while (";
Yunchao He4f285442017-04-21 12:15:49 +08001089 ASSERT(node->getCondition() != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +00001090 node->getCondition()->traverse(this);
1091 out << ");\n";
1092 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001093
zmo@google.com5601ea02011-06-10 18:23:25 +00001094 // No need to visit children. They have been already processed in
1095 // this function.
1096 return false;
1097}
1098
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001099bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001100{
1101 switch (node->getFlowOp())
1102 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001103 case EOpKill:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001104 writeTriplet(visit, "discard", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001105 break;
1106 case EOpBreak:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001107 writeTriplet(visit, "break", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001108 break;
1109 case EOpContinue:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001110 writeTriplet(visit, "continue", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001111 break;
1112 case EOpReturn:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001113 writeTriplet(visit, "return ", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001114 break;
1115 default:
1116 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001117 }
1118
1119 return true;
1120}
1121
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001122void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001123{
zmo@google.com5601ea02011-06-10 18:23:25 +00001124 TInfoSinkBase &out = objSink();
Yunchao He4f285442017-04-21 12:15:49 +08001125 if (node != nullptr)
zmo@google.com5601ea02011-06-10 18:23:25 +00001126 {
1127 node->traverse(this);
1128 // Single statements not part of a sequence need to be terminated
1129 // with semi-colon.
1130 if (isSingleStatement(node))
1131 out << ";\n";
1132 }
1133 else
1134 {
1135 out << "{\n}\n"; // Empty code block.
1136 }
1137}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001138
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001139TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001140{
Olli Etuahoe92507b2016-07-04 11:20:10 +03001141 if (type.getBasicType() == EbtStruct)
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001142 return hashName(TName(type.getStruct()->name()));
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001143 else
Olli Etuahoe92507b2016-07-04 11:20:10 +03001144 return type.getBuiltInTypeNameString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001145}
1146
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001147TString TOutputGLSLBase::hashName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001148{
Olli Etuaho855d9642017-05-17 14:05:06 +03001149 return HashName(name, mHashFunction, &mNameMap);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001150}
1151
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001152TString TOutputGLSLBase::hashVariableName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001153{
Olli Etuaho855d9642017-05-17 14:05:06 +03001154 if (mSymbolTable->findBuiltIn(name.getString(), mShaderVersion) != nullptr ||
1155 name.getString().substr(0, 3) == "gl_")
Olli Etuaho09b04a22016-12-15 13:30:26 +00001156 {
1157 if (mCompileOptions & SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM &&
1158 name.getString() == "gl_ViewID_OVR")
1159 {
Olli Etuaho2f90a9b2017-01-10 12:27:56 +00001160 TName uniformName(TString("ViewID_OVR"));
Olli Etuaho09b04a22016-12-15 13:30:26 +00001161 uniformName.setInternal(true);
1162 return hashName(uniformName);
1163 }
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001164 return name.getString();
Olli Etuaho09b04a22016-12-15 13:30:26 +00001165 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001166 return hashName(name);
1167}
1168
Olli Etuahoec9232b2017-03-27 17:01:37 +03001169TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TFunctionSymbolInfo &info)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001170{
Olli Etuaho855d9642017-05-17 14:05:06 +03001171 if (info.isMain())
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001172 {
Olli Etuahoec9232b2017-03-27 17:01:37 +03001173 return info.getName();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001174 }
Olli Etuaho59f9a642015-08-06 20:38:26 +03001175 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001176 {
Olli Etuahoec9232b2017-03-27 17:01:37 +03001177 return hashName(info.getNameObj());
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001178 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001179}
Jamie Madill98493dd2013-07-08 14:39:03 -04001180
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001181bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001182{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001183 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001184 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001185 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001186 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001187 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001188
1189 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001190}
1191
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001192void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001193{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001194 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001195
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001196 out << "struct " << hashName(TName(structure->name())) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001197 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001198 for (size_t i = 0; i < fields.size(); ++i)
1199 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001200 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001201 if (writeVariablePrecision(field->type()->getPrecision()))
1202 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001203 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Jamie Madill98493dd2013-07-08 14:39:03 -04001204 if (field->type()->isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001205 out << ArrayString(*field->type());
Jamie Madill98493dd2013-07-08 14:39:03 -04001206 out << ";\n";
1207 }
1208 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001209}
Jamie Madill98493dd2013-07-08 14:39:03 -04001210
Geoff Langbdcc54a2015-09-02 13:09:48 -04001211void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1212{
1213 TInfoSinkBase &out = objSink();
1214
1215 out << "layout(";
1216
1217 switch (interfaceBlock->blockStorage())
1218 {
1219 case EbsUnspecified:
1220 case EbsShared:
1221 // Default block storage is shared.
1222 out << "shared";
1223 break;
1224
1225 case EbsPacked:
1226 out << "packed";
1227 break;
1228
1229 case EbsStd140:
1230 out << "std140";
1231 break;
1232
1233 default:
1234 UNREACHABLE();
1235 break;
1236 }
1237
1238 out << ", ";
1239
1240 switch (interfaceBlock->matrixPacking())
1241 {
1242 case EmpUnspecified:
1243 case EmpColumnMajor:
1244 // Default matrix packing is column major.
1245 out << "column_major";
1246 break;
1247
1248 case EmpRowMajor:
1249 out << "row_major";
1250 break;
1251
1252 default:
1253 UNREACHABLE();
1254 break;
1255 }
1256
1257 out << ") ";
1258}
1259
1260void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1261{
1262 TInfoSinkBase &out = objSink();
1263
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001264 out << hashName(TName(interfaceBlock->name())) << "{\n";
Geoff Langbdcc54a2015-09-02 13:09:48 -04001265 const TFieldList &fields = interfaceBlock->fields();
1266 for (size_t i = 0; i < fields.size(); ++i)
1267 {
1268 const TField *field = fields[i];
1269 if (writeVariablePrecision(field->type()->getPrecision()))
1270 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001271 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Geoff Langbdcc54a2015-09-02 13:09:48 -04001272 if (field->type()->isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001273 out << ArrayString(*field->type());
Geoff Langbdcc54a2015-09-02 13:09:48 -04001274 out << ";\n";
1275 }
1276 out << "}";
1277}
Jamie Madill45bcc782016-11-07 13:58:48 -05001278
Shaob5cc1192017-07-06 10:47:20 +08001279void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out,
1280 sh::TLayoutPrimitiveType inputPrimitive,
1281 int invocations,
1282 sh::TLayoutPrimitiveType outputPrimitive,
1283 int maxVertices)
1284{
1285 // Omit 'invocations = 1'
1286 if (inputPrimitive != EptUndefined || invocations > 1)
1287 {
1288 out << "layout (";
1289
1290 if (inputPrimitive != EptUndefined)
1291 {
1292 out << getGeometryShaderPrimitiveTypeString(inputPrimitive);
1293 }
1294
1295 if (invocations > 1)
1296 {
1297 if (inputPrimitive != EptUndefined)
1298 {
1299 out << ", ";
1300 }
1301 out << "invocations = " << invocations;
1302 }
1303 out << ") in;\n";
1304 }
1305
1306 if (outputPrimitive != EptUndefined || maxVertices != -1)
1307 {
1308 out << "layout (";
1309
1310 if (outputPrimitive != EptUndefined)
1311 {
1312 out << getGeometryShaderPrimitiveTypeString(outputPrimitive);
1313 }
1314
1315 if (maxVertices != -1)
1316 {
1317 if (outputPrimitive != EptUndefined)
1318 {
1319 out << ", ";
1320 }
1321 out << "max_vertices = " << maxVertices;
1322 }
1323 out << ") out;\n";
1324 }
1325}
1326
Jamie Madill45bcc782016-11-07 13:58:48 -05001327} // namespace sh