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:
parent
dae0908735
commit
0280fcc9d4
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
*/
|
||||
#pragma once
|
||||
#include "vulkan.h"
|
||||
#include "vmallocator.h"
|
||||
|
||||
struct BufferData
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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, ¤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<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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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, ¤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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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")))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
|
|
Loading…
Reference in New Issue