From 8ebad1003b5bacc75745f1198f13342a008306c7 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Fri, 10 Jun 2022 00:12:03 +0200 Subject: [PATCH] Split postprocess part into more files --- src/CMakeLists.txt | 3 + .../vulkan/renderer/vk_descriptorset.cpp | 7 + .../vulkan/renderer/vk_descriptorset.h | 1 + .../vulkan/renderer/vk_postprocess.cpp | 500 +----------------- .../vulkan/renderer/vk_postprocess.h | 84 --- .../vulkan/renderer/vk_pprenderstate.cpp | 277 ++++++++++ .../vulkan/renderer/vk_pprenderstate.h | 30 ++ .../vulkan/renderer/vk_renderpass.cpp | 114 ++++ .../rendering/vulkan/renderer/vk_renderpass.h | 42 +- .../rendering/vulkan/shaders/vk_ppshader.cpp | 60 +++ .../rendering/vulkan/shaders/vk_ppshader.h | 17 + .../vulkan/system/vk_commandbuffer.h | 1 + .../vulkan/system/vk_framebuffer.cpp | 8 +- .../vulkan/textures/vk_pptexture.cpp | 108 ++++ .../rendering/vulkan/textures/vk_pptexture.h | 17 + .../vulkan/textures/vk_renderbuffers.cpp | 1 - .../rendering/vulkan/textures/vk_samplers.cpp | 62 ++- .../rendering/vulkan/textures/vk_samplers.h | 35 +- 18 files changed, 740 insertions(+), 627 deletions(-) create mode 100644 src/common/rendering/vulkan/renderer/vk_pprenderstate.cpp create mode 100644 src/common/rendering/vulkan/renderer/vk_pprenderstate.h create mode 100644 src/common/rendering/vulkan/shaders/vk_ppshader.cpp create mode 100644 src/common/rendering/vulkan/shaders/vk_ppshader.h create mode 100644 src/common/rendering/vulkan/textures/vk_pptexture.cpp create mode 100644 src/common/rendering/vulkan/textures/vk_pptexture.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8a75c354c..3079f539e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -803,11 +803,14 @@ set (VULKAN_SOURCES common/rendering/vulkan/renderer/vk_renderpass.cpp common/rendering/vulkan/renderer/vk_streambuffer.cpp common/rendering/vulkan/renderer/vk_postprocess.cpp + common/rendering/vulkan/renderer/vk_pprenderstate.cpp common/rendering/vulkan/renderer/vk_descriptorset.cpp common/rendering/vulkan/renderer/vk_raytrace.cpp common/rendering/vulkan/shaders/vk_shader.cpp + common/rendering/vulkan/shaders/vk_ppshader.cpp common/rendering/vulkan/textures/vk_samplers.cpp common/rendering/vulkan/textures/vk_hwtexture.cpp + common/rendering/vulkan/textures/vk_pptexture.cpp common/rendering/vulkan/textures/vk_imagetransition.cpp common/rendering/vulkan/textures/vk_renderbuffers.cpp common/rendering/vulkan/thirdparty/volk/volk.c diff --git a/src/common/rendering/vulkan/renderer/vk_descriptorset.cpp b/src/common/rendering/vulkan/renderer/vk_descriptorset.cpp index 479a992f4..f106bfc16 100644 --- a/src/common/rendering/vulkan/renderer/vk_descriptorset.cpp +++ b/src/common/rendering/vulkan/renderer/vk_descriptorset.cpp @@ -26,6 +26,7 @@ #include "vulkan/shaders/vk_shader.h" #include "vulkan/textures/vk_samplers.h" #include "vulkan/textures/vk_renderbuffers.h" +#include "vulkan/textures/vk_hwtexture.h" #include "vulkan/system/vk_builders.h" #include "vulkan/system/vk_framebuffer.h" #include "vulkan/system/vk_buffers.h" @@ -136,6 +137,12 @@ void VkDescriptorSetManager::TextureSetPoolReset() TextureDescriptorsLeft = 0; } +void VkDescriptorSetManager::FilterModeChanged() +{ + // Destroy the texture descriptors as they used the old samplers + VkMaterial::ResetAllDescriptors(); +} + void VkDescriptorSetManager::CreateNullTexture() { auto fb = GetVulkanFrameBuffer(); diff --git a/src/common/rendering/vulkan/renderer/vk_descriptorset.h b/src/common/rendering/vulkan/renderer/vk_descriptorset.h index ea85bd58c..6e17c593b 100644 --- a/src/common/rendering/vulkan/renderer/vk_descriptorset.h +++ b/src/common/rendering/vulkan/renderer/vk_descriptorset.h @@ -13,6 +13,7 @@ public: void UpdateFixedSet(); void UpdateDynamicSet(); void TextureSetPoolReset(); + void FilterModeChanged(); VulkanDescriptorSetLayout* GetDynamicSetLayout() { return DynamicSetLayout.get(); } VulkanDescriptorSetLayout* GetFixedSetLayout() { return FixedSetLayout.get(); } diff --git a/src/common/rendering/vulkan/renderer/vk_postprocess.cpp b/src/common/rendering/vulkan/renderer/vk_postprocess.cpp index f7676af10..dff03e703 100644 --- a/src/common/rendering/vulkan/renderer/vk_postprocess.cpp +++ b/src/common/rendering/vulkan/renderer/vk_postprocess.cpp @@ -28,6 +28,9 @@ #include "vulkan/system/vk_swapchain.h" #include "vulkan/system/vk_commandbuffer.h" #include "vulkan/renderer/vk_renderstate.h" +#include "vulkan/renderer/vk_pprenderstate.h" +#include "vulkan/shaders/vk_ppshader.h" +#include "vulkan/textures/vk_pptexture.h" #include "vulkan/textures/vk_renderbuffers.h" #include "vulkan/textures/vk_imagetransition.h" #include "hw_cvars.h" @@ -36,8 +39,6 @@ #include "hw_vrmodes.h" #include "flatvertices.h" #include "r_videoscale.h" -#include "filesystem.h" - EXTERN_CVAR(Int, gl_dither_bpc) @@ -318,502 +319,7 @@ std::unique_ptr VkPostprocess::AllocateDescriptorSet(Vulkan return mDescriptorPool->allocate(layout); } -void VkPostprocess::RenderBuffersReset() -{ - mRenderPassSetup.clear(); -} - -VulkanSampler *VkPostprocess::GetSampler(PPFilterMode filter, PPWrapMode wrap) -{ - int index = (((int)filter) << 1) | (int)wrap; - auto &sampler = mSamplers[index]; - if (sampler) - return sampler.get(); - - SamplerBuilder builder; - builder.setMipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST); - builder.setMinFilter(filter == PPFilterMode::Nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR); - builder.setMagFilter(filter == PPFilterMode::Nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR); - builder.setAddressMode(wrap == PPWrapMode::Clamp ? VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE : VK_SAMPLER_ADDRESS_MODE_REPEAT); - sampler = builder.create(GetVulkanFrameBuffer()->device); - sampler->SetDebugName("VkPostprocess.mSamplers"); - return sampler.get(); -} - void VkPostprocess::NextEye(int eyeCount) { } -///////////////////////////////////////////////////////////////////////////// - -VkPPTexture::VkPPTexture(PPTexture *texture) -{ - auto fb = GetVulkanFrameBuffer(); - - VkFormat format; - int pixelsize; - switch (texture->Format) - { - default: - case PixelFormat::Rgba8: format = VK_FORMAT_R8G8B8A8_UNORM; pixelsize = 4; break; - case PixelFormat::Rgba16f: format = VK_FORMAT_R16G16B16A16_SFLOAT; pixelsize = 8; break; - case PixelFormat::R32f: format = VK_FORMAT_R32_SFLOAT; pixelsize = 4; break; - case PixelFormat::Rg16f: format = VK_FORMAT_R16G16_SFLOAT; pixelsize = 4; break; - case PixelFormat::Rgba16_snorm: format = VK_FORMAT_R16G16B16A16_SNORM; pixelsize = 8; break; - } - - ImageBuilder imgbuilder; - imgbuilder.setFormat(format); - imgbuilder.setSize(texture->Width, texture->Height); - if (texture->Data) - imgbuilder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); - else - imgbuilder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); - if (!imgbuilder.isFormatSupported(fb->device)) - I_FatalError("Vulkan device does not support the image format required by a postprocess texture\n"); - TexImage.Image = imgbuilder.create(fb->device); - TexImage.Image->SetDebugName("VkPPTexture"); - Format = format; - - ImageViewBuilder viewbuilder; - viewbuilder.setImage(TexImage.Image.get(), format); - TexImage.View = viewbuilder.create(fb->device); - TexImage.View->SetDebugName("VkPPTextureView"); - - if (texture->Data) - { - size_t totalsize = texture->Width * texture->Height * pixelsize; - BufferBuilder stagingbuilder; - stagingbuilder.setSize(totalsize); - stagingbuilder.setUsage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); - Staging = stagingbuilder.create(fb->device); - Staging->SetDebugName("VkPPTextureStaging"); - - VkImageTransition barrier0; - barrier0.addImage(&TexImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true); - barrier0.execute(fb->GetCommands()->GetTransferCommands()); - - void *data = Staging->Map(0, totalsize); - memcpy(data, texture->Data.get(), totalsize); - Staging->Unmap(); - - VkBufferImageCopy region = {}; - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.imageSubresource.layerCount = 1; - region.imageExtent.depth = 1; - region.imageExtent.width = texture->Width; - region.imageExtent.height = texture->Height; - fb->GetCommands()->GetTransferCommands()->copyBufferToImage(Staging->buffer, TexImage.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - - VkImageTransition barrier1; - barrier1.addImage(&TexImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false); - barrier1.execute(fb->GetCommands()->GetTransferCommands()); - } - else - { - VkImageTransition barrier; - barrier.addImage(&TexImage, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true); - barrier.execute(fb->GetCommands()->GetTransferCommands()); - } -} - -VkPPTexture::~VkPPTexture() -{ - if (auto fb = GetVulkanFrameBuffer()) - { - if (TexImage.Image) fb->GetCommands()->FrameDeleteList.Images.push_back(std::move(TexImage.Image)); - if (TexImage.View) fb->GetCommands()->FrameDeleteList.ImageViews.push_back(std::move(TexImage.View)); - if (TexImage.DepthOnlyView) fb->GetCommands()->FrameDeleteList.ImageViews.push_back(std::move(TexImage.DepthOnlyView)); - if (TexImage.PPFramebuffer) fb->GetCommands()->FrameDeleteList.Framebuffers.push_back(std::move(TexImage.PPFramebuffer)); - if (Staging) fb->GetCommands()->FrameDeleteList.Buffers.push_back(std::move(Staging)); - } -} - -///////////////////////////////////////////////////////////////////////////// - -VkPPShader::VkPPShader(PPShader *shader) -{ - auto fb = GetVulkanFrameBuffer(); - - FString prolog; - if (!shader->Uniforms.empty()) - prolog = UniformBlockDecl::Create("Uniforms", shader->Uniforms, -1); - prolog += shader->Defines; - - ShaderBuilder vertbuilder; - vertbuilder.setVertexShader(LoadShaderCode(shader->VertexShader, "", shader->Version)); - VertexShader = vertbuilder.create(shader->VertexShader.GetChars(), fb->device); - VertexShader->SetDebugName(shader->VertexShader.GetChars()); - - ShaderBuilder fragbuilder; - fragbuilder.setFragmentShader(LoadShaderCode(shader->FragmentShader, prolog, shader->Version)); - FragmentShader = fragbuilder.create(shader->FragmentShader.GetChars(), fb->device); - FragmentShader->SetDebugName(shader->FragmentShader.GetChars()); -} - -FString VkPPShader::LoadShaderCode(const FString &lumpName, const FString &defines, int version) -{ - int lump = fileSystem.CheckNumForFullName(lumpName); - if (lump == -1) I_FatalError("Unable to load '%s'", lumpName.GetChars()); - FString code = fileSystem.ReadFile(lump).GetString().GetChars(); - - FString patchedCode; - patchedCode.AppendFormat("#version %d\n", 450); - patchedCode << defines; - patchedCode << "#line 1\n"; - patchedCode << code; - return patchedCode; -} - -///////////////////////////////////////////////////////////////////////////// - -void VkPPRenderState::PushGroup(const FString &name) -{ - GetVulkanFrameBuffer()->GetCommands()->PushGroup(name); -} - -void VkPPRenderState::PopGroup() -{ - GetVulkanFrameBuffer()->GetCommands()->PopGroup(); -} - -void VkPPRenderState::Draw() -{ - auto fb = GetVulkanFrameBuffer(); - auto pp = fb->GetPostprocess(); - - fb->GetRenderState()->EndRenderPass(); - - VkPPRenderPassKey key; - key.BlendMode = BlendMode; - key.InputTextures = Textures.Size(); - key.Uniforms = Uniforms.Data.Size(); - key.Shader = GetVkShader(Shader); - key.SwapChain = (Output.Type == PPTextureType::SwapChain); - key.ShadowMapBuffers = ShadowMapBuffers; - if (Output.Type == PPTextureType::PPTexture) - key.OutputFormat = GetVkTexture(Output.Texture)->Format; - else if (Output.Type == PPTextureType::SwapChain) - key.OutputFormat = GetVulkanFrameBuffer()->GetCommands()->swapChain->swapChainFormat.format; - else if (Output.Type == PPTextureType::ShadowMap) - key.OutputFormat = VK_FORMAT_R32_SFLOAT; - else - key.OutputFormat = VK_FORMAT_R16G16B16A16_SFLOAT; - - if (Output.Type == PPTextureType::SceneColor) - { - key.StencilTest = 1; - key.Samples = fb->GetBuffers()->GetSceneSamples(); - } - else - { - key.StencilTest = 0; - key.Samples = VK_SAMPLE_COUNT_1_BIT; - } - - auto &passSetup = pp->mRenderPassSetup[key]; - if (!passSetup) - passSetup.reset(new VkPPRenderPassSetup(key)); - - int framebufferWidth = 0, framebufferHeight = 0; - VulkanDescriptorSet *input = GetInput(passSetup.get(), Textures, ShadowMapBuffers); - VulkanFramebuffer *output = GetOutput(passSetup.get(), Output, key.StencilTest, framebufferWidth, framebufferHeight); - - RenderScreenQuad(passSetup.get(), input, output, framebufferWidth, framebufferHeight, Viewport.left, Viewport.top, Viewport.width, Viewport.height, Uniforms.Data.Data(), Uniforms.Data.Size(), key.StencilTest); - - // Advance to next PP texture if our output was sent there - if (Output.Type == PPTextureType::NextPipelineTexture) - { - pp->mCurrentPipelineImage = (pp->mCurrentPipelineImage + 1) % VkRenderBuffers::NumPipelineImages; - } -} - -void VkPPRenderState::RenderScreenQuad(VkPPRenderPassSetup *passSetup, VulkanDescriptorSet *descriptorSet, VulkanFramebuffer *framebuffer, int framebufferWidth, int framebufferHeight, int x, int y, int width, int height, const void *pushConstants, uint32_t pushConstantsSize, bool stencilTest) -{ - auto fb = GetVulkanFrameBuffer(); - auto cmdbuffer = fb->GetCommands()->GetDrawCommands(); - - VkViewport viewport = { }; - viewport.x = (float)x; - viewport.y = (float)y; - viewport.width = (float)width; - viewport.height = (float)height; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - - VkRect2D scissor = { }; - scissor.offset.x = 0; - scissor.offset.y = 0; - scissor.extent.width = framebufferWidth; - scissor.extent.height = framebufferHeight; - - RenderPassBegin beginInfo; - beginInfo.setRenderPass(passSetup->RenderPass.get()); - beginInfo.setRenderArea(0, 0, framebufferWidth, framebufferHeight); - beginInfo.setFramebuffer(framebuffer); - beginInfo.addClearColor(0.0f, 0.0f, 0.0f, 1.0f); - - VkBuffer vertexBuffers[] = { static_cast(screen->mVertexData->GetBufferObjects().first)->mBuffer->buffer }; - VkDeviceSize offsets[] = { 0 }; - - cmdbuffer->beginRenderPass(beginInfo); - cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, passSetup->Pipeline.get()); - cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passSetup->PipelineLayout.get(), 0, descriptorSet); - cmdbuffer->bindVertexBuffers(0, 1, vertexBuffers, offsets); - cmdbuffer->setViewport(0, 1, &viewport); - cmdbuffer->setScissor(0, 1, &scissor); - if (stencilTest) - cmdbuffer->setStencilReference(VK_STENCIL_FRONT_AND_BACK, screen->stencilValue); - if (pushConstantsSize > 0) - cmdbuffer->pushConstants(passSetup->PipelineLayout.get(), VK_SHADER_STAGE_FRAGMENT_BIT, 0, pushConstantsSize, pushConstants); - cmdbuffer->draw(3, 1, FFlatVertexBuffer::PRESENT_INDEX, 0); - cmdbuffer->endRenderPass(); -} - -VulkanDescriptorSet *VkPPRenderState::GetInput(VkPPRenderPassSetup *passSetup, const TArray &textures, bool bindShadowMapBuffers) -{ - auto fb = GetVulkanFrameBuffer(); - auto pp = fb->GetPostprocess(); - auto descriptors = pp->AllocateDescriptorSet(passSetup->DescriptorLayout.get()); - descriptors->SetDebugName("VkPostprocess.descriptors"); - - WriteDescriptors write; - VkImageTransition imageTransition; - - for (unsigned int index = 0; index < textures.Size(); index++) - { - const PPTextureInput &input = textures[index]; - VulkanSampler *sampler = pp->GetSampler(input.Filter, input.Wrap); - VkTextureImage *tex = GetTexture(input.Type, input.Texture); - - write.addCombinedImageSampler(descriptors.get(), index, tex->DepthOnlyView ? tex->DepthOnlyView.get() : tex->View.get(), sampler, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - imageTransition.addImage(tex, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false); - } - - if (bindShadowMapBuffers) - { - write.addBuffer(descriptors.get(), LIGHTNODES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->LightNodes->mBuffer.get()); - write.addBuffer(descriptors.get(), LIGHTLINES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->LightLines->mBuffer.get()); - write.addBuffer(descriptors.get(), LIGHTLIST_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->LightList->mBuffer.get()); - } - - write.updateSets(fb->device); - imageTransition.execute(fb->GetCommands()->GetDrawCommands()); - - VulkanDescriptorSet *set = descriptors.get(); - fb->GetCommands()->FrameDeleteList.Descriptors.push_back(std::move(descriptors)); - return set; -} - -VulkanFramebuffer *VkPPRenderState::GetOutput(VkPPRenderPassSetup *passSetup, const PPOutput &output, bool stencilTest, int &framebufferWidth, int &framebufferHeight) -{ - auto fb = GetVulkanFrameBuffer(); - - VkTextureImage *tex = GetTexture(output.Type, output.Texture); - - VkImageView view; - std::unique_ptr *framebufferptr = nullptr; - int w, h; - if (tex) - { - VkImageTransition imageTransition; - imageTransition.addImage(tex, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, output.Type == PPTextureType::NextPipelineTexture); - if (stencilTest) - imageTransition.addImage(&fb->GetBuffers()->SceneDepthStencil, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false); - imageTransition.execute(fb->GetCommands()->GetDrawCommands()); - - view = tex->View->view; - w = tex->Image->width; - h = tex->Image->height; - framebufferptr = &tex->PPFramebuffer; - } - else - { - view = fb->GetCommands()->swapChain->swapChainImageViews[fb->GetCommands()->presentImageIndex]; - framebufferptr = &fb->GetCommands()->swapChain->framebuffers[fb->GetCommands()->presentImageIndex]; - w = fb->GetCommands()->swapChain->actualExtent.width; - h = fb->GetCommands()->swapChain->actualExtent.height; - } - - auto &framebuffer = *framebufferptr; - if (!framebuffer) - { - FramebufferBuilder builder; - builder.setRenderPass(passSetup->RenderPass.get()); - builder.setSize(w, h); - builder.addAttachment(view); - if (stencilTest) - builder.addAttachment(fb->GetBuffers()->SceneDepthStencil.View.get()); - framebuffer = builder.create(GetVulkanFrameBuffer()->device); - } - - framebufferWidth = w; - framebufferHeight = h; - return framebuffer.get(); -} - -VkTextureImage *VkPPRenderState::GetTexture(const PPTextureType &type, PPTexture *pptexture) -{ - auto fb = GetVulkanFrameBuffer(); - - if (type == PPTextureType::CurrentPipelineTexture || type == PPTextureType::NextPipelineTexture) - { - int idx = fb->GetPostprocess()->mCurrentPipelineImage; - if (type == PPTextureType::NextPipelineTexture) - idx = (idx + 1) % VkRenderBuffers::NumPipelineImages; - - return &fb->GetBuffers()->PipelineImage[idx]; - } - else if (type == PPTextureType::PPTexture) - { - auto vktex = GetVkTexture(pptexture); - return &vktex->TexImage; - } - else if (type == PPTextureType::SceneColor) - { - return &fb->GetBuffers()->SceneColor; - } - else if (type == PPTextureType::SceneNormal) - { - return &fb->GetBuffers()->SceneNormal; - } - else if (type == PPTextureType::SceneFog) - { - return &fb->GetBuffers()->SceneFog; - } - else if (type == PPTextureType::SceneDepth) - { - return &fb->GetBuffers()->SceneDepthStencil; - } - else if (type == PPTextureType::ShadowMap) - { - return &fb->GetBuffers()->Shadowmap; - } - else if (type == PPTextureType::SwapChain) - { - return nullptr; - } - else - { - I_FatalError("VkPPRenderState::GetTexture not implemented yet for this texture type"); - return nullptr; - } -} - -VkPPShader *VkPPRenderState::GetVkShader(PPShader *shader) -{ - if (!shader->Backend) - shader->Backend = std::make_unique(shader); - return static_cast(shader->Backend.get()); -} - -VkPPTexture *VkPPRenderState::GetVkTexture(PPTexture *texture) -{ - if (!texture->Backend) - texture->Backend = std::make_unique(texture); - return static_cast(texture->Backend.get()); -} - -///////////////////////////////////////////////////////////////////////////// - -VkPPRenderPassSetup::VkPPRenderPassSetup(const VkPPRenderPassKey &key) -{ - CreateDescriptorLayout(key); - CreatePipelineLayout(key); - CreateRenderPass(key); - CreatePipeline(key); -} - -void VkPPRenderPassSetup::CreateDescriptorLayout(const VkPPRenderPassKey &key) -{ - DescriptorSetLayoutBuilder builder; - for (int i = 0; i < key.InputTextures; i++) - builder.addBinding(i, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - if (key.ShadowMapBuffers) - { - builder.addBinding(LIGHTNODES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - builder.addBinding(LIGHTLINES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - builder.addBinding(LIGHTLIST_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); - } - DescriptorLayout = builder.create(GetVulkanFrameBuffer()->device); - DescriptorLayout->SetDebugName("VkPPRenderPassSetup.DescriptorLayout"); -} - -void VkPPRenderPassSetup::CreatePipelineLayout(const VkPPRenderPassKey &key) -{ - PipelineLayoutBuilder builder; - builder.addSetLayout(DescriptorLayout.get()); - if (key.Uniforms > 0) - builder.addPushConstantRange(VK_SHADER_STAGE_FRAGMENT_BIT, 0, key.Uniforms); - PipelineLayout = builder.create(GetVulkanFrameBuffer()->device); - PipelineLayout->SetDebugName("VkPPRenderPassSetup.PipelineLayout"); -} - -void VkPPRenderPassSetup::CreatePipeline(const VkPPRenderPassKey &key) -{ - GraphicsPipelineBuilder builder; - builder.addVertexShader(key.Shader->VertexShader.get()); - builder.addFragmentShader(key.Shader->FragmentShader.get()); - - builder.addVertexBufferBinding(0, sizeof(FFlatVertex)); - builder.addVertexAttribute(0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(FFlatVertex, x)); - builder.addVertexAttribute(1, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(FFlatVertex, u)); - builder.addDynamicState(VK_DYNAMIC_STATE_VIEWPORT); - builder.addDynamicState(VK_DYNAMIC_STATE_SCISSOR); - // Note: the actual values are ignored since we use dynamic viewport+scissor states - builder.setViewport(0.0f, 0.0f, 320.0f, 200.0f); - builder.setScissor(0, 0, 320, 200); - if (key.StencilTest) - { - builder.addDynamicState(VK_DYNAMIC_STATE_STENCIL_REFERENCE); - builder.setDepthStencilEnable(false, false, true); - builder.setStencil(VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_EQUAL, 0xffffffff, 0xffffffff, 0); - } - builder.setTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP); - builder.setBlendMode(key.BlendMode); - builder.setRasterizationSamples(key.Samples); - builder.setLayout(PipelineLayout.get()); - builder.setRenderPass(RenderPass.get()); - Pipeline = builder.create(GetVulkanFrameBuffer()->device); - Pipeline->SetDebugName("VkPPRenderPassSetup.Pipeline"); -} - -void VkPPRenderPassSetup::CreateRenderPass(const VkPPRenderPassKey &key) -{ - RenderPassBuilder builder; - if (key.SwapChain) - builder.addAttachment(key.OutputFormat, key.Samples, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); - else - builder.addAttachment(key.OutputFormat, key.Samples, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - if (key.StencilTest) - { - builder.addDepthStencilAttachment( - GetVulkanFrameBuffer()->GetBuffers()->SceneDepthStencilFormat, key.Samples, - VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - } - - builder.addSubpass(); - builder.addSubpassColorAttachmentRef(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - if (key.StencilTest) - { - builder.addSubpassDepthStencilAttachmentRef(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - builder.addExternalSubpassDependency( - VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT); - } - else - { - builder.addExternalSubpassDependency( - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT); - } - - RenderPass = builder.create(GetVulkanFrameBuffer()->device); - RenderPass->SetDebugName("VkPPRenderPassSetup.RenderPass"); -} diff --git a/src/common/rendering/vulkan/renderer/vk_postprocess.h b/src/common/rendering/vulkan/renderer/vk_postprocess.h index 67660fe51..ee91d6225 100644 --- a/src/common/rendering/vulkan/renderer/vk_postprocess.h +++ b/src/common/rendering/vulkan/renderer/vk_postprocess.h @@ -14,35 +14,14 @@ class FString; class VkPPShader; class VkPPTexture; -class VkPPRenderPassSetup; class PipelineBarrier; -class VkPPRenderPassKey -{ -public: - VkPPShader *Shader; - int Uniforms; - int InputTextures; - PPBlendMode BlendMode; - VkFormat OutputFormat; - int SwapChain; - int ShadowMapBuffers; - int StencilTest; - VkSampleCountFlagBits Samples; - - bool operator<(const VkPPRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkPPRenderPassKey)) < 0; } - bool operator==(const VkPPRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkPPRenderPassKey)) == 0; } - bool operator!=(const VkPPRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkPPRenderPassKey)) != 0; } -}; - class VkPostprocess { public: VkPostprocess(); ~VkPostprocess(); - void RenderBuffersReset(); - void SetActiveRenderTarget(); void PostProcessScene(int fixedcm, float flash, const std::function &afterBloomDrawEndScene2D); @@ -62,72 +41,9 @@ private: void NextEye(int eyeCount); std::unique_ptr AllocateDescriptorSet(VulkanDescriptorSetLayout *layout); - VulkanSampler *GetSampler(PPFilterMode filter, PPWrapMode wrap); - std::array, 4> mSamplers; - std::map> mRenderPassSetup; std::unique_ptr mDescriptorPool; int mCurrentPipelineImage = 0; friend class VkPPRenderState; }; - -class VkPPShader : public PPShaderBackend -{ -public: - VkPPShader(PPShader *shader); - - std::unique_ptr VertexShader; - std::unique_ptr FragmentShader; - -private: - FString LoadShaderCode(const FString &lumpname, const FString &defines, int version); -}; - -class VkPPTexture : public PPTextureBackend -{ -public: - VkPPTexture(PPTexture *texture); - ~VkPPTexture(); - - VkTextureImage TexImage; - std::unique_ptr Staging; - VkFormat Format; -}; - -class VkPPRenderPassSetup -{ -public: - VkPPRenderPassSetup(const VkPPRenderPassKey &key); - - std::unique_ptr DescriptorLayout; - std::unique_ptr PipelineLayout; - std::unique_ptr RenderPass; - std::unique_ptr Pipeline; - -private: - void CreateDescriptorLayout(const VkPPRenderPassKey &key); - void CreatePipelineLayout(const VkPPRenderPassKey &key); - void CreatePipeline(const VkPPRenderPassKey &key); - void CreateRenderPass(const VkPPRenderPassKey &key); -}; - -class VkPPRenderState : public PPRenderState -{ -public: - void PushGroup(const FString &name) override; - void PopGroup() override; - - void Draw() override; - -private: - void RenderScreenQuad(VkPPRenderPassSetup *passSetup, VulkanDescriptorSet *descriptorSet, VulkanFramebuffer *framebuffer, int framebufferWidth, int framebufferHeight, int x, int y, int width, int height, const void *pushConstants, uint32_t pushConstantsSize, bool stencilTest); - - VulkanDescriptorSet *GetInput(VkPPRenderPassSetup *passSetup, const TArray &textures, bool bindShadowMapBuffers); - VulkanFramebuffer *GetOutput(VkPPRenderPassSetup *passSetup, const PPOutput &output, bool stencilTest, int &framebufferWidth, int &framebufferHeight); - - VkPPShader *GetVkShader(PPShader *shader); - VkPPTexture *GetVkTexture(PPTexture *texture); - - VkTextureImage *GetTexture(const PPTextureType &type, PPTexture *tex); -}; diff --git a/src/common/rendering/vulkan/renderer/vk_pprenderstate.cpp b/src/common/rendering/vulkan/renderer/vk_pprenderstate.cpp new file mode 100644 index 000000000..8d7c1530e --- /dev/null +++ b/src/common/rendering/vulkan/renderer/vk_pprenderstate.cpp @@ -0,0 +1,277 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include "vk_pprenderstate.h" +#include "vk_postprocess.h" +#include "vulkan/system/vk_framebuffer.h" +#include "vulkan/system/vk_commandbuffer.h" +#include "vulkan/system/vk_swapchain.h" +#include "vulkan/shaders/vk_ppshader.h" +#include "vulkan/textures/vk_pptexture.h" +#include "vulkan/textures/vk_renderbuffers.h" +#include "vulkan/textures/vk_samplers.h" +#include "vulkan/renderer/vk_renderstate.h" +#include "flatvertices.h" + +void VkPPRenderState::PushGroup(const FString &name) +{ + GetVulkanFrameBuffer()->GetCommands()->PushGroup(name); +} + +void VkPPRenderState::PopGroup() +{ + GetVulkanFrameBuffer()->GetCommands()->PopGroup(); +} + +void VkPPRenderState::Draw() +{ + auto fb = GetVulkanFrameBuffer(); + auto pp = fb->GetPostprocess(); + + fb->GetRenderState()->EndRenderPass(); + + VkPPRenderPassKey key; + key.BlendMode = BlendMode; + key.InputTextures = Textures.Size(); + key.Uniforms = Uniforms.Data.Size(); + key.Shader = GetVkShader(Shader); + key.SwapChain = (Output.Type == PPTextureType::SwapChain); + key.ShadowMapBuffers = ShadowMapBuffers; + if (Output.Type == PPTextureType::PPTexture) + key.OutputFormat = GetVkTexture(Output.Texture)->Format; + else if (Output.Type == PPTextureType::SwapChain) + key.OutputFormat = GetVulkanFrameBuffer()->GetCommands()->swapChain->swapChainFormat.format; + else if (Output.Type == PPTextureType::ShadowMap) + key.OutputFormat = VK_FORMAT_R32_SFLOAT; + else + key.OutputFormat = VK_FORMAT_R16G16B16A16_SFLOAT; + + if (Output.Type == PPTextureType::SceneColor) + { + key.StencilTest = 1; + key.Samples = fb->GetBuffers()->GetSceneSamples(); + } + else + { + key.StencilTest = 0; + key.Samples = VK_SAMPLE_COUNT_1_BIT; + } + + auto passSetup = fb->GetRenderPassManager()->GetPPRenderPass(key); + + int framebufferWidth = 0, framebufferHeight = 0; + VulkanDescriptorSet *input = GetInput(passSetup, Textures, ShadowMapBuffers); + VulkanFramebuffer *output = GetOutput(passSetup, Output, key.StencilTest, framebufferWidth, framebufferHeight); + + RenderScreenQuad(passSetup, input, output, framebufferWidth, framebufferHeight, Viewport.left, Viewport.top, Viewport.width, Viewport.height, Uniforms.Data.Data(), Uniforms.Data.Size(), key.StencilTest); + + // Advance to next PP texture if our output was sent there + if (Output.Type == PPTextureType::NextPipelineTexture) + { + pp->mCurrentPipelineImage = (pp->mCurrentPipelineImage + 1) % VkRenderBuffers::NumPipelineImages; + } +} + +void VkPPRenderState::RenderScreenQuad(VkPPRenderPassSetup *passSetup, VulkanDescriptorSet *descriptorSet, VulkanFramebuffer *framebuffer, int framebufferWidth, int framebufferHeight, int x, int y, int width, int height, const void *pushConstants, uint32_t pushConstantsSize, bool stencilTest) +{ + auto fb = GetVulkanFrameBuffer(); + auto cmdbuffer = fb->GetCommands()->GetDrawCommands(); + + VkViewport viewport = { }; + viewport.x = (float)x; + viewport.y = (float)y; + viewport.width = (float)width; + viewport.height = (float)height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor = { }; + scissor.offset.x = 0; + scissor.offset.y = 0; + scissor.extent.width = framebufferWidth; + scissor.extent.height = framebufferHeight; + + RenderPassBegin beginInfo; + beginInfo.setRenderPass(passSetup->RenderPass.get()); + beginInfo.setRenderArea(0, 0, framebufferWidth, framebufferHeight); + beginInfo.setFramebuffer(framebuffer); + beginInfo.addClearColor(0.0f, 0.0f, 0.0f, 1.0f); + + VkBuffer vertexBuffers[] = { static_cast(screen->mVertexData->GetBufferObjects().first)->mBuffer->buffer }; + VkDeviceSize offsets[] = { 0 }; + + cmdbuffer->beginRenderPass(beginInfo); + cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, passSetup->Pipeline.get()); + cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passSetup->PipelineLayout.get(), 0, descriptorSet); + cmdbuffer->bindVertexBuffers(0, 1, vertexBuffers, offsets); + cmdbuffer->setViewport(0, 1, &viewport); + cmdbuffer->setScissor(0, 1, &scissor); + if (stencilTest) + cmdbuffer->setStencilReference(VK_STENCIL_FRONT_AND_BACK, screen->stencilValue); + if (pushConstantsSize > 0) + cmdbuffer->pushConstants(passSetup->PipelineLayout.get(), VK_SHADER_STAGE_FRAGMENT_BIT, 0, pushConstantsSize, pushConstants); + cmdbuffer->draw(3, 1, FFlatVertexBuffer::PRESENT_INDEX, 0); + cmdbuffer->endRenderPass(); +} + +VulkanDescriptorSet *VkPPRenderState::GetInput(VkPPRenderPassSetup *passSetup, const TArray &textures, bool bindShadowMapBuffers) +{ + auto fb = GetVulkanFrameBuffer(); + auto descriptors = fb->GetPostprocess()->AllocateDescriptorSet(passSetup->DescriptorLayout.get()); + descriptors->SetDebugName("VkPostprocess.descriptors"); + + WriteDescriptors write; + VkImageTransition imageTransition; + + for (unsigned int index = 0; index < textures.Size(); index++) + { + const PPTextureInput &input = textures[index]; + VulkanSampler *sampler = fb->GetSamplerManager()->Get(input.Filter, input.Wrap); + VkTextureImage *tex = GetTexture(input.Type, input.Texture); + + write.addCombinedImageSampler(descriptors.get(), index, tex->DepthOnlyView ? tex->DepthOnlyView.get() : tex->View.get(), sampler, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + imageTransition.addImage(tex, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false); + } + + if (bindShadowMapBuffers) + { + write.addBuffer(descriptors.get(), LIGHTNODES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->LightNodes->mBuffer.get()); + write.addBuffer(descriptors.get(), LIGHTLINES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->LightLines->mBuffer.get()); + write.addBuffer(descriptors.get(), LIGHTLIST_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->LightList->mBuffer.get()); + } + + write.updateSets(fb->device); + imageTransition.execute(fb->GetCommands()->GetDrawCommands()); + + VulkanDescriptorSet *set = descriptors.get(); + fb->GetCommands()->FrameDeleteList.Descriptors.push_back(std::move(descriptors)); + return set; +} + +VulkanFramebuffer *VkPPRenderState::GetOutput(VkPPRenderPassSetup *passSetup, const PPOutput &output, bool stencilTest, int &framebufferWidth, int &framebufferHeight) +{ + auto fb = GetVulkanFrameBuffer(); + + VkTextureImage *tex = GetTexture(output.Type, output.Texture); + + VkImageView view; + std::unique_ptr *framebufferptr = nullptr; + int w, h; + if (tex) + { + VkImageTransition imageTransition; + imageTransition.addImage(tex, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, output.Type == PPTextureType::NextPipelineTexture); + if (stencilTest) + imageTransition.addImage(&fb->GetBuffers()->SceneDepthStencil, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false); + imageTransition.execute(fb->GetCommands()->GetDrawCommands()); + + view = tex->View->view; + w = tex->Image->width; + h = tex->Image->height; + framebufferptr = &tex->PPFramebuffer; + } + else + { + view = fb->GetCommands()->swapChain->swapChainImageViews[fb->GetCommands()->presentImageIndex]; + framebufferptr = &fb->GetCommands()->swapChain->framebuffers[fb->GetCommands()->presentImageIndex]; + w = fb->GetCommands()->swapChain->actualExtent.width; + h = fb->GetCommands()->swapChain->actualExtent.height; + } + + auto &framebuffer = *framebufferptr; + if (!framebuffer) + { + FramebufferBuilder builder; + builder.setRenderPass(passSetup->RenderPass.get()); + builder.setSize(w, h); + builder.addAttachment(view); + if (stencilTest) + builder.addAttachment(fb->GetBuffers()->SceneDepthStencil.View.get()); + framebuffer = builder.create(GetVulkanFrameBuffer()->device); + } + + framebufferWidth = w; + framebufferHeight = h; + return framebuffer.get(); +} + +VkTextureImage *VkPPRenderState::GetTexture(const PPTextureType &type, PPTexture *pptexture) +{ + auto fb = GetVulkanFrameBuffer(); + + if (type == PPTextureType::CurrentPipelineTexture || type == PPTextureType::NextPipelineTexture) + { + int idx = fb->GetPostprocess()->mCurrentPipelineImage; + if (type == PPTextureType::NextPipelineTexture) + idx = (idx + 1) % VkRenderBuffers::NumPipelineImages; + + return &fb->GetBuffers()->PipelineImage[idx]; + } + else if (type == PPTextureType::PPTexture) + { + auto vktex = GetVkTexture(pptexture); + return &vktex->TexImage; + } + else if (type == PPTextureType::SceneColor) + { + return &fb->GetBuffers()->SceneColor; + } + else if (type == PPTextureType::SceneNormal) + { + return &fb->GetBuffers()->SceneNormal; + } + else if (type == PPTextureType::SceneFog) + { + return &fb->GetBuffers()->SceneFog; + } + else if (type == PPTextureType::SceneDepth) + { + return &fb->GetBuffers()->SceneDepthStencil; + } + else if (type == PPTextureType::ShadowMap) + { + return &fb->GetBuffers()->Shadowmap; + } + else if (type == PPTextureType::SwapChain) + { + return nullptr; + } + else + { + I_FatalError("VkPPRenderState::GetTexture not implemented yet for this texture type"); + return nullptr; + } +} + +VkPPShader *VkPPRenderState::GetVkShader(PPShader *shader) +{ + if (!shader->Backend) + shader->Backend = std::make_unique(shader); + return static_cast(shader->Backend.get()); +} + +VkPPTexture *VkPPRenderState::GetVkTexture(PPTexture *texture) +{ + if (!texture->Backend) + texture->Backend = std::make_unique(texture); + return static_cast(texture->Backend.get()); +} diff --git a/src/common/rendering/vulkan/renderer/vk_pprenderstate.h b/src/common/rendering/vulkan/renderer/vk_pprenderstate.h new file mode 100644 index 000000000..8f63a2486 --- /dev/null +++ b/src/common/rendering/vulkan/renderer/vk_pprenderstate.h @@ -0,0 +1,30 @@ + +#pragma once + +#include "hwrenderer/postprocessing/hw_postprocess.h" +#include "vulkan/system/vk_objects.h" + +class VkPPRenderPassSetup; +class VkPPShader; +class VkPPTexture; +class VkTextureImage; + +class VkPPRenderState : public PPRenderState +{ +public: + void PushGroup(const FString &name) override; + void PopGroup() override; + + void Draw() override; + +private: + void RenderScreenQuad(VkPPRenderPassSetup *passSetup, VulkanDescriptorSet *descriptorSet, VulkanFramebuffer *framebuffer, int framebufferWidth, int framebufferHeight, int x, int y, int width, int height, const void *pushConstants, uint32_t pushConstantsSize, bool stencilTest); + + VulkanDescriptorSet *GetInput(VkPPRenderPassSetup *passSetup, const TArray &textures, bool bindShadowMapBuffers); + VulkanFramebuffer *GetOutput(VkPPRenderPassSetup *passSetup, const PPOutput &output, bool stencilTest, int &framebufferWidth, int &framebufferHeight); + + VkPPShader *GetVkShader(PPShader *shader); + VkPPTexture *GetVkTexture(PPTexture *texture); + + VkTextureImage *GetTexture(const PPTextureType &type, PPTexture *tex); +}; diff --git a/src/common/rendering/vulkan/renderer/vk_renderpass.cpp b/src/common/rendering/vulkan/renderer/vk_renderpass.cpp index 672272d8f..78bfe56a4 100644 --- a/src/common/rendering/vulkan/renderer/vk_renderpass.cpp +++ b/src/common/rendering/vulkan/renderer/vk_renderpass.cpp @@ -27,6 +27,7 @@ #include "vulkan/textures/vk_renderbuffers.h" #include "vulkan/textures/vk_samplers.h" #include "vulkan/shaders/vk_shader.h" +#include "vulkan/shaders/vk_ppshader.h" #include "vulkan/system/vk_builders.h" #include "vulkan/system/vk_framebuffer.h" #include "vulkan/system/vk_buffers.h" @@ -45,6 +46,7 @@ VkRenderPassManager::~VkRenderPassManager() void VkRenderPassManager::RenderBuffersReset() { RenderPassSetup.clear(); + PPRenderPassSetup.clear(); } VkRenderPassSetup *VkRenderPassManager::GetRenderPass(const VkRenderPassKey &key) @@ -120,6 +122,14 @@ VulkanPipelineLayout* VkRenderPassManager::GetPipelineLayout(int numLayers) return layout.get(); } +VkPPRenderPassSetup* VkRenderPassManager::GetPPRenderPass(const VkPPRenderPassKey& key) +{ + auto& passSetup = PPRenderPassSetup[key]; + if (!passSetup) + passSetup.reset(new VkPPRenderPassSetup(key)); + return passSetup.get(); +} + ///////////////////////////////////////////////////////////////////////////// VkRenderPassSetup::VkRenderPassSetup(const VkRenderPassKey &key) : PassKey(key) @@ -284,3 +294,107 @@ std::unique_ptr VkRenderPassSetup::CreatePipeline(const VkPipeli pipeline->SetDebugName("VkRenderPassSetup.Pipeline"); return pipeline; } + +///////////////////////////////////////////////////////////////////////////// + +VkPPRenderPassSetup::VkPPRenderPassSetup(const VkPPRenderPassKey& key) +{ + CreateDescriptorLayout(key); + CreatePipelineLayout(key); + CreateRenderPass(key); + CreatePipeline(key); +} + +void VkPPRenderPassSetup::CreateDescriptorLayout(const VkPPRenderPassKey& key) +{ + DescriptorSetLayoutBuilder builder; + for (int i = 0; i < key.InputTextures; i++) + builder.addBinding(i, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + if (key.ShadowMapBuffers) + { + builder.addBinding(LIGHTNODES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + builder.addBinding(LIGHTLINES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + builder.addBinding(LIGHTLIST_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT); + } + DescriptorLayout = builder.create(GetVulkanFrameBuffer()->device); + DescriptorLayout->SetDebugName("VkPPRenderPassSetup.DescriptorLayout"); +} + +void VkPPRenderPassSetup::CreatePipelineLayout(const VkPPRenderPassKey& key) +{ + PipelineLayoutBuilder builder; + builder.addSetLayout(DescriptorLayout.get()); + if (key.Uniforms > 0) + builder.addPushConstantRange(VK_SHADER_STAGE_FRAGMENT_BIT, 0, key.Uniforms); + PipelineLayout = builder.create(GetVulkanFrameBuffer()->device); + PipelineLayout->SetDebugName("VkPPRenderPassSetup.PipelineLayout"); +} + +void VkPPRenderPassSetup::CreatePipeline(const VkPPRenderPassKey& key) +{ + GraphicsPipelineBuilder builder; + builder.addVertexShader(key.Shader->VertexShader.get()); + builder.addFragmentShader(key.Shader->FragmentShader.get()); + + builder.addVertexBufferBinding(0, sizeof(FFlatVertex)); + builder.addVertexAttribute(0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(FFlatVertex, x)); + builder.addVertexAttribute(1, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(FFlatVertex, u)); + builder.addDynamicState(VK_DYNAMIC_STATE_VIEWPORT); + builder.addDynamicState(VK_DYNAMIC_STATE_SCISSOR); + // Note: the actual values are ignored since we use dynamic viewport+scissor states + builder.setViewport(0.0f, 0.0f, 320.0f, 200.0f); + builder.setScissor(0, 0, 320, 200); + if (key.StencilTest) + { + builder.addDynamicState(VK_DYNAMIC_STATE_STENCIL_REFERENCE); + builder.setDepthStencilEnable(false, false, true); + builder.setStencil(VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_EQUAL, 0xffffffff, 0xffffffff, 0); + } + builder.setTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP); + builder.setBlendMode(key.BlendMode); + builder.setRasterizationSamples(key.Samples); + builder.setLayout(PipelineLayout.get()); + builder.setRenderPass(RenderPass.get()); + Pipeline = builder.create(GetVulkanFrameBuffer()->device); + Pipeline->SetDebugName("VkPPRenderPassSetup.Pipeline"); +} + +void VkPPRenderPassSetup::CreateRenderPass(const VkPPRenderPassKey& key) +{ + RenderPassBuilder builder; + if (key.SwapChain) + builder.addAttachment(key.OutputFormat, key.Samples, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + else + builder.addAttachment(key.OutputFormat, key.Samples, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + if (key.StencilTest) + { + builder.addDepthStencilAttachment( + GetVulkanFrameBuffer()->GetBuffers()->SceneDepthStencilFormat, key.Samples, + VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, + VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + } + + builder.addSubpass(); + builder.addSubpassColorAttachmentRef(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + if (key.StencilTest) + { + builder.addSubpassDepthStencilAttachmentRef(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + builder.addExternalSubpassDependency( + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT); + } + else + { + builder.addExternalSubpassDependency( + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT); + } + + RenderPass = builder.create(GetVulkanFrameBuffer()->device); + RenderPass->SetDebugName("VkPPRenderPassSetup.RenderPass"); +} diff --git a/src/common/rendering/vulkan/renderer/vk_renderpass.h b/src/common/rendering/vulkan/renderer/vk_renderpass.h index ba5867b6a..943cfdb0a 100644 --- a/src/common/rendering/vulkan/renderer/vk_renderpass.h +++ b/src/common/rendering/vulkan/renderer/vk_renderpass.h @@ -4,11 +4,12 @@ #include "vulkan/system/vk_objects.h" #include "renderstyle.h" #include "hwrenderer/data/buffers.h" +#include "hwrenderer/postprocessing/hw_postprocess.h" #include "hw_renderstate.h" #include #include -class VKDataBuffer; +class VkPPShader; class VkPipelineKey { @@ -74,6 +75,41 @@ public: int UseVertexData; }; +class VkPPRenderPassKey +{ +public: + VkPPShader* Shader; + int Uniforms; + int InputTextures; + PPBlendMode BlendMode; + VkFormat OutputFormat; + int SwapChain; + int ShadowMapBuffers; + int StencilTest; + VkSampleCountFlagBits Samples; + + bool operator<(const VkPPRenderPassKey& other) const { return memcmp(this, &other, sizeof(VkPPRenderPassKey)) < 0; } + bool operator==(const VkPPRenderPassKey& other) const { return memcmp(this, &other, sizeof(VkPPRenderPassKey)) == 0; } + bool operator!=(const VkPPRenderPassKey& other) const { return memcmp(this, &other, sizeof(VkPPRenderPassKey)) != 0; } +}; + +class VkPPRenderPassSetup +{ +public: + VkPPRenderPassSetup(const VkPPRenderPassKey& key); + + std::unique_ptr DescriptorLayout; + std::unique_ptr PipelineLayout; + std::unique_ptr RenderPass; + std::unique_ptr Pipeline; + +private: + void CreateDescriptorLayout(const VkPPRenderPassKey& key); + void CreatePipelineLayout(const VkPPRenderPassKey& key); + void CreatePipeline(const VkPPRenderPassKey& key); + void CreateRenderPass(const VkPPRenderPassKey& key); +}; + class VkRenderPassManager { public: @@ -87,8 +123,12 @@ public: VkVertexFormat *GetVertexFormat(int index); VulkanPipelineLayout* GetPipelineLayout(int numLayers); + VkPPRenderPassSetup* GetPPRenderPass(const VkPPRenderPassKey& key); + private: std::map> RenderPassSetup; std::vector> PipelineLayouts; std::vector VertexFormats; + + std::map> PPRenderPassSetup; }; diff --git a/src/common/rendering/vulkan/shaders/vk_ppshader.cpp b/src/common/rendering/vulkan/shaders/vk_ppshader.cpp new file mode 100644 index 000000000..8f9a9f799 --- /dev/null +++ b/src/common/rendering/vulkan/shaders/vk_ppshader.cpp @@ -0,0 +1,60 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include "vk_ppshader.h" +#include "vulkan/system/vk_framebuffer.h" +#include "vulkan/system/vk_builders.h" +#include "filesystem.h" + +VkPPShader::VkPPShader(PPShader *shader) +{ + auto fb = GetVulkanFrameBuffer(); + + FString prolog; + if (!shader->Uniforms.empty()) + prolog = UniformBlockDecl::Create("Uniforms", shader->Uniforms, -1); + prolog += shader->Defines; + + ShaderBuilder vertbuilder; + vertbuilder.setVertexShader(LoadShaderCode(shader->VertexShader, "", shader->Version)); + VertexShader = vertbuilder.create(shader->VertexShader.GetChars(), fb->device); + VertexShader->SetDebugName(shader->VertexShader.GetChars()); + + ShaderBuilder fragbuilder; + fragbuilder.setFragmentShader(LoadShaderCode(shader->FragmentShader, prolog, shader->Version)); + FragmentShader = fragbuilder.create(shader->FragmentShader.GetChars(), fb->device); + FragmentShader->SetDebugName(shader->FragmentShader.GetChars()); +} + +FString VkPPShader::LoadShaderCode(const FString &lumpName, const FString &defines, int version) +{ + int lump = fileSystem.CheckNumForFullName(lumpName); + if (lump == -1) I_FatalError("Unable to load '%s'", lumpName.GetChars()); + FString code = fileSystem.ReadFile(lump).GetString().GetChars(); + + FString patchedCode; + patchedCode.AppendFormat("#version %d\n", 450); + patchedCode << defines; + patchedCode << "#line 1\n"; + patchedCode << code; + return patchedCode; +} diff --git a/src/common/rendering/vulkan/shaders/vk_ppshader.h b/src/common/rendering/vulkan/shaders/vk_ppshader.h new file mode 100644 index 000000000..d25b4d4a1 --- /dev/null +++ b/src/common/rendering/vulkan/shaders/vk_ppshader.h @@ -0,0 +1,17 @@ + +#pragma once + +#include "hwrenderer/postprocessing/hw_postprocess.h" +#include "vulkan/system/vk_objects.h" + +class VkPPShader : public PPShaderBackend +{ +public: + VkPPShader(PPShader *shader); + + std::unique_ptr VertexShader; + std::unique_ptr FragmentShader; + +private: + FString LoadShaderCode(const FString &lumpname, const FString &defines, int version); +}; diff --git a/src/common/rendering/vulkan/system/vk_commandbuffer.h b/src/common/rendering/vulkan/system/vk_commandbuffer.h index 71c12e926..1caa16348 100644 --- a/src/common/rendering/vulkan/system/vk_commandbuffer.h +++ b/src/common/rendering/vulkan/system/vk_commandbuffer.h @@ -36,6 +36,7 @@ public: std::vector> Descriptors; std::vector> DescriptorPools; std::vector> CommandBuffers; + std::vector< std::unique_ptr> Samplers; } FrameDeleteList; struct diff --git a/src/common/rendering/vulkan/system/vk_framebuffer.cpp b/src/common/rendering/vulkan/system/vk_framebuffer.cpp index 99a8d296c..87c9a448d 100644 --- a/src/common/rendering/vulkan/system/vk_framebuffer.cpp +++ b/src/common/rendering/vulkan/system/vk_framebuffer.cpp @@ -151,7 +151,7 @@ void VulkanFrameBuffer::InitializeState() StreamBuffer = new VkStreamBuffer(sizeof(StreamUBO), 300); mShaderManager.reset(new VkShaderManager(device)); - mSamplerManager.reset(new VkSamplerManager(device)); + mSamplerManager.reset(new VkSamplerManager(this)); mDescriptorSetManager->Init(); #ifdef __APPLE__ mRenderState.reset(new VkRenderStateMolten()); @@ -299,10 +299,8 @@ void VulkanFrameBuffer::SetTextureFilterMode() { if (mSamplerManager) { - // Destroy the texture descriptors as they used the old samplers - VkMaterial::ResetAllDescriptors(); - - mSamplerManager->SetTextureFilterMode(); + mDescriptorSetManager->FilterModeChanged(); + mSamplerManager->FilterModeChanged(); } } diff --git a/src/common/rendering/vulkan/textures/vk_pptexture.cpp b/src/common/rendering/vulkan/textures/vk_pptexture.cpp new file mode 100644 index 000000000..e973491a1 --- /dev/null +++ b/src/common/rendering/vulkan/textures/vk_pptexture.cpp @@ -0,0 +1,108 @@ +/* +** Vulkan backend +** Copyright (c) 2016-2020 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +** +*/ + +#include "vk_pptexture.h" +#include "vulkan/system/vk_framebuffer.h" +#include "vulkan/system/vk_commandbuffer.h" + +VkPPTexture::VkPPTexture(PPTexture *texture) +{ + auto fb = GetVulkanFrameBuffer(); + + VkFormat format; + int pixelsize; + switch (texture->Format) + { + default: + case PixelFormat::Rgba8: format = VK_FORMAT_R8G8B8A8_UNORM; pixelsize = 4; break; + case PixelFormat::Rgba16f: format = VK_FORMAT_R16G16B16A16_SFLOAT; pixelsize = 8; break; + case PixelFormat::R32f: format = VK_FORMAT_R32_SFLOAT; pixelsize = 4; break; + case PixelFormat::Rg16f: format = VK_FORMAT_R16G16_SFLOAT; pixelsize = 4; break; + case PixelFormat::Rgba16_snorm: format = VK_FORMAT_R16G16B16A16_SNORM; pixelsize = 8; break; + } + + ImageBuilder imgbuilder; + imgbuilder.setFormat(format); + imgbuilder.setSize(texture->Width, texture->Height); + if (texture->Data) + imgbuilder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + else + imgbuilder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); + if (!imgbuilder.isFormatSupported(fb->device)) + I_FatalError("Vulkan device does not support the image format required by a postprocess texture\n"); + TexImage.Image = imgbuilder.create(fb->device); + TexImage.Image->SetDebugName("VkPPTexture"); + Format = format; + + ImageViewBuilder viewbuilder; + viewbuilder.setImage(TexImage.Image.get(), format); + TexImage.View = viewbuilder.create(fb->device); + TexImage.View->SetDebugName("VkPPTextureView"); + + if (texture->Data) + { + size_t totalsize = texture->Width * texture->Height * pixelsize; + BufferBuilder stagingbuilder; + stagingbuilder.setSize(totalsize); + stagingbuilder.setUsage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); + Staging = stagingbuilder.create(fb->device); + Staging->SetDebugName("VkPPTextureStaging"); + + VkImageTransition barrier0; + barrier0.addImage(&TexImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true); + barrier0.execute(fb->GetCommands()->GetTransferCommands()); + + void *data = Staging->Map(0, totalsize); + memcpy(data, texture->Data.get(), totalsize); + Staging->Unmap(); + + VkBufferImageCopy region = {}; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.layerCount = 1; + region.imageExtent.depth = 1; + region.imageExtent.width = texture->Width; + region.imageExtent.height = texture->Height; + fb->GetCommands()->GetTransferCommands()->copyBufferToImage(Staging->buffer, TexImage.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + VkImageTransition barrier1; + barrier1.addImage(&TexImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false); + barrier1.execute(fb->GetCommands()->GetTransferCommands()); + } + else + { + VkImageTransition barrier; + barrier.addImage(&TexImage, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true); + barrier.execute(fb->GetCommands()->GetTransferCommands()); + } +} + +VkPPTexture::~VkPPTexture() +{ + if (auto fb = GetVulkanFrameBuffer()) + { + if (TexImage.Image) fb->GetCommands()->FrameDeleteList.Images.push_back(std::move(TexImage.Image)); + if (TexImage.View) fb->GetCommands()->FrameDeleteList.ImageViews.push_back(std::move(TexImage.View)); + if (TexImage.DepthOnlyView) fb->GetCommands()->FrameDeleteList.ImageViews.push_back(std::move(TexImage.DepthOnlyView)); + if (TexImage.PPFramebuffer) fb->GetCommands()->FrameDeleteList.Framebuffers.push_back(std::move(TexImage.PPFramebuffer)); + if (Staging) fb->GetCommands()->FrameDeleteList.Buffers.push_back(std::move(Staging)); + } +} diff --git a/src/common/rendering/vulkan/textures/vk_pptexture.h b/src/common/rendering/vulkan/textures/vk_pptexture.h new file mode 100644 index 000000000..62f36c5bd --- /dev/null +++ b/src/common/rendering/vulkan/textures/vk_pptexture.h @@ -0,0 +1,17 @@ + +#pragma once + +#include "hwrenderer/postprocessing/hw_postprocess.h" +#include "vulkan/system/vk_objects.h" +#include "vulkan/textures/vk_imagetransition.h" + +class VkPPTexture : public PPTextureBackend +{ +public: + VkPPTexture(PPTexture *texture); + ~VkPPTexture(); + + VkTextureImage TexImage; + std::unique_ptr Staging; + VkFormat Format; +}; diff --git a/src/common/rendering/vulkan/textures/vk_renderbuffers.cpp b/src/common/rendering/vulkan/textures/vk_renderbuffers.cpp index 2cd3ef673..005d8de60 100644 --- a/src/common/rendering/vulkan/textures/vk_renderbuffers.cpp +++ b/src/common/rendering/vulkan/textures/vk_renderbuffers.cpp @@ -68,7 +68,6 @@ void VkRenderBuffers::BeginFrame(int width, int height, int sceneWidth, int scen { auto fb = GetVulkanFrameBuffer(); fb->GetRenderPassManager()->RenderBuffersReset(); - fb->GetPostprocess()->RenderBuffersReset(); } if (width != mWidth || height != mHeight) diff --git a/src/common/rendering/vulkan/textures/vk_samplers.cpp b/src/common/rendering/vulkan/textures/vk_samplers.cpp index 06e105aed..f47be0a91 100644 --- a/src/common/rendering/vulkan/textures/vk_samplers.cpp +++ b/src/common/rendering/vulkan/textures/vk_samplers.cpp @@ -23,13 +23,15 @@ #include "volk/volk.h" #include "c_cvars.h" #include "v_video.h" - #include "hw_cvars.h" #include "vulkan/system/vk_device.h" #include "vulkan/system/vk_builders.h" +#include "vulkan/system/vk_framebuffer.h" +#include "vulkan/system/vk_commandbuffer.h" #include "vk_samplers.h" #include "hw_material.h" #include "i_interface.h" +#include "hwrenderer/postprocessing/hw_postprocess.h" struct VkTexFilter { @@ -37,16 +39,17 @@ struct VkTexFilter VkFilter magFilter; VkSamplerMipmapMode mipfilter; bool mipmapping; -} ; +}; -VkTexFilter TexFilter[]={ +static VkTexFilter TexFilter[] = +{ {VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, false}, {VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, true}, {VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST, false}, {VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST, true}, {VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_LINEAR, true}, {VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_LINEAR, true}, - {VK_FILTER_LINEAR, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_LINEAR, true}, + {VK_FILTER_LINEAR, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_LINEAR, true} }; struct VkTexClamp @@ -55,31 +58,30 @@ struct VkTexClamp VkSamplerAddressMode clamp_v; }; -VkTexClamp TexClamp[] ={ +static VkTexClamp TexClamp[] = +{ { VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT }, { VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_REPEAT }, { VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE }, { VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE }, }; -VkSamplerManager::VkSamplerManager(VulkanDevice *dev) +VkSamplerManager::VkSamplerManager(VulkanFrameBuffer* fb) : fb(fb) { - vDevice = dev; - Create(); + CreateHWSamplers(); } VkSamplerManager::~VkSamplerManager() { - Destroy(); } -void VkSamplerManager::SetTextureFilterMode() +void VkSamplerManager::FilterModeChanged() { - Destroy(); - Create(); + DeleteHWSamplers(); + CreateHWSamplers(); } -void VkSamplerManager::Create() +void VkSamplerManager::CreateHWSamplers() { int filter = sysCallbacks.DisableTextureFilter && sysCallbacks.DisableTextureFilter()? 0 : gl_texture_filter; @@ -99,7 +101,7 @@ void VkSamplerManager::Create() { builder.setMaxLod(0.25f); } - mSamplers[i] = builder.create(vDevice); + mSamplers[i] = builder.create(fb->device); mSamplers[i]->SetDebugName("VkSamplerManager.mSamplers"); } { @@ -109,7 +111,7 @@ void VkSamplerManager::Create() builder.setAddressMode(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_REPEAT); builder.setMipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST); builder.setMaxLod(0.25f); - mSamplers[CLAMP_XY_NOMIP] = builder.create(vDevice); + mSamplers[CLAMP_XY_NOMIP] = builder.create(fb->device); mSamplers[CLAMP_XY_NOMIP]->SetDebugName("VkSamplerManager.mSamplers"); } for (int i = CLAMP_NOFILTER; i <= CLAMP_NOFILTER_XY; i++) @@ -120,7 +122,7 @@ void VkSamplerManager::Create() builder.setAddressMode(TexClamp[i - CLAMP_NOFILTER].clamp_u, TexClamp[i - CLAMP_NOFILTER].clamp_v, VK_SAMPLER_ADDRESS_MODE_REPEAT); builder.setMipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST); builder.setMaxLod(0.25f); - mSamplers[i] = builder.create(vDevice); + mSamplers[i] = builder.create(fb->device); mSamplers[i]->SetDebugName("VkSamplerManager.mSamplers"); } // CAMTEX is repeating with texture filter and no mipmap @@ -131,13 +133,33 @@ void VkSamplerManager::Create() builder.setAddressMode(VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT); builder.setMipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST); builder.setMaxLod(0.25f); - mSamplers[CLAMP_CAMTEX] = builder.create(vDevice); + mSamplers[CLAMP_CAMTEX] = builder.create(fb->device); mSamplers[CLAMP_CAMTEX]->SetDebugName("VkSamplerManager.mSamplers"); } } -void VkSamplerManager::Destroy() +void VkSamplerManager::DeleteHWSamplers() { - for (int i = 0; i < NUMSAMPLERS; i++) - mSamplers[i].reset(); + for (auto& sampler : mSamplers) + { + if (sampler) + fb->GetCommands()->FrameDeleteList.Samplers.push_back(std::move(sampler)); + } +} + +VulkanSampler* VkSamplerManager::Get(PPFilterMode filter, PPWrapMode wrap) +{ + int index = (((int)filter) << 1) | (int)wrap; + auto& sampler = mPPSamplers[index]; + if (sampler) + return sampler.get(); + + SamplerBuilder builder; + builder.setMipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST); + builder.setMinFilter(filter == PPFilterMode::Nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR); + builder.setMagFilter(filter == PPFilterMode::Nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR); + builder.setAddressMode(wrap == PPWrapMode::Clamp ? VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE : VK_SAMPLER_ADDRESS_MODE_REPEAT); + sampler = builder.create(GetVulkanFrameBuffer()->device); + sampler->SetDebugName("VkPostprocess.mSamplers"); + return sampler.get(); } diff --git a/src/common/rendering/vulkan/textures/vk_samplers.h b/src/common/rendering/vulkan/textures/vk_samplers.h index 59c49fbf4..daa341cff 100644 --- a/src/common/rendering/vulkan/textures/vk_samplers.h +++ b/src/common/rendering/vulkan/textures/vk_samplers.h @@ -1,32 +1,29 @@ -#ifndef __VK_SAMPLERS_H -#define __VK_SAMPLERS_H + +#pragma once #include "vulkan/system/vk_objects.h" +#include -class VulkanDevice; +class VulkanFrameBuffer; +enum class PPFilterMode; +enum class PPWrapMode; class VkSamplerManager { - VulkanDevice *vDevice; - std::unique_ptr mSamplers[NUMSAMPLERS]; - - //void UnbindAll(); - - void Create(); - void Destroy(); - public: - - VkSamplerManager(VulkanDevice *dev); + VkSamplerManager(VulkanFrameBuffer* fb); ~VkSamplerManager(); - //uint8_t Bind(int texunit, int num, int lastval); - void SetTextureFilterMode(); + void FilterModeChanged(); VulkanSampler *Get(int no) const { return mSamplers[no].get(); } + VulkanSampler* Get(PPFilterMode filter, PPWrapMode wrap); +private: + void CreateHWSamplers(); + void DeleteHWSamplers(); + + VulkanFrameBuffer* fb = nullptr; + std::array, NUMSAMPLERS> mSamplers; + std::array, 4> mPPSamplers; }; - - -#endif -