blob: 29da221e9df7ed4c9489012acac1e3772fdd46c8 [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"
zmo@google.com5601ea02011-06-10 18:23:25 +000013
daniel@transgaming.com773ff742013-01-11 04:12:51 +000014#include <cfloat>
daniel@transgaming.com6c1203f2013-01-11 04:12:43 +000015
Jamie Madill45bcc782016-11-07 13:58:48 -050016namespace sh
17{
18
zmo@google.com5601ea02011-06-10 18:23:25 +000019namespace
20{
Zhenyao Mo9eedea02014-05-12 16:02:35 -070021TString arrayBrackets(const TType &type)
zmo@google.com5601ea02011-06-10 18:23:25 +000022{
23 ASSERT(type.isArray());
24 TInfoSinkBase out;
25 out << "[" << type.getArraySize() << "]";
26 return TString(out.c_str());
27}
28
Zhenyao Mo9eedea02014-05-12 16:02:35 -070029bool isSingleStatement(TIntermNode *node)
30{
Olli Etuaho336b1472016-10-05 16:37:55 +010031 if (node->getAsFunctionDefinition())
zmo@google.com5601ea02011-06-10 18:23:25 +000032 {
Olli Etuaho336b1472016-10-05 16:37:55 +010033 return false;
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010034 }
35 else if (node->getAsBlock())
36 {
37 return false;
zmo@google.com5601ea02011-06-10 18:23:25 +000038 }
Olli Etuaho57961272016-09-14 13:57:46 +030039 else if (node->getAsIfElseNode())
zmo@google.com5601ea02011-06-10 18:23:25 +000040 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +030041 return false;
zmo@google.com5601ea02011-06-10 18:23:25 +000042 }
43 else if (node->getAsLoopNode())
44 {
45 return false;
46 }
Olli Etuaho01cd8af2015-02-20 10:39:20 +020047 else if (node->getAsSwitchNode())
48 {
49 return false;
50 }
51 else if (node->getAsCaseNode())
52 {
53 return false;
54 }
zmo@google.com5601ea02011-06-10 18:23:25 +000055 return true;
56}
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080057
Martin Radev2cc85b32016-08-05 16:22:53 +030058// If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
59// variables with specified layout qualifiers are copied. Additional checks are needed against the
60// type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
61// TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
62// NeedsToWriteLayoutQualifier.
63bool NeedsToWriteLayoutQualifier(const TType &type)
64{
65 if (type.getBasicType() == EbtInterfaceBlock)
66 {
67 return false;
68 }
69
70 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
71
72 if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn) &&
73 layoutQualifier.location >= 0)
74 {
75 return true;
76 }
Olli Etuaho43364892017-02-13 16:00:12 +000077
Andrei Volykhina5527072017-03-22 16:46:30 +030078 if (type.getQualifier() == EvqFragmentOut && layoutQualifier.yuv == true)
79 {
80 return true;
81 }
82
Olli Etuaho43364892017-02-13 16:00:12 +000083 if (IsOpaqueType(type.getBasicType()) && layoutQualifier.binding != -1)
84 {
85 return true;
86 }
87
Martin Radev2cc85b32016-08-05 16:22:53 +030088 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
89 {
90 return true;
91 }
92 return false;
93}
94
Olli Etuaho43364892017-02-13 16:00:12 +000095class CommaSeparatedListItemPrefixGenerator
96{
97 public:
98 CommaSeparatedListItemPrefixGenerator() : mFirst(true) {}
99 private:
100 bool mFirst;
101
102 friend TInfoSinkBase &operator<<(TInfoSinkBase &out,
103 CommaSeparatedListItemPrefixGenerator &gen);
104};
105
106TInfoSinkBase &operator<<(TInfoSinkBase &out, CommaSeparatedListItemPrefixGenerator &gen)
107{
108 if (gen.mFirst)
109 {
110 gen.mFirst = false;
111 }
112 else
113 {
114 out << ", ";
115 }
116 return out;
117}
118
zmo@google.com5601ea02011-06-10 18:23:25 +0000119} // namespace
120
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700121TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000122 ShArrayIndexClampingStrategy clampingStrategy,
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000123 ShHashFunction64 hashFunction,
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700124 NameMap &nameMap,
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300125 TSymbolTable *symbolTable,
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000126 sh::GLenum shaderType,
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800127 int shaderVersion,
Qiankun Miao705a9192016-08-29 10:05:27 +0800128 ShShaderOutput output,
129 ShCompileOptions compileOptions)
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300130 : TIntermTraverser(true, true, true, symbolTable),
zmo@google.com5601ea02011-06-10 18:23:25 +0000131 mObjSink(objSink),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000132 mDeclaringVariables(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +0000133 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000134 mHashFunction(hashFunction),
135 mNameMap(nameMap),
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
jchen1005c31da2017-07-18 16:11:39 +0800249 if (IsAtomicCounter(type.getBasicType()))
250 {
251 out << listItemPrefix << "offset = " << layoutQualifier.offset;
252 }
253
Martin Radev2cc85b32016-08-05 16:22:53 +0300254 out << ") ";
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300255}
256
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800257const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier)
258{
259 if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 &&
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000260 (mCompileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0)
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800261 {
262 switch (qualifier)
263 {
264 // The return string is consistent with sh::getQualifierString() from
265 // BaseTypes.h minus the "centroid" keyword.
266 case EvqCentroid:
267 return "";
268 case EvqCentroidIn:
269 return "smooth in";
270 case EvqCentroidOut:
271 return "smooth out";
272 default:
273 break;
274 }
275 }
276 if (sh::IsGLSL130OrNewer(mOutput))
277 {
278 switch (qualifier)
279 {
280 case EvqAttribute:
281 return "in";
282 case EvqVaryingIn:
283 return "in";
284 case EvqVaryingOut:
285 return "out";
286 default:
287 break;
288 }
289 }
290 return sh::getQualifierString(qualifier);
291}
292
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700293void TOutputGLSLBase::writeVariableType(const TType &type)
294{
Qiankun Miao705a9192016-08-29 10:05:27 +0800295 TQualifier qualifier = type.getQualifier();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500296 TInfoSinkBase &out = objSink();
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800297 if (type.isInvariant())
Olli Etuaho214c2d82015-04-27 14:49:13 +0300298 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800299 writeInvariantQualifier(type);
Olli Etuaho214c2d82015-04-27 14:49:13 +0300300 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400301 if (type.getBasicType() == EbtInterfaceBlock)
302 {
303 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
304 declareInterfaceBlockLayout(interfaceBlock);
305 }
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400306 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400307 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800308 const char *qualifierString = mapQualifierToString(qualifier);
309 if (qualifierString && qualifierString[0] != '\0')
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800310 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800311 out << qualifierString << " ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800312 }
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400313 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300314
315 const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
316 if (memoryQualifier.readonly)
317 {
318 ASSERT(IsImage(type.getBasicType()));
319 out << "readonly ";
320 }
321
322 if (memoryQualifier.writeonly)
323 {
324 ASSERT(IsImage(type.getBasicType()));
325 out << "writeonly ";
326 }
327
Martin Radev049edfa2016-11-11 14:35:37 +0200328 if (memoryQualifier.coherent)
329 {
330 ASSERT(IsImage(type.getBasicType()));
331 out << "coherent ";
332 }
333
334 if (memoryQualifier.restrictQualifier)
335 {
336 ASSERT(IsImage(type.getBasicType()));
337 out << "restrict ";
338 }
339
340 if (memoryQualifier.volatileQualifier)
341 {
342 ASSERT(IsImage(type.getBasicType()));
343 out << "volatile ";
344 }
345
zmo@google.com5601ea02011-06-10 18:23:25 +0000346 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700347 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000348 {
Jamie Madill01f85ac2014-06-06 11:55:04 -0400349 TStructure *structure = type.getStruct();
350
351 declareStruct(structure);
352
353 if (!structure->name().empty())
354 {
355 mDeclaredStructs.insert(structure->uniqueId());
356 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000357 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400358 else if (type.getBasicType() == EbtInterfaceBlock)
359 {
360 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
361 declareInterfaceBlock(interfaceBlock);
362 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000363 else
364 {
365 if (writeVariablePrecision(type.getPrecision()))
366 out << " ";
367 out << getTypeName(type);
368 }
369}
370
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700371void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000372{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700373 TInfoSinkBase &out = objSink();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500374 for (TIntermSequence::const_iterator iter = args.begin(); iter != args.end(); ++iter)
zmo@google.com5601ea02011-06-10 18:23:25 +0000375 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700376 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
Yunchao He4f285442017-04-21 12:15:49 +0800377 ASSERT(arg != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +0000378
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700379 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000380 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000381
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000382 if (!arg->getName().getString().empty())
383 out << " " << hashName(arg->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000384 if (type.isArray())
385 out << arrayBrackets(type);
386
387 // Put a comma if this is not the last argument.
388 if (iter != args.end() - 1)
389 out << ", ";
390 }
391}
392
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500393const TConstantUnion *TOutputGLSLBase::writeConstantUnion(const TType &type,
394 const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000395{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700396 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000397
398 if (type.getBasicType() == EbtStruct)
399 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700400 const TStructure *structure = type.getStruct();
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000401 out << hashName(TName(structure->name())) << "(";
Jamie Madill98493dd2013-07-08 14:39:03 -0400402
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700403 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400404 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000405 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700406 const TType *fieldType = fields[i]->type();
Yunchao He4f285442017-04-21 12:15:49 +0800407 ASSERT(fieldType != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +0000408 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700409 if (i != fields.size() - 1)
410 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000411 }
412 out << ")";
413 }
414 else
415 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500416 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000417 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700418 if (writeType)
419 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400420 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000421 {
422 switch (pConstUnion->getType())
423 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500424 case EbtFloat:
425 writeFloat(out, pConstUnion->getFConst());
426 break;
427 case EbtInt:
428 out << pConstUnion->getIConst();
429 break;
430 case EbtUInt:
431 out << pConstUnion->getUConst() << "u";
432 break;
433 case EbtBool:
434 out << pConstUnion->getBConst();
435 break;
Andrei Volykhina5527072017-03-22 16:46:30 +0300436 case EbtYuvCscStandardEXT:
437 out << getYuvCscStandardEXTString(pConstUnion->getYuvCscStandardEXTConst());
438 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500439 default:
440 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000441 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700442 if (i != size - 1)
443 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000444 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700445 if (writeType)
446 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000447 }
448 return pConstUnion;
449}
450
Olli Etuahoe92507b2016-07-04 11:20:10 +0300451void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
Olli Etuahof40319e2015-03-10 14:33:00 +0200452{
453 TInfoSinkBase &out = objSink();
454 if (visit == PreVisit)
455 {
456 if (type.isArray())
457 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300458 out << getTypeName(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200459 out << arrayBrackets(type);
460 out << "(";
461 }
462 else
463 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300464 out << getTypeName(type) << "(";
Olli Etuahof40319e2015-03-10 14:33:00 +0200465 }
466 }
467 else
468 {
469 writeTriplet(visit, nullptr, ", ", ")");
470 }
471}
472
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700473void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000474{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700475 TInfoSinkBase &out = objSink();
Corentin Wallez1b896c62016-11-16 13:10:44 -0500476 out << hashVariableName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000477
478 if (mDeclaringVariables && node->getType().isArray())
479 out << arrayBrackets(node->getType());
480}
481
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700482void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000483{
484 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
485}
486
Olli Etuahob6fa0432016-09-28 16:28:05 +0100487bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
488{
489 TInfoSinkBase &out = objSink();
490 if (visit == PostVisit)
491 {
492 out << ".";
493 node->writeOffsetsAsXYZW(&out);
494 }
495 return true;
496}
497
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700498bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000499{
500 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700501 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000502 switch (node->getOp())
503 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100504 case EOpComma:
505 writeTriplet(visit, "(", ", ", ")");
506 break;
507 case EOpInitialize:
zmo@google.com5601ea02011-06-10 18:23:25 +0000508 if (visit == InVisit)
509 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100510 out << " = ";
511 // RHS of initialize is not being declared.
512 mDeclaringVariables = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000513 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100514 break;
515 case EOpAssign:
516 writeTriplet(visit, "(", " = ", ")");
517 break;
518 case EOpAddAssign:
519 writeTriplet(visit, "(", " += ", ")");
520 break;
521 case EOpSubAssign:
522 writeTriplet(visit, "(", " -= ", ")");
523 break;
524 case EOpDivAssign:
525 writeTriplet(visit, "(", " /= ", ")");
526 break;
527 case EOpIModAssign:
528 writeTriplet(visit, "(", " %= ", ")");
529 break;
530 // Notice the fall-through.
531 case EOpMulAssign:
532 case EOpVectorTimesMatrixAssign:
533 case EOpVectorTimesScalarAssign:
534 case EOpMatrixTimesScalarAssign:
535 case EOpMatrixTimesMatrixAssign:
536 writeTriplet(visit, "(", " *= ", ")");
537 break;
538 case EOpBitShiftLeftAssign:
539 writeTriplet(visit, "(", " <<= ", ")");
540 break;
541 case EOpBitShiftRightAssign:
542 writeTriplet(visit, "(", " >>= ", ")");
543 break;
544 case EOpBitwiseAndAssign:
545 writeTriplet(visit, "(", " &= ", ")");
546 break;
547 case EOpBitwiseXorAssign:
548 writeTriplet(visit, "(", " ^= ", ")");
549 break;
550 case EOpBitwiseOrAssign:
551 writeTriplet(visit, "(", " |= ", ")");
552 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000553
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100554 case EOpIndexDirect:
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800555 writeTriplet(visit, nullptr, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100556 break;
557 case EOpIndexIndirect:
558 if (node->getAddIndexClamp())
559 {
560 if (visit == InVisit)
561 {
562 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
563 out << "[int(clamp(float(";
564 else
565 out << "[webgl_int_clamp(";
566 }
567 else if (visit == PostVisit)
568 {
569 int maxSize;
570 TIntermTyped *left = node->getLeft();
571 TType leftType = left->getType();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700572
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100573 if (left->isArray())
574 {
575 // The shader will fail validation if the array length is not > 0.
576 maxSize = static_cast<int>(leftType.getArraySize()) - 1;
577 }
578 else
579 {
580 maxSize = leftType.getNominalSize() - 1;
581 }
582
583 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
584 out << "), 0.0, float(" << maxSize << ")))]";
585 else
586 out << ", 0, " << maxSize << ")]";
587 }
588 }
589 else
590 {
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800591 writeTriplet(visit, nullptr, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100592 }
593 break;
594 case EOpIndexDirectStruct:
595 if (visit == InVisit)
596 {
597 // Here we are writing out "foo.bar", where "foo" is struct
598 // and "bar" is field. In AST, it is represented as a binary
599 // node, where left child represents "foo" and right child "bar".
600 // The node itself represents ".". The struct field "bar" is
601 // actually stored as an index into TStructure::fields.
602 out << ".";
603 const TStructure *structure = node->getLeft()->getType().getStruct();
604 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
605 const TField *field = structure->fields()[index->getIConst(0)];
606
607 TString fieldName = field->name();
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300608 if (!mSymbolTable->findBuiltIn(structure->name(), mShaderVersion))
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000609 fieldName = hashName(TName(fieldName));
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100610
611 out << fieldName;
612 visitChildren = false;
613 }
614 break;
615 case EOpIndexDirectInterfaceBlock:
616 if (visit == InVisit)
617 {
618 out << ".";
619 const TInterfaceBlock *interfaceBlock =
620 node->getLeft()->getType().getInterfaceBlock();
621 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
622 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
623
624 TString fieldName = field->name();
Jiawei Shaod8105a02017-08-08 09:54:36 +0800625 ASSERT(!mSymbolTable->findBuiltIn(interfaceBlock->name(), mShaderVersion) ||
626 interfaceBlock->name() == "gl_PerVertex");
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000627 fieldName = hashName(TName(fieldName));
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700628
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100629 out << fieldName;
630 visitChildren = false;
631 }
632 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400633
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100634 case EOpAdd:
635 writeTriplet(visit, "(", " + ", ")");
636 break;
637 case EOpSub:
638 writeTriplet(visit, "(", " - ", ")");
639 break;
640 case EOpMul:
641 writeTriplet(visit, "(", " * ", ")");
642 break;
643 case EOpDiv:
644 writeTriplet(visit, "(", " / ", ")");
645 break;
646 case EOpIMod:
647 writeTriplet(visit, "(", " % ", ")");
648 break;
649 case EOpBitShiftLeft:
650 writeTriplet(visit, "(", " << ", ")");
651 break;
652 case EOpBitShiftRight:
653 writeTriplet(visit, "(", " >> ", ")");
654 break;
655 case EOpBitwiseAnd:
656 writeTriplet(visit, "(", " & ", ")");
657 break;
658 case EOpBitwiseXor:
659 writeTriplet(visit, "(", " ^ ", ")");
660 break;
661 case EOpBitwiseOr:
662 writeTriplet(visit, "(", " | ", ")");
663 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400664
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100665 case EOpEqual:
666 writeTriplet(visit, "(", " == ", ")");
667 break;
668 case EOpNotEqual:
669 writeTriplet(visit, "(", " != ", ")");
670 break;
671 case EOpLessThan:
672 writeTriplet(visit, "(", " < ", ")");
673 break;
674 case EOpGreaterThan:
675 writeTriplet(visit, "(", " > ", ")");
676 break;
677 case EOpLessThanEqual:
678 writeTriplet(visit, "(", " <= ", ")");
679 break;
680 case EOpGreaterThanEqual:
681 writeTriplet(visit, "(", " >= ", ")");
682 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000683
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100684 // Notice the fall-through.
685 case EOpVectorTimesScalar:
686 case EOpVectorTimesMatrix:
687 case EOpMatrixTimesVector:
688 case EOpMatrixTimesScalar:
689 case EOpMatrixTimesMatrix:
690 writeTriplet(visit, "(", " * ", ")");
691 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200692
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100693 case EOpLogicalOr:
694 writeTriplet(visit, "(", " || ", ")");
695 break;
696 case EOpLogicalXor:
697 writeTriplet(visit, "(", " ^^ ", ")");
698 break;
699 case EOpLogicalAnd:
700 writeTriplet(visit, "(", " && ", ")");
701 break;
702 default:
703 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000704 }
705
706 return visitChildren;
707}
708
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700709bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000710{
zmo@google.com32e97312011-08-24 01:03:11 +0000711 TString preString;
712 TString postString = ")";
713
zmo@google.com5601ea02011-06-10 18:23:25 +0000714 switch (node->getOp())
715 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500716 case EOpNegative:
717 preString = "(-";
718 break;
719 case EOpPositive:
720 preString = "(+";
721 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500722 case EOpLogicalNot:
723 preString = "(!";
724 break;
725 case EOpBitwiseNot:
726 preString = "(~";
727 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000728
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500729 case EOpPostIncrement:
730 preString = "(";
731 postString = "++)";
732 break;
733 case EOpPostDecrement:
734 preString = "(";
735 postString = "--)";
736 break;
737 case EOpPreIncrement:
738 preString = "(++";
739 break;
740 case EOpPreDecrement:
741 preString = "(--";
742 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000743
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500744 case EOpRadians:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500745 case EOpDegrees:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500746 case EOpSin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500747 case EOpCos:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500748 case EOpTan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500749 case EOpAsin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500750 case EOpAcos:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500751 case EOpAtan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500752 case EOpSinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500753 case EOpCosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500754 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500755 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500756 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500757 case EOpAtanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500758 case EOpExp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500759 case EOpLog:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500760 case EOpExp2:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500761 case EOpLog2:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500762 case EOpSqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500763 case EOpInverseSqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500764 case EOpAbs:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500765 case EOpSign:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500766 case EOpFloor:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500767 case EOpTrunc:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500768 case EOpRound:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500769 case EOpRoundEven:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500770 case EOpCeil:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500771 case EOpFract:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500772 case EOpIsNan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500773 case EOpIsInf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500774 case EOpFloatBitsToInt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500775 case EOpFloatBitsToUint:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500776 case EOpIntBitsToFloat:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500777 case EOpUintBitsToFloat:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500778 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500779 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500780 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500781 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500782 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500783 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800784 case EOpPackUnorm4x8:
785 case EOpPackSnorm4x8:
786 case EOpUnpackUnorm4x8:
787 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500788 case EOpLength:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500789 case EOpNormalize:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500790 case EOpDFdx:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500791 case EOpDFdy:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500792 case EOpFwidth:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500793 case EOpTranspose:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500794 case EOpDeterminant:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500795 case EOpInverse:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500796 case EOpAny:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500797 case EOpAll:
Olli Etuahod68924e2017-01-02 17:34:40 +0000798 case EOpLogicalNotComponentWise:
Olli Etuaho9250cb22017-01-21 10:51:27 +0000799 case EOpBitfieldReverse:
800 case EOpBitCount:
801 case EOpFindLSB:
802 case EOpFindMSB:
Olli Etuahod68924e2017-01-02 17:34:40 +0000803 writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
804 return true;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500805 default:
806 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000807 }
808
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800809 writeTriplet(visit, preString.c_str(), nullptr, postString.c_str());
zmo@google.com32e97312011-08-24 01:03:11 +0000810
zmo@google.com5601ea02011-06-10 18:23:25 +0000811 return true;
812}
813
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300814bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
815{
816 TInfoSinkBase &out = objSink();
817 // Notice two brackets at the beginning and end. The outer ones
818 // encapsulate the whole ternary expression. This preserves the
819 // order of precedence when ternary expressions are used in a
820 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
821 out << "((";
822 node->getCondition()->traverse(this);
823 out << ") ? (";
824 node->getTrueExpression()->traverse(this);
825 out << ") : (";
826 node->getFalseExpression()->traverse(this);
827 out << "))";
828 return false;
829}
830
Olli Etuaho57961272016-09-14 13:57:46 +0300831bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000832{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700833 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000834
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300835 out << "if (";
836 node->getCondition()->traverse(this);
837 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000838
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300839 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000840
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300841 if (node->getFalseBlock())
842 {
843 out << "else\n";
844 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000845 }
846 return false;
847}
848
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200849bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200850{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200851 if (node->getStatementList())
852 {
853 writeTriplet(visit, "switch (", ") ", nullptr);
854 // The curly braces get written when visiting the statementList aggregate
855 }
856 else
857 {
858 // No statementList, so it won't output curly braces
859 writeTriplet(visit, "switch (", ") {", "}\n");
860 }
861 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200862}
863
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200864bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200865{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200866 if (node->hasCondition())
867 {
868 writeTriplet(visit, "case (", nullptr, "):\n");
869 return true;
870 }
871 else
872 {
873 TInfoSinkBase &out = objSink();
874 out << "default:\n";
875 return false;
876 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200877}
878
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100879bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
880{
881 TInfoSinkBase &out = objSink();
882 // Scope the blocks except when at the global scope.
883 if (mDepth > 0)
884 {
885 out << "{\n";
886 }
887
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100888 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
889 iter != node->getSequence()->end(); ++iter)
890 {
891 TIntermNode *curNode = *iter;
892 ASSERT(curNode != nullptr);
893 curNode->traverse(this);
894
895 if (isSingleStatement(curNode))
896 out << ";\n";
897 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100898
899 // Scope the blocks except when at the global scope.
900 if (mDepth > 0)
901 {
902 out << "}\n";
903 }
904 return false;
905}
906
Olli Etuaho336b1472016-10-05 16:37:55 +0100907bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
908{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000909 TIntermFunctionPrototype *prototype = node->getFunctionPrototype();
910 prototype->traverse(this);
Olli Etuaho336b1472016-10-05 16:37:55 +0100911 visitCodeBlock(node->getBody());
Olli Etuaho336b1472016-10-05 16:37:55 +0100912
913 // Fully processed; no need to visit children.
914 return false;
915}
916
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000917bool TOutputGLSLBase::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
918{
919 TInfoSinkBase &out = objSink();
920 ASSERT(visit == PreVisit);
921 const TIntermSymbol *symbol = node->getSymbol();
922 out << "invariant " << hashVariableName(symbol->getName());
923 return false;
924}
925
Olli Etuaho16c745a2017-01-16 17:02:27 +0000926bool TOutputGLSLBase::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
927{
928 TInfoSinkBase &out = objSink();
929 ASSERT(visit == PreVisit);
930
931 const TType &type = node->getType();
932 writeVariableType(type);
933 if (type.isArray())
934 out << arrayBrackets(type);
935
Olli Etuahoec9232b2017-03-27 17:01:37 +0300936 out << " " << hashFunctionNameIfNeeded(*node->getFunctionSymbolInfo());
Olli Etuaho16c745a2017-01-16 17:02:27 +0000937
938 out << "(";
939 writeFunctionParameters(*(node->getSequence()));
940 out << ")";
941
942 return false;
943}
944
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700945bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000946{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500947 bool visitChildren = true;
948 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000949 switch (node->getOp())
950 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800951 case EOpCallFunctionInAST:
952 case EOpCallInternalRawFunction:
953 case EOpCallBuiltInFunction:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500954 // Function call.
955 if (visit == PreVisit)
Olli Etuahoec9232b2017-03-27 17:01:37 +0300956 {
957 if (node->getOp() == EOpCallBuiltInFunction)
958 {
959 out << translateTextureFunction(node->getFunctionSymbolInfo()->getName());
960 }
961 else
962 {
963 out << hashFunctionNameIfNeeded(*node->getFunctionSymbolInfo());
964 }
965 out << "(";
966 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500967 else if (visit == InVisit)
968 out << ", ";
969 else
970 out << ")";
971 break;
Olli Etuaho8fab3202017-05-08 18:22:22 +0300972 case EOpConstruct:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500973 writeConstructorTriplet(visit, node->getType());
974 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200975
Olli Etuahoe1805592017-01-02 16:41:20 +0000976 case EOpEqualComponentWise:
977 case EOpNotEqualComponentWise:
978 case EOpLessThanComponentWise:
979 case EOpGreaterThanComponentWise:
980 case EOpLessThanEqualComponentWise:
981 case EOpGreaterThanEqualComponentWise:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500982 case EOpMod:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500983 case EOpModf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500984 case EOpPow:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500985 case EOpAtan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500986 case EOpMin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500987 case EOpMax:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500988 case EOpClamp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500989 case EOpMix:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500990 case EOpStep:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500991 case EOpSmoothStep:
Olli Etuaho74da73f2017-02-01 15:37:48 +0000992 case EOpFrexp:
993 case EOpLdexp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500994 case EOpDistance:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500995 case EOpDot:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500996 case EOpCross:
Jamie Madille72595b2017-06-06 15:12:26 -0400997 case EOpFaceforward:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500998 case EOpReflect:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500999 case EOpRefract:
Olli Etuahoe1805592017-01-02 16:41:20 +00001000 case EOpMulMatrixComponentWise:
1001 case EOpOuterProduct:
Olli Etuaho9250cb22017-01-21 10:51:27 +00001002 case EOpBitfieldExtract:
1003 case EOpBitfieldInsert:
1004 case EOpUaddCarry:
1005 case EOpUsubBorrow:
1006 case EOpUmulExtended:
1007 case EOpImulExtended:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001008 case EOpBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001009 case EOpMemoryBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001010 case EOpMemoryBarrierAtomicCounter:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001011 case EOpMemoryBarrierBuffer:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001012 case EOpMemoryBarrierImage:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001013 case EOpMemoryBarrierShared:
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001014 case EOpGroupMemoryBarrier:
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 Etuaho0982a2b2016-11-01 15:13:46 +00001149 if (name.getString().empty())
1150 {
1151 ASSERT(!name.isInternal());
1152 return name.getString();
1153 }
1154 if (name.isInternal())
1155 {
1156 // TODO(oetuaho): Would be nicer to prefix non-internal names with "_" instead, like is
1157 // done in the HLSL output, but that requires fairly complex changes elsewhere in the code
1158 // as well.
1159 // We need to use a prefix that is reserved in WebGL in order to guarantee that the internal
1160 // names don't conflict with user-defined names from WebGL.
1161 return "webgl_angle_" + name.getString();
1162 }
1163 if (mHashFunction == nullptr)
1164 {
1165 return name.getString();
1166 }
1167 NameMap::const_iterator it = mNameMap.find(name.getString().c_str());
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001168 if (it != mNameMap.end())
1169 return it->second.c_str();
Olli Etuahocccf2b02017-07-05 14:50:54 +03001170 TString hashedName = HashName(name.getString(), mHashFunction);
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001171 mNameMap[name.getString().c_str()] = hashedName.c_str();
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001172 return hashedName;
1173}
1174
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001175TString TOutputGLSLBase::hashVariableName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001176{
Olli Etuahoa5e693a2017-07-13 16:07:26 +03001177 if (mSymbolTable->findBuiltIn(name.getString(), mShaderVersion) != nullptr)
Olli Etuaho09b04a22016-12-15 13:30:26 +00001178 {
1179 if (mCompileOptions & SH_TRANSLATE_VIEWID_OVR_TO_UNIFORM &&
1180 name.getString() == "gl_ViewID_OVR")
1181 {
Olli Etuaho2f90a9b2017-01-10 12:27:56 +00001182 TName uniformName(TString("ViewID_OVR"));
Olli Etuaho09b04a22016-12-15 13:30:26 +00001183 uniformName.setInternal(true);
1184 return hashName(uniformName);
1185 }
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001186 return name.getString();
Olli Etuaho09b04a22016-12-15 13:30:26 +00001187 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001188 return hashName(name);
1189}
1190
Olli Etuahoec9232b2017-03-27 17:01:37 +03001191TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TFunctionSymbolInfo &info)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001192{
Olli Etuahoec9232b2017-03-27 17:01:37 +03001193 if (info.isMain() || info.getNameObj().isInternal())
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001194 {
1195 // Internal function names are outputted as-is - they may refer to functions manually added
1196 // to the output shader source that are not included in the AST at all.
Olli Etuahoec9232b2017-03-27 17:01:37 +03001197 return info.getName();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001198 }
Olli Etuaho59f9a642015-08-06 20:38:26 +03001199 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001200 {
Olli Etuahoec9232b2017-03-27 17:01:37 +03001201 return hashName(info.getNameObj());
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001202 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001203}
Jamie Madill98493dd2013-07-08 14:39:03 -04001204
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001205bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001206{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001207 ASSERT(structure);
Jamie Madill01f85ac2014-06-06 11:55:04 -04001208 if (structure->name().empty())
Zhenyao Mo904a9162014-05-09 14:07:45 -07001209 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001210 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001211 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001212
1213 return (mDeclaredStructs.count(structure->uniqueId()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001214}
1215
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001216void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001217{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001218 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001219
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001220 out << "struct " << hashName(TName(structure->name())) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001221 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001222 for (size_t i = 0; i < fields.size(); ++i)
1223 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001224 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001225 if (writeVariablePrecision(field->type()->getPrecision()))
1226 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001227 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Jamie Madill98493dd2013-07-08 14:39:03 -04001228 if (field->type()->isArray())
1229 out << arrayBrackets(*field->type());
1230 out << ";\n";
1231 }
1232 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001233}
Jamie Madill98493dd2013-07-08 14:39:03 -04001234
Geoff Langbdcc54a2015-09-02 13:09:48 -04001235void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1236{
1237 TInfoSinkBase &out = objSink();
1238
1239 out << "layout(";
1240
1241 switch (interfaceBlock->blockStorage())
1242 {
1243 case EbsUnspecified:
1244 case EbsShared:
1245 // Default block storage is shared.
1246 out << "shared";
1247 break;
1248
1249 case EbsPacked:
1250 out << "packed";
1251 break;
1252
1253 case EbsStd140:
1254 out << "std140";
1255 break;
1256
1257 default:
1258 UNREACHABLE();
1259 break;
1260 }
1261
1262 out << ", ";
1263
1264 switch (interfaceBlock->matrixPacking())
1265 {
1266 case EmpUnspecified:
1267 case EmpColumnMajor:
1268 // Default matrix packing is column major.
1269 out << "column_major";
1270 break;
1271
1272 case EmpRowMajor:
1273 out << "row_major";
1274 break;
1275
1276 default:
1277 UNREACHABLE();
1278 break;
1279 }
1280
1281 out << ") ";
1282}
1283
1284void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1285{
1286 TInfoSinkBase &out = objSink();
1287
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001288 out << hashName(TName(interfaceBlock->name())) << "{\n";
Geoff Langbdcc54a2015-09-02 13:09:48 -04001289 const TFieldList &fields = interfaceBlock->fields();
1290 for (size_t i = 0; i < fields.size(); ++i)
1291 {
1292 const TField *field = fields[i];
1293 if (writeVariablePrecision(field->type()->getPrecision()))
1294 out << " ";
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001295 out << getTypeName(*field->type()) << " " << hashName(TName(field->name()));
Geoff Langbdcc54a2015-09-02 13:09:48 -04001296 if (field->type()->isArray())
1297 out << arrayBrackets(*field->type());
1298 out << ";\n";
1299 }
1300 out << "}";
1301}
Jamie Madill45bcc782016-11-07 13:58:48 -05001302
Shaob5cc1192017-07-06 10:47:20 +08001303void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out,
1304 sh::TLayoutPrimitiveType inputPrimitive,
1305 int invocations,
1306 sh::TLayoutPrimitiveType outputPrimitive,
1307 int maxVertices)
1308{
1309 // Omit 'invocations = 1'
1310 if (inputPrimitive != EptUndefined || invocations > 1)
1311 {
1312 out << "layout (";
1313
1314 if (inputPrimitive != EptUndefined)
1315 {
1316 out << getGeometryShaderPrimitiveTypeString(inputPrimitive);
1317 }
1318
1319 if (invocations > 1)
1320 {
1321 if (inputPrimitive != EptUndefined)
1322 {
1323 out << ", ";
1324 }
1325 out << "invocations = " << invocations;
1326 }
1327 out << ") in;\n";
1328 }
1329
1330 if (outputPrimitive != EptUndefined || maxVertices != -1)
1331 {
1332 out << "layout (";
1333
1334 if (outputPrimitive != EptUndefined)
1335 {
1336 out << getGeometryShaderPrimitiveTypeString(outputPrimitive);
1337 }
1338
1339 if (maxVertices != -1)
1340 {
1341 if (outputPrimitive != EptUndefined)
1342 {
1343 out << ", ";
1344 }
1345 out << "max_vertices = " << maxVertices;
1346 }
1347 out << ") out;\n";
1348 }
1349}
1350
Jamie Madill45bcc782016-11-07 13:58:48 -05001351} // namespace sh