Skip to content
10 changes: 4 additions & 6 deletions include/nbl/asset/IPipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ namespace nbl::asset
Vulkan supports multiple types of pipelines:
- graphics pipeline
- compute pipeline
- TODO: Raytracing
- raytracing pipeline
*/
class IPipelineBase
{
public:
// TODO: tbf these shouldn't even be laying around in `nbl::asset`, we should probably move to `nbl::video::IGPUPipelineBase`
enum class CreationFlags : uint64_t
enum class CreationFlags : uint64_t
{
NONE = 0, // disallowed in maintanance5
DISABLE_OPTIMIZATIONS = 1 << 0,
Expand All @@ -47,10 +47,8 @@ class IPipelineBase
// This is for NV-raytracing extension. Now this is done via IDeferredOperation
//DEFER_COMPILE_NV = 1<<5,

// We use Renderdoc to take care of this for us,
// we won't be parsing the statistics and internal representation ourselves.
//CAPTURE_STATISTICS = 1<<6,
//CAPTURE_INTERNAL_REPRESENTATIONS = 1<<7,
CAPTURE_STATISTICS = 1<<6,
CAPTURE_INTERNAL_REPRESENTATIONS = 1<<7,

// Will soon be deprecated due to
// https://github.com/Devsh-Graphics-Programming/Nabla/issues/854
Expand Down
2 changes: 2 additions & 0 deletions include/nbl/asset/IRayTracingPipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class IRayTracingPipelineBase : public virtual core::IReferenceCounted
NO_NULL_MISS_SHADERS = 1<<16,
NO_NULL_INTERSECTION_SHADERS = 1<<17,
ALLOW_MOTION = 1<<20,
CAPTURE_STATISTICS = base_flag(CAPTURE_STATISTICS),
CAPTURE_INTERNAL_REPRESENTATIONS = base_flag(CAPTURE_INTERNAL_REPRESENTATIONS),
};
#undef base_flag

Expand Down
2 changes: 2 additions & 0 deletions include/nbl/video/CVulkanRayTracingPipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class CVulkanRayTracingPipeline final : public IGPURayTracingPipeline

inline VkPipeline getInternalObject() const { return m_vkPipeline; }

void populateExecutableInfo(bool includeInternalRepresentations) override;

virtual const SShaderGroupHandle& getRaygen() const override;
virtual std::span<const SShaderGroupHandle> getMissHandles() const override;
virtual std::span<const SShaderGroupHandle> getHitHandles() const override;
Expand Down
2 changes: 2 additions & 0 deletions include/nbl/video/IGPUComputePipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class IGPUComputePipeline : public IGPUPipeline<asset::IComputePipeline<const IG
DISPATCH_BASE = 1<<4,
FAIL_ON_PIPELINE_COMPILE_REQUIRED = base_flag(FAIL_ON_PIPELINE_COMPILE_REQUIRED),
EARLY_RETURN_ON_FAILURE = base_flag(EARLY_RETURN_ON_FAILURE),
CAPTURE_STATISTICS = base_flag(CAPTURE_STATISTICS),
CAPTURE_INTERNAL_REPRESENTATIONS = base_flag(CAPTURE_INTERNAL_REPRESENTATIONS),
// Not Supported Yet
//CREATE_LIBRARY = base_flag(CREATE_LIBRARY),
// Not Supported Yet
Expand Down
2 changes: 2 additions & 0 deletions include/nbl/video/IGPUGraphicsPipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ class IGPUGraphicsPipeline : public IGPUPipeline<asset::IGraphicsPipeline<const
VIEW_INDEX_FROM_DEVICE_INDEX = 1<<3,
FAIL_ON_PIPELINE_COMPILE_REQUIRED = base_flag(FAIL_ON_PIPELINE_COMPILE_REQUIRED),
EARLY_RETURN_ON_FAILURE = base_flag(EARLY_RETURN_ON_FAILURE),
CAPTURE_STATISTICS = base_flag(CAPTURE_STATISTICS),
CAPTURE_INTERNAL_REPRESENTATIONS = base_flag(CAPTURE_INTERNAL_REPRESENTATIONS),
};
#undef base_flag

Expand Down
65 changes: 65 additions & 0 deletions include/nbl/video/IGPUPipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "nbl/video/SPipelineCreationParams.h"
#include "nbl/asset/ICPUPipeline.h"
#include "nbl/asset/IPipeline.h"
#include "nbl/system/to_string.h"

namespace nbl::video
{
Expand Down Expand Up @@ -127,6 +128,21 @@ class IGPUPipelineBase {

using SShaderEntryMap = SShaderSpecInfo::entry_map_t;

// Per-executable info from VK_KHR_pipeline_executable_properties
struct SExecutableInfo
{
std::string name;
std::string description;
core::bitflag<hlsl::ShaderStage> stages = hlsl::ShaderStage::ESS_UNKNOWN;
uint32_t subgroupSize = 0;
std::string statistics;
std::string internalRepresentations;
};

inline std::span<const SExecutableInfo> getExecutableInfo() const { return m_executableInfo; }

protected:
core::vector<SExecutableInfo> m_executableInfo;
};

// Common Base class for pipelines
Expand All @@ -142,6 +158,55 @@ class IGPUPipeline : public IBackendObject, public PipelineNonBackendObjectBase,
{}
virtual ~IGPUPipeline() = default;

virtual void populateExecutableInfo(bool includeInternalRepresentations) = 0;

};

}

namespace nbl::system::impl
{

template<>
struct to_string_helper<video::IGPUPipelineBase::SExecutableInfo>
{
static std::string __call(const video::IGPUPipelineBase::SExecutableInfo& info)
{
std::string result;
result += "======== ";
result += info.name;
result += " ========\n";
result += info.description;
result += "\nSubgroup Size: ";
result += std::to_string(info.subgroupSize);
if (!info.statistics.empty())
{
result += "\n";
result += info.statistics;
}
if (!info.internalRepresentations.empty())
{
result += "\n";
result += info.internalRepresentations;
}
return result;
}
};

// Another version for core::vector?
template<>
struct to_string_helper<std::span<const video::IGPUPipelineBase::SExecutableInfo>>
{
static std::string __call(const std::span<const video::IGPUPipelineBase::SExecutableInfo>& infos)
{
std::string result;
for (const auto& info : infos)
{
result += to_string_helper<video::IGPUPipelineBase::SExecutableInfo>::__call(info);
result += "\n";
}
return result;
}
};

}
Expand Down
15 changes: 15 additions & 0 deletions include/nbl/video/ILogicalDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "nbl/video/IGPUCommandBuffer.h"
#include "nbl/video/CThreadSafeQueueAdapter.h"
#include "nbl/video/CJITIncludeLoader.h"
#include "nbl/system/to_string.h"

#include "git_info.h"
#define NBL_LOG_FUNCTION m_logger.log
Expand Down Expand Up @@ -1273,6 +1274,20 @@ class NBL_API2 ILogicalDevice : public core::IReferenceCounted, public IDeviceMe
return {};
}

// CAPTURE_STATISTICS and CAPTURE_INTERNAL_REPRESENTATIONS require pipelineExecutableInfo feature
constexpr auto CaptureStatsFlag = CreationParams::FLAGS::CAPTURE_STATISTICS;
constexpr auto CaptureIRFlag = CreationParams::FLAGS::CAPTURE_INTERNAL_REPRESENTATIONS;
if (ci.getFlags().hasFlags(CaptureStatsFlag) && !getEnabledFeatures().pipelineExecutableInfo)
{
NBL_LOG_ERROR("CAPTURE_STATISTICS flag requires `pipelineExecutableInfo` feature (params[%d])", i);
return {};
}
if (ci.getFlags().hasFlags(CaptureIRFlag) && !getEnabledFeatures().pipelineExecutableInfo)
{
NBL_LOG_ERROR("CAPTURE_INTERNAL_REPRESENTATIONS flag requires `pipelineExecutableInfo` feature (params[%d])", i);
return {};
}

retval += validation;
}
return retval;
Expand Down
7 changes: 7 additions & 0 deletions src/nbl/video/CVulkanComputePipeline.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "nbl/video/CVulkanComputePipeline.h"

#include "nbl/video/CVulkanLogicalDevice.h"
#include "nbl/video/CVulkanPipelineExecutableInfo.h"

namespace nbl::video
{
Expand All @@ -12,6 +13,12 @@ CVulkanComputePipeline::~CVulkanComputePipeline()
vk->vk.vkDestroyPipeline(vulkanDevice->getInternalObject(), m_pipeline, nullptr);
}

void CVulkanComputePipeline::populateExecutableInfo(bool includeInternalRepresentations)
{
const CVulkanLogicalDevice* vulkanDevice = static_cast<const CVulkanLogicalDevice*>(getOriginDevice());
populateExecutableInfoFromVulkan(m_executableInfo, vulkanDevice->getFunctionTable(), vulkanDevice->getInternalObject(), m_pipeline, includeInternalRepresentations);
}

void CVulkanComputePipeline::setObjectDebugName(const char* label) const
{
IBackendObject::setObjectDebugName(label);
Expand Down
10 changes: 8 additions & 2 deletions src/nbl/video/CVulkanComputePipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,18 @@ class CVulkanComputePipeline final : public IGPUComputePipeline
CVulkanComputePipeline(
const SCreationParams& params,
const VkPipeline pipeline
) : IGPUComputePipeline(params), m_pipeline(pipeline) {}
) : IGPUComputePipeline(params), m_pipeline(pipeline)
{
if (params.flags.hasFlags(SCreationParams::FLAGS::CAPTURE_STATISTICS))
populateExecutableInfo(params.flags.hasFlags(SCreationParams::FLAGS::CAPTURE_INTERNAL_REPRESENTATIONS));
}

inline const void* getNativeHandle() const override { return &m_pipeline; }

inline VkPipeline getInternalObject() const { return m_pipeline; }


void populateExecutableInfo(bool includeInternalRepresentations) override;

void setObjectDebugName(const char* label) const override;

private:
Expand Down
7 changes: 7 additions & 0 deletions src/nbl/video/CVulkanGraphicsPipeline.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
#include "nbl/video/CVulkanGraphicsPipeline.h"

#include "nbl/video/CVulkanLogicalDevice.h"
#include "CVulkanPipelineExecutableInfo.h"

namespace nbl::video
{

void CVulkanGraphicsPipeline::populateExecutableInfo(bool includeInternalRepresentations)
{
const CVulkanLogicalDevice* vulkanDevice = static_cast<const CVulkanLogicalDevice*>(getOriginDevice());
populateExecutableInfoFromVulkan(m_executableInfo, vulkanDevice->getFunctionTable(), vulkanDevice->getInternalObject(), m_vkPipeline, includeInternalRepresentations);
}

CVulkanGraphicsPipeline::~CVulkanGraphicsPipeline()
{
const CVulkanLogicalDevice* vulkanDevice = static_cast<const CVulkanLogicalDevice*>(getOriginDevice());
Expand Down
8 changes: 7 additions & 1 deletion src/nbl/video/CVulkanGraphicsPipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,18 @@ class CVulkanGraphicsPipeline final : public IGPUGraphicsPipeline
{
public:
CVulkanGraphicsPipeline(const SCreationParams& params, const VkPipeline vk_pipeline) :
IGPUGraphicsPipeline(params), m_vkPipeline(vk_pipeline) {}
IGPUGraphicsPipeline(params), m_vkPipeline(vk_pipeline)
{
if (params.flags.hasFlags(SCreationParams::FLAGS::CAPTURE_STATISTICS))
populateExecutableInfo(params.flags.hasFlags(SCreationParams::FLAGS::CAPTURE_INTERNAL_REPRESENTATIONS));
}

inline const void* getNativeHandle() const override {return &m_vkPipeline;}

inline VkPipeline getInternalObject() const {return m_vkPipeline;}

void populateExecutableInfo(bool includeInternalRepresentations) override;

private:
~CVulkanGraphicsPipeline();

Expand Down
10 changes: 7 additions & 3 deletions src/nbl/video/CVulkanLogicalDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1192,9 +1192,10 @@ void CVulkanLogicalDevice::createComputePipelines_impl(
const VkPipeline vk_pipeline = vk_pipelines[i];
// break the lifetime cause of the aliasing
std::uninitialized_default_construct_n(output+i,1);
output[i] = core::make_smart_refctd_ptr<CVulkanComputePipeline>(
auto pipeline = core::make_smart_refctd_ptr<CVulkanComputePipeline>(
info,vk_pipeline
);
output[i] = std::move(pipeline);
debugNameBuilder.str("");
const auto& specInfo = createInfos[i].shader;
debugNameBuilder << specInfo.shader->getFilepathHint() << "(" << specInfo.entryPoint << "," << hlsl::ShaderStage::ESS_COMPUTE << ")\n";
Expand Down Expand Up @@ -1448,7 +1449,8 @@ void CVulkanLogicalDevice::createGraphicsPipelines_impl(
const VkPipeline vk_pipeline = vk_pipelines[i];
// break the lifetime cause of the aliasing
std::uninitialized_default_construct_n(output+i,1);
output[i] = core::make_smart_refctd_ptr<CVulkanGraphicsPipeline>(createInfos[i],vk_pipeline);
auto pipeline = core::make_smart_refctd_ptr<CVulkanGraphicsPipeline>(createInfos[i],vk_pipeline);
output[i] = std::move(pipeline);
debugNameBuilder.str("");
auto buildDebugName = [&](const IGPUPipelineBase::SShaderSpecInfo& spec, hlsl::ShaderStage stage)
{
Expand Down Expand Up @@ -1653,11 +1655,13 @@ void CVulkanLogicalDevice::createRayTracingPipelines_impl(
const auto success = m_devf.vk.vkGetRayTracingShaderGroupHandlesKHR(m_vkdev, vk_pipeline, 0, handleCount, dataSize, shaderGroupHandles->data()) == VK_SUCCESS;
assert(success);

output[i] = core::make_smart_refctd_ptr<CVulkanRayTracingPipeline>(
auto pipeline = core::make_smart_refctd_ptr<CVulkanRayTracingPipeline>(
createInfos[i],
vk_pipeline,
std::move(shaderGroupHandles)
);

output[i] = std::move(pipeline);
}
}
else
Expand Down
Loading
Loading