/* ** 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/system/vk_buffer.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/textures/vk_texture.h" #include "vulkan/renderer/vk_renderstate.h" #include "vulkan/renderer/vk_descriptorset.h" #include "flatvertices.h" VkPPRenderState::VkPPRenderState(VulkanFrameBuffer* fb) : fb(fb) { } void VkPPRenderState::PushGroup(const FString &name) { fb->GetCommands()->PushGroup(name); } void VkPPRenderState::PopGroup() { fb->GetCommands()->PopGroup(); } void VkPPRenderState::Draw() { fb->GetRenderState()->EndRenderPass(); VkPPRenderPassKey key; key.BlendMode = BlendMode; key.InputTextures = Textures.Size(); key.Uniforms = Uniforms.Data.Size(); key.Shader = fb->GetShaderManager()->GetVkShader(Shader); key.SwapChain = (Output.Type == PPTextureType::SwapChain); key.ShadowMapBuffers = ShadowMapBuffers; if (Output.Type == PPTextureType::PPTexture) key.OutputFormat = fb->GetTextureManager()->GetTextureFormat(Output.Texture); else if (Output.Type == PPTextureType::SwapChain) key.OutputFormat = fb->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 = WhichDepthStencil::Scene; key.Samples = fb->GetBuffers()->GetSceneSamples(); } else { key.StencilTest = WhichDepthStencil::None; key.Samples = VK_SAMPLE_COUNT_1_BIT; } auto passSetup = fb->GetRenderPassManager()->GetPPRenderPass(key); int framebufferWidth = 0, framebufferHeight = 0; VulkanDescriptorSet *input = fb->GetDescriptorSetManager()->GetInput(passSetup, Textures, ShadowMapBuffers); VulkanFramebuffer *output = fb->GetBuffers()->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 == WhichDepthStencil::Scene); // Advance to next PP texture if our output was sent there if (Output.Type == PPTextureType::NextPipelineTexture) { auto pp = fb->GetPostprocess(); 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 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(); }