From 7c0d53684c638af98bece65edc7e744cae80806c Mon Sep 17 00:00:00 2001 From: ladevieq Date: Mon, 18 Jan 2021 22:56:18 +0100 Subject: Event logic & handle resize & close for xcb windows --- src/main.cpp | 22 +++++++++++++--- src/vk-renderer.cpp | 15 ++++++----- src/window.cpp | 75 +++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 88 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index 03db2ab..56e8d08 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -55,17 +55,31 @@ int main() { while(wnd.isOpen) { wnd.poll_events(); + for (auto event: wnd.events) { + switch(event.type) { + case EVENT_TYPES::RESIZE: { + renderer.recreate_swapchain(); + renderer.mapped_data->width = event.width; + renderer.mapped_data->height = event.height; + break; + } + case EVENT_TYPES::QUIT: { + exit(1); + } + default: { + } + } + } + + wnd.events.clear(); + // To start a frame capture, call StartFrameCapture. // You can specify NULL, NULL for the device to capture on if you have only one device and // either no windows at all or only one window, and it will capture from that device. // See the documentation below for a longer explanation if(rdoc_api) rdoc_api->StartFrameCapture(NULL, NULL); - auto start = std::chrono::high_resolution_clock::now(); renderer.compute(); - auto end = std::chrono::high_resolution_clock::now(); - - std::cerr << "Image generation took " << std::chrono::duration_cast(end - start).count() << "ms" << std::endl; // stop the capture if(rdoc_api) rdoc_api->EndFrameCapture(NULL, NULL); diff --git a/src/vk-renderer.cpp b/src/vk-renderer.cpp index d5511a9..e2e171e 100644 --- a/src/vk-renderer.cpp +++ b/src/vk-renderer.cpp @@ -155,9 +155,7 @@ void vkrenderer::compute() { void vkrenderer::recreate_swapchain() { VKRESULT(vkWaitForFences(device, 1, &submission_fences[frame_index], VK_TRUE, UINT64_MAX)) - destroy_swapchain(); - - create_surface(); + destroy_swapchain_images(); create_swapchain(); @@ -309,6 +307,8 @@ void vkrenderer::create_swapchain() { surface_format = supported_formats[0]; + VkSwapchainKHR old_swapchain = swapchain; + VkSwapchainCreateInfoKHR create_info = {}; create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; create_info.pNext = nullptr; @@ -325,10 +325,13 @@ void vkrenderer::create_swapchain() { create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; create_info.presentMode = VK_PRESENT_MODE_FIFO_KHR; create_info.clipped = VK_TRUE; - create_info.oldSwapchain = swapchain; + create_info.oldSwapchain = old_swapchain; VKRESULT(vkCreateSwapchainKHR(device, &create_info, nullptr, &swapchain)) + if (old_swapchain != VK_NULL_HANDLE) { + vkDestroySwapchainKHR(device, old_swapchain, nullptr); + } swapchain_images_count = 0; VKRESULT(vkGetSwapchainImagesKHR(device, swapchain, (uint32_t*)&swapchain_images_count, VK_NULL_HANDLE)) @@ -560,7 +563,7 @@ void vkrenderer::create_input_buffer(const input_data& inputs) { } -void vkrenderer::destroy_swapchain() { +void vkrenderer::destroy_swapchain_images() { if (swapchain != VK_NULL_HANDLE) { for (auto view: swapchain_images_views) { vkDestroyImageView(device, view, nullptr); @@ -568,8 +571,6 @@ void vkrenderer::destroy_swapchain() { swapchain_images_views.clear(); swapchain_images.clear(); - - vkDestroySwapchainKHR(device, swapchain, nullptr); } } diff --git a/src/window.cpp b/src/window.cpp index 7662295..d1d2f4f 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -11,6 +11,9 @@ window::window(uint32_t width, uint32_t height) auto setup = xcb_get_setup (connection); auto screen_info = xcb_setup_roots_iterator(setup).data; + xcb_event_mask_t events[] = { + XCB_EVENT_MASK_STRUCTURE_NOTIFY, + }; xcb_create_window( connection, XCB_COPY_FROM_PARENT, @@ -23,8 +26,29 @@ window::window(uint32_t width, uint32_t height) 10, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen_info->root_visual, - 0, - nullptr + XCB_CW_EVENT_MASK, + events + ); + + // Ask for WM_PROTOCOLS atom + auto protocols_id = xcb_intern_atom(connection, true, 12, "WM_PROTOCOLS"); + auto protocols_atom = xcb_intern_atom_reply(connection, protocols_id, NULL)->atom; + + // Ask for WM_DELETE_WINDOW atom + auto win_delete_id = xcb_intern_atom(connection, false, 16, "WM_DELETE_WINDOW"); + win_delete_atom = xcb_intern_atom_reply(connection, win_delete_id, NULL)->atom; + + // Allow the window to receive win close events + // https://lists.freedesktop.org/archives/xcb/2010-December/006713.html + xcb_change_property( + connection, + XCB_PROP_MODE_REPLACE, + win, + protocols_atom, + 4, // Predefined value for atom type + 32, + 1, + &win_delete_atom ); xcb_map_window(connection, win); @@ -32,6 +56,41 @@ window::window(uint32_t width, uint32_t height) isOpen = true; } + +void window::poll_events() { + xcb_generic_event_t *event; + while((event = xcb_poll_for_event (connection))) { + switch(event->response_type & ~0x80) { + case XCB_CONFIGURE_NOTIFY: { + auto notify_event = (xcb_configure_notify_event_t*)event; + + if (width != notify_event->width || height != notify_event->height) { + events.push_back({ + .width = notify_event->width, + .height = notify_event->height, + .type = EVENT_TYPES::RESIZE + }); + + width = notify_event->width; + height = notify_event->height; + } + + break; + } + case XCB_CLIENT_MESSAGE: { + auto client_message_event = (xcb_client_message_event_t*)event; + if (client_message_event->data.data32[0] == win_delete_atom) { + events.push_back({ .type = EVENT_TYPES::QUIT }); + } + } + default: { + } + } + + free(event); + } +} + #elif defined(WINDOWS) LRESULT CALLBACK window::window_procedure(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam) { window* win = nullptr; @@ -102,17 +161,7 @@ LRESULT window::message_handler(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lpar break; } case WM_SIZE: { - RECT rect; - if(GetWindowRect(hwnd, &rect)) - { - width = rect.right - rect.left; - height = rect.bottom - rect.top; - } - - if (renderer != nullptr) { - renderer->recreate_swapchain(); - break; - } + event.push_back({ EVENT_TYPES::RESIZE }); } default: return DefWindowProc(hwnd, umsg, wparam, lparam); -- cgit v1.3