Search code examples
graphicsnvidiavulkanraytracingcompute-shader

Compute shader in vulkan raytracing


I posted this question on vulkan forums and NVIDIA forums. Due to lack of responses, I tried to modify the ray tracing example by repurposing the closest hit shader to also act as a compute shader

  VkPipelineShaderStageCreateInfo stage{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO};
  stage.stage = VK_SHADER_STAGE_COMPUTE_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;

I get the following validation error due to this

 vkCreateRayTracingPipelinesKHR: value of pCreateInfos[0].pStages[3].stage contains multiple members of VkShaderStageFlagBits when only a single value is allowed The Vulkan spec states: stage must be a valid VkShaderStageFlagBits value 

I have the following questions regarding this

  1. Does the closest hit shader need the VK_SHADER_STAGE_COMPUTE_BIT value to use cooperative matrices?
  2. I think this answer clarifies that multiple values cannot be set for the stage attribute. Does this mean that what I am trying to do is not possible by design?

Note : I am very new to vulkan and still learning it.

Thanks


Solution

  • Disclaimer: I never used VK_NV_cooperative_matrix extension.

    Does the closest hit shader need the VK_SHADER_STAGE_COMPUTE_BIT value to use cooperative matrices?

    I think you misunderstood the purpose of VkPipelineShaderStageCreateInfo::stage : it does not give any property to anything. It specifies at which stage of the pipeline the module is used. So what you are trying to do cannot possibly work. No shader needs any VkShaderStageFlagBits. The shader probably does not even know it's called from Vulkan. But Vulkan needs to know when to call the shader.

    Moreover, ray tracing shaders are invoked in a VkPipeline that has been created using vkCreateRayTracingPipelinesKHR (or its NV equivalent). But compute shaders are invoked in one created by vkCreateComputePipelines. Those are COMPLETELY different things:

    Image source: Introduction to Real-Time Ray Tracing with Vulkan - NVIDIA Developer blog

    This image compares classical rasterization pipelines (created with vkCreateGraphicsPipelines) and ray tracing ones, but you get the idea.


    I think this answer clarifies that multiple values cannot be set for the stage attribute. Does this mean that what I am trying to do is not possible by design?

    I do not really understand what you mean by "what I am trying to do" (mainly because of your first sentence) so:

    • If you mean "giving two stages to VkPipelineShaderStageCreateInfo, the answer is yes, it's impossible (at least as of Vulkan 1.3).

    • If you mean "make a closest-hit shader act like a compute shader", the answer is again yes, it's (probably) impossible, but not for the same reason. You are likely to have ray-tracing dedicated functions that simply won't compile if you tell glslang "make me compute shader out of that thing".

    • If on the other hand you mean "use cooperative matrices in closest-hit shaders", I don't really know. But I think there should not be any problem using them. The extension description says the following (emphasis mine):

    [...] Cooperative matrix types are medium-sized matrices that are primarily supported in compute shaders, where the storage for the matrix is spread across all invocations in some scope (usually a subgroup) and those invocations cooperate to efficiently perform matrix multiplies.[...]

    If I understand that correctly, it does not mean it is not supported in other types of shaders. Just that it is mainly used (and thus supported) in compute shaders. Again, I've never used that extension so I may be wrong.

    Note that it's a device extension, it needs to be manually enabled upon creation of the logical device (VkDevice). You will also need to add a #extension GL_NV_cooperative_matrix : enable at the top of the shader using it.


    That said, do you really need those cooperative matrices in your closest-hit shader? What performance gain will you have by having them? Keep in mind that your closest hit shader is called at EACH intersection. Looking at the code you posted on the Vulkan forums, I believe your approach will make you loose more than what you could gain.