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