// // 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" #include 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; } bool IsAdvancedBlendEquation(gl::BlendEquationType blendEquation) { return blendEquation >= gl::BlendEquationType::Multiply && blendEquation <= gl::BlendEquationType::HslLuminosity; } } // 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)); } RasterizerState &RasterizerState::operator=(const RasterizerState &other) { memcpy(this, &other, sizeof(RasterizerState)); return *this; } 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(-1); stencilWritemask = static_cast(-1); stencilBackFunc = GL_ALWAYS; stencilBackMask = static_cast(-1); stencilBackWritemask = static_cast(-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)); } DepthStencilState &DepthStencilState::operator=(const DepthStencilState &other) { memcpy(this, &other, sizeof(DepthStencilState)); return *this; } 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(FromGLenum(minFilter)); return true; } return false; } bool SamplerState::setMagFilter(GLenum magFilter) { if (mMagFilter != magFilter) { mMagFilter = magFilter; mCompleteness.typed.magFilter = static_cast(FromGLenum(magFilter)); return true; } return false; } bool SamplerState::setWrapS(GLenum wrapS) { if (mWrapS != wrapS) { mWrapS = wrapS; mCompleteness.typed.wrapS = static_cast(FromGLenum(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(FromGLenum(mWrapT)); uint8_t compare = static_cast(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 drawBufferCount) : mParameterMask(FactorStorage::GetMask(drawBufferCount)), mSrcColor(FactorStorage::GetReplicatedValue(BlendFactorType::One, mParameterMask)), mDstColor(FactorStorage::GetReplicatedValue(BlendFactorType::Zero, mParameterMask)), mSrcAlpha(FactorStorage::GetReplicatedValue(BlendFactorType::One, mParameterMask)), mDstAlpha(FactorStorage::GetReplicatedValue(BlendFactorType::Zero, mParameterMask)), mEquationColor(EquationStorage::GetReplicatedValue(BlendEquationType::Add, mParameterMask)), mEquationAlpha(EquationStorage::GetReplicatedValue(BlendEquationType::Add, mParameterMask)), mAllColorMask( ColorMaskStorage::GetReplicatedValue(PackColorMask(true, true, true, true), ColorMaskStorage::GetMask(drawBufferCount))), mColorMask(mAllColorMask), mAllEnabledMask(0xFF >> (8 - drawBufferCount)), mDrawBufferCount(drawBufferCount) {} BlendStateExt::BlendStateExt(const BlendStateExt &other) = default; BlendStateExt &BlendStateExt::operator=(const BlendStateExt &other) = default; void BlendStateExt::setEnabled(const bool enabled) { mEnabledMask = enabled ? mAllEnabledMask : DrawBufferMask::Zero(); } void BlendStateExt::setEnabledIndexed(const size_t index, const bool enabled) { ASSERT(index < mDrawBufferCount); 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), mAllColorMask); } BlendStateExt::ColorMaskStorage::Type BlendStateExt::expandColorMaskIndexed( const size_t index) const { return ColorMaskStorage::GetReplicatedValue( ColorMaskStorage::GetValueIndexed(index, mColorMask), mAllColorMask); } 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 < mDrawBufferCount); 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 < mDrawBufferCount); ColorMaskStorage::SetValueIndexed(index, PackColorMask(red, green, blue, alpha), &mColorMask); } uint8_t BlendStateExt::getColorMaskIndexed(const size_t index) const { ASSERT(index < mDrawBufferCount); return ColorMaskStorage::GetValueIndexed(index, mColorMask); } void BlendStateExt::getColorMaskIndexed(const size_t index, bool *red, bool *green, bool *blue, bool *alpha) const { ASSERT(index < mDrawBufferCount); 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(mode), mParameterMask); } BlendStateExt::EquationStorage::Type BlendStateExt::expandEquationValue( const gl::BlendEquationType equation) const { return EquationStorage::GetReplicatedValue(equation, mParameterMask); } BlendStateExt::EquationStorage::Type BlendStateExt::expandEquationColorIndexed( const size_t index) const { return EquationStorage::GetReplicatedValue( EquationStorage::GetValueIndexed(index, mEquationColor), mParameterMask); } BlendStateExt::EquationStorage::Type BlendStateExt::expandEquationAlphaIndexed( const size_t index) const { return EquationStorage::GetReplicatedValue( EquationStorage::GetValueIndexed(index, mEquationAlpha), mParameterMask); } void BlendStateExt::setEquations(const GLenum modeColor, const GLenum modeAlpha) { const gl::BlendEquationType colorEquation = FromGLenum(modeColor); const gl::BlendEquationType alphaEquation = FromGLenum(modeAlpha); mEquationColor = expandEquationValue(colorEquation); mEquationAlpha = expandEquationValue(alphaEquation); // Note that advanced blend equations cannot be independently set for color and alpha, so only // the color equation can be checked. if (IsAdvancedBlendEquation(colorEquation)) { mUsesAdvancedBlendEquationMask = mAllEnabledMask; } else { mUsesAdvancedBlendEquationMask.reset(); } } void BlendStateExt::setEquationsIndexed(const size_t index, const GLenum modeColor, const GLenum modeAlpha) { ASSERT(index < mDrawBufferCount); const gl::BlendEquationType colorEquation = FromGLenum(modeColor); const gl::BlendEquationType alphaEquation = FromGLenum(modeAlpha); EquationStorage::SetValueIndexed(index, colorEquation, &mEquationColor); EquationStorage::SetValueIndexed(index, alphaEquation, &mEquationAlpha); mUsesAdvancedBlendEquationMask.set(index, IsAdvancedBlendEquation(colorEquation)); } void BlendStateExt::setEquationsIndexed(const size_t index, const size_t sourceIndex, const BlendStateExt &source) { ASSERT(index < mDrawBufferCount); ASSERT(sourceIndex < source.mDrawBufferCount); const gl::BlendEquationType colorEquation = EquationStorage::GetValueIndexed(sourceIndex, source.mEquationColor); const gl::BlendEquationType alphaEquation = EquationStorage::GetValueIndexed(sourceIndex, source.mEquationAlpha); EquationStorage::SetValueIndexed(index, colorEquation, &mEquationColor); EquationStorage::SetValueIndexed(index, alphaEquation, &mEquationAlpha); mUsesAdvancedBlendEquationMask.set(index, IsAdvancedBlendEquation(colorEquation)); } GLenum BlendStateExt::getEquationColorIndexed(size_t index) const { ASSERT(index < mDrawBufferCount); return ToGLenum(EquationStorage::GetValueIndexed(index, mEquationColor)); } GLenum BlendStateExt::getEquationAlphaIndexed(size_t index) const { ASSERT(index < mDrawBufferCount); 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(func), mParameterMask); } BlendStateExt::FactorStorage::Type BlendStateExt::expandSrcColorIndexed(const size_t index) const { ASSERT(index < mDrawBufferCount); return FactorStorage::GetReplicatedValue(FactorStorage::GetValueIndexed(index, mSrcColor), mParameterMask); } BlendStateExt::FactorStorage::Type BlendStateExt::expandDstColorIndexed(const size_t index) const { ASSERT(index < mDrawBufferCount); return FactorStorage::GetReplicatedValue(FactorStorage::GetValueIndexed(index, mDstColor), mParameterMask); } BlendStateExt::FactorStorage::Type BlendStateExt::expandSrcAlphaIndexed(const size_t index) const { ASSERT(index < mDrawBufferCount); return FactorStorage::GetReplicatedValue(FactorStorage::GetValueIndexed(index, mSrcAlpha), mParameterMask); } BlendStateExt::FactorStorage::Type BlendStateExt::expandDstAlphaIndexed(const size_t index) const { ASSERT(index < mDrawBufferCount); return FactorStorage::GetReplicatedValue(FactorStorage::GetValueIndexed(index, mDstAlpha), mParameterMask); } 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 < mDrawBufferCount); FactorStorage::SetValueIndexed(index, FromGLenum(srcColor), &mSrcColor); FactorStorage::SetValueIndexed(index, FromGLenum(dstColor), &mDstColor); FactorStorage::SetValueIndexed(index, FromGLenum(srcAlpha), &mSrcAlpha); FactorStorage::SetValueIndexed(index, FromGLenum(dstAlpha), &mDstAlpha); } void BlendStateExt::setFactorsIndexed(const size_t index, const size_t sourceIndex, const BlendStateExt &source) { ASSERT(index < mDrawBufferCount); ASSERT(sourceIndex < source.mDrawBufferCount); 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 < mDrawBufferCount); return ToGLenum(FactorStorage::GetValueIndexed(index, mSrcColor)); } GLenum BlendStateExt::getDstColorIndexed(size_t index) const { ASSERT(index < mDrawBufferCount); return ToGLenum(FactorStorage::GetValueIndexed(index, mDstColor)); } GLenum BlendStateExt::getSrcAlphaIndexed(size_t index) const { ASSERT(index < mDrawBufferCount); return ToGLenum(FactorStorage::GetValueIndexed(index, mSrcAlpha)); } GLenum BlendStateExt::getDstAlphaIndexed(size_t index) const { ASSERT(index < mDrawBufferCount); 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; } } template <> bool RectangleImpl::empty() const { return width == 0 && height == 0; } template <> bool RectangleImpl::empty() const { return std::abs(width) < std::numeric_limits::epsilon() && std::abs(height) < std::numeric_limits::epsilon(); } bool ClipRectangle(const Rectangle &source, const Rectangle &clip, Rectangle *intersection) { angle::CheckedNumeric sourceX2(source.x); sourceX2 += source.width; if (!sourceX2.IsValid()) { return false; } angle::CheckedNumeric 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 clipX2(clip.x); clipX2 += clip.width; if (!clipX2.IsValid()) { return false; } angle::CheckedNumeric 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(rect1.x) + rect1.width).IsValid()); ASSERT((angle::CheckedNumeric(rect1.y) + rect1.height).IsValid()); ASSERT((angle::CheckedNumeric(rect2.x) + rect2.width).IsValid()); ASSERT((angle::CheckedNumeric(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(source.x) + source.width).IsValid()); ASSERT((angle::CheckedNumeric(source.y) + source.height).IsValid()); ASSERT((angle::CheckedNumeric(extend.x) + extend.width).IsValid()); ASSERT((angle::CheckedNumeric(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::valid() const { return width != 0 && height != 0 && depth != 0; } 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 Box::contains(const Box &other) const { return x <= other.x && y <= other.y && z <= other.z && x + width >= other.x + other.width && y + height >= other.y + other.height && z + depth >= other.z + other.depth; } size_t Box::volume() const { return width * height * depth; } void Box::extend(const Box &other) { // This extends the logic of "ExtendRectangle" to 3 dimensions int x0 = x; int x1 = x + width; int y0 = y; int y1 = y + height; int z0 = z; int z1 = z + depth; const int otherx0 = other.x; const int otherx1 = other.x + other.width; const int othery0 = other.y; const int othery1 = other.y + other.height; const int otherz0 = other.z; const int otherz1 = other.z + other.depth; // For each side of the box, calculate whether it can be extended by the other box. // If so, extend it and continue to the next side with the new dimensions. const bool enclosesWidth = EnclosesRange(otherx0, otherx1, x0, x1); const bool enclosesHeight = EnclosesRange(othery0, othery1, y0, y1); const bool enclosesDepth = EnclosesRange(otherz0, otherz1, z0, z1); // Left: Reduce x0 if the other box's Y and Z plane encloses the source if (otherx0 < x0 && otherx1 >= x0 && enclosesHeight && enclosesDepth) { x0 = otherx0; } // Right: Increase x1 simiarly. if (otherx0 <= x1 && otherx1 > x1 && enclosesHeight && enclosesDepth) { x1 = otherx1; } // Bottom: Reduce y0 if the other box's X and Z plane encloses the source if (othery0 < y0 && othery1 >= y0 && enclosesWidth && enclosesDepth) { y0 = othery0; } // Top: Increase y1 simiarly. if (othery0 <= y1 && othery1 > y1 && enclosesWidth && enclosesDepth) { y1 = othery1; } // Front: Reduce z0 if the other box's X and Y plane encloses the source if (otherz0 < z0 && otherz1 >= z0 && enclosesWidth && enclosesHeight) { z0 = otherz0; } // Back: Increase z1 simiarly. if (otherz0 <= z1 && otherz1 > z1 && enclosesWidth && enclosesHeight) { z1 = otherz1; } // Update member var with new dimensions x = x0; width = x1 - x0; y = y0; height = y1 - y0; z = z0; depth = z1 - z0; } 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 &binding) { Buffer *buffer = binding.get(); if (buffer == nullptr) { return 0; } const GLsizeiptr bufferSize = static_cast(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