From b4f923f502eee6fa6f5dbaf16d882ab5d8258112 Mon Sep 17 00:00:00 2001
From: Sascha Willems <webmaster@saschawillems.de>
Date: Sat, 19 Oct 2024 14:14:21 +0200
Subject: [PATCH 01/11] Replace deprecated debug reports extension with debug
 utils

Fix validation layers not being enabled in debug builds
Refs #1168
---
 samples/api/hello_triangle/hello_triangle.cpp | 63 ++++++++++---------
 samples/api/hello_triangle/hello_triangle.h   |  4 +-
 2 files changed, 36 insertions(+), 31 deletions(-)

diff --git a/samples/api/hello_triangle/hello_triangle.cpp b/samples/api/hello_triangle/hello_triangle.cpp
index 33aec7d81..689124cdc 100644
--- a/samples/api/hello_triangle/hello_triangle.cpp
+++ b/samples/api/hello_triangle/hello_triangle.cpp
@@ -24,26 +24,28 @@
 #include "platform/window.h"
 
 #if defined(VKB_DEBUG) || defined(VKB_VALIDATION_LAYERS)
-/// @brief A debug callback called from Vulkan validation layers.
-static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT type,
-                                                     uint64_t object, size_t location, int32_t message_code,
-                                                     const char *layer_prefix, const char *message, void *user_data)
+/// @brief A debug callback used to report messages from the validation layers. See instance creation for details on how this is set up
+static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity, VkDebugUtilsMessageTypeFlagsEXT message_type,
+                                                     const VkDebugUtilsMessengerCallbackDataEXT *callback_data,
+                                                     void                                       *user_data)
 {
-	if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
+	(void) user_data;
+
+	if (message_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
 	{
-		LOGE("Validation Layer: Error: {}: {}", layer_prefix, message);
+		LOGE("{} Validation Layer: Error: {}: {}", callback_data->messageIdNumber, callback_data->pMessageIdName, callback_data->pMessage)
 	}
-	else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
+	else if (message_severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
 	{
-		LOGE("Validation Layer: Warning: {}: {}", layer_prefix, message);
+		LOGE("{} Validation Layer: Warning: {}: {}", callback_data->messageIdNumber, callback_data->pMessageIdName, callback_data->pMessage)
 	}
-	else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)
+	else if (message_type & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)
 	{
-		LOGI("Validation Layer: Performance warning: {}: {}", layer_prefix, message);
+		LOGI("{} Validation Layer: Performance warning: {}: {}", callback_data->messageIdNumber, callback_data->pMessageIdName, callback_data->pMessage)
 	}
 	else
 	{
-		LOGI("Validation Layer: Information: {}: {}", layer_prefix, message);
+		LOGI("{} Validation Layer: Information: {}: {}", callback_data->messageIdNumber, callback_data->pMessageIdName, callback_data->pMessage)
 	}
 	return VK_FALSE;
 }
@@ -176,22 +178,22 @@ void HelloTriangle::init_instance(Context                         &context,
 	std::vector<const char *> active_instance_extensions(required_instance_extensions);
 
 #if defined(VKB_DEBUG) || defined(VKB_VALIDATION_LAYERS)
-	bool has_debug_report = false;
+	// Validation layers help finding wrong api usage, we enable them when explicitly requested or in debug builds
+	// For this we use the debug utils extension if it is supported
+	bool has_debug_utils = false;
 	for (const auto &ext : available_instance_extensions)
 	{
-		if (strcmp(ext.extensionName, VK_EXT_DEBUG_REPORT_EXTENSION_NAME) == 0)
+		if (strcmp(ext.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0)
 		{
-			has_debug_report = true;
+			has_debug_utils = true;
+			active_instance_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
 			break;
 		}
 	}
-	if (has_debug_report)
+	if (!has_debug_utils)
 	{
-		active_instance_extensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
-	}
-	else
-	{
-		LOGW("{} is not available; disabling debug reporting", VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
+		LOGW("{} not supported or available", VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+		LOGW("Make sure to compile the sample in debug mode and/or enable the validation layers");
 	}
 #endif
 
@@ -238,7 +240,7 @@ void HelloTriangle::init_instance(Context                         &context,
 
 	std::vector<const char *> requested_validation_layers(required_validation_layers);
 
-#ifdef VKB_VALIDATION_LAYERS
+#if defined(VKB_DEBUG) || defined(VKB_VALIDATION_LAYERS)
 	// Determine the optimal validation layers to enable that are necessary for useful debugging
 	std::vector<const char *> optimal_validation_layers = vkb::get_optimal_validation_layers(supported_validation_layers);
 	requested_validation_layers.insert(requested_validation_layers.end(), optimal_validation_layers.begin(), optimal_validation_layers.end());
@@ -270,13 +272,16 @@ void HelloTriangle::init_instance(Context                         &context,
 	instance_info.ppEnabledLayerNames     = requested_validation_layers.data();
 
 #if defined(VKB_DEBUG) || defined(VKB_VALIDATION_LAYERS)
-	VkDebugReportCallbackCreateInfoEXT debug_report_create_info = {VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT};
-	if (has_debug_report)
+	// Validation layers help finding wrong api usage, we enable them when explicitly requested or in debug builds
+	// For this we use the debug utils extension if it is supported
+	VkDebugUtilsMessengerCreateInfoEXT debug_utils_create_info = {VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT};
+	if (has_debug_utils)
 	{
-		debug_report_create_info.flags       = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
-		debug_report_create_info.pfnCallback = debug_callback;
+		debug_utils_create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
+		debug_utils_create_info.messageType     = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
+		debug_utils_create_info.pfnUserCallback = debug_callback;
 
-		instance_info.pNext = &debug_report_create_info;
+		instance_info.pNext = &debug_utils_create_info;
 	}
 #endif
 
@@ -293,9 +298,9 @@ void HelloTriangle::init_instance(Context                         &context,
 	volkLoadInstance(context.instance);
 
 #if defined(VKB_DEBUG) || defined(VKB_VALIDATION_LAYERS)
-	if (has_debug_report)
+	if (has_debug_utils)
 	{
-		VK_CHECK(vkCreateDebugReportCallbackEXT(context.instance, &debug_report_create_info, nullptr, &context.debug_callback));
+		VK_CHECK(vkCreateDebugUtilsMessengerEXT(context.instance, &debug_utils_create_info, nullptr, &context.debug_callback));
 	}
 #endif
 }
@@ -1062,7 +1067,7 @@ void HelloTriangle::teardown(Context &context)
 
 	if (context.debug_callback != VK_NULL_HANDLE)
 	{
-		vkDestroyDebugReportCallbackEXT(context.instance, context.debug_callback, nullptr);
+		vkDestroyDebugUtilsMessengerEXT(context.instance, context.debug_callback, nullptr);
 		context.debug_callback = VK_NULL_HANDLE;
 	}
 
diff --git a/samples/api/hello_triangle/hello_triangle.h b/samples/api/hello_triangle/hello_triangle.h
index a093769f4..0f3c62614 100644
--- a/samples/api/hello_triangle/hello_triangle.h
+++ b/samples/api/hello_triangle/hello_triangle.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2023, Arm Limited and Contributors
+/* Copyright (c) 2018-2024, Arm Limited and Contributors
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -110,7 +110,7 @@ class HelloTriangle : public vkb::Application
 		VkPipelineLayout pipeline_layout = VK_NULL_HANDLE;
 
 		/// The debug report callback.
-		VkDebugReportCallbackEXT debug_callback = VK_NULL_HANDLE;
+		VkDebugUtilsMessengerEXT debug_callback = VK_NULL_HANDLE;
 
 		/// A set of semaphores that can be reused.
 		std::vector<VkSemaphore> recycled_semaphores;

From 687bee876e2d6e3c244a7cb7670fe5a7a708b812 Mon Sep 17 00:00:00 2001
From: Sascha Willems <webmaster@saschawillems.de>
Date: Sat, 19 Oct 2024 17:14:12 +0200
Subject: [PATCH 02/11] Update comment

---
 samples/api/hello_triangle/hello_triangle.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/samples/api/hello_triangle/hello_triangle.h b/samples/api/hello_triangle/hello_triangle.h
index 0f3c62614..bef309cb6 100644
--- a/samples/api/hello_triangle/hello_triangle.h
+++ b/samples/api/hello_triangle/hello_triangle.h
@@ -109,7 +109,7 @@ class HelloTriangle : public vkb::Application
 		 */
 		VkPipelineLayout pipeline_layout = VK_NULL_HANDLE;
 
-		/// The debug report callback.
+		/// The debug utility callback.
 		VkDebugUtilsMessengerEXT debug_callback = VK_NULL_HANDLE;
 
 		/// A set of semaphores that can be reused.

From 0bc8b33d8fca99ced98c0e6a0602da9761812dea Mon Sep 17 00:00:00 2001
From: Sascha Willems <webmaster@saschawillems.de>
Date: Sat, 19 Oct 2024 17:25:09 +0200
Subject: [PATCH 03/11] Fix error messages

---
 samples/api/hello_triangle/hello_triangle.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/samples/api/hello_triangle/hello_triangle.cpp b/samples/api/hello_triangle/hello_triangle.cpp
index 689124cdc..38d2733fc 100644
--- a/samples/api/hello_triangle/hello_triangle.cpp
+++ b/samples/api/hello_triangle/hello_triangle.cpp
@@ -358,7 +358,7 @@ void HelloTriangle::init_device(Context                         &context,
 
 	if (context.graphics_queue_index < 0)
 	{
-		LOGE("Did not find suitable queue which supports graphics, compute and presentation.");
+		LOGE("Did not find suitable queue which supports graphics and presentation.");
 	}
 
 	uint32_t device_extension_count;
@@ -368,7 +368,7 @@ void HelloTriangle::init_device(Context                         &context,
 
 	if (!validate_extensions(required_device_extensions, device_extensions))
 	{
-		throw std::runtime_error("Required device extensions are missing, will try without.");
+		throw std::runtime_error("Required device extensions are missing.");
 	}
 
 	float queue_priority = 1.0f;

From be7969005c25c6ffa949723c45577fb0714ba691 Mon Sep 17 00:00:00 2001
From: Sascha Willems <webmaster@saschawillems.de>
Date: Sat, 19 Oct 2024 18:57:39 +0200
Subject: [PATCH 04/11] Remove unnecessary per-frame properties

---
 samples/api/hello_triangle/hello_triangle.cpp | 10 ++--------
 samples/api/hello_triangle/hello_triangle.h   | 18 +++++-------------
 2 files changed, 7 insertions(+), 21 deletions(-)

diff --git a/samples/api/hello_triangle/hello_triangle.cpp b/samples/api/hello_triangle/hello_triangle.cpp
index 38d2733fc..d9226c228 100644
--- a/samples/api/hello_triangle/hello_triangle.cpp
+++ b/samples/api/hello_triangle/hello_triangle.cpp
@@ -412,9 +412,6 @@ void HelloTriangle::init_per_frame(Context &context, PerFrame &per_frame)
 	cmd_buf_info.level              = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
 	cmd_buf_info.commandBufferCount = 1;
 	VK_CHECK(vkAllocateCommandBuffers(context.device, &cmd_buf_info, &per_frame.primary_command_buffer));
-
-	per_frame.device      = context.device;
-	per_frame.queue_index = context.graphics_queue_index;
 }
 
 /**
@@ -458,9 +455,6 @@ void HelloTriangle::teardown_per_frame(Context &context, PerFrame &per_frame)
 
 		per_frame.swapchain_release_semaphore = VK_NULL_HANDLE;
 	}
-
-	per_frame.device      = VK_NULL_HANDLE;
-	per_frame.queue_index = -1;
 }
 
 /**
@@ -474,7 +468,7 @@ void HelloTriangle::init_swapchain(Context &context)
 
 	VkSurfaceFormatKHR format = vkb::select_surface_format(context.gpu, context.surface);
 
-	VkExtent2D swapchain_size;
+	VkExtent2D swapchain_size{};
 	if (surface_properties.currentExtent.width == 0xFFFFFFFF)
 	{
 		swapchain_size.width  = context.swapchain_dimensions.width;
@@ -880,7 +874,7 @@ void HelloTriangle::render_triangle(Context &context, uint32_t swapchain_index)
 	vkBeginCommandBuffer(cmd, &begin_info);
 
 	// Set clear color values.
-	VkClearValue clear_value;
+	VkClearValue clear_value{};
 	clear_value.color = {{0.01f, 0.01f, 0.033f, 1.0f}};
 
 	// Begin the render pass.
diff --git a/samples/api/hello_triangle/hello_triangle.h b/samples/api/hello_triangle/hello_triangle.h
index bef309cb6..09b078af4 100644
--- a/samples/api/hello_triangle/hello_triangle.h
+++ b/samples/api/hello_triangle/hello_triangle.h
@@ -47,19 +47,11 @@ class HelloTriangle : public vkb::Application
 	 */
 	struct PerFrame
 	{
-		VkDevice device = VK_NULL_HANDLE;
-
-		VkFence queue_submit_fence = VK_NULL_HANDLE;
-
-		VkCommandPool primary_command_pool = VK_NULL_HANDLE;
-
-		VkCommandBuffer primary_command_buffer = VK_NULL_HANDLE;
-
-		VkSemaphore swapchain_acquire_semaphore = VK_NULL_HANDLE;
-
-		VkSemaphore swapchain_release_semaphore = VK_NULL_HANDLE;
-
-		int32_t queue_index;
+		VkFence         queue_submit_fence          = VK_NULL_HANDLE;
+		VkCommandPool   primary_command_pool        = VK_NULL_HANDLE;
+		VkCommandBuffer primary_command_buffer      = VK_NULL_HANDLE;
+		VkSemaphore     swapchain_acquire_semaphore = VK_NULL_HANDLE;
+		VkSemaphore     swapchain_release_semaphore = VK_NULL_HANDLE;
 	};
 
 	/**

From b4e46874b0473470b9594d251487bf0ecd2fa239 Mon Sep 17 00:00:00 2001
From: Sascha Willems <webmaster@saschawillems.de>
Date: Sat, 19 Oct 2024 19:09:31 +0200
Subject: [PATCH 05/11] Clean up instance and device creation code Use
 extension name constants instead of strings Remove unnecessary arguments

---
 samples/api/hello_triangle/hello_triangle.cpp | 44 +++++++++----------
 samples/api/hello_triangle/hello_triangle.h   |  7 +--
 2 files changed, 23 insertions(+), 28 deletions(-)

diff --git a/samples/api/hello_triangle/hello_triangle.cpp b/samples/api/hello_triangle/hello_triangle.cpp
index d9226c228..a50688f39 100644
--- a/samples/api/hello_triangle/hello_triangle.cpp
+++ b/samples/api/hello_triangle/hello_triangle.cpp
@@ -158,9 +158,7 @@ VkShaderStageFlagBits HelloTriangle::find_shader_stage(const std::string &ext)
  * @param required_instance_extensions The required Vulkan instance extensions.
  * @param required_validation_layers The required Vulkan validation layers
  */
-void HelloTriangle::init_instance(Context                         &context,
-                                  const std::vector<const char *> &required_instance_extensions,
-                                  const std::vector<const char *> &required_validation_layers)
+void HelloTriangle::init_instance(Context &context)
 {
 	LOGI("Initializing vulkan instance.");
 
@@ -175,7 +173,7 @@ void HelloTriangle::init_instance(Context                         &context,
 	std::vector<VkExtensionProperties> available_instance_extensions(instance_extension_count);
 	VK_CHECK(vkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, available_instance_extensions.data()));
 
-	std::vector<const char *> active_instance_extensions(required_instance_extensions);
+	std::vector<const char *> required_instance_extensions{VK_KHR_SURFACE_EXTENSION_NAME};
 
 #if defined(VKB_DEBUG) || defined(VKB_VALIDATION_LAYERS)
 	// Validation layers help finding wrong api usage, we enable them when explicitly requested or in debug builds
@@ -186,7 +184,7 @@ void HelloTriangle::init_instance(Context                         &context,
 		if (strcmp(ext.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0)
 		{
 			has_debug_utils = true;
-			active_instance_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
+			required_instance_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
 			break;
 		}
 	}
@@ -198,36 +196,36 @@ void HelloTriangle::init_instance(Context                         &context,
 #endif
 
 #if (defined(VKB_ENABLE_PORTABILITY))
-	active_instance_extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+	required_instance_extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
 	bool portability_enumeration_available = false;
 	if (std::any_of(available_instance_extensions.begin(),
 	                available_instance_extensions.end(),
 	                [](VkExtensionProperties extension) { return strcmp(extension.extensionName, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME) == 0; }))
 	{
-		active_instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
+		required_instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
 		portability_enumeration_available = true;
 	}
 #endif
 
 #if defined(VK_USE_PLATFORM_ANDROID_KHR)
-	active_instance_extensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
+	required_instance_extensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
 #elif defined(VK_USE_PLATFORM_WIN32_KHR)
-	active_instance_extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
+	required_instance_extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
 #elif defined(VK_USE_PLATFORM_METAL_EXT)
-	active_instance_extensions.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
+	required_instance_extensions.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
 #elif defined(VK_USE_PLATFORM_XCB_KHR)
-	active_instance_extensions.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
+	required_instance_extensions.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
 #elif defined(VK_USE_PLATFORM_XLIB_KHR)
-	active_instance_extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
+	required_instance_extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
-	active_instance_extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
+	required_instance_extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
 #elif defined(VK_USE_PLATFORM_DISPLAY_KHR)
-	active_instance_extensions.push_back(VK_KHR_DISPLAY_EXTENSION_NAME);
+	required_instance_extensions.push_back(VK_KHR_DISPLAY_EXTENSION_NAME);
 #else
 #	pragma error Platform not supported
 #endif
 
-	if (!validate_extensions(active_instance_extensions, available_instance_extensions))
+	if (!validate_extensions(required_instance_extensions, available_instance_extensions))
 	{
 		throw std::runtime_error("Required instance extensions are missing.");
 	}
@@ -238,7 +236,7 @@ void HelloTriangle::init_instance(Context                         &context,
 	std::vector<VkLayerProperties> supported_validation_layers(instance_layer_count);
 	VK_CHECK(vkEnumerateInstanceLayerProperties(&instance_layer_count, supported_validation_layers.data()));
 
-	std::vector<const char *> requested_validation_layers(required_validation_layers);
+	std::vector<const char *> requested_validation_layers{};
 
 #if defined(VKB_DEBUG) || defined(VKB_VALIDATION_LAYERS)
 	// Determine the optimal validation layers to enable that are necessary for useful debugging
@@ -266,8 +264,8 @@ void HelloTriangle::init_instance(Context                         &context,
 
 	VkInstanceCreateInfo instance_info{VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO};
 	instance_info.pApplicationInfo        = &app;
-	instance_info.enabledExtensionCount   = vkb::to_u32(active_instance_extensions.size());
-	instance_info.ppEnabledExtensionNames = active_instance_extensions.data();
+	instance_info.enabledExtensionCount   = vkb::to_u32(required_instance_extensions.size());
+	instance_info.ppEnabledExtensionNames = required_instance_extensions.data();
 	instance_info.enabledLayerCount       = vkb::to_u32(requested_validation_layers.size());
 	instance_info.ppEnabledLayerNames     = requested_validation_layers.data();
 
@@ -309,10 +307,8 @@ void HelloTriangle::init_instance(Context                         &context,
  * @brief Initializes the Vulkan physical device and logical device.
  *
  * @param context A Vulkan context with an instance already set up.
- * @param required_device_extensions The required Vulkan device extensions.
  */
-void HelloTriangle::init_device(Context                         &context,
-                                const std::vector<const char *> &required_device_extensions)
+void HelloTriangle::init_device(Context &context)
 {
 	LOGI("Initializing vulkan device.");
 
@@ -366,6 +362,8 @@ void HelloTriangle::init_device(Context                         &context,
 	std::vector<VkExtensionProperties> device_extensions(device_extension_count);
 	VK_CHECK(vkEnumerateDeviceExtensionProperties(context.gpu, nullptr, &device_extension_count, device_extensions.data()));
 
+	// Since this sample has visual output, the device needs to support the swapchain extension
+	std::vector<const char *> required_device_extensions{VK_KHR_SWAPCHAIN_EXTENSION_NAME};
 	if (!validate_extensions(required_device_extensions, device_extensions))
 	{
 		throw std::runtime_error("Required device extensions are missing.");
@@ -1081,7 +1079,7 @@ bool HelloTriangle::prepare(const vkb::ApplicationOptions &options)
 {
 	assert(options.window != nullptr);
 
-	init_instance(context, {VK_KHR_SURFACE_EXTENSION_NAME}, {});
+	init_instance(context);
 
 	vk_instance = std::make_unique<vkb::Instance>(context.instance);
 
@@ -1095,7 +1093,7 @@ bool HelloTriangle::prepare(const vkb::ApplicationOptions &options)
 		throw std::runtime_error("Failed to create window surface.");
 	}
 
-	init_device(context, {"VK_KHR_swapchain"});
+	init_device(context);
 
 	init_swapchain(context);
 
diff --git a/samples/api/hello_triangle/hello_triangle.h b/samples/api/hello_triangle/hello_triangle.h
index 09b078af4..a33df2553 100644
--- a/samples/api/hello_triangle/hello_triangle.h
+++ b/samples/api/hello_triangle/hello_triangle.h
@@ -130,12 +130,9 @@ class HelloTriangle : public vkb::Application
 
 	VkShaderStageFlagBits find_shader_stage(const std::string &ext);
 
-	void init_instance(Context                         &context,
-	                   const std::vector<const char *> &required_instance_extensions,
-	                   const std::vector<const char *> &required_validation_layers);
+	void init_instance(Context &context);
 
-	void init_device(Context                         &context,
-	                 const std::vector<const char *> &required_device_extensions);
+	void init_device(Context &context);
 
 	void init_per_frame(Context &context, PerFrame &per_frame);
 

From 68a037fdb23f824d22f99fac8a2d53d6351264bd Mon Sep 17 00:00:00 2001
From: Sascha Willems <webmaster@saschawillems.de>
Date: Sat, 19 Oct 2024 19:13:45 +0200
Subject: [PATCH 06/11] Remove unnecessary passing of the context

---
 samples/api/hello_triangle/hello_triangle.cpp | 68 +++++++++----------
 samples/api/hello_triangle/hello_triangle.h   | 28 ++++----
 2 files changed, 48 insertions(+), 48 deletions(-)

diff --git a/samples/api/hello_triangle/hello_triangle.cpp b/samples/api/hello_triangle/hello_triangle.cpp
index a50688f39..a215fe539 100644
--- a/samples/api/hello_triangle/hello_triangle.cpp
+++ b/samples/api/hello_triangle/hello_triangle.cpp
@@ -158,7 +158,7 @@ VkShaderStageFlagBits HelloTriangle::find_shader_stage(const std::string &ext)
  * @param required_instance_extensions The required Vulkan instance extensions.
  * @param required_validation_layers The required Vulkan validation layers
  */
-void HelloTriangle::init_instance(Context &context)
+void HelloTriangle::init_instance()
 {
 	LOGI("Initializing vulkan instance.");
 
@@ -308,7 +308,7 @@ void HelloTriangle::init_instance(Context &context)
  *
  * @param context A Vulkan context with an instance already set up.
  */
-void HelloTriangle::init_device(Context &context)
+void HelloTriangle::init_device()
 {
 	LOGI("Initializing vulkan device.");
 
@@ -394,7 +394,7 @@ void HelloTriangle::init_device(Context &context)
  * @param context A newly created Vulkan context.
  * @param per_frame The data of a frame.
  */
-void HelloTriangle::init_per_frame(Context &context, PerFrame &per_frame)
+void HelloTriangle::init_per_frame(PerFrame &per_frame)
 {
 	VkFenceCreateInfo info{VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
 	info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
@@ -417,7 +417,7 @@ void HelloTriangle::init_per_frame(Context &context, PerFrame &per_frame)
  * @param context The Vulkan context.
  * @param per_frame The data of a frame.
  */
-void HelloTriangle::teardown_per_frame(Context &context, PerFrame &per_frame)
+void HelloTriangle::teardown_per_frame(PerFrame &per_frame)
 {
 	if (per_frame.queue_submit_fence != VK_NULL_HANDLE)
 	{
@@ -459,7 +459,7 @@ void HelloTriangle::teardown_per_frame(Context &context, PerFrame &per_frame)
  * @brief Initializes the Vulkan swapchain.
  * @param context A Vulkan context with a physical device already set up.
  */
-void HelloTriangle::init_swapchain(Context &context)
+void HelloTriangle::init_swapchain()
 {
 	VkSurfaceCapabilitiesKHR surface_properties;
 	VK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(context.gpu, context.surface, &surface_properties));
@@ -552,7 +552,7 @@ void HelloTriangle::init_swapchain(Context &context)
 
 		for (size_t i = 0; i < image_count; i++)
 		{
-			teardown_per_frame(context, context.per_frame[i]);
+			teardown_per_frame(context.per_frame[i]);
 		}
 
 		context.swapchain_image_views.clear();
@@ -577,7 +577,7 @@ void HelloTriangle::init_swapchain(Context &context)
 
 	for (size_t i = 0; i < image_count; i++)
 	{
-		init_per_frame(context, context.per_frame[i]);
+		init_per_frame(context.per_frame[i]);
 	}
 
 	for (size_t i = 0; i < image_count; i++)
@@ -606,7 +606,7 @@ void HelloTriangle::init_swapchain(Context &context)
  * @brief Initializes the Vulkan render pass.
  * @param context A Vulkan context with a device already set up.
  */
-void HelloTriangle::init_render_pass(Context &context)
+void HelloTriangle::init_render_pass()
 {
 	VkAttachmentDescription attachment = {0};
 	// Backbuffer format.
@@ -673,7 +673,7 @@ void HelloTriangle::init_render_pass(Context &context)
  * @param path The path for the shader (relative to the assets directory).
  * @returns A VkShaderModule handle. Aborts execution if shader creation fails.
  */
-VkShaderModule HelloTriangle::load_shader_module(Context &context, const char *path)
+VkShaderModule HelloTriangle::load_shader_module(const char *path)
 {
 	vkb::GLSLCompiler glsl_compiler;
 
@@ -708,7 +708,7 @@ VkShaderModule HelloTriangle::load_shader_module(Context &context, const char *p
  * @brief Initializes the Vulkan pipeline.
  * @param context A Vulkan context with a device and a render pass already set up.
  */
-void HelloTriangle::init_pipeline(Context &context)
+void HelloTriangle::init_pipeline()
 {
 	// Create a blank pipeline layout.
 	// We are not binding any resources to the pipeline in this first sample.
@@ -760,13 +760,13 @@ void HelloTriangle::init_pipeline(Context &context)
 	// Vertex stage of the pipeline
 	shader_stages[0].sType  = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
 	shader_stages[0].stage  = VK_SHADER_STAGE_VERTEX_BIT;
-	shader_stages[0].module = load_shader_module(context, "triangle.vert");
+	shader_stages[0].module = load_shader_module("triangle.vert");
 	shader_stages[0].pName  = "main";
 
 	// Fragment stage of the pipeline
 	shader_stages[1].sType  = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
 	shader_stages[1].stage  = VK_SHADER_STAGE_FRAGMENT_BIT;
-	shader_stages[1].module = load_shader_module(context, "triangle.frag");
+	shader_stages[1].module = load_shader_module("triangle.frag");
 	shader_stages[1].pName  = "main";
 
 	VkGraphicsPipelineCreateInfo pipe{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO};
@@ -798,7 +798,7 @@ void HelloTriangle::init_pipeline(Context &context)
  * @param[out] image The swapchain index for the acquired image.
  * @returns Vulkan result code
  */
-VkResult HelloTriangle::acquire_next_image(Context &context, uint32_t *image)
+VkResult HelloTriangle::acquire_next_image(uint32_t *image)
 {
 	VkSemaphore acquire_semaphore;
 	if (context.recycled_semaphores.empty())
@@ -857,7 +857,7 @@ VkResult HelloTriangle::acquire_next_image(Context &context, uint32_t *image)
  * @param context A Vulkan context set up for rendering.
  * @param swapchain_index The swapchain index for the image being rendered.
  */
-void HelloTriangle::render_triangle(Context &context, uint32_t swapchain_index)
+void HelloTriangle::render_triangle(uint32_t swapchain_index)
 {
 	// Render to this framebuffer.
 	VkFramebuffer framebuffer = context.swapchain_framebuffers[swapchain_index];
@@ -940,7 +940,7 @@ void HelloTriangle::render_triangle(Context &context, uint32_t swapchain_index)
  * @param index The swapchain index previously obtained from @ref acquire_next_image.
  * @returns Vulkan result code
  */
-VkResult HelloTriangle::present_image(Context &context, uint32_t index)
+VkResult HelloTriangle::present_image(uint32_t index)
 {
 	VkPresentInfoKHR present{VK_STRUCTURE_TYPE_PRESENT_INFO_KHR};
 	present.swapchainCount     = 1;
@@ -956,7 +956,7 @@ VkResult HelloTriangle::present_image(Context &context, uint32_t index)
  * @brief Initializes the Vulkan framebuffers.
  * @param context A Vulkan context with the render pass already set up.
  */
-void HelloTriangle::init_framebuffers(Context &context)
+void HelloTriangle::init_framebuffers()
 {
 	VkDevice device = context.device;
 
@@ -983,7 +983,7 @@ void HelloTriangle::init_framebuffers(Context &context)
  * @brief Tears down the framebuffers. If our swapchain changes, we will call this, and create a new swapchain.
  * @param context The Vulkan context.
  */
-void HelloTriangle::teardown_framebuffers(Context &context)
+void HelloTriangle::teardown_framebuffers()
 {
 	// Wait until device is idle before teardown.
 	vkQueueWaitIdle(context.queue);
@@ -1000,16 +1000,16 @@ void HelloTriangle::teardown_framebuffers(Context &context)
  * @brief Tears down the Vulkan context.
  * @param context The Vulkan context.
  */
-void HelloTriangle::teardown(Context &context)
+void HelloTriangle::teardown()
 {
 	// Don't release anything until the GPU is completely idle.
 	vkDeviceWaitIdle(context.device);
 
-	teardown_framebuffers(context);
+	teardown_framebuffers();
 
 	for (auto &per_frame : context.per_frame)
 	{
-		teardown_per_frame(context, per_frame);
+		teardown_per_frame(per_frame);
 	}
 
 	context.per_frame.clear();
@@ -1072,14 +1072,14 @@ HelloTriangle::HelloTriangle()
 
 HelloTriangle::~HelloTriangle()
 {
-	teardown(context);
+	teardown();
 }
 
 bool HelloTriangle::prepare(const vkb::ApplicationOptions &options)
 {
 	assert(options.window != nullptr);
 
-	init_instance(context);
+	init_instance();
 
 	vk_instance = std::make_unique<vkb::Instance>(context.instance);
 
@@ -1093,14 +1093,14 @@ bool HelloTriangle::prepare(const vkb::ApplicationOptions &options)
 		throw std::runtime_error("Failed to create window surface.");
 	}
 
-	init_device(context);
+	init_device();
 
-	init_swapchain(context);
+	init_swapchain();
 
 	// Create the necessary objects for rendering.
-	init_render_pass(context);
-	init_pipeline(context);
-	init_framebuffers(context);
+	init_render_pass();
+	init_pipeline();
+	init_framebuffers();
 
 	return true;
 }
@@ -1109,13 +1109,13 @@ void HelloTriangle::update(float delta_time)
 {
 	uint32_t index;
 
-	auto res = acquire_next_image(context, &index);
+	auto res = acquire_next_image(&index);
 
 	// Handle outdated error in acquire.
 	if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR)
 	{
 		resize(context.swapchain_dimensions.width, context.swapchain_dimensions.height);
-		res = acquire_next_image(context, &index);
+		res = acquire_next_image(&index);
 	}
 
 	if (res != VK_SUCCESS)
@@ -1124,8 +1124,8 @@ void HelloTriangle::update(float delta_time)
 		return;
 	}
 
-	render_triangle(context, index);
-	res = present_image(context, index);
+	render_triangle(index);
+	res = present_image(index);
 
 	// Handle Outdated error in present.
 	if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR)
@@ -1156,10 +1156,10 @@ bool HelloTriangle::resize(const uint32_t, const uint32_t)
 	}
 
 	vkDeviceWaitIdle(context.device);
-	teardown_framebuffers(context);
+	teardown_framebuffers();
 
-	init_swapchain(context);
-	init_framebuffers(context);
+	init_swapchain();
+	init_framebuffers();
 	return true;
 }
 
diff --git a/samples/api/hello_triangle/hello_triangle.h b/samples/api/hello_triangle/hello_triangle.h
index a33df2553..c35f92ad4 100644
--- a/samples/api/hello_triangle/hello_triangle.h
+++ b/samples/api/hello_triangle/hello_triangle.h
@@ -130,33 +130,33 @@ class HelloTriangle : public vkb::Application
 
 	VkShaderStageFlagBits find_shader_stage(const std::string &ext);
 
-	void init_instance(Context &context);
+	void init_instance();
 
-	void init_device(Context &context);
+	void init_device();
 
-	void init_per_frame(Context &context, PerFrame &per_frame);
+	void init_per_frame(PerFrame &per_frame);
 
-	void teardown_per_frame(Context &context, PerFrame &per_frame);
+	void teardown_per_frame(PerFrame &per_frame);
 
-	void init_swapchain(Context &context);
+	void init_swapchain();
 
-	void init_render_pass(Context &context);
+	void init_render_pass();
 
-	VkShaderModule load_shader_module(Context &context, const char *path);
+	VkShaderModule load_shader_module(const char *path);
 
-	void init_pipeline(Context &context);
+	void init_pipeline();
 
-	VkResult acquire_next_image(Context &context, uint32_t *image);
+	VkResult acquire_next_image(uint32_t *image);
 
-	void render_triangle(Context &context, uint32_t swapchain_index);
+	void render_triangle(uint32_t swapchain_index);
 
-	VkResult present_image(Context &context, uint32_t index);
+	VkResult present_image(uint32_t index);
 
-	void init_framebuffers(Context &context);
+	void init_framebuffers();
 
-	void teardown_framebuffers(Context &context);
+	void teardown_framebuffers();
 
-	void teardown(Context &context);
+	void teardown();
 
   private:
 	Context context;

From 34d6b35358d99755a0ba2cb373e0d0310c9b8e66 Mon Sep 17 00:00:00 2001
From: Sascha Willems <webmaster@saschawillems.de>
Date: Sat, 19 Oct 2024 19:19:07 +0200
Subject: [PATCH 07/11] Move resource destruction into the sample class
 destrutor The teardown function was only used for that anyway and was
 unnecessary

---
 samples/api/hello_triangle/hello_triangle.cpp | 26 +++++--------------
 1 file changed, 7 insertions(+), 19 deletions(-)

diff --git a/samples/api/hello_triangle/hello_triangle.cpp b/samples/api/hello_triangle/hello_triangle.cpp
index a215fe539..c8ffc09e9 100644
--- a/samples/api/hello_triangle/hello_triangle.cpp
+++ b/samples/api/hello_triangle/hello_triangle.cpp
@@ -996,13 +996,14 @@ void HelloTriangle::teardown_framebuffers()
 	context.swapchain_framebuffers.clear();
 }
 
-/**
- * @brief Tears down the Vulkan context.
- * @param context The Vulkan context.
- */
-void HelloTriangle::teardown()
+HelloTriangle::HelloTriangle()
+{
+}
+
+HelloTriangle::~HelloTriangle()
 {
-	// Don't release anything until the GPU is completely idle.
+	// When destroying the application, we need to make sure the GPU is no longer accessing any resources
+	// This is done by doing a device wait idle, which blocks until the GPU signals
 	vkDeviceWaitIdle(context.device);
 
 	teardown_framebuffers();
@@ -1042,39 +1043,26 @@ void HelloTriangle::teardown()
 	if (context.swapchain != VK_NULL_HANDLE)
 	{
 		vkDestroySwapchainKHR(context.device, context.swapchain, nullptr);
-		context.swapchain = VK_NULL_HANDLE;
 	}
 
 	if (context.surface != VK_NULL_HANDLE)
 	{
 		vkDestroySurfaceKHR(context.instance, context.surface, nullptr);
-		context.surface = VK_NULL_HANDLE;
 	}
 
 	if (context.device != VK_NULL_HANDLE)
 	{
 		vkDestroyDevice(context.device, nullptr);
-		context.device = VK_NULL_HANDLE;
 	}
 
 	if (context.debug_callback != VK_NULL_HANDLE)
 	{
 		vkDestroyDebugUtilsMessengerEXT(context.instance, context.debug_callback, nullptr);
-		context.debug_callback = VK_NULL_HANDLE;
 	}
 
 	vk_instance.reset();
 }
 
-HelloTriangle::HelloTriangle()
-{
-}
-
-HelloTriangle::~HelloTriangle()
-{
-	teardown();
-}
-
 bool HelloTriangle::prepare(const vkb::ApplicationOptions &options)
 {
 	assert(options.window != nullptr);

From 9c252f8aaae8b855d5981342c051b7f0389b4c6c Mon Sep 17 00:00:00 2001
From: Sascha Willems <webmaster@saschawillems.de>
Date: Sat, 19 Oct 2024 19:22:25 +0200
Subject: [PATCH 08/11] Remove context parameter from function doc

---
 samples/api/hello_triangle/hello_triangle.cpp | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/samples/api/hello_triangle/hello_triangle.cpp b/samples/api/hello_triangle/hello_triangle.cpp
index c8ffc09e9..d8e165983 100644
--- a/samples/api/hello_triangle/hello_triangle.cpp
+++ b/samples/api/hello_triangle/hello_triangle.cpp
@@ -154,7 +154,6 @@ VkShaderStageFlagBits HelloTriangle::find_shader_stage(const std::string &ext)
 /**
  * @brief Initializes the Vulkan instance.
  *
- * @param context A newly created Vulkan context.
  * @param required_instance_extensions The required Vulkan instance extensions.
  * @param required_validation_layers The required Vulkan validation layers
  */
@@ -305,8 +304,6 @@ void HelloTriangle::init_instance()
 
 /**
  * @brief Initializes the Vulkan physical device and logical device.
- *
- * @param context A Vulkan context with an instance already set up.
  */
 void HelloTriangle::init_device()
 {
@@ -391,7 +388,6 @@ void HelloTriangle::init_device()
 
 /**
  * @brief Initializes per frame data.
- * @param context A newly created Vulkan context.
  * @param per_frame The data of a frame.
  */
 void HelloTriangle::init_per_frame(PerFrame &per_frame)
@@ -414,7 +410,6 @@ void HelloTriangle::init_per_frame(PerFrame &per_frame)
 
 /**
  * @brief Tears down the frame data.
- * @param context The Vulkan context.
  * @param per_frame The data of a frame.
  */
 void HelloTriangle::teardown_per_frame(PerFrame &per_frame)
@@ -457,7 +452,6 @@ void HelloTriangle::teardown_per_frame(PerFrame &per_frame)
 
 /**
  * @brief Initializes the Vulkan swapchain.
- * @param context A Vulkan context with a physical device already set up.
  */
 void HelloTriangle::init_swapchain()
 {
@@ -604,7 +598,6 @@ void HelloTriangle::init_swapchain()
 
 /**
  * @brief Initializes the Vulkan render pass.
- * @param context A Vulkan context with a device already set up.
  */
 void HelloTriangle::init_render_pass()
 {
@@ -669,7 +662,6 @@ void HelloTriangle::init_render_pass()
 
 /**
  * @brief Helper function to load a shader module.
- * @param context A Vulkan context with a device.
  * @param path The path for the shader (relative to the assets directory).
  * @returns A VkShaderModule handle. Aborts execution if shader creation fails.
  */
@@ -706,7 +698,6 @@ VkShaderModule HelloTriangle::load_shader_module(const char *path)
 
 /**
  * @brief Initializes the Vulkan pipeline.
- * @param context A Vulkan context with a device and a render pass already set up.
  */
 void HelloTriangle::init_pipeline()
 {
@@ -794,7 +785,6 @@ void HelloTriangle::init_pipeline()
 
 /**
  * @brief Acquires an image from the swapchain.
- * @param context A Vulkan context with a swapchain already set up.
  * @param[out] image The swapchain index for the acquired image.
  * @returns Vulkan result code
  */
@@ -854,7 +844,6 @@ VkResult HelloTriangle::acquire_next_image(uint32_t *image)
 
 /**
  * @brief Renders a triangle to the specified swapchain image.
- * @param context A Vulkan context set up for rendering.
  * @param swapchain_index The swapchain index for the image being rendered.
  */
 void HelloTriangle::render_triangle(uint32_t swapchain_index)
@@ -936,7 +925,6 @@ void HelloTriangle::render_triangle(uint32_t swapchain_index)
 
 /**
  * @brief Presents an image to the swapchain.
- * @param context The Vulkan context, with a swapchain and per-frame resources already set up.
  * @param index The swapchain index previously obtained from @ref acquire_next_image.
  * @returns Vulkan result code
  */
@@ -954,7 +942,6 @@ VkResult HelloTriangle::present_image(uint32_t index)
 
 /**
  * @brief Initializes the Vulkan framebuffers.
- * @param context A Vulkan context with the render pass already set up.
  */
 void HelloTriangle::init_framebuffers()
 {
@@ -981,7 +968,6 @@ void HelloTriangle::init_framebuffers()
 
 /**
  * @brief Tears down the framebuffers. If our swapchain changes, we will call this, and create a new swapchain.
- * @param context The Vulkan context.
  */
 void HelloTriangle::teardown_framebuffers()
 {

From d37645a4348a9ece86d0a1f3f840a565ee6b181d Mon Sep 17 00:00:00 2001
From: Sascha Willems <webmaster@saschawillems.de>
Date: Sat, 19 Oct 2024 19:25:52 +0200
Subject: [PATCH 09/11] Doc cleanup

---
 samples/api/hello_triangle/hello_triangle.cpp | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/samples/api/hello_triangle/hello_triangle.cpp b/samples/api/hello_triangle/hello_triangle.cpp
index d8e165983..0990d489f 100644
--- a/samples/api/hello_triangle/hello_triangle.cpp
+++ b/samples/api/hello_triangle/hello_triangle.cpp
@@ -153,9 +153,6 @@ VkShaderStageFlagBits HelloTriangle::find_shader_stage(const std::string &ext)
 
 /**
  * @brief Initializes the Vulkan instance.
- *
- * @param required_instance_extensions The required Vulkan instance extensions.
- * @param required_validation_layers The required Vulkan validation layers
  */
 void HelloTriangle::init_instance()
 {

From 67fcc7e31e9996c3142a11d014bd3de16f6e812e Mon Sep 17 00:00:00 2001
From: Sascha Willems <webmaster@saschawillems.de>
Date: Sat, 19 Oct 2024 21:48:10 +0200
Subject: [PATCH 10/11] Remove unnecessary function for frame buffer teardown,
 also remove duplicate queue idle wait Add comments, throw if no device is
 found Males code easier to follow

---
 samples/api/hello_triangle/hello_triangle.cpp | 39 +++++++------------
 samples/api/hello_triangle/hello_triangle.h   |  4 --
 2 files changed, 15 insertions(+), 28 deletions(-)

diff --git a/samples/api/hello_triangle/hello_triangle.cpp b/samples/api/hello_triangle/hello_triangle.cpp
index 0990d489f..247fe77f5 100644
--- a/samples/api/hello_triangle/hello_triangle.cpp
+++ b/samples/api/hello_triangle/hello_triangle.cpp
@@ -314,6 +314,7 @@ void HelloTriangle::init_device()
 		throw std::runtime_error("No physical device found.");
 	}
 
+	// For simplicity, the sample selects the first gpu that has a graphics and present queue
 	std::vector<VkPhysicalDevice> gpus(gpu_count);
 	VK_CHECK(vkEnumeratePhysicalDevices(context.instance, &gpu_count, gpus.data()));
 
@@ -348,7 +349,7 @@ void HelloTriangle::init_device()
 
 	if (context.graphics_queue_index < 0)
 	{
-		LOGE("Did not find suitable queue which supports graphics and presentation.");
+		throw std::runtime_error("Did not find suitable device with a queue that supports graphics and presentation.");
 	}
 
 	uint32_t device_extension_count;
@@ -363,9 +364,8 @@ void HelloTriangle::init_device()
 		throw std::runtime_error("Required device extensions are missing.");
 	}
 
-	float queue_priority = 1.0f;
-
-	// Create one queue
+	// The sample uses a single graphics queue
+	const float queue_priority = 1.0f;
 	VkDeviceQueueCreateInfo queue_info{VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO};
 	queue_info.queueFamilyIndex = context.graphics_queue_index;
 	queue_info.queueCount       = 1;
@@ -942,7 +942,7 @@ VkResult HelloTriangle::present_image(uint32_t index)
  */
 void HelloTriangle::init_framebuffers()
 {
-	VkDevice device = context.device;
+	context.swapchain_framebuffers.clear();
 
 	// Create framebuffer for each swapchain image view
 	for (auto &image_view : context.swapchain_image_views)
@@ -957,28 +957,12 @@ void HelloTriangle::init_framebuffers()
 		fb_info.layers          = 1;
 
 		VkFramebuffer framebuffer;
-		VK_CHECK(vkCreateFramebuffer(device, &fb_info, nullptr, &framebuffer));
+		VK_CHECK(vkCreateFramebuffer(context.device, &fb_info, nullptr, &framebuffer));
 
 		context.swapchain_framebuffers.push_back(framebuffer);
 	}
 }
 
-/**
- * @brief Tears down the framebuffers. If our swapchain changes, we will call this, and create a new swapchain.
- */
-void HelloTriangle::teardown_framebuffers()
-{
-	// Wait until device is idle before teardown.
-	vkQueueWaitIdle(context.queue);
-
-	for (auto &framebuffer : context.swapchain_framebuffers)
-	{
-		vkDestroyFramebuffer(context.device, framebuffer, nullptr);
-	}
-
-	context.swapchain_framebuffers.clear();
-}
-
 HelloTriangle::HelloTriangle()
 {
 }
@@ -989,7 +973,10 @@ HelloTriangle::~HelloTriangle()
 	// This is done by doing a device wait idle, which blocks until the GPU signals
 	vkDeviceWaitIdle(context.device);
 
-	teardown_framebuffers();
+	for (auto &framebuffer : context.swapchain_framebuffers)
+	{
+		vkDestroyFramebuffer(context.device, framebuffer, nullptr);
+	}
 
 	for (auto &per_frame : context.per_frame)
 	{
@@ -1127,7 +1114,11 @@ bool HelloTriangle::resize(const uint32_t, const uint32_t)
 	}
 
 	vkDeviceWaitIdle(context.device);
-	teardown_framebuffers();
+
+	for (auto &framebuffer : context.swapchain_framebuffers)
+	{
+		vkDestroyFramebuffer(context.device, framebuffer, nullptr);
+	}
 
 	init_swapchain();
 	init_framebuffers();
diff --git a/samples/api/hello_triangle/hello_triangle.h b/samples/api/hello_triangle/hello_triangle.h
index c35f92ad4..5a23153a2 100644
--- a/samples/api/hello_triangle/hello_triangle.h
+++ b/samples/api/hello_triangle/hello_triangle.h
@@ -154,10 +154,6 @@ class HelloTriangle : public vkb::Application
 
 	void init_framebuffers();
 
-	void teardown_framebuffers();
-
-	void teardown();
-
   private:
 	Context context;
 

From dab29d1295714c64e5b9c90dde1a19c1e752d8d6 Mon Sep 17 00:00:00 2001
From: Sascha Willems <webmaster@saschawillems.de>
Date: Sat, 19 Oct 2024 21:50:23 +0200
Subject: [PATCH 11/11] Making clang format happy

---
 samples/api/hello_triangle/hello_triangle.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/samples/api/hello_triangle/hello_triangle.cpp b/samples/api/hello_triangle/hello_triangle.cpp
index 247fe77f5..b4b378907 100644
--- a/samples/api/hello_triangle/hello_triangle.cpp
+++ b/samples/api/hello_triangle/hello_triangle.cpp
@@ -366,6 +366,7 @@ void HelloTriangle::init_device()
 
 	// The sample uses a single graphics queue
 	const float queue_priority = 1.0f;
+
 	VkDeviceQueueCreateInfo queue_info{VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO};
 	queue_info.queueFamilyIndex = context.graphics_queue_index;
 	queue_info.queueCount       = 1;