blob: 7d4a9aedaf604983eadc15009fdf92f9139aefb7 [file] [log] [blame]
zmo@google.com5601ea02011-06-10 18:23:25 +00001//
Nicolas Capens16004fc2014-06-11 11:29:11 -04002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
zmo@google.com5601ea02011-06-10 18:23:25 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Geoff Lang17732822013-08-29 13:46:49 -04007#include "compiler/translator/OutputGLSLBase.h"
Olli Etuahod57e0db2015-04-24 15:05:08 +03008
9#include "common/debug.h"
Olli Etuaho56a2f952016-12-08 12:16:27 +000010#include "common/mathutil.h"
Olli Etuahocccf2b02017-07-05 14:50:54 +030011#include "compiler/translator/Compiler.h"
zmo@google.com5601ea02011-06-10 18:23:25 +000012
daniel@transgaming.com773ff742013-01-11 04:12:51 +000013#include <cfloat>
daniel@transgaming.com6c1203f2013-01-11 04:12:43 +000014
Jamie Madill45bcc782016-11-07 13:58:48 -050015namespace sh
16{
17
zmo@google.com5601ea02011-06-10 18:23:25 +000018namespace
19{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070020TString arrayBrackets(const TType &type)
zmo@google.com5601ea02011-06-10 18:23:25 +000021{
22 ASSERT(type.isArray());
23 TInfoSinkBase out;
24 out << "[" << type.getArraySize() << "]";
25 return TString(out.c_str());
26}
27
Zhenyao Mo9eedea02014-05-12 16:02:35 -070028bool isSingleStatement(TIntermNode *node)
29{
Olli Etuaho336b1472016-10-05 16:37:55 +010030 if (node->getAsFunctionDefinition())
zmo@google.com5601ea02011-06-10 18:23:25 +000031 {
Olli Etuaho336b1472016-10-05 16:37:55 +010032 return false;
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010033 }
34 else if (node->getAsBlock())
35 {
36 return false;
zmo@google.com5601ea02011-06-10 18:23:25 +000037 }
Olli Etuaho57961272016-09-14 13:57:46 +030038 else if (node->getAsIfElseNode())
zmo@google.com5601ea02011-06-10 18:23:25 +000039 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +030040 return false;
zmo@google.com5601ea02011-06-10 18:23:25 +000041 }
42 else if (node->getAsLoopNode())
43 {
44 return false;
45 }
Olli Etuaho01cd8af2015-02-20 10:39:20 +020046 else if (node->getAsSwitchNode())
47 {
48 return false;
49 }
50 else if (node->getAsCaseNode())
51 {
52 return false;
53 }
zmo@google.com5601ea02011-06-10 18:23:25 +000054 return true;
55}
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080056
Martin Radev2cc85b32016-08-05 16:22:53 +030057// If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
58// variables with specified layout qualifiers are copied. Additional checks are needed against the
59// type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
60// TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
61// NeedsToWriteLayoutQualifier.
62bool NeedsToWriteLayoutQualifier(const TType &type)
63{
64 if (type.getBasicType() == EbtInterfaceBlock)
65 {
66 return false;
67 }
68
69 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
70
71 if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn) &&
72 layoutQualifier.location >= 0)
73 {
74 return true;
75 }
Olli Etuaho43364892017-02-13 16:00:12 +000076
Andrei Volykhina5527072017-03-22 16:46:30 +030077 if (type.getQualifier() == EvqFragmentOut && layoutQualifier.yuv == true)
78 {
79 return true;
80 }
81
Olli Etuaho43364892017-02-13 16:00:12 +000082 if (IsOpaqueType(type.getBasicType()) && layoutQualifier.binding != -1)
83 {
84 return true;
85 }
86
Martin Radev2cc85b32016-08-05 16:22:53 +030087 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
88 {
89 return true;
90 }
91 return false;
92}
93
Olli Etuaho43364892017-02-13 16:00:12 +000094class CommaSeparatedListItemPrefixGenerator
95{
96 public:
97 CommaSeparatedListItemPrefixGenerator() : mFirst(true) {}
98 private:
99 bool mFirst;
100
101 friend TInfoSinkBase &operator<<(TInfoSinkBase &out,
102 CommaSeparatedListItemPrefixGenerator &gen);
103};
104
105TInfoSinkBase &operator<<(TInfoSinkBase &out, CommaSeparatedListItemPrefixGenerator &gen)
106{
107 if (gen.mFirst)
108 {
109 gen.mFirst = false;
110 }
111 else
112 {
113 out << ", ";
114 }
115 return out;
116}
117
zmo@google.com5601ea02011-06-10 18:23:25 +0000118} // namespace
119
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700120TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000121 ShArrayIndexClampingStrategy clampingStrategy,
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000122 ShHashFunction64 hashFunction,
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700123 NameMap &nameMap,
124 TSymbolTable &symbolTable,
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000125 sh::GLenum shaderType,
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800126 int shaderVersion,
Qiankun Miao705a9192016-08-29 10:05:27 +0800127 ShShaderOutput output,
128 ShCompileOptions compileOptions)
zmo@google.com5601ea02011-06-10 18:23:25 +0000129 : TIntermTraverser(true, true, true),
130 mObjSink(objSink),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000131 mDeclaringVariables(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000132 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000133 mHashFunction(hashFunction),
134 mNameMap(nameMap),
Jamie Madill02f20dd2013-09-12 12:07:42 -0400135 mSymbolTable(symbolTable),
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000136 mShaderType(shaderType),
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800137 mShaderVersion(shaderVersion),
Qiankun Miao705a9192016-08-29 10:05:27 +0800138 mOutput(output),
139 mCompileOptions(compileOptions)
zmo@google.com5601ea02011-06-10 18:23:25 +0000140{
141}
142
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800143void TOutputGLSLBase::writeInvariantQualifier(const TType &type)
144{
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000145 if (!sh::RemoveInvariant(mShaderType, mShaderVersion, mOutput, mCompileOptions))
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800146 {
147 TInfoSinkBase &out = objSink();
148 out << "invariant ";
149 }
150}
151
Olli Etuaho56a2f952016-12-08 12:16:27 +0000152void TOutputGLSLBase::writeFloat(TInfoSinkBase &out, float f)
153{
154 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300)
155 {
156 out << "uintBitsToFloat(" << gl::bitCast<uint32_t>(f) << "u)";
157 }
158 else
159 {
160 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
161 }
162}
163
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500164void TOutputGLSLBase::writeTriplet(Visit visit,
165 const char *preStr,
166 const char *inStr,
167 const char *postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000168{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700169 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000170 if (visit == PreVisit && preStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000171 out << preStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000172 else if (visit == InVisit && inStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000173 out << inStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000174 else if (visit == PostVisit && postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000175 out << postStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000176}
177
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500178void TOutputGLSLBase::writeBuiltInFunctionTriplet(Visit visit,
Olli Etuahoe1805592017-01-02 16:41:20 +0000179 TOperator op,
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500180 bool useEmulatedFunction)
zmo@google.com5601ea02011-06-10 18:23:25 +0000181{
Olli Etuahod68924e2017-01-02 17:34:40 +0000182 TInfoSinkBase &out = objSink();
183 if (visit == PreVisit)
Olli Etuahoe1805592017-01-02 16:41:20 +0000184 {
Olli Etuahod68924e2017-01-02 17:34:40 +0000185 const char *opStr(GetOperatorString(op));
186 if (useEmulatedFunction)
187 {
188 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
189 }
190 else
191 {
192 out << opStr;
193 }
194 out << "(";
Olli Etuahoe1805592017-01-02 16:41:20 +0000195 }
Olli Etuahod68924e2017-01-02 17:34:40 +0000196 else
197 {
198 writeTriplet(visit, nullptr, ", ", ")");
199 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700200}
201
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300202void TOutputGLSLBase::writeLayoutQualifier(const TType &type)
203{
Martin Radev2cc85b32016-08-05 16:22:53 +0300204 if (!NeedsToWriteLayoutQualifier(type))
205 {
206 return;
207 }
208
209 TInfoSinkBase &out = objSink();
210 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
211 out << "layout(";
212
Olli Etuaho43364892017-02-13 16:00:12 +0000213 CommaSeparatedListItemPrefixGenerator listItemPrefix;
214
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300215 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn)
216 {
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300217 if (layoutQualifier.location >= 0)
218 {
Olli Etuaho43364892017-02-13 16:00:12 +0000219 out << listItemPrefix << "location = " << layoutQualifier.location;
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300220 }
221 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300222
Andrei Volykhina5527072017-03-22 16:46:30 +0300223 if (type.getQualifier() == EvqFragmentOut)
224 {
225 if (layoutQualifier.yuv == true)
226 {
227 out << listItemPrefix << "yuv";
228 }
229 }
230
Olli Etuaho43364892017-02-13 16:00:12 +0000231 if (IsOpaqueType(type.getBasicType()))
Martin Radev2cc85b32016-08-05 16:22:53 +0300232 {
Olli Etuaho43364892017-02-13 16:00:12 +0000233 if (layoutQualifier.binding >= 0)
234 {
235 out << listItemPrefix << "binding = " << layoutQualifier.binding;
236 }
237 }
238
239 if (IsImage(type.getBasicType()))
240 {
241 if (layoutQualifier.imageInternalFormat != EiifUnspecified)
242 {
243 ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
244 out << listItemPrefix
245 << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
246 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300247 }
248
249 out << ") ";
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300250}
251
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800252const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier)
253{
254 if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 &&
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000255 (mCompileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0)
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800256 {
257 switch (qualifier)
258 {
259 // The return string is consistent with sh::getQualifierString() from
260 // BaseTypes.h minus the "centroid" keyword.
261 case EvqCentroid:
262 return "";
263 case EvqCentroidIn:
264 return "smooth in";
265 case EvqCentroidOut:
266 return "smooth out";
267 default:
268 break;
269 }
270 }
271 if (sh::IsGLSL130OrNewer(mOutput))
272 {
273 switch (qualifier)
274 {
275 case EvqAttribute:
276 return "in";
277 case EvqVaryingIn:
278 return "in";
279 case EvqVaryingOut:
280 return "out";
281 default:
282 break;
283 }
284 }
285 return sh::getQualifierString(qualifier);
286}
287
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700288void TOutputGLSLBase::writeVariableType(const TType &type)
289{
Qiankun Miao705a9192016-08-29 10:05:27 +0800290 TQualifier qualifier = type.getQualifier();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500291 TInfoSinkBase &out = objSink();
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800292 if (type.isInvariant())
Olli Etuaho214c2d82015-04-27 14:49:13 +0300293 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800294 writeInvariantQualifier(type);
Olli Etuaho214c2d82015-04-27 14:49:13 +0300295 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400296 if (type.getBasicType() == EbtInterfaceBlock)
297 {
298 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
299 declareInterfaceBlockLayout(interfaceBlock);
300 }
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400301 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400302 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800303 const char *qualifierString = mapQualifierToString(qualifier);
304 if (qualifierString && qualifierString[0] != '\0')
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800305 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800306 out << qualifierString << " ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800307 }
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400308 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300309
310 const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
311 if (memoryQualifier.readonly)
312 {
313 ASSERT(IsImage(type.getBasicType()));
314 out << "readonly ";
315 }
316
317 if (memoryQualifier.writeonly)
318 {
319 ASSERT(IsImage(type.getBasicType()));
320 out << "writeonly ";
321 }
322
Martin Radev049edfa2016-11-11 14:35:37 +0200323 if (memoryQualifier.coherent)
324 {
325 ASSERT(IsImage(type.getBasicType()));
326 out << "coherent ";
327 }
328
329 if (memoryQualifier.restrictQualifier)
330 {
331 ASSERT(IsImage(type.getBasicType()));
332 out << "restrict ";
333 }
334
335 if (memoryQualifier.volatileQualifier)
336 {
337 ASSERT(IsImage(type.getBasicType()));
338 out << "volatile ";
339 }
340
zmo@google.com5601ea02011-06-10 18:23:25 +0000341 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700342 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000343 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400344 TStructure *structure = type.getStruct();
345
346 declareStruct(structure);
347
348 if (!structure->name().empty())
349 {
350 mDeclaredStructs.insert(structure->uniqueId());
351 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000352 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400353 else if (type.getBasicType() == EbtInterfaceBlock)
354 {
355 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
356 declareInterfaceBlock(interfaceBlock);
357 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000358 else
359 {
360 if (writeVariablePrecision(type.getPrecision()))
361 out << " ";
362 out << getTypeName(type);
363 }
364}
365
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700366void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000367{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700368 TInfoSinkBase &out = objSink();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500369 for (TIntermSequence::const_iterator iter = args.begin(); iter != args.end(); ++iter)
zmo@google.com5601ea02011-06-10 18:23:25 +0000370 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700371 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
Yunchao He4f285442017-04-21 12:15:49 +0800372 ASSERT(arg != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +0000373
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700374 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000375 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000376
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000377 if (!arg->getName().getString().empty())
378 out << " " << hashName(arg->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000379 if (type.isArray())
380 out << arrayBrackets(type);
381
382 // Put a comma if this is not the last argument.
383 if (iter != args.end() - 1)
384 out << ", ";
385 }
386}
387
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500388const TConstantUnion *TOutputGLSLBase::writeConstantUnion(const TType &type,
389 const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000390{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700391 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000392
393 if (type.getBasicType() == EbtStruct)
394 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700395 const TStructure *structure = type.getStruct();
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000396 out << hashName(TName(structure->name())) << "(";
Jamie Madill98493dd2013-07-08 14:39:03 -0400397
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700398 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400399 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000400 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700401 const TType *fieldType = fields[i]->type();
Yunchao He4f285442017-04-21 12:15:49 +0800402 ASSERT(fieldType != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +0000403 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700404 if (i != fields.size() - 1)
405 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000406 }
407 out << ")";
408 }
409 else
410 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500411 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000412 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700413 if (writeType)
414 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400415 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000416 {
417 switch (pConstUnion->getType())
418 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500419 case EbtFloat:
420 writeFloat(out, pConstUnion->getFConst());
421 break;
422 case EbtInt:
423 out << pConstUnion->getIConst();
424 break;
425 case EbtUInt:
426 out << pConstUnion->getUConst() << "u";
427 break;
428 case EbtBool:
429 out << pConstUnion->getBConst();
430 break;
Andrei Volykhina5527072017-03-22 16:46:30 +0300431 case EbtYuvCscStandardEXT:
432 out << getYuvCscStandardEXTString(pConstUnion->getYuvCscStandardEXTConst());
433 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500434 default:
435 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000436 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700437 if (i != size - 1)
438 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000439 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700440 if (writeType)
441 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000442 }
443 return pConstUnion;
444}
445
Olli Etuahoe92507b2016-07-04 11:20:10 +0300446void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
Olli Etuahof40319e2015-03-10 14:33:00 +0200447{
448 TInfoSinkBase &out = objSink();
449 if (visit == PreVisit)
450 {
451 if (type.isArray())
452 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300453 out << getTypeName(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200454 out << arrayBrackets(type);
455 out << "(";
456 }
457 else
458 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300459 out << getTypeName(type) << "(";
Olli Etuahof40319e2015-03-10 14:33:00 +0200460 }
461 }
462 else
463 {
464 writeTriplet(visit, nullptr, ", ", ")");
465 }
466}
467
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700468void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000469{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700470 TInfoSinkBase &out = objSink();
Corentin Wallez1b896c62016-11-16 13:10:44 -0500471 out << hashVariableName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000472
473 if (mDeclaringVariables && node->getType().isArray())
474 out << arrayBrackets(node->getType());
475}
476
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700477void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000478{
479 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
480}
481
Olli Etuahob6fa0432016-09-28 16:28:05 +0100482bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
483{
484 TInfoSinkBase &out = objSink();
485 if (visit == PostVisit)
486 {
487 out << ".";
488 node->writeOffsetsAsXYZW(&out);
489 }
490 return true;
491}
492
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700493bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000494{
495 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700496 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000497 switch (node->getOp())
498 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100499 case EOpComma:
500 writeTriplet(visit, "(", ", ", ")");
501 break;
502 case EOpInitialize:
zmo@google.com5601ea02011-06-10 18:23:25 +0000503 if (visit == InVisit)
504 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100505 out << " = ";
506 // RHS of initialize is not being declared.
507 mDeclaringVariables = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000508 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100509 break;
510 case EOpAssign:
511 writeTriplet(visit, "(", " = ", ")");
512 break;
513 case EOpAddAssign:
514 writeTriplet(visit, "(", " += ", ")");
515 break;
516 case EOpSubAssign:
517 writeTriplet(visit, "(", " -= ", ")");
518 break;
519 case EOpDivAssign:
520 writeTriplet(visit, "(", " /= ", ")");
521 break;
522 case EOpIModAssign:
523 writeTriplet(visit, "(", " %= ", ")");
524 break;
525 // Notice the fall-through.
526 case EOpMulAssign:
527 case EOpVectorTimesMatrixAssign:
528 case EOpVectorTimesScalarAssign:
529 case EOpMatrixTimesScalarAssign:
530 case EOpMatrixTimesMatrixAssign:
531 writeTriplet(visit, "(", " *= ", ")");
532 break;
533 case EOpBitShiftLeftAssign:
534 writeTriplet(visit, "(", " <<= ", ")");
535 break;
536 case EOpBitShiftRightAssign:
537 writeTriplet(visit, "(", " >>= ", ")");
538 break;
539 case EOpBitwiseAndAssign:
540 writeTriplet(visit, "(", " &= ", ")");
541 break;
542 case EOpBitwiseXorAssign:
543 writeTriplet(visit, "(", " ^= ", ")");
544 break;
545 case EOpBitwiseOrAssign:
546 writeTriplet(visit, "(", " |= ", ")");
547 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000548
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100549 case EOpIndexDirect:
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800550 writeTriplet(visit, nullptr, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100551 break;
552 case EOpIndexIndirect:
553 if (node->getAddIndexClamp())
554 {
555 if (visit == InVisit)
556 {
557 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
558 out << "[int(clamp(float(";
559 else
560 out << "[webgl_int_clamp(";
561 }
562 else if (visit == PostVisit)
563 {
564 int maxSize;
565 TIntermTyped *left = node->getLeft();
566 TType leftType = left->getType();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700567
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100568 if (left->isArray())
569 {
570 // The shader will fail validation if the array length is not > 0.
571 maxSize = static_cast<int>(leftType.getArraySize()) - 1;
572 }
573 else
574 {
575 maxSize = leftType.getNominalSize() - 1;
576 }
577
578 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
579 out << "), 0.0, float(" << maxSize << ")))]";
580 else
581 out << ", 0, " << maxSize << ")]";
582 }
583 }
584 else
585 {
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800586 writeTriplet(visit, nullptr, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100587 }
588 break;
589 case EOpIndexDirectStruct:
590 if (visit == InVisit)
591 {
592 // Here we are writing out "foo.bar", where "foo" is struct
593 // and "bar" is field. In AST, it is represented as a binary
594 // node, where left child represents "foo" and right child "bar".
595 // The node itself represents ".". The struct field "bar" is
596 // actually stored as an index into TStructure::fields.
597 out << ".";
598 const TStructure *structure = node->getLeft()->getType().getStruct();
599 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
600 const TField *field = structure->fields()[index->getIConst(0)];
601
602 TString fieldName = field->name();
603 if (!mSymbolTable.findBuiltIn(structure->name(), mShaderVersion))
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000604 fieldName = hashName(TName(fieldName));
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100605
606 out << fieldName;
607 visitChildren = false;
608 }
609 break;
610 case EOpIndexDirectInterfaceBlock:
611 if (visit == InVisit)
612 {
613 out << ".";
614 const TInterfaceBlock *interfaceBlock =
615 node->getLeft()->getType().getInterfaceBlock();
616 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
617 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
618
619 TString fieldName = field->name();
620 ASSERT(!mSymbolTable.findBuiltIn(interfaceBlock->name(), mShaderVersion));
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;
zmo@google.com5601ea02011-06-10 18:23:25 +0000737
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500738 case EOpRadians:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500739 case EOpDegrees:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500740 case EOpSin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500741 case EOpCos:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500742 case EOpTan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500743 case EOpAsin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500744 case EOpAcos:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500745 case EOpAtan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500746 case EOpSinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500747 case EOpCosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500748 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500749 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500750 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500751 case EOpAtanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500752 case EOpExp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500753 case EOpLog:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500754 case EOpExp2:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500755 case EOpLog2:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500756 case EOpSqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500757 case EOpInverseSqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500758 case EOpAbs:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500759 case EOpSign:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500760 case EOpFloor:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500761 case EOpTrunc:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500762 case EOpRound:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500763 case EOpRoundEven:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500764 case EOpCeil:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500765 case EOpFract:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500766 case EOpIsNan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500767 case EOpIsInf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500768 case EOpFloatBitsToInt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500769 case EOpFloatBitsToUint:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500770 case EOpIntBitsToFloat:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500771 case EOpUintBitsToFloat:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500772 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500773 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500774 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500775 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500776 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500777 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800778 case EOpPackUnorm4x8:
779 case EOpPackSnorm4x8:
780 case EOpUnpackUnorm4x8:
781 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500782 case EOpLength:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500783 case EOpNormalize:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500784 case EOpDFdx:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500785 case EOpDFdy:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500786 case EOpFwidth:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500787 case EOpTranspose:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500788 case EOpDeterminant:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500789 case EOpInverse:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500790 case EOpAny:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500791 case EOpAll:
Olli Etuahod68924e2017-01-02 17:34:40 +0000792 case EOpLogicalNotComponentWise:
Olli Etuaho9250cb22017-01-21 10:51:27 +0000793 case EOpBitfieldReverse:
794 case EOpBitCount:
795 case EOpFindLSB:
796 case EOpFindMSB:
Olli Etuahod68924e2017-01-02 17:34:40 +0000797 writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
798 return true;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500799 default:
800 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000801 }
802
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800803 writeTriplet(visit, preString.c_str(), nullptr, postString.c_str());
zmo@google.com32e97312011-08-24 01:03:11 +0000804
zmo@google.com5601ea02011-06-10 18:23:25 +0000805 return true;
806}
807
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300808bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
809{
810 TInfoSinkBase &out = objSink();
811 // Notice two brackets at the beginning and end. The outer ones
812 // encapsulate the whole ternary expression. This preserves the
813 // order of precedence when ternary expressions are used in a
814 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
815 out << "((";
816 node->getCondition()->traverse(this);
817 out << ") ? (";
818 node->getTrueExpression()->traverse(this);
819 out << ") : (";
820 node->getFalseExpression()->traverse(this);
821 out << "))";
822 return false;
823}
824
Olli Etuaho57961272016-09-14 13:57:46 +0300825bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000826{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700827 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000828
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300829 out << "if (";
830 node->getCondition()->traverse(this);
831 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000832
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300833 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000834
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300835 if (node->getFalseBlock())
836 {
837 out << "else\n";
838 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000839 }
840 return false;
841}
842
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200843bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200844{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200845 if (node->getStatementList())
846 {
847 writeTriplet(visit, "switch (", ") ", nullptr);
848 // The curly braces get written when visiting the statementList aggregate
849 }
850 else
851 {
852 // No statementList, so it won't output curly braces
853 writeTriplet(visit, "switch (", ") {", "}\n");
854 }
855 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200856}
857
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200858bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200859{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200860 if (node->hasCondition())
861 {
862 writeTriplet(visit, "case (", nullptr, "):\n");
863 return true;
864 }
865 else
866 {
867 TInfoSinkBase &out = objSink();
868 out << "default:\n";
869 return false;
870 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200871}
872
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100873bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
874{
875 TInfoSinkBase &out = objSink();
876 // Scope the blocks except when at the global scope.
877 if (mDepth > 0)
878 {
879 out << "{\n";
880 }
881
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100882 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
883 iter != node->getSequence()->end(); ++iter)
884 {
885 TIntermNode *curNode = *iter;
886 ASSERT(curNode != nullptr);
887 curNode->traverse(this);
888
889 if (isSingleStatement(curNode))
890 out << ";\n";
891 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100892
893 // Scope the blocks except when at the global scope.
894 if (mDepth > 0)
895 {
896 out << "}\n";
897 }
898 return false;
899}
900
Olli Etuaho336b1472016-10-05 16:37:55 +0100901bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
902{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000903 TIntermFunctionPrototype *prototype = node->getFunctionPrototype();
904 prototype->traverse(this);
Olli Etuaho336b1472016-10-05 16:37:55 +0100905 visitCodeBlock(node->getBody());
Olli Etuaho336b1472016-10-05 16:37:55 +0100906
907 // Fully processed; no need to visit children.
908 return false;
909}
910
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000911bool TOutputGLSLBase::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
912{
913 TInfoSinkBase &out = objSink();
914 ASSERT(visit == PreVisit);
915 const TIntermSymbol *symbol = node->getSymbol();
916 out << "invariant " << hashVariableName(symbol->getName());
917 return false;
918}
919
Olli Etuaho16c745a2017-01-16 17:02:27 +0000920bool TOutputGLSLBase::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
921{
922 TInfoSinkBase &out = objSink();
923 ASSERT(visit == PreVisit);
924
925 const TType &type = node->getType();
926 writeVariableType(type);
927 if (type.isArray())
928 out << arrayBrackets(type);
929
Olli Etuahoec9232b2017-03-27 17:01:37 +0300930 out << " " << hashFunctionNameIfNeeded(*node->getFunctionSymbolInfo());
Olli Etuaho16c745a2017-01-16 17:02:27 +0000931
932 out << "(";
933 writeFunctionParameters(*(node->getSequence()));
934 out << ")";
935
936 return false;
937}
938
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700939bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000940{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500941 bool visitChildren = true;
942 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000943 switch (node->getOp())
944 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800945 case EOpCallFunctionInAST:
946 case EOpCallInternalRawFunction:
947 case EOpCallBuiltInFunction:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500948 // Function call.
949 if (visit == PreVisit)
Olli Etuahoec9232b2017-03-27 17:01:37 +0300950 {
951 if (node->getOp() == EOpCallBuiltInFunction)
952 {
953 out << translateTextureFunction(node->getFunctionSymbolInfo()->getName());
954 }
955 else
956 {
957 out << hashFunctionNameIfNeeded(*node->getFunctionSymbolInfo());
958 }
959 out << "(";
960 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500961 else if (visit == InVisit)
962 out << ", ";
963 else
964 out << ")";
965 break;
Olli Etuaho8fab3202017-05-08 18:22:22 +0300966 case EOpConstruct:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500967 writeConstructorTriplet(visit, node->getType());
968 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200969
Olli Etuahoe1805592017-01-02 16:41:20 +0000970 case EOpEqualComponentWise:
971 case EOpNotEqualComponentWise:
972 case EOpLessThanComponentWise:
973 case EOpGreaterThanComponentWise:
974 case EOpLessThanEqualComponentWise:
975 case EOpGreaterThanEqualComponentWise:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500976 case EOpMod:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500977 case EOpModf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500978 case EOpPow:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500979 case EOpAtan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500980 case EOpMin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500981 case EOpMax:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500982 case EOpClamp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500983 case EOpMix:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500984 case EOpStep:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500985 case EOpSmoothStep:
Olli Etuaho74da73f2017-02-01 15:37:48 +0000986 case EOpFrexp:
987 case EOpLdexp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500988 case EOpDistance:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500989 case EOpDot:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500990 case EOpCross:
Jamie Madille72595b2017-06-06 15:12:26 -0400991 case EOpFaceforward:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500992 case EOpReflect:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500993 case EOpRefract:
Olli Etuahoe1805592017-01-02 16:41:20 +0000994 case EOpMulMatrixComponentWise:
995 case EOpOuterProduct:
Olli Etuaho9250cb22017-01-21 10:51:27 +0000996 case EOpBitfieldExtract:
997 case EOpBitfieldInsert:
998 case EOpUaddCarry:
999 case EOpUsubBorrow:
1000 case EOpUmulExtended:
1001 case EOpImulExtended:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001002 case EOpBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001003 case EOpMemoryBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001004 case EOpMemoryBarrierAtomicCounter:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001005 case EOpMemoryBarrierBuffer:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001006 case EOpMemoryBarrierImage:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001007 case EOpMemoryBarrierShared:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001008 case EOpGroupMemoryBarrier:
Olli Etuahod68924e2017-01-02 17:34:40 +00001009 writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001010 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001011 default:
1012 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001013 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001014 return visitChildren;
1015}
1016
Olli Etuaho13389b62016-10-16 11:48:18 +01001017bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
1018{
1019 TInfoSinkBase &out = objSink();
1020
1021 // Variable declaration.
1022 if (visit == PreVisit)
1023 {
1024 const TIntermSequence &sequence = *(node->getSequence());
1025 const TIntermTyped *variable = sequence.front()->getAsTyped();
1026 writeLayoutQualifier(variable->getType());
1027 writeVariableType(variable->getType());
1028 out << " ";
1029 mDeclaringVariables = true;
1030 }
1031 else if (visit == InVisit)
1032 {
1033 out << ", ";
1034 mDeclaringVariables = true;
1035 }
1036 else
1037 {
1038 mDeclaringVariables = false;
1039 }
1040 return true;
1041}
1042
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001043bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001044{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001045 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001046
zmo@google.com5601ea02011-06-10 18:23:25 +00001047 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001048
zmo@google.com5601ea02011-06-10 18:23:25 +00001049 if (loopType == ELoopFor) // for loop
1050 {
Corentin Wallez1b896c62016-11-16 13:10:44 -05001051 out << "for (";
1052 if (node->getInit())
1053 node->getInit()->traverse(this);
1054 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001055
Corentin Wallez1b896c62016-11-16 13:10:44 -05001056 if (node->getCondition())
1057 node->getCondition()->traverse(this);
1058 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001059
Corentin Wallez1b896c62016-11-16 13:10:44 -05001060 if (node->getExpression())
1061 node->getExpression()->traverse(this);
1062 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001063
Corentin Wallez1b896c62016-11-16 13:10:44 -05001064 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001065 }
1066 else if (loopType == ELoopWhile) // while loop
1067 {
1068 out << "while (";
Yunchao He4f285442017-04-21 12:15:49 +08001069 ASSERT(node->getCondition() != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +00001070 node->getCondition()->traverse(this);
1071 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001072
1073 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001074 }
1075 else // do-while loop
1076 {
1077 ASSERT(loopType == ELoopDoWhile);
1078 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001079
zmo@google.com5601ea02011-06-10 18:23:25 +00001080 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001081
zmo@google.com5601ea02011-06-10 18:23:25 +00001082 out << "while (";
Yunchao He4f285442017-04-21 12:15:49 +08001083 ASSERT(node->getCondition() != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +00001084 node->getCondition()->traverse(this);
1085 out << ");\n";
1086 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001087
zmo@google.com5601ea02011-06-10 18:23:25 +00001088 // No need to visit children. They have been already processed in
1089 // this function.
1090 return false;
1091}
1092
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001093bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001094{
1095 switch (node->getFlowOp())
1096 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001097 case EOpKill:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001098 writeTriplet(visit, "discard", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001099 break;
1100 case EOpBreak:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001101 writeTriplet(visit, "break", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001102 break;
1103 case EOpContinue:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001104 writeTriplet(visit, "continue", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001105 break;
1106 case EOpReturn:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001107 writeTriplet(visit, "return ", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001108 break;
1109 default:
1110 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001111 }
1112
1113 return true;
1114}
1115
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001116void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001117{
zmo@google.com5601ea02011-06-10 18:23:25 +00001118 TInfoSinkBase &out = objSink();
Yunchao He4f285442017-04-21 12:15:49 +08001119 if (node != nullptr)
zmo@google.com5601ea02011-06-10 18:23:25 +00001120 {
1121 node->traverse(this);
1122 // Single statements not part of a sequence need to be terminated
1123 // with semi-colon.
1124 if (isSingleStatement(node))
1125 out << ";\n";
1126 }
1127 else
1128 {
1129 out << "{\n}\n"; // Empty code block.
1130 }
1131}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001132
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001133TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001134{
Olli Etuahoe92507b2016-07-04 11:20:10 +03001135 if (type.getBasicType() == EbtStruct)
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001136 return hashName(TName(type.getStruct()->name()));
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001137 else
Olli Etuahoe92507b2016-07-04 11:20:10 +03001138 return type.getBuiltInTypeNameString();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001139}
1140
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001141TString TOutputGLSLBase::hashName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001142{
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001143 if (name.getString().empty())
1144 {
1145 ASSERT(!name.isInternal());
1146 return name.getString();
1147 }
1148 if (name.isInternal())
1149 {
1150 // TODO(oetuaho): Would be nicer to prefix non-internal names with "_" instead, like is
1151 // done in the HLSL output, but that requires fairly complex changes elsewhere in the code
1152 // as well.
1153 // We need to use a prefix that is reserved in WebGL in order to guarantee that the internal
1154 // names don't conflict with user-defined names from WebGL.
1155 return "webgl_angle_" + name.getString();
1156 }
1157 if (mHashFunction == nullptr)
1158 {
1159 return name.getString();
1160 }
1161 NameMap::const_iterator it = mNameMap.find(name.getString().c_str());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001162 if (it != mNameMap.end())
1163 return it->second.c_str();
Olli Etuahocccf2b02017-07-05 14:50:54 +03001164 TString hashedName = HashName(name.getString(), mHashFunction);
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001165 mNameMap[name.getString().c_str()] = hashedName.c_str();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001166 return hashedName;
1167}
1168
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001169TString TOutputGLSLBase::hashVariableName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001170{
Yunchao He4f285442017-04-21 12:15:49 +08001171 if (mSymbolTable.findBuiltIn(name.getString(), mShaderVersion) != nullptr)
Olli Etuaho09b04a22016-12-15 13:30:26 +00001172 {
1173 if (mCompileOptions & SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM &&
1174 name.getString() == "gl_ViewID_OVR")
1175 {
Olli Etuaho2f90a9b2017-01-10 12:27:56 +00001176 TName uniformName(TString("ViewID_OVR"));
Olli Etuaho09b04a22016-12-15 13:30:26 +00001177 uniformName.setInternal(true);
1178 return hashName(uniformName);
1179 }
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001180 return name.getString();
Olli Etuaho09b04a22016-12-15 13:30:26 +00001181 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001182 return hashName(name);
1183}
1184
Olli Etuahoec9232b2017-03-27 17:01:37 +03001185TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TFunctionSymbolInfo &info)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001186{
Olli Etuahoec9232b2017-03-27 17:01:37 +03001187 if (info.isMain() || info.getNameObj().isInternal())
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001188 {
1189 // Internal function names are outputted as-is - they may refer to functions manually added
1190 // to the output shader source that are not included in the AST at all.
Olli Etuahoec9232b2017-03-27 17:01:37 +03001191 return info.getName();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001192 }
Olli Etuaho59f9a642015-08-06 20:38:26 +03001193 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001194 {
Olli Etuahoec9232b2017-03-27 17:01:37 +03001195 return hashName(info.getNameObj());
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001196 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001197}
Jamie Madill98493dd2013-07-08 14:39:03 -04001198
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001199bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001200{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001201 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001202 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001203 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001204 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001205 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001206
1207 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001208}
1209
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001210void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001211{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001212 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001213
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001214 out << "struct " << hashName(TName(structure->name())) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001215 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001216 for (size_t i = 0; i < fields.size(); ++i)
1217 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001218 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001219 if (writeVariablePrecision(field->type()->getPrecision()))
1220 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001221 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Jamie Madill98493dd2013-07-08 14:39:03 -04001222 if (field->type()->isArray())
1223 out << arrayBrackets(*field->type());
1224 out << ";\n";
1225 }
1226 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001227}
Jamie Madill98493dd2013-07-08 14:39:03 -04001228
Geoff Langbdcc54a2015-09-02 13:09:48 -04001229void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1230{
1231 TInfoSinkBase &out = objSink();
1232
1233 out << "layout(";
1234
1235 switch (interfaceBlock->blockStorage())
1236 {
1237 case EbsUnspecified:
1238 case EbsShared:
1239 // Default block storage is shared.
1240 out << "shared";
1241 break;
1242
1243 case EbsPacked:
1244 out << "packed";
1245 break;
1246
1247 case EbsStd140:
1248 out << "std140";
1249 break;
1250
1251 default:
1252 UNREACHABLE();
1253 break;
1254 }
1255
1256 out << ", ";
1257
1258 switch (interfaceBlock->matrixPacking())
1259 {
1260 case EmpUnspecified:
1261 case EmpColumnMajor:
1262 // Default matrix packing is column major.
1263 out << "column_major";
1264 break;
1265
1266 case EmpRowMajor:
1267 out << "row_major";
1268 break;
1269
1270 default:
1271 UNREACHABLE();
1272 break;
1273 }
1274
1275 out << ") ";
1276}
1277
1278void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1279{
1280 TInfoSinkBase &out = objSink();
1281
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001282 out << hashName(TName(interfaceBlock->name())) << "{\n";
Geoff Langbdcc54a2015-09-02 13:09:48 -04001283 const TFieldList &fields = interfaceBlock->fields();
1284 for (size_t i = 0; i < fields.size(); ++i)
1285 {
1286 const TField *field = fields[i];
1287 if (writeVariablePrecision(field->type()->getPrecision()))
1288 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001289 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Geoff Langbdcc54a2015-09-02 13:09:48 -04001290 if (field->type()->isArray())
1291 out << arrayBrackets(*field->type());
1292 out << ";\n";
1293 }
1294 out << "}";
1295}
Jamie Madill45bcc782016-11-07 13:58:48 -05001296
1297} // namespace sh