blob: 7a1be2e6df191ff233f9e75ab49c747527a16188 [file] [log] [blame]
zmo@google.com5601ea02011-06-10 18:23:25 +00001//
Nicolas Capens16004fc2014-06-11 11:29:11 -04002// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
zmo@google.com5601ea02011-06-10 18:23:25 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Geoff Lang17732822013-08-29 13:46:49 -04007#include "compiler/translator/OutputGLSLBase.h"
Olli Etuahod57e0db2015-04-24 15:05:08 +03008
Shaob5cc1192017-07-06 10:47:20 +08009#include "angle_gl.h"
Olli Etuahod57e0db2015-04-24 15:05:08 +030010#include "common/debug.h"
Olli Etuaho56a2f952016-12-08 12:16:27 +000011#include "common/mathutil.h"
Olli Etuahocccf2b02017-07-05 14:50:54 +030012#include "compiler/translator/Compiler.h"
Olli Etuaho96f6adf2017-08-16 11:18:54 +030013#include "compiler/translator/util.h"
zmo@google.com5601ea02011-06-10 18:23:25 +000014
daniel@transgaming.com773ff742013-01-11 04:12:51 +000015#include <cfloat>
daniel@transgaming.com6c1203f2013-01-11 04:12:43 +000016
Jamie Madill45bcc782016-11-07 13:58:48 -050017namespace sh
18{
19
zmo@google.com5601ea02011-06-10 18:23:25 +000020namespace
21{
zmo@google.com5601ea02011-06-10 18:23:25 +000022
Zhenyao Mo9eedea02014-05-12 16:02:35 -070023bool isSingleStatement(TIntermNode *node)
24{
Olli Etuaho336b1472016-10-05 16:37:55 +010025 if (node->getAsFunctionDefinition())
zmo@google.com5601ea02011-06-10 18:23:25 +000026 {
Olli Etuaho336b1472016-10-05 16:37:55 +010027 return false;
Olli Etuaho6d40bbd2016-09-30 13:49:38 +010028 }
29 else if (node->getAsBlock())
30 {
31 return false;
zmo@google.com5601ea02011-06-10 18:23:25 +000032 }
Olli Etuaho57961272016-09-14 13:57:46 +030033 else if (node->getAsIfElseNode())
zmo@google.com5601ea02011-06-10 18:23:25 +000034 {
Olli Etuahod0bad2c2016-09-09 18:01:16 +030035 return false;
zmo@google.com5601ea02011-06-10 18:23:25 +000036 }
37 else if (node->getAsLoopNode())
38 {
39 return false;
40 }
Olli Etuaho01cd8af2015-02-20 10:39:20 +020041 else if (node->getAsSwitchNode())
42 {
43 return false;
44 }
45 else if (node->getAsCaseNode())
46 {
47 return false;
48 }
zmo@google.com5601ea02011-06-10 18:23:25 +000049 return true;
50}
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080051
Olli Etuaho43364892017-02-13 16:00:12 +000052class CommaSeparatedListItemPrefixGenerator
53{
54 public:
55 CommaSeparatedListItemPrefixGenerator() : mFirst(true) {}
56 private:
57 bool mFirst;
58
59 friend TInfoSinkBase &operator<<(TInfoSinkBase &out,
60 CommaSeparatedListItemPrefixGenerator &gen);
61};
62
63TInfoSinkBase &operator<<(TInfoSinkBase &out, CommaSeparatedListItemPrefixGenerator &gen)
64{
65 if (gen.mFirst)
66 {
67 gen.mFirst = false;
68 }
69 else
70 {
71 out << ", ";
72 }
73 return out;
74}
75
zmo@google.com5601ea02011-06-10 18:23:25 +000076} // namespace
77
Zhenyao Mo9eedea02014-05-12 16:02:35 -070078TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase &objSink,
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000079 ShArrayIndexClampingStrategy clampingStrategy,
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000080 ShHashFunction64 hashFunction,
Zhenyao Mo9eedea02014-05-12 16:02:35 -070081 NameMap &nameMap,
Olli Etuahoa5e693a2017-07-13 16:07:26 +030082 TSymbolTable *symbolTable,
Qiankun Miao89dd8f32016-11-09 12:59:30 +000083 sh::GLenum shaderType,
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080084 int shaderVersion,
Qiankun Miao705a9192016-08-29 10:05:27 +080085 ShShaderOutput output,
86 ShCompileOptions compileOptions)
Olli Etuahoa5e693a2017-07-13 16:07:26 +030087 : TIntermTraverser(true, true, true, symbolTable),
zmo@google.com5601ea02011-06-10 18:23:25 +000088 mObjSink(objSink),
Olli Etuaho39f74df2017-11-20 16:09:57 +020089 mDeclaringVariable(false),
shannon.woods@transgaming.com1d432bb2013-01-25 21:57:28 +000090 mClampingStrategy(clampingStrategy),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +000091 mHashFunction(hashFunction),
92 mNameMap(nameMap),
Qiankun Miao89dd8f32016-11-09 12:59:30 +000093 mShaderType(shaderType),
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -080094 mShaderVersion(shaderVersion),
Qiankun Miao705a9192016-08-29 10:05:27 +080095 mOutput(output),
96 mCompileOptions(compileOptions)
zmo@google.com5601ea02011-06-10 18:23:25 +000097{
98}
99
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800100void TOutputGLSLBase::writeInvariantQualifier(const TType &type)
101{
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000102 if (!sh::RemoveInvariant(mShaderType, mShaderVersion, mOutput, mCompileOptions))
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800103 {
104 TInfoSinkBase &out = objSink();
105 out << "invariant ";
106 }
107}
108
Olli Etuaho56a2f952016-12-08 12:16:27 +0000109void TOutputGLSLBase::writeFloat(TInfoSinkBase &out, float f)
110{
111 if ((gl::isInf(f) || gl::isNaN(f)) && mShaderVersion >= 300)
112 {
113 out << "uintBitsToFloat(" << gl::bitCast<uint32_t>(f) << "u)";
114 }
115 else
116 {
117 out << std::min(FLT_MAX, std::max(-FLT_MAX, f));
118 }
119}
120
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500121void TOutputGLSLBase::writeTriplet(Visit visit,
122 const char *preStr,
123 const char *inStr,
124 const char *postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000125{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700126 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000127 if (visit == PreVisit && preStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000128 out << preStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000129 else if (visit == InVisit && inStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000130 out << inStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000131 else if (visit == PostVisit && postStr)
zmo@google.com5601ea02011-06-10 18:23:25 +0000132 out << postStr;
zmo@google.com5601ea02011-06-10 18:23:25 +0000133}
134
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500135void TOutputGLSLBase::writeBuiltInFunctionTriplet(Visit visit,
Olli Etuahoe1805592017-01-02 16:41:20 +0000136 TOperator op,
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500137 bool useEmulatedFunction)
zmo@google.com5601ea02011-06-10 18:23:25 +0000138{
Olli Etuahod68924e2017-01-02 17:34:40 +0000139 TInfoSinkBase &out = objSink();
140 if (visit == PreVisit)
Olli Etuahoe1805592017-01-02 16:41:20 +0000141 {
Olli Etuahod68924e2017-01-02 17:34:40 +0000142 const char *opStr(GetOperatorString(op));
143 if (useEmulatedFunction)
144 {
145 BuiltInFunctionEmulator::WriteEmulatedFunctionName(out, opStr);
146 }
147 else
148 {
149 out << opStr;
150 }
151 out << "(";
Olli Etuahoe1805592017-01-02 16:41:20 +0000152 }
Olli Etuahod68924e2017-01-02 17:34:40 +0000153 else
154 {
155 writeTriplet(visit, nullptr, ", ", ")");
156 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700157}
158
Jamie Madill2a9e1072017-09-22 11:31:57 -0400159void TOutputGLSLBase::writeLayoutQualifier(TIntermTyped *variable)
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300160{
Jamie Madill2a9e1072017-09-22 11:31:57 -0400161 const TType &type = variable->getType();
162
Martin Radev2cc85b32016-08-05 16:22:53 +0300163 if (!NeedsToWriteLayoutQualifier(type))
164 {
165 return;
166 }
167
168 TInfoSinkBase &out = objSink();
169 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
170 out << "layout(";
171
Olli Etuaho43364892017-02-13 16:00:12 +0000172 CommaSeparatedListItemPrefixGenerator listItemPrefix;
173
Jiawei Shao4cc89e22017-08-31 14:25:54 +0800174 if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn ||
175 IsVarying(type.getQualifier()))
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300176 {
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300177 if (layoutQualifier.location >= 0)
178 {
Olli Etuaho43364892017-02-13 16:00:12 +0000179 out << listItemPrefix << "location = " << layoutQualifier.location;
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300180 }
181 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300182
Andrei Volykhina5527072017-03-22 16:46:30 +0300183 if (type.getQualifier() == EvqFragmentOut)
184 {
185 if (layoutQualifier.yuv == true)
186 {
187 out << listItemPrefix << "yuv";
188 }
189 }
190
Olli Etuaho43364892017-02-13 16:00:12 +0000191 if (IsOpaqueType(type.getBasicType()))
Martin Radev2cc85b32016-08-05 16:22:53 +0300192 {
Olli Etuaho43364892017-02-13 16:00:12 +0000193 if (layoutQualifier.binding >= 0)
194 {
195 out << listItemPrefix << "binding = " << layoutQualifier.binding;
196 }
197 }
198
199 if (IsImage(type.getBasicType()))
200 {
201 if (layoutQualifier.imageInternalFormat != EiifUnspecified)
202 {
203 ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform);
204 out << listItemPrefix
205 << getImageInternalFormatString(layoutQualifier.imageInternalFormat);
206 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300207 }
208
jchen1005c31da2017-07-18 16:11:39 +0800209 if (IsAtomicCounter(type.getBasicType()))
210 {
211 out << listItemPrefix << "offset = " << layoutQualifier.offset;
212 }
213
Martin Radev2cc85b32016-08-05 16:22:53 +0300214 out << ") ";
Olli Etuahoae69d7e2015-10-07 17:19:50 +0300215}
216
Jamie Madillaed1b562018-04-17 11:47:46 -0400217const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier, const TSymbol *symbol)
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800218{
219 if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 &&
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000220 (mCompileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0)
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800221 {
222 switch (qualifier)
223 {
224 // The return string is consistent with sh::getQualifierString() from
225 // BaseTypes.h minus the "centroid" keyword.
226 case EvqCentroid:
227 return "";
228 case EvqCentroidIn:
229 return "smooth in";
230 case EvqCentroidOut:
231 return "smooth out";
232 default:
233 break;
234 }
235 }
236 if (sh::IsGLSL130OrNewer(mOutput))
237 {
238 switch (qualifier)
239 {
240 case EvqAttribute:
241 return "in";
242 case EvqVaryingIn:
243 return "in";
244 case EvqVaryingOut:
245 return "out";
246 default:
247 break;
248 }
249 }
250 return sh::getQualifierString(qualifier);
251}
252
Jamie Madillaed1b562018-04-17 11:47:46 -0400253void TOutputGLSLBase::writeVariableType(const TType &type, const TSymbol *symbol)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700254{
Qiankun Miao705a9192016-08-29 10:05:27 +0800255 TQualifier qualifier = type.getQualifier();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500256 TInfoSinkBase &out = objSink();
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800257 if (type.isInvariant())
Olli Etuaho214c2d82015-04-27 14:49:13 +0300258 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800259 writeInvariantQualifier(type);
Olli Etuaho214c2d82015-04-27 14:49:13 +0300260 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400261 if (type.getBasicType() == EbtInterfaceBlock)
262 {
Olli Etuahodd21ecf2018-01-10 12:42:09 +0200263 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
Geoff Langbdcc54a2015-09-02 13:09:48 -0400264 declareInterfaceBlockLayout(interfaceBlock);
265 }
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400266 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400267 {
Jamie Madillaed1b562018-04-17 11:47:46 -0400268 const char *qualifierString = mapQualifierToString(qualifier, symbol);
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800269 if (qualifierString && qualifierString[0] != '\0')
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800270 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800271 out << qualifierString << " ";
Zhenyao Mo05b6b7f2015-03-02 17:08:09 -0800272 }
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400273 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300274
275 const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
276 if (memoryQualifier.readonly)
277 {
278 ASSERT(IsImage(type.getBasicType()));
279 out << "readonly ";
280 }
281
282 if (memoryQualifier.writeonly)
283 {
284 ASSERT(IsImage(type.getBasicType()));
285 out << "writeonly ";
286 }
287
Martin Radev049edfa2016-11-11 14:35:37 +0200288 if (memoryQualifier.coherent)
289 {
290 ASSERT(IsImage(type.getBasicType()));
291 out << "coherent ";
292 }
293
294 if (memoryQualifier.restrictQualifier)
295 {
296 ASSERT(IsImage(type.getBasicType()));
297 out << "restrict ";
298 }
299
300 if (memoryQualifier.volatileQualifier)
301 {
302 ASSERT(IsImage(type.getBasicType()));
303 out << "volatile ";
304 }
305
zmo@google.com5601ea02011-06-10 18:23:25 +0000306 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700307 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000308 {
Olli Etuahobd3cd502017-11-03 15:48:52 +0200309 const TStructure *structure = type.getStruct();
Jamie Madill01f85ac2014-06-06 11:55:04 -0400310
311 declareStruct(structure);
312
Olli Etuaho9d4d7f02017-12-07 17:11:41 +0100313 if (structure->symbolType() != SymbolType::Empty)
Jamie Madill01f85ac2014-06-06 11:55:04 -0400314 {
Olli Etuaho97fa8552017-11-28 16:28:42 +0200315 mDeclaredStructs.insert(structure->uniqueId().get());
Jamie Madill01f85ac2014-06-06 11:55:04 -0400316 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000317 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400318 else if (type.getBasicType() == EbtInterfaceBlock)
319 {
Olli Etuahodd21ecf2018-01-10 12:42:09 +0200320 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
Geoff Langbdcc54a2015-09-02 13:09:48 -0400321 declareInterfaceBlock(interfaceBlock);
322 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000323 else
324 {
325 if (writeVariablePrecision(type.getPrecision()))
326 out << " ";
327 out << getTypeName(type);
328 }
329}
330
Olli Etuahod4bd9632018-03-08 16:32:44 +0200331void TOutputGLSLBase::writeFunctionParameters(const TFunction *func)
zmo@google.com5601ea02011-06-10 18:23:25 +0000332{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700333 TInfoSinkBase &out = objSink();
Olli Etuahod4bd9632018-03-08 16:32:44 +0200334 size_t paramCount = func->getParamCount();
335 for (size_t i = 0; i < paramCount; ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000336 {
Olli Etuahod4bd9632018-03-08 16:32:44 +0200337 const TVariable *param = func->getParam(i);
338 const TType &type = param->getType();
Jamie Madillaed1b562018-04-17 11:47:46 -0400339 writeVariableType(type, param);
zmo@google.com5601ea02011-06-10 18:23:25 +0000340
Olli Etuahod4bd9632018-03-08 16:32:44 +0200341 if (param->symbolType() != SymbolType::Empty)
342 out << " " << hashName(param);
zmo@google.com5601ea02011-06-10 18:23:25 +0000343 if (type.isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300344 out << ArrayString(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000345
346 // Put a comma if this is not the last argument.
Olli Etuahod4bd9632018-03-08 16:32:44 +0200347 if (i != paramCount - 1)
zmo@google.com5601ea02011-06-10 18:23:25 +0000348 out << ", ";
349 }
350}
351
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500352const TConstantUnion *TOutputGLSLBase::writeConstantUnion(const TType &type,
353 const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000354{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700355 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000356
357 if (type.getBasicType() == EbtStruct)
358 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700359 const TStructure *structure = type.getStruct();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200360 out << hashName(structure) << "(";
Jamie Madill98493dd2013-07-08 14:39:03 -0400361
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700362 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400363 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000364 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700365 const TType *fieldType = fields[i]->type();
Yunchao He4f285442017-04-21 12:15:49 +0800366 ASSERT(fieldType != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +0000367 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700368 if (i != fields.size() - 1)
369 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000370 }
371 out << ")";
372 }
373 else
374 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500375 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000376 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700377 if (writeType)
378 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400379 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000380 {
381 switch (pConstUnion->getType())
382 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500383 case EbtFloat:
384 writeFloat(out, pConstUnion->getFConst());
385 break;
386 case EbtInt:
387 out << pConstUnion->getIConst();
388 break;
389 case EbtUInt:
390 out << pConstUnion->getUConst() << "u";
391 break;
392 case EbtBool:
393 out << pConstUnion->getBConst();
394 break;
Andrei Volykhina5527072017-03-22 16:46:30 +0300395 case EbtYuvCscStandardEXT:
396 out << getYuvCscStandardEXTString(pConstUnion->getYuvCscStandardEXTConst());
397 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500398 default:
399 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000400 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700401 if (i != size - 1)
402 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000403 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700404 if (writeType)
405 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000406 }
407 return pConstUnion;
408}
409
Olli Etuahoe92507b2016-07-04 11:20:10 +0300410void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
Olli Etuahof40319e2015-03-10 14:33:00 +0200411{
412 TInfoSinkBase &out = objSink();
413 if (visit == PreVisit)
414 {
415 if (type.isArray())
416 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300417 out << getTypeName(type);
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300418 out << ArrayString(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200419 out << "(";
420 }
421 else
422 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300423 out << getTypeName(type) << "(";
Olli Etuahof40319e2015-03-10 14:33:00 +0200424 }
425 }
426 else
427 {
428 writeTriplet(visit, nullptr, ", ", ")");
429 }
430}
431
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700432void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000433{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700434 TInfoSinkBase &out = objSink();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200435 out << hashName(&node->variable());
zmo@google.com5601ea02011-06-10 18:23:25 +0000436
Olli Etuaho39f74df2017-11-20 16:09:57 +0200437 if (mDeclaringVariable && node->getType().isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300438 out << ArrayString(node->getType());
zmo@google.com5601ea02011-06-10 18:23:25 +0000439}
440
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700441void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000442{
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200443 writeConstantUnion(node->getType(), node->getConstantValue());
zmo@google.com5601ea02011-06-10 18:23:25 +0000444}
445
Olli Etuahob6fa0432016-09-28 16:28:05 +0100446bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
447{
448 TInfoSinkBase &out = objSink();
449 if (visit == PostVisit)
450 {
451 out << ".";
452 node->writeOffsetsAsXYZW(&out);
453 }
454 return true;
455}
456
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700457bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000458{
459 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700460 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000461 switch (node->getOp())
462 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100463 case EOpComma:
464 writeTriplet(visit, "(", ", ", ")");
465 break;
466 case EOpInitialize:
zmo@google.com5601ea02011-06-10 18:23:25 +0000467 if (visit == InVisit)
468 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100469 out << " = ";
470 // RHS of initialize is not being declared.
Olli Etuaho39f74df2017-11-20 16:09:57 +0200471 mDeclaringVariable = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000472 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100473 break;
474 case EOpAssign:
475 writeTriplet(visit, "(", " = ", ")");
476 break;
477 case EOpAddAssign:
478 writeTriplet(visit, "(", " += ", ")");
479 break;
480 case EOpSubAssign:
481 writeTriplet(visit, "(", " -= ", ")");
482 break;
483 case EOpDivAssign:
484 writeTriplet(visit, "(", " /= ", ")");
485 break;
486 case EOpIModAssign:
487 writeTriplet(visit, "(", " %= ", ")");
488 break;
489 // Notice the fall-through.
490 case EOpMulAssign:
491 case EOpVectorTimesMatrixAssign:
492 case EOpVectorTimesScalarAssign:
493 case EOpMatrixTimesScalarAssign:
494 case EOpMatrixTimesMatrixAssign:
495 writeTriplet(visit, "(", " *= ", ")");
496 break;
497 case EOpBitShiftLeftAssign:
498 writeTriplet(visit, "(", " <<= ", ")");
499 break;
500 case EOpBitShiftRightAssign:
501 writeTriplet(visit, "(", " >>= ", ")");
502 break;
503 case EOpBitwiseAndAssign:
504 writeTriplet(visit, "(", " &= ", ")");
505 break;
506 case EOpBitwiseXorAssign:
507 writeTriplet(visit, "(", " ^= ", ")");
508 break;
509 case EOpBitwiseOrAssign:
510 writeTriplet(visit, "(", " |= ", ")");
511 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000512
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100513 case EOpIndexDirect:
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800514 writeTriplet(visit, nullptr, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100515 break;
516 case EOpIndexIndirect:
517 if (node->getAddIndexClamp())
518 {
519 if (visit == InVisit)
520 {
521 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
522 out << "[int(clamp(float(";
523 else
524 out << "[webgl_int_clamp(";
525 }
526 else if (visit == PostVisit)
527 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100528 TIntermTyped *left = node->getLeft();
529 TType leftType = left->getType();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700530
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100531 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
Olli Etuahoebee5b32017-11-23 12:56:32 +0200532 out << "), 0.0, float(";
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100533 else
Olli Etuahoebee5b32017-11-23 12:56:32 +0200534 out << ", 0, ";
535
536 if (leftType.isUnsizedArray())
537 {
538 // For runtime-sized arrays in ESSL 3.10 we need to call the length method
539 // to get the length to clamp against. See ESSL 3.10 section 4.1.9. Note
540 // that a runtime-sized array expression is guaranteed not to have side
541 // effects, so it's fine to add the expression to the output twice.
542 ASSERT(mShaderVersion >= 310);
543 ASSERT(!left->hasSideEffects());
544 left->traverse(this);
545 out << ".length() - 1";
546 }
547 else
548 {
549 int maxSize;
550 if (leftType.isArray())
551 {
552 maxSize = static_cast<int>(leftType.getOutermostArraySize()) - 1;
553 }
554 else
555 {
556 maxSize = leftType.getNominalSize() - 1;
557 }
558 out << maxSize;
559 }
560 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
561 out << ")))]";
562 else
563 out << ")]";
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100564 }
565 }
566 else
567 {
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800568 writeTriplet(visit, nullptr, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100569 }
570 break;
571 case EOpIndexDirectStruct:
572 if (visit == InVisit)
573 {
574 // Here we are writing out "foo.bar", where "foo" is struct
575 // and "bar" is field. In AST, it is represented as a binary
576 // node, where left child represents "foo" and right child "bar".
577 // The node itself represents ".". The struct field "bar" is
578 // actually stored as an index into TStructure::fields.
579 out << ".";
580 const TStructure *structure = node->getLeft()->getType().getStruct();
581 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
582 const TField *field = structure->fields()[index->getIConst(0)];
583
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200584 out << hashFieldName(structure, field->name());
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100585 visitChildren = false;
586 }
587 break;
588 case EOpIndexDirectInterfaceBlock:
589 if (visit == InVisit)
590 {
591 out << ".";
592 const TInterfaceBlock *interfaceBlock =
593 node->getLeft()->getType().getInterfaceBlock();
594 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
595 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200596 ASSERT(interfaceBlock->symbolType() == SymbolType::UserDefined ||
597 interfaceBlock->name() == "gl_PerVertex");
598 out << hashFieldName(interfaceBlock, field->name());
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100599 visitChildren = false;
600 }
601 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400602
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100603 case EOpAdd:
604 writeTriplet(visit, "(", " + ", ")");
605 break;
606 case EOpSub:
607 writeTriplet(visit, "(", " - ", ")");
608 break;
609 case EOpMul:
610 writeTriplet(visit, "(", " * ", ")");
611 break;
612 case EOpDiv:
613 writeTriplet(visit, "(", " / ", ")");
614 break;
615 case EOpIMod:
616 writeTriplet(visit, "(", " % ", ")");
617 break;
618 case EOpBitShiftLeft:
619 writeTriplet(visit, "(", " << ", ")");
620 break;
621 case EOpBitShiftRight:
622 writeTriplet(visit, "(", " >> ", ")");
623 break;
624 case EOpBitwiseAnd:
625 writeTriplet(visit, "(", " & ", ")");
626 break;
627 case EOpBitwiseXor:
628 writeTriplet(visit, "(", " ^ ", ")");
629 break;
630 case EOpBitwiseOr:
631 writeTriplet(visit, "(", " | ", ")");
632 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400633
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100634 case EOpEqual:
635 writeTriplet(visit, "(", " == ", ")");
636 break;
637 case EOpNotEqual:
638 writeTriplet(visit, "(", " != ", ")");
639 break;
640 case EOpLessThan:
641 writeTriplet(visit, "(", " < ", ")");
642 break;
643 case EOpGreaterThan:
644 writeTriplet(visit, "(", " > ", ")");
645 break;
646 case EOpLessThanEqual:
647 writeTriplet(visit, "(", " <= ", ")");
648 break;
649 case EOpGreaterThanEqual:
650 writeTriplet(visit, "(", " >= ", ")");
651 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000652
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100653 // Notice the fall-through.
654 case EOpVectorTimesScalar:
655 case EOpVectorTimesMatrix:
656 case EOpMatrixTimesVector:
657 case EOpMatrixTimesScalar:
658 case EOpMatrixTimesMatrix:
659 writeTriplet(visit, "(", " * ", ")");
660 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200661
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100662 case EOpLogicalOr:
663 writeTriplet(visit, "(", " || ", ")");
664 break;
665 case EOpLogicalXor:
666 writeTriplet(visit, "(", " ^^ ", ")");
667 break;
668 case EOpLogicalAnd:
669 writeTriplet(visit, "(", " && ", ")");
670 break;
671 default:
672 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000673 }
674
675 return visitChildren;
676}
677
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700678bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000679{
Olli Etuaho2f7c04a2018-01-25 14:50:37 +0200680 const char *preString = "";
681 const char *postString = ")";
zmo@google.com32e97312011-08-24 01:03:11 +0000682
zmo@google.com5601ea02011-06-10 18:23:25 +0000683 switch (node->getOp())
684 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500685 case EOpNegative:
686 preString = "(-";
687 break;
688 case EOpPositive:
689 preString = "(+";
690 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500691 case EOpLogicalNot:
692 preString = "(!";
693 break;
694 case EOpBitwiseNot:
695 preString = "(~";
696 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000697
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500698 case EOpPostIncrement:
699 preString = "(";
700 postString = "++)";
701 break;
702 case EOpPostDecrement:
703 preString = "(";
704 postString = "--)";
705 break;
706 case EOpPreIncrement:
707 preString = "(++";
708 break;
709 case EOpPreDecrement:
710 preString = "(--";
711 break;
Olli Etuahobb5a7e22017-08-30 13:03:12 +0300712 case EOpArrayLength:
713 preString = "((";
714 postString = ").length())";
715 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000716
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500717 case EOpRadians:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500718 case EOpDegrees:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500719 case EOpSin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500720 case EOpCos:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500721 case EOpTan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500722 case EOpAsin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500723 case EOpAcos:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500724 case EOpAtan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500725 case EOpSinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500726 case EOpCosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500727 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500728 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500729 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500730 case EOpAtanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500731 case EOpExp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500732 case EOpLog:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500733 case EOpExp2:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500734 case EOpLog2:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500735 case EOpSqrt:
Olli Etuahof7f0b8c2018-02-21 20:02:23 +0200736 case EOpInversesqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500737 case EOpAbs:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500738 case EOpSign:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500739 case EOpFloor:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500740 case EOpTrunc:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500741 case EOpRound:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500742 case EOpRoundEven:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500743 case EOpCeil:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500744 case EOpFract:
Olli Etuahof7f0b8c2018-02-21 20:02:23 +0200745 case EOpIsnan:
746 case EOpIsinf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500747 case EOpFloatBitsToInt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500748 case EOpFloatBitsToUint:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500749 case EOpIntBitsToFloat:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500750 case EOpUintBitsToFloat:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500751 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500752 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500753 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500754 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500755 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500756 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800757 case EOpPackUnorm4x8:
758 case EOpPackSnorm4x8:
759 case EOpUnpackUnorm4x8:
760 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500761 case EOpLength:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500762 case EOpNormalize:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500763 case EOpDFdx:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500764 case EOpDFdy:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500765 case EOpFwidth:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500766 case EOpTranspose:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500767 case EOpDeterminant:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500768 case EOpInverse:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500769 case EOpAny:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500770 case EOpAll:
Olli Etuahod68924e2017-01-02 17:34:40 +0000771 case EOpLogicalNotComponentWise:
Olli Etuaho9250cb22017-01-21 10:51:27 +0000772 case EOpBitfieldReverse:
773 case EOpBitCount:
774 case EOpFindLSB:
775 case EOpFindMSB:
Olli Etuahod68924e2017-01-02 17:34:40 +0000776 writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
777 return true;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500778 default:
779 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000780 }
781
Olli Etuaho2f7c04a2018-01-25 14:50:37 +0200782 writeTriplet(visit, preString, nullptr, postString);
zmo@google.com32e97312011-08-24 01:03:11 +0000783
zmo@google.com5601ea02011-06-10 18:23:25 +0000784 return true;
785}
786
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300787bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
788{
789 TInfoSinkBase &out = objSink();
790 // Notice two brackets at the beginning and end. The outer ones
791 // encapsulate the whole ternary expression. This preserves the
792 // order of precedence when ternary expressions are used in a
793 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
794 out << "((";
795 node->getCondition()->traverse(this);
796 out << ") ? (";
797 node->getTrueExpression()->traverse(this);
798 out << ") : (";
799 node->getFalseExpression()->traverse(this);
800 out << "))";
801 return false;
802}
803
Olli Etuaho57961272016-09-14 13:57:46 +0300804bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000805{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700806 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000807
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300808 out << "if (";
809 node->getCondition()->traverse(this);
810 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000811
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300812 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000813
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300814 if (node->getFalseBlock())
815 {
816 out << "else\n";
817 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000818 }
819 return false;
820}
821
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200822bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200823{
Olli Etuaho923ecef2017-10-11 12:01:38 +0300824 ASSERT(node->getStatementList());
825 writeTriplet(visit, "switch (", ") ", nullptr);
826 // The curly braces get written when visiting the statementList aggregate
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200827 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200828}
829
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200830bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200831{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200832 if (node->hasCondition())
833 {
834 writeTriplet(visit, "case (", nullptr, "):\n");
835 return true;
836 }
837 else
838 {
839 TInfoSinkBase &out = objSink();
840 out << "default:\n";
841 return false;
842 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200843}
844
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100845bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
846{
847 TInfoSinkBase &out = objSink();
848 // Scope the blocks except when at the global scope.
Olli Etuaho4002e922018-04-04 16:55:34 +0300849 if (getCurrentTraversalDepth() > 0)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100850 {
851 out << "{\n";
852 }
853
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100854 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
855 iter != node->getSequence()->end(); ++iter)
856 {
857 TIntermNode *curNode = *iter;
858 ASSERT(curNode != nullptr);
859 curNode->traverse(this);
860
861 if (isSingleStatement(curNode))
862 out << ";\n";
863 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100864
865 // Scope the blocks except when at the global scope.
Olli Etuaho4002e922018-04-04 16:55:34 +0300866 if (getCurrentTraversalDepth() > 0)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100867 {
868 out << "}\n";
869 }
870 return false;
871}
872
Olli Etuaho336b1472016-10-05 16:37:55 +0100873bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
874{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000875 TIntermFunctionPrototype *prototype = node->getFunctionPrototype();
876 prototype->traverse(this);
Olli Etuaho336b1472016-10-05 16:37:55 +0100877 visitCodeBlock(node->getBody());
Olli Etuaho336b1472016-10-05 16:37:55 +0100878
879 // Fully processed; no need to visit children.
880 return false;
881}
882
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000883bool TOutputGLSLBase::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
884{
885 TInfoSinkBase &out = objSink();
886 ASSERT(visit == PreVisit);
887 const TIntermSymbol *symbol = node->getSymbol();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200888 out << "invariant " << hashName(&symbol->variable());
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000889 return false;
890}
891
Olli Etuahod4bd9632018-03-08 16:32:44 +0200892void TOutputGLSLBase::visitFunctionPrototype(TIntermFunctionPrototype *node)
Olli Etuaho16c745a2017-01-16 17:02:27 +0000893{
894 TInfoSinkBase &out = objSink();
Olli Etuaho16c745a2017-01-16 17:02:27 +0000895
896 const TType &type = node->getType();
Jamie Madillaed1b562018-04-17 11:47:46 -0400897 writeVariableType(type, node->getFunction());
Olli Etuaho16c745a2017-01-16 17:02:27 +0000898 if (type.isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300899 out << ArrayString(type);
Olli Etuaho16c745a2017-01-16 17:02:27 +0000900
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200901 out << " " << hashFunctionNameIfNeeded(node->getFunction());
Olli Etuaho16c745a2017-01-16 17:02:27 +0000902
903 out << "(";
Olli Etuahod4bd9632018-03-08 16:32:44 +0200904 writeFunctionParameters(node->getFunction());
Olli Etuaho16c745a2017-01-16 17:02:27 +0000905 out << ")";
Olli Etuaho16c745a2017-01-16 17:02:27 +0000906}
907
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700908bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000909{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500910 bool visitChildren = true;
911 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000912 switch (node->getOp())
913 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800914 case EOpCallFunctionInAST:
915 case EOpCallInternalRawFunction:
916 case EOpCallBuiltInFunction:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500917 // Function call.
918 if (visit == PreVisit)
Olli Etuahoec9232b2017-03-27 17:01:37 +0300919 {
920 if (node->getOp() == EOpCallBuiltInFunction)
921 {
Olli Etuahobed35d72017-12-20 16:36:26 +0200922 out << translateTextureFunction(node->getFunction()->name());
Olli Etuahoec9232b2017-03-27 17:01:37 +0300923 }
924 else
925 {
Olli Etuaho1bb85282017-12-14 13:39:53 +0200926 out << hashFunctionNameIfNeeded(node->getFunction());
Olli Etuahoec9232b2017-03-27 17:01:37 +0300927 }
928 out << "(";
929 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500930 else if (visit == InVisit)
931 out << ", ";
932 else
933 out << ")";
934 break;
Olli Etuaho8fab3202017-05-08 18:22:22 +0300935 case EOpConstruct:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500936 writeConstructorTriplet(visit, node->getType());
937 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200938
Olli Etuahoe1805592017-01-02 16:41:20 +0000939 case EOpEqualComponentWise:
940 case EOpNotEqualComponentWise:
941 case EOpLessThanComponentWise:
942 case EOpGreaterThanComponentWise:
943 case EOpLessThanEqualComponentWise:
944 case EOpGreaterThanEqualComponentWise:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500945 case EOpMod:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500946 case EOpModf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500947 case EOpPow:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500948 case EOpAtan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500949 case EOpMin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500950 case EOpMax:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500951 case EOpClamp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500952 case EOpMix:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500953 case EOpStep:
Olli Etuahof7f0b8c2018-02-21 20:02:23 +0200954 case EOpSmoothstep:
Olli Etuaho74da73f2017-02-01 15:37:48 +0000955 case EOpFrexp:
956 case EOpLdexp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500957 case EOpDistance:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500958 case EOpDot:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500959 case EOpCross:
Jamie Madille72595b2017-06-06 15:12:26 -0400960 case EOpFaceforward:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500961 case EOpReflect:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500962 case EOpRefract:
Olli Etuahoe1805592017-01-02 16:41:20 +0000963 case EOpMulMatrixComponentWise:
964 case EOpOuterProduct:
Olli Etuaho9250cb22017-01-21 10:51:27 +0000965 case EOpBitfieldExtract:
966 case EOpBitfieldInsert:
967 case EOpUaddCarry:
968 case EOpUsubBorrow:
969 case EOpUmulExtended:
970 case EOpImulExtended:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300971 case EOpBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300972 case EOpMemoryBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300973 case EOpMemoryBarrierAtomicCounter:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300974 case EOpMemoryBarrierBuffer:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300975 case EOpMemoryBarrierImage:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300976 case EOpMemoryBarrierShared:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300977 case EOpGroupMemoryBarrier:
Jiawei Shaod27f5c82017-08-23 09:38:08 +0800978 case EOpEmitVertex:
979 case EOpEndPrimitive:
Olli Etuahod68924e2017-01-02 17:34:40 +0000980 writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300981 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500982 default:
983 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000984 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000985 return visitChildren;
986}
987
Olli Etuaho13389b62016-10-16 11:48:18 +0100988bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
989{
990 TInfoSinkBase &out = objSink();
991
992 // Variable declaration.
993 if (visit == PreVisit)
994 {
995 const TIntermSequence &sequence = *(node->getSequence());
Jamie Madill2a9e1072017-09-22 11:31:57 -0400996 TIntermTyped *variable = sequence.front()->getAsTyped();
997 writeLayoutQualifier(variable);
Jamie Madillaed1b562018-04-17 11:47:46 -0400998 writeVariableType(variable->getType(), &variable->getAsSymbolNode()->variable());
Olli Etuaho39f74df2017-11-20 16:09:57 +0200999 if (variable->getAsSymbolNode() == nullptr ||
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001000 variable->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty)
Olli Etuaho39f74df2017-11-20 16:09:57 +02001001 {
1002 out << " ";
1003 }
1004 mDeclaringVariable = true;
Olli Etuaho13389b62016-10-16 11:48:18 +01001005 }
1006 else if (visit == InVisit)
1007 {
Olli Etuaho39f74df2017-11-20 16:09:57 +02001008 UNREACHABLE();
Olli Etuaho13389b62016-10-16 11:48:18 +01001009 }
1010 else
1011 {
Olli Etuaho39f74df2017-11-20 16:09:57 +02001012 mDeclaringVariable = false;
Olli Etuaho13389b62016-10-16 11:48:18 +01001013 }
1014 return true;
1015}
1016
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001017bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001018{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001019 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001020
zmo@google.com5601ea02011-06-10 18:23:25 +00001021 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001022
zmo@google.com5601ea02011-06-10 18:23:25 +00001023 if (loopType == ELoopFor) // for loop
1024 {
Corentin Wallez1b896c62016-11-16 13:10:44 -05001025 out << "for (";
1026 if (node->getInit())
1027 node->getInit()->traverse(this);
1028 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001029
Corentin Wallez1b896c62016-11-16 13:10:44 -05001030 if (node->getCondition())
1031 node->getCondition()->traverse(this);
1032 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001033
Corentin Wallez1b896c62016-11-16 13:10:44 -05001034 if (node->getExpression())
1035 node->getExpression()->traverse(this);
1036 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001037
Corentin Wallez1b896c62016-11-16 13:10:44 -05001038 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001039 }
1040 else if (loopType == ELoopWhile) // while loop
1041 {
1042 out << "while (";
Yunchao He4f285442017-04-21 12:15:49 +08001043 ASSERT(node->getCondition() != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +00001044 node->getCondition()->traverse(this);
1045 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001046
1047 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001048 }
1049 else // do-while loop
1050 {
1051 ASSERT(loopType == ELoopDoWhile);
1052 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001053
zmo@google.com5601ea02011-06-10 18:23:25 +00001054 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001055
zmo@google.com5601ea02011-06-10 18:23:25 +00001056 out << "while (";
Yunchao He4f285442017-04-21 12:15:49 +08001057 ASSERT(node->getCondition() != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +00001058 node->getCondition()->traverse(this);
1059 out << ");\n";
1060 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001061
zmo@google.com5601ea02011-06-10 18:23:25 +00001062 // No need to visit children. They have been already processed in
1063 // this function.
1064 return false;
1065}
1066
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001067bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001068{
1069 switch (node->getFlowOp())
1070 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001071 case EOpKill:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001072 writeTriplet(visit, "discard", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001073 break;
1074 case EOpBreak:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001075 writeTriplet(visit, "break", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001076 break;
1077 case EOpContinue:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001078 writeTriplet(visit, "continue", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001079 break;
1080 case EOpReturn:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001081 writeTriplet(visit, "return ", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001082 break;
1083 default:
1084 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001085 }
1086
1087 return true;
1088}
1089
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001090void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001091{
zmo@google.com5601ea02011-06-10 18:23:25 +00001092 TInfoSinkBase &out = objSink();
Yunchao He4f285442017-04-21 12:15:49 +08001093 if (node != nullptr)
zmo@google.com5601ea02011-06-10 18:23:25 +00001094 {
1095 node->traverse(this);
1096 // Single statements not part of a sequence need to be terminated
1097 // with semi-colon.
1098 if (isSingleStatement(node))
1099 out << ";\n";
1100 }
1101 else
1102 {
1103 out << "{\n}\n"; // Empty code block.
1104 }
1105}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001106
Olli Etuahofbb1c792018-01-19 16:26:59 +02001107ImmutableString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001108{
Jamie Madill6276b922017-09-25 02:35:57 -04001109 return GetTypeName(type, mHashFunction, &mNameMap);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001110}
1111
Olli Etuahofbb1c792018-01-19 16:26:59 +02001112ImmutableString TOutputGLSLBase::hashName(const TSymbol *symbol)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001113{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001114 return HashName(symbol, mHashFunction, &mNameMap);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001115}
1116
Olli Etuahofbb1c792018-01-19 16:26:59 +02001117ImmutableString TOutputGLSLBase::hashFieldName(const TSymbol *containingStruct,
1118 const ImmutableString &fieldName)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001119{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001120 if (containingStruct->symbolType() == SymbolType::UserDefined ||
1121 containingStruct->symbolType() == SymbolType::Empty)
Olli Etuaho09b04a22016-12-15 13:30:26 +00001122 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001123 return HashName(fieldName, mHashFunction, &mNameMap);
Olli Etuaho09b04a22016-12-15 13:30:26 +00001124 }
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001125 else
1126 {
1127 return fieldName;
1128 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001129}
1130
Olli Etuahofbb1c792018-01-19 16:26:59 +02001131ImmutableString TOutputGLSLBase::hashFunctionNameIfNeeded(const TFunction *func)
Olli Etuaho1bb85282017-12-14 13:39:53 +02001132{
1133 if (func->isMain())
1134 {
Olli Etuahobed35d72017-12-20 16:36:26 +02001135 return func->name();
Olli Etuaho1bb85282017-12-14 13:39:53 +02001136 }
1137 else
1138 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001139 return hashName(func);
Olli Etuaho1bb85282017-12-14 13:39:53 +02001140 }
1141}
1142
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001143bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001144{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001145 ASSERT(structure);
Olli Etuaho9d4d7f02017-12-07 17:11:41 +01001146 if (structure->symbolType() == SymbolType::Empty)
Zhenyao Mo904a9162014-05-09 14:07:45 -07001147 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001148 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001149 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001150
Olli Etuaho97fa8552017-11-28 16:28:42 +02001151 return (mDeclaredStructs.count(structure->uniqueId().get()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001152}
1153
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001154void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001155{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001156 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001157
Olli Etuahobed35d72017-12-20 16:36:26 +02001158 out << "struct ";
1159
1160 if (structure->symbolType() != SymbolType::Empty)
1161 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001162 out << hashName(structure) << " ";
Olli Etuahobed35d72017-12-20 16:36:26 +02001163 }
1164 out << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001165 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001166 for (size_t i = 0; i < fields.size(); ++i)
1167 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001168 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001169 if (writeVariablePrecision(field->type()->getPrecision()))
1170 out << " ";
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001171 out << getTypeName(*field->type()) << " " << hashFieldName(structure, field->name());
Jamie Madill98493dd2013-07-08 14:39:03 -04001172 if (field->type()->isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001173 out << ArrayString(*field->type());
Jamie Madill98493dd2013-07-08 14:39:03 -04001174 out << ";\n";
1175 }
1176 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001177}
Jamie Madill98493dd2013-07-08 14:39:03 -04001178
Geoff Langbdcc54a2015-09-02 13:09:48 -04001179void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1180{
1181 TInfoSinkBase &out = objSink();
1182
1183 out << "layout(";
1184
1185 switch (interfaceBlock->blockStorage())
1186 {
1187 case EbsUnspecified:
1188 case EbsShared:
1189 // Default block storage is shared.
1190 out << "shared";
1191 break;
1192
1193 case EbsPacked:
1194 out << "packed";
1195 break;
1196
1197 case EbsStd140:
1198 out << "std140";
1199 break;
1200
Qin Jiajiaca68d982017-09-18 16:41:56 +08001201 case EbsStd430:
1202 out << "std430";
1203 break;
1204
Geoff Langbdcc54a2015-09-02 13:09:48 -04001205 default:
1206 UNREACHABLE();
1207 break;
1208 }
1209
Jiajia Qinfeb2c632017-12-08 17:59:19 +08001210 if (interfaceBlock->blockBinding() >= 0)
Jiajia Qin729b2c62017-08-14 09:36:11 +08001211 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08001212 out << ", ";
Olli Etuaho3de27032017-11-30 12:16:47 +02001213 out << "binding = " << interfaceBlock->blockBinding();
Geoff Langbdcc54a2015-09-02 13:09:48 -04001214 }
1215
1216 out << ") ";
1217}
1218
1219void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1220{
1221 TInfoSinkBase &out = objSink();
1222
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001223 out << hashName(interfaceBlock) << "{\n";
Geoff Langbdcc54a2015-09-02 13:09:48 -04001224 const TFieldList &fields = interfaceBlock->fields();
Olli Etuaho3de27032017-11-30 12:16:47 +02001225 for (const TField *field : fields)
Geoff Langbdcc54a2015-09-02 13:09:48 -04001226 {
Olli Etuaho3de27032017-11-30 12:16:47 +02001227 if (field->type()->isMatrix() || field->type()->isStructureContainingMatrices())
1228 {
1229 out << "layout(";
1230 switch (field->type()->getLayoutQualifier().matrixPacking)
1231 {
1232 case EmpUnspecified:
1233 case EmpColumnMajor:
1234 // Default matrix packing is column major.
1235 out << "column_major";
1236 break;
1237
1238 case EmpRowMajor:
1239 out << "row_major";
1240 break;
1241
1242 default:
1243 UNREACHABLE();
1244 break;
1245 }
1246 out << ") ";
1247 }
1248
Geoff Langbdcc54a2015-09-02 13:09:48 -04001249 if (writeVariablePrecision(field->type()->getPrecision()))
1250 out << " ";
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001251 out << getTypeName(*field->type()) << " " << hashFieldName(interfaceBlock, field->name());
Geoff Langbdcc54a2015-09-02 13:09:48 -04001252 if (field->type()->isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001253 out << ArrayString(*field->type());
Geoff Langbdcc54a2015-09-02 13:09:48 -04001254 out << ";\n";
1255 }
1256 out << "}";
1257}
Jamie Madill45bcc782016-11-07 13:58:48 -05001258
Shaob5cc1192017-07-06 10:47:20 +08001259void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out,
1260 sh::TLayoutPrimitiveType inputPrimitive,
1261 int invocations,
1262 sh::TLayoutPrimitiveType outputPrimitive,
1263 int maxVertices)
1264{
1265 // Omit 'invocations = 1'
1266 if (inputPrimitive != EptUndefined || invocations > 1)
1267 {
1268 out << "layout (";
1269
1270 if (inputPrimitive != EptUndefined)
1271 {
1272 out << getGeometryShaderPrimitiveTypeString(inputPrimitive);
1273 }
1274
1275 if (invocations > 1)
1276 {
1277 if (inputPrimitive != EptUndefined)
1278 {
1279 out << ", ";
1280 }
1281 out << "invocations = " << invocations;
1282 }
1283 out << ") in;\n";
1284 }
1285
1286 if (outputPrimitive != EptUndefined || maxVertices != -1)
1287 {
1288 out << "layout (";
1289
1290 if (outputPrimitive != EptUndefined)
1291 {
1292 out << getGeometryShaderPrimitiveTypeString(outputPrimitive);
1293 }
1294
1295 if (maxVertices != -1)
1296 {
1297 if (outputPrimitive != EptUndefined)
1298 {
1299 out << ", ";
1300 }
1301 out << "max_vertices = " << maxVertices;
1302 }
1303 out << ") out;\n";
1304 }
1305}
1306
Jamie Madill2a9e1072017-09-22 11:31:57 -04001307// If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
1308// variables with specified layout qualifiers are copied. Additional checks are needed against the
1309// type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
1310// TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
1311// NeedsToWriteLayoutQualifier.
1312bool NeedsToWriteLayoutQualifier(const TType &type)
1313{
1314 if (type.getBasicType() == EbtInterfaceBlock)
1315 {
1316 return false;
1317 }
1318
1319 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
1320
1321 if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn ||
1322 IsVarying(type.getQualifier())) &&
1323 layoutQualifier.location >= 0)
1324 {
1325 return true;
1326 }
1327
1328 if (type.getQualifier() == EvqFragmentOut && layoutQualifier.yuv == true)
1329 {
1330 return true;
1331 }
1332
1333 if (IsOpaqueType(type.getBasicType()) && layoutQualifier.binding != -1)
1334 {
1335 return true;
1336 }
1337
1338 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
1339 {
1340 return true;
1341 }
1342 return false;
1343}
1344
Jamie Madill45bcc782016-11-07 13:58:48 -05001345} // namespace sh