From 963161cce182a84e5f8f77406c75d477e3cce71c Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 5 Sep 2023 17:41:39 +0200 Subject: [PATCH] Add the 3x3 blur --- .../vulkan/accelstructs/vk_lightmap.cpp | 212 +++++++++++++++++- .../vulkan/accelstructs/vk_lightmap.h | 22 ++ 2 files changed, 232 insertions(+), 2 deletions(-) diff --git a/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp b/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp index 432046679..bfe50fab0 100644 --- a/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp +++ b/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp @@ -19,6 +19,7 @@ VkLightmap::VkLightmap(VulkanRenderDevice* fb) : fb(fb) CreateShaders(); CreateRaytracePipeline(); CreateResolvePipeline(); + CreateBlurPipeline(); } VkLightmap::~VkLightmap() @@ -50,6 +51,8 @@ void VkLightmap::Raytrace(LevelMesh* level) for (size_t pageIndex = 0; pageIndex < atlasImages.size(); pageIndex++) { ResolveAtlasImage(pageIndex); + BlurAtlasImage(pageIndex); + CopyAtlasImageResult(pageIndex); } } @@ -257,6 +260,108 @@ void VkLightmap::ResolveAtlasImage(size_t pageIndex) cmdbuffer->draw(vertexCount, 1, firstVertex, 0); cmdbuffer->endRenderPass(); +} + +void VkLightmap::BlurAtlasImage(size_t pageIndex) +{ + LightmapImage& img = atlasImages[pageIndex]; + + auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); + + PipelineBarrier() + .AddImage(img.resolve.Image.get(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT) + .Execute(cmdbuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + + // Pass 0 + { + RenderPassBegin() + .RenderPass(blur.renderPass.get()) + .RenderArea(0, 0, atlasImageSize, atlasImageSize) + .Framebuffer(img.blur.Framebuffer.get()) + .Execute(cmdbuffer); + + VkDeviceSize offset = 0; + cmdbuffer->bindVertexBuffers(0, 1, &vertices.Buffer->buffer, &offset); + cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, blur.pipeline[0].get()); + cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, blur.pipelineLayout.get(), 0, img.blur.DescriptorSet[0].get()); + + VkViewport viewport = {}; + viewport.maxDepth = 1; + viewport.width = (float)atlasImageSize; + viewport.height = (float)atlasImageSize; + cmdbuffer->setViewport(0, 1, &viewport); + + LightmapPushConstants pc; + pc.LightStart = 0; + pc.LightEnd = 0; + pc.SurfaceIndex = 0; + pc.LightmapOrigin = FVector3(0.0f, 0.0f, 0.0f); + pc.LightmapStepX = FVector3(0.0f, 0.0f, 0.0f); + pc.LightmapStepY = FVector3(0.0f, 0.0f, 0.0f); + cmdbuffer->pushConstants(blur.pipelineLayout.get(), VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(LightmapPushConstants), &pc); + + int firstVertex = vertices.Pos; + int vertexCount = 4; + vertices.Pos += vertexCount; + SceneVertex* vertex = &vertices.Vertices[firstVertex]; + vertex[0].Position = FVector2(0.0f, 0.0f); + vertex[1].Position = FVector2(1.0f, 0.0f); + vertex[2].Position = FVector2(1.0f, 1.0f); + vertex[3].Position = FVector2(0.0f, 1.0f); + cmdbuffer->draw(vertexCount, 1, firstVertex, 0); + + cmdbuffer->endRenderPass(); + } + + PipelineBarrier() + .AddImage(img.blur.Image.get(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT) + .Execute(cmdbuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + + // Pass 1 (outputs back into resolve fb) + { + RenderPassBegin() + .RenderPass(blur.renderPass.get()) + .RenderArea(0, 0, atlasImageSize, atlasImageSize) + .Framebuffer(img.resolve.Framebuffer.get()) + .Execute(cmdbuffer); + + VkDeviceSize offset = 0; + cmdbuffer->bindVertexBuffers(0, 1, &vertices.Buffer->buffer, &offset); + cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, blur.pipeline[1].get()); + cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, blur.pipelineLayout.get(), 0, img.blur.DescriptorSet[1].get()); + + VkViewport viewport = {}; + viewport.maxDepth = 1; + viewport.width = (float)atlasImageSize; + viewport.height = (float)atlasImageSize; + cmdbuffer->setViewport(0, 1, &viewport); + + LightmapPushConstants pc; + pc.LightStart = 0; + pc.LightEnd = 0; + pc.SurfaceIndex = 0; + pc.LightmapOrigin = FVector3(0.0f, 0.0f, 0.0f); + pc.LightmapStepX = FVector3(0.0f, 0.0f, 0.0f); + pc.LightmapStepY = FVector3(0.0f, 0.0f, 0.0f); + cmdbuffer->pushConstants(blur.pipelineLayout.get(), VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(LightmapPushConstants), &pc); + + int firstVertex = vertices.Pos; + int vertexCount = 4; + vertices.Pos += vertexCount; + SceneVertex* vertex = &vertices.Vertices[firstVertex]; + vertex[0].Position = FVector2(0.0f, 0.0f); + vertex[1].Position = FVector2(1.0f, 0.0f); + vertex[2].Position = FVector2(1.0f, 1.0f); + vertex[3].Position = FVector2(0.0f, 1.0f); + cmdbuffer->draw(vertexCount, 1, firstVertex, 0); + + cmdbuffer->endRenderPass(); + } +} + +void VkLightmap::CopyAtlasImageResult(size_t pageIndex) +{ + LightmapImage& img = atlasImages[pageIndex]; std::vector regions; for (int i = 0, count = mesh->GetSurfaceCount(); i < count; i++) @@ -283,6 +388,8 @@ void VkLightmap::ResolveAtlasImage(size_t pageIndex) if (!regions.empty()) { + auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); + PipelineBarrier() .AddImage(img.resolve.Image.get(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT) .AddImage(fb->GetTextureManager()->Lightmap.Image.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, (int)pageIndex, 1) @@ -292,7 +399,7 @@ void VkLightmap::ResolveAtlasImage(size_t pageIndex) PipelineBarrier() .AddImage(fb->GetTextureManager()->Lightmap.Image.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, (int)pageIndex, 1) - .Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + .Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); } } @@ -334,6 +441,20 @@ void VkLightmap::CreateShaders() .AddSource("frag_resolve.glsl", LoadPrivateShaderLump("shaders/lightmap/frag_resolve.glsl").GetChars()) .DebugName("VkLightmap.FragResolve") .Create("VkLightmap.FragResolve", fb->GetDevice()); + + shaders.fragBlur[0] = ShaderBuilder() + .Type(ShaderType::Fragment) + .AddSource("VersionBlock", prefix + "#define BLUR_HORIZONTAL\r\n") + .AddSource("frag_blur.glsl", LoadPrivateShaderLump("shaders/lightmap/frag_blur.glsl").GetChars()) + .DebugName("VkLightmap.FragBlur") + .Create("VkLightmap.FragBlur", fb->GetDevice()); + + shaders.fragBlur[1] = ShaderBuilder() + .Type(ShaderType::Fragment) + .AddSource("VersionBlock", prefix + "#define BLUR_VERTICAL\r\n") + .AddSource("frag_blur.glsl", LoadPrivateShaderLump("shaders/lightmap/frag_blur.glsl").GetChars()) + .DebugName("VkLightmap.FragBlur") + .Create("VkLightmap.FragBlur", fb->GetDevice()); } FString VkLightmap::LoadPrivateShaderLump(const char* lumpname) @@ -526,6 +647,65 @@ void VkLightmap::CreateResolvePipeline() .Create(fb->GetDevice()); } +void VkLightmap::CreateBlurPipeline() +{ + blur.descriptorSetLayout = DescriptorSetLayoutBuilder() + .AddBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT) + .DebugName("blur.descriptorSetLayout") + .Create(fb->GetDevice()); + + blur.pipelineLayout = PipelineLayoutBuilder() + .AddSetLayout(blur.descriptorSetLayout.get()) + .AddPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(LightmapPushConstants)) + .DebugName("blur.pipelineLayout") + .Create(fb->GetDevice()); + + blur.renderPass = RenderPassBuilder() + .AddAttachment( + VK_FORMAT_R16G16B16A16_SFLOAT, + VK_SAMPLE_COUNT_1_BIT, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_STORE, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + .AddSubpass() + .AddSubpassColorAttachmentRef(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + .AddExternalSubpassDependency( + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT) + .DebugName("blur.renderpass") + .Create(fb->GetDevice()); + + for (int i = 0; i < 2; i++) + { + blur.pipeline[i] = GraphicsPipelineBuilder() + .Layout(blur.pipelineLayout.get()) + .RenderPass(blur.renderPass.get()) + .AddVertexShader(shaders.vert.get()) + .AddFragmentShader(shaders.fragBlur[i].get()) + .AddVertexBufferBinding(0, sizeof(SceneVertex)) + .AddVertexAttribute(0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(SceneVertex, Position)) + .Topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) + .AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT) + .Viewport(0.0f, 0.0f, 0.0f, 0.0f) + .Scissor(0, 0, 4096, 4096) + .DebugName("blur.pipeline") + .Create(fb->GetDevice()); + } + + blur.descriptorPool = DescriptorPoolBuilder() + .AddPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 256) + .MaxSets(256) + .DebugName("blur.descriptorPool") + .Create(fb->GetDevice()); + + blur.sampler = SamplerBuilder() + .DebugName("blur.Sampler") + .Create(fb->GetDevice()); +} + LightmapImage VkLightmap::CreateImage(int width, int height) { LightmapImage img; @@ -551,7 +731,7 @@ LightmapImage VkLightmap::CreateImage(int width, int height) .Create(fb->GetDevice()); img.resolve.Image = ImageBuilder() - .Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT) + .Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT) .Format(VK_FORMAT_R16G16B16A16_SFLOAT) .Size(width, height) .DebugName("LightmapImage.resolve.Image") @@ -572,8 +752,36 @@ LightmapImage VkLightmap::CreateImage(int width, int height) img.resolve.DescriptorSet = resolve.descriptorPool->allocate(resolve.descriptorSetLayout.get()); img.resolve.DescriptorSet->SetDebugName("resolve.descriptorSet"); + + img.blur.Image = ImageBuilder() + .Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT) + .Format(VK_FORMAT_R16G16B16A16_SFLOAT) + .Size(width, height) + .DebugName("LightmapImage.blur.Image") + .Create(fb->GetDevice()); + + img.blur.View = ImageViewBuilder() + .Image(img.blur.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT) + .DebugName("LightmapImage.blur.View") + .Create(fb->GetDevice()); + + img.blur.Framebuffer = FramebufferBuilder() + .RenderPass(blur.renderPass.get()) + .Size(width, height) + .AddAttachment(img.blur.View.get()) + .DebugName("LightmapImage.blur.Framebuffer") + .Create(fb->GetDevice()); + + img.blur.DescriptorSet[0] = blur.descriptorPool->allocate(blur.descriptorSetLayout.get()); + img.blur.DescriptorSet[0]->SetDebugName("blur.descriptorSet"); + + img.blur.DescriptorSet[1] = blur.descriptorPool->allocate(blur.descriptorSetLayout.get()); + img.blur.DescriptorSet[1]->SetDebugName("blur.descriptorSet"); + WriteDescriptors() .AddCombinedImageSampler(img.resolve.DescriptorSet.get(), 0, img.raytrace.View.get(), resolve.sampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + .AddCombinedImageSampler(img.blur.DescriptorSet[0].get(), 0, img.resolve.View.get(), blur.sampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + .AddCombinedImageSampler(img.blur.DescriptorSet[1].get(), 0, img.blur.View.get(), blur.sampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) .Execute(fb->GetDevice()); return img; diff --git a/src/common/rendering/vulkan/accelstructs/vk_lightmap.h b/src/common/rendering/vulkan/accelstructs/vk_lightmap.h index 381a6fec2..d23f739b8 100644 --- a/src/common/rendering/vulkan/accelstructs/vk_lightmap.h +++ b/src/common/rendering/vulkan/accelstructs/vk_lightmap.h @@ -47,6 +47,14 @@ struct LightmapImage std::unique_ptr Framebuffer; std::unique_ptr DescriptorSet; } resolve; + + struct + { + std::unique_ptr Image; + std::unique_ptr View; + std::unique_ptr Framebuffer; + std::unique_ptr DescriptorSet[2]; + } blur; }; struct SceneVertex @@ -87,12 +95,15 @@ private: void CreateAtlasImages(); void RenderAtlasImage(size_t pageIndex); void ResolveAtlasImage(size_t pageIndex); + void BlurAtlasImage(size_t pageIndex); + void CopyAtlasImageResult(size_t pageIndex); LightmapImage CreateImage(int width, int height); void CreateShaders(); void CreateRaytracePipeline(); void CreateResolvePipeline(); + void CreateBlurPipeline(); void CreateUniformBuffer(); void CreateSceneVertexBuffer(); void CreateSceneLightBuffer(); @@ -138,6 +149,7 @@ private: std::unique_ptr vert; std::unique_ptr fragRaytrace; std::unique_ptr fragResolve; + std::unique_ptr fragBlur[2]; } shaders; struct @@ -163,6 +175,16 @@ private: std::unique_ptr sampler; } resolve; + struct + { + std::unique_ptr descriptorSetLayout; + std::unique_ptr pipelineLayout; + std::unique_ptr pipeline[2]; + std::unique_ptr renderPass; + std::unique_ptr descriptorPool; + std::unique_ptr sampler; + } blur; + std::vector atlasImages; static const int atlasImageSize = 2048; };