• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2014 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // ShaderVars.cpp:
7 //  Methods for GL variable types (varyings, uniforms, etc)
8 //
9 
10 #include <GLSLANG/ShaderLang.h>
11 
12 #include "common/debug.h"
13 #include "common/utilities.h"
14 
15 namespace sh
16 {
17 
18 namespace
19 {
20 
GetNonAuxiliaryInterpolationType(InterpolationType interpolation)21 InterpolationType GetNonAuxiliaryInterpolationType(InterpolationType interpolation)
22 {
23     return (interpolation == INTERPOLATION_CENTROID ? INTERPOLATION_SMOOTH : interpolation);
24 }
25 }  // namespace
26 // The ES 3.0 spec is not clear on this point, but the ES 3.1 spec, and discussion
27 // on Khronos.org, clarifies that a smooth/flat mismatch produces a link error,
28 // but auxiliary qualifier mismatch (centroid) does not.
InterpolationTypesMatch(InterpolationType a,InterpolationType b)29 bool InterpolationTypesMatch(InterpolationType a, InterpolationType b)
30 {
31     return (GetNonAuxiliaryInterpolationType(a) == GetNonAuxiliaryInterpolationType(b));
32 }
33 
ShaderVariable()34 ShaderVariable::ShaderVariable() : ShaderVariable(GL_NONE) {}
35 
ShaderVariable(GLenum typeIn)36 ShaderVariable::ShaderVariable(GLenum typeIn)
37     : type(typeIn),
38       precision(0),
39       staticUse(false),
40       active(false),
41       isRowMajorLayout(false),
42       location(-1),
43       binding(-1),
44       imageUnitFormat(GL_NONE),
45       offset(-1),
46       readonly(false),
47       writeonly(false),
48       index(-1),
49       interpolation(INTERPOLATION_SMOOTH),
50       isInvariant(false),
51       flattenedOffsetInParentArrays(-1)
52 {}
53 
ShaderVariable(GLenum typeIn,unsigned int arraySizeIn)54 ShaderVariable::ShaderVariable(GLenum typeIn, unsigned int arraySizeIn) : ShaderVariable(typeIn)
55 {
56     ASSERT(arraySizeIn != 0);
57     arraySizes.push_back(arraySizeIn);
58 }
59 
~ShaderVariable()60 ShaderVariable::~ShaderVariable() {}
61 
ShaderVariable(const ShaderVariable & other)62 ShaderVariable::ShaderVariable(const ShaderVariable &other)
63     : type(other.type),
64       precision(other.precision),
65       name(other.name),
66       mappedName(other.mappedName),
67       arraySizes(other.arraySizes),
68       staticUse(other.staticUse),
69       active(other.active),
70       fields(other.fields),
71       structName(other.structName),
72       isRowMajorLayout(other.isRowMajorLayout),
73       location(other.location),
74       binding(other.binding),
75       imageUnitFormat(other.imageUnitFormat),
76       offset(other.offset),
77       readonly(other.readonly),
78       writeonly(other.writeonly),
79       index(other.index),
80       interpolation(other.interpolation),
81       isInvariant(other.isInvariant),
82       flattenedOffsetInParentArrays(other.flattenedOffsetInParentArrays)
83 {}
84 
operator =(const ShaderVariable & other)85 ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other)
86 {
87     type                          = other.type;
88     precision                     = other.precision;
89     name                          = other.name;
90     mappedName                    = other.mappedName;
91     arraySizes                    = other.arraySizes;
92     staticUse                     = other.staticUse;
93     active                        = other.active;
94     fields                        = other.fields;
95     structName                    = other.structName;
96     isRowMajorLayout              = other.isRowMajorLayout;
97     flattenedOffsetInParentArrays = other.flattenedOffsetInParentArrays;
98     location                      = other.location;
99     binding                       = other.binding;
100     imageUnitFormat               = other.imageUnitFormat;
101     offset                        = other.offset;
102     readonly                      = other.readonly;
103     writeonly                     = other.writeonly;
104     index                         = other.index;
105     interpolation                 = other.interpolation;
106     isInvariant                   = other.isInvariant;
107     return *this;
108 }
109 
operator ==(const ShaderVariable & other) const110 bool ShaderVariable::operator==(const ShaderVariable &other) const
111 {
112     if (type != other.type || precision != other.precision || name != other.name ||
113         mappedName != other.mappedName || arraySizes != other.arraySizes ||
114         staticUse != other.staticUse || active != other.active ||
115         fields.size() != other.fields.size() || structName != other.structName ||
116         isRowMajorLayout != other.isRowMajorLayout || location != other.location ||
117         binding != other.binding || imageUnitFormat != other.imageUnitFormat ||
118         offset != other.offset || readonly != other.readonly || writeonly != other.writeonly ||
119         index != other.index || interpolation != other.interpolation ||
120         isInvariant != other.isInvariant)
121     {
122         return false;
123     }
124     for (size_t ii = 0; ii < fields.size(); ++ii)
125     {
126         if (fields[ii] != other.fields[ii])
127             return false;
128     }
129     return true;
130 }
131 
setArraySize(unsigned int size)132 void ShaderVariable::setArraySize(unsigned int size)
133 {
134     arraySizes.clear();
135     if (size != 0)
136     {
137         arraySizes.push_back(size);
138     }
139 }
140 
getInnerArraySizeProduct() const141 unsigned int ShaderVariable::getInnerArraySizeProduct() const
142 {
143     unsigned int arraySizeProduct = 1u;
144     for (size_t idx = 1; idx < arraySizes.size(); ++idx)
145     {
146         arraySizeProduct *= getNestedArraySize(static_cast<unsigned int>(idx));
147     }
148     return arraySizeProduct;
149 }
150 
getArraySizeProduct() const151 unsigned int ShaderVariable::getArraySizeProduct() const
152 {
153     return gl::ArraySizeProduct(arraySizes);
154 }
155 
indexIntoArray(unsigned int arrayIndex)156 void ShaderVariable::indexIntoArray(unsigned int arrayIndex)
157 {
158     ASSERT(isArray());
159     flattenedOffsetInParentArrays = arrayIndex + getOutermostArraySize() * parentArrayIndex();
160     arraySizes.pop_back();
161 }
162 
getNestedArraySize(unsigned int arrayNestingIndex) const163 unsigned int ShaderVariable::getNestedArraySize(unsigned int arrayNestingIndex) const
164 {
165     ASSERT(arraySizes.size() > arrayNestingIndex);
166     unsigned int arraySize = arraySizes[arraySizes.size() - 1u - arrayNestingIndex];
167 
168     if (arraySize == 0)
169     {
170         // Unsized array, so give it at least 1 entry
171         arraySize = 1;
172     }
173 
174     return arraySize;
175 }
176 
getBasicTypeElementCount() const177 unsigned int ShaderVariable::getBasicTypeElementCount() const
178 {
179     // GLES 3.1 Nov 2016 section 7.3.1.1 page 77 specifies that a separate entry should be generated
180     // for each array element when dealing with an array of arrays or an array of structs.
181     ASSERT(!isArrayOfArrays());
182     ASSERT(!isStruct() || !isArray());
183 
184     // GLES 3.1 Nov 2016 page 82.
185     if (isArray())
186     {
187         return getOutermostArraySize();
188     }
189     return 1u;
190 }
191 
getExternalSize() const192 unsigned int ShaderVariable::getExternalSize() const
193 {
194     unsigned int memorySize = 0;
195 
196     if (isStruct())
197     {
198         // Have a structure, need to compute the structure size.
199         for (const auto &field : fields)
200         {
201             memorySize += field.getExternalSize();
202         }
203     }
204     else
205     {
206         memorySize += gl::VariableExternalSize(type);
207     }
208 
209     // multiply by array size to get total memory size of this variable / struct.
210     memorySize *= getArraySizeProduct();
211 
212     return memorySize;
213 }
214 
findInfoByMappedName(const std::string & mappedFullName,const ShaderVariable ** leafVar,std::string * originalFullName) const215 bool ShaderVariable::findInfoByMappedName(const std::string &mappedFullName,
216                                           const ShaderVariable **leafVar,
217                                           std::string *originalFullName) const
218 {
219     ASSERT(leafVar && originalFullName);
220     // There are three cases:
221     // 1) the top variable is of struct type;
222     // 2) the top variable is an array;
223     // 3) otherwise.
224     size_t pos = mappedFullName.find_first_of(".[");
225 
226     if (pos == std::string::npos)
227     {
228         // Case 3.
229         if (mappedFullName != this->mappedName)
230             return false;
231         *originalFullName = this->name;
232         *leafVar          = this;
233         return true;
234     }
235     else
236     {
237         std::string topName = mappedFullName.substr(0, pos);
238         if (topName != this->mappedName)
239             return false;
240         std::string originalName = this->name;
241         std::string remaining;
242         if (mappedFullName[pos] == '[')
243         {
244             // Case 2.
245             size_t closePos = mappedFullName.find_first_of(']');
246             if (closePos < pos || closePos == std::string::npos)
247                 return false;
248             // Append '[index]'.
249             originalName += mappedFullName.substr(pos, closePos - pos + 1);
250             if (closePos + 1 == mappedFullName.size())
251             {
252                 *originalFullName = originalName;
253                 *leafVar          = this;
254                 return true;
255             }
256             else
257             {
258                 // In the form of 'a[0].b', so after ']', '.' is expected.
259                 if (mappedFullName[closePos + 1] != '.')
260                     return false;
261                 remaining = mappedFullName.substr(closePos + 2);  // Skip "]."
262             }
263         }
264         else
265         {
266             // Case 1.
267             remaining = mappedFullName.substr(pos + 1);  // Skip "."
268         }
269         for (size_t ii = 0; ii < this->fields.size(); ++ii)
270         {
271             const ShaderVariable *fieldVar = nullptr;
272             std::string originalFieldName;
273             bool found = fields[ii].findInfoByMappedName(remaining, &fieldVar, &originalFieldName);
274             if (found)
275             {
276                 *originalFullName = originalName + "." + originalFieldName;
277                 *leafVar          = fieldVar;
278                 return true;
279             }
280         }
281         return false;
282     }
283 }
284 
isBuiltIn() const285 bool ShaderVariable::isBuiltIn() const
286 {
287     return (name.size() >= 4 && name[0] == 'g' && name[1] == 'l' && name[2] == '_');
288 }
289 
isEmulatedBuiltIn() const290 bool ShaderVariable::isEmulatedBuiltIn() const
291 {
292     return isBuiltIn() && name != mappedName;
293 }
294 
isSameVariableAtLinkTime(const ShaderVariable & other,bool matchPrecision,bool matchName) const295 bool ShaderVariable::isSameVariableAtLinkTime(const ShaderVariable &other,
296                                               bool matchPrecision,
297                                               bool matchName) const
298 {
299     if (type != other.type)
300         return false;
301     if (matchPrecision && precision != other.precision)
302         return false;
303     if (matchName && name != other.name)
304         return false;
305     ASSERT(!matchName || mappedName == other.mappedName);
306     if (arraySizes != other.arraySizes)
307         return false;
308     if (isRowMajorLayout != other.isRowMajorLayout)
309         return false;
310     if (fields.size() != other.fields.size())
311         return false;
312 
313     // [OpenGL ES 3.1 SPEC Chapter 7.4.1]
314     // Variables declared as structures are considered to match in type if and only if structure
315     // members match in name, type, qualification, and declaration order.
316     for (size_t ii = 0; ii < fields.size(); ++ii)
317     {
318         if (!fields[ii].isSameVariableAtLinkTime(other.fields[ii], matchPrecision, true))
319         {
320             return false;
321         }
322     }
323     if (structName != other.structName)
324         return false;
325     return true;
326 }
327 
isSameUniformAtLinkTime(const ShaderVariable & other) const328 bool ShaderVariable::isSameUniformAtLinkTime(const ShaderVariable &other) const
329 {
330     // Enforce a consistent match.
331     // https://cvs.khronos.org/bugzilla/show_bug.cgi?id=16261
332     if (binding != -1 && other.binding != -1 && binding != other.binding)
333     {
334         return false;
335     }
336     if (imageUnitFormat != other.imageUnitFormat)
337     {
338         return false;
339     }
340     if (location != -1 && other.location != -1 && location != other.location)
341     {
342         return false;
343     }
344     if (offset != other.offset)
345     {
346         return false;
347     }
348     if (readonly != other.readonly || writeonly != other.writeonly)
349     {
350         return false;
351     }
352     return ShaderVariable::isSameVariableAtLinkTime(other, true, true);
353 }
354 
isSameInterfaceBlockFieldAtLinkTime(const ShaderVariable & other) const355 bool ShaderVariable::isSameInterfaceBlockFieldAtLinkTime(const ShaderVariable &other) const
356 {
357     return (ShaderVariable::isSameVariableAtLinkTime(other, true, true));
358 }
359 
isSameVaryingAtLinkTime(const ShaderVariable & other) const360 bool ShaderVariable::isSameVaryingAtLinkTime(const ShaderVariable &other) const
361 {
362     return isSameVaryingAtLinkTime(other, 100);
363 }
364 
isSameVaryingAtLinkTime(const ShaderVariable & other,int shaderVersion) const365 bool ShaderVariable::isSameVaryingAtLinkTime(const ShaderVariable &other, int shaderVersion) const
366 {
367     return (ShaderVariable::isSameVariableAtLinkTime(other, false, false) &&
368             InterpolationTypesMatch(interpolation, other.interpolation) &&
369             (shaderVersion >= 300 || isInvariant == other.isInvariant) &&
370             (location == other.location) &&
371             (name == other.name || (shaderVersion >= 310 && location >= 0)));
372 }
373 
InterfaceBlock()374 InterfaceBlock::InterfaceBlock()
375     : arraySize(0),
376       layout(BLOCKLAYOUT_PACKED),
377       isRowMajorLayout(false),
378       binding(-1),
379       staticUse(false),
380       active(false),
381       blockType(BlockType::BLOCK_UNIFORM)
382 {}
383 
~InterfaceBlock()384 InterfaceBlock::~InterfaceBlock() {}
385 
InterfaceBlock(const InterfaceBlock & other)386 InterfaceBlock::InterfaceBlock(const InterfaceBlock &other)
387     : name(other.name),
388       mappedName(other.mappedName),
389       instanceName(other.instanceName),
390       arraySize(other.arraySize),
391       layout(other.layout),
392       isRowMajorLayout(other.isRowMajorLayout),
393       binding(other.binding),
394       staticUse(other.staticUse),
395       active(other.active),
396       blockType(other.blockType),
397       fields(other.fields)
398 {}
399 
operator =(const InterfaceBlock & other)400 InterfaceBlock &InterfaceBlock::operator=(const InterfaceBlock &other)
401 {
402     name             = other.name;
403     mappedName       = other.mappedName;
404     instanceName     = other.instanceName;
405     arraySize        = other.arraySize;
406     layout           = other.layout;
407     isRowMajorLayout = other.isRowMajorLayout;
408     binding          = other.binding;
409     staticUse        = other.staticUse;
410     active           = other.active;
411     blockType        = other.blockType;
412     fields           = other.fields;
413     return *this;
414 }
415 
fieldPrefix() const416 std::string InterfaceBlock::fieldPrefix() const
417 {
418     return instanceName.empty() ? "" : name;
419 }
420 
fieldMappedPrefix() const421 std::string InterfaceBlock::fieldMappedPrefix() const
422 {
423     return instanceName.empty() ? "" : mappedName;
424 }
425 
isSameInterfaceBlockAtLinkTime(const InterfaceBlock & other) const426 bool InterfaceBlock::isSameInterfaceBlockAtLinkTime(const InterfaceBlock &other) const
427 {
428     if (name != other.name || mappedName != other.mappedName || arraySize != other.arraySize ||
429         layout != other.layout || isRowMajorLayout != other.isRowMajorLayout ||
430         binding != other.binding || blockType != other.blockType ||
431         fields.size() != other.fields.size())
432     {
433         return false;
434     }
435 
436     for (size_t fieldIndex = 0; fieldIndex < fields.size(); ++fieldIndex)
437     {
438         if (!fields[fieldIndex].isSameInterfaceBlockFieldAtLinkTime(other.fields[fieldIndex]))
439         {
440             return false;
441         }
442     }
443 
444     return true;
445 }
446 
isBuiltIn() const447 bool InterfaceBlock::isBuiltIn() const
448 {
449     return (name.size() >= 4 && name[0] == 'g' && name[1] == 'l' && name[2] == '_');
450 }
451 
fill(int fillValue)452 void WorkGroupSize::fill(int fillValue)
453 {
454     localSizeQualifiers[0] = fillValue;
455     localSizeQualifiers[1] = fillValue;
456     localSizeQualifiers[2] = fillValue;
457 }
458 
setLocalSize(int localSizeX,int localSizeY,int localSizeZ)459 void WorkGroupSize::setLocalSize(int localSizeX, int localSizeY, int localSizeZ)
460 {
461     localSizeQualifiers[0] = localSizeX;
462     localSizeQualifiers[1] = localSizeY;
463     localSizeQualifiers[2] = localSizeZ;
464 }
465 
466 // check that if one of them is less than 1, then all of them are.
467 // Or if one is positive, then all of them are positive.
isLocalSizeValid() const468 bool WorkGroupSize::isLocalSizeValid() const
469 {
470     return (
471         (localSizeQualifiers[0] < 1 && localSizeQualifiers[1] < 1 && localSizeQualifiers[2] < 1) ||
472         (localSizeQualifiers[0] > 0 && localSizeQualifiers[1] > 0 && localSizeQualifiers[2] > 0));
473 }
474 
isAnyValueSet() const475 bool WorkGroupSize::isAnyValueSet() const
476 {
477     return localSizeQualifiers[0] > 0 || localSizeQualifiers[1] > 0 || localSizeQualifiers[2] > 0;
478 }
479 
isDeclared() const480 bool WorkGroupSize::isDeclared() const
481 {
482     bool localSizeDeclared = localSizeQualifiers[0] > 0;
483     ASSERT(isLocalSizeValid());
484     return localSizeDeclared;
485 }
486 
isWorkGroupSizeMatching(const WorkGroupSize & right) const487 bool WorkGroupSize::isWorkGroupSizeMatching(const WorkGroupSize &right) const
488 {
489     for (size_t i = 0u; i < size(); ++i)
490     {
491         bool result = (localSizeQualifiers[i] == right.localSizeQualifiers[i] ||
492                        (localSizeQualifiers[i] == 1 && right.localSizeQualifiers[i] == -1) ||
493                        (localSizeQualifiers[i] == -1 && right.localSizeQualifiers[i] == 1));
494         if (!result)
495         {
496             return false;
497         }
498     }
499     return true;
500 }
501 
operator [](size_t index)502 int &WorkGroupSize::operator[](size_t index)
503 {
504     ASSERT(index < size());
505     return localSizeQualifiers[index];
506 }
507 
operator [](size_t index) const508 int WorkGroupSize::operator[](size_t index) const
509 {
510     ASSERT(index < size());
511     return localSizeQualifiers[index];
512 }
513 
size() const514 size_t WorkGroupSize::size() const
515 {
516     return 3u;
517 }
518 
519 }  // namespace sh
520