mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2025-02-16 08:32:02 +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();
|
Flush3D.Clock();
|
||||||
|
|
||||||
int newWidth = GetClientWidth();
|
presentImageIndex = swapChain->AcquireImage(GetClientWidth(), GetClientHeight(), mSwapChainImageAvailableSemaphore.get());
|
||||||
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!");
|
|
||||||
|
|
||||||
GetPostprocess()->SetActiveRenderTarget();
|
GetPostprocess()->SetActiveRenderTarget();
|
||||||
|
|
||||||
|
@ -180,7 +167,8 @@ void VulkanFrameBuffer::Update()
|
||||||
mRenderState->EndRenderPass();
|
mRenderState->EndRenderPass();
|
||||||
mRenderState->EndFrame();
|
mRenderState->EndFrame();
|
||||||
|
|
||||||
mPostprocess->DrawPresentTexture(mOutputLetterbox, true, true);
|
if (presentImageIndex != 0xffffffff)
|
||||||
|
mPostprocess->DrawPresentTexture(mOutputLetterbox, true, true);
|
||||||
|
|
||||||
SubmitCommands(true);
|
SubmitCommands(true);
|
||||||
|
|
||||||
|
@ -191,17 +179,8 @@ void VulkanFrameBuffer::Update()
|
||||||
Finish.Reset();
|
Finish.Reset();
|
||||||
Finish.Clock();
|
Finish.Clock();
|
||||||
|
|
||||||
VkSemaphore waitSemaphores[] = { mRenderFinishedSemaphore->semaphore };
|
if (presentImageIndex != 0xffffffff)
|
||||||
VkSwapchainKHR swapChains[] = { swapChain->swapChain };
|
swapChain->QueuePresent(presentImageIndex, mRenderFinishedSemaphore.get());
|
||||||
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);
|
|
||||||
|
|
||||||
vkWaitForFences(device->device, 1, &mRenderFinishedFence->fence, VK_TRUE, std::numeric_limits<uint64_t>::max());
|
vkWaitForFences(device->device, 1, &mRenderFinishedFence->fence, VK_TRUE, std::numeric_limits<uint64_t>::max());
|
||||||
vkResetFences(device->device, 1, &mRenderFinishedFence->fence);
|
vkResetFences(device->device, 1, &mRenderFinishedFence->fence);
|
||||||
|
|
|
@ -23,7 +23,7 @@ class VulkanFrameBuffer : public SystemBaseFrameBuffer
|
||||||
public:
|
public:
|
||||||
VulkanDevice *device;
|
VulkanDevice *device;
|
||||||
std::unique_ptr<VulkanSwapChain> swapChain;
|
std::unique_ptr<VulkanSwapChain> swapChain;
|
||||||
uint32_t presentImageIndex = 0;
|
uint32_t presentImageIndex = 0xffffffff;
|
||||||
|
|
||||||
VulkanCommandBuffer *GetTransferCommands();
|
VulkanCommandBuffer *GetTransferCommands();
|
||||||
VulkanCommandBuffer *GetDrawCommands();
|
VulkanCommandBuffer *GetDrawCommands();
|
||||||
|
@ -124,9 +124,6 @@ private:
|
||||||
std::unique_ptr<VulkanFence> mRenderFinishedFence;
|
std::unique_ptr<VulkanFence> mRenderFinishedFence;
|
||||||
|
|
||||||
VkRenderBuffers *mActiveRenderBuffers = nullptr;
|
VkRenderBuffers *mActiveRenderBuffers = nullptr;
|
||||||
|
|
||||||
int lastSwapWidth = 0;
|
|
||||||
int lastSwapHeight = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline VulkanFrameBuffer *GetVulkanFrameBuffer() { return static_cast<VulkanFrameBuffer*>(screen); }
|
inline VulkanFrameBuffer *GetVulkanFrameBuffer() { return static_cast<VulkanFrameBuffer*>(screen); }
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
|
||||||
#include "vk_swapchain.h"
|
#include "vk_swapchain.h"
|
||||||
|
#include "vk_objects.h"
|
||||||
#include "c_cvars.h"
|
#include "c_cvars.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
|
@ -18,10 +19,10 @@ VulkanSwapChain::VulkanSwapChain(VulkanDevice *device) : vsync(vid_vsync), devic
|
||||||
{
|
{
|
||||||
SelectFormat();
|
SelectFormat();
|
||||||
SelectPresentMode();
|
SelectPresentMode();
|
||||||
CreateSwapChain();
|
if (!CreateSwapChain())
|
||||||
|
throw std::runtime_error("Could not create vulkan swapchain");
|
||||||
GetImages();
|
GetImages();
|
||||||
CreateViews();
|
CreateViews();
|
||||||
// SetHdrMetadata(); // This isn't required it seems
|
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
@ -35,7 +36,101 @@ VulkanSwapChain::~VulkanSwapChain()
|
||||||
ReleaseResources();
|
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;
|
int width, height;
|
||||||
I_GetVulkanDrawableSize(&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 = { 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.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));
|
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;
|
uint32_t imageCount = surfaceCapabilities.minImageCount + 1;
|
||||||
if (surfaceCapabilities.maxImageCount > 0 && imageCount > surfaceCapabilities.maxImageCount)
|
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.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; // If alpha channel is passed on to the DWM or not
|
||||||
swapChainCreateInfo.presentMode = swapChainPresentMode;
|
swapChainCreateInfo.presentMode = swapChainPresentMode;
|
||||||
swapChainCreateInfo.clipped = VK_TRUE;
|
swapChainCreateInfo.clipped = VK_TRUE;
|
||||||
swapChainCreateInfo.oldSwapchain = VK_NULL_HANDLE;
|
swapChainCreateInfo.oldSwapchain = oldSwapChain;
|
||||||
|
|
||||||
VkResult result = vkCreateSwapchainKHR(device->device, &swapChainCreateInfo, nullptr, &swapChain);
|
VkResult result = vkCreateSwapchainKHR(device->device, &swapChainCreateInfo, nullptr, &swapChain);
|
||||||
if (result != VK_SUCCESS)
|
if (result != VK_SUCCESS)
|
||||||
throw std::runtime_error("Could not create vulkan swapchain");
|
{
|
||||||
|
swapChain = VK_NULL_HANDLE;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanSwapChain::CreateViews()
|
void VulkanSwapChain::CreateViews()
|
||||||
|
@ -218,14 +323,18 @@ void VulkanSwapChain::GetImages()
|
||||||
throw std::runtime_error("vkGetSwapchainImagesKHR failed (2)");
|
throw std::runtime_error("vkGetSwapchainImagesKHR failed (2)");
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanSwapChain::ReleaseResources()
|
void VulkanSwapChain::ReleaseViews()
|
||||||
{
|
{
|
||||||
for (auto &view : swapChainImageViews)
|
for (auto &view : swapChainImageViews)
|
||||||
{
|
{
|
||||||
vkDestroyImageView(device->device, view, nullptr);
|
vkDestroyImageView(device->device, view, nullptr);
|
||||||
}
|
}
|
||||||
swapChainImageViews.clear();
|
swapChainImageViews.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanSwapChain::ReleaseResources()
|
||||||
|
{
|
||||||
|
ReleaseViews();
|
||||||
if (swapChain)
|
if (swapChain)
|
||||||
vkDestroySwapchainKHR(device->device, swapChain, nullptr);
|
vkDestroySwapchainKHR(device->device, swapChain, nullptr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,20 @@
|
||||||
|
|
||||||
#include "vk_device.h"
|
#include "vk_device.h"
|
||||||
|
|
||||||
|
class VulkanSemaphore;
|
||||||
|
class VulkanFence;
|
||||||
|
|
||||||
class VulkanSwapChain
|
class VulkanSwapChain
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VulkanSwapChain(VulkanDevice *device);
|
VulkanSwapChain(VulkanDevice *device);
|
||||||
~VulkanSwapChain();
|
~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;
|
bool vsync;
|
||||||
VkSwapchainKHR swapChain = VK_NULL_HANDLE;
|
VkSwapchainKHR swapChain = VK_NULL_HANDLE;
|
||||||
VkSurfaceFormatKHR swapChainFormat;
|
VkSurfaceFormatKHR swapChainFormat;
|
||||||
|
@ -21,11 +29,12 @@ public:
|
||||||
private:
|
private:
|
||||||
void SelectFormat();
|
void SelectFormat();
|
||||||
void SelectPresentMode();
|
void SelectPresentMode();
|
||||||
void CreateSwapChain();
|
bool CreateSwapChain(VkSwapchainKHR oldSwapChain = VK_NULL_HANDLE);
|
||||||
void CreateViews();
|
void CreateViews();
|
||||||
void SetHdrMetadata();
|
void SetHdrMetadata();
|
||||||
void GetImages();
|
void GetImages();
|
||||||
void ReleaseResources();
|
void ReleaseResources();
|
||||||
|
void ReleaseViews();
|
||||||
|
|
||||||
VkSurfaceCapabilitiesKHR GetSurfaceCapabilities();
|
VkSurfaceCapabilitiesKHR GetSurfaceCapabilities();
|
||||||
std::vector<VkSurfaceFormatKHR> GetSurfaceFormats();
|
std::vector<VkSurfaceFormatKHR> GetSurfaceFormats();
|
||||||
|
@ -33,6 +42,9 @@ private:
|
||||||
|
|
||||||
VulkanDevice *device = nullptr;
|
VulkanDevice *device = nullptr;
|
||||||
|
|
||||||
|
int lastSwapWidth = 0;
|
||||||
|
int lastSwapHeight = 0;
|
||||||
|
|
||||||
VulkanSwapChain(const VulkanSwapChain &) = delete;
|
VulkanSwapChain(const VulkanSwapChain &) = delete;
|
||||||
VulkanSwapChain &operator=(const VulkanSwapChain &) = delete;
|
VulkanSwapChain &operator=(const VulkanSwapChain &) = delete;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue