From 63ecb368892f54c5e1cbf91e57332a741577e76d Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 25 Sep 2021 00:13:25 +0200 Subject: [PATCH] Add lightmap texture support to vulkan backend Also fix a warning in SetFlatVertex --- .../vulkan/renderer/vk_renderbuffers.cpp | 39 ++++++++++ .../vulkan/renderer/vk_renderbuffers.h | 4 + .../vulkan/renderer/vk_renderpass.cpp | 6 +- .../rendering/vulkan/system/vk_builders.h | 11 ++- .../vulkan/system/vk_framebuffer.cpp | 75 +++++++++++++++++++ .../rendering/vulkan/system/vk_framebuffer.h | 1 + src/g_levellocals.h | 2 +- src/maploader/maploader.cpp | 4 +- src/rendering/hwrenderer/hw_vertexbuilder.cpp | 4 +- 9 files changed, 137 insertions(+), 9 deletions(-) diff --git a/src/common/rendering/vulkan/renderer/vk_renderbuffers.cpp b/src/common/rendering/vulkan/renderer/vk_renderbuffers.cpp index 75288a4f2..aa2479721 100644 --- a/src/common/rendering/vulkan/renderer/vk_renderbuffers.cpp +++ b/src/common/rendering/vulkan/renderer/vk_renderbuffers.cpp @@ -78,6 +78,7 @@ void VkRenderBuffers::BeginFrame(int width, int height, int sceneWidth, int scen CreateScene(width, height, samples); CreateShadowmap(); + CreateLightmapSampler(); mWidth = width; mHeight = height; @@ -269,3 +270,41 @@ void VkRenderBuffers::CreateShadowmap() ShadowmapSampler->SetDebugName("VkRenderBuffers.ShadowmapSampler"); } } + +void VkRenderBuffers::CreateLightmapSampler() +{ + if (!Lightmap.Image) + { + auto fb = GetVulkanFrameBuffer(); + + ImageBuilder builder; + builder.setSize(1, 1); + builder.setFormat(VK_FORMAT_R16G16B16A16_SFLOAT); + builder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT); + Lightmap.Image = builder.create(fb->device); + Lightmap.Image->SetDebugName("VkRenderBuffers.Lightmap"); + + ImageViewBuilder viewbuilder; + viewbuilder.setType(VK_IMAGE_VIEW_TYPE_2D_ARRAY); + viewbuilder.setImage(Lightmap.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT); + Lightmap.View = viewbuilder.create(fb->device); + Lightmap.View->SetDebugName("VkRenderBuffers.LightmapView"); + + VkImageTransition barrier; + barrier.addImage(&Lightmap, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, true); + barrier.execute(fb->GetDrawCommands()); + } + + if (!LightmapSampler) + { + auto fb = GetVulkanFrameBuffer(); + + SamplerBuilder builder; + builder.setMipmapMode(VK_SAMPLER_MIPMAP_MODE_LINEAR); + builder.setMinFilter(VK_FILTER_LINEAR); + builder.setMagFilter(VK_FILTER_LINEAR); + builder.setAddressMode(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); + LightmapSampler = builder.create(fb->device); + LightmapSampler->SetDebugName("VkRenderBuffers.LightmapSampler"); + } +} diff --git a/src/common/rendering/vulkan/renderer/vk_renderbuffers.h b/src/common/rendering/vulkan/renderer/vk_renderbuffers.h index 92ad9c5be..02eb1947c 100644 --- a/src/common/rendering/vulkan/renderer/vk_renderbuffers.h +++ b/src/common/rendering/vulkan/renderer/vk_renderbuffers.h @@ -32,6 +32,9 @@ public: VkTextureImage Shadowmap; std::unique_ptr ShadowmapSampler; + VkTextureImage Lightmap; + std::unique_ptr LightmapSampler; + private: void CreatePipeline(int width, int height); void CreateScene(int width, int height, VkSampleCountFlagBits samples); @@ -40,6 +43,7 @@ private: void CreateSceneFog(int width, int height, VkSampleCountFlagBits samples); void CreateSceneNormal(int width, int height, VkSampleCountFlagBits samples); void CreateShadowmap(); + void CreateLightmapSampler(); VkSampleCountFlagBits GetBestSampleCount(); int mWidth = 0; diff --git a/src/common/rendering/vulkan/renderer/vk_renderpass.cpp b/src/common/rendering/vulkan/renderer/vk_renderpass.cpp index 44c325ecf..7d11a7029 100644 --- a/src/common/rendering/vulkan/renderer/vk_renderpass.cpp +++ b/src/common/rendering/vulkan/renderer/vk_renderpass.cpp @@ -130,6 +130,7 @@ void VkRenderPassManager::CreateDynamicSetLayout() builder.addBinding(2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); builder.addBinding(3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); builder.addBinding(4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + builder.addBinding(5, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); DynamicSetLayout = builder.create(GetVulkanFrameBuffer()->device); DynamicSetLayout->SetDebugName("VkRenderPassManager.DynamicSetLayout"); } @@ -249,6 +250,7 @@ void VkRenderPassManager::UpdateDynamicSet() update.addBuffer(DynamicSet.get(), 2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->MatrixBuffer->UniformBuffer->mBuffer.get(), 0, sizeof(MatricesUBO)); update.addBuffer(DynamicSet.get(), 3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->StreamBuffer->UniformBuffer->mBuffer.get(), 0, sizeof(StreamUBO)); update.addCombinedImageSampler(DynamicSet.get(), 4, fb->GetBuffers()->Shadowmap.View.get(), fb->GetBuffers()->ShadowmapSampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + update.addCombinedImageSampler(DynamicSet.get(), 5, fb->GetBuffers()->Lightmap.View.get(), fb->GetBuffers()->LightmapSampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); update.updateSets(fb->device); } @@ -376,7 +378,7 @@ std::unique_ptr VkRenderPassSetup::CreatePipeline(const VkPipeli VK_FORMAT_A2B10G10R10_SNORM_PACK32 }; - bool inputLocations[6] = { false, false, false, false, false, false }; + bool inputLocations[7] = { false, false, false, false, false, false, false }; for (size_t i = 0; i < vfmt.Attrs.size(); i++) { @@ -386,7 +388,7 @@ std::unique_ptr VkRenderPassSetup::CreatePipeline(const VkPipeli } // Vulkan requires an attribute binding for each location specified in the shader - for (int i = 0; i < 6; i++) + for (int i = 0; i < 7; i++) { if (!inputLocations[i]) builder.addVertexAttribute(i, 0, VK_FORMAT_R32G32B32_SFLOAT, 0); diff --git a/src/common/rendering/vulkan/system/vk_builders.h b/src/common/rendering/vulkan/system/vk_builders.h index 343313bbd..657d913dc 100644 --- a/src/common/rendering/vulkan/system/vk_builders.h +++ b/src/common/rendering/vulkan/system/vk_builders.h @@ -38,7 +38,7 @@ class ImageBuilder public: ImageBuilder(); - void setSize(int width, int height, int miplevels = 1); + void setSize(int width, int height, int miplevels = 1, int arrayLayers = 1); void setSamples(VkSampleCountFlagBits samples); void setFormat(VkFormat format); void setUsage(VkImageUsageFlags imageUsage, VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_GPU_ONLY, VmaAllocationCreateFlags allocFlags = 0); @@ -60,6 +60,7 @@ class ImageViewBuilder public: ImageViewBuilder(); + void setType(VkImageViewType type); void setImage(VulkanImage *image, VkFormat format, VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT); std::unique_ptr create(VulkanDevice *device); @@ -374,11 +375,12 @@ inline ImageBuilder::ImageBuilder() imageInfo.flags = 0; } -inline void ImageBuilder::setSize(int width, int height, int mipLevels) +inline void ImageBuilder::setSize(int width, int height, int mipLevels, int arrayLayers) { imageInfo.extent.width = width; imageInfo.extent.height = height; imageInfo.mipLevels = mipLevels; + imageInfo.arrayLayers = arrayLayers; } inline void ImageBuilder::setSamples(VkSampleCountFlagBits samples) @@ -474,6 +476,11 @@ inline ImageViewBuilder::ImageViewBuilder() viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; } +inline void ImageViewBuilder::setType(VkImageViewType type) +{ + viewInfo.viewType = type; +} + inline void ImageViewBuilder::setImage(VulkanImage *image, VkFormat format, VkImageAspectFlags aspectMask) { viewInfo.image = image->image; diff --git a/src/common/rendering/vulkan/system/vk_framebuffer.cpp b/src/common/rendering/vulkan/system/vk_framebuffer.cpp index 4d08212ec..b8e821242 100644 --- a/src/common/rendering/vulkan/system/vk_framebuffer.cpp +++ b/src/common/rendering/vulkan/system/vk_framebuffer.cpp @@ -582,6 +582,81 @@ void VulkanFrameBuffer::BeginFrame() } } +void VulkanFrameBuffer::InitLightmap(FLevelLocals* Level) +{ + if (Level->LMTextureData.Size() > 0) + { + int w = Level->LMTextureSize; + int h = Level->LMTextureSize; + int count = Level->LMTextureCount; + int pixelsize = 8; + auto& lightmap = mActiveRenderBuffers->Lightmap; + + if (lightmap.Image) + { + FrameDeleteList.Images.push_back(std::move(lightmap.Image)); + FrameDeleteList.ImageViews.push_back(std::move(lightmap.View)); + lightmap.reset(); + } + + ImageBuilder builder; + builder.setSize(w, h, 1, count); + builder.setFormat(VK_FORMAT_R16G16B16A16_SFLOAT); + builder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + lightmap.Image = builder.create(device); + lightmap.Image->SetDebugName("VkRenderBuffers.Lightmap"); + + ImageViewBuilder viewbuilder; + viewbuilder.setType(VK_IMAGE_VIEW_TYPE_2D_ARRAY); + viewbuilder.setImage(lightmap.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT); + lightmap.View = viewbuilder.create(device); + lightmap.View->SetDebugName("VkRenderBuffers.LightmapView"); + + auto cmdbuffer = GetTransferCommands(); + + int totalSize = w * h * count * pixelsize; + + BufferBuilder bufbuilder; + bufbuilder.setSize(totalSize); + bufbuilder.setUsage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); + std::unique_ptr stagingBuffer = bufbuilder.create(device); + stagingBuffer->SetDebugName("VkHardwareTexture.mStagingBuffer"); + + uint16_t one = 0x3c00; // half-float 1.0 + uint16_t* src = &Level->LMTextureData[0]; + 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 imageTransition; + imageTransition.addImage(&lightmap, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true); + imageTransition.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 barrier; + barrier.addImage(&lightmap, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, true); + barrier.execute(cmdbuffer); + + FrameTextureUpload.Buffers.push_back(std::move(stagingBuffer)); + FrameTextureUpload.TotalSize += totalSize; + + Level->LMTextureData.Reset(); // We no longer need this, release the memory + } +} + void VulkanFrameBuffer::PushGroup(const FString &name) { if (!gpuStatActive) diff --git a/src/common/rendering/vulkan/system/vk_framebuffer.h b/src/common/rendering/vulkan/system/vk_framebuffer.h index 365278acb..a18be697d 100644 --- a/src/common/rendering/vulkan/system/vk_framebuffer.h +++ b/src/common/rendering/vulkan/system/vk_framebuffer.h @@ -85,6 +85,7 @@ public: void SetTextureFilterMode() override; void StartPrecaching() override; void BeginFrame() override; + void InitLightmap(FLevelLocals* Level) override; void BlurScene(float amount) override; void PostProcessScene(bool swscene, int fixedcm, float flash, const std::function &afterBloomDrawEndScene2D) override; void AmbientOccludeScene(float m5) override; diff --git a/src/g_levellocals.h b/src/g_levellocals.h index c23c59d63..94f7a5d91 100644 --- a/src/g_levellocals.h +++ b/src/g_levellocals.h @@ -456,7 +456,7 @@ public: TArray LMTexCoords; int LMTextureCount = 0; int LMTextureSize = 0; - TArray LMTextureData; + TArray LMTextureData; // Portal information. FDisplacementTable Displacements; diff --git a/src/maploader/maploader.cpp b/src/maploader/maploader.cpp index e45bfaa77..5a8efc528 100644 --- a/src/maploader/maploader.cpp +++ b/src/maploader/maploader.cpp @@ -3423,8 +3423,8 @@ void MapLoader::LoadLightmap(MapData *map) Level->LMTextureCount = numTextures; Level->LMTextureSize = textureSize; - Level->LMTextureData.Resize(numTexBytes); - uint8_t* data = &Level->LMTextureData[0]; + Level->LMTextureData.Resize((numTexBytes + 1) / 2); + uint8_t* data = (uint8_t*)&Level->LMTextureData[0]; fr.Read(data, numTexBytes); #if 0 // Apply compression predictor diff --git a/src/rendering/hwrenderer/hw_vertexbuilder.cpp b/src/rendering/hwrenderer/hw_vertexbuilder.cpp index d7aeb4cbb..91c6bb3c6 100644 --- a/src/rendering/hwrenderer/hw_vertexbuilder.cpp +++ b/src/rendering/hwrenderer/hw_vertexbuilder.cpp @@ -191,7 +191,7 @@ static void SetFlatVertex(FFlatVertex& ffv, vertex_t* vt, const secplane_t& plan ffv.lindex = -1.0f; } -static void SetFlatVertex(FFlatVertex& ffv, vertex_t* vt, const secplane_t& plane, float llu, float llv, float llindex) +static void SetFlatVertex(FFlatVertex& ffv, vertex_t* vt, const secplane_t& plane, float llu, float llv, int llindex) { ffv.x = (float)vt->fX(); ffv.y = (float)vt->fY(); @@ -200,7 +200,7 @@ static void SetFlatVertex(FFlatVertex& ffv, vertex_t* vt, const secplane_t& plan ffv.v = -(float)vt->fY() / 64.f; ffv.lu = llu; ffv.lv = llv; - ffv.lindex = llindex; + ffv.lindex = (float)llindex; } //==========================================================================