summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/libANGLE/angletypes.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/libANGLE/angletypes.cpp')
-rw-r--r--gfx/angle/checkout/src/libANGLE/angletypes.cpp1039
1 files changed, 1039 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/angletypes.cpp b/gfx/angle/checkout/src/libANGLE/angletypes.cpp
new file mode 100644
index 0000000000..19f9a25441
--- /dev/null
+++ b/gfx/angle/checkout/src/libANGLE/angletypes.cpp
@@ -0,0 +1,1039 @@
+//
+// 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 <limits>
+
+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<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));
+}
+
+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<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 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<BlendEquationType>(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<BlendEquationType>(modeColor);
+ const gl::BlendEquationType alphaEquation = FromGLenum<BlendEquationType>(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<BlendEquationType>(modeColor);
+ const gl::BlendEquationType alphaEquation = FromGLenum<BlendEquationType>(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<BlendFactorType>(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<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 < 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<int>::empty() const
+{
+ return width == 0 && height == 0;
+}
+
+template <>
+bool RectangleImpl<float>::empty() const
+{
+ return std::abs(width) < std::numeric_limits<float>::epsilon() &&
+ std::abs(height) < std::numeric_limits<float>::epsilon();
+}
+
+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::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<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