diff --git a/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp b/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp index 179ad44f7..4ec1e8faf 100644 --- a/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp +++ b/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp @@ -10,16 +10,14 @@ #include "filesystem.h" static int lastSurfaceCount; -static glcycle_t lightmapRaytrace; static glcycle_t lightmapRaytraceLast; static uint32_t lastPixelCount; -static uint32_t totalPixelCount; ADD_STAT(lightmapper) { FString out; - out.Format("last: %.3fms\ntotal: %3.fms\nLast batch surface count: %d\nLast batch pixel count: %u\nTotal pixel count: %u", lightmapRaytraceLast.TimeMS(), lightmapRaytrace.TimeMS(), lastSurfaceCount, lastPixelCount, totalPixelCount); + out.Format("CPU time: %.3fms\nSurface count: %d\nPixel count: %u K", lightmapRaytraceLast.TimeMS(), lastSurfaceCount, lastPixelCount / 1024); return out; } @@ -32,12 +30,14 @@ VkLightmap::VkLightmap(VulkanRenderDevice* fb) : fb(fb) useRayQuery = fb->GetDevice()->PhysicalDevice.Features.RayQuery.rayQuery; CreateUniformBuffer(); - CreateSceneLightBuffer(); + CreateLightBuffer(); + CreateTileBuffer(); CreateShaders(); CreateRaytracePipeline(); CreateResolvePipeline(); CreateBlurPipeline(); + CreateCopyPipeline(); CreateBakeImage(); } @@ -45,6 +45,8 @@ VkLightmap::~VkLightmap() { if (lights.Buffer) lights.Buffer->Unmap(); + if (copytiles.Buffer) + copytiles.Buffer->Unmap(); } void VkLightmap::SetLevelMesh(LevelMesh* level) @@ -52,9 +54,7 @@ void VkLightmap::SetLevelMesh(LevelMesh* level) mesh = level; UpdateAccelStructDescriptors(); - lightmapRaytrace.Reset(); lightmapRaytraceLast.Reset(); - totalPixelCount = 0; lastPixelCount = 0; lastSurfaceCount = 0; } @@ -69,10 +69,8 @@ void VkLightmap::Raytrace(const TArray& surfaces) { if (surfaces.Size()) { - lightmapRaytrace.active = true; lightmapRaytraceLast.active = true; - lightmapRaytrace.Clock(); lightmapRaytraceLast.ResetAndClock(); SelectSurfaces(surfaces); @@ -81,15 +79,14 @@ void VkLightmap::Raytrace(const TArray& surfaces) fb->GetCommands()->PushGroup(fb->GetCommands()->GetTransferCommands(), "lightmap.total"); UploadUniforms(); - RenderBakeImage(); - ResolveBakeImage(); - BlurBakeImage(); - CopyBakeImageResult(); + Render(); + Resolve(); + Blur(); + CopyResult(); fb->GetCommands()->PopGroup(fb->GetCommands()->GetTransferCommands()); } - lightmapRaytrace.Unclock(); lightmapRaytraceLast.Unclock(); } } @@ -128,7 +125,7 @@ void VkLightmap::SelectSurfaces(const TArray& surfaces) } } -void VkLightmap::RenderBakeImage() +void VkLightmap::Render() { auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); @@ -166,7 +163,7 @@ void VkLightmap::RenderBakeImage() continue; } - LightmapPushConstants pc; + LightmapRaytracePC pc; pc.TileX = (float)selectedSurface.X; pc.TileY = (float)selectedSurface.Y; pc.SurfaceIndex = mesh->GetSurfaceIndex(targetSurface); @@ -228,7 +225,7 @@ void VkLightmap::RenderBakeImage() pc.LightStart = surface->LightListPos; pc.LightEnd = pc.LightStart + lightCount; - cmdbuffer->pushConstants(raytrace.pipelineLayout.get(), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(LightmapPushConstants), &pc); + cmdbuffer->pushConstants(raytrace.pipelineLayout.get(), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(LightmapRaytracePC), &pc); cmdbuffer->drawIndexed(surface->numElements, 1, surface->startElementIndex, 0, 0); } @@ -268,7 +265,7 @@ void VkLightmap::UploadUniforms() .Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); } -void VkLightmap::ResolveBakeImage() +void VkLightmap::Resolve() { auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); @@ -300,7 +297,7 @@ void VkLightmap::ResolveBakeImage() fb->GetCommands()->PopGroup(cmdbuffer); } -void VkLightmap::BlurBakeImage() +void VkLightmap::Blur() { auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); @@ -361,63 +358,127 @@ void VkLightmap::BlurBakeImage() fb->GetCommands()->PopGroup(cmdbuffer); } -void VkLightmap::CopyBakeImageResult() +void VkLightmap::CopyResult() { + // Sort by destination uint32_t pixels = 0; lastSurfaceCount = 0; - std::set seenPages; - std::vector regions; + for (auto& list : copylists) list.Clear(); for (int i = 0, count = selectedSurfaces.Size(); i < count; i++) { auto& selected = selectedSurfaces[i]; if (selected.Rendered) { - LevelMeshSurface* surface = selected.Surface; - VkImageCopy region = {}; - region.srcOffset.x = selected.X; - region.srcOffset.y = selected.Y; - region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.srcSubresource.layerCount = 1; - region.dstOffset.x = surface->atlasX; - region.dstOffset.y = surface->atlasY; - region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.dstSubresource.layerCount = 1; - region.dstSubresource.baseArrayLayer = surface->atlasPageIndex; - region.extent.width = surface->texWidth; - region.extent.height = surface->texHeight; - region.extent.depth = 1; - regions.push_back(region); - seenPages.insert(surface->atlasPageIndex); + unsigned int pageIndex = (unsigned int)selected.Surface->atlasPageIndex; + if (pageIndex >= copylists.Size()) + { + copylists.Resize(pageIndex + 1); + } + copylists[pageIndex].Push(&selected); - pixels += surface->Area(); + pixels += selected.Surface->Area(); lastSurfaceCount++; } } - lastPixelCount = pixels; - totalPixelCount += pixels; - if (!regions.empty()) + if (pixels == 0) + return; + + VkTextureImage* destTexture = &fb->GetTextureManager()->Lightmap; + int destSize = fb->GetTextureManager()->LMTextureSize; + + auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); + + fb->GetCommands()->PushGroup(cmdbuffer, "lightmap.copy"); + + // Transition lightmap destination images to be used as framebuffers and the resolve image as sampling source + PipelineBarrier barrier0; + barrier0.AddImage(bakeImage.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); + for (unsigned int i = 0, count = copylists.Size(); i < count; i++) { - auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); - - fb->GetCommands()->PushGroup(cmdbuffer, "lightmap.copy"); - - PipelineBarrier barrier0; - barrier0.AddImage(bakeImage.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); - for (int pageIndex : seenPages) - barrier0.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, pageIndex, 1); - barrier0.Execute(cmdbuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - - cmdbuffer->copyImage(bakeImage.resolve.Image->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, fb->GetTextureManager()->Lightmap.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, (uint32_t)regions.size(), regions.data()); - - PipelineBarrier barrier1; - for (int pageIndex : seenPages) - barrier1.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, pageIndex, 1); - barrier1.Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - - fb->GetCommands()->PopGroup(cmdbuffer); + if (copylists[i].Size() > 0) + barrier0.AddImage(destTexture->Image.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, i, 1); } + barrier0.Execute(cmdbuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + + // Copy into the lightmap images + int start = 0; + int pos = 0; + for (unsigned int i = 0, count = copylists.Size(); i < count; i++) + { + auto& list = copylists[i]; + if (list.Size() == 0) + continue; + + // Create framebuffer object if it doesn't exist + if (i >= destTexture->LMFramebuffers.size()) + { + destTexture->LMFramebuffers.resize(i + 1); + } + + auto& framebuffer = destTexture->LMFramebuffers[i]; + if (!framebuffer) + { + framebuffer = FramebufferBuilder() + .RenderPass(copy.renderPass.get()) + .Size(destSize, destSize) + .AddAttachment(destTexture->View.get()) + .DebugName("LMFramebuffer") + .Create(fb->GetDevice()); + } + + // Copy the tile positions into a storage buffer for the vertex shader to read + start = pos; + for (SelectedSurface* selected : list) + { + LevelMeshSurface* surface = selected->Surface; + + CopyTileInfo* copyinfo = ©tiles.Tiles[pos++]; + copyinfo->SrcPosX = selected->X; + copyinfo->SrcPosY = selected->Y; + copyinfo->DestPosX = surface->atlasX; + copyinfo->DestPosY = surface->atlasY; + copyinfo->TileWidth = surface->texWidth; + copyinfo->TileHeight = surface->texHeight; + } + + // Draw the tiles. One instance per tile. + RenderPassBegin() + .RenderPass(copy.renderPass.get()) + .RenderArea(0, 0, destSize, destSize) + .Framebuffer(framebuffer.get()) + .Execute(cmdbuffer); + + cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, copy.pipeline.get()); + cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, copy.pipelineLayout.get(), 0, bakeImage.copy.DescriptorSet.get()); + + VkViewport viewport = {}; + viewport.maxDepth = 1; + viewport.width = (float)destSize; + viewport.height = (float)destSize; + cmdbuffer->setViewport(0, 1, &viewport); + + LightmapCopyPC pc; + pc.SrcTexSize = bakeImageSize; + pc.DestTexSize = destSize; + cmdbuffer->pushConstants(copy.pipelineLayout.get(), VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(LightmapCopyPC), &pc); + + cmdbuffer->draw(4, pos - start, 0, start); + + cmdbuffer->endRenderPass(); + } + + // Transition lightmap destination images back to be used for fragment shader sampling + PipelineBarrier barrier1; + for (unsigned int i = 0, count = copylists.Size(); i < count; i++) + { + if (copylists[i].Size() > 0) + barrier1.AddImage(destTexture->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, VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, i, 1); + } + barrier1.Execute(cmdbuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + + fb->GetCommands()->PopGroup(cmdbuffer); } FVector2 VkLightmap::ToUV(const FVector3& vert, const LevelMeshSurface* targetSurface) @@ -453,6 +514,13 @@ void VkLightmap::CreateShaders() .DebugName("VkLightmap.VertScreenquad") .Create("VkLightmap.VertScreenquad", fb->GetDevice()); + shaders.vertCopy = ShaderBuilder() + .Type(ShaderType::Vertex) + .AddSource("VersionBlock", prefix) + .AddSource("vert_copy.glsl", LoadPrivateShaderLump("shaders/lightmap/vert_copy.glsl").GetChars()) + .DebugName("VkLightmap.VertCopy") + .Create("VkLightmap.VertCopy", fb->GetDevice()); + shaders.fragRaytrace = ShaderBuilder() .Type(ShaderType::Fragment) .AddSource("VersionBlock", traceprefix) @@ -480,6 +548,13 @@ void VkLightmap::CreateShaders() .AddSource("frag_blur.glsl", LoadPrivateShaderLump("shaders/lightmap/frag_blur.glsl").GetChars()) .DebugName("VkLightmap.FragBlur") .Create("VkLightmap.FragBlur", fb->GetDevice()); + + shaders.fragCopy = ShaderBuilder() + .Type(ShaderType::Fragment) + .AddSource("VersionBlock", prefix) + .AddSource("frag_copy.glsl", LoadPrivateShaderLump("shaders/lightmap/frag_copy.glsl").GetChars()) + .DebugName("VkLightmap.FragCopy") + .Create("VkLightmap.FragCopy", fb->GetDevice()); } FString VkLightmap::LoadPrivateShaderLump(const char* lumpname) @@ -524,7 +599,7 @@ void VkLightmap::CreateRaytracePipeline() .AddSetLayout(raytrace.descriptorSetLayout0.get()) .AddSetLayout(raytrace.descriptorSetLayout1.get()) .AddSetLayout(fb->GetDescriptorSetManager()->GetBindlessSetLayout()) - .AddPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(LightmapPushConstants)) + .AddPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(LightmapRaytracePC)) .DebugName("raytrace.pipelineLayout") .Create(fb->GetDevice()); @@ -631,7 +706,6 @@ void VkLightmap::CreateResolvePipeline() resolve.pipelineLayout = PipelineLayoutBuilder() .AddSetLayout(resolve.descriptorSetLayout.get()) - .AddPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(LightmapPushConstants)) .DebugName("resolve.pipelineLayout") .Create(fb->GetDevice()); @@ -666,8 +740,8 @@ void VkLightmap::CreateResolvePipeline() .Create(fb->GetDevice()); resolve.descriptorPool = DescriptorPoolBuilder() - .AddPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 256) - .MaxSets(256) + .AddPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1) + .MaxSets(1) .DebugName("resolve.descriptorPool") .Create(fb->GetDevice()); @@ -685,7 +759,6 @@ void VkLightmap::CreateBlurPipeline() blur.pipelineLayout = PipelineLayoutBuilder() .AddSetLayout(blur.descriptorSetLayout.get()) - .AddPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(LightmapPushConstants)) .DebugName("blur.pipelineLayout") .Create(fb->GetDevice()); @@ -723,8 +796,8 @@ void VkLightmap::CreateBlurPipeline() } blur.descriptorPool = DescriptorPoolBuilder() - .AddPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 256) - .MaxSets(256) + .AddPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2) + .MaxSets(2) .DebugName("blur.descriptorPool") .Create(fb->GetDevice()); @@ -733,6 +806,61 @@ void VkLightmap::CreateBlurPipeline() .Create(fb->GetDevice()); } +void VkLightmap::CreateCopyPipeline() +{ + copy.descriptorSetLayout = DescriptorSetLayoutBuilder() + .AddBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT) + .AddBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT) + .DebugName("copy.descriptorSetLayout") + .Create(fb->GetDevice()); + + copy.pipelineLayout = PipelineLayoutBuilder() + .AddSetLayout(copy.descriptorSetLayout.get()) + .AddPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(LightmapCopyPC)) + .DebugName("copy.pipelineLayout") + .Create(fb->GetDevice()); + + copy.renderPass = RenderPassBuilder() + .AddAttachment( + VK_FORMAT_R16G16B16A16_SFLOAT, + VK_SAMPLE_COUNT_1_BIT, + VK_ATTACHMENT_LOAD_OP_LOAD, + VK_ATTACHMENT_STORE_OP_STORE, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + 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("copy.renderpass") + .Create(fb->GetDevice()); + + copy.pipeline = GraphicsPipelineBuilder() + .Layout(copy.pipelineLayout.get()) + .RenderPass(copy.renderPass.get()) + .AddVertexShader(shaders.vertCopy.get()) + .AddFragmentShader(shaders.fragCopy.get()) + .Topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP) + .AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT) + .Viewport(0.0f, 0.0f, 0.0f, 0.0f) + .Scissor(0, 0, 4096, 4096) + .DebugName("copy.pipeline") + .Create(fb->GetDevice()); + + copy.descriptorPool = DescriptorPoolBuilder() + .AddPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 256) + .MaxSets(256) + .DebugName("copy.descriptorPool") + .Create(fb->GetDevice()); + + copy.sampler = SamplerBuilder() + .DebugName("copy.Sampler") + .Create(fb->GetDevice()); +} + void VkLightmap::CreateBakeImage() { int width = bakeImageSize; @@ -806,10 +934,15 @@ void VkLightmap::CreateBakeImage() bakeImage.blur.DescriptorSet[1] = blur.descriptorPool->allocate(blur.descriptorSetLayout.get()); bakeImage.blur.DescriptorSet[1]->SetDebugName("blur.descriptorSet"); + bakeImage.copy.DescriptorSet = copy.descriptorPool->allocate(copy.descriptorSetLayout.get()); + bakeImage.copy.DescriptorSet->SetDebugName("copy.descriptorSet"); + WriteDescriptors() .AddCombinedImageSampler(bakeImage.resolve.DescriptorSet.get(), 0, bakeImage.raytrace.View.get(), resolve.sampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) .AddCombinedImageSampler(bakeImage.blur.DescriptorSet[0].get(), 0, bakeImage.resolve.View.get(), blur.sampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) .AddCombinedImageSampler(bakeImage.blur.DescriptorSet[1].get(), 0, bakeImage.blur.View.get(), blur.sampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + .AddCombinedImageSampler(bakeImage.copy.DescriptorSet.get(), 0, bakeImage.resolve.View.get(), blur.sampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + .AddBuffer(bakeImage.copy.DescriptorSet.get(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, copytiles.Buffer.get()) .Execute(fb->GetDevice()); } @@ -831,7 +964,7 @@ void VkLightmap::CreateUniformBuffer() .Create(fb->GetDevice()); } -void VkLightmap::CreateSceneLightBuffer() +void VkLightmap::CreateLightBuffer() { size_t size = sizeof(LightInfo) * lights.BufferSize; @@ -849,3 +982,21 @@ void VkLightmap::CreateSceneLightBuffer() lights.Lights = (LightInfo*)lights.Buffer->Map(0, size); lights.Pos = 0; } + +void VkLightmap::CreateTileBuffer() +{ + size_t size = sizeof(CopyTileInfo) * copytiles.BufferSize; + + copytiles.Buffer = BufferBuilder() + .Usage( + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + VMA_MEMORY_USAGE_UNKNOWN, VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT) + .MemoryType( + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) + .Size(size) + .DebugName("CopyTileBuffer") + .Create(fb->GetDevice()); + + copytiles.Tiles = (CopyTileInfo*)copytiles.Buffer->Map(0, size); +} diff --git a/src/common/rendering/vulkan/accelstructs/vk_lightmap.h b/src/common/rendering/vulkan/accelstructs/vk_lightmap.h index 5e5d7e25e..056ccd450 100644 --- a/src/common/rendering/vulkan/accelstructs/vk_lightmap.h +++ b/src/common/rendering/vulkan/accelstructs/vk_lightmap.h @@ -17,7 +17,7 @@ struct Uniforms float SunIntensity; }; -struct LightmapPushConstants +struct LightmapRaytracePC { uint32_t LightStart; uint32_t LightEnd; @@ -35,6 +35,14 @@ struct LightmapPushConstants float TileHeight; }; +struct LightmapCopyPC +{ + int SrcTexSize; + int DestTexSize; + int Padding1; + int Padding2; +}; + struct LightmapBakeImage { struct @@ -60,6 +68,11 @@ struct LightmapBakeImage std::unique_ptr DescriptorSet[2]; } blur; + struct + { + std::unique_ptr DescriptorSet; + } copy; + // how much of the image is used for the baking uint16_t maxX = 0; uint16_t maxY = 0; @@ -91,6 +104,20 @@ struct SelectedSurface static_assert(sizeof(LightInfo) == sizeof(float) * 20); +struct CopyTileInfo +{ + int SrcPosX; + int SrcPosY; + int DestPosX; + int DestPosY; + int TileWidth; + int TileHeight; + int Padding1; + int Padding2; +}; + +static_assert(sizeof(CopyTileInfo) == sizeof(int32_t) * 8); + class VkLightmap { public: @@ -104,10 +131,10 @@ public: private: void SelectSurfaces(const TArray& surfaces); void UploadUniforms(); - void RenderBakeImage(); - void ResolveBakeImage(); - void BlurBakeImage(); - void CopyBakeImageResult(); + void Render(); + void Resolve(); + void Blur(); + void CopyResult(); void UpdateAccelStructDescriptors(); @@ -115,8 +142,10 @@ private: void CreateRaytracePipeline(); void CreateResolvePipeline(); void CreateBlurPipeline(); + void CreateCopyPipeline(); void CreateUniformBuffer(); - void CreateSceneLightBuffer(); + void CreateLightBuffer(); + void CreateTileBuffer(); void CreateBakeImage(); static FVector2 ToUV(const FVector3& vert, const LevelMeshSurface* targetSurface); @@ -129,6 +158,7 @@ private: bool useRayQuery = true; TArray selectedSurfaces; + TArray> copylists; struct { @@ -150,13 +180,22 @@ private: int ResetCounter = 0; } lights; + struct + { + const int BufferSize = 100'000; + std::unique_ptr Buffer; + CopyTileInfo* Tiles = nullptr; + } copytiles; + struct { std::unique_ptr vertRaytrace; std::unique_ptr vertScreenquad; + std::unique_ptr vertCopy; std::unique_ptr fragRaytrace; std::unique_ptr fragResolve; std::unique_ptr fragBlur[2]; + std::unique_ptr fragCopy; } shaders; struct @@ -192,6 +231,16 @@ private: std::unique_ptr sampler; } blur; + struct + { + std::unique_ptr descriptorSetLayout; + std::unique_ptr pipelineLayout; + std::unique_ptr pipeline; + std::unique_ptr renderPass; + std::unique_ptr descriptorPool; + std::unique_ptr sampler; + } copy; + LightmapBakeImage bakeImage; static const int bakeImageSize = 2048; }; diff --git a/src/common/rendering/vulkan/textures/vk_imagetransition.h b/src/common/rendering/vulkan/textures/vk_imagetransition.h index 3dd78a48b..71a476dd3 100644 --- a/src/common/rendering/vulkan/textures/vk_imagetransition.h +++ b/src/common/rendering/vulkan/textures/vk_imagetransition.h @@ -19,6 +19,9 @@ public: for (auto &it : RSFramebuffers) deletelist->Add(std::move(it.second)); RSFramebuffers.clear(); + for (auto& framebuffer : LMFramebuffers) + deletelist->Add(std::move(framebuffer)); + LMFramebuffers.clear(); deletelist->Add(std::move(DepthOnlyView)); deletelist->Add(std::move(View)); deletelist->Add(std::move(Image)); @@ -33,6 +36,7 @@ public: VkImageAspectFlags AspectMask = VK_IMAGE_ASPECT_COLOR_BIT; std::unique_ptr PPFramebuffer; std::map> RSFramebuffers; + std::vector> LMFramebuffers; }; class VkImageTransition diff --git a/src/common/rendering/vulkan/textures/vk_texture.cpp b/src/common/rendering/vulkan/textures/vk_texture.cpp index d94c5c989..1554c472e 100644 --- a/src/common/rendering/vulkan/textures/vk_texture.cpp +++ b/src/common/rendering/vulkan/textures/vk_texture.cpp @@ -185,8 +185,7 @@ void VkTextureManager::CreateLightmap() data.Push(0); data.Push(0); data.Push(0); - data.Push(0x3c00); // half-float 1.0 - SetLightmap(1, 1, data); + CreateLightmap(1, 1, std::move(data)); } void VkTextureManager::CreateLightmap(int newLMTextureSize, int newLMTextureCount, TArray&& newPixelData) @@ -207,7 +206,7 @@ void VkTextureManager::CreateLightmap(int newLMTextureSize, int newLMTextureCoun Lightmap.Image = ImageBuilder() .Size(w, h, 1, count) .Format(VK_FORMAT_R16G16B16A16_SFLOAT) - .Usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT) + .Usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) .DebugName("VkRenderBuffers.Lightmap") .Create(fb->GetDevice()); @@ -264,66 +263,3 @@ void VkTextureManager::CreateLightmap(int newLMTextureSize, int newLMTextureCoun .AddImage(&Lightmap, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false, 0, count) .Execute(cmdbuffer); } - -void VkTextureManager::SetLightmap(int LMTextureSize, int LMTextureCount, const TArray& LMTextureData) -{ - int w = LMTextureSize; - int h = LMTextureSize; - int count = LMTextureCount; - int pixelsize = 8; - - Lightmap.Reset(fb); - - Lightmap.Image = ImageBuilder() - .Size(w, h, 1, count) - .Format(VK_FORMAT_R16G16B16A16_SFLOAT) - .Usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT) - .DebugName("VkRenderBuffers.Lightmap") - .Create(fb->GetDevice()); - - Lightmap.View = ImageViewBuilder() - .Type(VK_IMAGE_VIEW_TYPE_2D_ARRAY) - .Image(Lightmap.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT) - .DebugName("VkRenderBuffers.LightmapView") - .Create(fb->GetDevice()); - - auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); - - int totalSize = w * h * count * pixelsize; - - auto stagingBuffer = BufferBuilder() - .Size(totalSize) - .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) - .DebugName("VkHardwareTexture.mStagingBuffer") - .Create(fb->GetDevice()); - - uint16_t one = 0x3c00; // half-float 1.0 - const uint16_t* src = LMTextureData.Data(); - uint16_t* data = (uint16_t*)stagingBuffer->Map(0, totalSize); - for (int i = w * h * count; i > 0; i--) - { - *(data++) = *(src++); - *(data++) = *(src++); - *(data++) = *(src++); - *(data++) = one; - } - stagingBuffer->Unmap(); - - VkImageTransition() - .AddImage(&Lightmap, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true, 0, count) - .Execute(cmdbuffer); - - VkBufferImageCopy region = {}; - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.imageSubresource.layerCount = count; - region.imageExtent.depth = 1; - region.imageExtent.width = w; - region.imageExtent.height = h; - cmdbuffer->copyBufferToImage(stagingBuffer->buffer, Lightmap.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - - VkImageTransition() - .AddImage(&Lightmap, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false, 0, count) - .Execute(cmdbuffer); - - fb->GetCommands()->TransferDeleteList->Add(std::move(stagingBuffer)); -} diff --git a/src/common/rendering/vulkan/textures/vk_texture.h b/src/common/rendering/vulkan/textures/vk_texture.h index 530abc913..0376a909f 100644 --- a/src/common/rendering/vulkan/textures/vk_texture.h +++ b/src/common/rendering/vulkan/textures/vk_texture.h @@ -24,7 +24,6 @@ public: void BeginFrame(); void CreateLightmap(int newLMTextureSize, int newLMTextureCount, TArray&& newPixelData); - void SetLightmap(int LMTextureSize, int LMTextureCount, const TArray& LMTextureData); VkTextureImage* GetTexture(const PPTextureType& type, PPTexture* tex); VkFormat GetTextureFormat(PPTexture* texture); diff --git a/wadsrc/static/shaders/lightmap/frag_copy.glsl b/wadsrc/static/shaders/lightmap/frag_copy.glsl new file mode 100644 index 000000000..77f683bab --- /dev/null +++ b/wadsrc/static/shaders/lightmap/frag_copy.glsl @@ -0,0 +1,10 @@ + +layout(set = 0, binding = 0) uniform sampler2D Tex; + +layout(location = 0) in vec2 TexCoord; +layout(location = 0) out vec4 FragColor; + +void main() +{ + FragColor = texture(Tex, TexCoord); +} diff --git a/wadsrc/static/shaders/lightmap/frag_raytrace.glsl b/wadsrc/static/shaders/lightmap/frag_raytrace.glsl index e3c6cec97..ba0fdcfc7 100644 --- a/wadsrc/static/shaders/lightmap/frag_raytrace.glsl +++ b/wadsrc/static/shaders/lightmap/frag_raytrace.glsl @@ -127,7 +127,7 @@ void main() } #if defined(USE_RAYQUERY) // The non-rtx version of TraceFirstHitTriangle is too slow to do AO without the shader getting killed ;( - incoming.rgb *= TraceAmbientOcclusion(origin, normal); + //incoming.rgb *= TraceAmbientOcclusion(origin, normal); #endif fragcolor = vec4(incoming, 1.0); diff --git a/wadsrc/static/shaders/lightmap/vert_copy.glsl b/wadsrc/static/shaders/lightmap/vert_copy.glsl new file mode 100644 index 000000000..9e2643667 --- /dev/null +++ b/wadsrc/static/shaders/lightmap/vert_copy.glsl @@ -0,0 +1,41 @@ + +layout(push_constant) uniform PushConstants +{ + int SrcTexSize; + int DestTexSize; + int Padding1; + int Padding2; +}; + +struct TileCopy +{ + ivec2 SrcPos; + ivec2 DestPos; + ivec2 TileSize; + int Padding1, Padding2; +}; + +layout(std430, set = 0, binding = 1) buffer CopyBuffer +{ + TileCopy tiles[]; +}; + +layout(location = 0) out vec2 TexCoord; + +vec2 positions[4] = vec2[]( + vec2(0.0, 0.0), + vec2(1.0, 0.0), + vec2(0.0, 1.0), + vec2(1.0, 1.0) +); + +void main() +{ + TileCopy tile = tiles[gl_InstanceIndex]; + vec2 uv = positions[gl_VertexIndex]; + vec2 src = (vec2(tile.SrcPos) + uv * vec2(tile.TileSize)) / float(SrcTexSize); + vec2 dest = (vec2(tile.DestPos) + uv * vec2(tile.TileSize)) / float(DestTexSize); + + gl_Position = vec4(dest * 2.0 - 1.0, 0.0, 1.0); + TexCoord = src; +}