mirror of https://github.com/PCSX2/pcsx2.git
Frontend: Add VulkanHostDisplay
This commit is contained in:
parent
a27b6a113a
commit
c4ab6280c6
|
@ -885,6 +885,17 @@ set(pcsx2FrontendHeaders
|
|||
Frontend/OpenGLHostDisplay.h
|
||||
)
|
||||
|
||||
if(USE_VULKAN)
|
||||
list(APPEND pcsx2FrontendSources
|
||||
Frontend/VulkanHostDisplay.cpp
|
||||
Frontend/imgui_impl_vulkan.cpp
|
||||
)
|
||||
list(APPEND pcsx2FrontendHeaders
|
||||
Frontend/imgui_impl_vulkan.h
|
||||
Frontend/VulkanHostDisplay.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND pcsx2FrontendSources
|
||||
Frontend/D3D11HostDisplay.cpp
|
||||
|
|
|
@ -403,6 +403,7 @@ struct Pcsx2Config
|
|||
UseDebugDevice : 1,
|
||||
UseBlitSwapChain : 1,
|
||||
DisableShaderCache : 1,
|
||||
ThreadedPresentation : 1,
|
||||
OsdShowMessages : 1,
|
||||
OsdShowSpeed : 1,
|
||||
OsdShowFPS : 1,
|
||||
|
|
|
@ -217,7 +217,7 @@ void D3D11HostDisplay::SetVSync(VsyncMode mode)
|
|||
m_vsync = mode;
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device)
|
||||
bool D3D11HostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool threaded_presentation, bool debug_device)
|
||||
{
|
||||
UINT create_flags = 0;
|
||||
if (debug_device)
|
||||
|
|
|
@ -42,7 +42,7 @@ public:
|
|||
bool HasRenderDevice() const override;
|
||||
bool HasRenderSurface() const override;
|
||||
|
||||
bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device) override;
|
||||
bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool threaded_presentation, bool debug_device) override;
|
||||
bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) override;
|
||||
void DestroyRenderDevice() override;
|
||||
|
||||
|
|
|
@ -196,7 +196,7 @@ bool OpenGLHostDisplay::HasRenderSurface() const
|
|||
return m_window_info.type != WindowInfo::Type::Surfaceless;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device)
|
||||
bool OpenGLHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool threaded_presentation, bool debug_device)
|
||||
{
|
||||
m_gl_context = GL::Context::Create(wi);
|
||||
if (!m_gl_context)
|
||||
|
|
|
@ -36,7 +36,7 @@ public:
|
|||
bool HasRenderDevice() const override;
|
||||
bool HasRenderSurface() const override;
|
||||
|
||||
bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device) override;
|
||||
bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool threaded_presentation, bool debug_device) override;
|
||||
bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) override;
|
||||
void DestroyRenderDevice() override;
|
||||
|
||||
|
|
|
@ -0,0 +1,401 @@
|
|||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "VulkanHostDisplay.h"
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/ScopedGuard.h"
|
||||
#include "common/Vulkan/Builders.h"
|
||||
#include "common/Vulkan/Context.h"
|
||||
#include "common/Vulkan/ShaderCache.h"
|
||||
#include "common/Vulkan/StreamBuffer.h"
|
||||
#include "common/Vulkan/SwapChain.h"
|
||||
#include "common/Vulkan/Util.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_vulkan.h"
|
||||
#include <array>
|
||||
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 1;
|
||||
|
||||
class VulkanHostDisplayTexture : public HostDisplayTexture
|
||||
{
|
||||
public:
|
||||
explicit VulkanHostDisplayTexture(Vulkan::Texture texture)
|
||||
: m_texture(std::move(texture))
|
||||
{
|
||||
}
|
||||
~VulkanHostDisplayTexture() override = default;
|
||||
|
||||
void* GetHandle() const override { return const_cast<Vulkan::Texture*>(&m_texture); }
|
||||
u32 GetWidth() const override { return m_texture.GetWidth(); }
|
||||
u32 GetHeight() const override { return m_texture.GetHeight(); }
|
||||
u32 GetLayers() const override { return m_texture.GetLayers(); }
|
||||
u32 GetLevels() const override { return m_texture.GetLevels(); }
|
||||
|
||||
const Vulkan::Texture& GetTexture() const { return m_texture; }
|
||||
Vulkan::Texture& GetTexture() { return m_texture; }
|
||||
|
||||
private:
|
||||
Vulkan::Texture m_texture;
|
||||
};
|
||||
|
||||
VulkanHostDisplay::VulkanHostDisplay() = default;
|
||||
|
||||
VulkanHostDisplay::~VulkanHostDisplay()
|
||||
{
|
||||
pxAssertRel(!g_vulkan_context, "Context should have been destroyed by now");
|
||||
pxAssertRel(!m_swap_chain, "Swap chain should have been destroyed by now");
|
||||
}
|
||||
|
||||
HostDisplay::RenderAPI VulkanHostDisplay::GetRenderAPI() const { return HostDisplay::RenderAPI::Vulkan; }
|
||||
|
||||
void* VulkanHostDisplay::GetRenderDevice() const { return nullptr; }
|
||||
|
||||
void* VulkanHostDisplay::GetRenderContext() const { return nullptr; }
|
||||
|
||||
void* VulkanHostDisplay::GetRenderSurface() const { return m_swap_chain.get(); }
|
||||
|
||||
bool VulkanHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi)
|
||||
{
|
||||
g_vulkan_context->WaitForGPUIdle();
|
||||
|
||||
if (new_wi.type == WindowInfo::Type::Surfaceless)
|
||||
{
|
||||
g_vulkan_context->ExecuteCommandBuffer(true);
|
||||
m_swap_chain.reset();
|
||||
m_window_info = new_wi;
|
||||
return true;
|
||||
}
|
||||
|
||||
// recreate surface in existing swap chain if it already exists
|
||||
if (m_swap_chain)
|
||||
{
|
||||
if (m_swap_chain->RecreateSurface(new_wi))
|
||||
{
|
||||
m_window_info = m_swap_chain->GetWindowInfo();
|
||||
return true;
|
||||
}
|
||||
|
||||
m_swap_chain.reset();
|
||||
}
|
||||
|
||||
WindowInfo wi_copy(new_wi);
|
||||
VkSurfaceKHR surface = Vulkan::SwapChain::CreateVulkanSurface(
|
||||
g_vulkan_context->GetVulkanInstance(), g_vulkan_context->GetPhysicalDevice(), &wi_copy);
|
||||
if (surface == VK_NULL_HANDLE)
|
||||
{
|
||||
Console.Error("Failed to create new surface for swap chain");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_swap_chain = Vulkan::SwapChain::Create(wi_copy, surface, false);
|
||||
if (!m_swap_chain)
|
||||
{
|
||||
Console.Error("Failed to create swap chain");
|
||||
Vulkan::SwapChain::DestroyVulkanSurface(g_vulkan_context->GetVulkanInstance(), &wi_copy, surface);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_window_info = m_swap_chain->GetWindowInfo();
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_height, float new_window_scale)
|
||||
{
|
||||
g_vulkan_context->WaitForGPUIdle();
|
||||
|
||||
if (!m_swap_chain->ResizeSwapChain(new_window_width, new_window_height))
|
||||
pxFailRel("Failed to resize swap chain");
|
||||
|
||||
m_window_info = m_swap_chain->GetWindowInfo();
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::SupportsFullscreen() const { return false; }
|
||||
|
||||
bool VulkanHostDisplay::IsFullscreen() { return false; }
|
||||
|
||||
bool VulkanHostDisplay::SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) { return false; }
|
||||
|
||||
HostDisplay::AdapterAndModeList VulkanHostDisplay::GetAdapterAndModeList()
|
||||
{
|
||||
return StaticGetAdapterAndModeList(m_window_info.type != WindowInfo::Type::Surfaceless ? &m_window_info : nullptr);
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::DestroyRenderSurface()
|
||||
{
|
||||
m_window_info = {};
|
||||
g_vulkan_context->WaitForGPUIdle();
|
||||
m_swap_chain.reset();
|
||||
}
|
||||
|
||||
static bool UploadBufferToTexture(Vulkan::Texture* texture, u32 width, u32 height, const void* data, u32 data_stride)
|
||||
{
|
||||
const u32 tight_stride = Vulkan::Util::GetTexelSize(texture->GetFormat()) * width;
|
||||
const u32 tight_size = tight_stride * height;
|
||||
|
||||
Vulkan::StreamBuffer& buf = g_vulkan_context->GetTextureUploadBuffer();
|
||||
if (!buf.ReserveMemory(tight_size, g_vulkan_context->GetBufferImageGranularity()))
|
||||
{
|
||||
Console.WriteLn("Executing command buffer for UploadBufferToTexture()");
|
||||
g_vulkan_context->ExecuteCommandBuffer(false);
|
||||
if (!buf.ReserveMemory(tight_size, g_vulkan_context->GetBufferImageGranularity()))
|
||||
{
|
||||
Console.WriteLn("Failed to allocate %u bytes in stream buffer for UploadBufferToTexture()", tight_size);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const u32 buf_offset = buf.GetCurrentOffset();
|
||||
StringUtil::StrideMemCpy(buf.GetCurrentHostPointer(), tight_stride, data, data_stride, tight_stride, height);
|
||||
buf.CommitMemory(tight_size);
|
||||
|
||||
texture->UpdateFromBuffer(
|
||||
g_vulkan_context->GetCurrentCommandBuffer(), 0, 0, 0, 0, width, height, width, buf.GetBuffer(), buf_offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> VulkanHostDisplay::CreateTexture(
|
||||
u32 width, u32 height, u32 layers, u32 levels, const void* data, u32 data_stride, bool dynamic /* = false */)
|
||||
{
|
||||
static constexpr VkFormat vk_format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
static constexpr VkImageUsageFlags usage =
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
|
||||
Vulkan::Texture texture;
|
||||
if (!texture.Create(width, height, levels, layers, vk_format, VK_SAMPLE_COUNT_1_BIT,
|
||||
(layers > 1) ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, usage))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
texture.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
|
||||
if (data)
|
||||
{
|
||||
if (!UploadBufferToTexture(&texture, width, height, data, data_stride))
|
||||
return {};
|
||||
}
|
||||
else
|
||||
{
|
||||
// clear it instead so we don't read uninitialized data (and keep the validation layer happy!)
|
||||
static constexpr VkClearColorValue ccv = {};
|
||||
static constexpr VkImageSubresourceRange isr = {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u};
|
||||
vkCmdClearColorImage(
|
||||
g_vulkan_context->GetCurrentCommandBuffer(), texture.GetImage(), texture.GetLayout(), &ccv, 1u, &isr);
|
||||
}
|
||||
|
||||
texture.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
return std::make_unique<VulkanHostDisplayTexture>(std::move(texture));
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::UpdateTexture(
|
||||
HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 data_stride)
|
||||
{
|
||||
UploadBufferToTexture(
|
||||
&static_cast<VulkanHostDisplayTexture*>(texture)->GetTexture(), width, height, data, data_stride);
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::SetVSync(VsyncMode mode)
|
||||
{
|
||||
if (!m_swap_chain)
|
||||
return;
|
||||
|
||||
// This swap chain should not be used by the current buffer, thus safe to destroy.
|
||||
g_vulkan_context->WaitForGPUIdle();
|
||||
m_swap_chain->SetVSync(mode != VsyncMode::Off);
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::CreateRenderDevice(
|
||||
const WindowInfo& wi, std::string_view adapter_name, bool threaded_presentation, bool debug_device)
|
||||
{
|
||||
// debug_device = true;
|
||||
|
||||
WindowInfo local_wi(wi);
|
||||
if (!Vulkan::Context::Create(
|
||||
adapter_name, &local_wi, &m_swap_chain, threaded_presentation, debug_device, debug_device))
|
||||
{
|
||||
Console.Error("Failed to create Vulkan context");
|
||||
m_window_info = {};
|
||||
return false;
|
||||
}
|
||||
|
||||
m_window_info = m_swap_chain ? m_swap_chain->GetWindowInfo() : local_wi;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device)
|
||||
{
|
||||
Vulkan::ShaderCache::Create(shader_cache_directory, SHADER_CACHE_VERSION, debug_device);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::HasRenderDevice() const { return static_cast<bool>(g_vulkan_context); }
|
||||
|
||||
bool VulkanHostDisplay::HasRenderSurface() const { return static_cast<bool>(m_swap_chain); }
|
||||
|
||||
bool VulkanHostDisplay::CreateImGuiContext()
|
||||
{
|
||||
ImGui_ImplVulkan_InitInfo vii = {};
|
||||
vii.Instance = g_vulkan_context->GetVulkanInstance();
|
||||
vii.PhysicalDevice = g_vulkan_context->GetPhysicalDevice();
|
||||
vii.Device = g_vulkan_context->GetDevice();
|
||||
vii.QueueFamily = g_vulkan_context->GetGraphicsQueueFamilyIndex();
|
||||
vii.Queue = g_vulkan_context->GetGraphicsQueue();
|
||||
vii.PipelineCache = g_vulkan_shader_cache->GetPipelineCache();
|
||||
vii.MinImageCount = m_swap_chain->GetImageCount();
|
||||
vii.ImageCount = m_swap_chain->GetImageCount();
|
||||
vii.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
return ImGui_ImplVulkan_Init(&vii, m_swap_chain->GetClearRenderPass());
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::DestroyImGuiContext()
|
||||
{
|
||||
g_vulkan_context->WaitForGPUIdle();
|
||||
ImGui_ImplVulkan_Shutdown();
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::UpdateImGuiFontTexture()
|
||||
{
|
||||
// Just in case we were drawing something.
|
||||
g_vulkan_context->ExecuteCommandBuffer(true);
|
||||
ImGui_ImplVulkan_DestroyFontUploadObjects();
|
||||
return ImGui_ImplVulkan_CreateFontsTexture(g_vulkan_context->GetCurrentCommandBuffer());
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::DestroyRenderDevice()
|
||||
{
|
||||
if (!g_vulkan_context)
|
||||
return;
|
||||
|
||||
g_vulkan_context->WaitForGPUIdle();
|
||||
|
||||
Vulkan::ShaderCache::Destroy();
|
||||
DestroyRenderSurface();
|
||||
Vulkan::Context::Destroy();
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::MakeRenderContextCurrent() { return true; }
|
||||
|
||||
bool VulkanHostDisplay::DoneRenderContextCurrent() { return true; }
|
||||
|
||||
bool VulkanHostDisplay::BeginPresent(bool frame_skip)
|
||||
{
|
||||
if (frame_skip || !m_swap_chain)
|
||||
{
|
||||
ImGui::EndFrame();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Previous frame needs to be presented before we can acquire the swap chain.
|
||||
g_vulkan_context->WaitForPresentComplete();
|
||||
|
||||
VkResult res = m_swap_chain->AcquireNextImage();
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR)
|
||||
{
|
||||
ResizeRenderWindow(0, 0, m_window_info.surface_scale);
|
||||
res = m_swap_chain->AcquireNextImage();
|
||||
}
|
||||
else if (res == VK_ERROR_SURFACE_LOST_KHR)
|
||||
{
|
||||
Console.Warning("Surface lost, attempting to recreate");
|
||||
if (!m_swap_chain->RecreateSurface(m_window_info))
|
||||
{
|
||||
Console.Error("Failed to recreate surface after loss");
|
||||
g_vulkan_context->ExecuteCommandBuffer(false);
|
||||
m_swap_chain.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
res = m_swap_chain->AcquireNextImage();
|
||||
}
|
||||
|
||||
// This can happen when multiple resize events happen in quick succession.
|
||||
// In this case, just wait until the next frame to try again.
|
||||
if (res != VK_SUCCESS && res != VK_SUBOPTIMAL_KHR)
|
||||
{
|
||||
// Still submit the command buffer, otherwise we'll end up with several frames waiting.
|
||||
LOG_VULKAN_ERROR(res, "vkAcquireNextImageKHR() failed: ");
|
||||
g_vulkan_context->ExecuteCommandBuffer(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
|
||||
// Swap chain images start in undefined
|
||||
Vulkan::Texture& swap_chain_texture = m_swap_chain->GetCurrentTexture();
|
||||
swap_chain_texture.OverrideImageLayout(VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
swap_chain_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
||||
const VkClearValue clear_value = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
|
||||
const VkRenderPassBeginInfo rp = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr,
|
||||
m_swap_chain->GetClearRenderPass(), m_swap_chain->GetCurrentFramebuffer(),
|
||||
{{0, 0}, {swap_chain_texture.GetWidth(), swap_chain_texture.GetHeight()}}, 1u, &clear_value};
|
||||
vkCmdBeginRenderPass(g_vulkan_context->GetCurrentCommandBuffer(), &rp, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
const VkViewport vp{0.0f, 0.0f, static_cast<float>(swap_chain_texture.GetWidth()),
|
||||
static_cast<float>(swap_chain_texture.GetHeight()), 0.0f, 1.0f};
|
||||
const VkRect2D scissor{
|
||||
{0, 0}, {static_cast<u32>(swap_chain_texture.GetWidth()), static_cast<u32>(swap_chain_texture.GetHeight())}};
|
||||
vkCmdSetViewport(g_vulkan_context->GetCurrentCommandBuffer(), 0, 1, &vp);
|
||||
vkCmdSetScissor(g_vulkan_context->GetCurrentCommandBuffer(), 0, 1, &scissor);
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::EndPresent()
|
||||
{
|
||||
ImGui::Render();
|
||||
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), g_vulkan_context->GetCurrentCommandBuffer());
|
||||
|
||||
VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer();
|
||||
vkCmdEndRenderPass(g_vulkan_context->GetCurrentCommandBuffer());
|
||||
m_swap_chain->GetCurrentTexture().TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
|
||||
g_vulkan_context->SubmitCommandBuffer(m_swap_chain->GetImageAvailableSemaphore(),
|
||||
m_swap_chain->GetRenderingFinishedSemaphore(), m_swap_chain->GetSwapChain(),
|
||||
m_swap_chain->GetCurrentImageIndex(), !m_swap_chain->IsVSyncEnabled());
|
||||
g_vulkan_context->MoveToNextCommandBuffer();
|
||||
}
|
||||
|
||||
HostDisplay::AdapterAndModeList VulkanHostDisplay::StaticGetAdapterAndModeList(const WindowInfo* wi)
|
||||
{
|
||||
AdapterAndModeList ret;
|
||||
std::vector<Vulkan::SwapChain::FullscreenModeInfo> fsmodes;
|
||||
|
||||
if (g_vulkan_context)
|
||||
{
|
||||
ret.adapter_names = Vulkan::Context::EnumerateGPUNames(g_vulkan_context->GetVulkanInstance());
|
||||
if (wi)
|
||||
{
|
||||
fsmodes = Vulkan::SwapChain::GetSurfaceFullscreenModes(
|
||||
g_vulkan_context->GetVulkanInstance(), g_vulkan_context->GetPhysicalDevice(), *wi);
|
||||
}
|
||||
}
|
||||
else if (Vulkan::LoadVulkanLibrary())
|
||||
{
|
||||
ScopedGuard lib_guard([]() { Vulkan::UnloadVulkanLibrary(); });
|
||||
|
||||
VkInstance instance = Vulkan::Context::CreateVulkanInstance(nullptr, false, false);
|
||||
if (instance != VK_NULL_HANDLE)
|
||||
{
|
||||
ScopedGuard instance_guard([&instance]() { vkDestroyInstance(instance, nullptr); });
|
||||
|
||||
if (Vulkan::LoadVulkanInstanceFunctions(instance))
|
||||
ret.adapter_names = Vulkan::Context::EnumerateGPUNames(instance);
|
||||
}
|
||||
}
|
||||
|
||||
if (!fsmodes.empty())
|
||||
{
|
||||
ret.fullscreen_modes.reserve(fsmodes.size());
|
||||
for (const Vulkan::SwapChain::FullscreenModeInfo& fmi : fsmodes)
|
||||
{
|
||||
ret.fullscreen_modes.push_back(GetFullscreenModeString(fmi.width, fmi.height, fmi.refresh_rate));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
#pragma once
|
||||
#include "common/Vulkan/Loader.h"
|
||||
#include "common/Vulkan/StreamBuffer.h"
|
||||
#include "common/Vulkan/SwapChain.h"
|
||||
#include "common/WindowInfo.h"
|
||||
#include "pcsx2/HostDisplay.h"
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
namespace Vulkan
|
||||
{
|
||||
class StreamBuffer;
|
||||
class SwapChain;
|
||||
} // namespace Vulkan
|
||||
|
||||
class VulkanHostDisplay final : public HostDisplay
|
||||
{
|
||||
public:
|
||||
VulkanHostDisplay();
|
||||
~VulkanHostDisplay();
|
||||
|
||||
RenderAPI GetRenderAPI() const override;
|
||||
void* GetRenderDevice() const override;
|
||||
void* GetRenderContext() const override;
|
||||
void* GetRenderSurface() const override;
|
||||
|
||||
bool HasRenderDevice() const override;
|
||||
bool HasRenderSurface() const override;
|
||||
|
||||
bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool threaded_presentation, bool debug_device) override;
|
||||
bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) override;
|
||||
void DestroyRenderDevice() override;
|
||||
|
||||
bool MakeRenderContextCurrent() override;
|
||||
bool DoneRenderContextCurrent() override;
|
||||
|
||||
bool ChangeRenderWindow(const WindowInfo& new_wi) override;
|
||||
void ResizeRenderWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override;
|
||||
bool SupportsFullscreen() const override;
|
||||
bool IsFullscreen() override;
|
||||
bool SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) override;
|
||||
AdapterAndModeList GetAdapterAndModeList() override;
|
||||
void DestroyRenderSurface() override;
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, u32 layers, u32 levels,
|
||||
const void* data, u32 data_stride, bool dynamic = false) override;
|
||||
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data,
|
||||
u32 texture_data_stride) override;
|
||||
|
||||
void SetVSync(VsyncMode mode) override;
|
||||
|
||||
bool BeginPresent(bool frame_skip) override;
|
||||
void EndPresent() override;
|
||||
|
||||
static AdapterAndModeList StaticGetAdapterAndModeList(const WindowInfo* wi);
|
||||
|
||||
protected:
|
||||
bool CreateImGuiContext() override;
|
||||
void DestroyImGuiContext() override;
|
||||
bool UpdateImGuiFontTexture() override;
|
||||
|
||||
std::unique_ptr<Vulkan::SwapChain> m_swap_chain;
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,125 @@
|
|||
// dear imgui: Renderer for Vulkan
|
||||
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices.
|
||||
// Missing features:
|
||||
// [ ] Renderer: User texture binding. Changes of ImTextureID aren't supported by this binding! See https://github.com/ocornut/imgui/pull/914
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
||||
// https://github.com/ocornut/imgui
|
||||
|
||||
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
|
||||
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
|
||||
|
||||
// Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app.
|
||||
// - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h.
|
||||
// You will use those if you want to use this rendering back-end in your engine/app.
|
||||
// - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by
|
||||
// the back-end itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code.
|
||||
// Read comments in imgui_impl_vulkan.h.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "imgui.h"
|
||||
#include "common/Vulkan/Loader.h"
|
||||
|
||||
// Initialization data, for ImGui_ImplVulkan_Init()
|
||||
// [Please zero-clear before use!]
|
||||
struct ImGui_ImplVulkan_InitInfo
|
||||
{
|
||||
VkInstance Instance;
|
||||
VkPhysicalDevice PhysicalDevice;
|
||||
VkDevice Device;
|
||||
uint32_t QueueFamily;
|
||||
VkQueue Queue;
|
||||
VkPipelineCache PipelineCache;
|
||||
uint32_t MinImageCount; // >= 2
|
||||
uint32_t ImageCount; // >= MinImageCount
|
||||
VkSampleCountFlagBits MSAASamples; // >= VK_SAMPLE_COUNT_1_BIT
|
||||
const VkAllocationCallbacks* Allocator;
|
||||
void (*CheckVkResultFn)(VkResult err);
|
||||
};
|
||||
|
||||
// Called by user code
|
||||
IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass);
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer);
|
||||
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontUploadObjects();
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated)
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Internal / Miscellaneous Vulkan Helpers
|
||||
// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app.)
|
||||
//-------------------------------------------------------------------------
|
||||
// You probably do NOT need to use or care about those functions.
|
||||
// Those functions only exist because:
|
||||
// 1) they facilitate the readability and maintenance of the multiple main.cpp examples files.
|
||||
// 2) the upcoming multi-viewport feature will need them internally.
|
||||
// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings,
|
||||
// but it is too much code to duplicate everywhere so we exceptionally expose them.
|
||||
//
|
||||
// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.).
|
||||
// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work.
|
||||
// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions)
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
struct ImGui_ImplVulkanH_Frame;
|
||||
struct ImGui_ImplVulkanH_Window;
|
||||
|
||||
// Helpers
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wnd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wnd, const VkAllocationCallbacks* allocator);
|
||||
IMGUI_IMPL_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space);
|
||||
IMGUI_IMPL_API VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count);
|
||||
IMGUI_IMPL_API int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode);
|
||||
|
||||
// Helper structure to hold the data needed by one rendering frame
|
||||
// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
|
||||
// [Please zero-clear before use!]
|
||||
struct ImGui_ImplVulkanH_Frame
|
||||
{
|
||||
VkCommandPool CommandPool;
|
||||
VkCommandBuffer CommandBuffer;
|
||||
VkFence Fence;
|
||||
VkImage Backbuffer;
|
||||
VkImageView BackbufferView;
|
||||
VkFramebuffer Framebuffer;
|
||||
};
|
||||
|
||||
struct ImGui_ImplVulkanH_FrameSemaphores
|
||||
{
|
||||
VkSemaphore ImageAcquiredSemaphore;
|
||||
VkSemaphore RenderCompleteSemaphore;
|
||||
};
|
||||
|
||||
// Helper structure to hold the data needed by one rendering context into one OS window
|
||||
// (Used by example's main.cpp. Used by multi-viewport features. Probably NOT used by your own engine/app.)
|
||||
struct ImGui_ImplVulkanH_Window
|
||||
{
|
||||
int Width;
|
||||
int Height;
|
||||
VkSwapchainKHR Swapchain;
|
||||
VkSurfaceKHR Surface;
|
||||
VkSurfaceFormatKHR SurfaceFormat;
|
||||
VkPresentModeKHR PresentMode;
|
||||
VkRenderPass RenderPass;
|
||||
bool ClearEnable;
|
||||
VkClearValue ClearValue;
|
||||
uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount)
|
||||
uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count)
|
||||
uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data)
|
||||
ImGui_ImplVulkanH_Frame* Frames;
|
||||
ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores;
|
||||
|
||||
ImGui_ImplVulkanH_Window()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR;
|
||||
ClearEnable = true;
|
||||
}
|
||||
};
|
||||
|
|
@ -709,7 +709,8 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config)
|
|||
GSConfig.Adapter != old_config.Adapter ||
|
||||
GSConfig.UseDebugDevice != old_config.UseDebugDevice ||
|
||||
GSConfig.UseBlitSwapChain != old_config.UseBlitSwapChain ||
|
||||
GSConfig.DisableShaderCache != old_config.DisableShaderCache
|
||||
GSConfig.DisableShaderCache != old_config.DisableShaderCache ||
|
||||
GSConfig.ThreadedPresentation != old_config.ThreadedPresentation
|
||||
);
|
||||
GSreopen(do_full_restart);
|
||||
return;
|
||||
|
@ -1300,7 +1301,7 @@ void GSApp::Init()
|
|||
m_default_configuration["shaderfx_conf"] = "shaders/GS_FX_Settings.ini";
|
||||
m_default_configuration["shaderfx_glsl"] = "shaders/GS.fx";
|
||||
m_default_configuration["skip_duplicate_frames"] = "0";
|
||||
m_default_configuration["threaded_presentation"] = "0";
|
||||
m_default_configuration["ThreadedPresentation"] = "0";
|
||||
m_default_configuration["throttle_present_rate"] = "0";
|
||||
m_default_configuration["TVShader"] = "0";
|
||||
m_default_configuration["upscale_multiplier"] = "1";
|
||||
|
|
|
@ -106,6 +106,10 @@ std::string HostDisplay::GetFullscreenModeString(u32 width, u32 height, float re
|
|||
|
||||
#include "Frontend/OpenGLHostDisplay.h"
|
||||
|
||||
#ifdef ENABLE_VULKAN
|
||||
#include "Frontend/VulkanHostDisplay.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Frontend/D3D11HostDisplay.h"
|
||||
#endif
|
||||
|
@ -123,6 +127,11 @@ std::unique_ptr<HostDisplay> HostDisplay::CreateDisplayForAPI(RenderAPI api)
|
|||
case HostDisplay::RenderAPI::OpenGLES:
|
||||
return std::make_unique<OpenGLHostDisplay>();
|
||||
|
||||
#ifdef ENABLE_VULKAN
|
||||
case RenderAPI::Vulkan:
|
||||
return std::make_unique<VulkanHostDisplay>();
|
||||
#endif
|
||||
|
||||
default:
|
||||
Console.Error("Unknown render API %u", static_cast<unsigned>(api));
|
||||
return {};
|
||||
|
|
|
@ -97,7 +97,7 @@ public:
|
|||
virtual bool HasRenderDevice() const = 0;
|
||||
virtual bool HasRenderSurface() const = 0;
|
||||
|
||||
virtual bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device) = 0;
|
||||
virtual bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool threaded_presentation, bool debug_device) = 0;
|
||||
virtual bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) = 0;
|
||||
virtual bool MakeRenderContextCurrent() = 0;
|
||||
virtual bool DoneRenderContextCurrent() = 0;
|
||||
|
|
|
@ -281,6 +281,7 @@ Pcsx2Config::GSOptions::GSOptions()
|
|||
UseDebugDevice = false;
|
||||
UseBlitSwapChain = false;
|
||||
DisableShaderCache = false;
|
||||
ThreadedPresentation = false;
|
||||
OsdShowMessages = true;
|
||||
OsdShowSpeed = false;
|
||||
OsdShowFPS = false;
|
||||
|
@ -390,7 +391,8 @@ bool Pcsx2Config::GSOptions::RestartOptionsAreEqual(const GSOptions& right) cons
|
|||
OpEqu(Adapter) &&
|
||||
OpEqu(UseDebugDevice) &&
|
||||
OpEqu(UseBlitSwapChain) &&
|
||||
OpEqu(DisableShaderCache);
|
||||
OpEqu(DisableShaderCache) &&
|
||||
OpEqu(ThreadedPresentation);
|
||||
}
|
||||
|
||||
void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
|
||||
|
@ -417,6 +419,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
|
|||
// These are loaded from GSWindow in wx.
|
||||
SettingsWrapEnumEx(AspectRatio, "AspectRatio", AspectRatioNames);
|
||||
SettingsWrapEnumEx(FMVAspectRatioSwitch, "FMVAspectRatioSwitch", FMVAspectRatioSwitchNames);
|
||||
|
||||
SettingsWrapEntry(Zoom);
|
||||
SettingsWrapEntry(StretchY);
|
||||
SettingsWrapEntry(OffsetX);
|
||||
|
@ -467,6 +470,7 @@ void Pcsx2Config::GSOptions::ReloadIniSettings()
|
|||
GSSettingBool(UseDebugDevice);
|
||||
GSSettingBool(UseBlitSwapChain);
|
||||
GSSettingBoolEx(DisableShaderCache, "disable_shader_cache");
|
||||
GSSettingBool(ThreadedPresentation);
|
||||
GSSettingBool(OsdShowMessages);
|
||||
GSSettingBool(OsdShowSpeed);
|
||||
GSSettingBool(OsdShowFPS);
|
||||
|
|
|
@ -120,7 +120,7 @@ HostDisplay* Host::AcquireHostDisplay(HostDisplay::RenderAPI api)
|
|||
if (!s_host_display)
|
||||
return nullptr;
|
||||
|
||||
if (!s_host_display->CreateRenderDevice(g_gs_window_info, GSConfig.Adapter, GSConfig.UseDebugDevice) ||
|
||||
if (!s_host_display->CreateRenderDevice(g_gs_window_info, GSConfig.Adapter, GSConfig.ThreadedPresentation, GSConfig.UseDebugDevice) ||
|
||||
!s_host_display->InitializeRenderDevice(StringUtil::wxStringToUTF8String(EmuFolders::Cache.ToString()), GSConfig.UseDebugDevice) ||
|
||||
!ImGuiManager::Initialize())
|
||||
{
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
<ForcedIncludeFiles>PrecompiledHeader.h;%(ForcedIncludeFiles)</ForcedIncludeFiles>
|
||||
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
|
||||
<AdditionalOptions>/Zc:externConstexpr %(AdditionalOptions)</AdditionalOptions>
|
||||
<PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;LZMA_API_STATIC;BUILD_DX=1;SPU2X_CUBEB;DIRECTINPUT_VERSION=0x0800;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;LZMA_API_STATIC;BUILD_DX=1;ENABLE_VULKAN;SPU2X_CUBEB;DIRECTINPUT_VERSION=0x0800;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions Condition="$(Configuration.Contains(Debug))">PCSX2_DEBUG;PCSX2_DEVBUILD;_SECURE_SCL_=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions Condition="$(Configuration.Contains(Devel))">PCSX2_DEVEL;PCSX2_DEVBUILD;NDEBUG;_SECURE_SCL_=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions Condition="$(Configuration.Contains(Release))">NDEBUG;_SECURE_SCL_=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
|
@ -305,7 +305,9 @@
|
|||
<ClCompile Include="DEV9\Win32\tap-win32.cpp" />
|
||||
<ClCompile Include="Frontend\D3D11HostDisplay.cpp" />
|
||||
<ClCompile Include="Frontend\ImGuiManager.cpp" />
|
||||
<ClCompile Include="Frontend\imgui_impl_vulkan.cpp" />
|
||||
<ClCompile Include="Frontend\OpenGLHostDisplay.cpp" />
|
||||
<ClCompile Include="Frontend\VulkanHostDisplay.cpp" />
|
||||
<ClCompile Include="GameDatabase.cpp" />
|
||||
<ClCompile Include="Gif_Logger.cpp" />
|
||||
<ClCompile Include="Gif_Unit.cpp" />
|
||||
|
@ -748,6 +750,7 @@
|
|||
<ClInclude Include="Frontend\D3D11HostDisplay.h" />
|
||||
<ClInclude Include="Frontend\ImGuiManager.h" />
|
||||
<ClInclude Include="Frontend\OpenGLHostDisplay.h" />
|
||||
<ClInclude Include="Frontend\VulkanHostDisplay.h" />
|
||||
<ClInclude Include="GameDatabase.h" />
|
||||
<ClInclude Include="Gif_Unit.h" />
|
||||
<ClInclude Include="GS\Renderers\DX11\D3D.h" />
|
||||
|
|
|
@ -1664,6 +1664,12 @@
|
|||
<ClCompile Include="Host.cpp">
|
||||
<Filter>Host</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Frontend\VulkanHostDisplay.cpp">
|
||||
<Filter>Host</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Frontend\imgui_impl_vulkan.cpp">
|
||||
<Filter>Host</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Patch.h">
|
||||
|
@ -2779,6 +2785,9 @@
|
|||
<ClInclude Include="Frontend\ImGuiManager.h">
|
||||
<Filter>Host</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Frontend\VulkanHostDisplay.h">
|
||||
<Filter>Host</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="windows\wxResources.rc">
|
||||
|
|
Loading…
Reference in New Issue