blob: 9d029191e13cd90284aceb68446d4eb518fbef59 [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
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800217const char *TOutputGLSLBase::mapQualifierToString(TQualifier qualifier)
218{
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
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700253void TOutputGLSLBase::writeVariableType(const TType &type)
254{
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 {
263 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
264 declareInterfaceBlockLayout(interfaceBlock);
265 }
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400266 if (qualifier != EvqTemporary && qualifier != EvqGlobal)
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400267 {
Zhenyao Mob7bf7422016-11-08 14:44:05 -0800268 const char *qualifierString = mapQualifierToString(qualifier);
269 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 {
320 TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
321 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
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700331void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence &args)
zmo@google.com5601ea02011-06-10 18:23:25 +0000332{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700333 TInfoSinkBase &out = objSink();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500334 for (TIntermSequence::const_iterator iter = args.begin(); iter != args.end(); ++iter)
zmo@google.com5601ea02011-06-10 18:23:25 +0000335 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700336 const TIntermSymbol *arg = (*iter)->getAsSymbolNode();
Yunchao He4f285442017-04-21 12:15:49 +0800337 ASSERT(arg != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +0000338
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700339 const TType &type = arg->getType();
zmo@google.com189be2f2011-06-16 18:28:53 +0000340 writeVariableType(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000341
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000342 if (!arg->getName().getString().empty())
343 out << " " << hashName(arg->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000344 if (type.isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300345 out << ArrayString(type);
zmo@google.com5601ea02011-06-10 18:23:25 +0000346
347 // Put a comma if this is not the last argument.
348 if (iter != args.end() - 1)
349 out << ", ";
350 }
351}
352
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500353const TConstantUnion *TOutputGLSLBase::writeConstantUnion(const TType &type,
354 const TConstantUnion *pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000355{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700356 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000357
358 if (type.getBasicType() == EbtStruct)
359 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700360 const TStructure *structure = type.getStruct();
Olli Etuaho0982a2b2016-11-01 15:13:46 +0000361 out << hashName(TName(structure->name())) << "(";
Jamie Madill98493dd2013-07-08 14:39:03 -0400362
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700363 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -0400364 for (size_t i = 0; i < fields.size(); ++i)
zmo@google.com5601ea02011-06-10 18:23:25 +0000365 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700366 const TType *fieldType = fields[i]->type();
Yunchao He4f285442017-04-21 12:15:49 +0800367 ASSERT(fieldType != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +0000368 pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700369 if (i != fields.size() - 1)
370 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000371 }
372 out << ")";
373 }
374 else
375 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500376 size_t size = type.getObjectSize();
zmo@google.com5601ea02011-06-10 18:23:25 +0000377 bool writeType = size > 1;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700378 if (writeType)
379 out << getTypeName(type) << "(";
Jamie Madill94bf7f22013-07-08 13:31:15 -0400380 for (size_t i = 0; i < size; ++i, ++pConstUnion)
zmo@google.com5601ea02011-06-10 18:23:25 +0000381 {
382 switch (pConstUnion->getType())
383 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500384 case EbtFloat:
385 writeFloat(out, pConstUnion->getFConst());
386 break;
387 case EbtInt:
388 out << pConstUnion->getIConst();
389 break;
390 case EbtUInt:
391 out << pConstUnion->getUConst() << "u";
392 break;
393 case EbtBool:
394 out << pConstUnion->getBConst();
395 break;
Andrei Volykhina5527072017-03-22 16:46:30 +0300396 case EbtYuvCscStandardEXT:
397 out << getYuvCscStandardEXTString(pConstUnion->getYuvCscStandardEXTConst());
398 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500399 default:
400 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000401 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700402 if (i != size - 1)
403 out << ", ";
zmo@google.com5601ea02011-06-10 18:23:25 +0000404 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700405 if (writeType)
406 out << ")";
zmo@google.com5601ea02011-06-10 18:23:25 +0000407 }
408 return pConstUnion;
409}
410
Olli Etuahoe92507b2016-07-04 11:20:10 +0300411void TOutputGLSLBase::writeConstructorTriplet(Visit visit, const TType &type)
Olli Etuahof40319e2015-03-10 14:33:00 +0200412{
413 TInfoSinkBase &out = objSink();
414 if (visit == PreVisit)
415 {
416 if (type.isArray())
417 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300418 out << getTypeName(type);
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300419 out << ArrayString(type);
Olli Etuahof40319e2015-03-10 14:33:00 +0200420 out << "(";
421 }
422 else
423 {
Olli Etuahoe92507b2016-07-04 11:20:10 +0300424 out << getTypeName(type) << "(";
Olli Etuahof40319e2015-03-10 14:33:00 +0200425 }
426 }
427 else
428 {
429 writeTriplet(visit, nullptr, ", ", ")");
430 }
431}
432
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700433void TOutputGLSLBase::visitSymbol(TIntermSymbol *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000434{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700435 TInfoSinkBase &out = objSink();
Corentin Wallez1b896c62016-11-16 13:10:44 -0500436 out << hashVariableName(node->getName());
zmo@google.com5601ea02011-06-10 18:23:25 +0000437
Olli Etuaho39f74df2017-11-20 16:09:57 +0200438 if (mDeclaringVariable && node->getType().isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300439 out << ArrayString(node->getType());
zmo@google.com5601ea02011-06-10 18:23:25 +0000440}
441
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700442void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000443{
444 writeConstantUnion(node->getType(), node->getUnionArrayPointer());
445}
446
Olli Etuahob6fa0432016-09-28 16:28:05 +0100447bool TOutputGLSLBase::visitSwizzle(Visit visit, TIntermSwizzle *node)
448{
449 TInfoSinkBase &out = objSink();
450 if (visit == PostVisit)
451 {
452 out << ".";
453 node->writeOffsetsAsXYZW(&out);
454 }
455 return true;
456}
457
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700458bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000459{
460 bool visitChildren = true;
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700461 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000462 switch (node->getOp())
463 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100464 case EOpComma:
465 writeTriplet(visit, "(", ", ", ")");
466 break;
467 case EOpInitialize:
zmo@google.com5601ea02011-06-10 18:23:25 +0000468 if (visit == InVisit)
469 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100470 out << " = ";
471 // RHS of initialize is not being declared.
Olli Etuaho39f74df2017-11-20 16:09:57 +0200472 mDeclaringVariable = false;
zmo@google.com5601ea02011-06-10 18:23:25 +0000473 }
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100474 break;
475 case EOpAssign:
476 writeTriplet(visit, "(", " = ", ")");
477 break;
478 case EOpAddAssign:
479 writeTriplet(visit, "(", " += ", ")");
480 break;
481 case EOpSubAssign:
482 writeTriplet(visit, "(", " -= ", ")");
483 break;
484 case EOpDivAssign:
485 writeTriplet(visit, "(", " /= ", ")");
486 break;
487 case EOpIModAssign:
488 writeTriplet(visit, "(", " %= ", ")");
489 break;
490 // Notice the fall-through.
491 case EOpMulAssign:
492 case EOpVectorTimesMatrixAssign:
493 case EOpVectorTimesScalarAssign:
494 case EOpMatrixTimesScalarAssign:
495 case EOpMatrixTimesMatrixAssign:
496 writeTriplet(visit, "(", " *= ", ")");
497 break;
498 case EOpBitShiftLeftAssign:
499 writeTriplet(visit, "(", " <<= ", ")");
500 break;
501 case EOpBitShiftRightAssign:
502 writeTriplet(visit, "(", " >>= ", ")");
503 break;
504 case EOpBitwiseAndAssign:
505 writeTriplet(visit, "(", " &= ", ")");
506 break;
507 case EOpBitwiseXorAssign:
508 writeTriplet(visit, "(", " ^= ", ")");
509 break;
510 case EOpBitwiseOrAssign:
511 writeTriplet(visit, "(", " |= ", ")");
512 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000513
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100514 case EOpIndexDirect:
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800515 writeTriplet(visit, nullptr, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100516 break;
517 case EOpIndexIndirect:
518 if (node->getAddIndexClamp())
519 {
520 if (visit == InVisit)
521 {
522 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
523 out << "[int(clamp(float(";
524 else
525 out << "[webgl_int_clamp(";
526 }
527 else if (visit == PostVisit)
528 {
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100529 TIntermTyped *left = node->getLeft();
530 TType leftType = left->getType();
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700531
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100532 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
Olli Etuahoebee5b32017-11-23 12:56:32 +0200533 out << "), 0.0, float(";
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100534 else
Olli Etuahoebee5b32017-11-23 12:56:32 +0200535 out << ", 0, ";
536
537 if (leftType.isUnsizedArray())
538 {
539 // For runtime-sized arrays in ESSL 3.10 we need to call the length method
540 // to get the length to clamp against. See ESSL 3.10 section 4.1.9. Note
541 // that a runtime-sized array expression is guaranteed not to have side
542 // effects, so it's fine to add the expression to the output twice.
543 ASSERT(mShaderVersion >= 310);
544 ASSERT(!left->hasSideEffects());
545 left->traverse(this);
546 out << ".length() - 1";
547 }
548 else
549 {
550 int maxSize;
551 if (leftType.isArray())
552 {
553 maxSize = static_cast<int>(leftType.getOutermostArraySize()) - 1;
554 }
555 else
556 {
557 maxSize = leftType.getNominalSize() - 1;
558 }
559 out << maxSize;
560 }
561 if (mClampingStrategy == SH_CLAMP_WITH_CLAMP_INTRINSIC)
562 out << ")))]";
563 else
564 out << ")]";
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100565 }
566 }
567 else
568 {
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800569 writeTriplet(visit, nullptr, "[", "]");
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100570 }
571 break;
572 case EOpIndexDirectStruct:
573 if (visit == InVisit)
574 {
575 // Here we are writing out "foo.bar", where "foo" is struct
576 // and "bar" is field. In AST, it is represented as a binary
577 // node, where left child represents "foo" and right child "bar".
578 // The node itself represents ".". The struct field "bar" is
579 // actually stored as an index into TStructure::fields.
580 out << ".";
581 const TStructure *structure = node->getLeft()->getType().getStruct();
582 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
583 const TField *field = structure->fields()[index->getIConst(0)];
584
585 TString fieldName = field->name();
Olli Etuaho9d4d7f02017-12-07 17:11:41 +0100586 if (structure->symbolType() == SymbolType::UserDefined ||
587 structure->symbolType() == SymbolType::Empty)
Olli Etuahoae4dbf32017-12-08 20:49:00 +0100588 fieldName = hashName(TName(&fieldName));
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100589
590 out << fieldName;
591 visitChildren = false;
592 }
593 break;
594 case EOpIndexDirectInterfaceBlock:
595 if (visit == InVisit)
596 {
597 out << ".";
598 const TInterfaceBlock *interfaceBlock =
599 node->getLeft()->getType().getInterfaceBlock();
600 const TIntermConstantUnion *index = node->getRight()->getAsConstantUnion();
601 const TField *field = interfaceBlock->fields()[index->getIConst(0)];
602
603 TString fieldName = field->name();
Olli Etuaho9d4d7f02017-12-07 17:11:41 +0100604 ASSERT(interfaceBlock->symbolType() != SymbolType::Empty);
605 if (interfaceBlock->symbolType() == SymbolType::UserDefined)
Jiawei Shao65c56dd2017-10-13 16:18:57 +0800606 {
Olli Etuahoae4dbf32017-12-08 20:49:00 +0100607 fieldName = hashName(TName(&fieldName));
Jiawei Shao65c56dd2017-10-13 16:18:57 +0800608 }
609 else
610 {
Olli Etuahoae4dbf32017-12-08 20:49:00 +0100611 ASSERT(*interfaceBlock->name() == "gl_PerVertex");
Jiawei Shao65c56dd2017-10-13 16:18:57 +0800612 }
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700613
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100614 out << fieldName;
615 visitChildren = false;
616 }
617 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400618
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100619 case EOpAdd:
620 writeTriplet(visit, "(", " + ", ")");
621 break;
622 case EOpSub:
623 writeTriplet(visit, "(", " - ", ")");
624 break;
625 case EOpMul:
626 writeTriplet(visit, "(", " * ", ")");
627 break;
628 case EOpDiv:
629 writeTriplet(visit, "(", " / ", ")");
630 break;
631 case EOpIMod:
632 writeTriplet(visit, "(", " % ", ")");
633 break;
634 case EOpBitShiftLeft:
635 writeTriplet(visit, "(", " << ", ")");
636 break;
637 case EOpBitShiftRight:
638 writeTriplet(visit, "(", " >> ", ")");
639 break;
640 case EOpBitwiseAnd:
641 writeTriplet(visit, "(", " & ", ")");
642 break;
643 case EOpBitwiseXor:
644 writeTriplet(visit, "(", " ^ ", ")");
645 break;
646 case EOpBitwiseOr:
647 writeTriplet(visit, "(", " | ", ")");
648 break;
Geoff Lang6e360422015-09-02 15:54:36 -0400649
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100650 case EOpEqual:
651 writeTriplet(visit, "(", " == ", ")");
652 break;
653 case EOpNotEqual:
654 writeTriplet(visit, "(", " != ", ")");
655 break;
656 case EOpLessThan:
657 writeTriplet(visit, "(", " < ", ")");
658 break;
659 case EOpGreaterThan:
660 writeTriplet(visit, "(", " > ", ")");
661 break;
662 case EOpLessThanEqual:
663 writeTriplet(visit, "(", " <= ", ")");
664 break;
665 case EOpGreaterThanEqual:
666 writeTriplet(visit, "(", " >= ", ")");
667 break;
daniel@transgaming.com97b16d12013-02-01 03:20:42 +0000668
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100669 // Notice the fall-through.
670 case EOpVectorTimesScalar:
671 case EOpVectorTimesMatrix:
672 case EOpMatrixTimesVector:
673 case EOpMatrixTimesScalar:
674 case EOpMatrixTimesMatrix:
675 writeTriplet(visit, "(", " * ", ")");
676 break;
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200677
Olli Etuaho4db7ded2016-10-13 12:23:11 +0100678 case EOpLogicalOr:
679 writeTriplet(visit, "(", " || ", ")");
680 break;
681 case EOpLogicalXor:
682 writeTriplet(visit, "(", " ^^ ", ")");
683 break;
684 case EOpLogicalAnd:
685 writeTriplet(visit, "(", " && ", ")");
686 break;
687 default:
688 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000689 }
690
691 return visitChildren;
692}
693
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700694bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000695{
zmo@google.com32e97312011-08-24 01:03:11 +0000696 TString preString;
697 TString postString = ")";
698
zmo@google.com5601ea02011-06-10 18:23:25 +0000699 switch (node->getOp())
700 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500701 case EOpNegative:
702 preString = "(-";
703 break;
704 case EOpPositive:
705 preString = "(+";
706 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500707 case EOpLogicalNot:
708 preString = "(!";
709 break;
710 case EOpBitwiseNot:
711 preString = "(~";
712 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000713
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500714 case EOpPostIncrement:
715 preString = "(";
716 postString = "++)";
717 break;
718 case EOpPostDecrement:
719 preString = "(";
720 postString = "--)";
721 break;
722 case EOpPreIncrement:
723 preString = "(++";
724 break;
725 case EOpPreDecrement:
726 preString = "(--";
727 break;
Olli Etuahobb5a7e22017-08-30 13:03:12 +0300728 case EOpArrayLength:
729 preString = "((";
730 postString = ").length())";
731 break;
zmo@google.com5601ea02011-06-10 18:23:25 +0000732
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500733 case EOpRadians:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500734 case EOpDegrees:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500735 case EOpSin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500736 case EOpCos:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500737 case EOpTan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500738 case EOpAsin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500739 case EOpAcos:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500740 case EOpAtan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500741 case EOpSinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500742 case EOpCosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500743 case EOpTanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500744 case EOpAsinh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500745 case EOpAcosh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500746 case EOpAtanh:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500747 case EOpExp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500748 case EOpLog:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500749 case EOpExp2:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500750 case EOpLog2:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500751 case EOpSqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500752 case EOpInverseSqrt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500753 case EOpAbs:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500754 case EOpSign:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500755 case EOpFloor:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500756 case EOpTrunc:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500757 case EOpRound:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500758 case EOpRoundEven:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500759 case EOpCeil:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500760 case EOpFract:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500761 case EOpIsNan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500762 case EOpIsInf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500763 case EOpFloatBitsToInt:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500764 case EOpFloatBitsToUint:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500765 case EOpIntBitsToFloat:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500766 case EOpUintBitsToFloat:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500767 case EOpPackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500768 case EOpPackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500769 case EOpPackHalf2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500770 case EOpUnpackSnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500771 case EOpUnpackUnorm2x16:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500772 case EOpUnpackHalf2x16:
Olli Etuaho25aef452017-01-29 16:15:44 -0800773 case EOpPackUnorm4x8:
774 case EOpPackSnorm4x8:
775 case EOpUnpackUnorm4x8:
776 case EOpUnpackSnorm4x8:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500777 case EOpLength:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500778 case EOpNormalize:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500779 case EOpDFdx:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500780 case EOpDFdy:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500781 case EOpFwidth:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500782 case EOpTranspose:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500783 case EOpDeterminant:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500784 case EOpInverse:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500785 case EOpAny:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500786 case EOpAll:
Olli Etuahod68924e2017-01-02 17:34:40 +0000787 case EOpLogicalNotComponentWise:
Olli Etuaho9250cb22017-01-21 10:51:27 +0000788 case EOpBitfieldReverse:
789 case EOpBitCount:
790 case EOpFindLSB:
791 case EOpFindMSB:
Olli Etuahod68924e2017-01-02 17:34:40 +0000792 writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
793 return true;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500794 default:
795 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +0000796 }
797
Yunchao Hef81ce4a2017-04-24 10:49:17 +0800798 writeTriplet(visit, preString.c_str(), nullptr, postString.c_str());
zmo@google.com32e97312011-08-24 01:03:11 +0000799
zmo@google.com5601ea02011-06-10 18:23:25 +0000800 return true;
801}
802
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300803bool TOutputGLSLBase::visitTernary(Visit visit, TIntermTernary *node)
804{
805 TInfoSinkBase &out = objSink();
806 // Notice two brackets at the beginning and end. The outer ones
807 // encapsulate the whole ternary expression. This preserves the
808 // order of precedence when ternary expressions are used in a
809 // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
810 out << "((";
811 node->getCondition()->traverse(this);
812 out << ") ? (";
813 node->getTrueExpression()->traverse(this);
814 out << ") : (";
815 node->getFalseExpression()->traverse(this);
816 out << "))";
817 return false;
818}
819
Olli Etuaho57961272016-09-14 13:57:46 +0300820bool TOutputGLSLBase::visitIfElse(Visit visit, TIntermIfElse *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000821{
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700822 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000823
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300824 out << "if (";
825 node->getCondition()->traverse(this);
826 out << ")\n";
zmo@google.com5601ea02011-06-10 18:23:25 +0000827
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300828 visitCodeBlock(node->getTrueBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000829
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300830 if (node->getFalseBlock())
831 {
832 out << "else\n";
833 visitCodeBlock(node->getFalseBlock());
zmo@google.com5601ea02011-06-10 18:23:25 +0000834 }
835 return false;
836}
837
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200838bool TOutputGLSLBase::visitSwitch(Visit visit, TIntermSwitch *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200839{
Olli Etuaho923ecef2017-10-11 12:01:38 +0300840 ASSERT(node->getStatementList());
841 writeTriplet(visit, "switch (", ") ", nullptr);
842 // The curly braces get written when visiting the statementList aggregate
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200843 return true;
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200844}
845
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200846bool TOutputGLSLBase::visitCase(Visit visit, TIntermCase *node)
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200847{
Olli Etuaho01cd8af2015-02-20 10:39:20 +0200848 if (node->hasCondition())
849 {
850 writeTriplet(visit, "case (", nullptr, "):\n");
851 return true;
852 }
853 else
854 {
855 TInfoSinkBase &out = objSink();
856 out << "default:\n";
857 return false;
858 }
Olli Etuaho3c1dfb52015-02-20 11:34:03 +0200859}
860
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100861bool TOutputGLSLBase::visitBlock(Visit visit, TIntermBlock *node)
862{
863 TInfoSinkBase &out = objSink();
864 // Scope the blocks except when at the global scope.
865 if (mDepth > 0)
866 {
867 out << "{\n";
868 }
869
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100870 for (TIntermSequence::const_iterator iter = node->getSequence()->begin();
871 iter != node->getSequence()->end(); ++iter)
872 {
873 TIntermNode *curNode = *iter;
874 ASSERT(curNode != nullptr);
875 curNode->traverse(this);
876
877 if (isSingleStatement(curNode))
878 out << ";\n";
879 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100880
881 // Scope the blocks except when at the global scope.
882 if (mDepth > 0)
883 {
884 out << "}\n";
885 }
886 return false;
887}
888
Olli Etuaho336b1472016-10-05 16:37:55 +0100889bool TOutputGLSLBase::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
890{
Olli Etuaho8ad9e752017-01-16 19:55:20 +0000891 TIntermFunctionPrototype *prototype = node->getFunctionPrototype();
892 prototype->traverse(this);
Olli Etuaho336b1472016-10-05 16:37:55 +0100893 visitCodeBlock(node->getBody());
Olli Etuaho336b1472016-10-05 16:37:55 +0100894
895 // Fully processed; no need to visit children.
896 return false;
897}
898
Olli Etuahobf4e1b72016-12-09 11:30:15 +0000899bool TOutputGLSLBase::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
900{
901 TInfoSinkBase &out = objSink();
902 ASSERT(visit == PreVisit);
903 const TIntermSymbol *symbol = node->getSymbol();
904 out << "invariant " << hashVariableName(symbol->getName());
905 return false;
906}
907
Olli Etuaho16c745a2017-01-16 17:02:27 +0000908bool TOutputGLSLBase::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
909{
910 TInfoSinkBase &out = objSink();
911 ASSERT(visit == PreVisit);
912
913 const TType &type = node->getType();
914 writeVariableType(type);
915 if (type.isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300916 out << ArrayString(type);
Olli Etuaho16c745a2017-01-16 17:02:27 +0000917
Olli Etuahoec9232b2017-03-27 17:01:37 +0300918 out << " " << hashFunctionNameIfNeeded(*node->getFunctionSymbolInfo());
Olli Etuaho16c745a2017-01-16 17:02:27 +0000919
920 out << "(";
921 writeFunctionParameters(*(node->getSequence()));
922 out << ")";
923
924 return false;
925}
926
Zhenyao Mo9eedea02014-05-12 16:02:35 -0700927bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate *node)
zmo@google.com5601ea02011-06-10 18:23:25 +0000928{
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500929 bool visitChildren = true;
930 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +0000931 switch (node->getOp())
932 {
Olli Etuaho1ecd14b2017-01-26 13:54:15 -0800933 case EOpCallFunctionInAST:
934 case EOpCallInternalRawFunction:
935 case EOpCallBuiltInFunction:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500936 // Function call.
937 if (visit == PreVisit)
Olli Etuahoec9232b2017-03-27 17:01:37 +0300938 {
939 if (node->getOp() == EOpCallBuiltInFunction)
940 {
941 out << translateTextureFunction(node->getFunctionSymbolInfo()->getName());
942 }
943 else
944 {
945 out << hashFunctionNameIfNeeded(*node->getFunctionSymbolInfo());
946 }
947 out << "(";
948 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500949 else if (visit == InVisit)
950 out << ", ";
951 else
952 out << ")";
953 break;
Olli Etuaho8fab3202017-05-08 18:22:22 +0300954 case EOpConstruct:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500955 writeConstructorTriplet(visit, node->getType());
956 break;
Olli Etuahoe39706d2014-12-30 16:40:36 +0200957
Olli Etuahoe1805592017-01-02 16:41:20 +0000958 case EOpEqualComponentWise:
959 case EOpNotEqualComponentWise:
960 case EOpLessThanComponentWise:
961 case EOpGreaterThanComponentWise:
962 case EOpLessThanEqualComponentWise:
963 case EOpGreaterThanEqualComponentWise:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500964 case EOpMod:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500965 case EOpModf:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500966 case EOpPow:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500967 case EOpAtan:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500968 case EOpMin:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500969 case EOpMax:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500970 case EOpClamp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500971 case EOpMix:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500972 case EOpStep:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500973 case EOpSmoothStep:
Olli Etuaho74da73f2017-02-01 15:37:48 +0000974 case EOpFrexp:
975 case EOpLdexp:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500976 case EOpDistance:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500977 case EOpDot:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500978 case EOpCross:
Jamie Madille72595b2017-06-06 15:12:26 -0400979 case EOpFaceforward:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500980 case EOpReflect:
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500981 case EOpRefract:
Olli Etuahoe1805592017-01-02 16:41:20 +0000982 case EOpMulMatrixComponentWise:
983 case EOpOuterProduct:
Olli Etuaho9250cb22017-01-21 10:51:27 +0000984 case EOpBitfieldExtract:
985 case EOpBitfieldInsert:
986 case EOpUaddCarry:
987 case EOpUsubBorrow:
988 case EOpUmulExtended:
989 case EOpImulExtended:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300990 case EOpBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300991 case EOpMemoryBarrier:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300992 case EOpMemoryBarrierAtomicCounter:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300993 case EOpMemoryBarrierBuffer:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300994 case EOpMemoryBarrierImage:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300995 case EOpMemoryBarrierShared:
Martin Radevd7c5b0a2016-07-27 14:04:43 +0300996 case EOpGroupMemoryBarrier:
Jiawei Shaod27f5c82017-08-23 09:38:08 +0800997 case EOpEmitVertex:
998 case EOpEndPrimitive:
Olli Etuahod68924e2017-01-02 17:34:40 +0000999 writeBuiltInFunctionTriplet(visit, node->getOp(), node->getUseEmulatedFunction());
Martin Radevd7c5b0a2016-07-27 14:04:43 +03001000 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001001 default:
1002 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001003 }
zmo@google.com5601ea02011-06-10 18:23:25 +00001004 return visitChildren;
1005}
1006
Olli Etuaho13389b62016-10-16 11:48:18 +01001007bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
1008{
1009 TInfoSinkBase &out = objSink();
1010
1011 // Variable declaration.
1012 if (visit == PreVisit)
1013 {
1014 const TIntermSequence &sequence = *(node->getSequence());
Jamie Madill2a9e1072017-09-22 11:31:57 -04001015 TIntermTyped *variable = sequence.front()->getAsTyped();
1016 writeLayoutQualifier(variable);
Olli Etuaho13389b62016-10-16 11:48:18 +01001017 writeVariableType(variable->getType());
Olli Etuaho39f74df2017-11-20 16:09:57 +02001018 if (variable->getAsSymbolNode() == nullptr ||
1019 !variable->getAsSymbolNode()->getSymbol().empty())
1020 {
1021 out << " ";
1022 }
1023 mDeclaringVariable = true;
Olli Etuaho13389b62016-10-16 11:48:18 +01001024 }
1025 else if (visit == InVisit)
1026 {
Olli Etuaho39f74df2017-11-20 16:09:57 +02001027 UNREACHABLE();
Olli Etuaho13389b62016-10-16 11:48:18 +01001028 }
1029 else
1030 {
Olli Etuaho39f74df2017-11-20 16:09:57 +02001031 mDeclaringVariable = false;
Olli Etuaho13389b62016-10-16 11:48:18 +01001032 }
1033 return true;
1034}
1035
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001036bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001037{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001038 TInfoSinkBase &out = objSink();
zmo@google.com5601ea02011-06-10 18:23:25 +00001039
zmo@google.com5601ea02011-06-10 18:23:25 +00001040 TLoopType loopType = node->getType();
Corentin Wallez7258e302015-09-22 10:40:24 -07001041
zmo@google.com5601ea02011-06-10 18:23:25 +00001042 if (loopType == ELoopFor) // for loop
1043 {
Corentin Wallez1b896c62016-11-16 13:10:44 -05001044 out << "for (";
1045 if (node->getInit())
1046 node->getInit()->traverse(this);
1047 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001048
Corentin Wallez1b896c62016-11-16 13:10:44 -05001049 if (node->getCondition())
1050 node->getCondition()->traverse(this);
1051 out << "; ";
zmo@google.com5601ea02011-06-10 18:23:25 +00001052
Corentin Wallez1b896c62016-11-16 13:10:44 -05001053 if (node->getExpression())
1054 node->getExpression()->traverse(this);
1055 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001056
Corentin Wallez1b896c62016-11-16 13:10:44 -05001057 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001058 }
1059 else if (loopType == ELoopWhile) // while loop
1060 {
1061 out << "while (";
Yunchao He4f285442017-04-21 12:15:49 +08001062 ASSERT(node->getCondition() != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +00001063 node->getCondition()->traverse(this);
1064 out << ")\n";
Corentin Wallez7258e302015-09-22 10:40:24 -07001065
1066 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001067 }
1068 else // do-while loop
1069 {
1070 ASSERT(loopType == ELoopDoWhile);
1071 out << "do\n";
zmo@google.com5601ea02011-06-10 18:23:25 +00001072
zmo@google.com5601ea02011-06-10 18:23:25 +00001073 visitCodeBlock(node->getBody());
zmo@google.com5601ea02011-06-10 18:23:25 +00001074
zmo@google.com5601ea02011-06-10 18:23:25 +00001075 out << "while (";
Yunchao He4f285442017-04-21 12:15:49 +08001076 ASSERT(node->getCondition() != nullptr);
zmo@google.com5601ea02011-06-10 18:23:25 +00001077 node->getCondition()->traverse(this);
1078 out << ");\n";
1079 }
Corentin Wallez7258e302015-09-22 10:40:24 -07001080
zmo@google.com5601ea02011-06-10 18:23:25 +00001081 // No need to visit children. They have been already processed in
1082 // this function.
1083 return false;
1084}
1085
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001086bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch *node)
zmo@google.com5601ea02011-06-10 18:23:25 +00001087{
1088 switch (node->getFlowOp())
1089 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001090 case EOpKill:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001091 writeTriplet(visit, "discard", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001092 break;
1093 case EOpBreak:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001094 writeTriplet(visit, "break", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001095 break;
1096 case EOpContinue:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001097 writeTriplet(visit, "continue", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001098 break;
1099 case EOpReturn:
Yunchao Hef81ce4a2017-04-24 10:49:17 +08001100 writeTriplet(visit, "return ", nullptr, nullptr);
Jamie Madilld7b1ab52016-12-12 14:42:19 -05001101 break;
1102 default:
1103 UNREACHABLE();
zmo@google.com5601ea02011-06-10 18:23:25 +00001104 }
1105
1106 return true;
1107}
1108
Olli Etuaho6d40bbd2016-09-30 13:49:38 +01001109void TOutputGLSLBase::visitCodeBlock(TIntermBlock *node)
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001110{
zmo@google.com5601ea02011-06-10 18:23:25 +00001111 TInfoSinkBase &out = objSink();
Yunchao He4f285442017-04-21 12:15:49 +08001112 if (node != nullptr)
zmo@google.com5601ea02011-06-10 18:23:25 +00001113 {
1114 node->traverse(this);
1115 // Single statements not part of a sequence need to be terminated
1116 // with semi-colon.
1117 if (isSingleStatement(node))
1118 out << ";\n";
1119 }
1120 else
1121 {
1122 out << "{\n}\n"; // Empty code block.
1123 }
1124}
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001125
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001126TString TOutputGLSLBase::getTypeName(const TType &type)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001127{
Jamie Madill6276b922017-09-25 02:35:57 -04001128 return GetTypeName(type, mHashFunction, &mNameMap);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001129}
1130
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001131TString TOutputGLSLBase::hashName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001132{
Olli Etuaho855d9642017-05-17 14:05:06 +03001133 return HashName(name, mHashFunction, &mNameMap);
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001134}
1135
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001136TString TOutputGLSLBase::hashVariableName(const TName &name)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001137{
Olli Etuaho855d9642017-05-17 14:05:06 +03001138 if (mSymbolTable->findBuiltIn(name.getString(), mShaderVersion) != nullptr ||
1139 name.getString().substr(0, 3) == "gl_")
Olli Etuaho09b04a22016-12-15 13:30:26 +00001140 {
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001141 return name.getString();
Olli Etuaho09b04a22016-12-15 13:30:26 +00001142 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001143 return hashName(name);
1144}
1145
Olli Etuahoec9232b2017-03-27 17:01:37 +03001146TString TOutputGLSLBase::hashFunctionNameIfNeeded(const TFunctionSymbolInfo &info)
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001147{
Olli Etuaho855d9642017-05-17 14:05:06 +03001148 if (info.isMain())
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001149 {
Olli Etuahoec9232b2017-03-27 17:01:37 +03001150 return info.getName();
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001151 }
Olli Etuaho59f9a642015-08-06 20:38:26 +03001152 else
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001153 {
Olli Etuahoec9232b2017-03-27 17:01:37 +03001154 return hashName(info.getNameObj());
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001155 }
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +00001156}
Jamie Madill98493dd2013-07-08 14:39:03 -04001157
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001158bool TOutputGLSLBase::structDeclared(const TStructure *structure) const
Jamie Madill98493dd2013-07-08 14:39:03 -04001159{
Zhenyao Mo904a9162014-05-09 14:07:45 -07001160 ASSERT(structure);
Olli Etuaho9d4d7f02017-12-07 17:11:41 +01001161 if (structure->symbolType() == SymbolType::Empty)
Zhenyao Mo904a9162014-05-09 14:07:45 -07001162 {
Jamie Madill01f85ac2014-06-06 11:55:04 -04001163 return false;
Zhenyao Mo904a9162014-05-09 14:07:45 -07001164 }
Jamie Madill01f85ac2014-06-06 11:55:04 -04001165
Olli Etuaho97fa8552017-11-28 16:28:42 +02001166 return (mDeclaredStructs.count(structure->uniqueId().get()) > 0);
Jamie Madill98493dd2013-07-08 14:39:03 -04001167}
1168
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001169void TOutputGLSLBase::declareStruct(const TStructure *structure)
Jamie Madill98493dd2013-07-08 14:39:03 -04001170{
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001171 TInfoSinkBase &out = objSink();
Jamie Madill98493dd2013-07-08 14:39:03 -04001172
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001173 out << "struct " << hashName(TName(structure->name())) << "{\n";
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001174 const TFieldList &fields = structure->fields();
Jamie Madill98493dd2013-07-08 14:39:03 -04001175 for (size_t i = 0; i < fields.size(); ++i)
1176 {
Zhenyao Mo9eedea02014-05-12 16:02:35 -07001177 const TField *field = fields[i];
Jamie Madill98493dd2013-07-08 14:39:03 -04001178 if (writeVariablePrecision(field->type()->getPrecision()))
1179 out << " ";
Olli Etuahoae4dbf32017-12-08 20:49:00 +01001180 out << getTypeName(*field->type()) << " " << hashName(TName(&field->name()));
Jamie Madill98493dd2013-07-08 14:39:03 -04001181 if (field->type()->isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001182 out << ArrayString(*field->type());
Jamie Madill98493dd2013-07-08 14:39:03 -04001183 out << ";\n";
1184 }
1185 out << "}";
Zhenyao Mo904a9162014-05-09 14:07:45 -07001186}
Jamie Madill98493dd2013-07-08 14:39:03 -04001187
Geoff Langbdcc54a2015-09-02 13:09:48 -04001188void TOutputGLSLBase::declareInterfaceBlockLayout(const TInterfaceBlock *interfaceBlock)
1189{
1190 TInfoSinkBase &out = objSink();
1191
1192 out << "layout(";
1193
1194 switch (interfaceBlock->blockStorage())
1195 {
1196 case EbsUnspecified:
1197 case EbsShared:
1198 // Default block storage is shared.
1199 out << "shared";
1200 break;
1201
1202 case EbsPacked:
1203 out << "packed";
1204 break;
1205
1206 case EbsStd140:
1207 out << "std140";
1208 break;
1209
Qin Jiajiaca68d982017-09-18 16:41:56 +08001210 case EbsStd430:
1211 out << "std430";
1212 break;
1213
Geoff Langbdcc54a2015-09-02 13:09:48 -04001214 default:
1215 UNREACHABLE();
1216 break;
1217 }
1218
Jiajia Qinfeb2c632017-12-08 17:59:19 +08001219 if (interfaceBlock->blockBinding() >= 0)
Jiajia Qin729b2c62017-08-14 09:36:11 +08001220 {
Jiajia Qin729b2c62017-08-14 09:36:11 +08001221 out << ", ";
Olli Etuaho3de27032017-11-30 12:16:47 +02001222 out << "binding = " << interfaceBlock->blockBinding();
Geoff Langbdcc54a2015-09-02 13:09:48 -04001223 }
1224
1225 out << ") ";
1226}
1227
1228void TOutputGLSLBase::declareInterfaceBlock(const TInterfaceBlock *interfaceBlock)
1229{
1230 TInfoSinkBase &out = objSink();
1231
Olli Etuaho0982a2b2016-11-01 15:13:46 +00001232 out << hashName(TName(interfaceBlock->name())) << "{\n";
Geoff Langbdcc54a2015-09-02 13:09:48 -04001233 const TFieldList &fields = interfaceBlock->fields();
Olli Etuaho3de27032017-11-30 12:16:47 +02001234 for (const TField *field : fields)
Geoff Langbdcc54a2015-09-02 13:09:48 -04001235 {
Olli Etuaho3de27032017-11-30 12:16:47 +02001236 if (field->type()->isMatrix() || field->type()->isStructureContainingMatrices())
1237 {
1238 out << "layout(";
1239 switch (field->type()->getLayoutQualifier().matrixPacking)
1240 {
1241 case EmpUnspecified:
1242 case EmpColumnMajor:
1243 // Default matrix packing is column major.
1244 out << "column_major";
1245 break;
1246
1247 case EmpRowMajor:
1248 out << "row_major";
1249 break;
1250
1251 default:
1252 UNREACHABLE();
1253 break;
1254 }
1255 out << ") ";
1256 }
1257
Geoff Langbdcc54a2015-09-02 13:09:48 -04001258 if (writeVariablePrecision(field->type()->getPrecision()))
1259 out << " ";
Olli Etuahoae4dbf32017-12-08 20:49:00 +01001260 out << getTypeName(*field->type()) << " " << hashName(TName(&field->name()));
Geoff Langbdcc54a2015-09-02 13:09:48 -04001261 if (field->type()->isArray())
Olli Etuaho96f6adf2017-08-16 11:18:54 +03001262 out << ArrayString(*field->type());
Geoff Langbdcc54a2015-09-02 13:09:48 -04001263 out << ";\n";
1264 }
1265 out << "}";
1266}
Jamie Madill45bcc782016-11-07 13:58:48 -05001267
Shaob5cc1192017-07-06 10:47:20 +08001268void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out,
1269 sh::TLayoutPrimitiveType inputPrimitive,
1270 int invocations,
1271 sh::TLayoutPrimitiveType outputPrimitive,
1272 int maxVertices)
1273{
1274 // Omit 'invocations = 1'
1275 if (inputPrimitive != EptUndefined || invocations > 1)
1276 {
1277 out << "layout (";
1278
1279 if (inputPrimitive != EptUndefined)
1280 {
1281 out << getGeometryShaderPrimitiveTypeString(inputPrimitive);
1282 }
1283
1284 if (invocations > 1)
1285 {
1286 if (inputPrimitive != EptUndefined)
1287 {
1288 out << ", ";
1289 }
1290 out << "invocations = " << invocations;
1291 }
1292 out << ") in;\n";
1293 }
1294
1295 if (outputPrimitive != EptUndefined || maxVertices != -1)
1296 {
1297 out << "layout (";
1298
1299 if (outputPrimitive != EptUndefined)
1300 {
1301 out << getGeometryShaderPrimitiveTypeString(outputPrimitive);
1302 }
1303
1304 if (maxVertices != -1)
1305 {
1306 if (outputPrimitive != EptUndefined)
1307 {
1308 out << ", ";
1309 }
1310 out << "max_vertices = " << maxVertices;
1311 }
1312 out << ") out;\n";
1313 }
1314}
1315
Jamie Madill2a9e1072017-09-22 11:31:57 -04001316// If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
1317// variables with specified layout qualifiers are copied. Additional checks are needed against the
1318// type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
1319// TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
1320// NeedsToWriteLayoutQualifier.
1321bool NeedsToWriteLayoutQualifier(const TType &type)
1322{
1323 if (type.getBasicType() == EbtInterfaceBlock)
1324 {
1325 return false;
1326 }
1327
1328 const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
1329
1330 if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn ||
1331 IsVarying(type.getQualifier())) &&
1332 layoutQualifier.location >= 0)
1333 {
1334 return true;
1335 }
1336
1337 if (type.getQualifier() == EvqFragmentOut && layoutQualifier.yuv == true)
1338 {
1339 return true;
1340 }
1341
1342 if (IsOpaqueType(type.getBasicType()) && layoutQualifier.binding != -1)
1343 {
1344 return true;
1345 }
1346
1347 if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
1348 {
1349 return true;
1350 }
1351 return false;
1352}
1353
Jamie Madill45bcc782016-11-07 13:58:48 -05001354} // namespace sh