yum-mirror/slang

Making it easier to work with shaders

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

Ellie HermaszewskaMove switch statement bodies to their own lines (#5493)b118451e3

master
20.9 KiB517 linesraw
1// vk-pipeline-state.cpp
2#include "vk-pipeline-state.h"
3
4#include "vk-device.h"
5#include "vk-helper-functions.h"
6#include "vk-shader-object-layout.h"
7#include "vk-shader-program.h"
8#include "vk-vertex-layout.h"
9
10namespace gfx
11{
12
13using namespace Slang;
14
15namespace vk
16{
17
18PipelineStateImpl::PipelineStateImpl(DeviceImpl* device)
19{
20    // Only weakly reference `device` at start.
21    // We make it a strong reference only when the pipeline state is exposed to the user.
22    // Note that `PipelineState`s may also be created via implicit specialization that
23    // happens behind the scenes, and the user will not have access to those specialized
24    // pipeline states. Only those pipeline states that are returned to the user needs to
25    // hold a strong reference to `device`.
26    m_device.setWeakReference(device);
27}
28
29PipelineStateImpl::~PipelineStateImpl()
30{
31    if (m_pipeline != VK_NULL_HANDLE)
32    {
33        m_device->m_api.vkDestroyPipeline(m_device->m_api.m_device, m_pipeline, nullptr);
34    }
35}
36
37void PipelineStateImpl::establishStrongDeviceReference()
38{
39    m_device.establishStrongReference();
40}
41
42void PipelineStateImpl::comFree()
43{
44    m_device.breakStrongReference();
45}
46
47void PipelineStateImpl::init(const GraphicsPipelineStateDesc& inDesc)
48{
49    PipelineStateDesc pipelineDesc;
50    pipelineDesc.type = PipelineType::Graphics;
51    pipelineDesc.graphics = inDesc;
52    initializeBase(pipelineDesc);
53}
54
55void PipelineStateImpl::init(const ComputePipelineStateDesc& inDesc)
56{
57    PipelineStateDesc pipelineDesc;
58    pipelineDesc.type = PipelineType::Compute;
59    pipelineDesc.compute = inDesc;
60    initializeBase(pipelineDesc);
61}
62
63void PipelineStateImpl::init(const RayTracingPipelineStateDesc& inDesc)
64{
65    PipelineStateDesc pipelineDesc;
66    pipelineDesc.type = PipelineType::RayTracing;
67    pipelineDesc.rayTracing.set(inDesc);
68    initializeBase(pipelineDesc);
69}
70
71Result PipelineStateImpl::createVKGraphicsPipelineState()
72{
73    VkPipelineCache pipelineCache = VK_NULL_HANDLE;
74
75    auto inputLayoutImpl = (InputLayoutImpl*)desc.graphics.inputLayout;
76
77    // VertexBuffer/s
78    VkPipelineVertexInputStateCreateInfo vertexInputInfo = {
79        VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO};
80    vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
81    vertexInputInfo.vertexBindingDescriptionCount = 0;
82    vertexInputInfo.vertexAttributeDescriptionCount = 0;
83
84    if (inputLayoutImpl)
85    {
86        const auto& srcAttributeDescs = inputLayoutImpl->m_attributeDescs;
87        const auto& srcStreamDescs = inputLayoutImpl->m_streamDescs;
88
89        vertexInputInfo.vertexBindingDescriptionCount = (uint32_t)srcStreamDescs.getCount();
90        vertexInputInfo.pVertexBindingDescriptions = srcStreamDescs.getBuffer();
91
92        vertexInputInfo.vertexAttributeDescriptionCount = (uint32_t)srcAttributeDescs.getCount();
93        vertexInputInfo.pVertexAttributeDescriptions = srcAttributeDescs.getBuffer();
94    }
95
96    VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
97    inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
98    // All other forms of primitive toplogies are specified via dynamic state.
99    inputAssembly.topology =
100        VulkanUtil::translatePrimitiveTypeToListTopology(desc.graphics.primitiveType);
101    inputAssembly.primitiveRestartEnable = VK_FALSE; // TODO: Currently unsupported
102
103    VkViewport viewport = {};
104    viewport.x = 0.0f;
105    viewport.y = 0.0f;
106    // We are using dynamic viewport and scissor state.
107    // Here we specify an arbitrary size, actual viewport will be set at `beginRenderPass`
108    // time.
109    viewport.width = 16.0f;
110    viewport.height = 16.0f;
111    viewport.minDepth = 0.0f;
112    viewport.maxDepth = 1.0f;
113
114    VkRect2D scissor = {};
115    scissor.offset = {0, 0};
116    scissor.extent = {uint32_t(16), uint32_t(16)};
117
118    VkPipelineViewportStateCreateInfo viewportState = {};
119    viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
120    viewportState.viewportCount = 1;
121    viewportState.pViewports = &viewport;
122    viewportState.scissorCount = 1;
123    viewportState.pScissors = &scissor;
124
125    auto rasterizerDesc = desc.graphics.rasterizer;
126
127    VkPipelineRasterizationStateCreateInfo rasterizer = {};
128    rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
129    rasterizer.depthClampEnable =
130        VK_TRUE; // TODO: Depth clipping and clamping are different between Vk and D3D12
131    rasterizer.rasterizerDiscardEnable = VK_FALSE; // TODO: Currently unsupported
132    rasterizer.polygonMode = VulkanUtil::translateFillMode(rasterizerDesc.fillMode);
133    rasterizer.cullMode = VulkanUtil::translateCullMode(rasterizerDesc.cullMode);
134    rasterizer.frontFace = VulkanUtil::translateFrontFaceMode(rasterizerDesc.frontFace);
135    rasterizer.depthBiasEnable = (rasterizerDesc.depthBias == 0) ? VK_FALSE : VK_TRUE;
136    rasterizer.depthBiasConstantFactor = (float)rasterizerDesc.depthBias;
137    rasterizer.depthBiasClamp = rasterizerDesc.depthBiasClamp;
138    rasterizer.depthBiasSlopeFactor = rasterizerDesc.slopeScaledDepthBias;
139    rasterizer.lineWidth = 1.0f; // TODO: Currently unsupported
140
141    VkPipelineRasterizationConservativeStateCreateInfoEXT conservativeRasterInfo = {};
142    conservativeRasterInfo.sType =
143        VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT;
144    conservativeRasterInfo.conservativeRasterizationMode =
145        VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
146    if (desc.graphics.rasterizer.enableConservativeRasterization)
147    {
148        rasterizer.pNext = &conservativeRasterInfo;
149    }
150
151    auto framebufferLayoutImpl =
152        static_cast<FramebufferLayoutImpl*>(desc.graphics.framebufferLayout);
153    auto forcedSampleCount = rasterizerDesc.forcedSampleCount;
154    auto blendDesc = desc.graphics.blend;
155
156    VkPipelineMultisampleStateCreateInfo multisampling = {};
157    multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
158    multisampling.rasterizationSamples = (forcedSampleCount == 0)
159                                             ? framebufferLayoutImpl->m_sampleCount
160                                             : VulkanUtil::translateSampleCount(forcedSampleCount);
161    multisampling.sampleShadingEnable =
162        VK_FALSE; // TODO: Should check if fragment shader needs this
163    // TODO: Sample mask is dynamic in D3D12 but PSO state in Vulkan
164    multisampling.alphaToCoverageEnable = blendDesc.alphaToCoverageEnable;
165    multisampling.alphaToOneEnable = VK_FALSE;
166
167    auto targetCount = GfxCount(
168        Math::Min(framebufferLayoutImpl->m_renderTargetCount, (uint32_t)blendDesc.targetCount));
169    List<VkPipelineColorBlendAttachmentState> colorBlendTargets;
170
171    // Regardless of whether blending is enabled, Vulkan always applies the color write mask
172    // operation, so if there is no blending then we need to add an attachment that defines
173    // the color write mask to ensure colors are actually written.
174    if (targetCount == 0)
175    {
176        colorBlendTargets.setCount(1);
177        auto& vkBlendDesc = colorBlendTargets[0];
178        memset(&vkBlendDesc, 0, sizeof(vkBlendDesc));
179        vkBlendDesc.blendEnable = VK_FALSE;
180        vkBlendDesc.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
181        vkBlendDesc.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
182        vkBlendDesc.colorBlendOp = VK_BLEND_OP_ADD;
183        vkBlendDesc.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
184        vkBlendDesc.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
185        vkBlendDesc.alphaBlendOp = VK_BLEND_OP_ADD;
186        vkBlendDesc.colorWriteMask = (VkColorComponentFlags)RenderTargetWriteMask::EnableAll;
187    }
188    else
189    {
190        colorBlendTargets.setCount(targetCount);
191        for (GfxIndex i = 0; i < targetCount; ++i)
192        {
193            auto& gfxBlendDesc = blendDesc.targets[i];
194            auto& vkBlendDesc = colorBlendTargets[i];
195
196            vkBlendDesc.blendEnable = gfxBlendDesc.enableBlend;
197            vkBlendDesc.srcColorBlendFactor =
198                VulkanUtil::translateBlendFactor(gfxBlendDesc.color.srcFactor);
199            vkBlendDesc.dstColorBlendFactor =
200                VulkanUtil::translateBlendFactor(gfxBlendDesc.color.dstFactor);
201            vkBlendDesc.colorBlendOp = VulkanUtil::translateBlendOp(gfxBlendDesc.color.op);
202            vkBlendDesc.srcAlphaBlendFactor =
203                VulkanUtil::translateBlendFactor(gfxBlendDesc.alpha.srcFactor);
204            vkBlendDesc.dstAlphaBlendFactor =
205                VulkanUtil::translateBlendFactor(gfxBlendDesc.alpha.dstFactor);
206            vkBlendDesc.alphaBlendOp = VulkanUtil::translateBlendOp(gfxBlendDesc.alpha.op);
207            vkBlendDesc.colorWriteMask = (VkColorComponentFlags)gfxBlendDesc.writeMask;
208        }
209    }
210
211    VkPipelineColorBlendStateCreateInfo colorBlending = {};
212    colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
213    colorBlending.logicOpEnable = VK_FALSE; // TODO: D3D12 has per attachment logic op (and
214                                            // both have way more than one op)
215    colorBlending.logicOp = VK_LOGIC_OP_COPY;
216    colorBlending.attachmentCount = (uint32_t)colorBlendTargets.getCount();
217    colorBlending.pAttachments = colorBlendTargets.getBuffer();
218    colorBlending.blendConstants[0] = 0.0f;
219    colorBlending.blendConstants[1] = 0.0f;
220    colorBlending.blendConstants[2] = 0.0f;
221    colorBlending.blendConstants[3] = 0.0f;
222
223    Array<VkDynamicState, 8> dynamicStates;
224    dynamicStates.add(VK_DYNAMIC_STATE_VIEWPORT);
225    dynamicStates.add(VK_DYNAMIC_STATE_SCISSOR);
226    dynamicStates.add(VK_DYNAMIC_STATE_STENCIL_REFERENCE);
227    dynamicStates.add(VK_DYNAMIC_STATE_BLEND_CONSTANTS);
228    // It's not valid to specify VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT when
229    // the pipeline contains a mesh shader.
230    if (!m_program->isMeshShaderProgram() &&
231        m_device->m_api.m_extendedFeatures.extendedDynamicStateFeatures.extendedDynamicState)
232
233    {
234        dynamicStates.add(VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT);
235    }
236    VkPipelineDynamicStateCreateInfo dynamicStateInfo = {};
237    dynamicStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
238    dynamicStateInfo.dynamicStateCount = (uint32_t)dynamicStates.getCount();
239    dynamicStateInfo.pDynamicStates = dynamicStates.getBuffer();
240
241    VkPipelineDepthStencilStateCreateInfo depthStencilStateInfo = {};
242    depthStencilStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
243    depthStencilStateInfo.depthTestEnable = desc.graphics.depthStencil.depthTestEnable ? 1 : 0;
244    depthStencilStateInfo.back =
245        VulkanUtil::translateStencilState(desc.graphics.depthStencil.backFace);
246    depthStencilStateInfo.front =
247        VulkanUtil::translateStencilState(desc.graphics.depthStencil.frontFace);
248    depthStencilStateInfo.back.compareMask = desc.graphics.depthStencil.stencilReadMask;
249    depthStencilStateInfo.back.writeMask = desc.graphics.depthStencil.stencilWriteMask;
250    depthStencilStateInfo.front.compareMask = desc.graphics.depthStencil.stencilReadMask;
251    depthStencilStateInfo.front.writeMask = desc.graphics.depthStencil.stencilWriteMask;
252    depthStencilStateInfo.depthBoundsTestEnable = 0; // TODO: Currently unsupported
253    depthStencilStateInfo.depthCompareOp =
254        VulkanUtil::translateComparisonFunc(desc.graphics.depthStencil.depthFunc);
255    depthStencilStateInfo.depthWriteEnable = desc.graphics.depthStencil.depthWriteEnable ? 1 : 0;
256    depthStencilStateInfo.stencilTestEnable = desc.graphics.depthStencil.stencilEnable ? 1 : 0;
257
258    VkGraphicsPipelineCreateInfo pipelineInfo = {VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO};
259
260    auto programImpl = static_cast<ShaderProgramImpl*>(m_program.Ptr());
261    if (programImpl->m_stageCreateInfos.getCount() == 0)
262    {
263        SLANG_RETURN_ON_FAIL(programImpl->compileShaders(m_device));
264    }
265
266    pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
267    pipelineInfo.stageCount = (uint32_t)programImpl->m_stageCreateInfos.getCount();
268    pipelineInfo.pStages = programImpl->m_stageCreateInfos.getBuffer();
269    pipelineInfo.pVertexInputState = &vertexInputInfo;
270    pipelineInfo.pInputAssemblyState = &inputAssembly;
271    pipelineInfo.pViewportState = &viewportState;
272    pipelineInfo.pRasterizationState = &rasterizer;
273    pipelineInfo.pMultisampleState = &multisampling;
274    pipelineInfo.pColorBlendState = &colorBlending;
275    pipelineInfo.pDepthStencilState = &depthStencilStateInfo;
276    pipelineInfo.layout = programImpl->m_rootObjectLayout->m_pipelineLayout;
277    pipelineInfo.renderPass = framebufferLayoutImpl->m_renderPass;
278    pipelineInfo.subpass = 0;
279    pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
280    pipelineInfo.pDynamicState = &dynamicStateInfo;
281
282    if (m_device->m_pipelineCreationAPIDispatcher)
283    {
284        SLANG_RETURN_ON_FAIL(m_device->m_pipelineCreationAPIDispatcher->createGraphicsPipelineState(
285            m_device,
286            programImpl->linkedProgram.get(),
287            &pipelineInfo,
288            (void**)&m_pipeline));
289    }
290    else
291    {
292        SLANG_VK_RETURN_ON_FAIL(m_device->m_api.vkCreateGraphicsPipelines(
293            m_device->m_device,
294            pipelineCache,
295            1,
296            &pipelineInfo,
297            nullptr,
298            &m_pipeline));
299    }
300
301    return SLANG_OK;
302}
303
304Result PipelineStateImpl::createVKComputePipelineState()
305{
306    auto programImpl = static_cast<ShaderProgramImpl*>(m_program.Ptr());
307    if (programImpl->m_stageCreateInfos.getCount() == 0)
308    {
309        SLANG_RETURN_ON_FAIL(programImpl->compileShaders(m_device));
310    }
311
312    VkComputePipelineCreateInfo computePipelineInfo = {
313        VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO};
314    computePipelineInfo.stage = programImpl->m_stageCreateInfos[0];
315    computePipelineInfo.layout = programImpl->m_rootObjectLayout->m_pipelineLayout;
316
317    if (m_device->m_pipelineCreationAPIDispatcher)
318    {
319        SLANG_RETURN_ON_FAIL(m_device->m_pipelineCreationAPIDispatcher->createComputePipelineState(
320            m_device,
321            programImpl->linkedProgram.get(),
322            &computePipelineInfo,
323            (void**)&m_pipeline));
324    }
325    else
326    {
327        VkPipelineCache pipelineCache = VK_NULL_HANDLE;
328        SLANG_VK_RETURN_ON_FAIL(m_device->m_api.vkCreateComputePipelines(
329            m_device->m_device,
330            pipelineCache,
331            1,
332            &computePipelineInfo,
333            nullptr,
334            &m_pipeline));
335    }
336    return SLANG_OK;
337}
338
339Result PipelineStateImpl::ensureAPIPipelineStateCreated()
340{
341    if (m_pipeline)
342        return SLANG_OK;
343
344    switch (desc.type)
345    {
346    case PipelineType::Compute:
347        return createVKComputePipelineState();
348    case PipelineType::Graphics:
349        return createVKGraphicsPipelineState();
350    default:
351        SLANG_UNREACHABLE("Unknown pipeline type.");
352        return SLANG_FAIL;
353    }
354}
355SLANG_NO_THROW Result SLANG_MCALL PipelineStateImpl::getNativeHandle(InteropHandle* outHandle)
356{
357    SLANG_RETURN_ON_FAIL(ensureAPIPipelineStateCreated());
358    outHandle->api = InteropHandleAPI::Vulkan;
359    outHandle->handleValue = 0;
360    memcpy(&outHandle->handleValue, &m_pipeline, sizeof(m_pipeline));
361    return SLANG_OK;
362}
363
364RayTracingPipelineStateImpl::RayTracingPipelineStateImpl(DeviceImpl* device)
365    : PipelineStateImpl(device)
366{
367}
368uint32_t RayTracingPipelineStateImpl::findEntryPointIndexByName(
369    const Dictionary<String, Index>& entryPointNameToIndex,
370    const char* name)
371{
372    if (!name)
373        return VK_SHADER_UNUSED_KHR;
374
375    auto indexPtr = entryPointNameToIndex.tryGetValue(String(name));
376    if (indexPtr)
377        return (uint32_t)*indexPtr;
378    // TODO: Error reporting?
379    return VK_SHADER_UNUSED_KHR;
380}
381Result RayTracingPipelineStateImpl::createVKRayTracingPipelineState()
382{
383    auto programImpl = static_cast<ShaderProgramImpl*>(m_program.Ptr());
384    if (programImpl->m_stageCreateInfos.getCount() == 0)
385    {
386        SLANG_RETURN_ON_FAIL(programImpl->compileShaders(m_device));
387    }
388
389    VkRayTracingPipelineCreateInfoKHR raytracingPipelineInfo = {
390        VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR};
391    raytracingPipelineInfo.pNext = nullptr;
392    raytracingPipelineInfo.flags = translateRayTracingPipelineFlags(desc.rayTracing.flags);
393
394    raytracingPipelineInfo.stageCount = (uint32_t)programImpl->m_stageCreateInfos.getCount();
395    raytracingPipelineInfo.pStages = programImpl->m_stageCreateInfos.getBuffer();
396
397    // Build Dictionary from entry point name to entry point index (stageCreateInfos index)
398    // for all hit shaders - findShaderIndexByName
399    Dictionary<String, Index> entryPointNameToIndex;
400
401    List<VkRayTracingShaderGroupCreateInfoKHR> shaderGroupInfos;
402    for (uint32_t i = 0; i < raytracingPipelineInfo.stageCount; ++i)
403    {
404        auto stageCreateInfo = programImpl->m_stageCreateInfos[i];
405        auto entryPointName = programImpl->m_entryPointNames[i];
406        entryPointNameToIndex.add(entryPointName, i);
407        if (stageCreateInfo.stage &
408            (VK_SHADER_STAGE_ANY_HIT_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR |
409             VK_SHADER_STAGE_INTERSECTION_BIT_KHR))
410            continue;
411
412        VkRayTracingShaderGroupCreateInfoKHR shaderGroupInfo = {
413            VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR};
414        shaderGroupInfo.pNext = nullptr;
415        shaderGroupInfo.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
416        shaderGroupInfo.generalShader = i;
417        shaderGroupInfo.closestHitShader = VK_SHADER_UNUSED_KHR;
418        shaderGroupInfo.anyHitShader = VK_SHADER_UNUSED_KHR;
419        shaderGroupInfo.intersectionShader = VK_SHADER_UNUSED_KHR;
420        shaderGroupInfo.pShaderGroupCaptureReplayHandle = nullptr;
421
422        // For groups with a single entry point, the group name is the entry point name.
423        auto shaderGroupName = entryPointName;
424        auto shaderGroupIndex = shaderGroupInfos.getCount();
425        shaderGroupInfos.add(shaderGroupInfo);
426        shaderGroupNameToIndex.add(shaderGroupName, shaderGroupIndex);
427    }
428
429    for (int32_t i = 0; i < desc.rayTracing.hitGroupDescs.getCount(); ++i)
430    {
431        VkRayTracingShaderGroupCreateInfoKHR shaderGroupInfo = {
432            VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR};
433        auto& groupDesc = desc.rayTracing.hitGroupDescs[i];
434
435        shaderGroupInfo.pNext = nullptr;
436        shaderGroupInfo.type = (groupDesc.intersectionEntryPoint)
437                                   ? VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR
438                                   : VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
439        shaderGroupInfo.generalShader = VK_SHADER_UNUSED_KHR;
440        shaderGroupInfo.closestHitShader =
441            findEntryPointIndexByName(entryPointNameToIndex, groupDesc.closestHitEntryPoint);
442        shaderGroupInfo.anyHitShader =
443            findEntryPointIndexByName(entryPointNameToIndex, groupDesc.anyHitEntryPoint);
444        shaderGroupInfo.intersectionShader =
445            findEntryPointIndexByName(entryPointNameToIndex, groupDesc.intersectionEntryPoint);
446        shaderGroupInfo.pShaderGroupCaptureReplayHandle = nullptr;
447
448        auto shaderGroupIndex = shaderGroupInfos.getCount();
449        shaderGroupInfos.add(shaderGroupInfo);
450        shaderGroupNameToIndex.add(String(groupDesc.hitGroupName), shaderGroupIndex);
451    }
452
453    raytracingPipelineInfo.groupCount = (uint32_t)shaderGroupInfos.getCount();
454    raytracingPipelineInfo.pGroups = shaderGroupInfos.getBuffer();
455
456    raytracingPipelineInfo.maxPipelineRayRecursionDepth = (uint32_t)desc.rayTracing.maxRecursion;
457
458    raytracingPipelineInfo.pLibraryInfo = nullptr;
459    raytracingPipelineInfo.pLibraryInterface = nullptr;
460
461    raytracingPipelineInfo.pDynamicState = nullptr;
462
463    raytracingPipelineInfo.layout = programImpl->m_rootObjectLayout->m_pipelineLayout;
464    raytracingPipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
465    raytracingPipelineInfo.basePipelineIndex = 0;
466
467    if (m_device->m_pipelineCreationAPIDispatcher)
468    {
469        m_device->m_pipelineCreationAPIDispatcher->beforeCreateRayTracingState(
470            m_device,
471            programImpl->linkedProgram.get());
472    }
473
474    VkPipelineCache pipelineCache = VK_NULL_HANDLE;
475    SLANG_VK_RETURN_ON_FAIL(m_device->m_api.vkCreateRayTracingPipelinesKHR(
476        m_device->m_device,
477        VK_NULL_HANDLE,
478        pipelineCache,
479        1,
480        &raytracingPipelineInfo,
481        nullptr,
482        &m_pipeline));
483    shaderGroupCount = shaderGroupInfos.getCount();
484
485    if (m_device->m_pipelineCreationAPIDispatcher)
486    {
487        m_device->m_pipelineCreationAPIDispatcher->afterCreateRayTracingState(
488            m_device,
489            programImpl->linkedProgram.get());
490    }
491    return SLANG_OK;
492}
493Result RayTracingPipelineStateImpl::ensureAPIPipelineStateCreated()
494{
495    if (m_pipeline)
496        return SLANG_OK;
497
498    switch (desc.type)
499    {
500    case PipelineType::RayTracing:
501        return createVKRayTracingPipelineState();
502    default:
503        SLANG_UNREACHABLE("Unknown pipeline type.");
504        return SLANG_FAIL;
505    }
506}
507Result RayTracingPipelineStateImpl::getNativeHandle(InteropHandle* outHandle)
508{
509    SLANG_RETURN_ON_FAIL(ensureAPIPipelineStateCreated());
510    outHandle->api = InteropHandleAPI::Vulkan;
511    outHandle->handleValue = 0;
512    memcpy(&outHandle->handleValue, &m_pipeline, sizeof(m_pipeline));
513    return SLANG_OK;
514}
515
516} // namespace vk
517} // namespace gfx