tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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