blob: fd1958c61a28b7ace2a125f62b9f2a7db7b2cf31 [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
Luc Ferronf1d3c202018-04-16 07:44:27 -0400217void TOutputGLSLBase::writeQualifier(TQualifier qualifier, const TSymbol *symbol)
218{
219 const char *result = mapQualifierToString(qualifier);
220 if (result && result[0] != '\0')
221 {
222 objSink() << result << " ";
223 }
224}
225
226const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier)
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800227{
228 if (sh::IsGLSL410OrOlder(mOutput) && mShaderVersion >= 300 &&
Qiankun Miao89dd8f32016-11-09 12:59:30 +0000229 (mCompileOptions & SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3) != 0)
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800230 {
231 switch (qualifier)
232 {
233 // The return string is consistent with sh::getQualifierString() from
234 // BaseTypes.h minus the "centroid" keyword.
235 case EvqCentroid:
236 return "";
237 case EvqCentroidIn:
238 return "smooth in";
239 case EvqCentroidOut:
240 return "smooth out";
241 default:
242 break;
243 }
244 }
245 if (sh::IsGLSL130OrNewer(mOutput))
246 {
247 switch (qualifier)
248 {
249 case EvqAttribute:
250 return "in";
251 case EvqVaryingIn:
252 return "in";
253 case EvqVaryingOut:
254 return "out";
255 default:
256 break;
257 }
258 }
259 return sh::getQualifierString(qualifier);
260}
261
Jamie Madillaed1b562018-04-17 11:47:46 -0400262void TOutputGLSLBase::writeVariableType(const TType &type, const TSymbol *symbol)
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700263{
Qiankun Miao705a9192016-08-29 10:05:27 +0800264 TQualifier qualifier = type.getQualifier();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500265 TInfoSinkBase &out = objSink();
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800266 if (type.isInvariant())
Olli Etuaho214c2d82015-04-27 14:49:13 +0300267 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800268 writeInvariantQualifier(type);
Olli Etuaho214c2d82015-04-27 14:49:13 +0300269 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400270 if (type.getBasicType() == EbtInterfaceBlock)
271 {
Olli Etuahodd21ecf2018-01-10 12:42:09 +0200272 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
Geoff Langbdcc54a2015-09-02 13:09:48 -0400273 declareInterfaceBlockLayout(interfaceBlock);
274 }
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400275 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400276 {
Luc Ferronf1d3c202018-04-16 07:44:27 -0400277 writeQualifier(qualifier, symbol);
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400278 }
Martin Radev2cc85b32016-08-05 16:22:53 +0300279
280 const TMemoryQualifier &memoryQualifier = type.getMemoryQualifier();
281 if (memoryQualifier.readonly)
282 {
283 ASSERT(IsImage(type.getBasicType()));
284 out << "readonly ";
285 }
286
287 if (memoryQualifier.writeonly)
288 {
289 ASSERT(IsImage(type.getBasicType()));
290 out << "writeonly ";
291 }
292
Martin Radev049edfa2016-11-11 14:35:37 +0200293 if (memoryQualifier.coherent)
294 {
295 ASSERT(IsImage(type.getBasicType()));
296 out << "coherent ";
297 }
298
299 if (memoryQualifier.restrictQualifier)
300 {
301 ASSERT(IsImage(type.getBasicType()));
302 out << "restrict ";
303 }
304
305 if (memoryQualifier.volatileQualifier)
306 {
307 ASSERT(IsImage(type.getBasicType()));
308 out << "volatile ";
309 }
310
zmo@google.com5601ea02011-06-10 18:23:25 +0000311 // Declare the struct if we have not done so already.
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700312 if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct()))
zmo@google.com5601ea02011-06-10 18:23:25 +0000313 {
Olli Etuahobd3cd502017-11-03 15:48:52 +0200314 const TStructure *structure = type.getStruct();
Jamie Madill01f85ac2014-06-06 11:55:04 -0400315
316 declareStruct(structure);
317
Olli Etuaho9d4d7f02017-12-07 17:11:41 +0100318 if (structure->symbolType() != SymbolType::Empty)
Jamie Madill01f85ac2014-06-06 11:55:04 -0400319 {
Olli Etuaho97fa8552017-11-28 16:28:42 +0200320 mDeclaredStructs.insert(structure->uniqueId().get());
Jamie Madill01f85ac2014-06-06 11:55:04 -0400321 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000322 }
Geoff Langbdcc54a2015-09-02 13:09:48 -0400323 else if (type.getBasicType() == EbtInterfaceBlock)
324 {
Olli Etuahodd21ecf2018-01-10 12:42:09 +0200325 const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
Geoff Langbdcc54a2015-09-02 13:09:48 -0400326 declareInterfaceBlock(interfaceBlock);
327 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000328 else
329 {
330 if (writeVariablePrecision(type.getPrecision()))
331 out << " ";
332 out << getTypeName(type);
333 }
334}
335
Olli Etuahod4bd9632018-03-08 16:32:44 +0200336void TOutputGLSLBase::writeFunctionParameters(const TFunction *func)
zmo@google.com5601ea02011-06-10 18:23:25 +0000337{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700338 TInfoSinkBase &out = objSink();
Olli Etuahod4bd9632018-03-08 16:32:44 +0200339 size_t paramCount = func->getParamCount();
340 for (size_t i = 0; i < paramCount; ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000341 {
Olli Etuahod4bd9632018-03-08 16:32:44 +0200342 const TVariable *param = func->getParam(i);
343 const TType &type = param->getType();
Jamie Madillaed1b562018-04-17 11:47:46 -0400344 writeVariableType(type, param);
zmo@google.com5601ea02011-06-10 18:23:25 +0000345
Olli Etuahod4bd9632018-03-08 16:32:44 +0200346 if (param->symbolType() != SymbolType::Empty)
347 out << " " << hashName(param);
zmo@google.com5601ea02011-06-10 18:23:25 +0000348 if (type.isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300349 out << ArrayString(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000350
351 // Put a comma if this is not the last argument.
Olli Etuahod4bd9632018-03-08 16:32:44 +0200352 if (i != paramCount - 1)
zmo@google.com5601ea02011-06-10 18:23:25 +0000353 out << ", ";
354 }
355}
356
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500357const TConstantUnion *TOutputGLSLBase::writeConstantUnion(const TType &type,
358 const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000359{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700360 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000361
362 if (type.getBasicType() == EbtStruct)
363 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700364 const TStructure *structure = type.getStruct();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200365 out << hashName(structure) << "(";
Jamie Madill98493dd2013-07-08 14:39:03 -0400366
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700367 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400368 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000369 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700370 const TType *fieldType = fields[i]->type();
Yunchao He4f285442017-04-21 12:15:49 +0800371 ASSERT(fieldType != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +0000372 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700373 if (i != fields.size() - 1)
374 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000375 }
376 out << ")";
377 }
378 else
379 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500380 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000381 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700382 if (writeType)
383 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400384 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000385 {
386 switch (pConstUnion->getType())
387 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500388 case EbtFloat:
389 writeFloat(out, pConstUnion->getFConst());
390 break;
391 case EbtInt:
392 out << pConstUnion->getIConst();
393 break;
394 case EbtUInt:
395 out << pConstUnion->getUConst() << "u";
396 break;
397 case EbtBool:
398 out << pConstUnion->getBConst();
399 break;
Andrei Volykhina5527072017-03-22 16:46:30 +0300400 case EbtYuvCscStandardEXT:
401 out << getYuvCscStandardEXTString(pConstUnion->getYuvCscStandardEXTConst());
402 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500403 default:
404 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000405 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700406 if (i != size - 1)
407 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000408 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700409 if (writeType)
410 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000411 }
412 return pConstUnion;
413}
414
Olli Etuahoe92507b2016-07-04 11:20:10 +0300415void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
Olli Etuahof40319e2015-03-10 14:33:00 +0200416{
417 TInfoSinkBase &out = objSink();
418 if (visit == PreVisit)
419 {
420 if (type.isArray())
421 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300422 out << getTypeName(type);
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300423 out << ArrayString(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200424 out << "(";
425 }
426 else
427 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300428 out << getTypeName(type) << "(";
Olli Etuahof40319e2015-03-10 14:33:00 +0200429 }
430 }
431 else
432 {
433 writeTriplet(visit, nullptr, ", ", ")");
434 }
435}
436
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700437void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000438{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700439 TInfoSinkBase &out = objSink();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200440 out << hashName(&node->variable());
zmo@google.com5601ea02011-06-10 18:23:25 +0000441
Olli Etuaho39f74df2017-11-20 16:09:57 +0200442 if (mDeclaringVariable && node->getType().isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300443 out << ArrayString(node->getType());
zmo@google.com5601ea02011-06-10 18:23:25 +0000444}
445
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700446void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000447{
Olli Etuahoea22b7a2018-01-04 17:09:11 +0200448 writeConstantUnion(node->getType(), node->getConstantValue());
zmo@google.com5601ea02011-06-10 18:23:25 +0000449}
450
Olli Etuahob6fa0432016-09-28 16:28:05 +0100451bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
452{
453 TInfoSinkBase &out = objSink();
454 if (visit == PostVisit)
455 {
456 out << ".";
457 node->writeOffsetsAsXYZW(&out);
458 }
459 return true;
460}
461
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700462bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000463{
464 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700465 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000466 switch (node->getOp())
467 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100468 case EOpComma:
469 writeTriplet(visit, "(", ", ", ")");
470 break;
471 case EOpInitialize:
zmo@google.com5601ea02011-06-10 18:23:25 +0000472 if (visit == InVisit)
473 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100474 out << " = ";
475 // RHS of initialize is not being declared.
Olli Etuaho39f74df2017-11-20 16:09:57 +0200476 mDeclaringVariable = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000477 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100478 break;
479 case EOpAssign:
480 writeTriplet(visit, "(", " = ", ")");
481 break;
482 case EOpAddAssign:
483 writeTriplet(visit, "(", " += ", ")");
484 break;
485 case EOpSubAssign:
486 writeTriplet(visit, "(", " -= ", ")");
487 break;
488 case EOpDivAssign:
489 writeTriplet(visit, "(", " /= ", ")");
490 break;
491 case EOpIModAssign:
492 writeTriplet(visit, "(", " %= ", ")");
493 break;
494 // Notice the fall-through.
495 case EOpMulAssign:
496 case EOpVectorTimesMatrixAssign:
497 case EOpVectorTimesScalarAssign:
498 case EOpMatrixTimesScalarAssign:
499 case EOpMatrixTimesMatrixAssign:
500 writeTriplet(visit, "(", " *= ", ")");
501 break;
502 case EOpBitShiftLeftAssign:
503 writeTriplet(visit, "(", " <<= ", ")");
504 break;
505 case EOpBitShiftRightAssign:
506 writeTriplet(visit, "(", " >>= ", ")");
507 break;
508 case EOpBitwiseAndAssign:
509 writeTriplet(visit, "(", " &= ", ")");
510 break;
511 case EOpBitwiseXorAssign:
512 writeTriplet(visit, "(", " ^= ", ")");
513 break;
514 case EOpBitwiseOrAssign:
515 writeTriplet(visit, "(", " |= ", ")");
516 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000517
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100518 case EOpIndexDirect:
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800519 writeTriplet(visit, nullptr, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100520 break;
521 case EOpIndexIndirect:
522 if (node->getAddIndexClamp())
523 {
524 if (visit == InVisit)
525 {
526 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
527 out << "[int(clamp(float(";
528 else
529 out << "[webgl_int_clamp(";
530 }
531 else if (visit == PostVisit)
532 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100533 TIntermTyped *left = node->getLeft();
534 TType leftType = left->getType();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700535
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100536 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
Olli Etuahoebee5b32017-11-23 12:56:32 +0200537 out << "), 0.0, float(";
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100538 else
Olli Etuahoebee5b32017-11-23 12:56:32 +0200539 out << ", 0, ";
540
541 if (leftType.isUnsizedArray())
542 {
543 // For runtime-sized arrays in ESSL 3.10 we need to call the length method
544 // to get the length to clamp against. See ESSL 3.10 section 4.1.9. Note
545 // that a runtime-sized array expression is guaranteed not to have side
546 // effects, so it's fine to add the expression to the output twice.
547 ASSERT(mShaderVersion >= 310);
548 ASSERT(!left->hasSideEffects());
549 left->traverse(this);
550 out << ".length() - 1";
551 }
552 else
553 {
554 int maxSize;
555 if (leftType.isArray())
556 {
557 maxSize = static_cast<int>(leftType.getOutermostArraySize()) - 1;
558 }
559 else
560 {
561 maxSize = leftType.getNominalSize() - 1;
562 }
563 out << maxSize;
564 }
565 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
566 out << ")))]";
567 else
568 out << ")]";
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100569 }
570 }
571 else
572 {
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800573 writeTriplet(visit, nullptr, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100574 }
575 break;
576 case EOpIndexDirectStruct:
577 if (visit == InVisit)
578 {
579 // Here we are writing out "foo.bar", where "foo" is struct
580 // and "bar" is field. In AST, it is represented as a binary
581 // node, where left child represents "foo" and right child "bar".
582 // The node itself represents ".". The struct field "bar" is
583 // actually stored as an index into TStructure::fields.
584 out << ".";
585 const TStructure *structure = node->getLeft()->getType().getStruct();
586 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
587 const TField *field = structure->fields()[index->getIConst(0)];
588
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200589 out << hashFieldName(structure, field->name());
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100590 visitChildren = false;
591 }
592 break;
593 case EOpIndexDirectInterfaceBlock:
594 if (visit == InVisit)
595 {
596 out << ".";
597 const TInterfaceBlock *interfaceBlock =
598 node->getLeft()->getType().getInterfaceBlock();
599 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
600 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200601 ASSERT(interfaceBlock->symbolType() == SymbolType::UserDefined ||
602 interfaceBlock->name() == "gl_PerVertex");
603 out << hashFieldName(interfaceBlock, field->name());
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100604 visitChildren = false;
605 }
606 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400607
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100608 case EOpAdd:
609 writeTriplet(visit, "(", " + ", ")");
610 break;
611 case EOpSub:
612 writeTriplet(visit, "(", " - ", ")");
613 break;
614 case EOpMul:
615 writeTriplet(visit, "(", " * ", ")");
616 break;
617 case EOpDiv:
618 writeTriplet(visit, "(", " / ", ")");
619 break;
620 case EOpIMod:
621 writeTriplet(visit, "(", " % ", ")");
622 break;
623 case EOpBitShiftLeft:
624 writeTriplet(visit, "(", " << ", ")");
625 break;
626 case EOpBitShiftRight:
627 writeTriplet(visit, "(", " >> ", ")");
628 break;
629 case EOpBitwiseAnd:
630 writeTriplet(visit, "(", " & ", ")");
631 break;
632 case EOpBitwiseXor:
633 writeTriplet(visit, "(", " ^ ", ")");
634 break;
635 case EOpBitwiseOr:
636 writeTriplet(visit, "(", " | ", ")");
637 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400638
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100639 case EOpEqual:
640 writeTriplet(visit, "(", " == ", ")");
641 break;
642 case EOpNotEqual:
643 writeTriplet(visit, "(", " != ", ")");
644 break;
645 case EOpLessThan:
646 writeTriplet(visit, "(", " < ", ")");
647 break;
648 case EOpGreaterThan:
649 writeTriplet(visit, "(", " > ", ")");
650 break;
651 case EOpLessThanEqual:
652 writeTriplet(visit, "(", " <= ", ")");
653 break;
654 case EOpGreaterThanEqual:
655 writeTriplet(visit, "(", " >= ", ")");
656 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000657
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100658 // Notice the fall-through.
659 case EOpVectorTimesScalar:
660 case EOpVectorTimesMatrix:
661 case EOpMatrixTimesVector:
662 case EOpMatrixTimesScalar:
663 case EOpMatrixTimesMatrix:
664 writeTriplet(visit, "(", " * ", ")");
665 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200666
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100667 case EOpLogicalOr:
668 writeTriplet(visit, "(", " || ", ")");
669 break;
670 case EOpLogicalXor:
671 writeTriplet(visit, "(", " ^^ ", ")");
672 break;
673 case EOpLogicalAnd:
674 writeTriplet(visit, "(", " && ", ")");
675 break;
676 default:
677 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000678 }
679
680 return visitChildren;
681}
682
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700683bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000684{
Olli Etuaho2f7c04a2018-01-25 14:50:37 +0200685 const char *preString = "";
686 const char *postString = ")";
zmo@google.com32e97312011-08-24 01:03:11 +0000687
zmo@google.com5601ea02011-06-10 18:23:25 +0000688 switch (node->getOp())
689 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500690 case EOpNegative:
691 preString = "(-";
692 break;
693 case EOpPositive:
694 preString = "(+";
695 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500696 case EOpLogicalNot:
697 preString = "(!";
698 break;
699 case EOpBitwiseNot:
700 preString = "(~";
701 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000702
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500703 case EOpPostIncrement:
704 preString = "(";
705 postString = "++)";
706 break;
707 case EOpPostDecrement:
708 preString = "(";
709 postString = "--)";
710 break;
711 case EOpPreIncrement:
712 preString = "(++";
713 break;
714 case EOpPreDecrement:
715 preString = "(--";
716 break;
Olli Etuahobb5a7e22017-08-30 13:03:12 +0300717 case EOpArrayLength:
718 preString = "((";
719 postString = ").length())";
720 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000721
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500722 case EOpRadians:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500723 case EOpDegrees:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500724 case EOpSin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500725 case EOpCos:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500726 case EOpTan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500727 case EOpAsin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500728 case EOpAcos:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500729 case EOpAtan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500730 case EOpSinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500731 case EOpCosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500732 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500733 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500734 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500735 case EOpAtanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500736 case EOpExp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500737 case EOpLog:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500738 case EOpExp2:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500739 case EOpLog2:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500740 case EOpSqrt:
Olli Etuahof7f0b8c2018-02-21 20:02:23 +0200741 case EOpInversesqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500742 case EOpAbs:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500743 case EOpSign:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500744 case EOpFloor:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500745 case EOpTrunc:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500746 case EOpRound:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500747 case EOpRoundEven:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500748 case EOpCeil:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500749 case EOpFract:
Olli Etuahof7f0b8c2018-02-21 20:02:23 +0200750 case EOpIsnan:
751 case EOpIsinf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500752 case EOpFloatBitsToInt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500753 case EOpFloatBitsToUint:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500754 case EOpIntBitsToFloat:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500755 case EOpUintBitsToFloat:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500756 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500757 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500758 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500759 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500760 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500761 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800762 case EOpPackUnorm4x8:
763 case EOpPackSnorm4x8:
764 case EOpUnpackUnorm4x8:
765 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500766 case EOpLength:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500767 case EOpNormalize:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500768 case EOpDFdx:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500769 case EOpDFdy:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500770 case EOpFwidth:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500771 case EOpTranspose:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500772 case EOpDeterminant:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500773 case EOpInverse:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500774 case EOpAny:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500775 case EOpAll:
Olli Etuahod68924e2017-01-02 17:34:40 +0000776 case EOpLogicalNotComponentWise:
Olli Etuaho9250cb22017-01-21 10:51:27 +0000777 case EOpBitfieldReverse:
778 case EOpBitCount:
779 case EOpFindLSB:
780 case EOpFindMSB:
Olli Etuahod68924e2017-01-02 17:34:40 +0000781 writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
782 return true;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500783 default:
784 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000785 }
786
Olli Etuaho2f7c04a2018-01-25 14:50:37 +0200787 writeTriplet(visit, preString, nullptr, postString);
zmo@google.com32e97312011-08-24 01:03:11 +0000788
zmo@google.com5601ea02011-06-10 18:23:25 +0000789 return true;
790}
791
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300792bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
793{
794 TInfoSinkBase &out = objSink();
795 // Notice two brackets at the beginning and end. The outer ones
796 // encapsulate the whole ternary expression. This preserves the
797 // order of precedence when ternary expressions are used in a
798 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
799 out << "((";
800 node->getCondition()->traverse(this);
801 out << ") ? (";
802 node->getTrueExpression()->traverse(this);
803 out << ") : (";
804 node->getFalseExpression()->traverse(this);
805 out << "))";
806 return false;
807}
808
Olli Etuaho57961272016-09-14 13:57:46 +0300809bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000810{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700811 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000812
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300813 out << "if (";
814 node->getCondition()->traverse(this);
815 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000816
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300817 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000818
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300819 if (node->getFalseBlock())
820 {
821 out << "else\n";
822 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000823 }
824 return false;
825}
826
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200827bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200828{
Olli Etuaho923ecef2017-10-11 12:01:38 +0300829 ASSERT(node->getStatementList());
830 writeTriplet(visit, "switch (", ") ", nullptr);
831 // The curly braces get written when visiting the statementList aggregate
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200832 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200833}
834
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200835bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200836{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200837 if (node->hasCondition())
838 {
839 writeTriplet(visit, "case (", nullptr, "):\n");
840 return true;
841 }
842 else
843 {
844 TInfoSinkBase &out = objSink();
845 out << "default:\n";
846 return false;
847 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200848}
849
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100850bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
851{
852 TInfoSinkBase &out = objSink();
853 // Scope the blocks except when at the global scope.
Olli Etuaho4002e922018-04-04 16:55:34 +0300854 if (getCurrentTraversalDepth() > 0)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100855 {
856 out << "{\n";
857 }
858
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100859 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
860 iter != node->getSequence()->end(); ++iter)
861 {
862 TIntermNode *curNode = *iter;
863 ASSERT(curNode != nullptr);
864 curNode->traverse(this);
865
866 if (isSingleStatement(curNode))
867 out << ";\n";
868 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100869
870 // Scope the blocks except when at the global scope.
Olli Etuaho4002e922018-04-04 16:55:34 +0300871 if (getCurrentTraversalDepth() > 0)
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100872 {
873 out << "}\n";
874 }
875 return false;
876}
877
Olli Etuaho336b1472016-10-05 16:37:55 +0100878bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
879{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000880 TIntermFunctionPrototype *prototype = node->getFunctionPrototype();
881 prototype->traverse(this);
Olli Etuaho336b1472016-10-05 16:37:55 +0100882 visitCodeBlock(node->getBody());
Olli Etuaho336b1472016-10-05 16:37:55 +0100883
884 // Fully processed; no need to visit children.
885 return false;
886}
887
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000888bool TOutputGLSLBase::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
889{
890 TInfoSinkBase &out = objSink();
891 ASSERT(visit == PreVisit);
892 const TIntermSymbol *symbol = node->getSymbol();
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +0200893 out << "invariant " << hashName(&symbol->variable());
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000894 return false;
895}
896
Olli Etuahod4bd9632018-03-08 16:32:44 +0200897void TOutputGLSLBase::visitFunctionPrototype(TIntermFunctionPrototype *node)
Olli Etuaho16c745a2017-01-16 17:02:27 +0000898{
899 TInfoSinkBase &out = objSink();
Olli Etuaho16c745a2017-01-16 17:02:27 +0000900
901 const TType &type = node->getType();
Jamie Madillaed1b562018-04-17 11:47:46 -0400902 writeVariableType(type, node->getFunction());
Olli Etuaho16c745a2017-01-16 17:02:27 +0000903 if (type.isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300904 out << ArrayString(type);
Olli Etuaho16c745a2017-01-16 17:02:27 +0000905
Olli Etuahobeb6dc72017-12-14 16:03:03 +0200906 out << " " << hashFunctionNameIfNeeded(node->getFunction());
Olli Etuaho16c745a2017-01-16 17:02:27 +0000907
908 out << "(";
Olli Etuahod4bd9632018-03-08 16:32:44 +0200909 writeFunctionParameters(node->getFunction());
Olli Etuaho16c745a2017-01-16 17:02:27 +0000910 out << ")";
Olli Etuaho16c745a2017-01-16 17:02:27 +0000911}
912
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700913bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000914{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500915 bool visitChildren = true;
916 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000917 switch (node->getOp())
918 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800919 case EOpCallFunctionInAST:
920 case EOpCallInternalRawFunction:
921 case EOpCallBuiltInFunction:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500922 // Function call.
923 if (visit == PreVisit)
Olli Etuahoec9232b2017-03-27 17:01:37 +0300924 {
925 if (node->getOp() == EOpCallBuiltInFunction)
926 {
Olli Etuahobed35d72017-12-20 16:36:26 +0200927 out << translateTextureFunction(node->getFunction()->name());
Olli Etuahoec9232b2017-03-27 17:01:37 +0300928 }
929 else
930 {
Olli Etuaho1bb85282017-12-14 13:39:53 +0200931 out << hashFunctionNameIfNeeded(node->getFunction());
Olli Etuahoec9232b2017-03-27 17:01:37 +0300932 }
933 out << "(";
934 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500935 else if (visit == InVisit)
936 out << ", ";
937 else
938 out << ")";
939 break;
Olli Etuaho8fab3202017-05-08 18:22:22 +0300940 case EOpConstruct:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500941 writeConstructorTriplet(visit, node->getType());
942 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200943
Olli Etuahoe1805592017-01-02 16:41:20 +0000944 case EOpEqualComponentWise:
945 case EOpNotEqualComponentWise:
946 case EOpLessThanComponentWise:
947 case EOpGreaterThanComponentWise:
948 case EOpLessThanEqualComponentWise:
949 case EOpGreaterThanEqualComponentWise:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500950 case EOpMod:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500951 case EOpModf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500952 case EOpPow:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500953 case EOpAtan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500954 case EOpMin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500955 case EOpMax:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500956 case EOpClamp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500957 case EOpMix:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500958 case EOpStep:
Olli Etuahof7f0b8c2018-02-21 20:02:23 +0200959 case EOpSmoothstep:
Olli Etuaho74da73f2017-02-01 15:37:48 +0000960 case EOpFrexp:
961 case EOpLdexp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500962 case EOpDistance:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500963 case EOpDot:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500964 case EOpCross:
Jamie Madille72595b2017-06-06 15:12:26 -0400965 case EOpFaceforward:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500966 case EOpReflect:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500967 case EOpRefract:
Olli Etuahoe1805592017-01-02 16:41:20 +0000968 case EOpMulMatrixComponentWise:
969 case EOpOuterProduct:
Olli Etuaho9250cb22017-01-21 10:51:27 +0000970 case EOpBitfieldExtract:
971 case EOpBitfieldInsert:
972 case EOpUaddCarry:
973 case EOpUsubBorrow:
974 case EOpUmulExtended:
975 case EOpImulExtended:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300976 case EOpBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300977 case EOpMemoryBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300978 case EOpMemoryBarrierAtomicCounter:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300979 case EOpMemoryBarrierBuffer:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300980 case EOpMemoryBarrierImage:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300981 case EOpMemoryBarrierShared:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300982 case EOpGroupMemoryBarrier:
Jiawei Shaod27f5c82017-08-23 09:38:08 +0800983 case EOpEmitVertex:
984 case EOpEndPrimitive:
Olli Etuahod68924e2017-01-02 17:34:40 +0000985 writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300986 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500987 default:
988 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000989 }
zmo@google.com5601ea02011-06-10 18:23:25 +0000990 return visitChildren;
991}
992
Olli Etuaho13389b62016-10-16 11:48:18 +0100993bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
994{
995 TInfoSinkBase &out = objSink();
996
997 // Variable declaration.
998 if (visit == PreVisit)
999 {
1000 const TIntermSequence &sequence = *(node->getSequence());
Jamie Madill2a9e1072017-09-22 11:31:57 -04001001 TIntermTyped *variable = sequence.front()->getAsTyped();
1002 writeLayoutQualifier(variable);
Jamie Madillc90d4d32018-04-17 13:11:15 -04001003 TIntermSymbol *symbolNode = variable->getAsSymbolNode();
1004 writeVariableType(variable->getType(), symbolNode ? &symbolNode->variable() : nullptr);
Olli Etuaho39f74df2017-11-20 16:09:57 +02001005 if (variable->getAsSymbolNode() == nullptr ||
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001006 variable->getAsSymbolNode()->variable().symbolType() != SymbolType::Empty)
Olli Etuaho39f74df2017-11-20 16:09:57 +02001007 {
1008 out << " ";
1009 }
1010 mDeclaringVariable = true;
Olli Etuaho13389b62016-10-16 11:48:18 +01001011 }
1012 else if (visit == InVisit)
1013 {
Olli Etuaho39f74df2017-11-20 16:09:57 +02001014 UNREACHABLE();
Olli Etuaho13389b62016-10-16 11:48:18 +01001015 }
1016 else
1017 {
Olli Etuaho39f74df2017-11-20 16:09:57 +02001018 mDeclaringVariable = false;
Olli Etuaho13389b62016-10-16 11:48:18 +01001019 }
1020 return true;
1021}
1022
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001023bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001024{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001025 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001026
zmo@google.com5601ea02011-06-10 18:23:25 +00001027 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001028
zmo@google.com5601ea02011-06-10 18:23:25 +00001029 if (loopType == ELoopFor) // for loop
1030 {
Corentin Wallez1b896c62016-11-16 13:10:44 -05001031 out << "for (";
1032 if (node->getInit())
1033 node->getInit()->traverse(this);
1034 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001035
Corentin Wallez1b896c62016-11-16 13:10:44 -05001036 if (node->getCondition())
1037 node->getCondition()->traverse(this);
1038 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001039
Corentin Wallez1b896c62016-11-16 13:10:44 -05001040 if (node->getExpression())
1041 node->getExpression()->traverse(this);
1042 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001043
Corentin Wallez1b896c62016-11-16 13:10:44 -05001044 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001045 }
1046 else if (loopType == ELoopWhile) // while loop
1047 {
1048 out << "while (";
Yunchao He4f285442017-04-21 12:15:49 +08001049 ASSERT(node->getCondition() != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +00001050 node->getCondition()->traverse(this);
1051 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001052
1053 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001054 }
1055 else // do-while loop
1056 {
1057 ASSERT(loopType == ELoopDoWhile);
1058 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001059
zmo@google.com5601ea02011-06-10 18:23:25 +00001060 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001061
zmo@google.com5601ea02011-06-10 18:23:25 +00001062 out << "while (";
Yunchao He4f285442017-04-21 12:15:49 +08001063 ASSERT(node->getCondition() != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +00001064 node->getCondition()->traverse(this);
1065 out << ");\n";
1066 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001067
zmo@google.com5601ea02011-06-10 18:23:25 +00001068 // No need to visit children. They have been already processed in
1069 // this function.
1070 return false;
1071}
1072
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001073bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001074{
1075 switch (node->getFlowOp())
1076 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001077 case EOpKill:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001078 writeTriplet(visit, "discard", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001079 break;
1080 case EOpBreak:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001081 writeTriplet(visit, "break", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001082 break;
1083 case EOpContinue:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001084 writeTriplet(visit, "continue", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001085 break;
1086 case EOpReturn:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001087 writeTriplet(visit, "return ", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001088 break;
1089 default:
1090 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001091 }
1092
1093 return true;
1094}
1095
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001096void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001097{
zmo@google.com5601ea02011-06-10 18:23:25 +00001098 TInfoSinkBase &out = objSink();
Yunchao He4f285442017-04-21 12:15:49 +08001099 if (node != nullptr)
zmo@google.com5601ea02011-06-10 18:23:25 +00001100 {
1101 node->traverse(this);
1102 // Single statements not part of a sequence need to be terminated
1103 // with semi-colon.
1104 if (isSingleStatement(node))
1105 out << ";\n";
1106 }
1107 else
1108 {
1109 out << "{\n}\n"; // Empty code block.
1110 }
1111}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001112
Olli Etuahofbb1c792018-01-19 16:26:59 +02001113ImmutableString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001114{
Jamie Madill6276b922017-09-25 02:35:57 -04001115 return GetTypeName(type, mHashFunction, &mNameMap);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001116}
1117
Olli Etuahofbb1c792018-01-19 16:26:59 +02001118ImmutableString TOutputGLSLBase::hashName(const TSymbol *symbol)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001119{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001120 return HashName(symbol, mHashFunction, &mNameMap);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001121}
1122
Olli Etuahofbb1c792018-01-19 16:26:59 +02001123ImmutableString TOutputGLSLBase::hashFieldName(const TSymbol *containingStruct,
1124 const ImmutableString &fieldName)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001125{
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001126 if (containingStruct->symbolType() == SymbolType::UserDefined ||
1127 containingStruct->symbolType() == SymbolType::Empty)
Olli Etuaho09b04a22016-12-15 13:30:26 +00001128 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001129 return HashName(fieldName, mHashFunction, &mNameMap);
Olli Etuaho09b04a22016-12-15 13:30:26 +00001130 }
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001131 else
1132 {
1133 return fieldName;
1134 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001135}
1136
Olli Etuahofbb1c792018-01-19 16:26:59 +02001137ImmutableString TOutputGLSLBase::hashFunctionNameIfNeeded(const TFunction *func)
Olli Etuaho1bb85282017-12-14 13:39:53 +02001138{
1139 if (func->isMain())
1140 {
Olli Etuahobed35d72017-12-20 16:36:26 +02001141 return func->name();
Olli Etuaho1bb85282017-12-14 13:39:53 +02001142 }
1143 else
1144 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001145 return hashName(func);
Olli Etuaho1bb85282017-12-14 13:39:53 +02001146 }
1147}
1148
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001149bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001150{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001151 ASSERT(structure);
Olli Etuaho9d4d7f02017-12-07 17:11:41 +01001152 if (structure->symbolType() == SymbolType::Empty)
Zhenyao Mo904a9162014-05-09 14:07:45 -07001153 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001154 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001155 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001156
Olli Etuaho97fa8552017-11-28 16:28:42 +02001157 return (mDeclaredStructs.count(structure->uniqueId().get()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001158}
1159
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001160void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001161{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001162 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001163
Olli Etuahobed35d72017-12-20 16:36:26 +02001164 out << "struct ";
1165
1166 if (structure->symbolType() != SymbolType::Empty)
1167 {
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001168 out << hashName(structure) << " ";
Olli Etuahobed35d72017-12-20 16:36:26 +02001169 }
1170 out << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001171 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001172 for (size_t i = 0; i < fields.size(); ++i)
1173 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001174 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001175 if (writeVariablePrecision(field->type()->getPrecision()))
1176 out << " ";
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001177 out << getTypeName(*field->type()) << " " << hashFieldName(structure, field->name());
Jamie Madill98493dd2013-07-08 14:39:03 -04001178 if (field->type()->isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001179 out << ArrayString(*field->type());
Jamie Madill98493dd2013-07-08 14:39:03 -04001180 out << ";\n";
1181 }
1182 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001183}
Jamie Madill98493dd2013-07-08 14:39:03 -04001184
Geoff Langbdcc54a2015-09-02 13:09:48 -04001185void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1186{
1187 TInfoSinkBase &out = objSink();
1188
1189 out << "layout(";
1190
1191 switch (interfaceBlock->blockStorage())
1192 {
1193 case EbsUnspecified:
1194 case EbsShared:
1195 // Default block storage is shared.
1196 out << "shared";
1197 break;
1198
1199 case EbsPacked:
1200 out << "packed";
1201 break;
1202
1203 case EbsStd140:
1204 out << "std140";
1205 break;
1206
Qin Jiajiaca68d982017-09-18 16:41:56 +08001207 case EbsStd430:
1208 out << "std430";
1209 break;
1210
Geoff Langbdcc54a2015-09-02 13:09:48 -04001211 default:
1212 UNREACHABLE();
1213 break;
1214 }
1215
Jiajia Qinfeb2c632017-12-08 17:59:19 +08001216 if (interfaceBlock->blockBinding() >= 0)
Jiajia Qin729b2c62017-08-14 09:36:11 +08001217 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08001218 out << ", ";
Olli Etuaho3de27032017-11-30 12:16:47 +02001219 out << "binding = " << interfaceBlock->blockBinding();
Geoff Langbdcc54a2015-09-02 13:09:48 -04001220 }
1221
1222 out << ") ";
1223}
1224
1225void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1226{
1227 TInfoSinkBase &out = objSink();
1228
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001229 out << hashName(interfaceBlock) << "{\n";
Geoff Langbdcc54a2015-09-02 13:09:48 -04001230 const TFieldList &fields = interfaceBlock->fields();
Olli Etuaho3de27032017-11-30 12:16:47 +02001231 for (const TField *field : fields)
Geoff Langbdcc54a2015-09-02 13:09:48 -04001232 {
Olli Etuaho3de27032017-11-30 12:16:47 +02001233 if (field->type()->isMatrix() || field->type()->isStructureContainingMatrices())
1234 {
1235 out << "layout(";
1236 switch (field->type()->getLayoutQualifier().matrixPacking)
1237 {
1238 case EmpUnspecified:
1239 case EmpColumnMajor:
1240 // Default matrix packing is column major.
1241 out << "column_major";
1242 break;
1243
1244 case EmpRowMajor:
1245 out << "row_major";
1246 break;
1247
1248 default:
1249 UNREACHABLE();
1250 break;
1251 }
1252 out << ") ";
1253 }
1254
Geoff Langbdcc54a2015-09-02 13:09:48 -04001255 if (writeVariablePrecision(field->type()->getPrecision()))
1256 out << " ";
Olli Etuaho8b5e8fd2017-12-15 14:59:15 +02001257 out << getTypeName(*field->type()) << " " << hashFieldName(interfaceBlock, field->name());
Geoff Langbdcc54a2015-09-02 13:09:48 -04001258 if (field->type()->isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001259 out << ArrayString(*field->type());
Geoff Langbdcc54a2015-09-02 13:09:48 -04001260 out << ";\n";
1261 }
1262 out << "}";
1263}
Jamie Madill45bcc782016-11-07 13:58:48 -05001264
Shaob5cc1192017-07-06 10:47:20 +08001265void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out,
1266 sh::TLayoutPrimitiveType inputPrimitive,
1267 int invocations,
1268 sh::TLayoutPrimitiveType outputPrimitive,
1269 int maxVertices)
1270{
1271 // Omit 'invocations = 1'
1272 if (inputPrimitive != EptUndefined || invocations > 1)
1273 {
1274 out << "layout (";
1275
1276 if (inputPrimitive != EptUndefined)
1277 {
1278 out << getGeometryShaderPrimitiveTypeString(inputPrimitive);
1279 }
1280
1281 if (invocations > 1)
1282 {
1283 if (inputPrimitive != EptUndefined)
1284 {
1285 out << ", ";
1286 }
1287 out << "invocations = " << invocations;
1288 }
1289 out << ") in;\n";
1290 }
1291
1292 if (outputPrimitive != EptUndefined || maxVertices != -1)
1293 {
1294 out << "layout (";
1295
1296 if (outputPrimitive != EptUndefined)
1297 {
1298 out << getGeometryShaderPrimitiveTypeString(outputPrimitive);
1299 }
1300
1301 if (maxVertices != -1)
1302 {
1303 if (outputPrimitive != EptUndefined)
1304 {
1305 out << ", ";
1306 }
1307 out << "max_vertices = " << maxVertices;
1308 }
1309 out << ") out;\n";
1310 }
1311}
1312
Jamie Madill2a9e1072017-09-22 11:31:57 -04001313// If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
1314// variables with specified layout qualifiers are copied. Additional checks are needed against the
1315// type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
1316// TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
1317// NeedsToWriteLayoutQualifier.
1318bool NeedsToWriteLayoutQualifier(const TType &type)
1319{
1320 if (type.getBasicType() == EbtInterfaceBlock)
1321 {
1322 return false;
1323 }
1324
1325 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
1326
1327 if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn ||
1328 IsVarying(type.getQualifier())) &&
1329 layoutQualifier.location >= 0)
1330 {
1331 return true;
1332 }
1333
1334 if (type.getQualifier() == EvqFragmentOut && layoutQualifier.yuv == true)
1335 {
1336 return true;
1337 }
1338
1339 if (IsOpaqueType(type.getBasicType()) && layoutQualifier.binding != -1)
1340 {
1341 return true;
1342 }
1343
1344 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
1345 {
1346 return true;
1347 }
1348 return false;
1349}
1350
Jamie Madill45bcc782016-11-07 13:58:48 -05001351} // namespace sh