mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-11-26 11:04:18 +01:00
Vulkan: Refactor swapchain code (#399)
This commit is contained in:
parent
592c9b2776
commit
348d86648f
@ -178,6 +178,8 @@ add_library(CemuCafe
|
|||||||
HW/Latte/Renderer/Vulkan/LatteTextureVk.h
|
HW/Latte/Renderer/Vulkan/LatteTextureVk.h
|
||||||
HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp
|
HW/Latte/Renderer/Vulkan/RendererShaderVk.cpp
|
||||||
HW/Latte/Renderer/Vulkan/RendererShaderVk.h
|
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/TextureReadbackVk.cpp
|
||||||
HW/Latte/Renderer/Vulkan/VKRBase.h
|
HW/Latte/Renderer/Vulkan/VKRBase.h
|
||||||
HW/Latte/Renderer/Vulkan/VKRMemoryManager.cpp
|
HW/Latte/Renderer/Vulkan/VKRMemoryManager.cpp
|
||||||
|
367
src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp
Normal file
367
src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.cpp
Normal file
@ -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;
|
||||||
|
}
|
101
src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.h
Normal file
101
src/Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.h
Normal file
@ -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;
|
||||||
|
};
|
@ -180,7 +180,7 @@ void VulkanRenderer::DetermineVendor()
|
|||||||
if (m_featureControl.deviceExtensions.driver_properties)
|
if (m_featureControl.deviceExtensions.driver_properties)
|
||||||
properties.pNext = &driverProperties;
|
properties.pNext = &driverProperties;
|
||||||
|
|
||||||
vkGetPhysicalDeviceProperties2(m_physical_device, &properties);
|
vkGetPhysicalDeviceProperties2(m_physicalDevice, &properties);
|
||||||
switch (properties.properties.vendorID)
|
switch (properties.properties.vendorID)
|
||||||
{
|
{
|
||||||
case 0x10DE:
|
case 0x10DE:
|
||||||
@ -241,7 +241,7 @@ void VulkanRenderer::GetDeviceFeatures()
|
|||||||
physicalDeviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
physicalDeviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
||||||
physicalDeviceFeatures2.pNext = &pcc;
|
physicalDeviceFeatures2.pNext = &pcc;
|
||||||
|
|
||||||
vkGetPhysicalDeviceFeatures2(m_physical_device, &physicalDeviceFeatures2);
|
vkGetPhysicalDeviceFeatures2(m_physicalDevice, &physicalDeviceFeatures2);
|
||||||
|
|
||||||
m_featureControl.deviceExtensions.pipeline_creation_cache_control = pcc.pipelineCreationCacheControl;
|
m_featureControl.deviceExtensions.pipeline_creation_cache_control = pcc.pipelineCreationCacheControl;
|
||||||
m_featureControl.deviceExtensions.custom_border_color_without_format = m_featureControl.deviceExtensions.custom_border_color && bcf.customBorderColorWithoutFormat;
|
m_featureControl.deviceExtensions.custom_border_color_without_format = m_featureControl.deviceExtensions.custom_border_color && bcf.customBorderColorWithoutFormat;
|
||||||
@ -267,7 +267,7 @@ void VulkanRenderer::GetDeviceFeatures()
|
|||||||
// retrieve limits
|
// retrieve limits
|
||||||
VkPhysicalDeviceProperties2 p2{};
|
VkPhysicalDeviceProperties2 p2{};
|
||||||
p2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
|
p2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
|
||||||
vkGetPhysicalDeviceProperties2(m_physical_device, &p2);
|
vkGetPhysicalDeviceProperties2(m_physicalDevice, &p2);
|
||||||
m_featureControl.limits.minUniformBufferOffsetAlignment = std::max(p2.properties.limits.minUniformBufferOffsetAlignment, (VkDeviceSize)4);
|
m_featureControl.limits.minUniformBufferOffsetAlignment = std::max(p2.properties.limits.minUniformBufferOffsetAlignment, (VkDeviceSize)4);
|
||||||
m_featureControl.limits.nonCoherentAtomSize = std::max(p2.properties.limits.nonCoherentAtomSize, (VkDeviceSize)4);
|
m_featureControl.limits.nonCoherentAtomSize = std::max(p2.properties.limits.nonCoherentAtomSize, (VkDeviceSize)4);
|
||||||
cemuLog_log(LogType::Force, fmt::format("VulkanLimits: UBAlignment {0} nonCoherentAtomSize {1}", p2.properties.limits.minUniformBufferOffsetAlignment, p2.properties.limits.nonCoherentAtomSize));
|
cemuLog_log(LogType::Force, fmt::format("VulkanLimits: UBAlignment {0} nonCoherentAtomSize {1}", p2.properties.limits.minUniformBufferOffsetAlignment, p2.properties.limits.nonCoherentAtomSize));
|
||||||
@ -358,24 +358,24 @@ VulkanRenderer::VulkanRenderer()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_physical_device = device;
|
m_physicalDevice = device;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_physical_device == VK_NULL_HANDLE && fallbackDevice != VK_NULL_HANDLE)
|
if (m_physicalDevice == VK_NULL_HANDLE && fallbackDevice != VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
forceLog_printf("The selected GPU could not be found or is not suitable. Falling back to first available device instead");
|
forceLog_printf("The selected GPU could not be found or is not suitable. Falling back to first available device instead");
|
||||||
m_physical_device = fallbackDevice;
|
m_physicalDevice = fallbackDevice;
|
||||||
config.graphic_device_uuid = {}; // resetting device selection
|
config.graphic_device_uuid = {}; // resetting device selection
|
||||||
}
|
}
|
||||||
else if (m_physical_device == VK_NULL_HANDLE)
|
else if (m_physicalDevice == VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
forceLog_printf("No physical GPU could be found with the required extensions and swap chain support.");
|
forceLog_printf("No physical GPU could be found with the required extensions and swap chain support.");
|
||||||
throw std::runtime_error("No physical GPU could be found with the required extensions and swap chain support.");
|
throw std::runtime_error("No physical GPU could be found with the required extensions and swap chain support.");
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckDeviceExtensionSupport(m_physical_device, m_featureControl); // todo - merge this with GetDeviceFeatures and separate from IsDeviceSuitable?
|
CheckDeviceExtensionSupport(m_physicalDevice, m_featureControl); // todo - merge this with GetDeviceFeatures and separate from IsDeviceSuitable?
|
||||||
if (m_featureControl.debugMarkersSupported)
|
if (m_featureControl.debugMarkersSupported)
|
||||||
forceLog_printf("Debug: Frame debugger attached, will use vkDebugMarkerSetObjectNameEXT");
|
forceLog_printf("Debug: Frame debugger attached, will use vkDebugMarkerSetObjectNameEXT");
|
||||||
|
|
||||||
@ -390,7 +390,7 @@ VulkanRenderer::VulkanRenderer()
|
|||||||
VkPhysicalDeviceIDProperties physDeviceIDProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES };
|
VkPhysicalDeviceIDProperties physDeviceIDProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES };
|
||||||
VkPhysicalDeviceProperties2 physDeviceProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 };
|
VkPhysicalDeviceProperties2 physDeviceProps = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 };
|
||||||
physDeviceProps.pNext = &physDeviceIDProps;
|
physDeviceProps.pNext = &physDeviceIDProps;
|
||||||
vkGetPhysicalDeviceProperties2(m_physical_device, &physDeviceProps);
|
vkGetPhysicalDeviceProperties2(m_physicalDevice, &physDeviceProps);
|
||||||
|
|
||||||
#if BOOST_OS_WINDOWS
|
#if BOOST_OS_WINDOWS
|
||||||
m_dxgi_wrapper = std::make_unique<DXGIWrapper>(physDeviceIDProps.deviceLUID);
|
m_dxgi_wrapper = std::make_unique<DXGIWrapper>(physDeviceIDProps.deviceLUID);
|
||||||
@ -402,7 +402,7 @@ VulkanRenderer::VulkanRenderer()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create logical device
|
// create logical device
|
||||||
m_indices = FindQueueFamilies(surface, m_physical_device);
|
m_indices = SwapchainInfoVk::FindQueueFamilies(surface, m_physicalDevice);
|
||||||
std::set<int> uniqueQueueFamilies = { m_indices.graphicsFamily, m_indices.presentFamily };
|
std::set<int> uniqueQueueFamilies = { m_indices.graphicsFamily, m_indices.presentFamily };
|
||||||
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos = CreateQueueCreateInfos(uniqueQueueFamilies);
|
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos = CreateQueueCreateInfos(uniqueQueueFamilies);
|
||||||
VkPhysicalDeviceFeatures deviceFeatures = {};
|
VkPhysicalDeviceFeatures deviceFeatures = {};
|
||||||
@ -452,7 +452,7 @@ VulkanRenderer::VulkanRenderer()
|
|||||||
std::vector<const char*> used_extensions;
|
std::vector<const char*> used_extensions;
|
||||||
VkDeviceCreateInfo createInfo = CreateDeviceCreateInfo(queueCreateInfos, deviceFeatures, deviceExtensionFeatures, used_extensions);
|
VkDeviceCreateInfo createInfo = CreateDeviceCreateInfo(queueCreateInfos, deviceFeatures, deviceExtensionFeatures, used_extensions);
|
||||||
|
|
||||||
VkResult result = vkCreateDevice(m_physical_device, &createInfo, nullptr, &m_logicalDevice);
|
VkResult result = vkCreateDevice(m_physicalDevice, &createInfo, nullptr, &m_logicalDevice);
|
||||||
if (result != VK_SUCCESS)
|
if (result != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
forceLog_printf("Vulkan: Unable to create a logical device. Error %d", (sint32)result);
|
forceLog_printf("Vulkan: Unable to create a logical device. Error %d", (sint32)result);
|
||||||
@ -557,7 +557,7 @@ VulkanRenderer::VulkanRenderer()
|
|||||||
VulkanRenderer::~VulkanRenderer()
|
VulkanRenderer::~VulkanRenderer()
|
||||||
{
|
{
|
||||||
SubmitCommandBuffer();
|
SubmitCommandBuffer();
|
||||||
vkDeviceWaitIdle(m_logicalDevice);
|
WaitDeviceIdle();
|
||||||
WaitCommandBufferFinished(GetCurrentCommandBufferId());
|
WaitCommandBufferFinished(GetCurrentCommandBufferId());
|
||||||
// shut down pipeline save thread
|
// shut down pipeline save thread
|
||||||
m_destructionRequested = true;
|
m_destructionRequested = true;
|
||||||
@ -643,26 +643,39 @@ VulkanRenderer* VulkanRenderer::GetInstance()
|
|||||||
return (VulkanRenderer*)g_renderer.get();
|
return (VulkanRenderer*)g_renderer.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::Initialize(const Vector2i& size, bool isMainWindow)
|
void VulkanRenderer::Initialize(const Vector2i& size, bool mainWindow)
|
||||||
{
|
{
|
||||||
auto& windowHandleInfo = isMainWindow ? gui_getWindowInfo().canvas_main : gui_getWindowInfo().canvas_pad;
|
auto& windowHandleInfo = mainWindow ? gui_getWindowInfo().canvas_main : gui_getWindowInfo().canvas_pad;
|
||||||
|
|
||||||
const auto surface = CreateFramebufferSurface(m_instance, windowHandleInfo);
|
const auto surface = CreateFramebufferSurface(m_instance, windowHandleInfo);
|
||||||
if (isMainWindow)
|
if (mainWindow)
|
||||||
{
|
{
|
||||||
m_mainSwapchainInfo = std::make_unique<SwapChainInfo>(m_logicalDevice, surface);
|
m_mainSwapchainInfo = std::make_unique<SwapchainInfoVk>(surface, mainWindow);
|
||||||
CreateSwapChain(*m_mainSwapchainInfo, size, isMainWindow);
|
SetSwapchainTargetSize(size, mainWindow);
|
||||||
|
m_mainSwapchainInfo->Create(m_physicalDevice, m_logicalDevice);
|
||||||
|
|
||||||
// aquire first command buffer
|
// aquire first command buffer
|
||||||
InitFirstCommandBuffer();
|
InitFirstCommandBuffer();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_padSwapchainInfo = std::make_unique<SwapChainInfo>(m_logicalDevice, surface);
|
m_padSwapchainInfo = std::make_unique<SwapchainInfoVk>(surface, mainWindow);
|
||||||
CreateSwapChain(*m_padSwapchainInfo, size, isMainWindow);
|
SetSwapchainTargetSize(size, mainWindow);
|
||||||
|
// todo: figure out a way to exclusively create swapchain on main LatteThread
|
||||||
|
m_padSwapchainInfo->Create(m_physicalDevice, m_logicalDevice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::unique_ptr<SwapchainInfoVk>& VulkanRenderer::GetChainInfoPtr(bool mainWindow) const
|
||||||
|
{
|
||||||
|
return mainWindow ? m_mainSwapchainInfo : m_padSwapchainInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
SwapchainInfoVk& VulkanRenderer::GetChainInfo(bool mainWindow) const
|
||||||
|
{
|
||||||
|
return *GetChainInfoPtr(mainWindow);
|
||||||
|
}
|
||||||
|
|
||||||
bool VulkanRenderer::IsPadWindowActive()
|
bool VulkanRenderer::IsPadWindowActive()
|
||||||
{
|
{
|
||||||
return IsSwapchainInfoValid(false);
|
return IsSwapchainInfoValid(false);
|
||||||
@ -712,13 +725,13 @@ void VulkanRenderer::HandleScreenshotRequest(LatteTextureView* texView, bool pad
|
|||||||
if (format != VK_FORMAT_R8G8B8A8_UNORM && format != VK_FORMAT_R8G8B8A8_SRGB && format != VK_FORMAT_R8G8B8_UNORM && format != VK_FORMAT_R8G8B8_SNORM)
|
if (format != VK_FORMAT_R8G8B8A8_UNORM && format != VK_FORMAT_R8G8B8A8_SRGB && format != VK_FORMAT_R8G8B8_UNORM && format != VK_FORMAT_R8G8B8_SNORM)
|
||||||
{
|
{
|
||||||
VkFormatProperties formatProps;
|
VkFormatProperties formatProps;
|
||||||
vkGetPhysicalDeviceFormatProperties(m_physical_device, format, &formatProps);
|
vkGetPhysicalDeviceFormatProperties(m_physicalDevice, format, &formatProps);
|
||||||
bool supportsBlit = (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT) != 0;
|
bool supportsBlit = (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT) != 0;
|
||||||
|
|
||||||
const bool dstUsesSRGB = (!padView && LatteGPUState.tvBufferUsesSRGB) || (padView && LatteGPUState.drcBufferUsesSRGB);
|
const bool dstUsesSRGB = (!padView && LatteGPUState.tvBufferUsesSRGB) || (padView && LatteGPUState.drcBufferUsesSRGB);
|
||||||
const auto blitFormat = dstUsesSRGB ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
|
const auto blitFormat = dstUsesSRGB ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
|
||||||
vkGetPhysicalDeviceFormatProperties(m_physical_device, blitFormat, &formatProps);
|
vkGetPhysicalDeviceFormatProperties(m_physicalDevice, blitFormat, &formatProps);
|
||||||
supportsBlit &= (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT) != 0;
|
supportsBlit &= (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT) != 0;
|
||||||
|
|
||||||
// convert texture using blitting
|
// convert texture using blitting
|
||||||
@ -958,18 +971,9 @@ void VulkanRenderer::HandleScreenshotRequest(LatteTextureView* texView, bool pad
|
|||||||
SaveScreenshot(rgb_data, width, height, !padView);
|
SaveScreenshot(rgb_data, width, height, !padView);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::ResizeSwapchain(const Vector2i& size, bool isMainWindow)
|
void VulkanRenderer::SetSwapchainTargetSize(const Vector2i& size, bool mainWindow)
|
||||||
{
|
{
|
||||||
if (isMainWindow)
|
GetChainInfo(mainWindow).setSize(size);
|
||||||
{
|
|
||||||
m_swapchainState.newExtentMainWindow = size;
|
|
||||||
m_swapchainState.resizeRequestedMainWindow = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_swapchainState.newExtentPadWindow = size;
|
|
||||||
m_swapchainState.resizeRequestedPadWindow = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const float kQueuePriority = 1.0f;
|
static const float kQueuePriority = 1.0f;
|
||||||
@ -1050,36 +1054,6 @@ void VulkanRenderer::shader_unbind(RendererShader::ShaderType shaderType)
|
|||||||
// does nothing on Vulkan
|
// does nothing on Vulkan
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanRenderer::QueueFamilyIndices VulkanRenderer::FindQueueFamilies(VkSurfaceKHR surface, const 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VulkanRenderer::CheckDeviceExtensionSupport(const VkPhysicalDevice device, FeatureControl& info)
|
bool VulkanRenderer::CheckDeviceExtensionSupport(const VkPhysicalDevice device, FeatureControl& info)
|
||||||
{
|
{
|
||||||
std::vector<VkExtensionProperties> availableDeviceExtensions;
|
std::vector<VkExtensionProperties> availableDeviceExtensions;
|
||||||
@ -1212,62 +1186,9 @@ std::vector<const char*> VulkanRenderer::CheckInstanceExtensionSupport(FeatureCo
|
|||||||
return enabledInstanceExtensions;
|
return enabledInstanceExtensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
VulkanRenderer::SwapChainSupportDetails VulkanRenderer::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;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VulkanRenderer::IsDeviceSuitable(VkSurfaceKHR surface, const VkPhysicalDevice& device)
|
bool VulkanRenderer::IsDeviceSuitable(VkSurfaceKHR surface, const VkPhysicalDevice& device)
|
||||||
{
|
{
|
||||||
if (!FindQueueFamilies(surface, device).IsComplete())
|
if (!SwapchainInfoVk::FindQueueFamilies(surface, device).IsComplete())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// check API version (using Vulkan 1.0 way of querying properties)
|
// check API version (using Vulkan 1.0 way of querying properties)
|
||||||
@ -1282,9 +1203,9 @@ bool VulkanRenderer::IsDeviceSuitable(VkSurfaceKHR surface, const VkPhysicalDevi
|
|||||||
if (!CheckDeviceExtensionSupport(device, info))
|
if (!CheckDeviceExtensionSupport(device, info))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const SwapChainSupportDetails swapChainSupport = QuerySwapChainSupport(surface, device);
|
const auto swapchainSupport = SwapchainInfoVk::QuerySwapchainSupport(surface, device);
|
||||||
|
|
||||||
return !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
|
return !swapchainSupport.formats.empty() && !swapchainSupport.presentModes.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if BOOST_OS_WINDOWS
|
#if BOOST_OS_WINDOWS
|
||||||
@ -1358,70 +1279,6 @@ VkSurfaceKHR VulkanRenderer::CreateFramebufferSurface(VkInstance instance, struc
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
VkSurfaceFormatKHR VulkanRenderer::ChooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& formats, bool mainWindow) 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)
|
|
||||||
{
|
|
||||||
if ((mainWindow && LatteGPUState.tvBufferUsesSRGB) || (!mainWindow && LatteGPUState.drcBufferUsesSRGB))
|
|
||||||
{
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
|
|
||||||
VkPresentModeKHR VulkanRenderer::ChooseSwapPresentMode(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkExtent2D VulkanRenderer::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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::CreateCommandPool()
|
void VulkanRenderer::CreateCommandPool()
|
||||||
{
|
{
|
||||||
VkCommandPoolCreateInfo poolInfo{};
|
VkCommandPoolCreateInfo poolInfo{};
|
||||||
@ -1470,209 +1327,12 @@ void VulkanRenderer::CreateCommandBuffers()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkSwapchainCreateInfoKHR VulkanRenderer::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_physical_device);
|
|
||||||
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 = ChooseSwapPresentMode(swapChainSupport.presentModes);
|
|
||||||
createInfo.clipped = VK_TRUE;
|
|
||||||
|
|
||||||
forceLogDebug_printf("vulkan presentation mode: %d", createInfo.presentMode);
|
|
||||||
return createInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VulkanRenderer::IsSwapchainInfoValid(bool mainWindow) const
|
bool VulkanRenderer::IsSwapchainInfoValid(bool mainWindow) const
|
||||||
{
|
{
|
||||||
if (mainWindow)
|
auto& chainInfo = GetChainInfoPtr(mainWindow);
|
||||||
return m_mainSwapchainInfo && m_mainSwapchainInfo->swapChain && m_mainSwapchainInfo->m_imageAvailableFence;
|
return chainInfo && chainInfo->IsValid();
|
||||||
|
|
||||||
return m_padSwapchainInfo && m_padSwapchainInfo->swapChain && m_padSwapchainInfo->m_imageAvailableFence;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VkSwapchainKHR VulkanRenderer::CreateSwapChain(SwapChainInfo& swap_chain_info, const Vector2i& size, bool mainwindow)
|
|
||||||
{
|
|
||||||
const SwapChainSupportDetails details = QuerySwapChainSupport(swap_chain_info.surface, m_physical_device);
|
|
||||||
m_swapchainFormat = ChooseSwapSurfaceFormat(details.formats, mainwindow);
|
|
||||||
swap_chain_info.swapchainExtend = ChooseSwapExtent(details.capabilities, size);
|
|
||||||
// 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(swap_chain_info.surface, details, m_swapchainFormat, image_count, swap_chain_info.swapchainExtend);
|
|
||||||
create_info.oldSwapchain = swap_chain_info.swapChain;
|
|
||||||
swap_chain_info.swapChain = nullptr;
|
|
||||||
create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
|
||||||
|
|
||||||
VkResult result = vkCreateSwapchainKHR(m_logicalDevice, &create_info, nullptr, &swap_chain_info.swapChain);
|
|
||||||
if (result != VK_SUCCESS)
|
|
||||||
UnrecoverableError("Error attempting to create a swapchain");
|
|
||||||
|
|
||||||
result = vkGetSwapchainImagesKHR(m_logicalDevice, swap_chain_info.swapChain, &image_count, nullptr);
|
|
||||||
if (result != VK_SUCCESS)
|
|
||||||
UnrecoverableError("Error attempting to retrieve the count of swapchain images");
|
|
||||||
|
|
||||||
// clean up previously initialized swapchain
|
|
||||||
for (const auto& image : swap_chain_info.m_swapchainImages)
|
|
||||||
vkDestroyImage(m_logicalDevice, image, nullptr);
|
|
||||||
swap_chain_info.m_swapchainImages.clear();
|
|
||||||
for (auto& sem : swap_chain_info.m_swapchainPresentSemaphores)
|
|
||||||
vkDestroySemaphore(m_logicalDevice, sem, nullptr);
|
|
||||||
swap_chain_info.m_swapchainPresentSemaphores.clear();
|
|
||||||
|
|
||||||
|
|
||||||
swap_chain_info.m_swapchainImages.resize(image_count);
|
|
||||||
result = vkGetSwapchainImagesKHR(m_logicalDevice, swap_chain_info.swapChain, &image_count, swap_chain_info.m_swapchainImages.data());
|
|
||||||
if (result != VK_SUCCESS)
|
|
||||||
UnrecoverableError("Error attempting to retrieve swapchain images");
|
|
||||||
// create default renderpass
|
|
||||||
VkAttachmentDescription colorAttachment = {};
|
|
||||||
colorAttachment.format = m_swapchainFormat.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;
|
|
||||||
|
|
||||||
if (swap_chain_info.m_swapChainRenderPass)
|
|
||||||
{
|
|
||||||
vkDestroyRenderPass(m_logicalDevice, swap_chain_info.m_swapChainRenderPass, nullptr);
|
|
||||||
swap_chain_info.m_swapChainRenderPass = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
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(m_logicalDevice, &renderPassInfo, nullptr, &swap_chain_info.m_swapChainRenderPass);
|
|
||||||
if (result != VK_SUCCESS)
|
|
||||||
UnrecoverableError("Failed to create renderpass for swapchain");
|
|
||||||
|
|
||||||
// create swapchain image views
|
|
||||||
for (const auto& image_view : swap_chain_info.m_swapchainImageViews)
|
|
||||||
{
|
|
||||||
vkDestroyImageView(m_logicalDevice, image_view, nullptr);
|
|
||||||
}
|
|
||||||
swap_chain_info.m_swapchainImageViews.clear();
|
|
||||||
|
|
||||||
swap_chain_info.m_swapchainImageViews.resize(swap_chain_info.m_swapchainImages.size());
|
|
||||||
for (sint32 i = 0; i < swap_chain_info.m_swapchainImages.size(); i++)
|
|
||||||
{
|
|
||||||
VkImageViewCreateInfo createInfo = {};
|
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
||||||
createInfo.image = swap_chain_info.m_swapchainImages[i];
|
|
||||||
createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
||||||
createInfo.format = m_swapchainFormat.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(m_logicalDevice, &createInfo, nullptr, &swap_chain_info.m_swapchainImageViews[i]);
|
|
||||||
if (result != VK_SUCCESS)
|
|
||||||
UnrecoverableError("Failed to create imageviews for swapchain");
|
|
||||||
}
|
|
||||||
|
|
||||||
// create swapchain framebuffers
|
|
||||||
for (const auto& framebuffer : swap_chain_info.m_swapchainFramebuffers)
|
|
||||||
{
|
|
||||||
vkDestroyFramebuffer(m_logicalDevice, framebuffer, nullptr);
|
|
||||||
}
|
|
||||||
swap_chain_info.m_swapchainFramebuffers.clear();
|
|
||||||
|
|
||||||
swap_chain_info.m_swapchainFramebuffers.resize(swap_chain_info.m_swapchainImages.size());
|
|
||||||
swap_chain_info.m_swapchainPresentSemaphores.resize(swap_chain_info.m_swapchainImages.size());
|
|
||||||
for (size_t i = 0; i < swap_chain_info.m_swapchainImages.size(); i++)
|
|
||||||
{
|
|
||||||
VkImageView attachments[1];
|
|
||||||
attachments[0] = swap_chain_info.m_swapchainImageViews[i];
|
|
||||||
// create framebuffer
|
|
||||||
VkFramebufferCreateInfo framebufferInfo = {};
|
|
||||||
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
|
||||||
framebufferInfo.renderPass = swap_chain_info.m_swapChainRenderPass;
|
|
||||||
framebufferInfo.attachmentCount = 1;
|
|
||||||
framebufferInfo.pAttachments = attachments;
|
|
||||||
framebufferInfo.width = swap_chain_info.swapchainExtend.width;
|
|
||||||
framebufferInfo.height = swap_chain_info.swapchainExtend.height;
|
|
||||||
framebufferInfo.layers = 1;
|
|
||||||
result = vkCreateFramebuffer(m_logicalDevice, &framebufferInfo, nullptr, &swap_chain_info.m_swapchainFramebuffers[i]);
|
|
||||||
if (result != VK_SUCCESS)
|
|
||||||
UnrecoverableError("Failed to create framebuffer for swapchain");
|
|
||||||
// create present semaphore
|
|
||||||
VkSemaphoreCreateInfo info = {};
|
|
||||||
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
|
||||||
if (vkCreateSemaphore(m_logicalDevice, &info, nullptr, &swap_chain_info.m_swapchainPresentSemaphores[i]) != VK_SUCCESS)
|
|
||||||
UnrecoverableError("Failed to create semaphore for swapchain present");
|
|
||||||
}
|
|
||||||
|
|
||||||
// init m_acquireInfo
|
|
||||||
for (auto& itr : swap_chain_info.m_acquireInfo)
|
|
||||||
{
|
|
||||||
vkDestroySemaphore(m_logicalDevice, itr.acquireSemaphore, nullptr);
|
|
||||||
}
|
|
||||||
swap_chain_info.m_acquireInfo.clear();
|
|
||||||
swap_chain_info.m_acquireInfo.resize(swap_chain_info.m_swapchainImages.size());
|
|
||||||
for (auto& itr : swap_chain_info.m_acquireInfo)
|
|
||||||
{
|
|
||||||
VkSemaphoreCreateInfo info = {};
|
|
||||||
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
|
||||||
if (vkCreateSemaphore(m_logicalDevice, &info, nullptr, &itr.acquireSemaphore) != VK_SUCCESS)
|
|
||||||
UnrecoverableError("Failed to create semaphore for swapchain acquire");
|
|
||||||
}
|
|
||||||
swap_chain_info.m_acquireIndex = 0;
|
|
||||||
|
|
||||||
|
|
||||||
if (swap_chain_info.m_imageAvailableFence)
|
|
||||||
{
|
|
||||||
vkDestroyFence(m_logicalDevice, swap_chain_info.m_imageAvailableFence, nullptr);
|
|
||||||
swap_chain_info.m_imageAvailableFence = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkFenceCreateInfo fenceInfo = {};
|
|
||||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
|
||||||
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
|
||||||
result = vkCreateFence(m_logicalDevice, &fenceInfo, nullptr, &swap_chain_info.m_imageAvailableFence);
|
|
||||||
if (result != VK_SUCCESS)
|
|
||||||
UnrecoverableError("Failed to create fence for swapchain");
|
|
||||||
|
|
||||||
return swap_chain_info.swapChain;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VulkanRenderer::CreateNullTexture(NullTexture& nullTex, VkImageType imageType)
|
void VulkanRenderer::CreateNullTexture(NullTexture& nullTex, VkImageType imageType)
|
||||||
{
|
{
|
||||||
@ -1775,7 +1435,7 @@ void VulkanRenderer::ImguiInit()
|
|||||||
{
|
{
|
||||||
// TODO: renderpass swapchain format may change between srgb and rgb -> need reinit
|
// TODO: renderpass swapchain format may change between srgb and rgb -> need reinit
|
||||||
VkAttachmentDescription colorAttachment = {};
|
VkAttachmentDescription colorAttachment = {};
|
||||||
colorAttachment.format = m_swapchainFormat.format;
|
colorAttachment.format = m_mainSwapchainInfo->m_surfaceFormat.format;
|
||||||
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||||
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
@ -1798,13 +1458,13 @@ void VulkanRenderer::ImguiInit()
|
|||||||
renderPassInfo.pAttachments = &colorAttachment;
|
renderPassInfo.pAttachments = &colorAttachment;
|
||||||
renderPassInfo.subpassCount = 1;
|
renderPassInfo.subpassCount = 1;
|
||||||
renderPassInfo.pSubpasses = &subpass;
|
renderPassInfo.pSubpasses = &subpass;
|
||||||
const auto result = vkCreateRenderPass(m_logicalDevice, &renderPassInfo, nullptr, &m_mainSwapchainInfo->m_imguiRenderPass);
|
const auto result = vkCreateRenderPass(m_logicalDevice, &renderPassInfo, nullptr, &m_imguiRenderPass);
|
||||||
if (result != VK_SUCCESS)
|
if (result != VK_SUCCESS)
|
||||||
throw VkException(result, "can't create imgui renderpass");
|
throw VkException(result, "can't create imgui renderpass");
|
||||||
|
|
||||||
ImGui_ImplVulkan_InitInfo info{};
|
ImGui_ImplVulkan_InitInfo info{};
|
||||||
info.Instance = m_instance;
|
info.Instance = m_instance;
|
||||||
info.PhysicalDevice = m_physical_device;
|
info.PhysicalDevice = m_physicalDevice;
|
||||||
info.Device = m_logicalDevice;
|
info.Device = m_logicalDevice;
|
||||||
info.QueueFamily = m_indices.presentFamily;
|
info.QueueFamily = m_indices.presentFamily;
|
||||||
info.Queue = m_presentQueue;
|
info.Queue = m_presentQueue;
|
||||||
@ -1813,7 +1473,7 @@ void VulkanRenderer::ImguiInit()
|
|||||||
info.MinImageCount = m_mainSwapchainInfo->m_swapchainImages.size();
|
info.MinImageCount = m_mainSwapchainInfo->m_swapchainImages.size();
|
||||||
info.ImageCount = info.MinImageCount;
|
info.ImageCount = info.MinImageCount;
|
||||||
|
|
||||||
ImGui_ImplVulkan_Init(&info, m_mainSwapchainInfo->m_imguiRenderPass);
|
ImGui_ImplVulkan_Init(&info, m_imguiRenderPass);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::Initialize()
|
void VulkanRenderer::Initialize()
|
||||||
@ -1826,7 +1486,7 @@ void VulkanRenderer::Initialize()
|
|||||||
void VulkanRenderer::Shutdown()
|
void VulkanRenderer::Shutdown()
|
||||||
{
|
{
|
||||||
SubmitCommandBuffer();
|
SubmitCommandBuffer();
|
||||||
vkDeviceWaitIdle(m_logicalDevice);
|
WaitDeviceIdle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::UnrecoverableError(const char* errMsg) const
|
void VulkanRenderer::UnrecoverableError(const char* errMsg) const
|
||||||
@ -1901,7 +1561,7 @@ VulkanRequestedFormat_t requestedFormatList[] =
|
|||||||
void VulkanRenderer::QueryMemoryInfo()
|
void VulkanRenderer::QueryMemoryInfo()
|
||||||
{
|
{
|
||||||
VkPhysicalDeviceMemoryProperties memProperties;
|
VkPhysicalDeviceMemoryProperties memProperties;
|
||||||
vkGetPhysicalDeviceMemoryProperties(m_physical_device, &memProperties);
|
vkGetPhysicalDeviceMemoryProperties(m_physicalDevice, &memProperties);
|
||||||
forceLog_printf("Vulkan device memory info:");
|
forceLog_printf("Vulkan device memory info:");
|
||||||
for (uint32 i = 0; i < memProperties.memoryHeapCount; i++)
|
for (uint32 i = 0; i < memProperties.memoryHeapCount; i++)
|
||||||
{
|
{
|
||||||
@ -1916,7 +1576,7 @@ void VulkanRenderer::QueryMemoryInfo()
|
|||||||
void VulkanRenderer::QueryAvailableFormats()
|
void VulkanRenderer::QueryAvailableFormats()
|
||||||
{
|
{
|
||||||
VkFormatProperties fmtProp{};
|
VkFormatProperties fmtProp{};
|
||||||
vkGetPhysicalDeviceFormatProperties(m_physical_device, VK_FORMAT_D24_UNORM_S8_UINT, &fmtProp);
|
vkGetPhysicalDeviceFormatProperties(m_physicalDevice, VK_FORMAT_D24_UNORM_S8_UINT, &fmtProp);
|
||||||
// D24S8
|
// D24S8
|
||||||
if (fmtProp.optimalTilingFeatures != 0) // todo - more restrictive check
|
if (fmtProp.optimalTilingFeatures != 0) // todo - more restrictive check
|
||||||
{
|
{
|
||||||
@ -1924,28 +1584,28 @@ void VulkanRenderer::QueryAvailableFormats()
|
|||||||
}
|
}
|
||||||
// R4G4
|
// R4G4
|
||||||
fmtProp = {};
|
fmtProp = {};
|
||||||
vkGetPhysicalDeviceFormatProperties(m_physical_device, VK_FORMAT_R4G4_UNORM_PACK8, &fmtProp);
|
vkGetPhysicalDeviceFormatProperties(m_physicalDevice, VK_FORMAT_R4G4_UNORM_PACK8, &fmtProp);
|
||||||
if (fmtProp.optimalTilingFeatures != 0)
|
if (fmtProp.optimalTilingFeatures != 0)
|
||||||
{
|
{
|
||||||
m_supportedFormatInfo.fmt_r4g4_unorm_pack = true;
|
m_supportedFormatInfo.fmt_r4g4_unorm_pack = true;
|
||||||
}
|
}
|
||||||
// R5G6B5
|
// R5G6B5
|
||||||
fmtProp = {};
|
fmtProp = {};
|
||||||
vkGetPhysicalDeviceFormatProperties(m_physical_device, VK_FORMAT_R5G6B5_UNORM_PACK16, &fmtProp);
|
vkGetPhysicalDeviceFormatProperties(m_physicalDevice, VK_FORMAT_R5G6B5_UNORM_PACK16, &fmtProp);
|
||||||
if (fmtProp.optimalTilingFeatures != 0)
|
if (fmtProp.optimalTilingFeatures != 0)
|
||||||
{
|
{
|
||||||
m_supportedFormatInfo.fmt_r5g6b5_unorm_pack = true;
|
m_supportedFormatInfo.fmt_r5g6b5_unorm_pack = true;
|
||||||
}
|
}
|
||||||
// R4G4B4A4
|
// R4G4B4A4
|
||||||
fmtProp = {};
|
fmtProp = {};
|
||||||
vkGetPhysicalDeviceFormatProperties(m_physical_device, VK_FORMAT_R4G4B4A4_UNORM_PACK16, &fmtProp);
|
vkGetPhysicalDeviceFormatProperties(m_physicalDevice, VK_FORMAT_R4G4B4A4_UNORM_PACK16, &fmtProp);
|
||||||
if (fmtProp.optimalTilingFeatures != 0)
|
if (fmtProp.optimalTilingFeatures != 0)
|
||||||
{
|
{
|
||||||
m_supportedFormatInfo.fmt_r4g4b4a4_unorm_pack = true;
|
m_supportedFormatInfo.fmt_r4g4b4a4_unorm_pack = true;
|
||||||
}
|
}
|
||||||
// A1R5G5B5
|
// A1R5G5B5
|
||||||
fmtProp = {};
|
fmtProp = {};
|
||||||
vkGetPhysicalDeviceFormatProperties(m_physical_device, VK_FORMAT_A1R5G5B5_UNORM_PACK16, &fmtProp);
|
vkGetPhysicalDeviceFormatProperties(m_physicalDevice, VK_FORMAT_A1R5G5B5_UNORM_PACK16, &fmtProp);
|
||||||
if (fmtProp.optimalTilingFeatures != 0)
|
if (fmtProp.optimalTilingFeatures != 0)
|
||||||
{
|
{
|
||||||
m_supportedFormatInfo.fmt_a1r5g5b5_unorm_pack = true;
|
m_supportedFormatInfo.fmt_a1r5g5b5_unorm_pack = true;
|
||||||
@ -1954,7 +1614,7 @@ void VulkanRenderer::QueryAvailableFormats()
|
|||||||
for (auto& it : requestedFormatList)
|
for (auto& it : requestedFormatList)
|
||||||
{
|
{
|
||||||
fmtProp = {};
|
fmtProp = {};
|
||||||
vkGetPhysicalDeviceFormatProperties(m_physical_device, it.fmt, &fmtProp);
|
vkGetPhysicalDeviceFormatProperties(m_physicalDevice, it.fmt, &fmtProp);
|
||||||
VkFormatFeatureFlags requestedBits = 0;
|
VkFormatFeatureFlags requestedBits = 0;
|
||||||
if (it.mustSupportAttachment)
|
if (it.mustSupportAttachment)
|
||||||
{
|
{
|
||||||
@ -1996,6 +1656,8 @@ bool VulkanRenderer::ImguiBegin(bool mainWindow)
|
|||||||
if (!Renderer::ImguiBegin(mainWindow))
|
if (!Renderer::ImguiBegin(mainWindow))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
auto& chainInfo = GetChainInfo(mainWindow);
|
||||||
|
|
||||||
if (!IsSwapchainInfoValid(mainWindow))
|
if (!IsSwapchainInfoValid(mainWindow))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -2004,16 +1666,14 @@ bool VulkanRenderer::ImguiBegin(bool mainWindow)
|
|||||||
|
|
||||||
AcquireNextSwapchainImage(mainWindow);
|
AcquireNextSwapchainImage(mainWindow);
|
||||||
|
|
||||||
auto& swapchain_info = mainWindow ? *m_mainSwapchainInfo : *m_padSwapchainInfo;
|
|
||||||
|
|
||||||
ImGui_ImplVulkan_CreateFontsTexture(m_state.currentCommandBuffer);
|
ImGui_ImplVulkan_CreateFontsTexture(m_state.currentCommandBuffer);
|
||||||
ImGui_ImplVulkan_NewFrame(m_state.currentCommandBuffer, swapchain_info.m_swapchainFramebuffers[swapchain_info.swapchainImageIndex], swapchain_info.swapchainExtend);
|
ImGui_ImplVulkan_NewFrame(m_state.currentCommandBuffer, chainInfo.m_swapchainFramebuffers[chainInfo.swapchainImageIndex], chainInfo.swapchainExtent);
|
||||||
ImGui_UpdateWindowInformation(mainWindow);
|
ImGui_UpdateWindowInformation(mainWindow);
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void VulkanRenderer::ImguiEnd()
|
void VulkanRenderer::ImguiEnd()
|
||||||
{
|
{
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
@ -2046,7 +1706,7 @@ ImTextureID VulkanRenderer::GenerateTexture(const std::vector<uint8>& data, cons
|
|||||||
|
|
||||||
void VulkanRenderer::DeleteTexture(ImTextureID id)
|
void VulkanRenderer::DeleteTexture(ImTextureID id)
|
||||||
{
|
{
|
||||||
vkDeviceWaitIdle(m_logicalDevice);
|
WaitDeviceIdle();
|
||||||
ImGui_ImplVulkan_DeleteTexture(id);
|
ImGui_ImplVulkan_DeleteTexture(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2063,16 +1723,13 @@ bool VulkanRenderer::BeginFrame(bool mainWindow)
|
|||||||
|
|
||||||
AcquireNextSwapchainImage(mainWindow);
|
AcquireNextSwapchainImage(mainWindow);
|
||||||
|
|
||||||
auto& swap_info = mainWindow ? *m_mainSwapchainInfo : *m_padSwapchainInfo;
|
auto& chainInfo = GetChainInfo(mainWindow);
|
||||||
|
|
||||||
VkClearColorValue clearColor{ 0, 0, 0, 0 };
|
VkClearColorValue clearColor{ 0, 0, 0, 0 };
|
||||||
ClearColorImageRaw(swap_info.m_swapchainImages[swap_info.swapchainImageIndex], 0, 0, clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
ClearColorImageRaw(chainInfo.m_swapchainImages[chainInfo.swapchainImageIndex], 0, 0, clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||||
|
|
||||||
// mark current swapchain image as well defined
|
// mark current swapchain image as well defined
|
||||||
if (!mainWindow)
|
chainInfo.hasDefinedSwapchainImage = true;
|
||||||
m_swapchainState.drcHasDefinedSwapchainImage = true;
|
|
||||||
else
|
|
||||||
m_swapchainState.tvHasDefinedSwapchainImage = true;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2758,7 +2415,7 @@ VkPipelineShaderStageCreateInfo VulkanRenderer::CreatePipelineShaderStageCreateI
|
|||||||
|
|
||||||
VkPipeline VulkanRenderer::backbufferBlit_createGraphicsPipeline(VkDescriptorSetLayout descriptorLayout, bool padView, RendererOutputShader* shader)
|
VkPipeline VulkanRenderer::backbufferBlit_createGraphicsPipeline(VkDescriptorSetLayout descriptorLayout, bool padView, RendererOutputShader* shader)
|
||||||
{
|
{
|
||||||
auto& swap_info = !padView ? *m_mainSwapchainInfo : *m_padSwapchainInfo;
|
auto& chainInfo = GetChainInfo(!padView);
|
||||||
|
|
||||||
RendererShaderVk* vertexRendererShader = static_cast<RendererShaderVk*>(shader->GetVertexShader());
|
RendererShaderVk* vertexRendererShader = static_cast<RendererShaderVk*>(shader->GetVertexShader());
|
||||||
RendererShaderVk* fragmentRendererShader = static_cast<RendererShaderVk*>(shader->GetFragmentShader());
|
RendererShaderVk* fragmentRendererShader = static_cast<RendererShaderVk*>(shader->GetFragmentShader());
|
||||||
@ -2766,7 +2423,7 @@ VkPipeline VulkanRenderer::backbufferBlit_createGraphicsPipeline(VkDescriptorSet
|
|||||||
uint64 hash = 0;
|
uint64 hash = 0;
|
||||||
hash += (uint64)vertexRendererShader;
|
hash += (uint64)vertexRendererShader;
|
||||||
hash += (uint64)fragmentRendererShader;
|
hash += (uint64)fragmentRendererShader;
|
||||||
hash += (uint64)(padView ? m_drvBufferUsesSRGB : m_tvBufferUsesSRGB);
|
hash += (uint64)(chainInfo.m_usesSRGB);
|
||||||
hash += ((uint64)padView) << 1;
|
hash += ((uint64)padView) << 1;
|
||||||
|
|
||||||
static std::unordered_map<uint64, VkPipeline> s_pipeline_cache;
|
static std::unordered_map<uint64, VkPipeline> s_pipeline_cache;
|
||||||
@ -2854,7 +2511,7 @@ VkPipeline VulkanRenderer::backbufferBlit_createGraphicsPipeline(VkDescriptorSet
|
|||||||
pipelineInfo.pMultisampleState = &multisampling;
|
pipelineInfo.pMultisampleState = &multisampling;
|
||||||
pipelineInfo.pColorBlendState = &colorBlending;
|
pipelineInfo.pColorBlendState = &colorBlending;
|
||||||
pipelineInfo.layout = m_pipelineLayout;
|
pipelineInfo.layout = m_pipelineLayout;
|
||||||
pipelineInfo.renderPass = swap_info.m_swapChainRenderPass;
|
pipelineInfo.renderPass = chainInfo.m_swapchainRenderPass;
|
||||||
pipelineInfo.subpass = 0;
|
pipelineInfo.subpass = 0;
|
||||||
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
|
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
|
||||||
|
|
||||||
@ -2873,29 +2530,28 @@ VkPipeline VulkanRenderer::backbufferBlit_createGraphicsPipeline(VkDescriptorSet
|
|||||||
return pipeline;
|
return pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::AcquireNextSwapchainImage(bool main_window)
|
void VulkanRenderer::AcquireNextSwapchainImage(bool mainWindow)
|
||||||
{
|
{
|
||||||
auto& swapInfo = main_window ? *m_mainSwapchainInfo : *m_padSwapchainInfo;
|
auto& chainInfo = GetChainInfo(mainWindow);
|
||||||
if (swapInfo.swapchainImageIndex != -1)
|
if (chainInfo.swapchainImageIndex != -1)
|
||||||
return; // image already reserved
|
return; // image already reserved
|
||||||
|
|
||||||
|
vkWaitForFences(m_logicalDevice, 1, &chainInfo.m_imageAvailableFence, VK_TRUE, std::numeric_limits<uint64_t>::max());
|
||||||
|
vkResetFences(m_logicalDevice, 1, &chainInfo.m_imageAvailableFence);
|
||||||
|
|
||||||
vkWaitForFences(m_logicalDevice, 1, &swapInfo.m_imageAvailableFence, VK_TRUE, std::numeric_limits<uint64_t>::max());
|
auto& acquireSemaphore = chainInfo.m_acquireSemaphores[chainInfo.m_acquireIndex];
|
||||||
vkResetFences(m_logicalDevice, 1, &swapInfo.m_imageAvailableFence);
|
|
||||||
|
|
||||||
auto& acquireInfo = swapInfo.m_acquireInfo[swapInfo.m_acquireIndex];
|
VkResult result = vkAcquireNextImageKHR(m_logicalDevice, chainInfo.swapchain, std::numeric_limits<uint64_t>::max(), acquireSemaphore, chainInfo.m_imageAvailableFence, &chainInfo.swapchainImageIndex);
|
||||||
|
|
||||||
VkResult result = vkAcquireNextImageKHR(m_logicalDevice, swapInfo.swapChain, std::numeric_limits<uint64_t>::max(), acquireInfo.acquireSemaphore, swapInfo.m_imageAvailableFence, &swapInfo.swapchainImageIndex);
|
|
||||||
if (result != VK_SUCCESS)
|
if (result != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
while (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) // todo: handle error state correctly. Looping doesnt always make sense?
|
while (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) // todo: handle error state correctly. Looping doesnt always make sense?
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
RecreateSwapchain(main_window);
|
RecreateSwapchain(mainWindow);
|
||||||
if (vkWaitForFences(m_logicalDevice, 1, &swapInfo.m_imageAvailableFence, VK_TRUE, 0) == VK_SUCCESS)
|
if (vkWaitForFences(m_logicalDevice, 1, &chainInfo.m_imageAvailableFence, VK_TRUE, 0) == VK_SUCCESS)
|
||||||
vkResetFences(m_logicalDevice, 1, &swapInfo.m_imageAvailableFence);
|
vkResetFences(m_logicalDevice, 1, &chainInfo.m_imageAvailableFence);
|
||||||
result = vkAcquireNextImageKHR(m_logicalDevice, swapInfo.swapChain, std::numeric_limits<uint64_t>::max(), acquireInfo.acquireSemaphore, swapInfo.m_imageAvailableFence, &swapInfo.swapchainImageIndex);
|
result = vkAcquireNextImageKHR(m_logicalDevice, chainInfo.swapchain, std::numeric_limits<uint64_t>::max(), acquireSemaphore, chainInfo.m_imageAvailableFence, &chainInfo.swapchainImageIndex);
|
||||||
if (result == VK_SUCCESS)
|
if (result == VK_SUCCESS)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2908,22 +2564,22 @@ void VulkanRenderer::AcquireNextSwapchainImage(bool main_window)
|
|||||||
throw std::runtime_error(fmt::format("Failed to acquire next image: {}", result));
|
throw std::runtime_error(fmt::format("Failed to acquire next image: {}", result));
|
||||||
}
|
}
|
||||||
|
|
||||||
swapInfo.m_acquireIndex = (swapInfo.m_acquireIndex + 1) % swapInfo.m_acquireInfo.size();
|
chainInfo.m_acquireIndex = (chainInfo.m_acquireIndex + 1) % chainInfo.m_acquireSemaphores.size();
|
||||||
|
|
||||||
SubmitCommandBuffer(nullptr, &acquireInfo.acquireSemaphore);
|
SubmitCommandBuffer(nullptr, &acquireSemaphore);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::RecreateSwapchain(bool main_window)
|
void VulkanRenderer::RecreateSwapchain(bool mainWindow)
|
||||||
{
|
{
|
||||||
SubmitCommandBuffer();
|
SubmitCommandBuffer();
|
||||||
vkDeviceWaitIdle(m_logicalDevice);
|
WaitDeviceIdle();
|
||||||
auto& swapinfo = main_window ? *m_mainSwapchainInfo : *m_padSwapchainInfo;
|
auto& chainInfo = GetChainInfo(mainWindow);
|
||||||
vkWaitForFences(m_logicalDevice, 1, &swapinfo.m_imageAvailableFence, VK_TRUE,
|
vkWaitForFences(m_logicalDevice, 1, &chainInfo.m_imageAvailableFence, VK_TRUE,
|
||||||
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds(10)).count()
|
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds(10)).count()
|
||||||
);
|
);
|
||||||
|
|
||||||
Vector2i size;
|
Vector2i size;
|
||||||
if (main_window)
|
if (mainWindow)
|
||||||
{
|
{
|
||||||
ImGui_ImplVulkan_Shutdown();
|
ImGui_ImplVulkan_Shutdown();
|
||||||
gui_getWindowSize(&size.x, &size.y);
|
gui_getWindowSize(&size.x, &size.y);
|
||||||
@ -2933,80 +2589,50 @@ void VulkanRenderer::RecreateSwapchain(bool main_window)
|
|||||||
gui_getPadWindowSize(&size.x, &size.y);
|
gui_getPadWindowSize(&size.x, &size.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (swapinfo.swapChain != VK_NULL_HANDLE)
|
chainInfo.Cleanup();
|
||||||
{
|
chainInfo.setSize(size);
|
||||||
// todo - for some reason using the swapchain replacement method (old var being set) causes crashes and other issues
|
chainInfo.Create(m_physicalDevice, m_logicalDevice);
|
||||||
vkDestroySwapchainKHR(m_logicalDevice, swapinfo.swapChain, nullptr);
|
chainInfo.swapchainImageIndex = -1;
|
||||||
swapinfo.m_swapchainImages.clear(); // swapchain images are automatically destroyed
|
|
||||||
swapinfo.swapChain = VK_NULL_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
swapinfo.swapChain = nullptr;
|
if (mainWindow)
|
||||||
swapinfo.swapChain = CreateSwapChain(swapinfo, size, main_window);
|
|
||||||
swapinfo.swapchainImageIndex = -1;
|
|
||||||
|
|
||||||
if (main_window)
|
|
||||||
ImguiInit();
|
ImguiInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::UpdateVSyncState(bool main_window)
|
void VulkanRenderer::UpdateVSyncState(bool mainWindow)
|
||||||
{
|
{
|
||||||
auto& swapInfo = main_window ? *m_mainSwapchainInfo : *m_padSwapchainInfo;
|
auto& chainInfo = GetChainInfo(mainWindow);
|
||||||
const auto configValue = (VSync)GetConfig().vsync.GetValue();
|
const auto configValue = (VSync)GetConfig().vsync.GetValue();
|
||||||
if(swapInfo.m_activeVSyncState != configValue){
|
if(chainInfo.m_vsyncState != configValue){
|
||||||
RecreateSwapchain(main_window);
|
RecreateSwapchain(mainWindow);
|
||||||
swapInfo.m_activeVSyncState = configValue;
|
chainInfo.m_vsyncState = configValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::SwapBuffer(bool main_window)
|
void VulkanRenderer::SwapBuffer(bool mainWindow)
|
||||||
{
|
{
|
||||||
auto& swapInfo = main_window ? *m_mainSwapchainInfo : *m_padSwapchainInfo;
|
auto& chainInfo = GetChainInfo(mainWindow);
|
||||||
|
|
||||||
if (main_window)
|
const bool latteBufferUsesSRGB = mainWindow ? LatteGPUState.tvBufferUsesSRGB : LatteGPUState.drcBufferUsesSRGB;
|
||||||
{
|
if (chainInfo.sizeOutOfDate || chainInfo.m_usesSRGB != latteBufferUsesSRGB)
|
||||||
const bool resize = m_swapchainState.resizeRequestedMainWindow;
|
|
||||||
m_swapchainState.resizeRequestedMainWindow = false;
|
|
||||||
|
|
||||||
if (resize || m_tvBufferUsesSRGB != LatteGPUState.tvBufferUsesSRGB)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
RecreateSwapchain(main_window);
|
RecreateSwapchain(mainWindow);
|
||||||
m_tvBufferUsesSRGB = LatteGPUState.tvBufferUsesSRGB;
|
chainInfo.m_usesSRGB = latteBufferUsesSRGB;
|
||||||
}
|
}
|
||||||
catch (std::exception&) { cemu_assert_debug(false); }
|
catch (std::exception&) { cemu_assert_debug(false); }
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const bool resize = m_swapchainState.resizeRequestedPadWindow;
|
|
||||||
m_swapchainState.resizeRequestedPadWindow = false;
|
|
||||||
|
|
||||||
if (resize || m_drvBufferUsesSRGB != LatteGPUState.drcBufferUsesSRGB)
|
UpdateVSyncState(mainWindow);
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
RecreateSwapchain(main_window);
|
|
||||||
m_drvBufferUsesSRGB = LatteGPUState.drcBufferUsesSRGB;
|
|
||||||
}
|
|
||||||
catch (std::exception&) { cemu_assert_debug(false); }
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateVSyncState(main_window);
|
AcquireNextSwapchainImage(mainWindow);
|
||||||
|
|
||||||
auto& swapinfo = main_window ? *m_mainSwapchainInfo : *m_padSwapchainInfo;
|
if (!chainInfo.hasDefinedSwapchainImage)
|
||||||
AcquireNextSwapchainImage(main_window);
|
|
||||||
|
|
||||||
if ((main_window && m_swapchainState.tvHasDefinedSwapchainImage == false) ||
|
|
||||||
(!main_window && m_swapchainState.drcHasDefinedSwapchainImage == false))
|
|
||||||
{
|
{
|
||||||
// set the swapchain image to a defined state
|
// set the swapchain image to a defined state
|
||||||
VkClearColorValue clearColor{ 0, 0, 0, 0 };
|
VkClearColorValue clearColor{ 0, 0, 0, 0 };
|
||||||
ClearColorImageRaw(swapInfo.m_swapchainImages[swapInfo.swapchainImageIndex], 0, 0, clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
ClearColorImageRaw(chainInfo.m_swapchainImages[chainInfo.swapchainImageIndex], 0, 0, clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure any writes to the image have finished (is this necessary? End of command buffer implicitly flushes everything?)
|
// make sure any writes to the image have finished (is this necessary? End of command buffer implicitly flushes everything?)
|
||||||
@ -3019,7 +2645,7 @@ void VulkanRenderer::SwapBuffer(bool main_window)
|
|||||||
vkCmdPipelineBarrier(m_state.currentCommandBuffer, srcStage, dstStage, 0, 1, &memoryBarrier, 0, nullptr, 0, nullptr);
|
vkCmdPipelineBarrier(m_state.currentCommandBuffer, srcStage, dstStage, 0, 1, &memoryBarrier, 0, nullptr, 0, nullptr);
|
||||||
|
|
||||||
|
|
||||||
VkSemaphore presentSemaphore = swapInfo.m_swapchainPresentSemaphores[swapInfo.swapchainImageIndex];
|
VkSemaphore presentSemaphore = chainInfo.m_swapchainPresentSemaphores[chainInfo.swapchainImageIndex];
|
||||||
SubmitCommandBuffer(&presentSemaphore); // submit all command and signal semaphore
|
SubmitCommandBuffer(&presentSemaphore); // submit all command and signal semaphore
|
||||||
|
|
||||||
cemu_assert_debug(m_numSubmittedCmdBuffers > 0);
|
cemu_assert_debug(m_numSubmittedCmdBuffers > 0);
|
||||||
@ -3028,8 +2654,8 @@ void VulkanRenderer::SwapBuffer(bool main_window)
|
|||||||
VkPresentInfoKHR presentInfo = {};
|
VkPresentInfoKHR presentInfo = {};
|
||||||
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||||
presentInfo.swapchainCount = 1;
|
presentInfo.swapchainCount = 1;
|
||||||
presentInfo.pSwapchains = &swapinfo.swapChain;
|
presentInfo.pSwapchains = &chainInfo.swapchain;
|
||||||
presentInfo.pImageIndices = &swapinfo.swapchainImageIndex;
|
presentInfo.pImageIndices = &chainInfo.swapchainImageIndex;
|
||||||
// wait on command buffer semaphore
|
// wait on command buffer semaphore
|
||||||
presentInfo.waitSemaphoreCount = 1;
|
presentInfo.waitSemaphoreCount = 1;
|
||||||
presentInfo.pWaitSemaphores = &presentSemaphore;
|
presentInfo.pWaitSemaphores = &presentSemaphore;
|
||||||
@ -3044,7 +2670,7 @@ void VulkanRenderer::SwapBuffer(bool main_window)
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
RecreateSwapchain(main_window);
|
RecreateSwapchain(mainWindow);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (std::exception&)
|
catch (std::exception&)
|
||||||
@ -3070,12 +2696,9 @@ void VulkanRenderer::SwapBuffer(bool main_window)
|
|||||||
throw std::runtime_error(fmt::format("Failed to present draw command buffer: {}", result));
|
throw std::runtime_error(fmt::format("Failed to present draw command buffer: {}", result));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (main_window)
|
chainInfo.hasDefinedSwapchainImage = false;
|
||||||
m_swapchainState.tvHasDefinedSwapchainImage = false;
|
|
||||||
else
|
|
||||||
m_swapchainState.drcHasDefinedSwapchainImage = false;
|
|
||||||
|
|
||||||
swapinfo.swapchainImageIndex = -1;
|
chainInfo.swapchainImageIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::Flush(bool waitIdle)
|
void VulkanRenderer::Flush(bool waitIdle)
|
||||||
@ -3108,12 +2731,12 @@ void VulkanRenderer::ClearColorbuffer(bool padView)
|
|||||||
if (!IsSwapchainInfoValid(!padView))
|
if (!IsSwapchainInfoValid(!padView))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto& swap_info = padView ? *m_padSwapchainInfo : *m_mainSwapchainInfo;
|
auto& chainInfo = GetChainInfo(!padView);
|
||||||
if (swap_info.swapchainImageIndex == -1)
|
if (chainInfo.swapchainImageIndex == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
VkClearColorValue clearColor{ 0, 0, 0, 0 };
|
VkClearColorValue clearColor{ 0, 0, 0, 0 };
|
||||||
ClearColorImageRaw(swap_info.m_swapchainImages[swap_info.swapchainImageIndex], 0, 0, clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
ClearColorImageRaw(chainInfo.m_swapchainImages[chainInfo.swapchainImageIndex], 0, 0, clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::ClearColorImageRaw(VkImage image, uint32 sliceIndex, uint32 mipIndex, const VkClearColorValue& color, VkImageLayout inputLayout, VkImageLayout outputLayout)
|
void VulkanRenderer::ClearColorImageRaw(VkImage image, uint32 sliceIndex, uint32 mipIndex, const VkClearColorValue& color, VkImageLayout inputLayout, VkImageLayout outputLayout)
|
||||||
@ -3198,7 +2821,7 @@ void VulkanRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu
|
|||||||
if (!IsSwapchainInfoValid(!padView))
|
if (!IsSwapchainInfoValid(!padView))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto& swapInfo = !padView ? *m_mainSwapchainInfo : *m_padSwapchainInfo;
|
auto& chainInfo = GetChainInfo(!padView);
|
||||||
LatteTextureViewVk* texViewVk = (LatteTextureViewVk*)texView;
|
LatteTextureViewVk* texViewVk = (LatteTextureViewVk*)texView;
|
||||||
draw_endRenderPass();
|
draw_endRenderPass();
|
||||||
|
|
||||||
@ -3220,10 +2843,10 @@ void VulkanRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu
|
|||||||
|
|
||||||
VkRenderPassBeginInfo renderPassInfo = {};
|
VkRenderPassBeginInfo renderPassInfo = {};
|
||||||
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||||
renderPassInfo.renderPass = swapInfo.m_swapChainRenderPass;
|
renderPassInfo.renderPass = chainInfo.m_swapchainRenderPass;
|
||||||
renderPassInfo.framebuffer = swapInfo.m_swapchainFramebuffers[swapInfo.swapchainImageIndex];
|
renderPassInfo.framebuffer = chainInfo.m_swapchainFramebuffers[chainInfo.swapchainImageIndex];
|
||||||
renderPassInfo.renderArea.offset = { 0, 0 };
|
renderPassInfo.renderArea.offset = { 0, 0 };
|
||||||
renderPassInfo.renderArea.extent = swapInfo.swapchainExtend;
|
renderPassInfo.renderArea.extent = chainInfo.swapchainExtent;
|
||||||
renderPassInfo.clearValueCount = 0;
|
renderPassInfo.clearValueCount = 0;
|
||||||
|
|
||||||
VkViewport viewport{};
|
VkViewport viewport{};
|
||||||
@ -3236,7 +2859,7 @@ void VulkanRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu
|
|||||||
vkCmdSetViewport(m_state.currentCommandBuffer, 0, 1, &viewport);
|
vkCmdSetViewport(m_state.currentCommandBuffer, 0, 1, &viewport);
|
||||||
|
|
||||||
VkRect2D scissor{};
|
VkRect2D scissor{};
|
||||||
scissor.extent = swapInfo.swapchainExtend;
|
scissor.extent = chainInfo.swapchainExtent;
|
||||||
vkCmdSetScissor(m_state.currentCommandBuffer, 0, 1, &scissor);
|
vkCmdSetScissor(m_state.currentCommandBuffer, 0, 1, &scissor);
|
||||||
|
|
||||||
auto descriptSet = backbufferBlit_createDescriptorSet(m_swapchainDescriptorSetLayout, texViewVk, useLinearTexFilter);
|
auto descriptSet = backbufferBlit_createDescriptorSet(m_swapchainDescriptorSetLayout, texViewVk, useLinearTexFilter);
|
||||||
@ -3258,10 +2881,7 @@ void VulkanRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutpu
|
|||||||
vkCmdSetViewport(m_state.currentCommandBuffer, 0, 1, &m_state.currentViewport);
|
vkCmdSetViewport(m_state.currentCommandBuffer, 0, 1, &m_state.currentViewport);
|
||||||
|
|
||||||
// mark current swapchain image as well defined
|
// mark current swapchain image as well defined
|
||||||
if (padView)
|
chainInfo.hasDefinedSwapchainImage = true;
|
||||||
m_swapchainState.drcHasDefinedSwapchainImage = true;
|
|
||||||
else
|
|
||||||
m_swapchainState.tvHasDefinedSwapchainImage = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanRenderer::CreateDescriptorPool()
|
void VulkanRenderer::CreateDescriptorPool()
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Cafe/HW/Latte/Renderer/Renderer.h"
|
#include "Cafe/HW/Latte/Renderer/Renderer.h"
|
||||||
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
|
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
|
||||||
#include "Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.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/LatteTextureViewVk.h"
|
||||||
#include "Cafe/HW/Latte/Renderer/Vulkan/CachedFBOVk.h"
|
#include "Cafe/HW/Latte/Renderer/Vulkan/CachedFBOVk.h"
|
||||||
#include "Cafe/HW/Latte/Renderer/Vulkan/VKRMemoryManager.h"
|
#include "Cafe/HW/Latte/Renderer/Vulkan/VKRMemoryManager.h"
|
||||||
|
#include "Cafe/HW/Latte/Renderer/Vulkan/SwapchainInfoVk.h"
|
||||||
#include "util/math/vector2.h"
|
#include "util/math/vector2.h"
|
||||||
#include "util/helpers/Semaphore.h"
|
#include "util/helpers/Semaphore.h"
|
||||||
#include "util/containers/flat_hash_map.hpp"
|
#include "util/containers/flat_hash_map.hpp"
|
||||||
@ -124,6 +126,9 @@ class VulkanRenderer : public Renderer
|
|||||||
friend class LatteTextureReadbackInfoVk;
|
friend class LatteTextureReadbackInfoVk;
|
||||||
friend class PipelineCompiler;
|
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 UNIFORMVAR_RINGBUFFER_SIZE = 1024 * 1024 * 16; // 16MB
|
||||||
static const inline int INDEX_STREAM_BUFFER_SIZE = 16 * 1024 * 1024; // 16 MB
|
static const inline int INDEX_STREAM_BUFFER_SIZE = 16 * 1024 * 1024; // 16 MB
|
||||||
|
|
||||||
@ -132,14 +137,6 @@ class VulkanRenderer : public Renderer
|
|||||||
static const inline int OCCLUSION_QUERY_POOL_SIZE = 1024;
|
static const inline int OCCLUSION_QUERY_POOL_SIZE = 1024;
|
||||||
|
|
||||||
public:
|
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
|
// memory management
|
||||||
VKRMemoryManager* memoryManager{};
|
VKRMemoryManager* memoryManager{};
|
||||||
@ -185,12 +182,15 @@ public:
|
|||||||
|
|
||||||
void GetDeviceFeatures();
|
void GetDeviceFeatures();
|
||||||
void DetermineVendor();
|
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;
|
bool IsPadWindowActive() override;
|
||||||
|
|
||||||
void HandleScreenshotRequest(LatteTextureView* texView, bool padView) 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 QueryMemoryInfo();
|
||||||
void QueryAvailableFormats();
|
void QueryAvailableFormats();
|
||||||
@ -210,7 +210,7 @@ public:
|
|||||||
void ImguiInit();
|
void ImguiInit();
|
||||||
VkInstance GetVkInstance() const { return m_instance; }
|
VkInstance GetVkInstance() const { return m_instance; }
|
||||||
VkDevice GetLogicalDevice() const { return m_logicalDevice; }
|
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; }
|
VkDescriptorPool GetDescriptorPool() const { return m_descriptorPool; }
|
||||||
|
|
||||||
@ -431,86 +431,12 @@ private:
|
|||||||
bool drawSequenceSkip; // if true, skip draw_execute()
|
bool drawSequenceSkip; // if true, skip draw_execute()
|
||||||
}m_state;
|
}m_state;
|
||||||
|
|
||||||
// swapchain - todo move this to m_swapchainState
|
std::unique_ptr<SwapchainInfoVk> m_mainSwapchainInfo{}, m_padSwapchainInfo{};
|
||||||
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{};
|
|
||||||
bool IsSwapchainInfoValid(bool mainWindow) const;
|
bool IsSwapchainInfoValid(bool mainWindow) const;
|
||||||
VkSwapchainKHR CreateSwapChain(SwapChainInfo& swap_chain_info, const Vector2i& size, bool mainwindow);
|
|
||||||
|
|
||||||
struct
|
VkRenderPass m_imguiRenderPass = nullptr;
|
||||||
{
|
|
||||||
bool resizeRequestedMainWindow{};
|
|
||||||
Vector2i newExtentMainWindow;
|
|
||||||
bool resizeRequestedPadWindow{};
|
|
||||||
Vector2i newExtentPadWindow;
|
|
||||||
bool tvHasDefinedSwapchainImage{}; // indicates if the swapchain image is in a defined state
|
|
||||||
bool drcHasDefinedSwapchainImage{};
|
|
||||||
}m_swapchainState;
|
|
||||||
|
|
||||||
VkDescriptorPool m_descriptorPool;
|
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
|
struct FeatureControl
|
||||||
{
|
{
|
||||||
@ -556,15 +482,8 @@ private:
|
|||||||
static bool CheckDeviceExtensionSupport(const VkPhysicalDevice device, FeatureControl& info);
|
static bool CheckDeviceExtensionSupport(const VkPhysicalDevice device, FeatureControl& info);
|
||||||
static std::vector<const char*> CheckInstanceExtensionSupport(FeatureControl& info);
|
static std::vector<const char*> CheckInstanceExtensionSupport(FeatureControl& info);
|
||||||
|
|
||||||
void UpdateVSyncState(bool main_window);
|
void UpdateVSyncState(bool mainWindow);
|
||||||
void SwapBuffer(bool main_window);
|
void SwapBuffer(bool mainWindow);
|
||||||
|
|
||||||
struct SwapChainSupportDetails
|
|
||||||
{
|
|
||||||
VkSurfaceCapabilitiesKHR capabilities;
|
|
||||||
std::vector<VkSurfaceFormatKHR> formats;
|
|
||||||
std::vector<VkPresentModeKHR> presentModes;
|
|
||||||
};
|
|
||||||
|
|
||||||
VkDescriptorSetLayout m_swapchainDescriptorSetLayout;
|
VkDescriptorSetLayout m_swapchainDescriptorSetLayout;
|
||||||
|
|
||||||
@ -572,14 +491,9 @@ private:
|
|||||||
|
|
||||||
// swapchain
|
// swapchain
|
||||||
|
|
||||||
static SwapChainSupportDetails QuerySwapChainSupport(VkSurfaceKHR surface, const VkPhysicalDevice& device);
|
|
||||||
std::vector<VkDeviceQueueCreateInfo> CreateQueueCreateInfos(const std::set<int>& uniqueQueueFamilies) const;
|
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;
|
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);
|
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 CreateCommandPool();
|
||||||
void CreateCommandBuffers();
|
void CreateCommandBuffers();
|
||||||
@ -641,8 +555,8 @@ private:
|
|||||||
void CreatePipelineCache();
|
void CreatePipelineCache();
|
||||||
VkPipelineShaderStageCreateInfo CreatePipelineShaderStageCreateInfo(VkShaderStageFlagBits stage, VkShaderModule& module, const char* entryName) const;
|
VkPipelineShaderStageCreateInfo CreatePipelineShaderStageCreateInfo(VkShaderStageFlagBits stage, VkShaderModule& module, const char* entryName) const;
|
||||||
VkPipeline backbufferBlit_createGraphicsPipeline(VkDescriptorSetLayout descriptorLayout, bool padView, RendererOutputShader* shader);
|
VkPipeline backbufferBlit_createGraphicsPipeline(VkDescriptorSetLayout descriptorLayout, bool padView, RendererOutputShader* shader);
|
||||||
void AcquireNextSwapchainImage(bool main_window);
|
void AcquireNextSwapchainImage(bool mainWindow);
|
||||||
void RecreateSwapchain(bool mainwindow);
|
void RecreateSwapchain(bool mainWindow);
|
||||||
|
|
||||||
// streamout
|
// streamout
|
||||||
void streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) override;
|
void streamout_setupXfbBuffer(uint32 bufferIndex, sint32 ringBufferOffset, uint32 rangeAddr, uint32 rangeSize) override;
|
||||||
@ -665,7 +579,7 @@ private:
|
|||||||
|
|
||||||
std::vector<const char*> m_layerNames;
|
std::vector<const char*> m_layerNames;
|
||||||
VkInstance m_instance = VK_NULL_HANDLE;
|
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;
|
VkDevice m_logicalDevice = VK_NULL_HANDLE;
|
||||||
VkDebugUtilsMessengerEXT m_debugCallback = nullptr;
|
VkDebugUtilsMessengerEXT m_debugCallback = nullptr;
|
||||||
volatile bool m_destructionRequested = false;
|
volatile bool m_destructionRequested = false;
|
||||||
|
@ -60,5 +60,5 @@ void VulkanCanvas::OnResize(wxSizeEvent& event)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
auto vulkan_renderer = VulkanRenderer::GetInstance();
|
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_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_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_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);
|
void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator);
|
||||||
|
|
||||||
struct ImGuiTexture
|
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.
|
// 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;
|
VkResult err;
|
||||||
VkSwapchainKHR old_swapchain = wd->Swapchain;
|
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 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;
|
(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);
|
ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user