mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-02-16 17:21:10 +00:00
Use a shader to copy the pixels as vkCmdCopyImage is very slow. Also gives us more flexibility in the future for composite lightmaps
This commit is contained in:
parent
cf6f349943
commit
ae4e50a2d4
8 changed files with 331 additions and 141 deletions
|
@ -11,16 +11,14 @@
|
|||
#include "cmdlib.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;
|
||||
}
|
||||
|
||||
|
@ -33,12 +31,14 @@ VkLightmap::VkLightmap(VulkanRenderDevice* fb) : fb(fb)
|
|||
useRayQuery = fb->GetDevice()->PhysicalDevice.Features.RayQuery.rayQuery;
|
||||
|
||||
CreateUniformBuffer();
|
||||
CreateSceneLightBuffer();
|
||||
CreateLightBuffer();
|
||||
CreateTileBuffer();
|
||||
|
||||
CreateShaders();
|
||||
CreateRaytracePipeline();
|
||||
CreateResolvePipeline();
|
||||
CreateBlurPipeline();
|
||||
CreateCopyPipeline();
|
||||
CreateBakeImage();
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,8 @@ VkLightmap::~VkLightmap()
|
|||
{
|
||||
if (lights.Buffer)
|
||||
lights.Buffer->Unmap();
|
||||
if (copytiles.Buffer)
|
||||
copytiles.Buffer->Unmap();
|
||||
}
|
||||
|
||||
void VkLightmap::SetLevelMesh(LevelMesh* level)
|
||||
|
@ -53,9 +55,7 @@ void VkLightmap::SetLevelMesh(LevelMesh* level)
|
|||
mesh = level;
|
||||
UpdateAccelStructDescriptors();
|
||||
|
||||
lightmapRaytrace.Reset();
|
||||
lightmapRaytraceLast.Reset();
|
||||
totalPixelCount = 0;
|
||||
lastPixelCount = 0;
|
||||
lastSurfaceCount = 0;
|
||||
}
|
||||
|
@ -70,10 +70,8 @@ void VkLightmap::Raytrace(const TArray<LevelMeshSurface*>& surfaces)
|
|||
{
|
||||
if (surfaces.Size())
|
||||
{
|
||||
lightmapRaytrace.active = true;
|
||||
lightmapRaytraceLast.active = true;
|
||||
|
||||
lightmapRaytrace.Clock();
|
||||
lightmapRaytraceLast.ResetAndClock();
|
||||
|
||||
SelectSurfaces(surfaces);
|
||||
|
@ -82,15 +80,14 @@ void VkLightmap::Raytrace(const TArray<LevelMeshSurface*>& 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();
|
||||
}
|
||||
}
|
||||
|
@ -129,7 +126,7 @@ void VkLightmap::SelectSurfaces(const TArray<LevelMeshSurface*>& surfaces)
|
|||
}
|
||||
}
|
||||
|
||||
void VkLightmap::RenderBakeImage()
|
||||
void VkLightmap::Render()
|
||||
{
|
||||
auto cmdbuffer = fb->GetCommands()->GetTransferCommands();
|
||||
|
||||
|
@ -167,7 +164,7 @@ void VkLightmap::RenderBakeImage()
|
|||
continue;
|
||||
}
|
||||
|
||||
LightmapPushConstants pc;
|
||||
LightmapRaytracePC pc;
|
||||
pc.TileX = (float)selectedSurface.X;
|
||||
pc.TileY = (float)selectedSurface.Y;
|
||||
pc.SurfaceIndex = mesh->GetSurfaceIndex(targetSurface);
|
||||
|
@ -229,7 +226,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);
|
||||
}
|
||||
|
||||
|
@ -269,7 +266,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();
|
||||
|
||||
|
@ -301,7 +298,7 @@ void VkLightmap::ResolveBakeImage()
|
|||
fb->GetCommands()->PopGroup(cmdbuffer);
|
||||
}
|
||||
|
||||
void VkLightmap::BlurBakeImage()
|
||||
void VkLightmap::Blur()
|
||||
{
|
||||
auto cmdbuffer = fb->GetCommands()->GetTransferCommands();
|
||||
|
||||
|
@ -362,63 +359,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<int> seenPages;
|
||||
std::vector<VkImageCopy> 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)
|
||||
|
@ -454,6 +515,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)
|
||||
|
@ -481,6 +549,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);
|
||||
}
|
||||
|
|
|
@ -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<VulkanDescriptorSet> DescriptorSet[2];
|
||||
} blur;
|
||||
|
||||
struct
|
||||
{
|
||||
std::unique_ptr<VulkanDescriptorSet> 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<LevelMeshSurface*>& 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<SelectedSurface> selectedSurfaces;
|
||||
TArray<TArray<SelectedSurface*>> copylists;
|
||||
|
||||
struct
|
||||
{
|
||||
|
@ -150,13 +180,22 @@ private:
|
|||
int ResetCounter = 0;
|
||||
} lights;
|
||||
|
||||
struct
|
||||
{
|
||||
const int BufferSize = 100'000;
|
||||
std::unique_ptr<VulkanBuffer> Buffer;
|
||||
CopyTileInfo* Tiles = nullptr;
|
||||
} copytiles;
|
||||
|
||||
struct
|
||||
{
|
||||
std::unique_ptr<VulkanShader> vertRaytrace;
|
||||
std::unique_ptr<VulkanShader> vertScreenquad;
|
||||
std::unique_ptr<VulkanShader> vertCopy;
|
||||
std::unique_ptr<VulkanShader> fragRaytrace;
|
||||
std::unique_ptr<VulkanShader> fragResolve;
|
||||
std::unique_ptr<VulkanShader> fragBlur[2];
|
||||
std::unique_ptr<VulkanShader> fragCopy;
|
||||
} shaders;
|
||||
|
||||
struct
|
||||
|
@ -192,6 +231,16 @@ private:
|
|||
std::unique_ptr<VulkanSampler> sampler;
|
||||
} blur;
|
||||
|
||||
struct
|
||||
{
|
||||
std::unique_ptr<VulkanDescriptorSetLayout> descriptorSetLayout;
|
||||
std::unique_ptr<VulkanPipelineLayout> pipelineLayout;
|
||||
std::unique_ptr<VulkanPipeline> pipeline;
|
||||
std::unique_ptr<VulkanRenderPass> renderPass;
|
||||
std::unique_ptr<VulkanDescriptorPool> descriptorPool;
|
||||
std::unique_ptr<VulkanSampler> sampler;
|
||||
} copy;
|
||||
|
||||
LightmapBakeImage bakeImage;
|
||||
static const int bakeImageSize = 2048;
|
||||
};
|
||||
|
|
|
@ -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<VulkanFramebuffer> PPFramebuffer;
|
||||
std::map<VkRenderPassKey, std::unique_ptr<VulkanFramebuffer>> RSFramebuffers;
|
||||
std::vector<std::unique_ptr<VulkanFramebuffer>> LMFramebuffers;
|
||||
};
|
||||
|
||||
class VkImageTransition
|
||||
|
|
|
@ -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<uint16_t>&& 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<uint16_t>& 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));
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ public:
|
|||
void BeginFrame();
|
||||
|
||||
void CreateLightmap(int newLMTextureSize, int newLMTextureCount, TArray<uint16_t>&& newPixelData);
|
||||
void SetLightmap(int LMTextureSize, int LMTextureCount, const TArray<uint16_t>& LMTextureData);
|
||||
|
||||
VkTextureImage* GetTexture(const PPTextureType& type, PPTexture* tex);
|
||||
VkFormat GetTextureFormat(PPTexture* texture);
|
||||
|
|
10
wadsrc/static/shaders/lightmap/frag_copy.glsl
Normal file
10
wadsrc/static/shaders/lightmap/frag_copy.glsl
Normal file
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
|
|
41
wadsrc/static/shaders/lightmap/vert_copy.glsl
Normal file
41
wadsrc/static/shaders/lightmap/vert_copy.glsl
Normal file
|
@ -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;
|
||||
}
|
Loading…
Reference in a new issue