Edit

kc3-lang/angle/src/common/utilities.cpp

Branch :

  • Show log

    Commit

  • Author : Geoff Lang
    Date : 2020-04-16 16:31:24
    Hash : 4e6f6545
    Message : GLX: Support X11 pixmaps Add support for creating EGL pixmaps from X11 pixmaps using GLX. Pixmaps are needed for various external APIs such as VAAPI. Add support for EGL_NOK_texture_from_pixmap to allow binding pixmaps to textures. BUG=angleproject:4560 Change-Id: I4a6d3ad7e87151ff5317bbdaaf093ac1b46daf5f Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2153805 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: Jonah Ryan-Davis <jonahr@google.com> Reviewed-by: Tim Van Patten <timvp@google.com> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>

  • src/common/utilities.cpp
  • //
    // Copyright 2002 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    
    // utilities.cpp: Conversion functions and other utility routines.
    
    #include "common/utilities.h"
    #include "GLES3/gl3.h"
    #include "common/mathutil.h"
    #include "common/platform.h"
    
    #include <set>
    
    #if defined(ANGLE_ENABLE_WINDOWS_UWP)
    #    include <windows.applicationmodel.core.h>
    #    include <windows.graphics.display.h>
    #    include <wrl.h>
    #    include <wrl/wrappers/corewrappers.h>
    #endif
    
    namespace
    {
    
    template <class IndexType>
    gl::IndexRange ComputeTypedIndexRange(const IndexType *indices,
                                          size_t count,
                                          bool primitiveRestartEnabled,
                                          GLuint primitiveRestartIndex)
    {
        ASSERT(count > 0);
    
        IndexType minIndex                = 0;
        IndexType maxIndex                = 0;
        size_t nonPrimitiveRestartIndices = 0;
    
        if (primitiveRestartEnabled)
        {
            // Find the first non-primitive restart index to initialize the min and max values
            size_t i = 0;
            for (; i < count; i++)
            {
                if (indices[i] != primitiveRestartIndex)
                {
                    minIndex = indices[i];
                    maxIndex = indices[i];
                    nonPrimitiveRestartIndices++;
                    break;
                }
            }
    
            // Loop over the rest of the indices
            for (; i < count; i++)
            {
                if (indices[i] != primitiveRestartIndex)
                {
                    if (minIndex > indices[i])
                    {
                        minIndex = indices[i];
                    }
                    if (maxIndex < indices[i])
                    {
                        maxIndex = indices[i];
                    }
                    nonPrimitiveRestartIndices++;
                }
            }
        }
        else
        {
            minIndex                   = indices[0];
            maxIndex                   = indices[0];
            nonPrimitiveRestartIndices = count;
    
            for (size_t i = 1; i < count; i++)
            {
                if (minIndex > indices[i])
                {
                    minIndex = indices[i];
                }
                if (maxIndex < indices[i])
                {
                    maxIndex = indices[i];
                }
            }
        }
    
        return gl::IndexRange(static_cast<size_t>(minIndex), static_cast<size_t>(maxIndex),
                              nonPrimitiveRestartIndices);
    }
    
    }  // anonymous namespace
    
    namespace gl
    {
    
    int VariableComponentCount(GLenum type)
    {
        return VariableRowCount(type) * VariableColumnCount(type);
    }
    
    GLenum VariableComponentType(GLenum type)
    {
        switch (type)
        {
            case GL_BOOL:
            case GL_BOOL_VEC2:
            case GL_BOOL_VEC3:
            case GL_BOOL_VEC4:
                return GL_BOOL;
            case GL_FLOAT:
            case GL_FLOAT_VEC2:
            case GL_FLOAT_VEC3:
            case GL_FLOAT_VEC4:
            case GL_FLOAT_MAT2:
            case GL_FLOAT_MAT3:
            case GL_FLOAT_MAT4:
            case GL_FLOAT_MAT2x3:
            case GL_FLOAT_MAT3x2:
            case GL_FLOAT_MAT2x4:
            case GL_FLOAT_MAT4x2:
            case GL_FLOAT_MAT3x4:
            case GL_FLOAT_MAT4x3:
                return GL_FLOAT;
            case GL_INT:
            case GL_SAMPLER_2D:
            case GL_SAMPLER_2D_RECT_ANGLE:
            case GL_SAMPLER_3D:
            case GL_SAMPLER_CUBE:
            case GL_SAMPLER_2D_ARRAY:
            case GL_SAMPLER_EXTERNAL_OES:
            case GL_SAMPLER_2D_MULTISAMPLE:
            case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
            case GL_INT_SAMPLER_2D:
            case GL_INT_SAMPLER_3D:
            case GL_INT_SAMPLER_CUBE:
            case GL_INT_SAMPLER_2D_ARRAY:
            case GL_INT_SAMPLER_2D_MULTISAMPLE:
            case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
            case GL_UNSIGNED_INT_SAMPLER_2D:
            case GL_UNSIGNED_INT_SAMPLER_3D:
            case GL_UNSIGNED_INT_SAMPLER_CUBE:
            case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
            case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
            case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
            case GL_SAMPLER_2D_SHADOW:
            case GL_SAMPLER_CUBE_SHADOW:
            case GL_SAMPLER_2D_ARRAY_SHADOW:
            case GL_INT_VEC2:
            case GL_INT_VEC3:
            case GL_INT_VEC4:
            case GL_IMAGE_2D:
            case GL_INT_IMAGE_2D:
            case GL_UNSIGNED_INT_IMAGE_2D:
            case GL_IMAGE_3D:
            case GL_INT_IMAGE_3D:
            case GL_UNSIGNED_INT_IMAGE_3D:
            case GL_IMAGE_2D_ARRAY:
            case GL_INT_IMAGE_2D_ARRAY:
            case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
            case GL_IMAGE_CUBE:
            case GL_INT_IMAGE_CUBE:
            case GL_UNSIGNED_INT_IMAGE_CUBE:
            case GL_IMAGE_CUBE_MAP_ARRAY:
            case GL_INT_IMAGE_CUBE_MAP_ARRAY:
            case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
            case GL_UNSIGNED_INT_ATOMIC_COUNTER:
            case GL_SAMPLER_VIDEO_IMAGE_WEBGL:
                return GL_INT;
            case GL_UNSIGNED_INT:
            case GL_UNSIGNED_INT_VEC2:
            case GL_UNSIGNED_INT_VEC3:
            case GL_UNSIGNED_INT_VEC4:
                return GL_UNSIGNED_INT;
            default:
                UNREACHABLE();
        }
    
        return GL_NONE;
    }
    
    size_t VariableComponentSize(GLenum type)
    {
        switch (type)
        {
            case GL_BOOL:
                return sizeof(GLint);
            case GL_FLOAT:
                return sizeof(GLfloat);
            case GL_INT:
                return sizeof(GLint);
            case GL_UNSIGNED_INT:
                return sizeof(GLuint);
            default:
                UNREACHABLE();
        }
    
        return 0;
    }
    
    size_t VariableInternalSize(GLenum type)
    {
        // Expanded to 4-element vectors
        return VariableComponentSize(VariableComponentType(type)) * VariableRowCount(type) * 4;
    }
    
    size_t VariableExternalSize(GLenum type)
    {
        return VariableComponentSize(VariableComponentType(type)) * VariableComponentCount(type);
    }
    
    std::string GetGLSLTypeString(GLenum type)
    {
        switch (type)
        {
            case GL_BOOL:
                return "bool";
            case GL_INT:
                return "int";
            case GL_UNSIGNED_INT:
                return "uint";
            case GL_FLOAT:
                return "float";
            case GL_BOOL_VEC2:
                return "bvec2";
            case GL_BOOL_VEC3:
                return "bvec3";
            case GL_BOOL_VEC4:
                return "bvec4";
            case GL_INT_VEC2:
                return "ivec2";
            case GL_INT_VEC3:
                return "ivec3";
            case GL_INT_VEC4:
                return "ivec4";
            case GL_FLOAT_VEC2:
                return "vec2";
            case GL_FLOAT_VEC3:
                return "vec3";
            case GL_FLOAT_VEC4:
                return "vec4";
            case GL_UNSIGNED_INT_VEC2:
                return "uvec2";
            case GL_UNSIGNED_INT_VEC3:
                return "uvec3";
            case GL_UNSIGNED_INT_VEC4:
                return "uvec4";
            case GL_FLOAT_MAT2:
                return "mat2";
            case GL_FLOAT_MAT3:
                return "mat3";
            case GL_FLOAT_MAT4:
                return "mat4";
            default:
                UNREACHABLE();
                return nullptr;
        }
    }
    
    GLenum VariableBoolVectorType(GLenum type)
    {
        switch (type)
        {
            case GL_FLOAT:
            case GL_INT:
            case GL_UNSIGNED_INT:
                return GL_BOOL;
            case GL_FLOAT_VEC2:
            case GL_INT_VEC2:
            case GL_UNSIGNED_INT_VEC2:
                return GL_BOOL_VEC2;
            case GL_FLOAT_VEC3:
            case GL_INT_VEC3:
            case GL_UNSIGNED_INT_VEC3:
                return GL_BOOL_VEC3;
            case GL_FLOAT_VEC4:
            case GL_INT_VEC4:
            case GL_UNSIGNED_INT_VEC4:
                return GL_BOOL_VEC4;
    
            default:
                UNREACHABLE();
                return GL_NONE;
        }
    }
    
    int VariableRowCount(GLenum type)
    {
        switch (type)
        {
            case GL_NONE:
                return 0;
            case GL_BOOL:
            case GL_FLOAT:
            case GL_INT:
            case GL_UNSIGNED_INT:
            case GL_BOOL_VEC2:
            case GL_FLOAT_VEC2:
            case GL_INT_VEC2:
            case GL_UNSIGNED_INT_VEC2:
            case GL_BOOL_VEC3:
            case GL_FLOAT_VEC3:
            case GL_INT_VEC3:
            case GL_UNSIGNED_INT_VEC3:
            case GL_BOOL_VEC4:
            case GL_FLOAT_VEC4:
            case GL_INT_VEC4:
            case GL_UNSIGNED_INT_VEC4:
            case GL_SAMPLER_2D:
            case GL_SAMPLER_3D:
            case GL_SAMPLER_CUBE:
            case GL_SAMPLER_2D_ARRAY:
            case GL_SAMPLER_EXTERNAL_OES:
            case GL_SAMPLER_2D_RECT_ANGLE:
            case GL_SAMPLER_2D_MULTISAMPLE:
            case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
            case GL_SAMPLER_CUBE_MAP_ARRAY:
            case GL_INT_SAMPLER_2D:
            case GL_INT_SAMPLER_3D:
            case GL_INT_SAMPLER_CUBE:
            case GL_INT_SAMPLER_2D_ARRAY:
            case GL_INT_SAMPLER_2D_MULTISAMPLE:
            case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
            case GL_INT_SAMPLER_CUBE_MAP_ARRAY:
            case GL_UNSIGNED_INT_SAMPLER_2D:
            case GL_UNSIGNED_INT_SAMPLER_3D:
            case GL_UNSIGNED_INT_SAMPLER_CUBE:
            case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
            case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
            case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
            case GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY:
            case GL_SAMPLER_2D_SHADOW:
            case GL_SAMPLER_CUBE_SHADOW:
            case GL_SAMPLER_2D_ARRAY_SHADOW:
            case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
            case GL_IMAGE_2D:
            case GL_INT_IMAGE_2D:
            case GL_UNSIGNED_INT_IMAGE_2D:
            case GL_IMAGE_2D_ARRAY:
            case GL_INT_IMAGE_2D_ARRAY:
            case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
            case GL_IMAGE_3D:
            case GL_INT_IMAGE_3D:
            case GL_UNSIGNED_INT_IMAGE_3D:
            case GL_IMAGE_CUBE:
            case GL_INT_IMAGE_CUBE:
            case GL_UNSIGNED_INT_IMAGE_CUBE:
            case GL_UNSIGNED_INT_ATOMIC_COUNTER:
            case GL_IMAGE_CUBE_MAP_ARRAY:
            case GL_INT_IMAGE_CUBE_MAP_ARRAY:
            case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
            case GL_SAMPLER_VIDEO_IMAGE_WEBGL:
                return 1;
            case GL_FLOAT_MAT2:
            case GL_FLOAT_MAT3x2:
            case GL_FLOAT_MAT4x2:
                return 2;
            case GL_FLOAT_MAT3:
            case GL_FLOAT_MAT2x3:
            case GL_FLOAT_MAT4x3:
                return 3;
            case GL_FLOAT_MAT4:
            case GL_FLOAT_MAT2x4:
            case GL_FLOAT_MAT3x4:
                return 4;
            default:
                UNREACHABLE();
        }
    
        return 0;
    }
    
    int VariableColumnCount(GLenum type)
    {
        switch (type)
        {
            case GL_NONE:
                return 0;
            case GL_BOOL:
            case GL_FLOAT:
            case GL_INT:
            case GL_UNSIGNED_INT:
            case GL_SAMPLER_2D:
            case GL_SAMPLER_3D:
            case GL_SAMPLER_CUBE:
            case GL_SAMPLER_2D_ARRAY:
            case GL_SAMPLER_2D_MULTISAMPLE:
            case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
            case GL_SAMPLER_CUBE_MAP_ARRAY:
            case GL_INT_SAMPLER_2D:
            case GL_INT_SAMPLER_3D:
            case GL_INT_SAMPLER_CUBE:
            case GL_INT_SAMPLER_2D_ARRAY:
            case GL_INT_SAMPLER_2D_MULTISAMPLE:
            case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
            case GL_INT_SAMPLER_CUBE_MAP_ARRAY:
            case GL_SAMPLER_EXTERNAL_OES:
            case GL_SAMPLER_2D_RECT_ANGLE:
            case GL_UNSIGNED_INT_SAMPLER_2D:
            case GL_UNSIGNED_INT_SAMPLER_3D:
            case GL_UNSIGNED_INT_SAMPLER_CUBE:
            case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
            case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
            case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
            case GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY:
            case GL_SAMPLER_2D_SHADOW:
            case GL_SAMPLER_CUBE_SHADOW:
            case GL_SAMPLER_2D_ARRAY_SHADOW:
            case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
            case GL_IMAGE_2D:
            case GL_INT_IMAGE_2D:
            case GL_UNSIGNED_INT_IMAGE_2D:
            case GL_IMAGE_3D:
            case GL_INT_IMAGE_3D:
            case GL_UNSIGNED_INT_IMAGE_3D:
            case GL_IMAGE_2D_ARRAY:
            case GL_INT_IMAGE_2D_ARRAY:
            case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
            case GL_IMAGE_CUBE_MAP_ARRAY:
            case GL_INT_IMAGE_CUBE_MAP_ARRAY:
            case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
            case GL_IMAGE_CUBE:
            case GL_INT_IMAGE_CUBE:
            case GL_UNSIGNED_INT_IMAGE_CUBE:
            case GL_UNSIGNED_INT_ATOMIC_COUNTER:
            case GL_SAMPLER_VIDEO_IMAGE_WEBGL:
                return 1;
            case GL_BOOL_VEC2:
            case GL_FLOAT_VEC2:
            case GL_INT_VEC2:
            case GL_UNSIGNED_INT_VEC2:
            case GL_FLOAT_MAT2:
            case GL_FLOAT_MAT2x3:
            case GL_FLOAT_MAT2x4:
                return 2;
            case GL_BOOL_VEC3:
            case GL_FLOAT_VEC3:
            case GL_INT_VEC3:
            case GL_UNSIGNED_INT_VEC3:
            case GL_FLOAT_MAT3:
            case GL_FLOAT_MAT3x2:
            case GL_FLOAT_MAT3x4:
                return 3;
            case GL_BOOL_VEC4:
            case GL_FLOAT_VEC4:
            case GL_INT_VEC4:
            case GL_UNSIGNED_INT_VEC4:
            case GL_FLOAT_MAT4:
            case GL_FLOAT_MAT4x2:
            case GL_FLOAT_MAT4x3:
                return 4;
            default:
                UNREACHABLE();
        }
    
        return 0;
    }
    
    bool IsSamplerType(GLenum type)
    {
        switch (type)
        {
            case GL_SAMPLER_2D:
            case GL_SAMPLER_3D:
            case GL_SAMPLER_CUBE:
            case GL_SAMPLER_2D_ARRAY:
            case GL_SAMPLER_EXTERNAL_OES:
            case GL_SAMPLER_2D_MULTISAMPLE:
            case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
            case GL_SAMPLER_CUBE_MAP_ARRAY:
            case GL_SAMPLER_2D_RECT_ANGLE:
            case GL_INT_SAMPLER_2D:
            case GL_INT_SAMPLER_3D:
            case GL_INT_SAMPLER_CUBE:
            case GL_INT_SAMPLER_2D_ARRAY:
            case GL_INT_SAMPLER_2D_MULTISAMPLE:
            case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
            case GL_INT_SAMPLER_CUBE_MAP_ARRAY:
            case GL_UNSIGNED_INT_SAMPLER_2D:
            case GL_UNSIGNED_INT_SAMPLER_3D:
            case GL_UNSIGNED_INT_SAMPLER_CUBE:
            case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
            case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
            case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
            case GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY:
            case GL_SAMPLER_2D_SHADOW:
            case GL_SAMPLER_CUBE_SHADOW:
            case GL_SAMPLER_2D_ARRAY_SHADOW:
            case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
            case GL_SAMPLER_VIDEO_IMAGE_WEBGL:
                return true;
        }
    
        return false;
    }
    
    bool IsSamplerCubeType(GLenum type)
    {
        switch (type)
        {
            case GL_SAMPLER_CUBE:
            case GL_INT_SAMPLER_CUBE:
            case GL_UNSIGNED_INT_SAMPLER_CUBE:
            case GL_SAMPLER_CUBE_SHADOW:
                return true;
        }
    
        return false;
    }
    
    bool IsImageType(GLenum type)
    {
        switch (type)
        {
            case GL_IMAGE_2D:
            case GL_INT_IMAGE_2D:
            case GL_UNSIGNED_INT_IMAGE_2D:
            case GL_IMAGE_3D:
            case GL_INT_IMAGE_3D:
            case GL_UNSIGNED_INT_IMAGE_3D:
            case GL_IMAGE_2D_ARRAY:
            case GL_INT_IMAGE_2D_ARRAY:
            case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
            case GL_IMAGE_CUBE_MAP_ARRAY:
            case GL_INT_IMAGE_CUBE_MAP_ARRAY:
            case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
            case GL_IMAGE_CUBE:
            case GL_INT_IMAGE_CUBE:
            case GL_UNSIGNED_INT_IMAGE_CUBE:
                return true;
        }
        return false;
    }
    
    bool IsImage2DType(GLenum type)
    {
        switch (type)
        {
            case GL_IMAGE_2D:
            case GL_INT_IMAGE_2D:
            case GL_UNSIGNED_INT_IMAGE_2D:
                return true;
            case GL_IMAGE_3D:
            case GL_INT_IMAGE_3D:
            case GL_UNSIGNED_INT_IMAGE_3D:
            case GL_IMAGE_2D_ARRAY:
            case GL_INT_IMAGE_2D_ARRAY:
            case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
            case GL_IMAGE_CUBE_MAP_ARRAY:
            case GL_INT_IMAGE_CUBE_MAP_ARRAY:
            case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
            case GL_IMAGE_CUBE:
            case GL_INT_IMAGE_CUBE:
            case GL_UNSIGNED_INT_IMAGE_CUBE:
                return false;
            default:
                UNREACHABLE();
                return false;
        }
    }
    
    bool IsAtomicCounterType(GLenum type)
    {
        return type == GL_UNSIGNED_INT_ATOMIC_COUNTER;
    }
    
    bool IsOpaqueType(GLenum type)
    {
        // ESSL 3.10 section 4.1.7 defines opaque types as: samplers, images and atomic counters.
        return IsImageType(type) || IsSamplerType(type) || IsAtomicCounterType(type);
    }
    
    bool IsMatrixType(GLenum type)
    {
        return VariableRowCount(type) > 1;
    }
    
    GLenum TransposeMatrixType(GLenum type)
    {
        if (!IsMatrixType(type))
        {
            return type;
        }
    
        switch (type)
        {
            case GL_FLOAT_MAT2:
                return GL_FLOAT_MAT2;
            case GL_FLOAT_MAT3:
                return GL_FLOAT_MAT3;
            case GL_FLOAT_MAT4:
                return GL_FLOAT_MAT4;
            case GL_FLOAT_MAT2x3:
                return GL_FLOAT_MAT3x2;
            case GL_FLOAT_MAT3x2:
                return GL_FLOAT_MAT2x3;
            case GL_FLOAT_MAT2x4:
                return GL_FLOAT_MAT4x2;
            case GL_FLOAT_MAT4x2:
                return GL_FLOAT_MAT2x4;
            case GL_FLOAT_MAT3x4:
                return GL_FLOAT_MAT4x3;
            case GL_FLOAT_MAT4x3:
                return GL_FLOAT_MAT3x4;
            default:
                UNREACHABLE();
                return GL_NONE;
        }
    }
    
    int MatrixRegisterCount(GLenum type, bool isRowMajorMatrix)
    {
        ASSERT(IsMatrixType(type));
        return isRowMajorMatrix ? VariableRowCount(type) : VariableColumnCount(type);
    }
    
    int MatrixComponentCount(GLenum type, bool isRowMajorMatrix)
    {
        ASSERT(IsMatrixType(type));
        return isRowMajorMatrix ? VariableColumnCount(type) : VariableRowCount(type);
    }
    
    int VariableRegisterCount(GLenum type)
    {
        return IsMatrixType(type) ? VariableColumnCount(type) : 1;
    }
    
    int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize)
    {
        ASSERT(allocationSize <= bitsSize);
    
        unsigned int mask = std::numeric_limits<unsigned int>::max() >>
                            (std::numeric_limits<unsigned int>::digits - allocationSize);
    
        for (unsigned int i = 0; i < bitsSize - allocationSize + 1; i++)
        {
            if ((*bits & mask) == 0)
            {
                *bits |= mask;
                return i;
            }
    
            mask <<= 1;
        }
    
        return -1;
    }
    
    IndexRange ComputeIndexRange(DrawElementsType indexType,
                                 const GLvoid *indices,
                                 size_t count,
                                 bool primitiveRestartEnabled)
    {
        switch (indexType)
        {
            case DrawElementsType::UnsignedByte:
                return ComputeTypedIndexRange(static_cast<const GLubyte *>(indices), count,
                                              primitiveRestartEnabled,
                                              GetPrimitiveRestartIndex(indexType));
            case DrawElementsType::UnsignedShort:
                return ComputeTypedIndexRange(static_cast<const GLushort *>(indices), count,
                                              primitiveRestartEnabled,
                                              GetPrimitiveRestartIndex(indexType));
            case DrawElementsType::UnsignedInt:
                return ComputeTypedIndexRange(static_cast<const GLuint *>(indices), count,
                                              primitiveRestartEnabled,
                                              GetPrimitiveRestartIndex(indexType));
            default:
                UNREACHABLE();
                return IndexRange();
        }
    }
    
    GLuint GetPrimitiveRestartIndex(DrawElementsType indexType)
    {
        switch (indexType)
        {
            case DrawElementsType::UnsignedByte:
                return 0xFF;
            case DrawElementsType::UnsignedShort:
                return 0xFFFF;
            case DrawElementsType::UnsignedInt:
                return 0xFFFFFFFF;
            default:
                UNREACHABLE();
                return 0;
        }
    }
    
    bool IsTriangleMode(PrimitiveMode drawMode)
    {
        switch (drawMode)
        {
            case PrimitiveMode::Triangles:
            case PrimitiveMode::TriangleFan:
            case PrimitiveMode::TriangleStrip:
                return true;
            case PrimitiveMode::Points:
            case PrimitiveMode::Lines:
            case PrimitiveMode::LineLoop:
            case PrimitiveMode::LineStrip:
                return false;
            default:
                UNREACHABLE();
        }
    
        return false;
    }
    
    bool IsPolygonMode(PrimitiveMode mode)
    {
        switch (mode)
        {
            case PrimitiveMode::Points:
            case PrimitiveMode::Lines:
            case PrimitiveMode::LineStrip:
            case PrimitiveMode::LineLoop:
            case PrimitiveMode::LinesAdjacency:
            case PrimitiveMode::LineStripAdjacency:
                return false;
            default:
                break;
        }
    
        return true;
    }
    
    namespace priv
    {
    const angle::PackedEnumMap<PrimitiveMode, bool> gLineModes = {
        {{PrimitiveMode::LineLoop, true},
         {PrimitiveMode::LineStrip, true},
         {PrimitiveMode::LineStripAdjacency, true},
         {PrimitiveMode::Lines, true}}};
    }  // namespace priv
    
    bool IsIntegerFormat(GLenum unsizedFormat)
    {
        switch (unsizedFormat)
        {
            case GL_RGBA_INTEGER:
            case GL_RGB_INTEGER:
            case GL_RG_INTEGER:
            case GL_RED_INTEGER:
                return true;
    
            default:
                return false;
        }
    }
    
    // [OpenGL ES SL 3.00.4] Section 11 p. 120
    // Vertex Outs/Fragment Ins packing priorities
    int VariableSortOrder(GLenum type)
    {
        switch (type)
        {
            // 1. Arrays of mat4 and mat4
            // Non-square matrices of type matCxR consume the same space as a square
            // matrix of type matN where N is the greater of C and R
            case GL_FLOAT_MAT4:
            case GL_FLOAT_MAT2x4:
            case GL_FLOAT_MAT3x4:
            case GL_FLOAT_MAT4x2:
            case GL_FLOAT_MAT4x3:
                return 0;
    
            // 2. Arrays of mat2 and mat2 (since they occupy full rows)
            case GL_FLOAT_MAT2:
                return 1;
    
            // 3. Arrays of vec4 and vec4
            case GL_FLOAT_VEC4:
            case GL_INT_VEC4:
            case GL_BOOL_VEC4:
            case GL_UNSIGNED_INT_VEC4:
                return 2;
    
            // 4. Arrays of mat3 and mat3
            case GL_FLOAT_MAT3:
            case GL_FLOAT_MAT2x3:
            case GL_FLOAT_MAT3x2:
                return 3;
    
            // 5. Arrays of vec3 and vec3
            case GL_FLOAT_VEC3:
            case GL_INT_VEC3:
            case GL_BOOL_VEC3:
            case GL_UNSIGNED_INT_VEC3:
                return 4;
    
            // 6. Arrays of vec2 and vec2
            case GL_FLOAT_VEC2:
            case GL_INT_VEC2:
            case GL_BOOL_VEC2:
            case GL_UNSIGNED_INT_VEC2:
                return 5;
    
            // 7. Single component types
            case GL_FLOAT:
            case GL_INT:
            case GL_BOOL:
            case GL_UNSIGNED_INT:
            case GL_SAMPLER_2D:
            case GL_SAMPLER_CUBE:
            case GL_SAMPLER_EXTERNAL_OES:
            case GL_SAMPLER_2D_RECT_ANGLE:
            case GL_SAMPLER_2D_ARRAY:
            case GL_SAMPLER_2D_MULTISAMPLE:
            case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
            case GL_SAMPLER_3D:
            case GL_INT_SAMPLER_2D:
            case GL_INT_SAMPLER_3D:
            case GL_INT_SAMPLER_CUBE:
            case GL_INT_SAMPLER_2D_ARRAY:
            case GL_INT_SAMPLER_2D_MULTISAMPLE:
            case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
            case GL_UNSIGNED_INT_SAMPLER_2D:
            case GL_UNSIGNED_INT_SAMPLER_3D:
            case GL_UNSIGNED_INT_SAMPLER_CUBE:
            case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
            case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
            case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
            case GL_SAMPLER_2D_SHADOW:
            case GL_SAMPLER_2D_ARRAY_SHADOW:
            case GL_SAMPLER_CUBE_SHADOW:
            case GL_IMAGE_2D:
            case GL_INT_IMAGE_2D:
            case GL_UNSIGNED_INT_IMAGE_2D:
            case GL_IMAGE_3D:
            case GL_INT_IMAGE_3D:
            case GL_UNSIGNED_INT_IMAGE_3D:
            case GL_IMAGE_2D_ARRAY:
            case GL_INT_IMAGE_2D_ARRAY:
            case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
            case GL_IMAGE_CUBE:
            case GL_INT_IMAGE_CUBE:
            case GL_UNSIGNED_INT_IMAGE_CUBE:
            case GL_UNSIGNED_INT_ATOMIC_COUNTER:
            case GL_SAMPLER_VIDEO_IMAGE_WEBGL:
                return 6;
    
            default:
                UNREACHABLE();
                return 0;
        }
    }
    
    std::string ParseResourceName(const std::string &name, std::vector<unsigned int> *outSubscripts)
    {
        if (outSubscripts)
        {
            outSubscripts->clear();
        }
        // Strip any trailing array indexing operators and retrieve the subscripts.
        size_t baseNameLength = name.length();
        bool hasIndex         = true;
        while (hasIndex)
        {
            size_t open  = name.find_last_of('[', baseNameLength - 1);
            size_t close = name.find_last_of(']', baseNameLength - 1);
            hasIndex     = (open != std::string::npos) && (close == baseNameLength - 1);
            if (hasIndex)
            {
                baseNameLength = open;
                if (outSubscripts)
                {
                    int index = atoi(name.substr(open + 1).c_str());
                    if (index >= 0)
                    {
                        outSubscripts->push_back(index);
                    }
                    else
                    {
                        outSubscripts->push_back(GL_INVALID_INDEX);
                    }
                }
            }
        }
    
        return name.substr(0, baseNameLength);
    }
    
    std::string StripLastArrayIndex(const std::string &name)
    {
        size_t strippedNameLength = name.find_last_of('[');
        if (strippedNameLength != std::string::npos && name.back() == ']')
        {
            return name.substr(0, strippedNameLength);
        }
        return name;
    }
    
    bool SamplerNameContainsNonZeroArrayElement(const std::string &name)
    {
        constexpr char kZERO_ELEMENT[] = "[0]";
    
        size_t start = 0;
        while (true)
        {
            start = name.find(kZERO_ELEMENT[0], start);
            if (start == std::string::npos)
            {
                break;
            }
            if (name.compare(start, strlen(kZERO_ELEMENT), kZERO_ELEMENT) != 0)
            {
                return true;
            }
            start++;
        }
        return false;
    }
    
    unsigned int ArraySizeProduct(const std::vector<unsigned int> &arraySizes)
    {
        unsigned int arraySizeProduct = 1u;
        for (unsigned int arraySize : arraySizes)
        {
            arraySizeProduct *= arraySize;
        }
        return arraySizeProduct;
    }
    
    unsigned int ParseArrayIndex(const std::string &name, size_t *nameLengthWithoutArrayIndexOut)
    {
        ASSERT(nameLengthWithoutArrayIndexOut != nullptr);
    
        // Strip any trailing array operator and retrieve the subscript
        size_t open = name.find_last_of('[');
        if (open != std::string::npos && name.back() == ']')
        {
            bool indexIsValidDecimalNumber = true;
            for (size_t i = open + 1; i < name.length() - 1u; ++i)
            {
                if (!isdigit(name[i]))
                {
                    indexIsValidDecimalNumber = false;
                    break;
                }
    
                // Leading zeroes are invalid
                if ((i == (open + 1)) && (name[i] == '0') && (name[i + 1] != ']'))
                {
                    indexIsValidDecimalNumber = false;
                    break;
                }
            }
            if (indexIsValidDecimalNumber)
            {
                errno = 0;  // reset global error flag.
                unsigned long subscript =
                    strtoul(name.c_str() + open + 1, /*endptr*/ nullptr, /*radix*/ 10);
    
                // Check if resulting integer is out-of-range or conversion error.
                if (angle::base::IsValueInRangeForNumericType<uint32_t>(subscript) &&
                    !(subscript == ULONG_MAX && errno == ERANGE) && !(errno != 0 && subscript == 0))
                {
                    *nameLengthWithoutArrayIndexOut = open;
                    return static_cast<unsigned int>(subscript);
                }
            }
        }
    
        *nameLengthWithoutArrayIndexOut = name.length();
        return GL_INVALID_INDEX;
    }
    
    const char *GetGenericErrorMessage(GLenum error)
    {
        switch (error)
        {
            case GL_NO_ERROR:
                return "";
            case GL_INVALID_ENUM:
                return "Invalid enum.";
            case GL_INVALID_VALUE:
                return "Invalid value.";
            case GL_INVALID_OPERATION:
                return "Invalid operation.";
            case GL_STACK_OVERFLOW:
                return "Stack overflow.";
            case GL_STACK_UNDERFLOW:
                return "Stack underflow.";
            case GL_OUT_OF_MEMORY:
                return "Out of memory.";
            case GL_INVALID_FRAMEBUFFER_OPERATION:
                return "Invalid framebuffer operation.";
            default:
                UNREACHABLE();
                return "Unknown error.";
        }
    }
    
    unsigned int ElementTypeSize(GLenum elementType)
    {
        switch (elementType)
        {
            case GL_UNSIGNED_BYTE:
                return sizeof(GLubyte);
            case GL_UNSIGNED_SHORT:
                return sizeof(GLushort);
            case GL_UNSIGNED_INT:
                return sizeof(GLuint);
            default:
                UNREACHABLE();
                return 0;
        }
    }
    
    PipelineType GetPipelineType(ShaderType type)
    {
        switch (type)
        {
            case ShaderType::Vertex:
            case ShaderType::Fragment:
            case ShaderType::Geometry:
                return PipelineType::GraphicsPipeline;
            case ShaderType::Compute:
                return PipelineType::ComputePipeline;
            default:
                UNREACHABLE();
                return PipelineType::GraphicsPipeline;
        }
    }
    
    const char *GetDebugMessageSourceString(GLenum source)
    {
        switch (source)
        {
            case GL_DEBUG_SOURCE_API:
                return "API";
            case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
                return "Window System";
            case GL_DEBUG_SOURCE_SHADER_COMPILER:
                return "Shader Compiler";
            case GL_DEBUG_SOURCE_THIRD_PARTY:
                return "Third Party";
            case GL_DEBUG_SOURCE_APPLICATION:
                return "Application";
            case GL_DEBUG_SOURCE_OTHER:
                return "Other";
            default:
                return "Unknown Source";
        }
    }
    
    const char *GetDebugMessageTypeString(GLenum type)
    {
        switch (type)
        {
            case GL_DEBUG_TYPE_ERROR:
                return "Error";
            case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
                return "Deprecated behavior";
            case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
                return "Undefined behavior";
            case GL_DEBUG_TYPE_PORTABILITY:
                return "Portability";
            case GL_DEBUG_TYPE_PERFORMANCE:
                return "Performance";
            case GL_DEBUG_TYPE_OTHER:
                return "Other";
            case GL_DEBUG_TYPE_MARKER:
                return "Marker";
            default:
                return "Unknown Type";
        }
    }
    
    const char *GetDebugMessageSeverityString(GLenum severity)
    {
        switch (severity)
        {
            case GL_DEBUG_SEVERITY_HIGH:
                return "High";
            case GL_DEBUG_SEVERITY_MEDIUM:
                return "Medium";
            case GL_DEBUG_SEVERITY_LOW:
                return "Low";
            case GL_DEBUG_SEVERITY_NOTIFICATION:
                return "Notification";
            default:
                return "Unknown Severity";
        }
    }
    }  // namespace gl
    
    namespace egl
    {
    static_assert(EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 1,
                  "Unexpected EGL cube map enum value.");
    static_assert(EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 2,
                  "Unexpected EGL cube map enum value.");
    static_assert(EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 3,
                  "Unexpected EGL cube map enum value.");
    static_assert(EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 4,
                  "Unexpected EGL cube map enum value.");
    static_assert(EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 5,
                  "Unexpected EGL cube map enum value.");
    
    bool IsCubeMapTextureTarget(EGLenum target)
    {
        return (target >= FirstCubeMapTextureTarget && target <= LastCubeMapTextureTarget);
    }
    
    size_t CubeMapTextureTargetToLayerIndex(EGLenum target)
    {
        ASSERT(IsCubeMapTextureTarget(target));
        return target - static_cast<size_t>(FirstCubeMapTextureTarget);
    }
    
    EGLenum LayerIndexToCubeMapTextureTarget(size_t index)
    {
        ASSERT(index <= (LastCubeMapTextureTarget - FirstCubeMapTextureTarget));
        return FirstCubeMapTextureTarget + static_cast<GLenum>(index);
    }
    
    bool IsTextureTarget(EGLenum target)
    {
        switch (target)
        {
            case EGL_GL_TEXTURE_2D_KHR:
            case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR:
            case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR:
            case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR:
            case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR:
            case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR:
            case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR:
            case EGL_GL_TEXTURE_3D_KHR:
                return true;
    
            default:
                return false;
        }
    }
    
    bool IsRenderbufferTarget(EGLenum target)
    {
        return target == EGL_GL_RENDERBUFFER_KHR;
    }
    
    bool IsExternalImageTarget(EGLenum target)
    {
        switch (target)
        {
            case EGL_NATIVE_BUFFER_ANDROID:
            case EGL_D3D11_TEXTURE_ANGLE:
            case EGL_LINUX_DMA_BUF_EXT:
                return true;
    
            default:
                return false;
        }
    }
    
    const char *GetGenericErrorMessage(EGLint error)
    {
        switch (error)
        {
            case EGL_SUCCESS:
                return "";
            case EGL_NOT_INITIALIZED:
                return "Not initialized.";
            case EGL_BAD_ACCESS:
                return "Bad access.";
            case EGL_BAD_ALLOC:
                return "Bad allocation.";
            case EGL_BAD_ATTRIBUTE:
                return "Bad attribute.";
            case EGL_BAD_CONFIG:
                return "Bad config.";
            case EGL_BAD_CONTEXT:
                return "Bad context.";
            case EGL_BAD_CURRENT_SURFACE:
                return "Bad current surface.";
            case EGL_BAD_DISPLAY:
                return "Bad display.";
            case EGL_BAD_MATCH:
                return "Bad match.";
            case EGL_BAD_NATIVE_WINDOW:
                return "Bad native window.";
            case EGL_BAD_NATIVE_PIXMAP:
                return "Bad native pixmap.";
            case EGL_BAD_PARAMETER:
                return "Bad parameter.";
            case EGL_BAD_SURFACE:
                return "Bad surface.";
            case EGL_CONTEXT_LOST:
                return "Context lost.";
            case EGL_BAD_STREAM_KHR:
                return "Bad stream.";
            case EGL_BAD_STATE_KHR:
                return "Bad state.";
            case EGL_BAD_DEVICE_EXT:
                return "Bad device.";
            default:
                UNREACHABLE();
                return "Unknown error.";
        }
    }
    
    }  // namespace egl
    
    namespace egl_gl
    {
    GLuint EGLClientBufferToGLObjectHandle(EGLClientBuffer buffer)
    {
        return static_cast<GLuint>(reinterpret_cast<uintptr_t>(buffer));
    }
    }  // namespace egl_gl
    
    namespace gl_egl
    {
    EGLenum GLComponentTypeToEGLColorComponentType(GLenum glComponentType)
    {
        switch (glComponentType)
        {
            case GL_FLOAT:
                return EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT;
    
            case GL_UNSIGNED_NORMALIZED:
                return EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
    
            default:
                UNREACHABLE();
                return EGL_NONE;
        }
    }
    
    EGLClientBuffer GLObjectHandleToEGLClientBuffer(GLuint handle)
    {
        return reinterpret_cast<EGLClientBuffer>(static_cast<uintptr_t>(handle));
    }
    
    }  // namespace gl_egl
    
    #if !defined(ANGLE_ENABLE_WINDOWS_UWP)
    std::string getTempPath()
    {
    #    ifdef ANGLE_PLATFORM_WINDOWS
        char path[MAX_PATH];
        DWORD pathLen = GetTempPathA(sizeof(path) / sizeof(path[0]), path);
        if (pathLen == 0)
        {
            UNREACHABLE();
            return std::string();
        }
    
        UINT unique = GetTempFileNameA(path, "sh", 0, path);
        if (unique == 0)
        {
            UNREACHABLE();
            return std::string();
        }
    
        return path;
    #    else
        UNIMPLEMENTED();
        return "";
    #    endif
    }
    
    void writeFile(const char *path, const void *content, size_t size)
    {
        FILE *file = fopen(path, "w");
        if (!file)
        {
            UNREACHABLE();
            return;
        }
    
        fwrite(content, sizeof(char), size, file);
        fclose(file);
    }
    #endif  // !ANGLE_ENABLE_WINDOWS_UWP
    
    #if defined(ANGLE_PLATFORM_WINDOWS)
    
    // Causes the thread to relinquish the remainder of its time slice to any
    // other thread that is ready to run.If there are no other threads ready
    // to run, the function returns immediately, and the thread continues execution.
    void ScheduleYield()
    {
        Sleep(0);
    }
    
    #endif