Skip to content

Commit

Permalink
[Release] fixed deadlock on swapchain resize (#180)
Browse files Browse the repository at this point in the history
* fixed deadlock on swapchain resize

added pNext to the swapchain creation

* Restyle fixed deadlock on swapchain resize (#181)

* Restyled by astyle

* Restyled by clang-format

---------

Co-authored-by: Restyled.io <[email protected]>

---------

Co-authored-by: restyled-io[bot] <32688539+restyled-io[bot]@users.noreply.github.com>
Co-authored-by: Restyled.io <[email protected]>
  • Loading branch information
3 people authored Oct 1, 2024
1 parent 5fd453f commit 5a1120f
Show file tree
Hide file tree
Showing 10 changed files with 105 additions and 121 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

cmake_minimum_required(VERSION 3.22)

set(WISDOM_VERSION "0.3.4")
set(WISDOM_VERSION "0.3.5")
project("Wisdom" VERSION ${WISDOM_VERSION})

set(CMAKE_DEBUG_POSTFIX d)
Expand Down
6 changes: 6 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Version History

- 0.3.5

- Made internal function for swapchain recreation in Vulkan accept a pNext chain
- Fixed cross-adapter example not finishing correctly
- Fixed swapchain deadlocking on resize for Vulkan

- 0.3.4

- Made a lot of views CPP API only, that makes C API more lightweight
Expand Down
4 changes: 4 additions & 0 deletions examples/custom/cross_device/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ App::App(uint32_t width, uint32_t height)
{
CreateDevices();
}
App::~App()
{
transfer.input_buffer.Unmap();
}

void App::CreateDevices()
{
Expand Down
1 change: 1 addition & 0 deletions examples/custom/cross_device/app.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class App

public:
App(uint32_t width, uint32_t height);
~App();

public:
void CreateDevices();
Expand Down
12 changes: 7 additions & 5 deletions examples/custom/cross_device/work_node.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,33 @@ struct ExternalBuffer {
ExternalBuffer(wis::SharedDevice device, VkBuffer buffer, VkDeviceMemory memory)
: device(std::move(device)), buffer(buffer), memory(memory)
{
this->device.table().vkMapMemory(this->device.get(), memory, 0, VK_WHOLE_SIZE, 0, &mapping);
}
ExternalBuffer(ExternalBuffer&& other) noexcept
: device(std::move(other.device)), buffer(std::move(other.buffer)), memory(std::move(other.memory)), mapping(std::exchange(other.mapping, nullptr))
: device(std::move(other.device)), buffer(std::move(other.buffer)), memory(std::move(other.memory))
{
}
ExternalBuffer& operator=(ExternalBuffer&& other) noexcept
{
if (this == &other)
return *this;

Destroy();
device = std::move(other.device);
buffer = std::move(other.buffer);
memory = std::move(other.memory);
mapping = std::exchange(other.mapping, nullptr);
return *this;
}
~ExternalBuffer()
void Destroy() noexcept
{
if (buffer)
device.table().vkDestroyBuffer(device.get(), buffer, nullptr);
if (memory)
device.table().vkFreeMemory(device.get(), memory, nullptr);
}
~ExternalBuffer()
{
Destroy();
}

public:
operator wis::VKBufferView() const noexcept
Expand All @@ -42,7 +45,6 @@ struct ExternalBuffer {
wis::SharedDevice device;
wis::h::VkBuffer buffer;
wis::h::VkDeviceMemory memory;
void* mapping = nullptr;
};

struct ExtMemoryHost : public wis::DeviceExtension {
Expand Down
7 changes: 4 additions & 3 deletions wisdom/include/wisdom/vulkan/impl/vk_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -908,7 +908,8 @@ wis::ImplVKDevice::VKCreateAllocator(bool interop) const noexcept
wis::ResultValue<wis::VKSwapChain>
wis::ImplVKDevice::VKCreateSwapChain(wis::SharedSurface surface,
const SwapchainDesc* desc,
VkQueue graphics_queue) const noexcept
VkQueue graphics_queue,
void* pNext) const noexcept
{
auto& itable = GetInstanceTable();
auto& dtable = device.table();
Expand Down Expand Up @@ -1045,14 +1046,14 @@ wis::ImplVKDevice::VKCreateSwapChain(wis::SharedSurface surface,

VkSwapchainPresentModesCreateInfoEXT present_modes{
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODES_CREATE_INFO_EXT,
.pNext = nullptr,
.pNext = pNext,
.presentModeCount = compatible_modes_count,
.pPresentModes = compatible_modes.data(),
};

VkSwapchainCreateInfoKHR swap_info{
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
.pNext = ext1.GetFeatures().dynamic_vsync ? &present_modes : nullptr,
.pNext = ext1.GetFeatures().dynamic_vsync ? &present_modes : pNext,
.flags = 0,
.surface = surface.get(),
.minImageCount = desc->buffer_count,
Expand Down
188 changes: 78 additions & 110 deletions wisdom/include/wisdom/vulkan/impl/vk_swapchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,105 +196,21 @@ wis::Result wis::detail::VKSwapChainCreateInfo::InitSemaphores() noexcept
void wis::detail::VKSwapChainCreateInfo::ReleaseSemaphores() noexcept
{
auto& dtable = device.table();
if (!supported_presentations) {
dtable.vkQueueSubmit(graphics_queue, 0, nullptr, fence);
dtable.vkWaitForFences(device.get(), 1, &fence, VK_TRUE, std::numeric_limits<uint64_t>::max());
dtable.vkResetFences(device.get(), 1, &fence);

dtable.vkQueueSubmit(present_queue, 0, nullptr, fence);
dtable.vkWaitForFences(device.get(), 1, &fence, VK_TRUE, std::numeric_limits<uint64_t>::max());
dtable.vkResetFences(device.get(), 1, &fence);
} else {
dtable.vkWaitForFences(device.get(), 1, &fence, VK_TRUE, std::numeric_limits<uint64_t>::max());
dtable.vkResetFences(device.get(), 1, &fence);
}
dtable.vkQueueSubmit(graphics_queue, 0, nullptr, fence);
dtable.vkWaitForFences(device.get(), 1, &fence, VK_TRUE, std::numeric_limits<uint64_t>::max());
dtable.vkResetFences(device.get(), 1, &fence);

if (fence) {
dtable.vkDestroyFence(device.get(), fence, nullptr);
fence = nullptr;
}
dtable.vkQueueSubmit(present_queue, 0, nullptr, fence);
dtable.vkWaitForFences(device.get(), 1, &fence, VK_TRUE, std::numeric_limits<uint64_t>::max());
dtable.vkResetFences(device.get(), 1, &fence);

dtable.vkDestroyFence(device.get(), fence, nullptr);
fence = nullptr;
}

wis::Result wis::ImplVKSwapChain::Resize(uint32_t width, uint32_t height) noexcept
{
auto& dtable = device.table();
auto& itable = surface.header().parent.table();

if (!supported_presentations) {
VkPipelineStageFlags wait_stages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;

VkSubmitInfo wait_desc{
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.pNext = nullptr,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &image_ready_semaphores[acquire_index],
.pWaitDstStageMask = &wait_stages,
};
dtable.vkQueueSubmit(graphics_queue, 1, &wait_desc, fence);
dtable.vkWaitForFences(device.get(), 1, &fence, VK_TRUE, std::numeric_limits<uint64_t>::max());
dtable.vkResetFences(device.get(), 1, &fence);

dtable.vkQueueSubmit(present_queue, 0, nullptr, fence);
dtable.vkWaitForFences(device.get(), 1, &fence, VK_TRUE, std::numeric_limits<uint64_t>::max());
dtable.vkResetFences(device.get(), 1, &fence);
} else {
dtable.vkWaitForFences(device.get(), 1, &fence, VK_TRUE, std::numeric_limits<uint64_t>::max());
dtable.vkResetFences(device.get(), 1, &fence);

VkPipelineStageFlags wait_stages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
VkSubmitInfo wait_desc{
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.pNext = nullptr,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &image_ready_semaphores[acquire_index],
.pWaitDstStageMask = &wait_stages,
};
dtable.vkQueueSubmit(graphics_queue, 1, &wait_desc, fence);
dtable.vkWaitForFences(device.get(), 1, &fence, VK_TRUE, std::numeric_limits<uint64_t>::max());
dtable.vkResetFences(device.get(), 1, &fence);
}

VkSurfaceCapabilitiesKHR caps{};
itable.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(adapter, surface.get(), &caps);

width = std::clamp(width, caps.minImageExtent.width, caps.maxImageExtent.width);
height = std::clamp(height, caps.minImageExtent.height, caps.maxImageExtent.height);
stereo = stereo_requested && caps.maxImageArrayLayers > 1;

VkSwapchainKHR old_swapchain = swapchain;
VkSwapchainCreateInfoKHR desc{
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
.pNext = nullptr,
.flags = 0,
.surface = surface.get(),
.minImageCount = back_buffer_count,
.imageFormat = format.format,
.imageColorSpace = format.colorSpace,
.imageExtent = { width, height },
.imageArrayLayers = stereo ? 2u : 1u,
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
.presentMode = present_mode,
.clipped = VK_TRUE,
.oldSwapchain = old_swapchain,
};

auto result = dtable.vkCreateSwapchainKHR(device.get(), &desc, nullptr, &swapchain);
if (!succeeded(result)) {
return wis::make_result<FUNC, "vkCreateSwapchainKHR failed">(result);
}

dtable.vkDestroySwapchainKHR(device.get(), old_swapchain, nullptr);

auto rres = InitBackBuffers(desc.imageExtent);
if (rres.status != wis::Status::Ok)
return rres;

return AquireNextIndex();
return VKRecreateSwapchain(width, height, nullptr);
}

wis::Result wis::ImplVKSwapChain::Present() const noexcept
Expand All @@ -321,16 +237,9 @@ wis::Result wis::ImplVKSwapChain::Present() const noexcept
.pPresentIds = &this->present_id,
};

VkSwapchainPresentFenceInfoEXT present_fence{
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT,
.pNext = dtable.vkWaitForPresentKHR ? &present_id : nullptr,
.swapchainCount = 1,
.pFences = &fence.handle
};

VkPresentInfoKHR present_info{
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
.pNext = supported_presentations ? &present_fence : present_fence.pNext,
.pNext = dtable.vkWaitForPresentKHR ? &present_id : nullptr,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &present_semaphores[present_index],
.swapchainCount = 1,
Expand Down Expand Up @@ -404,16 +313,9 @@ wis::Result wis::ImplVKSwapChain::Present2(bool in_vsync) const noexcept
.pPresentIds = &this->present_id,
};

VkSwapchainPresentFenceInfoEXT present_fence{
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT,
.pNext = dtable.vkWaitForPresentKHR ? &present_id : nullptr,
.swapchainCount = 1,
.pFences = &fence.handle
};

VkSwapchainPresentModeInfoEXT present_mode_info{
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT,
.pNext = &present_fence,
.pNext = &dtable.vkWaitForPresentKHR ? &present_id : nullptr,
.swapchainCount = 1,
.pPresentModes = &new_present_mode,
};
Expand Down Expand Up @@ -457,4 +359,70 @@ wis::ImplVKSwapChain::WaitForPresent(uint64_t timeout_ns) const noexcept
return wis::succeeded(res) ? wis::success : wis::make_result<FUNC, "vkWaitForPresentKHR failed">(res);
}

wis::Result
wis::ImplVKSwapChain::VKRecreateSwapchain(uint32_t width, uint32_t height, void* pNext) noexcept
{
auto& dtable = device.table();
auto& itable = surface.header().parent.table();

VkPipelineStageFlags wait_stages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;

VkSubmitInfo wait_desc{
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.pNext = nullptr,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &image_ready_semaphores[acquire_index],
.pWaitDstStageMask = &wait_stages,
};
dtable.vkQueueSubmit(graphics_queue, 1, &wait_desc, fence);
dtable.vkWaitForFences(device.get(), 1, &fence, VK_TRUE, std::numeric_limits<uint64_t>::max());
dtable.vkResetFences(device.get(), 1, &fence);

dtable.vkQueueSubmit(present_queue, 0, nullptr, fence);
dtable.vkWaitForFences(device.get(), 1, &fence, VK_TRUE, std::numeric_limits<uint64_t>::max());
dtable.vkResetFences(device.get(), 1, &fence);

VkSurfaceCapabilitiesKHR caps{};
itable.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(adapter, surface.get(), &caps);

width = std::clamp(width, caps.minImageExtent.width, caps.maxImageExtent.width);
height = std::clamp(height, caps.minImageExtent.height, caps.maxImageExtent.height);
stereo = stereo_requested && caps.maxImageArrayLayers > 1;

VkSwapchainKHR old_swapchain = swapchain;
VkSwapchainCreateInfoKHR desc{
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
.pNext = pNext,
.flags = 0,
.surface = surface.get(),
.minImageCount = back_buffer_count,
.imageFormat = format.format,
.imageColorSpace = format.colorSpace,
.imageExtent = { width, height },
.imageArrayLayers = stereo ? 2u : 1u,
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
.presentMode = present_mode,
.clipped = VK_TRUE,
.oldSwapchain = old_swapchain,
};

auto result = dtable.vkCreateSwapchainKHR(device.get(), &desc, nullptr, &swapchain);
if (!succeeded(result)) {
return wis::make_result<FUNC, "vkCreateSwapchainKHR failed">(result);
}

dtable.vkDestroySwapchainKHR(device.get(), old_swapchain, nullptr);

auto rres = InitBackBuffers(desc.imageExtent);
if (rres.status != wis::Status::Ok)
return rres;

return AquireNextIndex();
}

#endif // VK_SWAPCHAIN_H
2 changes: 1 addition & 1 deletion wisdom/include/wisdom/vulkan/vk_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ class ImplVKDevice : public QueryInternal<VKDevice>

public:
[[nodiscard]] WIS_INLINE wis::ResultValue<wis::VKSwapChain>
VKCreateSwapChain(wis::SharedSurface surface, const SwapchainDesc* desc, VkQueue graphics_queue) const noexcept;
VKCreateSwapChain(wis::SharedSurface surface, const SwapchainDesc* desc, VkQueue graphics_queue, void* pNext = nullptr) const noexcept;

private:
[[nodiscard]] WIS_INLINE wis::ResultValue<wis::shared_handle<VmaAllocator>>
Expand Down
3 changes: 3 additions & 0 deletions wisdom/include/wisdom/vulkan/vk_swapchain.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ class ImplVKSwapChain : public QueryInternal<VKSwapChain>
return { back_buffers.get(), back_buffer_count };
}
[[nodiscard]] WIS_INLINE wis::Result WaitForPresent(uint64_t timeout_ns = std::numeric_limits<uint64_t>::max()) const noexcept;

public:
[[nodiscard]] WIS_INLINE wis::Result VKRecreateSwapchain(uint32_t width, uint32_t height, void* pNext) noexcept;
};

#pragma region VKSwapChain
Expand Down
1 change: 0 additions & 1 deletion wisdom/platform/windows/wisdom/wisdom_windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include <wisdom/wisdom_windows.h>
#include <wisdom/util/log_layer.h>
#include <wisdom/dx12/dx12_device.h>
#include <wisdom/util/log_layer.h>
#include <d3d11.h>

namespace wis::detail {
Expand Down

0 comments on commit 5a1120f

Please sign in to comment.