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