From 55de73a963d8f58b52f6d32f065debbddec8889f Mon Sep 17 00:00:00 2001 From: Ozan Yasin Dogan Date: Sun, 9 Aug 2026 00:17:12 +0300 Subject: [PATCH 1/3] Fix segfault on window close: let GLFW outlive the Vulkan objects `cleanup()` called `glfwDestroyWindow()` and `glfwTerminate()` while every `vk::raii` member was still alive. Those members belong to the application class, so they are destroyed only after `run()` returns - that is, after GLFW has already torn down the window system connection they still reference. `vkDestroySwapchainKHR` then marshals a request on freed Wayland proxies and the process dies during exit: #12 HelloTriangleApplication::~HelloTriangleApplication() #11 vk::raii::SwapchainKHR::~SwapchainKHR() #10 vk::raii::SwapchainKHR::clear() #4 libnvidia-glcore.so #3 wl_proxy_marshal_flags #0 libwayland-client.so.0 <- SEGV_MAPERR The pre-RAII tutorial destroyed every Vulkan object by hand at the end of `cleanup()`, so `glfwTerminate()` genuinely ran last. Converting to `vk::raii` removed those explicit calls but left the two GLFW calls behind, silently inverting the order. Ownership of the GLFW lifetime now belongs to a `GlfwGuard` member declared first in the class. Members are destroyed in reverse declaration order, so being first means it is destroyed last - after every Vulkan object, however many later chapters add. `glfwTerminate()` also destroys any windows still open, so the separate `glfwDestroyWindow()` call is no longer needed. Applied to all 34 affected chapters, plus 00_base_code so the pattern is correct from the very first chapter and never has to change again - which is what the Base Code chapter already promises the reader. Verified on Arch Linux / Wayland / KWin, NVIDIA 610.43.03, Vulkan 1.4.357: - all 304 build targets compile - 22 chapters that present a frame: launched and closed with a real compositor close request, all exit 0 (each exited 139 before) - 14_command_buffers (never presents, so its surface is never mapped and it cannot be closed by the compositor) checked by breaking out of the main loop instead: 3/3 SIGSEGV before, 3/3 clean after - no validation layer errors, and no coredumps from any fixed binary Refs: #138 --- attachments/00_base_code.cpp | 18 ++++++-- attachments/01_instance_creation.cpp | 18 ++++++-- attachments/02_validation_layers.cpp | 18 ++++++-- attachments/03_physical_device_selection.cpp | 18 ++++++-- attachments/04_logical_device.cpp | 18 ++++++-- attachments/05_window_surface.cpp | 18 ++++++-- attachments/06_swap_chain_creation.cpp | 18 ++++++-- attachments/07_image_views.cpp | 18 ++++++-- attachments/08_graphics_pipeline.cpp | 18 ++++++-- attachments/09_shader_modules.cpp | 18 ++++++-- attachments/10_fixed_functions.cpp | 18 ++++++-- attachments/12_graphics_pipeline_complete.cpp | 18 ++++++-- attachments/14_command_buffers.cpp | 18 ++++++-- attachments/15_hello_triangle.cpp | 18 ++++++-- attachments/16_frames_in_flight.cpp | 18 ++++++-- attachments/17_swap_chain_recreation.cpp | 18 ++++++-- attachments/19_vertex_buffer.cpp | 18 ++++++-- attachments/20_staging_buffer.cpp | 18 ++++++-- attachments/21_index_buffer.cpp | 18 ++++++-- attachments/22_descriptor_layout.cpp | 18 ++++++-- attachments/23_descriptor_sets.cpp | 18 ++++++-- attachments/24_texture_image.cpp | 18 ++++++-- attachments/25_sampler.cpp | 18 ++++++-- attachments/26_texture_mapping.cpp | 18 ++++++-- attachments/27_depth_buffering.cpp | 18 ++++++-- attachments/28_model_loading.cpp | 18 ++++++-- attachments/29_mipmapping.cpp | 18 ++++++-- attachments/30_multisampling.cpp | 18 ++++++-- attachments/31_compute_shader.cpp | 15 +++++-- attachments/32_ecosystem_utilities.cpp | 14 ++++++- attachments/33_vulkan_profiles.cpp | 17 +++++++- attachments/35_gltf_ktx.cpp | 14 ++++++- attachments/36_multiple_objects.cpp | 16 ++++++-- attachments/37_multithreading.cpp | 15 +++++-- attachments/38_ray_tracing.cpp | 15 +++++-- .../00_Setup/00_Base_code.adoc | 41 +++++++++++++++---- .../04_Swap_chain_recreation.adoc | 6 +-- 37 files changed, 544 insertions(+), 113 deletions(-) diff --git a/attachments/00_base_code.cpp b/attachments/00_base_code.cpp index 3b685670d..6cbc61408 100644 --- a/attachments/00_base_code.cpp +++ b/attachments/00_base_code.cpp @@ -25,6 +25,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every member below. Later + // chapters add Vulkan objects here that still reference the window system + // connection while they are destroyed, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; void initWindow() @@ -51,9 +63,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every other + // member. Terminating GLFW here would free the window system connection + // while later chapters' Vulkan objects are still alive. } }; diff --git a/attachments/01_instance_creation.cpp b/attachments/01_instance_creation.cpp index 4686f1b66..91743a3b0 100644 --- a/attachments/01_instance_creation.cpp +++ b/attachments/01_instance_creation.cpp @@ -28,6 +28,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; @@ -58,9 +70,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void createInstance() diff --git a/attachments/02_validation_layers.cpp b/attachments/02_validation_layers.cpp index 2d5ea7f80..6aa47b08e 100644 --- a/attachments/02_validation_layers.cpp +++ b/attachments/02_validation_layers.cpp @@ -39,6 +39,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; @@ -71,9 +83,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void createInstance() diff --git a/attachments/03_physical_device_selection.cpp b/attachments/03_physical_device_selection.cpp index 2fa960441..58d15c911 100644 --- a/attachments/03_physical_device_selection.cpp +++ b/attachments/03_physical_device_selection.cpp @@ -39,6 +39,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; @@ -77,9 +89,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void createInstance() diff --git a/attachments/04_logical_device.cpp b/attachments/04_logical_device.cpp index a8c285a33..4c2d9b3de 100644 --- a/attachments/04_logical_device.cpp +++ b/attachments/04_logical_device.cpp @@ -40,6 +40,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; @@ -82,9 +94,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void createInstance() diff --git a/attachments/05_window_surface.cpp b/attachments/05_window_surface.cpp index bb7b4bee7..360b82c17 100644 --- a/attachments/05_window_surface.cpp +++ b/attachments/05_window_surface.cpp @@ -39,6 +39,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -80,9 +92,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void createInstance() diff --git a/attachments/06_swap_chain_creation.cpp b/attachments/06_swap_chain_creation.cpp index d6bb77244..811b51286 100644 --- a/attachments/06_swap_chain_creation.cpp +++ b/attachments/06_swap_chain_creation.cpp @@ -41,6 +41,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -88,9 +100,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void createInstance() diff --git a/attachments/07_image_views.cpp b/attachments/07_image_views.cpp index a6cb5c23b..a78abe612 100644 --- a/attachments/07_image_views.cpp +++ b/attachments/07_image_views.cpp @@ -41,6 +41,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -89,9 +101,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void createInstance() diff --git a/attachments/08_graphics_pipeline.cpp b/attachments/08_graphics_pipeline.cpp index 8705c2016..04eb1c0d8 100644 --- a/attachments/08_graphics_pipeline.cpp +++ b/attachments/08_graphics_pipeline.cpp @@ -41,6 +41,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -90,9 +102,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void createInstance() diff --git a/attachments/09_shader_modules.cpp b/attachments/09_shader_modules.cpp index 5e9ed2b4c..8a27fe319 100644 --- a/attachments/09_shader_modules.cpp +++ b/attachments/09_shader_modules.cpp @@ -42,6 +42,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -91,9 +103,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void createInstance() diff --git a/attachments/10_fixed_functions.cpp b/attachments/10_fixed_functions.cpp index 2998d3aee..6ca5afeba 100644 --- a/attachments/10_fixed_functions.cpp +++ b/attachments/10_fixed_functions.cpp @@ -42,6 +42,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -93,9 +105,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void createInstance() diff --git a/attachments/12_graphics_pipeline_complete.cpp b/attachments/12_graphics_pipeline_complete.cpp index c8d7a47db..12192a4ee 100644 --- a/attachments/12_graphics_pipeline_complete.cpp +++ b/attachments/12_graphics_pipeline_complete.cpp @@ -42,6 +42,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -94,9 +106,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void createInstance() diff --git a/attachments/14_command_buffers.cpp b/attachments/14_command_buffers.cpp index badf1d532..e201a6f85 100644 --- a/attachments/14_command_buffers.cpp +++ b/attachments/14_command_buffers.cpp @@ -42,6 +42,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -99,9 +111,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void createInstance() diff --git a/attachments/15_hello_triangle.cpp b/attachments/15_hello_triangle.cpp index 91f0e5c80..580ec2146 100644 --- a/attachments/15_hello_triangle.cpp +++ b/attachments/15_hello_triangle.cpp @@ -42,6 +42,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -107,9 +119,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void createInstance() diff --git a/attachments/16_frames_in_flight.cpp b/attachments/16_frames_in_flight.cpp index 189c11338..abde61ed2 100644 --- a/attachments/16_frames_in_flight.cpp +++ b/attachments/16_frames_in_flight.cpp @@ -43,6 +43,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -110,9 +122,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void createInstance() diff --git a/attachments/17_swap_chain_recreation.cpp b/attachments/17_swap_chain_recreation.cpp index fcd6df655..f5bc48bf5 100644 --- a/attachments/17_swap_chain_recreation.cpp +++ b/attachments/17_swap_chain_recreation.cpp @@ -43,6 +43,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -126,9 +138,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void recreateSwapChain() diff --git a/attachments/19_vertex_buffer.cpp b/attachments/19_vertex_buffer.cpp index 77721ad6d..94a73edb6 100644 --- a/attachments/19_vertex_buffer.cpp +++ b/attachments/19_vertex_buffer.cpp @@ -67,6 +67,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -154,9 +166,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void recreateSwapChain() diff --git a/attachments/20_staging_buffer.cpp b/attachments/20_staging_buffer.cpp index 64980f7f4..d1e4b5e4b 100644 --- a/attachments/20_staging_buffer.cpp +++ b/attachments/20_staging_buffer.cpp @@ -67,6 +67,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -154,9 +166,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void recreateSwapChain() diff --git a/attachments/21_index_buffer.cpp b/attachments/21_index_buffer.cpp index 957b735a4..d0d61c17e 100644 --- a/attachments/21_index_buffer.cpp +++ b/attachments/21_index_buffer.cpp @@ -71,6 +71,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -161,9 +173,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void recreateSwapChain() diff --git a/attachments/22_descriptor_layout.cpp b/attachments/22_descriptor_layout.cpp index 833553111..742e26cc3 100644 --- a/attachments/22_descriptor_layout.cpp +++ b/attachments/22_descriptor_layout.cpp @@ -82,6 +82,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -179,9 +191,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void recreateSwapChain() diff --git a/attachments/23_descriptor_sets.cpp b/attachments/23_descriptor_sets.cpp index 881abc5c4..73d0df825 100644 --- a/attachments/23_descriptor_sets.cpp +++ b/attachments/23_descriptor_sets.cpp @@ -82,6 +82,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -184,9 +196,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void recreateSwapChain() diff --git a/attachments/24_texture_image.cpp b/attachments/24_texture_image.cpp index b8d61315d..846f90e5d 100644 --- a/attachments/24_texture_image.cpp +++ b/attachments/24_texture_image.cpp @@ -85,6 +85,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -191,9 +203,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void recreateSwapChain() diff --git a/attachments/25_sampler.cpp b/attachments/25_sampler.cpp index 0608f1727..2e16b966d 100644 --- a/attachments/25_sampler.cpp +++ b/attachments/25_sampler.cpp @@ -85,6 +85,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -195,9 +207,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void recreateSwapChain() diff --git a/attachments/26_texture_mapping.cpp b/attachments/26_texture_mapping.cpp index 268111919..f7b0a46be 100644 --- a/attachments/26_texture_mapping.cpp +++ b/attachments/26_texture_mapping.cpp @@ -86,6 +86,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -196,9 +208,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void recreateSwapChain() diff --git a/attachments/27_depth_buffering.cpp b/attachments/27_depth_buffering.cpp index dfb24250e..c4cbbc0f9 100644 --- a/attachments/27_depth_buffering.cpp +++ b/attachments/27_depth_buffering.cpp @@ -94,6 +94,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -211,9 +223,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void recreateSwapChain() diff --git a/attachments/28_model_loading.cpp b/attachments/28_model_loading.cpp index fe4ada523..635914207 100644 --- a/attachments/28_model_loading.cpp +++ b/attachments/28_model_loading.cpp @@ -100,6 +100,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -218,9 +230,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void recreateSwapChain() diff --git a/attachments/29_mipmapping.cpp b/attachments/29_mipmapping.cpp index d80a73cb1..849de674d 100644 --- a/attachments/29_mipmapping.cpp +++ b/attachments/29_mipmapping.cpp @@ -100,6 +100,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -219,9 +231,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void recreateSwapChain() diff --git a/attachments/30_multisampling.cpp b/attachments/30_multisampling.cpp index 9a312fa2b..6698f903d 100644 --- a/attachments/30_multisampling.cpp +++ b/attachments/30_multisampling.cpp @@ -100,6 +100,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -225,9 +237,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void recreateSwapChain() diff --git a/attachments/31_compute_shader.cpp b/attachments/31_compute_shader.cpp index 67ffe9435..90e3a17e3 100644 --- a/attachments/31_compute_shader.cpp +++ b/attachments/31_compute_shader.cpp @@ -79,6 +79,18 @@ class ComputeShaderApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -194,9 +206,6 @@ class ComputeShaderApplication void cleanup() const { - glfwDestroyWindow(window); - - glfwTerminate(); } void recreateSwapChain() diff --git a/attachments/32_ecosystem_utilities.cpp b/attachments/32_ecosystem_utilities.cpp index a0a4c2d2f..3a7a3c474 100644 --- a/attachments/32_ecosystem_utilities.cpp +++ b/attachments/32_ecosystem_utilities.cpp @@ -106,6 +106,18 @@ class HelloTriangleApplication private: AppInfo appInfo; + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -254,8 +266,6 @@ class HelloTriangleApplication void cleanup() const { - glfwDestroyWindow(window); - glfwTerminate(); } void recreateSwapChain() diff --git a/attachments/33_vulkan_profiles.cpp b/attachments/33_vulkan_profiles.cpp index 4b1268e57..0835a1d56 100644 --- a/attachments/33_vulkan_profiles.cpp +++ b/attachments/33_vulkan_profiles.cpp @@ -103,6 +103,18 @@ class HelloTriangleApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -255,8 +267,9 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - glfwTerminate(); + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void recreateSwapChain() diff --git a/attachments/35_gltf_ktx.cpp b/attachments/35_gltf_ktx.cpp index 777010f40..d3d656af7 100644 --- a/attachments/35_gltf_ktx.cpp +++ b/attachments/35_gltf_ktx.cpp @@ -264,6 +264,18 @@ class VulkanApplication return 0; } #else + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; #endif @@ -394,8 +406,6 @@ class VulkanApplication #if PLATFORM_DESKTOP void cleanup() const { - glfwDestroyWindow(window); - glfwTerminate(); } #endif diff --git a/attachments/36_multiple_objects.cpp b/attachments/36_multiple_objects.cpp index 9afc90037..6545de521 100644 --- a/attachments/36_multiple_objects.cpp +++ b/attachments/36_multiple_objects.cpp @@ -318,6 +318,18 @@ class VulkanApplication return 0; } #else + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; #endif @@ -465,10 +477,6 @@ class VulkanApplication gameObject.uniformBuffersMapped.clear(); gameObject.descriptorSets.clear(); } - - // Clean up GLFW resources - glfwDestroyWindow(window); - glfwTerminate(); } #endif diff --git a/attachments/37_multithreading.cpp b/attachments/37_multithreading.cpp index aa443369d..736e05d4a 100644 --- a/attachments/37_multithreading.cpp +++ b/attachments/37_multithreading.cpp @@ -164,6 +164,18 @@ class MultithreadedApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -555,9 +567,6 @@ class MultithreadedApplication void cleanup() { stopThreads(); - - glfwDestroyWindow(window); - glfwTerminate(); } void createInstance() diff --git a/attachments/38_ray_tracing.cpp b/attachments/38_ray_tracing.cpp index e0843931c..d8f393990 100644 --- a/attachments/38_ray_tracing.cpp +++ b/attachments/38_ray_tracing.cpp @@ -129,6 +129,18 @@ class VulkanRaytracingApplication } private: + // Declared first, so it is destroyed last - after every vk::raii member below. + // The swapchain and surface still reference the window system connection when + // their destructors run, so glfwTerminate() has to outlive them. It also + // destroys any windows that are still open. + struct GlfwGuard + { + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; @@ -301,9 +313,6 @@ class VulkanRaytracingApplication void cleanup() const { - glfwDestroyWindow(window); - - glfwTerminate(); } void recreateSwapChain() diff --git a/en/03_Drawing_a_triangle/00_Setup/00_Base_code.adoc b/en/03_Drawing_a_triangle/00_Setup/00_Base_code.adoc index eeaf07029..b8df105cd 100644 --- a/en/03_Drawing_a_triangle/00_Setup/00_Base_code.adoc +++ b/en/03_Drawing_a_triangle/00_Setup/00_Base_code.adoc @@ -293,20 +293,47 @@ This code should be fairly self-explanatory. It loops and checks for events like pressing the X button until the user has closed the window. This is also the loop where we'll later call a function to render a single frame. -Once the window is closed, we need to clean up resources by destroying it and -terminating GLFW itself. This will be our first `cleanup` code: +Once the window is closed we have to release it and shut GLFW down again. It is +tempting to do that in `cleanup`, but that would be a mistake. From the next +chapter on this class holds Vulkan objects, and those objects still talk to the +window system while they are being destroyed. Member variables are destroyed +*after* `run` returns, so anything `cleanup` tears down is released too early - +the swap chain would end up being destroyed after the connection it still points +at is gone, which crashes on exit. + +Instead we let a small guard own the GLFW lifetime. Members are destroyed in +reverse declaration order, so declaring it *first* means it is destroyed *last*, +after every Vulkan object we add in later chapters: [,c++] ---- -void cleanup() { - glfwDestroyWindow(window); +class HelloTriangleApplication { + // ... + +private: + // Declared first, so it is destroyed last. + struct GlfwGuard { + ~GlfwGuard() { glfwTerminate(); } + } glfwGuard; + + GLFWwindow* window = nullptr; + + // ... +}; +---- + +`glfwTerminate` also destroys any windows that are still open, so we don't need +a separate `glfwDestroyWindow` call. That leaves `cleanup` empty for now: - glfwTerminate(); +[,c++] +---- +void cleanup() { } ---- -Note that in this tutorial, this is the last time we'll have to do anything -in the cleanup() function. This code will never need to change again. +Note that in this tutorial, this is the last time we'll have to think about +tearing GLFW down. Because the guard is declared first, it keeps working no +matter how many Vulkan objects the later chapters add. When you run the program now, you should see a window titled `Vulkan` show up until the application is terminated by closing the window. Now that we have the diff --git a/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc b/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc index 3a942cdc4..7da3b682f 100644 --- a/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc +++ b/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc @@ -66,12 +66,12 @@ void cleanupSwapChain() void cleanup() { cleanupSwapChain(); - - glfwDestroyWindow(window); - glfwTerminate(); } ---- +GLFW is still torn down by `glfwGuard`, which is destroyed after every Vulkan +member, so `cleanup` must not terminate it here. + Note that in `chooseSwapExtent` we already query the new window resolution to make sure that the swap chain images have the (new) right size, so there's no need to modify `chooseSwapExtent` (remember that we already had to use `glfwGetFramebufferSize` to get the resolution of the surface in pixels when creating the swap chain). That's all it takes to recreate the swap chain! From 8d7abf5166268d2074c6fa65e64b1077852d7855 Mon Sep 17 00:00:00 2001 From: Ozan Yasin Dogan Date: Mon, 10 Aug 2026 16:10:20 +0300 Subject: [PATCH 2/3] Initialize GLFW in the guard's constructor and check the result Follow-up to review feedback on #443. `glfwInit()` was called at the top of `initWindow()` and its return value discarded in every chapter, so a failed initialization surfaced later as a null window rather than as an error. Moving it into `GlfwGuard` gives the guard both ends of the GLFW lifetime and gives the failure somewhere to go: GlfwGuard() { if (!glfwInit()) { throw std::runtime_error("failed to initialize GLFW!"); } } The constructor runs during member initialization, before `run()` is entered, and every chapter already constructs the application object inside the `try` in `main()`, so the error is reported through the same path as every other `std::runtime_error`. If it throws, `~GlfwGuard()` never runs, so `glfwTerminate()` is correctly skipped after a failed init. Also in this change: - 34_android.cpp gains the same guard. Its PLATFORM_DESKTOP path creates a GLFW window but never called `glfwTerminate()` or `glfwDestroyWindow()`, so it leaked GLFW rather than destroying it out of order. Every chapter that owns a window now uses the guard. - `cleanup()` was left as bare empty braces in 31_compute_shader, 32_ecosystem_utilities, 35_gltf_ktx and 38_ray_tracing, while 28 other chapters carried a comment explaining where GLFW teardown had moved to. Those four now match. - The guard in 32_ecosystem_utilities moved above `AppInfo appInfo` so that "declared first" is literally true there. - 00_Base_code.adoc introduces the guard where GLFW initialization is taught, instead of reintroducing it in the cleanup section, and 04_Swap_chain_recreation.adoc drops `glfwInit()` from its initWindow snippet. Verified on Windows 11, MSVC 14.51, Vulkan 1.4.357, RTX 5080: - all 144 build targets compile with no new warnings - clang-format-diff.py over the diff against main reports no violations - every chapter built from a pristine main and from this branch, then closed with a real WM_CLOSE and its exit code recorded: 36/36 exit 0 on both sides. Windows does not fault on the original ordering, so this measures no regression rather than a fix on that platform. Refs: #138 --- attachments/00_base_code.cpp | 19 +++-- attachments/01_instance_creation.cpp | 19 +++-- attachments/02_validation_layers.cpp | 19 +++-- attachments/03_physical_device_selection.cpp | 19 +++-- attachments/04_logical_device.cpp | 19 +++-- attachments/05_window_surface.cpp | 19 +++-- attachments/06_swap_chain_creation.cpp | 19 +++-- attachments/07_image_views.cpp | 19 +++-- attachments/08_graphics_pipeline.cpp | 19 +++-- attachments/09_shader_modules.cpp | 19 +++-- attachments/10_fixed_functions.cpp | 19 +++-- attachments/12_graphics_pipeline_complete.cpp | 19 +++-- attachments/14_command_buffers.cpp | 19 +++-- attachments/15_hello_triangle.cpp | 19 +++-- attachments/16_frames_in_flight.cpp | 19 +++-- attachments/17_swap_chain_recreation.cpp | 19 +++-- attachments/19_vertex_buffer.cpp | 19 +++-- attachments/20_staging_buffer.cpp | 19 +++-- attachments/21_index_buffer.cpp | 19 +++-- attachments/22_descriptor_layout.cpp | 19 +++-- attachments/23_descriptor_sets.cpp | 19 +++-- attachments/24_texture_image.cpp | 19 +++-- attachments/25_sampler.cpp | 19 +++-- attachments/26_texture_mapping.cpp | 19 +++-- attachments/27_depth_buffering.cpp | 19 +++-- attachments/28_model_loading.cpp | 19 +++-- attachments/29_mipmapping.cpp | 19 +++-- attachments/30_multisampling.cpp | 19 +++-- attachments/31_compute_shader.cpp | 22 +++-- attachments/32_ecosystem_utilities.cpp | 26 ++++-- attachments/33_vulkan_profiles.cpp | 18 +++-- attachments/34_android.cpp | 22 ++++- attachments/35_gltf_ktx.cpp | 22 +++-- attachments/36_multiple_objects.cpp | 19 +++-- attachments/37_multithreading.cpp | 19 +++-- attachments/38_ray_tracing.cpp | 22 +++-- .../00_Setup/00_Base_code.adoc | 81 ++++++++++--------- .../04_Swap_chain_recreation.adoc | 2 - 38 files changed, 534 insertions(+), 251 deletions(-) diff --git a/attachments/00_base_code.cpp b/attachments/00_base_code.cpp index 6cbc61408..763d9137b 100644 --- a/attachments/00_base_code.cpp +++ b/attachments/00_base_code.cpp @@ -25,12 +25,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every member below. Later - // chapters add Vulkan objects here that still reference the window system - // connection while they are destroyed, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every member + // below. Later chapters add Vulkan objects here that still reference the + // window system connection while they are destroyed, so glfwTerminate() has + // to outlive them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -41,8 +50,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); diff --git a/attachments/01_instance_creation.cpp b/attachments/01_instance_creation.cpp index 91743a3b0..b6725deb6 100644 --- a/attachments/01_instance_creation.cpp +++ b/attachments/01_instance_creation.cpp @@ -28,12 +28,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -47,8 +56,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); diff --git a/attachments/02_validation_layers.cpp b/attachments/02_validation_layers.cpp index 6aa47b08e..9d87106ad 100644 --- a/attachments/02_validation_layers.cpp +++ b/attachments/02_validation_layers.cpp @@ -39,12 +39,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -59,8 +68,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); diff --git a/attachments/03_physical_device_selection.cpp b/attachments/03_physical_device_selection.cpp index 58d15c911..3d87f8564 100644 --- a/attachments/03_physical_device_selection.cpp +++ b/attachments/03_physical_device_selection.cpp @@ -39,12 +39,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -64,8 +73,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); diff --git a/attachments/04_logical_device.cpp b/attachments/04_logical_device.cpp index 4c2d9b3de..1a9ed4234 100644 --- a/attachments/04_logical_device.cpp +++ b/attachments/04_logical_device.cpp @@ -40,12 +40,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -68,8 +77,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); diff --git a/attachments/05_window_surface.cpp b/attachments/05_window_surface.cpp index 360b82c17..a5fd47770 100644 --- a/attachments/05_window_surface.cpp +++ b/attachments/05_window_surface.cpp @@ -39,12 +39,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -65,8 +74,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); diff --git a/attachments/06_swap_chain_creation.cpp b/attachments/06_swap_chain_creation.cpp index 811b51286..f11933e86 100644 --- a/attachments/06_swap_chain_creation.cpp +++ b/attachments/06_swap_chain_creation.cpp @@ -41,12 +41,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -72,8 +81,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); diff --git a/attachments/07_image_views.cpp b/attachments/07_image_views.cpp index a78abe612..4f865a0fe 100644 --- a/attachments/07_image_views.cpp +++ b/attachments/07_image_views.cpp @@ -41,12 +41,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -72,8 +81,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); diff --git a/attachments/08_graphics_pipeline.cpp b/attachments/08_graphics_pipeline.cpp index 04eb1c0d8..b1fd03933 100644 --- a/attachments/08_graphics_pipeline.cpp +++ b/attachments/08_graphics_pipeline.cpp @@ -41,12 +41,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -72,8 +81,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); diff --git a/attachments/09_shader_modules.cpp b/attachments/09_shader_modules.cpp index 8a27fe319..4c7b71a3d 100644 --- a/attachments/09_shader_modules.cpp +++ b/attachments/09_shader_modules.cpp @@ -42,12 +42,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -73,8 +82,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); diff --git a/attachments/10_fixed_functions.cpp b/attachments/10_fixed_functions.cpp index 6ca5afeba..612a5fcf7 100644 --- a/attachments/10_fixed_functions.cpp +++ b/attachments/10_fixed_functions.cpp @@ -42,12 +42,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -75,8 +84,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); diff --git a/attachments/12_graphics_pipeline_complete.cpp b/attachments/12_graphics_pipeline_complete.cpp index 12192a4ee..762ae6e99 100644 --- a/attachments/12_graphics_pipeline_complete.cpp +++ b/attachments/12_graphics_pipeline_complete.cpp @@ -42,12 +42,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -76,8 +85,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); diff --git a/attachments/14_command_buffers.cpp b/attachments/14_command_buffers.cpp index e201a6f85..754c7358f 100644 --- a/attachments/14_command_buffers.cpp +++ b/attachments/14_command_buffers.cpp @@ -42,12 +42,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -79,8 +88,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); diff --git a/attachments/15_hello_triangle.cpp b/attachments/15_hello_triangle.cpp index 580ec2146..b9e6e1786 100644 --- a/attachments/15_hello_triangle.cpp +++ b/attachments/15_hello_triangle.cpp @@ -42,12 +42,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -84,8 +93,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); diff --git a/attachments/16_frames_in_flight.cpp b/attachments/16_frames_in_flight.cpp index abde61ed2..dacd583e2 100644 --- a/attachments/16_frames_in_flight.cpp +++ b/attachments/16_frames_in_flight.cpp @@ -43,12 +43,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -86,8 +95,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); diff --git a/attachments/17_swap_chain_recreation.cpp b/attachments/17_swap_chain_recreation.cpp index f5bc48bf5..91c6e171e 100644 --- a/attachments/17_swap_chain_recreation.cpp +++ b/attachments/17_swap_chain_recreation.cpp @@ -43,12 +43,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -88,8 +97,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); diff --git a/attachments/19_vertex_buffer.cpp b/attachments/19_vertex_buffer.cpp index 94a73edb6..8df4ff01e 100644 --- a/attachments/19_vertex_buffer.cpp +++ b/attachments/19_vertex_buffer.cpp @@ -67,12 +67,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -115,8 +124,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); diff --git a/attachments/20_staging_buffer.cpp b/attachments/20_staging_buffer.cpp index d1e4b5e4b..94ae1da30 100644 --- a/attachments/20_staging_buffer.cpp +++ b/attachments/20_staging_buffer.cpp @@ -67,12 +67,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -115,8 +124,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); diff --git a/attachments/21_index_buffer.cpp b/attachments/21_index_buffer.cpp index d0d61c17e..d625a2917 100644 --- a/attachments/21_index_buffer.cpp +++ b/attachments/21_index_buffer.cpp @@ -71,12 +71,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -121,8 +130,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); diff --git a/attachments/22_descriptor_layout.cpp b/attachments/22_descriptor_layout.cpp index 742e26cc3..4b14ffe4c 100644 --- a/attachments/22_descriptor_layout.cpp +++ b/attachments/22_descriptor_layout.cpp @@ -82,12 +82,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -137,8 +146,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); diff --git a/attachments/23_descriptor_sets.cpp b/attachments/23_descriptor_sets.cpp index 73d0df825..97f504120 100644 --- a/attachments/23_descriptor_sets.cpp +++ b/attachments/23_descriptor_sets.cpp @@ -82,12 +82,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -140,8 +149,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); diff --git a/attachments/24_texture_image.cpp b/attachments/24_texture_image.cpp index 846f90e5d..91cc44ff5 100644 --- a/attachments/24_texture_image.cpp +++ b/attachments/24_texture_image.cpp @@ -85,12 +85,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -146,8 +155,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); diff --git a/attachments/25_sampler.cpp b/attachments/25_sampler.cpp index 2e16b966d..268c6f638 100644 --- a/attachments/25_sampler.cpp +++ b/attachments/25_sampler.cpp @@ -85,12 +85,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -148,8 +157,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); diff --git a/attachments/26_texture_mapping.cpp b/attachments/26_texture_mapping.cpp index f7b0a46be..01c9bd499 100644 --- a/attachments/26_texture_mapping.cpp +++ b/attachments/26_texture_mapping.cpp @@ -86,12 +86,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -149,8 +158,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); diff --git a/attachments/27_depth_buffering.cpp b/attachments/27_depth_buffering.cpp index c4cbbc0f9..0e0c7ef24 100644 --- a/attachments/27_depth_buffering.cpp +++ b/attachments/27_depth_buffering.cpp @@ -94,12 +94,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -163,8 +172,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); diff --git a/attachments/28_model_loading.cpp b/attachments/28_model_loading.cpp index 635914207..f4b58eb29 100644 --- a/attachments/28_model_loading.cpp +++ b/attachments/28_model_loading.cpp @@ -100,12 +100,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -169,8 +178,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); diff --git a/attachments/29_mipmapping.cpp b/attachments/29_mipmapping.cpp index 849de674d..05621ee19 100644 --- a/attachments/29_mipmapping.cpp +++ b/attachments/29_mipmapping.cpp @@ -100,12 +100,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -170,8 +179,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); diff --git a/attachments/30_multisampling.cpp b/attachments/30_multisampling.cpp index 6698f903d..ec42910b9 100644 --- a/attachments/30_multisampling.cpp +++ b/attachments/30_multisampling.cpp @@ -100,12 +100,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -175,8 +184,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); diff --git a/attachments/31_compute_shader.cpp b/attachments/31_compute_shader.cpp index 90e3a17e3..37b6b3916 100644 --- a/attachments/31_compute_shader.cpp +++ b/attachments/31_compute_shader.cpp @@ -79,12 +79,21 @@ class ComputeShaderApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -143,8 +152,6 @@ class ComputeShaderApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -206,6 +213,9 @@ class ComputeShaderApplication void cleanup() const { + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void recreateSwapChain() diff --git a/attachments/32_ecosystem_utilities.cpp b/attachments/32_ecosystem_utilities.cpp index 3a7a3c474..1c54bc6f5 100644 --- a/attachments/32_ecosystem_utilities.cpp +++ b/attachments/32_ecosystem_utilities.cpp @@ -104,20 +104,29 @@ class HelloTriangleApplication } private: - AppInfo appInfo; - - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); } } glfwGuard; + AppInfo appInfo; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -188,8 +197,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -266,6 +273,9 @@ class HelloTriangleApplication void cleanup() const { + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void recreateSwapChain() diff --git a/attachments/33_vulkan_profiles.cpp b/attachments/33_vulkan_profiles.cpp index 0835a1d56..b3c81576c 100644 --- a/attachments/33_vulkan_profiles.cpp +++ b/attachments/33_vulkan_profiles.cpp @@ -103,12 +103,21 @@ class HelloTriangleApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -181,7 +190,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); diff --git a/attachments/34_android.cpp b/attachments/34_android.cpp index c32c63610..2005245de 100644 --- a/attachments/34_android.cpp +++ b/attachments/34_android.cpp @@ -268,7 +268,6 @@ class HelloTriangleApplication // Initialize window (Desktop only) void initWindow() { - glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -323,6 +322,27 @@ class HelloTriangleApplication AssetManagerType *assetManager = nullptr; #else // Desktop-specific members + // glfwGuard owns the GLFW lifetime: it initialises GLFW here and terminates it + // in the destructor. Declared before the vk::raii members below, so it is + // destroyed after them - the swapchain and surface still reference the window + // system connection when their destructors run. It also destroys any windows + // that are still open. + struct GlfwGuard + { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + + ~GlfwGuard() + { + glfwTerminate(); + } + } glfwGuard; + GLFWwindow *window = nullptr; #endif bool initialized = false; diff --git a/attachments/35_gltf_ktx.cpp b/attachments/35_gltf_ktx.cpp index d3d656af7..b1b2c5a97 100644 --- a/attachments/35_gltf_ktx.cpp +++ b/attachments/35_gltf_ktx.cpp @@ -264,12 +264,21 @@ class VulkanApplication return 0; } #else - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -339,8 +348,6 @@ class VulkanApplication #if PLATFORM_DESKTOP void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -406,6 +413,9 @@ class VulkanApplication #if PLATFORM_DESKTOP void cleanup() const { + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } #endif diff --git a/attachments/36_multiple_objects.cpp b/attachments/36_multiple_objects.cpp index 6545de521..425c01668 100644 --- a/attachments/36_multiple_objects.cpp +++ b/attachments/36_multiple_objects.cpp @@ -318,12 +318,21 @@ class VulkanApplication return 0; } #else - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -391,8 +400,6 @@ class VulkanApplication #if PLATFORM_DESKTOP void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); diff --git a/attachments/37_multithreading.cpp b/attachments/37_multithreading.cpp index 736e05d4a..d26252221 100644 --- a/attachments/37_multithreading.cpp +++ b/attachments/37_multithreading.cpp @@ -164,12 +164,21 @@ class MultithreadedApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -318,8 +327,6 @@ class MultithreadedApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); diff --git a/attachments/38_ray_tracing.cpp b/attachments/38_ray_tracing.cpp index d8f393990..a8debf558 100644 --- a/attachments/38_ray_tracing.cpp +++ b/attachments/38_ray_tracing.cpp @@ -129,12 +129,21 @@ class VulkanRaytracingApplication } private: - // Declared first, so it is destroyed last - after every vk::raii member below. - // The swapchain and surface still reference the window system connection when - // their destructors run, so glfwTerminate() has to outlive them. It also - // destroys any windows that are still open. + // Owns the GLFW lifetime: initialises it here and terminates it in the + // destructor. Declared first, so it is destroyed last - after every vk::raii + // member below. The swapchain and surface still reference the window system + // connection when their destructors run, so glfwTerminate() has to outlive + // them. It also destroys any windows that are still open. struct GlfwGuard { + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + ~GlfwGuard() { glfwTerminate(); @@ -252,8 +261,6 @@ class VulkanRaytracingApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); @@ -313,6 +320,9 @@ class VulkanRaytracingApplication void cleanup() const { + // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii + // member. Destroying the window or terminating GLFW here would free the + // window system connection while the swapchain and surface are still alive. } void recreateSwapChain() diff --git a/en/03_Drawing_a_triangle/00_Setup/00_Base_code.adoc b/en/03_Drawing_a_triangle/00_Setup/00_Base_code.adoc index b8df105cd..ffbc53dc7 100644 --- a/en/03_Drawing_a_triangle/00_Setup/00_Base_code.adoc +++ b/en/03_Drawing_a_triangle/00_Setup/00_Base_code.adoc @@ -208,10 +208,34 @@ private: } ---- -The very first call in `initWindow` should be `glfwInit()`, which initializes -the GLFW library. Because GLFW was originally designed to create an OpenGL -context, we need to tell it to not create an OpenGL context with a later -call: +Before we can open a window, the GLFW library has to be initialized with +`glfwInit()`, and it has to be shut down again with `glfwTerminate()` once we +are done with it. Instead of calling those by hand, we'll let a small guard +object own that lifetime, so GLFW is always shut down no matter how the program +exits. Add it as the *first* private member of the class: + +[,c++] +---- +private: + struct GlfwGuard { + GlfwGuard() { + if (!glfwInit()) { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + + ~GlfwGuard() { glfwTerminate(); } + } glfwGuard; +---- + +Because it is a member, its constructor runs before `run` is ever called, so +GLFW is ready by the time `initWindow` executes. It also gives us somewhere to +check the result: `glfwInit` returns false if the library could not be +initialized. Why it has to be declared *first* is something we'll come back to +when we get to `cleanup`. + +Because GLFW was originally designed to create an OpenGL context, we need to +tell it to not create an OpenGL context with a window hint: [,c++] ---- @@ -268,8 +292,6 @@ You should now have a `initWindow` function that looks like this: [,c++] ---- void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); @@ -293,37 +315,22 @@ This code should be fairly self-explanatory. It loops and checks for events like pressing the X button until the user has closed the window. This is also the loop where we'll later call a function to render a single frame. -Once the window is closed we have to release it and shut GLFW down again. It is -tempting to do that in `cleanup`, but that would be a mistake. From the next -chapter on this class holds Vulkan objects, and those objects still talk to the -window system while they are being destroyed. Member variables are destroyed -*after* `run` returns, so anything `cleanup` tears down is released too early - -the swap chain would end up being destroyed after the connection it still points -at is gone, which crashes on exit. - -Instead we let a small guard own the GLFW lifetime. Members are destroyed in -reverse declaration order, so declaring it *first* means it is destroyed *last*, -after every Vulkan object we add in later chapters: - -[,c++] ----- -class HelloTriangleApplication { - // ... - -private: - // Declared first, so it is destroyed last. - struct GlfwGuard { - ~GlfwGuard() { glfwTerminate(); } - } glfwGuard; - - GLFWwindow* window = nullptr; - - // ... -}; ----- - -`glfwTerminate` also destroys any windows that are still open, so we don't need -a separate `glfwDestroyWindow` call. That leaves `cleanup` empty for now: +Once the window is closed we have to release it and shut GLFW down again. That +already happens on its own: `glfwGuard` is a member, so its destructor runs when +the application object is destroyed, and `glfwTerminate` also destroys any +windows that are still open. This is why we don't need a separate +`glfwDestroyWindow` call. + +What matters is *when* that happens, and this is where the declaration order +comes in. From the next chapter on, this class holds Vulkan objects, and those +objects still talk to the window system while they are being destroyed. Members +are destroyed in reverse declaration order, so declaring the guard *first* means +it is destroyed *last* - after every Vulkan object we add later. + +Terminating GLFW in `cleanup` instead would break exactly that. `run` calls +`cleanup` before any member is destroyed, so the connection to the window system +would be gone while the swap chain still pointed at it, and the program would +crash on exit. So `cleanup` stays empty for now: [,c++] ---- diff --git a/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc b/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc index 7da3b682f..d5bbe1b94 100644 --- a/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc +++ b/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc @@ -221,8 +221,6 @@ Now, to actually detect resizes, we can use the `glfwSetFramebufferSizeCallback` ---- void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); From e5c990199dbe9afb82332fbe318714abcf864dd0 Mon Sep 17 00:00:00 2001 From: Ozan Yasin Dogan Date: Tue, 20 Oct 2026 03:31:03 +0300 Subject: [PATCH 3/3] Move GlfwGuard into a shared header The guard was repeated in all 36 chapters that own a window. It now lives once in attachments/glfw_guard.h, together with the explanation of why it has to be declared first. Each chapter includes the header right after its own GLFW include, so GLFW_INCLUDE_VULKAN is still defined when GLFW is first included, and declares `GlfwGuard glfwGuard;` as its first member with a one-line comment, since that ordering is what keeps GLFW alive until every vk::raii member is gone. In 34_android, 35_gltf_ktx and 36_multiple_objects both stay inside the existing desktop-only branch. Docs: - Base code teaches the header, the include order and the member. - Every page that links a chapter's source now also links glfw_guard.h, so a chapter downloaded on its own still compiles. - The ray tracing course overview lists the header with the other files. - The Multiple Objects cleanup() snippet no longer calls glfwDestroyWindow()/glfwTerminate(). It was added after this PR was opened and showed exactly the ordering this PR fixes; the chapter's code already doesn't do it. --- attachments/00_base_code.cpp | 28 ++--------- attachments/01_instance_creation.cpp | 28 ++--------- attachments/02_validation_layers.cpp | 28 ++--------- attachments/03_physical_device_selection.cpp | 28 ++--------- attachments/04_logical_device.cpp | 28 ++--------- attachments/05_window_surface.cpp | 28 ++--------- attachments/06_swap_chain_creation.cpp | 28 ++--------- attachments/07_image_views.cpp | 28 ++--------- attachments/08_graphics_pipeline.cpp | 28 ++--------- attachments/09_shader_modules.cpp | 28 ++--------- attachments/10_fixed_functions.cpp | 28 ++--------- attachments/12_graphics_pipeline_complete.cpp | 28 ++--------- attachments/14_command_buffers.cpp | 28 ++--------- attachments/15_hello_triangle.cpp | 28 ++--------- attachments/16_frames_in_flight.cpp | 28 ++--------- attachments/17_swap_chain_recreation.cpp | 28 ++--------- attachments/19_vertex_buffer.cpp | 28 ++--------- attachments/20_staging_buffer.cpp | 28 ++--------- attachments/21_index_buffer.cpp | 28 ++--------- attachments/22_descriptor_layout.cpp | 28 ++--------- attachments/23_descriptor_sets.cpp | 28 ++--------- attachments/24_texture_image.cpp | 28 ++--------- attachments/25_sampler.cpp | 28 ++--------- attachments/26_texture_mapping.cpp | 28 ++--------- attachments/27_depth_buffering.cpp | 28 ++--------- attachments/28_model_loading.cpp | 28 ++--------- attachments/29_mipmapping.cpp | 28 ++--------- attachments/30_multisampling.cpp | 28 ++--------- attachments/31_compute_shader.cpp | 28 ++--------- attachments/32_ecosystem_utilities.cpp | 28 ++--------- attachments/33_vulkan_profiles.cpp | 28 ++--------- attachments/34_android.cpp | 24 ++-------- attachments/35_gltf_ktx.cpp | 28 ++--------- attachments/36_multiple_objects.cpp | 24 ++-------- attachments/37_multithreading.cpp | 24 ++-------- attachments/38_ray_tracing.cpp | 28 ++--------- attachments/glfw_guard.h | 35 ++++++++++++++ .../00_Setup/00_Base_code.adoc | 47 +++++++++++++++---- .../00_Setup/01_Instance.adoc | 3 +- .../00_Setup/02_Validation_layers.adoc | 3 +- ...3_Physical_devices_and_queue_families.adoc | 3 +- .../04_Logical_device_and_queues.adoc | 3 +- .../01_Presentation/00_Window_surface.adoc | 3 +- .../01_Presentation/01_Swap_chain.adoc | 3 +- .../01_Presentation/02_Image_views.adoc | 3 +- .../00_Introduction.adoc | 3 +- .../01_Shader_modules.adoc | 1 + .../02_Fixed_functions.adoc | 1 + .../03_Dynamic_rendering.adoc | 1 + .../04_Conclusion.adoc | 1 + .../03_Drawing/00_Dynamic_rendering.adoc | 1 + .../03_Drawing/01_Command_buffers.adoc | 1 + .../02_Rendering_and_presentation.adoc | 1 + .../03_Drawing/03_Frames_in_flight.adoc | 1 + .../04_Swap_chain_recreation.adoc | 1 + .../00_Vertex_input_description.adoc | 1 + .../01_Vertex_buffer_creation.adoc | 1 + en/04_Vertex_buffers/02_Staging_buffer.adoc | 1 + en/04_Vertex_buffers/03_Index_buffer.adoc | 1 + .../00_Descriptor_set_layout_and_buffer.adoc | 1 + .../01_Descriptor_pool_and_sets.adoc | 1 + en/06_Texture_mapping/00_Images.adoc | 1 + .../01_Image_view_and_sampler.adoc | 1 + .../02_Combined_image_sampler.adoc | 1 + en/07_Depth_buffering.adoc | 1 + en/08_Loading_models.adoc | 1 + en/09_Generating_Mipmaps.adoc | 1 + en/10_Multisampling.adoc | 1 + en/11_Compute_Shader.adoc | 1 + ...Ecosystem_Utilities_and_Compatibility.adoc | 3 +- en/13_Vulkan_Profiles.adoc | 3 +- en/14_Android.adoc | 3 +- en/15_GLTF_KTX2_Migration.adoc | 3 +- en/16_Multiple_Objects.adoc | 6 +-- en/17_Multithreading.adoc | 3 +- en/courses/18_Ray_tracing/00_Overview.adoc | 3 +- 76 files changed, 302 insertions(+), 847 deletions(-) create mode 100644 attachments/glfw_guard.h diff --git a/attachments/00_base_code.cpp b/attachments/00_base_code.cpp index 763d9137b..86e0b8cde 100644 --- a/attachments/00_base_code.cpp +++ b/attachments/00_base_code.cpp @@ -6,6 +6,8 @@ import vulkan_hpp; #endif #include +#include "glfw_guard.h" + #include #include #include @@ -25,26 +27,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every member - // below. Later chapters add Vulkan objects here that still reference the - // window system connection while they are destroyed, so glfwTerminate() has - // to outlive them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; @@ -70,9 +54,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every other - // member. Terminating GLFW here would free the window system connection - // while later chapters' Vulkan objects are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } }; diff --git a/attachments/01_instance_creation.cpp b/attachments/01_instance_creation.cpp index b6725deb6..513410242 100644 --- a/attachments/01_instance_creation.cpp +++ b/attachments/01_instance_creation.cpp @@ -13,6 +13,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + constexpr uint32_t WIDTH = 800; constexpr uint32_t HEIGHT = 600; @@ -28,26 +30,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; @@ -77,9 +61,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void createInstance() diff --git a/attachments/02_validation_layers.cpp b/attachments/02_validation_layers.cpp index 9d87106ad..c35252f16 100644 --- a/attachments/02_validation_layers.cpp +++ b/attachments/02_validation_layers.cpp @@ -15,6 +15,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + constexpr uint32_t WIDTH = 800; constexpr uint32_t HEIGHT = 600; @@ -39,26 +41,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; @@ -90,9 +74,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void createInstance() diff --git a/attachments/03_physical_device_selection.cpp b/attachments/03_physical_device_selection.cpp index 3d87f8564..8d10000a4 100644 --- a/attachments/03_physical_device_selection.cpp +++ b/attachments/03_physical_device_selection.cpp @@ -15,6 +15,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + constexpr uint32_t WIDTH = 800; constexpr uint32_t HEIGHT = 600; @@ -39,26 +41,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; @@ -96,9 +80,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void createInstance() diff --git a/attachments/04_logical_device.cpp b/attachments/04_logical_device.cpp index 1a9ed4234..3fbfc8508 100644 --- a/attachments/04_logical_device.cpp +++ b/attachments/04_logical_device.cpp @@ -16,6 +16,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + constexpr uint32_t WIDTH = 800; constexpr uint32_t HEIGHT = 600; @@ -40,26 +42,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; @@ -101,9 +85,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void createInstance() diff --git a/attachments/05_window_surface.cpp b/attachments/05_window_surface.cpp index e27c1b48f..324649e0c 100644 --- a/attachments/05_window_surface.cpp +++ b/attachments/05_window_surface.cpp @@ -15,6 +15,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + constexpr uint32_t WIDTH = 800; constexpr uint32_t HEIGHT = 600; @@ -39,26 +41,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -99,9 +83,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void createInstance() diff --git a/attachments/06_swap_chain_creation.cpp b/attachments/06_swap_chain_creation.cpp index bef7256b1..17306033d 100644 --- a/attachments/06_swap_chain_creation.cpp +++ b/attachments/06_swap_chain_creation.cpp @@ -17,6 +17,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + constexpr uint32_t WIDTH = 800; constexpr uint32_t HEIGHT = 600; @@ -41,26 +43,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -107,9 +91,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void createInstance() diff --git a/attachments/07_image_views.cpp b/attachments/07_image_views.cpp index f996aaee9..b20ea1ce6 100644 --- a/attachments/07_image_views.cpp +++ b/attachments/07_image_views.cpp @@ -17,6 +17,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + constexpr uint32_t WIDTH = 800; constexpr uint32_t HEIGHT = 600; @@ -41,26 +43,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -108,9 +92,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void createInstance() diff --git a/attachments/08_graphics_pipeline.cpp b/attachments/08_graphics_pipeline.cpp index 863ac1b2f..8bc2ecf06 100644 --- a/attachments/08_graphics_pipeline.cpp +++ b/attachments/08_graphics_pipeline.cpp @@ -17,6 +17,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + constexpr uint32_t WIDTH = 800; constexpr uint32_t HEIGHT = 600; @@ -41,26 +43,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -109,9 +93,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void createInstance() diff --git a/attachments/09_shader_modules.cpp b/attachments/09_shader_modules.cpp index 69effad8e..d46e738a8 100644 --- a/attachments/09_shader_modules.cpp +++ b/attachments/09_shader_modules.cpp @@ -18,6 +18,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + constexpr uint32_t WIDTH = 800; constexpr uint32_t HEIGHT = 600; @@ -42,26 +44,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -110,9 +94,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void createInstance() diff --git a/attachments/10_fixed_functions.cpp b/attachments/10_fixed_functions.cpp index b886fa12b..b48726b54 100644 --- a/attachments/10_fixed_functions.cpp +++ b/attachments/10_fixed_functions.cpp @@ -18,6 +18,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + constexpr uint32_t WIDTH = 800; constexpr uint32_t HEIGHT = 600; @@ -42,26 +44,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -112,9 +96,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void createInstance() diff --git a/attachments/12_graphics_pipeline_complete.cpp b/attachments/12_graphics_pipeline_complete.cpp index b8ce9251e..cd9fad6de 100644 --- a/attachments/12_graphics_pipeline_complete.cpp +++ b/attachments/12_graphics_pipeline_complete.cpp @@ -18,6 +18,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + constexpr uint32_t WIDTH = 800; constexpr uint32_t HEIGHT = 600; @@ -42,26 +44,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -113,9 +97,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void createInstance() diff --git a/attachments/14_command_buffers.cpp b/attachments/14_command_buffers.cpp index 7258b0a20..5ab8456b9 100644 --- a/attachments/14_command_buffers.cpp +++ b/attachments/14_command_buffers.cpp @@ -18,6 +18,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + constexpr uint32_t WIDTH = 800; constexpr uint32_t HEIGHT = 600; @@ -42,26 +44,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -118,9 +102,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void createInstance() diff --git a/attachments/15_hello_triangle.cpp b/attachments/15_hello_triangle.cpp index 17ce9d5a6..75e482527 100644 --- a/attachments/15_hello_triangle.cpp +++ b/attachments/15_hello_triangle.cpp @@ -18,6 +18,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + constexpr uint32_t WIDTH = 800; constexpr uint32_t HEIGHT = 600; @@ -42,26 +44,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -126,9 +110,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void createInstance() diff --git a/attachments/16_frames_in_flight.cpp b/attachments/16_frames_in_flight.cpp index d99ec415e..c3b9f5abc 100644 --- a/attachments/16_frames_in_flight.cpp +++ b/attachments/16_frames_in_flight.cpp @@ -18,6 +18,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + constexpr uint32_t WIDTH = 800; constexpr uint32_t HEIGHT = 600; constexpr int MAX_FRAMES_IN_FLIGHT = 2; @@ -43,26 +45,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -129,9 +113,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void createInstance() diff --git a/attachments/17_swap_chain_recreation.cpp b/attachments/17_swap_chain_recreation.cpp index f477b7e7a..a8a57ca6a 100644 --- a/attachments/17_swap_chain_recreation.cpp +++ b/attachments/17_swap_chain_recreation.cpp @@ -18,6 +18,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + constexpr uint32_t WIDTH = 800; constexpr uint32_t HEIGHT = 600; constexpr int MAX_FRAMES_IN_FLIGHT = 2; @@ -43,26 +45,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -145,9 +129,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void recreateSwapChain() diff --git a/attachments/19_vertex_buffer.cpp b/attachments/19_vertex_buffer.cpp index af2f2f4bf..d711846f1 100644 --- a/attachments/19_vertex_buffer.cpp +++ b/attachments/19_vertex_buffer.cpp @@ -18,6 +18,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include + +#include "glfw_guard.h" #include constexpr uint32_t WIDTH = 800; @@ -67,26 +69,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -173,9 +157,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void recreateSwapChain() diff --git a/attachments/20_staging_buffer.cpp b/attachments/20_staging_buffer.cpp index bb6adda69..b3b8207e5 100644 --- a/attachments/20_staging_buffer.cpp +++ b/attachments/20_staging_buffer.cpp @@ -18,6 +18,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include + +#include "glfw_guard.h" #include constexpr uint32_t WIDTH = 800; @@ -67,26 +69,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -173,9 +157,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void recreateSwapChain() diff --git a/attachments/21_index_buffer.cpp b/attachments/21_index_buffer.cpp index ef9e20b3d..7031004b5 100644 --- a/attachments/21_index_buffer.cpp +++ b/attachments/21_index_buffer.cpp @@ -18,6 +18,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include + +#include "glfw_guard.h" #include constexpr uint32_t WIDTH = 800; @@ -71,26 +73,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -180,9 +164,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void recreateSwapChain() diff --git a/attachments/22_descriptor_layout.cpp b/attachments/22_descriptor_layout.cpp index c97826b9c..d2bf80c7e 100644 --- a/attachments/22_descriptor_layout.cpp +++ b/attachments/22_descriptor_layout.cpp @@ -20,6 +20,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + #define GLM_FORCE_RADIANS #include #include @@ -82,26 +84,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -198,9 +182,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void recreateSwapChain() diff --git a/attachments/23_descriptor_sets.cpp b/attachments/23_descriptor_sets.cpp index 86ff9315a..779ee9b1f 100644 --- a/attachments/23_descriptor_sets.cpp +++ b/attachments/23_descriptor_sets.cpp @@ -20,6 +20,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + #define GLM_FORCE_RADIANS #include #include @@ -82,26 +84,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -203,9 +187,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void recreateSwapChain() diff --git a/attachments/24_texture_image.cpp b/attachments/24_texture_image.cpp index 0f70d4624..094c0e2a7 100644 --- a/attachments/24_texture_image.cpp +++ b/attachments/24_texture_image.cpp @@ -20,6 +20,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + #define GLM_FORCE_RADIANS #include #include @@ -85,26 +87,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -210,9 +194,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void recreateSwapChain() diff --git a/attachments/25_sampler.cpp b/attachments/25_sampler.cpp index 550398286..b6fb7501d 100644 --- a/attachments/25_sampler.cpp +++ b/attachments/25_sampler.cpp @@ -20,6 +20,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + #define GLM_FORCE_RADIANS #include #include @@ -85,26 +87,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -214,9 +198,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void recreateSwapChain() diff --git a/attachments/26_texture_mapping.cpp b/attachments/26_texture_mapping.cpp index c4295184c..795d8373c 100644 --- a/attachments/26_texture_mapping.cpp +++ b/attachments/26_texture_mapping.cpp @@ -20,6 +20,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + #define GLM_FORCE_RADIANS #include #include @@ -86,26 +88,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -215,9 +199,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void recreateSwapChain() diff --git a/attachments/27_depth_buffering.cpp b/attachments/27_depth_buffering.cpp index ef5e3bfbe..1fa9525ec 100644 --- a/attachments/27_depth_buffering.cpp +++ b/attachments/27_depth_buffering.cpp @@ -20,6 +20,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + #define GLM_FORCE_RADIANS #define GLM_FORCE_DEPTH_ZERO_TO_ONE #include @@ -94,26 +96,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -230,9 +214,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void recreateSwapChain() diff --git a/attachments/28_model_loading.cpp b/attachments/28_model_loading.cpp index 3c447e28e..f867a8ca3 100644 --- a/attachments/28_model_loading.cpp +++ b/attachments/28_model_loading.cpp @@ -20,6 +20,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + #define GLM_FORCE_RADIANS #define GLM_FORCE_DEPTH_ZERO_TO_ONE #define GLM_ENABLE_EXPERIMENTAL @@ -100,26 +102,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -237,9 +221,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void recreateSwapChain() diff --git a/attachments/29_mipmapping.cpp b/attachments/29_mipmapping.cpp index 8dda29022..acb33e254 100644 --- a/attachments/29_mipmapping.cpp +++ b/attachments/29_mipmapping.cpp @@ -20,6 +20,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + #define GLM_FORCE_RADIANS #define GLM_FORCE_DEPTH_ZERO_TO_ONE #define GLM_ENABLE_EXPERIMENTAL @@ -100,26 +102,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -238,9 +222,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void recreateSwapChain() diff --git a/attachments/30_multisampling.cpp b/attachments/30_multisampling.cpp index 90deec85e..3ddb81370 100644 --- a/attachments/30_multisampling.cpp +++ b/attachments/30_multisampling.cpp @@ -20,6 +20,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + #define GLM_FORCE_RADIANS #define GLM_FORCE_DEPTH_ZERO_TO_ONE #define GLM_ENABLE_EXPERIMENTAL @@ -100,26 +102,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -244,9 +228,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void recreateSwapChain() diff --git a/attachments/31_compute_shader.cpp b/attachments/31_compute_shader.cpp index 805bf568a..467cabfd7 100644 --- a/attachments/31_compute_shader.cpp +++ b/attachments/31_compute_shader.cpp @@ -24,6 +24,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + #define GLM_FORCE_RADIANS #include #include @@ -79,26 +81,8 @@ class ComputeShaderApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -213,9 +197,7 @@ class ComputeShaderApplication void cleanup() const { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void recreateSwapChain() diff --git a/attachments/32_ecosystem_utilities.cpp b/attachments/32_ecosystem_utilities.cpp index 4bb954c96..8820a0f42 100644 --- a/attachments/32_ecosystem_utilities.cpp +++ b/attachments/32_ecosystem_utilities.cpp @@ -22,6 +22,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + #define GLM_FORCE_RADIANS #define GLM_FORCE_DEPTH_ZERO_TO_ONE #define GLM_ENABLE_EXPERIMENTAL @@ -105,26 +107,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; AppInfo appInfo; @@ -275,9 +259,7 @@ class HelloTriangleApplication void cleanup() const { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void recreateSwapChain() diff --git a/attachments/33_vulkan_profiles.cpp b/attachments/33_vulkan_profiles.cpp index 70111efe2..5097774e2 100644 --- a/attachments/33_vulkan_profiles.cpp +++ b/attachments/33_vulkan_profiles.cpp @@ -22,6 +22,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + #define GLM_FORCE_RADIANS #define GLM_FORCE_DEPTH_ZERO_TO_ONE #define GLM_ENABLE_EXPERIMENTAL @@ -103,26 +105,8 @@ class HelloTriangleApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; @@ -275,9 +259,7 @@ class HelloTriangleApplication void cleanup() { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void recreateSwapChain() diff --git a/attachments/34_android.cpp b/attachments/34_android.cpp index 41f09b55c..6851c42b3 100644 --- a/attachments/34_android.cpp +++ b/attachments/34_android.cpp @@ -69,6 +69,8 @@ typedef void AssetManagerType; # define GLFW_INCLUDE_VULKAN # include +# include "glfw_guard.h" + // Define logging macros for Desktop # define LOGI(...) \ printf(__VA_ARGS__); \ @@ -322,26 +324,8 @@ class HelloTriangleApplication AssetManagerType *assetManager = nullptr; #else // Desktop-specific members - // glfwGuard owns the GLFW lifetime: it initialises GLFW here and terminates it - // in the destructor. Declared before the vk::raii members below, so it is - // destroyed after them - the swapchain and surface still reference the window - // system connection when their destructors run. It also destroys any windows - // that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared before every vk::raii member below, so GLFW outlives them. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; #endif diff --git a/attachments/35_gltf_ktx.cpp b/attachments/35_gltf_ktx.cpp index 239a4dca0..bcc9357d1 100644 --- a/attachments/35_gltf_ktx.cpp +++ b/attachments/35_gltf_ktx.cpp @@ -63,6 +63,8 @@ typedef void AssetManagerType; # define GLFW_INCLUDE_VULKAN # include +# include "glfw_guard.h" + // Define logging macros for Desktop # define LOGI(...) \ printf(__VA_ARGS__); \ @@ -264,26 +266,8 @@ class VulkanApplication return 0; } #else - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; #endif @@ -413,9 +397,7 @@ class VulkanApplication #if PLATFORM_DESKTOP void cleanup() const { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } #endif diff --git a/attachments/36_multiple_objects.cpp b/attachments/36_multiple_objects.cpp index 8400c3bb7..785575644 100644 --- a/attachments/36_multiple_objects.cpp +++ b/attachments/36_multiple_objects.cpp @@ -63,6 +63,8 @@ typedef void AssetManagerType; # define GLFW_INCLUDE_VULKAN # include +# include "glfw_guard.h" + // Define logging macros for Desktop # define LOGI(...) \ printf(__VA_ARGS__); \ @@ -318,26 +320,8 @@ class VulkanApplication return 0; } #else - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; #endif diff --git a/attachments/37_multithreading.cpp b/attachments/37_multithreading.cpp index 47d898f16..b843fd0a6 100644 --- a/attachments/37_multithreading.cpp +++ b/attachments/37_multithreading.cpp @@ -26,6 +26,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + #define GLM_FORCE_RADIANS #include #include @@ -164,26 +166,8 @@ class MultithreadedApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; vk::raii::Context context; diff --git a/attachments/38_ray_tracing.cpp b/attachments/38_ray_tracing.cpp index e0d359e4e..8325bf77d 100644 --- a/attachments/38_ray_tracing.cpp +++ b/attachments/38_ray_tracing.cpp @@ -19,6 +19,8 @@ import vulkan_hpp; #define GLFW_INCLUDE_VULKAN // REQUIRED only for GLFW CreateWindowSurface. #include +#include "glfw_guard.h" + #define GLM_FORCE_RADIANS #define GLM_FORCE_DEPTH_ZERO_TO_ONE #define GLM_ENABLE_EXPERIMENTAL @@ -129,26 +131,8 @@ class VulkanRaytracingApplication } private: - // Owns the GLFW lifetime: initialises it here and terminates it in the - // destructor. Declared first, so it is destroyed last - after every vk::raii - // member below. The swapchain and surface still reference the window system - // connection when their destructors run, so glfwTerminate() has to outlive - // them. It also destroys any windows that are still open. - struct GlfwGuard - { - GlfwGuard() - { - if (!glfwInit()) - { - throw std::runtime_error("failed to initialize GLFW!"); - } - } - - ~GlfwGuard() - { - glfwTerminate(); - } - } glfwGuard; + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; GLFWwindow *window = nullptr; @@ -320,9 +304,7 @@ class VulkanRaytracingApplication void cleanup() const { - // GLFW is torn down by glfwGuard, which is destroyed after every vk::raii - // member. Destroying the window or terminating GLFW here would free the - // window system connection while the swapchain and surface are still alive. + // GLFW is torn down by glfwGuard (see glfw_guard.h), not here. } void recreateSwapChain() diff --git a/attachments/glfw_guard.h b/attachments/glfw_guard.h new file mode 100644 index 000000000..0d50ab729 --- /dev/null +++ b/attachments/glfw_guard.h @@ -0,0 +1,35 @@ +#pragma once + +// Include this after the chapter's own GLFW include, so that GLFW_INCLUDE_VULKAN +// is already defined when GLFW is first included. +#include + +#include + +// Owns the GLFW lifetime: it initialises GLFW in the constructor and terminates +// it in the destructor. +// +// Declare it as the first member of the application class. Members are +// destroyed in reverse declaration order, so the first one declared is +// destroyed last - after every vk::raii member. The swapchain and surface still +// reference the window system connection when their destructors run, so +// glfwTerminate() has to outlive them. It also destroys any windows that are +// still open, so no separate glfwDestroyWindow() call is needed. +// +// If glfwInit() fails, the constructor throws and the destructor never runs, so +// glfwTerminate() is correctly skipped. +struct GlfwGuard +{ + GlfwGuard() + { + if (!glfwInit()) + { + throw std::runtime_error("failed to initialize GLFW!"); + } + } + + ~GlfwGuard() + { + glfwTerminate(); + } +}; diff --git a/en/03_Drawing_a_triangle/00_Setup/00_Base_code.adoc b/en/03_Drawing_a_triangle/00_Setup/00_Base_code.adoc index 0dcbbda45..23ce35fad 100644 --- a/en/03_Drawing_a_triangle/00_Setup/00_Base_code.adoc +++ b/en/03_Drawing_a_triangle/00_Setup/00_Base_code.adoc @@ -225,20 +225,46 @@ Before we can open a window, the GLFW library has to be initialized with `glfwInit()`, and it has to be shut down again with `glfwTerminate()` once we are done with it. Instead of calling those by hand, we'll let a small guard object own that lifetime, so GLFW is always shut down no matter how the program -exits. Add it as the *first* private member of the class: +exits. Every chapter from here on uses the same guard, so it lives in its own +header, link:/attachments/glfw_guard.h[`glfw_guard.h`], next to the chapter +sources: [,c++] ---- -private: - struct GlfwGuard { - GlfwGuard() { - if (!glfwInit()) { - throw std::runtime_error("failed to initialize GLFW!"); - } +#pragma once + +#include + +#include + +struct GlfwGuard { + GlfwGuard() { + if (!glfwInit()) { + throw std::runtime_error("failed to initialize GLFW!"); } + } + + ~GlfwGuard() { glfwTerminate(); } +}; +---- + +Include it right after GLFW itself. The header includes GLFW too, so including +it first would pull GLFW in before `GLFW_INCLUDE_VULKAN` is defined: - ~GlfwGuard() { glfwTerminate(); } - } glfwGuard; +[,c++] +---- +#define GLFW_INCLUDE_VULKAN +#include + +#include "glfw_guard.h" +---- + +Then add the guard as the *first* private member of the class: + +[,c++] +---- +private: + GlfwGuard glfwGuard; ---- Because it is a member, its constructor runs before `run` is ever called, so @@ -367,4 +393,5 @@ X11 shows the window immediately, as described above. Now that we have the skeleton for the Vulkan application, let's xref:./01_Instance.adoc[create the first Vulkan object]! -link:/attachments/00_base_code.cpp[C{pp} code] +link:/attachments/00_base_code.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] diff --git a/en/03_Drawing_a_triangle/00_Setup/01_Instance.adoc b/en/03_Drawing_a_triangle/00_Setup/01_Instance.adoc index 85710c7f0..36c572356 100644 --- a/en/03_Drawing_a_triangle/00_Setup/01_Instance.adoc +++ b/en/03_Drawing_a_triangle/00_Setup/01_Instance.adoc @@ -241,4 +241,5 @@ some details about the Vulkan support. Before continuing with the more complex steps after instance creation, it's time to evaluate our debugging options by checking out xref:./02_Validation_layers.adoc[validation layers]. -link:/attachments/01_instance_creation.cpp[C{pp} code] +link:/attachments/01_instance_creation.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] diff --git a/en/03_Drawing_a_triangle/00_Setup/02_Validation_layers.adoc b/en/03_Drawing_a_triangle/00_Setup/02_Validation_layers.adoc index 5b7a70d1c..86c7c00b5 100644 --- a/en/03_Drawing_a_triangle/00_Setup/02_Validation_layers.adoc +++ b/en/03_Drawing_a_triangle/00_Setup/02_Validation_layers.adoc @@ -478,4 +478,5 @@ to show you how helpful the validation layers are with catching them and to teac how important it is to know exactly what you're doing with Vulkan. Now it's time to look at xref:./03_Physical_devices_and_queue_families.adoc[Vulkan devices in the system]. -link:/attachments/02_validation_layers.cpp[C{pp} code] +link:/attachments/02_validation_layers.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] diff --git a/en/03_Drawing_a_triangle/00_Setup/03_Physical_devices_and_queue_families.adoc b/en/03_Drawing_a_triangle/00_Setup/03_Physical_devices_and_queue_families.adoc index 1f85cd2a4..d3fd5d08f 100644 --- a/en/03_Drawing_a_triangle/00_Setup/03_Physical_devices_and_queue_families.adoc +++ b/en/03_Drawing_a_triangle/00_Setup/03_Physical_devices_and_queue_families.adoc @@ -300,4 +300,5 @@ Great, that's all we need for now to find the right physical device! The next step is to xref:./04_Logical_device_and_queues.adoc[create a logical device] to interface with it. -link:/attachments/03_physical_device_selection.cpp[C{pp} code] +link:/attachments/03_physical_device_selection.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] diff --git a/en/03_Drawing_a_triangle/00_Setup/04_Logical_device_and_queues.adoc b/en/03_Drawing_a_triangle/00_Setup/04_Logical_device_and_queues.adoc index bd32bbf54..fc1aef362 100644 --- a/en/03_Drawing_a_triangle/00_Setup/04_Logical_device_and_queues.adoc +++ b/en/03_Drawing_a_triangle/00_Setup/04_Logical_device_and_queues.adoc @@ -214,4 +214,5 @@ graphics card to do things! In the xref:/03_Drawing_a_triangle/01_Presentation/00_Window_surface.adoc[next few chapters], we'll set up the resources to present results to the window system. -link:/attachments/04_logical_device.cpp[C{pp} code] +link:/attachments/04_logical_device.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] diff --git a/en/03_Drawing_a_triangle/01_Presentation/00_Window_surface.adoc b/en/03_Drawing_a_triangle/01_Presentation/00_Window_surface.adoc index d56f1b672..af278ba32 100644 --- a/en/03_Drawing_a_triangle/01_Presentation/00_Window_surface.adoc +++ b/en/03_Drawing_a_triangle/01_Presentation/00_Window_surface.adoc @@ -238,4 +238,5 @@ void createLogicalDevice() { In the xref:./01_Swap_chain.adoc[next chapter], we're going to look at swap chains and how they allow us to present images to the surface. -link:/attachments/05_window_surface.cpp[C{pp} code] +link:/attachments/05_window_surface.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] diff --git a/en/03_Drawing_a_triangle/01_Presentation/01_Swap_chain.adoc b/en/03_Drawing_a_triangle/01_Presentation/01_Swap_chain.adoc index b1cb6e379..806c69804 100644 --- a/en/03_Drawing_a_triangle/01_Presentation/01_Swap_chain.adoc +++ b/en/03_Drawing_a_triangle/01_Presentation/01_Swap_chain.adoc @@ -509,4 +509,5 @@ window. The xref:./02_Image_views.adoc[next chapter] will begin to cover how we render targets, and then we start looking into the actual graphics pipeline and drawing commands! -link:/attachments/06_swap_chain_creation.cpp[C{pp} code] +link:/attachments/06_swap_chain_creation.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] diff --git a/en/03_Drawing_a_triangle/01_Presentation/02_Image_views.adoc b/en/03_Drawing_a_triangle/01_Presentation/02_Image_views.adoc index d7db2ca9a..d8ad210e2 100644 --- a/en/03_Drawing_a_triangle/01_Presentation/02_Image_views.adoc +++ b/en/03_Drawing_a_triangle/01_Presentation/02_Image_views.adoc @@ -135,4 +135,5 @@ An image view is sufficient to start using an image as a texture, but it's not q That requires one more step, known as a framebuffer. In the xref:/03_Drawing_a_triangle/02_Graphics_pipeline_basics/00_Introduction.adoc[next chapters,] we'll have to set up the graphics pipeline. -link:/attachments/07_image_views.cpp[C{pp} code] +link:/attachments/07_image_views.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] diff --git a/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/00_Introduction.adoc b/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/00_Introduction.adoc index 34b966a74..2d6a1fecb 100644 --- a/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/00_Introduction.adoc +++ b/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/00_Introduction.adoc @@ -107,4 +107,5 @@ void createGraphicsPipeline() { The xref:./01_Shader_modules.adoc[next chapter] will talk about shader modules required to actually put something on the screen. -link:/attachments/08_graphics_pipeline.cpp[C{pp} code] +link:/attachments/08_graphics_pipeline.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] diff --git a/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/01_Shader_modules.adoc b/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/01_Shader_modules.adoc index bf961fdf5..50ca87bae 100644 --- a/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/01_Shader_modules.adoc +++ b/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/01_Shader_modules.adoc @@ -528,6 +528,7 @@ That's all there is describing the programmable stages of the pipeline. In the xref:./02_Fixed_functions.adoc[next chapter,] we'll look at the fixed-function stages. link:/attachments/09_shader_modules.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/09_shader_base.slang[Slang shader] / link:/attachments/09_shader_base.vert[GLSL Vertex shader] / link:/attachments/09_shader_base.frag[GLSL Fragment shader] diff --git a/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/02_Fixed_functions.adoc b/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/02_Fixed_functions.adoc index ed2a9abf3..48bba949f 100644 --- a/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/02_Fixed_functions.adoc +++ b/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/02_Fixed_functions.adoc @@ -315,6 +315,7 @@ This reduces the chance of running into unexpected behavior because the default In the xref:./03_Dynamic_rendering.adoc[next step] we will set up dynamic rendering to tell the graphics pipeline what and how attachments will be used. link:/attachments/10_fixed_functions.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/09_shader_base.slang[Slang shader] / link:/attachments/09_shader_base.vert[GLSL Vertex shader] / link:/attachments/09_shader_base.frag[GLSL Fragment shader] diff --git a/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/03_Dynamic_rendering.adoc b/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/03_Dynamic_rendering.adoc index e2bb05ea2..694bd23de 100644 --- a/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/03_Dynamic_rendering.adoc +++ b/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/03_Dynamic_rendering.adoc @@ -47,6 +47,7 @@ The advantage of dynamic rendering is that it simplifies the rendering process b In the xref:./04_Conclusion.adoc[next chapter], we'll put everything together to finally create the graphics pipeline object! link:/attachments/12_graphics_pipeline_complete.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/09_shader_base.slang[Slang shader] / link:/attachments/09_shader_base.vert[GLSL Vertex shader] / link:/attachments/09_shader_base.frag[GLSL Fragment shader] diff --git a/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/04_Conclusion.adoc b/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/04_Conclusion.adoc index e8d64796d..3e3499751 100644 --- a/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/04_Conclusion.adoc +++ b/en/03_Drawing_a_triangle/02_Graphics_pipeline_basics/04_Conclusion.adoc @@ -83,6 +83,7 @@ In the xref:/03_Drawing_a_triangle/03_Drawing/00_Dynamic_rendering.adoc[next cou we'll set up dynamic rendering for the swap chain images and prepare the drawing commands. link:/attachments/12_graphics_pipeline_complete.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/09_shader_base.slang[Slang shader] / link:/attachments/09_shader_base.vert[GLSL Vertex shader] / link:/attachments/09_shader_base.frag[GLSL Fragment shader] diff --git a/en/03_Drawing_a_triangle/03_Drawing/00_Dynamic_rendering.adoc b/en/03_Drawing_a_triangle/03_Drawing/00_Dynamic_rendering.adoc index ac9e06312..43e8992c0 100644 --- a/en/03_Drawing_a_triangle/03_Drawing/00_Dynamic_rendering.adoc +++ b/en/03_Drawing_a_triangle/03_Drawing/00_Dynamic_rendering.adoc @@ -82,6 +82,7 @@ With this approach, we don't need to create framebuffers or render passes, which In the xref:./01_Command_buffers.adoc[next chapter,] we'll create command buffers and write the first actual drawing commands using dynamic rendering. link:/attachments/14_command_buffers.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/09_shader_base.slang[Slang shader] / link:/attachments/09_shader_base.vert[GLSL Vertex shader] / link:/attachments/09_shader_base.frag[GLSL Fragment shader] diff --git a/en/03_Drawing_a_triangle/03_Drawing/01_Command_buffers.adoc b/en/03_Drawing_a_triangle/03_Drawing/01_Command_buffers.adoc index 0ebb216a4..c77f3d1c5 100644 --- a/en/03_Drawing_a_triangle/03_Drawing/01_Command_buffers.adoc +++ b/en/03_Drawing_a_triangle/03_Drawing/01_Command_buffers.adoc @@ -336,6 +336,7 @@ commandBuffer.end(); In the xref:./02_Rendering_and_presentation.adoc[next chapter] we'll write the code for the main loop, which will acquire an image from the swap chain, record and execute a command buffer, then return the finished image to the swap chain. link:/attachments/14_command_buffers.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/09_shader_base.slang[Slang shader] / link:/attachments/09_shader_base.vert[GLSL Vertex shader] / link:/attachments/09_shader_base.frag[GLSL Fragment shader] diff --git a/en/03_Drawing_a_triangle/03_Drawing/02_Rendering_and_presentation.adoc b/en/03_Drawing_a_triangle/03_Drawing/02_Rendering_and_presentation.adoc index b807c4bf1..b8d423c62 100644 --- a/en/03_Drawing_a_triangle/03_Drawing/02_Rendering_and_presentation.adoc +++ b/en/03_Drawing_a_triangle/03_Drawing/02_Rendering_and_presentation.adoc @@ -399,6 +399,7 @@ barriers and further refine our understanding of synchronization in Vulkan. The xref:./03_Frames_in_flight.adoc[next chapter] will expand the render loop to handle multiple frames in flight. link:/attachments/15_hello_triangle.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/09_shader_base.slang[Slang shader] / link:/attachments/09_shader_base.vert[GLSL Vertex shader] / link:/attachments/09_shader_base.frag[GLSL Fragment shader] diff --git a/en/03_Drawing_a_triangle/03_Drawing/03_Frames_in_flight.adoc b/en/03_Drawing_a_triangle/03_Drawing/03_Frames_in_flight.adoc index 2c9fa3516..4613ce88f 100644 --- a/en/03_Drawing_a_triangle/03_Drawing/03_Frames_in_flight.adoc +++ b/en/03_Drawing_a_triangle/03_Drawing/03_Frames_in_flight.adoc @@ -176,6 +176,7 @@ In the xref:../03_Drawing_a_triangle/04_Swap_chain_recreation.adoc[next chapter] we'll deal with one more small thing required for a well-behaved Vulkan program. link:/attachments/16_frames_in_flight.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/09_shader_base.slang[Slang shader] / link:/attachments/09_shader_base.vert[GLSL Vertex shader] / link:/attachments/09_shader_base.frag[GLSL Fragment shader] diff --git a/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc b/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc index bbb1d531f..b59951a03 100644 --- a/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc +++ b/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc @@ -282,6 +282,7 @@ Congratulations, you've now finished your very first well-behaved Vulkan program In the xref:04_Vertex_buffers/00_Vertex_input_description.adoc[next chapter] we're going to get rid of the hardcoded vertices in the vertex shader and actually use a vertex buffer. link:/attachments/17_swap_chain_recreation.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/09_shader_base.slang[Slang shader] / link:/attachments/09_shader_base.vert[GLSL Vertex shader] / link:/attachments/09_shader_base.frag[GLSL Fragment shader] diff --git a/en/04_Vertex_buffers/00_Vertex_input_description.adoc b/en/04_Vertex_buffers/00_Vertex_input_description.adoc index 9f2989491..4f2d0aa94 100644 --- a/en/04_Vertex_buffers/00_Vertex_input_description.adoc +++ b/en/04_Vertex_buffers/00_Vertex_input_description.adoc @@ -183,6 +183,7 @@ The pipeline is now ready to accept vertex data in the format of the `vertices` The xref:./01_Vertex_buffer_creation.adoc[next step] is to create a vertex buffer and move the vertex data to it so the GPU is able to access it. link:/attachments/19_vertex_buffer.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/19_shader_vertexbuffer.slang[slang shader] / link:/attachments/19_shader_vertexbuffer.vert[GLSL Vertex shader] / link:/attachments/19_shader_vertexbuffer.frag[GLSL Fragment shader] diff --git a/en/04_Vertex_buffers/01_Vertex_buffer_creation.adoc b/en/04_Vertex_buffers/01_Vertex_buffer_creation.adoc index 7fc47f1bf..99abc2c5a 100644 --- a/en/04_Vertex_buffers/01_Vertex_buffer_creation.adoc +++ b/en/04_Vertex_buffers/01_Vertex_buffer_creation.adoc @@ -274,6 +274,7 @@ image::/images/triangle_white.png[] In the xref:./02_Staging_buffer.adoc[next chapter,] we'll look at a different way to copy vertex data to a vertex buffer that results in better performance, but takes some more work. link:/attachments/19_vertex_buffer.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/19_shader_vertexbuffer.slang[slang shader] / link:/attachments/19_shader_vertexbuffer.vert[GLSL Vertex shader] / link:/attachments/19_shader_vertexbuffer.frag[GLSL Fragment shader] diff --git a/en/04_Vertex_buffers/02_Staging_buffer.adoc b/en/04_Vertex_buffers/02_Staging_buffer.adoc index aa5a06424..abae4d7fe 100644 --- a/en/04_Vertex_buffers/02_Staging_buffer.adoc +++ b/en/04_Vertex_buffers/02_Staging_buffer.adoc @@ -189,6 +189,7 @@ However, for this tutorial, it's okay to use a separate allocation for every res In the xref:./03_Index_buffer.adoc[next chapter,] we'll learn about index buffers for vertex reuse. link:/attachments/20_staging_buffer.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/19_shader_vertexbuffer.slang[slang shader] / link:/attachments/19_shader_vertexbuffer.vert[GLSL Vertex shader] / link:/attachments/19_shader_vertexbuffer.frag[GLSL Fragment shader] diff --git a/en/04_Vertex_buffers/03_Index_buffer.adoc b/en/04_Vertex_buffers/03_Index_buffer.adoc index 760cbfd0a..105c9b177 100644 --- a/en/04_Vertex_buffers/03_Index_buffer.adoc +++ b/en/04_Vertex_buffers/03_Index_buffer.adoc @@ -143,6 +143,7 @@ This is known as _aliasing_ and some Vulkan functions have explicit flags to spe The xref:05_Uniform_buffers/00_Descriptor_set_layout_and_buffer.adoc[next chapter] we'll learn how to pass frequently changing parameters to the GPU. link:/attachments/21_index_buffer.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/19_shader_vertexbuffer.slang[slang shader] / link:/attachments/19_shader_vertexbuffer.vert[GLSL Vertex shader] / link:/attachments/19_shader_vertexbuffer.frag[GLSL Fragment shader] diff --git a/en/05_Uniform_buffers/00_Descriptor_set_layout_and_buffer.adoc b/en/05_Uniform_buffers/00_Descriptor_set_layout_and_buffer.adoc index 5be0ec1d7..5dc1c8f6e 100644 --- a/en/05_Uniform_buffers/00_Descriptor_set_layout_and_buffer.adoc +++ b/en/05_Uniform_buffers/00_Descriptor_set_layout_and_buffer.adoc @@ -361,6 +361,7 @@ We may look at these in a future chapter. In the xref:./01_Descriptor_pool_and_sets.adoc[next chapter] we'll look at descriptor sets, which will actually bind the ``vk::raii::Buffer``s to the uniform buffer descriptors so that the shader can access this transformation data. link:/attachments/22_descriptor_layout.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/22_shader_ubo.slang[slang shader] / link:/attachments/22_shader_ubo.vert[GLSL Vertex shader] / link:/attachments/22_shader_ubo.frag[GLSL Fragment shader] diff --git a/en/05_Uniform_buffers/01_Descriptor_pool_and_sets.adoc b/en/05_Uniform_buffers/01_Descriptor_pool_and_sets.adoc index 1aba2cba4..305c2f9a1 100644 --- a/en/05_Uniform_buffers/01_Descriptor_pool_and_sets.adoc +++ b/en/05_Uniform_buffers/01_Descriptor_pool_and_sets.adoc @@ -382,6 +382,7 @@ In that case, you avoid rebinding most of the descriptors across draw calls whic In the xref:06_Texture_mapping/00_Images.adoc[next chapters] we'll build upon what we just learned and add textures to our scene. link:/attachments/23_descriptor_sets.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/22_shader_ubo.slang[slang shader] / link:/attachments/22_shader_ubo.vert[GLSL Vertex shader] / link:/attachments/22_shader_ubo.frag[GLSL Fragment shader] diff --git a/en/06_Texture_mapping/00_Images.adoc b/en/06_Texture_mapping/00_Images.adoc index 8a535ada4..2a1724f42 100644 --- a/en/06_Texture_mapping/00_Images.adoc +++ b/en/06_Texture_mapping/00_Images.adoc @@ -532,6 +532,7 @@ The image now contains the texture, but we still need a way to access it from th We'll work on that in the xref:./01_Image_view_and_sampler.adoc[next chapter]. link:/attachments/24_texture_image.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/22_shader_ubo.slang[slang shader] / link:/attachments/22_shader_ubo.vert[GLSL Vertex shader] / link:/attachments/22_shader_ubo.frag[GLSL Frag shader] diff --git a/en/06_Texture_mapping/01_Image_view_and_sampler.adoc b/en/06_Texture_mapping/01_Image_view_and_sampler.adoc index 94e80ecd6..5b5749a25 100644 --- a/en/06_Texture_mapping/01_Image_view_and_sampler.adoc +++ b/en/06_Texture_mapping/01_Image_view_and_sampler.adoc @@ -340,6 +340,7 @@ samplerInfo.maxAnisotropy = 1.0f; In the xref:./02_Combined_image_sampler.adoc[next chapter] we will expose the image and sampler objects to the shaders to draw the texture onto the square. link:/attachments/25_sampler.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/22_shader_ubo.slang[slang shader] / link:/attachments/22_shader_ubo.vert[GLSL Vertex shader] / link:/attachments/22_shader_ubo.frag[GLSL Fragment shader] diff --git a/en/06_Texture_mapping/02_Combined_image_sampler.adoc b/en/06_Texture_mapping/02_Combined_image_sampler.adoc index f3dba50ec..198bef544 100644 --- a/en/06_Texture_mapping/02_Combined_image_sampler.adoc +++ b/en/06_Texture_mapping/02_Combined_image_sampler.adoc @@ -248,6 +248,7 @@ You can use these images as inputs to implement cool effects like post-processin In the xref:07_Depth_buffering.adoc[next chapter] we'll learn how to add depth buffering for properly sorting objects. link:/attachments/26_texture_mapping.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/26_shader_textures.slang[slang shader] / link:/attachments/26_shader_textures.vert[GLSL Vertex shader] / link:/attachments/26_shader_textures.frag[GLSL Fragment shader] diff --git a/en/07_Depth_buffering.adoc b/en/07_Depth_buffering.adoc index a512d7e83..760573a26 100644 --- a/en/07_Depth_buffering.adoc +++ b/en/07_Depth_buffering.adoc @@ -466,6 +466,7 @@ Congratulations, your application is now finally ready to render arbitrary 3D ge We're going to try this out in the xref:08_Loading_models.adoc[next chapter] by drawing a textured model! link:/attachments/27_depth_buffering.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/27_shader_depth.slang[slang shader] / link:/attachments/27_shader_depth.vert[GLSL Vertex shader] / link:/attachments/27_shader_depth.frag[GLSL Fragment shader] diff --git a/en/08_Loading_models.adoc b/en/08_Loading_models.adoc index 31005b0f9..9d34dac5d 100644 --- a/en/08_Loading_models.adoc +++ b/en/08_Loading_models.adoc @@ -317,6 +317,7 @@ This definitely saves us a lot of GPU memory. In the xref:09_Generating_Mipmaps.adoc[next chapter,] we'll learn about a technique to improve texture rendering. link:/attachments/28_model_loading.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/27_shader_depth.slang[slang shader] / link:/attachments/27_shader_depth.vert[GLSL Vertex shader] / link:/attachments/27_shader_depth.frag[GLSL Fragment shader] diff --git a/en/09_Generating_Mipmaps.adoc b/en/09_Generating_Mipmaps.adoc index 57b9d7b4c..229d35da9 100644 --- a/en/09_Generating_Mipmaps.adoc +++ b/en/09_Generating_Mipmaps.adoc @@ -511,6 +511,7 @@ This is how higher mip levels will be used when objects are further away from th The xref:10_Multisampling.adoc[next chapter] will walk us through multisampling to produce a smoother image. link:/attachments/29_mipmapping.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/27_shader_depth.slang[slang shader] / link:/attachments/27_shader_depth.vert[GLSL Vertex shader] / link:/attachments/27_shader_depth.frag[GLSL Fragment shader] diff --git a/en/10_Multisampling.adoc b/en/10_Multisampling.adoc index b687a4404..61534415f 100644 --- a/en/10_Multisampling.adoc +++ b/en/10_Multisampling.adoc @@ -345,6 +345,7 @@ The current program can be extended in many ways, like adding Blinn-Phong lighti You should be able to learn how these effects work from tutorials for other APIs, because despite Vulkan's explicitness, many concepts still work the same. link:/attachments/30_multisampling.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/27_shader_depth.slang[slang shader] / link:/attachments/27_shader_depth.vert[GLSL Vertex shader] / link:/attachments/27_shader_depth.frag[GLSL Fragment shader] diff --git a/en/11_Compute_Shader.adoc b/en/11_Compute_Shader.adoc index 87537d08f..9dc64fe04 100644 --- a/en/11_Compute_Shader.adoc +++ b/en/11_Compute_Shader.adoc @@ -840,6 +840,7 @@ So now that you know how to use compute shaders, you may want to take a look at You can find some advanced compute samples in the https://github.com/KhronosGroup/Vulkan-Samples/tree/master/samples/api[official Khronos Vulkan Samples repository]. link:/attachments/31_compute_shader.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] / link:/attachments/31_shader_compute.slang[slang shader] / link:/attachments/31_shader_compute.vert[GLSL Vertex shader] / link:/attachments/31_shader_compute.frag[GLSL Fragment shader] / diff --git a/en/12_Ecosystem_Utilities_and_Compatibility.adoc b/en/12_Ecosystem_Utilities_and_Compatibility.adoc index 1a46dd199..f053e2f5b 100644 --- a/en/12_Ecosystem_Utilities_and_Compatibility.adoc +++ b/en/12_Ecosystem_Utilities_and_Compatibility.adoc @@ -547,4 +547,5 @@ Based on what we've learned, here are some best practices for developing Vulkan Understanding Vulkan ecosystem utilities and knowing how to adapt your code for different GPU capabilities are essential skills for Vulkan developers. By following the approaches outlined in this chapter, you can create applications that run on a wide range of hardware while still taking advantage of the latest features when available. -link:/attachments/32_ecosystem_utilities.cpp[C{pp} code] +link:/attachments/32_ecosystem_utilities.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] diff --git a/en/13_Vulkan_Profiles.adoc b/en/13_Vulkan_Profiles.adoc index 5f25627ed..d25999dda 100644 --- a/en/13_Vulkan_Profiles.adoc +++ b/en/13_Vulkan_Profiles.adoc @@ -318,4 +318,5 @@ Vulkan profiles provide a powerful way to simplify your Vulkan code by eliminati The example we've explored in this chapter demonstrates how profiles can replace the complex feature detection and fallback paths we had to implement in the previous chapter. By using profiles, you can focus more on your application's core functionality and less on the intricacies of hardware compatibility. -link:/attachments/33_vulkan_profiles.cpp[C{pp} code] +link:/attachments/33_vulkan_profiles.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] diff --git a/en/14_Android.adoc b/en/14_Android.adoc index e5527d1e9..7a52aec03 100644 --- a/en/14_Android.adoc +++ b/en/14_Android.adoc @@ -840,4 +840,5 @@ The complete Android example can be found in the attachments/android directory. Remember that Vulkan HPP is not included by default in the Android NDK, so you'll need to download it separately from the https://github.com/KhronosGroup/Vulkan-Hpp[Vulkan-Hpp GitHub repository] or use the version included in the Vulkan SDK. -link:/attachments/34_android.cpp[C{pp} code] +link:/attachments/34_android.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] diff --git a/en/15_GLTF_KTX2_Migration.adoc b/en/15_GLTF_KTX2_Migration.adoc index 285770b9f..c3f725441 100644 --- a/en/15_GLTF_KTX2_Migration.adoc +++ b/en/15_GLTF_KTX2_Migration.adoc @@ -702,4 +702,5 @@ Migrating from OBJ/PNG to glTF/KTX2 brings significant benefits for modern graph While the migration requires some code changes, the benefits in terms of performance, features, and future-proofing make it worthwhile for serious graphics applications. -link:/attachments/35_gltf_ktx.cpp[C{pp} code] +link:/attachments/35_gltf_ktx.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] diff --git a/en/16_Multiple_Objects.adoc b/en/16_Multiple_Objects.adoc index 4da661c3b..369301b64 100644 --- a/en/16_Multiple_Objects.adoc +++ b/en/16_Multiple_Objects.adoc @@ -316,9 +316,6 @@ void cleanup() { gameObject.uniformBuffersMapped.clear(); gameObject.descriptorSets.clear(); } - - glfwDestroyWindow(window); - glfwTerminate(); } ---- @@ -356,4 +353,5 @@ In a real-world application, you might extend this system with: The foundation you've built here will serve as a solid starting point for these more advanced techniques. -link:/attachments/36_multiple_objects.cpp[C{pp} code] +link:/attachments/36_multiple_objects.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] diff --git a/en/17_Multithreading.adoc b/en/17_Multithreading.adoc index cb5c4ee22..78f418fe7 100644 --- a/en/17_Multithreading.adoc +++ b/en/17_Multithreading.adoc @@ -527,4 +527,5 @@ By distributing work across multiple CPU cores, we can significantly improve per As you continue to develop your Vulkan applications, consider how multithreading can help you leverage the full power of modern CPUs, and remember to always measure performance to ensure your threading model is actually beneficial for your specific use case. -link:/attachments/37_multithreading.cpp[C{pp} code] +link:/attachments/37_multithreading.cpp[C{pp} code] / +link:/attachments/glfw_guard.h[glfw_guard.h] diff --git a/en/courses/18_Ray_tracing/00_Overview.adoc b/en/courses/18_Ray_tracing/00_Overview.adoc index 334ff02bd..3d384776d 100644 --- a/en/courses/18_Ray_tracing/00_Overview.adoc +++ b/en/courses/18_Ray_tracing/00_Overview.adoc @@ -28,9 +28,10 @@ This series targets intermediate Vulkan programmers. We assume you have complete - We use Ray Queries (from `VK_KHR_ray_query`) within fragment shaders instead of a separate ray tracing pipeline. On mobile, ray queries are far more widely supported and often (depending on the use case) more efficient than the full ray tracing pipeline. Ray queries integrate nicely into fragment shading, benefiting from on-chip compression and avoiding context switches. *Provided Code*: -The provided code is a Vulkan renderer that already implements a basic graphics pipeline with dynamic rendering. It is based on the Vulkan Tutorial and it is self-contained in a single C++ source file and a Slang shader file: +The provided code is a Vulkan renderer that already implements a basic graphics pipeline with dynamic rendering. It is based on the Vulkan Tutorial and consists of a single C++ source file, the GLFW guard header shared by all chapters, and a Slang shader file: - link:/attachments/38_ray_tracing.cpp[38_ray_tracing.cpp] +- link:/attachments/glfw_guard.h[glfw_guard.h] - link:/attachments/38_ray_tracing.slang[38_ray_tracing.slang] - If you get stuck on shader tasks, you can refer to the provided reference solution: link:/attachments/38_ray_tracing_complete.slang[38_ray_tracing_complete.slang]