.. _program_listing_file_Src_GraphicsEngineVulkan_renderer_Raytracing.cpp: Program Listing for File Raytracing.cpp ======================================= |exhale_lsh| :ref:`Return to documentation for file ` (``Src/GraphicsEngineVulkan/renderer/Raytracing.cpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #include "Raytracing.hpp" #include #include #include #include #include "common/MemoryHelper.hpp" #include "common/Utilities.hpp" #include "renderer/VulkanRendererConfig.hpp" #include "util/File.hpp" #include "vulkan_base/ShaderHelper.hpp" Kataglyphis::VulkanRendererInternals::Raytracing::Raytracing() {} void Kataglyphis::VulkanRendererInternals::Raytracing::init(VulkanDevice *device, const std::vector &descriptorSetLayouts) { this->device = device; createPCRange(); createGraphicsPipeline(descriptorSetLayouts); createSBT(); } void Kataglyphis::VulkanRendererInternals::Raytracing::shaderHotReload( const std::vector &descriptor_set_layouts) { vkDestroyPipeline(device->getLogicalDevice(), graphicsPipeline, nullptr); createGraphicsPipeline(descriptor_set_layouts); } void Kataglyphis::VulkanRendererInternals::Raytracing::recordCommands(VkCommandBuffer &commandBuffer, VulkanSwapChain *vulkanSwapChain, const std::vector &descriptorSets) { uint32_t handle_size = raytracing_properties.shaderGroupHandleSize; uint32_t handle_size_aligned = align_up(handle_size, raytracing_properties.shaderGroupHandleAlignment); PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR = reinterpret_cast( vkGetDeviceProcAddr(device->getLogicalDevice(), "vkGetBufferDeviceAddressKHR")); PFN_vkCmdTraceRaysKHR pvkCmdTraceRaysKHR = (PFN_vkCmdTraceRaysKHR)vkGetDeviceProcAddr(device->getLogicalDevice(), "vkCmdTraceRaysKHR"); VkBufferDeviceAddressInfoKHR bufferDeviceAI{}; bufferDeviceAI.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; bufferDeviceAI.buffer = raygenShaderBindingTableBuffer.getBuffer(); rgen_region.deviceAddress = vkGetBufferDeviceAddressKHR(device->getLogicalDevice(), &bufferDeviceAI); rgen_region.stride = handle_size_aligned; rgen_region.size = handle_size_aligned; bufferDeviceAI.buffer = missShaderBindingTableBuffer.getBuffer(); miss_region.deviceAddress = vkGetBufferDeviceAddressKHR(device->getLogicalDevice(), &bufferDeviceAI); miss_region.stride = handle_size_aligned; miss_region.size = handle_size_aligned; bufferDeviceAI.buffer = hitShaderBindingTableBuffer.getBuffer(); hit_region.deviceAddress = vkGetBufferDeviceAddressKHR(device->getLogicalDevice(), &bufferDeviceAI); hit_region.stride = handle_size_aligned; hit_region.size = handle_size_aligned; // for GCC doen't allow references on rvalues go like that ... pc.clear_color = { 0.2f, 0.65f, 0.4f, 1.0f }; // just "Push" constants to given shader stage directly (no buffer) vkCmdPushConstants(commandBuffer, pipeline_layout, VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, 0, sizeof(PushConstantRaytracing), &pc); vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, graphicsPipeline); vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline_layout, 0, static_cast(descriptorSets.size()), descriptorSets.data(), 0, nullptr); const VkExtent2D &swap_chain_extent = vulkanSwapChain->getSwapChainExtent(); pvkCmdTraceRaysKHR(commandBuffer, &rgen_region, &miss_region, &hit_region, &call_region, swap_chain_extent.width, swap_chain_extent.height, 1); } void Kataglyphis::VulkanRendererInternals::Raytracing::cleanUp() { shaderBindingTableBuffer.cleanUp(); raygenShaderBindingTableBuffer.cleanUp(); missShaderBindingTableBuffer.cleanUp(); hitShaderBindingTableBuffer.cleanUp(); vkDestroyPipeline(device->getLogicalDevice(), graphicsPipeline, nullptr); vkDestroyPipelineLayout(device->getLogicalDevice(), pipeline_layout, nullptr); } Kataglyphis::VulkanRendererInternals::Raytracing::~Raytracing() {} void Kataglyphis::VulkanRendererInternals::Raytracing::createPCRange() { // define push constant values (no 'create' needed) pc_ranges.stageFlags = VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR; pc_ranges.offset = 0; pc_ranges.size = sizeof(PushConstantRaytracing);// size of data being passed } void Kataglyphis::VulkanRendererInternals::Raytracing::createGraphicsPipeline( const std::vector &descriptorSetLayouts) { PFN_vkCreateRayTracingPipelinesKHR pvkCreateRayTracingPipelinesKHR = (PFN_vkCreateRayTracingPipelinesKHR)vkGetDeviceProcAddr( device->getLogicalDevice(), "vkCreateRayTracingPipelinesKHR"); std::stringstream raytracing_shader_dir; std::filesystem::path cwd = std::filesystem::current_path(); raytracing_shader_dir << cwd.string(); raytracing_shader_dir << RELATIVE_RESOURCE_PATH; raytracing_shader_dir << "Shaders/raytracing/"; std::string raygen_shader = "raytrace.rgen"; std::string chit_shader = "raytrace.rchit"; std::string miss_shader = "raytrace.rmiss"; std::string shadow_shader = "shadow.rmiss"; ShaderHelper shaderHelper; shaderHelper.compileShader(raytracing_shader_dir.str(), raygen_shader); shaderHelper.compileShader(raytracing_shader_dir.str(), chit_shader); shaderHelper.compileShader(raytracing_shader_dir.str(), miss_shader); shaderHelper.compileShader(raytracing_shader_dir.str(), shadow_shader); File raygenFile(shaderHelper.getShaderSpvDir(raytracing_shader_dir.str(), raygen_shader)); File raychitFile(shaderHelper.getShaderSpvDir(raytracing_shader_dir.str(), chit_shader)); File raymissFile(shaderHelper.getShaderSpvDir(raytracing_shader_dir.str(), miss_shader)); File shadowFile(shaderHelper.getShaderSpvDir(raytracing_shader_dir.str(), shadow_shader)); std::vector raygen_shader_code = raygenFile.readCharSequence(); std::vector raychit_shader_code = raychitFile.readCharSequence(); std::vector raymiss_shader_code = raymissFile.readCharSequence(); std::vector shadow_shader_code = shadowFile.readCharSequence(); // build shader modules to link to graphics pipeline VkShaderModule raygen_shader_module = shaderHelper.createShaderModule(device, raygen_shader_code); VkShaderModule raychit_shader_module = shaderHelper.createShaderModule(device, raychit_shader_code); VkShaderModule raymiss_shader_module = shaderHelper.createShaderModule(device, raymiss_shader_code); VkShaderModule shadow_shader_module = shaderHelper.createShaderModule(device, shadow_shader_code); // create all shader stage infos for creating a group VkPipelineShaderStageCreateInfo rgen_shader_stage_info{}; rgen_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; rgen_shader_stage_info.stage = VK_SHADER_STAGE_RAYGEN_BIT_KHR; rgen_shader_stage_info.module = raygen_shader_module; rgen_shader_stage_info.pName = "main"; VkPipelineShaderStageCreateInfo rmiss_shader_stage_info{}; rmiss_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; rmiss_shader_stage_info.stage = VK_SHADER_STAGE_MISS_BIT_KHR; rmiss_shader_stage_info.module = raymiss_shader_module; rmiss_shader_stage_info.pName = "main"; VkPipelineShaderStageCreateInfo shadow_shader_stage_info{}; shadow_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; shadow_shader_stage_info.stage = VK_SHADER_STAGE_MISS_BIT_KHR; shadow_shader_stage_info.module = shadow_shader_module; shadow_shader_stage_info.pName = "main"; VkPipelineShaderStageCreateInfo rchit_shader_stage_info{}; rchit_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; rchit_shader_stage_info.stage = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; rchit_shader_stage_info.module = raychit_shader_module; rchit_shader_stage_info.pName = "main"; // we have all shader stages together std::array shader_stages = { rgen_shader_stage_info, rmiss_shader_stage_info, shadow_shader_stage_info, rchit_shader_stage_info }; enum StageIndices { eRaygen, eMiss, eMiss2, eClosestHit, eShaderGroupCount }; shader_groups.reserve(4); VkRayTracingShaderGroupCreateInfoKHR shader_group_create_infos[4]; shader_group_create_infos[0].sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; shader_group_create_infos[0].pNext = nullptr; shader_group_create_infos[0].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; shader_group_create_infos[0].generalShader = eRaygen; shader_group_create_infos[0].closestHitShader = VK_SHADER_UNUSED_KHR; shader_group_create_infos[0].anyHitShader = VK_SHADER_UNUSED_KHR; shader_group_create_infos[0].intersectionShader = VK_SHADER_UNUSED_KHR; shader_group_create_infos[0].pShaderGroupCaptureReplayHandle = nullptr; shader_groups.push_back(shader_group_create_infos[0]); shader_group_create_infos[1].sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; shader_group_create_infos[1].pNext = nullptr; shader_group_create_infos[1].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; shader_group_create_infos[1].generalShader = eMiss; shader_group_create_infos[1].closestHitShader = VK_SHADER_UNUSED_KHR; shader_group_create_infos[1].anyHitShader = VK_SHADER_UNUSED_KHR; shader_group_create_infos[1].intersectionShader = VK_SHADER_UNUSED_KHR; shader_group_create_infos[1].pShaderGroupCaptureReplayHandle = nullptr; shader_groups.push_back(shader_group_create_infos[1]); shader_group_create_infos[2].sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; shader_group_create_infos[2].pNext = nullptr; shader_group_create_infos[2].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; shader_group_create_infos[2].generalShader = eMiss2; shader_group_create_infos[2].closestHitShader = VK_SHADER_UNUSED_KHR; shader_group_create_infos[2].anyHitShader = VK_SHADER_UNUSED_KHR; shader_group_create_infos[2].intersectionShader = VK_SHADER_UNUSED_KHR; shader_group_create_infos[2].pShaderGroupCaptureReplayHandle = nullptr; shader_groups.push_back(shader_group_create_infos[2]); shader_group_create_infos[3].sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; shader_group_create_infos[3].pNext = nullptr; shader_group_create_infos[3].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; shader_group_create_infos[3].generalShader = VK_SHADER_UNUSED_KHR; shader_group_create_infos[3].closestHitShader = eClosestHit; shader_group_create_infos[3].anyHitShader = VK_SHADER_UNUSED_KHR; shader_group_create_infos[3].intersectionShader = VK_SHADER_UNUSED_KHR; shader_group_create_infos[3].pShaderGroupCaptureReplayHandle = nullptr; shader_groups.push_back(shader_group_create_infos[3]); VkPipelineLayoutCreateInfo pipeline_layout_create_info{}; pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_create_info.setLayoutCount = static_cast(descriptorSetLayouts.size()); pipeline_layout_create_info.pSetLayouts = descriptorSetLayouts.data(); pipeline_layout_create_info.pushConstantRangeCount = 1; pipeline_layout_create_info.pPushConstantRanges = &pc_ranges; VkResult result = vkCreatePipelineLayout(device->getLogicalDevice(), &pipeline_layout_create_info, nullptr, &pipeline_layout); ASSERT_VULKAN(result, "Failed to create raytracing pipeline layout!") VkPipelineLibraryCreateInfoKHR pipeline_library_create_info{}; pipeline_library_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR; pipeline_library_create_info.pNext = nullptr; pipeline_library_create_info.libraryCount = 0; pipeline_library_create_info.pLibraries = nullptr; VkRayTracingPipelineCreateInfoKHR raytracing_pipeline_create_info{}; raytracing_pipeline_create_info.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR; raytracing_pipeline_create_info.pNext = nullptr; raytracing_pipeline_create_info.flags = 0; raytracing_pipeline_create_info.stageCount = static_cast(shader_stages.size()); raytracing_pipeline_create_info.pStages = shader_stages.data(); raytracing_pipeline_create_info.groupCount = static_cast(shader_groups.size()); raytracing_pipeline_create_info.pGroups = shader_groups.data(); /*raytracing_pipeline_create_info.pLibraryInfo = &pipeline_library_create_info; raytracing_pipeline_create_info.pLibraryInterface = NULL;*/ // TODO: HARDCODED FOR NOW; raytracing_pipeline_create_info.maxPipelineRayRecursionDepth = 2; raytracing_pipeline_create_info.layout = pipeline_layout; result = pvkCreateRayTracingPipelinesKHR(device->getLogicalDevice(), VK_NULL_HANDLE, VK_NULL_HANDLE, 1, &raytracing_pipeline_create_info, nullptr, &graphicsPipeline); ASSERT_VULKAN(result, "Failed to create raytracing pipeline!") vkDestroyShaderModule(device->getLogicalDevice(), raygen_shader_module, nullptr); vkDestroyShaderModule(device->getLogicalDevice(), raymiss_shader_module, nullptr); vkDestroyShaderModule(device->getLogicalDevice(), raychit_shader_module, nullptr); vkDestroyShaderModule(device->getLogicalDevice(), shadow_shader_module, nullptr); } void Kataglyphis::VulkanRendererInternals::Raytracing::createSBT() { // load in functionality for raytracing shader group handles PFN_vkGetRayTracingShaderGroupHandlesKHR pvkGetRayTracingShaderGroupHandlesKHR = (PFN_vkGetRayTracingShaderGroupHandlesKHR)vkGetDeviceProcAddr( device->getLogicalDevice(), "vkGetRayTracingShaderGroupHandlesKHR"); raytracing_properties = VkPhysicalDeviceRayTracingPipelinePropertiesKHR{}; raytracing_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR; VkPhysicalDeviceProperties2 properties{}; properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; properties.pNext = &raytracing_properties; vkGetPhysicalDeviceProperties2(device->getPhysicalDevice(), &properties); uint32_t handle_size = raytracing_properties.shaderGroupHandleSize; uint32_t handle_size_aligned = align_up(handle_size, raytracing_properties.shaderGroupHandleAlignment); uint32_t group_count = static_cast(shader_groups.size()); uint32_t sbt_size = group_count * handle_size_aligned; std::vector handles(sbt_size); VkResult result = pvkGetRayTracingShaderGroupHandlesKHR( device->getLogicalDevice(), graphicsPipeline, 0, group_count, sbt_size, handles.data()); ASSERT_VULKAN(result, "Failed to get ray tracing shader group handles!") const VkBufferUsageFlags bufferUsageFlags = VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; const VkMemoryPropertyFlags memoryUsageFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; raygenShaderBindingTableBuffer.create(device, handle_size, bufferUsageFlags, memoryUsageFlags); missShaderBindingTableBuffer.create(device, 2 * handle_size, bufferUsageFlags, memoryUsageFlags); hitShaderBindingTableBuffer.create(device, handle_size, bufferUsageFlags, memoryUsageFlags); void *mapped_raygen = nullptr; vkMapMemory(device->getLogicalDevice(), raygenShaderBindingTableBuffer.getBufferMemory(), 0, VK_WHOLE_SIZE, 0, &mapped_raygen); void *mapped_miss = nullptr; vkMapMemory( device->getLogicalDevice(), missShaderBindingTableBuffer.getBufferMemory(), 0, VK_WHOLE_SIZE, 0, &mapped_miss); void *mapped_rchit = nullptr; vkMapMemory( device->getLogicalDevice(), hitShaderBindingTableBuffer.getBufferMemory(), 0, VK_WHOLE_SIZE, 0, &mapped_rchit); memcpy(mapped_raygen, handles.data(), handle_size); memcpy(mapped_miss, handles.data() + handle_size_aligned, handle_size * 2); memcpy(mapped_rchit, handles.data() + handle_size_aligned * 3, handle_size); }