• 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       flattenedOffsetInParentArrays(-1)
43 {}
44 
ShaderVariable(GLenum typeIn,unsigned int arraySizeIn)45 ShaderVariable::ShaderVariable(GLenum typeIn, unsigned int arraySizeIn) : ShaderVariable(typeIn)
46 {
47     ASSERT(arraySizeIn != 0);
48     arraySizes.push_back(arraySizeIn);
49 }
50 
~ShaderVariable()51 ShaderVariable::~ShaderVariable() {}
52 
ShaderVariable(const ShaderVariable & other)53 ShaderVariable::ShaderVariable(const ShaderVariable &other)
54     : type(other.type),
55       precision(other.precision),
56       name(other.name),
57       mappedName(other.mappedName),
58       arraySizes(other.arraySizes),
59       staticUse(other.staticUse),
60       active(other.active),
61       fields(other.fields),
62       structName(other.structName),
63       isRowMajorLayout(other.isRowMajorLayout),
64       flattenedOffsetInParentArrays(other.flattenedOffsetInParentArrays)
65 {}
66 
operator =(const ShaderVariable & other)67 ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other)
68 {
69     type                          = other.type;
70     precision                     = other.precision;
71     name                          = other.name;
72     mappedName                    = other.mappedName;
73     arraySizes                    = other.arraySizes;
74     staticUse                     = other.staticUse;
75     active                        = other.active;
76     fields                        = other.fields;
77     structName                    = other.structName;
78     isRowMajorLayout              = other.isRowMajorLayout;
79     flattenedOffsetInParentArrays = other.flattenedOffsetInParentArrays;
80     return *this;
81 }
82 
operator ==(const ShaderVariable & other) const83 bool ShaderVariable::operator==(const ShaderVariable &other) const
84 {
85     if (type != other.type || precision != other.precision || name != other.name ||
86         mappedName != other.mappedName || arraySizes != other.arraySizes ||
87         staticUse != other.staticUse || active != other.active ||
88         fields.size() != other.fields.size() || structName != other.structName ||
89         isRowMajorLayout != other.isRowMajorLayout)
90     {
91         return false;
92     }
93     for (size_t ii = 0; ii < fields.size(); ++ii)
94     {
95         if (fields[ii] != other.fields[ii])
96             return false;
97     }
98     return true;
99 }
100 
setArraySize(unsigned int size)101 void ShaderVariable::setArraySize(unsigned int size)
102 {
103     arraySizes.clear();
104     if (size != 0)
105     {
106         arraySizes.push_back(size);
107     }
108 }
109 
getInnerArraySizeProduct() const110 unsigned int ShaderVariable::getInnerArraySizeProduct() const
111 {
112     unsigned int arraySizeProduct = 1u;
113     for (size_t index = 1; index < arraySizes.size(); ++index)
114     {
115         arraySizeProduct *= getNestedArraySize(static_cast<unsigned int>(index));
116     }
117     return arraySizeProduct;
118 }
119 
getArraySizeProduct() const120 unsigned int ShaderVariable::getArraySizeProduct() const
121 {
122     return gl::ArraySizeProduct(arraySizes);
123 }
124 
indexIntoArray(unsigned int arrayIndex)125 void ShaderVariable::indexIntoArray(unsigned int arrayIndex)
126 {
127     ASSERT(isArray());
128     flattenedOffsetInParentArrays = arrayIndex + getOutermostArraySize() * parentArrayIndex();
129     arraySizes.pop_back();
130 }
131 
getNestedArraySize(unsigned int arrayNestingIndex) const132 unsigned int ShaderVariable::getNestedArraySize(unsigned int arrayNestingIndex) const
133 {
134     ASSERT(arraySizes.size() > arrayNestingIndex);
135     return arraySizes[arraySizes.size() - 1u - arrayNestingIndex];
136 }
137 
getBasicTypeElementCount() const138 unsigned int ShaderVariable::getBasicTypeElementCount() const
139 {
140     // GLES 3.1 Nov 2016 section 7.3.1.1 page 77 specifies that a separate entry should be generated
141     // for each array element when dealing with an array of arrays or an array of structs.
142     ASSERT(!isArrayOfArrays());
143     ASSERT(!isStruct() || !isArray());
144 
145     // GLES 3.1 Nov 2016 page 82.
146     if (isArray())
147     {
148         return getOutermostArraySize();
149     }
150     return 1u;
151 }
152 
findInfoByMappedName(const std::string & mappedFullName,const ShaderVariable ** leafVar,std::string * originalFullName) const153 bool ShaderVariable::findInfoByMappedName(const std::string &mappedFullName,
154                                           const ShaderVariable **leafVar,
155                                           std::string *originalFullName) const
156 {
157     ASSERT(leafVar && originalFullName);
158     // There are three cases:
159     // 1) the top variable is of struct type;
160     // 2) the top variable is an array;
161     // 3) otherwise.
162     size_t pos = mappedFullName.find_first_of(".[");
163 
164     if (pos == std::string::npos)
165     {
166         // Case 3.
167         if (mappedFullName != this->mappedName)
168             return false;
169         *originalFullName = this->name;
170         *leafVar          = this;
171         return true;
172     }
173     else
174     {
175         std::string topName = mappedFullName.substr(0, pos);
176         if (topName != this->mappedName)
177             return false;
178         std::string originalName = this->name;
179         std::string remaining;
180         if (mappedFullName[pos] == '[')
181         {
182             // Case 2.
183             size_t closePos = mappedFullName.find_first_of(']');
184             if (closePos < pos || closePos == std::string::npos)
185                 return false;
186             // Append '[index]'.
187             originalName += mappedFullName.substr(pos, closePos - pos + 1);
188             if (closePos + 1 == mappedFullName.size())
189             {
190                 *originalFullName = originalName;
191                 *leafVar          = this;
192                 return true;
193             }
194             else
195             {
196                 // In the form of 'a[0].b', so after ']', '.' is expected.
197                 if (mappedFullName[closePos + 1] != '.')
198                     return false;
199                 remaining = mappedFullName.substr(closePos + 2);  // Skip "]."
200             }
201         }
202         else
203         {
204             // Case 1.
205             remaining = mappedFullName.substr(pos + 1);  // Skip "."
206         }
207         for (size_t ii = 0; ii < this->fields.size(); ++ii)
208         {
209             const ShaderVariable *fieldVar = nullptr;
210             std::string originalFieldName;
211             bool found = fields[ii].findInfoByMappedName(remaining, &fieldVar, &originalFieldName);
212             if (found)
213             {
214                 *originalFullName = originalName + "." + originalFieldName;
215                 *leafVar          = fieldVar;
216                 return true;
217             }
218         }
219         return false;
220     }
221 }
222 
isBuiltIn() const223 bool ShaderVariable::isBuiltIn() const
224 {
225     return (name.size() >= 4 && name[0] == 'g' && name[1] == 'l' && name[2] == '_');
226 }
227 
isEmulatedBuiltIn() const228 bool ShaderVariable::isEmulatedBuiltIn() const
229 {
230     return isBuiltIn() && name != mappedName;
231 }
232 
isSameVariableAtLinkTime(const ShaderVariable & other,bool matchPrecision,bool matchName) const233 bool ShaderVariable::isSameVariableAtLinkTime(const ShaderVariable &other,
234                                               bool matchPrecision,
235                                               bool matchName) const
236 {
237     if (type != other.type)
238         return false;
239     if (matchPrecision && precision != other.precision)
240         return false;
241     if (matchName && name != other.name)
242         return false;
243     ASSERT(!matchName || mappedName == other.mappedName);
244     if (arraySizes != other.arraySizes)
245         return false;
246     if (isRowMajorLayout != other.isRowMajorLayout)
247         return false;
248     if (fields.size() != other.fields.size())
249         return false;
250 
251     // [OpenGL ES 3.1 SPEC Chapter 7.4.1]
252     // Variables declared as structures are considered to match in type if and only if structure
253     // members match in name, type, qualification, and declaration order.
254     for (size_t ii = 0; ii < fields.size(); ++ii)
255     {
256         if (!fields[ii].isSameVariableAtLinkTime(other.fields[ii], matchPrecision, true))
257         {
258             return false;
259         }
260     }
261     if (structName != other.structName)
262         return false;
263     return true;
264 }
265 
Uniform()266 Uniform::Uniform()
267     : binding(-1), imageUnitFormat(GL_NONE), offset(-1), readonly(false), writeonly(false)
268 {}
269 
~Uniform()270 Uniform::~Uniform() {}
271 
Uniform(const Uniform & other)272 Uniform::Uniform(const Uniform &other)
273     : VariableWithLocation(other),
274       binding(other.binding),
275       imageUnitFormat(other.imageUnitFormat),
276       offset(other.offset),
277       readonly(other.readonly),
278       writeonly(other.writeonly)
279 {}
280 
operator =(const Uniform & other)281 Uniform &Uniform::operator=(const Uniform &other)
282 {
283     VariableWithLocation::operator=(other);
284     binding                       = other.binding;
285     imageUnitFormat               = other.imageUnitFormat;
286     offset                        = other.offset;
287     readonly                      = other.readonly;
288     writeonly                     = other.writeonly;
289     return *this;
290 }
291 
operator ==(const Uniform & other) const292 bool Uniform::operator==(const Uniform &other) const
293 {
294     return VariableWithLocation::operator==(other) && binding == other.binding &&
295            imageUnitFormat == other.imageUnitFormat && offset == other.offset &&
296            readonly == other.readonly && writeonly == other.writeonly;
297 }
298 
isSameUniformAtLinkTime(const Uniform & other) const299 bool Uniform::isSameUniformAtLinkTime(const Uniform &other) const
300 {
301     // Enforce a consistent match.
302     // https://cvs.khronos.org/bugzilla/show_bug.cgi?id=16261
303     if (binding != -1 && other.binding != -1 && binding != other.binding)
304     {
305         return false;
306     }
307     if (imageUnitFormat != other.imageUnitFormat)
308     {
309         return false;
310     }
311     if (location != -1 && other.location != -1 && location != other.location)
312     {
313         return false;
314     }
315     if (offset != other.offset)
316     {
317         return false;
318     }
319     if (readonly != other.readonly || writeonly != other.writeonly)
320     {
321         return false;
322     }
323     return VariableWithLocation::isSameVariableAtLinkTime(other, true, true);
324 }
325 
VariableWithLocation()326 VariableWithLocation::VariableWithLocation() : location(-1) {}
327 
~VariableWithLocation()328 VariableWithLocation::~VariableWithLocation() {}
329 
VariableWithLocation(const VariableWithLocation & other)330 VariableWithLocation::VariableWithLocation(const VariableWithLocation &other)
331     : ShaderVariable(other), location(other.location)
332 {}
333 
operator =(const VariableWithLocation & other)334 VariableWithLocation &VariableWithLocation::operator=(const VariableWithLocation &other)
335 {
336     ShaderVariable::operator=(other);
337     location                = other.location;
338     return *this;
339 }
340 
operator ==(const VariableWithLocation & other) const341 bool VariableWithLocation::operator==(const VariableWithLocation &other) const
342 {
343     return (ShaderVariable::operator==(other) && location == other.location);
344 }
345 
Attribute()346 Attribute::Attribute() {}
347 
~Attribute()348 Attribute::~Attribute() {}
349 
Attribute(const Attribute & other)350 Attribute::Attribute(const Attribute &other) : VariableWithLocation(other) {}
351 
operator =(const Attribute & other)352 Attribute &Attribute::operator=(const Attribute &other)
353 {
354     VariableWithLocation::operator=(other);
355     return *this;
356 }
357 
operator ==(const Attribute & other) const358 bool Attribute::operator==(const Attribute &other) const
359 {
360     return VariableWithLocation::operator==(other);
361 }
362 
OutputVariable()363 OutputVariable::OutputVariable() : index(-1) {}
364 
~OutputVariable()365 OutputVariable::~OutputVariable() {}
366 
367 OutputVariable::OutputVariable(const OutputVariable &other) = default;
368 OutputVariable &OutputVariable::operator=(const OutputVariable &other) = default;
369 
operator ==(const OutputVariable & other) const370 bool OutputVariable::operator==(const OutputVariable &other) const
371 {
372     return VariableWithLocation::operator==(other) && index == other.index;
373 }
374 
InterfaceBlockField()375 InterfaceBlockField::InterfaceBlockField() {}
376 
~InterfaceBlockField()377 InterfaceBlockField::~InterfaceBlockField() {}
378 
InterfaceBlockField(const InterfaceBlockField & other)379 InterfaceBlockField::InterfaceBlockField(const InterfaceBlockField &other) : ShaderVariable(other)
380 {}
381 
operator =(const InterfaceBlockField & other)382 InterfaceBlockField &InterfaceBlockField::operator=(const InterfaceBlockField &other)
383 {
384     ShaderVariable::operator=(other);
385     return *this;
386 }
387 
operator ==(const InterfaceBlockField & other) const388 bool InterfaceBlockField::operator==(const InterfaceBlockField &other) const
389 {
390     return ShaderVariable::operator==(other);
391 }
392 
isSameInterfaceBlockFieldAtLinkTime(const InterfaceBlockField & other) const393 bool InterfaceBlockField::isSameInterfaceBlockFieldAtLinkTime(
394     const InterfaceBlockField &other) const
395 {
396     return (ShaderVariable::isSameVariableAtLinkTime(other, true, true));
397 }
398 
Varying()399 Varying::Varying() : interpolation(INTERPOLATION_SMOOTH), isInvariant(false) {}
400 
~Varying()401 Varying::~Varying() {}
402 
Varying(const Varying & other)403 Varying::Varying(const Varying &other)
404     : VariableWithLocation(other),
405       interpolation(other.interpolation),
406       isInvariant(other.isInvariant)
407 {}
408 
operator =(const Varying & other)409 Varying &Varying::operator=(const Varying &other)
410 {
411     VariableWithLocation::operator=(other);
412     interpolation                 = other.interpolation;
413     isInvariant                   = other.isInvariant;
414     return *this;
415 }
416 
operator ==(const Varying & other) const417 bool Varying::operator==(const Varying &other) const
418 {
419     return (VariableWithLocation::operator==(other) && interpolation == other.interpolation &&
420             isInvariant == other.isInvariant);
421 }
422 
isSameVaryingAtLinkTime(const Varying & other) const423 bool Varying::isSameVaryingAtLinkTime(const Varying &other) const
424 {
425     return isSameVaryingAtLinkTime(other, 100);
426 }
427 
isSameVaryingAtLinkTime(const Varying & other,int shaderVersion) const428 bool Varying::isSameVaryingAtLinkTime(const Varying &other, int shaderVersion) const
429 {
430     return (ShaderVariable::isSameVariableAtLinkTime(other, false, false) &&
431             InterpolationTypesMatch(interpolation, other.interpolation) &&
432             (shaderVersion >= 300 || isInvariant == other.isInvariant) &&
433             (location == other.location) &&
434             (name == other.name || (shaderVersion >= 310 && location >= 0)));
435 }
436 
InterfaceBlock()437 InterfaceBlock::InterfaceBlock()
438     : arraySize(0),
439       layout(BLOCKLAYOUT_PACKED),
440       isRowMajorLayout(false),
441       binding(-1),
442       staticUse(false),
443       active(false),
444       blockType(BlockType::BLOCK_UNIFORM)
445 {}
446 
~InterfaceBlock()447 InterfaceBlock::~InterfaceBlock() {}
448 
InterfaceBlock(const InterfaceBlock & other)449 InterfaceBlock::InterfaceBlock(const InterfaceBlock &other)
450     : name(other.name),
451       mappedName(other.mappedName),
452       instanceName(other.instanceName),
453       arraySize(other.arraySize),
454       layout(other.layout),
455       isRowMajorLayout(other.isRowMajorLayout),
456       binding(other.binding),
457       staticUse(other.staticUse),
458       active(other.active),
459       blockType(other.blockType),
460       fields(other.fields)
461 {}
462 
operator =(const InterfaceBlock & other)463 InterfaceBlock &InterfaceBlock::operator=(const InterfaceBlock &other)
464 {
465     name             = other.name;
466     mappedName       = other.mappedName;
467     instanceName     = other.instanceName;
468     arraySize        = other.arraySize;
469     layout           = other.layout;
470     isRowMajorLayout = other.isRowMajorLayout;
471     binding          = other.binding;
472     staticUse        = other.staticUse;
473     active           = other.active;
474     blockType        = other.blockType;
475     fields           = other.fields;
476     return *this;
477 }
478 
fieldPrefix() const479 std::string InterfaceBlock::fieldPrefix() const
480 {
481     return instanceName.empty() ? "" : name;
482 }
483 
fieldMappedPrefix() const484 std::string InterfaceBlock::fieldMappedPrefix() const
485 {
486     return instanceName.empty() ? "" : mappedName;
487 }
488 
isSameInterfaceBlockAtLinkTime(const InterfaceBlock & other) const489 bool InterfaceBlock::isSameInterfaceBlockAtLinkTime(const InterfaceBlock &other) const
490 {
491     if (name != other.name || mappedName != other.mappedName || arraySize != other.arraySize ||
492         layout != other.layout || isRowMajorLayout != other.isRowMajorLayout ||
493         binding != other.binding || blockType != other.blockType ||
494         fields.size() != other.fields.size())
495     {
496         return false;
497     }
498 
499     for (size_t fieldIndex = 0; fieldIndex < fields.size(); ++fieldIndex)
500     {
501         if (!fields[fieldIndex].isSameInterfaceBlockFieldAtLinkTime(other.fields[fieldIndex]))
502         {
503             return false;
504         }
505     }
506 
507     return true;
508 }
509 
isBuiltIn() const510 bool InterfaceBlock::isBuiltIn() const
511 {
512     return (name.size() >= 4 && name[0] == 'g' && name[1] == 'l' && name[2] == '_');
513 }
514 
fill(int fillValue)515 void WorkGroupSize::fill(int fillValue)
516 {
517     localSizeQualifiers[0] = fillValue;
518     localSizeQualifiers[1] = fillValue;
519     localSizeQualifiers[2] = fillValue;
520 }
521 
setLocalSize(int localSizeX,int localSizeY,int localSizeZ)522 void WorkGroupSize::setLocalSize(int localSizeX, int localSizeY, int localSizeZ)
523 {
524     localSizeQualifiers[0] = localSizeX;
525     localSizeQualifiers[1] = localSizeY;
526     localSizeQualifiers[2] = localSizeZ;
527 }
528 
529 // check that if one of them is less than 1, then all of them are.
530 // Or if one is positive, then all of them are positive.
isLocalSizeValid() const531 bool WorkGroupSize::isLocalSizeValid() const
532 {
533     return (
534         (localSizeQualifiers[0] < 1 && localSizeQualifiers[1] < 1 && localSizeQualifiers[2] < 1) ||
535         (localSizeQualifiers[0] > 0 && localSizeQualifiers[1] > 0 && localSizeQualifiers[2] > 0));
536 }
537 
isAnyValueSet() const538 bool WorkGroupSize::isAnyValueSet() const
539 {
540     return localSizeQualifiers[0] > 0 || localSizeQualifiers[1] > 0 || localSizeQualifiers[2] > 0;
541 }
542 
isDeclared() const543 bool WorkGroupSize::isDeclared() const
544 {
545     bool localSizeDeclared = localSizeQualifiers[0] > 0;
546     ASSERT(isLocalSizeValid());
547     return localSizeDeclared;
548 }
549 
isWorkGroupSizeMatching(const WorkGroupSize & right) const550 bool WorkGroupSize::isWorkGroupSizeMatching(const WorkGroupSize &right) const
551 {
552     for (size_t i = 0u; i < size(); ++i)
553     {
554         bool result = (localSizeQualifiers[i] == right.localSizeQualifiers[i] ||
555                        (localSizeQualifiers[i] == 1 && right.localSizeQualifiers[i] == -1) ||
556                        (localSizeQualifiers[i] == -1 && right.localSizeQualifiers[i] == 1));
557         if (!result)
558         {
559             return false;
560         }
561     }
562     return true;
563 }
564 
operator [](size_t index)565 int &WorkGroupSize::operator[](size_t index)
566 {
567     ASSERT(index < size());
568     return localSizeQualifiers[index];
569 }
570 
operator [](size_t index) const571 int WorkGroupSize::operator[](size_t index) const
572 {
573     ASSERT(index < size());
574     return localSizeQualifiers[index];
575 }
576 
size() const577 size_t WorkGroupSize::size() const
578 {
579     return 3u;
580 }
581 
582 }  // namespace sh
583