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