Edit

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

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.cpp
  • //
    // Copyright 2013 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
    
    #include "libANGLE/angletypes.h"
    #include "libANGLE/Program.h"
    #include "libANGLE/State.h"
    #include "libANGLE/VertexArray.h"
    #include "libANGLE/VertexAttribute.h"
    
    namespace gl
    {
    namespace
    {
    bool IsStencilNoOp(GLenum stencilFunc,
                       GLenum stencilFail,
                       GLenum stencilPassDepthFail,
                       GLenum stencilPassDepthPass)
    {
        const bool isNeverAndKeep           = stencilFunc == GL_NEVER && stencilFail == GL_KEEP;
        const bool isAlwaysAndKeepOrAllKeep = (stencilFunc == GL_ALWAYS || stencilFail == GL_KEEP) &&
                                              stencilPassDepthFail == GL_KEEP &&
                                              stencilPassDepthPass == GL_KEEP;
    
        return isNeverAndKeep || isAlwaysAndKeepOrAllKeep;
    }
    
    // Calculate whether the range [outsideLow, outsideHigh] encloses the range [insideLow, insideHigh]
    bool EnclosesRange(int outsideLow, int outsideHigh, int insideLow, int insideHigh)
    {
        return outsideLow <= insideLow && outsideHigh >= insideHigh;
    }
    }  // anonymous namespace
    
    RasterizerState::RasterizerState()
    {
        memset(this, 0, sizeof(RasterizerState));
    
        rasterizerDiscard   = false;
        cullFace            = false;
        cullMode            = CullFaceMode::Back;
        frontFace           = GL_CCW;
        polygonOffsetFill   = false;
        polygonOffsetFactor = 0.0f;
        polygonOffsetUnits  = 0.0f;
        pointDrawMode       = false;
        multiSample         = false;
        dither              = true;
    }
    
    RasterizerState::RasterizerState(const RasterizerState &other)
    {
        memcpy(this, &other, sizeof(RasterizerState));
    }
    
    bool operator==(const RasterizerState &a, const RasterizerState &b)
    {
        return memcmp(&a, &b, sizeof(RasterizerState)) == 0;
    }
    
    bool operator!=(const RasterizerState &a, const RasterizerState &b)
    {
        return !(a == b);
    }
    
    BlendState::BlendState()
    {
        memset(this, 0, sizeof(BlendState));
    
        blend              = false;
        sourceBlendRGB     = GL_ONE;
        sourceBlendAlpha   = GL_ONE;
        destBlendRGB       = GL_ZERO;
        destBlendAlpha     = GL_ZERO;
        blendEquationRGB   = GL_FUNC_ADD;
        blendEquationAlpha = GL_FUNC_ADD;
        colorMaskRed       = true;
        colorMaskGreen     = true;
        colorMaskBlue      = true;
        colorMaskAlpha     = true;
    }
    
    BlendState::BlendState(const BlendState &other)
    {
        memcpy(this, &other, sizeof(BlendState));
    }
    
    bool operator==(const BlendState &a, const BlendState &b)
    {
        return memcmp(&a, &b, sizeof(BlendState)) == 0;
    }
    
    bool operator!=(const BlendState &a, const BlendState &b)
    {
        return !(a == b);
    }
    
    DepthStencilState::DepthStencilState()
    {
        memset(this, 0, sizeof(DepthStencilState));
    
        depthTest                = false;
        depthFunc                = GL_LESS;
        depthMask                = true;
        stencilTest              = false;
        stencilFunc              = GL_ALWAYS;
        stencilMask              = static_cast<GLuint>(-1);
        stencilWritemask         = static_cast<GLuint>(-1);
        stencilBackFunc          = GL_ALWAYS;
        stencilBackMask          = static_cast<GLuint>(-1);
        stencilBackWritemask     = static_cast<GLuint>(-1);
        stencilFail              = GL_KEEP;
        stencilPassDepthFail     = GL_KEEP;
        stencilPassDepthPass     = GL_KEEP;
        stencilBackFail          = GL_KEEP;
        stencilBackPassDepthFail = GL_KEEP;
        stencilBackPassDepthPass = GL_KEEP;
    }
    
    DepthStencilState::DepthStencilState(const DepthStencilState &other)
    {
        memcpy(this, &other, sizeof(DepthStencilState));
    }
    
    bool DepthStencilState::isDepthMaskedOut() const
    {
        return !depthMask;
    }
    
    bool DepthStencilState::isStencilMaskedOut() const
    {
        return (stencilMask & stencilWritemask) == 0;
    }
    
    bool DepthStencilState::isStencilNoOp() const
    {
        return isStencilMaskedOut() ||
               IsStencilNoOp(stencilFunc, stencilFail, stencilPassDepthFail, stencilPassDepthPass);
    }
    
    bool DepthStencilState::isStencilBackNoOp() const
    {
        const bool isStencilBackMaskedOut = (stencilBackMask & stencilBackWritemask) == 0;
        return isStencilBackMaskedOut ||
               IsStencilNoOp(stencilBackFunc, stencilBackFail, stencilBackPassDepthFail,
                             stencilBackPassDepthPass);
    }
    
    bool operator==(const DepthStencilState &a, const DepthStencilState &b)
    {
        return memcmp(&a, &b, sizeof(DepthStencilState)) == 0;
    }
    
    bool operator!=(const DepthStencilState &a, const DepthStencilState &b)
    {
        return !(a == b);
    }
    
    SamplerState::SamplerState()
    {
        memset(this, 0, sizeof(SamplerState));
    
        setMinFilter(GL_NEAREST_MIPMAP_LINEAR);
        setMagFilter(GL_LINEAR);
        setWrapS(GL_REPEAT);
        setWrapT(GL_REPEAT);
        setWrapR(GL_REPEAT);
        setMaxAnisotropy(1.0f);
        setMinLod(-1000.0f);
        setMaxLod(1000.0f);
        setCompareMode(GL_NONE);
        setCompareFunc(GL_LEQUAL);
        setSRGBDecode(GL_DECODE_EXT);
    }
    
    SamplerState::SamplerState(const SamplerState &other) = default;
    
    SamplerState &SamplerState::operator=(const SamplerState &other) = default;
    
    // static
    SamplerState SamplerState::CreateDefaultForTarget(TextureType type)
    {
        SamplerState state;
    
        // According to OES_EGL_image_external and ARB_texture_rectangle: For external textures, the
        // default min filter is GL_LINEAR and the default s and t wrap modes are GL_CLAMP_TO_EDGE.
        if (type == TextureType::External || type == TextureType::Rectangle)
        {
            state.mMinFilter = GL_LINEAR;
            state.mWrapS     = GL_CLAMP_TO_EDGE;
            state.mWrapT     = GL_CLAMP_TO_EDGE;
        }
    
        return state;
    }
    
    bool SamplerState::setMinFilter(GLenum minFilter)
    {
        if (mMinFilter != minFilter)
        {
            mMinFilter                    = minFilter;
            mCompleteness.typed.minFilter = static_cast<uint8_t>(FromGLenum<FilterMode>(minFilter));
            return true;
        }
        return false;
    }
    
    bool SamplerState::setMagFilter(GLenum magFilter)
    {
        if (mMagFilter != magFilter)
        {
            mMagFilter                    = magFilter;
            mCompleteness.typed.magFilter = static_cast<uint8_t>(FromGLenum<FilterMode>(magFilter));
            return true;
        }
        return false;
    }
    
    bool SamplerState::setWrapS(GLenum wrapS)
    {
        if (mWrapS != wrapS)
        {
            mWrapS                    = wrapS;
            mCompleteness.typed.wrapS = static_cast<uint8_t>(FromGLenum<WrapMode>(wrapS));
            return true;
        }
        return false;
    }
    
    bool SamplerState::setWrapT(GLenum wrapT)
    {
        if (mWrapT != wrapT)
        {
            mWrapT = wrapT;
            updateWrapTCompareMode();
            return true;
        }
        return false;
    }
    
    bool SamplerState::setWrapR(GLenum wrapR)
    {
        if (mWrapR != wrapR)
        {
            mWrapR = wrapR;
            return true;
        }
        return false;
    }
    
    bool SamplerState::setMaxAnisotropy(float maxAnisotropy)
    {
        if (mMaxAnisotropy != maxAnisotropy)
        {
            mMaxAnisotropy = maxAnisotropy;
            return true;
        }
        return false;
    }
    
    bool SamplerState::setMinLod(GLfloat minLod)
    {
        if (mMinLod != minLod)
        {
            mMinLod = minLod;
            return true;
        }
        return false;
    }
    
    bool SamplerState::setMaxLod(GLfloat maxLod)
    {
        if (mMaxLod != maxLod)
        {
            mMaxLod = maxLod;
            return true;
        }
        return false;
    }
    
    bool SamplerState::setCompareMode(GLenum compareMode)
    {
        if (mCompareMode != compareMode)
        {
            mCompareMode = compareMode;
            updateWrapTCompareMode();
            return true;
        }
        return false;
    }
    
    bool SamplerState::setCompareFunc(GLenum compareFunc)
    {
        if (mCompareFunc != compareFunc)
        {
            mCompareFunc = compareFunc;
            return true;
        }
        return false;
    }
    
    bool SamplerState::setSRGBDecode(GLenum sRGBDecode)
    {
        if (mSRGBDecode != sRGBDecode)
        {
            mSRGBDecode = sRGBDecode;
            return true;
        }
        return false;
    }
    
    bool SamplerState::setBorderColor(const ColorGeneric &color)
    {
        if (mBorderColor != color)
        {
            mBorderColor = color;
            return true;
        }
        return false;
    }
    
    void SamplerState::updateWrapTCompareMode()
    {
        uint8_t wrap    = static_cast<uint8_t>(FromGLenum<WrapMode>(mWrapT));
        uint8_t compare = static_cast<uint8_t>(mCompareMode == GL_NONE ? 0x10 : 0x00);
        mCompleteness.typed.wrapTCompareMode = wrap | compare;
    }
    
    ImageUnit::ImageUnit()
        : texture(), level(0), layered(false), layer(0), access(GL_READ_ONLY), format(GL_R32UI)
    {}
    
    ImageUnit::ImageUnit(const ImageUnit &other) = default;
    
    ImageUnit::~ImageUnit() = default;
    
    BlendStateExt::BlendStateExt(const size_t drawBuffers)
        : mMaxFactorMask(FactorStorage::GetMask(drawBuffers)),
          mSrcColor(FactorStorage::GetReplicatedValue(BlendFactorType::One, mMaxFactorMask)),
          mDstColor(FactorStorage::GetReplicatedValue(BlendFactorType::Zero, mMaxFactorMask)),
          mSrcAlpha(FactorStorage::GetReplicatedValue(BlendFactorType::One, mMaxFactorMask)),
          mDstAlpha(FactorStorage::GetReplicatedValue(BlendFactorType::Zero, mMaxFactorMask)),
          mMaxEquationMask(EquationStorage::GetMask(drawBuffers)),
          mEquationColor(EquationStorage::GetReplicatedValue(BlendEquationType::Add, mMaxEquationMask)),
          mEquationAlpha(EquationStorage::GetReplicatedValue(BlendEquationType::Add, mMaxEquationMask)),
          mMaxColorMask(ColorMaskStorage::GetMask(drawBuffers)),
          mColorMask(ColorMaskStorage::GetReplicatedValue(PackColorMask(true, true, true, true),
                                                          mMaxColorMask)),
          mMaxEnabledMask(0xFF >> (8 - drawBuffers)),
          mEnabledMask(),
          mMaxDrawBuffers(drawBuffers)
    {}
    
    BlendStateExt::BlendStateExt(const BlendStateExt &other) = default;
    
    BlendStateExt &BlendStateExt::operator=(const BlendStateExt &other) = default;
    
    void BlendStateExt::setEnabled(const bool enabled)
    {
        mEnabledMask = enabled ? mMaxEnabledMask : DrawBufferMask::Zero();
    }
    
    void BlendStateExt::setEnabledIndexed(const size_t index, const bool enabled)
    {
        ASSERT(index < mMaxDrawBuffers);
        mEnabledMask.set(index, enabled);
    }
    
    BlendStateExt::ColorMaskStorage::Type BlendStateExt::expandColorMaskValue(const bool red,
                                                                              const bool green,
                                                                              const bool blue,
                                                                              const bool alpha) const
    {
        return BlendStateExt::ColorMaskStorage::GetReplicatedValue(
            PackColorMask(red, green, blue, alpha), mMaxColorMask);
    }
    
    BlendStateExt::ColorMaskStorage::Type BlendStateExt::expandColorMaskIndexed(
        const size_t index) const
    {
        return ColorMaskStorage::GetReplicatedValue(
            ColorMaskStorage::GetValueIndexed(index, mColorMask), mMaxColorMask);
    }
    
    void BlendStateExt::setColorMask(const bool red,
                                     const bool green,
                                     const bool blue,
                                     const bool alpha)
    {
        mColorMask = expandColorMaskValue(red, green, blue, alpha);
    }
    
    void BlendStateExt::setColorMaskIndexed(const size_t index, const uint8_t value)
    {
        ASSERT(index < mMaxDrawBuffers);
        ASSERT(value <= 0xF);
        ColorMaskStorage::SetValueIndexed(index, value, &mColorMask);
    }
    
    void BlendStateExt::setColorMaskIndexed(const size_t index,
                                            const bool red,
                                            const bool green,
                                            const bool blue,
                                            const bool alpha)
    {
        ASSERT(index < mMaxDrawBuffers);
        ColorMaskStorage::SetValueIndexed(index, PackColorMask(red, green, blue, alpha), &mColorMask);
    }
    
    uint8_t BlendStateExt::getColorMaskIndexed(const size_t index) const
    {
        ASSERT(index < mMaxDrawBuffers);
        return ColorMaskStorage::GetValueIndexed(index, mColorMask);
    }
    
    void BlendStateExt::getColorMaskIndexed(const size_t index,
                                            bool *red,
                                            bool *green,
                                            bool *blue,
                                            bool *alpha) const
    {
        ASSERT(index < mMaxDrawBuffers);
        UnpackColorMask(ColorMaskStorage::GetValueIndexed(index, mColorMask), red, green, blue, alpha);
    }
    
    DrawBufferMask BlendStateExt::compareColorMask(ColorMaskStorage::Type other) const
    {
        return ColorMaskStorage::GetDiffMask(mColorMask, other);
    }
    
    BlendStateExt::EquationStorage::Type BlendStateExt::expandEquationValue(const GLenum mode) const
    {
        return EquationStorage::GetReplicatedValue(FromGLenum<BlendEquationType>(mode),
                                                   mMaxEquationMask);
    }
    
    BlendStateExt::EquationStorage::Type BlendStateExt::expandEquationColorIndexed(
        const size_t index) const
    {
        return EquationStorage::GetReplicatedValue(
            EquationStorage::GetValueIndexed(index, mEquationColor), mMaxEquationMask);
    }
    
    BlendStateExt::EquationStorage::Type BlendStateExt::expandEquationAlphaIndexed(
        const size_t index) const
    {
        return EquationStorage::GetReplicatedValue(
            EquationStorage::GetValueIndexed(index, mEquationAlpha), mMaxEquationMask);
    }
    
    void BlendStateExt::setEquations(const GLenum modeColor, const GLenum modeAlpha)
    {
        mEquationColor = expandEquationValue(modeColor);
        mEquationAlpha = expandEquationValue(modeAlpha);
    }
    
    void BlendStateExt::setEquationsIndexed(const size_t index,
                                            const GLenum modeColor,
                                            const GLenum modeAlpha)
    {
        ASSERT(index < mMaxDrawBuffers);
        EquationStorage::SetValueIndexed(index, FromGLenum<BlendEquationType>(modeColor),
                                         &mEquationColor);
        EquationStorage::SetValueIndexed(index, FromGLenum<BlendEquationType>(modeAlpha),
                                         &mEquationAlpha);
    }
    
    void BlendStateExt::setEquationsIndexed(const size_t index,
                                            const size_t sourceIndex,
                                            const BlendStateExt &source)
    {
        ASSERT(index < mMaxDrawBuffers);
        ASSERT(sourceIndex < source.mMaxDrawBuffers);
        EquationStorage::SetValueIndexed(
            index, EquationStorage::GetValueIndexed(sourceIndex, source.mEquationColor),
            &mEquationColor);
        EquationStorage::SetValueIndexed(
            index, EquationStorage::GetValueIndexed(sourceIndex, source.mEquationAlpha),
            &mEquationAlpha);
    }
    
    GLenum BlendStateExt::getEquationColorIndexed(size_t index) const
    {
        ASSERT(index < mMaxDrawBuffers);
        return ToGLenum(EquationStorage::GetValueIndexed(index, mEquationColor));
    }
    
    GLenum BlendStateExt::getEquationAlphaIndexed(size_t index) const
    {
        ASSERT(index < mMaxDrawBuffers);
        return ToGLenum(EquationStorage::GetValueIndexed(index, mEquationAlpha));
    }
    
    DrawBufferMask BlendStateExt::compareEquations(const EquationStorage::Type color,
                                                   const EquationStorage::Type alpha) const
    {
        return EquationStorage::GetDiffMask(mEquationColor, color) |
               EquationStorage::GetDiffMask(mEquationAlpha, alpha);
    }
    
    BlendStateExt::FactorStorage::Type BlendStateExt::expandFactorValue(const GLenum func) const
    {
        return FactorStorage::GetReplicatedValue(FromGLenum<BlendFactorType>(func), mMaxFactorMask);
    }
    
    BlendStateExt::FactorStorage::Type BlendStateExt::expandSrcColorIndexed(const size_t index) const
    {
        ASSERT(index < mMaxDrawBuffers);
        return FactorStorage::GetReplicatedValue(FactorStorage::GetValueIndexed(index, mSrcColor),
                                                 mMaxFactorMask);
    }
    
    BlendStateExt::FactorStorage::Type BlendStateExt::expandDstColorIndexed(const size_t index) const
    {
        ASSERT(index < mMaxDrawBuffers);
        return FactorStorage::GetReplicatedValue(FactorStorage::GetValueIndexed(index, mDstColor),
                                                 mMaxFactorMask);
    }
    
    BlendStateExt::FactorStorage::Type BlendStateExt::expandSrcAlphaIndexed(const size_t index) const
    {
        ASSERT(index < mMaxDrawBuffers);
        return FactorStorage::GetReplicatedValue(FactorStorage::GetValueIndexed(index, mSrcAlpha),
                                                 mMaxFactorMask);
    }
    
    BlendStateExt::FactorStorage::Type BlendStateExt::expandDstAlphaIndexed(const size_t index) const
    {
        ASSERT(index < mMaxDrawBuffers);
        return FactorStorage::GetReplicatedValue(FactorStorage::GetValueIndexed(index, mDstAlpha),
                                                 mMaxFactorMask);
    }
    
    void BlendStateExt::setFactors(const GLenum srcColor,
                                   const GLenum dstColor,
                                   const GLenum srcAlpha,
                                   const GLenum dstAlpha)
    {
        mSrcColor = expandFactorValue(srcColor);
        mDstColor = expandFactorValue(dstColor);
        mSrcAlpha = expandFactorValue(srcAlpha);
        mDstAlpha = expandFactorValue(dstAlpha);
    }
    
    void BlendStateExt::setFactorsIndexed(const size_t index,
                                          const GLenum srcColor,
                                          const GLenum dstColor,
                                          const GLenum srcAlpha,
                                          const GLenum dstAlpha)
    {
        ASSERT(index < mMaxDrawBuffers);
        FactorStorage::SetValueIndexed(index, FromGLenum<BlendFactorType>(srcColor), &mSrcColor);
        FactorStorage::SetValueIndexed(index, FromGLenum<BlendFactorType>(dstColor), &mDstColor);
        FactorStorage::SetValueIndexed(index, FromGLenum<BlendFactorType>(srcAlpha), &mSrcAlpha);
        FactorStorage::SetValueIndexed(index, FromGLenum<BlendFactorType>(dstAlpha), &mDstAlpha);
    }
    
    void BlendStateExt::setFactorsIndexed(const size_t index,
                                          const size_t sourceIndex,
                                          const BlendStateExt &source)
    {
        ASSERT(index < mMaxDrawBuffers);
        ASSERT(sourceIndex < source.mMaxDrawBuffers);
        FactorStorage::SetValueIndexed(
            index, FactorStorage::GetValueIndexed(sourceIndex, source.mSrcColor), &mSrcColor);
        FactorStorage::SetValueIndexed(
            index, FactorStorage::GetValueIndexed(sourceIndex, source.mDstColor), &mDstColor);
        FactorStorage::SetValueIndexed(
            index, FactorStorage::GetValueIndexed(sourceIndex, source.mSrcAlpha), &mSrcAlpha);
        FactorStorage::SetValueIndexed(
            index, FactorStorage::GetValueIndexed(sourceIndex, source.mDstAlpha), &mDstAlpha);
    }
    
    GLenum BlendStateExt::getSrcColorIndexed(size_t index) const
    {
        ASSERT(index < mMaxDrawBuffers);
        return ToGLenum(FactorStorage::GetValueIndexed(index, mSrcColor));
    }
    
    GLenum BlendStateExt::getDstColorIndexed(size_t index) const
    {
        ASSERT(index < mMaxDrawBuffers);
        return ToGLenum(FactorStorage::GetValueIndexed(index, mDstColor));
    }
    
    GLenum BlendStateExt::getSrcAlphaIndexed(size_t index) const
    {
        ASSERT(index < mMaxDrawBuffers);
        return ToGLenum(FactorStorage::GetValueIndexed(index, mSrcAlpha));
    }
    
    GLenum BlendStateExt::getDstAlphaIndexed(size_t index) const
    {
        ASSERT(index < mMaxDrawBuffers);
        return ToGLenum(FactorStorage::GetValueIndexed(index, mDstAlpha));
    }
    
    DrawBufferMask BlendStateExt::compareFactors(const FactorStorage::Type srcColor,
                                                 const FactorStorage::Type dstColor,
                                                 const FactorStorage::Type srcAlpha,
                                                 const FactorStorage::Type dstAlpha) const
    {
        return FactorStorage::GetDiffMask(mSrcColor, srcColor) |
               FactorStorage::GetDiffMask(mDstColor, dstColor) |
               FactorStorage::GetDiffMask(mSrcAlpha, srcAlpha) |
               FactorStorage::GetDiffMask(mDstAlpha, dstAlpha);
    }
    
    static void MinMax(int a, int b, int *minimum, int *maximum)
    {
        if (a < b)
        {
            *minimum = a;
            *maximum = b;
        }
        else
        {
            *minimum = b;
            *maximum = a;
        }
    }
    
    Rectangle Rectangle::flip(bool flipX, bool flipY) const
    {
        Rectangle flipped = *this;
        if (flipX)
        {
            flipped.x     = flipped.x + flipped.width;
            flipped.width = -flipped.width;
        }
        if (flipY)
        {
            flipped.y      = flipped.y + flipped.height;
            flipped.height = -flipped.height;
        }
        return flipped;
    }
    
    Rectangle Rectangle::removeReversal() const
    {
        return flip(isReversedX(), isReversedY());
    }
    
    bool Rectangle::encloses(const gl::Rectangle &inside) const
    {
        return x0() <= inside.x0() && y0() <= inside.y0() && x1() >= inside.x1() && y1() >= inside.y1();
    }
    
    bool ClipRectangle(const Rectangle &source, const Rectangle &clip, Rectangle *intersection)
    {
        angle::CheckedNumeric<int> sourceX2(source.x);
        sourceX2 += source.width;
        if (!sourceX2.IsValid())
        {
            return false;
        }
        angle::CheckedNumeric<int> sourceY2(source.y);
        sourceY2 += source.height;
        if (!sourceY2.IsValid())
        {
            return false;
        }
    
        int minSourceX, maxSourceX, minSourceY, maxSourceY;
        MinMax(source.x, sourceX2.ValueOrDie(), &minSourceX, &maxSourceX);
        MinMax(source.y, sourceY2.ValueOrDie(), &minSourceY, &maxSourceY);
    
        angle::CheckedNumeric<int> clipX2(clip.x);
        clipX2 += clip.width;
        if (!clipX2.IsValid())
        {
            return false;
        }
        angle::CheckedNumeric<int> clipY2(clip.y);
        clipY2 += clip.height;
        if (!clipY2.IsValid())
        {
            return false;
        }
    
        int minClipX, maxClipX, minClipY, maxClipY;
        MinMax(clip.x, clipX2.ValueOrDie(), &minClipX, &maxClipX);
        MinMax(clip.y, clipY2.ValueOrDie(), &minClipY, &maxClipY);
    
        if (minSourceX >= maxClipX || maxSourceX <= minClipX || minSourceY >= maxClipY ||
            maxSourceY <= minClipY)
        {
            return false;
        }
    
        int x      = std::max(minSourceX, minClipX);
        int y      = std::max(minSourceY, minClipY);
        int width  = std::min(maxSourceX, maxClipX) - x;
        int height = std::min(maxSourceY, maxClipY) - y;
    
        if (intersection)
        {
            intersection->x      = x;
            intersection->y      = y;
            intersection->width  = width;
            intersection->height = height;
        }
        return width != 0 && height != 0;
    }
    
    void GetEnclosingRectangle(const Rectangle &rect1, const Rectangle &rect2, Rectangle *rectUnion)
    {
        // All callers use non-flipped framebuffer-size-clipped rectangles, so both flip and overflow
        // are impossible.
        ASSERT(!rect1.isReversedX() && !rect1.isReversedY());
        ASSERT(!rect2.isReversedX() && !rect2.isReversedY());
        ASSERT((angle::CheckedNumeric<int>(rect1.x) + rect1.width).IsValid());
        ASSERT((angle::CheckedNumeric<int>(rect1.y) + rect1.height).IsValid());
        ASSERT((angle::CheckedNumeric<int>(rect2.x) + rect2.width).IsValid());
        ASSERT((angle::CheckedNumeric<int>(rect2.y) + rect2.height).IsValid());
    
        // This function calculates a rectangle that covers both input rectangles:
        //
        //                     +---------+
        //          rect1 -->  |         |
        //                     |     +---+-----+
        //                     |     |   |     | <-- rect2
        //                     +-----+---+     |
        //                           |         |
        //                           +---------+
        //
        //   xy0 = min(rect1.xy0, rect2.xy0)
        //                    \
        //                     +---------+-----+
        //          union -->  |         .     |
        //                     |     + . + . . +
        //                     |     .   .     |
        //                     + . . + . +     |
        //                     |     .         |
        //                     +-----+---------+
        //                                    /
        //                         xy1 = max(rect1.xy1, rect2.xy1)
    
        int x0 = std::min(rect1.x0(), rect2.x0());
        int y0 = std::min(rect1.y0(), rect2.y0());
    
        int x1 = std::max(rect1.x1(), rect2.x1());
        int y1 = std::max(rect1.y1(), rect2.y1());
    
        rectUnion->x      = x0;
        rectUnion->y      = y0;
        rectUnion->width  = x1 - x0;
        rectUnion->height = y1 - y0;
    }
    
    void ExtendRectangle(const Rectangle &source, const Rectangle &extend, Rectangle *extended)
    {
        // All callers use non-flipped framebuffer-size-clipped rectangles, so both flip and overflow
        // are impossible.
        ASSERT(!source.isReversedX() && !source.isReversedY());
        ASSERT(!extend.isReversedX() && !extend.isReversedY());
        ASSERT((angle::CheckedNumeric<int>(source.x) + source.width).IsValid());
        ASSERT((angle::CheckedNumeric<int>(source.y) + source.height).IsValid());
        ASSERT((angle::CheckedNumeric<int>(extend.x) + extend.width).IsValid());
        ASSERT((angle::CheckedNumeric<int>(extend.y) + extend.height).IsValid());
    
        int x0 = source.x0();
        int x1 = source.x1();
        int y0 = source.y0();
        int y1 = source.y1();
    
        const int extendX0 = extend.x0();
        const int extendX1 = extend.x1();
        const int extendY0 = extend.y0();
        const int extendY1 = extend.y1();
    
        // For each side of the rectangle, calculate whether it can be extended by the second rectangle.
        // If so, extend it and continue for the next side with the new dimensions.
    
        // Left: Reduce x0 if the second rectangle's vertical edge covers the source's:
        //
        //     +--- - - -                +--- - - -
        //     |                         |
        //     |  +--------------+       +-----------------+
        //     |  |    source    |  -->  |       source    |
        //     |  +--------------+       +-----------------+
        //     |                         |
        //     +--- - - -                +--- - - -
        //
        const bool enclosesHeight = EnclosesRange(extendY0, extendY1, y0, y1);
        if (extendX0 < x0 && extendX1 >= x0 && enclosesHeight)
        {
            x0 = extendX0;
        }
    
        // Right: Increase x1 simiarly.
        if (extendX0 <= x1 && extendX1 > x1 && enclosesHeight)
        {
            x1 = extendX1;
        }
    
        // Top: Reduce y0 if the second rectangle's horizontal edge covers the source's potentially
        // extended edge.
        const bool enclosesWidth = EnclosesRange(extendX0, extendX1, x0, x1);
        if (extendY0 < y0 && extendY1 >= y0 && enclosesWidth)
        {
            y0 = extendY0;
        }
    
        // Right: Increase y1 simiarly.
        if (extendY0 <= y1 && extendY1 > y1 && enclosesWidth)
        {
            y1 = extendY1;
        }
    
        extended->x      = x0;
        extended->y      = y0;
        extended->width  = x1 - x0;
        extended->height = y1 - y0;
    }
    
    bool Box::operator==(const Box &other) const
    {
        return (x == other.x && y == other.y && z == other.z && width == other.width &&
                height == other.height && depth == other.depth);
    }
    
    bool Box::operator!=(const Box &other) const
    {
        return !(*this == other);
    }
    
    Rectangle Box::toRect() const
    {
        ASSERT(z == 0 && depth == 1);
        return Rectangle(x, y, width, height);
    }
    
    bool Box::coversSameExtent(const Extents &size) const
    {
        return x == 0 && y == 0 && z == 0 && width == size.width && height == size.height &&
               depth == size.depth;
    }
    
    bool operator==(const Offset &a, const Offset &b)
    {
        return a.x == b.x && a.y == b.y && a.z == b.z;
    }
    
    bool operator!=(const Offset &a, const Offset &b)
    {
        return !(a == b);
    }
    
    bool operator==(const Extents &lhs, const Extents &rhs)
    {
        return lhs.width == rhs.width && lhs.height == rhs.height && lhs.depth == rhs.depth;
    }
    
    bool operator!=(const Extents &lhs, const Extents &rhs)
    {
        return !(lhs == rhs);
    }
    
    bool ValidateComponentTypeMasks(unsigned long outputTypes,
                                    unsigned long inputTypes,
                                    unsigned long outputMask,
                                    unsigned long inputMask)
    {
        static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS <= kMaxComponentTypeMaskIndex,
                      "Output/input masks should fit into 16 bits - 1 bit per draw buffer. The "
                      "corresponding type masks should fit into 32 bits - 2 bits per draw buffer.");
        static_assert(MAX_VERTEX_ATTRIBS <= kMaxComponentTypeMaskIndex,
                      "Output/input masks should fit into 16 bits - 1 bit per attrib. The "
                      "corresponding type masks should fit into 32 bits - 2 bits per attrib.");
    
        // For performance reasons, draw buffer and attribute type validation is done using bit masks.
        // We store two bits representing the type split, with the low bit in the lower 16 bits of the
        // variable, and the high bit in the upper 16 bits of the variable. This is done so we can AND
        // with the elswewhere used DrawBufferMask or AttributeMask.
    
        // OR the masks with themselves, shifted 16 bits. This is to match our split type bits.
        outputMask |= (outputMask << kMaxComponentTypeMaskIndex);
        inputMask |= (inputMask << kMaxComponentTypeMaskIndex);
    
        // To validate:
        // 1. Remove any indexes that are not enabled in the input (& inputMask)
        // 2. Remove any indexes that exist in output, but not in input (& outputMask)
        // 3. Use == to verify equality
        return (outputTypes & inputMask) == ((inputTypes & outputMask) & inputMask);
    }
    
    GLsizeiptr GetBoundBufferAvailableSize(const OffsetBindingPointer<Buffer> &binding)
    {
        Buffer *buffer = binding.get();
        if (buffer == nullptr)
        {
            return 0;
        }
    
        const GLsizeiptr bufferSize = static_cast<GLsizeiptr>(buffer->getSize());
    
        if (binding.getSize() == 0)
        {
            return bufferSize;
        }
    
        const GLintptr offset = binding.getOffset();
        const GLsizeiptr size = binding.getSize();
    
        ASSERT(offset >= 0 && bufferSize >= 0);
    
        if (bufferSize <= offset)
        {
            return 0;
        }
    
        return std::min(size, bufferSize - offset);
    }
    
    }  // namespace gl