Edit

kc3-lang/angle/src/common/PackedEnums.h

Branch :

  • Show log

    Commit

  • Author : Shahbaz Youssefi
    Date : 2020-12-04 12:14:37
    Hash : b35a468a
    Message : Vulkan: Support geometry/tessellation primitive topologies Bug: angleproject:5406 Change-Id: Ifb7553e87164c204353e1ed94b8d64f5fb4b7206 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2574822 Reviewed-by: Jamie Madill <jmadill@chromium.org> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>

  • src/common/PackedEnums.h
  • // Copyright 2017 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.
    //
    // PackedGLEnums_autogen.h:
    //   Declares ANGLE-specific enums classes for GLEnum and functions operating
    //   on them.
    
    #ifndef COMMON_PACKEDGLENUMS_H_
    #define COMMON_PACKEDGLENUMS_H_
    
    #include "common/PackedEGLEnums_autogen.h"
    #include "common/PackedGLEnums_autogen.h"
    
    #include <array>
    #include <bitset>
    #include <cstddef>
    
    #include <EGL/egl.h>
    
    #include "common/bitset_utils.h"
    
    namespace angle
    {
    
    // Return the number of elements of a packed enum, including the InvalidEnum element.
    template <typename E>
    constexpr size_t EnumSize()
    {
        using UnderlyingType = typename std::underlying_type<E>::type;
        return static_cast<UnderlyingType>(E::EnumCount);
    }
    
    // Implementation of AllEnums which allows iterating over all the possible values for a packed enums
    // like so:
    //     for (auto value : AllEnums<MyPackedEnum>()) {
    //         // Do something with the enum.
    //     }
    
    template <typename E>
    class EnumIterator final
    {
      private:
        using UnderlyingType = typename std::underlying_type<E>::type;
    
      public:
        EnumIterator(E value) : mValue(static_cast<UnderlyingType>(value)) {}
        EnumIterator &operator++()
        {
            mValue++;
            return *this;
        }
        bool operator==(const EnumIterator &other) const { return mValue == other.mValue; }
        bool operator!=(const EnumIterator &other) const { return mValue != other.mValue; }
        E operator*() const { return static_cast<E>(mValue); }
    
      private:
        UnderlyingType mValue;
    };
    
    template <typename E>
    struct AllEnums
    {
        EnumIterator<E> begin() const { return {static_cast<E>(0)}; }
        EnumIterator<E> end() const { return {E::InvalidEnum}; }
    };
    
    // PackedEnumMap<E, T> is like an std::array<T, E::EnumCount> but is indexed with enum values. It
    // implements all of the std::array interface except with enum values instead of indices.
    template <typename E, typename T, size_t MaxSize = EnumSize<E>()>
    class PackedEnumMap
    {
        using UnderlyingType = typename std::underlying_type<E>::type;
        using Storage        = std::array<T, MaxSize>;
    
      public:
        using InitPair = std::pair<E, T>;
    
        constexpr PackedEnumMap() = default;
    
        constexpr PackedEnumMap(std::initializer_list<InitPair> init) : mPrivateData{}
        {
            // We use a for loop instead of range-for to work around a limitation in MSVC.
            for (const InitPair *it = init.begin(); it != init.end(); ++it)
            {
    #if (__cplusplus < 201703L)
                // This horrible const_cast pattern is necessary to work around a constexpr limitation.
                // See https://stackoverflow.com/q/34199774/ . Note that it should be fixed with C++17.
                const_cast<T &>(const_cast<const Storage &>(
                    mPrivateData)[static_cast<UnderlyingType>(it->first)]) = it->second;
    #else
                mPrivateData[static_cast<UnderlyingType>(it->first)] = it->second;
    #endif
            }
        }
    
        // types:
        using value_type      = T;
        using pointer         = T *;
        using const_pointer   = const T *;
        using reference       = T &;
        using const_reference = const T &;
    
        using size_type       = size_t;
        using difference_type = ptrdiff_t;
    
        using iterator               = typename Storage::iterator;
        using const_iterator         = typename Storage::const_iterator;
        using reverse_iterator       = std::reverse_iterator<iterator>;
        using const_reverse_iterator = std::reverse_iterator<const_iterator>;
    
        // No explicit construct/copy/destroy for aggregate type
        void fill(const T &u) { mPrivateData.fill(u); }
        void swap(PackedEnumMap<E, T, MaxSize> &a) noexcept { mPrivateData.swap(a.mPrivateData); }
    
        // iterators:
        iterator begin() noexcept { return mPrivateData.begin(); }
        const_iterator begin() const noexcept { return mPrivateData.begin(); }
        iterator end() noexcept { return mPrivateData.end(); }
        const_iterator end() const noexcept { return mPrivateData.end(); }
    
        reverse_iterator rbegin() noexcept { return mPrivateData.rbegin(); }
        const_reverse_iterator rbegin() const noexcept { return mPrivateData.rbegin(); }
        reverse_iterator rend() noexcept { return mPrivateData.rend(); }
        const_reverse_iterator rend() const noexcept { return mPrivateData.rend(); }
    
        // capacity:
        constexpr size_type size() const noexcept { return mPrivateData.size(); }
        constexpr size_type max_size() const noexcept { return mPrivateData.max_size(); }
        constexpr bool empty() const noexcept { return mPrivateData.empty(); }
    
        // element access:
        reference operator[](E n)
        {
            ASSERT(static_cast<size_t>(n) < mPrivateData.size());
            return mPrivateData[static_cast<UnderlyingType>(n)];
        }
    
        constexpr const_reference operator[](E n) const
        {
            ASSERT(static_cast<size_t>(n) < mPrivateData.size());
            return mPrivateData[static_cast<UnderlyingType>(n)];
        }
    
        const_reference at(E n) const { return mPrivateData.at(static_cast<UnderlyingType>(n)); }
        reference at(E n) { return mPrivateData.at(static_cast<UnderlyingType>(n)); }
    
        reference front() { return mPrivateData.front(); }
        const_reference front() const { return mPrivateData.front(); }
        reference back() { return mPrivateData.back(); }
        const_reference back() const { return mPrivateData.back(); }
    
        T *data() noexcept { return mPrivateData.data(); }
        const T *data() const noexcept { return mPrivateData.data(); }
    
        bool operator==(const PackedEnumMap &rhs) const { return mPrivateData == rhs.mPrivateData; }
        bool operator!=(const PackedEnumMap &rhs) const { return mPrivateData != rhs.mPrivateData; }
    
      private:
        Storage mPrivateData;
    };
    
    // PackedEnumBitSetE> is like an std::bitset<E::EnumCount> but is indexed with enum values. It
    // implements the std::bitset interface except with enum values instead of indices.
    template <typename E, typename DataT = uint32_t>
    using PackedEnumBitSet = BitSetT<EnumSize<E>(), DataT, E>;
    
    }  // namespace angle
    
    namespace gl
    {
    
    TextureType TextureTargetToType(TextureTarget target);
    TextureTarget NonCubeTextureTypeToTarget(TextureType type);
    
    TextureTarget CubeFaceIndexToTextureTarget(size_t face);
    size_t CubeMapTextureTargetToFaceIndex(TextureTarget target);
    bool IsCubeMapFaceTarget(TextureTarget target);
    
    constexpr TextureTarget kCubeMapTextureTargetMin = TextureTarget::CubeMapPositiveX;
    constexpr TextureTarget kCubeMapTextureTargetMax = TextureTarget::CubeMapNegativeZ;
    constexpr TextureTarget kAfterCubeMapTextureTargetMax =
        static_cast<TextureTarget>(static_cast<uint8_t>(kCubeMapTextureTargetMax) + 1);
    struct AllCubeFaceTextureTargets
    {
        angle::EnumIterator<TextureTarget> begin() const { return kCubeMapTextureTargetMin; }
        angle::EnumIterator<TextureTarget> end() const { return kAfterCubeMapTextureTargetMax; }
    };
    
    constexpr std::array<ShaderType, 2> kAllGLES2ShaderTypes = {ShaderType::Vertex,
                                                                ShaderType::Fragment};
    
    constexpr ShaderType kShaderTypeMin = ShaderType::Vertex;
    constexpr ShaderType kShaderTypeMax = ShaderType::Compute;
    constexpr ShaderType kAfterShaderTypeMax =
        static_cast<ShaderType>(static_cast<uint8_t>(kShaderTypeMax) + 1);
    struct AllShaderTypes
    {
        angle::EnumIterator<ShaderType> begin() const { return kShaderTypeMin; }
        angle::EnumIterator<ShaderType> end() const { return kAfterShaderTypeMax; }
    };
    
    constexpr size_t kGraphicsShaderCount = static_cast<size_t>(ShaderType::EnumCount) - 1u;
    // Arrange the shader types in the order of rendering pipeline
    constexpr std::array<ShaderType, kGraphicsShaderCount> kAllGraphicsShaderTypes = {
        ShaderType::Vertex, ShaderType::TessControl, ShaderType::TessEvaluation, ShaderType::Geometry,
        ShaderType::Fragment};
    
    using ShaderBitSet = angle::PackedEnumBitSet<ShaderType, uint8_t>;
    static_assert(sizeof(ShaderBitSet) == sizeof(uint8_t), "Unexpected size");
    
    template <typename T>
    using ShaderMap = angle::PackedEnumMap<ShaderType, T>;
    
    TextureType SamplerTypeToTextureType(GLenum samplerType);
    TextureType ImageTypeToTextureType(GLenum imageType);
    
    bool IsMultisampled(gl::TextureType type);
    bool IsArrayTextureType(gl::TextureType type);
    
    bool IsStaticBufferUsage(BufferUsage useage);
    
    enum class PrimitiveMode : uint8_t
    {
        Points                 = 0x0,
        Lines                  = 0x1,
        LineLoop               = 0x2,
        LineStrip              = 0x3,
        Triangles              = 0x4,
        TriangleStrip          = 0x5,
        TriangleFan            = 0x6,
        Unused1                = 0x7,
        Unused2                = 0x8,
        Unused3                = 0x9,
        LinesAdjacency         = 0xA,
        LineStripAdjacency     = 0xB,
        TrianglesAdjacency     = 0xC,
        TriangleStripAdjacency = 0xD,
        Patches                = 0xE,
    
        InvalidEnum = 0xF,
        EnumCount   = 0xF,
    };
    
    template <>
    constexpr PrimitiveMode FromGLenum<PrimitiveMode>(GLenum from)
    {
        if (from >= static_cast<GLenum>(PrimitiveMode::EnumCount))
        {
            return PrimitiveMode::InvalidEnum;
        }
    
        return static_cast<PrimitiveMode>(from);
    }
    
    constexpr GLenum ToGLenum(PrimitiveMode from)
    {
        return static_cast<GLenum>(from);
    }
    
    static_assert(ToGLenum(PrimitiveMode::Points) == GL_POINTS, "PrimitiveMode violation");
    static_assert(ToGLenum(PrimitiveMode::Lines) == GL_LINES, "PrimitiveMode violation");
    static_assert(ToGLenum(PrimitiveMode::LineLoop) == GL_LINE_LOOP, "PrimitiveMode violation");
    static_assert(ToGLenum(PrimitiveMode::LineStrip) == GL_LINE_STRIP, "PrimitiveMode violation");
    static_assert(ToGLenum(PrimitiveMode::Triangles) == GL_TRIANGLES, "PrimitiveMode violation");
    static_assert(ToGLenum(PrimitiveMode::TriangleStrip) == GL_TRIANGLE_STRIP,
                  "PrimitiveMode violation");
    static_assert(ToGLenum(PrimitiveMode::TriangleFan) == GL_TRIANGLE_FAN, "PrimitiveMode violation");
    static_assert(ToGLenum(PrimitiveMode::LinesAdjacency) == GL_LINES_ADJACENCY,
                  "PrimitiveMode violation");
    static_assert(ToGLenum(PrimitiveMode::LineStripAdjacency) == GL_LINE_STRIP_ADJACENCY,
                  "PrimitiveMode violation");
    static_assert(ToGLenum(PrimitiveMode::TrianglesAdjacency) == GL_TRIANGLES_ADJACENCY,
                  "PrimitiveMode violation");
    static_assert(ToGLenum(PrimitiveMode::TriangleStripAdjacency) == GL_TRIANGLE_STRIP_ADJACENCY,
                  "PrimitiveMode violation");
    
    std::ostream &operator<<(std::ostream &os, PrimitiveMode value);
    
    enum class DrawElementsType : size_t
    {
        UnsignedByte  = 0,
        UnsignedShort = 1,
        UnsignedInt   = 2,
        InvalidEnum   = 3,
        EnumCount     = 3,
    };
    
    template <>
    constexpr DrawElementsType FromGLenum<DrawElementsType>(GLenum from)
    {
    
        GLenum scaled = (from - GL_UNSIGNED_BYTE);
        // This code sequence generates a ROR instruction on x86/arm. We want to check if the lowest bit
        // of scaled is set and if (scaled >> 1) is greater than a non-pot value. If we rotate the
        // lowest bit to the hightest bit both conditions can be checked with a single test.
        static_assert(sizeof(GLenum) == 4, "Update (scaled << 31) to sizeof(GLenum) * 8 - 1");
        GLenum packed = (scaled >> 1) | (scaled << 31);
    
        // operator ? with a simple assignment usually translates to a cmov instruction and thus avoids
        // a branch.
        packed = (packed >= static_cast<GLenum>(DrawElementsType::EnumCount))
                     ? static_cast<GLenum>(DrawElementsType::InvalidEnum)
                     : packed;
    
        return static_cast<DrawElementsType>(packed);
    }
    
    constexpr GLenum ToGLenum(DrawElementsType from)
    {
        return ((static_cast<GLenum>(from) << 1) + GL_UNSIGNED_BYTE);
    }
    
    #define ANGLE_VALIDATE_PACKED_ENUM(type, packed, glenum)                 \
        static_assert(ToGLenum(type::packed) == glenum, #type " violation"); \
        static_assert(FromGLenum<type>(glenum) == type::packed, #type " violation")
    
    ANGLE_VALIDATE_PACKED_ENUM(DrawElementsType, UnsignedByte, GL_UNSIGNED_BYTE);
    ANGLE_VALIDATE_PACKED_ENUM(DrawElementsType, UnsignedShort, GL_UNSIGNED_SHORT);
    ANGLE_VALIDATE_PACKED_ENUM(DrawElementsType, UnsignedInt, GL_UNSIGNED_INT);
    
    std::ostream &operator<<(std::ostream &os, DrawElementsType value);
    
    enum class BlendEquationType
    {
        Add             = 0,  // GLenum == 0x8006
        Min             = 1,  // GLenum == 0x8007
        Max             = 2,  // GLenum == 0x8008
        Unused          = 3,
        Subtract        = 4,  // GLenum == 0x800A
        ReverseSubtract = 5,  // GLenum == 0x800B
        InvalidEnum     = 6,
        EnumCount       = 6
    };
    
    template <>
    constexpr BlendEquationType FromGLenum<BlendEquationType>(GLenum from)
    {
        const GLenum scaled = (from - GL_FUNC_ADD);
        return (scaled == static_cast<GLenum>(BlendEquationType::Unused) ||
                scaled >= static_cast<GLenum>(BlendEquationType::EnumCount))
                   ? BlendEquationType::InvalidEnum
                   : static_cast<BlendEquationType>(scaled);
    }
    
    constexpr GLenum ToGLenum(BlendEquationType from)
    {
        return static_cast<GLenum>(from) + GL_FUNC_ADD;
    }
    
    ANGLE_VALIDATE_PACKED_ENUM(BlendEquationType, Add, GL_FUNC_ADD);
    ANGLE_VALIDATE_PACKED_ENUM(BlendEquationType, Min, GL_MIN);
    ANGLE_VALIDATE_PACKED_ENUM(BlendEquationType, Max, GL_MAX);
    ANGLE_VALIDATE_PACKED_ENUM(BlendEquationType, Subtract, GL_FUNC_SUBTRACT);
    ANGLE_VALIDATE_PACKED_ENUM(BlendEquationType, ReverseSubtract, GL_FUNC_REVERSE_SUBTRACT);
    
    std::ostream &operator<<(std::ostream &os, BlendEquationType value);
    
    enum class BlendFactorType
    {
        Zero = 0,  // GLenum == 0
        One  = 1,  // GLenum == 1
    
        MinSrcDstType    = 2,
        SrcColor         = 2,   // GLenum == 0x0300
        OneMinusSrcColor = 3,   // GLenum == 0x0301
        SrcAlpha         = 4,   // GLenum == 0x0302
        OneMinusSrcAlpha = 5,   // GLenum == 0x0303
        DstAlpha         = 6,   // GLenum == 0x0304
        OneMinusDstAlpha = 7,   // GLenum == 0x0305
        DstColor         = 8,   // GLenum == 0x0306
        OneMinusDstColor = 9,   // GLenum == 0x0307
        SrcAlphaSaturate = 10,  // GLenum == 0x0308
        MaxSrcDstType    = 10,
    
        MinConstantType       = 11,
        ConstantColor         = 11,  // GLenum == 0x8001
        OneMinusConstantColor = 12,  // GLenum == 0x8002
        ConstantAlpha         = 13,  // GLenum == 0x8003
        OneMinusConstantAlpha = 14,  // GLenum == 0x8004
        MaxConstantType       = 14,
    
        // GL_EXT_blend_func_extended
    
        Src1Alpha = 15,  // GLenum == 0x8589
    
        Src1Color         = 16,  // GLenum == 0x88F9
        OneMinusSrc1Color = 17,  // GLenum == 0x88FA
        OneMinusSrc1Alpha = 18,  // GLenum == 0x88FB
    
        InvalidEnum = 19,
        EnumCount   = 19
    };
    
    template <>
    constexpr BlendFactorType FromGLenum<BlendFactorType>(GLenum from)
    {
        if (from <= 1)
            return static_cast<BlendFactorType>(from);
        if (from >= GL_SRC_COLOR && from <= GL_SRC_ALPHA_SATURATE)
            return static_cast<BlendFactorType>(from - GL_SRC_COLOR + 2);
        if (from >= GL_CONSTANT_COLOR && from <= GL_ONE_MINUS_CONSTANT_ALPHA)
            return static_cast<BlendFactorType>(from - GL_CONSTANT_COLOR + 11);
        if (from == GL_SRC1_ALPHA_EXT)
            return BlendFactorType::Src1Alpha;
        if (from >= GL_SRC1_COLOR_EXT && from <= GL_ONE_MINUS_SRC1_ALPHA_EXT)
            return static_cast<BlendFactorType>(from - GL_SRC1_COLOR_EXT + 16);
        return BlendFactorType::InvalidEnum;
    }
    
    constexpr GLenum ToGLenum(BlendFactorType from)
    {
        const GLenum value = static_cast<GLenum>(from);
        if (value <= 1)
            return value;
        if (from >= BlendFactorType::MinSrcDstType && from <= BlendFactorType::MaxSrcDstType)
            return value - 2 + GL_SRC_COLOR;
        if (from >= BlendFactorType::MinConstantType && from <= BlendFactorType::MaxConstantType)
            return value - 11 + GL_CONSTANT_COLOR;
        if (from == BlendFactorType::Src1Alpha)
            return GL_SRC1_ALPHA_EXT;
        return value - 16 + GL_SRC1_COLOR_EXT;
    }
    
    ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, Zero, GL_ZERO);
    ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, One, GL_ONE);
    ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, SrcColor, GL_SRC_COLOR);
    ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, OneMinusSrcColor, GL_ONE_MINUS_SRC_COLOR);
    ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, SrcAlpha, GL_SRC_ALPHA);
    ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, OneMinusSrcAlpha, GL_ONE_MINUS_SRC_ALPHA);
    ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, DstAlpha, GL_DST_ALPHA);
    ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, OneMinusDstAlpha, GL_ONE_MINUS_DST_ALPHA);
    ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, DstColor, GL_DST_COLOR);
    ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, OneMinusDstColor, GL_ONE_MINUS_DST_COLOR);
    ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, SrcAlphaSaturate, GL_SRC_ALPHA_SATURATE);
    ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, ConstantColor, GL_CONSTANT_COLOR);
    ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, OneMinusConstantColor, GL_ONE_MINUS_CONSTANT_COLOR);
    ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, ConstantAlpha, GL_CONSTANT_ALPHA);
    ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, OneMinusConstantAlpha, GL_ONE_MINUS_CONSTANT_ALPHA);
    ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, Src1Alpha, GL_SRC1_ALPHA_EXT);
    ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, Src1Color, GL_SRC1_COLOR_EXT);
    ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, OneMinusSrc1Color, GL_ONE_MINUS_SRC1_COLOR_EXT);
    ANGLE_VALIDATE_PACKED_ENUM(BlendFactorType, OneMinusSrc1Alpha, GL_ONE_MINUS_SRC1_ALPHA_EXT);
    
    std::ostream &operator<<(std::ostream &os, BlendFactorType value);
    
    enum class VertexAttribType
    {
        Byte               = 0,   // GLenum == 0x1400
        UnsignedByte       = 1,   // GLenum == 0x1401
        Short              = 2,   // GLenum == 0x1402
        UnsignedShort      = 3,   // GLenum == 0x1403
        Int                = 4,   // GLenum == 0x1404
        UnsignedInt        = 5,   // GLenum == 0x1405
        Float              = 6,   // GLenum == 0x1406
        Unused1            = 7,   // GLenum == 0x1407
        Unused2            = 8,   // GLenum == 0x1408
        Unused3            = 9,   // GLenum == 0x1409
        Unused4            = 10,  // GLenum == 0x140A
        HalfFloat          = 11,  // GLenum == 0x140B
        Fixed              = 12,  // GLenum == 0x140C
        MaxBasicType       = 12,
        UnsignedInt2101010 = 13,  // GLenum == 0x8368
        HalfFloatOES       = 14,  // GLenum == 0x8D61
        Int2101010         = 15,  // GLenum == 0x8D9F
        UnsignedInt1010102 = 16,  // GLenum == 0x8DF6
        Int1010102         = 17,  // GLenum == 0x8DF7
        InvalidEnum        = 18,
        EnumCount          = 18,
    };
    
    template <>
    constexpr VertexAttribType FromGLenum<VertexAttribType>(GLenum from)
    {
        GLenum packed = from - GL_BYTE;
        if (packed <= static_cast<GLenum>(VertexAttribType::MaxBasicType))
            return static_cast<VertexAttribType>(packed);
        if (from == GL_UNSIGNED_INT_2_10_10_10_REV)
            return VertexAttribType::UnsignedInt2101010;
        if (from == GL_HALF_FLOAT_OES)
            return VertexAttribType::HalfFloatOES;
        if (from == GL_INT_2_10_10_10_REV)
            return VertexAttribType::Int2101010;
        if (from == GL_UNSIGNED_INT_10_10_10_2_OES)
            return VertexAttribType::UnsignedInt1010102;
        if (from == GL_INT_10_10_10_2_OES)
            return VertexAttribType::Int1010102;
        return VertexAttribType::InvalidEnum;
    }
    
    constexpr GLenum ToGLenum(VertexAttribType from)
    {
        // This could be optimized using a constexpr table.
        if (from == VertexAttribType::Int2101010)
            return GL_INT_2_10_10_10_REV;
        if (from == VertexAttribType::HalfFloatOES)
            return GL_HALF_FLOAT_OES;
        if (from == VertexAttribType::UnsignedInt2101010)
            return GL_UNSIGNED_INT_2_10_10_10_REV;
        if (from == VertexAttribType::UnsignedInt1010102)
            return GL_UNSIGNED_INT_10_10_10_2_OES;
        if (from == VertexAttribType::Int1010102)
            return GL_INT_10_10_10_2_OES;
        return static_cast<GLenum>(from) + GL_BYTE;
    }
    
    ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Byte, GL_BYTE);
    ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedByte, GL_UNSIGNED_BYTE);
    ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Short, GL_SHORT);
    ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedShort, GL_UNSIGNED_SHORT);
    ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Int, GL_INT);
    ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedInt, GL_UNSIGNED_INT);
    ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Float, GL_FLOAT);
    ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, HalfFloat, GL_HALF_FLOAT);
    ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Fixed, GL_FIXED);
    ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Int2101010, GL_INT_2_10_10_10_REV);
    ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, HalfFloatOES, GL_HALF_FLOAT_OES);
    ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedInt2101010, GL_UNSIGNED_INT_2_10_10_10_REV);
    ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, Int1010102, GL_INT_10_10_10_2_OES);
    ANGLE_VALIDATE_PACKED_ENUM(VertexAttribType, UnsignedInt1010102, GL_UNSIGNED_INT_10_10_10_2_OES);
    
    std::ostream &operator<<(std::ostream &os, VertexAttribType value);
    
    enum class TessEvaluationType
    {
        Triangles             = 0,
        Quads                 = 1,
        Isolines              = 2,
        EqualSpacing          = 3,
        FractionalEvenSpacing = 4,
        FractionalOddSpacing  = 5,
        Cw                    = 6,
        Ccw                   = 7,
        PointMode             = 8,
        InvalidEnum           = 9,
        EnumCount             = 9
    };
    
    template <>
    constexpr TessEvaluationType FromGLenum<TessEvaluationType>(GLenum from)
    {
        if (from == GL_TRIANGLES)
            return TessEvaluationType::Triangles;
        if (from == GL_QUADS)
            return TessEvaluationType::Quads;
        if (from == GL_ISOLINES)
            return TessEvaluationType::Isolines;
        if (from == GL_EQUAL)
            return TessEvaluationType::EqualSpacing;
        if (from == GL_FRACTIONAL_EVEN)
            return TessEvaluationType::FractionalEvenSpacing;
        if (from == GL_FRACTIONAL_ODD)
            return TessEvaluationType::FractionalOddSpacing;
        if (from == GL_CW)
            return TessEvaluationType::Cw;
        if (from == GL_CCW)
            return TessEvaluationType::Ccw;
        if (from == GL_TESS_GEN_POINT_MODE)
            return TessEvaluationType::PointMode;
        return TessEvaluationType::InvalidEnum;
    }
    
    constexpr GLenum ToGLenum(TessEvaluationType from)
    {
        switch (from)
        {
            case TessEvaluationType::Triangles:
                return GL_TRIANGLES;
            case TessEvaluationType::Quads:
                return GL_QUADS;
            case TessEvaluationType::Isolines:
                return GL_ISOLINES;
            case TessEvaluationType::EqualSpacing:
                return GL_EQUAL;
            case TessEvaluationType::FractionalEvenSpacing:
                return GL_FRACTIONAL_EVEN;
            case TessEvaluationType::FractionalOddSpacing:
                return GL_FRACTIONAL_ODD;
            case TessEvaluationType::Cw:
                return GL_CW;
            case TessEvaluationType::Ccw:
                return GL_CCW;
            case TessEvaluationType::PointMode:
                return GL_TESS_GEN_POINT_MODE;
            default:
                return GL_INVALID_ENUM;
        }
    }
    
    ANGLE_VALIDATE_PACKED_ENUM(TessEvaluationType, Triangles, GL_TRIANGLES);
    ANGLE_VALIDATE_PACKED_ENUM(TessEvaluationType, Quads, GL_QUADS);
    ANGLE_VALIDATE_PACKED_ENUM(TessEvaluationType, Isolines, GL_ISOLINES);
    ANGLE_VALIDATE_PACKED_ENUM(TessEvaluationType, EqualSpacing, GL_EQUAL);
    ANGLE_VALIDATE_PACKED_ENUM(TessEvaluationType, FractionalEvenSpacing, GL_FRACTIONAL_EVEN);
    ANGLE_VALIDATE_PACKED_ENUM(TessEvaluationType, FractionalOddSpacing, GL_FRACTIONAL_ODD);
    ANGLE_VALIDATE_PACKED_ENUM(TessEvaluationType, Cw, GL_CW);
    ANGLE_VALIDATE_PACKED_ENUM(TessEvaluationType, Ccw, GL_CCW);
    ANGLE_VALIDATE_PACKED_ENUM(TessEvaluationType, PointMode, GL_TESS_GEN_POINT_MODE);
    
    std::ostream &operator<<(std::ostream &os, TessEvaluationType value);
    
    // Typesafe object handles.
    
    template <typename T>
    struct ResourceTypeToID;
    
    template <typename T>
    struct IsResourceIDType;
    
    // Clang Format doesn't like the following X macro.
    // clang-format off
    #define ANGLE_ID_TYPES_OP(X) \
        X(Buffer)                \
        X(FenceNV)               \
        X(Framebuffer)           \
        X(MemoryObject)          \
        X(Path)                  \
        X(ProgramPipeline)       \
        X(Query)                 \
        X(Renderbuffer)          \
        X(Sampler)               \
        X(Semaphore)             \
        X(Texture)               \
        X(TransformFeedback)     \
        X(VertexArray)
    // clang-format on
    
    #define ANGLE_DEFINE_ID_TYPE(Type)          \
        class Type;                             \
        struct Type##ID                         \
        {                                       \
            GLuint value;                       \
        };                                      \
        template <>                             \
        struct ResourceTypeToID<Type>           \
        {                                       \
            using IDType = Type##ID;            \
        };                                      \
        template <>                             \
        struct IsResourceIDType<Type##ID>       \
        {                                       \
            static constexpr bool value = true; \
        };
    
    ANGLE_ID_TYPES_OP(ANGLE_DEFINE_ID_TYPE)
    
    #undef ANGLE_DEFINE_ID_TYPE
    #undef ANGLE_ID_TYPES_OP
    
    // Shaders and programs are a bit special as they share IDs.
    struct ShaderProgramID
    {
        GLuint value;
    };
    
    template <>
    struct IsResourceIDType<ShaderProgramID>
    {
        constexpr static bool value = true;
    };
    
    class Shader;
    template <>
    struct ResourceTypeToID<Shader>
    {
        using IDType = ShaderProgramID;
    };
    
    class Program;
    template <>
    struct ResourceTypeToID<Program>
    {
        using IDType = ShaderProgramID;
    };
    
    template <typename T>
    struct ResourceTypeToID
    {
        using IDType = void;
    };
    
    template <typename T>
    struct IsResourceIDType
    {
        static constexpr bool value = false;
    };
    
    template <typename T>
    bool ValueEquals(T lhs, T rhs)
    {
        return lhs.value == rhs.value;
    }
    
    // Util funcs for resourceIDs
    template <typename T>
    typename std::enable_if<IsResourceIDType<T>::value, bool>::type operator==(const T &lhs,
                                                                               const T &rhs)
    {
        return lhs.value == rhs.value;
    }
    
    template <typename T>
    typename std::enable_if<IsResourceIDType<T>::value, bool>::type operator!=(const T &lhs,
                                                                               const T &rhs)
    {
        return lhs.value != rhs.value;
    }
    
    template <typename T>
    typename std::enable_if<IsResourceIDType<T>::value, bool>::type operator<(const T &lhs,
                                                                              const T &rhs)
    {
        return lhs.value < rhs.value;
    }
    
    // Used to unbox typed values.
    template <typename ResourceIDType>
    GLuint GetIDValue(ResourceIDType id);
    
    template <>
    inline GLuint GetIDValue(GLuint id)
    {
        return id;
    }
    
    template <typename ResourceIDType>
    inline GLuint GetIDValue(ResourceIDType id)
    {
        return id.value;
    }
    
    // First case: handling packed enums.
    template <typename EnumT, typename FromT>
    typename std::enable_if<std::is_enum<EnumT>::value, EnumT>::type PackParam(FromT from)
    {
        return FromGLenum<EnumT>(from);
    }
    
    // Second case: handling non-pointer resource ids.
    template <typename EnumT, typename FromT>
    typename std::enable_if<!std::is_pointer<FromT>::value && !std::is_enum<EnumT>::value, EnumT>::type
    PackParam(FromT from)
    {
        return {from};
    }
    
    // Third case: handling pointer resource ids.
    template <typename EnumT, typename FromT>
    typename std::enable_if<std::is_pointer<FromT>::value && !std::is_enum<EnumT>::value, EnumT>::type
    PackParam(FromT from)
    {
        return reinterpret_cast<EnumT>(from);
    }
    
    struct UniformLocation
    {
        int value;
    };
    }  // namespace gl
    
    namespace egl
    {
    MessageType ErrorCodeToMessageType(EGLint errorCode);
    }  // namespace egl
    
    namespace egl_gl
    {
    gl::TextureTarget EGLCubeMapTargetToCubeMapTarget(EGLenum eglTarget);
    gl::TextureTarget EGLImageTargetToTextureTarget(EGLenum eglTarget);
    gl::TextureType EGLTextureTargetToTextureType(EGLenum eglTarget);
    }  // namespace egl_gl
    
    #endif  // COMMON_PACKEDGLENUMS_H_