From c280153ac2a59ea829cf6412955ffdd8de244ba0 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 5 Mar 2019 23:31:38 +0100 Subject: [PATCH] - implement VkPostprocess::RenderScreenQuad --- .../hwrenderer/data/shaderuniforms.h | 6 +- .../vulkan/renderer/vk_postprocess.cpp | 212 +++++++++++++++++- .../vulkan/renderer/vk_postprocess.h | 50 ++++- .../vulkan/renderer/vk_renderpass.cpp | 28 +-- src/rendering/vulkan/system/vk_builders.cpp | 41 ++++ src/rendering/vulkan/system/vk_builders.h | 3 + 6 files changed, 304 insertions(+), 36 deletions(-) diff --git a/src/rendering/hwrenderer/data/shaderuniforms.h b/src/rendering/hwrenderer/data/shaderuniforms.h index 765b64938d..db593b8cbf 100644 --- a/src/rendering/hwrenderer/data/shaderuniforms.h +++ b/src/rendering/hwrenderer/data/shaderuniforms.h @@ -46,7 +46,11 @@ public: { FString decl; FString layout; - if (screen->glslversion < 4.20) + if (bindingpoint == -1) + { + layout = "push_constant"; + } + else if (screen->glslversion < 4.20) { layout = "std140"; } diff --git a/src/rendering/vulkan/renderer/vk_postprocess.cpp b/src/rendering/vulkan/renderer/vk_postprocess.cpp index a4ef6dc719..5ebb03c9a9 100644 --- a/src/rendering/vulkan/renderer/vk_postprocess.cpp +++ b/src/rendering/vulkan/renderer/vk_postprocess.cpp @@ -94,6 +94,7 @@ void VkPostprocess::ClearTonemapPalette() void VkPostprocess::RenderBuffersReset() { + mRenderPassSetup.clear(); } void VkPostprocess::UpdateEffectTextures() @@ -136,6 +137,7 @@ void VkPostprocess::UpdateEffectTextures() if (!imgbuilder.isFormatSupported(fb->device)) I_FatalError("Vulkan device does not support the image format required by %s\n", pair->Key.GetChars()); vktex->Image = imgbuilder.create(fb->device); + vktex->Format = format; ImageViewBuilder viewbuilder; viewbuilder.setImage(vktex->Image.get(), format); @@ -197,7 +199,7 @@ void VkPostprocess::CompileEffectShaders() FString prolog; if (!desc.Uniforms.empty()) - prolog = UniformBlockDecl::Create("Uniforms", desc.Uniforms, uniformbindingpoint); + prolog = UniformBlockDecl::Create("Uniforms", desc.Uniforms, -1); prolog += desc.Defines; ShaderBuilder vertbuilder; @@ -227,15 +229,215 @@ FString VkPostprocess::LoadShaderCode(const FString &lumpName, const FString &de void VkPostprocess::RenderEffect(const FString &name) { + if (hw_postprocess.Effects[name].Size() == 0) + return; + + for (const PPStep &step : hw_postprocess.Effects[name]) + { + VkPPRenderPassKey key; + key.BlendMode = step.BlendMode; + key.InputTextures = step.Textures.Size(); + key.Uniforms = step.Uniforms.Data.Size() != 0; + key.Shader = mShaders[step.ShaderName].get(); + key.OutputFormat = (step.Output.Type == PPTextureType::PPTexture) ? mTextures[step.Output.Texture]->Format : VK_FORMAT_R16G16B16A16_SFLOAT; + + auto &passSetup = mRenderPassSetup[key]; + if (!passSetup) + passSetup.reset(new VkPPRenderPassSetup(key)); + + VulkanDescriptorSet *input = GetInput(passSetup.get(), step.Textures); + VulkanFramebuffer *output = GetOutput(passSetup.get(), step.Output); + + RenderScreenQuad(passSetup.get(), input, output, step.Viewport.left, step.Viewport.top, step.Viewport.width, step.Viewport.height, step.Uniforms.Data.Data(), step.Uniforms.Data.Size()); + + // Advance to next PP texture if our output was sent there + if (step.Output.Type == PPTextureType::NextPipelineTexture) + NextTexture(); + } } -void VkPostprocess::RenderScreenQuad() +void VkPostprocess::RenderScreenQuad(VkPPRenderPassSetup *passSetup, VulkanDescriptorSet *descriptorSet, VulkanFramebuffer *framebuffer, int x, int y, int width, int height, const void *pushConstants, uint32_t pushConstantsSize) { - //auto buffer = static_cast(screen->mVertexData->GetBufferObjects().first); - //buffer->Bind(nullptr); - //glDrawArrays(GL_TRIANGLE_STRIP, FFlatVertexBuffer::PRESENT_INDEX, 4); + auto fb = GetVulkanFrameBuffer(); + auto cmdbuffer = fb->GetDrawCommands(); + + RenderPassBegin beginInfo; + beginInfo.setRenderPass(passSetup->RenderPass.get()); + beginInfo.setRenderArea(x, y, width, height); + beginInfo.setFramebuffer(framebuffer); + + VkViewport viewport = { }; + viewport.x = x; + viewport.y = y; + viewport.width = width; + viewport.height = height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 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->setViewport(0, 1, &viewport); + cmdbuffer->bindVertexBuffers(0, 1, vertexBuffers, offsets); + if (pushConstantsSize > 0) + cmdbuffer->pushConstants(passSetup->PipelineLayout.get(), VK_SHADER_STAGE_FRAGMENT_BIT, 0, pushConstantsSize, pushConstants); + cmdbuffer->draw(4, 1, FFlatVertexBuffer::PRESENT_INDEX, 0); + cmdbuffer->endRenderPass(); +} + +VulkanDescriptorSet *VkPostprocess::GetInput(VkPPRenderPassSetup *passSetup, const TArray &textures) +{ +#if 0 + // Bind input textures + for (unsigned int index = 0; index < step.Textures.Size(); index++) + { + const PPTextureInput &input = step.Textures[index]; + VulkanSampler *sampler = GetSampler(input.Filter, input.Wrap); + + switch (input.Type) + { + default: + case PPTextureType::CurrentPipelineTexture: + BindCurrentTexture(index, filter, wrap); + break; + + case PPTextureType::NextPipelineTexture: + I_FatalError("PPTextureType::NextPipelineTexture not allowed as input\n"); + break; + + case PPTextureType::PPTexture: + GLTextures[input.Texture].Bind(index, filter, wrap); + break; + + case PPTextureType::SceneColor: + BindSceneColorTexture(index); + break; + + case PPTextureType::SceneFog: + BindSceneFogTexture(index); + break; + + case PPTextureType::SceneNormal: + BindSceneNormalTexture(index); + break; + + case PPTextureType::SceneDepth: + BindSceneDepthTexture(index); + break; + } + } +#endif + return nullptr; +} + +VulkanFramebuffer *VkPostprocess::GetOutput(VkPPRenderPassSetup *passSetup, const PPOutput &output) +{ +#if 0 + switch (output.Type) + { + default: + I_FatalError("Unsupported postprocess output type\n"); + break; + + case PPTextureType::CurrentPipelineTexture: + BindCurrentFB(); + break; + + case PPTextureType::NextPipelineTexture: + BindNextFB(); + break; + + case PPTextureType::PPTexture: + mTextures[step.Output.Texture]->View + break; + + case PPTextureType::SceneColor: + BindSceneFB(false); + break; + } +#endif + return nullptr; +} + +VulkanSampler *VkPostprocess::GetSampler(PPFilterMode filter, PPWrapMode wrap) +{ + int index = (((int)filter) << 2) | (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); + return sampler.get(); } void VkPostprocess::NextEye(int eyeCount) { } + +void VkPostprocess::NextTexture() +{ +} + +///////////////////////////////////////////////////////////////////////////// + +VkPPRenderPassSetup::VkPPRenderPassSetup(const VkPPRenderPassKey &key) +{ + CreateDescriptorLayout(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); + DescriptorLayout = builder.create(GetVulkanFrameBuffer()->device); +} + +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); +} + +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.setViewport(0.0f, 0.0f, (float)SCREENWIDTH, (float)SCREENHEIGHT); + builder.setTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP); + builder.setBlendMode(key.BlendMode); + builder.setLayout(PipelineLayout.get()); + builder.setRenderPass(RenderPass.get()); + Pipeline = builder.create(GetVulkanFrameBuffer()->device); +} + +void VkPPRenderPassSetup::CreateRenderPass(const VkPPRenderPassKey &key) +{ + RenderPassBuilder builder; + builder.addColorAttachment(false, key.OutputFormat, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + builder.addSubpass(); + builder.addSubpassColorAttachmentRef(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + builder.addExternalSubpassDependency( + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT); + RenderPass = builder.create(GetVulkanFrameBuffer()->device); +} diff --git a/src/rendering/vulkan/renderer/vk_postprocess.h b/src/rendering/vulkan/renderer/vk_postprocess.h index 4e7070e148..116e40351a 100644 --- a/src/rendering/vulkan/renderer/vk_postprocess.h +++ b/src/rendering/vulkan/renderer/vk_postprocess.h @@ -3,6 +3,7 @@ #include #include +#include #include "hwrenderer/postprocessing/hw_postprocess.h" #include "vulkan/system/vk_objects.h" @@ -11,6 +12,21 @@ class FString; class VkPPShader; class VkPPTexture; +class VkPPRenderPassSetup; + +class VkPPRenderPassKey +{ +public: + VkPPShader *Shader; + int Uniforms; + int InputTextures; + PPBlendMode BlendMode; + VkFormat OutputFormat; + + 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 { @@ -32,12 +48,17 @@ private: FString LoadShaderCode(const FString &lumpname, const FString &defines, int version); void RenderEffect(const FString &name); void NextEye(int eyeCount); - void RenderScreenQuad(); + void NextTexture(); + void RenderScreenQuad(VkPPRenderPassSetup *passSetup, VulkanDescriptorSet *descriptorSet, VulkanFramebuffer *framebuffer, int x, int y, int width, int height, const void *pushConstants, uint32_t pushConstantsSize); + + VulkanDescriptorSet *GetInput(VkPPRenderPassSetup *passSetup, const TArray &textures); + VulkanFramebuffer *GetOutput(VkPPRenderPassSetup *passSetup, const PPOutput &output); + VulkanSampler *GetSampler(PPFilterMode filter, PPWrapMode wrap); std::map> mTextures; std::map> mShaders; - - const static int uniformbindingpoint = 7; + std::array, 16> mSamplers; + std::map> mRenderPassSetup; }; class VkPPShader @@ -54,4 +75,27 @@ public: std::unique_ptr View; std::unique_ptr Staging; VkImageLayout Layout = VK_IMAGE_LAYOUT_UNDEFINED; + 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; + + //std::unique_ptr DescriptorPool; + + //std::unique_ptr Framebuffer; + //std::unique_ptr DescriptorSet; + +private: + void CreateDescriptorLayout(const VkPPRenderPassKey &key); + void CreatePipelineLayout(const VkPPRenderPassKey &key); + void CreatePipeline(const VkPPRenderPassKey &key); + void CreateRenderPass(const VkPPRenderPassKey &key); }; diff --git a/src/rendering/vulkan/renderer/vk_renderpass.cpp b/src/rendering/vulkan/renderer/vk_renderpass.cpp index 086d63e4da..3b00e07134 100644 --- a/src/rendering/vulkan/renderer/vk_renderpass.cpp +++ b/src/rendering/vulkan/renderer/vk_renderpass.cpp @@ -243,32 +243,6 @@ void VkRenderPassSetup::CreatePipeline(const VkRenderPassKey &key) VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP }; - static const int blendstyles[] = { - VK_BLEND_FACTOR_ZERO, - VK_BLEND_FACTOR_ONE, - VK_BLEND_FACTOR_SRC_ALPHA, - VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - VK_BLEND_FACTOR_SRC_COLOR, - VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, - VK_BLEND_FACTOR_DST_COLOR, - VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR, - }; - - static const int renderops[] = { - 0, VK_BLEND_OP_ADD, VK_BLEND_OP_SUBTRACT, VK_BLEND_OP_REVERSE_SUBTRACT, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 - }; - - int srcblend = blendstyles[key.RenderStyle.SrcAlpha%STYLEALPHA_MAX]; - int dstblend = blendstyles[key.RenderStyle.DestAlpha%STYLEALPHA_MAX]; - int blendequation = renderops[key.RenderStyle.BlendOp & 15]; - - if (blendequation == -1) // This was a fuzz style. - { - srcblend = VK_BLEND_FACTOR_DST_COLOR; - dstblend = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - blendequation = VK_BLEND_OP_ADD; - } - static const VkStencilOp op2vk[] = { VK_STENCIL_OP_KEEP, VK_STENCIL_OP_INCREMENT_AND_CLAMP, VK_STENCIL_OP_DECREMENT_AND_CLAMP }; static const VkCompareOp depthfunc2vk[] = { VK_COMPARE_OP_LESS, VK_COMPARE_OP_LESS_OR_EQUAL, VK_COMPARE_OP_ALWAYS }; @@ -280,7 +254,7 @@ void VkRenderPassSetup::CreatePipeline(const VkRenderPassKey &key) builder.setCull(key.CullMode == Cull_None ? VK_CULL_MODE_NONE : VK_CULL_MODE_FRONT_AND_BACK, key.CullMode == Cull_CW ? VK_FRONT_FACE_CLOCKWISE : VK_FRONT_FACE_COUNTER_CLOCKWISE); builder.setColorWriteMask((VkColorComponentFlags)key.ColorMask); builder.setStencil(VK_STENCIL_OP_KEEP, op2vk[key.StencilPassOp], VK_STENCIL_OP_KEEP, VK_COMPARE_OP_EQUAL, 0xffffffff, 0xffffffff, 0); - builder.setBlendMode((VkBlendOp)blendequation, (VkBlendFactor)srcblend, (VkBlendFactor)dstblend); + builder.setBlendMode(key.RenderStyle); builder.setLayout(fb->GetRenderPassManager()->PipelineLayout.get()); builder.setRenderPass(RenderPass.get()); diff --git a/src/rendering/vulkan/system/vk_builders.cpp b/src/rendering/vulkan/system/vk_builders.cpp index f4a961f654..4a3e3a21e5 100644 --- a/src/rendering/vulkan/system/vk_builders.cpp +++ b/src/rendering/vulkan/system/vk_builders.cpp @@ -1,6 +1,7 @@ #include "vk_builders.h" #include "doomerrors.h" +#include "r_data/renderstyle.h" #include #include @@ -180,3 +181,43 @@ std::unique_ptr ShaderBuilder::create(VulkanDevice *device) return std::make_unique(device, shaderModule); } + +///////////////////////////////////////////////////////////////////////////// + +void GraphicsPipelineBuilder::setBlendMode(const FRenderStyle &style) +{ + // Just in case Vulkan doesn't do this optimization itself + if (style.BlendOp == STYLEOP_Add && style.SrcAlpha == STYLEALPHA_One && style.DestAlpha == STYLEALPHA_Zero && style.Flags == 0) + { + colorBlendAttachment.blendEnable = VK_FALSE; + return; + } + + static const int blendstyles[] = { + VK_BLEND_FACTOR_ZERO, + VK_BLEND_FACTOR_ONE, + VK_BLEND_FACTOR_SRC_ALPHA, + VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + VK_BLEND_FACTOR_SRC_COLOR, + VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, + VK_BLEND_FACTOR_DST_COLOR, + VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR, + }; + + static const int renderops[] = { + 0, VK_BLEND_OP_ADD, VK_BLEND_OP_SUBTRACT, VK_BLEND_OP_REVERSE_SUBTRACT, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + }; + + int srcblend = blendstyles[style.SrcAlpha%STYLEALPHA_MAX]; + int dstblend = blendstyles[style.DestAlpha%STYLEALPHA_MAX]; + int blendequation = renderops[style.BlendOp & 15]; + + if (blendequation == -1) // This was a fuzz style. + { + srcblend = VK_BLEND_FACTOR_DST_COLOR; + dstblend = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + blendequation = VK_BLEND_OP_ADD; + } + + setBlendMode((VkBlendOp)blendequation, (VkBlendFactor)srcblend, (VkBlendFactor)dstblend); +} diff --git a/src/rendering/vulkan/system/vk_builders.h b/src/rendering/vulkan/system/vk_builders.h index c69285d998..c3c871fbb9 100644 --- a/src/rendering/vulkan/system/vk_builders.h +++ b/src/rendering/vulkan/system/vk_builders.h @@ -175,6 +175,8 @@ private: FixedSizeVector attachments; }; +union FRenderStyle; + class GraphicsPipelineBuilder { public: @@ -197,6 +199,7 @@ public: void setAdditiveBlendMode(); void setAlphaBlendMode(); + void setBlendMode(const FRenderStyle &style); void setBlendMode(VkBlendOp op, VkBlendFactor src, VkBlendFactor dst); void setSubpassColorAttachmentCount(int count);