Skip to content

Commit d4ade8c

Browse files
committed
Added support for VK_KHR_PIPELINE_EXECUTABLE_PROPERTIES
1 parent 03b5e34 commit d4ade8c

9 files changed

Lines changed: 180 additions & 8 deletions

File tree

include/nbl/asset/IPipeline.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ namespace nbl::asset
2323
Vulkan supports multiple types of pipelines:
2424
- graphics pipeline
2525
- compute pipeline
26-
- TODO: Raytracing
26+
- raytracing pipeline
2727
*/
2828
class IPipelineBase
2929
{
3030
public:
3131
// TODO: tbf these shouldn't even be laying around in `nbl::asset`, we should probably move to `nbl::video::IGPUPipelineBase`
32-
enum class CreationFlags : uint64_t
32+
enum class CreationFlags : uint64_t
3333
{
3434
NONE = 0, // disallowed in maintanance5
3535
DISABLE_OPTIMIZATIONS = 1 << 0,
@@ -47,10 +47,8 @@ class IPipelineBase
4747
// This is for NV-raytracing extension. Now this is done via IDeferredOperation
4848
//DEFER_COMPILE_NV = 1<<5,
4949

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

5553
// Will soon be deprecated due to
5654
// https://github.com/Devsh-Graphics-Programming/Nabla/issues/854

include/nbl/asset/IRayTracingPipeline.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ class IRayTracingPipelineBase : public virtual core::IReferenceCounted
3131
NO_NULL_MISS_SHADERS = 1<<16,
3232
NO_NULL_INTERSECTION_SHADERS = 1<<17,
3333
ALLOW_MOTION = 1<<20,
34+
CAPTURE_STATISTICS = base_flag(CAPTURE_STATISTICS),
35+
CAPTURE_INTERNAL_REPRESENTATIONS = base_flag(CAPTURE_INTERNAL_REPRESENTATIONS),
3436
};
3537
#undef base_flag
3638

include/nbl/video/IGPUComputePipeline.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ class IGPUComputePipeline : public IGPUPipeline<asset::IComputePipeline<const IG
3838
DISPATCH_BASE = 1<<4,
3939
FAIL_ON_PIPELINE_COMPILE_REQUIRED = base_flag(FAIL_ON_PIPELINE_COMPILE_REQUIRED),
4040
EARLY_RETURN_ON_FAILURE = base_flag(EARLY_RETURN_ON_FAILURE),
41+
CAPTURE_STATISTICS = base_flag(CAPTURE_STATISTICS),
42+
CAPTURE_INTERNAL_REPRESENTATIONS = base_flag(CAPTURE_INTERNAL_REPRESENTATIONS),
4143
// Not Supported Yet
4244
//CREATE_LIBRARY = base_flag(CREATE_LIBRARY),
4345
// Not Supported Yet

include/nbl/video/IGPUGraphicsPipeline.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ class IGPUGraphicsPipeline : public IGPUPipeline<asset::IGraphicsPipeline<const
2929
VIEW_INDEX_FROM_DEVICE_INDEX = 1<<3,
3030
FAIL_ON_PIPELINE_COMPILE_REQUIRED = base_flag(FAIL_ON_PIPELINE_COMPILE_REQUIRED),
3131
EARLY_RETURN_ON_FAILURE = base_flag(EARLY_RETURN_ON_FAILURE),
32+
CAPTURE_STATISTICS = base_flag(CAPTURE_STATISTICS),
33+
CAPTURE_INTERNAL_REPRESENTATIONS = base_flag(CAPTURE_INTERNAL_REPRESENTATIONS),
3234
};
3335
#undef base_flag
3436

include/nbl/video/ILogicalDevice.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,26 @@ class NBL_API2 ILogicalDevice : public core::IReferenceCounted, public IDeviceMe
10331033
const std::span<const IGPURayTracingPipeline::SCreationParams> params,
10341034
core::smart_refctd_ptr<IGPURayTracingPipeline>* const output);
10351035

1036+
// Pipeline executable statistics report (VK_KHR_pipeline_executable_properties).
1037+
// Pipeline must have been created with CAPTURE_STATISTICS flag.
1038+
// If includeInternalRepresentations is true, also includes shader IR/assembly
1039+
// (pipeline must have been created with CAPTURE_INTERNAL_REPRESENTATIONS flag).
1040+
template<typename Pipeline>
1041+
std::string getPipelineExecutableReport(const Pipeline* pipeline, bool includeInternalRepresentations = false)
1042+
{
1043+
if (!pipeline)
1044+
{
1045+
NBL_LOG_ERROR("Null pipeline");
1046+
return {};
1047+
}
1048+
if (!getEnabledFeatures().pipelineExecutableInfo)
1049+
{
1050+
NBL_LOG_ERROR("Feature `pipelineExecutableInfo` is not enabled");
1051+
return {};
1052+
}
1053+
return getPipelineExecutableReport_impl(pipeline->getNativeHandle(), includeInternalRepresentations);
1054+
}
1055+
10361056
// queries
10371057
inline core::smart_refctd_ptr<IQueryPool> createQueryPool(const IQueryPool::SCreationParams& params)
10381058
{
@@ -1296,6 +1316,8 @@ class NBL_API2 ILogicalDevice : public core::IReferenceCounted, public IDeviceMe
12961316
const SSpecializationValidationResult& validation
12971317
) = 0;
12981318

1319+
virtual std::string getPipelineExecutableReport_impl(const void* nativeHandle, bool includeInternalRepresentations) = 0;
1320+
12991321
virtual core::smart_refctd_ptr<IQueryPool> createQueryPool_impl(const IQueryPool::SCreationParams& params) = 0;
13001322
virtual bool getQueryPoolResults_impl(const IQueryPool* const queryPool, const uint32_t firstQuery, const uint32_t queryCount, void* const pData, const size_t stride, const core::bitflag<IQueryPool::RESULTS_FLAGS> flags) = 0;
13011323

src/nbl/video/CVulkanLogicalDevice.cpp

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1662,6 +1662,150 @@ void CVulkanLogicalDevice::createRayTracingPipelines_impl(
16621662
std::fill_n(output,vk_createInfos.size(),nullptr);
16631663
}
16641664

1665+
std::string CVulkanLogicalDevice::getPipelineExecutableReport_impl(const void* nativeHandle, bool includeInternalRepresentations)
1666+
{
1667+
const VkPipeline vkPipeline = *reinterpret_cast<const VkPipeline*>(nativeHandle);
1668+
1669+
VkPipelineInfoKHR pipelineInfo = {VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR, nullptr};
1670+
pipelineInfo.pipeline = vkPipeline;
1671+
1672+
// Enumerate executables
1673+
uint32_t executableCount = 0;
1674+
m_devf.vk.vkGetPipelineExecutablePropertiesKHR(m_vkdev, &pipelineInfo, &executableCount, nullptr);
1675+
1676+
core::vector<VkPipelineExecutablePropertiesKHR> properties(executableCount);
1677+
for (uint32_t i = 0; i < executableCount; ++i)
1678+
properties[i] = {VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_PROPERTIES_KHR, nullptr};
1679+
m_devf.vk.vkGetPipelineExecutablePropertiesKHR(m_vkdev, &pipelineInfo, &executableCount, properties.data());
1680+
1681+
std::string report;
1682+
report.reserve(1024); // avoid some reallocations, we can adjust this if needed
1683+
for (uint32_t i = 0; i < executableCount; ++i)
1684+
{
1685+
const auto& prop = properties[i];
1686+
1687+
report += "======== ";
1688+
report += prop.name;
1689+
report += " ========\n";
1690+
report += prop.description;
1691+
report += "\n";
1692+
1693+
VkPipelineExecutableInfoKHR execInfo = {VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INFO_KHR, nullptr};
1694+
execInfo.pipeline = vkPipeline;
1695+
execInfo.executableIndex = i;
1696+
1697+
// Statistics
1698+
report += "==== Statistics ====\n";
1699+
report += "Subgroup Size: ";
1700+
report += std::to_string(prop.subgroupSize);
1701+
report += "\n";
1702+
1703+
uint32_t statCount = 0;
1704+
m_devf.vk.vkGetPipelineExecutableStatisticsKHR(m_vkdev, &execInfo, &statCount, nullptr);
1705+
1706+
if (statCount > 0)
1707+
{
1708+
core::vector<VkPipelineExecutableStatisticKHR> stats(statCount);
1709+
for (uint32_t s = 0; s < statCount; ++s)
1710+
stats[s] = {VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_STATISTIC_KHR, nullptr};
1711+
m_devf.vk.vkGetPipelineExecutableStatisticsKHR(m_vkdev, &execInfo, &statCount, stats.data());
1712+
1713+
// First pass: format name:value pairs and find max width for alignment
1714+
core::vector<std::string> nameValues(statCount);
1715+
size_t maxNameValueLen = 0;
1716+
for (uint32_t s = 0; s < statCount; ++s)
1717+
{
1718+
const auto& stat = stats[s];
1719+
std::string value;
1720+
switch (stat.format)
1721+
{
1722+
case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_BOOL32_KHR:
1723+
value = stat.value.b32 ? "true" : "false";
1724+
break;
1725+
case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_INT64_KHR:
1726+
value = std::to_string(stat.value.i64);
1727+
break;
1728+
case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_UINT64_KHR:
1729+
value = std::to_string(stat.value.u64);
1730+
break;
1731+
case VK_PIPELINE_EXECUTABLE_STATISTIC_FORMAT_FLOAT64_KHR:
1732+
value = std::to_string(stat.value.f64);
1733+
break;
1734+
default:
1735+
value = "<unknown format>";
1736+
break;
1737+
}
1738+
nameValues[s] = std::string(stat.name) + ": " + value;
1739+
maxNameValueLen = std::max(maxNameValueLen, nameValues[s].size());
1740+
}
1741+
1742+
// Overkill for now, but it produces nicely aligned output which is easier to read. We can optimize later if needed.
1743+
// Second pass: emit with aligned columns
1744+
for (uint32_t s = 0; s < statCount; ++s)
1745+
{
1746+
report += nameValues[s];
1747+
report.append(maxNameValueLen - nameValues[s].size() + 4, ' ');
1748+
report += "// ";
1749+
report += stats[s].description;
1750+
report += "\n";
1751+
}
1752+
}
1753+
1754+
// Internal representations
1755+
if (includeInternalRepresentations)
1756+
{
1757+
uint32_t irCount = 0;
1758+
m_devf.vk.vkGetPipelineExecutableInternalRepresentationsKHR(m_vkdev, &execInfo, &irCount, nullptr);
1759+
1760+
if (irCount > 0)
1761+
{
1762+
core::vector<VkPipelineExecutableInternalRepresentationKHR> irs(irCount);
1763+
for (uint32_t r = 0; r < irCount; ++r)
1764+
irs[r] = {VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_INTERNAL_REPRESENTATION_KHR, nullptr};
1765+
1766+
// First call to get sizes
1767+
m_devf.vk.vkGetPipelineExecutableInternalRepresentationsKHR(m_vkdev, &execInfo, &irCount, irs.data());
1768+
1769+
// Allocate data buffers and second call to get data
1770+
core::vector<core::vector<char>> irData(irCount);
1771+
for (uint32_t r = 0; r < irCount; ++r)
1772+
{
1773+
irData[r].resize(irs[r].dataSize);
1774+
irs[r].pData = irData[r].data();
1775+
}
1776+
1777+
m_devf.vk.vkGetPipelineExecutableInternalRepresentationsKHR(m_vkdev, &execInfo, &irCount, irs.data());
1778+
1779+
report += "\n";
1780+
for (uint32_t r = 0; r < irCount; ++r)
1781+
{
1782+
report += "---- ";
1783+
report += irs[r].name;
1784+
report += " ----\n";
1785+
report += "; ";
1786+
report += irs[r].description;
1787+
report += "\n";
1788+
if (irs[r].isText)
1789+
{
1790+
auto* str = static_cast<const char*>(irs[r].pData);
1791+
report.append(str, irs[r].dataSize > 0 ? irs[r].dataSize - 1 : 0);
1792+
report += "\n";
1793+
}
1794+
else
1795+
{
1796+
report += "[binary data, ";
1797+
report += std::to_string(irs[r].dataSize);
1798+
report += " bytes]\n";
1799+
}
1800+
}
1801+
}
1802+
}
1803+
report += "\n";
1804+
}
1805+
1806+
return report;
1807+
}
1808+
16651809
core::smart_refctd_ptr<IQueryPool> CVulkanLogicalDevice::createQueryPool_impl(const IQueryPool::SCreationParams& params)
16661810
{
16671811
VkQueryPoolCreateInfo info = {VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, nullptr};

src/nbl/video/CVulkanLogicalDevice.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,9 @@ class CVulkanLogicalDevice final : public ILogicalDevice
301301
const SSpecializationValidationResult& validation
302302
) override;
303303

304+
// pipeline executable statistics
305+
std::string getPipelineExecutableReport_impl(const void* nativeHandle, bool includeInternalRepresentations) override;
306+
304307
// queries
305308
core::smart_refctd_ptr<IQueryPool> createQueryPool_impl(const IQueryPool::SCreationParams& params) override;
306309
bool getQueryPoolResults_impl(const IQueryPool* const queryPool, const uint32_t firstQuery, const uint32_t queryCount, void* const pData, const size_t stride, const core::bitflag<IQueryPool::RESULTS_FLAGS> flags) override;

src/nbl/video/device_capabilities/device_features.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2922,7 +2922,6 @@
29222922
"name": "pipelineExecutableInfo",
29232923
"value": false,
29242924
"comment": [
2925-
"[TODO] need impl",
29262925
"PipelineExecutablePropertiesFeaturesKHR",
29272926
"VK_KHR_pipeline_executable_properties"
29282927
]

0 commit comments

Comments
 (0)