diff --git a/core/rend/gui_util.h b/core/rend/gui_util.h index 5e9c8dfa9..25bf55641 100644 --- a/core/rend/gui_util.h +++ b/core/rend/gui_util.h @@ -22,7 +22,7 @@ #include "imgui/imgui.h" #include "vulkan/imgui_impl_vulkan.h" #include "gles/imgui_impl_opengl3.h" -#include "vulkan/vulkan.h" +#include "vulkan/vulkan_context.h" typedef void (*StringCallback)(bool cancelled, std::string selection); diff --git a/core/rend/vulkan/buffer.cpp b/core/rend/vulkan/buffer.cpp index 71e6b4021..62852b40e 100644 --- a/core/rend/vulkan/buffer.cpp +++ b/core/rend/vulkan/buffer.cpp @@ -20,6 +20,7 @@ */ #include "buffer.h" #include "utils.h" +#include "vulkan_context.h" BufferData::BufferData(vk::DeviceSize size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags propertyFlags) : bufferSize(size) diff --git a/core/rend/vulkan/buffer.h b/core/rend/vulkan/buffer.h index 86218453c..00da94347 100644 --- a/core/rend/vulkan/buffer.h +++ b/core/rend/vulkan/buffer.h @@ -20,6 +20,7 @@ */ #pragma once #include "vulkan.h" +#include "vmallocator.h" struct BufferData { diff --git a/core/rend/vulkan/commandpool.h b/core/rend/vulkan/commandpool.h index bd51f293b..42557ea0a 100644 --- a/core/rend/vulkan/commandpool.h +++ b/core/rend/vulkan/commandpool.h @@ -19,7 +19,7 @@ along with Flycast. If not, see . */ #pragma once -#include "vulkan.h" +#include "vulkan_context.h" class CommandPool { @@ -58,10 +58,9 @@ public: void EndFrame() { - vk::CommandBuffer commandBuffer = Allocate(); - commandBuffer.begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit)); - commandBuffer.end(); - VulkanContext::Instance()->GetGraphicsQueue().submit(vk::SubmitInfo(0, nullptr, nullptr, 1, &commandBuffer), *fences[index]); + std::vector commandBuffers = GetInFlightCommandBuffers(); + VulkanContext::Instance()->GetGraphicsQueue().submit( + vk::SubmitInfo(0, nullptr, nullptr, commandBuffers.size(), commandBuffers.data()), *fences[index]); } void BeginFrame() @@ -95,7 +94,23 @@ public: return *inFlightBuffers[index].back(); } + vk::Fence GetCurrentFence() + { + return *fences[index]; + } + private: + std::vector GetInFlightCommandBuffers() const + { + const auto& buffers = inFlightBuffers[index]; + std::vector v; + v.reserve(buffers.size()); + std::for_each(buffers.begin(), buffers.end(), + [&v](const vk::UniqueCommandBuffer& cmdBuf) { v.push_back(*cmdBuf); }); + + return v; + } + int index = 0; std::vector> freeBuffers; std::vector> inFlightBuffers; diff --git a/core/rend/vulkan/compiler.cpp b/core/rend/vulkan/compiler.cpp index f349a35ee..439b53f0b 100644 --- a/core/rend/vulkan/compiler.cpp +++ b/core/rend/vulkan/compiler.cpp @@ -21,6 +21,7 @@ #include #include "compiler.h" #include "SPIRV/GlslangToSpv.h" +#include "vulkan_context.h" static const TBuiltInResource DefaultTBuiltInResource = { /* .MaxLights = */ 32, diff --git a/core/rend/vulkan/drawer.cpp b/core/rend/vulkan/drawer.cpp index ccc662601..51ab3e62d 100644 --- a/core/rend/vulkan/drawer.cpp +++ b/core/rend/vulkan/drawer.cpp @@ -408,7 +408,7 @@ vk::CommandBuffer TextureDrawer::BeginRenderPass() { if (!depthAttachment) depthAttachment = std::unique_ptr(new FramebufferAttachment(context->GetPhysicalDevice(), device)); - depthAttachment->Init(widthPow2, heightPow2, GetContext()->GetDepthFormat()); + depthAttachment->Init(widthPow2, heightPow2, GetContext()->GetDepthFormat(), vk::ImageUsageFlagBits::eDepthStencilAttachment); } vk::ImageView colorImageView; vk::ImageLayout colorImageCurrentLayout; @@ -464,7 +464,8 @@ vk::CommandBuffer TextureDrawer::BeginRenderPass() { colorAttachment = std::unique_ptr(new FramebufferAttachment(context->GetPhysicalDevice(), device)); } - colorAttachment->Init(widthPow2, heightPow2, vk::Format::eR8G8B8A8Unorm); + colorAttachment->Init(widthPow2, heightPow2, vk::Format::eR8G8B8A8Unorm, + vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc); } colorImage = colorAttachment->GetImage(); colorImageView = colorAttachment->GetImageView(); @@ -517,16 +518,14 @@ void TextureDrawer::EndRenderPass() } currentCommandBuffer.end(); - GetContext()->GetGraphicsQueue().submit(vk::SubmitInfo(0, nullptr, nullptr, 1, ¤tCommandBuffer), - settings.rend.RenderToTextureBuffer ? *fence : nullptr); colorImage = nullptr; currentCommandBuffer = nullptr; commandPool->EndFrame(); if (settings.rend.RenderToTextureBuffer) { - GetContext()->GetDevice().waitForFences(1, &fence.get(), true, UINT64_MAX); - GetContext()->GetDevice().resetFences(1, &fence.get()); + vk::Fence fence = commandPool->GetCurrentFence(); + GetContext()->GetDevice().waitForFences(1, &fence, true, UINT64_MAX); u16 *dst = (u16 *)&vram[textureAddr]; @@ -546,15 +545,29 @@ void TextureDrawer::EndRenderPass() vk::CommandBuffer ScreenDrawer::BeginRenderPass() { - GetContext()->NewFrame(); - GetContext()->BeginRenderPass(); - vk::CommandBuffer commandBuffer = GetContext()->GetCurrentCommandBuffer(); - commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, (float)screen_width, (float)screen_height, 1.0f, 0.0f)); + if (currentScreenScaling != settings.rend.ScreenScaling) + Init(samplerManager, shaderManager); + vk::CommandBuffer commandBuffer = commandPool->Allocate(); + commandBuffer.begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit)); + + const vk::ClearValue clear_colors[] = { vk::ClearColorValue(std::array { 0.f, 0.f, 0.f, 1.f }), vk::ClearDepthStencilValue { 0.f, 0 } }; + commandBuffer.beginRenderPass(vk::RenderPassBeginInfo(*renderPass, *framebuffer, + vk::Rect2D( { 0, 0 }, viewport), 2, clear_colors), vk::SubpassContents::eInline); + commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, viewport.width, viewport.height, 1.0f, 0.0f)); matrices.CalcMatrices(&pvrrc); SetBaseScissor(); - commandBuffer.setScissor(0, baseScissor); + currentCommandBuffer = commandBuffer; + return commandBuffer; } + +void ScreenDrawer::EndRenderPass() +{ + currentCommandBuffer.endRenderPass(); + currentCommandBuffer.end(); + commandPool->EndFrame(); + GetContext()->PresentFrame(colorAttachment->GetImageView(), vk::Offset2D(viewport.width, viewport.height)); +} diff --git a/core/rend/vulkan/drawer.h b/core/rend/vulkan/drawer.h index 9c5bb0841..7d51dc790 100644 --- a/core/rend/vulkan/drawer.h +++ b/core/rend/vulkan/drawer.h @@ -105,6 +105,7 @@ public: Drawer& operator=(Drawer&& other) = default; virtual vk::CommandBuffer BeginRenderPass() = 0; virtual void EndRenderPass() = 0; + void SetCommandPool(CommandPool *commandPool) { this->commandPool = commandPool; } protected: void Init(SamplerManager *samplerManager, PipelineManager *pipelineManager) @@ -116,6 +117,9 @@ protected: virtual BufferData *GetMainBuffer(u32 size) = 0; PipelineManager *pipelineManager = nullptr; + vk::CommandBuffer currentCommandBuffer; + SamplerManager *samplerManager = nullptr; + CommandPool *commandPool = nullptr; private: void SortTriangles(); @@ -135,8 +139,6 @@ private: std::vector> sortedPolys; std::vector> sortedIndexes; u32 sortedIndexCount = 0; - - SamplerManager *samplerManager = nullptr; }; class ScreenDrawer : public Drawer @@ -144,9 +146,64 @@ class ScreenDrawer : public Drawer public: void Init(SamplerManager *samplerManager, ShaderManager *shaderManager) { + this->shaderManager = shaderManager; + currentScreenScaling = settings.rend.ScreenScaling; + viewport = GetContext()->GetViewPort(); + viewport.width = lroundf(viewport.width * currentScreenScaling / 100.f); + viewport.height = lroundf(viewport.height * currentScreenScaling / 100.f); + depthAttachment = std::unique_ptr( + new FramebufferAttachment(GetContext()->GetPhysicalDevice(), GetContext()->GetDevice())); + depthAttachment->Init(viewport.width, viewport.height, GetContext()->GetDepthFormat(), vk::ImageUsageFlagBits::eDepthStencilAttachment); + colorAttachment = std::unique_ptr( + new FramebufferAttachment(GetContext()->GetPhysicalDevice(), GetContext()->GetDevice())); + colorAttachment->Init(viewport.width, viewport.height, GetContext()->GetColorFormat(), + vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eSampled); + + if (!renderPass) + { + vk::AttachmentDescription attachmentDescriptions[] = { + // Color attachment + vk::AttachmentDescription(vk::AttachmentDescriptionFlags(), GetContext()->GetColorFormat(), vk::SampleCountFlagBits::e1, + vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eStore, + vk::AttachmentLoadOp::eDontCare, vk::AttachmentStoreOp::eDontCare, + vk::ImageLayout::eUndefined, vk::ImageLayout::eShaderReadOnlyOptimal), + // Depth attachment + vk::AttachmentDescription(vk::AttachmentDescriptionFlags(), GetContext()->GetDepthFormat(), vk::SampleCountFlagBits::e1, + vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eDontCare, + vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eDontCare, + vk::ImageLayout::eUndefined, vk::ImageLayout::eDepthStencilAttachmentOptimal), + }; + vk::AttachmentReference colorReference(0, vk::ImageLayout::eColorAttachmentOptimal); + vk::AttachmentReference depthReference(1, vk::ImageLayout::eDepthStencilAttachmentOptimal); + + vk::SubpassDescription subpasses[] = { + vk::SubpassDescription(vk::SubpassDescriptionFlags(), vk::PipelineBindPoint::eGraphics, + 0, nullptr, + 1, &colorReference, + nullptr, + &depthReference), + }; + + std::vector dependencies; + dependencies.emplace_back(0, VK_SUBPASS_EXTERNAL, vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eFragmentShader, + vk::AccessFlagBits::eColorAttachmentWrite, vk::AccessFlagBits::eShaderRead, vk::DependencyFlagBits::eByRegion); + + renderPass = GetContext()->GetDevice().createRenderPassUnique(vk::RenderPassCreateInfo(vk::RenderPassCreateFlags(), + ARRAY_SIZE(attachmentDescriptions), attachmentDescriptions, + ARRAY_SIZE(subpasses), subpasses, + dependencies.size(), dependencies.data())); + } + vk::ImageView attachments[] = { + colorAttachment->GetImageView(), + depthAttachment->GetImageView(), + }; + vk::FramebufferCreateInfo createInfo(vk::FramebufferCreateFlags(), *renderPass, + ARRAY_SIZE(attachments), attachments, viewport.width, viewport.height, 1); + framebuffer = GetContext()->GetDevice().createFramebufferUnique(createInfo); + if (!screenPipelineManager) screenPipelineManager = std::unique_ptr(new PipelineManager()); - screenPipelineManager->Init(shaderManager); + screenPipelineManager->Init(shaderManager, *renderPass); Drawer::Init(samplerManager, screenPipelineManager.get()); if (descriptorSets.size() > GetContext()->GetSwapChainSize()) @@ -158,16 +215,14 @@ public: descriptorSets.back().Init(samplerManager, screenPipelineManager->GetPipelineLayout(), screenPipelineManager->GetPerFrameDSLayout(), screenPipelineManager->GetPerPolyDSLayout()); } } + ScreenDrawer() = default; ScreenDrawer(const ScreenDrawer& other) = delete; ScreenDrawer(ScreenDrawer&& other) = default; ScreenDrawer& operator=(const ScreenDrawer& other) = delete; ScreenDrawer& operator=(ScreenDrawer&& other) = default; virtual vk::CommandBuffer BeginRenderPass() override; - virtual void EndRenderPass() override - { - GetContext()->EndFrame(); - } + virtual void EndRenderPass() override; protected: virtual DescriptorSets& GetCurrentDescSet() override { return descriptorSets[GetCurrentImage()]; } @@ -197,6 +252,14 @@ private: std::vector descriptorSets; std::vector> mainBuffers; std::unique_ptr screenPipelineManager; + + vk::UniqueRenderPass renderPass; + vk::UniqueFramebuffer framebuffer; + std::unique_ptr colorAttachment; + std::unique_ptr depthAttachment; + vk::Extent2D viewport; + int currentScreenScaling = 0; + ShaderManager *shaderManager = nullptr; }; class TextureDrawer : public Drawer @@ -207,10 +270,8 @@ public: Drawer::Init(samplerManager, pipelineManager); descriptorSets.Init(samplerManager, pipelineManager->GetPipelineLayout(), pipelineManager->GetPerFrameDSLayout(), pipelineManager->GetPerPolyDSLayout()); - fence = GetContext()->GetDevice().createFenceUnique(vk::FenceCreateInfo()); this->textureCache = textureCache; } - void SetCommandPool(CommandPool *commandPool) { this->commandPool = commandPool; } TextureDrawer() = default; TextureDrawer(const TextureDrawer& other) = delete; @@ -244,14 +305,11 @@ private: Texture *texture = nullptr; vk::Image colorImage; - vk::CommandBuffer currentCommandBuffer; vk::UniqueFramebuffer framebuffer; std::unique_ptr colorAttachment; std::unique_ptr depthAttachment; - vk::UniqueFence fence; DescriptorSets descriptorSets; std::unique_ptr mainBuffer; - CommandPool *commandPool = nullptr; TextureCache *textureCache = nullptr; }; diff --git a/core/rend/vulkan/imgui_impl_vulkan.cpp b/core/rend/vulkan/imgui_impl_vulkan.cpp index 16657f241..83df6e62f 100644 --- a/core/rend/vulkan/imgui_impl_vulkan.cpp +++ b/core/rend/vulkan/imgui_impl_vulkan.cpp @@ -702,6 +702,7 @@ void ImGui_ImplVulkan_InvalidateDeviceObjects() if (g_DescriptorSetLayout) { vkDestroyDescriptorSetLayout(g_Device, g_DescriptorSetLayout, g_Allocator); g_DescriptorSetLayout = VK_NULL_HANDLE; } if (g_PipelineLayout) { vkDestroyPipelineLayout(g_Device, g_PipelineLayout, g_Allocator); g_PipelineLayout = VK_NULL_HANDLE; } if (g_Pipeline) { vkDestroyPipeline(g_Device, g_Pipeline, g_Allocator); g_Pipeline = VK_NULL_HANDLE; } + g_DescriptorSet = VK_NULL_HANDLE; } bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass, int subpass) @@ -739,6 +740,15 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass rend void ImGui_ImplVulkan_Shutdown() { ImGui_ImplVulkan_InvalidateDeviceObjects(); + g_Instance = VK_NULL_HANDLE; + g_PhysicalDevice = VK_NULL_HANDLE; + g_Device = VK_NULL_HANDLE; + g_Queue = VK_NULL_HANDLE; + g_RenderPass = VK_NULL_HANDLE; + g_PipelineCache = VK_NULL_HANDLE; + g_DescriptorPool = VK_NULL_HANDLE; + g_Allocator = nullptr; + g_CheckVkResultFn = nullptr; } void ImGui_ImplVulkan_NewFrame() diff --git a/core/rend/vulkan/oit_drawer.cpp b/core/rend/vulkan/oit_drawer.cpp index d6b46f66a..8f468286f 100644 --- a/core/rend/vulkan/oit_drawer.cpp +++ b/core/rend/vulkan/oit_drawer.cpp @@ -283,7 +283,7 @@ bool OITDrawer::Draw(const Texture *fogTexture) if (!finalPass) targetFramebuffer = *tempFramebuffers[(pvrrc.render_passes.used() - 1 - render_pass) % 2]; else - targetFramebuffer = GetCurrentFramebuffer(); + targetFramebuffer = *framebuffer; cmdBuffer.beginRenderPass( vk::RenderPassBeginInfo(pipelineManager->GetRenderPass(initialPass, finalPass), targetFramebuffer, viewport, clear_colors.size(), clear_colors.data()), @@ -361,13 +361,15 @@ void OITDrawer::MakeBuffers(int width, int height) attachment.reset(); attachment = std::unique_ptr( new FramebufferAttachment(GetContext()->GetPhysicalDevice(), GetContext()->GetDevice())); - attachment->Init(maxWidth, maxHeight, GetColorFormat(), vk::ImageUsageFlagBits::eInputAttachment); + attachment->Init(maxWidth, maxHeight, GetColorFormat(), + vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eInputAttachment); } depthAttachment.reset(); depthAttachment = std::unique_ptr( new FramebufferAttachment(GetContext()->GetPhysicalDevice(), GetContext()->GetDevice())); - depthAttachment->Init(maxWidth, maxHeight, GetContext()->GetDepthFormat(), vk::ImageUsageFlagBits::eInputAttachment); + depthAttachment->Init(maxWidth, maxHeight, GetContext()->GetDepthFormat(), + vk::ImageUsageFlagBits::eDepthStencilAttachment | vk::ImageUsageFlagBits::eInputAttachment); vk::ImageView attachments[] = { colorAttachments[1]->GetImageView(), @@ -382,23 +384,32 @@ void OITDrawer::MakeBuffers(int width, int height) tempFramebuffers[1] = GetContext()->GetDevice().createFramebufferUnique(createInfo); } -void OITScreenDrawer::MakeFramebuffers(int width, int height) +void OITScreenDrawer::MakeFramebuffers() { - MakeBuffers(width, height); + if (currentScreenScaling == settings.rend.ScreenScaling) + return; + currentScreenScaling = settings.rend.ScreenScaling; + viewport.offset.x = 0; + viewport.offset.y = 0; + viewport.extent = GetContext()->GetViewPort(); + viewport.extent.width = lroundf(viewport.extent.width * currentScreenScaling / 100.f); + viewport.extent.height = lroundf(viewport.extent.height * currentScreenScaling / 100.f); + + MakeBuffers(viewport.extent.width, viewport.extent.height); + finalColorAttachment.reset(); + finalColorAttachment = std::unique_ptr( + new FramebufferAttachment(GetContext()->GetPhysicalDevice(), GetContext()->GetDevice())); + finalColorAttachment->Init(viewport.extent.width, viewport.extent.height, GetContext()->GetColorFormat(), + vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eSampled); vk::ImageView attachments[] = { - nullptr, // swap chain image view, set later + finalColorAttachment->GetImageView(), colorAttachments[0]->GetImageView(), depthAttachment->GetImageView(), }; - framebuffers.clear(); - framebuffers.reserve(GetContext()->GetSwapChainSize()); - for (int i = 0; i < GetContext()->GetSwapChainSize(); i++) - { - vk::FramebufferCreateInfo createInfo(vk::FramebufferCreateFlags(), pipelineManager->GetRenderPass(true, true), - ARRAY_SIZE(attachments), attachments, width, height, 1); - attachments[0] = GetContext()->GetSwapChainImageView(i); - framebuffers.push_back(GetContext()->GetDevice().createFramebufferUnique(createInfo)); - } + framebuffer.reset(); + vk::FramebufferCreateInfo createInfo(vk::FramebufferCreateFlags(), pipelineManager->GetRenderPass(true, true), + ARRAY_SIZE(attachments), attachments, viewport.extent.width, viewport.extent.height, 1); + framebuffer = GetContext()->GetDevice().createFramebufferUnique(createInfo); } vk::CommandBuffer OITTextureDrawer::NewFrame() @@ -493,7 +504,8 @@ vk::CommandBuffer OITTextureDrawer::NewFrame() colorAttachment = std::unique_ptr( new FramebufferAttachment(context->GetPhysicalDevice(), device)); } - colorAttachment->Init(widthPow2, heightPow2, vk::Format::eR8G8B8A8Unorm); + colorAttachment->Init(widthPow2, heightPow2, vk::Format::eR8G8B8A8Unorm, + vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc); } colorImage = colorAttachment->GetImage(); colorImageView = colorAttachment->GetImageView(); @@ -545,18 +557,14 @@ void OITTextureDrawer::EndFrame() } currentCommandBuffer.end(); - GetContext()->GetGraphicsQueue().submit(vk::SubmitInfo(0, nullptr, nullptr, 1, ¤tCommandBuffer), - settings.rend.RenderToTextureBuffer ? *fence : nullptr); colorImage = nullptr; currentCommandBuffer = nullptr; commandPool->EndFrame(); - - if (settings.rend.RenderToTextureBuffer) { - GetContext()->GetDevice().waitForFences(1, &fence.get(), true, UINT64_MAX); - GetContext()->GetDevice().resetFences(1, &fence.get()); + vk::Fence fence = commandPool->GetCurrentFence(); + GetContext()->GetDevice().waitForFences(1, &fence, true, UINT64_MAX); u16 *dst = (u16 *)&vram[textureAddr]; @@ -576,13 +584,9 @@ void OITTextureDrawer::EndFrame() vk::CommandBuffer OITScreenDrawer::NewFrame() { - GetContext()->NewFrame(); - GetContext()->InitImgui(GetRenderPass(), 2); - vk::CommandBuffer commandBuffer = GetContext()->GetCurrentCommandBuffer(); - - viewport.offset.x = 0; - viewport.offset.y = 0; - viewport.extent = GetContext()->GetViewPort(); + MakeFramebuffers(); + vk::CommandBuffer commandBuffer = commandPool->Allocate(); + commandBuffer.begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit)); matrices.CalcMatrices(&pvrrc); @@ -590,6 +594,7 @@ vk::CommandBuffer OITScreenDrawer::NewFrame() commandBuffer.setScissor(0, baseScissor); commandBuffer.setViewport(0, vk::Viewport(viewport.offset.x, viewport.offset.y, viewport.extent.width, viewport.extent.height, 1.0f, 0.0f)); + currentCommandBuffer = commandBuffer; return commandBuffer; } diff --git a/core/rend/vulkan/oit_drawer.h b/core/rend/vulkan/oit_drawer.h index 3536b45fe..96281702c 100644 --- a/core/rend/vulkan/oit_drawer.h +++ b/core/rend/vulkan/oit_drawer.h @@ -45,6 +45,7 @@ public: virtual vk::CommandBuffer NewFrame() = 0; virtual void EndFrame() = 0; + void SetCommandPool(CommandPool *commandPool) { this->commandPool = commandPool; } protected: void Init(SamplerManager *samplerManager, OITPipelineManager *pipelineManager, OITBuffers *oitBuffers) @@ -64,7 +65,6 @@ protected: } virtual OITDescriptorSets& GetCurrentDescSet() = 0; virtual BufferData *GetMainBuffer(u32 size) = 0; - virtual vk::Framebuffer GetCurrentFramebuffer() const = 0; void MakeBuffers(int width, int height); virtual vk::Format GetColorFormat() const = 0; @@ -72,6 +72,9 @@ protected: vk::Rect2D viewport; std::array, 2> colorAttachments; std::unique_ptr depthAttachment; + CommandPool *commandPool = nullptr; + vk::CommandBuffer currentCommandBuffer; + vk::UniqueFramebuffer framebuffer; private: void DrawPoly(const vk::CommandBuffer& cmdBuffer, u32 listType, bool sortTriangles, int pass, @@ -123,14 +126,13 @@ public: screenPipelineManager->GetPerPolyDSLayout(), screenPipelineManager->GetColorInputDSLayout()); } - vk::Extent2D viewport = GetContext()->GetViewPort(); - MakeFramebuffers(viewport.width, viewport.height); + MakeFramebuffers(); } void Term() { mainBuffers.clear(); screenPipelineManager.reset(); - framebuffers.clear(); + framebuffer.reset(); descriptorSets.clear(); OITDrawer::Term(); } @@ -143,9 +145,13 @@ public: virtual vk::CommandBuffer NewFrame() override; virtual void EndFrame() override { - GetContext()->EndFrame(); + currentCommandBuffer.endRenderPass(); + currentCommandBuffer.end(); + currentCommandBuffer = nullptr; + commandPool->EndFrame(); + GetContext()->PresentFrame(finalColorAttachment->GetImageView(), + vk::Offset2D(viewport.extent.width, viewport.extent.height)); } - vk::RenderPass GetRenderPass() { return screenPipelineManager->GetRenderPass(true, true); } protected: virtual OITDescriptorSets& GetCurrentDescSet() override { return descriptorSets[GetCurrentImage()]; } @@ -170,17 +176,17 @@ protected: } return mainBuffers[GetCurrentImage()].get(); }; - virtual vk::Framebuffer GetCurrentFramebuffer() const override { return *framebuffers[GetCurrentImage()]; } virtual vk::Format GetColorFormat() const override { return GetContext()->GetColorFormat(); } private: int GetCurrentImage() const { return GetContext()->GetCurrentImageIndex(); } - void MakeFramebuffers(int width, int height); + void MakeFramebuffers(); - std::vector framebuffers; + std::unique_ptr finalColorAttachment; std::vector descriptorSets; std::vector> mainBuffers; std::unique_ptr screenPipelineManager; + int currentScreenScaling = 0; }; class OITTextureDrawer : public OITDrawer @@ -196,7 +202,6 @@ public: pipelineManager->GetPerFrameDSLayout(), pipelineManager->GetPerPolyDSLayout(), pipelineManager->GetColorInputDSLayout()); - fence = GetContext()->GetDevice().createFenceUnique(vk::FenceCreateInfo()); this->textureCache = textureCache; } void Term() @@ -204,12 +209,9 @@ public: mainBuffer.reset(); colorAttachment.reset(); framebuffer.reset(); - fence.reset(); OITDrawer::Term(); } - void SetCommandPool(CommandPool *commandPool) { this->commandPool = commandPool; } - OITTextureDrawer() = default; OITTextureDrawer(const OITTextureDrawer& other) = delete; OITTextureDrawer(OITTextureDrawer&& other) = default; @@ -235,7 +237,6 @@ protected: } return mainBuffer.get(); } - virtual vk::Framebuffer GetCurrentFramebuffer() const override { return *framebuffer; } virtual vk::Format GetColorFormat() const override { return vk::Format::eR8G8B8A8Unorm; } private: @@ -243,13 +244,9 @@ private: Texture *texture = nullptr; vk::Image colorImage; - vk::CommandBuffer currentCommandBuffer; - vk::UniqueFramebuffer framebuffer; std::unique_ptr colorAttachment; - vk::UniqueFence fence; OITDescriptorSets descriptorSets; std::unique_ptr mainBuffer; - CommandPool *commandPool = nullptr; TextureCache *textureCache = nullptr; }; diff --git a/core/rend/vulkan/oit_renderer.cpp b/core/rend/vulkan/oit_renderer.cpp index 0771abd64..57efb19c6 100644 --- a/core/rend/vulkan/oit_renderer.cpp +++ b/core/rend/vulkan/oit_renderer.cpp @@ -44,7 +44,7 @@ public: textureDrawer.SetCommandPool(&texCommandPool); screenDrawer.Init(&samplerManager, &shaderManager, &oitBuffers); - quadPipeline.Init(&normalShaderManager); + screenDrawer.SetCommandPool(&texCommandPool); quadBuffer = std::unique_ptr(new QuadBuffer()); #ifdef __ANDROID__ @@ -67,8 +67,9 @@ public: vjoyTexture->SetCommandBuffer(texCommandPool.Allocate()); vjoyTexture->UploadToGPU(OSD_TEX_W, OSD_TEX_H, image_data); vjoyTexture->SetCommandBuffer(nullptr); + texCommandPool.EndFrame(); delete [] image_data; - osdPipeline.Init(&normalShaderManager, vjoyTexture->GetImageView(), screenDrawer.GetRenderPass(), 2); + osdPipeline.Init(&normalShaderManager, vjoyTexture->GetImageView(), GetContext()->GetRenderPass()); } } if (!osdBuffer) @@ -86,9 +87,8 @@ public: NOTICE_LOG(RENDERER, "OIT Resize %d x %d", w, h); texCommandPool.Init(); screenDrawer.Init(&samplerManager, &shaderManager, &oitBuffers); - quadPipeline.Init(&normalShaderManager); #ifdef __ANDROID__ - osdPipeline.Init(&normalShaderManager, vjoyTexture->GetImageView(), screenDrawer.GetRenderPass(), 2); + osdPipeline.Init(&normalShaderManager, vjoyTexture->GetImageView(), GetContext()->GetRenderPass()); #endif } @@ -134,50 +134,7 @@ public: curTexture->SetCommandBuffer(nullptr); texCommandPool.EndFrame(); - TransformMatrix matrices(pvrrc); - glm::vec4 viewport_min = matrices.GetViewportMatrix() * glm::vec4(0, 0, 0, 1.f); - glm::vec4 viewport_dim = matrices.GetViewportMatrix() * glm::vec4(640.f, 480.f, 0, 0); - - float min_x = viewport_min[0]; - float min_y = viewport_min[1]; - width = viewport_dim[0]; - height = viewport_dim[1]; - if (width < 0) - { - min_x += width; - width = -width; - } - if (height < 0) - { - min_y += height; - height = -height; - } - quadBuffer->Update(); - - GetContext()->NewFrame(); - GetContext()->BeginRenderPass(); - vk::CommandBuffer cmdBuffer = GetContext()->GetCurrentCommandBuffer(); - - vk::Pipeline pipeline = quadPipeline.GetPipeline(); - cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); - - quadPipeline.SetTexture(curTexture.get()); - quadPipeline.BindDescriptorSets(cmdBuffer); - - float blendConstants[4] = { 1.0, 1.0, 1.0, 1.0 }; - cmdBuffer.setBlendConstants(blendConstants); - - vk::Viewport viewport(min_x, min_y, width, height); - cmdBuffer.setViewport(0, 1, &viewport); - cmdBuffer.setScissor(0, vk::Rect2D( - vk::Offset2D((u32)std::max(lroundf(min_x), 0L), (u32)std::max(lroundf(min_y), 0L)), - vk::Extent2D((u32)std::max(lroundf(width), 0L), (u32)std::max(lroundf(height), 0L)))); - quadBuffer->Bind(cmdBuffer); - quadBuffer->Draw(cmdBuffer); - - gui_display_osd(); - - GetContext()->EndFrame(); + GetContext()->PresentFrame(curTexture->GetImageView(), { 640, 480 }); return true; } @@ -208,7 +165,7 @@ public: if (result) CheckFogTexture(); - if (!result || !ctx->rend.isRTT) + if (!result) texCommandPool.EndFrame(); return result; @@ -267,8 +224,7 @@ public: drawer = &screenDrawer; drawer->Draw(fogTexture.get()); - if (!pvrrc.isRTT) - DrawOSD(false); + drawer->EndFrame(); return !pvrrc.isRTT; @@ -340,7 +296,6 @@ private: RttOITPipelineManager rttPipelineManager; OITTextureDrawer textureDrawer; std::vector> framebufferTextures; - QuadPipeline quadPipeline; OSDPipeline osdPipeline; std::unique_ptr vjoyTexture; std::unique_ptr osdBuffer; diff --git a/core/rend/vulkan/oit_renderpass.cpp b/core/rend/vulkan/oit_renderpass.cpp index 065f994d9..1941ec86d 100644 --- a/core/rend/vulkan/oit_renderpass.cpp +++ b/core/rend/vulkan/oit_renderpass.cpp @@ -27,13 +27,15 @@ vk::UniqueRenderPass RenderPasses::MakeRenderPass(bool initial, bool last) GetAttachment0Description(initial, last), // OP+PT color attachment vk::AttachmentDescription(vk::AttachmentDescriptionFlags(), GetColorFormat(), vk::SampleCountFlagBits::e1, - initial ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad, vk::AttachmentStoreOp::eStore, + initial ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad, + last ? vk::AttachmentStoreOp::eDontCare : vk::AttachmentStoreOp::eStore, vk::AttachmentLoadOp::eDontCare, vk::AttachmentStoreOp::eDontCare, initial ? vk::ImageLayout::eUndefined : vk::ImageLayout::eShaderReadOnlyOptimal, vk::ImageLayout::eShaderReadOnlyOptimal), // OP+PT depth attachment vk::AttachmentDescription(vk::AttachmentDescriptionFlags(), GetContext()->GetDepthFormat(), vk::SampleCountFlagBits::e1, - initial ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad, vk::AttachmentStoreOp::eStore, - vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eStore, + initial ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad, + last ? vk::AttachmentStoreOp::eDontCare : vk::AttachmentStoreOp::eStore, + vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eDontCare, initial ? vk::ImageLayout::eUndefined : vk::ImageLayout::eDepthStencilReadOnlyOptimal, vk::ImageLayout::eDepthStencilReadOnlyOptimal), }; vk::AttachmentReference swapChainReference(0, vk::ImageLayout::eColorAttachmentOptimal); diff --git a/core/rend/vulkan/oit_renderpass.h b/core/rend/vulkan/oit_renderpass.h index 740c00e00..10b617d1d 100644 --- a/core/rend/vulkan/oit_renderpass.h +++ b/core/rend/vulkan/oit_renderpass.h @@ -19,7 +19,7 @@ along with Flycast. If not, see . */ #pragma once -#include "vulkan.h" +#include "vulkan_context.h" class RenderPasses { @@ -45,7 +45,7 @@ protected: { return vk::AttachmentDescription(vk::AttachmentDescriptionFlags(), GetContext()->GetColorFormat(), vk::SampleCountFlagBits::e1, vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eStore, vk::AttachmentLoadOp::eDontCare, vk::AttachmentStoreOp::eDontCare, - vk::ImageLayout::eUndefined, last ? vk::ImageLayout::ePresentSrcKHR : vk::ImageLayout::eShaderReadOnlyOptimal); + vk::ImageLayout::eUndefined, vk::ImageLayout::eShaderReadOnlyOptimal); } virtual vk::Format GetColorFormat() const { return GetContext()->GetColorFormat(); } virtual std::vector GetSubpassDependencies() const diff --git a/core/rend/vulkan/pipeline.cpp b/core/rend/vulkan/pipeline.cpp index 43ee7c178..32a1f7ecd 100644 --- a/core/rend/vulkan/pipeline.cpp +++ b/core/rend/vulkan/pipeline.cpp @@ -325,75 +325,6 @@ void PipelineManager::CreatePipeline(u32 listType, bool sortTriangles, const Pol graphicsPipelineCreateInfo); } -void QuadPipeline::CreatePipeline() -{ - vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo = GetQuadInputStateCreateInfo(true); - - // Input assembly state - vk::PipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateCreateInfo(vk::PipelineInputAssemblyStateCreateFlags(), vk::PrimitiveTopology::eTriangleStrip); - - // Viewport and scissor states - vk::PipelineViewportStateCreateInfo pipelineViewportStateCreateInfo(vk::PipelineViewportStateCreateFlags(), 1, nullptr, 1, nullptr); - - // Rasterization and multisample states - vk::PipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo; - pipelineRasterizationStateCreateInfo.lineWidth = 1.0; - vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo; - - // Depth and stencil - vk::PipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo; - - // Color flags and blending - vk::PipelineColorBlendAttachmentState pipelineColorBlendAttachmentState( - true, // blendEnable - vk::BlendFactor::eConstantAlpha, // srcColorBlendFactor - vk::BlendFactor::eOneMinusConstantAlpha, // dstColorBlendFactor - vk::BlendOp::eAdd, // colorBlendOp - vk::BlendFactor::eConstantAlpha, // srcAlphaBlendFactor - vk::BlendFactor::eOneMinusConstantAlpha, // dstAlphaBlendFactor - vk::BlendOp::eAdd, // alphaBlendOp - vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG - | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA - ); - vk::PipelineColorBlendStateCreateInfo pipelineColorBlendStateCreateInfo - ( - vk::PipelineColorBlendStateCreateFlags(), // flags - false, // logicOpEnable - vk::LogicOp::eNoOp, // logicOp - 1, // attachmentCount - &pipelineColorBlendAttachmentState, // pAttachments - { { 1.0f, 1.0f, 1.0f, 1.0f } } // blendConstants - ); - - vk::DynamicState dynamicStates[] = { vk::DynamicState::eViewport, vk::DynamicState::eScissor, vk::DynamicState::eBlendConstants }; - vk::PipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo(vk::PipelineDynamicStateCreateFlags(), ARRAY_SIZE(dynamicStates), - dynamicStates); - - vk::PipelineShaderStageCreateInfo stages[] = { - { vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eVertex, shaderManager->GetQuadVertexShader(), "main" }, - { vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eFragment, shaderManager->GetQuadFragmentShader(), "main" }, - }; - vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo - ( - vk::PipelineCreateFlags(), // flags - 2, // stageCount - stages, // pStages - &pipelineVertexInputStateCreateInfo, // pVertexInputState - &pipelineInputAssemblyStateCreateInfo, // pInputAssemblyState - nullptr, // pTessellationState - &pipelineViewportStateCreateInfo, // pViewportState - &pipelineRasterizationStateCreateInfo, // pRasterizationState - &pipelineMultisampleStateCreateInfo, // pMultisampleState - &pipelineDepthStencilStateCreateInfo, // pDepthStencilState - &pipelineColorBlendStateCreateInfo, // pColorBlendState - &pipelineDynamicStateCreateInfo, // pDynamicState - *pipelineLayout, // layout - renderPass // renderPass - ); - - pipeline = GetContext()->GetDevice().createGraphicsPipelineUnique(GetContext()->GetPipelineCache(), graphicsPipelineCreateInfo); -} - void OSDPipeline::CreatePipeline() { // Vertex input state @@ -474,7 +405,7 @@ void OSDPipeline::CreatePipeline() &pipelineDynamicStateCreateInfo, // pDynamicState *pipelineLayout, // layout renderPass, // renderPass - subpass + 0 // subpass ); pipeline = GetContext()->GetDevice().createGraphicsPipelineUnique(GetContext()->GetPipelineCache(), graphicsPipelineCreateInfo); diff --git a/core/rend/vulkan/pipeline.h b/core/rend/vulkan/pipeline.h index ac842f2ca..a71ab7966 100644 --- a/core/rend/vulkan/pipeline.h +++ b/core/rend/vulkan/pipeline.h @@ -24,6 +24,7 @@ #include "texture.h" #include "utils.h" #include "hw/pvr/ta_ctx.h" +#include "vulkan_context.h" class DescriptorSets { @@ -126,7 +127,7 @@ class PipelineManager public: virtual ~PipelineManager() = default; - virtual void Init(ShaderManager *shaderManager) + void Init(ShaderManager *shaderManager, vk::RenderPass renderPass) { this->shaderManager = shaderManager; @@ -151,9 +152,9 @@ public: vk::PipelineLayoutCreateInfo(vk::PipelineLayoutCreateFlags(), ARRAY_SIZE(layouts), layouts, 1, &pushConstant)); } - if (renderPass != VulkanContext::Instance()->GetRenderPass()) + if (this->renderPass != renderPass) { - renderPass = VulkanContext::Instance()->GetRenderPass(); + this->renderPass = renderPass; pipelines.clear(); modVolPipelines.clear(); } @@ -244,10 +245,8 @@ protected: class RttPipelineManager : public PipelineManager { public: - void Init(ShaderManager *shaderManager) override + void Init(ShaderManager *shaderManager) { - PipelineManager::Init(shaderManager); - // RTT render pass renderToTextureBuffer = settings.rend.RenderToTextureBuffer; vk::AttachmentDescription attachmentDescriptions[] = { @@ -276,8 +275,10 @@ public: rttRenderPass = GetContext()->GetDevice().createRenderPassUnique(vk::RenderPassCreateInfo(vk::RenderPassCreateFlags(), 2, attachmentDescriptions, 1, &subpass, renderToTextureBuffer ? ARRAY_SIZE(vramWriteDeps) : ARRAY_SIZE(dependencies), renderToTextureBuffer ? vramWriteDeps : dependencies)); - renderPass = *rttRenderPass; + + PipelineManager::Init(shaderManager, *rttRenderPass); } + void CheckSettingsChange() { if (renderToTextureBuffer != settings.rend.RenderToTextureBuffer) @@ -289,82 +290,10 @@ private: bool renderToTextureBuffer; }; -class QuadPipeline -{ -public: - void Init(ShaderManager *shaderManager) - { - this->shaderManager = shaderManager; - if (!pipelineLayout) - { - vk::DescriptorSetLayoutBinding bindings[] = { - { 0, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment },// texture - }; - descSetLayout = GetContext()->GetDevice().createDescriptorSetLayoutUnique( - vk::DescriptorSetLayoutCreateInfo(vk::DescriptorSetLayoutCreateFlags(), ARRAY_SIZE(bindings), bindings)); - pipelineLayout = GetContext()->GetDevice().createPipelineLayoutUnique( - vk::PipelineLayoutCreateInfo(vk::PipelineLayoutCreateFlags(), 1, &descSetLayout.get())); - } - if (!sampler) - { - sampler = VulkanContext::Instance()->GetDevice().createSamplerUnique( - vk::SamplerCreateInfo(vk::SamplerCreateFlags(), vk::Filter::eLinear, vk::Filter::eLinear, - vk::SamplerMipmapMode::eLinear, vk::SamplerAddressMode::eClampToEdge, vk::SamplerAddressMode::eClampToEdge, - vk::SamplerAddressMode::eClampToEdge, 0.0f, false, 16.0f, false, - vk::CompareOp::eNever, 0.0f, 0.0f, vk::BorderColor::eFloatOpaqueBlack)); - } - if (GetContext()->GetRenderPass() != renderPass) - { - renderPass = GetContext()->GetRenderPass(); - pipeline.reset(); - } - descriptorSets.resize(GetContext()->GetSwapChainSize()); - } - - vk::Pipeline GetPipeline() - { - if (!pipeline) - CreatePipeline(); - return *pipeline; - } - - void SetTexture(Texture *texture) - { - vk::UniqueDescriptorSet& descriptorSet = descriptorSets[GetContext()->GetCurrentImageIndex()]; - if (!descriptorSet) - { - descriptorSet = std::move(GetContext()->GetDevice().allocateDescriptorSetsUnique( - vk::DescriptorSetAllocateInfo(GetContext()->GetDescriptorPool(), 1, &descSetLayout.get())).front()); - } - vk::DescriptorImageInfo imageInfo(*sampler, texture->GetImageView(), vk::ImageLayout::eShaderReadOnlyOptimal); - std::vector writeDescriptorSets; - writeDescriptorSets.push_back(vk::WriteDescriptorSet(*descriptorSet, 0, 0, 1, vk::DescriptorType::eCombinedImageSampler, &imageInfo, nullptr, nullptr)); - - GetContext()->GetDevice().updateDescriptorSets(writeDescriptorSets, nullptr); - } - - void BindDescriptorSets(vk::CommandBuffer cmdBuffer) - { - cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *pipelineLayout, 0, 1, &descriptorSets[GetContext()->GetCurrentImageIndex()].get(), 0, nullptr); - } - -private: - VulkanContext *GetContext() const { return VulkanContext::Instance(); } - void CreatePipeline(); - - vk::RenderPass renderPass; - vk::UniquePipeline pipeline; - vk::UniqueSampler sampler; - std::vector descriptorSets; - vk::UniquePipelineLayout pipelineLayout; - vk::UniqueDescriptorSetLayout descSetLayout; - ShaderManager *shaderManager; -}; - class OSDPipeline { public: - void Init(ShaderManager *shaderManager, vk::ImageView imageView, vk::RenderPass renderPass, int subpass = 0) + void Init(ShaderManager *shaderManager, vk::ImageView imageView, vk::RenderPass renderPass) { this->shaderManager = shaderManager; if (!pipelineLayout) @@ -379,16 +308,15 @@ public: } if (!sampler) { - sampler = VulkanContext::Instance()->GetDevice().createSamplerUnique( + sampler = GetContext()->GetDevice().createSamplerUnique( vk::SamplerCreateInfo(vk::SamplerCreateFlags(), vk::Filter::eLinear, vk::Filter::eLinear, vk::SamplerMipmapMode::eLinear, vk::SamplerAddressMode::eClampToEdge, vk::SamplerAddressMode::eClampToEdge, vk::SamplerAddressMode::eClampToEdge, 0.0f, false, 16.0f, false, vk::CompareOp::eNever, 0.0f, 0.0f, vk::BorderColor::eFloatOpaqueBlack)); } - if (this->renderPass != renderPass || this->subpass != subpass) + if (this->renderPass != renderPass) { this->renderPass = renderPass; - this->subpass = subpass; pipeline.reset(); } if (!descriptorSet) @@ -419,7 +347,6 @@ private: void CreatePipeline(); vk::RenderPass renderPass; - int subpass = 0; vk::UniquePipeline pipeline; vk::UniqueSampler sampler; vk::UniqueDescriptorSet descriptorSet; diff --git a/core/rend/vulkan/quad.cpp b/core/rend/vulkan/quad.cpp index 1cc0faa7b..20b70abe7 100644 --- a/core/rend/vulkan/quad.cpp +++ b/core/rend/vulkan/quad.cpp @@ -19,6 +19,12 @@ along with Flycast. If not, see . */ #include "quad.h" +#include "vulkan_context.h" + +static VulkanContext *GetContext() +{ + return VulkanContext::Instance(); +} vk::PipelineVertexInputStateCreateInfo GetQuadInputStateCreateInfo(bool uv) { @@ -39,3 +45,134 @@ vk::PipelineVertexInputStateCreateInfo GetQuadInputStateCreateInfo(bool uv) ARRAY_SIZE(vertexInputAttributeDescriptions) - (uv ? 0 : 1), vertexInputAttributeDescriptions); } + +void QuadPipeline::CreatePipeline() +{ + vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo = GetQuadInputStateCreateInfo(true); + + // Input assembly state + vk::PipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateCreateInfo(vk::PipelineInputAssemblyStateCreateFlags(), vk::PrimitiveTopology::eTriangleStrip); + + // Viewport and scissor states + vk::PipelineViewportStateCreateInfo pipelineViewportStateCreateInfo(vk::PipelineViewportStateCreateFlags(), 1, nullptr, 1, nullptr); + + // Rasterization and multisample states + vk::PipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo; + pipelineRasterizationStateCreateInfo.lineWidth = 1.0; + vk::PipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo; + + // Depth and stencil + vk::PipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo; + + // Color flags and blending + vk::PipelineColorBlendAttachmentState pipelineColorBlendAttachmentState( + true, // blendEnable + vk::BlendFactor::eConstantAlpha, // srcColorBlendFactor + vk::BlendFactor::eOneMinusConstantAlpha, // dstColorBlendFactor + vk::BlendOp::eAdd, // colorBlendOp + vk::BlendFactor::eConstantAlpha, // srcAlphaBlendFactor + vk::BlendFactor::eOneMinusConstantAlpha, // dstAlphaBlendFactor + vk::BlendOp::eAdd, // alphaBlendOp + vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG + | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA + ); + vk::PipelineColorBlendStateCreateInfo pipelineColorBlendStateCreateInfo + ( + vk::PipelineColorBlendStateCreateFlags(), // flags + false, // logicOpEnable + vk::LogicOp::eNoOp, // logicOp + 1, // attachmentCount + &pipelineColorBlendAttachmentState, // pAttachments + { { 1.0f, 1.0f, 1.0f, 1.0f } } // blendConstants + ); + + vk::DynamicState dynamicStates[] = { vk::DynamicState::eViewport, vk::DynamicState::eScissor, vk::DynamicState::eBlendConstants }; + vk::PipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo(vk::PipelineDynamicStateCreateFlags(), ARRAY_SIZE(dynamicStates), + dynamicStates); + + vk::PipelineShaderStageCreateInfo stages[] = { + { vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eVertex, shaderManager->GetQuadVertexShader(), "main" }, + { vk::PipelineShaderStageCreateFlags(), vk::ShaderStageFlagBits::eFragment, shaderManager->GetQuadFragmentShader(), "main" }, + }; + vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo + ( + vk::PipelineCreateFlags(), // flags + 2, // stageCount + stages, // pStages + &pipelineVertexInputStateCreateInfo, // pVertexInputState + &pipelineInputAssemblyStateCreateInfo, // pInputAssemblyState + nullptr, // pTessellationState + &pipelineViewportStateCreateInfo, // pViewportState + &pipelineRasterizationStateCreateInfo, // pRasterizationState + &pipelineMultisampleStateCreateInfo, // pMultisampleState + &pipelineDepthStencilStateCreateInfo, // pDepthStencilState + &pipelineColorBlendStateCreateInfo, // pColorBlendState + &pipelineDynamicStateCreateInfo, // pDynamicState + *pipelineLayout, // layout + VulkanContext::Instance()->GetRenderPass() // renderPass + ); + + pipeline = GetContext()->GetDevice().createGraphicsPipelineUnique(GetContext()->GetPipelineCache(), graphicsPipelineCreateInfo); +} + +void QuadPipeline::Init(ShaderManager *shaderManager) { + this->shaderManager = shaderManager; + if (!pipelineLayout) { + vk::DescriptorSetLayoutBinding bindings[] = { { 0, + vk::DescriptorType::eCombinedImageSampler, 1, + vk::ShaderStageFlagBits::eFragment }, // texture + }; + descSetLayout = + GetContext()->GetDevice().createDescriptorSetLayoutUnique( + vk::DescriptorSetLayoutCreateInfo( + vk::DescriptorSetLayoutCreateFlags(), + ARRAY_SIZE(bindings), bindings)); + pipelineLayout = GetContext()->GetDevice().createPipelineLayoutUnique( + vk::PipelineLayoutCreateInfo(vk::PipelineLayoutCreateFlags(), 1, + &descSetLayout.get())); + } + if (!sampler) { + sampler = GetContext()->GetDevice().createSamplerUnique( + vk::SamplerCreateInfo(vk::SamplerCreateFlags(), + vk::Filter::eLinear, vk::Filter::eLinear, + vk::SamplerMipmapMode::eLinear, + vk::SamplerAddressMode::eClampToBorder, + vk::SamplerAddressMode::eClampToBorder, + vk::SamplerAddressMode::eClampToBorder, 0.0f, false, + 16.0f, false, vk::CompareOp::eNever, 0.0f, 0.0f, + vk::BorderColor::eFloatOpaqueBlack)); + } + if (GetContext()->GetRenderPass() != renderPass) { + renderPass = GetContext()->GetRenderPass(); + pipeline.reset(); + } + descriptorSets.resize(GetContext()->GetSwapChainSize()); +} + +void QuadPipeline::SetTexture(vk::ImageView imageView) { + vk::UniqueDescriptorSet &descriptorSet = + descriptorSets[GetContext()->GetCurrentImageIndex()]; + if (!descriptorSet) { + descriptorSet = std::move( + GetContext()->GetDevice().allocateDescriptorSetsUnique( + vk::DescriptorSetAllocateInfo( + GetContext()->GetDescriptorPool(), 1, + &descSetLayout.get())).front()); + } + vk::DescriptorImageInfo imageInfo(*sampler, imageView, + vk::ImageLayout::eShaderReadOnlyOptimal); + std::vector writeDescriptorSets; + writeDescriptorSets.push_back( + vk::WriteDescriptorSet(*descriptorSet, 0, 0, 1, + vk::DescriptorType::eCombinedImageSampler, &imageInfo, + nullptr, nullptr)); + GetContext()->GetDevice().updateDescriptorSets(writeDescriptorSets, + nullptr); +} + +void QuadPipeline::BindDescriptorSets(vk::CommandBuffer cmdBuffer) { + cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, + *pipelineLayout, 0, 1, + &descriptorSets[GetContext()->GetCurrentImageIndex()].get(), 0, + nullptr); +} diff --git a/core/rend/vulkan/quad.h b/core/rend/vulkan/quad.h index 10d8c7cf3..4c8b7554c 100644 --- a/core/rend/vulkan/quad.h +++ b/core/rend/vulkan/quad.h @@ -21,6 +21,7 @@ #pragma once #include "vulkan.h" #include "buffer.h" +#include "shaders.h" struct QuadVertex { @@ -65,3 +66,31 @@ public: private: std::unique_ptr buffer; }; + +class QuadPipeline +{ +public: + void Init(ShaderManager *shaderManager); + + vk::Pipeline GetPipeline() + { + if (!pipeline) + CreatePipeline(); + return *pipeline; + } + + void SetTexture(vk::ImageView imageView); + + void BindDescriptorSets(vk::CommandBuffer cmdBuffer); + +private: + void CreatePipeline(); + + vk::RenderPass renderPass; + vk::UniquePipeline pipeline; + vk::UniqueSampler sampler; + std::vector descriptorSets; + vk::UniquePipelineLayout pipelineLayout; + vk::UniqueDescriptorSetLayout descSetLayout; + ShaderManager *shaderManager; +}; diff --git a/core/rend/vulkan/texture.cpp b/core/rend/vulkan/texture.cpp index cd173817c..0a9449dc8 100644 --- a/core/rend/vulkan/texture.cpp +++ b/core/rend/vulkan/texture.cpp @@ -259,8 +259,6 @@ void Texture::SetImage(u32 srcSize, void *srcData, bool isNew) setImageLayout(commandBuffer, image.get(), format, mipmapLevels, vk::ImageLayout::ePreinitialized, vk::ImageLayout::eShaderReadOnlyOptimal); } commandBuffer.end(); - - VulkanContext::Instance()->GetGraphicsQueue().submit(vk::SubmitInfo(0, nullptr, nullptr, 1, &commandBuffer), nullptr); } void Texture::GenerateMipmaps() @@ -315,38 +313,19 @@ void Texture::GenerateMipmaps() commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, nullptr, nullptr, barrier); } -void FramebufferAttachment::Init(u32 width, u32 height, vk::Format format, vk::ImageUsageFlags additionalUsageFlags) +void FramebufferAttachment::Init(u32 width, u32 height, vk::Format format, vk::ImageUsageFlags usage) { this->format = format; this->extent = vk::Extent2D { width, height }; bool depth = format == vk::Format::eD32SfloatS8Uint || format == vk::Format::eD24UnormS8Uint || format == vk::Format::eD16UnormS8Uint; - vk::ImageUsageFlags usage; - if (depth) + if (usage & vk::ImageUsageFlagBits::eTransferSrc) { - usage = vk::ImageUsageFlagBits::eDepthStencilAttachment; + stagingBufferData = std::unique_ptr(new BufferData(width * height * 4, + vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst)); } - else - { - if (!(additionalUsageFlags & vk::ImageUsageFlagBits::eStorage)) - usage = vk::ImageUsageFlagBits::eColorAttachment; - if (!(additionalUsageFlags & (vk::ImageUsageFlagBits::eInputAttachment | vk::ImageUsageFlagBits::eStorage))) - { - if (settings.rend.RenderToTextureBuffer) - { - usage |= vk::ImageUsageFlagBits::eTransferSrc; - stagingBufferData = std::unique_ptr(new BufferData(width * height * 4, - vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst)); - } - else - { - usage |= vk::ImageUsageFlagBits::eSampled; - } - } - } - usage |= additionalUsageFlags; vk::ImageCreateInfo imageCreateInfo(vk::ImageCreateFlags(), vk::ImageType::e2D, format, vk::Extent3D(extent, 1), 1, 1, vk::SampleCountFlagBits::e1, - (additionalUsageFlags & vk::ImageUsageFlagBits::eStorage) ? vk::ImageTiling::eLinear : vk::ImageTiling::eOptimal, + (usage & vk::ImageUsageFlagBits::eStorage) ? vk::ImageTiling::eLinear : vk::ImageTiling::eOptimal, usage, vk::SharingMode::eExclusive, 0, nullptr, vk::ImageLayout::eUndefined); image = device.createImageUnique(imageCreateInfo); @@ -358,7 +337,7 @@ void FramebufferAttachment::Init(u32 width, u32 height, vk::Format format, vk::I format, vk::ComponentMapping(), vk::ImageSubresourceRange(depth ? vk::ImageAspectFlagBits::eDepth : vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)); imageView = device.createImageViewUnique(imageViewCreateInfo); - if (depth && (additionalUsageFlags & vk::ImageUsageFlagBits::eInputAttachment)) + if ((usage & vk::ImageUsageFlagBits::eDepthStencilAttachment) && (usage & vk::ImageUsageFlagBits::eInputAttachment)) { // Also create an imageView for the stencil imageViewCreateInfo.subresourceRange = vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eStencil, 0, 1, 0, 1); diff --git a/core/rend/vulkan/texture.h b/core/rend/vulkan/texture.h index 0941abf19..eb93fd7b2 100644 --- a/core/rend/vulkan/texture.h +++ b/core/rend/vulkan/texture.h @@ -20,7 +20,7 @@ */ #pragma once #include -#include "vulkan.h" +#include "vulkan_context.h" #include "buffer.h" #include "rend/TexCache.h" #include "hw/pvr/Renderer_if.h" @@ -106,7 +106,7 @@ public: FramebufferAttachment(vk::PhysicalDevice physicalDevice, vk::Device device) : physicalDevice(physicalDevice), device(device), format(vk::Format::eUndefined) {} - void Init(u32 width, u32 height, vk::Format format, vk::ImageUsageFlags = vk::ImageUsageFlags()); + void Init(u32 width, u32 height, vk::Format format, vk::ImageUsageFlags usage); void Reset() { image.reset(); imageView.reset(); } vk::ImageView GetImageView() const { return *imageView; } diff --git a/core/rend/vulkan/vmallocator.cpp b/core/rend/vulkan/vmallocator.cpp index 5f32bf7f5..a21dbd58a 100644 --- a/core/rend/vulkan/vmallocator.cpp +++ b/core/rend/vulkan/vmallocator.cpp @@ -20,6 +20,8 @@ */ #define VMA_IMPLEMENTATION #include "vulkan.h" +#include "vmallocator.h" +#include "vulkan_context.h" #if HOST_CPU == CPU_ARM __attribute__((pcs("aapcs-vfp"))) diff --git a/core/rend/vulkan/vulkan.h b/core/rend/vulkan/vulkan.h index aa2dec7af..76ad7dd8f 100644 --- a/core/rend/vulkan/vulkan.h +++ b/core/rend/vulkan/vulkan.h @@ -24,173 +24,5 @@ #include "volk/volk.h" #undef VK_NO_PROTOTYPES #include "vulkan/vulkan.hpp" -#include "rend/TexCache.h" -#include "vmallocator.h" -//#define VK_DEBUG - -extern int screen_width, screen_height; - -class VulkanContext -{ -public: - VulkanContext() { verify(contextInstance == nullptr); contextInstance = this; } - ~VulkanContext() { verify(contextInstance == this); contextInstance = nullptr; } - - bool Init(); - bool InitInstance(const char** extensions, uint32_t extensions_count); - bool InitDevice(); - void InitImgui(vk::RenderPass renderPass, int subpass = 0); - void CreateSwapChain(); - void Term(); - void SetWindow(void *window, void *display) { this->window = window; this->display = display; } - - VkInstance GetInstance() const { return static_cast(instance.get()); } - u32 GetGraphicsQueueFamilyIndex() const { return graphicsQueueIndex; } - void SetWindowSize(u32 width, u32 height) { this->width = screen_width = width; this->height = screen_height = height; } - void NewFrame(); - void BeginRenderPass(); - void EndFrame(); - void Present(); - - vk::PhysicalDevice GetPhysicalDevice() const { return physicalDevice; } - vk::Device GetDevice() const { return *device; } - vk::PipelineCache GetPipelineCache() const { return *pipelineCache; } - vk::RenderPass GetRenderPass() const { return *renderPass; } - vk::CommandPool GetCurrentCommandPool() const { return *commandPools[GetCurrentImageIndex()]; } - vk::CommandBuffer GetCurrentCommandBuffer() const { return *commandBuffers[GetCurrentImageIndex()]; } - vk::DescriptorPool GetDescriptorPool() const { return *descriptorPool; } - vk::Extent2D GetViewPort() const { return { width, height }; } - int GetSwapChainSize() const { return (int)imageViews.size(); } - int GetCurrentImageIndex() const { return currentImage; } - void WaitIdle() const { graphicsQueue.waitIdle(); } - bool IsRendering() const { return rendering; } - vk::Queue GetGraphicsQueue() const { return graphicsQueue; } - vk::DeviceSize GetUniformBufferAlignment() const { return uniformBufferAlignment; } - vk::DeviceSize GetStorageBufferAlignment() const { return storageBufferAlignment; } - bool IsFormatSupported(TextureType textureType) - { - switch (textureType) - { - case TextureType::_4444: - return optimalTilingSupported4444; - case TextureType::_565: - return optimalTilingSupported565; - case TextureType::_5551: - return optimalTilingSupported1555; - default: - return true; - } - } - std::string GetDriverName() const { vk::PhysicalDeviceProperties props; physicalDevice.getProperties(&props); return props.deviceName; } - std::string GetDriverVersion() const { vk::PhysicalDeviceProperties props; physicalDevice.getProperties(&props); return std::to_string(props.driverVersion); } - vk::Format GetColorFormat() const { return colorFormat; } - vk::Format GetDepthFormat() const { return depthFormat; } - vk::ImageView GetSwapChainImageView(int i) const { return imageViews[i].get(); } - static VulkanContext *Instance() { return contextInstance; } - bool SupportsFragmentShaderStoresAndAtomics() const { return fragmentStoresAndAtomics; } - bool SupportsSamplerAnisotropy() const { return samplerAnisotropy; } - bool SupportsDedicatedAllocation() const { return dedicatedAllocationSupported; } - const VMAllocator& GetAllocator() const { return allocator; } - bool IsUnifiedMemory() const { return unifiedMemory; } - -private: - vk::Format InitDepthBuffer(); - void DoSwapAutomation(); - vk::SurfaceKHR GetSurface() { -#ifdef USE_SDL - return surface; -#else - return *surface; -#endif - } - - bool HasSurfaceDimensionChanged() - { - vk::SurfaceCapabilitiesKHR surfaceCapabilities = physicalDevice.getSurfaceCapabilitiesKHR(GetSurface()); - VkExtent2D swapchainExtent; - if (surfaceCapabilities.currentExtent.width == std::numeric_limits::max()) - { - // If the surface size is undefined, the size is set to the size of the images requested. - swapchainExtent.width = std::min(std::max(width, surfaceCapabilities.minImageExtent.width), surfaceCapabilities.maxImageExtent.width); - swapchainExtent.height = std::min(std::max(height, surfaceCapabilities.minImageExtent.height), surfaceCapabilities.maxImageExtent.height); - } - else - { - // If the surface size is defined, the swap chain size must match - swapchainExtent = surfaceCapabilities.currentExtent; - } - if (width == swapchainExtent.width && height == swapchainExtent.height) - return false; - - screen_width = width = swapchainExtent.width; - screen_height = height = swapchainExtent.height; - - return true; - } - - VMAllocator allocator; - void *window = nullptr; - void *display = nullptr; - bool rendering = false; - bool renderDone = false; - u32 width = 0; - u32 height = 0; - vk::UniqueInstance instance; - vk::PhysicalDevice physicalDevice; - - u32 graphicsQueueIndex = 0; - u32 presentQueueIndex = 0; - vk::DeviceSize uniformBufferAlignment = 0; - vk::DeviceSize storageBufferAlignment = 0; - bool optimalTilingSupported565 = false; - bool optimalTilingSupported1555 = false; - bool optimalTilingSupported4444 = false; - bool fragmentStoresAndAtomics = false; - bool samplerAnisotropy = false; - bool dedicatedAllocationSupported = false; - bool unifiedMemory = false; - vk::UniqueDevice device; - -#ifdef USE_SDL - vk::SurfaceKHR surface; -#else - vk::UniqueSurfaceKHR surface; -#endif - - vk::UniqueSwapchainKHR swapChain; - std::vector imageViews; - u32 currentImage = 0; - vk::Format colorFormat = vk::Format::eUndefined; - - vk::Queue graphicsQueue; - vk::Queue presentQueue; - - vk::UniqueDescriptorPool descriptorPool; - vk::UniqueRenderPass renderPass; - - vk::UniqueImage depthImage; - vk::UniqueImageView depthView; - vk::UniqueDeviceMemory depthMemory; - vk::Format depthFormat = vk::Format::eUndefined; - - std::vector commandPools; - std::vector commandBuffers; - - std::vector framebuffers; - - std::vector drawFences; - std::vector renderCompleteSemaphores; - std::vector imageAcquiredSemaphores; - u32 currentSemaphore = 0; - - vk::UniquePipelineCache pipelineCache; -#ifdef VK_DEBUG -#ifndef __ANDROID__ - vk::UniqueDebugUtilsMessengerEXT debugUtilsMessenger; -#else - vk::UniqueDebugReportCallbackEXT debugReportCallback; -#endif -#endif - static VulkanContext *contextInstance; -}; +#define VK_DEBUG diff --git a/core/rend/vulkan/vulkan_context.cpp b/core/rend/vulkan/vulkan_context.cpp index 757e0790a..339b4b80f 100644 --- a/core/rend/vulkan/vulkan_context.cpp +++ b/core/rend/vulkan/vulkan_context.cpp @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with Flycast. If not, see . */ -#include "vulkan.h" +#include "vulkan_context.h" #include "imgui/imgui.h" #include "imgui_impl_vulkan.h" #include "../gui.h" @@ -137,15 +137,14 @@ bool VulkanContext::InitInstance(const char** extensions, uint32_t extensions_co vext.push_back(extensions[i]); std::vector layer_names; + //layer_names.push_back("VK_LAYER_ARM_AGA"); #ifdef VK_DEBUG #ifndef __ANDROID__ vext.push_back("VK_EXT_debug_utils"); - extensions_count += 1; // layer_names.push_back("VK_LAYER_LUNARG_api_dump"); layer_names.push_back("VK_LAYER_LUNARG_standard_validation"); #else vext.push_back("VK_EXT_debug_report"); // NDK <= 19? - extensions_count += 1; layer_names.push_back("VK_LAYER_GOOGLE_threading"); layer_names.push_back("VK_LAYER_LUNARG_parameter_validation"); layer_names.push_back("VK_LAYER_LUNARG_object_tracker"); @@ -153,8 +152,8 @@ bool VulkanContext::InitInstance(const char** extensions, uint32_t extensions_co layer_names.push_back("VK_LAYER_GOOGLE_unique_objects"); #endif #endif - extensions = &vext[0]; - vk::InstanceCreateInfo instanceCreateInfo({}, &applicationInfo, layer_names.size(), &layer_names[0], extensions_count, extensions); + vk::InstanceCreateInfo instanceCreateInfo({}, &applicationInfo, layer_names.size(), layer_names.data(), + vext.size(), vext.data()); // create a UniqueInstance instance = vk::createInstanceUnique(instanceCreateInfo); @@ -217,7 +216,7 @@ bool VulkanContext::InitInstance(const char** extensions, uint32_t extensions_co return false; } -vk::Format VulkanContext::InitDepthBuffer() +vk::Format VulkanContext::FindDepthFormat() { const vk::Format depthFormats[] = { vk::Format::eD32SfloatS8Uint, vk::Format::eD24UnormS8Uint, vk::Format::eD16UnormS8Uint }; vk::ImageTiling tiling; @@ -252,36 +251,10 @@ vk::Format VulkanContext::InitDepthBuffer() } NOTICE_LOG(RENDERER, "Using depth format %s tiling %s", vk::to_string(depthFormat).c_str(), vk::to_string(tiling).c_str()); - vk::ImageCreateInfo imageCreateInfo(vk::ImageCreateFlags(), vk::ImageType::e2D, depthFormat, vk::Extent3D(width, height, 1), 1, 1, - vk::SampleCountFlagBits::e1, tiling, vk::ImageUsageFlagBits::eDepthStencilAttachment); - depthImage = device->createImageUnique(imageCreateInfo); - - vk::PhysicalDeviceMemoryProperties memoryProperties = physicalDevice.getMemoryProperties(); - vk::MemoryRequirements memoryRequirements = device->getImageMemoryRequirements(*depthImage); - uint32_t typeBits = memoryRequirements.memoryTypeBits; - uint32_t typeIndex = uint32_t(~0); - for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) - { - if ((typeBits & 1) && ((memoryProperties.memoryTypes[i].propertyFlags & vk::MemoryPropertyFlagBits::eDeviceLocal) == vk::MemoryPropertyFlagBits::eDeviceLocal)) - { - typeIndex = i; - break; - } - typeBits >>= 1; - } - verify(typeIndex != ~0); - depthMemory = device->allocateMemoryUnique(vk::MemoryAllocateInfo(memoryRequirements.size, typeIndex)); - - device->bindImageMemory(*depthImage, *depthMemory, 0); - - vk::ComponentMapping componentMapping(vk::ComponentSwizzle::eR, vk::ComponentSwizzle::eG, vk::ComponentSwizzle::eB, vk::ComponentSwizzle::eA); - vk::ImageSubresourceRange subResourceRange(vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1); - depthView = device->createImageViewUnique(vk::ImageViewCreateInfo(vk::ImageViewCreateFlags(), *depthImage, vk::ImageViewType::e2D, depthFormat, componentMapping, subResourceRange)); - return depthFormat; } -void VulkanContext::InitImgui(vk::RenderPass renderPass, int subpass) +void VulkanContext::InitImgui() { gui_init(); ImGui_ImplVulkan_InitInfo initInfo = {}; @@ -296,7 +269,7 @@ void VulkanContext::InitImgui(vk::RenderPass renderPass, int subpass) initInfo.CheckVkResultFn = &CheckImGuiResult; #endif - if (!ImGui_ImplVulkan_Init(&initInfo, (VkRenderPass)renderPass, subpass)) + if (!ImGui_ImplVulkan_Init(&initInfo, (VkRenderPass)*renderPass, 0)) { die("ImGui initialization failed"); } @@ -399,8 +372,9 @@ bool VulkanContext::InitDevice() features.fragmentStoresAndAtomics = true; if (samplerAnisotropy) features.samplerAnisotropy = true; + const char *layers[] = { "VK_LAYER_ARM_AGA" }; device = physicalDevice.createDeviceUnique(vk::DeviceCreateInfo(vk::DeviceCreateFlags(), 1, &deviceQueueCreateInfo, - 0, nullptr, deviceExtensions.size(), &deviceExtensions[0], &features)); + 0, layers, deviceExtensions.size(), &deviceExtensions[0], &features)); // This links entry points directly from the driver and isn't absolutely necessary volkLoadDevice(static_cast(*device)); @@ -446,6 +420,10 @@ bool VulkanContext::InitDevice() } allocator.Init(physicalDevice, *device); + quadBuffer = std::unique_ptr(new QuadBuffer()); + shaderManager = std::unique_ptr(new ShaderManager()); + quadPipeline = std::unique_ptr(new QuadPipeline()); + CreateSwapChain(); return true; @@ -574,25 +552,21 @@ void VulkanContext::CreateSwapChain() commandBuffers.push_back(std::move(device->allocateCommandBuffersUnique(vk::CommandBufferAllocateInfo(*commandPools.back(), vk::CommandBufferLevel::ePrimary, 1)).front())); } - vk::Format depthFormat = InitDepthBuffer(); + vk::Format depthFormat = FindDepthFormat(); // Render pass - vk::AttachmentDescription attachmentDescriptions[2]; - // FIXME we should use vk::AttachmentLoadOp::eLoad for loadOp to preserve previous framebuffer but it fails on the first render - attachmentDescriptions[0] = vk::AttachmentDescription(vk::AttachmentDescriptionFlags(), colorFormat, vk::SampleCountFlagBits::e1, vk::AttachmentLoadOp::eClear, - vk::AttachmentStoreOp::eStore, vk::AttachmentLoadOp::eDontCare, vk::AttachmentStoreOp::eDontCare, vk::ImageLayout::eUndefined, vk::ImageLayout::ePresentSrcKHR); - attachmentDescriptions[1] = vk::AttachmentDescription(vk::AttachmentDescriptionFlags(), depthFormat, vk::SampleCountFlagBits::e1, vk::AttachmentLoadOp::eClear, - vk::AttachmentStoreOp::eDontCare, vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eDontCare, vk::ImageLayout::eUndefined, vk::ImageLayout::eDepthStencilAttachmentOptimal); + vk::AttachmentDescription attachmentDescription = vk::AttachmentDescription(vk::AttachmentDescriptionFlags(), colorFormat, vk::SampleCountFlagBits::e1, + vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eStore, vk::AttachmentLoadOp::eDontCare, vk::AttachmentStoreOp::eDontCare, + vk::ImageLayout::eUndefined, vk::ImageLayout::ePresentSrcKHR); vk::AttachmentReference colorReference(0, vk::ImageLayout::eColorAttachmentOptimal); - vk::AttachmentReference depthReference(1, vk::ImageLayout::eDepthStencilAttachmentOptimal); - vk::SubpassDescription subpass(vk::SubpassDescriptionFlags(), vk::PipelineBindPoint::eGraphics, 0, nullptr, 1, &colorReference, nullptr, &depthReference); + vk::SubpassDescription subpass(vk::SubpassDescriptionFlags(), vk::PipelineBindPoint::eGraphics, 0, nullptr, 1, &colorReference, + nullptr, nullptr); - renderPass = device->createRenderPassUnique(vk::RenderPassCreateInfo(vk::RenderPassCreateFlags(), 2, attachmentDescriptions, 1, &subpass)); + renderPass = device->createRenderPassUnique(vk::RenderPassCreateInfo(vk::RenderPassCreateFlags(), + 1, &attachmentDescription, 1, &subpass)); // Framebuffers, fences, semaphores - vk::ImageView attachments[2]; - attachments[1] = *depthView; framebuffers.reserve(imageViews.size()); drawFences.reserve(imageViews.size()); @@ -600,14 +574,17 @@ void VulkanContext::CreateSwapChain() imageAcquiredSemaphores.reserve(imageViews.size()); for (auto const& view : imageViews) { - attachments[0] = *view; - framebuffers.push_back(device->createFramebufferUnique(vk::FramebufferCreateInfo(vk::FramebufferCreateFlags(), *renderPass, 2, attachments, width, height, 1))); + framebuffers.push_back(device->createFramebufferUnique(vk::FramebufferCreateInfo(vk::FramebufferCreateFlags(), *renderPass, + 1, &view.get(), width, height, 1))); drawFences.push_back(device->createFenceUnique(vk::FenceCreateInfo(vk::FenceCreateFlagBits::eSignaled))); renderCompleteSemaphores.push_back(device->createSemaphoreUnique(vk::SemaphoreCreateInfo())); imageAcquiredSemaphores.push_back(device->createSemaphoreUnique(vk::SemaphoreCreateInfo())); } + quadPipeline->Init(shaderManager.get()); - InitImgui(*renderPass); + InitImgui(); + + currentImage = GetSwapChainSize() - 1; INFO_LOG(RENDERER, "Vulkan swap chain created: %d x %d, swap chain size %d", width, height, (int)imageViews.size()); } @@ -680,7 +657,6 @@ void VulkanContext::NewFrame() void VulkanContext::BeginRenderPass() { - InitImgui(*renderPass); const vk::ClearValue clear_colors[] = { vk::ClearColorValue(std::array{0.f, 0.f, 0.f, 1.f}), vk::ClearDepthStencilValue{ 0.f, 0 } }; vk::CommandBuffer commandBuffer = *commandBuffers[currentImage]; commandBuffer.beginRenderPass(vk::RenderPassBeginInfo(*renderPass, *framebuffers[currentImage], vk::Rect2D({0, 0}, {width, height}), 2, clear_colors), @@ -716,6 +692,41 @@ void VulkanContext::Present() } } +extern Renderer *renderer; + +void VulkanContext::PresentFrame(vk::ImageView imageView, vk::Offset2D extent) +{ + NewFrame(); + BeginRenderPass(); + + float marginWidth = ((float)extent.y / extent.x * width / height - 1.f) / 2.f; + QuadVertex vtx[] = { + { { -1, -1, 0 }, { 0 - marginWidth, 0 } }, + { { 1, -1, 0 }, { 1 + marginWidth, 0 } }, + { { -1, 1, 0 }, { 0 - marginWidth, 1 } }, + { { 1, 1, 0 }, { 1 + marginWidth, 1 } }, + }; + quadBuffer->Update(vtx); + + vk::CommandBuffer commandBuffer = GetCurrentCommandBuffer(); + vk::Pipeline pipeline = quadPipeline->GetPipeline(); + commandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); + + quadPipeline->SetTexture(imageView); + quadPipeline->BindDescriptorSets(commandBuffer); + + float blendConstants[4] = { 1.0, 1.0, 1.0, 1.0 }; + commandBuffer.setBlendConstants(blendConstants); + + vk::Viewport viewport(0, 0, width, height); + commandBuffer.setViewport(0, 1, &viewport); + commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), vk::Extent2D(width, height))); + quadBuffer->Bind(commandBuffer); + quadBuffer->Draw(commandBuffer); + renderer->DrawOSD(false); + EndFrame(); +} + void VulkanContext::Term() { ImGui_ImplVulkan_Shutdown(); @@ -739,10 +750,10 @@ void VulkanContext::Term() imageViews.clear(); framebuffers.clear(); renderPass.reset(); + quadBuffer.reset(); + quadPipeline.reset(); + shaderManager.reset(); descriptorPool.reset(); - depthView.reset(); - depthMemory.reset(); - depthImage.reset(); commandBuffers.clear(); commandPools.clear(); imageAcquiredSemaphores.clear(); diff --git a/core/rend/vulkan/vulkan_context.h b/core/rend/vulkan/vulkan_context.h new file mode 100644 index 000000000..68bc65de9 --- /dev/null +++ b/core/rend/vulkan/vulkan_context.h @@ -0,0 +1,192 @@ +/* + Created on: Nov 29, 2019 + + Copyright 2019 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ +#pragma once +#include "vulkan.h" +#include "vmallocator.h" +#include "quad.h" +#include "rend/TexCache.h" + +extern int screen_width, screen_height; + +class VulkanContext +{ +public: + VulkanContext() { verify(contextInstance == nullptr); contextInstance = this; } + ~VulkanContext() { verify(contextInstance == this); contextInstance = nullptr; } + + bool Init(); + bool InitInstance(const char** extensions, uint32_t extensions_count); + bool InitDevice(); + void CreateSwapChain(); + void Term(); + void SetWindow(void *window, void *display) { this->window = window; this->display = display; } + + VkInstance GetInstance() const { return static_cast(instance.get()); } + u32 GetGraphicsQueueFamilyIndex() const { return graphicsQueueIndex; } + void SetWindowSize(u32 width, u32 height) { this->width = screen_width = width; this->height = screen_height = height; } + void NewFrame(); + void BeginRenderPass(); + void EndFrame(); + void Present(); + void PresentFrame(vk::ImageView imageView, vk::Offset2D extent); + + vk::PhysicalDevice GetPhysicalDevice() const { return physicalDevice; } + vk::Device GetDevice() const { return *device; } + vk::PipelineCache GetPipelineCache() const { return *pipelineCache; } + vk::RenderPass GetRenderPass() const { return *renderPass; } + vk::CommandBuffer GetCurrentCommandBuffer() const { return *commandBuffers[GetCurrentImageIndex()]; } + vk::DescriptorPool GetDescriptorPool() const { return *descriptorPool; } + vk::Extent2D GetViewPort() const { return { width, height }; } + int GetSwapChainSize() const { return (int)imageViews.size(); } + int GetCurrentImageIndex() const { return currentImage; } + void WaitIdle() const { graphicsQueue.waitIdle(); } + bool IsRendering() const { return rendering; } + vk::Queue GetGraphicsQueue() const { return graphicsQueue; } + vk::DeviceSize GetUniformBufferAlignment() const { return uniformBufferAlignment; } + vk::DeviceSize GetStorageBufferAlignment() const { return storageBufferAlignment; } + bool IsFormatSupported(TextureType textureType) + { + switch (textureType) + { + case TextureType::_4444: + return optimalTilingSupported4444; + case TextureType::_565: + return optimalTilingSupported565; + case TextureType::_5551: + return optimalTilingSupported1555; + default: + return true; + } + } + std::string GetDriverName() const { vk::PhysicalDeviceProperties props; physicalDevice.getProperties(&props); return props.deviceName; } + std::string GetDriverVersion() const { vk::PhysicalDeviceProperties props; physicalDevice.getProperties(&props); return std::to_string(props.driverVersion); } + vk::Format GetColorFormat() const { return colorFormat; } + vk::Format GetDepthFormat() const { return depthFormat; } + static VulkanContext *Instance() { return contextInstance; } + bool SupportsFragmentShaderStoresAndAtomics() const { return fragmentStoresAndAtomics; } + bool SupportsSamplerAnisotropy() const { return samplerAnisotropy; } + bool SupportsDedicatedAllocation() const { return dedicatedAllocationSupported; } + const VMAllocator& GetAllocator() const { return allocator; } + bool IsUnifiedMemory() const { return unifiedMemory; } + +private: + vk::Format FindDepthFormat(); + void InitImgui(); + void DoSwapAutomation(); + vk::SurfaceKHR GetSurface() { +#ifdef USE_SDL + return surface; +#else + return *surface; +#endif + } + + bool HasSurfaceDimensionChanged() + { + vk::SurfaceCapabilitiesKHR surfaceCapabilities = physicalDevice.getSurfaceCapabilitiesKHR(GetSurface()); + VkExtent2D swapchainExtent; + if (surfaceCapabilities.currentExtent.width == std::numeric_limits::max()) + { + // If the surface size is undefined, the size is set to the size of the images requested. + swapchainExtent.width = std::min(std::max(width, surfaceCapabilities.minImageExtent.width), surfaceCapabilities.maxImageExtent.width); + swapchainExtent.height = std::min(std::max(height, surfaceCapabilities.minImageExtent.height), surfaceCapabilities.maxImageExtent.height); + } + else + { + // If the surface size is defined, the swap chain size must match + swapchainExtent = surfaceCapabilities.currentExtent; + } + if (width == swapchainExtent.width && height == swapchainExtent.height) + return false; + + screen_width = width = swapchainExtent.width; + screen_height = height = swapchainExtent.height; + + return true; + } + + VMAllocator allocator; + void *window = nullptr; + void *display = nullptr; + bool rendering = false; + bool renderDone = false; + u32 width = 0; + u32 height = 0; + vk::UniqueInstance instance; + vk::PhysicalDevice physicalDevice; + + u32 graphicsQueueIndex = 0; + u32 presentQueueIndex = 0; + vk::DeviceSize uniformBufferAlignment = 0; + vk::DeviceSize storageBufferAlignment = 0; + bool optimalTilingSupported565 = false; + bool optimalTilingSupported1555 = false; + bool optimalTilingSupported4444 = false; + bool fragmentStoresAndAtomics = false; + bool samplerAnisotropy = false; + bool dedicatedAllocationSupported = false; + bool unifiedMemory = false; + vk::UniqueDevice device; + +#ifdef USE_SDL + vk::SurfaceKHR surface; +#else + vk::UniqueSurfaceKHR surface; +#endif + + vk::UniqueSwapchainKHR swapChain; + std::vector imageViews; + u32 currentImage = 0; + vk::Format colorFormat = vk::Format::eUndefined; + + vk::Queue graphicsQueue; + vk::Queue presentQueue; + + vk::UniqueDescriptorPool descriptorPool; + vk::UniqueRenderPass renderPass; + + vk::Format depthFormat = vk::Format::eUndefined; + + std::vector commandPools; + std::vector commandBuffers; + + std::vector framebuffers; + + std::vector drawFences; + std::vector renderCompleteSemaphores; + std::vector imageAcquiredSemaphores; + u32 currentSemaphore = 0; + + vk::UniquePipelineCache pipelineCache; + + std::unique_ptr quadBuffer; + std::unique_ptr quadPipeline; + std::unique_ptr shaderManager; + +#ifdef VK_DEBUG +#ifndef __ANDROID__ + vk::UniqueDebugUtilsMessengerEXT debugUtilsMessenger; +#else + vk::UniqueDebugReportCallbackEXT debugReportCallback; +#endif +#endif + static VulkanContext *contextInstance; +}; diff --git a/core/rend/vulkan/vulkan_renderer.cpp b/core/rend/vulkan/vulkan_renderer.cpp index ea8b89a9b..f88e1947f 100644 --- a/core/rend/vulkan/vulkan_renderer.cpp +++ b/core/rend/vulkan/vulkan_renderer.cpp @@ -52,6 +52,7 @@ public: } screenDrawer.Init(&samplerManager, &shaderManager); + screenDrawer.SetCommandPool(&texCommandPool); quadPipeline.Init(&shaderManager); quadBuffer = std::unique_ptr(new QuadBuffer()); @@ -75,6 +76,7 @@ public: vjoyTexture->SetCommandBuffer(texCommandPool.Allocate()); vjoyTexture->UploadToGPU(OSD_TEX_W, OSD_TEX_H, image_data); vjoyTexture->SetCommandBuffer(nullptr); + texCommandPool.EndFrame(); delete [] image_data; osdPipeline.Init(&shaderManager, vjoyTexture->GetImageView(), GetContext()->GetRenderPass()); } @@ -137,48 +139,7 @@ public: curTexture->SetCommandBuffer(nullptr); texCommandPool.EndFrame(); - TransformMatrix matrices(pvrrc); - glm::vec4 viewport_min = matrices.GetViewportMatrix() * glm::vec4(0, 0, 0, 1.f); - glm::vec4 viewport_dim = matrices.GetViewportMatrix() * glm::vec4(640.f, 480.f, 0, 0); - - float min_x = viewport_min[0]; - float min_y = viewport_min[1]; - width = viewport_dim[0]; - height = viewport_dim[1]; - if (width < 0) - { - min_x += width; - width = -width; - } - if (height < 0) - { - min_y += height; - height = -height; - } - quadBuffer->Update(); - - vk::CommandBuffer cmdBuffer = screenDrawer.BeginRenderPass(); - - vk::Pipeline pipeline = quadPipeline.GetPipeline(); - cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); - - quadPipeline.SetTexture(curTexture.get()); - quadPipeline.BindDescriptorSets(cmdBuffer); - - float blendConstants[4] = { 1.0, 1.0, 1.0, 1.0 }; - cmdBuffer.setBlendConstants(blendConstants); - - vk::Viewport viewport(min_x, min_y, width, height); - cmdBuffer.setViewport(0, 1, &viewport); - cmdBuffer.setScissor(0, vk::Rect2D( - vk::Offset2D((u32)std::max(lroundf(min_x), 0L), (u32)std::max(lroundf(min_y), 0L)), - vk::Extent2D((u32)std::max(lroundf(width), 0L), (u32)std::max(lroundf(height), 0L)))); - quadBuffer->Bind(cmdBuffer); - quadBuffer->Draw(cmdBuffer); - - gui_display_osd(); - - screenDrawer.EndRenderPass(); + GetContext()->PresentFrame(curTexture->GetImageView(), { 640, 480 }); return true; } @@ -209,12 +170,13 @@ public: if (result) CheckFogTexture(); - if (!result || !ctx->rend.isRTT) + if (!result) texCommandPool.EndFrame(); return result; } + // FIXME This needs to go in its own class void DrawOSD(bool clear_screen) override { gui_display_osd(); @@ -268,8 +230,7 @@ public: drawer = &screenDrawer; drawer->Draw(fogTexture.get()); - if (!pvrrc.isRTT) - DrawOSD(false); + drawer->EndRenderPass(); return !pvrrc.isRTT; diff --git a/core/wsi/context.h b/core/wsi/context.h index 0ba7bf743..88ce8f8c4 100644 --- a/core/wsi/context.h +++ b/core/wsi/context.h @@ -21,7 +21,7 @@ #pragma once #include "gl_context.h" #ifdef USE_VULKAN -#include "rend/vulkan/vulkan.h" +#include "rend/vulkan/vulkan_context.h" extern VulkanContext theVulkanContext; #endif diff --git a/core/wsi/switcher.cpp b/core/wsi/switcher.cpp index a6577f8ae..85ae2d459 100644 --- a/core/wsi/switcher.cpp +++ b/core/wsi/switcher.cpp @@ -33,6 +33,8 @@ void InitRenderApi() if (theVulkanContext.Init()) return; // Fall back to Open GL + WARN_LOG(RENDERER, "Vulkan init failed. Falling back to Open GL."); + settings.pvr.rend = 0; } #endif if (!theGLContext.Init())