yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
3aff764c2
master
1// main.cpp 2 3// This tools reads a gfx pipeline dump file and replays the pipeline creation to trigger 4// shader compilation in the driver. 5// 6#include "../../source/core/slang-stream.h" 7#include "../../source/core/slang-string-util.h" 8#include "examples/hello-world/vulkan-api.h" 9#include "slang-com-ptr.h" 10#include "slang.h" 11 12#include <chrono> 13#include <slang-rhi.h> 14 15#if SLANG_WINDOWS_FAMILY 16#include <windows.h> 17#else 18#include <dlfcn.h> 19#endif 20 21using namespace Slang ; 22using namespace rhi ; 23 24struct PipelineCreationReplay 25{ 26// The Vulkan functions pointers result from loading the vulkan library. 27VulkanAPI vkAPI ; 28 29Dictionary < Index ,VkPipelineLayout > pipelineLayouts ; 30Dictionary < Index ,VkDescriptorSetLayout > descSetLayouts ; 31Dictionary < Index ,VkShaderModule > shaderModules ; 32Dictionary < Index ,VkPipeline > pipelines ; 33 34VkPipelineLayout pipelineLayout = VK_NULL_HANDLE ; 35VkPipeline pipeline = VK_NULL_HANDLE ; 36 37int initVulkanInstanceAndDevice (); 38 39List < uint8_t > fileBlob ; 40List < Index > pipelineOffsets ; 41 42struct Reader 43 { 44Index position ; 45List < uint8_t >& fileBlob ; 46Reader (List < uint8_t >& blob ,Index pos ) 47 :fileBlob (blob ),position (pos ) 48 { 49 } 50template < typename T > 51void readRaw (T & val ) 52 { 53memcpy (& val ,fileBlob .getBuffer ()+ position ,sizeof (T )); 54position += sizeof (T ); 55 } 56 57Index readIndex () 58 { 59Index index ; 60readRaw (index ); 61return index ; 62 } 63 64uint32_t readUInt32 () 65 { 66uint32_t index ; 67readRaw (index ); 68return index ; 69 } 70 71const char * readString () 72 { 73uint32_t len = readUInt32 (); 74auto result = (const char * )fileBlob .getBuffer ()+ position ; 75position += len ; 76return result ; 77 } 78 79const char * getPtr () {return (const char * )fileBlob .getBuffer ()+ position ; } 80 }; 81 82VkShaderModule loadShaderModule (Index offset ) 83 { 84VkShaderModule shader = VK_NULL_HANDLE ; 85if (shaderModules .tryGetValue (offset ,shader )) 86return shader ; 87 88Reader reader (fileBlob ,offset ); 89VkShaderModuleCreateInfo createInfo = {}; 90reader .readRaw (createInfo .sType ); 91reader .readRaw (createInfo .flags ); 92createInfo .codeSize = reader .readUInt32 (); 93createInfo .codeSize *=sizeof (uint32_t ); 94createInfo .pCode = (uint32_t * )reader .getPtr (); 95vkAPI .vkCreateShaderModule (vkAPI .device ,& createInfo ,nullptr ,& shader ); 96shaderModules [offset ]= shader ; 97 98return shader ; 99 } 100 101VkDescriptorSetLayout loadDescriptorSetLayout (Index offset ) 102 { 103VkDescriptorSetLayout layout = VK_NULL_HANDLE ; 104if (descSetLayouts .tryGetValue (offset ,layout )) 105return layout ; 106Reader reader (fileBlob ,offset ); 107VkDescriptorSetLayoutCreateInfo createInfo = {}; 108reader .readRaw (createInfo .sType ); 109reader .readRaw (createInfo .flags ); 110reader .readRaw (createInfo .bindingCount ); 111List < VkDescriptorSetLayoutBinding > bindings ; 112bindings .setCount (createInfo .bindingCount ); 113memcpy ( 114bindings .getBuffer (), 115reader .getPtr (), 116sizeof (VkDescriptorSetLayoutBinding )* bindings .getCount ()); 117createInfo .pBindings = bindings .getBuffer (); 118 119vkAPI .vkCreateDescriptorSetLayout (vkAPI .device ,& createInfo ,nullptr ,& layout ); 120descSetLayouts [offset ]= layout ; 121return layout ; 122 } 123 124VkPipelineLayout loadPipelineLayout (Index offset ) 125 { 126VkPipelineLayout layout = VK_NULL_HANDLE ; 127if (pipelineLayouts .tryGetValue (offset ,layout )) 128return layout ; 129 130Reader reader (fileBlob ,offset ); 131VkPipelineLayoutCreateInfo createInfo = {}; 132reader .readRaw (createInfo .sType ); 133reader .readRaw (createInfo .flags ); 134reader .readRaw (createInfo .setLayoutCount ); 135List < VkDescriptorSetLayout > setLayouts ; 136for (uint32_t i = 0 ;i < createInfo .setLayoutCount ;i ++ ) 137 { 138setLayouts .add (loadDescriptorSetLayout (reader .readIndex ())); 139 } 140createInfo .pSetLayouts = setLayouts .getBuffer (); 141reader .readRaw (createInfo .pushConstantRangeCount ); 142List < VkPushConstantRange > pushConstants ; 143pushConstants .setCount (createInfo .pushConstantRangeCount ); 144memcpy ( 145pushConstants .getBuffer (), 146reader .getPtr (), 147sizeof (VkPushConstantRange )* createInfo .pushConstantRangeCount ); 148createInfo .pPushConstantRanges = pushConstants .getBuffer (); 149 150vkAPI .vkCreatePipelineLayout (vkAPI .device ,& createInfo ,nullptr ,& layout ); 151pipelineLayouts [offset ]= layout ; 152return layout ; 153 } 154 155void loadPipeline (Index id ,Index offset ) 156 { 157printf ("Creating pipeline %d..." , (int )id ); 158 159Reader reader (fileBlob ,offset ); 160VkComputePipelineCreateInfo createInfo = {}; 161reader .readRaw (createInfo .sType ); 162reader .readRaw (createInfo .flags ); 163reader .readRaw (createInfo .stage .sType ); 164reader .readRaw (createInfo .stage .flags ); 165reader .readRaw (createInfo .stage .stage ); 166createInfo .stage .module = loadShaderModule (reader .readIndex ()); 167createInfo .stage .pName = reader .readString (); 168createInfo .layout = loadPipelineLayout (reader .readIndex ()); 169 170VkPipeline pipeline = VK_NULL_HANDLE ; 171 172auto startTime = std::chrono::high_resolution_clock::now (); 173 174if (vkAPI .vkCreateComputePipelines ( 175vkAPI .device , 176VK_NULL_HANDLE , 1771 , 178& createInfo , 179nullptr , 180& pipeline )== 0 ) 181printf ("done" ); 182else 183printf ("failed" ); 184 185auto endTime = std::chrono::high_resolution_clock::now (); 186auto elapsed = std::chrono::duration_cast < std::chrono::milliseconds > (endTime - startTime ); 187printf (" in %.2fs.\n" ,elapsed .count () /1000.0 ); 188 189vkAPI .vkDestroyPipeline (vkAPI .device ,pipeline ,nullptr ); 190 } 191 192int createComputePipelineFromShader (UnownedStringSlice path ,Int pipelineIndex ) 193 { 194RefPtr < FileStream > f = new FileStream (); 195f -> init (path ,FileMode ::Open ); 196uint32_t pipelineCount ; 197size_t readBytes ; 198f -> read (& pipelineCount ,sizeof (uint32_t ),readBytes ); 199for (uint32_t i = 0 ;i < pipelineCount ;++ i ) 200 { 201Index offset ; 202f -> read (& offset ,sizeof (Index ),readBytes ); 203pipelineOffsets .add (offset ); 204 } 205Index blobSize ; 206f -> read (& blobSize ,sizeof (Index ),readBytes ); 207fileBlob .setCount (blobSize ); 208f -> read (fileBlob .getBuffer (),sizeof (uint8_t )* blobSize ,readBytes ); 209 210if (pipelineIndex == -1 ) 211 { 212for (Index i = 0 ;i < pipelineOffsets .getCount ();++ i ) 213 { 214loadPipeline (i ,pipelineOffsets [i ]); 215 } 216 } 217else if (pipelineIndex < pipelineOffsets .getCount ()) 218 { 219loadPipeline (pipelineIndex ,pipelineOffsets [pipelineIndex ]); 220 } 221 222for (auto p :descSetLayouts ) 223vkAPI .vkDestroyDescriptorSetLayout ( 224vkAPI .device , 225* KeyValueDetail ::getValue (& p ), 226nullptr ); 227for (auto p :pipelineLayouts ) 228vkAPI .vkDestroyPipelineLayout (vkAPI .device ,* KeyValueDetail ::getValue (& p ),nullptr ); 229for (auto p :shaderModules ) 230vkAPI .vkDestroyShaderModule (vkAPI .device ,* KeyValueDetail ::getValue (& p ),nullptr ); 231 232return 0 ; 233 } 234 235int run (int argc ,const char ** argv ); 236 237void initVulkanAPI (IDevice * device ); 238}; 239 240int main (int argc ,const char ** argv ) 241{ 242PipelineCreationReplay app ; 243return app .run (argc ,argv ); 244} 245 246int PipelineCreationReplay ::run (int argc ,const char ** argv ) 247{ 248DeviceDesc deviceDesc = {}; 249deviceDesc .deviceType = DeviceType ::Vulkan ; 250ComPtr < IDevice > device ; 251SLANG_RETURN_ON_FAIL (createDevice (& deviceDesc ,device .writeRef ())); 252initVulkanAPI (device ); 253 254if (argc < 2 ) 255 { 256printf ("Usage: vk-pipeline-create <path-to-pipeline-file> [pipeline-index]\n" ); 257return -1 ; 258 } 259UnownedStringSlice path = UnownedStringSlice (argv [1 ]); 260Int pipelineIndex = -1 ; 261if (argc > 2 ) 262 { 263StringUtil ::parseInt (UnownedStringSlice (argv [2 ]),pipelineIndex ); 264 } 265 266RETURN_ON_FAIL (createComputePipelineFromShader (path ,pipelineIndex )); 267 268vkAPI .vkDestroyDevice = nullptr ; 269vkAPI .vkDestroyDebugReportCallbackEXT = nullptr ; 270vkAPI .vkDestroyInstance = nullptr ; 271return 0 ; 272} 273 274void PipelineCreationReplay ::initVulkanAPI (IDevice * device ) 275{ 276DeviceNativeHandles handle ; 277device -> getNativeDeviceHandles (& handle ); 278vkAPI .device = (VkDevice )(handle .handles [2 ].value ); 279vkAPI .instance = (VkInstance )(handle .handles [0 ].value ); 280#if SLANG_WINDOWS_FAMILY 281auto dynamicLibraryName = L"vulkan-1.dll" ; 282HMODULE module = ::LoadLibraryW (dynamicLibraryName ); 283vkAPI .vulkanLibraryHandle = (void * )module ; 284#define VK_API_GET_GLOBAL_PROC (x ) vkAPI.x = (PFN_##x)GetProcAddress(module, #x); 285#else 286auto dynamicLibraryName = "libvulkan.so.1" ; 287vkAPI .vulkanLibraryHandle = dlopen (dynamicLibraryName ,RTLD_NOW ); 288#define VK_API_GET_GLOBAL_PROC (x ) vkAPI.x = (PFN_##x)dlsym(vkAPI.vulkanLibraryHandle, #x); 289#endif 290 291// Initialize all the global functions. 292VK_API_ALL_GLOBAL_PROCS (VK_API_GET_GLOBAL_PROC ); 293 294vkAPI .initInstanceProcs (); 295vkAPI .initDeviceProcs (); 296} 297 298int PipelineCreationReplay ::initVulkanInstanceAndDevice () 299{ 300if (initializeVulkanDevice (vkAPI )!= 0 ) 301 { 302printf ("Failed to load Vulkan.\n" ); 303return -1 ; 304 } 305return 0 ; 306}