• 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       hasImplicitLocation(false),
44       binding(-1),
45       imageUnitFormat(GL_NONE),
46       offset(-1),
47       rasterOrdered(false),
48       readonly(false),
49       writeonly(false),
50       isFragmentInOut(false),
51       index(-1),
52       yuv(false),
53       interpolation(INTERPOLATION_SMOOTH),
54       isInvariant(false),
55       isShaderIOBlock(false),
56       isPatch(false),
57       texelFetchStaticUse(false),
58       id(0),
59       flattenedOffsetInParentArrays(-1)
60 {}
61 
ShaderVariable(GLenum typeIn,unsigned int arraySizeIn)62 ShaderVariable::ShaderVariable(GLenum typeIn, unsigned int arraySizeIn) : ShaderVariable(typeIn)
63 {
64     ASSERT(arraySizeIn != 0);
65     arraySizes.push_back(arraySizeIn);
66 }
67 
~ShaderVariable()68 ShaderVariable::~ShaderVariable() {}
69 
ShaderVariable(const ShaderVariable & other)70 ShaderVariable::ShaderVariable(const ShaderVariable &other)
71     : type(other.type),
72       precision(other.precision),
73       name(other.name),
74       mappedName(other.mappedName),
75       arraySizes(other.arraySizes),
76       staticUse(other.staticUse),
77       active(other.active),
78       fields(other.fields),
79       structOrBlockName(other.structOrBlockName),
80       mappedStructOrBlockName(other.mappedStructOrBlockName),
81       isRowMajorLayout(other.isRowMajorLayout),
82       location(other.location),
83       hasImplicitLocation(other.hasImplicitLocation),
84       binding(other.binding),
85       imageUnitFormat(other.imageUnitFormat),
86       offset(other.offset),
87       rasterOrdered(other.rasterOrdered),
88       readonly(other.readonly),
89       writeonly(other.writeonly),
90       isFragmentInOut(other.isFragmentInOut),
91       index(other.index),
92       yuv(other.yuv),
93       interpolation(other.interpolation),
94       isInvariant(other.isInvariant),
95       isShaderIOBlock(other.isShaderIOBlock),
96       isPatch(other.isPatch),
97       texelFetchStaticUse(other.texelFetchStaticUse),
98       id(other.id),
99       flattenedOffsetInParentArrays(other.flattenedOffsetInParentArrays)
100 {}
101 
operator =(const ShaderVariable & other)102 ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other)
103 {
104     type                          = other.type;
105     precision                     = other.precision;
106     name                          = other.name;
107     mappedName                    = other.mappedName;
108     arraySizes                    = other.arraySizes;
109     staticUse                     = other.staticUse;
110     active                        = other.active;
111     fields                        = other.fields;
112     structOrBlockName             = other.structOrBlockName;
113     mappedStructOrBlockName       = other.mappedStructOrBlockName;
114     isRowMajorLayout              = other.isRowMajorLayout;
115     flattenedOffsetInParentArrays = other.flattenedOffsetInParentArrays;
116     location                      = other.location;
117     hasImplicitLocation           = other.hasImplicitLocation;
118     binding                       = other.binding;
119     imageUnitFormat               = other.imageUnitFormat;
120     offset                        = other.offset;
121     rasterOrdered                 = other.rasterOrdered;
122     readonly                      = other.readonly;
123     writeonly                     = other.writeonly;
124     isFragmentInOut               = other.isFragmentInOut;
125     index                         = other.index;
126     yuv                           = other.yuv;
127     interpolation                 = other.interpolation;
128     isInvariant                   = other.isInvariant;
129     isShaderIOBlock               = other.isShaderIOBlock;
130     isPatch                       = other.isPatch;
131     texelFetchStaticUse           = other.texelFetchStaticUse;
132     id                            = other.id;
133     return *this;
134 }
135 
operator ==(const ShaderVariable & other) const136 bool ShaderVariable::operator==(const ShaderVariable &other) const
137 {
138     if (type != other.type || precision != other.precision || name != other.name ||
139         mappedName != other.mappedName || arraySizes != other.arraySizes ||
140         staticUse != other.staticUse || active != other.active ||
141         fields.size() != other.fields.size() || structOrBlockName != other.structOrBlockName ||
142         mappedStructOrBlockName != other.mappedStructOrBlockName ||
143         isRowMajorLayout != other.isRowMajorLayout || location != other.location ||
144         hasImplicitLocation != other.hasImplicitLocation || binding != other.binding ||
145         imageUnitFormat != other.imageUnitFormat || offset != other.offset ||
146         rasterOrdered != other.rasterOrdered || readonly != other.readonly ||
147         writeonly != other.writeonly || index != other.index || yuv != other.yuv ||
148         interpolation != other.interpolation || isInvariant != other.isInvariant ||
149         isShaderIOBlock != other.isShaderIOBlock || isPatch != other.isPatch ||
150         texelFetchStaticUse != other.texelFetchStaticUse ||
151         isFragmentInOut != other.isFragmentInOut)
152     {
153         return false;
154     }
155     for (size_t ii = 0; ii < fields.size(); ++ii)
156     {
157         if (fields[ii] != other.fields[ii])
158             return false;
159     }
160     return true;
161 }
162 
setArraySize(unsigned int size)163 void ShaderVariable::setArraySize(unsigned int size)
164 {
165     arraySizes.clear();
166     if (size != 0)
167     {
168         arraySizes.push_back(size);
169     }
170 }
171 
getInnerArraySizeProduct() const172 unsigned int ShaderVariable::getInnerArraySizeProduct() const
173 {
174     return gl::InnerArraySizeProduct(arraySizes);
175 }
176 
getArraySizeProduct() const177 unsigned int ShaderVariable::getArraySizeProduct() const
178 {
179     return gl::ArraySizeProduct(arraySizes);
180 }
181 
indexIntoArray(unsigned int arrayIndex)182 void ShaderVariable::indexIntoArray(unsigned int arrayIndex)
183 {
184     ASSERT(isArray());
185     flattenedOffsetInParentArrays = arrayIndex + getOutermostArraySize() * parentArrayIndex();
186     arraySizes.pop_back();
187 }
188 
getNestedArraySize(unsigned int arrayNestingIndex) const189 unsigned int ShaderVariable::getNestedArraySize(unsigned int arrayNestingIndex) const
190 {
191     ASSERT(arraySizes.size() > arrayNestingIndex);
192     unsigned int arraySize = arraySizes[arraySizes.size() - 1u - arrayNestingIndex];
193 
194     if (arraySize == 0)
195     {
196         // Unsized array, so give it at least 1 entry
197         arraySize = 1;
198     }
199 
200     return arraySize;
201 }
202 
getBasicTypeElementCount() const203 unsigned int ShaderVariable::getBasicTypeElementCount() const
204 {
205     // GLES 3.1 Nov 2016 section 7.3.1.1 page 77 specifies that a separate entry should be generated
206     // for each array element when dealing with an array of arrays or an array of structs.
207     ASSERT(!isArrayOfArrays());
208     ASSERT(!isStruct() || !isArray());
209 
210     // GLES 3.1 Nov 2016 page 82.
211     if (isArray())
212     {
213         return getOutermostArraySize();
214     }
215     return 1u;
216 }
217 
getExternalSize() const218 unsigned int ShaderVariable::getExternalSize() const
219 {
220     unsigned int memorySize = 0;
221 
222     if (isStruct())
223     {
224         // Have a structure, need to compute the structure size.
225         for (const auto &field : fields)
226         {
227             memorySize += field.getExternalSize();
228         }
229     }
230     else
231     {
232         memorySize += gl::VariableExternalSize(type);
233     }
234 
235     // multiply by array size to get total memory size of this variable / struct.
236     memorySize *= getArraySizeProduct();
237 
238     return memorySize;
239 }
240 
findInfoByMappedName(const std::string & mappedFullName,const ShaderVariable ** leafVar,std::string * originalFullName) const241 bool ShaderVariable::findInfoByMappedName(const std::string &mappedFullName,
242                                           const ShaderVariable **leafVar,
243                                           std::string *originalFullName) const
244 {
245     ASSERT(leafVar && originalFullName);
246     // There are three cases:
247     // 1) the top variable is of struct type;
248     // 2) the top variable is an array;
249     // 3) otherwise.
250     size_t pos = mappedFullName.find_first_of(".[");
251 
252     if (pos == std::string::npos)
253     {
254         // Case 3.
255         if (mappedFullName != this->mappedName)
256             return false;
257         *originalFullName = this->name;
258         *leafVar          = this;
259         return true;
260     }
261     else
262     {
263         std::string topName = mappedFullName.substr(0, pos);
264         if (topName != this->mappedName)
265             return false;
266         std::string originalName = this->name;
267         std::string remaining;
268         if (mappedFullName[pos] == '[')
269         {
270             // Case 2.
271             size_t closePos = mappedFullName.find_first_of(']');
272             if (closePos < pos || closePos == std::string::npos)
273                 return false;
274             // Append '[index]'.
275             originalName += mappedFullName.substr(pos, closePos - pos + 1);
276             if (closePos + 1 == mappedFullName.size())
277             {
278                 *originalFullName = originalName;
279                 *leafVar          = this;
280                 return true;
281             }
282             else
283             {
284                 // In the form of 'a[0].b', so after ']', '.' is expected.
285                 if (mappedFullName[closePos + 1] != '.')
286                     return false;
287                 remaining = mappedFullName.substr(closePos + 2);  // Skip "]."
288             }
289         }
290         else
291         {
292             // Case 1.
293             remaining = mappedFullName.substr(pos + 1);  // Skip "."
294         }
295         for (size_t ii = 0; ii < this->fields.size(); ++ii)
296         {
297             const ShaderVariable *fieldVar = nullptr;
298             std::string originalFieldName;
299             bool found = fields[ii].findInfoByMappedName(remaining, &fieldVar, &originalFieldName);
300             if (found)
301             {
302                 *originalFullName = originalName + "." + originalFieldName;
303                 *leafVar          = fieldVar;
304                 return true;
305             }
306         }
307         return false;
308     }
309 }
310 
findField(const std::string & fullName,uint32_t * fieldIndexOut) const311 const sh::ShaderVariable *ShaderVariable::findField(const std::string &fullName,
312                                                     uint32_t *fieldIndexOut) const
313 {
314     if (fields.empty())
315     {
316         return nullptr;
317     }
318     size_t pos = fullName.find_first_of(".");
319     std::string topName, fieldName;
320     if (pos == std::string::npos)
321     {
322         // If this is a shader I/O block without an instance name, return the field given only the
323         // field name.
324         if (!isShaderIOBlock || !name.empty())
325         {
326             return nullptr;
327         }
328 
329         fieldName = fullName;
330     }
331     else
332     {
333         std::string baseName = isShaderIOBlock ? structOrBlockName : name;
334         topName              = fullName.substr(0, pos);
335         if (topName != baseName)
336         {
337             return nullptr;
338         }
339         fieldName = fullName.substr(pos + 1);
340     }
341     if (fieldName.empty())
342     {
343         return nullptr;
344     }
345     for (size_t field = 0; field < fields.size(); ++field)
346     {
347         if (fields[field].name == fieldName)
348         {
349             *fieldIndexOut = static_cast<GLuint>(field);
350             return &fields[field];
351         }
352     }
353     return nullptr;
354 }
355 
isBuiltIn() const356 bool ShaderVariable::isBuiltIn() const
357 {
358     return gl::IsBuiltInName(name);
359 }
360 
isEmulatedBuiltIn() const361 bool ShaderVariable::isEmulatedBuiltIn() const
362 {
363     return isBuiltIn() && name != mappedName;
364 }
365 
isSameVariableAtLinkTime(const ShaderVariable & other,bool matchPrecision,bool matchName) const366 bool ShaderVariable::isSameVariableAtLinkTime(const ShaderVariable &other,
367                                               bool matchPrecision,
368                                               bool matchName) const
369 {
370     if (type != other.type)
371         return false;
372     if (matchPrecision && precision != other.precision)
373         return false;
374     if (matchName && name != other.name)
375         return false;
376     ASSERT(!matchName || mappedName == other.mappedName);
377     if (arraySizes != other.arraySizes)
378         return false;
379     if (isRowMajorLayout != other.isRowMajorLayout)
380         return false;
381     if (fields.size() != other.fields.size())
382         return false;
383 
384     // [OpenGL ES 3.1 SPEC Chapter 7.4.1]
385     // Variables declared as structures are considered to match in type if and only if structure
386     // members match in name, type, qualification, and declaration order.
387     for (size_t ii = 0; ii < fields.size(); ++ii)
388     {
389         if (!fields[ii].isSameVariableAtLinkTime(other.fields[ii], matchPrecision, true))
390         {
391             return false;
392         }
393     }
394     if (structOrBlockName != other.structOrBlockName ||
395         mappedStructOrBlockName != other.mappedStructOrBlockName)
396         return false;
397     return true;
398 }
399 
updateEffectiveLocation(const sh::ShaderVariable & parent)400 void ShaderVariable::updateEffectiveLocation(const sh::ShaderVariable &parent)
401 {
402     if ((location < 0 || hasImplicitLocation) && !parent.hasImplicitLocation)
403     {
404         location = parent.location;
405     }
406 }
407 
resetEffectiveLocation()408 void ShaderVariable::resetEffectiveLocation()
409 {
410     if (hasImplicitLocation)
411     {
412         location = -1;
413     }
414 }
415 
isSameUniformAtLinkTime(const ShaderVariable & other) const416 bool ShaderVariable::isSameUniformAtLinkTime(const ShaderVariable &other) const
417 {
418     // Enforce a consistent match.
419     // https://cvs.khronos.org/bugzilla/show_bug.cgi?id=16261
420     if (binding != -1 && other.binding != -1 && binding != other.binding)
421     {
422         return false;
423     }
424     if (imageUnitFormat != other.imageUnitFormat)
425     {
426         return false;
427     }
428     if (location != -1 && other.location != -1 && location != other.location)
429     {
430         return false;
431     }
432     if (offset != other.offset)
433     {
434         return false;
435     }
436     if (rasterOrdered != other.rasterOrdered)
437     {
438         return false;
439     }
440     if (readonly != other.readonly || writeonly != other.writeonly)
441     {
442         return false;
443     }
444     return ShaderVariable::isSameVariableAtLinkTime(other, true, true);
445 }
446 
isSameInterfaceBlockFieldAtLinkTime(const ShaderVariable & other) const447 bool ShaderVariable::isSameInterfaceBlockFieldAtLinkTime(const ShaderVariable &other) const
448 {
449     return (ShaderVariable::isSameVariableAtLinkTime(other, true, true));
450 }
451 
isSameVaryingAtLinkTime(const ShaderVariable & other) const452 bool ShaderVariable::isSameVaryingAtLinkTime(const ShaderVariable &other) const
453 {
454     return isSameVaryingAtLinkTime(other, 100);
455 }
456 
isSameVaryingAtLinkTime(const ShaderVariable & other,int shaderVersion) const457 bool ShaderVariable::isSameVaryingAtLinkTime(const ShaderVariable &other, int shaderVersion) const
458 {
459     return ShaderVariable::isSameVariableAtLinkTime(other, false, false) &&
460            InterpolationTypesMatch(interpolation, other.interpolation) &&
461            (shaderVersion >= 300 || isInvariant == other.isInvariant) &&
462            (isPatch == other.isPatch) && location == other.location &&
463            (isSameNameAtLinkTime(other) || (shaderVersion >= 310 && location >= 0));
464 }
465 
isSameNameAtLinkTime(const ShaderVariable & other) const466 bool ShaderVariable::isSameNameAtLinkTime(const ShaderVariable &other) const
467 {
468     if (isShaderIOBlock != other.isShaderIOBlock)
469     {
470         return false;
471     }
472 
473     if (isShaderIOBlock)
474     {
475         // Shader I/O blocks match by block name.
476         return structOrBlockName == other.structOrBlockName;
477     }
478 
479     // Otherwise match by name.
480     return name == other.name;
481 }
482 
InterfaceBlock()483 InterfaceBlock::InterfaceBlock()
484     : arraySize(0),
485       layout(BLOCKLAYOUT_PACKED),
486       isRowMajorLayout(false),
487       binding(-1),
488       staticUse(false),
489       active(false),
490       isReadOnly(false),
491       blockType(BlockType::BLOCK_UNIFORM),
492       id(0)
493 {}
494 
~InterfaceBlock()495 InterfaceBlock::~InterfaceBlock() {}
496 
InterfaceBlock(const InterfaceBlock & other)497 InterfaceBlock::InterfaceBlock(const InterfaceBlock &other)
498     : name(other.name),
499       mappedName(other.mappedName),
500       instanceName(other.instanceName),
501       arraySize(other.arraySize),
502       layout(other.layout),
503       isRowMajorLayout(other.isRowMajorLayout),
504       binding(other.binding),
505       staticUse(other.staticUse),
506       active(other.active),
507       isReadOnly(other.isReadOnly),
508       blockType(other.blockType),
509       fields(other.fields),
510       id(other.id)
511 {}
512 
operator =(const InterfaceBlock & other)513 InterfaceBlock &InterfaceBlock::operator=(const InterfaceBlock &other)
514 {
515     name             = other.name;
516     mappedName       = other.mappedName;
517     instanceName     = other.instanceName;
518     arraySize        = other.arraySize;
519     layout           = other.layout;
520     isRowMajorLayout = other.isRowMajorLayout;
521     binding          = other.binding;
522     staticUse        = other.staticUse;
523     active           = other.active;
524     isReadOnly       = other.isReadOnly;
525     blockType        = other.blockType;
526     id               = other.id;
527     fields           = other.fields;
528     return *this;
529 }
530 
fieldPrefix() const531 std::string InterfaceBlock::fieldPrefix() const
532 {
533     return instanceName.empty() ? "" : name;
534 }
535 
fieldMappedPrefix() const536 std::string InterfaceBlock::fieldMappedPrefix() const
537 {
538     return instanceName.empty() ? "" : mappedName;
539 }
540 
isSameInterfaceBlockAtLinkTime(const InterfaceBlock & other) const541 bool InterfaceBlock::isSameInterfaceBlockAtLinkTime(const InterfaceBlock &other) const
542 {
543     if (name != other.name || mappedName != other.mappedName || arraySize != other.arraySize ||
544         layout != other.layout || isRowMajorLayout != other.isRowMajorLayout ||
545         binding != other.binding || blockType != other.blockType ||
546         fields.size() != other.fields.size())
547     {
548         return false;
549     }
550 
551     for (size_t fieldIndex = 0; fieldIndex < fields.size(); ++fieldIndex)
552     {
553         if (!fields[fieldIndex].isSameInterfaceBlockFieldAtLinkTime(other.fields[fieldIndex]))
554         {
555             return false;
556         }
557     }
558 
559     return true;
560 }
561 
isBuiltIn() const562 bool InterfaceBlock::isBuiltIn() const
563 {
564     return gl::IsBuiltInName(name);
565 }
566 
fill(int fillValue)567 void WorkGroupSize::fill(int fillValue)
568 {
569     localSizeQualifiers[0] = fillValue;
570     localSizeQualifiers[1] = fillValue;
571     localSizeQualifiers[2] = fillValue;
572 }
573 
setLocalSize(int localSizeX,int localSizeY,int localSizeZ)574 void WorkGroupSize::setLocalSize(int localSizeX, int localSizeY, int localSizeZ)
575 {
576     localSizeQualifiers[0] = localSizeX;
577     localSizeQualifiers[1] = localSizeY;
578     localSizeQualifiers[2] = localSizeZ;
579 }
580 
581 // check that if one of them is less than 1, then all of them are.
582 // Or if one is positive, then all of them are positive.
isLocalSizeValid() const583 bool WorkGroupSize::isLocalSizeValid() const
584 {
585     return (
586         (localSizeQualifiers[0] < 1 && localSizeQualifiers[1] < 1 && localSizeQualifiers[2] < 1) ||
587         (localSizeQualifiers[0] > 0 && localSizeQualifiers[1] > 0 && localSizeQualifiers[2] > 0));
588 }
589 
isAnyValueSet() const590 bool WorkGroupSize::isAnyValueSet() const
591 {
592     return localSizeQualifiers[0] > 0 || localSizeQualifiers[1] > 0 || localSizeQualifiers[2] > 0;
593 }
594 
isDeclared() const595 bool WorkGroupSize::isDeclared() const
596 {
597     bool localSizeDeclared = localSizeQualifiers[0] > 0;
598     ASSERT(isLocalSizeValid());
599     return localSizeDeclared;
600 }
601 
isWorkGroupSizeMatching(const WorkGroupSize & right) const602 bool WorkGroupSize::isWorkGroupSizeMatching(const WorkGroupSize &right) const
603 {
604     for (size_t i = 0u; i < size(); ++i)
605     {
606         bool result = (localSizeQualifiers[i] == right.localSizeQualifiers[i] ||
607                        (localSizeQualifiers[i] == 1 && right.localSizeQualifiers[i] == -1) ||
608                        (localSizeQualifiers[i] == -1 && right.localSizeQualifiers[i] == 1));
609         if (!result)
610         {
611             return false;
612         }
613     }
614     return true;
615 }
616 
operator [](size_t index)617 int &WorkGroupSize::operator[](size_t index)
618 {
619     ASSERT(index < size());
620     return localSizeQualifiers[index];
621 }
622 
operator [](size_t index) const623 int WorkGroupSize::operator[](size_t index) const
624 {
625     ASSERT(index < size());
626     return localSizeQualifiers[index];
627 }
628 
size() const629 size_t WorkGroupSize::size() const
630 {
631     return 3u;
632 }
633 
634 }  // namespace sh
635