mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-28 06:53:58 +00:00
- improve swap chain resize and handle the edge cases for the swap chain
This commit is contained in:
parent
20fde9f8be
commit
c98dfd1790
4 changed files with 134 additions and 37 deletions
|
@ -157,20 +157,7 @@ void VulkanFrameBuffer::Update()
|
|||
|
||||
Flush3D.Clock();
|
||||
|
||||
int newWidth = GetClientWidth();
|
||||
int newHeight = GetClientHeight();
|
||||
if (lastSwapWidth != newWidth || lastSwapHeight != newHeight)
|
||||
{
|
||||
swapChain.reset();
|
||||
swapChain = std::make_unique<VulkanSwapChain>(device);
|
||||
|
||||
lastSwapWidth = newWidth;
|
||||
lastSwapHeight = newHeight;
|
||||
}
|
||||
|
||||
VkResult result = vkAcquireNextImageKHR(device->device, swapChain->swapChain, std::numeric_limits<uint64_t>::max(), mSwapChainImageAvailableSemaphore->semaphore, VK_NULL_HANDLE, &presentImageIndex);
|
||||
if (result != VK_SUCCESS)
|
||||
throw std::runtime_error("Failed to acquire next image!");
|
||||
presentImageIndex = swapChain->AcquireImage(GetClientWidth(), GetClientHeight(), mSwapChainImageAvailableSemaphore.get());
|
||||
|
||||
GetPostprocess()->SetActiveRenderTarget();
|
||||
|
||||
|
@ -180,7 +167,8 @@ void VulkanFrameBuffer::Update()
|
|||
mRenderState->EndRenderPass();
|
||||
mRenderState->EndFrame();
|
||||
|
||||
mPostprocess->DrawPresentTexture(mOutputLetterbox, true, true);
|
||||
if (presentImageIndex != 0xffffffff)
|
||||
mPostprocess->DrawPresentTexture(mOutputLetterbox, true, true);
|
||||
|
||||
SubmitCommands(true);
|
||||
|
||||
|
@ -191,17 +179,8 @@ void VulkanFrameBuffer::Update()
|
|||
Finish.Reset();
|
||||
Finish.Clock();
|
||||
|
||||
VkSemaphore waitSemaphores[] = { mRenderFinishedSemaphore->semaphore };
|
||||
VkSwapchainKHR swapChains[] = { swapChain->swapChain };
|
||||
VkPresentInfoKHR presentInfo = {};
|
||||
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
presentInfo.waitSemaphoreCount = 1;
|
||||
presentInfo.pWaitSemaphores = waitSemaphores;
|
||||
presentInfo.swapchainCount = 1;
|
||||
presentInfo.pSwapchains = swapChains;
|
||||
presentInfo.pImageIndices = &presentImageIndex;
|
||||
presentInfo.pResults = nullptr;
|
||||
vkQueuePresentKHR(device->presentQueue, &presentInfo);
|
||||
if (presentImageIndex != 0xffffffff)
|
||||
swapChain->QueuePresent(presentImageIndex, mRenderFinishedSemaphore.get());
|
||||
|
||||
vkWaitForFences(device->device, 1, &mRenderFinishedFence->fence, VK_TRUE, std::numeric_limits<uint64_t>::max());
|
||||
vkResetFences(device->device, 1, &mRenderFinishedFence->fence);
|
||||
|
|
|
@ -23,7 +23,7 @@ class VulkanFrameBuffer : public SystemBaseFrameBuffer
|
|||
public:
|
||||
VulkanDevice *device;
|
||||
std::unique_ptr<VulkanSwapChain> swapChain;
|
||||
uint32_t presentImageIndex = 0;
|
||||
uint32_t presentImageIndex = 0xffffffff;
|
||||
|
||||
VulkanCommandBuffer *GetTransferCommands();
|
||||
VulkanCommandBuffer *GetDrawCommands();
|
||||
|
@ -124,9 +124,6 @@ private:
|
|||
std::unique_ptr<VulkanFence> mRenderFinishedFence;
|
||||
|
||||
VkRenderBuffers *mActiveRenderBuffers = nullptr;
|
||||
|
||||
int lastSwapWidth = 0;
|
||||
int lastSwapHeight = 0;
|
||||
};
|
||||
|
||||
inline VulkanFrameBuffer *GetVulkanFrameBuffer() { return static_cast<VulkanFrameBuffer*>(screen); }
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
#include "vk_swapchain.h"
|
||||
#include "vk_objects.h"
|
||||
#include "c_cvars.h"
|
||||
#include "version.h"
|
||||
|
||||
|
@ -18,10 +19,10 @@ VulkanSwapChain::VulkanSwapChain(VulkanDevice *device) : vsync(vid_vsync), devic
|
|||
{
|
||||
SelectFormat();
|
||||
SelectPresentMode();
|
||||
CreateSwapChain();
|
||||
if (!CreateSwapChain())
|
||||
throw std::runtime_error("Could not create vulkan swapchain");
|
||||
GetImages();
|
||||
CreateViews();
|
||||
// SetHdrMetadata(); // This isn't required it seems
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
@ -35,7 +36,101 @@ VulkanSwapChain::~VulkanSwapChain()
|
|||
ReleaseResources();
|
||||
}
|
||||
|
||||
void VulkanSwapChain::CreateSwapChain()
|
||||
uint32_t VulkanSwapChain::AcquireImage(int width, int height, VulkanSemaphore *semaphore, VulkanFence *fence)
|
||||
{
|
||||
if (lastSwapWidth != width || lastSwapHeight != height || !swapChain)
|
||||
{
|
||||
Recreate();
|
||||
lastSwapWidth = width;
|
||||
lastSwapHeight = height;
|
||||
}
|
||||
|
||||
uint32_t imageIndex;
|
||||
while (true)
|
||||
{
|
||||
if (!swapChain)
|
||||
{
|
||||
imageIndex = 0xffffffff;
|
||||
break;
|
||||
}
|
||||
|
||||
VkResult result = vkAcquireNextImageKHR(device->device, swapChain, std::numeric_limits<uint64_t>::max(), semaphore ? semaphore->semaphore : VK_NULL_HANDLE, fence ? fence->fence : VK_NULL_HANDLE, &imageIndex);
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
|
||||
{
|
||||
Recreate();
|
||||
}
|
||||
else if (result == VK_SUCCESS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (result == VK_TIMEOUT || result == VK_NOT_READY)
|
||||
{
|
||||
imageIndex = 0xffffffff;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Failed to acquire next image!");
|
||||
}
|
||||
}
|
||||
return imageIndex;
|
||||
}
|
||||
|
||||
void VulkanSwapChain::QueuePresent(uint32_t imageIndex, VulkanSemaphore *semaphore)
|
||||
{
|
||||
VkPresentInfoKHR presentInfo = {};
|
||||
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
presentInfo.waitSemaphoreCount = semaphore ? 1 : 0;
|
||||
presentInfo.pWaitSemaphores = semaphore ? &semaphore->semaphore : VK_NULL_HANDLE;
|
||||
presentInfo.swapchainCount = 1;
|
||||
presentInfo.pSwapchains = &swapChain;
|
||||
presentInfo.pImageIndices = &imageIndex;
|
||||
presentInfo.pResults = nullptr;
|
||||
VkResult result = vkQueuePresentKHR(device->presentQueue, &presentInfo);
|
||||
if (result == VK_SUBOPTIMAL_KHR || result == VK_ERROR_OUT_OF_DATE_KHR)
|
||||
{
|
||||
lastSwapWidth = 0;
|
||||
lastSwapHeight = 0;
|
||||
}
|
||||
else if (result == VK_ERROR_OUT_OF_HOST_MEMORY || result == VK_ERROR_OUT_OF_DEVICE_MEMORY)
|
||||
{
|
||||
// The spec says we can recover from this.
|
||||
// However, if we are out of memory it is better to crash now than in some other weird place further away from the source of the problem.
|
||||
|
||||
throw std::runtime_error("vkQueuePresentKHR failed: out of memory");
|
||||
}
|
||||
else if (result == VK_ERROR_DEVICE_LOST)
|
||||
{
|
||||
throw std::runtime_error("vkQueuePresentKHR failed: device lost");
|
||||
}
|
||||
else if (result == VK_ERROR_SURFACE_LOST_KHR)
|
||||
{
|
||||
throw std::runtime_error("vkQueuePresentKHR failed: surface lost");
|
||||
}
|
||||
else if (result != VK_SUCCESS)
|
||||
{
|
||||
throw std::runtime_error("vkQueuePresentKHR failed");
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanSwapChain::Recreate()
|
||||
{
|
||||
ReleaseViews();
|
||||
swapChainImages.clear();
|
||||
|
||||
VkSwapchainKHR oldSwapChain = swapChain;
|
||||
CreateSwapChain(oldSwapChain);
|
||||
if (oldSwapChain)
|
||||
vkDestroySwapchainKHR(device->device, oldSwapChain, nullptr);
|
||||
|
||||
if (swapChain)
|
||||
{
|
||||
GetImages();
|
||||
CreateViews();
|
||||
}
|
||||
}
|
||||
|
||||
bool VulkanSwapChain::CreateSwapChain(VkSwapchainKHR oldSwapChain)
|
||||
{
|
||||
int width, height;
|
||||
I_GetVulkanDrawableSize(&width, &height);
|
||||
|
@ -45,6 +140,11 @@ void VulkanSwapChain::CreateSwapChain()
|
|||
actualExtent = { static_cast<uint32_t>(width), static_cast<uint32_t>(height) };
|
||||
actualExtent.width = std::max(surfaceCapabilities.minImageExtent.width, std::min(surfaceCapabilities.maxImageExtent.width, actualExtent.width));
|
||||
actualExtent.height = std::max(surfaceCapabilities.minImageExtent.height, std::min(surfaceCapabilities.maxImageExtent.height, actualExtent.height));
|
||||
if (actualExtent.width == 0 || actualExtent.height == 0)
|
||||
{
|
||||
swapChain = VK_NULL_HANDLE;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t imageCount = surfaceCapabilities.minImageCount + 1;
|
||||
if (surfaceCapabilities.maxImageCount > 0 && imageCount > surfaceCapabilities.maxImageCount)
|
||||
|
@ -80,11 +180,16 @@ void VulkanSwapChain::CreateSwapChain()
|
|||
swapChainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; // If alpha channel is passed on to the DWM or not
|
||||
swapChainCreateInfo.presentMode = swapChainPresentMode;
|
||||
swapChainCreateInfo.clipped = VK_TRUE;
|
||||
swapChainCreateInfo.oldSwapchain = VK_NULL_HANDLE;
|
||||
swapChainCreateInfo.oldSwapchain = oldSwapChain;
|
||||
|
||||
VkResult result = vkCreateSwapchainKHR(device->device, &swapChainCreateInfo, nullptr, &swapChain);
|
||||
if (result != VK_SUCCESS)
|
||||
throw std::runtime_error("Could not create vulkan swapchain");
|
||||
{
|
||||
swapChain = VK_NULL_HANDLE;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VulkanSwapChain::CreateViews()
|
||||
|
@ -218,14 +323,18 @@ void VulkanSwapChain::GetImages()
|
|||
throw std::runtime_error("vkGetSwapchainImagesKHR failed (2)");
|
||||
}
|
||||
|
||||
void VulkanSwapChain::ReleaseResources()
|
||||
void VulkanSwapChain::ReleaseViews()
|
||||
{
|
||||
for (auto &view : swapChainImageViews)
|
||||
{
|
||||
vkDestroyImageView(device->device, view, nullptr);
|
||||
}
|
||||
swapChainImageViews.clear();
|
||||
}
|
||||
|
||||
void VulkanSwapChain::ReleaseResources()
|
||||
{
|
||||
ReleaseViews();
|
||||
if (swapChain)
|
||||
vkDestroySwapchainKHR(device->device, swapChain, nullptr);
|
||||
}
|
||||
|
|
|
@ -2,12 +2,20 @@
|
|||
|
||||
#include "vk_device.h"
|
||||
|
||||
class VulkanSemaphore;
|
||||
class VulkanFence;
|
||||
|
||||
class VulkanSwapChain
|
||||
{
|
||||
public:
|
||||
VulkanSwapChain(VulkanDevice *device);
|
||||
~VulkanSwapChain();
|
||||
|
||||
uint32_t AcquireImage(int width, int height, VulkanSemaphore *semaphore = nullptr, VulkanFence *fence = nullptr);
|
||||
void QueuePresent(uint32_t imageIndex, VulkanSemaphore *semaphore = nullptr);
|
||||
|
||||
void Recreate();
|
||||
|
||||
bool vsync;
|
||||
VkSwapchainKHR swapChain = VK_NULL_HANDLE;
|
||||
VkSurfaceFormatKHR swapChainFormat;
|
||||
|
@ -21,11 +29,12 @@ public:
|
|||
private:
|
||||
void SelectFormat();
|
||||
void SelectPresentMode();
|
||||
void CreateSwapChain();
|
||||
bool CreateSwapChain(VkSwapchainKHR oldSwapChain = VK_NULL_HANDLE);
|
||||
void CreateViews();
|
||||
void SetHdrMetadata();
|
||||
void GetImages();
|
||||
void ReleaseResources();
|
||||
void ReleaseViews();
|
||||
|
||||
VkSurfaceCapabilitiesKHR GetSurfaceCapabilities();
|
||||
std::vector<VkSurfaceFormatKHR> GetSurfaceFormats();
|
||||
|
@ -33,6 +42,9 @@ private:
|
|||
|
||||
VulkanDevice *device = nullptr;
|
||||
|
||||
int lastSwapWidth = 0;
|
||||
int lastSwapHeight = 0;
|
||||
|
||||
VulkanSwapChain(const VulkanSwapChain &) = delete;
|
||||
VulkanSwapChain &operator=(const VulkanSwapChain &) = delete;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue