vulkan: render to temp fbo then to screen

renderers render to image which is blitted to the screen by the context
batch texture updates command buffers and submit once
fix screen scaling
This commit is contained in:
Flyinghead 2019-11-29 19:28:22 +01:00
parent dae0908735
commit 0280fcc9d4
26 changed files with 646 additions and 585 deletions

View File

@ -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);

View File

@ -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)

View File

@ -20,6 +20,7 @@
*/
#pragma once
#include "vulkan.h"
#include "vmallocator.h"
struct BufferData
{

View File

@ -19,7 +19,7 @@
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
*/
#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<vk::CommandBuffer> 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<vk::CommandBuffer> GetInFlightCommandBuffers() const
{
const auto& buffers = inFlightBuffers[index];
std::vector<vk::CommandBuffer> 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<std::vector<vk::UniqueCommandBuffer>> freeBuffers;
std::vector<std::vector<vk::UniqueCommandBuffer>> inFlightBuffers;

View File

@ -21,6 +21,7 @@
#include <glm/glm.hpp>
#include "compiler.h"
#include "SPIRV/GlslangToSpv.h"
#include "vulkan_context.h"
static const TBuiltInResource DefaultTBuiltInResource = {
/* .MaxLights = */ 32,

View File

@ -408,7 +408,7 @@ vk::CommandBuffer TextureDrawer::BeginRenderPass()
{
if (!depthAttachment)
depthAttachment = std::unique_ptr<FramebufferAttachment>(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<FramebufferAttachment>(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, &currentCommandBuffer),
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<float, 4> { 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));
}

View File

@ -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<std::vector<SortTrigDrawParam>> sortedPolys;
std::vector<std::vector<u32>> 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<FramebufferAttachment>(
new FramebufferAttachment(GetContext()->GetPhysicalDevice(), GetContext()->GetDevice()));
depthAttachment->Init(viewport.width, viewport.height, GetContext()->GetDepthFormat(), vk::ImageUsageFlagBits::eDepthStencilAttachment);
colorAttachment = std::unique_ptr<FramebufferAttachment>(
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<vk::SubpassDependency> 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<PipelineManager>(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> descriptorSets;
std::vector<std::unique_ptr<BufferData>> mainBuffers;
std::unique_ptr<PipelineManager> screenPipelineManager;
vk::UniqueRenderPass renderPass;
vk::UniqueFramebuffer framebuffer;
std::unique_ptr<FramebufferAttachment> colorAttachment;
std::unique_ptr<FramebufferAttachment> 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<FramebufferAttachment> colorAttachment;
std::unique_ptr<FramebufferAttachment> depthAttachment;
vk::UniqueFence fence;
DescriptorSets descriptorSets;
std::unique_ptr<BufferData> mainBuffer;
CommandPool *commandPool = nullptr;
TextureCache *textureCache = nullptr;
};

View File

@ -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()

View File

@ -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<FramebufferAttachment>(
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<FramebufferAttachment>(
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<FramebufferAttachment>(
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<FramebufferAttachment>(
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, &currentCommandBuffer),
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;
}

View File

@ -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<std::unique_ptr<FramebufferAttachment>, 2> colorAttachments;
std::unique_ptr<FramebufferAttachment> 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<vk::UniqueFramebuffer> framebuffers;
std::unique_ptr<FramebufferAttachment> finalColorAttachment;
std::vector<OITDescriptorSets> descriptorSets;
std::vector<std::unique_ptr<BufferData>> mainBuffers;
std::unique_ptr<OITPipelineManager> 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<FramebufferAttachment> colorAttachment;
vk::UniqueFence fence;
OITDescriptorSets descriptorSets;
std::unique_ptr<BufferData> mainBuffer;
CommandPool *commandPool = nullptr;
TextureCache *textureCache = nullptr;
};

View File

@ -44,7 +44,7 @@ public:
textureDrawer.SetCommandPool(&texCommandPool);
screenDrawer.Init(&samplerManager, &shaderManager, &oitBuffers);
quadPipeline.Init(&normalShaderManager);
screenDrawer.SetCommandPool(&texCommandPool);
quadBuffer = std::unique_ptr<QuadBuffer>(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<false> 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<std::unique_ptr<Texture>> framebufferTextures;
QuadPipeline quadPipeline;
OSDPipeline osdPipeline;
std::unique_ptr<Texture> vjoyTexture;
std::unique_ptr<BufferData> osdBuffer;

View File

@ -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);

View File

@ -19,7 +19,7 @@
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
*/
#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<vk::SubpassDependency> GetSubpassDependencies() const

View File

@ -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);

View File

@ -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<vk::WriteDescriptorSet> 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<vk::UniqueDescriptorSet> 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;

View File

@ -19,6 +19,12 @@
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
*/
#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<vk::WriteDescriptorSet> 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);
}

View File

@ -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<BufferData> 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<vk::UniqueDescriptorSet> descriptorSets;
vk::UniquePipelineLayout pipelineLayout;
vk::UniqueDescriptorSetLayout descSetLayout;
ShaderManager *shaderManager;
};

View File

@ -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<BufferData>(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<BufferData>(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);

View File

@ -20,7 +20,7 @@
*/
#pragma once
#include <memory>
#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; }

View File

@ -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")))

View File

@ -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<VkInstance>(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<uint32_t>::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<vk::UniqueImageView> 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<vk::UniqueCommandPool> commandPools;
std::vector<vk::UniqueCommandBuffer> commandBuffers;
std::vector<vk::UniqueFramebuffer> framebuffers;
std::vector<vk::UniqueFence> drawFences;
std::vector<vk::UniqueSemaphore> renderCompleteSemaphores;
std::vector<vk::UniqueSemaphore> 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

View File

@ -18,7 +18,7 @@
You should have received a copy of the GNU General Public License
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
*/
#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<const char *> 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<VkDevice>(*device));
@ -446,6 +420,10 @@ bool VulkanContext::InitDevice()
}
allocator.Init(physicalDevice, *device);
quadBuffer = std::unique_ptr<QuadBuffer>(new QuadBuffer());
shaderManager = std::unique_ptr<ShaderManager>(new ShaderManager());
quadPipeline = std::unique_ptr<QuadPipeline>(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<float, 4>{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();

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
#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<VkInstance>(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<uint32_t>::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<vk::UniqueImageView> 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<vk::UniqueCommandPool> commandPools;
std::vector<vk::UniqueCommandBuffer> commandBuffers;
std::vector<vk::UniqueFramebuffer> framebuffers;
std::vector<vk::UniqueFence> drawFences;
std::vector<vk::UniqueSemaphore> renderCompleteSemaphores;
std::vector<vk::UniqueSemaphore> imageAcquiredSemaphores;
u32 currentSemaphore = 0;
vk::UniquePipelineCache pipelineCache;
std::unique_ptr<QuadBuffer> quadBuffer;
std::unique_ptr<QuadPipeline> quadPipeline;
std::unique_ptr<ShaderManager> shaderManager;
#ifdef VK_DEBUG
#ifndef __ANDROID__
vk::UniqueDebugUtilsMessengerEXT debugUtilsMessenger;
#else
vk::UniqueDebugReportCallbackEXT debugReportCallback;
#endif
#endif
static VulkanContext *contextInstance;
};

View File

@ -52,6 +52,7 @@ public:
}
screenDrawer.Init(&samplerManager, &shaderManager);
screenDrawer.SetCommandPool(&texCommandPool);
quadPipeline.Init(&shaderManager);
quadBuffer = std::unique_ptr<QuadBuffer>(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<false> 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;

View File

@ -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

View File

@ -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())