Hook up the acceleration structure to the shader and start shooting some rays!

This commit is contained in:
Magnus Norddahl 2022-06-06 01:52:56 +02:00 committed by Christoph Oelckers
parent e08965b0b3
commit 0c1aab074c
6 changed files with 98 additions and 11 deletions

View file

@ -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;

View file

@ -9,6 +9,8 @@ class VkRaytrace
public:
void SetLevelMesh(hwrenderer::LevelMesh* mesh);
VulkanAccelerationStructure* GetAccelStruct();
private:
void Reset();
void CreateVulkanObjects();

View file

@ -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);
}

View file

@ -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<VulkanShader> VkShaderManager::LoadVertShader(FString shadername
std::unique_ptr<VulkanShader> 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<VulkanShader> 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)

View file

@ -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<VkWriteDescriptorSet> 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<WriteExtra>();
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);

View file

@ -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)