diff --git a/ray_tracing__simple/hello_vulkan.cpp b/ray_tracing__simple/hello_vulkan.cpp index 4b0877f..d8e6aec 100644 --- a/ray_tracing__simple/hello_vulkan.cpp +++ b/ray_tracing__simple/hello_vulkan.cpp @@ -840,39 +840,70 @@ void HelloVulkan::createRtPipeline() // The Shader Binding Table (SBT) // - getting all shader handles and write them in a SBT buffer // - Besides exception, this could be always done like this -// See how the SBT buffer is used in run() // void HelloVulkan::createRtShaderBindingTable() { - auto groupCount = static_cast(m_rtShaderGroups.size()); // 4 shaders: raygen, 2 miss, chit - uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier - // Compute the actual size needed per SBT entry (round-up to alignment needed). - uint32_t groupSizeAligned = nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - // Bytes needed for the SBT. - uint32_t sbtSize = groupCount * groupSizeAligned; + uint32_t missCount{2}; + uint32_t hitCount{1}; + auto handleCount = 1 + missCount + hitCount; + uint32_t handleSize = m_rtProperties.shaderGroupHandleSize; - // Fetch all the shader handles used in the pipeline. This is opaque data,/ so we store it in a vector of bytes. - // The order of handles follow the stage entry. - std::vector shaderHandleStorage(sbtSize); - auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()); + // The SBT (buffer) need to have starting groups to be aligned and handles in the group to be aligned. + uint32_t handleSizeAligned = nvh::align_up(handleSize, m_rtProperties.shaderGroupHandleAlignment); + m_rgenRegion.stride = nvh::align_up(handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); + m_rgenRegion.size = m_rgenRegion.stride; // The size member of pRayGenShaderBindingTable must be equal to its stride member + m_missRegion.stride = handleSizeAligned; + m_missRegion.size = nvh::align_up(missCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); + m_hitRegion.stride = handleSizeAligned; + m_hitRegion.size = nvh::align_up(hitCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); + + // Get the shader group handles + uint32_t dataSize = handleCount * handleSize; + std::vector handles(dataSize); + auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, handleCount, dataSize, handles.data()); assert(result == VK_SUCCESS); - // Allocate a buffer for storing the SBT. Give it a debug name for NSight. - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, + // Allocate a buffer for storing the SBT. + VkDeviceSize sbtSize = m_rgenRegion.size + m_missRegion.size + m_hitRegion.size + m_callRegion.size; + m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); + m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); // Give it a debug name for NSight. + + // Find the SBT addresses of each group + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, nullptr, m_rtSBTBuffer.buffer}; + VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info); + m_rgenRegion.deviceAddress = sbtAddress; + m_missRegion.deviceAddress = sbtAddress + m_rgenRegion.size; + m_hitRegion.deviceAddress = sbtAddress + m_rgenRegion.size + m_missRegion.size; + + // Helper to retrieve the handle data + auto getHandle = [&](int i) { return handles.data() + i * handleSize; }; // Map the SBT buffer and write in the handles. - void* mapped = m_alloc.map(m_rtSBTBuffer); - auto* pData = reinterpret_cast(mapped); - for(uint32_t g = 0; g < groupCount; g++) + auto* pSBTBuffer = reinterpret_cast(m_alloc.map(m_rtSBTBuffer)); + uint8_t* pData{nullptr}; + uint32_t handleIdx{0}; + // Raygen + pData = pSBTBuffer; + memcpy(pData, getHandle(handleIdx++), handleSize); + // Miss + pData = pSBTBuffer + m_rgenRegion.size; + for(uint32_t c = 0; c < missCount; c++) { - memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); - pData += groupSizeAligned; + memcpy(pData, getHandle(handleIdx++), handleSize); + pData += m_missRegion.stride; } + // Hit + pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size; + for(uint32_t c = 0; c < hitCount; c++) + { + memcpy(pData, getHandle(handleIdx++), handleSize); + pData += m_hitRegion.stride; + } + m_alloc.unmap(m_rtSBTBuffer); m_alloc.finalizeAndReleaseStaging(); } @@ -898,22 +929,7 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c 0, sizeof(PushConstantRay), &m_pcRay); - // Size of a program identifier - uint32_t groupSize = nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - uint32_t groupStride = groupSize; - - VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, nullptr, m_rtSBTBuffer.buffer}; - VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info); - - using Stride = VkStridedDeviceAddressRegionKHR; - std::array strideAddresses{Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen - Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss - Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit - Stride{0u, 0u, 0u}}; // callable - - - vkCmdTraceRaysKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], &strideAddresses[2], &strideAddresses[3], - m_size.width, m_size.height, 1); + vkCmdTraceRaysKHR(cmdBuf, &m_rgenRegion, &m_missRegion, &m_hitRegion, &m_callRegion, m_size.width, m_size.height, 1); m_debug.endLabel(cmdBuf); diff --git a/ray_tracing__simple/hello_vulkan.h b/ray_tracing__simple/hello_vulkan.h index 65b1332..9916a59 100644 --- a/ray_tracing__simple/hello_vulkan.h +++ b/ray_tracing__simple/hello_vulkan.h @@ -144,7 +144,12 @@ public: std::vector m_rtShaderGroups; VkPipelineLayout m_rtPipelineLayout; VkPipeline m_rtPipeline; - nvvk::Buffer m_rtSBTBuffer; + + nvvk::Buffer m_rtSBTBuffer; + VkStridedDeviceAddressRegionKHR m_rgenRegion{}; + VkStridedDeviceAddressRegionKHR m_missRegion{}; + VkStridedDeviceAddressRegionKHR m_hitRegion{}; + VkStridedDeviceAddressRegionKHR m_callRegion{}; // Push constant for ray tracer PushConstantRay m_pcRay{}; diff --git a/ray_tracing_anyhit/hello_vulkan.cpp b/ray_tracing_anyhit/hello_vulkan.cpp index 99672d5..d39c97b 100644 --- a/ray_tracing_anyhit/hello_vulkan.cpp +++ b/ray_tracing_anyhit/hello_vulkan.cpp @@ -39,7 +39,6 @@ extern std::vector defaultSearchPaths; - //-------------------------------------------------------------------------------------------------- // Keep the handle on the device // Initialize the tool to do all our allocations: buffers, images @@ -685,8 +684,7 @@ void HelloVulkan::createTopLevelAS() // void HelloVulkan::createRtDescriptorSet() { - // Top-level acceleration structure, usable by both the ray generation and the closest hit (to - // shoot shadow rays) + // Top-level acceleration structure, usable by both the ray generation and the closest hit (to shoot shadow rays) m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, @@ -857,39 +855,70 @@ void HelloVulkan::createRtPipeline() // The Shader Binding Table (SBT) // - getting all shader handles and write them in a SBT buffer // - Besides exception, this could be always done like this -// See how the SBT buffer is used in run() // void HelloVulkan::createRtShaderBindingTable() { - auto groupCount = static_cast(m_rtShaderGroups.size()); // shaders: raygen, 2 miss, chit, 2 ahit - uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier - // Compute the actual size needed per SBT entry (round-up to alignment needed). - uint32_t groupSizeAligned = nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - // Bytes needed for the SBT. - uint32_t sbtSize = groupCount * groupSizeAligned; + uint32_t missCount{2}; + uint32_t hitCount{2}; + auto handleCount = 1 + missCount + hitCount; + uint32_t handleSize = m_rtProperties.shaderGroupHandleSize; - // Fetch all the shader handles used in the pipeline. This is opaque data, - // so we store it in a vector of bytes. - std::vector shaderHandleStorage(sbtSize); - auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()); + // The SBT (buffer) need to have starting groups to be aligned and handles in the group to be aligned. + uint32_t handleSizeAligned = nvh::align_up(handleSize, m_rtProperties.shaderGroupHandleAlignment); + + m_rgenRegion.stride = nvh::align_up(handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); + m_rgenRegion.size = m_rgenRegion.stride; // The size member of pRayGenShaderBindingTable must be equal to its stride member + m_missRegion.stride = handleSizeAligned; + m_missRegion.size = nvh::align_up(missCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); + m_hitRegion.stride = handleSizeAligned; + m_hitRegion.size = nvh::align_up(hitCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); + // Get the shader group handles + uint32_t dataSize = handleCount * handleSize; + std::vector handles(dataSize); + auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, handleCount, dataSize, handles.data()); assert(result == VK_SUCCESS); - - // Allocate a buffer for storing the SBT. Give it a debug name for NSight. - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, + + // Allocate a buffer for storing the SBT. + VkDeviceSize sbtSize = m_rgenRegion.size + m_missRegion.size + m_hitRegion.size + m_callRegion.size; + m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str()); + m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); // Give it a debug name for NSight. + + // Find the SBT addresses of each group + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, nullptr, m_rtSBTBuffer.buffer}; + VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info); + m_rgenRegion.deviceAddress = sbtAddress; + m_missRegion.deviceAddress = sbtAddress + m_rgenRegion.size; + m_hitRegion.deviceAddress = sbtAddress + m_rgenRegion.size + m_missRegion.size; + + // Helper to retrieve the handle data + auto getHandle = [&](int i) { return handles.data() + i * handleSize; }; // Map the SBT buffer and write in the handles. - void* mapped = m_alloc.map(m_rtSBTBuffer); - auto* pData = reinterpret_cast(mapped); - for(uint32_t g = 0; g < groupCount; g++) + auto* pSBTBuffer = reinterpret_cast(m_alloc.map(m_rtSBTBuffer)); + uint8_t* pData{nullptr}; + uint32_t handleIdx{0}; + // Raygen + pData = pSBTBuffer; + memcpy(pData, getHandle(handleIdx++), handleSize); + // Miss + pData = pSBTBuffer + m_rgenRegion.size; + for(uint32_t c = 0; c < missCount; c++) { - memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); - pData += groupSizeAligned; + memcpy(pData, getHandle(handleIdx++), handleSize); + pData += m_missRegion.stride; } + // Hit + pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size; + for(uint32_t c = 0; c < hitCount; c++) + { + memcpy(pData, getHandle(handleIdx++), handleSize); + pData += m_hitRegion.stride; + } + m_alloc.unmap(m_rtSBTBuffer); m_alloc.finalizeAndReleaseStaging(); } @@ -910,7 +939,6 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c m_pcRay.lightIntensity = m_pcRaster.lightIntensity; m_pcRay.lightType = m_pcRaster.lightType; - std::vector descSets{m_rtDescSet, m_descSet}; vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, @@ -920,21 +948,7 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c 0, sizeof(PushConstantRay), &m_pcRay); - // Size of a program identifier - uint32_t groupSize = nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - uint32_t groupStride = groupSize; - - VkDeviceAddress sbtAddress = nvvk::getBufferDeviceAddress(m_device, m_rtSBTBuffer.buffer); - - using Stride = VkStridedDeviceAddressRegionKHR; - std::array strideAddresses{Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen - Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss - Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 2}, // hit - Stride{0u, 0u, 0u}}; // callable - - - vkCmdTraceRaysKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], &strideAddresses[2], &strideAddresses[3], - m_size.width, m_size.height, 1); + vkCmdTraceRaysKHR(cmdBuf, &m_rgenRegion, &m_missRegion, &m_hitRegion, &m_callRegion, m_size.width, m_size.height, 1); m_debug.endLabel(cmdBuf); diff --git a/ray_tracing_anyhit/hello_vulkan.h b/ray_tracing_anyhit/hello_vulkan.h index e3a567b..34f67d7 100644 --- a/ray_tracing_anyhit/hello_vulkan.h +++ b/ray_tracing_anyhit/hello_vulkan.h @@ -145,8 +145,14 @@ public: std::vector m_rtShaderGroups; VkPipelineLayout m_rtPipelineLayout; VkPipeline m_rtPipeline; - nvvk::Buffer m_rtSBTBuffer; - int m_maxFrames{10000}; + + nvvk::Buffer m_rtSBTBuffer; + VkStridedDeviceAddressRegionKHR m_rgenRegion{}; + VkStridedDeviceAddressRegionKHR m_missRegion{}; + VkStridedDeviceAddressRegionKHR m_hitRegion{}; + VkStridedDeviceAddressRegionKHR m_callRegion{}; + + int m_maxFrames{10000}; // Push constant for ray tracer PushConstantRay m_pcRay{}; diff --git a/ray_tracing_indirect_scissor/hello_vulkan.cpp b/ray_tracing_indirect_scissor/hello_vulkan.cpp index e91be10..58b3fa7 100644 --- a/ray_tracing_indirect_scissor/hello_vulkan.cpp +++ b/ray_tracing_indirect_scissor/hello_vulkan.cpp @@ -1116,41 +1116,71 @@ void HelloVulkan::createRtPipeline() // The Shader Binding Table (SBT) // - getting all shader handles and write them in a SBT buffer // - Besides exception, this could be always done like this -// See how the SBT buffer is used in run() // void HelloVulkan::createRtShaderBindingTable() { - auto groupCount = static_cast(m_rtShaderGroups.size()); - assert(groupCount == 8 && "Update Comment"); // 8 shaders: raygen, 3 miss, 4 chit + uint32_t missCount{3}; + uint32_t hitCount{4}; + auto handleCount = 1 + missCount + hitCount; + uint32_t handleSize = m_rtProperties.shaderGroupHandleSize; - uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier - // Compute the actual size needed per SBT entry (round-up to alignment needed). - uint32_t groupSizeAligned = nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - // Bytes needed for the SBT. - uint32_t sbtSize = groupCount * groupSizeAligned; - - // Fetch all the shader handles used in the pipeline. This is opaque data, - // so we store it in a vector of bytes. - std::vector shaderHandleStorage(sbtSize); - auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()); + // The SBT (buffer) need to have starting groups to be aligned and handles in the group to be aligned. + uint32_t handleSizeAligned = nvh::align_up(handleSize, m_rtProperties.shaderGroupHandleAlignment); + + m_rgenRegion.stride = nvh::align_up(handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); + m_rgenRegion.size = m_rgenRegion.stride; // The size member of pRayGenShaderBindingTable must be equal to its stride member + m_missRegion.stride = handleSizeAligned; + m_missRegion.size = nvh::align_up(missCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); + m_hitRegion.stride = handleSizeAligned; + m_hitRegion.size = nvh::align_up(hitCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); + // Get the shader group handles + uint32_t dataSize = handleCount * handleSize; + std::vector handles(dataSize); + auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, handleCount, dataSize, handles.data()); assert(result == VK_SUCCESS); - // Allocate a buffer for storing the SBT. Give it a debug name for NSight. - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, + // Allocate a buffer for storing the SBT. + VkDeviceSize sbtSize = m_rgenRegion.size + m_missRegion.size + m_hitRegion.size + m_callRegion.size; + m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); + m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); // Give it a debug name for NSight. + + // Find the SBT addresses of each group + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, nullptr, m_rtSBTBuffer.buffer}; + VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info); + m_rgenRegion.deviceAddress = sbtAddress; + m_missRegion.deviceAddress = sbtAddress + m_rgenRegion.size; + m_hitRegion.deviceAddress = sbtAddress + m_rgenRegion.size + m_missRegion.size; + + // Helper to retrieve the handle data + auto getHandle = [&](int i) { return handles.data() + i * handleSize; }; // Map the SBT buffer and write in the handles. - void* mapped = m_alloc.map(m_rtSBTBuffer); - auto* pData = reinterpret_cast(mapped); - for(uint32_t g = 0; g < groupCount; g++) + auto* pSBTBuffer = reinterpret_cast(m_alloc.map(m_rtSBTBuffer)); + uint8_t* pData{nullptr}; + uint32_t handleIdx{0}; + // Raygen + pData = pSBTBuffer; + memcpy(pData, getHandle(handleIdx++), handleSize); + // Miss + pData = pSBTBuffer + m_rgenRegion.size; + for(uint32_t c = 0; c < missCount; c++) { - memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); - pData += groupSizeAligned; + memcpy(pData, getHandle(handleIdx++), handleSize); + pData += m_missRegion.stride; } + // Hit + pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size; + for(uint32_t c = 0; c < hitCount; c++) + { + memcpy(pData, getHandle(handleIdx++), handleSize); + pData += m_hitRegion.stride; + } + + m_alloc.unmap(m_rtSBTBuffer); m_alloc.finalizeAndReleaseStaging(); } @@ -1323,22 +1353,8 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c 0, sizeof(PushConstantRay), &m_pcRay); - // Size of a program identifier - uint32_t groupSize = nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - uint32_t groupStride = groupSize; + vkCmdTraceRaysKHR(cmdBuf, &m_rgenRegion, &m_missRegion, &m_hitRegion, &m_callRegion, m_size.width, m_size.height, 1); - VkDeviceAddress sbtAddress = nvvk::getBufferDeviceAddress(m_device, m_rtSBTBuffer.buffer); - - using Stride = VkStridedDeviceAddressRegionKHR; - std::array strideAddresses{Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen - Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 3}, // miss - Stride{sbtAddress + 4u * groupSize, groupStride, groupSize * 4}, // hit - Stride{0u, 0u, 0u}}; // callable - - - // First pass, illuminate scene with global light. - vkCmdTraceRaysKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], &strideAddresses[2], &strideAddresses[3], - m_size.width, m_size.height, 1); // Lantern passes, ensure previous pass completed, then add light contribution from each lantern. for(int i = 0; i < static_cast(m_lanternCount); ++i) @@ -1372,9 +1388,7 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c nvvk::getBufferDeviceAddress(m_device, m_lanternIndirectBuffer.buffer) + i * sizeof(LanternIndirectEntry); // Execute lantern pass. - vkCmdTraceRaysIndirectKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], // - &strideAddresses[2], &strideAddresses[3], // - indirectDeviceAddress); + vkCmdTraceRaysIndirectKHR(cmdBuf, &m_rgenRegion, &m_missRegion, &m_hitRegion, &m_callRegion, indirectDeviceAddress); } m_debug.endLabel(cmdBuf); diff --git a/ray_tracing_indirect_scissor/hello_vulkan.h b/ray_tracing_indirect_scissor/hello_vulkan.h index 34355e7..190b5b2 100644 --- a/ray_tracing_indirect_scissor/hello_vulkan.h +++ b/ray_tracing_indirect_scissor/hello_vulkan.h @@ -206,7 +206,12 @@ public: VkDescriptorSet m_lanternIndirectDescSet; VkPipelineLayout m_lanternIndirectCompPipelineLayout; VkPipeline m_lanternIndirectCompPipeline; - nvvk::Buffer m_rtSBTBuffer; + + nvvk::Buffer m_rtSBTBuffer; + VkStridedDeviceAddressRegionKHR m_rgenRegion{}; + VkStridedDeviceAddressRegionKHR m_missRegion{}; + VkStridedDeviceAddressRegionKHR m_hitRegion{}; + VkStridedDeviceAddressRegionKHR m_callRegion{}; // Buffer to source vkCmdTraceRaysIndirectKHR indirect parameters and lantern color, // position, etc. from when doing lantern lighting passes. diff --git a/ray_tracing_intersection/hello_vulkan.cpp b/ray_tracing_intersection/hello_vulkan.cpp index 9ab57f3..f95039e 100644 --- a/ray_tracing_intersection/hello_vulkan.cpp +++ b/ray_tracing_intersection/hello_vulkan.cpp @@ -423,7 +423,7 @@ void HelloVulkan::rasterize(const VkCommandBuffer& cmdBuf) vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descSet, 0, nullptr); - uint32_t nbInst = static_cast(m_instances.size() - 1); // Remove the implicit object + auto nbInst = static_cast(m_instances.size() - 1); // Remove the implicit object for(uint32_t i = 0; i < nbInst; ++i) { auto& inst = m_instances[i]; @@ -998,39 +998,70 @@ void HelloVulkan::createRtPipeline() // The Shader Binding Table (SBT) // - getting all shader handles and write them in a SBT buffer // - Besides exception, this could be always done like this -// See how the SBT buffer is used in run() // void HelloVulkan::createRtShaderBindingTable() { - auto groupCount = static_cast(m_rtShaderGroups.size()); // 4 shaders: raygen, 2 miss, chit - uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier - // Compute the actual size needed per SBT entry (round-up to alignment needed). - uint32_t groupSizeAligned = nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - // Bytes needed for the SBT. - uint32_t sbtSize = groupCount * groupSizeAligned; + uint32_t missCount{2}; + uint32_t hitCount{2}; + auto handleCount = 1 + missCount + hitCount; + uint32_t handleSize = m_rtProperties.shaderGroupHandleSize; - // Fetch all the shader handles used in the pipeline. This is opaque data, - // so we store it in a vector of bytes. - std::vector shaderHandleStorage(sbtSize); - auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()); + // The SBT (buffer) need to have starting groups to be aligned and handles in the group to be aligned. + uint32_t handleSizeAligned = nvh::align_up(handleSize, m_rtProperties.shaderGroupHandleAlignment); + m_rgenRegion.stride = nvh::align_up(handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); + m_rgenRegion.size = m_rgenRegion.stride; // The size member of pRayGenShaderBindingTable must be equal to its stride member + m_missRegion.stride = handleSizeAligned; + m_missRegion.size = nvh::align_up(missCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); + m_hitRegion.stride = handleSizeAligned; + m_hitRegion.size = nvh::align_up(hitCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); + + // Get the shader group handles + uint32_t dataSize = handleCount * handleSize; + std::vector handles(dataSize); + auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, handleCount, dataSize, handles.data()); assert(result == VK_SUCCESS); - // Allocate a buffer for storing the SBT. Give it a debug name for NSight. - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, + // Allocate a buffer for storing the SBT. + VkDeviceSize sbtSize = m_rgenRegion.size + m_missRegion.size + m_hitRegion.size + m_callRegion.size; + m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); + m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); // Give it a debug name for NSight. + + // Find the SBT addresses of each group + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, nullptr, m_rtSBTBuffer.buffer}; + VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info); + m_rgenRegion.deviceAddress = sbtAddress; + m_missRegion.deviceAddress = sbtAddress + m_rgenRegion.size; + m_hitRegion.deviceAddress = sbtAddress + m_rgenRegion.size + m_missRegion.size; + + // Helper to retrieve the handle data + auto getHandle = [&](int i) { return handles.data() + i * handleSize; }; // Map the SBT buffer and write in the handles. - void* mapped = m_alloc.map(m_rtSBTBuffer); - auto* pData = reinterpret_cast(mapped); - for(uint32_t g = 0; g < groupCount; g++) + auto* pSBTBuffer = reinterpret_cast(m_alloc.map(m_rtSBTBuffer)); + uint8_t* pData{nullptr}; + uint32_t handleIdx{0}; + // Raygen + pData = pSBTBuffer; + memcpy(pData, getHandle(handleIdx++), handleSize); + // Miss + pData = pSBTBuffer + m_rgenRegion.size; + for(uint32_t c = 0; c < missCount; c++) { - memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); - pData += groupSizeAligned; + memcpy(pData, getHandle(handleIdx++), handleSize); + pData += m_missRegion.stride; } + // Hit + pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size; + for(uint32_t c = 0; c < hitCount; c++) + { + memcpy(pData, getHandle(handleIdx++), handleSize); + pData += m_hitRegion.stride; + } + m_alloc.unmap(m_rtSBTBuffer); m_alloc.finalizeAndReleaseStaging(); } @@ -1047,7 +1078,6 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c m_pcRay.lightIntensity = m_pcRaster.lightIntensity; m_pcRay.lightType = m_pcRaster.lightType; - std::vector descSets{m_rtDescSet, m_descSet}; vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, @@ -1057,21 +1087,7 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c 0, sizeof(PushConstantRay), &m_pcRay); - // Size of a program identifier - uint32_t groupSize = nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - uint32_t groupStride = groupSize; - - VkDeviceAddress sbtAddress = nvvk::getBufferDeviceAddress(m_device, m_rtSBTBuffer.buffer); - - using Stride = VkStridedDeviceAddressRegionKHR; - std::array strideAddresses{Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen - Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss - Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 2}, // hit - Stride{0u, 0u, 0u}}; // callable - - - vkCmdTraceRaysKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], &strideAddresses[2], &strideAddresses[3], - m_size.width, m_size.height, 1); + vkCmdTraceRaysKHR(cmdBuf, &m_rgenRegion, &m_missRegion, &m_hitRegion, &m_callRegion, m_size.width, m_size.height, 1); m_debug.endLabel(cmdBuf); diff --git a/ray_tracing_intersection/hello_vulkan.h b/ray_tracing_intersection/hello_vulkan.h index 971eb73..0182790 100644 --- a/ray_tracing_intersection/hello_vulkan.h +++ b/ray_tracing_intersection/hello_vulkan.h @@ -144,7 +144,12 @@ public: std::vector m_rtShaderGroups; VkPipelineLayout m_rtPipelineLayout; VkPipeline m_rtPipeline; - nvvk::Buffer m_rtSBTBuffer; + + nvvk::Buffer m_rtSBTBuffer; + VkStridedDeviceAddressRegionKHR m_rgenRegion{}; + VkStridedDeviceAddressRegionKHR m_missRegion{}; + VkStridedDeviceAddressRegionKHR m_hitRegion{}; + VkStridedDeviceAddressRegionKHR m_callRegion{}; // Push constant for ray tracer PushConstantRay m_pcRay{}; diff --git a/ray_tracing_jitter_cam/hello_vulkan.cpp b/ray_tracing_jitter_cam/hello_vulkan.cpp index 14ad2af..a8c6e2d 100644 --- a/ray_tracing_jitter_cam/hello_vulkan.cpp +++ b/ray_tracing_jitter_cam/hello_vulkan.cpp @@ -843,39 +843,70 @@ void HelloVulkan::createRtPipeline() // The Shader Binding Table (SBT) // - getting all shader handles and write them in a SBT buffer // - Besides exception, this could be always done like this -// See how the SBT buffer is used in run() // void HelloVulkan::createRtShaderBindingTable() { - auto groupCount = static_cast(m_rtShaderGroups.size()); // 4 shaders: raygen, 2 miss, chit - uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier - // Compute the actual size needed per SBT entry (round-up to alignment needed). - uint32_t groupSizeAligned = nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - // Bytes needed for the SBT. - uint32_t sbtSize = groupCount * groupSizeAligned; + uint32_t missCount{2}; + uint32_t hitCount{1}; + auto handleCount = 1 + missCount + hitCount; + uint32_t handleSize = m_rtProperties.shaderGroupHandleSize; - // Fetch all the shader handles used in the pipeline. This is opaque data,/ so we store it in a vector of bytes. - // The order of handles follow the stage entry. - std::vector shaderHandleStorage(sbtSize); - auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()); + // The SBT (buffer) need to have starting groups to be aligned and handles in the group to be aligned. + uint32_t handleSizeAligned = nvh::align_up(handleSize, m_rtProperties.shaderGroupHandleAlignment); + + m_rgenRegion.stride = nvh::align_up(handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); + m_rgenRegion.size = m_rgenRegion.stride; // The size member of pRayGenShaderBindingTable must be equal to its stride member + m_missRegion.stride = handleSizeAligned; + m_missRegion.size = nvh::align_up(missCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); + m_hitRegion.stride = handleSizeAligned; + m_hitRegion.size = nvh::align_up(hitCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); + // Get the shader group handles + uint32_t dataSize = handleCount * handleSize; + std::vector handles(dataSize); + auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, handleCount, dataSize, handles.data()); assert(result == VK_SUCCESS); - // Allocate a buffer for storing the SBT. Give it a debug name for NSight. - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, + // Allocate a buffer for storing the SBT. + VkDeviceSize sbtSize = m_rgenRegion.size + m_missRegion.size + m_hitRegion.size + m_callRegion.size; + m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); + m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); // Give it a debug name for NSight. + + // Find the SBT addresses of each group + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, nullptr, m_rtSBTBuffer.buffer}; + VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info); + m_rgenRegion.deviceAddress = sbtAddress; + m_missRegion.deviceAddress = sbtAddress + m_rgenRegion.size; + m_hitRegion.deviceAddress = sbtAddress + m_rgenRegion.size + m_missRegion.size; + + // Helper to retrieve the handle data + auto getHandle = [&](int i) { return handles.data() + i * handleSize; }; // Map the SBT buffer and write in the handles. - void* mapped = m_alloc.map(m_rtSBTBuffer); - auto* pData = reinterpret_cast(mapped); - for(uint32_t g = 0; g < groupCount; g++) + auto* pSBTBuffer = reinterpret_cast(m_alloc.map(m_rtSBTBuffer)); + uint8_t* pData{nullptr}; + uint32_t handleIdx{0}; + // Raygen + pData = pSBTBuffer; + memcpy(pData, getHandle(handleIdx++), handleSize); + // Miss + pData = pSBTBuffer + m_rgenRegion.size; + for(uint32_t c = 0; c < missCount; c++) { - memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); - pData += groupSizeAligned; + memcpy(pData, getHandle(handleIdx++), handleSize); + pData += m_missRegion.stride; } + // Hit + pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size; + for(uint32_t c = 0; c < hitCount; c++) + { + memcpy(pData, getHandle(handleIdx++), handleSize); + pData += m_hitRegion.stride; + } + m_alloc.unmap(m_rtSBTBuffer); m_alloc.finalizeAndReleaseStaging(); } @@ -906,21 +937,7 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c 0, sizeof(PushConstantRay), &m_pcRay); - // Size of a program identifier - uint32_t groupSize = nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - uint32_t groupStride = groupSize; - - VkDeviceAddress sbtAddress = nvvk::getBufferDeviceAddress(m_device, m_rtSBTBuffer.buffer); - - using Stride = VkStridedDeviceAddressRegionKHR; - std::array strideAddresses{Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen - Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss - Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit - Stride{0u, 0u, 0u}}; // callable - - - vkCmdTraceRaysKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], &strideAddresses[2], &strideAddresses[3], - m_size.width, m_size.height, 1); + vkCmdTraceRaysKHR(cmdBuf, &m_rgenRegion, &m_missRegion, &m_hitRegion, &m_callRegion, m_size.width, m_size.height, 1); m_debug.endLabel(cmdBuf); diff --git a/ray_tracing_jitter_cam/hello_vulkan.h b/ray_tracing_jitter_cam/hello_vulkan.h index e6c9ed6..a39a59c 100644 --- a/ray_tracing_jitter_cam/hello_vulkan.h +++ b/ray_tracing_jitter_cam/hello_vulkan.h @@ -145,8 +145,14 @@ public: std::vector m_rtShaderGroups; VkPipelineLayout m_rtPipelineLayout; VkPipeline m_rtPipeline; - nvvk::Buffer m_rtSBTBuffer; - int m_maxFrames{10}; + + nvvk::Buffer m_rtSBTBuffer; + VkStridedDeviceAddressRegionKHR m_rgenRegion{}; + VkStridedDeviceAddressRegionKHR m_missRegion{}; + VkStridedDeviceAddressRegionKHR m_hitRegion{}; + VkStridedDeviceAddressRegionKHR m_callRegion{}; + + int m_maxFrames{10}; // Push constant for ray tracer PushConstantRay m_pcRay{}; diff --git a/ray_tracing_manyhits/README.md b/ray_tracing_manyhits/README.md index dd12205..66e0c2b 100644 --- a/ray_tracing_manyhits/README.md +++ b/ray_tracing_manyhits/README.md @@ -133,16 +133,10 @@ This information can be used to pass extra information to a shader, for each ent **:warning: Note:** Since each entry in an SBT group must have the same size, each entry of the group has to have enough space to accommodate the largest element in the entire group. -The following diagram represents our current SBT, with the addition of some data to `HitGroup1`. As mentioned in the **note**, even if -`HitGroup0` doesn't have any shader record data, it still needs to have the same size as `HitGroup1`, the largest of the hit group. +The following diagram represents our current SBT, with some data added to `HitGroup1`. As mentioned in the **note**, even though `HitGroup0` has no shader record data, it still needs to be the same size as `HitGroup1`, the largest of the hit group and aligned to the Handle alignment. + +![](images/sbt_0.png) -|Group|Handle| -| ------ | ------ | -| RayGen | Handle 0 | -| Miss0 | Handle 1 | -| Miss1 | Handle 2 | -| HitGroup0 | Handle 3
-Empty- | -| HitGroup1 | Handle 4
Data 0 | ## `hello_vulkan.h` @@ -200,16 +194,9 @@ data `m_hitShaderRecord` to the Hit group. // Find handle indices and add data m_sbtWrapper.addIndices(rayPipelineInfo); m_sbtWrapper.addData(SBTWrapper::eHit, 1, m_hitShaderRecord[0]); - m_sbtWrapper.addData(SBTWrapper::eHit, 2, m_hitShaderRecord[1]); m_sbtWrapper.create(m_rtPipeline); ```` -The buffer for Hit will have the following layout - -``` -| handle | handle,data | handle,data | -``` - The wrapper will make sure the stride covers the largest data and is aligned based on the GPU properties. @@ -217,96 +204,27 @@ based on the GPU properties. ~~Since we are no longer compacting all handles in a continuous buffer, we need to fill the SBT as described above.~~ -~~After retrieving the handles of all 5 groups (raygen, miss, miss shadow, hit0, and hit1) -using `getRayTracingShaderGroupHandlesKHR`, store the pointers to easily retrieve them.~~ - ~~~~ C++ - // Retrieve the handle pointers - std::vector handles(groupCount); - for(uint32_t i = 0; i < groupCount; i++) - { - handles[i] = &shaderHandleStorage[i * groupHandleSize]; - } -~~~~ - -~~The size of each group can be described as follows:~~ - -~~~~ C++ - // Sizes - uint32_t rayGenSize = baseAlignment; - uint32_t missSize = baseAlignment; - uint32_t hitSize = - ROUND_UP(groupHandleSize + static_cast(sizeof(HitRecordBuffer)), baseAlignment); - uint32_t newSbtSize = rayGenSize + 2 * missSize + 2 * hitSize; + m_hitRegion.stride = nvh::align_up(handleSize + sizeof(HitRecordBuffer), m_rtProperties.shaderGroupHandleAlignment); ~~~~ ~~Then write the new SBT like this, where only Hit 1 has extra data.~~ ~~~~ C++ - std::vector sbtBuffer(newSbtSize); - { - uint8_t* pBuffer = sbtBuffer.data(); + // Hit + pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size; + memcpy(pData, getHandle(handleIdx++), handleSize); - memcpy(pBuffer, handles[0], groupHandleSize); // Raygen - pBuffer += rayGenSize; - memcpy(pBuffer, handles[1], groupHandleSize); // Miss 0 - pBuffer += missSize; - memcpy(pBuffer, handles[2], groupHandleSize); // Miss 1 - pBuffer += missSize; - - uint8_t* pHitBuffer = pBuffer; - memcpy(pHitBuffer, handles[3], groupHandleSize); // Hit 0 - // No data - pBuffer += hitSize; - - pHitBuffer = pBuffer; - memcpy(pHitBuffer, handles[4], groupHandleSize); // Hit 1 - pHitBuffer += groupHandleSize; - memcpy(pHitBuffer, &m_hitShaderRecord[0], sizeof(HitRecordBuffer)); // Hit 1 data - pBuffer += hitSize; - } + // hit 1 + pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size + m_hitRegion.stride; + memcpy(pData, getHandle(handleIdx++), handleSize); + pData += handleSize; + memcpy(pData, &m_hitShaderRecord[0], sizeof(HitRecordBuffer)); // Hit 1 data ~~~~ -~~Then change the call to `m_alloc.createBuffer` to create the SBT buffer from `sbtBuffer`:~~ +## Ray Trace -~~~~ C++ - m_rtSBTBuffer = m_alloc.createBuffer(cmdBuf, sbtBuffer, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR); -~~~~ - -### `raytrace` - -**:star:NEW:star:** - -The mvvk::SBTWrapper gives use the information without having to compute the `VkStridedDeviceAddressRegionKHR` - -``` C - auto& regions = m_sbtWrapper.getRegions(); - vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], m_size.width, m_size.height, 1); -``` - -**OLD** - -~~Finally, since the size of the hit group is now larger than just the handle, we need to set the new value of the hit group stride in `HelloVulkan::raytrace`.~~ - -~~~~ C++ - VkDeviceSize hitGroupSize = - nvh::align_up(m_rtProperties.shaderGroupHandleSize + sizeof(HitRecordBuffer), - m_rtProperties.shaderGroupBaseAlignment); -~~~~ - -~~The stride device address will be modified like this:~~ - -~~~~ C++ - using Stride = VkStridedDeviceAddressRegionKHR; - std::array strideAddresses{ - Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen - Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss - Stride{sbtAddress + 3u * groupSize, hitGroupSize, hitGroupSize * 3}, // hit - Stride{0u, 0u, 0u}}; // callable -~~~~ - -~~**Note:** - The result should now show both `wuson` models with a yellow color.~~ +The result should now show both `wuson` models with a yellow color.~~ ![](images/manyhits4.png) @@ -316,14 +234,8 @@ The SBT can be larger than the number of shading models, which could then be use The following modification will add another entry to the SBT with a different color per instance. The new SBT hit group (2) will use the same CHIT handle (4) as hit group 1. -|Group|Handle| -| ------ | ------ | -| RayGen | Handle 0 | -| Miss0 | Handle 1 | -| Miss1 | Handle 2 | -| HitGroup0 | Handle 3
-Empty- | -| HitGroup1 | Handle 4
Data 0 | -| HitGroup1 | Handle 4
Data 1 | +![](images/sbt_1.png) + ### `main.cpp` @@ -342,25 +254,24 @@ In the description of the scene in `main`, we will tell the `wuson` models to us **:star:NEW:star:** -If you are using the SBT wrapper, this part is automatically handled. +If you are using the SBT wrapper, make sure to add the data to the third Hit (2). + +~~~~ C + // Find handle indices and add data + m_sbtWrapper.addIndices(rayPipelineInfo); + m_sbtWrapper.addData(nvvk::SBTWrapper::eHit, 1, m_hitShaderRecord[0]); + m_sbtWrapper.addData(nvvk::SBTWrapper::eHit, 2, m_hitShaderRecord[1]); + m_sbtWrapper.create(m_rtPipeline); +~~~~ **OLD** - -~~The size of the SBT will now account for its 3 hit groups:~~ - ~~~~ C++ - uint32_t newSbtSize = rayGenSize + 2 * missSize + 3 * hitSize; -~~~~ - -~~Finally, we need to add the new entry as well at the end of the buffer, reusing the handle of the second Hit Group and setting a different color.~~ - -~~~~ C++ - pHitBuffer = pBuffer; - memcpy(pHitBuffer, handles[4], groupHandleSize); // Hit 2 - pHitBuffer += groupHandleSize; - memcpy(pHitBuffer, &m_hitShaderRecord[1], sizeof(HitRecordBuffer)); // Hit 2 data - pBuffer += hitSize; + // hit 2 + pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size + (2 * m_hitRegion.stride); + memcpy(pData, getHandle(handleIdx++), handleSize); + pData += handleSize; + memcpy(pData, &m_hitShaderRecord[1], sizeof(HitRecordBuffer)); // Hit 2 data ~~~~ ~~**Note:** diff --git a/ray_tracing_manyhits/hello_vulkan.cpp b/ray_tracing_manyhits/hello_vulkan.cpp index 075917f..3861e22 100644 --- a/ray_tracing_manyhits/hello_vulkan.cpp +++ b/ray_tracing_manyhits/hello_vulkan.cpp @@ -384,13 +384,16 @@ void HelloVulkan::destroyResources() // #VKRay +#ifdef USE_SBT_WRAPPER m_sbtWrapper.destroy(); +#else + m_alloc.destroy(m_rtSBTBuffer); +#endif m_rtBuilder.destroy(); vkDestroyPipeline(m_device, m_rtPipeline, nullptr); vkDestroyPipelineLayout(m_device, m_rtPipelineLayout, nullptr); vkDestroyDescriptorPool(m_device, m_rtDescPool, nullptr); vkDestroyDescriptorSetLayout(m_device, m_rtDescSetLayout, nullptr); - m_alloc.destroy(m_rtSBTBuffer); m_alloc.deinit(); } @@ -595,7 +598,9 @@ void HelloVulkan::initRayTracing() m_rtBuilder.setup(m_device, &m_alloc, m_graphicsQueueIndex); +#ifdef USE_SBT_WRAPPER m_sbtWrapper.setup(m_device, m_graphicsQueueIndex, &m_alloc, m_rtProperties); +#endif } //-------------------------------------------------------------------------------------------------- @@ -848,11 +853,15 @@ void HelloVulkan::createRtPipeline() vkCreateRayTracingPipelinesKHR(m_device, {}, {}, 1, &rayPipelineInfo, nullptr, &m_rtPipeline); +#ifdef USE_SBT_WRAPPER // Find handle indices and add data m_sbtWrapper.addIndices(rayPipelineInfo); - m_sbtWrapper.addData(SBTWrapper::eHit, 1, m_hitShaderRecord[0]); - m_sbtWrapper.addData(SBTWrapper::eHit, 2, m_hitShaderRecord[1]); + m_sbtWrapper.addData(nvvk::SBTWrapper::eHit, 1, m_hitShaderRecord[0]); + m_sbtWrapper.addData(nvvk::SBTWrapper::eHit, 2, m_hitShaderRecord[1]); m_sbtWrapper.create(m_rtPipeline); +#else + createRtShaderBindingTable(); +#endif for(auto& s : stages) vkDestroyShaderModule(m_device, s.module, nullptr); @@ -864,78 +873,84 @@ void HelloVulkan::createRtPipeline() // - Besides exception, this could be always done like this // See how the SBT buffer is used in run() // +#ifndef USE_SBT_WRAPPER void HelloVulkan::createRtShaderBindingTable() { - auto groupCount = static_cast(m_rtShaderGroups.size()); // 4 shaders: raygen, 2 miss, chit - uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier - // Compute the actual size needed per SBT entry (round-up to alignment needed). - uint32_t groupSizeAligned = nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - // Bytes needed for the SBT. - uint32_t sbtSize = groupCount * groupSizeAligned; - // Fetch all the shader handles used in the pipeline. This is opaque data,/ so we store it in a vector of bytes. - // The order of handles follow the stage entry. - std::vector shaderHandleStorage(sbtSize); - auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()); + uint32_t missCount{2}; + uint32_t hitCount{3}; + auto handleCount = 1 + missCount + hitCount; + uint32_t handleSize = m_rtProperties.shaderGroupHandleSize; + // Get the shader group handles + uint32_t dataSize = handleCount * handleSize; + std::vector handles(dataSize); + auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, handleCount, dataSize, handles.data()); assert(result == VK_SUCCESS); - // Retrieve the handle pointers - std::vector handles(groupCount); - for(uint32_t i = 0; i < groupCount; i++) + // The SBT (buffer) need to have starting groups to be aligned and handles in the group to be aligned. + uint32_t handleSizeAligned = nvh::align_up(handleSize, m_rtProperties.shaderGroupHandleAlignment); + + m_rgenRegion.stride = nvh::align_up(handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); + m_rgenRegion.size = m_rgenRegion.stride; // The size member of pRayGenShaderBindingTable must be equal to its stride member + m_missRegion.stride = handleSizeAligned; + m_missRegion.size = nvh::align_up(missCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); + m_hitRegion.stride = nvh::align_up(handleSize + sizeof(HitRecordBuffer), m_rtProperties.shaderGroupHandleAlignment); + m_hitRegion.size = nvh::align_up(hitCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); + + // Allocate a buffer for storing the SBT. + VkDeviceSize sbtSize = m_rgenRegion.size + m_missRegion.size + m_hitRegion.size + m_callRegion.size; + m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, + VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT + | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); // Give it a debug name for NSight. + + // Find the SBT addresses of each group + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, nullptr, m_rtSBTBuffer.buffer}; + VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info); + m_rgenRegion.deviceAddress = sbtAddress; + m_missRegion.deviceAddress = sbtAddress + m_rgenRegion.size; + m_hitRegion.deviceAddress = sbtAddress + m_rgenRegion.size + m_missRegion.size; + + // Helper to retrieve the handle data + auto getHandle = [&](int i) { return handles.data() + i * handleSize; }; + + // Map the SBT buffer and write in the handles. + auto* pSBTBuffer = reinterpret_cast(m_alloc.map(m_rtSBTBuffer)); + uint8_t* pData{nullptr}; + uint32_t handleIdx{0}; + // Raygen + pData = pSBTBuffer; + memcpy(pData, getHandle(handleIdx++), handleSize); + // Miss + pData = pSBTBuffer + m_rgenRegion.size; + for(uint32_t c = 0; c < missCount; c++) { - handles[i] = &shaderHandleStorage[i * groupHandleSize]; + memcpy(pData, getHandle(handleIdx++), handleSize); + pData += m_missRegion.stride; } + // Hit + pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size; + memcpy(pData, getHandle(handleIdx++), handleSize); - // Sizes - uint32_t rayGenSize = groupSizeAligned; - uint32_t missSize = groupSizeAligned; - uint32_t hitSize = nvh::align_up(groupHandleSize + static_cast(sizeof(HitRecordBuffer)), groupSizeAligned); - uint32_t newSbtSize = rayGenSize + 2 * missSize + 3 * hitSize; + // hit 1 + pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size + m_hitRegion.stride; + memcpy(pData, getHandle(handleIdx++), handleSize); + pData += handleSize; + memcpy(pData, &m_hitShaderRecord[0], sizeof(HitRecordBuffer)); // Hit 1 data - std::vector sbtBuffer(newSbtSize); - { - uint8_t* pBuffer = sbtBuffer.data(); - - memcpy(pBuffer, handles[0], groupHandleSize); // Raygen - pBuffer += rayGenSize; - memcpy(pBuffer, handles[1], groupHandleSize); // Miss 0 - pBuffer += missSize; - memcpy(pBuffer, handles[2], groupHandleSize); // Miss 1 - pBuffer += missSize; - - uint8_t* pHitBuffer = pBuffer; - memcpy(pHitBuffer, handles[3], groupHandleSize); // Hit 0 - // No data - pBuffer += hitSize; - - pHitBuffer = pBuffer; - memcpy(pHitBuffer, handles[4], groupHandleSize); // Hit 1 - pHitBuffer += groupHandleSize; - memcpy(pHitBuffer, &m_hitShaderRecord[0], sizeof(HitRecordBuffer)); // Hit 1 data - pBuffer += hitSize; - - pHitBuffer = pBuffer; - memcpy(pHitBuffer, handles[4], groupHandleSize); // Hit 2 - pHitBuffer += groupHandleSize; - memcpy(pHitBuffer, &m_hitShaderRecord[1], sizeof(HitRecordBuffer)); // Hit 2 data - // pBuffer += hitSize; - } - - // Write the handles in the SBT - nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); - VkCommandBuffer cmdBuf = genCmdBuf.createCommandBuffer(); - - m_rtSBTBuffer = m_alloc.createBuffer(cmdBuf, sbtBuffer, - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR); - - m_debug.setObjectName(m_rtSBTBuffer.buffer, "SBT"); + // hit 2 + pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size + (2 * m_hitRegion.stride); + memcpy(pData, getHandle(handleIdx++), handleSize); + pData += handleSize; + memcpy(pData, &m_hitShaderRecord[1], sizeof(HitRecordBuffer)); // Hit 2 data - genCmdBuf.submitAndWait(cmdBuf); - + m_alloc.unmap(m_rtSBTBuffer); m_alloc.finalizeAndReleaseStaging(); } +#endif //-------------------------------------------------------------------------------------------------- // Ray Tracing the scene @@ -959,39 +974,12 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c 0, sizeof(PushConstantRay), &m_pcRay); - //// Size of a program identifier - //uint32_t groupSize = - // nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - //uint32_t groupStride = groupSize; - //vk::DeviceSize hitGroupSize = - // nvh::align_up(m_rtProperties.shaderGroupHandleSize + sizeof(HitRecordBuffer), - // m_rtProperties.shaderGroupBaseAlignment); - //vk::DeviceAddress sbtAddress = m_device.getBufferAddress({m_rtSBTBuffer.buffer}); - - //using Stride = vk::StridedDeviceAddressRegionKHR; - //std::array strideAddresses{ - // Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen - // Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss - // Stride{sbtAddress + 3u * groupSize, hitGroupSize, hitGroupSize * 2}, // hit - // Stride{0u, 0u, 0u}}; // callable - - //strideAddresses[0] = m_sbtWrapper.getRaygenRegion(); - //strideAddresses[1] = m_sbtWrapper.getMissRegion(); - //strideAddresses[2] = m_sbtWrapper.getHitRegion(); - - //cmdBuf.traceRaysKHR(&strideAddresses[0], &strideAddresses[1], &strideAddresses[2], - // &strideAddresses[3], // - // m_size.width, m_size.height, 1); // - - //std::array regions; - //regions[0] = m_sbtWrapper.getRegion(SBTWrapper::eRaygen); - //regions[1] = m_sbtWrapper.getRegion(SBTWrapper::eMiss); - //regions[2] = m_sbtWrapper.getRegion(SBTWrapper::eHit); - //regions[3] = m_sbtWrapper.getRegion(SBTWrapper::eCallable); - +#ifdef USE_SBT_WRAPPER auto& regions = m_sbtWrapper.getRegions(); vkCmdTraceRaysKHR(cmdBuf, ®ions[0], ®ions[1], ®ions[2], ®ions[3], m_size.width, m_size.height, 1); - +#else + vkCmdTraceRaysKHR(cmdBuf, &m_rgenRegion, &m_missRegion, &m_hitRegion, &m_callRegion, m_size.width, m_size.height, 1); +#endif m_debug.endLabel(cmdBuf); } diff --git a/ray_tracing_manyhits/hello_vulkan.h b/ray_tracing_manyhits/hello_vulkan.h index f08da79..5d3fdba 100644 --- a/ray_tracing_manyhits/hello_vulkan.h +++ b/ray_tracing_manyhits/hello_vulkan.h @@ -28,8 +28,12 @@ // #VKRay #include "nvvk/raytraceKHR_vk.hpp" + + +#define USE_SBT_WRAPPER +#ifdef USE_SBT_WRAPPER #include "nvvk/sbtwrapper_vk.hpp" -using nvvk::SBTWrapper; +#endif //-------------------------------------------------------------------------------------------------- // Simple rasterizer of OBJ objects @@ -147,7 +151,16 @@ public: std::vector m_rtShaderGroups; VkPipelineLayout m_rtPipelineLayout; VkPipeline m_rtPipeline; - nvvk::Buffer m_rtSBTBuffer; + +#ifdef USE_SBT_WRAPPER + nvvk::SBTWrapper m_sbtWrapper; +#else + nvvk::Buffer m_rtSBTBuffer; + VkStridedDeviceAddressRegionKHR m_rgenRegion{}; + VkStridedDeviceAddressRegionKHR m_missRegion{}; + VkStridedDeviceAddressRegionKHR m_hitRegion{}; + VkStridedDeviceAddressRegionKHR m_callRegion{}; +#endif // Push constant for ray tracer PushConstantRay m_pcRay{}; @@ -157,6 +170,4 @@ public: nvmath::vec4f color; }; std::vector m_hitShaderRecord; - - nvvk::SBTWrapper m_sbtWrapper; }; diff --git a/ray_tracing_manyhits/images/sbt_0.png b/ray_tracing_manyhits/images/sbt_0.png new file mode 100644 index 0000000..0216305 Binary files /dev/null and b/ray_tracing_manyhits/images/sbt_0.png differ diff --git a/ray_tracing_manyhits/images/sbt_1.png b/ray_tracing_manyhits/images/sbt_1.png new file mode 100644 index 0000000..5a5ef47 Binary files /dev/null and b/ray_tracing_manyhits/images/sbt_1.png differ diff --git a/ray_tracing_reflections/hello_vulkan.cpp b/ray_tracing_reflections/hello_vulkan.cpp index 698aebb..1b48dc0 100644 --- a/ray_tracing_reflections/hello_vulkan.cpp +++ b/ray_tracing_reflections/hello_vulkan.cpp @@ -39,7 +39,6 @@ extern std::vector defaultSearchPaths; - //-------------------------------------------------------------------------------------------------- // Keep the handle on the device // Initialize the tool to do all our allocations: buffers, images @@ -683,8 +682,7 @@ void HelloVulkan::createTopLevelAS() // void HelloVulkan::createRtDescriptorSet() { - // Top-level acceleration structure, usable by both the ray generation and the closest hit (to - // shoot shadow rays) + // Top-level acceleration structure, usable by both the ray generation and the closest hit (to shoot shadow rays) m_rtDescSetLayoutBind.addBinding(RtxBindings::eTlas, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR); // TLAS m_rtDescSetLayoutBind.addBinding(RtxBindings::eOutImage, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, @@ -836,39 +834,70 @@ void HelloVulkan::createRtPipeline() // The Shader Binding Table (SBT) // - getting all shader handles and write them in a SBT buffer // - Besides exception, this could be always done like this -// See how the SBT buffer is used in run() // void HelloVulkan::createRtShaderBindingTable() { - auto groupCount = static_cast(m_rtShaderGroups.size()); // 4 shaders: raygen, 2 miss, chit - uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier - // Compute the actual size needed per SBT entry (round-up to alignment needed). - uint32_t groupSizeAligned = nvh::align_up(groupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - // Bytes needed for the SBT. - uint32_t sbtSize = groupCount * groupSizeAligned; + uint32_t missCount{2}; + uint32_t hitCount{1}; + auto handleCount = 1 + missCount + hitCount; + uint32_t handleSize = m_rtProperties.shaderGroupHandleSize; - // Fetch all the shader handles used in the pipeline. This is opaque data,/ so we store it in a vector of bytes. - // The order of handles follow the stage entry. - std::vector shaderHandleStorage(sbtSize); - auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()); + // The SBT (buffer) need to have starting groups to be aligned and handles in the group to be aligned. + uint32_t handleSizeAligned = nvh::align_up(handleSize, m_rtProperties.shaderGroupHandleAlignment); + + m_rgenRegion.stride = nvh::align_up(handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); + m_rgenRegion.size = m_rgenRegion.stride; // The size member of pRayGenShaderBindingTable must be equal to its stride member + m_missRegion.stride = handleSizeAligned; + m_missRegion.size = nvh::align_up(missCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); + m_hitRegion.stride = handleSizeAligned; + m_hitRegion.size = nvh::align_up(hitCount * handleSizeAligned, m_rtProperties.shaderGroupBaseAlignment); + // Get the shader group handles + uint32_t dataSize = handleCount * handleSize; + std::vector handles(dataSize); + auto result = vkGetRayTracingShaderGroupHandlesKHR(m_device, m_rtPipeline, 0, handleCount, dataSize, handles.data()); assert(result == VK_SUCCESS); - // Allocate a buffer for storing the SBT. Give it a debug name for NSight. - m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, + // Allocate a buffer for storing the SBT. + VkDeviceSize sbtSize = m_rgenRegion.size + m_missRegion.size + m_hitRegion.size + m_callRegion.size; + m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); + m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT")); // Give it a debug name for NSight. + + // Find the SBT addresses of each group + VkBufferDeviceAddressInfo info{VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, nullptr, m_rtSBTBuffer.buffer}; + VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(m_device, &info); + m_rgenRegion.deviceAddress = sbtAddress; + m_missRegion.deviceAddress = sbtAddress + m_rgenRegion.size; + m_hitRegion.deviceAddress = sbtAddress + m_rgenRegion.size + m_missRegion.size; + + // Helper to retrieve the handle data + auto getHandle = [&](int i) { return handles.data() + i * handleSize; }; // Map the SBT buffer and write in the handles. - void* mapped = m_alloc.map(m_rtSBTBuffer); - auto* pData = reinterpret_cast(mapped); - for(uint32_t g = 0; g < groupCount; g++) + auto* pSBTBuffer = reinterpret_cast(m_alloc.map(m_rtSBTBuffer)); + uint8_t* pData{nullptr}; + uint32_t handleIdx{0}; + // Raygen + pData = pSBTBuffer; + memcpy(pData, getHandle(handleIdx++), handleSize); + // Miss + pData = pSBTBuffer + m_rgenRegion.size; + for(uint32_t c = 0; c < missCount; c++) { - memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); - pData += groupSizeAligned; + memcpy(pData, getHandle(handleIdx++), handleSize); + pData += m_missRegion.stride; } + // Hit + pData = pSBTBuffer + m_rgenRegion.size + m_missRegion.size; + for(uint32_t c = 0; c < hitCount; c++) + { + memcpy(pData, getHandle(handleIdx++), handleSize); + pData += m_hitRegion.stride; + } + m_alloc.unmap(m_rtSBTBuffer); m_alloc.finalizeAndReleaseStaging(); } @@ -885,7 +914,6 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c m_pcRay.lightIntensity = m_pcRaster.lightIntensity; m_pcRay.lightType = m_pcRaster.lightType; - std::vector descSets{m_rtDescSet, m_descSet}; vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline); vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipelineLayout, 0, @@ -895,21 +923,7 @@ void HelloVulkan::raytrace(const VkCommandBuffer& cmdBuf, const nvmath::vec4f& c 0, sizeof(PushConstantRay), &m_pcRay); - // Size of a program identifier - uint32_t groupSize = nvh::align_up(m_rtProperties.shaderGroupHandleSize, m_rtProperties.shaderGroupBaseAlignment); - uint32_t groupStride = groupSize; - - VkDeviceAddress sbtAddress = nvvk::getBufferDeviceAddress(m_device, m_rtSBTBuffer.buffer); - - using Stride = VkStridedDeviceAddressRegionKHR; - std::array strideAddresses{Stride{sbtAddress + 0u * groupSize, groupStride, groupSize * 1}, // raygen - Stride{sbtAddress + 1u * groupSize, groupStride, groupSize * 2}, // miss - Stride{sbtAddress + 3u * groupSize, groupStride, groupSize * 1}, // hit - Stride{0u, 0u, 0u}}; // callable - - - vkCmdTraceRaysKHR(cmdBuf, &strideAddresses[0], &strideAddresses[1], &strideAddresses[2], &strideAddresses[3], - m_size.width, m_size.height, 1); + vkCmdTraceRaysKHR(cmdBuf, &m_rgenRegion, &m_missRegion, &m_hitRegion, &m_callRegion, m_size.width, m_size.height, 1); m_debug.endLabel(cmdBuf); diff --git a/ray_tracing_reflections/hello_vulkan.h b/ray_tracing_reflections/hello_vulkan.h index f1f70ef..d4c7f4f 100644 --- a/ray_tracing_reflections/hello_vulkan.h +++ b/ray_tracing_reflections/hello_vulkan.h @@ -144,7 +144,12 @@ public: std::vector m_rtShaderGroups; VkPipelineLayout m_rtPipelineLayout; VkPipeline m_rtPipeline; - nvvk::Buffer m_rtSBTBuffer; + + nvvk::Buffer m_rtSBTBuffer; + VkStridedDeviceAddressRegionKHR m_rgenRegion{}; + VkStridedDeviceAddressRegionKHR m_missRegion{}; + VkStridedDeviceAddressRegionKHR m_hitRegion{}; + VkStridedDeviceAddressRegionKHR m_callRegion{}; // Push constant for ray tracer PushConstantRay m_pcRay{{}, {}, 0, 0, 10};