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