/* Crafter®.Graphics Copyright (C) 2026 Catcrafts® catcrafts.net This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3.0 as published by the Free Software Foundation; This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ module; #ifdef CRAFTER_GRAPHICS_RENDERER_VULKAN #include "vulkan/vulkan.h" #endif export module Crafter.Graphics:PipelineRTVulkan; #ifdef CRAFTER_GRAPHICS_RENDERER_VULKAN import std; import :Device; import :VulkanBuffer; import :ShaderBindingTableVulkan; import :Types; export namespace Crafter { struct PipelineRTVulkan { VkPipeline pipeline; std::vector shaderHandles; VulkanBuffer sbtBuffer; VkStridedDeviceAddressRegionKHR raygenRegion; VkStridedDeviceAddressRegionKHR missRegion; VkStridedDeviceAddressRegionKHR hitRegion; VkStridedDeviceAddressRegionKHR callableRegion; void Init(VkCommandBuffer cmd, std::span raygenGroups, std::span missGroups, std::span hitGroups, ShaderBindingTableVulkan& shaderTable) { std::vector groups; groups.reserve(raygenGroups.size() + missGroups.size() + hitGroups.size()); groups.insert(groups.end(), raygenGroups.begin(), raygenGroups.end()); groups.insert(groups.end(), missGroups.begin(), missGroups.end()); groups.insert(groups.end(), hitGroups.begin(), hitGroups.end()); VkPipelineCreateFlags2CreateInfo flags2 = { .sType = VK_STRUCTURE_TYPE_PIPELINE_CREATE_FLAGS_2_CREATE_INFO, .flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT }; VkRayTracingPipelineCreateInfoKHR rtPipelineInfo { .sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR, .pNext = &flags2, .flags = 0, .stageCount = static_cast(shaderTable.shaderStages.size()), .pStages = shaderTable.shaderStages.data(), .groupCount = static_cast(groups.size()), .pGroups = groups.data(), .maxPipelineRayRecursionDepth = 1, .layout = VK_NULL_HANDLE }; Device::CheckVkResult(Device::vkCreateRayTracingPipelinesKHR(Device::device, {}, {}, 1, &rtPipelineInfo, nullptr, &pipeline)); std::size_t dataSize = Device::rayTracingProperties.shaderGroupHandleSize * rtPipelineInfo.groupCount; shaderHandles.resize(dataSize); Device::CheckVkResult(Device::vkGetRayTracingShaderGroupHandlesKHR(Device::device, pipeline, 0, rtPipelineInfo.groupCount, dataSize, shaderHandles.data())); std::uint32_t sbtStride = AlignUp(Device::rayTracingProperties.shaderGroupHandleSize, Device::rayTracingProperties.shaderGroupHandleAlignment); raygenRegion.stride = sbtStride; raygenRegion.deviceAddress = 0; raygenRegion.size = raygenGroups.size() * sbtStride; missRegion.stride = sbtStride; missRegion.deviceAddress = AlignUp(raygenRegion.size, Device::rayTracingProperties.shaderGroupBaseAlignment); missRegion.size = missGroups.size() * sbtStride; hitRegion.stride = sbtStride; hitRegion.deviceAddress = AlignUp(missRegion.deviceAddress + missRegion.size, Device::rayTracingProperties.shaderGroupBaseAlignment); hitRegion.size = hitGroups.size() * sbtStride; std::size_t bufferSize = hitRegion.deviceAddress + hitRegion.size; sbtBuffer.Create(VK_BUFFER_USAGE_2_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, bufferSize); std::uint8_t* offset = sbtBuffer.value; std::uint8_t* handleOffset = shaderHandles.data(); std::memcpy(offset, handleOffset, raygenGroups.size() * Device::rayTracingProperties.shaderGroupHandleSize); offset += AlignUp(raygenRegion.size, Device::rayTracingProperties.shaderGroupBaseAlignment); handleOffset += raygenGroups.size() * Device::rayTracingProperties.shaderGroupHandleSize; std::memcpy(offset, handleOffset, missGroups.size() * Device::rayTracingProperties.shaderGroupHandleSize); offset += AlignUp(missRegion.size, Device::rayTracingProperties.shaderGroupBaseAlignment); handleOffset += missGroups.size() * Device::rayTracingProperties.shaderGroupHandleSize; std::memcpy(offset, handleOffset, hitGroups.size() * Device::rayTracingProperties.shaderGroupHandleSize); sbtBuffer.FlushDevice(cmd, VK_ACCESS_MEMORY_READ_BIT, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR); raygenRegion.deviceAddress += sbtBuffer.address; missRegion.deviceAddress += sbtBuffer.address; hitRegion.deviceAddress += sbtBuffer.address; callableRegion.deviceAddress = 0; callableRegion.stride = 0; callableRegion.size = 0; } }; } #endif