diff --git a/attachments/00_base_code.cpp b/attachments/00_base_code.cpp index 3b685670..86e0b8cd 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,12 +27,13 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); @@ -51,9 +54,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 4686f1b6..51341024 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,6 +30,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; @@ -35,8 +40,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); @@ -58,9 +61,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 2d5ea7f8..c35252f1 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,6 +41,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; @@ -47,8 +52,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); @@ -71,9 +74,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 2fa96044..8d10000a 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,6 +41,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; @@ -52,8 +57,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); @@ -77,9 +80,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 a8c285a3..3fbfc850 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,6 +42,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; @@ -56,8 +61,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); @@ -82,9 +85,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 d8b27fe4..324649e0 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,6 +41,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -53,8 +58,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); @@ -80,9 +83,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 bbf7d8fb..17306033 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,6 +43,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -60,8 +65,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); @@ -88,9 +91,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 79839491..b20ea1ce 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,6 +43,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -60,8 +65,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); @@ -89,9 +92,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 29ac55f8..8bc2ecf0 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,6 +43,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -60,8 +65,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); @@ -90,9 +93,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 305979b4..d46e738a 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,6 +44,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -61,8 +66,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); @@ -91,9 +94,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 7948f0b8..b48726b5 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,6 +44,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -63,8 +68,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); @@ -93,9 +96,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 2792364e..cd9fad6d 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,6 +44,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -64,8 +69,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); @@ -94,9 +97,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 f56c365a..5ab8456b 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,6 +44,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -67,8 +72,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); @@ -99,9 +102,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 e7bbada4..75e48252 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,6 +44,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -72,8 +77,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); @@ -107,9 +110,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 ad3476b8..c3b9f5ab 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,6 +45,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -74,8 +79,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); @@ -110,9 +113,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 9a2dc288..a8a57ca6 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,6 +45,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -76,8 +81,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -126,9 +129,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 e56a20b9..d711846f 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,6 +69,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -103,8 +108,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -154,9 +157,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 04c51319..b3b8207e 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,6 +69,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -103,8 +108,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -154,9 +157,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 1d41d2a0..7031004b 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,6 +73,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -109,8 +114,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -161,9 +164,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 02c7ff92..d2bf80c7 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,6 +84,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -125,8 +130,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -179,9 +182,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 30cc11c5..779ee9b1 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,6 +84,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -128,8 +133,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -184,9 +187,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 9b1e1b9c..094c0e2a 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,6 +87,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -134,8 +139,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -191,9 +194,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 bcd1c6ed..b6fb7501 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,6 +87,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -136,8 +141,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -195,9 +198,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 8b9ed974..795d8373 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,6 +88,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -137,8 +142,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -196,9 +199,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 4be97211..1fa9525e 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,6 +96,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -151,8 +156,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -211,9 +214,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 68046b1f..f867a8ca 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,6 +102,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -157,8 +162,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -218,9 +221,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 fc967f4d..acb33e25 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,6 +102,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -158,8 +163,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -219,9 +222,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 30a74141..3ddb8137 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,6 +102,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -163,8 +168,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -225,9 +228,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 0ed50d21..467cabfd 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,6 +81,9 @@ class ComputeShaderApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -131,8 +136,6 @@ class ComputeShaderApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -194,9 +197,7 @@ class ComputeShaderApplication void cleanup() const { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 f69b128a..8820a0f4 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,6 +107,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + AppInfo appInfo; GLFWwindow *window = nullptr; @@ -178,8 +183,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -256,8 +259,7 @@ class HelloTriangleApplication void cleanup() const { - glfwDestroyWindow(window); - glfwTerminate(); + // 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 c021f6c5..5097774e 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,6 +105,9 @@ class HelloTriangleApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -169,7 +174,6 @@ class HelloTriangleApplication void initWindow() { - glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -255,8 +259,7 @@ class HelloTriangleApplication void cleanup() { - glfwDestroyWindow(window); - glfwTerminate(); + // 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 8b69dcd3..6851c42b 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__); \ @@ -268,7 +270,6 @@ class HelloTriangleApplication // Initialize window (Desktop only) void initWindow() { - glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -323,6 +324,9 @@ class HelloTriangleApplication AssetManagerType *assetManager = nullptr; #else // Desktop-specific members + // Declared before every vk::raii member below, so GLFW outlives them. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; #endif bool initialized = false; diff --git a/attachments/35_gltf_ktx.cpp b/attachments/35_gltf_ktx.cpp index 66b77dae..bcc9357d 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,6 +266,9 @@ class VulkanApplication return 0; } #else + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; #endif @@ -327,8 +332,6 @@ class VulkanApplication #if PLATFORM_DESKTOP void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -394,8 +397,7 @@ class VulkanApplication #if PLATFORM_DESKTOP void cleanup() const { - glfwDestroyWindow(window); - glfwTerminate(); + // 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 5318b03b..78557564 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,6 +320,9 @@ class VulkanApplication return 0; } #else + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; #endif @@ -379,8 +384,6 @@ class VulkanApplication #if PLATFORM_DESKTOP void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -465,10 +468,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 a9850c62..b843fd0a 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,6 +166,9 @@ class MultithreadedApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; vk::raii::Instance instance = nullptr; @@ -306,8 +311,6 @@ class MultithreadedApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); @@ -559,9 +562,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 b51dd0c5..8325bf77 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,6 +131,9 @@ class VulkanRaytracingApplication } private: + // Declared first, so GLFW outlives every Vulkan member below. See glfw_guard.h. + GlfwGuard glfwGuard; + GLFWwindow *window = nullptr; vk::raii::Context context; @@ -240,8 +245,6 @@ class VulkanRaytracingApplication void initWindow() { - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); @@ -301,9 +304,7 @@ class VulkanRaytracingApplication void cleanup() const { - glfwDestroyWindow(window); - - glfwTerminate(); + // 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 00000000..0d50ab72 --- /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 87176d09..23ce35fa 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 @@ -221,10 +221,60 @@ 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. 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++] +---- +#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: + +[,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 +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++] ---- @@ -281,8 +331,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); @@ -306,20 +354,32 @@ 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. 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++] ---- void cleanup() { - glfwDestroyWindow(window); - - glfwTerminate(); } ---- -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. @@ -333,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 85710c7f..36c57235 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 5b7a70d1..86c7c00b 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 1f85cd2a..d3fd5d08 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 bd32bbf5..fc1aef36 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 d56f1b67..af278ba3 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 b1cb6e37..806c6980 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 d7db2ca9..d8ad210e 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 34b966a7..2d6a1fec 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 bf961fdf..50ca87ba 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 ed2a9abf..48bba949 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 e2bb05ea..694bd23d 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 e8d64796..3e349975 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 ac9e0631..43e8992c 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 0ebb216a..c77f3d1c 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 b807c4bf..b8d423c6 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 2c9fa351..4613ce88 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 164eb098..b59951a0 100644 --- a/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc +++ b/en/03_Drawing_a_triangle/04_Swap_chain_recreation.adoc @@ -61,12 +61,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! @@ -214,8 +214,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); @@ -284,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 9f298949..4f2d0aa9 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 7fc47f1b..99abc2c5 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 aa5a0642..abae4d7f 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 760cbfd0..105c9b17 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 5be0ec1d..5dc1c8f6 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 1aba2cba..305c2f9a 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 8a535ada..2a1724f4 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 94e80ecd..5b5749a2 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 f3dba50e..198bef54 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 a512d7e8..760573a2 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 31005b0f..9d34dac5 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 57b9d7b4..229d35da 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 b687a440..61534415 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 87537d08..9dc64fe0 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 1a46dd19..f053e2f5 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 5f25627e..d25999dd 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 e5527d1e..7a52aec0 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 285770b9..c3f72544 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 4da661c3..369301b6 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 cb5c4ee2..78f418fe 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 334ff02b..3d384776 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]