Vulkan window resize fixes

This commit is contained in:
Jack Andersen 2017-02-15 17:17:18 -10:00
parent bfd912b0a9
commit 3197142d1f
4 changed files with 153 additions and 111 deletions

View File

@ -10,6 +10,7 @@
#include <unordered_set> #include <unordered_set>
#include <unordered_map> #include <unordered_map>
#include <mutex> #include <mutex>
#include <queue>
#include "boo/graphicsdev/VulkanDispatchTable.hpp" #include "boo/graphicsdev/VulkanDispatchTable.hpp"
namespace boo namespace boo
@ -77,7 +78,26 @@ struct VulkanContext
bool enumerateDevices(); bool enumerateDevices();
void initDevice(); void initDevice();
void initSwapChain(Window& windowCtx, VkSurfaceKHR surface, VkFormat format, VkColorSpaceKHR colorspace); void initSwapChain(Window& windowCtx, VkSurfaceKHR surface, VkFormat format, VkColorSpaceKHR colorspace);
void resizeSwapChain(Window& windowCtx, VkSurfaceKHR surface, VkFormat format, VkColorSpaceKHR colorspace);
struct SwapChainResize
{
Window& m_windowCtx;
VkSurfaceKHR m_surface;
VkFormat m_format;
VkColorSpaceKHR m_colorspace;
SWindowRect m_rect;
SwapChainResize(Window& windowCtx, VkSurfaceKHR surface,
VkFormat format, VkColorSpaceKHR colorspace,
const SWindowRect& rect)
: m_windowCtx(windowCtx), m_surface(surface),
m_format(format), m_colorspace(colorspace), m_rect(rect) {}
};
std::queue<SwapChainResize> m_deferredResizes;
std::mutex m_resizeLock;
void resizeSwapChain(Window& windowCtx, VkSurfaceKHR surface,
VkFormat format, VkColorSpaceKHR colorspace,
const SWindowRect& rect);
bool _resizeSwapChains();
}; };
extern VulkanContext g_VulkanContext; extern VulkanContext g_VulkanContext;

View File

@ -544,17 +544,32 @@ void VulkanContext::initSwapChain(VulkanContext::Window& windowCtx, VkSurfaceKHR
} }
} }
void VulkanContext::resizeSwapChain(VulkanContext::Window& windowCtx, VkSurfaceKHR surface,
void VulkanContext::resizeSwapChain(VulkanContext::Window& windowCtx, VkSurfaceKHR surface, VkFormat format, VkColorSpaceKHR colorspace) VkFormat format, VkColorSpaceKHR colorspace,
const SWindowRect& rect)
{ {
std::unique_lock<std::mutex> lk(m_resizeLock);
m_deferredResizes.emplace(windowCtx, surface, format, colorspace, rect);
}
bool VulkanContext::_resizeSwapChains()
{
std::unique_lock<std::mutex> lk(m_resizeLock);
if (m_deferredResizes.empty())
return false;
while (m_deferredResizes.size())
{
SwapChainResize& resize = m_deferredResizes.front();
VkSurfaceCapabilitiesKHR surfCapabilities; VkSurfaceCapabilitiesKHR surfCapabilities;
ThrowIfFailed(vk::GetPhysicalDeviceSurfaceCapabilitiesKHR(m_gpus[0], surface, &surfCapabilities)); ThrowIfFailed(vk::GetPhysicalDeviceSurfaceCapabilitiesKHR(m_gpus[0], resize.m_surface, &surfCapabilities));
uint32_t presentModeCount; uint32_t presentModeCount;
ThrowIfFailed(vk::GetPhysicalDeviceSurfacePresentModesKHR(m_gpus[0], surface, &presentModeCount, nullptr)); ThrowIfFailed(vk::GetPhysicalDeviceSurfacePresentModesKHR(m_gpus[0], resize.m_surface, &presentModeCount, nullptr));
std::unique_ptr<VkPresentModeKHR[]> presentModes(new VkPresentModeKHR[presentModeCount]); std::unique_ptr<VkPresentModeKHR[]> presentModes(new VkPresentModeKHR[presentModeCount]);
ThrowIfFailed(vk::GetPhysicalDeviceSurfacePresentModesKHR(m_gpus[0], surface, &presentModeCount, presentModes.get())); ThrowIfFailed(vk::GetPhysicalDeviceSurfacePresentModesKHR(m_gpus[0], resize.m_surface, &presentModeCount, presentModes.get()));
VkExtent2D swapChainExtent; VkExtent2D swapChainExtent;
// width and height are either both -1, or both not -1. // width and height are either both -1, or both not -1.
@ -607,30 +622,33 @@ void VulkanContext::resizeSwapChain(VulkanContext::Window& windowCtx, VkSurfaceK
else else
preTransform = surfCapabilities.currentTransform; preTransform = surfCapabilities.currentTransform;
Window::SwapChain& oldSc = resize.m_windowCtx.m_swapChains[resize.m_windowCtx.m_activeSwapChain];
VkSwapchainCreateInfoKHR swapChainInfo = {}; VkSwapchainCreateInfoKHR swapChainInfo = {};
swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapChainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
swapChainInfo.pNext = nullptr; swapChainInfo.pNext = nullptr;
swapChainInfo.surface = surface; swapChainInfo.surface = resize.m_surface;
swapChainInfo.minImageCount = desiredNumberOfSwapChainImages; swapChainInfo.minImageCount = desiredNumberOfSwapChainImages;
swapChainInfo.imageFormat = format; swapChainInfo.imageFormat = resize.m_format;
swapChainInfo.imageExtent.width = swapChainExtent.width; swapChainInfo.imageExtent.width = swapChainExtent.width;
swapChainInfo.imageExtent.height = swapChainExtent.height; swapChainInfo.imageExtent.height = swapChainExtent.height;
swapChainInfo.preTransform = preTransform; swapChainInfo.preTransform = preTransform;
swapChainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; swapChainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
swapChainInfo.imageArrayLayers = 1; swapChainInfo.imageArrayLayers = 1;
swapChainInfo.presentMode = swapchainPresentMode; swapChainInfo.presentMode = swapchainPresentMode;
swapChainInfo.oldSwapchain = nullptr; swapChainInfo.oldSwapchain = oldSc.m_swapChain;
swapChainInfo.clipped = true; swapChainInfo.clipped = true;
swapChainInfo.imageColorSpace = colorspace; swapChainInfo.imageColorSpace = resize.m_colorspace;
swapChainInfo.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; swapChainInfo.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
swapChainInfo.queueFamilyIndexCount = 0; swapChainInfo.queueFamilyIndexCount = 0;
swapChainInfo.pQueueFamilyIndices = nullptr; swapChainInfo.pQueueFamilyIndices = nullptr;
Window::SwapChain& sc = windowCtx.m_swapChains[windowCtx.m_activeSwapChain ^ 1]; resize.m_windowCtx.m_activeSwapChain ^= 1;
Window::SwapChain& sc = resize.m_windowCtx.m_swapChains[resize.m_windowCtx.m_activeSwapChain];
sc.destroy(m_dev); sc.destroy(m_dev);
ThrowIfFailed(vk::CreateSwapchainKHR(m_dev, &swapChainInfo, nullptr, &sc.m_swapChain)); ThrowIfFailed(vk::CreateSwapchainKHR(m_dev, &swapChainInfo, nullptr, &sc.m_swapChain));
sc.m_format = format; sc.m_format = resize.m_format;
uint32_t swapchainImageCount; uint32_t swapchainImageCount;
ThrowIfFailed(vk::GetSwapchainImagesKHR(m_dev, sc.m_swapChain, &swapchainImageCount, nullptr)); ThrowIfFailed(vk::GetSwapchainImagesKHR(m_dev, sc.m_swapChain, &swapchainImageCount, nullptr));
@ -645,6 +663,11 @@ void VulkanContext::resizeSwapChain(VulkanContext::Window& windowCtx, VkSurfaceK
Window::SwapChain::Buffer& buf = sc.m_bufs[i]; Window::SwapChain::Buffer& buf = sc.m_bufs[i];
buf.m_image = swapchainImages[i]; buf.m_image = swapchainImages[i];
} }
m_deferredResizes.pop();
}
return true;
} }
struct VulkanData : IGraphicsDataPriv<VulkanData> struct VulkanData : IGraphicsDataPriv<VulkanData>
@ -3298,6 +3321,8 @@ void VulkanCommandQueue::execute()
ThrowIfFailed(vk::QueueSubmit(m_ctx->m_queue, 1, &submitInfo, m_dynamicBufFence)); ThrowIfFailed(vk::QueueSubmit(m_ctx->m_queue, 1, &submitInfo, m_dynamicBufFence));
} }
vk::CmdEndRenderPass(m_cmdBufs[m_fillBuf]);
/* Check on fence */ /* Check on fence */
if (m_submitted && vk::GetFenceStatus(m_ctx->m_dev, m_drawCompleteFence) == VK_NOT_READY) if (m_submitted && vk::GetFenceStatus(m_ctx->m_dev, m_drawCompleteFence) == VK_NOT_READY)
{ {
@ -3307,6 +3332,9 @@ void VulkanCommandQueue::execute()
m_resolveDispSource = nullptr; m_resolveDispSource = nullptr;
return; return;
} }
m_submitted = false;
vk::ResetFences(m_ctx->m_dev, 1, &m_drawCompleteFence);
/* Clear dead data */ /* Clear dead data */
datalk.lock(); datalk.lock();
@ -3333,8 +3361,8 @@ void VulkanCommandQueue::execute()
} }
datalk.unlock(); datalk.unlock();
/* Perform texture resizes */ /* Perform texture and swap-chain resizes */
if (m_texResizes.size()) if (m_ctx->_resizeSwapChains() || m_texResizes.size())
{ {
for (const auto& resize : m_texResizes) for (const auto& resize : m_texResizes)
{ {
@ -3346,20 +3374,9 @@ void VulkanCommandQueue::execute()
resetCommandBuffer(); resetCommandBuffer();
m_dynamicNeedsReset = true; m_dynamicNeedsReset = true;
m_resolveDispSource = nullptr; m_resolveDispSource = nullptr;
VulkanContext::Window::SwapChain& otherSc = m_windowCtx->m_swapChains[m_windowCtx->m_activeSwapChain ^ 1];
if (otherSc.m_swapChain)
{
VulkanContext::Window::SwapChain& thisSc = m_windowCtx->m_swapChains[m_windowCtx->m_activeSwapChain];
thisSc.destroy(m_ctx->m_dev);
m_windowCtx->m_activeSwapChain ^= 1;
}
return; return;
} }
vk::ResetFences(m_ctx->m_dev, 1, &m_drawCompleteFence);
vk::CmdEndRenderPass(m_cmdBufs[m_fillBuf]);
m_drawBuf = m_fillBuf; m_drawBuf = m_fillBuf;
m_fillBuf ^= 1; m_fillBuf ^= 1;

View File

@ -54,6 +54,11 @@ struct GraphicsContextWin32 : IGraphicsContext
m_pf(EPixelFormat::RGBA8), m_pf(EPixelFormat::RGBA8),
m_parentWindow(parentWindow), m_parentWindow(parentWindow),
m_3dCtx(b3dCtx) {} m_3dCtx(b3dCtx) {}
virtual void resized(const SWindowRect& rect)
{
m_3dCtx.resize(m_parentWindow, rect.size[0], rect.size[1]);
}
}; };
struct GraphicsContextWin32D3D : GraphicsContextWin32 struct GraphicsContextWin32D3D : GraphicsContextWin32
@ -461,10 +466,10 @@ public:
VulkanContext::Window* m_windowCtx = nullptr; VulkanContext::Window* m_windowCtx = nullptr;
void resized(SWindowRect& rect) void resized(const SWindowRect& rect)
{ {
if (m_windowCtx) if (m_windowCtx)
m_ctx->resizeSwapChain(*m_windowCtx, m_surface, m_format, m_colorspace); m_ctx->resizeSwapChain(*m_windowCtx, m_surface, m_format, m_colorspace, rect);
} }
void _setCallback(IWindowCallback* cb) void _setCallback(IWindowCallback* cb)
@ -1290,7 +1295,7 @@ public:
getWindowFrame(rect.location[0], rect.location[1], rect.size[0], rect.size[1]); getWindowFrame(rect.location[0], rect.location[1], rect.size[0], rect.size[1]);
if (!rect.size[0] || !rect.size[1]) if (!rect.size[0] || !rect.size[1])
return; return;
m_gfxCtx->m_3dCtx.resize(this, rect.size[0], rect.size[1]); m_gfxCtx->resized(rect);
if (m_callback) if (m_callback)
m_callback->resized(rect, m_openGL); m_callback->resized(rect, m_openGL);
return; return;

View File

@ -297,7 +297,7 @@ struct GraphicsContextXlib : IGraphicsContext
m_parentWindow(parentWindow), m_parentWindow(parentWindow),
m_xDisp(disp) {} m_xDisp(disp) {}
virtual void destroy()=0; virtual void destroy()=0;
virtual void resized(SWindowRect& rect)=0; virtual void resized(const SWindowRect& rect)=0;
}; };
struct GraphicsContextXlibGLX : GraphicsContextXlib struct GraphicsContextXlibGLX : GraphicsContextXlib
@ -414,7 +414,7 @@ public:
~GraphicsContextXlibGLX() {destroy();} ~GraphicsContextXlibGLX() {destroy();}
void resized(SWindowRect& rect) void resized(const SWindowRect& rect)
{ {
} }
@ -650,10 +650,10 @@ public:
VulkanContext::Window* m_windowCtx = nullptr; VulkanContext::Window* m_windowCtx = nullptr;
void resized(SWindowRect& rect) void resized(const SWindowRect& rect)
{ {
if (m_windowCtx) if (m_windowCtx)
m_ctx->resizeSwapChain(*m_windowCtx, m_surface, m_format, m_colorspace); m_ctx->resizeSwapChain(*m_windowCtx, m_surface, m_format, m_colorspace, rect);
} }
void _setCallback(IWindowCallback* cb) void _setCallback(IWindowCallback* cb)