Edit

kc3-lang/angle/src/libANGLE/angletypes.h

Branch :

  • Show log

    Commit

  • Author : Peter Kasting
    Date : 2021-06-25 14:52:02
    Hash : d2816b4e
    Message : Fix a -Wdeprecated-copy warning. Bug: chromium:1221591 Change-Id: Idbbb4aa16e58a9f4e7e25590667cf15706233de4 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2989632 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Geoff Lang <geofflang@chromium.org>

  • src/libANGLE/angletypes.h
  • //
    // Copyright 2012 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.
    //
    
    // angletypes.h : Defines a variety of structures and enum types that are used throughout libGLESv2
    
    #ifndef LIBANGLE_ANGLETYPES_H_
    #define LIBANGLE_ANGLETYPES_H_
    
    #include "common/Color.h"
    #include "common/FixedVector.h"
    #include "common/PackedEnums.h"
    #include "common/bitset_utils.h"
    #include "common/vector_utils.h"
    #include "libANGLE/Constants.h"
    #include "libANGLE/Error.h"
    #include "libANGLE/RefCountObject.h"
    
    #include <inttypes.h>
    #include <stdint.h>
    
    #include <bitset>
    #include <map>
    #include <unordered_map>
    
    namespace gl
    {
    class Buffer;
    class Texture;
    
    enum class Command
    {
        Blit,
        Clear,
        CopyImage,
        Dispatch,
        Draw,
        GenerateMipmap,
        ReadPixels,
        TexImage,
        Other
    };
    
    enum class InitState
    {
        MayNeedInit,
        Initialized,
    };
    
    struct Rectangle
    {
        Rectangle() : x(0), y(0), width(0), height(0) {}
        constexpr Rectangle(int x_in, int y_in, int width_in, int height_in)
            : x(x_in), y(y_in), width(width_in), height(height_in)
        {}
    
        int x0() const { return x; }
        int y0() const { return y; }
        int x1() const { return x + width; }
        int y1() const { return y + height; }
    
        bool isReversedX() const { return width < 0; }
        bool isReversedY() const { return height < 0; }
    
        // Returns a rectangle with the same area but flipped in X, Y, neither or both.
        Rectangle flip(bool flipX, bool flipY) const;
    
        // Returns a rectangle with the same area but with height and width guaranteed to be positive.
        Rectangle removeReversal() const;
    
        bool encloses(const gl::Rectangle &inside) const;
    
        bool empty() const { return width == 0 && height == 0; }
    
        int x;
        int y;
        int width;
        int height;
    };
    
    bool operator==(const Rectangle &a, const Rectangle &b);
    bool operator!=(const Rectangle &a, const Rectangle &b);
    
    enum class ClipSpaceOrigin
    {
        LowerLeft = 0,
        UpperLeft = 1
    };
    
    // Calculate the intersection of two rectangles.  Returns false if the intersection is empty.
    ANGLE_NO_DISCARD bool ClipRectangle(const Rectangle &source,
                                        const Rectangle &clip,
                                        Rectangle *intersection);
    // Calculate the smallest rectangle that covers both rectangles.  This rectangle may cover areas
    // not covered by the two rectangles, for example in this situation:
    //
    //   +--+        +----+
    //   | ++-+  ->  |    |
    //   +-++ |      |    |
    //     +--+      +----+
    //
    void GetEnclosingRectangle(const Rectangle &rect1, const Rectangle &rect2, Rectangle *rectUnion);
    // Extend the source rectangle to cover parts (or all of) the second rectangle, in such a way that
    // no area is covered that isn't covered by both rectangles.  For example:
    //
    //             +--+        +--+
    //  source --> |  |        |  |
    //            ++--+-+  ->  |  |
    //            |+--+ |      |  |
    //            +-----+      +--+
    //
    void ExtendRectangle(const Rectangle &source, const Rectangle &extend, Rectangle *extended);
    
    struct Offset
    {
        constexpr Offset() : x(0), y(0), z(0) {}
        constexpr Offset(int x_in, int y_in, int z_in) : x(x_in), y(y_in), z(z_in) {}
    
        int x;
        int y;
        int z;
    };
    
    constexpr Offset kOffsetZero(0, 0, 0);
    
    bool operator==(const Offset &a, const Offset &b);
    bool operator!=(const Offset &a, const Offset &b);
    
    struct Extents
    {
        Extents() : width(0), height(0), depth(0) {}
        Extents(int width_, int height_, int depth_) : width(width_), height(height_), depth(depth_) {}
    
        Extents(const Extents &other) = default;
        Extents &operator=(const Extents &other) = default;
    
        bool empty() const { return (width * height * depth) == 0; }
    
        int width;
        int height;
        int depth;
    };
    
    bool operator==(const Extents &lhs, const Extents &rhs);
    bool operator!=(const Extents &lhs, const Extents &rhs);
    
    struct Box
    {
        Box() : x(0), y(0), z(0), width(0), height(0), depth(0) {}
        Box(int x_in, int y_in, int z_in, int width_in, int height_in, int depth_in)
            : x(x_in), y(y_in), z(z_in), width(width_in), height(height_in), depth(depth_in)
        {}
        template <typename O, typename E>
        Box(const O &offset, const E &size)
            : x(offset.x),
              y(offset.y),
              z(offset.z),
              width(size.width),
              height(size.height),
              depth(size.depth)
        {}
        bool operator==(const Box &other) const;
        bool operator!=(const Box &other) const;
        Rectangle toRect() const;
    
        // Whether the Box has offset 0 and the same extents as argument.
        bool coversSameExtent(const Extents &size) const;
    
        int x;
        int y;
        int z;
        int width;
        int height;
        int depth;
    };
    
    struct RasterizerState final
    {
        // This will zero-initialize the struct, including padding.
        RasterizerState();
        RasterizerState(const RasterizerState &other);
    
        bool cullFace;
        CullFaceMode cullMode;
        GLenum frontFace;
    
        bool polygonOffsetFill;
        GLfloat polygonOffsetFactor;
        GLfloat polygonOffsetUnits;
    
        // pointDrawMode/multiSample are only used in the D3D back-end right now.
        bool pointDrawMode;
        bool multiSample;
    
        bool rasterizerDiscard;
    
        bool dither;
    };
    
    bool operator==(const RasterizerState &a, const RasterizerState &b);
    bool operator!=(const RasterizerState &a, const RasterizerState &b);
    
    struct BlendState final
    {
        // This will zero-initialize the struct, including padding.
        BlendState();
        BlendState(const BlendState &other);
    
        bool blend;
        GLenum sourceBlendRGB;
        GLenum destBlendRGB;
        GLenum sourceBlendAlpha;
        GLenum destBlendAlpha;
        GLenum blendEquationRGB;
        GLenum blendEquationAlpha;
    
        bool colorMaskRed;
        bool colorMaskGreen;
        bool colorMaskBlue;
        bool colorMaskAlpha;
    };
    
    bool operator==(const BlendState &a, const BlendState &b);
    bool operator!=(const BlendState &a, const BlendState &b);
    
    struct DepthStencilState final
    {
        // This will zero-initialize the struct, including padding.
        DepthStencilState();
        DepthStencilState(const DepthStencilState &other);
    
        bool isDepthMaskedOut() const;
        bool isStencilMaskedOut() const;
        bool isStencilNoOp() const;
        bool isStencilBackNoOp() const;
    
        bool depthTest;
        GLenum depthFunc;
        bool depthMask;
    
        bool stencilTest;
        GLenum stencilFunc;
        GLuint stencilMask;
        GLenum stencilFail;
        GLenum stencilPassDepthFail;
        GLenum stencilPassDepthPass;
        GLuint stencilWritemask;
        GLenum stencilBackFunc;
        GLuint stencilBackMask;
        GLenum stencilBackFail;
        GLenum stencilBackPassDepthFail;
        GLenum stencilBackPassDepthPass;
        GLuint stencilBackWritemask;
    };
    
    bool operator==(const DepthStencilState &a, const DepthStencilState &b);
    bool operator!=(const DepthStencilState &a, const DepthStencilState &b);
    
    // Packs a sampler state for completeness checks:
    // * minFilter: 5 values (3 bits)
    // * magFilter: 2 values (1 bit)
    // * wrapS:     3 values (2 bits)
    // * wrapT:     3 values (2 bits)
    // * compareMode: 1 bit (for == GL_NONE).
    // This makes a total of 9 bits. We can pack this easily into 32 bits:
    // * minFilter: 8 bits
    // * magFilter: 8 bits
    // * wrapS:     8 bits
    // * wrapT:     4 bits
    // * compareMode: 4 bits
    
    struct PackedSamplerCompleteness
    {
        uint8_t minFilter;
        uint8_t magFilter;
        uint8_t wrapS;
        uint8_t wrapTCompareMode;
    };
    
    static_assert(sizeof(PackedSamplerCompleteness) == sizeof(uint32_t), "Unexpected size");
    
    // State from Table 6.10 (state per sampler object)
    class SamplerState final
    {
      public:
        // This will zero-initialize the struct, including padding.
        SamplerState();
        SamplerState(const SamplerState &other);
    
        SamplerState &operator=(const SamplerState &other);
    
        static SamplerState CreateDefaultForTarget(TextureType type);
    
        GLenum getMinFilter() const { return mMinFilter; }
    
        bool setMinFilter(GLenum minFilter);
    
        GLenum getMagFilter() const { return mMagFilter; }
    
        bool setMagFilter(GLenum magFilter);
    
        GLenum getWrapS() const { return mWrapS; }
    
        bool setWrapS(GLenum wrapS);
    
        GLenum getWrapT() const { return mWrapT; }
    
        bool setWrapT(GLenum wrapT);
    
        GLenum getWrapR() const { return mWrapR; }
    
        bool setWrapR(GLenum wrapR);
    
        float getMaxAnisotropy() const { return mMaxAnisotropy; }
    
        bool setMaxAnisotropy(float maxAnisotropy);
    
        GLfloat getMinLod() const { return mMinLod; }
    
        bool setMinLod(GLfloat minLod);
    
        GLfloat getMaxLod() const { return mMaxLod; }
    
        bool setMaxLod(GLfloat maxLod);
    
        GLenum getCompareMode() const { return mCompareMode; }
    
        bool setCompareMode(GLenum compareMode);
    
        GLenum getCompareFunc() const { return mCompareFunc; }
    
        bool setCompareFunc(GLenum compareFunc);
    
        GLenum getSRGBDecode() const { return mSRGBDecode; }
    
        bool setSRGBDecode(GLenum sRGBDecode);
    
        bool setBorderColor(const ColorGeneric &color);
    
        const ColorGeneric &getBorderColor() const { return mBorderColor; }
    
        bool sameCompleteness(const SamplerState &samplerState) const
        {
            return mCompleteness.packed == samplerState.mCompleteness.packed;
        }
    
      private:
        void updateWrapTCompareMode();
    
        GLenum mMinFilter;
        GLenum mMagFilter;
    
        GLenum mWrapS;
        GLenum mWrapT;
        GLenum mWrapR;
    
        // From EXT_texture_filter_anisotropic
        float mMaxAnisotropy;
    
        GLfloat mMinLod;
        GLfloat mMaxLod;
    
        GLenum mCompareMode;
        GLenum mCompareFunc;
    
        GLenum mSRGBDecode;
    
        ColorGeneric mBorderColor;
    
        union Completeness
        {
            uint32_t packed;
            PackedSamplerCompleteness typed;
        };
    
        Completeness mCompleteness;
    };
    
    bool operator==(const SamplerState &a, const SamplerState &b);
    bool operator!=(const SamplerState &a, const SamplerState &b);
    
    struct DrawArraysIndirectCommand
    {
        GLuint count;
        GLuint instanceCount;
        GLuint first;
        GLuint baseInstance;
    };
    static_assert(sizeof(DrawArraysIndirectCommand) == 16,
                  "Unexpected size of DrawArraysIndirectCommand");
    
    struct DrawElementsIndirectCommand
    {
        GLuint count;
        GLuint primCount;
        GLuint firstIndex;
        GLint baseVertex;
        GLuint baseInstance;
    };
    static_assert(sizeof(DrawElementsIndirectCommand) == 20,
                  "Unexpected size of DrawElementsIndirectCommand");
    
    struct ImageUnit
    {
        ImageUnit();
        ImageUnit(const ImageUnit &other);
        ~ImageUnit();
    
        BindingPointer<Texture> texture;
        GLint level;
        GLboolean layered;
        GLint layer;
        GLenum access;
        GLenum format;
    };
    
    using ImageUnitTextureTypeMap = std::map<unsigned int, gl::TextureType>;
    
    struct PixelStoreStateBase
    {
        GLint alignment   = 4;
        GLint rowLength   = 0;
        GLint skipRows    = 0;
        GLint skipPixels  = 0;
        GLint imageHeight = 0;
        GLint skipImages  = 0;
    };
    
    struct PixelUnpackState : PixelStoreStateBase
    {};
    
    struct PixelPackState : PixelStoreStateBase
    {
        bool reverseRowOrder = false;
    };
    
    // Used in Program and VertexArray.
    using AttributesMask = angle::BitSet<MAX_VERTEX_ATTRIBS>;
    
    // Used in Program
    using UniformBlockBindingMask = angle::BitSet<IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS>;
    
    // Used in Framebuffer / Program
    using DrawBufferMask = angle::BitSet8<IMPLEMENTATION_MAX_DRAW_BUFFERS>;
    
    class BlendStateExt final
    {
        static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS == 8, "Only up to 8 draw buffers supported.");
    
      public:
        template <typename ElementType, size_t ElementCount>
        struct StorageType final
        {
            static_assert(ElementCount <= 256, "ElementCount cannot exceed 256.");
    
    #if defined(ANGLE_IS_64_BIT_CPU)
            // Always use uint64_t on 64-bit systems
            static constexpr size_t kBits = 8;
    #else
            static constexpr size_t kBits = ElementCount > 16 ? 8 : 4;
    #endif
    
            using Type = typename std::conditional<kBits == 8, uint64_t, uint32_t>::type;
    
            static constexpr Type kMaxValueMask = (kBits == 8) ? 0xFF : 0xF;
    
            static constexpr Type GetMask(const size_t drawBuffers)
            {
                ASSERT(drawBuffers > 0);
                ASSERT(drawBuffers <= IMPLEMENTATION_MAX_DRAW_BUFFERS);
                return static_cast<Type>(0xFFFFFFFFFFFFFFFFull >> (64 - drawBuffers * kBits));
            }
    
            // A multiplier that is used to replicate 4- or 8-bit value 8 times.
            static constexpr Type kReplicator = (kBits == 8) ? 0x0101010101010101ull : 0x11111111;
    
            // Extract packed `Bits`-bit value of index `index`. `values` variable contains up to 8
            // packed values.
            static constexpr ElementType GetValueIndexed(const size_t index, const Type values)
            {
                ASSERT(index < IMPLEMENTATION_MAX_DRAW_BUFFERS);
    
                return static_cast<ElementType>((values >> (index * kBits)) & kMaxValueMask);
            }
    
            // Replicate `Bits`-bit value 8 times and mask the result.
            static constexpr Type GetReplicatedValue(const ElementType value, const Type mask)
            {
                ASSERT(static_cast<size_t>(value) <= kMaxValueMask);
                return (static_cast<size_t>(value) * kReplicator) & mask;
            }
    
            // Replace `Bits`-bit value of index `index` in `target` with `value`.
            static constexpr void SetValueIndexed(const size_t index,
                                                  const ElementType value,
                                                  Type *target)
            {
                ASSERT(static_cast<size_t>(value) <= kMaxValueMask);
                ASSERT(index < IMPLEMENTATION_MAX_DRAW_BUFFERS);
    
                // Bitmask with set bits that contain the value of index `index`.
                const Type selector = kMaxValueMask << (index * kBits);
    
                // Shift the new `value` to its position in the packed value.
                const Type builtValue = static_cast<Type>(value) << (index * kBits);
    
                // Mark differing bits of `target` and `builtValue`, then flip the bits on those
                // positions in `target`.
                // Taken from https://graphics.stanford.edu/~seander/bithacks.html#MaskedMerge
                *target = *target ^ ((*target ^ builtValue) & selector);
            }
    
            // Compare two packed sets of eight 4-bit values and return an 8-bit diff mask.
            static constexpr DrawBufferMask GetDiffMask(const uint32_t packedValue1,
                                                        const uint32_t packedValue2)
            {
                uint32_t diff = packedValue1 ^ packedValue2;
    
                // For each 4-bit value that is different between inputs, set the msb to 1 and other
                // bits to 0.
                diff = (diff | ((diff & 0x77777777) + 0x77777777)) & 0x88888888;
    
                // By this point, `diff` looks like a...b...c...d...e...f...g...h... (dots mean zeros).
                // To get DrawBufferMask, we need to compress this 32-bit value to 8 bits, i.e. abcdefgh
    
                // Multiplying the lower half of `diff` by 0x249 (0x200 + 0x40 + 0x8 + 0x1) produces:
                // ................e...f...g...h... +
                // .............e...f...g...h...... +
                // ..........e...f...g...h......... +
                // .......e...f...g...h............
                // ________________________________ =
                // .......e..ef.efgefghfgh.gh..h...
                //                 ^^^^
                // Similar operation is applied to the upper word.
                // This calculation could be replaced with a single PEXT instruction from BMI2 set.
                diff = ((((diff & 0xFFFF0000) * 0x249) >> 24) & 0xF0) | (((diff * 0x249) >> 12) & 0xF);
    
                return DrawBufferMask(static_cast<uint8_t>(diff));
            }
    
            // Compare two packed sets of eight 8-bit values and return an 8-bit diff mask.
            static constexpr DrawBufferMask GetDiffMask(const uint64_t packedValue1,
                                                        const uint64_t packedValue2)
            {
                uint64_t diff = packedValue1 ^ packedValue2;
    
                // For each 8-bit value that is different between inputs, set the msb to 1 and other
                // bits to 0.
                diff = (diff | ((diff & 0x7F7F7F7F7F7F7F7F) + 0x7F7F7F7F7F7F7F7F)) & 0x8080808080808080;
    
                // By this point, `diff` looks like (dots mean zeros):
                // a.......b.......c.......d.......e.......f.......g.......h.......
                // To get DrawBufferMask, we need to compress this 64-bit value to 8 bits, i.e. abcdefgh
    
                // Multiplying `diff` by 0x0002040810204081 produces:
                // a.......b.......c.......d.......e.......f.......g.......h....... +
                // .b.......c.......d.......e.......f.......g.......h.............. +
                // ..c.......d.......e.......f.......g.......h..................... +
                // ...d.......e.......f.......g.......h............................ +
                // ....e.......f.......g.......h................................... +
                // .....f.......g.......h.......................................... +
                // ......g.......h................................................. +
                // .......h........................................................
                // ________________________________________________________________ =
                // abcdefghbcdefgh.cdefgh..defgh...efgh....fgh.....gh......h.......
                // ^^^^^^^^
                // This operation could be replaced with a single PEXT instruction from BMI2 set.
                diff = 0x0002040810204081 * diff >> 56;
    
                return DrawBufferMask(static_cast<uint8_t>(diff));
            }
        };
    
        using FactorStorage    = StorageType<BlendFactorType, angle::EnumSize<BlendFactorType>()>;
        using EquationStorage  = StorageType<BlendEquationType, angle::EnumSize<BlendEquationType>()>;
        using ColorMaskStorage = StorageType<uint8_t, 16>;
    
        BlendStateExt(const size_t drawBuffers = 1);
    
        BlendStateExt(const BlendStateExt &other);
        BlendStateExt &operator=(const BlendStateExt &other);
    
        ///////// Blending Toggle /////////
    
        void setEnabled(const bool enabled);
        void setEnabledIndexed(const size_t index, const bool enabled);
    
        ///////// Color Write Mask /////////
    
        static constexpr size_t PackColorMask(const bool red,
                                              const bool green,
                                              const bool blue,
                                              const bool alpha)
        {
            return (red ? 1 : 0) | (green ? 2 : 0) | (blue ? 4 : 0) | (alpha ? 8 : 0);
        }
    
        static constexpr void UnpackColorMask(const size_t value,
                                              bool *red,
                                              bool *green,
                                              bool *blue,
                                              bool *alpha)
        {
            *red   = static_cast<bool>(value & 1);
            *green = static_cast<bool>(value & 2);
            *blue  = static_cast<bool>(value & 4);
            *alpha = static_cast<bool>(value & 8);
        }
    
        ColorMaskStorage::Type expandColorMaskValue(const bool red,
                                                    const bool green,
                                                    const bool blue,
                                                    const bool alpha) const;
        ColorMaskStorage::Type expandColorMaskIndexed(const size_t index) const;
        void setColorMask(const bool red, const bool green, const bool blue, const bool alpha);
        void setColorMaskIndexed(const size_t index, const uint8_t value);
        void setColorMaskIndexed(const size_t index,
                                 const bool red,
                                 const bool green,
                                 const bool blue,
                                 const bool alpha);
        uint8_t getColorMaskIndexed(const size_t index) const;
        void getColorMaskIndexed(const size_t index,
                                 bool *red,
                                 bool *green,
                                 bool *blue,
                                 bool *alpha) const;
        DrawBufferMask compareColorMask(ColorMaskStorage::Type other) const;
    
        ///////// Blend Equation /////////
    
        EquationStorage::Type expandEquationValue(const GLenum mode) const;
        EquationStorage::Type expandEquationColorIndexed(const size_t index) const;
        EquationStorage::Type expandEquationAlphaIndexed(const size_t index) const;
        void setEquations(const GLenum modeColor, const GLenum modeAlpha);
        void setEquationsIndexed(const size_t index, const GLenum modeColor, const GLenum modeAlpha);
        void setEquationsIndexed(const size_t index,
                                 const size_t otherIndex,
                                 const BlendStateExt &other);
        GLenum getEquationColorIndexed(size_t index) const;
        GLenum getEquationAlphaIndexed(size_t index) const;
        DrawBufferMask compareEquations(const EquationStorage::Type color,
                                        const EquationStorage::Type alpha) const;
    
        ///////// Blend Factors /////////
    
        FactorStorage::Type expandFactorValue(const GLenum func) const;
        FactorStorage::Type expandSrcColorIndexed(const size_t index) const;
        FactorStorage::Type expandDstColorIndexed(const size_t index) const;
        FactorStorage::Type expandSrcAlphaIndexed(const size_t index) const;
        FactorStorage::Type expandDstAlphaIndexed(const size_t index) const;
        void setFactors(const GLenum srcColor,
                        const GLenum dstColor,
                        const GLenum srcAlpha,
                        const GLenum dstAlpha);
        void setFactorsIndexed(const size_t index,
                               const GLenum srcColor,
                               const GLenum dstColor,
                               const GLenum srcAlpha,
                               const GLenum dstAlpha);
        void setFactorsIndexed(const size_t index, const size_t otherIndex, const BlendStateExt &other);
        GLenum getSrcColorIndexed(size_t index) const;
        GLenum getDstColorIndexed(size_t index) const;
        GLenum getSrcAlphaIndexed(size_t index) const;
        GLenum getDstAlphaIndexed(size_t index) const;
        DrawBufferMask compareFactors(const FactorStorage::Type srcColor,
                                      const FactorStorage::Type dstColor,
                                      const FactorStorage::Type srcAlpha,
                                      const FactorStorage::Type dstAlpha) const;
    
        ///////// Data Members /////////
    
        FactorStorage::Type mMaxFactorMask;
        FactorStorage::Type mSrcColor;
        FactorStorage::Type mDstColor;
        FactorStorage::Type mSrcAlpha;
        FactorStorage::Type mDstAlpha;
    
        EquationStorage::Type mMaxEquationMask;
        EquationStorage::Type mEquationColor;
        EquationStorage::Type mEquationAlpha;
    
        ColorMaskStorage::Type mMaxColorMask;
        ColorMaskStorage::Type mColorMask;
    
        DrawBufferMask mMaxEnabledMask;
        DrawBufferMask mEnabledMask;
    
        size_t mMaxDrawBuffers;
    };
    
    // Used in StateCache
    using StorageBuffersMask = angle::BitSet<IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS>;
    
    template <typename T>
    using TexLevelArray = std::array<T, IMPLEMENTATION_MAX_TEXTURE_LEVELS>;
    
    using TexLevelMask = angle::BitSet<IMPLEMENTATION_MAX_TEXTURE_LEVELS>;
    
    enum class ComponentType
    {
        Float       = 0,
        Int         = 1,
        UnsignedInt = 2,
        NoType      = 3,
        EnumCount   = 4,
        InvalidEnum = 4,
    };
    
    constexpr ComponentType GLenumToComponentType(GLenum componentType)
    {
        switch (componentType)
        {
            case GL_FLOAT:
                return ComponentType::Float;
            case GL_INT:
                return ComponentType::Int;
            case GL_UNSIGNED_INT:
                return ComponentType::UnsignedInt;
            case GL_NONE:
                return ComponentType::NoType;
            default:
                return ComponentType::InvalidEnum;
        }
    }
    
    constexpr angle::PackedEnumMap<ComponentType, uint32_t> kComponentMasks = {{
        {ComponentType::Float, 0x10001},
        {ComponentType::Int, 0x00001},
        {ComponentType::UnsignedInt, 0x10000},
    }};
    
    constexpr size_t kMaxComponentTypeMaskIndex = 16;
    using ComponentTypeMask                     = angle::BitSet<kMaxComponentTypeMaskIndex * 2>;
    
    ANGLE_INLINE void SetComponentTypeMask(ComponentType type, size_t index, ComponentTypeMask *mask)
    {
        ASSERT(index <= kMaxComponentTypeMaskIndex);
        *mask &= ~(0x10001 << index);
        *mask |= kComponentMasks[type] << index;
    }
    
    ANGLE_INLINE ComponentType GetComponentTypeMask(const ComponentTypeMask &mask, size_t index)
    {
        ASSERT(index <= kMaxComponentTypeMaskIndex);
        uint32_t mask_bits = static_cast<uint32_t>((mask.to_ulong() >> index) & 0x10001);
        switch (mask_bits)
        {
            case 0x10001:
                return ComponentType::Float;
            case 0x00001:
                return ComponentType::Int;
            case 0x10000:
                return ComponentType::UnsignedInt;
            default:
                return ComponentType::InvalidEnum;
        }
    }
    
    bool ValidateComponentTypeMasks(unsigned long outputTypes,
                                    unsigned long inputTypes,
                                    unsigned long outputMask,
                                    unsigned long inputMask);
    
    enum class RenderToTextureImageIndex
    {
        // The default image of the texture, where data is expected to be.
        Default = 0,
    
        // Intermediate multisampled images for EXT_multisampled_render_to_texture.
        // These values must match log2(SampleCount).
        IntermediateImage2xMultisampled  = 1,
        IntermediateImage4xMultisampled  = 2,
        IntermediateImage8xMultisampled  = 3,
        IntermediateImage16xMultisampled = 4,
    
        // We currently only support up to 16xMSAA in backends that use this enum.
        InvalidEnum = 5,
        EnumCount   = 5,
    };
    
    template <typename T>
    using RenderToTextureImageMap = angle::PackedEnumMap<RenderToTextureImageIndex, T>;
    
    struct ContextID
    {
        uint32_t value;
    };
    
    inline bool operator==(ContextID lhs, ContextID rhs)
    {
        return lhs.value == rhs.value;
    }
    
    inline bool operator!=(ContextID lhs, ContextID rhs)
    {
        return lhs.value != rhs.value;
    }
    
    inline bool operator<(ContextID lhs, ContextID rhs)
    {
        return lhs.value < rhs.value;
    }
    
    constexpr size_t kCubeFaceCount = 6;
    
    template <typename T>
    using TextureTypeMap = angle::PackedEnumMap<TextureType, T>;
    using TextureMap     = TextureTypeMap<BindingPointer<Texture>>;
    
    // ShaderVector can contain one item per shader.  It differs from ShaderMap in that the values are
    // not indexed by ShaderType.
    template <typename T>
    using ShaderVector = angle::FixedVector<T, static_cast<size_t>(ShaderType::EnumCount)>;
    
    template <typename T>
    using AttachmentArray = std::array<T, IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS>;
    
    template <typename T>
    using AttachmentVector = angle::FixedVector<T, IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS>;
    
    using AttachmentsMask = angle::BitSet<IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS>;
    
    template <typename T>
    using DrawBuffersArray = std::array<T, IMPLEMENTATION_MAX_DRAW_BUFFERS>;
    
    template <typename T>
    using DrawBuffersVector = angle::FixedVector<T, IMPLEMENTATION_MAX_DRAW_BUFFERS>;
    
    template <typename T>
    using AttribArray = std::array<T, MAX_VERTEX_ATTRIBS>;
    
    using ActiveTextureMask = angle::BitSet<IMPLEMENTATION_MAX_ACTIVE_TEXTURES>;
    
    template <typename T>
    using ActiveTextureArray = std::array<T, IMPLEMENTATION_MAX_ACTIVE_TEXTURES>;
    
    using ActiveTextureTypeArray = ActiveTextureArray<TextureType>;
    
    template <typename T>
    using UniformBuffersArray = std::array<T, IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS>;
    template <typename T>
    using StorageBuffersArray = std::array<T, IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS>;
    template <typename T>
    using AtomicCounterBuffersArray = std::array<T, IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS>;
    using AtomicCounterBufferMask   = angle::BitSet<IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS>;
    template <typename T>
    using ImagesArray = std::array<T, IMPLEMENTATION_MAX_IMAGE_UNITS>;
    
    using ImageUnitMask = angle::BitSet<IMPLEMENTATION_MAX_IMAGE_UNITS>;
    
    using SupportedSampleSet = std::set<GLuint>;
    
    template <typename T>
    using TransformFeedbackBuffersArray =
        std::array<T, gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS>;
    
    template <typename T>
    using QueryTypeMap = angle::PackedEnumMap<QueryType, T>;
    
    constexpr size_t kBarrierVectorDefaultSize = 16;
    
    template <typename T>
    using BarrierVector = angle::FastVector<T, kBarrierVectorDefaultSize>;
    
    using BufferBarrierVector = BarrierVector<Buffer *>;
    
    struct TextureAndLayout
    {
        Texture *texture;
        GLenum layout;
    };
    using TextureBarrierVector = BarrierVector<TextureAndLayout>;
    
    // OffsetBindingPointer.getSize() returns the size specified by the user, which may be larger than
    // the size of the bound buffer. This function reduces the returned size to fit the bound buffer if
    // necessary. Returns 0 if no buffer is bound or if integer overflow occurs.
    GLsizeiptr GetBoundBufferAvailableSize(const OffsetBindingPointer<Buffer> &binding);
    
    // A texture level index.
    template <typename T>
    class LevelIndexWrapper
    {
      public:
        LevelIndexWrapper() = default;
        explicit constexpr LevelIndexWrapper(T levelIndex) : mLevelIndex(levelIndex) {}
        constexpr LevelIndexWrapper(const LevelIndexWrapper &other) = default;
        constexpr LevelIndexWrapper &operator=(const LevelIndexWrapper &other) = default;
    
        constexpr T get() const { return mLevelIndex; }
    
        LevelIndexWrapper &operator++()
        {
            ++mLevelIndex;
            return *this;
        }
        constexpr bool operator<(const LevelIndexWrapper &other) const
        {
            return mLevelIndex < other.mLevelIndex;
        }
        constexpr bool operator<=(const LevelIndexWrapper &other) const
        {
            return mLevelIndex <= other.mLevelIndex;
        }
        constexpr bool operator>(const LevelIndexWrapper &other) const
        {
            return mLevelIndex > other.mLevelIndex;
        }
        constexpr bool operator>=(const LevelIndexWrapper &other) const
        {
            return mLevelIndex >= other.mLevelIndex;
        }
        constexpr bool operator==(const LevelIndexWrapper &other) const
        {
            return mLevelIndex == other.mLevelIndex;
        }
        constexpr bool operator!=(const LevelIndexWrapper &other) const
        {
            return mLevelIndex != other.mLevelIndex;
        }
        constexpr LevelIndexWrapper operator+(T other) const
        {
            return LevelIndexWrapper(mLevelIndex + other);
        }
        constexpr LevelIndexWrapper operator-(T other) const
        {
            return LevelIndexWrapper(mLevelIndex - other);
        }
        constexpr T operator-(LevelIndexWrapper other) const { return mLevelIndex - other.mLevelIndex; }
    
      private:
        T mLevelIndex;
    };
    
    // A GL texture level index.
    using LevelIndex = LevelIndexWrapper<GLint>;
    
    enum class MultisamplingMode
    {
        // Regular multisampling
        Regular = 0,
        // GL_EXT_multisampled_render_to_texture renderbuffer/texture attachments which perform implicit
        // resolve of multisampled data.
        MultisampledRenderToTexture,
    };
    }  // namespace gl
    
    namespace rx
    {
    // A macro that determines whether an object has a given runtime type.
    #if defined(__clang__)
    #    if __has_feature(cxx_rtti)
    #        define ANGLE_HAS_DYNAMIC_CAST 1
    #    endif
    #elif !defined(NDEBUG) && (!defined(_MSC_VER) || defined(_CPPRTTI)) &&              \
        (!defined(__GNUC__) || __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3) || \
         defined(__GXX_RTTI))
    #    define ANGLE_HAS_DYNAMIC_CAST 1
    #endif
    
    #ifdef ANGLE_HAS_DYNAMIC_CAST
    #    define ANGLE_HAS_DYNAMIC_TYPE(type, obj) (dynamic_cast<type>(obj) != nullptr)
    #    undef ANGLE_HAS_DYNAMIC_CAST
    #else
    #    define ANGLE_HAS_DYNAMIC_TYPE(type, obj) (obj != nullptr)
    #endif
    
    // Downcast a base implementation object (EG TextureImpl to TextureD3D)
    template <typename DestT, typename SrcT>
    inline DestT *GetAs(SrcT *src)
    {
        ASSERT(ANGLE_HAS_DYNAMIC_TYPE(DestT *, src));
        return static_cast<DestT *>(src);
    }
    
    template <typename DestT, typename SrcT>
    inline const DestT *GetAs(const SrcT *src)
    {
        ASSERT(ANGLE_HAS_DYNAMIC_TYPE(const DestT *, src));
        return static_cast<const DestT *>(src);
    }
    
    #undef ANGLE_HAS_DYNAMIC_TYPE
    
    // Downcast a GL object to an Impl (EG gl::Texture to rx::TextureD3D)
    template <typename DestT, typename SrcT>
    inline DestT *GetImplAs(SrcT *src)
    {
        return GetAs<DestT>(src->getImplementation());
    }
    
    template <typename DestT, typename SrcT>
    inline DestT *SafeGetImplAs(SrcT *src)
    {
        return src != nullptr ? GetAs<DestT>(src->getImplementation()) : nullptr;
    }
    
    }  // namespace rx
    
    #include "angletypes.inc"
    
    namespace angle
    {
    // Zero-based for better array indexing
    enum FramebufferBinding
    {
        FramebufferBindingRead = 0,
        FramebufferBindingDraw,
        FramebufferBindingSingletonMax,
        FramebufferBindingBoth = FramebufferBindingSingletonMax,
        FramebufferBindingMax,
        FramebufferBindingUnknown = FramebufferBindingMax,
    };
    
    inline FramebufferBinding EnumToFramebufferBinding(GLenum enumValue)
    {
        switch (enumValue)
        {
            case GL_READ_FRAMEBUFFER:
                return FramebufferBindingRead;
            case GL_DRAW_FRAMEBUFFER:
                return FramebufferBindingDraw;
            case GL_FRAMEBUFFER:
                return FramebufferBindingBoth;
            default:
                UNREACHABLE();
                return FramebufferBindingUnknown;
        }
    }
    
    inline GLenum FramebufferBindingToEnum(FramebufferBinding binding)
    {
        switch (binding)
        {
            case FramebufferBindingRead:
                return GL_READ_FRAMEBUFFER;
            case FramebufferBindingDraw:
                return GL_DRAW_FRAMEBUFFER;
            case FramebufferBindingBoth:
                return GL_FRAMEBUFFER;
            default:
                UNREACHABLE();
                return GL_NONE;
        }
    }
    
    template <typename ObjT, typename ContextT>
    class DestroyThenDelete
    {
      public:
        DestroyThenDelete(const ContextT *context) : mContext(context) {}
    
        void operator()(ObjT *obj)
        {
            (void)(obj->onDestroy(mContext));
            delete obj;
        }
    
      private:
        const ContextT *mContext;
    };
    
    // Helper class for wrapping an onDestroy function.
    template <typename ObjT, typename DeleterT>
    class UniqueObjectPointerBase : angle::NonCopyable
    {
      public:
        template <typename ContextT>
        UniqueObjectPointerBase(const ContextT *context) : mObject(nullptr), mDeleter(context)
        {}
    
        template <typename ContextT>
        UniqueObjectPointerBase(ObjT *obj, const ContextT *context) : mObject(obj), mDeleter(context)
        {}
    
        ~UniqueObjectPointerBase()
        {
            if (mObject)
            {
                mDeleter(mObject);
            }
        }
    
        ObjT *operator->() const { return mObject; }
    
        ObjT *release()
        {
            auto obj = mObject;
            mObject  = nullptr;
            return obj;
        }
    
        ObjT *get() const { return mObject; }
    
        void reset(ObjT *obj)
        {
            if (mObject)
            {
                mDeleter(mObject);
            }
            mObject = obj;
        }
    
      private:
        ObjT *mObject;
        DeleterT mDeleter;
    };
    
    template <typename ObjT, typename ContextT>
    using UniqueObjectPointer = UniqueObjectPointerBase<ObjT, DestroyThenDelete<ObjT, ContextT>>;
    
    }  // namespace angle
    
    namespace gl
    {
    class State;
    }  // namespace gl
    
    #endif  // LIBANGLE_ANGLETYPES_H_