• 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 
findField(const std::string & fullName,uint32_t * fieldIndexOut) const285 const sh::ShaderVariable *ShaderVariable::findField(const std::string &fullName,
286                                                     uint32_t *fieldIndexOut) const
287 {
288     if (fields.empty())
289     {
290         return nullptr;
291     }
292     size_t pos = fullName.find_first_of(".");
293     if (pos == std::string::npos)
294     {
295         return nullptr;
296     }
297     std::string topName = fullName.substr(0, pos);
298     if (topName != name)
299     {
300         return nullptr;
301     }
302     std::string fieldName = fullName.substr(pos + 1);
303     if (fieldName.empty())
304     {
305         return nullptr;
306     }
307     for (size_t field = 0; field < fields.size(); ++field)
308     {
309         if (fields[field].name == fieldName)
310         {
311             *fieldIndexOut = static_cast<GLuint>(field);
312             return &fields[field];
313         }
314     }
315     return nullptr;
316 }
317 
isBuiltIn() const318 bool ShaderVariable::isBuiltIn() const
319 {
320     return (name.size() >= 4 && name[0] == 'g' && name[1] == 'l' && name[2] == '_');
321 }
322 
isEmulatedBuiltIn() const323 bool ShaderVariable::isEmulatedBuiltIn() const
324 {
325     return isBuiltIn() && name != mappedName;
326 }
327 
isSameVariableAtLinkTime(const ShaderVariable & other,bool matchPrecision,bool matchName) const328 bool ShaderVariable::isSameVariableAtLinkTime(const ShaderVariable &other,
329                                               bool matchPrecision,
330                                               bool matchName) const
331 {
332     if (type != other.type)
333         return false;
334     if (matchPrecision && precision != other.precision)
335         return false;
336     if (matchName && name != other.name)
337         return false;
338     ASSERT(!matchName || mappedName == other.mappedName);
339     if (arraySizes != other.arraySizes)
340         return false;
341     if (isRowMajorLayout != other.isRowMajorLayout)
342         return false;
343     if (fields.size() != other.fields.size())
344         return false;
345 
346     // [OpenGL ES 3.1 SPEC Chapter 7.4.1]
347     // Variables declared as structures are considered to match in type if and only if structure
348     // members match in name, type, qualification, and declaration order.
349     for (size_t ii = 0; ii < fields.size(); ++ii)
350     {
351         if (!fields[ii].isSameVariableAtLinkTime(other.fields[ii], matchPrecision, true))
352         {
353             return false;
354         }
355     }
356     if (structName != other.structName)
357         return false;
358     return true;
359 }
360 
isSameUniformAtLinkTime(const ShaderVariable & other) const361 bool ShaderVariable::isSameUniformAtLinkTime(const ShaderVariable &other) const
362 {
363     // Enforce a consistent match.
364     // https://cvs.khronos.org/bugzilla/show_bug.cgi?id=16261
365     if (binding != -1 && other.binding != -1 && binding != other.binding)
366     {
367         return false;
368     }
369     if (imageUnitFormat != other.imageUnitFormat)
370     {
371         return false;
372     }
373     if (location != -1 && other.location != -1 && location != other.location)
374     {
375         return false;
376     }
377     if (offset != other.offset)
378     {
379         return false;
380     }
381     if (readonly != other.readonly || writeonly != other.writeonly)
382     {
383         return false;
384     }
385     return ShaderVariable::isSameVariableAtLinkTime(other, true, true);
386 }
387 
isSameInterfaceBlockFieldAtLinkTime(const ShaderVariable & other) const388 bool ShaderVariable::isSameInterfaceBlockFieldAtLinkTime(const ShaderVariable &other) const
389 {
390     return (ShaderVariable::isSameVariableAtLinkTime(other, true, true));
391 }
392 
isSameVaryingAtLinkTime(const ShaderVariable & other) const393 bool ShaderVariable::isSameVaryingAtLinkTime(const ShaderVariable &other) const
394 {
395     return isSameVaryingAtLinkTime(other, 100);
396 }
397 
isSameVaryingAtLinkTime(const ShaderVariable & other,int shaderVersion) const398 bool ShaderVariable::isSameVaryingAtLinkTime(const ShaderVariable &other, int shaderVersion) const
399 {
400     return (ShaderVariable::isSameVariableAtLinkTime(other, false, false) &&
401             InterpolationTypesMatch(interpolation, other.interpolation) &&
402             (shaderVersion >= 300 || isInvariant == other.isInvariant) &&
403             (location == other.location) &&
404             (name == other.name || (shaderVersion >= 310 && location >= 0)));
405 }
406 
InterfaceBlock()407 InterfaceBlock::InterfaceBlock()
408     : arraySize(0),
409       layout(BLOCKLAYOUT_PACKED),
410       isRowMajorLayout(false),
411       binding(-1),
412       staticUse(false),
413       active(false),
414       blockType(BlockType::BLOCK_UNIFORM)
415 {}
416 
~InterfaceBlock()417 InterfaceBlock::~InterfaceBlock() {}
418 
InterfaceBlock(const InterfaceBlock & other)419 InterfaceBlock::InterfaceBlock(const InterfaceBlock &other)
420     : name(other.name),
421       mappedName(other.mappedName),
422       instanceName(other.instanceName),
423       arraySize(other.arraySize),
424       layout(other.layout),
425       isRowMajorLayout(other.isRowMajorLayout),
426       binding(other.binding),
427       staticUse(other.staticUse),
428       active(other.active),
429       blockType(other.blockType),
430       fields(other.fields)
431 {}
432 
operator =(const InterfaceBlock & other)433 InterfaceBlock &InterfaceBlock::operator=(const InterfaceBlock &other)
434 {
435     name             = other.name;
436     mappedName       = other.mappedName;
437     instanceName     = other.instanceName;
438     arraySize        = other.arraySize;
439     layout           = other.layout;
440     isRowMajorLayout = other.isRowMajorLayout;
441     binding          = other.binding;
442     staticUse        = other.staticUse;
443     active           = other.active;
444     blockType        = other.blockType;
445     fields           = other.fields;
446     return *this;
447 }
448 
fieldPrefix() const449 std::string InterfaceBlock::fieldPrefix() const
450 {
451     return instanceName.empty() ? "" : name;
452 }
453 
fieldMappedPrefix() const454 std::string InterfaceBlock::fieldMappedPrefix() const
455 {
456     return instanceName.empty() ? "" : mappedName;
457 }
458 
isSameInterfaceBlockAtLinkTime(const InterfaceBlock & other) const459 bool InterfaceBlock::isSameInterfaceBlockAtLinkTime(const InterfaceBlock &other) const
460 {
461     if (name != other.name || mappedName != other.mappedName || arraySize != other.arraySize ||
462         layout != other.layout || isRowMajorLayout != other.isRowMajorLayout ||
463         binding != other.binding || blockType != other.blockType ||
464         fields.size() != other.fields.size())
465     {
466         return false;
467     }
468 
469     for (size_t fieldIndex = 0; fieldIndex < fields.size(); ++fieldIndex)
470     {
471         if (!fields[fieldIndex].isSameInterfaceBlockFieldAtLinkTime(other.fields[fieldIndex]))
472         {
473             return false;
474         }
475     }
476 
477     return true;
478 }
479 
isBuiltIn() const480 bool InterfaceBlock::isBuiltIn() const
481 {
482     return (name.size() >= 4 && name[0] == 'g' && name[1] == 'l' && name[2] == '_');
483 }
484 
fill(int fillValue)485 void WorkGroupSize::fill(int fillValue)
486 {
487     localSizeQualifiers[0] = fillValue;
488     localSizeQualifiers[1] = fillValue;
489     localSizeQualifiers[2] = fillValue;
490 }
491 
setLocalSize(int localSizeX,int localSizeY,int localSizeZ)492 void WorkGroupSize::setLocalSize(int localSizeX, int localSizeY, int localSizeZ)
493 {
494     localSizeQualifiers[0] = localSizeX;
495     localSizeQualifiers[1] = localSizeY;
496     localSizeQualifiers[2] = localSizeZ;
497 }
498 
499 // check that if one of them is less than 1, then all of them are.
500 // Or if one is positive, then all of them are positive.
isLocalSizeValid() const501 bool WorkGroupSize::isLocalSizeValid() const
502 {
503     return (
504         (localSizeQualifiers[0] < 1 && localSizeQualifiers[1] < 1 && localSizeQualifiers[2] < 1) ||
505         (localSizeQualifiers[0] > 0 && localSizeQualifiers[1] > 0 && localSizeQualifiers[2] > 0));
506 }
507 
isAnyValueSet() const508 bool WorkGroupSize::isAnyValueSet() const
509 {
510     return localSizeQualifiers[0] > 0 || localSizeQualifiers[1] > 0 || localSizeQualifiers[2] > 0;
511 }
512 
isDeclared() const513 bool WorkGroupSize::isDeclared() const
514 {
515     bool localSizeDeclared = localSizeQualifiers[0] > 0;
516     ASSERT(isLocalSizeValid());
517     return localSizeDeclared;
518 }
519 
isWorkGroupSizeMatching(const WorkGroupSize & right) const520 bool WorkGroupSize::isWorkGroupSizeMatching(const WorkGroupSize &right) const
521 {
522     for (size_t i = 0u; i < size(); ++i)
523     {
524         bool result = (localSizeQualifiers[i] == right.localSizeQualifiers[i] ||
525                        (localSizeQualifiers[i] == 1 && right.localSizeQualifiers[i] == -1) ||
526                        (localSizeQualifiers[i] == -1 && right.localSizeQualifiers[i] == 1));
527         if (!result)
528         {
529             return false;
530         }
531     }
532     return true;
533 }
534 
operator [](size_t index)535 int &WorkGroupSize::operator[](size_t index)
536 {
537     ASSERT(index < size());
538     return localSizeQualifiers[index];
539 }
540 
operator [](size_t index) const541 int WorkGroupSize::operator[](size_t index) const
542 {
543     ASSERT(index < size());
544     return localSizeQualifiers[index];
545 }
546 
size() const547 size_t WorkGroupSize::size() const
548 {
549     return 3u;
550 }
551 
552 }  // namespace sh
553