diff --git a/src/common/rendering/vulkan/renderer/vk_raytrace.cpp b/src/common/rendering/vulkan/renderer/vk_raytrace.cpp index 36b14f3724..cb73c7466a 100644 --- a/src/common/rendering/vulkan/renderer/vk_raytrace.cpp +++ b/src/common/rendering/vulkan/renderer/vk_raytrace.cpp @@ -33,18 +33,37 @@ void VkRaytrace::SetLevelMesh(hwrenderer::LevelMesh* mesh) Mesh = mesh; if (Mesh) { - if (GetVulkanFrameBuffer()->device->SupportsDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME) && GetVulkanFrameBuffer()->device->SupportsDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME)) + if (GetVulkanFrameBuffer()->device->SupportsDeviceExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME)) { CreateVulkanObjects(); } - else - { - Printf("This vulkan device does not support ray tracing."); - } } } } +VulkanAccelerationStructure* VkRaytrace::GetAccelStruct() +{ + if (tlAccelStruct) + return tlAccelStruct.get(); + + // We need a dummy accel struct to keep vulkan happy: + hwrenderer::LevelMesh dummy; + dummy.MeshVertices.Push({ 0.0f, 0.0f, 0.0f }); + dummy.MeshVertices.Push({ 0.0f, 1.0f, 0.0f }); + dummy.MeshVertices.Push({ 1.0f, 0.0f, 0.0f }); + dummy.MeshUVIndex.Push(0); + dummy.MeshUVIndex.Push(1); + dummy.MeshUVIndex.Push(2); + dummy.MeshElements.Push(0); + dummy.MeshElements.Push(1); + dummy.MeshElements.Push(2); + dummy.MeshSurfaces.Push(0); + Mesh = &dummy; + CreateVulkanObjects(); + Mesh = nullptr; + return tlAccelStruct.get(); +} + void VkRaytrace::Reset() { vertexBuffer.reset(); @@ -73,8 +92,8 @@ void VkRaytrace::CreateVulkanObjects() //CreateDescriptorSet(); PipelineBarrier finishbuildbarrier; - finishbuildbarrier.addMemory(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR); - finishbuildbarrier.execute(GetVulkanFrameBuffer()->GetTransferCommands(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR); + finishbuildbarrier.addMemory(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_ACCESS_SHADER_READ_BIT); + finishbuildbarrier.execute(GetVulkanFrameBuffer()->GetTransferCommands(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); } void VkRaytrace::CreateVertexAndIndexBuffers() @@ -107,8 +126,8 @@ void VkRaytrace::CreateVertexAndIndexBuffers() memcpy(data + indexoffset, Mesh->MeshElements.Data(), indexbuffersize); transferBuffer->Unmap(); - GetVulkanFrameBuffer()->GetTransferCommands()->copyBuffer(transferBuffer.get(), vertexBuffer.get(), vertexoffset); - GetVulkanFrameBuffer()->GetTransferCommands()->copyBuffer(transferBuffer.get(), indexBuffer.get(), indexoffset); + GetVulkanFrameBuffer()->GetTransferCommands()->copyBuffer(transferBuffer.get(), vertexBuffer.get(), vertexoffset, 0, vertexbuffersize); + GetVulkanFrameBuffer()->GetTransferCommands()->copyBuffer(transferBuffer.get(), indexBuffer.get(), indexoffset, 0, indexbuffersize); VkMemoryBarrier barrier = { VK_STRUCTURE_TYPE_MEMORY_BARRIER }; barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; diff --git a/src/common/rendering/vulkan/renderer/vk_raytrace.h b/src/common/rendering/vulkan/renderer/vk_raytrace.h index 3236db8877..1976875cc2 100644 --- a/src/common/rendering/vulkan/renderer/vk_raytrace.h +++ b/src/common/rendering/vulkan/renderer/vk_raytrace.h @@ -9,6 +9,8 @@ class VkRaytrace public: void SetLevelMesh(hwrenderer::LevelMesh* mesh); + VulkanAccelerationStructure* GetAccelStruct(); + private: void Reset(); void CreateVulkanObjects(); diff --git a/src/common/rendering/vulkan/renderer/vk_renderpass.cpp b/src/common/rendering/vulkan/renderer/vk_renderpass.cpp index 711ed48ae0..0e5687ba01 100644 --- a/src/common/rendering/vulkan/renderer/vk_renderpass.cpp +++ b/src/common/rendering/vulkan/renderer/vk_renderpass.cpp @@ -23,6 +23,7 @@ #include "vk_renderpass.h" #include "vk_renderbuffers.h" #include "vk_renderstate.h" +#include "vk_raytrace.h" #include "vulkan/textures/vk_samplers.h" #include "vulkan/shaders/vk_shader.h" #include "vulkan/system/vk_builders.h" @@ -131,6 +132,8 @@ void VkRenderPassManager::CreateDynamicSetLayout() builder.addBinding(3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); builder.addBinding(4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); builder.addBinding(5, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + if (GetVulkanFrameBuffer()->device->SupportsDeviceExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME)) + builder.addBinding(6, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_FRAGMENT_BIT); DynamicSetLayout = builder.create(GetVulkanFrameBuffer()->device); DynamicSetLayout->SetDebugName("VkRenderPassManager.DynamicSetLayout"); } @@ -179,6 +182,8 @@ void VkRenderPassManager::CreateDescriptorPool() builder.addPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 3); builder.addPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1); builder.addPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2); + if (GetVulkanFrameBuffer()->device->SupportsDeviceExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME)) + builder.addPoolSize(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1); builder.setMaxSets(1); DynamicDescriptorPool = builder.create(GetVulkanFrameBuffer()->device); DynamicDescriptorPool->SetDebugName("VkRenderPassManager.DynamicDescriptorPool"); @@ -251,6 +256,8 @@ void VkRenderPassManager::UpdateDynamicSet() update.addBuffer(DynamicSet.get(), 3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->StreamBuffer->UniformBuffer->mBuffer.get(), 0, sizeof(StreamUBO)); update.addCombinedImageSampler(DynamicSet.get(), 4, fb->GetBuffers()->Shadowmap.View.get(), fb->GetBuffers()->ShadowmapSampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); update.addCombinedImageSampler(DynamicSet.get(), 5, fb->GetBuffers()->Lightmap.View.get(), fb->GetBuffers()->LightmapSampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + if (GetVulkanFrameBuffer()->device->SupportsDeviceExtension(VK_KHR_RAY_QUERY_EXTENSION_NAME)) + update.addAccelerationStructure(DynamicSet.get(), 6, fb->GetRaytrace()->GetAccelStruct()); update.updateSets(fb->device); } diff --git a/src/common/rendering/vulkan/shaders/vk_shader.cpp b/src/common/rendering/vulkan/shaders/vk_shader.cpp index dd8d442e3c..aaab9b6a93 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.cpp +++ b/src/common/rendering/vulkan/shaders/vk_shader.cpp @@ -216,6 +216,7 @@ static const char *shaderBindings = R"( layout(set = 0, binding = 4) uniform sampler2D ShadowMap; layout(set = 0, binding = 5) uniform sampler2DArray LightMap; + layout(set = 0, binding = 6) uniform accelerationStructureEXT TopLevelAS; // textures layout(set = 1, binding = 0) uniform sampler2D tex; @@ -337,6 +338,7 @@ std::unique_ptr VkShaderManager::LoadVertShader(FString shadername std::unique_ptr VkShaderManager::LoadFragShader(FString shadername, const char *frag_lump, const char *material_lump, const char *light_lump, const char *defines, bool alphatest, bool gbufferpass) { FString code = GetTargetGlslVersion(); + code << "\n#define SUPPORTS_RAYTRACING\n"; code << defines; code << "\n$placeholder$"; // here the code can later add more needed #defines. code << "\n#define MAX_STREAM_DATA " << std::to_string(MAX_STREAM_DATA).c_str() << "\n"; @@ -425,7 +427,17 @@ std::unique_ptr VkShaderManager::LoadFragShader(FString shadername FString VkShaderManager::GetTargetGlslVersion() { - return "#version 450 core\n"; + if (device->ApiVersion == VK_API_VERSION_1_2) + { + return R"(#version 460 + #extension GL_EXT_ray_tracing : enable + #extension GL_EXT_ray_query : enable + )"; + } + else + { + return "#version 450 core\n"; + } } FString VkShaderManager::LoadPublicShaderLump(const char *lumpname) diff --git a/src/common/rendering/vulkan/system/vk_builders.h b/src/common/rendering/vulkan/system/vk_builders.h index e30f91157b..326468ca3e 100644 --- a/src/common/rendering/vulkan/system/vk_builders.h +++ b/src/common/rendering/vulkan/system/vk_builders.h @@ -345,6 +345,7 @@ public: void addBuffer(VulkanDescriptorSet *descriptorSet, int binding, VkDescriptorType type, VulkanBuffer *buffer, size_t offset, size_t range); void addStorageImage(VulkanDescriptorSet *descriptorSet, int binding, VulkanImageView *view, VkImageLayout imageLayout); void addCombinedImageSampler(VulkanDescriptorSet *descriptorSet, int binding, VulkanImageView *view, VulkanSampler *sampler, VkImageLayout imageLayout); + void addAccelerationStructure(VulkanDescriptorSet* descriptorSet, int binding, VulkanAccelerationStructure* accelStruct); void updateSets(VulkanDevice *device); @@ -354,6 +355,7 @@ private: VkDescriptorImageInfo imageInfo; VkDescriptorBufferInfo bufferInfo; VkBufferView bufferView; + VkWriteDescriptorSetAccelerationStructureKHR accelStruct; }; std::vector writes; @@ -1384,6 +1386,26 @@ inline void WriteDescriptors::addCombinedImageSampler(VulkanDescriptorSet *descr writeExtras.push_back(std::move(extra)); } +inline void WriteDescriptors::addAccelerationStructure(VulkanDescriptorSet* descriptorSet, int binding, VulkanAccelerationStructure* accelStruct) +{ + auto extra = std::make_unique(); + extra->accelStruct = {}; + extra->accelStruct.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; + extra->accelStruct.accelerationStructureCount = 1; + extra->accelStruct.pAccelerationStructures = &accelStruct->accelstruct; + + VkWriteDescriptorSet descriptorWrite = {}; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.dstSet = descriptorSet->set; + descriptorWrite.dstBinding = binding; + descriptorWrite.dstArrayElement = 0; + descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR; + descriptorWrite.descriptorCount = 1; + descriptorWrite.pNext = &extra->accelStruct; + writes.push_back(descriptorWrite); + writeExtras.push_back(std::move(extra)); +} + inline void WriteDescriptors::updateSets(VulkanDevice *device) { vkUpdateDescriptorSets(device->device, (uint32_t)writes.size(), writes.data(), 0, nullptr); diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index 15af579a90..71a97e346a 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -341,10 +341,34 @@ float R_DoomLightingEquation(float light) //=========================================================================== // -// Check if light is in shadow according to its 1D shadow map +// Check if light is in shadow // //=========================================================================== +#ifdef SUPPORTS_RAYTRACING + +float shadowAttenuation(vec4 lightpos, float lightcolorA) +{ + vec3 origin = pixelpos.xyz; + vec3 direction = normalize(lightpos.xyz - pixelpos.xyz); + float lightDistance = distance(pixelpos.xyz, lightpos.xyz); + + rayQueryEXT rayQuery; + rayQueryInitializeEXT(rayQuery, TopLevelAS, gl_RayFlagsTerminateOnFirstHitEXT, 0xFF, origin, 0.01f, direction, lightDistance); + + while(rayQueryProceedEXT(rayQuery)) + { + } + + if (rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT) + { + return 0.0; + } + + return 1.0; +} + +#else #ifdef SUPPORTS_SHADOWMAPS float shadowDirToU(vec2 dir) @@ -488,6 +512,7 @@ float shadowAttenuation(vec4 lightpos, float lightcolorA) return 1.0; } +#endif #endif float spotLightAttenuation(vec4 lightpos, vec3 spotdir, float lightCosInnerAngle, float lightCosOuterAngle)