PipelineConfigVk.h#

CreateInfo object helpers / proxies for the Graphics and Compute pipelines.

Includes#

  • CommonHelpers.h (CommonHelpers.h)

  • PVRVk/ForwardDecObjectsVk.h

  • PVRVk/TypesVk.h

Included By#

Namespaces#

Classes#

Source Code#

#pragma once
#include "PVRVk/TypesVk.h"
#include "PVRVk/ForwardDecObjectsVk.h"
#include "CommonHelpers.h"
namespace pvrvk {

struct VertexAttributeInfoCmp_BindingLess_IndexLess
{
    bool operator()(const VertexInputAttributeDescription& lhs, const VertexInputAttributeDescription& rhs) const
    {
        return lhs.getBinding() < rhs.getBinding() || (lhs.getBinding() == rhs.getBinding() && lhs.getLocation() < rhs.getLocation());
    }
};

struct VertexAttributeInfoPred_BindingEquals
{
    uint16_t binding;
    VertexAttributeInfoPred_BindingEquals(uint16_t binding) : binding(binding) {}
    bool operator()(const VertexInputAttributeDescription& nfo) const { return nfo.getBinding() == binding; }
};

struct VertexBindingInfoCmp_BindingLess
{
    bool operator()(const VertexInputBindingDescription& lhs, const VertexInputBindingDescription& rhs) const { return lhs.getBinding() < rhs.getBinding(); }
};

struct VertexBindingInfoPred_BindingLess
{
    bool operator()(uint16_t lhs, const VertexInputBindingDescription& rhs) const { return lhs < rhs.getBinding(); }
};

struct VertexBindingInfoPred_BindingEqual
{
    uint16_t binding;
    VertexBindingInfoPred_BindingEqual(uint16_t binding) : binding(binding) {}
    bool operator()(const VertexInputBindingDescription& nfo) const { return nfo.getBinding() == binding; }
};

struct PipelineDepthStencilStateCreateInfo
{
private:
    // stencil
    bool _depthTest;
    bool _depthWrite;
    bool _stencilTestEnable;
    bool _depthBoundTest;
    bool _enableDepthStencilState;
    float _minDepth;
    float _maxDepth;

    StencilOpState _stencilFront;
    StencilOpState _stencilBack;

    pvrvk::CompareOp _depthCmpOp;

public:
    explicit PipelineDepthStencilStateCreateInfo(bool depthWrite = true, bool depthTest = false, pvrvk::CompareOp depthCompareFunc = pvrvk::CompareOp::e_LESS,
        bool stencilTest = false, bool depthBoundTest = false, const StencilOpState& stencilFront = StencilOpState(), const StencilOpState& stencilBack = StencilOpState(),
        float minDepth = 0.f, float maxDepth = 1.f)
        : _depthTest(depthTest), _depthWrite(depthWrite), _stencilTestEnable(stencilTest), _depthBoundTest(depthBoundTest), _enableDepthStencilState(true), _minDepth(minDepth),
          _maxDepth(maxDepth), _stencilFront(stencilFront), _stencilBack(stencilBack), _depthCmpOp(depthCompareFunc)
    {}

    bool isDepthTestEnable() const { return _depthTest; }

    bool isDepthWriteEnable() const { return _depthWrite; }

    bool isDepthBoundTestEnable() const { return _depthBoundTest; }

    bool isStencilTestEnable() const { return _stencilTestEnable; }

    float getMinDepth() const { return _minDepth; }

    float getMaxDepth() const { return _maxDepth; }

    pvrvk::CompareOp getDepthComapreOp() const { return _depthCmpOp; }

    bool isAllStatesEnabled() const { return _enableDepthStencilState; }

    PipelineDepthStencilStateCreateInfo& enableAllStates(bool flag)
    {
        _enableDepthStencilState = flag;
        return *this;
    }

    PipelineDepthStencilStateCreateInfo& enableDepthWrite(bool depthWrite)
    {
        _depthWrite = depthWrite;
        return *this;
    }

    PipelineDepthStencilStateCreateInfo& enableDepthTest(bool depthTest)
    {
        _depthTest = depthTest;
        return *this;
    }

    PipelineDepthStencilStateCreateInfo& setDepthCompareFunc(pvrvk::CompareOp compareFunc)
    {
        _depthCmpOp = compareFunc;
        return *this;
    }

    PipelineDepthStencilStateCreateInfo& enableStencilTest(bool stencilTest)
    {
        _stencilTestEnable = stencilTest;
        return *this;
    }

    PipelineDepthStencilStateCreateInfo& setStencilFront(const StencilOpState& stencil)
    {
        _stencilFront = stencil;
        return *this;
    }

    PipelineDepthStencilStateCreateInfo& setStencilBack(const StencilOpState& stencil)
    {
        _stencilBack = stencil;
        return *this;
    }

    PipelineDepthStencilStateCreateInfo& setStencilFrontAndBack(StencilOpState& stencil)
    {
        _stencilFront = stencil, _stencilBack = stencil;
        return *this;
    }

    const StencilOpState& getStencilFront() const { return _stencilFront; }

    const StencilOpState& getStencilBack() const { return _stencilBack; }

    PipelineDepthStencilStateCreateInfo& setDepthBoundEnabled(bool enabled)
    {
        _depthBoundTest = enabled;
        return *this;
    }

    PipelineDepthStencilStateCreateInfo& setMinDepthBound(float minDepth)
    {
        _minDepth = minDepth;
        return *this;
    }

    PipelineDepthStencilStateCreateInfo& setMaxDepthBound(float maxDepth)
    {
        _maxDepth = maxDepth;
        return *this;
    }
};

struct PipelineVertexInputStateCreateInfo
{
private:
    friend class ::pvrvk::impl::GraphicsPipeline_;

    std::vector<VertexInputBindingDescription> _inputBindings;
    std::vector<VertexInputAttributeDescription> _attributes;

public:
    const std::vector<VertexInputBindingDescription>& getInputBindings() const { return _inputBindings; }

    const std::vector<VertexInputAttributeDescription>& getAttributes() const { return _attributes; }

    PipelineVertexInputStateCreateInfo& clear()
    {
        _inputBindings.clear();
        _attributes.clear();
        return *this;
    }

    PipelineVertexInputStateCreateInfo& addInputBinding(const VertexInputBindingDescription& bindingDesc)
    {
        internal::insertSorted_overwrite(_inputBindings, bindingDesc, VertexBindingInfoCmp_BindingLess());
        return *this;
    }

    const VertexInputBindingDescription* getInputBinding(uint32_t bufferBinding) const
    {
        for (const VertexInputBindingDescription& it : _inputBindings)
        {
            if (it.getBinding() == bufferBinding) { return &it; }
        }
        return nullptr;
    }

    const VertexInputBindingDescription& getInputBindingByIndex(uint32_t index) const { return _inputBindings[index]; }

    PipelineVertexInputStateCreateInfo& addInputAttribute(const VertexInputAttributeDescription& attributeInfo)
    {
        internal::insertSorted_overwrite(_attributes, attributeInfo, VertexAttributeInfoCmp_BindingLess_IndexLess());
        return *this;
    }

    PipelineVertexInputStateCreateInfo& addInputAttributes(const VertexInputAttributeDescription* attributeInfo, uint32_t numAttributes)
    {
        for (uint32_t i = 0; i < numAttributes; ++i) { internal::insertSorted_overwrite(_attributes, attributeInfo[i], VertexAttributeInfoCmp_BindingLess_IndexLess()); }
        return *this;
    }
};

struct PipelineInputAssemblerStateCreateInfo
{
    friend class ::pvrvk::impl::GraphicsPipeline_;

private:
    mutable pvrvk::PrimitiveTopology _topology;
    bool _disableVertexReuse;
    bool _primitiveRestartEnable;
    uint32_t _primitiveRestartIndex;

public:
    explicit PipelineInputAssemblerStateCreateInfo(pvrvk::PrimitiveTopology topology = pvrvk::PrimitiveTopology::e_TRIANGLE_LIST, bool disableVertexReuse = true,
        bool primitiveRestartEnable = false, uint32_t primitiveRestartIndex = 0xFFFFFFFF)
        : _topology(topology), _disableVertexReuse(disableVertexReuse), _primitiveRestartEnable(primitiveRestartEnable), _primitiveRestartIndex(primitiveRestartIndex)
    {}

    PipelineInputAssemblerStateCreateInfo& setPrimitiveRestartEnable(bool enable)
    {
        _primitiveRestartEnable = enable;
        return *this;
    }

    PipelineInputAssemblerStateCreateInfo& setVertexReuseDisable(bool disable)
    {
        _disableVertexReuse = disable;
        return *this;
    }

    PipelineInputAssemblerStateCreateInfo& setPrimitiveTopology(pvrvk::PrimitiveTopology topology)
    {
        this->_topology = topology;
        return *this;
    }

    bool isVertexReuseDisabled() const { return _disableVertexReuse; }

    bool isPrimitiveRestartEnabled() const { return _primitiveRestartEnable; }

    uint32_t getPrimitiveRestartIndex() const { return _primitiveRestartIndex; }

    pvrvk::PrimitiveTopology getPrimitiveTopology() const { return _topology; }
};

struct PipelineColorBlendStateCreateInfo
{
private:
    friend class ::pvrvk::impl::GraphicsPipeline_;
    std::vector<PipelineColorBlendAttachmentState> _attachmentStates;
    bool _alphaToCoverageEnable;
    bool _logicOpEnable;
    pvrvk::LogicOp _logicOp;
    Color _colorBlendConstants;

public:
    const PipelineColorBlendAttachmentState* getAttachmentStates() const { return _attachmentStates.data(); }

    PipelineColorBlendStateCreateInfo(bool alphaToCoverageEnable, bool logicOpEnable, pvrvk::LogicOp logicOp, Color colorBlendConstants,
        PipelineColorBlendAttachmentState* attachmentStates, uint32_t numAttachmentStates)
        : _alphaToCoverageEnable(alphaToCoverageEnable), _logicOpEnable(logicOpEnable), _logicOp(logicOp), _colorBlendConstants(colorBlendConstants)
    {
        for (uint32_t i = 0; i < numAttachmentStates; i++) { _attachmentStates.emplace_back(attachmentStates[i]); }
    }

    explicit PipelineColorBlendStateCreateInfo(
        bool alphaToCoverageEnable = false, bool logicOpEnable = false, pvrvk::LogicOp logicOp = pvrvk::LogicOp::e_SET, Color colorBlendConstants = Color(0., 0., 0., 0.))
        : _alphaToCoverageEnable(alphaToCoverageEnable), _logicOpEnable(logicOpEnable), _logicOp(logicOp), _colorBlendConstants(colorBlendConstants)
    {}

    PipelineColorBlendStateCreateInfo& setColorBlendConst(const Color& blendConst)
    {
        _colorBlendConstants = blendConst;
        return *this;
    }

    const Color& getColorBlendConst() const { return _colorBlendConstants; }

    const PipelineColorBlendAttachmentState& getAttachmentState(uint32_t index) const { return _attachmentStates[index]; }

    uint32_t getNumAttachmentStates() const { return static_cast<uint32_t>(_attachmentStates.size()); }

    PipelineColorBlendStateCreateInfo& setAlphaToCoverageEnable(bool alphaToCoverageEnable)
    {
        _alphaToCoverageEnable = alphaToCoverageEnable;
        return *this;
    }

    PipelineColorBlendStateCreateInfo& setLogicOpEnable(bool logicOpEnable)
    {
        _logicOpEnable = logicOpEnable;
        return *this;
    }

    PipelineColorBlendStateCreateInfo& setLogicOp(pvrvk::LogicOp logicOp)
    {
        _logicOp = logicOp;
        return *this;
    }

    PipelineColorBlendStateCreateInfo& clearAttachments()
    {
        _attachmentStates.clear();
        return *this;
    }

    PipelineColorBlendStateCreateInfo& setAttachmentState(uint32_t index, const PipelineColorBlendAttachmentState& state)
    {
        setElementAtIndex<PipelineColorBlendAttachmentState>(index, state, _attachmentStates);
        return *this;
    }

    PipelineColorBlendStateCreateInfo& setAttachmentStates(uint32_t count, PipelineColorBlendAttachmentState const* states)
    {
        for (uint32_t i = 0; i < count; i++) { _attachmentStates.emplace_back(states[i]); }
        return *this;
    }

    bool isAlphaToCoverageEnabled() const { return _alphaToCoverageEnable; }

    bool isLogicOpEnabled() const { return _logicOpEnable; }

    pvrvk::LogicOp getLogicOp() const { return _logicOp; }
};

struct PipelineViewportStateCreateInfo
{
    friend class ::pvrvk::impl::GraphicsPipeline_;

private:
    std::pair<Rect2D, Viewport> _scissorViewports[FrameworkCaps::MaxScissorViewports];
    uint32_t _numScissorViewports;

public:
    PipelineViewportStateCreateInfo() : _numScissorViewports(0) {}

    PipelineViewportStateCreateInfo& setViewportAndScissor(uint32_t index, const Viewport& viewport, const Rect2D& scissor)
    {
        assert(index < FrameworkCaps::MaxScissorViewports && "Scissor Viewport out of range.");
        _scissorViewports[index].first = scissor;
        _scissorViewports[index].second = viewport;
        _numScissorViewports++;
        return *this;
    }

    PipelineViewportStateCreateInfo& clear()
    {
        for (uint32_t i = 0; i < FrameworkCaps::MaxScissorViewports; i++)
        {
            _scissorViewports[i].first = Rect2D();
            _scissorViewports[i].second = Viewport();
        }
        _numScissorViewports = 0;
        return *this;
    }

    const Rect2D& getScissor(uint32_t index) const { return _scissorViewports[index].first; }

    const Viewport& getViewport(uint32_t index) const { return _scissorViewports[index].second; }

    uint32_t getNumViewportScissors() const { return _numScissorViewports; }
};

struct PipelineRasterizationStateCreateInfo
{
private:
    pvrvk::CullModeFlags _cullFace;
    pvrvk::FrontFace _frontFaceWinding;
    bool _enableDepthClip;
    bool _enableRasterizerDiscard;
    bool _enableProgramPointSize;
    bool _enableDepthBias;
    float _depthBiasClamp;
    float _depthBiasConstantFactor;
    float _depthBiasSlopeFactor;
    pvrvk::PolygonMode _fillMode;
    float _lineWidth;
    uint32_t _rasterizationStream;
    friend class ::pvrvk::impl::GraphicsPipeline_;

public:
    explicit PipelineRasterizationStateCreateInfo(pvrvk::CullModeFlags cullFace = pvrvk::CullModeFlags::e_NONE,
        pvrvk::FrontFace frontFaceWinding = pvrvk::FrontFace::e_COUNTER_CLOCKWISE, bool enableDepthClip = true, bool enableRasterizerDiscard = false,
        bool enableProgramPointSize = false, pvrvk::PolygonMode fillMode = pvrvk::PolygonMode::e_FILL, float lineWidth = 1.0f, bool enableDepthBias = false,
        float depthBiasClamp = 0.f, float depthBiasConstantFactor = 0.f, float depthBiasSlopeFactor = 0.f, uint32_t rasterizationStream = 0)
        : _cullFace(cullFace), _frontFaceWinding(frontFaceWinding), _enableDepthClip(enableDepthClip), _enableRasterizerDiscard(enableRasterizerDiscard),
          _enableProgramPointSize(enableProgramPointSize), _enableDepthBias(enableDepthBias), _depthBiasClamp(depthBiasClamp), _depthBiasConstantFactor(depthBiasConstantFactor),
          _depthBiasSlopeFactor(depthBiasSlopeFactor), _fillMode(fillMode), _lineWidth(lineWidth), _rasterizationStream(rasterizationStream)
    {}

    PipelineRasterizationStateCreateInfo& setCullMode(pvrvk::CullModeFlags face)
    {
        _cullFace = face;
        return *this;
    }

    PipelineRasterizationStateCreateInfo& setLineWidth(float lineWidth)
    {
        _lineWidth = lineWidth;
        return *this;
    }

    PipelineRasterizationStateCreateInfo& setRasterizationStream(uint32_t rasterizationStream)
    {
        _rasterizationStream = rasterizationStream;
        return *this;
    }

    PipelineRasterizationStateCreateInfo& setDepthClip(bool enableDepthClip)
    {
        _enableDepthClip = enableDepthClip;
        return *this;
    }

    PipelineRasterizationStateCreateInfo& setDepthBias(bool enableDepthBias, bool depthBiasClamp = 0.f, bool depthBiasConstantFactor = 0.f, bool depthBiasSlopeFactor = 0.f)
    {
        _enableDepthBias = enableDepthBias;
        _depthBiasClamp = depthBiasClamp;
        _depthBiasConstantFactor = depthBiasConstantFactor;
        _depthBiasSlopeFactor = depthBiasSlopeFactor;
        return *this;
    }

    PipelineRasterizationStateCreateInfo& setFrontFaceWinding(pvrvk::FrontFace frontFaceWinding)
    {
        _frontFaceWinding = frontFaceWinding;
        return *this;
    }

    PipelineRasterizationStateCreateInfo& setRasterizerDiscard(bool enable)
    {
        _enableRasterizerDiscard = enable;
        return *this;
    }

    PipelineRasterizationStateCreateInfo& setProgramPointSize(bool enable)
    {
        _enableProgramPointSize = enable;
        return *this;
    }

    PipelineRasterizationStateCreateInfo& setPolygonMode(pvrvk::PolygonMode mode)
    {
        _fillMode = mode;
        return *this;
    }

    pvrvk::CullModeFlags getCullFace() const { return _cullFace; }

    pvrvk::FrontFace getFrontFaceWinding() const { return _frontFaceWinding; }

    bool isDepthClipEnabled() const { return _enableDepthClip; }

    bool isRasterizerDiscardEnabled() const { return _enableRasterizerDiscard; }

    bool isProgramPointSizeEnabled() const { return _enableProgramPointSize; }

    bool isDepthBiasEnabled() const { return _enableDepthBias; }

    float getDepthBiasClamp() const { return _depthBiasClamp; }

    float getDepthBiasConstantFactor() const { return _depthBiasConstantFactor; }

    float getDepthBiasSlopeFactor() const { return _depthBiasSlopeFactor; }

    pvrvk::PolygonMode getPolygonMode() const { return _fillMode; }

    float getLineWidth() const { return _lineWidth; }

    uint32_t getRasterizationStream() const { return _rasterizationStream; }
};

struct PipelineMultisampleStateCreateInfo
{
private:
    friend class ::pvrvk::impl::GraphicsPipeline_;
    bool _sampleShadingEnable;
    bool _alphaToCoverageEnable;
    bool _alphaToOneEnable;
    pvrvk::SampleCountFlags _numRasterizationSamples;
    float _minSampleShading;
    pvrvk::SampleMask _sampleMask;

public:
    explicit PipelineMultisampleStateCreateInfo(bool sampleShadingEnable = false, bool alphaToCoverageEnable = false, bool alphaToOneEnable = false,
        pvrvk::SampleCountFlags rasterizationSamples = pvrvk::SampleCountFlags::e_1_BIT, float minSampleShading = 0.f, pvrvk::SampleMask sampleMask = 0xffffffff)
        : _sampleShadingEnable(sampleShadingEnable), _alphaToCoverageEnable(alphaToCoverageEnable), _alphaToOneEnable(alphaToOneEnable),
          _numRasterizationSamples(rasterizationSamples), _minSampleShading(minSampleShading), _sampleMask(sampleMask)
    {}

    PipelineMultisampleStateCreateInfo& setAlphaToCoverage(bool enable)
    {
        _alphaToCoverageEnable = enable;
        return *this;
    }

    PipelineMultisampleStateCreateInfo& setSampleShading(bool enable)
    {
        _sampleShadingEnable = enable;
        return *this;
    }

    PipelineMultisampleStateCreateInfo& setAlphaToOne(bool enable)
    {
        _alphaToOneEnable = enable;
        return *this;
    }

    PipelineMultisampleStateCreateInfo& setNumRasterizationSamples(pvrvk::SampleCountFlags numSamples)
    {
        _numRasterizationSamples = numSamples;
        return *this;
    }

    PipelineMultisampleStateCreateInfo& setMinSampleShading(float minSampleShading)
    {
        _minSampleShading = minSampleShading;
        return *this;
    }

    PipelineMultisampleStateCreateInfo& setSampleMask(pvrvk::SampleMask mask)
    {
        _sampleMask = mask;
        return *this;
    }

    const pvrvk::SampleMask& getSampleMask() const { return _sampleMask; }

    pvrvk::SampleCountFlags getRasterizationSamples() const { return _numRasterizationSamples; }

    float getMinSampleShading() const { return _minSampleShading; }

    bool isSampleShadingEnabled() const { return _sampleShadingEnable; }

    bool isAlphaToCoverageEnabled() const { return _alphaToCoverageEnable; }

    bool isAlphaToOneEnabled() const { return _alphaToOneEnable; }
};

struct DynamicStatesCreateInfo
{
private:
    std::vector<DynamicState> _dynamicStates;

public:
    DynamicStatesCreateInfo() {}

    bool isDynamicStateEnabled(DynamicState state) const
    {
        for (DynamicState setState : _dynamicStates)
        {
            if (setState == state) { return true; }
        }
        return false;
    }

    const std::vector<DynamicState>& getDynamicStates() const { return _dynamicStates; }

    DynamicStatesCreateInfo& setDynamicState(DynamicState state, bool enable)
    {
        if (enable)
        {
            if (std::find(_dynamicStates.begin(), _dynamicStates.end(), state) == _dynamicStates.end()) { _dynamicStates.push_back(state); }
        }
        else
        {
            _dynamicStates.erase(std::remove(_dynamicStates.begin(), _dynamicStates.end(), state), _dynamicStates.end());
        }
        return *this;
    }
};

struct ShaderConstantInfo
{
    uint32_t constantId;
    unsigned char data[64];
    uint32_t sizeInBytes;

    ShaderConstantInfo() : constantId(0), sizeInBytes(0) { memset(data, 0, sizeof(data)); }

    bool isValid() const { return (sizeInBytes <= 64 && sizeInBytes > 0); }

    ShaderConstantInfo(uint32_t constantId, const void* data, uint32_t sizeOfData) : constantId(constantId), sizeInBytes(sizeOfData)
    {
        memset(this->data, 0, sizeof(this->data));
        memcpy(this->data, data, sizeInBytes);
    }
};

struct RayTracingShaderGroupCreateInfo
{
private:
    RayTracingShaderGroupTypeKHR _type;
    uint32_t _generalShader;
    uint32_t _closestHitShader;
    uint32_t _anyHitShader;
    uint32_t _intersectionShader;
    const void* _pShaderGroupCaptureReplayHandle;

public:
    RayTracingShaderGroupCreateInfo()
        : _type(RayTracingShaderGroupTypeKHR::e_MAX_ENUM), _generalShader(VK_SHADER_UNUSED_KHR), _closestHitShader(VK_SHADER_UNUSED_KHR), _anyHitShader(VK_SHADER_UNUSED_KHR),
          _intersectionShader(VK_SHADER_UNUSED_KHR), _pShaderGroupCaptureReplayHandle(nullptr)
    {}

    RayTracingShaderGroupCreateInfo(RayTracingShaderGroupTypeKHR type)
        : _type(type), _generalShader(VK_SHADER_UNUSED_KHR), _closestHitShader(VK_SHADER_UNUSED_KHR), _anyHitShader(VK_SHADER_UNUSED_KHR),
          _intersectionShader(VK_SHADER_UNUSED_KHR), _pShaderGroupCaptureReplayHandle(nullptr)
    {}

    pvrvk::RayTracingShaderGroupTypeKHR getType() const { return _type; }

    void setType(pvrvk::RayTracingShaderGroupTypeKHR type) { _type = type; }

    uint32_t getGeneralShader() const { return _generalShader; }

    void setGeneralShader(uint32_t generalShader) { _generalShader = generalShader; }

    uint32_t getClosestHitShader() const { return _closestHitShader; }

    void setClosestHitShader(uint32_t closestHitShader) { _closestHitShader = closestHitShader; }

    uint32_t getAnyHitShader() const { return _anyHitShader; }

    void setAnyHitShader(uint32_t anyHitShader) { _anyHitShader = anyHitShader; }

    uint32_t getIntersectionShader() const { return _intersectionShader; }

    void setIntersectionShader(uint32_t intersectionShader) { _intersectionShader = intersectionShader; }

    const void* getShaderGroupCaptureReplayHandle() const { return _pShaderGroupCaptureReplayHandle; }

    void setShaderGroupCaptureReplayHandle(void* pShaderGroupCaptureReplayHandle) { _pShaderGroupCaptureReplayHandle = pShaderGroupCaptureReplayHandle; }
};

struct PipelineShaderStageCreateInfo
{
    friend class ::pvrvk::impl::GraphicsPipeline_;

private:
    pvrvk::ShaderModule _shaderModule;
    std::vector<ShaderConstantInfo> _shaderConsts;
    std::string _entryPoint;
    pvrvk::ShaderStageFlags _shaderStage;

public:
    PipelineShaderStageCreateInfo() : _entryPoint("main"), _shaderStage(pvrvk::ShaderStageFlags::e_NONE) {}

    PipelineShaderStageCreateInfo(const ShaderModule& shader) : _shaderModule(shader), _entryPoint("main"), _shaderStage(pvrvk::ShaderStageFlags::e_NONE) {}

    const ShaderModule& getShader() const { return _shaderModule; }

    bool isActive() const { return _shaderModule != nullptr; }

    void setShader(const ShaderModule& shader) { _shaderModule = shader; }

    void setEntryPoint(const std::string& entryPoint) { _entryPoint = entryPoint; }

    const std::string& getEntryPoint() const { return _entryPoint; }

    PipelineShaderStageCreateInfo& operator=(const ShaderModule& shader)
    {
        setShader(shader);
        return *this;
    }

    PipelineShaderStageCreateInfo& setShaderConstant(uint32_t index, const ShaderConstantInfo& shaderConst)
    {
        if (_shaderConsts.size() < index + 1) { _shaderConsts.resize(index + 1); }
        _shaderConsts[index] = shaderConst;
        return *this;
    }

    PipelineShaderStageCreateInfo& setShaderConstants(const ShaderConstantInfo* shaderConsts, uint32_t numConstants)
    {
        _shaderConsts.resize(numConstants);
        for (uint32_t i = 0; i < numConstants; i++) { _shaderConsts[i] = shaderConsts[i]; }
        return *this;
    }

    const ShaderConstantInfo& getShaderConstant(uint32_t index) const { return _shaderConsts[index]; }

    const ShaderConstantInfo* getAllShaderConstants() const { return _shaderConsts.data(); }

    uint32_t getNumShaderConsts() const { return (uint32_t)_shaderConsts.size(); }

    pvrvk::ShaderStageFlags getShaderStage() const { return _shaderStage; }

    void setShaderStage(pvrvk::ShaderStageFlags shaderStage) { _shaderStage = shaderStage; }
};

struct TesselationStageCreateInfo
{
    friend class ::pvrvk::impl::GraphicsPipeline_;

private:
    ShaderModule _controlShader, _evalShader;
    uint32_t _patchControlPoints;
    std::vector<ShaderConstantInfo> _shaderConstsTessCtrl;

    std::vector<ShaderConstantInfo> _shaderConstTessEval;

    std::string _controlShaderEntryPoint;
    std::string _evalShaderEntryPoint;

public:
    TesselationStageCreateInfo() : _patchControlPoints(3), _controlShaderEntryPoint("main"), _evalShaderEntryPoint("main") {}

    const ShaderModule& getControlShader() const { return _controlShader; }

    const ShaderModule& getEvaluationShader() const { return _evalShader; }

    bool isControlShaderActive() const { return _controlShader != nullptr; }

    bool isEvaluationShaderActive() const { return _evalShader != nullptr; }

    TesselationStageCreateInfo& setControlShader(const ShaderModule& shader)
    {
        _controlShader = shader;
        return *this;
    }

    TesselationStageCreateInfo& setControlShaderEntryPoint(const char* entryPoint)
    {
        _controlShaderEntryPoint.assign(entryPoint);
        return *this;
    }

    TesselationStageCreateInfo& setEvaluationShaderEntryPoint(const char* entryPoint)
    {
        _evalShaderEntryPoint.assign(entryPoint);
        return *this;
    }

    TesselationStageCreateInfo& setEvaluationShader(const ShaderModule& shader)
    {
        _evalShader = shader;
        return *this;
    }

    TesselationStageCreateInfo& setNumPatchControlPoints(uint32_t controlPoints)
    {
        _patchControlPoints = controlPoints;
        return *this;
    }

    uint32_t getNumPatchControlPoints() const { return _patchControlPoints; }

    TesselationStageCreateInfo& setControlShaderConstant(uint32_t index, const ShaderConstantInfo& shaderConst)
    {
        if (_shaderConstsTessCtrl.size() < index + 1) { _shaderConstsTessCtrl.resize(index + 1); }

        _shaderConstsTessCtrl[index] = shaderConst;
        return *this;
    }

    TesselationStageCreateInfo& setControlShaderConstants(const ShaderConstantInfo* shaderConsts, uint32_t numConstants)
    {
        if (_shaderConstsTessCtrl.size() != numConstants) { _shaderConstsTessCtrl.resize(numConstants); }

        for (uint32_t i = 0; i < numConstants; i++) { _shaderConstsTessCtrl[i] = shaderConsts[numConstants]; }
        return *this;
    }

    const ShaderConstantInfo& getControlShaderConstant(uint32_t index) const { return _shaderConstsTessCtrl[index]; }

    const ShaderConstantInfo* getAllControlShaderConstants() const { return _shaderConstsTessCtrl.data(); }

    uint32_t getNumControlShaderConstants() const { return (uint32_t)_shaderConstsTessCtrl.size(); }

    void setEvaluationShaderConstant(uint32_t index, const ShaderConstantInfo& shaderConst)
    {
        if (_shaderConstTessEval.size() < index + 1) { _shaderConstTessEval.resize(index + 1); }
        _shaderConstTessEval[index] = shaderConst;
    }

    TesselationStageCreateInfo& setEvaluationShaderConstants(const ShaderConstantInfo* shaderConsts, uint32_t numConstants)
    {
        if (_shaderConstTessEval.size() != numConstants) { _shaderConstTessEval.resize(numConstants); }

        for (uint32_t i = 0; i < numConstants; i++) { _shaderConstTessEval[i] = shaderConsts[numConstants]; }
        return *this;
    }

    const ShaderConstantInfo& getEvaluationlShaderConstant(uint32_t index) const { return _shaderConstTessEval[index]; }

    const ShaderConstantInfo* getAllEvaluationShaderConstants() const { return _shaderConstTessEval.data(); }

    uint32_t getNumEvaluatinonShaderConstants() const { return (uint32_t)_shaderConstTessEval.size(); }

    const char* getEvaluationShaderEntryPoint() const { return _evalShaderEntryPoint.c_str(); }

    const char* getControlShaderEntryPoint() const { return _controlShaderEntryPoint.c_str(); }
};

struct FragmentShadingRateStateCreateInfo
{
private:
    bool _fragmentShadingRateEnabled;
    Extent2D _fragmentSize;
    FragmentShadingRateCombinerOpKHR _combinerOpPipelinePrimitive;
    FragmentShadingRateCombinerOpKHR _combinerOpResultAttachment;

public:
    explicit FragmentShadingRateStateCreateInfo(bool fragmentShadingRateEnabled = false, Extent2D fragmentSize = Extent2D(1, 1),
        FragmentShadingRateCombinerOpKHR combinerOpPipelinePrimitive = FragmentShadingRateCombinerOpKHR::e_KEEP_KHR,
        FragmentShadingRateCombinerOpKHR combinerOpResultAttachment = FragmentShadingRateCombinerOpKHR::e_KEEP_KHR)
        : _fragmentShadingRateEnabled(fragmentShadingRateEnabled), _fragmentSize(fragmentSize), _combinerOpPipelinePrimitive(combinerOpPipelinePrimitive),
          _combinerOpResultAttachment(combinerOpResultAttachment)
    {}

    bool isEnabled() const { return _fragmentShadingRateEnabled; }

    const Extent2D& getFragmentSize() const { return _fragmentSize; }

    FragmentShadingRateCombinerOpKHR getCombinerOpPipelinePrimitive() const { return _combinerOpPipelinePrimitive; }

    FragmentShadingRateCombinerOpKHR getCombinerOpResultAttachment() const { return _combinerOpResultAttachment; }

    FragmentShadingRateStateCreateInfo& enable()
    {
        _fragmentShadingRateEnabled = true;
        return *this;
    }

    FragmentShadingRateStateCreateInfo& disable()
    {
        _fragmentShadingRateEnabled = false;
        return *this;
    }

    FragmentShadingRateStateCreateInfo& setFragmentSize(Extent2D fragmentSize)
    {
        _fragmentSize = fragmentSize;
        return *this;
    }

    FragmentShadingRateStateCreateInfo& setCombinerOpPipelinePrimitive(FragmentShadingRateCombinerOpKHR combinerOpPipelinePrimitive)
    {
        _combinerOpPipelinePrimitive = combinerOpPipelinePrimitive;
        return *this;
    }

    FragmentShadingRateStateCreateInfo& setCombinerOpResultAttachment(FragmentShadingRateCombinerOpKHR combinerOpResultAttachment)
    {
        _combinerOpResultAttachment = combinerOpResultAttachment;
        return *this;
    }
};
} // namespace pvrvk