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