mirror of
https://github.com/izzy2lost/WeeU.git
synced 2026-07-06 00:19:59 -07:00
Vulkan: Refactor swapchain code (#399)
This commit is contained in:
@@ -178,6 +178,8 @@ add_library(CemuCafe
|
||||
HW/Latte/Renderer/Vulkan/LatteTextureVk.h
|
||||
HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp
|
||||
HW/Latte/Renderer/Vulkan/RendererShaderVk.h
|
||||
HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp
|
||||
HW/Latte/Renderer/Vulkan/SwapchainInfoVk.h
|
||||
HW/Latte/Renderer/Vulkan/TextureReadbackVk.cpp
|
||||
HW/Latte/Renderer/Vulkan/VKRBase.h
|
||||
HW/Latte/Renderer/Vulkan/VKRMemoryManager.cpp
|
||||
|
||||
@@ -0,0 +1,367 @@
|
||||
#include "SwapchainInfoVk.h"
|
||||
|
||||
#include "config/CemuConfig.h"
|
||||
#include "Cafe/HW/Latte/Core/Latte.h"
|
||||
#include "Cafe/HW/Latte/Core/LatteTiming.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
|
||||
|
||||
void SwapchainInfoVk::Create(VkPhysicalDevice physicalDevice, VkDevice logicalDevice)
|
||||
{
|
||||
m_physicalDevice = physicalDevice;
|
||||
m_logicalDevice = logicalDevice;
|
||||
const auto details = QuerySwapchainSupport(surface, physicalDevice);
|
||||
m_surfaceFormat = ChooseSurfaceFormat(details.formats);
|
||||
swapchainExtent = ChooseSwapExtent(details.capabilities, getSize());
|
||||
|
||||
// calculate number of swapchain presentation images
|
||||
uint32_t image_count = details.capabilities.minImageCount + 1;
|
||||
if (details.capabilities.maxImageCount > 0 && image_count > details.capabilities.maxImageCount)
|
||||
image_count = details.capabilities.maxImageCount;
|
||||
|
||||
VkSwapchainCreateInfoKHR create_info = CreateSwapchainCreateInfo(surface, details, m_surfaceFormat, image_count, swapchainExtent);
|
||||
create_info.oldSwapchain = nullptr;
|
||||
create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
|
||||
VkResult result = vkCreateSwapchainKHR(logicalDevice, &create_info, nullptr, &swapchain);
|
||||
if (result != VK_SUCCESS)
|
||||
UnrecoverableError("Error attempting to create a swapchain");
|
||||
|
||||
sizeOutOfDate = false;
|
||||
|
||||
result = vkGetSwapchainImagesKHR(logicalDevice, swapchain, &image_count, nullptr);
|
||||
if (result != VK_SUCCESS)
|
||||
UnrecoverableError("Error attempting to retrieve the count of swapchain images");
|
||||
|
||||
|
||||
m_swapchainImages.resize(image_count);
|
||||
result = vkGetSwapchainImagesKHR(logicalDevice, swapchain, &image_count, m_swapchainImages.data());
|
||||
if (result != VK_SUCCESS)
|
||||
UnrecoverableError("Error attempting to retrieve swapchain images");
|
||||
// create default renderpass
|
||||
VkAttachmentDescription colorAttachment = {};
|
||||
colorAttachment.format = m_surfaceFormat.format;
|
||||
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
|
||||
VkAttachmentReference colorAttachmentRef = {};
|
||||
colorAttachmentRef.attachment = 0;
|
||||
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
VkSubpassDescription subpass = {};
|
||||
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpass.colorAttachmentCount = 1;
|
||||
subpass.pColorAttachments = &colorAttachmentRef;
|
||||
|
||||
VkRenderPassCreateInfo renderPassInfo = {};
|
||||
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
renderPassInfo.attachmentCount = 1;
|
||||
renderPassInfo.pAttachments = &colorAttachment;
|
||||
renderPassInfo.subpassCount = 1;
|
||||
renderPassInfo.pSubpasses = &subpass;
|
||||
result = vkCreateRenderPass(logicalDevice, &renderPassInfo, nullptr, &m_swapchainRenderPass);
|
||||
if (result != VK_SUCCESS)
|
||||
UnrecoverableError("Failed to create renderpass for swapchain");
|
||||
|
||||
// create swapchain image views
|
||||
m_swapchainImageViews.resize(m_swapchainImages.size());
|
||||
for (sint32 i = 0; i < m_swapchainImages.size(); i++)
|
||||
{
|
||||
VkImageViewCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
createInfo.image = m_swapchainImages[i];
|
||||
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
createInfo.format = m_surfaceFormat.format;
|
||||
createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
createInfo.subresourceRange.baseMipLevel = 0;
|
||||
createInfo.subresourceRange.levelCount = 1;
|
||||
createInfo.subresourceRange.baseArrayLayer = 0;
|
||||
createInfo.subresourceRange.layerCount = 1;
|
||||
result = vkCreateImageView(logicalDevice, &createInfo, nullptr, &m_swapchainImageViews[i]);
|
||||
if (result != VK_SUCCESS)
|
||||
UnrecoverableError("Failed to create imageviews for swapchain");
|
||||
}
|
||||
|
||||
// create swapchain framebuffers
|
||||
m_swapchainFramebuffers.resize(m_swapchainImages.size());
|
||||
for (size_t i = 0; i < m_swapchainImages.size(); i++)
|
||||
{
|
||||
VkImageView attachments[1];
|
||||
attachments[0] = m_swapchainImageViews[i];
|
||||
// create framebuffer
|
||||
VkFramebufferCreateInfo framebufferInfo = {};
|
||||
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
framebufferInfo.renderPass = m_swapchainRenderPass;
|
||||
framebufferInfo.attachmentCount = 1;
|
||||
framebufferInfo.pAttachments = attachments;
|
||||
framebufferInfo.width = swapchainExtent.width;
|
||||
framebufferInfo.height = swapchainExtent.height;
|
||||
framebufferInfo.layers = 1;
|
||||
result = vkCreateFramebuffer(logicalDevice, &framebufferInfo, nullptr, &m_swapchainFramebuffers[i]);
|
||||
if (result != VK_SUCCESS)
|
||||
UnrecoverableError("Failed to create framebuffer for swapchain");
|
||||
}
|
||||
m_swapchainPresentSemaphores.resize(m_swapchainImages.size());
|
||||
// create present semaphore
|
||||
VkSemaphoreCreateInfo info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
for (auto& semaphore : m_swapchainPresentSemaphores){
|
||||
if (vkCreateSemaphore(logicalDevice, &info, nullptr, &semaphore) != VK_SUCCESS)
|
||||
UnrecoverableError("Failed to create semaphore for swapchain present");
|
||||
}
|
||||
|
||||
m_acquireSemaphores.resize(m_swapchainImages.size());
|
||||
for (auto& semaphore : m_acquireSemaphores)
|
||||
{
|
||||
VkSemaphoreCreateInfo info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
if (vkCreateSemaphore(logicalDevice, &info, nullptr, &semaphore) != VK_SUCCESS)
|
||||
UnrecoverableError("Failed to create semaphore for swapchain acquire");
|
||||
}
|
||||
m_acquireIndex = 0;
|
||||
|
||||
VkFenceCreateInfo fenceInfo = {};
|
||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
result = vkCreateFence(logicalDevice, &fenceInfo, nullptr, &m_imageAvailableFence);
|
||||
if (result != VK_SUCCESS)
|
||||
UnrecoverableError("Failed to create fence for swapchain");
|
||||
}
|
||||
|
||||
void SwapchainInfoVk::Cleanup()
|
||||
{
|
||||
m_swapchainImages.clear();
|
||||
|
||||
for (auto& sem: m_swapchainPresentSemaphores)
|
||||
vkDestroySemaphore(m_logicalDevice, sem, nullptr);
|
||||
m_swapchainPresentSemaphores.clear();
|
||||
|
||||
for (auto& itr: m_acquireSemaphores)
|
||||
vkDestroySemaphore(m_logicalDevice, itr, nullptr);
|
||||
m_acquireSemaphores.clear();
|
||||
|
||||
if (m_swapchainRenderPass)
|
||||
{
|
||||
vkDestroyRenderPass(m_logicalDevice, m_swapchainRenderPass, nullptr);
|
||||
m_swapchainRenderPass = nullptr;
|
||||
}
|
||||
|
||||
for (auto& imageView : m_swapchainImageViews)
|
||||
vkDestroyImageView(m_logicalDevice, imageView, nullptr);
|
||||
m_swapchainImageViews.clear();
|
||||
|
||||
for (auto& framebuffer : m_swapchainFramebuffers)
|
||||
vkDestroyFramebuffer(m_logicalDevice, framebuffer, nullptr);
|
||||
m_swapchainFramebuffers.clear();
|
||||
|
||||
|
||||
if (m_imageAvailableFence)
|
||||
{
|
||||
vkDestroyFence(m_logicalDevice, m_imageAvailableFence, nullptr);
|
||||
m_imageAvailableFence = nullptr;
|
||||
}
|
||||
if (swapchain)
|
||||
{
|
||||
vkDestroySwapchainKHR(m_logicalDevice, swapchain, nullptr);
|
||||
swapchain = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
bool SwapchainInfoVk::IsValid() const
|
||||
{
|
||||
return swapchain && m_imageAvailableFence;
|
||||
}
|
||||
|
||||
void SwapchainInfoVk::UnrecoverableError(const char* errMsg)
|
||||
{
|
||||
forceLog_printf("Unrecoverable error in Vulkan swapchain");
|
||||
forceLog_printf("Msg: %s", errMsg);
|
||||
throw std::runtime_error(errMsg);
|
||||
}
|
||||
|
||||
SwapchainInfoVk::QueueFamilyIndices SwapchainInfoVk::FindQueueFamilies(VkSurfaceKHR surface, VkPhysicalDevice device)
|
||||
{
|
||||
uint32_t queueFamilyCount = 0;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
|
||||
|
||||
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
|
||||
|
||||
QueueFamilyIndices indices;
|
||||
for (int i = 0; i < (int)queueFamilies.size(); ++i)
|
||||
{
|
||||
const auto& queueFamily = queueFamilies[i];
|
||||
if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
||||
indices.graphicsFamily = i;
|
||||
|
||||
VkBool32 presentSupport = false;
|
||||
const VkResult result = vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
|
||||
if (result != VK_SUCCESS)
|
||||
throw std::runtime_error(fmt::format("Error while attempting to check if a surface supports presentation: {}", result));
|
||||
|
||||
if (queueFamily.queueCount > 0 && presentSupport)
|
||||
indices.presentFamily = i;
|
||||
|
||||
if (indices.IsComplete())
|
||||
break;
|
||||
}
|
||||
|
||||
return indices;
|
||||
}
|
||||
|
||||
SwapchainInfoVk::SwapchainSupportDetails SwapchainInfoVk::QuerySwapchainSupport(VkSurfaceKHR surface, const VkPhysicalDevice& device)
|
||||
{
|
||||
SwapchainSupportDetails details;
|
||||
|
||||
VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
|
||||
if (result != VK_SUCCESS)
|
||||
{
|
||||
if (result != VK_ERROR_SURFACE_LOST_KHR)
|
||||
forceLog_printf("vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed. Error %d", (sint32)result);
|
||||
throw std::runtime_error(fmt::format("Unable to retrieve physical device surface capabilities: {}", result));
|
||||
}
|
||||
|
||||
uint32_t formatCount = 0;
|
||||
result = vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
|
||||
if (result != VK_SUCCESS)
|
||||
{
|
||||
forceLog_printf("vkGetPhysicalDeviceSurfaceFormatsKHR failed. Error %d", (sint32)result);
|
||||
throw std::runtime_error(fmt::format("Unable to retrieve the number of formats for a surface on a physical device: {}", result));
|
||||
}
|
||||
|
||||
if (formatCount != 0)
|
||||
{
|
||||
details.formats.resize(formatCount);
|
||||
result = vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
|
||||
if (result != VK_SUCCESS)
|
||||
{
|
||||
forceLog_printf("vkGetPhysicalDeviceSurfaceFormatsKHR failed. Error %d", (sint32)result);
|
||||
throw std::runtime_error(fmt::format("Unable to retrieve the formats for a surface on a physical device: {}", result));
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t presentModeCount = 0;
|
||||
result = vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
|
||||
if (result != VK_SUCCESS)
|
||||
{
|
||||
forceLog_printf("vkGetPhysicalDeviceSurfacePresentModesKHR failed. Error %d", (sint32)result);
|
||||
throw std::runtime_error(fmt::format("Unable to retrieve the count of present modes for a surface on a physical device: {}", result));
|
||||
}
|
||||
|
||||
if (presentModeCount != 0)
|
||||
{
|
||||
details.presentModes.resize(presentModeCount);
|
||||
result = vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
|
||||
if (result != VK_SUCCESS)
|
||||
{
|
||||
forceLog_printf("vkGetPhysicalDeviceSurfacePresentModesKHR failed. Error %d", (sint32)result);
|
||||
throw std::runtime_error(fmt::format("Unable to retrieve the present modes for a surface on a physical device: {}", result));
|
||||
}
|
||||
}
|
||||
|
||||
return details;
|
||||
}
|
||||
|
||||
VkSurfaceFormatKHR SwapchainInfoVk::ChooseSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& formats) const
|
||||
{
|
||||
if (formats.size() == 1 && formats[0].format == VK_FORMAT_UNDEFINED)
|
||||
return{ VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
|
||||
|
||||
for (const auto& format : formats)
|
||||
{
|
||||
bool useSRGB = mainWindow ? LatteGPUState.tvBufferUsesSRGB : LatteGPUState.drcBufferUsesSRGB;
|
||||
|
||||
if (useSRGB)
|
||||
{
|
||||
if (format.format == VK_FORMAT_B8G8R8A8_SRGB && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
||||
return format;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (format.format == VK_FORMAT_B8G8R8A8_UNORM && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
return formats[0];
|
||||
}
|
||||
|
||||
VkExtent2D SwapchainInfoVk::ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, const Vector2i& size) const
|
||||
{
|
||||
if (capabilities.currentExtent.width != std::numeric_limits<uint32>::max())
|
||||
return capabilities.currentExtent;
|
||||
|
||||
VkExtent2D actualExtent = { (uint32)size.x, (uint32)size.y };
|
||||
actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
|
||||
actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
|
||||
return actualExtent;
|
||||
}
|
||||
|
||||
VkPresentModeKHR SwapchainInfoVk::ChoosePresentMode(const std::vector<VkPresentModeKHR>& modes)
|
||||
{
|
||||
const auto vsyncState = (VSync)GetConfig().vsync.GetValue();
|
||||
if (vsyncState == VSync::MAILBOX)
|
||||
{
|
||||
if (std::find(modes.cbegin(), modes.cend(), VK_PRESENT_MODE_MAILBOX_KHR) != modes.cend())
|
||||
return VK_PRESENT_MODE_MAILBOX_KHR;
|
||||
|
||||
forceLog_printf("Vulkan: Can't find mailbox present mode");
|
||||
}
|
||||
else if (vsyncState == VSync::Immediate)
|
||||
{
|
||||
if (std::find(modes.cbegin(), modes.cend(), VK_PRESENT_MODE_IMMEDIATE_KHR) != modes.cend())
|
||||
return VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||
|
||||
forceLog_printf("Vulkan: Can't find immediate present mode");
|
||||
}
|
||||
else if (vsyncState == VSync::SYNC_AND_LIMIT)
|
||||
{
|
||||
LatteTiming_EnableHostDrivenVSync();
|
||||
// use immediate mode if available, other wise fall back to
|
||||
//if (std::find(modes.cbegin(), modes.cend(), VK_PRESENT_MODE_IMMEDIATE_KHR) != modes.cend())
|
||||
// return VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||
//else
|
||||
// forceLog_printf("Vulkan: Present mode 'immediate' not available. Vsync might not behave as intended");
|
||||
return VK_PRESENT_MODE_FIFO_KHR;
|
||||
}
|
||||
|
||||
return VK_PRESENT_MODE_FIFO_KHR;
|
||||
}
|
||||
|
||||
VkSwapchainCreateInfoKHR SwapchainInfoVk::CreateSwapchainCreateInfo(VkSurfaceKHR surface, const SwapchainSupportDetails& swapchainSupport, const VkSurfaceFormatKHR& surfaceFormat, uint32 imageCount, const VkExtent2D& extent)
|
||||
{
|
||||
VkSwapchainCreateInfoKHR createInfo{};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||
createInfo.surface = surface;
|
||||
createInfo.minImageCount = imageCount;
|
||||
createInfo.imageFormat = surfaceFormat.format;
|
||||
createInfo.imageExtent = extent;
|
||||
createInfo.imageArrayLayers = 1;
|
||||
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
const QueueFamilyIndices indices = FindQueueFamilies(surface, m_physicalDevice);
|
||||
uint32_t queueFamilyIndices[] = { (uint32)indices.graphicsFamily, (uint32)indices.presentFamily };
|
||||
if (indices.graphicsFamily != indices.presentFamily)
|
||||
{
|
||||
createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||
createInfo.queueFamilyIndexCount = 2;
|
||||
createInfo.pQueueFamilyIndices = queueFamilyIndices;
|
||||
}
|
||||
else
|
||||
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
||||
createInfo.preTransform = swapchainSupport.capabilities.currentTransform;
|
||||
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
createInfo.presentMode = ChoosePresentMode(swapchainSupport.presentModes);
|
||||
createInfo.clipped = VK_TRUE;
|
||||
|
||||
forceLogDebug_printf("vulkan presentation mode: %d", createInfo.presentMode);
|
||||
return createInfo;
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/math/vector2.h"
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
struct SwapchainInfoVk
|
||||
{
|
||||
enum class VSync
|
||||
{
|
||||
// values here must match GeneralSettings2::m_vsync
|
||||
Immediate = 0,
|
||||
FIFO = 1,
|
||||
MAILBOX = 2,
|
||||
SYNC_AND_LIMIT = 3, // synchronize emulated vsync events to monitor vsync. But skip events if rate higher than virtual vsync period
|
||||
};
|
||||
|
||||
struct QueueFamilyIndices
|
||||
{
|
||||
int32_t graphicsFamily = -1;
|
||||
int32_t presentFamily = -1;
|
||||
|
||||
bool IsComplete() const { return graphicsFamily >= 0 && presentFamily >= 0; }
|
||||
};
|
||||
|
||||
struct SwapchainSupportDetails
|
||||
{
|
||||
VkSurfaceCapabilitiesKHR capabilities;
|
||||
std::vector<VkSurfaceFormatKHR> formats;
|
||||
std::vector<VkPresentModeKHR> presentModes;
|
||||
};
|
||||
|
||||
void Cleanup();
|
||||
void Create(VkPhysicalDevice physicalDevice, VkDevice logicalDevice);
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
static void UnrecoverableError(const char* errMsg);
|
||||
|
||||
// todo: move this function somewhere more sensible. Not directly swapchain related
|
||||
static QueueFamilyIndices FindQueueFamilies(VkSurfaceKHR surface, VkPhysicalDevice device);
|
||||
static SwapchainSupportDetails QuerySwapchainSupport(VkSurfaceKHR surface, const VkPhysicalDevice& device);
|
||||
|
||||
VkPresentModeKHR ChoosePresentMode(const std::vector<VkPresentModeKHR>& modes);
|
||||
VkSurfaceFormatKHR ChooseSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& formats) const;
|
||||
VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, const Vector2i& size) const;
|
||||
|
||||
VkSwapchainCreateInfoKHR CreateSwapchainCreateInfo(VkSurfaceKHR surface, const SwapchainSupportDetails& swapchainSupport, const VkSurfaceFormatKHR& surfaceFormat, uint32 imageCount, const VkExtent2D& extent);
|
||||
|
||||
|
||||
void setSize(const Vector2i& newSize)
|
||||
{
|
||||
desiredExtent = newSize;
|
||||
sizeOutOfDate = true;
|
||||
}
|
||||
|
||||
const Vector2i& getSize() const
|
||||
{
|
||||
return desiredExtent;
|
||||
}
|
||||
|
||||
SwapchainInfoVk(VkSurfaceKHR surface, bool mainWindow)
|
||||
: surface(surface), mainWindow(mainWindow) {}
|
||||
SwapchainInfoVk(const SwapchainInfoVk&) = delete;
|
||||
SwapchainInfoVk(SwapchainInfoVk&&) noexcept = default;
|
||||
~SwapchainInfoVk()
|
||||
{
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
bool mainWindow{};
|
||||
|
||||
bool sizeOutOfDate{};
|
||||
bool m_usesSRGB = false;
|
||||
bool hasDefinedSwapchainImage{}; // indicates if the swapchain image is in a defined state
|
||||
|
||||
VkPhysicalDevice m_physicalDevice{};
|
||||
VkDevice m_logicalDevice{};
|
||||
VkSurfaceKHR surface{};
|
||||
VkSurfaceFormatKHR m_surfaceFormat{};
|
||||
VkSwapchainKHR swapchain{};
|
||||
VkExtent2D swapchainExtent{};
|
||||
VkFence m_imageAvailableFence{};
|
||||
uint32 swapchainImageIndex = (uint32)-1;
|
||||
uint32 m_acquireIndex = 0; // increases with every successful vkAcquireNextImageKHR
|
||||
VSync m_vsyncState = VSync::Immediate;
|
||||
|
||||
|
||||
// swapchain image ringbuffer (indexed by swapchainImageIndex)
|
||||
std::vector<VkImage> m_swapchainImages;
|
||||
std::vector<VkImageView> m_swapchainImageViews;
|
||||
std::vector<VkFramebuffer> m_swapchainFramebuffers;
|
||||
std::vector<VkSemaphore> m_swapchainPresentSemaphores;
|
||||
std::vector<VkSemaphore> m_acquireSemaphores; // indexed by acquireIndex
|
||||
|
||||
VkRenderPass m_swapchainRenderPass = nullptr;
|
||||
|
||||
|
||||
|
||||
private:
|
||||
Vector2i desiredExtent;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "Cafe/HW/Latte/Renderer/Renderer.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h"
|
||||
@@ -6,6 +7,7 @@
|
||||
#include "Cafe/HW/Latte/Renderer/Vulkan/LatteTextureViewVk.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Vulkan/CachedFBOVk.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Vulkan/VKRMemoryManager.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.h"
|
||||
#include "util/math/vector2.h"
|
||||
#include "util/helpers/Semaphore.h"
|
||||
#include "util/containers/flat_hash_map.hpp"
|
||||
@@ -124,6 +126,9 @@ class VulkanRenderer : public Renderer
|
||||
friend class LatteTextureReadbackInfoVk;
|
||||
friend class PipelineCompiler;
|
||||
|
||||
using VSync = SwapchainInfoVk::VSync;
|
||||
using QueueFamilyIndices = SwapchainInfoVk::QueueFamilyIndices;
|
||||
|
||||
static const inline int UNIFORMVAR_RINGBUFFER_SIZE = 1024 * 1024 * 16; // 16MB
|
||||
static const inline int INDEX_STREAM_BUFFER_SIZE = 16 * 1024 * 1024; // 16 MB
|
||||
|
||||
@@ -132,15 +137,7 @@ class VulkanRenderer : public Renderer
|
||||
static const inline int OCCLUSION_QUERY_POOL_SIZE = 1024;
|
||||
|
||||
public:
|
||||
enum class VSync
|
||||
{
|
||||
// values here must match GeneralSettings2::m_vsync
|
||||
Immediate = 0,
|
||||
FIFO = 1,
|
||||
MAILBOX = 2,
|
||||
SYNC_AND_LIMIT = 3, // synchronize emulated vsync events to monitor vsync. But skip events if rate higher than virtual vsync period
|
||||
};
|
||||
|
||||
|
||||
// memory management
|
||||
VKRMemoryManager* memoryManager{};
|
||||
VKRMemoryManager* GetMemoryManager() const { return memoryManager; };
|
||||
@@ -185,12 +182,15 @@ public:
|
||||
|
||||
void GetDeviceFeatures();
|
||||
void DetermineVendor();
|
||||
void Initialize(const Vector2i& size, bool isMainWindow);
|
||||
void Initialize(const Vector2i& size, bool mainWindow);
|
||||
|
||||
const std::unique_ptr<SwapchainInfoVk>& GetChainInfoPtr(bool mainWindow) const;
|
||||
SwapchainInfoVk& GetChainInfo(bool mainWindow) const;
|
||||
|
||||
bool IsPadWindowActive() override;
|
||||
|
||||
void HandleScreenshotRequest(LatteTextureView* texView, bool padView) override;
|
||||
void ResizeSwapchain(const Vector2i& size, bool isMainWindow);
|
||||
void SetSwapchainTargetSize(const Vector2i& size, bool mainWindow);
|
||||
|
||||
void QueryMemoryInfo();
|
||||
void QueryAvailableFormats();
|
||||
@@ -210,7 +210,7 @@ public:
|
||||
void ImguiInit();
|
||||
VkInstance GetVkInstance() const { return m_instance; }
|
||||
VkDevice GetLogicalDevice() const { return m_logicalDevice; }
|
||||
VkPhysicalDevice GetPhysicalDevice() const { return m_physical_device; }
|
||||
VkPhysicalDevice GetPhysicalDevice() const { return m_physicalDevice; }
|
||||
|
||||
VkDescriptorPool GetDescriptorPool() const { return m_descriptorPool; }
|
||||
|
||||
@@ -431,86 +431,12 @@ private:
|
||||
bool drawSequenceSkip; // if true, skip draw_execute()
|
||||
}m_state;
|
||||
|
||||
// swapchain - todo move this to m_swapchainState
|
||||
struct SwapChainInfo
|
||||
{
|
||||
SwapChainInfo(VkDevice device, VkSurfaceKHR surface) : m_device(device), surface(surface) {}
|
||||
SwapChainInfo(const SwapChainInfo&) = delete;
|
||||
SwapChainInfo(SwapChainInfo&&) noexcept = default;
|
||||
~SwapChainInfo()
|
||||
{
|
||||
if (m_swapChainRenderPass)
|
||||
{
|
||||
vkDestroyRenderPass(m_device, m_swapChainRenderPass, nullptr);
|
||||
m_swapChainRenderPass = VK_NULL_HANDLE;
|
||||
}
|
||||
if (swapChain)
|
||||
{
|
||||
vkDestroySwapchainKHR(m_device, swapChain, nullptr);
|
||||
swapChain = VK_NULL_HANDLE;
|
||||
}
|
||||
for (auto& imageView : m_swapchainImageViews)
|
||||
vkDestroyImageView(m_device, imageView, nullptr);
|
||||
m_swapchainImageViews.clear();
|
||||
for (auto& framebuffer : m_swapchainFramebuffers)
|
||||
vkDestroyFramebuffer(m_device, framebuffer, nullptr);
|
||||
m_swapchainFramebuffers.clear();
|
||||
}
|
||||
|
||||
VkDevice m_device;
|
||||
|
||||
VkSurfaceKHR surface{};
|
||||
VkSwapchainKHR swapChain{};
|
||||
VkExtent2D swapchainExtend{};
|
||||
uint32 swapchainImageIndex = (uint32)-1;
|
||||
uint32 m_acquireIndex = 0; // increases with every successful vkAcquireNextImageKHR
|
||||
VSync m_activeVSyncState = VSync::Immediate;
|
||||
|
||||
struct AcquireInfo
|
||||
{
|
||||
// move fence here?
|
||||
VkSemaphore acquireSemaphore;
|
||||
};
|
||||
std::vector<AcquireInfo> m_acquireInfo; // indexed by acquireIndex
|
||||
|
||||
// swapchain image ringbuffer (indexed by swapchainImageIndex)
|
||||
std::vector<VkImage> m_swapchainImages;
|
||||
std::vector<VkImageView> m_swapchainImageViews;
|
||||
std::vector<VkFramebuffer> m_swapchainFramebuffers;
|
||||
std::vector<VkSemaphore> m_swapchainPresentSemaphores;
|
||||
|
||||
VkFence m_imageAvailableFence = nullptr;
|
||||
VkRenderPass m_swapChainRenderPass = nullptr;
|
||||
VkRenderPass m_imguiRenderPass = nullptr;
|
||||
};
|
||||
std::unique_ptr<SwapChainInfo> m_mainSwapchainInfo{}, m_padSwapchainInfo{};
|
||||
std::unique_ptr<SwapchainInfoVk> m_mainSwapchainInfo{}, m_padSwapchainInfo{};
|
||||
bool IsSwapchainInfoValid(bool mainWindow) const;
|
||||
VkSwapchainKHR CreateSwapChain(SwapChainInfo& swap_chain_info, const Vector2i& size, bool mainwindow);
|
||||
|
||||
struct
|
||||
{
|
||||
bool resizeRequestedMainWindow{};
|
||||
Vector2i newExtentMainWindow;
|
||||
bool resizeRequestedPadWindow{};
|
||||
Vector2i newExtentPadWindow;
|
||||
bool tvHasDefinedSwapchainImage{}; // indicates if the swapchain image is in a defined state
|
||||
bool drcHasDefinedSwapchainImage{};
|
||||
}m_swapchainState;
|
||||
VkRenderPass m_imguiRenderPass = nullptr;
|
||||
|
||||
VkDescriptorPool m_descriptorPool;
|
||||
VkSurfaceFormatKHR m_swapchainFormat;
|
||||
|
||||
bool m_tvBufferUsesSRGB = false;
|
||||
bool m_drvBufferUsesSRGB = false;
|
||||
|
||||
struct QueueFamilyIndices
|
||||
{
|
||||
int32_t graphicsFamily = -1;
|
||||
int32_t presentFamily = -1;
|
||||
|
||||
bool IsComplete() const { return graphicsFamily >= 0 && presentFamily >= 0; }
|
||||
};
|
||||
static QueueFamilyIndices FindQueueFamilies(VkSurfaceKHR surface, const VkPhysicalDevice& device);
|
||||
|
||||
struct FeatureControl
|
||||
{
|
||||
@@ -556,15 +482,8 @@ private:
|
||||
static bool CheckDeviceExtensionSupport(const VkPhysicalDevice device, FeatureControl& info);
|
||||
static std::vector<const char*> CheckInstanceExtensionSupport(FeatureControl& info);
|
||||
|
||||
void UpdateVSyncState(bool main_window);
|
||||
void SwapBuffer(bool main_window);
|
||||
|
||||
struct SwapChainSupportDetails
|
||||
{
|
||||
VkSurfaceCapabilitiesKHR capabilities;
|
||||
std::vector<VkSurfaceFormatKHR> formats;
|
||||
std::vector<VkPresentModeKHR> presentModes;
|
||||
};
|
||||
void UpdateVSyncState(bool mainWindow);
|
||||
void SwapBuffer(bool mainWindow);
|
||||
|
||||
VkDescriptorSetLayout m_swapchainDescriptorSetLayout;
|
||||
|
||||
@@ -572,14 +491,9 @@ private:
|
||||
|
||||
// swapchain
|
||||
|
||||
static SwapChainSupportDetails QuerySwapChainSupport(VkSurfaceKHR surface, const VkPhysicalDevice& device);
|
||||
std::vector<VkDeviceQueueCreateInfo> CreateQueueCreateInfos(const std::set<int>& uniqueQueueFamilies) const;
|
||||
VkDeviceCreateInfo CreateDeviceCreateInfo(const std::vector<VkDeviceQueueCreateInfo>& queueCreateInfos, const VkPhysicalDeviceFeatures& deviceFeatures, const void* deviceExtensionStructs, std::vector<const char*>& used_extensions) const;
|
||||
static bool IsDeviceSuitable(VkSurfaceKHR surface, const VkPhysicalDevice& device);
|
||||
VkSurfaceFormatKHR ChooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& formats, bool mainWindow) const;
|
||||
VkPresentModeKHR ChooseSwapPresentMode(const std::vector<VkPresentModeKHR>& modes);
|
||||
VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, const Vector2i& size) const;
|
||||
VkSwapchainCreateInfoKHR CreateSwapchainCreateInfo(VkSurfaceKHR surface, const SwapChainSupportDetails& swapChainSupport, const VkSurfaceFormatKHR& surfaceFormat, uint32 imageCount, const VkExtent2D& extent);
|
||||
|
||||
void CreateCommandPool();
|
||||
void CreateCommandBuffers();
|
||||
@@ -641,8 +555,8 @@ private:
|
||||
void CreatePipelineCache();
|
||||
VkPipelineShaderStageCreateInfo CreatePipelineShaderStageCreateInfo(VkShaderStageFlagBits stage, VkShaderModule& module, const char* entryName) const;
|
||||
VkPipeline backbufferBlit_createGraphicsPipeline(VkDescriptorSetLayout descriptorLayout, bool padView, RendererOutputShader* shader);
|
||||
void AcquireNextSwapchainImage(bool main_window);
|
||||
void RecreateSwapchain(bool mainwindow);
|
||||
void AcquireNextSwapchainImage(bool mainWindow);
|
||||
void RecreateSwapchain(bool mainWindow);
|
||||
|
||||
// streamout
|
||||
void streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) override;
|
||||
@@ -665,7 +579,7 @@ private:
|
||||
|
||||
std::vector<const char*> m_layerNames;
|
||||
VkInstance m_instance = VK_NULL_HANDLE;
|
||||
VkPhysicalDevice m_physical_device = VK_NULL_HANDLE;
|
||||
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
|
||||
VkDevice m_logicalDevice = VK_NULL_HANDLE;
|
||||
VkDebugUtilsMessengerEXT m_debugCallback = nullptr;
|
||||
volatile bool m_destructionRequested = false;
|
||||
|
||||
@@ -60,5 +60,5 @@ void VulkanCanvas::OnResize(wxSizeEvent& event)
|
||||
return;
|
||||
|
||||
auto vulkan_renderer = VulkanRenderer::GetInstance();
|
||||
vulkan_renderer->ResizeSwapchain({ size.x, size.y }, m_is_main_window);
|
||||
}
|
||||
vulkan_renderer->SetSwapchainTargetSize({size.x, size.y}, m_is_main_window);
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd
|
||||
void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator);
|
||||
void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
|
||||
void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
|
||||
void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
|
||||
void ImGui_ImplVulkanH_CreateWindowSwapchain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
|
||||
void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator);
|
||||
|
||||
struct ImGuiTexture
|
||||
@@ -1082,7 +1082,7 @@ int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_m
|
||||
}
|
||||
|
||||
// Also destroy old swap chain and in-flight frames data, if any.
|
||||
void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count)
|
||||
void ImGui_ImplVulkanH_CreateWindowSwapchain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count)
|
||||
{
|
||||
VkResult err;
|
||||
VkSwapchainKHR old_swapchain = wd->Swapchain;
|
||||
@@ -1245,7 +1245,7 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V
|
||||
void ImGui_ImplVulkanH_CreateWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int width, int height, uint32_t min_image_count)
|
||||
{
|
||||
(void)instance;
|
||||
ImGui_ImplVulkanH_CreateWindowSwapChain(physical_device, device, wd, allocator, width, height, min_image_count);
|
||||
ImGui_ImplVulkanH_CreateWindowSwapchain(physical_device, device, wd, allocator, width, height, min_image_count);
|
||||
ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user