| // |
| // 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; |
| } |
| |
| void SamplerState::setMinFilter(GLenum minFilter) |
| { |
| mMinFilter = minFilter; |
| mCompleteness.typed.minFilter = static_cast<uint8_t>(FromGLenum<FilterMode>(minFilter)); |
| } |
| |
| void SamplerState::setMagFilter(GLenum magFilter) |
| { |
| mMagFilter = magFilter; |
| mCompleteness.typed.magFilter = static_cast<uint8_t>(FromGLenum<FilterMode>(magFilter)); |
| } |
| |
| void SamplerState::setWrapS(GLenum wrapS) |
| { |
| mWrapS = wrapS; |
| mCompleteness.typed.wrapS = static_cast<uint8_t>(FromGLenum<WrapMode>(wrapS)); |
| } |
| |
| void SamplerState::setWrapT(GLenum wrapT) |
| { |
| mWrapT = wrapT; |
| updateWrapTCompareMode(); |
| } |
| |
| void SamplerState::setWrapR(GLenum wrapR) |
| { |
| mWrapR = wrapR; |
| } |
| |
| void SamplerState::setMaxAnisotropy(float maxAnisotropy) |
| { |
| mMaxAnisotropy = maxAnisotropy; |
| } |
| |
| void SamplerState::setMinLod(GLfloat minLod) |
| { |
| mMinLod = minLod; |
| } |
| |
| void SamplerState::setMaxLod(GLfloat maxLod) |
| { |
| mMaxLod = maxLod; |
| } |
| |
| void SamplerState::setCompareMode(GLenum compareMode) |
| { |
| mCompareMode = compareMode; |
| updateWrapTCompareMode(); |
| } |
| |
| void SamplerState::setCompareFunc(GLenum compareFunc) |
| { |
| mCompareFunc = compareFunc; |
| } |
| |
| void SamplerState::setSRGBDecode(GLenum sRGBDecode) |
| { |
| mSRGBDecode = sRGBDecode; |
| } |
| |
| void SamplerState::setBorderColor(const ColorGeneric &color) |
| { |
| mBorderColor = color; |
| } |
| |
| 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::operator=(const BlendStateExt &other) |
| { |
| memcpy(this, &other, sizeof(BlendStateExt)); |
| return *this; |
| } |
| |
| 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) |
| { |
| if (binding.getSize() == 0) |
| return static_cast<GLsizeiptr>(buffer->getSize()); |
| angle::CheckedNumeric<GLintptr> offset = binding.getOffset(); |
| angle::CheckedNumeric<GLsizeiptr> size = binding.getSize(); |
| angle::CheckedNumeric<GLsizeiptr> bufferSize = buffer->getSize(); |
| auto end = offset + size; |
| auto clampedSize = size; |
| auto difference = end - bufferSize; |
| if (!difference.IsValid()) |
| { |
| return 0; |
| } |
| if (difference.ValueOrDie() > 0) |
| { |
| clampedSize = size - difference; |
| } |
| return clampedSize.ValueOrDefault(0); |
| } |
| else |
| { |
| return 0; |
| } |
| } |
| |
| } // namespace gl |