diff --git a/src/common/rendering/hwrenderer/data/hw_levelmesh.h b/src/common/rendering/hwrenderer/data/hw_levelmesh.h index 7824fae23f..bdd6cbb5d9 100644 --- a/src/common/rendering/hwrenderer/data/hw_levelmesh.h +++ b/src/common/rendering/hwrenderer/data/hw_levelmesh.h @@ -54,6 +54,7 @@ struct LevelMeshSurface int texHeight = 0; bool needsUpdate = true; + bool alreadyInVisibleList = false; // // Required for internal lightmapper: @@ -83,18 +84,8 @@ struct LevelMeshSurface // inline uint32_t Area() const { return texWidth * texHeight; } - // - // VkLightmap extra stuff that I dislike: - // - TArray verts; - // Touching light sources std::vector LightList; - - // Lightmapper has a lot of additional padding around the borders - int lightmapperAtlasPage = -1; - int lightmapperAtlasX = -1; - int lightmapperAtlasY = -1; }; inline float IsInFrontOfPlane(const FVector4& plane, const FVector3& point) diff --git a/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp b/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp index 7d3893e3b5..1c2a8ae476 100644 --- a/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp +++ b/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp @@ -39,6 +39,7 @@ VkLightmap::VkLightmap(VulkanRenderDevice* fb) : fb(fb) CreateRaytracePipeline(); CreateResolvePipeline(); CreateBlurPipeline(); + CreateBakeImage(); } VkLightmap::~VkLightmap() @@ -71,38 +72,14 @@ void VkLightmap::Raytrace(const TArray& surfaces) lightmapRaytrace.Clock(); lightmapRaytraceLast.ResetAndClock(); - CreateAtlasImages(surfaces); - - uint32_t pixels = 0; - - for (auto& surface : surfaces) + SelectSurfaces(surfaces); + if (selectedSurfaces.Size() > 0) { - surface->needsUpdate = false; // it may have been set to false already, but lightmapper ultimately decides so - pixels += surface->Area(); - } - - UploadUniforms(); - - lastSurfaceCount = surfaces.Size(); - lastPixelCount = pixels; - totalPixelCount += pixels; - - for (size_t pageIndex = 0; pageIndex < atlasImages.size(); pageIndex++) - { - if (atlasImages[pageIndex].pageMaxX && atlasImages[pageIndex].pageMaxY) - { - RenderAtlasImage(pageIndex, surfaces); - } - } - - for (size_t pageIndex = 0; pageIndex < atlasImages.size(); pageIndex++) - { - if (atlasImages[pageIndex].pageMaxX && atlasImages[pageIndex].pageMaxY) - { - ResolveAtlasImage(pageIndex); - BlurAtlasImage(pageIndex); - CopyAtlasImageResult(pageIndex, surfaces); - } + UploadUniforms(); + RenderBakeImage(); + ResolveBakeImage(); + BlurBakeImage(); + CopyBakeImageResult(); } lightmapRaytrace.Unclock(); @@ -110,45 +87,79 @@ void VkLightmap::Raytrace(const TArray& surfaces) } } -void VkLightmap::RenderAtlasImage(size_t pageIndex, const TArray& surfaces) +void VkLightmap::SelectSurfaces(const TArray& surfaces) { - LightmapImage& img = atlasImages[pageIndex]; + bakeImage.maxX = 0; + bakeImage.maxY = 0; + selectedSurfaces.Clear(); - // Begin with clear - { - auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); - - RenderPassBegin() - .RenderPass(raytrace.renderPassBegin.get()) - .RenderArea(0, 0, atlasImageSize, atlasImageSize) - .Framebuffer(img.raytrace.Framebuffer.get()) - .AddClearColor(0.0f, 0.0f, 0.0f, 0.0f) - .Execute(cmdbuffer); - - VkDeviceSize offset = 0; - cmdbuffer->bindVertexBuffers(0, 1, &vertices.Buffer->buffer, &offset); - cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipeline.get()); - cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipelineLayout.get(), 0, raytrace.descriptorSet0.get()); - cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipelineLayout.get(), 1, raytrace.descriptorSet1.get()); - } + const int spacing = 3; // Note: the spacing is here to avoid that the resolve sampler finds data from other surface tiles + RectPacker packer(bakeImageSize, bakeImageSize, RectPacker::Spacing(spacing)); for (int i = 0, count = surfaces.Size(); i < count; i++) { - LevelMeshSurface* targetSurface = surfaces[i]; - if (targetSurface->lightmapperAtlasPage != pageIndex) - continue; + LevelMeshSurface* surface = surfaces[i]; - if (targetSurface->LightList.empty() && (targetSurface->plane.XYZ() | mesh->SunDirection) < 0.0f) // No lights, no sun //TODO fill the area with black pixels skipping blur and resolve pass + // All surfaces needs to be updated until we rendered them. + surface->needsUpdate = true; + + // Only grab surfaces until our bake texture is full + auto result = packer.insert(surface->texWidth + 2, surface->texHeight + 2); + if (result.pageIndex == 0) + { + SelectedSurface selected; + selected.Surface = surface; + selected.X = result.pos.x + 1; + selected.Y = result.pos.y + 1; + selectedSurfaces.Push(selected); + + bakeImage.maxX = std::max(bakeImage.maxX, uint16_t(selected.X + surface->texWidth + spacing)); + bakeImage.maxY = std::max(bakeImage.maxY, uint16_t(selected.Y + surface->texHeight + spacing)); + } + } +} + +void VkLightmap::RenderBakeImage() +{ + auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); + + RenderPassBegin() + .RenderPass(raytrace.renderPass.get()) + .RenderArea(0, 0, bakeImageSize, bakeImageSize) + .Framebuffer(bakeImage.raytrace.Framebuffer.get()) + .AddClearColor(0.0f, 0.0f, 0.0f, 0.0f) + .Execute(cmdbuffer); + + VkDeviceSize offset = 0; + cmdbuffer->bindVertexBuffers(0, 1, &vertices.Buffer->buffer, &offset); + cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipeline.get()); + cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipelineLayout.get(), 0, raytrace.descriptorSet0.get()); + cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipelineLayout.get(), 1, raytrace.descriptorSet1.get()); + + lights.Pos = 0; + vertices.Pos = 0; + + for (int i = 0, count = selectedSurfaces.Size(); i < count; i++) + { + auto& selectedSurface = selectedSurfaces[i]; + LevelMeshSurface* targetSurface = selectedSurface.Surface; + + if (targetSurface->LightList.empty() && (targetSurface->plane.XYZ() | mesh->SunDirection) < 0.0f) // No lights, no sun + { + selectedSurface.Rendered = true; continue; + } VkViewport viewport = {}; viewport.maxDepth = 1; - viewport.x = (float)targetSurface->lightmapperAtlasX - 1; - viewport.y = (float)targetSurface->lightmapperAtlasY - 1; + viewport.x = (float)selectedSurface.X - 1; + viewport.y = (float)selectedSurface.Y - 1; viewport.width = (float)(targetSurface->texWidth + 2); viewport.height = (float)(targetSurface->texHeight + 2); fb->GetCommands()->GetTransferCommands()->setViewport(0, 1, &viewport); + bool buffersFull = false; + // Paint all surfaces part of the smoothing group into the surface for (LevelMeshSurface* surface : mesh->SmoothingGroups[targetSurface->smoothingGroupIndex].surfaces) { @@ -157,46 +168,18 @@ void VkLightmap::RenderAtlasImage(size_t pageIndex, const TArray 1.0f || minUV.Y > 1.0f)) continue; // Bounding box not visible - int firstLight = lights.Pos; - int firstVertex = vertices.Pos; int lightCount = (int)surface->LightList.size(); - int vertexCount = (int)surface->verts.Size(); + int vertexCount = surface->numVerts; + if (lights.Pos + lightCount > lights.BufferSize || vertices.Pos + vertexCount > vertices.BufferSize) { - // Flush scene buffers - fb->GetCommands()->GetTransferCommands()->endRenderPass(); - fb->GetCommands()->WaitForCommands(false); - lights.Pos = 0; - vertices.Pos = 0; - firstLight = 0; - firstVertex = 0; - - // Begin without clear - auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); - - RenderPassBegin() - .RenderPass(raytrace.renderPassContinue.get()) - .RenderArea(0, 0, atlasImageSize, atlasImageSize) - .Framebuffer(img.raytrace.Framebuffer.get()) - .Execute(cmdbuffer); - - VkDeviceSize offset = 0; - cmdbuffer->bindVertexBuffers(0, 1, &vertices.Buffer->buffer, &offset); - cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipeline.get()); - cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipelineLayout.get(), 0, raytrace.descriptorSet0.get()); - cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipelineLayout.get(), 1, raytrace.descriptorSet1.get()); - - cmdbuffer->setViewport(0, 1, &viewport); - - if (lights.Pos + lightCount > lights.BufferSize) - { - throw std::runtime_error("SceneLightBuffer is too small!"); - } - else if (vertices.Pos + vertexCount > vertices.BufferSize) - { - throw std::runtime_error("SceneVertexBuffer is too small!"); - } + // Our vertex or light buffer is full. Postpone the rest. + buffersFull = true; + break; } + + int firstLight = lights.Pos; + int firstVertex = vertices.Pos; lights.Pos += lightCount; vertices.Pos += vertexCount; @@ -229,57 +212,29 @@ void VkLightmap::RenderAtlasImage(size_t pageIndex, const TArrayPosition = ToUV(surface->verts[idx], targetSurface); + (vertex++)->Position = ToUV(mesh->MeshVertices[surface->startVertIndex + idx], targetSurface); } } else { - (vertex++)->Position = ToUV(surface->verts[0], targetSurface); - (vertex++)->Position = ToUV(surface->verts[2], targetSurface); - (vertex++)->Position = ToUV(surface->verts[3], targetSurface); - (vertex++)->Position = ToUV(surface->verts[1], targetSurface); + (vertex++)->Position = ToUV(mesh->MeshVertices[surface->startVertIndex + 0], targetSurface); + (vertex++)->Position = ToUV(mesh->MeshVertices[surface->startVertIndex + 2], targetSurface); + (vertex++)->Position = ToUV(mesh->MeshVertices[surface->startVertIndex + 3], targetSurface); + (vertex++)->Position = ToUV(mesh->MeshVertices[surface->startVertIndex + 1], targetSurface); } fb->GetCommands()->GetTransferCommands()->draw(vertexCount, 1, firstVertex, 0); } + + if (buffersFull) + break; + + selectedSurface.Rendered = true; } fb->GetCommands()->GetTransferCommands()->endRenderPass(); } -void VkLightmap::CreateAtlasImages(const TArray& surfaces) -{ - for (auto& page : atlasImages) - { - page.pageMaxX = 0; - page.pageMaxY = 0; - } - - const int spacing = 3; // Note: the spacing is here to avoid that the resolve sampler finds data from other surface tiles - RectPacker packer(atlasImageSize, atlasImageSize, RectPacker::Spacing(spacing)); - - size_t pageIndex = atlasImages.size(); - - for (int i = 0, count = surfaces.Size(); i < count; i++) - { - LevelMeshSurface* surface = surfaces[i]; - - auto result = packer.insert(surface->texWidth + 2, surface->texHeight + 2); - surface->lightmapperAtlasX = result.pos.x + 1; - surface->lightmapperAtlasY = result.pos.y + 1; - surface->lightmapperAtlasPage = (int)result.pageIndex; - - for (;pageIndex <= result.pageIndex; pageIndex++) - { - atlasImages.push_back(CreateImage(atlasImageSize, atlasImageSize)); - } - - auto& image = atlasImages[result.pageIndex]; - image.pageMaxX = std::max(image.pageMaxX, uint16_t(surface->lightmapperAtlasX + surface->texWidth + spacing)); - image.pageMaxY = std::max(image.pageMaxY, uint16_t(surface->lightmapperAtlasY + surface->texHeight + spacing)); - } -} - void VkLightmap::UploadUniforms() { Uniforms values = {}; @@ -298,31 +253,29 @@ void VkLightmap::UploadUniforms() .Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); } -void VkLightmap::ResolveAtlasImage(size_t pageIndex) +void VkLightmap::ResolveBakeImage() { - LightmapImage& img = atlasImages[pageIndex]; - auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); PipelineBarrier() - .AddImage(img.raytrace.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) + .AddImage(bakeImage.raytrace.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); RenderPassBegin() .RenderPass(resolve.renderPass.get()) - .RenderArea(0, 0, img.pageMaxX, img.pageMaxY) - .Framebuffer(img.resolve.Framebuffer.get()) + .RenderArea(0, 0, bakeImage.maxX, bakeImage.maxY) + .Framebuffer(bakeImage.resolve.Framebuffer.get()) .Execute(cmdbuffer); VkDeviceSize offset = 0; cmdbuffer->bindVertexBuffers(0, 1, &vertices.Buffer->buffer, &offset); cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, resolve.pipeline.get()); - cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, resolve.pipelineLayout.get(), 0, img.resolve.DescriptorSet.get()); + cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, resolve.pipelineLayout.get(), 0, bakeImage.resolve.DescriptorSet.get()); VkViewport viewport = {}; viewport.maxDepth = 1; - viewport.width = (float)img.pageMaxX; - viewport.height = (float)img.pageMaxY; + viewport.width = (float)bakeImage.maxX; + viewport.height = (float)bakeImage.maxY; cmdbuffer->setViewport(0, 1, &viewport); LightmapPushConstants pc; @@ -347,33 +300,31 @@ void VkLightmap::ResolveAtlasImage(size_t pageIndex) cmdbuffer->endRenderPass(); } -void VkLightmap::BlurAtlasImage(size_t pageIndex) +void VkLightmap::BlurBakeImage() { - 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) + .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) .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, img.pageMaxX, img.pageMaxY) - .Framebuffer(img.blur.Framebuffer.get()) + .RenderArea(0, 0, bakeImage.maxX, bakeImage.maxY) + .Framebuffer(bakeImage.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()); + cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, blur.pipelineLayout.get(), 0, bakeImage.blur.DescriptorSet[0].get()); VkViewport viewport = {}; viewport.maxDepth = 1; - viewport.width = (float)img.pageMaxX; - viewport.height = (float)img.pageMaxY; + viewport.width = (float)bakeImage.maxX; + viewport.height = (float)bakeImage.maxY; cmdbuffer->setViewport(0, 1, &viewport); LightmapPushConstants pc; @@ -399,26 +350,26 @@ void VkLightmap::BlurAtlasImage(size_t pageIndex) } 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) + .AddImage(bakeImage.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, img.pageMaxX, img.pageMaxY) - .Framebuffer(img.resolve.Framebuffer.get()) + .RenderArea(0, 0, bakeImage.maxX, bakeImage.maxY) + .Framebuffer(bakeImage.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()); + cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, blur.pipelineLayout.get(), 0, bakeImage.blur.DescriptorSet[1].get()); VkViewport viewport = {}; viewport.maxDepth = 1; - viewport.width = (float)img.pageMaxX; - viewport.height = (float)img.pageMaxY; + viewport.width = (float)bakeImage.maxX; + viewport.height = (float)bakeImage.maxY; cmdbuffer->setViewport(0, 1, &viewport); LightmapPushConstants pc; @@ -444,47 +395,61 @@ void VkLightmap::BlurAtlasImage(size_t pageIndex) } } -void VkLightmap::CopyAtlasImageResult(size_t pageIndex, const TArray& surfaces) +void VkLightmap::CopyBakeImageResult() { - LightmapImage& img = atlasImages[pageIndex]; + uint32_t pixels = 0; + std::set seenPages; std::vector regions; - for (int i = 0, count = surfaces.Size(); i < count; i++) + for (int i = 0, count = selectedSurfaces.Size(); i < count; i++) { - LevelMeshSurface* surface = surfaces[i]; - if (surface->lightmapperAtlasPage != pageIndex) - continue; + 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); - VkImageCopy region = {}; - region.srcOffset.x = surface->lightmapperAtlasX; - region.srcOffset.y = surface->lightmapperAtlasY; - 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); + // We rendered this surface. Does not need an update anymore. + surface->needsUpdate = false; + + pixels += surface->Area(); + lastSurfaceCount++; + } } + lastPixelCount = pixels; + totalPixelCount += pixels; + 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) - .Execute(cmdbuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + 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(img.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()); + 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() - .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(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + 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); } } @@ -584,7 +549,7 @@ void VkLightmap::CreateRaytracePipeline() .DebugName("raytrace.pipelineLayout") .Create(fb->GetDevice()); - raytrace.renderPassBegin = RenderPassBuilder() + raytrace.renderPass = RenderPassBuilder() .AddAttachment( VK_FORMAT_R16G16B16A16_SFLOAT, VK_SAMPLE_COUNT_4_BIT, @@ -599,30 +564,12 @@ void VkLightmap::CreateRaytracePipeline() VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT) - .DebugName("raytrace.renderPassBegin") - .Create(fb->GetDevice()); - - raytrace.renderPassContinue = RenderPassBuilder() - .AddAttachment( - VK_FORMAT_R16G16B16A16_SFLOAT, - VK_SAMPLE_COUNT_4_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("raytrace.renderPassContinue") + .DebugName("raytrace.renderPass") .Create(fb->GetDevice()); raytrace.pipeline = GraphicsPipelineBuilder() .Layout(raytrace.pipelineLayout.get()) - .RenderPass(raytrace.renderPassBegin.get()) + .RenderPass(raytrace.renderPass.get()) .AddVertexShader(shaders.vert.get()) .AddFragmentShader(shaders.fragRaytrace.get()) .AddVertexBufferBinding(0, sizeof(SceneVertex)) @@ -808,11 +755,12 @@ void VkLightmap::CreateBlurPipeline() .Create(fb->GetDevice()); } -LightmapImage VkLightmap::CreateImage(int width, int height) +void VkLightmap::CreateBakeImage() { - LightmapImage img; + int width = bakeImageSize; + int height = bakeImageSize; - img.raytrace.Image = ImageBuilder() + bakeImage.raytrace.Image = ImageBuilder() .Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT) .Format(VK_FORMAT_R16G16B16A16_SFLOAT) .Size(width, height) @@ -820,73 +768,71 @@ LightmapImage VkLightmap::CreateImage(int width, int height) .DebugName("LightmapImage.raytrace.Image") .Create(fb->GetDevice()); - img.raytrace.View = ImageViewBuilder() - .Image(img.raytrace.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT) + bakeImage.raytrace.View = ImageViewBuilder() + .Image(bakeImage.raytrace.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT) .DebugName("LightmapImage.raytrace.View") .Create(fb->GetDevice()); - img.raytrace.Framebuffer = FramebufferBuilder() - .RenderPass(raytrace.renderPassBegin.get()) + bakeImage.raytrace.Framebuffer = FramebufferBuilder() + .RenderPass(raytrace.renderPass.get()) .Size(width, height) - .AddAttachment(img.raytrace.View.get()) + .AddAttachment(bakeImage.raytrace.View.get()) .DebugName("LightmapImage.raytrace.Framebuffer") .Create(fb->GetDevice()); - img.resolve.Image = ImageBuilder() + bakeImage.resolve.Image = ImageBuilder() .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") .Create(fb->GetDevice()); - img.resolve.View = ImageViewBuilder() - .Image(img.resolve.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT) + bakeImage.resolve.View = ImageViewBuilder() + .Image(bakeImage.resolve.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT) .DebugName("LightmapImage.resolve.View") .Create(fb->GetDevice()); - img.resolve.Framebuffer = FramebufferBuilder() + bakeImage.resolve.Framebuffer = FramebufferBuilder() .RenderPass(resolve.renderPass.get()) .Size(width, height) - .AddAttachment(img.resolve.View.get()) + .AddAttachment(bakeImage.resolve.View.get()) .DebugName("LightmapImage.resolve.Framebuffer") .Create(fb->GetDevice()); - img.resolve.DescriptorSet = resolve.descriptorPool->allocate(resolve.descriptorSetLayout.get()); - img.resolve.DescriptorSet->SetDebugName("resolve.descriptorSet"); + bakeImage.resolve.DescriptorSet = resolve.descriptorPool->allocate(resolve.descriptorSetLayout.get()); + bakeImage.resolve.DescriptorSet->SetDebugName("resolve.descriptorSet"); - img.blur.Image = ImageBuilder() + bakeImage.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) + bakeImage.blur.View = ImageViewBuilder() + .Image(bakeImage.blur.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT) .DebugName("LightmapImage.blur.View") .Create(fb->GetDevice()); - img.blur.Framebuffer = FramebufferBuilder() + bakeImage.blur.Framebuffer = FramebufferBuilder() .RenderPass(blur.renderPass.get()) .Size(width, height) - .AddAttachment(img.blur.View.get()) + .AddAttachment(bakeImage.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"); + bakeImage.blur.DescriptorSet[0] = blur.descriptorPool->allocate(blur.descriptorSetLayout.get()); + bakeImage.blur.DescriptorSet[0]->SetDebugName("blur.descriptorSet"); - img.blur.DescriptorSet[1] = blur.descriptorPool->allocate(blur.descriptorSetLayout.get()); - img.blur.DescriptorSet[1]->SetDebugName("blur.descriptorSet"); + bakeImage.blur.DescriptorSet[1] = blur.descriptorPool->allocate(blur.descriptorSetLayout.get()); + bakeImage.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) + .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) .Execute(fb->GetDevice()); - - return img; } void VkLightmap::CreateUniformBuffer() diff --git a/src/common/rendering/vulkan/accelstructs/vk_lightmap.h b/src/common/rendering/vulkan/accelstructs/vk_lightmap.h index 49f169f6f4..33262b39e8 100644 --- a/src/common/rendering/vulkan/accelstructs/vk_lightmap.h +++ b/src/common/rendering/vulkan/accelstructs/vk_lightmap.h @@ -31,7 +31,7 @@ struct LightmapPushConstants float PushPadding4; }; -struct LightmapImage +struct LightmapBakeImage { struct { @@ -56,9 +56,9 @@ struct LightmapImage std::unique_ptr DescriptorSet[2]; } blur; - // how much of the page is used? - uint16_t pageMaxX = 0; - uint16_t pageMaxY = 0; + // how much of the image is used for the baking + uint16_t maxX = 0; + uint16_t maxY = 0; }; struct SceneVertex @@ -82,6 +82,14 @@ struct LightInfo float Padding3; }; +struct SelectedSurface +{ + LevelMeshSurface* Surface = nullptr; + int X = -1; + int Y = -1; + bool Rendered = false; +}; + static_assert(sizeof(LightInfo) == sizeof(float) * 20); class VkLightmap @@ -92,17 +100,16 @@ public: void Raytrace(const TArray& surfaces); void SetLevelMesh(LevelMesh* level); + private: - void UpdateAccelStructDescriptors(); - + void SelectSurfaces(const TArray& surfaces); void UploadUniforms(); - void CreateAtlasImages(const TArray& surfaces); - void RenderAtlasImage(size_t pageIndex, const TArray& surfaces); - void ResolveAtlasImage(size_t pageIndex); - void BlurAtlasImage(size_t pageIndex); - void CopyAtlasImageResult(size_t pageIndex, const TArray& surfaces); + void RenderBakeImage(); + void ResolveBakeImage(); + void BlurBakeImage(); + void CopyBakeImageResult(); - LightmapImage CreateImage(int width, int height); + void UpdateAccelStructDescriptors(); void CreateShaders(); void CreateRaytracePipeline(); @@ -111,6 +118,7 @@ private: void CreateUniformBuffer(); void CreateSceneVertexBuffer(); void CreateSceneLightBuffer(); + void CreateBakeImage(); static FVector2 ToUV(const FVector3& vert, const LevelMeshSurface* targetSurface); @@ -121,6 +129,8 @@ private: bool useRayQuery = true; + TArray selectedSurfaces; + struct { std::unique_ptr Buffer; @@ -162,8 +172,7 @@ private: std::unique_ptr descriptorSetLayout1; std::unique_ptr pipelineLayout; std::unique_ptr pipeline; - std::unique_ptr renderPassBegin; - std::unique_ptr renderPassContinue; + std::unique_ptr renderPass; std::unique_ptr descriptorPool0; std::unique_ptr descriptorPool1; std::unique_ptr descriptorSet0; @@ -190,6 +199,6 @@ private: std::unique_ptr sampler; } blur; - std::vector atlasImages; - static const int atlasImageSize = 2048; + LightmapBakeImage bakeImage; + static const int bakeImageSize = 2048; }; diff --git a/src/common/rendering/vulkan/textures/vk_texture.cpp b/src/common/rendering/vulkan/textures/vk_texture.cpp index d16f720051..d94c5c989e 100644 --- a/src/common/rendering/vulkan/textures/vk_texture.cpp +++ b/src/common/rendering/vulkan/textures/vk_texture.cpp @@ -221,7 +221,7 @@ void VkTextureManager::CreateLightmap(int newLMTextureSize, int newLMTextureCoun if (newPixelData.Size() >= (size_t)w * h * count * 3) { - assert(newPixelData.Size() == w * h * count * 3); + assert(newPixelData.Size() == (size_t)w * h * count * 3); int totalSize = w * h * count * pixelsize; diff --git a/src/common/rendering/vulkan/vk_renderdevice.cpp b/src/common/rendering/vulkan/vk_renderdevice.cpp index b15e0550eb..869ec0a44c 100644 --- a/src/common/rendering/vulkan/vk_renderdevice.cpp +++ b/src/common/rendering/vulkan/vk_renderdevice.cpp @@ -476,17 +476,6 @@ void VulkanRenderDevice::BeginFrame() levelMesh->UpdateLightLists(); GetTextureManager()->CreateLightmap(levelMesh->LMTextureSize, levelMesh->LMTextureCount, std::move(levelMesh->LMTextureData)); GetLightmap()->SetLevelMesh(levelMesh); - -#if 0 // full lightmap generation - TArray surfaces; - surfaces.Reserve(mesh->GetSurfaceCount()); - for (unsigned i = 0, count = mesh->GetSurfaceCount(); i < count; ++i) - { - surfaces[i] = mesh->GetSurface(i); - } - - GetLightmap()->Raytrace(surfaces); -#endif } } diff --git a/src/rendering/hwrenderer/doom_levelmesh.cpp b/src/rendering/hwrenderer/doom_levelmesh.cpp index f1a7a667fb..61c84970fb 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelmesh.cpp @@ -1079,15 +1079,6 @@ void DoomLevelMesh::SetupLightmapUvs() sortedSurfaces.push_back(&surface); } - // VkLightmapper old ZDRay properties - for (auto& surface : Surfaces) - { - for (int i = 0; i < surface.numVerts; ++i) - { - surface.verts.Push(MeshVertices[surface.startVertIndex + i]); - } - } - BuildSmoothingGroups(); std::sort(sortedSurfaces.begin(), sortedSurfaces.end(), [](LevelMeshSurface* a, LevelMeshSurface* b) { return a->texHeight != b->texHeight ? a->texHeight > b->texHeight : a->texWidth > b->texWidth; });