@@ -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+
16651809core::smart_refctd_ptr<IQueryPool> CVulkanLogicalDevice::createQueryPool_impl (const IQueryPool::SCreationParams& params)
16661810{
16671811 VkQueryPoolCreateInfo info = {VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO, nullptr };
0 commit comments