Source code

Revision control

Copy as Markdown

Other Tools

//
// Copyright 2019 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.
//
// mtl_state_cache.h:
// Defines the class interface for StateCache, RenderPipelineCache and various
// C struct versions of Metal sampler, depth stencil, render pass, render pipeline descriptors.
//
#ifndef LIBANGLE_RENDERER_METAL_MTL_STATE_CACHE_H_
#define LIBANGLE_RENDERER_METAL_MTL_STATE_CACHE_H_
#import <Metal/Metal.h>
#include <unordered_map>
#include "common/hash_utils.h"
#include "common/unsafe_buffers.h"
#include "libANGLE/State.h"
#include "libANGLE/angletypes.h"
#include "libANGLE/renderer/metal/mtl_common.h"
#include "libANGLE/renderer/metal/mtl_context_device.h"
#include "libANGLE/renderer/metal/mtl_resources.h"
static inline bool operator==(const MTLClearColor &lhs, const MTLClearColor &rhs);
namespace angle
{
struct FeaturesMtl;
}
namespace rx
{
class ContextMtl;
namespace mtl
{
ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
class StencilDesc
{
public:
constexpr StencilDesc()
: readMask(mtl::kStencilMaskAll),
writeMask(mtl::kStencilMaskAll),
mStencilFailureOperation(MTLStencilOperationKeep),
mDepthFailureOperation(MTLStencilOperationKeep),
mDepthStencilPassOperation(MTLStencilOperationKeep),
mStencilCompareFunction(MTLCompareFunctionAlways)
{}
constexpr bool operator==(const StencilDesc &rhs) const = default;
size_t hash() const;
void setStencilFailureOperation(MTLStencilOperation op)
{
mStencilFailureOperation = static_cast<uint32_t>(op);
}
MTLStencilOperation getStencilFailureOperation() const
{
return static_cast<MTLStencilOperation>(mStencilFailureOperation);
}
void setDepthFailureOperation(MTLStencilOperation op)
{
mDepthFailureOperation = static_cast<uint32_t>(op);
}
MTLStencilOperation getDepthFailureOperation() const
{
return static_cast<MTLStencilOperation>(mDepthFailureOperation);
}
void setDepthStencilPassOperation(MTLStencilOperation op)
{
mDepthStencilPassOperation = static_cast<uint32_t>(op);
}
MTLStencilOperation getDepthStencilPassOperation() const
{
return static_cast<MTLStencilOperation>(mDepthStencilPassOperation);
}
void setStencilCompareFunction(MTLCompareFunction func)
{
mStencilCompareFunction = static_cast<uint32_t>(func);
}
MTLCompareFunction getStencilCompareFunction() const
{
return static_cast<MTLCompareFunction>(mStencilCompareFunction);
}
// All bitfields in same access section to avoid padding between access specifiers.
uint32_t readMask : 8; // uint8_t.
uint32_t writeMask : 8; // uint8_t.
private:
uint32_t mStencilFailureOperation : 3; // MTLStencilOperation.
uint32_t mDepthFailureOperation : 3; // MTLStencilOperation.
uint32_t mDepthStencilPassOperation : 3; // MTLStencilOperation.
uint32_t mStencilCompareFunction : 7; // MTLCompareFunction 3 bits + 4 bits padding.
};
static_assert(alignof(StencilDesc) <= 4);
static_assert(sizeof(StencilDesc) == 4);
ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
inline size_t StencilDesc::hash() const
{
return angle::HashMultiple<uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t>(
readMask, writeMask, mStencilFailureOperation, mDepthFailureOperation,
mDepthStencilPassOperation, mStencilCompareFunction);
}
ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
class DepthStencilDesc
{
public:
constexpr DepthStencilDesc() : DepthStencilDesc(MTLCompareFunctionAlways, true) {}
constexpr DepthStencilDesc(MTLCompareFunction func, bool depthWriteEnabled)
: mDepthCompareFunction(static_cast<uint32_t>(func)), mDepthWriteEnabled(depthWriteEnabled)
{}
constexpr bool operator==(const DepthStencilDesc &rhs) const = default;
size_t hash() const;
void updateDepthTestEnabled(const gl::DepthStencilState &dsState);
void updateDepthWriteEnabled(const gl::DepthStencilState &dsState);
void updateDepthCompareFunc(const gl::DepthStencilState &dsState);
void updateStencilTestEnabled(const gl::DepthStencilState &dsState);
void updateStencilFrontOps(const gl::DepthStencilState &dsState);
void updateStencilBackOps(const gl::DepthStencilState &dsState);
void updateStencilFrontFuncs(const gl::DepthStencilState &dsState);
void updateStencilBackFuncs(const gl::DepthStencilState &dsState);
void updateStencilFrontWriteMask(const gl::DepthStencilState &dsState);
void updateStencilBackWriteMask(const gl::DepthStencilState &dsState);
MTLCompareFunction getDepthCompareFunction() const
{
return static_cast<MTLCompareFunction>(mDepthCompareFunction);
}
void setDepthWriteDisabled()
{
mDepthCompareFunction = MTLCompareFunctionAlways;
mDepthWriteEnabled = false;
}
bool isDepthWriteEnabled() const { return mDepthWriteEnabled; }
StencilDesc backFaceStencil;
StencilDesc frontFaceStencil;
private:
// All bitfields in same access section to avoid padding between access specifiers.
uint32_t mDepthCompareFunction : 3; // MTLCompareFunction.
uint32_t mDepthWriteEnabled : 29; // bool + 28 bit padding.
};
static_assert(alignof(DepthStencilDesc) <= 4);
static_assert(sizeof(DepthStencilDesc) == 12);
ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
inline size_t DepthStencilDesc::hash() const
{
return angle::HashMultiple<StencilDesc, StencilDesc, uint8_t, bool>(
backFaceStencil, frontFaceStencil, mDepthCompareFunction, mDepthWriteEnabled);
}
ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
class SamplerDesc
{
public:
constexpr SamplerDesc()
: mRAddressMode(MTLSamplerAddressModeClampToEdge),
mSAddressMode(MTLSamplerAddressModeClampToEdge),
mTAddressMode(MTLSamplerAddressModeClampToEdge),
mMinFilter(MTLSamplerMinMagFilterNearest),
mMagFilter(MTLSamplerMinMagFilterNearest),
mMipFilter(MTLSamplerMipFilterNearest),
mMaxAnisotropy(1),
mCompareFunction(MTLCompareFunctionNever)
{}
explicit SamplerDesc(const gl::SamplerState &glState);
constexpr bool operator==(const SamplerDesc &rhs) const = default;
size_t hash() const;
void setRAddressMode(MTLSamplerAddressMode mode)
{
mRAddressMode = static_cast<uint32_t>(mode);
}
MTLSamplerAddressMode getRAddressMode() const
{
return static_cast<MTLSamplerAddressMode>(mRAddressMode);
}
void setSAddressMode(MTLSamplerAddressMode mode)
{
mSAddressMode = static_cast<uint32_t>(mode);
}
MTLSamplerAddressMode getSAddressMode() const
{
return static_cast<MTLSamplerAddressMode>(mSAddressMode);
}
void setTAddressMode(MTLSamplerAddressMode mode)
{
mTAddressMode = static_cast<uint32_t>(mode);
}
MTLSamplerAddressMode getTAddressMode() const
{
return static_cast<MTLSamplerAddressMode>(mTAddressMode);
}
void setMinFilter(MTLSamplerMinMagFilter filter) { mMinFilter = static_cast<uint32_t>(filter); }
MTLSamplerMinMagFilter getMinFilter() const
{
return static_cast<MTLSamplerMinMagFilter>(mMinFilter);
}
void setMagFilter(MTLSamplerMinMagFilter filter) { mMagFilter = static_cast<uint32_t>(filter); }
MTLSamplerMinMagFilter getMagFilter() const
{
return static_cast<MTLSamplerMinMagFilter>(mMagFilter);
}
void setMipFilter(MTLSamplerMipFilter filter) { mMipFilter = static_cast<uint32_t>(filter); }
MTLSamplerMipFilter getMipFilter() const
{
return static_cast<MTLSamplerMipFilter>(mMipFilter);
}
void setMaxAnisotropy(NSUInteger value) { mMaxAnisotropy = static_cast<uint32_t>(value); }
NSUInteger getMaxAnisotropy() const { return static_cast<NSUInteger>(mMaxAnisotropy); }
void setCompareFunction(MTLCompareFunction func)
{
mCompareFunction = static_cast<uint32_t>(func);
}
MTLCompareFunction getCompareFunction() const
{
return static_cast<MTLCompareFunction>(mCompareFunction);
}
private:
uint32_t mRAddressMode : 3; // MTLSamplerAddressMode.
uint32_t mSAddressMode : 3; // MTLSamplerAddressMode.
uint32_t mTAddressMode : 3; // MTLSamplerAddressMode.
uint32_t mMinFilter : 1; // MTLSamplerMinMagFilter.
uint32_t mMagFilter : 1; // MTLSamplerMinMagFilter
uint32_t mMipFilter : 2; // MTLSamplerMipFilter.
uint32_t mMaxAnisotropy : 5; // NSUInteger.
uint32_t mCompareFunction : 14; // MTLCompareFunction 3 bits + 11 bits padding.
};
static_assert(alignof(SamplerDesc) <= 4);
static_assert(sizeof(SamplerDesc) == 4);
ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
inline size_t SamplerDesc::hash() const
{
return angle::HashMultiple<uint8_t, uint8_t, uint8_t, bool, bool, uint8_t, uint8_t, uint8_t>(
mRAddressMode, mSAddressMode, mTAddressMode, mMinFilter, mMagFilter, mMipFilter,
mMaxAnisotropy, mCompareFunction);
}
ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
class VertexAttributeDesc
{
public:
constexpr VertexAttributeDesc() : mFormat(0), mOffset(0), mBufferIndex(0) {}
constexpr VertexAttributeDesc(MTLVertexFormat format, NSUInteger offset, NSUInteger bufferIndex)
: mFormat(static_cast<uint32_t>(format)),
mOffset(static_cast<uint32_t>(offset)),
mBufferIndex(static_cast<uint32_t>(bufferIndex))
{}
constexpr bool operator==(const VertexAttributeDesc &rhs) const = default;
size_t hash() const;
MTLVertexFormat getFormat() const { return static_cast<MTLVertexFormat>(mFormat); }
NSUInteger getOffset() const { return static_cast<NSUInteger>(mOffset); }
NSUInteger getBufferIndex() const { return static_cast<NSUInteger>(mBufferIndex); }
private:
uint32_t mFormat : 8; // MTLVertexFormat.
// Offset is only used for default attributes buffer. So 8 bits are enough.
uint32_t mOffset : 8; // NSUInteger.
uint32_t mBufferIndex : 16; // NSUInteger 8 bits + 8 bits padding.
};
static_assert(alignof(VertexAttributeDesc) <= 4);
static_assert(sizeof(VertexAttributeDesc) == 4);
ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
inline size_t VertexAttributeDesc::hash() const
{
return angle::HashMultiple<uint8_t, uint8_t, uint8_t>(mFormat, mOffset, mBufferIndex);
}
ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
class VertexBufferLayoutDesc
{
public:
constexpr VertexBufferLayoutDesc() = default;
constexpr VertexBufferLayoutDesc(uint32_t stepRate, uint32_t stride, MTLVertexStepFunction func)
: stepRate(stepRate), stride(stride), mStepFunction(static_cast<uint32_t>(func))
{}
constexpr bool operator==(const VertexBufferLayoutDesc &rhs) const = default;
size_t hash() const;
uint32_t stepRate = 0;
uint32_t stride = 0;
MTLVertexStepFunction getStepFunction() const
{
return static_cast<MTLVertexStepFunction>(mStepFunction);
}
private:
uint32_t mStepFunction = MTLVertexStepFunctionConstant; // MTLVertexStepFunction.
};
static_assert(alignof(VertexBufferLayoutDesc) == 4);
static_assert(sizeof(VertexBufferLayoutDesc) == 12);
ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
inline size_t VertexBufferLayoutDesc::hash() const
{
return angle::HashMultiple<uint32_t, uint32_t, uint8_t>(stepRate, stride, mStepFunction);
}
ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
struct VertexDesc
{
constexpr VertexDesc() : numAttribs(0), numBufferLayouts(0) {}
constexpr bool operator==(const VertexDesc &rhs) const;
size_t hash() const;
VertexAttributeDesc attributes[kMaxVertexAttribs];
VertexBufferLayoutDesc layouts[kMaxVertexAttribs];
uint16_t numAttribs = 0;
uint16_t numBufferLayouts = 0;
};
static_assert(alignof(VertexDesc) == 4);
static_assert(sizeof(VertexDesc) == 260);
ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
constexpr inline bool VertexDesc::operator==(const VertexDesc &rhs) const
{
if (numAttribs != rhs.numAttribs || numBufferLayouts != rhs.numBufferLayouts)
{
return false;
}
for (uint8_t i = 0; i < numAttribs; ++i)
{
if (ANGLE_UNSAFE_TODO(attributes[i] != rhs.attributes[i]))
{
return false;
}
}
for (uint8_t i = 0; i < numBufferLayouts; ++i)
{
if (ANGLE_UNSAFE_TODO(layouts[i] != rhs.layouts[i]))
{
return false;
}
}
return true;
}
inline size_t VertexDesc::hash() const
{
size_t hash = 0;
angle::HashCombine(hash, numAttribs);
angle::HashCombine(hash, numBufferLayouts);
for (uint8_t i = 0; i < numAttribs; ++i)
{
angle::HashCombine(hash, ANGLE_UNSAFE_TODO(attributes[i]));
}
for (uint8_t i = 0; i < numBufferLayouts; ++i)
{
angle::HashCombine(hash, ANGLE_UNSAFE_TODO(layouts[i]));
}
return hash;
}
ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
class BlendDesc
{
public:
constexpr BlendDesc()
: mWriteMask(MTLColorWriteMaskAll),
mSourceRgbBlendFactor(MTLBlendFactorOne),
mSourceAlphaBlendFactor(MTLBlendFactorOne),
mDestinationRgbBlendFactor(MTLBlendFactorZero),
mDestinationAlphaBlendFactor(MTLBlendFactorZero),
mRgbBlendOperation(MTLBlendOperationAdd),
mAlphaBlendOperation(MTLBlendOperationAdd),
mBlendingEnabled(false)
{}
constexpr bool operator==(const BlendDesc &rhs) const = default;
size_t hash() const;
// Set default values
void reset(MTLColorWriteMask mask)
{
*this = {};
mWriteMask = static_cast<uint32_t>(mask);
}
void updateWriteMask(uint8_t angleMask);
void setBlendingEnabled(MTLBlendFactor sourceRgb,
MTLBlendFactor sourceAlpha,
MTLBlendFactor destRgb,
MTLBlendFactor destAlpha,
MTLBlendOperation opRgb,
MTLBlendOperation opAlpha)
{
mSourceRgbBlendFactor = static_cast<uint32_t>(sourceRgb);
mSourceAlphaBlendFactor = static_cast<uint32_t>(sourceAlpha);
mDestinationRgbBlendFactor = static_cast<uint32_t>(destRgb);
mDestinationAlphaBlendFactor = static_cast<uint32_t>(destAlpha);
mRgbBlendOperation = static_cast<uint32_t>(opRgb);
mAlphaBlendOperation = static_cast<uint32_t>(opAlpha);
mBlendingEnabled = true;
}
void setBlendingDisabled()
{
mSourceRgbBlendFactor = MTLBlendFactorOne;
mSourceAlphaBlendFactor = MTLBlendFactorOne;
mDestinationRgbBlendFactor = MTLBlendFactorZero;
mDestinationAlphaBlendFactor = MTLBlendFactorZero;
mRgbBlendOperation = MTLBlendOperationAdd;
mAlphaBlendOperation = MTLBlendOperationAdd;
mBlendingEnabled = false;
}
void setWriteMask(MTLColorWriteMask mask) { mWriteMask = static_cast<uint32_t>(mask); }
MTLColorWriteMask getWriteMask() const { return static_cast<uint8_t>(mWriteMask); }
MTLBlendFactor getSourceRgbBlendFactor() const
{
return static_cast<MTLBlendFactor>(mSourceRgbBlendFactor);
}
MTLBlendFactor getSourceAlphaBlendFactor() const
{
return static_cast<MTLBlendFactor>(mSourceAlphaBlendFactor);
}
MTLBlendFactor getDestinationRgbBlendFactor() const
{
return static_cast<MTLBlendFactor>(mDestinationRgbBlendFactor);
}
MTLBlendFactor getDestinationAlphaBlendFactor() const
{
return static_cast<MTLBlendFactor>(mDestinationAlphaBlendFactor);
}
MTLBlendOperation getRgbBlendOperation() const
{
return static_cast<MTLBlendOperation>(mRgbBlendOperation);
}
MTLBlendOperation getAlphaBlendOperation() const
{
return static_cast<MTLBlendOperation>(mAlphaBlendOperation);
}
bool isBlendingEnabled() const { return mBlendingEnabled; }
protected:
uint32_t mWriteMask : 4; // MTLColorWriteMask.
uint32_t mSourceRgbBlendFactor : 5; // MTLBlendFactor.
uint32_t mSourceAlphaBlendFactor : 5; // MTLBlendFactor
uint32_t mDestinationRgbBlendFactor : 5; // MTLBlendFactor
uint32_t mDestinationAlphaBlendFactor : 5; // MTLBlendFactor
uint32_t mRgbBlendOperation : 3; // MTLBlendOperation.
uint32_t mAlphaBlendOperation : 3; // MTLBlendOperation.
uint32_t mBlendingEnabled : 2; // bool + 1 bit padding.
};
static_assert(alignof(BlendDesc) <= 4);
static_assert(sizeof(BlendDesc) == 4);
ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
inline size_t BlendDesc::hash() const
{
return angle::HashMultiple<uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, bool>(
mWriteMask, mSourceRgbBlendFactor, mSourceAlphaBlendFactor, mDestinationRgbBlendFactor,
mDestinationAlphaBlendFactor, mRgbBlendOperation, mAlphaBlendOperation, mBlendingEnabled);
}
using BlendDescArray = std::array<BlendDesc, kMaxRenderTargets>;
using WriteMaskArray = std::array<uint8_t, kMaxRenderTargets>;
ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
class RenderPipelineColorAttachmentDesc : public BlendDesc
{
public:
constexpr bool operator==(const RenderPipelineColorAttachmentDesc &rhs) const = default;
size_t hash() const;
// Set default values
void reset(MTLPixelFormat format)
{
*this = {};
mPixelFormat = static_cast<uint32_t>(format);
}
void reset(MTLPixelFormat format, MTLColorWriteMask writeMask);
void reset(MTLPixelFormat format, const BlendDesc &blendDesc);
void setPixelFormat(MTLPixelFormat format) { mPixelFormat = static_cast<uint32_t>(format); }
MTLPixelFormat getPixelFormat() const { return static_cast<MTLPixelFormat>(mPixelFormat); }
private:
uint32_t mPixelFormat = MTLPixelFormatInvalid; // MTLPixelFormat + 16 bits padding.
};
static_assert(alignof(RenderPipelineColorAttachmentDesc) == 4);
static_assert(sizeof(RenderPipelineColorAttachmentDesc) == 8);
ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
inline size_t RenderPipelineColorAttachmentDesc::hash() const
{
size_t hash = BlendDesc::hash();
angle::HashCombine(hash, static_cast<uint16_t>(mPixelFormat));
return hash;
}
ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
class RenderPipelineOutputDesc
{
public:
constexpr RenderPipelineOutputDesc()
: mDepthAttachmentPixelFormat(0),
mStencilAttachmentPixelFormat(0),
mNumColorAttachments(0),
mRasterSampleCount(1)
{}
bool operator==(const RenderPipelineOutputDesc &rhs) const;
size_t hash() const;
void updateEnabledDrawBuffers(gl::DrawBufferMask enabledBuffers);
std::array<RenderPipelineColorAttachmentDesc, kMaxRenderTargets> colorAttachments;
void setDepthAttachmentPixelFormat(MTLPixelFormat value)
{
mDepthAttachmentPixelFormat = static_cast<uint32_t>(value);
}
MTLPixelFormat getDepthAttachmentPixelFormat() const
{
return static_cast<MTLPixelFormat>(mDepthAttachmentPixelFormat);
}
void setStencilAttachmentPixelFormat(MTLPixelFormat value)
{
mStencilAttachmentPixelFormat = static_cast<uint32_t>(value);
}
MTLPixelFormat getStencilAttachmentPixelFormat() const
{
return static_cast<MTLPixelFormat>(mStencilAttachmentPixelFormat);
}
void setNumColorAttachments(NSUInteger value)
{
mNumColorAttachments = static_cast<uint32_t>(value);
}
NSUInteger getNumColorAttachments() const
{
return static_cast<NSUInteger>(mNumColorAttachments);
}
void setRasterSampleCount(NSUInteger value)
{
mRasterSampleCount = static_cast<uint32_t>(value);
}
NSUInteger getRasterSampleCount() const { return static_cast<NSUInteger>(mRasterSampleCount); }
private:
uint32_t mDepthAttachmentPixelFormat : 16; // MTLPixelFormat.
uint32_t mStencilAttachmentPixelFormat : 16; // MTLPixelFormat.
uint32_t mNumColorAttachments : 16; // NSUInteger.
uint32_t mRasterSampleCount : 16; // NSUInteger.
};
static_assert(alignof(RenderPipelineOutputDesc) == 4);
static_assert(sizeof(RenderPipelineOutputDesc) == 72);
ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
enum class RenderPipelineRasterization : uint32_t
{
// This flag is used for vertex shader not writing any stage output (e.g gl_Position).
// This will disable fragment shader stage. This is useful for transform feedback ouput vertex
// shader.
Disabled,
// Fragment shader is enabled.
Enabled,
// This flag is for rasterization discard emulation when vertex shader still writes to stage
// output. Disabled flag cannot be used in this case since Metal doesn't allow that. The
// emulation would insert a code snippet to move gl_Position out of clip space's visible area to
// simulate the discard.
EmulatedDiscard,
EnumCount,
};
template <typename T>
using RenderPipelineRasterStateMap = angle::PackedEnumMap<RenderPipelineRasterization, T>;
ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
class RenderPipelineDesc
{
public:
constexpr RenderPipelineDesc()
: mInputPrimitiveTopology(MTLPrimitiveTopologyClassUnspecified),
mAlphaToCoverageEnabled(false),
mRasterizationType(static_cast<uint32_t>(RenderPipelineRasterization::Enabled))
{}
bool operator==(const RenderPipelineDesc &rhs) const = default;
size_t hash() const;
bool rasterizationEnabled() const;
angle::ObjCPtr<MTLRenderPipelineDescriptor> createMetalDesc(
id<MTLFunction> vertexShader,
id<MTLFunction> fragmentShader) const;
VertexDesc vertexDescriptor;
RenderPipelineOutputDesc outputDescriptor;
void setInputPrimitiveTopology(MTLPrimitiveTopologyClass value)
{
mInputPrimitiveTopology = static_cast<uint32_t>(value);
}
MTLPrimitiveTopologyClass getInputPrimitiveTopology() const
{
return static_cast<MTLPrimitiveTopologyClass>(mInputPrimitiveTopology);
}
void setAlphaToCoverageEnabled(bool value)
{
mAlphaToCoverageEnabled = static_cast<uint32_t>(value);
}
bool getAlphaToCoverageEnabled() const { return mAlphaToCoverageEnabled; }
void setRasterizationType(RenderPipelineRasterization value)
{
mRasterizationType = static_cast<uint32_t>(value);
}
RenderPipelineRasterization getRasterizationType() const
{
return static_cast<RenderPipelineRasterization>(mRasterizationType);
}
private:
uint32_t mInputPrimitiveTopology : 8; // MTLPrimitiveTopologyClass.
uint32_t mAlphaToCoverageEnabled : 8; // bool.
// These flags are for emulation and do not correspond to any flags in
// MTLRenderPipelineDescriptor descriptor. These flags should be used by
// RenderPipelineCacheSpecializeShaderFactory.
uint32_t mRasterizationType : 16; // RenderPipelineRasterization + padding.
};
static_assert(alignof(RenderPipelineDesc) <= 4);
static_assert(sizeof(RenderPipelineDesc) == 336);
ANGLE_DISABLE_STRUCT_PADDING_WARNINGS
inline size_t RenderPipelineDesc::hash() const
{
return angle::HashMultiple(
vertexDescriptor, outputDescriptor, static_cast<uint8_t>(mInputPrimitiveTopology),
static_cast<bool>(mAlphaToCoverageEnabled), static_cast<uint8_t>(mRasterizationType));
}
struct RenderPassAttachmentDesc
{
bool equalIgnoreLoadStoreOptions(const RenderPassAttachmentDesc &other) const;
bool operator==(const RenderPassAttachmentDesc &other) const;
ANGLE_INLINE bool hasImplicitMSTexture() const { return implicitMSTexture.get(); }
const TextureRef &getImplicitMSTextureIfAvailOrTexture() const
{
return hasImplicitMSTexture() ? implicitMSTexture : texture;
}
TextureRef texture;
// Implicit multisample texture that will be rendered into and discarded at the end of
// a render pass. Its result will be resolved into normal texture above.
TextureRef implicitMSTexture;
MipmapNativeLevel level = mtl::kZeroNativeMipLevel;
uint32_t sliceOrDepth = 0;
// This attachment is blendable or not.
bool blendable = false;
MTLLoadAction loadAction = MTLLoadActionLoad;
MTLStoreAction storeAction = MTLStoreActionStore;
MTLStoreActionOptions storeActionOptions = MTLStoreActionOptionNone;
};
struct RenderPassColorAttachmentDesc : public RenderPassAttachmentDesc
{
inline bool operator==(const RenderPassColorAttachmentDesc &other) const
{
return RenderPassAttachmentDesc::operator==(other) && clearColor == other.clearColor;
}
inline bool operator!=(const RenderPassColorAttachmentDesc &other) const
{
return !(*this == other);
}
MTLClearColor clearColor = {0, 0, 0, 0};
};
struct RenderPassDepthAttachmentDesc : public RenderPassAttachmentDesc
{
inline bool operator==(const RenderPassDepthAttachmentDesc &other) const
{
return RenderPassAttachmentDesc::operator==(other) && clearDepth == other.clearDepth;
}
inline bool operator!=(const RenderPassDepthAttachmentDesc &other) const
{
return !(*this == other);
}
double clearDepth = 1.0;
};
struct RenderPassStencilAttachmentDesc : public RenderPassAttachmentDesc
{
inline bool operator==(const RenderPassStencilAttachmentDesc &other) const
{
return RenderPassAttachmentDesc::operator==(other) && clearStencil == other.clearStencil;
}
inline bool operator!=(const RenderPassStencilAttachmentDesc &other) const
{
return !(*this == other);
}
uint32_t clearStencil = 0;
};
//
// This is C++ equivalent of Objective-C MTLRenderPassDescriptor.
// We could use MTLRenderPassDescriptor directly, however, using C++ struct has benefits of fast
// copy, stack allocation, inlined comparing function, etc.
//
struct RenderPassDesc
{
std::array<RenderPassColorAttachmentDesc, kMaxRenderTargets> colorAttachments;
RenderPassDepthAttachmentDesc depthAttachment;
RenderPassStencilAttachmentDesc stencilAttachment;
void convertToMetalDesc(MTLRenderPassDescriptor *objCDesc,
uint32_t deviceMaxRenderTargets) const;
// This will populate the RenderPipelineOutputDesc with default blend state and
// MTLColorWriteMaskAll
void populateRenderPipelineOutputDesc(RenderPipelineOutputDesc *outDesc) const;
// This will populate the RenderPipelineOutputDesc with default blend state and the specified
// MTLColorWriteMask
void populateRenderPipelineOutputDesc(const WriteMaskArray &writeMaskArray,
RenderPipelineOutputDesc *outDesc) const;
// This will populate the RenderPipelineOutputDesc with the specified blend state
void populateRenderPipelineOutputDesc(const BlendDescArray &blendDescArray,
RenderPipelineOutputDesc *outDesc) const;
bool equalIgnoreLoadStoreOptions(const RenderPassDesc &other) const;
bool operator==(const RenderPassDesc &other) const;
inline bool operator!=(const RenderPassDesc &other) const { return !(*this == other); }
uint32_t numColorAttachments = 0;
uint32_t rasterSampleCount = 1;
uint32_t defaultWidth = 0;
uint32_t defaultHeight = 0;
};
} // namespace mtl
} // namespace rx
namespace std
{
template <>
struct hash<rx::mtl::StencilDesc>
{
size_t operator()(const rx::mtl::StencilDesc &key) const { return key.hash(); }
};
template <>
struct hash<rx::mtl::DepthStencilDesc>
{
size_t operator()(const rx::mtl::DepthStencilDesc &key) const { return key.hash(); }
};
template <>
struct hash<rx::mtl::SamplerDesc>
{
size_t operator()(const rx::mtl::SamplerDesc &key) const { return key.hash(); }
};
template <>
struct hash<rx::mtl::VertexAttributeDesc>
{
size_t operator()(const rx::mtl::VertexAttributeDesc &key) const { return key.hash(); }
};
template <>
struct hash<rx::mtl::VertexBufferLayoutDesc>
{
size_t operator()(const rx::mtl::VertexBufferLayoutDesc &key) const { return key.hash(); }
};
template <>
struct hash<rx::mtl::VertexDesc>
{
size_t operator()(const rx::mtl::VertexDesc &key) const { return key.hash(); }
};
template <>
struct hash<rx::mtl::BlendDesc>
{
size_t operator()(const rx::mtl::BlendDesc &key) const { return key.hash(); }
};
template <>
struct hash<rx::mtl::RenderPipelineColorAttachmentDesc>
{
size_t operator()(const rx::mtl::RenderPipelineColorAttachmentDesc &key) const
{
return key.hash();
}
};
template <>
struct hash<rx::mtl::RenderPipelineOutputDesc>
{
size_t operator()(const rx::mtl::RenderPipelineOutputDesc &key) const { return key.hash(); }
};
template <>
struct hash<rx::mtl::RenderPipelineDesc>
{
size_t operator()(const rx::mtl::RenderPipelineDesc &key) const { return key.hash(); }
};
} // namespace std
namespace rx
{
namespace mtl
{
class StateCache final : angle::NonCopyable
{
public:
StateCache(const angle::FeaturesMtl &features);
~StateCache();
// Null depth stencil state has depth/stecil read & write disabled.
angle::ObjCPtr<id<MTLDepthStencilState>> getNullDepthStencilState(
const mtl::ContextDevice &device);
angle::ObjCPtr<id<MTLDepthStencilState>> getDepthStencilState(const mtl::ContextDevice &device,
const DepthStencilDesc &desc);
angle::ObjCPtr<id<MTLSamplerState>> getSamplerState(const mtl::ContextDevice &device,
const SamplerDesc &desc);
// Null sampler state uses default SamplerDesc
angle::ObjCPtr<id<MTLSamplerState>> getNullSamplerState(ContextMtl *context);
angle::ObjCPtr<id<MTLSamplerState>> getNullSamplerState(const mtl::ContextDevice &device);
void clear();
private:
const angle::FeaturesMtl &mFeatures;
angle::ObjCPtr<id<MTLDepthStencilState>> mNullDepthStencilState = nil;
angle::HashMap<DepthStencilDesc, angle::ObjCPtr<id<MTLDepthStencilState>>> mDepthStencilStates;
angle::HashMap<SamplerDesc, angle::ObjCPtr<id<MTLSamplerState>>> mSamplerStates;
};
} // namespace mtl
} // namespace rx
static inline bool operator==(const MTLClearColor &lhs, const MTLClearColor &rhs)
{
return lhs.red == rhs.red && lhs.green == rhs.green && lhs.blue == rhs.blue &&
lhs.alpha == rhs.alpha;
}
#endif /* LIBANGLE_RENDERER_METAL_MTL_STATE_CACHE_H_ */