Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/nbl/asset/IAsset.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ class IAsset : virtual public core::IReferenceCounted
ET_PIPELINE_CACHE = 1ull<<21, //!< asset::ICPUPipelineCache
ET_SCENE = 1ull<<22, //!< reserved, to implement later
ET_RAYTRACING_PIPELINE = 1ull << 23, //!< asset::ICPURayTracingPipeline
ET_MESH_PIPELINE = 1ull << 24,
ET_IMPLEMENTATION_SPECIFIC_METADATA = 1ull<<31u, //!< lights, etc.
//! Reserved special value used for things like terminating lists of this enum

Expand Down
14 changes: 7 additions & 7 deletions include/nbl/asset/ICPUGraphicsPipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,21 @@ class ICPUGraphicsPipeline final : public ICPUPipeline<IGraphicsPipeline<ICPUPip
return base_t::getSpecInfos(stage);
}

SShaderSpecInfo* getSpecInfo(const hlsl::ShaderStage stage)
std::span<SShaderSpecInfo> getSpecInfo(const hlsl::ShaderStage stage)
{
if (!isMutable()) return nullptr;
if (!isMutable()) return {};
const auto stageIndex = stageToIndex(stage);
if (stageIndex != -1)
return &m_specInfos[stageIndex];
return nullptr;
return {&m_specInfos[stageIndex], 1};
return {};
}

const SShaderSpecInfo* getSpecInfo(const hlsl::ShaderStage stage) const
std::span<const SShaderSpecInfo> getSpecInfo(const hlsl::ShaderStage stage) const
{
const auto stageIndex = stageToIndex(stage);
if (stageIndex != -1)
return &m_specInfos[stageIndex];
return nullptr;
return {&m_specInfos[stageIndex], 1};
return {};
}

inline bool valid() const override
Expand Down
149 changes: 149 additions & 0 deletions include/nbl/asset/ICPUMeshPipeline.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
#ifndef _NBL_I_CPU_MESH_PIPELINE_H_INCLUDED_
#define _NBL_I_CPU_MESH_PIPELINE_H_INCLUDED_


#include "nbl/asset/IMeshPipeline.h"
#include "nbl/asset/ICPURenderpass.h"
#include "nbl/asset/ICPUPipeline.h"


namespace nbl::asset
{

class ICPUMeshPipeline final : public ICPUPipeline<IMeshPipeline<ICPUPipelineLayout,ICPURenderpass>>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make a ICPURasterizationPipeline : IRasterizationPipeline<ICPUPipelineLayout,ICPUrenderpass>

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried IRasterization earlier.
I took another look. I don't use polymorphism too much, so maybe there's an easy answer staring me in the face. Most of the issue is that IGPURasterization is an incomplete type unless it's specialized with IMesh or IGraphics, at which point it's not an effective abstraction.
image
Here is perhaps the simplest solution.
image

Another potential solution I have is removing IGraphics and IMesh and replacing with IRasterization. However, that introduces a new problem, the construction parameters would be above the IGPU/ICPU abstraction level, unless some virtual functions are used.
image

If none of these solutions are acceptable, my recommendation would be a larger rewrite of the Pipeline system as whole. I have ideas here, but I'll hold until further direction is given.

{
using pipeline_base_t = IMeshPipeline<ICPUPipelineLayout, ICPURenderpass>;
using base_t = ICPUPipeline<pipeline_base_t>;

public:

static core::smart_refctd_ptr<ICPUMeshPipeline> create(ICPUPipelineLayout* layout, ICPURenderpass* renderpass = nullptr)
{
auto retval = new ICPUMeshPipeline(layout, renderpass);
return core::smart_refctd_ptr<ICPUMeshPipeline>(retval,core::dont_grab);
}

constexpr static inline auto AssetType = ET_MESH_PIPELINE;
inline E_TYPE getAssetType() const override { return AssetType; }

inline const SCachedCreationParams& getCachedCreationParams() const
{
return pipeline_base_t::getCachedCreationParams();
}

inline SCachedCreationParams& getCachedCreationParams()
{
assert(isMutable());
return m_params;
}
Comment on lines +29 to +38

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the creation params are identical for Gfx and MEsh, should go in ICPURasterizationPipeline

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

99168b9#diff-45681900933e70545ee1a41c9ad2419f9cd40ef479ad7afe82dc97f29095c36aR13.
If Programmable Vertex Pulling is enforced, VertexParams could be removed from GraphicsPipeline. With preprocessor branching, primitive type could potentially be moved out the shader and into the creation params, allowng the creation params to be the same for both rasterization pipelines.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I take that back, I only thought about outputtopology. Preprocessor branching the rest of the shader per primitive type is unreasonable.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use composition ot inheritance to split the SCachedCreationParams.

we will support vertex inputs as long as we support graphics pipelines.


inline std::span<const SShaderSpecInfo> getSpecInfos(const hlsl::ShaderStage stage) const override final
{
switch (stage) {
case hlsl::ShaderStage::ESS_TASK: return { &m_specInfos[0], 1 };
case hlsl::ShaderStage::ESS_MESH: return { &m_specInfos[1], 1 };
case hlsl::ShaderStage::ESS_FRAGMENT: return { &m_specInfos[2], 1 };
}
return {};
}

inline std::span<SShaderSpecInfo> getSpecInfos(const hlsl::ShaderStage stage)
{
return base_t::getSpecInfos(stage);
}

std::span<SShaderSpecInfo> getSpecInfo(const hlsl::ShaderStage stage)
{
if (!isMutable()) return {};
switch (stage) {
case hlsl::ShaderStage::ESS_TASK: return { &m_specInfos[0], 1 };
case hlsl::ShaderStage::ESS_MESH: return { &m_specInfos[1], 1 };
case hlsl::ShaderStage::ESS_FRAGMENT: return { &m_specInfos[2], 1 };
}
return {};
}

std::span<const SShaderSpecInfo> getSpecInfo(const hlsl::ShaderStage stage) const
{
switch (stage) {
case hlsl::ShaderStage::ESS_TASK: return { &m_specInfos[0], 1 };
case hlsl::ShaderStage::ESS_MESH: return { &m_specInfos[1], 1 };
case hlsl::ShaderStage::ESS_FRAGMENT: return { &m_specInfos[2], 1 };
}
return {};
}

inline bool valid() const override
{
if (!m_layout) return false;
if (!m_layout->valid())return false;

// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-dynamicRendering-06576
if (!m_renderpass || m_params.subpassIx >= m_renderpass->getSubpassCount()) return false;

core::bitflag<hlsl::ShaderStage> stagePresence = {};
for (auto shader_i = 0u; shader_i < m_specInfos.size(); shader_i++)
{
const auto& info = m_specInfos[shader_i];
if (info.shader)
stagePresence |= indexToStage(shader_i);
}
return hasRequiredStages(stagePresence);
}

protected:
using base_t::base_t;
virtual ~ICPUMeshPipeline() override = default;

std::array<SShaderSpecInfo, MESH_SHADER_STAGE_COUNT> m_specInfos;

private:
explicit ICPUMeshPipeline(ICPUPipelineLayout* layout, ICPURenderpass* renderpass)
: base_t(layout, {}, renderpass)
{}

static inline int8_t stageToIndex(const hlsl::ShaderStage stage)
{
switch(stage){
case hlsl::ShaderStage::ESS_TASK: return 0;
case hlsl::ShaderStage::ESS_MESH: return 1;
case hlsl::ShaderStage::ESS_FRAGMENT: return 2;
}
return -1;
}

static inline hlsl::ShaderStage indexToStage(const int8_t index)
{
switch (index) {
case 0: return hlsl::ShaderStage::ESS_TASK;
case 1: return hlsl::ShaderStage::ESS_MESH;
case 2: return hlsl::ShaderStage::ESS_FRAGMENT;
}
return hlsl::ShaderStage::ESS_UNKNOWN;
}

inline core::smart_refctd_ptr<base_t> clone_impl(core::smart_refctd_ptr<ICPUPipelineLayout>&& layout, uint32_t depth) const override final
{
auto* newPipeline = new ICPUMeshPipeline(layout.get(), m_renderpass.get());
newPipeline->m_params = m_params;

for (auto specInfo_i = 0u; specInfo_i < m_specInfos.size(); specInfo_i++)
{
newPipeline->m_specInfos[specInfo_i] = m_specInfos[specInfo_i].clone(depth);
}

return core::smart_refctd_ptr<base_t>(newPipeline, core::dont_grab);
}

inline void visitDependents_impl(std::function<bool(const IAsset*)> visit) const override
{
if (!visit(m_layout.get())) return;
if (!visit(m_renderpass.get())) return;
for (const auto& info : m_specInfos)
if (!visit(info.shader.get())) return;
}
};

}

#endif
16 changes: 6 additions & 10 deletions include/nbl/asset/IGraphicsPipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include "nbl/asset/IPipeline.h"
#include "nbl/asset/IRenderpass.h"

#include "nbl/asset/IRasterizationPipeline.h"

#include <span>


Expand Down Expand Up @@ -71,26 +73,21 @@ class IGraphicsPipelineBase : public virtual core::IReferenceCounted
public:
constexpr static inline uint8_t GRAPHICS_SHADER_STAGE_COUNT = 5u;

struct SCachedCreationParams final
struct SCachedCreationParams final : public IRasterizationPipelineBase::SCachedCreationParams
{
SVertexInputParams vertexInput = {};
SPrimitiveAssemblyParams primitiveAssembly = {};
SRasterizationParams rasterization = {};
SBlendParams blend = {};
uint32_t subpassIx = 0u;
};
};

template<typename PipelineLayoutType, typename RenderpassType>
class IGraphicsPipeline : public IPipeline<PipelineLayoutType>, public IGraphicsPipelineBase
class IGraphicsPipeline : public IRasterizationPipeline<PipelineLayoutType, RenderpassType>, public IGraphicsPipelineBase
{
protected:
using renderpass_t = RenderpassType;

public:
inline const SCachedCreationParams& getCachedCreationParams() const {return m_params;}
inline const renderpass_t* getRenderpass() const {return m_renderpass.get();}


static inline bool hasRequiredStages(const core::bitflag<hlsl::ShaderStage>& stagePresence, E_PRIMITIVE_TOPOLOGY primitiveType)
{
Expand All @@ -110,12 +107,11 @@ class IGraphicsPipeline : public IPipeline<PipelineLayoutType>, public IGraphics

protected:
explicit IGraphicsPipeline(PipelineLayoutType* layout, const SCachedCreationParams& cachedParams, renderpass_t* renderpass) :
IPipeline<PipelineLayoutType>(core::smart_refctd_ptr<PipelineLayoutType>(layout)),
m_params(cachedParams), m_renderpass(core::smart_refctd_ptr<renderpass_t>(renderpass))
IRasterizationPipeline<PipelineLayoutType, renderpass_t>(layout, renderpass),
m_params(cachedParams)
{}

SCachedCreationParams m_params = {};
core::smart_refctd_ptr<renderpass_t> m_renderpass = nullptr;
};

}
Expand Down
45 changes: 45 additions & 0 deletions include/nbl/asset/IMeshPipeline.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#ifndef _NBL_ASSET_I_MESH_PIPELINE_H_INCLUDED_
#define _NBL_ASSET_I_MESH_PIPELINE_H_INCLUDED_

#include "nbl/asset/IShader.h"
#include "nbl/asset/RasterizationStates.h"
#include "nbl/asset/IPipeline.h"

#include "nbl/asset/IRasterizationPipeline.h"


namespace nbl::asset {
class IMeshPipelineBase : public virtual core::IReferenceCounted {
public:
constexpr static inline uint8_t MESH_SHADER_STAGE_COUNT = 3u;
struct SCachedCreationParams final : public IRasterizationPipelineBase::SCachedCreationParams
{
uint8_t requireFullSubgroups = false;
};
};

template<typename PipelineLayoutType, typename RenderpassType>
class IMeshPipeline : public IRasterizationPipeline<PipelineLayoutType, RenderpassType>, public IMeshPipelineBase {
protected:
using renderpass_t = RenderpassType;
public:
inline const SCachedCreationParams& getCachedCreationParams() const { return m_params; }

static inline bool hasRequiredStages(const core::bitflag<hlsl::ShaderStage>& stagePresence)
{
return stagePresence.hasFlags(hlsl::ShaderStage::ESS_MESH);
}

protected:
explicit IMeshPipeline(PipelineLayoutType* layout, const IMeshPipelineBase::SCachedCreationParams& cachedParams, renderpass_t* renderpass) :
IRasterizationPipeline<PipelineLayoutType, renderpass_t>(layout, renderpass),
m_params(cachedParams)
{}

SCachedCreationParams m_params = {};
};

}


#endif
46 changes: 46 additions & 0 deletions include/nbl/asset/IRasterizationPipeline.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#ifndef _NBL_ASSET_I_RASTERIZATION_PIPELINE_H_INCLUDED_
#define _NBL_ASSET_I_RASTERIZATION_PIPELINE_H_INCLUDED_

#include "nbl/asset/IShader.h"
#include "nbl/asset/RasterizationStates.h"
#include "nbl/asset/IPipeline.h"
#include "nbl/asset/IRenderpass.h"


//the primary goal is to abstract between mesh and traditional graphics (vertex) pipelines
//so that any pipeline that can be bound to VK_PIPELINE_BIND_POINT_GRAPHICS can be returned polymorphically
//the secondary goal is to not change IGraphicsPipeline as little as possible

namespace nbl::asset {

class IRasterizationPipelineBase
{
//IRasterizationPipelineBase isn't inherited from, only SCachedCreationParams
public:
struct SCachedCreationParams {
SRasterizationParams rasterization = {};
SBlendParams blend = {};
uint32_t subpassIx = 0u;
};
};

template<typename PipelineLayoutType, typename RenderpassType>
class IRasterizationPipeline : public IPipeline<PipelineLayoutType>
{
protected:
using renderpass_t = RenderpassType;

public:
inline const renderpass_t* getRenderpass() const { return m_renderpass.get(); }
protected:
explicit IRasterizationPipeline(PipelineLayoutType* layout, renderpass_t* renderpass) :
IPipeline<PipelineLayoutType>(core::smart_refctd_ptr<PipelineLayoutType>(layout)),
m_renderpass(core::smart_refctd_ptr<renderpass_t>(renderpass))
{}

core::smart_refctd_ptr<renderpass_t> m_renderpass = nullptr;
};
}


#endif
3 changes: 3 additions & 0 deletions include/nbl/builtin/hlsl/indirect_commands.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ struct DispatchIndirectCommand_t
uint32_t num_groups_z;
};

// in vulkan this struct is distinct from DispatchIndirect, but has the same data - https://docs.vulkan.org/refpages/latest/refpages/source/VkDrawMeshTasksIndirectCommandEXT.html
using DrawMeshTasksIndirectCommand_t = DispatchIndirectCommand_t;

struct TraceRaysIndirectCommand_t
{
uint64_t raygenShaderRecordAddress;
Expand Down
Loading