yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Gangzheng TongUse wide char version of Windows API (#8390)3aff764c2

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