TEMP: Try to use 2 locks for swapchain resizing example

This commit is contained in:
Charles Giessen 2021-07-03 14:32:54 -06:00
parent 4a30810a87
commit 0b7529d0da
3 changed files with 140 additions and 90 deletions

View File

@ -22,10 +22,11 @@ std::atomic_bool should_resize;
uint32_t current_width = default_window_width;
uint32_t current_height = default_window_height;
std::mutex main_mutex;
std::mutex swapchain_mutex;
std::mutex render_mutex;
std::mutex render_wait_mutex;
std::condition_variable render_wait_condition_variable;
std::mutex render_thread_sleep_mutex;
std::condition_variable render_thread_sleep_condition_variable;
const bool run_multithreaded = true;
const bool use_refresh_callback = true;
@ -46,6 +47,8 @@ struct Renderer {
vkb::SwapchainManager swapchain_manager;
vkb::SwapchainInfo swap_info;
// where to place the new framebuffer when a resize event happens
VkFramebuffer new_framebuffer = VK_NULL_HANDLE;
vkb::DeletionQueue delete_queue;
@ -73,7 +76,7 @@ void unlock(std::mutex& mutex) {
}
int recreate_swapchain(Renderer& renderer);
int draw_frame(Renderer& renderer);
int draw_frame(Renderer& renderer, bool try_lock);
void glfw_resize_callback(GLFWwindow* window, int width, int height) {
if (!is_running || width == 0 || height == 0) {
@ -82,8 +85,6 @@ void glfw_resize_callback(GLFWwindow* window, int width, int height) {
should_resize = true;
current_width = width;
current_height = height;
std::lock_guard<std::mutex> lg(main_mutex);
Renderer* renderer = reinterpret_cast<Renderer*>(glfwGetWindowUserPointer(window));
int res = recreate_swapchain(*renderer);
if (res < 0) {
@ -91,23 +92,23 @@ void glfw_resize_callback(GLFWwindow* window, int width, int height) {
return;
}
if (!use_refresh_callback) {
res = draw_frame(*renderer);
res = draw_frame(*renderer, false);
if (res < 0) {
is_running = false;
}
}
should_resize = false;
render_wait_condition_variable.notify_one();
render_thread_sleep_condition_variable.notify_one();
}
void glfw_refresh_callback(GLFWwindow* window) {
if (try_lock(main_mutex)) {
Renderer* renderer = reinterpret_cast<Renderer*>(glfwGetWindowUserPointer(window));
int res = draw_frame(*renderer);
if (res < 0) {
is_running = false;
}
unlock(main_mutex);
// if (try_lock(render_mutex)) {
Renderer* renderer = reinterpret_cast<Renderer*>(glfwGetWindowUserPointer(window));
int res = draw_frame(*renderer, true);
if (res < 0) {
is_running = false;
}
// unlock(render_mutex);
//}
}
inline VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
@ -240,15 +241,14 @@ int create_render_pass(Renderer& renderer) {
return 0;
}
int create_framebuffer(Renderer& renderer) {
int create_framebuffer(Renderer& renderer, VkFramebuffer& output) {
vkb::ImagelessFramebufferBuilder if_builder(renderer.device);
renderer.framebuffer =
if_builder.set_renderpass(renderer.render_pass)
.set_extent(renderer.swap_info.extent)
.set_layers(1)
.add_attachment(renderer.swap_info.image_usage_flags, renderer.swap_info.image_format)
.build();
output = if_builder.set_renderpass(renderer.render_pass)
.set_extent(renderer.swap_info.extent)
.set_layers(1)
.add_attachment(renderer.swap_info.image_usage_flags, renderer.swap_info.image_format)
.build();
return 0;
}
@ -507,41 +507,59 @@ int record_command_buffer(Renderer& renderer, VkCommandBuffer command_buffer, Vk
}
int recreate_swapchain(Renderer& renderer) {
renderer.delete_queue.add_framebuffer(renderer.framebuffer);
renderer.framebuffer = VK_NULL_HANDLE;
std::lock_guard<std::mutex> lg(swapchain_mutex);
auto ret = renderer.swapchain_manager.recreate();
if (!ret) {
std::cout << "failed to recreate swapchain\n";
return -1;
}
renderer.swap_info = ret.value();
if (0 != create_framebuffer(renderer)) return -1;
if (renderer.new_framebuffer != VK_NULL_HANDLE) {
renderer.delete_queue.add_framebuffer(renderer.new_framebuffer);
}
if (0 != create_framebuffer(renderer, renderer.new_framebuffer)) return -1;
return 0;
}
int draw_frame(Renderer& renderer) {
vkb::SwapchainAcquireInfo acquire_info;
auto acquire_ret = renderer.swapchain_manager.acquire_image();
if (acquire_ret.matches_error(vkb::SwapchainManagerError::swapchain_out_of_date)) {
return 1;
} else if (!acquire_ret.has_value()) {
std::cout << "failed to acquire swapchain image\n";
return -1;
int draw_frame(Renderer& renderer, bool try_lock) {
std::unique_lock<std::mutex> lg(render_mutex, std::try_to_lock);
if (!try_lock && !lg.owns_lock()) {
lg.lock();
} else if (!lg.owns_lock()) {
return 0;
}
vkb::SwapchainAcquireInfo acquire_info;
{
std::lock_guard<std::mutex> slg(swapchain_mutex);
// swap old framebuffer with new one now that both locks are held
if (renderer.new_framebuffer != VK_NULL_HANDLE) {
renderer.delete_queue.add_framebuffer(renderer.framebuffer);
renderer.framebuffer = renderer.new_framebuffer;
renderer.new_framebuffer = VK_NULL_HANDLE;
}
acquire_info = acquire_ret.value();
if (should_resize) return 1;
auto acquire_ret = renderer.swapchain_manager.acquire_image();
if (acquire_ret.matches_error(vkb::SwapchainManagerError::swapchain_out_of_date)) {
return 1;
} else if (!acquire_ret.has_value()) {
std::cout << "failed to acquire swapchain image\n";
return -1;
}
acquire_info = acquire_ret.value();
}
if (should_resize) {
renderer.swapchain_manager.cancel_acquire_frame();
return 1;
}
renderer.dispatch.waitForFences(1, &renderer.fences[renderer.current_index], VK_TRUE, UINT64_MAX);
renderer.dispatch.resetFences(1, &renderer.fences[renderer.current_index]);
record_command_buffer(renderer, renderer.command_buffers[renderer.current_index], acquire_info.image_view);
auto semaphores = renderer.swapchain_manager.get_submit_semaphores().value();
VkSemaphore wait_semaphores[1] = { semaphores.wait };
VkSemaphore signal_semaphores[1] = { semaphores.signal };
VkSemaphore wait_semaphores[1] = { acquire_info.wait_semaphore };
VkSemaphore signal_semaphores[1] = { acquire_info.signal_semaphore };
VkPipelineStageFlags wait_stages[1] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
VkSubmitInfo submit_info = {};
@ -554,21 +572,31 @@ int draw_frame(Renderer& renderer) {
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = signal_semaphores;
if (renderer.dispatch.queueSubmit(
renderer.graphics_queue, 1, &submit_info, renderer.fences[renderer.current_index]) != VK_SUCCESS) {
std::cout << "failed to submit command buffer\n";
VkResult res = renderer.dispatch.queueSubmit(
renderer.graphics_queue, 1, &submit_info, renderer.fences[renderer.current_index]);
if (res != VK_SUCCESS) {
std::cout << "failed to submit command buffer" << res << "\n";
return -1;
}
renderer.current_index = (renderer.current_index + 1) % MAX_FRAMES_IN_FLIGHT;
if (should_resize) return 1;
auto present_ret = renderer.swapchain_manager.present();
if (present_ret.matches_error(vkb::SwapchainManagerError::swapchain_out_of_date)) {
if (should_resize) {
renderer.swapchain_manager.cancel_present_frame();
return 1;
} else if (!present_ret) {
std::cout << "failed to present swapchain image\n";
return -1;
}
{
std::lock_guard<std::mutex> slg(swapchain_mutex);
if (!renderer.swapchain_manager.able_to_present()) {
renderer.swapchain_manager.cancel_present_frame();
return 0;
}
auto present_ret = renderer.swapchain_manager.present();
if (present_ret.matches_error(vkb::SwapchainManagerError::swapchain_out_of_date)) {
return 1;
} else if (!present_ret) {
std::cout << "failed to present swapchain image " << present_ret.error().message() << "\n";
return -1;
}
}
renderer.delete_queue.tick();
renderer.current_time = glfwGetTime();
@ -600,21 +628,14 @@ void cleanup(Renderer& renderer) {
void render_loop(Renderer* renderer) {
while (is_running) {
std::unique_lock<std::mutex> lg(main_mutex, std::try_to_lock);
if (!lg.owns_lock()) {
std::unique_lock<std::mutex> ulg(render_wait_mutex);
render_wait_condition_variable.wait(ulg);
continue;
} else {
int res = draw_frame(*renderer);
if (res < 0) {
is_running = false;
}
if (res == 1) {
lg.unlock();
std::unique_lock<std::mutex> ulg(render_wait_mutex);
render_wait_condition_variable.wait(ulg);
}
int res = draw_frame(*renderer, true);
if (res < 0) {
is_running = false;
break;
}
if (res == 1) {
std::unique_lock<std::mutex> ulg(render_thread_sleep_mutex);
render_thread_sleep_condition_variable.wait(ulg);
}
}
}
@ -628,25 +649,24 @@ int main() {
if (0 != device_initialization(renderer)) return -1;
if (0 != get_queues(renderer)) return -1;
if (0 != create_render_pass(renderer)) return -1;
if (0 != create_framebuffer(renderer)) return -1;
if (0 != create_framebuffer(renderer, renderer.framebuffer)) return -1;
if (0 != create_graphics_pipeline(renderer)) return -1;
if (0 != create_command_buffers(renderer)) return -1;
is_running = true;
renderer.current_time = glfwGetTime();
if (run_multithreaded) {
std::thread render_thread{ render_loop, &renderer };
while (!glfwWindowShouldClose(renderer.window) && is_running) {
glfwPollEvents();
glfwWaitEvents();
}
is_running = false;
render_wait_condition_variable.notify_one();
render_thread_sleep_condition_variable.notify_one();
render_thread.join();
} else {
while (!glfwWindowShouldClose(renderer.window) && is_running) {
glfwPollEvents();
int res = draw_frame(renderer);
int res = draw_frame(renderer, false);
if (res < 0) {
is_running = false;
}

View File

@ -2299,6 +2299,8 @@ SwapchainManager::SwapchainManager(SwapchainBuilder const& builder,
detail::vulkan_functions().get_device_proc_addr(device, detail.fp_vkGetDeviceQueue, "vkGetDeviceQueue");
detail::vulkan_functions().get_device_proc_addr(device, detail.fp_vkAcquireNextImageKHR, "vkAcquireNextImageKHR");
detail::vulkan_functions().get_device_proc_addr(device, detail.fp_vkQueuePresentKHR, "vkQueuePresentKHR");
detail::vulkan_functions().get_device_proc_addr(device, detail.fp_vkQueueSubmit, "vkQueueSubmit");
detail.fp_vkGetSwapchainImagesKHR = fp_vkGetSwapchainImagesKHR;
detail.fp_vkCreateImageView = fp_vkCreateImageView;
detail.fp_vkGetDeviceQueue(device, detail.builder.info.graphics_queue_index, 0, &detail.graphics_queue);
@ -2387,21 +2389,15 @@ detail::Result<SwapchainAcquireInfo> SwapchainManager::acquire_image() noexcept
SwapchainAcquireInfo out{};
out.image_view = detail.swapchain_resources.image_views[detail.current_image_index];
out.image_index = detail.current_image_index;
out.wait_semaphore = detail.semaphore_manager.get_acquire_semaphore();
out.signal_semaphore = detail.semaphore_manager.get_submit_semaphore();
detail.current_acquire_semaphore = out.wait_semaphore;
detail.current_present_semaphore = out.signal_semaphore;
return out;
}
detail::Result<SwapchainSubmitSemaphores> SwapchainManager::get_submit_semaphores() noexcept {
assert(detail.current_status != Status::destroyed && "SwapchainManager was destroyed!");
if (detail.current_status == Status::expired) {
return make_error_code(SwapchainManagerError::swapchain_out_of_date);
}
if (detail.current_status == Status::ready_to_acquire) {
return make_error_code(SwapchainManagerError::must_call_acquire_image_first);
}
SwapchainSubmitSemaphores semaphores;
semaphores.signal = detail.semaphore_manager.get_submit_semaphore();
semaphores.wait = detail.semaphore_manager.get_acquire_semaphore();
return semaphores;
bool SwapchainManager::able_to_present() noexcept {
return detail.current_status == Status::ready_to_present;
}
detail::Result<detail::void_t> SwapchainManager::present() noexcept {
@ -2413,7 +2409,9 @@ detail::Result<detail::void_t> SwapchainManager::present() noexcept {
return make_error_code(SwapchainManagerError::must_call_acquire_image_first);
}
VkSemaphore wait_semaphores[1] = { detail.semaphore_manager.get_submit_semaphore() };
VkSemaphore wait_semaphores[1] = { detail.current_present_semaphore };
detail.current_acquire_semaphore = VK_NULL_HANDLE;
detail.current_present_semaphore = VK_NULL_HANDLE;
VkPresentInfoKHR present_info = {};
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
@ -2437,13 +2435,43 @@ detail::Result<detail::void_t> SwapchainManager::present() noexcept {
} else {
detail.current_status = Status::ready_to_acquire;
}
// clean up old swapchain resources
detail.delete_queue.tick();
return detail::void_t{};
}
void SwapchainManager::cancel_acquire_frame() noexcept {
VkPipelineStageFlags wait_stages[1] = { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT };
VkSubmitInfo submit_info = {};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &detail.current_acquire_semaphore;
submit_info.pWaitDstStageMask = wait_stages;
VkResult res = detail.fp_vkQueueSubmit(detail.graphics_queue, 1, &submit_info, VK_NULL_HANDLE);
assert(res == VK_SUCCESS);
detail.current_acquire_semaphore = VK_NULL_HANDLE;
detail.current_present_semaphore = VK_NULL_HANDLE;
}
void SwapchainManager::cancel_present_frame() noexcept {
VkPipelineStageFlags wait_stages[1] = { VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT };
VkSubmitInfo submit_info = {};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &detail.current_present_semaphore;
submit_info.pWaitDstStageMask = wait_stages;
VkResult res = detail.fp_vkQueueSubmit(detail.graphics_queue, 1, &submit_info, VK_NULL_HANDLE);
assert(res == VK_SUCCESS);
detail.current_acquire_semaphore = VK_NULL_HANDLE;
detail.current_present_semaphore = VK_NULL_HANDLE;
}
detail::Result<SwapchainInfo> SwapchainManager::recreate(uint32_t width, uint32_t height) noexcept {
assert(detail.current_status != Status::destroyed && "SwapchainManager was destroyed!");

View File

@ -978,11 +978,8 @@ struct SwapchainAcquireInfo {
VkImageView image_view{};
// index of the swapchain image to use this frame
uint32_t image_index = detail::INDEX_MAX_VALUE;
};
struct SwapchainSubmitSemaphores {
VkSemaphore signal;
VkSemaphore wait;
VkSemaphore signal_semaphore;
VkSemaphore wait_semaphore;
};
/**
@ -1098,10 +1095,12 @@ class SwapchainManager {
// Get a VkImageView handle to use in rendering
detail::Result<SwapchainAcquireInfo> acquire_image() noexcept;
detail::Result<SwapchainSubmitSemaphores> get_submit_semaphores() noexcept;
bool able_to_present() noexcept;
detail::Result<detail::void_t> present() noexcept;
void cancel_acquire_frame() noexcept;
void cancel_present_frame() noexcept;
// Recreate the swapchain, putting currently in-use internal resources in a delete queue
detail::Result<SwapchainInfo> recreate(uint32_t width = 0, uint32_t height = 0) noexcept;
@ -1138,6 +1137,9 @@ class SwapchainManager {
PFN_vkQueuePresentKHR fp_vkQueuePresentKHR;
PFN_vkGetSwapchainImagesKHR fp_vkGetSwapchainImagesKHR;
PFN_vkCreateImageView fp_vkCreateImageView;
PFN_vkQueueSubmit fp_vkQueueSubmit;
VkSemaphore current_acquire_semaphore;
VkSemaphore current_present_semaphore;
} detail;
explicit SwapchainManager(SwapchainBuilder const& builder,