diff --git a/libraries/ZVulkan/include/zvulkan/vulkanbuilders.h b/libraries/ZVulkan/include/zvulkan/vulkanbuilders.h index 4e1167669..1078acc2e 100644 --- a/libraries/ZVulkan/include/zvulkan/vulkanbuilders.h +++ b/libraries/ZVulkan/include/zvulkan/vulkanbuilders.h @@ -119,6 +119,8 @@ class ImageBuilder public: ImageBuilder(); + ImageBuilder& Type(VkImageType type); + ImageBuilder& Flags(VkImageCreateFlags flags); ImageBuilder& Size(int width, int height, int miplevels = 1, int arrayLayers = 1); ImageBuilder& Samples(VkSampleCountFlagBits samples); ImageBuilder& Format(VkFormat format); diff --git a/libraries/ZVulkan/src/vulkanbuilders.cpp b/libraries/ZVulkan/src/vulkanbuilders.cpp index 0e7c03a59..07129d16f 100644 --- a/libraries/ZVulkan/src/vulkanbuilders.cpp +++ b/libraries/ZVulkan/src/vulkanbuilders.cpp @@ -276,6 +276,18 @@ ImageBuilder::ImageBuilder() imageInfo.flags = 0; } +ImageBuilder& ImageBuilder::Type(VkImageType type) +{ + imageInfo.imageType = type; + return *this; +} + +ImageBuilder& ImageBuilder::Flags(VkImageCreateFlags flags) +{ + imageInfo.flags = flags; + return *this; +} + ImageBuilder& ImageBuilder::Size(int width, int height, int mipLevels, int arrayLayers) { imageInfo.extent.width = width; @@ -1759,6 +1771,7 @@ std::vector VulkanDeviceBuilder::FindDevices(const std:: enabledFeatures.Features.shaderClipDistance = deviceFeatures.Features.shaderClipDistance; enabledFeatures.Features.multiDrawIndirect = deviceFeatures.Features.multiDrawIndirect; enabledFeatures.Features.independentBlend = deviceFeatures.Features.independentBlend; + enabledFeatures.Features.imageCubeArray = deviceFeatures.Features.imageCubeArray; enabledFeatures.BufferDeviceAddress.bufferDeviceAddress = deviceFeatures.BufferDeviceAddress.bufferDeviceAddress; enabledFeatures.AccelerationStructure.accelerationStructure = deviceFeatures.AccelerationStructure.accelerationStructure; enabledFeatures.RayQuery.rayQuery = deviceFeatures.RayQuery.rayQuery; diff --git a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp index aa63ac417..4343612b9 100644 --- a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp +++ b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp @@ -143,17 +143,19 @@ void VkDescriptorSetManager::UpdateFixedSet() WriteDescriptors update; update.AddCombinedImageSampler(Fixed.Set.get(), 0, fb->GetTextureManager()->Shadowmap.View.get(), fb->GetSamplerManager()->ShadowmapSampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - update.AddCombinedImageSampler(Fixed.Set.get(), 1, fb->GetTextureManager()->Lightmap.View.get(), fb->GetSamplerManager()->LightmapSampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + update.AddCombinedImageSampler(Fixed.Set.get(), 1, fb->GetTextureManager()->Lightmap.Image.View.get(), fb->GetSamplerManager()->LightmapSampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); update.AddCombinedImageSampler(Fixed.Set.get(), 2, fb->GetBuffers()->SceneLinearDepth.View.get(), fb->GetSamplerManager()->Get(PPFilterMode::Nearest, PPWrapMode::Clamp), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + update.AddCombinedImageSampler(Fixed.Set.get(), 3, fb->GetTextureManager()->Irradiancemap.Image.View.get(), fb->GetSamplerManager()->IrradiancemapSampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + update.AddCombinedImageSampler(Fixed.Set.get(), 4, fb->GetTextureManager()->Prefiltermap.Image.View.get(), fb->GetSamplerManager()->PrefiltermapSampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); if (fb->IsRayQueryEnabled()) { - update.AddAccelerationStructure(Fixed.Set.get(), 3, fb->GetLevelMesh()->GetAccelStruct()); + update.AddAccelerationStructure(Fixed.Set.get(), 5, fb->GetLevelMesh()->GetAccelStruct()); } else { - update.AddBuffer(Fixed.Set.get(), 3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetNodeBuffer()); - update.AddBuffer(Fixed.Set.get(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetVertexBuffer()); - update.AddBuffer(Fixed.Set.get(), 5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetIndexBuffer()); + update.AddBuffer(Fixed.Set.get(), 5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetNodeBuffer()); + update.AddBuffer(Fixed.Set.get(), 6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetVertexBuffer()); + update.AddBuffer(Fixed.Set.get(), 7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetLevelMesh()->GetIndexBuffer()); } update.Execute(fb->GetDevice()); } @@ -269,15 +271,17 @@ void VkDescriptorSetManager::CreateFixedLayout() builder.AddBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); builder.AddBinding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); builder.AddBinding(2, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + builder.AddBinding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + builder.AddBinding(4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); if (fb->IsRayQueryEnabled()) { - builder.AddBinding(3, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + builder.AddBinding(5, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_FRAGMENT_BIT); } else { - builder.AddBinding(3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - builder.AddBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); builder.AddBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + builder.AddBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + builder.AddBinding(7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); } builder.DebugName("VkDescriptorSetManager.Fixed.SetLayout"); Fixed.Layout = builder.Create(fb->GetDevice()); @@ -343,7 +347,7 @@ void VkDescriptorSetManager::CreateRSBufferPool() void VkDescriptorSetManager::CreateFixedPool() { DescriptorPoolBuilder poolbuilder; - poolbuilder.AddPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 3 * MaxFixedSets); + poolbuilder.AddPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 5 * MaxFixedSets); if (fb->IsRayQueryEnabled()) { poolbuilder.AddPoolSize(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1 * MaxFixedSets); diff --git a/src/common/rendering/vulkan/samplers/vk_samplers.cpp b/src/common/rendering/vulkan/samplers/vk_samplers.cpp index 9d48a42cb..6c34464b8 100644 --- a/src/common/rendering/vulkan/samplers/vk_samplers.cpp +++ b/src/common/rendering/vulkan/samplers/vk_samplers.cpp @@ -130,6 +130,8 @@ VkSamplerManager::VkSamplerManager(VulkanRenderDevice* fb) : fb(fb) CreateShadowmapSampler(); CreateLightmapSampler(); CreateZMinMaxSampler(); + CreateIrradiancemapSampler(); + CreatePrefiltermapSampler(); } VkSamplerManager::~VkSamplerManager() @@ -325,3 +327,19 @@ void VkSamplerManager::CreateZMinMaxSampler() .DebugName("VkRenderBuffers.ZMinMaxSampler") .Create(fb->GetDevice()); } + +void VkSamplerManager::CreateIrradiancemapSampler() +{ + IrradiancemapSampler = SamplerBuilder() + .AddressMode(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE) + .DebugName("VkRenderBuffers.IrradiancemapSampler") + .Create(fb->GetDevice()); +} + +void VkSamplerManager::CreatePrefiltermapSampler() +{ + PrefiltermapSampler = SamplerBuilder() + .AddressMode(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE) + .DebugName("VkRenderBuffers.PrefiltermapSampler") + .Create(fb->GetDevice()); +} diff --git a/src/common/rendering/vulkan/samplers/vk_samplers.h b/src/common/rendering/vulkan/samplers/vk_samplers.h index 1579d02d6..8623cfe37 100644 --- a/src/common/rendering/vulkan/samplers/vk_samplers.h +++ b/src/common/rendering/vulkan/samplers/vk_samplers.h @@ -29,6 +29,8 @@ public: std::unique_ptr ShadowmapSampler; std::unique_ptr LightmapSampler; std::unique_ptr ZMinMaxSampler; + std::unique_ptr IrradiancemapSampler; + std::unique_ptr PrefiltermapSampler; private: void CreateHWSamplers(); @@ -36,6 +38,8 @@ private: void CreateShadowmapSampler(); void CreateLightmapSampler(); void CreateZMinMaxSampler(); + void CreateIrradiancemapSampler(); + void CreatePrefiltermapSampler(); VulkanRenderDevice* fb = nullptr; std::array, NUMSAMPLERS> mSamplers; diff --git a/src/common/rendering/vulkan/textures/vk_texture.cpp b/src/common/rendering/vulkan/textures/vk_texture.cpp index eee217749..c5f642119 100644 --- a/src/common/rendering/vulkan/textures/vk_texture.cpp +++ b/src/common/rendering/vulkan/textures/vk_texture.cpp @@ -32,6 +32,8 @@ VkTextureManager::VkTextureManager(VulkanRenderDevice* fb) : fb(fb) CreateNullTexture(); CreateShadowmap(); CreateLightmap(); + CreateIrradiancemap(); + CreatePrefiltermap(); } VkTextureManager::~VkTextureManager() @@ -192,32 +194,64 @@ void VkTextureManager::CreateLightmap() CreateLightmap(1, 1, std::move(data)); } -void VkTextureManager::CreateLightmap(int newLMTextureSize, int newLMTextureCount, TArray&& newPixelData) +void VkTextureManager::CreateIrradiancemap() { - if (LMTextureSize == newLMTextureSize && LMTextureCount == newLMTextureCount + 1 && newPixelData.Size() == 0) + TArray data; + for (int arrayIndex = 0; arrayIndex < 6; arrayIndex++) + { + data.Push(0); + data.Push(0); + data.Push(0); + } + CreateIrradiancemap(1, 6, std::move(data)); +} + +void VkTextureManager::CreatePrefiltermap() +{ + TArray data; + int size = 1 << MAX_REFLECTION_LOD; + for (int arrayIndex = 0; arrayIndex < 6; arrayIndex++) + { + for (int level = 0; level < MAX_REFLECTION_LOD; level++) + { + int mipsize = size >> level; + for (int i = 0; i < mipsize; i++) + { + data.Push(0); + data.Push(0); + data.Push(0); + } + } + } + CreatePrefiltermap(size, 6, std::move(data)); +} + +void VkTextureManager::CreateIrradiancemap(int size, int count, TArray&& newPixelData) +{ + if (Irradiancemap.Size == size && Irradiancemap.Count == count && newPixelData.Size() == 0) return; - LMTextureSize = newLMTextureSize; - LMTextureCount = newLMTextureCount + 1; // the extra texture is for the dynamic lightmap - - int w = newLMTextureSize; - int h = newLMTextureSize; - int count = newLMTextureCount; + Irradiancemap.Size = size; + Irradiancemap.Count = count; + + int w = size; + int h = size; int pixelsize = 8; - Lightmap.Reset(fb); + Irradiancemap.Image.Reset(fb); - Lightmap.Image = ImageBuilder() - .Size(w, h, 1, LMTextureCount) + Irradiancemap.Image.Image = ImageBuilder() + .Size(w, h, 1, count) .Format(VK_FORMAT_R16G16B16A16_SFLOAT) - .Usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) - .DebugName("VkRenderBuffers.Lightmap") + .Usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT) + .Flags(VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) + .DebugName("VkTextureManager.Irradiancemap") .Create(fb->GetDevice()); - Lightmap.View = ImageViewBuilder() - .Type(VK_IMAGE_VIEW_TYPE_2D_ARRAY) - .Image(Lightmap.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT) - .DebugName("VkRenderBuffers.LightmapView") + Irradiancemap.Image.View = ImageViewBuilder() + .Type(VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) + .Image(Irradiancemap.Image.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT) + .DebugName("VkTextureManager.IrradiancemapView") .Create(fb->GetDevice()); auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); @@ -231,7 +265,7 @@ void VkTextureManager::CreateLightmap(int newLMTextureSize, int newLMTextureCoun auto stagingBuffer = BufferBuilder() .Size(totalSize) .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) - .DebugName("VkHardwareTexture.mStagingBuffer") + .DebugName("VkRenderBuffers.IrradiancemapStagingBuffer") .Create(fb->GetDevice()); uint16_t one = 0x3c00; // half-float 1.0 @@ -247,7 +281,7 @@ void VkTextureManager::CreateLightmap(int newLMTextureSize, int newLMTextureCoun stagingBuffer->Unmap(); VkImageTransition() - .AddImage(&Lightmap, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true, 0, 1, 0, LMTextureCount) + .AddImage(&Irradiancemap.Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true, 0, 1, 0, count) .Execute(cmdbuffer); VkBufferImageCopy region = {}; @@ -256,7 +290,176 @@ void VkTextureManager::CreateLightmap(int newLMTextureSize, int newLMTextureCoun 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); + cmdbuffer->copyBufferToImage(stagingBuffer->buffer, Irradiancemap.Image.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + fb->GetCommands()->TransferDeleteList->Add(std::move(stagingBuffer)); + + newPixelData.Clear(); + } + + VkImageTransition() + .AddImage(&Irradiancemap.Image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false, 0, 1, 0, count) + .Execute(cmdbuffer); +} + +void VkTextureManager::CreatePrefiltermap(int size, int count, TArray&& newPixelData) +{ + if (Prefiltermap.Size == size && Prefiltermap.Count == count && newPixelData.Size() == 0) + return; + + Prefiltermap.Size = size; + Prefiltermap.Count = count; + + int w = size; + int h = size; + int pixelsize = 8; + int miplevels = MAX_REFLECTION_LOD + 1; + + Prefiltermap.Image.Reset(fb); + + Prefiltermap.Image.Image = ImageBuilder() + .Size(w, h, miplevels, count) + .Format(VK_FORMAT_R16G16B16A16_SFLOAT) + .Usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT) + .Flags(VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) + .DebugName("VkTextureManager.Prefiltermap") + .Create(fb->GetDevice()); + + Prefiltermap.Image.View = ImageViewBuilder() + .Type(VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) + .Image(Prefiltermap.Image.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT) + .DebugName("VkTextureManager.PrefiltermapView") + .Create(fb->GetDevice()); + + auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); + + if (count > 0 && newPixelData.Size() >= (size_t)w * h * count * 3) + { + assert(newPixelData.Size() == (size_t)w * h * count * 3); + + int totalSize = 0; + for (int level = 0; level < miplevels; level++) + { + int mipwidth = std::max(w >> level, 1); + int mipheight = std::max(h >> level, 1); + totalSize += mipwidth * mipheight * count * pixelsize; + } + + auto stagingBuffer = BufferBuilder() + .Size(totalSize) + .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) + .DebugName("VkTextureManager.PrefiltermapStagingBuffer") + .Create(fb->GetDevice()); + + uint16_t one = 0x3c00; // half-float 1.0 + const uint16_t* src = newPixelData.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(&Prefiltermap.Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true, 0, miplevels, 0, count) + .Execute(cmdbuffer); + + int offset = 0; + for (int level = 0; level < miplevels; level++) + { + VkBufferImageCopy region = {}; + region.bufferOffset = offset; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.layerCount = count; + region.imageSubresource.mipLevel = level; + region.imageExtent.depth = 1; + region.imageExtent.width = w; + region.imageExtent.height = h; + cmdbuffer->copyBufferToImage(stagingBuffer->buffer, Prefiltermap.Image.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + int mipwidth = std::max(w >> level, 1); + int mipheight = std::max(h >> level, 1); + offset += mipwidth * mipheight * count * pixelsize; + } + + fb->GetCommands()->TransferDeleteList->Add(std::move(stagingBuffer)); + + newPixelData.Clear(); + } + + VkImageTransition() + .AddImage(&Prefiltermap.Image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false, 0, miplevels, 0, count) + .Execute(cmdbuffer); +} + +void VkTextureManager::CreateLightmap(int newLMTextureSize, int newLMTextureCount, TArray&& newPixelData) +{ + if (Lightmap.Size == newLMTextureSize && Lightmap.Count == newLMTextureCount + 1 && newPixelData.Size() == 0) + return; + + Lightmap.Size = newLMTextureSize; + Lightmap.Count = newLMTextureCount + 1; // the extra texture is for the dynamic lightmap + + int w = newLMTextureSize; + int h = newLMTextureSize; + int count = newLMTextureCount; + int pixelsize = 8; + + Lightmap.Image.Reset(fb); + + Lightmap.Image.Image = ImageBuilder() + .Size(w, h, 1, Lightmap.Count) + .Format(VK_FORMAT_R16G16B16A16_SFLOAT) + .Usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) + .DebugName("VkTextureManager.Lightmap") + .Create(fb->GetDevice()); + + Lightmap.Image.View = ImageViewBuilder() + .Type(VK_IMAGE_VIEW_TYPE_2D_ARRAY) + .Image(Lightmap.Image.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT) + .DebugName("VkTextureManager.LightmapView") + .Create(fb->GetDevice()); + + auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); + + if (count > 0 && newPixelData.Size() >= (size_t)w * h * count * 3) + { + assert(newPixelData.Size() == (size_t)w * h * count * 3); + + int totalSize = w * h * count * pixelsize; + + auto stagingBuffer = BufferBuilder() + .Size(totalSize) + .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) + .DebugName("VkTextureManager.LightmapStagingBuffer") + .Create(fb->GetDevice()); + + uint16_t one = 0x3c00; // half-float 1.0 + const uint16_t* src = newPixelData.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.Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true, 0, 1, 0, Lightmap.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->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); fb->GetCommands()->TransferDeleteList->Add(std::move(stagingBuffer)); @@ -264,13 +467,13 @@ void VkTextureManager::CreateLightmap(int newLMTextureSize, int newLMTextureCoun } VkImageTransition() - .AddImage(&Lightmap, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false, 0, 1, 0, LMTextureCount) + .AddImage(&Lightmap.Image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false, 0, 1, 0, Lightmap.Count) .Execute(cmdbuffer); } void VkTextureManager::DownloadLightmap(int arrayIndex, uint16_t* buffer) { - unsigned int totalSize = LMTextureSize * LMTextureSize * 4; + unsigned int totalSize = Lightmap.Size * Lightmap.Size * 4; auto stagingBuffer = BufferBuilder() .Size(totalSize * sizeof(uint16_t)) @@ -281,7 +484,7 @@ void VkTextureManager::DownloadLightmap(int arrayIndex, uint16_t* buffer) auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); PipelineBarrier() - .AddImage(Lightmap.Image.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, arrayIndex, 1) + .AddImage(Lightmap.Image.Image.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, arrayIndex, 1) .Execute(cmdbuffer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); VkBufferImageCopy region = {}; @@ -289,13 +492,13 @@ void VkTextureManager::DownloadLightmap(int arrayIndex, uint16_t* buffer) region.imageSubresource.baseArrayLayer = arrayIndex; region.imageSubresource.layerCount = 1; region.imageSubresource.mipLevel = 0; - region.imageExtent.width = LMTextureSize; - region.imageExtent.height = LMTextureSize; + region.imageExtent.width = Lightmap.Size; + region.imageExtent.height = Lightmap.Size; region.imageExtent.depth = 1; - cmdbuffer->copyImageToBuffer(Lightmap.Image->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, stagingBuffer->buffer, 1, ®ion); + cmdbuffer->copyImageToBuffer(Lightmap.Image.Image->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, stagingBuffer->buffer, 1, ®ion); PipelineBarrier() - .AddImage(Lightmap.Image.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, arrayIndex, 1) + .AddImage(Lightmap.Image.Image.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, arrayIndex, 1) .Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); fb->GetCommands()->WaitForCommands(false); diff --git a/src/common/rendering/vulkan/textures/vk_texture.h b/src/common/rendering/vulkan/textures/vk_texture.h index f79163e31..64ab929ea 100644 --- a/src/common/rendering/vulkan/textures/vk_texture.h +++ b/src/common/rendering/vulkan/textures/vk_texture.h @@ -23,7 +23,9 @@ public: void BeginFrame(); - void CreateLightmap(int newLMTextureSize, int newLMTextureCount, TArray&& newPixelData); + void CreateLightmap(int size, int count, TArray&& data); + void CreateIrradiancemap(int size, int count, TArray&& data); + void CreatePrefiltermap(int size, int count, TArray&& data); void DownloadLightmap(int arrayIndex, uint16_t* buffer); VkTextureImage* GetTexture(const PPTextureType& type, PPTexture* tex); @@ -41,14 +43,22 @@ public: int GetHWTextureCount() { return (int)Textures.size(); } VkTextureImage Shadowmap; - VkTextureImage Lightmap; - int LMTextureSize = 0; - int LMTextureCount = 0; + + struct + { + VkTextureImage Image; + int Size = 0; + int Count = 0; + } Lightmap, Irradiancemap, Prefiltermap; + + static const int MAX_REFLECTION_LOD = 4; // Note: must match what lightmodel_pbr.glsl expects private: void CreateNullTexture(); void CreateShadowmap(); void CreateLightmap(); + void CreateIrradiancemap(); + void CreatePrefiltermap(); VkPPTexture* GetVkTexture(PPTexture* texture); diff --git a/src/common/rendering/vulkan/vk_lightmapper.cpp b/src/common/rendering/vulkan/vk_lightmapper.cpp index 9e0d2e9b0..57826c2ba 100644 --- a/src/common/rendering/vulkan/vk_lightmapper.cpp +++ b/src/common/rendering/vulkan/vk_lightmapper.cpp @@ -378,8 +378,8 @@ void VkLightmapper::CopyResult() if (pixels == 0) return; - VkTextureImage* destTexture = &fb->GetTextureManager()->Lightmap; - int destSize = fb->GetTextureManager()->LMTextureSize; + VkTextureImage* destTexture = &fb->GetTextureManager()->Lightmap.Image; + int destSize = fb->GetTextureManager()->Lightmap.Size; auto cmdbuffer = fb->GetCommands()->GetTransferCommands(); diff --git a/wadsrc/static/shaders/scene/binding_fixed.glsl b/wadsrc/static/shaders/scene/binding_fixed.glsl index 8bfcae2c4..902665a2c 100644 --- a/wadsrc/static/shaders/scene/binding_fixed.glsl +++ b/wadsrc/static/shaders/scene/binding_fixed.glsl @@ -2,10 +2,12 @@ layout(set = 0, binding = 0) uniform sampler2D ShadowMap; layout(set = 0, binding = 1) uniform sampler2DArray LightMap; layout(set = 0, binding = 2) uniform sampler2D LinearDepth; +layout(set = 0, binding = 3) uniform samplerCubeArray IrradianceMap; +layout(set = 0, binding = 4) uniform samplerCubeArray PrefilterMap; #if defined(USE_RAYTRACE) #if defined(SUPPORTS_RAYQUERY) -layout(set = 0, binding = 3) uniform accelerationStructureEXT TopLevelAS; +layout(set = 0, binding = 5) uniform accelerationStructureEXT TopLevelAS; #else struct CollisionNode { @@ -18,7 +20,7 @@ struct CollisionNode int element_index; int padding3; }; -layout(std430, set = 0, binding = 3) buffer NodeBuffer +layout(std430, set = 0, binding = 5) buffer NodeBuffer { int nodesRoot; int nodebufferPadding1; @@ -33,7 +35,7 @@ struct SurfaceVertex // Note: this must always match the FFlatVertex struct vec2 uv; vec2 luv; }; -layout(std430, set = 0, binding = 4) buffer VertexBuffer { SurfaceVertex vertices[]; }; -layout(std430, set = 0, binding = 5) buffer ElementBuffer { int elements[]; }; +layout(std430, set = 0, binding = 6) buffer VertexBuffer { SurfaceVertex vertices[]; }; +layout(std430, set = 0, binding = 7) buffer ElementBuffer { int elements[]; }; #endif #endif diff --git a/wadsrc/static/shaders/scene/layout_shared.glsl b/wadsrc/static/shaders/scene/layout_shared.glsl index 9160e4588..f1fef42cc 100644 --- a/wadsrc/static/shaders/scene/layout_shared.glsl +++ b/wadsrc/static/shaders/scene/layout_shared.glsl @@ -38,6 +38,8 @@ layout(push_constant) uniform PushConstants #define glowtexture texture4 #endif +#define BrdfLUT 0 // the BRDF convoluted texture is always in this texture slot + #define uObjectColor data[uDataIndex].uObjectColor #define uObjectColor2 data[uDataIndex].uObjectColor2 #define uDynLightColor data[uDataIndex].uDynLightColor diff --git a/wadsrc/static/shaders/scene/lightmodel_pbr.glsl b/wadsrc/static/shaders/scene/lightmodel_pbr.glsl index c87cbf52f..1ccf9ce5c 100644 --- a/wadsrc/static/shaders/scene/lightmodel_pbr.glsl +++ b/wadsrc/static/shaders/scene/lightmodel_pbr.glsl @@ -66,8 +66,7 @@ vec3 ProcessMaterialLight(Material material, vec3 ambientLight) { vec3 worldpos = pixelpos.xyz; - vec3 albedo = pow(material.Base.rgb, vec3(2.2)); // sRGB to linear - ambientLight = pow(ambientLight, vec3(2.2)); + vec3 albedo = material.Base.rgb; float metallic = material.Metallic; float roughness = material.Roughness; @@ -168,28 +167,50 @@ vec3 ProcessMaterialLight(Material material, vec3 ambientLight) } } - // Pretend we sampled the sector light level from an irradiance map + // Treat the ambient sector light as if it is a light source next to the wall + { + vec3 NN = N; + vec3 VV = V; + vec3 LL = N; + vec3 HH = normalize(VV + LL); + + vec3 radiance = ambientLight.rgb * 2.5; + + // cook-torrance brdf + float NDF = DistributionGGX(NN, HH, roughness); + float G = GeometrySmith(NN, VV, LL, roughness); + vec3 F = fresnelSchlick(clamp(dot(HH, VV), 0.0, 1.0), F0); + + vec3 kS = F; + vec3 kD = (vec3(1.0) - kS) * (1.0 - metallic); + + vec3 nominator = NDF * G * F; + float denominator = 4.0 * clamp(dot(NN, VV), 0.0, 1.0) * clamp(dot(NN, LL), 0.0, 1.0); + vec3 specular = nominator / max(denominator, 0.001); + specular = metallic * albedo * 0.40; + + Lo += (kD * albedo / PI + specular) * radiance; + } + + float probeIndex = 0.0; // To do: get this from an uniform vec3 F = fresnelSchlickRoughness(clamp(dot(N, V), 0.0, 1.0), F0, roughness); vec3 kS = F; vec3 kD = 1.0 - kS; - vec3 irradiance = ambientLight; // texture(irradianceMap, N).rgb + vec3 irradiance = texture(IrradianceMap, vec4(N, probeIndex)).rgb; vec3 diffuse = irradiance * albedo; - //kD *= 1.0 - metallic; - //const float MAX_REFLECTION_LOD = 4.0; - //vec3 prefilteredColor = textureLod(prefilterMap, R, roughness * MAX_REFLECTION_LOD).rgb; - //vec2 envBRDF = texture(brdfLUT, vec2(clamp(dot(N, V), 0.0, 1.0), roughness)).rg; - //vec3 specular = prefilteredColor * (F * envBRDF.x + envBRDF.y); + kD *= 1.0 - metallic; + const float MAX_REFLECTION_LOD = 4.0; + vec3 R = reflect(-V, N); + vec3 prefilteredColor = textureLod(PrefilterMap, vec4(R, probeIndex), roughness * MAX_REFLECTION_LOD).rgb; + vec2 envBRDF = texture(BrdfLUT, vec2(clamp(dot(N, V), 0.0, 1.0), roughness)).rg; + vec3 specular = prefilteredColor * (F * envBRDF.x + envBRDF.y); - //vec3 ambient = (kD * diffuse + specular) * ao; - vec3 ambient = (kD * diffuse) * ao; + vec3 ambient = (kD * diffuse + specular) * ao; vec3 color = max(ambient + Lo, vec3(0.0)); - - // Tonemap (reinhard) and apply sRGB gamma - //color = color / (color + vec3(1.0)); - return pow(color, vec3(1.0 / 2.2)); + return color; }