feat(renderer): contextn, test utils, refactors & changes
This commit is contained in:
		
							parent
							
								
									405c707e23
								
							
						
					
					
						commit
						5148b8836c
					
				
					 23 changed files with 836 additions and 155 deletions
				
			
		| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
add_library_module(renderer
 | 
					add_library_module(renderer
 | 
				
			||||||
    system.cpp
 | 
					    system.cpp
 | 
				
			||||||
 | 
					    vk/debug/messenger.cpp
 | 
				
			||||||
    vk/context/instance.cpp
 | 
					    vk/context/instance.cpp
 | 
				
			||||||
    vk/context/surface.cpp
 | 
					    vk/context/surface.cpp
 | 
				
			||||||
    vk/context/device.cpp
 | 
					    vk/context/device.cpp
 | 
				
			||||||
| 
						 | 
					@ -12,6 +13,7 @@ target_link_libraries(renderer
 | 
				
			||||||
PUBLIC 
 | 
					PUBLIC 
 | 
				
			||||||
    app 
 | 
					    app 
 | 
				
			||||||
    ecs
 | 
					    ecs
 | 
				
			||||||
 | 
					    memory
 | 
				
			||||||
PRIVATE
 | 
					PRIVATE
 | 
				
			||||||
    surface
 | 
					    surface
 | 
				
			||||||
    pthread
 | 
					    pthread
 | 
				
			||||||
| 
						 | 
					@ -19,6 +21,8 @@ PRIVATE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_test_module(renderer 
 | 
					add_test_module(renderer 
 | 
				
			||||||
    system.test.cpp
 | 
					    system.test.cpp
 | 
				
			||||||
 | 
					    vk/test_utils.cpp
 | 
				
			||||||
 | 
					    vk/debug/messenger.test.cpp
 | 
				
			||||||
    vk/context/instance.test.cpp
 | 
					    vk/context/instance.test.cpp
 | 
				
			||||||
    vk/context/surface.test.cpp
 | 
					    vk/context/surface.test.cpp
 | 
				
			||||||
    vk/context/device.test.cpp
 | 
					    vk/context/device.test.cpp
 | 
				
			||||||
| 
						 | 
					@ -26,3 +30,8 @@ add_test_module(renderer
 | 
				
			||||||
    vk/context/context.test.cpp
 | 
					    vk/context/context.test.cpp
 | 
				
			||||||
    vk/pipeline.test.cpp
 | 
					    vk/pipeline.test.cpp
 | 
				
			||||||
) 
 | 
					) 
 | 
				
			||||||
 | 
					target_link_libraries(renderer_tests
 | 
				
			||||||
 | 
					PRIVATE
 | 
				
			||||||
 | 
					    surface
 | 
				
			||||||
 | 
					    pthread
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -108,7 +108,7 @@ private:
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Suite raii = [] {
 | 
					Suite raii = "raii"_suite = [] {
 | 
				
			||||||
	Case { "happy path won't throw" } = [&] {
 | 
						Case { "happy path won't throw" } = [&] {
 | 
				
			||||||
		ignore = create_system();
 | 
							ignore = create_system();
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,3 @@
 | 
				
			||||||
#include <ranges>
 | 
					 | 
				
			||||||
#include <renderer/vk/context/context.hpp>
 | 
					#include <renderer/vk/context/context.hpp>
 | 
				
			||||||
#include <renderer/vk/context/instance.hpp>
 | 
					#include <renderer/vk/context/instance.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										0
									
								
								modules/renderer/private/vk/context/context.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								modules/renderer/private/vk/context/context.test.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -1,9 +1,14 @@
 | 
				
			||||||
#include <renderer/vk/context/device.hpp>
 | 
					#include <renderer/vk/context/device.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/context/instance.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/context/surface.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/debug/validation.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace lt::renderer::vk {
 | 
					namespace lt::renderer::vk {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Device::Device(const Surface &surface)
 | 
					Device::Device(const Surface &surface)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						ensure(surface.vk(), "Failed to initialize vk::Device: null vulkan surface");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	initialize_physical_device();
 | 
						initialize_physical_device();
 | 
				
			||||||
	initialize_logical_device();
 | 
						initialize_logical_device();
 | 
				
			||||||
	Instance::load_device_functions(m_device);
 | 
						Instance::load_device_functions(m_device);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,15 +1,14 @@
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <memory/pointer_types/null_on_move.hpp>
 | 
					#include <memory/pointer_types/null_on_move.hpp>
 | 
				
			||||||
#include <renderer/vk/context/instance.hpp>
 | 
					#include <renderer/vk/vulkan.hpp>
 | 
				
			||||||
#include <renderer/vk/context/surface.hpp>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace lt::renderer::vk {
 | 
					namespace lt::renderer::vk {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Device
 | 
					class Device
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	Device(const Surface &surface);
 | 
						Device(const class Surface &surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	~Device();
 | 
						~Device();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,7 +40,7 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void initialize_logical_device();
 | 
						void initialize_logical_device();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void initialize_queue(const Surface &surface);
 | 
						void initialize_queue(const class Surface &surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] auto find_suitable_queue_family() const -> uint32_t;
 | 
						[[nodiscard]] auto find_suitable_queue_family() const -> uint32_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										99
									
								
								modules/renderer/private/vk/context/device.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								modules/renderer/private/vk/context/device.test.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,99 @@
 | 
				
			||||||
 | 
					#include <ranges>
 | 
				
			||||||
 | 
					#include <renderer/vk/context/device.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/context/surface.hpp>
 | 
				
			||||||
 | 
					#include <surface/components.hpp>
 | 
				
			||||||
 | 
					#include <surface/system.hpp>
 | 
				
			||||||
 | 
					#include <test/test.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace lt;
 | 
				
			||||||
 | 
					using renderer::vk::Device;
 | 
				
			||||||
 | 
					using renderer::vk::Surface;
 | 
				
			||||||
 | 
					using test::Case;
 | 
				
			||||||
 | 
					using test::expect_ne;
 | 
				
			||||||
 | 
					using test::expect_throw;
 | 
				
			||||||
 | 
					using test::Suite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					constexpr auto resolution = math::uvec2 { 800u, 600u };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Suite raii = "device_raii"_suite = [] {
 | 
				
			||||||
 | 
						Case { "happy path won't throw" } = [] {
 | 
				
			||||||
 | 
							auto registry = create_ref<ecs::Registry>();
 | 
				
			||||||
 | 
							auto surface_system = surface::System { registry };
 | 
				
			||||||
 | 
							auto entity = ecs::Entity { registry, registry->create_entity() };
 | 
				
			||||||
 | 
							entity.add<surface::SurfaceComponent>(surface::SurfaceComponent::CreateInfo {
 | 
				
			||||||
 | 
							    .resolution = resolution,
 | 
				
			||||||
 | 
							    .visible = true,
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto surface = Surface { entity };
 | 
				
			||||||
 | 
							auto device = Device { surface };
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "many won't freeze/throw" } = [] {
 | 
				
			||||||
 | 
							auto registry = create_ref<ecs::Registry>();
 | 
				
			||||||
 | 
							auto surface_system = surface::System { registry };
 | 
				
			||||||
 | 
							auto entity = ecs::Entity { registry, registry->create_entity() };
 | 
				
			||||||
 | 
							entity.add<surface::SurfaceComponent>(surface::SurfaceComponent::CreateInfo {
 | 
				
			||||||
 | 
							    .resolution = resolution,
 | 
				
			||||||
 | 
							    .visible = true,
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
							auto surface = Surface { entity };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// it takes a loong time to initialize vulkan + setup device
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 10))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Device { surface };
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "unhappy path throws" } = [] {
 | 
				
			||||||
 | 
							auto registry = create_ref<ecs::Registry>();
 | 
				
			||||||
 | 
							auto surface_system = surface::System { registry };
 | 
				
			||||||
 | 
							auto entity = ecs::Entity { registry, registry->create_entity() };
 | 
				
			||||||
 | 
							entity.add<surface::SurfaceComponent>(surface::SurfaceComponent::CreateInfo {
 | 
				
			||||||
 | 
							    .resolution = resolution,
 | 
				
			||||||
 | 
							    .visible = true,
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto moved_out_surface = Surface { entity };
 | 
				
			||||||
 | 
							auto surface = std::move(moved_out_surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_throw([&] { Device { moved_out_surface }; });
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "post construct has correct state" } = [] {
 | 
				
			||||||
 | 
							auto registry = create_ref<ecs::Registry>();
 | 
				
			||||||
 | 
							auto surface_system = surface::System { registry };
 | 
				
			||||||
 | 
							auto entity = ecs::Entity { registry, registry->create_entity() };
 | 
				
			||||||
 | 
							entity.add<surface::SurfaceComponent>(surface::SurfaceComponent::CreateInfo {
 | 
				
			||||||
 | 
							    .resolution = resolution,
 | 
				
			||||||
 | 
							    .visible = true,
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto surface = Surface { entity };
 | 
				
			||||||
 | 
							auto device = Device { surface };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto &index : device.get_family_indices())
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								expect_ne(index, VK_QUEUE_FAMILY_IGNORED);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							test::expect_true(device.physical());
 | 
				
			||||||
 | 
							test::expect_true(device.vk());
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "post destruct has correct state" } = [] {
 | 
				
			||||||
 | 
							auto registry = create_ref<ecs::Registry>();
 | 
				
			||||||
 | 
							auto surface_system = surface::System { registry };
 | 
				
			||||||
 | 
							auto entity = ecs::Entity { registry, registry->create_entity() };
 | 
				
			||||||
 | 
							entity.add<surface::SurfaceComponent>(surface::SurfaceComponent::CreateInfo {
 | 
				
			||||||
 | 
							    .resolution = resolution,
 | 
				
			||||||
 | 
							    .visible = true,
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto surface = Surface { entity };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								auto device = Device { surface };
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
#include <app/system.hpp>
 | 
					#include <app/system.hpp>
 | 
				
			||||||
#include <renderer/vk/context/instance.hpp>
 | 
					#include <renderer/vk/context/instance.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/debug/validation.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(_WIN32)
 | 
					#if defined(_WIN32)
 | 
				
			||||||
	#error "Unsupported platform (currently)"
 | 
						#error "Unsupported platform (currently)"
 | 
				
			||||||
| 
						 | 
					@ -113,17 +114,11 @@ Instance::Instance()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	initialize_instance();
 | 
						initialize_instance();
 | 
				
			||||||
	load_instance_functions();
 | 
						load_instance_functions();
 | 
				
			||||||
	initialize_debug_messenger();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Instance::~Instance()
 | 
					Instance::~Instance()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (m_instance)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		vk_destroy_debug_messenger(m_instance, m_debug_messenger, nullptr);
 | 
					 | 
				
			||||||
	vk_destroy_instance(m_instance, nullptr);
 | 
						vk_destroy_instance(m_instance, nullptr);
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	unload_library();
 | 
						unload_library();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -143,12 +138,83 @@ void Instance::initialize_instance()
 | 
				
			||||||
		VK_KHR_SURFACE_EXTENSION_NAME,
 | 
							VK_KHR_SURFACE_EXTENSION_NAME,
 | 
				
			||||||
		VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
 | 
							VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const char *layer_name = "VK_LAYER_KHRONOS_validation";
 | 
				
			||||||
 | 
						const auto setting_validate_core = VkBool32 { VK_TRUE };
 | 
				
			||||||
 | 
						const auto setting_validate_sync = VkBool32 { VK_TRUE };
 | 
				
			||||||
 | 
						const auto setting_thread_safety = VkBool32 { VK_TRUE };
 | 
				
			||||||
 | 
						const auto *setting_debug_action = "";
 | 
				
			||||||
 | 
						const auto setting_enable_message_limit = VkBool32 { VK_TRUE };
 | 
				
			||||||
 | 
						const auto setting_duplicate_message_limit = uint32_t { 3u };
 | 
				
			||||||
 | 
						auto setting_report_flags = std::array<const char *, 5> {
 | 
				
			||||||
 | 
							"info", "warn", "perf", "error", "verbose",
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const auto settings = std::array<VkLayerSettingEXT, 7>({
 | 
				
			||||||
 | 
						    {
 | 
				
			||||||
 | 
						        .pLayerName = layer_name,
 | 
				
			||||||
 | 
						        .pSettingName = "validate_core",
 | 
				
			||||||
 | 
						        .type = VK_LAYER_SETTING_TYPE_BOOL32_EXT,
 | 
				
			||||||
 | 
						        .valueCount = 1,
 | 
				
			||||||
 | 
						        .pValues = &setting_validate_core,
 | 
				
			||||||
 | 
						    },
 | 
				
			||||||
 | 
						    {
 | 
				
			||||||
 | 
						        .pLayerName = layer_name,
 | 
				
			||||||
 | 
						        .pSettingName = "validate_sync",
 | 
				
			||||||
 | 
						        .type = VK_LAYER_SETTING_TYPE_BOOL32_EXT,
 | 
				
			||||||
 | 
						        .valueCount = 1,
 | 
				
			||||||
 | 
						        .pValues = &setting_validate_sync,
 | 
				
			||||||
 | 
						    },
 | 
				
			||||||
 | 
						    {
 | 
				
			||||||
 | 
						        .pLayerName = layer_name,
 | 
				
			||||||
 | 
						        .pSettingName = "thread_safety",
 | 
				
			||||||
 | 
						        .type = VK_LAYER_SETTING_TYPE_BOOL32_EXT,
 | 
				
			||||||
 | 
						        .valueCount = 1,
 | 
				
			||||||
 | 
						        .pValues = &setting_thread_safety,
 | 
				
			||||||
 | 
						    },
 | 
				
			||||||
 | 
						    {
 | 
				
			||||||
 | 
						        .pLayerName = layer_name,
 | 
				
			||||||
 | 
						        .pSettingName = "debug_action",
 | 
				
			||||||
 | 
						        .type = VK_LAYER_SETTING_TYPE_STRING_EXT,
 | 
				
			||||||
 | 
						        .valueCount = 1,
 | 
				
			||||||
 | 
						        .pValues = static_cast<const void *>(&setting_debug_action),
 | 
				
			||||||
 | 
						    },
 | 
				
			||||||
 | 
						    {
 | 
				
			||||||
 | 
						        .pLayerName = layer_name,
 | 
				
			||||||
 | 
						        .pSettingName = "report_flags",
 | 
				
			||||||
 | 
						        .type = VK_LAYER_SETTING_TYPE_STRING_EXT,
 | 
				
			||||||
 | 
						        .valueCount = setting_report_flags.size(),
 | 
				
			||||||
 | 
						        .pValues = static_cast<const void *>(setting_report_flags.data()),
 | 
				
			||||||
 | 
						    },
 | 
				
			||||||
 | 
						    {
 | 
				
			||||||
 | 
						        .pLayerName = layer_name,
 | 
				
			||||||
 | 
						        .pSettingName = "enable_message_limit",
 | 
				
			||||||
 | 
						        .type = VK_LAYER_SETTING_TYPE_BOOL32_EXT,
 | 
				
			||||||
 | 
						        .valueCount = 1,
 | 
				
			||||||
 | 
						        .pValues = &setting_enable_message_limit,
 | 
				
			||||||
 | 
						    },
 | 
				
			||||||
 | 
						    {
 | 
				
			||||||
 | 
						        .pLayerName = layer_name,
 | 
				
			||||||
 | 
						        .pSettingName = "duplicate_message_limit",
 | 
				
			||||||
 | 
						        .type = VK_LAYER_SETTING_TYPE_UINT32_EXT,
 | 
				
			||||||
 | 
						        .valueCount = 1u,
 | 
				
			||||||
 | 
						        .pValues = &setting_duplicate_message_limit,
 | 
				
			||||||
 | 
						    },
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const VkLayerSettingsCreateInfoEXT layer_settings_create_info = {
 | 
				
			||||||
 | 
							.sType = VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT,
 | 
				
			||||||
 | 
							.settingCount = settings.size(),
 | 
				
			||||||
 | 
							.pSettings = settings.data()
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto layers = std::vector<const char *> {
 | 
						auto layers = std::vector<const char *> {
 | 
				
			||||||
		"VK_LAYER_KHRONOS_validation",
 | 
							"VK_LAYER_KHRONOS_validation",
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto instance_info = VkInstanceCreateInfo {
 | 
						auto instance_info = VkInstanceCreateInfo {
 | 
				
			||||||
		.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
 | 
							.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
 | 
				
			||||||
 | 
							.pNext = &layer_settings_create_info,
 | 
				
			||||||
		.pApplicationInfo = &app_info,
 | 
							.pApplicationInfo = &app_info,
 | 
				
			||||||
		.enabledLayerCount = static_cast<uint32_t>(layers.size()),
 | 
							.enabledLayerCount = static_cast<uint32_t>(layers.size()),
 | 
				
			||||||
		.ppEnabledLayerNames = layers.data(),
 | 
							.ppEnabledLayerNames = layers.data(),
 | 
				
			||||||
| 
						 | 
					@ -174,32 +240,6 @@ void Instance::initialize_instance()
 | 
				
			||||||
	ensure(m_instance, "Failed to create vulkan instance");
 | 
						ensure(m_instance, "Failed to create vulkan instance");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Instance::initialize_debug_messenger()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	const auto info = VkDebugUtilsMessengerCreateInfoEXT {
 | 
					 | 
				
			||||||
		.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT
 | 
					 | 
				
			||||||
		                   | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT
 | 
					 | 
				
			||||||
		                   | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
 | 
					 | 
				
			||||||
		                   | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT
 | 
					 | 
				
			||||||
		               | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT
 | 
					 | 
				
			||||||
		               | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		.pfnUserCallback = &validation_layers_callback,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		.pUserData = {},
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ensure(
 | 
					 | 
				
			||||||
	    !vk_create_debug_messenger(m_instance, &info, nullptr, &m_debug_messenger),
 | 
					 | 
				
			||||||
	    "Failed to create vulkan debug utils messenger"
 | 
					 | 
				
			||||||
	);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Instance::load_library()
 | 
					void Instance::load_library()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	library = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
 | 
						library = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,103 +1,9 @@
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VK_NO_PROTOTYPES
 | 
					#include <renderer/vk/vulkan.hpp>
 | 
				
			||||||
#define VK_USE_PLATFORM_XLIB_KHR
 | 
					 | 
				
			||||||
#include <vulkan/vulkan.h>
 | 
					 | 
				
			||||||
#include <vulkan/vulkan_xlib.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace lt::renderer::vk {
 | 
					namespace lt::renderer::vk {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline void vkc(VkResult result)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (result)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		throw std::runtime_error {
 | 
					 | 
				
			||||||
			std::format("Vulkan call failed with result: {}", std::to_underlying(result))
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables)
 | 
					 | 
				
			||||||
// global functions
 | 
					 | 
				
			||||||
extern PFN_vkGetInstanceProcAddr vk_get_instance_proc_address;
 | 
					 | 
				
			||||||
extern PFN_vkCreateInstance vk_create_instance;
 | 
					 | 
				
			||||||
extern PFN_vkEnumerateInstanceExtensionProperties vk_enumerate_instance_extension_properties;
 | 
					 | 
				
			||||||
extern PFN_vkEnumerateInstanceLayerProperties vk_enumerate_instance_layer_properties;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// instance functions
 | 
					 | 
				
			||||||
extern PFN_vkDestroyInstance vk_destroy_instance;
 | 
					 | 
				
			||||||
extern PFN_vkEnumeratePhysicalDevices vk_enumerate_physical_devices;
 | 
					 | 
				
			||||||
extern PFN_vkGetPhysicalDeviceProperties vk_get_physical_device_properties;
 | 
					 | 
				
			||||||
extern PFN_vkGetPhysicalDeviceQueueFamilyProperties vk_get_physical_device_queue_family_properties;
 | 
					 | 
				
			||||||
extern PFN_vkCreateDevice vk_create_device;
 | 
					 | 
				
			||||||
extern PFN_vkGetDeviceProcAddr vk_get_device_proc_address;
 | 
					 | 
				
			||||||
extern PFN_vkDestroyDevice vk_destroy_device;
 | 
					 | 
				
			||||||
extern PFN_vkGetPhysicalDeviceFeatures vk_get_physical_device_features;
 | 
					 | 
				
			||||||
extern PFN_vkEnumerateDeviceExtensionProperties vk_enumerate_device_extension_properties;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// extension instance functions
 | 
					 | 
				
			||||||
extern PFN_vkCmdBeginDebugUtilsLabelEXT vk_cmd_begin_debug_label;
 | 
					 | 
				
			||||||
extern PFN_vkCmdEndDebugUtilsLabelEXT vk_cmd_end_debug_label;
 | 
					 | 
				
			||||||
extern PFN_vkCmdInsertDebugUtilsLabelEXT vk_cmd_insert_debug_label;
 | 
					 | 
				
			||||||
extern PFN_vkCreateDebugUtilsMessengerEXT vk_create_debug_messenger;
 | 
					 | 
				
			||||||
extern PFN_vkDestroyDebugUtilsMessengerEXT vk_destroy_debug_messenger;
 | 
					 | 
				
			||||||
extern PFN_vkQueueBeginDebugUtilsLabelEXT vk_queue_begin_debug_label;
 | 
					 | 
				
			||||||
extern PFN_vkQueueEndDebugUtilsLabelEXT vk_queue_end_debug_label;
 | 
					 | 
				
			||||||
extern PFN_vkQueueInsertDebugUtilsLabelEXT vk_queue_insert_debug_label;
 | 
					 | 
				
			||||||
extern PFN_vkSetDebugUtilsObjectNameEXT vk_set_debug_object_name;
 | 
					 | 
				
			||||||
extern PFN_vkSetDebugUtilsObjectTagEXT vk_set_debug_object_tag;
 | 
					 | 
				
			||||||
extern PFN_vkSubmitDebugUtilsMessageEXT vk_submit_debug_message;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// surface instance functions
 | 
					 | 
				
			||||||
extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vk_get_physical_device_surface_support;
 | 
					 | 
				
			||||||
extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vk_get_physical_device_surface_capabilities;
 | 
					 | 
				
			||||||
extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vk_get_physical_device_surface_formats;
 | 
					 | 
				
			||||||
extern PFN_vkCreateXlibSurfaceKHR vk_create_xlib_surface_khr;
 | 
					 | 
				
			||||||
extern PFN_vkDestroySurfaceKHR vk_destroy_surface_khr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// device functions
 | 
					 | 
				
			||||||
extern PFN_vkGetDeviceQueue vk_get_device_queue;
 | 
					 | 
				
			||||||
extern PFN_vkCreateCommandPool vk_create_command_pool;
 | 
					 | 
				
			||||||
extern PFN_vkDestroyCommandPool vk_destroy_command_pool;
 | 
					 | 
				
			||||||
extern PFN_vkAllocateCommandBuffers vk_allocate_command_buffers;
 | 
					 | 
				
			||||||
extern PFN_vkFreeCommandBuffers vk_free_command_buffers;
 | 
					 | 
				
			||||||
extern PFN_vkBeginCommandBuffer vk_begin_command_buffer;
 | 
					 | 
				
			||||||
extern PFN_vkEndCommandBuffer vk_end_command_buffer;
 | 
					 | 
				
			||||||
extern PFN_vkCmdPipelineBarrier vk_cmd_pipeline_barrier;
 | 
					 | 
				
			||||||
extern PFN_vkQueueSubmit vk_queue_submit;
 | 
					 | 
				
			||||||
extern PFN_vkQueueWaitIdle vk_queue_wait_idle;
 | 
					 | 
				
			||||||
extern PFN_vkDeviceWaitIdle vk_device_wait_idle;
 | 
					 | 
				
			||||||
extern PFN_vkCreateFence vk_create_fence;
 | 
					 | 
				
			||||||
extern PFN_vkDestroyFence vk_destroy_fence;
 | 
					 | 
				
			||||||
extern PFN_vkWaitForFences vk_wait_for_fences;
 | 
					 | 
				
			||||||
extern PFN_vkResetFences vk_reset_fences;
 | 
					 | 
				
			||||||
extern PFN_vkCreateSemaphore vk_create_semaphore;
 | 
					 | 
				
			||||||
extern PFN_vkDestroySemaphore vk_destroy_semaphore;
 | 
					 | 
				
			||||||
extern PFN_vkCreateSwapchainKHR vk_create_swapchain_khr;
 | 
					 | 
				
			||||||
extern PFN_vkDestroySwapchainKHR vk_destroy_swapchain_khr;
 | 
					 | 
				
			||||||
extern PFN_vkGetSwapchainImagesKHR vk_get_swapchain_images_khr;
 | 
					 | 
				
			||||||
extern PFN_vkAcquireNextImageKHR vk_acquire_next_image_khr;
 | 
					 | 
				
			||||||
extern PFN_vkQueuePresentKHR vk_queue_present_khr;
 | 
					 | 
				
			||||||
extern PFN_vkCreateImageView vk_create_image_view;
 | 
					 | 
				
			||||||
extern PFN_vkDestroyImageView vk_destroy_image_view;
 | 
					 | 
				
			||||||
extern PFN_vkCreateRenderPass vk_create_render_pass;
 | 
					 | 
				
			||||||
extern PFN_vkDestroyRenderPass vk_destroy_render_pass;
 | 
					 | 
				
			||||||
extern PFN_vkCreateFramebuffer vk_create_frame_buffer;
 | 
					 | 
				
			||||||
extern PFN_vkDestroyFramebuffer vk_destroy_frame_buffer;
 | 
					 | 
				
			||||||
extern PFN_vkCreateShaderModule vk_create_shader_module;
 | 
					 | 
				
			||||||
extern PFN_vkDestroyShaderModule vk_destroy_shader_module;
 | 
					 | 
				
			||||||
extern PFN_vkCreatePipelineLayout vk_create_pipeline_layout;
 | 
					 | 
				
			||||||
extern PFN_vkDestroyPipelineLayout vk_destroy_pipeline_layout;
 | 
					 | 
				
			||||||
extern PFN_vkCreateGraphicsPipelines vk_create_graphics_pipelines;
 | 
					 | 
				
			||||||
extern PFN_vkDestroyPipeline vk_destroy_pipeline;
 | 
					 | 
				
			||||||
extern PFN_vkCmdBeginRenderPass vk_cmd_begin_render_pass;
 | 
					 | 
				
			||||||
extern PFN_vkCmdEndRenderPass vk_cmd_end_render_pass;
 | 
					 | 
				
			||||||
extern PFN_vkCmdBindPipeline vk_cmd_bind_pipeline;
 | 
					 | 
				
			||||||
extern PFN_vkCmdDraw vk_cmd_draw;
 | 
					 | 
				
			||||||
extern PFN_vkCmdSetViewport vk_cmd_set_viewport;
 | 
					 | 
				
			||||||
extern PFN_vkCmdSetScissor vk_cmd_set_scissors;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Responsible for dynamically loading Vulkan library/functions.
 | 
					 * Responsible for dynamically loading Vulkan library/functions.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -141,8 +47,6 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void initialize_instance();
 | 
						void initialize_instance();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void initialize_debug_messenger();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void load_library();
 | 
						void load_library();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void unload_library();
 | 
						void unload_library();
 | 
				
			||||||
| 
						 | 
					@ -154,8 +58,6 @@ private:
 | 
				
			||||||
	void load_device_functions_impl(VkDevice device);
 | 
						void load_device_functions_impl(VkDevice device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	VkInstance m_instance = VK_NULL_HANDLE;
 | 
						VkInstance m_instance = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	VkDebugUtilsMessengerEXT m_debug_messenger = VK_NULL_HANDLE;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace lt::renderer::vk
 | 
					} // namespace lt::renderer::vk
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										95
									
								
								modules/renderer/private/vk/context/instance.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								modules/renderer/private/vk/context/instance.test.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,95 @@
 | 
				
			||||||
 | 
					#include <renderer/vk/context/instance.hpp>
 | 
				
			||||||
 | 
					#include <test/test.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace lt;
 | 
				
			||||||
 | 
					using renderer::vk::Instance;
 | 
				
			||||||
 | 
					using test::Case;
 | 
				
			||||||
 | 
					using test::expect_not_nullptr;
 | 
				
			||||||
 | 
					using test::Suite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NOLINTNEXTLINE
 | 
				
			||||||
 | 
					Suite raii = "raii"_suite = [] {
 | 
				
			||||||
 | 
						Case { "post singleton insantiation state is correct" } = [] {
 | 
				
			||||||
 | 
							expect_not_nullptr(Instance::get());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							using namespace renderer::vk;
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_get_instance_proc_address);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_create_instance);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_enumerate_instance_extension_properties);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_enumerate_instance_layer_properties);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_destroy_instance);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_enumerate_physical_devices);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_get_physical_device_properties);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_get_physical_device_queue_family_properties);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_create_device);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_get_device_proc_address);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_destroy_device);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_get_physical_device_features);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_enumerate_device_extension_properties);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_cmd_begin_debug_label);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_cmd_end_debug_label);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_cmd_insert_debug_label);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_create_debug_messenger);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_destroy_debug_messenger);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_queue_begin_debug_label);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_queue_end_debug_label);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_queue_insert_debug_label);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_set_debug_object_name);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_set_debug_object_tag);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_submit_debug_message);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_get_physical_device_surface_support);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_get_physical_device_surface_capabilities);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_get_physical_device_surface_formats);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_create_xlib_surface_khr);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_destroy_surface_khr);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "post load device functions state is correct" } = [] {
 | 
				
			||||||
 | 
							using namespace renderer::vk;
 | 
				
			||||||
 | 
							expect_not_nullptr(Instance::get());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_get_device_queue);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_create_command_pool);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_destroy_command_pool);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_allocate_command_buffers);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_free_command_buffers);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_begin_command_buffer);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_end_command_buffer);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_cmd_pipeline_barrier);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_queue_submit);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_queue_wait_idle);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_device_wait_idle);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_create_fence);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_destroy_fence);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_wait_for_fences);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_reset_fences);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_create_semaphore);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_destroy_semaphore);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_create_swapchain_khr);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_destroy_swapchain_khr);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_get_swapchain_images_khr);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_acquire_next_image_khr);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_queue_present_khr);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_create_image_view);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_destroy_image_view);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_create_render_pass);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_destroy_render_pass);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_create_frame_buffer);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_destroy_frame_buffer);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_create_shader_module);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_destroy_shader_module);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_create_pipeline_layout);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_destroy_pipeline_layout);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_create_graphics_pipelines);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_destroy_pipeline);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_cmd_begin_render_pass);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_cmd_end_render_pass);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_cmd_bind_pipeline);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_cmd_draw);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_cmd_set_viewport);
 | 
				
			||||||
 | 
							expect_not_nullptr(vk_cmd_set_scissors);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,3 @@
 | 
				
			||||||
#include <lt_debug/assertions.hpp>
 | 
					 | 
				
			||||||
#include <renderer/vk/context/surface.hpp>
 | 
					#include <renderer/vk/context/surface.hpp>
 | 
				
			||||||
#include <surface/components.hpp>
 | 
					#include <surface/components.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,8 +7,8 @@ Surface::Surface(const ecs::Entity &surface_entity)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const auto &component = surface_entity.get<surface::SurfaceComponent>();
 | 
						const auto &component = surface_entity.get<surface::SurfaceComponent>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	esnure(component.get_native_data().display, "Failed to initialize usrface: null x-display");
 | 
						ensure(component.get_native_data().display, "Failed to initialize vk::Surface: null x-display");
 | 
				
			||||||
	esnure(component.get_native_data().window, "Failed to initialize usrface: null x-window");
 | 
						ensure(component.get_native_data().window, "Failed to initialize vk::Surface: null x-window");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto create_info = VkXlibSurfaceCreateInfoKHR {
 | 
						auto create_info = VkXlibSurfaceCreateInfoKHR {
 | 
				
			||||||
		.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
 | 
							.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										51
									
								
								modules/renderer/private/vk/context/surface.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								modules/renderer/private/vk/context/surface.test.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,51 @@
 | 
				
			||||||
 | 
					#include <renderer/vk/context/surface.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/debug/messenger.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/test_utils.hpp>
 | 
				
			||||||
 | 
					#include <surface/components.hpp>
 | 
				
			||||||
 | 
					#include <surface/system.hpp>
 | 
				
			||||||
 | 
					#include <test/test.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ::lt::ecs::Entity;
 | 
				
			||||||
 | 
					using ::lt::ecs::Registry;
 | 
				
			||||||
 | 
					using ::lt::renderer::vk::Surface;
 | 
				
			||||||
 | 
					using ::lt::surface::SurfaceComponent;
 | 
				
			||||||
 | 
					using ::lt::surface::System;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Suite raii = "surface"_suite = [] {
 | 
				
			||||||
 | 
						Case { "happy path won't throw" } = [&] {
 | 
				
			||||||
 | 
							auto observer = ValidationObserver {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto registry = lt::create_ref<Registry>();
 | 
				
			||||||
 | 
							auto entity = Entity { registry, registry->create_entity() };
 | 
				
			||||||
 | 
							auto surface_system = System(registry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							entity.add<SurfaceComponent>(SurfaceComponent::CreateInfo {
 | 
				
			||||||
 | 
							    .title = "",
 | 
				
			||||||
 | 
							    .resolution = constants::resolution,
 | 
				
			||||||
 | 
							    .visible = true,
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const auto surface = Surface { entity };
 | 
				
			||||||
 | 
							const auto &[x, y] = surface.get_framebuffer_size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_eq(x, constants::resolution.x);
 | 
				
			||||||
 | 
							expect_eq(y, constants::resolution.y);
 | 
				
			||||||
 | 
							expect_not_nullptr(surface.vk());
 | 
				
			||||||
 | 
							expect_false(observer.had_any_messages());
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "unhappy path throws" } = [&] {
 | 
				
			||||||
 | 
							auto observer = ValidationObserver {};
 | 
				
			||||||
 | 
							auto registry = lt::create_ref<Registry>();
 | 
				
			||||||
 | 
							auto entity = Entity { registry, registry->create_entity() };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							entity.add<SurfaceComponent>(SurfaceComponent::CreateInfo {
 | 
				
			||||||
 | 
							    .title = "",
 | 
				
			||||||
 | 
							    .resolution = constants::resolution,
 | 
				
			||||||
 | 
							    .visible = true,
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_throw([&] { Surface { entity }; });
 | 
				
			||||||
 | 
							expect_false(observer.had_any_messages());
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,9 @@
 | 
				
			||||||
#include <ranges>
 | 
					#include <ranges>
 | 
				
			||||||
 | 
					#include <renderer/vk/context/device.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/context/instance.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/context/surface.hpp>
 | 
				
			||||||
#include <renderer/vk/context/swapchain.hpp>
 | 
					#include <renderer/vk/context/swapchain.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/debug/validation.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace lt::renderer::vk {
 | 
					namespace lt::renderer::vk {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,15 +1,14 @@
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <memory/pointer_types/null_on_move.hpp>
 | 
					#include <memory/pointer_types/null_on_move.hpp>
 | 
				
			||||||
#include <renderer/vk/context/device.hpp>
 | 
					#include <renderer/vk/vulkan.hpp>
 | 
				
			||||||
#include <renderer/vk/context/instance.hpp>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace lt::renderer::vk {
 | 
					namespace lt::renderer::vk {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Swapchain
 | 
					class Swapchain
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	Swapchain(const Device &device, const Surface &surface);
 | 
						Swapchain(const class Device &device, const class Surface &surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	~Swapchain();
 | 
						~Swapchain();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										0
									
								
								modules/renderer/private/vk/context/swapchain.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								modules/renderer/private/vk/context/swapchain.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								modules/renderer/private/vk/debug/messenger.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								modules/renderer/private/vk/debug/messenger.cpp
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										143
									
								
								modules/renderer/private/vk/debug/messenger.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								modules/renderer/private/vk/debug/messenger.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,143 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <memory/pointer_types/null_on_move.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/context/instance.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/vulkan.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::renderer::vk {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Messenger
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						// NOLINTNEXTLINE(performance-enum-size)
 | 
				
			||||||
 | 
						enum Severity : decltype(std::to_underlying(
 | 
				
			||||||
 | 
						    VK_DEBUG_UTILS_MESSAGE_SEVERITY_FLAG_BITS_MAX_ENUM_EXT
 | 
				
			||||||
 | 
						))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							verbose = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
 | 
				
			||||||
 | 
							info = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT,
 | 
				
			||||||
 | 
							warning = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT,
 | 
				
			||||||
 | 
							error = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							all_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT
 | 
				
			||||||
 | 
							               | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT
 | 
				
			||||||
 | 
							               | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
 | 
				
			||||||
 | 
							               | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// NOLINTNEXTLINE(performance-enum-size)
 | 
				
			||||||
 | 
						enum Type : decltype(std::to_underlying(VK_DEBUG_UTILS_MESSAGE_TYPE_FLAG_BITS_MAX_ENUM_EXT))
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							general = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT,
 | 
				
			||||||
 | 
							validation = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
 | 
				
			||||||
 | 
							performance = VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// address_binding = VK_DEBUG_UTILS_MESSAGE_TYPE_DEVICE_ADDRESS_BINDING_BIT_EXT,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/** @note: does not include address binding yet. */
 | 
				
			||||||
 | 
							all_type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT
 | 
				
			||||||
 | 
							           | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT
 | 
				
			||||||
 | 
							           | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						using CallbackData_T = const VkDebugUtilsMessengerCallbackDataEXT *;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						using Callback_T = std::function<void(
 | 
				
			||||||
 | 
						    Severity message_severity,
 | 
				
			||||||
 | 
						    Type message_type,
 | 
				
			||||||
 | 
						    CallbackData_T vulkan_data,
 | 
				
			||||||
 | 
						    void *user_data
 | 
				
			||||||
 | 
						)>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct CreateInfo
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Severity severity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Type type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Callback_T callback;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void *user_data;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						explicit Messenger(CreateInfo info)
 | 
				
			||||||
 | 
						    : m_callback(std::move(info.callback))
 | 
				
			||||||
 | 
						    , m_user_data(info.user_data)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							ensure(m_callback, "Failed to initialize vk::Messenger: null callback");
 | 
				
			||||||
 | 
							ensure(info.severity != Severity {}, "Failed to initialize vk::Messenger: null severity");
 | 
				
			||||||
 | 
							ensure(info.type != Type {}, "Failed to initialize vk::Messenger: null type");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Instance may not be initialized yet
 | 
				
			||||||
 | 
							// Making it get initialized inside a call to vk_create_debug_messenger
 | 
				
			||||||
 | 
							// Which would invoke a nullptr...
 | 
				
			||||||
 | 
							if (!vk_create_debug_messenger)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Instance::get();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const auto vulkan_info = VkDebugUtilsMessengerCreateInfoEXT {
 | 
				
			||||||
 | 
								.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
 | 
				
			||||||
 | 
								.messageSeverity = info.severity,
 | 
				
			||||||
 | 
								.messageType = info.type,
 | 
				
			||||||
 | 
								.pfnUserCallback = &validation_layers_callback,
 | 
				
			||||||
 | 
								.pUserData = this,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ensure(
 | 
				
			||||||
 | 
							    !vk_create_debug_messenger(Instance::get(), &vulkan_info, nullptr, &m_debug_messenger),
 | 
				
			||||||
 | 
							    "Failed to create vulkan debug utils messenger"
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						~Messenger()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							vk_destroy_debug_messenger(Instance::get(), m_debug_messenger, nullptr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Messenger(Messenger &&) = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Messenger(const Messenger &) = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto operator=(Messenger &&) -> Messenger & = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto operator=(const Messenger &) const -> Messenger & = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						static auto validation_layers_callback(
 | 
				
			||||||
 | 
						    VkDebugUtilsMessageSeverityFlagBitsEXT const message_severity,
 | 
				
			||||||
 | 
						    VkDebugUtilsMessageTypeFlagsEXT const message_type,
 | 
				
			||||||
 | 
						    VkDebugUtilsMessengerCallbackDataEXT const *const callback_data,
 | 
				
			||||||
 | 
						    void *const vulkan_user_data
 | 
				
			||||||
 | 
						) -> VkBool32
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							auto *messenger = (Messenger *)vulkan_user_data; // NOLINT
 | 
				
			||||||
 | 
							ensure(messenger, "Null vulkan_user_data received in messenger callback");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							messenger->validation_layers_callback_impl(message_severity, message_type, callback_data);
 | 
				
			||||||
 | 
							return VK_FALSE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void validation_layers_callback_impl(
 | 
				
			||||||
 | 
						    VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
 | 
				
			||||||
 | 
						    VkDebugUtilsMessageTypeFlagsEXT message_type,
 | 
				
			||||||
 | 
						    const VkDebugUtilsMessengerCallbackDataEXT *callback_data
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							m_callback(
 | 
				
			||||||
 | 
							    static_cast<Severity>(message_severity),
 | 
				
			||||||
 | 
							    static_cast<Type>(message_type),
 | 
				
			||||||
 | 
							    callback_data,
 | 
				
			||||||
 | 
							    m_user_data
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memory::NullOnMove<VkDebugUtilsMessengerEXT> m_debug_messenger = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Callback_T m_callback;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void *m_user_data;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::renderer::vk
 | 
				
			||||||
							
								
								
									
										149
									
								
								modules/renderer/private/vk/debug/messenger.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								modules/renderer/private/vk/debug/messenger.test.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,149 @@
 | 
				
			||||||
 | 
					#include <renderer/vk/context/surface.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/debug/messenger.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/test_utils.hpp>
 | 
				
			||||||
 | 
					#include <surface/components.hpp>
 | 
				
			||||||
 | 
					#include <surface/system.hpp>
 | 
				
			||||||
 | 
					#include <test/expects.hpp>
 | 
				
			||||||
 | 
					#include <test/test.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace lt;
 | 
				
			||||||
 | 
					using renderer::vk::Messenger;
 | 
				
			||||||
 | 
					using renderer::vk::Surface;
 | 
				
			||||||
 | 
					using enum Messenger::Severity;
 | 
				
			||||||
 | 
					using enum Messenger::Type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void noop_callback(
 | 
				
			||||||
 | 
					    Messenger::Severity message_severity,
 | 
				
			||||||
 | 
					    Messenger::Type message_type,
 | 
				
			||||||
 | 
					    Messenger::CallbackData_T vulkan_data,
 | 
				
			||||||
 | 
					    void *user_data
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Suite raii = "messenger_raii"_suite = [] {
 | 
				
			||||||
 | 
						Case { "happy path won't throw" } = [] {
 | 
				
			||||||
 | 
							Messenger(
 | 
				
			||||||
 | 
							    Messenger::CreateInfo {
 | 
				
			||||||
 | 
							        .severity = all_severity,
 | 
				
			||||||
 | 
							        .type = all_type,
 | 
				
			||||||
 | 
							        .callback = &noop_callback,
 | 
				
			||||||
 | 
							    }
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "unhappy path throws" } = [] {
 | 
				
			||||||
 | 
							expect_throw([] {
 | 
				
			||||||
 | 
								Messenger(
 | 
				
			||||||
 | 
								    Messenger::CreateInfo {
 | 
				
			||||||
 | 
								        .severity = all_severity,
 | 
				
			||||||
 | 
								        .type = all_type,
 | 
				
			||||||
 | 
								        .callback = {},
 | 
				
			||||||
 | 
								    }
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_throw([] {
 | 
				
			||||||
 | 
								Messenger(
 | 
				
			||||||
 | 
								    Messenger::CreateInfo {
 | 
				
			||||||
 | 
								        .severity = {},
 | 
				
			||||||
 | 
								        .type = all_type,
 | 
				
			||||||
 | 
								        .callback = &noop_callback,
 | 
				
			||||||
 | 
								    }
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_throw([] {
 | 
				
			||||||
 | 
								Messenger(
 | 
				
			||||||
 | 
								    Messenger::CreateInfo {
 | 
				
			||||||
 | 
								        .severity = all_severity,
 | 
				
			||||||
 | 
								        .type = {},
 | 
				
			||||||
 | 
								        .callback = &noop_callback,
 | 
				
			||||||
 | 
								    }
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NOLINTNEXTLINE(cppcoreguidelines-interfaces-global-init)
 | 
				
			||||||
 | 
					Suite callback = "messenger_callback"_suite = [] {
 | 
				
			||||||
 | 
						Case { "callback gets called with correct arguments" } = [] {
 | 
				
			||||||
 | 
							auto total_messages = 0u;
 | 
				
			||||||
 | 
							auto first_message_is_severity = false;
 | 
				
			||||||
 | 
							auto second_message_is_type = false;
 | 
				
			||||||
 | 
							auto third_message_is_user_callback = false;
 | 
				
			||||||
 | 
							auto all_messages_are_error = true;
 | 
				
			||||||
 | 
							auto all_messages_are_validation = true;
 | 
				
			||||||
 | 
							auto user_data_is_always_69 = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto callback = [&](Messenger::Severity message_severity,
 | 
				
			||||||
 | 
							                    Messenger::Type message_type,
 | 
				
			||||||
 | 
							                    Messenger::CallbackData_T vulkan_data,
 | 
				
			||||||
 | 
							                    void *user_data) {
 | 
				
			||||||
 | 
								++total_messages;
 | 
				
			||||||
 | 
								auto message = std::string_view { vulkan_data->pMessage };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
 | 
				
			||||||
 | 
								user_data_is_always_69 = user_data_is_always_69 && *(size_t *)user_data == 69u;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								all_messages_are_validation = all_messages_are_validation && message_type == validation;
 | 
				
			||||||
 | 
								all_messages_are_error = all_messages_are_error && message_severity == error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (total_messages == 1)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									first_message_is_severity = message.starts_with(
 | 
				
			||||||
 | 
									    "vkCreateDebugUtilsMessengerEXT(): pCreateInfo->messageSeverity is zero."
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (total_messages == 2)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									second_message_is_type = message.starts_with(
 | 
				
			||||||
 | 
									    "vkCreateDebugUtilsMessengerEXT(): pCreateInfo->messageType is zero."
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (total_messages == 3)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									third_message_is_user_callback = message.starts_with(
 | 
				
			||||||
 | 
									    "vkCreateDebugUtilsMessengerEXT(): pCreateInfo->pfnUserCallback is NULL."
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto user_data = size_t { 69 };
 | 
				
			||||||
 | 
							auto messenger = Messenger(
 | 
				
			||||||
 | 
							    Messenger::CreateInfo {
 | 
				
			||||||
 | 
							        .severity = all_severity,
 | 
				
			||||||
 | 
							        .type = all_type,
 | 
				
			||||||
 | 
							        .callback = callback,
 | 
				
			||||||
 | 
							        .user_data = &user_data,
 | 
				
			||||||
 | 
							    }
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								auto *messenger = VkDebugUtilsMessengerEXT {};
 | 
				
			||||||
 | 
								auto info = VkDebugUtilsMessengerCreateInfoEXT {
 | 
				
			||||||
 | 
									.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
								renderer::vk::vk_create_debug_messenger(
 | 
				
			||||||
 | 
								    renderer::vk::Instance::get(),
 | 
				
			||||||
 | 
								    &info,
 | 
				
			||||||
 | 
								    nullptr,
 | 
				
			||||||
 | 
								    &messenger
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_eq(total_messages, 3u);
 | 
				
			||||||
 | 
							expect_true(first_message_is_severity);
 | 
				
			||||||
 | 
							expect_true(second_message_is_type);
 | 
				
			||||||
 | 
							expect_true(third_message_is_user_callback);
 | 
				
			||||||
 | 
							expect_true(all_messages_are_error);
 | 
				
			||||||
 | 
							expect_true(all_messages_are_validation);
 | 
				
			||||||
 | 
							expect_true(user_data_is_always_69);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										17
									
								
								modules/renderer/private/vk/debug/validation.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								modules/renderer/private/vk/debug/validation.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <renderer/vk/vulkan.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::renderer::vk {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline void vkc(VkResult result)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (result)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							throw std::runtime_error {
 | 
				
			||||||
 | 
								std::format("Vulkan call failed with result: {}", std::to_underlying(result))
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::renderer::vk
 | 
				
			||||||
| 
						 | 
					@ -1,22 +1,14 @@
 | 
				
			||||||
#include <ranges>
 | 
					 | 
				
			||||||
#include <renderer/vk/context/context.hpp>
 | 
					#include <renderer/vk/context/context.hpp>
 | 
				
			||||||
#include <renderer/vk/pipeline.hpp>
 | 
					#include <renderer/vk/pipeline.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/test_utils.hpp>
 | 
				
			||||||
#include <surface/system.hpp>
 | 
					#include <surface/system.hpp>
 | 
				
			||||||
#include <test/test.hpp>
 | 
					#include <test/test.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace lt;
 | 
					using namespace lt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using std::ignore;
 | 
					 | 
				
			||||||
using test::Case;
 | 
					 | 
				
			||||||
using test::expect_throw;
 | 
					 | 
				
			||||||
using test::expect_true;
 | 
					 | 
				
			||||||
using test::Suite;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using renderer::vk::Context;
 | 
					using renderer::vk::Context;
 | 
				
			||||||
using renderer::vk::Pipeline;
 | 
					using renderer::vk::Pipeline;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
constexpr auto resolution = math::uvec2 { 800, 600 };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class VkPipelineTest
 | 
					class VkPipelineTest
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
| 
						 | 
					@ -29,7 +21,7 @@ public:
 | 
				
			||||||
		m_surface_entity = create_scope<ecs::Entity>(m_registry, m_registry->create_entity());
 | 
							m_surface_entity = create_scope<ecs::Entity>(m_registry, m_registry->create_entity());
 | 
				
			||||||
		m_surface_entity->add<surface::SurfaceComponent>(surface::SurfaceComponent::CreateInfo {
 | 
							m_surface_entity->add<surface::SurfaceComponent>(surface::SurfaceComponent::CreateInfo {
 | 
				
			||||||
		    .title = "",
 | 
							    .title = "",
 | 
				
			||||||
		    .resolution = resolution,
 | 
							    .resolution = constants::resolution,
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		m_context = create_ref<Context>(*m_surface_entity, m_stats);
 | 
							m_context = create_ref<Context>(*m_surface_entity, m_stats);
 | 
				
			||||||
| 
						 | 
					@ -57,7 +49,7 @@ private:
 | 
				
			||||||
	Ref<Context> m_context;
 | 
						Ref<Context> m_context;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Suite raii = [] {
 | 
					Suite raii = "raii"_suite = [] {
 | 
				
			||||||
	Case { "happy path won't throw" } = [] {
 | 
						Case { "happy path won't throw" } = [] {
 | 
				
			||||||
		auto fixture = VkPipelineTest {};
 | 
							auto fixture = VkPipelineTest {};
 | 
				
			||||||
		std::ignore = Pipeline { { .context = fixture.context() } };
 | 
							std::ignore = Pipeline { { .context = fixture.context() } };
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								modules/renderer/private/vk/test_utils.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								modules/renderer/private/vk/test_utils.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					#include <renderer/vk/test_utils.hpp>
 | 
				
			||||||
							
								
								
									
										87
									
								
								modules/renderer/private/vk/test_utils.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								modules/renderer/private/vk/test_utils.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,87 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <ranges>
 | 
				
			||||||
 | 
					#include <renderer/vk/context/surface.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/debug/messenger.hpp>
 | 
				
			||||||
 | 
					#include <surface/components.hpp>
 | 
				
			||||||
 | 
					#include <surface/system.hpp>
 | 
				
			||||||
 | 
					#include <test/test.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ::lt::test::Case;
 | 
				
			||||||
 | 
					using ::lt::test::expect_eq;
 | 
				
			||||||
 | 
					using ::lt::test::expect_false;
 | 
				
			||||||
 | 
					using ::lt::test::expect_not_nullptr;
 | 
				
			||||||
 | 
					using ::lt::test::expect_throw;
 | 
				
			||||||
 | 
					using ::lt::test::expect_true;
 | 
				
			||||||
 | 
					using ::lt::test::Suite;
 | 
				
			||||||
 | 
					using ::std::ignore;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace constants {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					constexpr auto resolution = lt::math::uvec2 { 800u, 600u };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ValidationObserver
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						using Messenger = lt::renderer::vk::Messenger;
 | 
				
			||||||
 | 
						using enum Messenger::Type;
 | 
				
			||||||
 | 
						using enum Messenger::Severity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						ValidationObserver()
 | 
				
			||||||
 | 
						    : m_messenger(
 | 
				
			||||||
 | 
						          Messenger::CreateInfo {
 | 
				
			||||||
 | 
						              .severity = all_severity,
 | 
				
			||||||
 | 
						              .type = lt::renderer::vk::Messenger::all_type,
 | 
				
			||||||
 | 
						              .callback = &callback,
 | 
				
			||||||
 | 
						              .user_data = &m_had_any_messages,
 | 
				
			||||||
 | 
						          }
 | 
				
			||||||
 | 
						      )
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto had_any_messages() const -> bool
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_had_any_messages;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						static void callback(
 | 
				
			||||||
 | 
						    Messenger::Severity message_severity,
 | 
				
			||||||
 | 
						    Messenger::Type message_type,
 | 
				
			||||||
 | 
						    Messenger::CallbackData_T vulkan_data,
 | 
				
			||||||
 | 
						    void *user_data
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							std::ignore = message_severity;
 | 
				
			||||||
 | 
							std::ignore = message_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							std::println("Validation message: {}", vulkan_data->pMessage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
 | 
				
			||||||
 | 
							*(bool *)user_data = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Messenger m_messenger;
 | 
				
			||||||
 | 
						bool m_had_any_messages = false;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<>
 | 
				
			||||||
 | 
					struct std::formatter<VkExtent2D>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						constexpr auto parse(std::format_parse_context &context)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return context.begin();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto format(const VkExtent2D &val, std::format_context &context) const
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return std::format_to(context.out(), "{}, {}", val.width, val.height);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline auto operator==(VkExtent2D lhs, VkExtent2D rhs) -> bool
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return lhs.width == rhs.width && lhs.height == rhs.height;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										91
									
								
								modules/renderer/private/vk/vulkan.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								modules/renderer/private/vk/vulkan.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,91 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define VK_NO_PROTOTYPES
 | 
				
			||||||
 | 
					#define VK_USE_PLATFORM_XLIB_KHR
 | 
				
			||||||
 | 
					#include <vulkan/vulkan.h>
 | 
				
			||||||
 | 
					#include <vulkan/vulkan_xlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::renderer::vk {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables)
 | 
				
			||||||
 | 
					// global functions
 | 
				
			||||||
 | 
					extern PFN_vkGetInstanceProcAddr vk_get_instance_proc_address;
 | 
				
			||||||
 | 
					extern PFN_vkCreateInstance vk_create_instance;
 | 
				
			||||||
 | 
					extern PFN_vkEnumerateInstanceExtensionProperties vk_enumerate_instance_extension_properties;
 | 
				
			||||||
 | 
					extern PFN_vkEnumerateInstanceLayerProperties vk_enumerate_instance_layer_properties;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// instance functions
 | 
				
			||||||
 | 
					extern PFN_vkDestroyInstance vk_destroy_instance;
 | 
				
			||||||
 | 
					extern PFN_vkEnumeratePhysicalDevices vk_enumerate_physical_devices;
 | 
				
			||||||
 | 
					extern PFN_vkGetPhysicalDeviceProperties vk_get_physical_device_properties;
 | 
				
			||||||
 | 
					extern PFN_vkGetPhysicalDeviceQueueFamilyProperties vk_get_physical_device_queue_family_properties;
 | 
				
			||||||
 | 
					extern PFN_vkCreateDevice vk_create_device;
 | 
				
			||||||
 | 
					extern PFN_vkGetDeviceProcAddr vk_get_device_proc_address;
 | 
				
			||||||
 | 
					extern PFN_vkDestroyDevice vk_destroy_device;
 | 
				
			||||||
 | 
					extern PFN_vkGetPhysicalDeviceFeatures vk_get_physical_device_features;
 | 
				
			||||||
 | 
					extern PFN_vkEnumerateDeviceExtensionProperties vk_enumerate_device_extension_properties;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// extension instance functions
 | 
				
			||||||
 | 
					extern PFN_vkCmdBeginDebugUtilsLabelEXT vk_cmd_begin_debug_label;
 | 
				
			||||||
 | 
					extern PFN_vkCmdEndDebugUtilsLabelEXT vk_cmd_end_debug_label;
 | 
				
			||||||
 | 
					extern PFN_vkCmdInsertDebugUtilsLabelEXT vk_cmd_insert_debug_label;
 | 
				
			||||||
 | 
					extern PFN_vkCreateDebugUtilsMessengerEXT vk_create_debug_messenger;
 | 
				
			||||||
 | 
					extern PFN_vkDestroyDebugUtilsMessengerEXT vk_destroy_debug_messenger;
 | 
				
			||||||
 | 
					extern PFN_vkQueueBeginDebugUtilsLabelEXT vk_queue_begin_debug_label;
 | 
				
			||||||
 | 
					extern PFN_vkQueueEndDebugUtilsLabelEXT vk_queue_end_debug_label;
 | 
				
			||||||
 | 
					extern PFN_vkQueueInsertDebugUtilsLabelEXT vk_queue_insert_debug_label;
 | 
				
			||||||
 | 
					extern PFN_vkSetDebugUtilsObjectNameEXT vk_set_debug_object_name;
 | 
				
			||||||
 | 
					extern PFN_vkSetDebugUtilsObjectTagEXT vk_set_debug_object_tag;
 | 
				
			||||||
 | 
					extern PFN_vkSubmitDebugUtilsMessageEXT vk_submit_debug_message;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// surface instance functions
 | 
				
			||||||
 | 
					extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vk_get_physical_device_surface_support;
 | 
				
			||||||
 | 
					extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vk_get_physical_device_surface_capabilities;
 | 
				
			||||||
 | 
					extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vk_get_physical_device_surface_formats;
 | 
				
			||||||
 | 
					extern PFN_vkCreateXlibSurfaceKHR vk_create_xlib_surface_khr;
 | 
				
			||||||
 | 
					extern PFN_vkDestroySurfaceKHR vk_destroy_surface_khr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// device functions
 | 
				
			||||||
 | 
					extern PFN_vkGetDeviceQueue vk_get_device_queue;
 | 
				
			||||||
 | 
					extern PFN_vkCreateCommandPool vk_create_command_pool;
 | 
				
			||||||
 | 
					extern PFN_vkDestroyCommandPool vk_destroy_command_pool;
 | 
				
			||||||
 | 
					extern PFN_vkAllocateCommandBuffers vk_allocate_command_buffers;
 | 
				
			||||||
 | 
					extern PFN_vkFreeCommandBuffers vk_free_command_buffers;
 | 
				
			||||||
 | 
					extern PFN_vkBeginCommandBuffer vk_begin_command_buffer;
 | 
				
			||||||
 | 
					extern PFN_vkEndCommandBuffer vk_end_command_buffer;
 | 
				
			||||||
 | 
					extern PFN_vkCmdPipelineBarrier vk_cmd_pipeline_barrier;
 | 
				
			||||||
 | 
					extern PFN_vkQueueSubmit vk_queue_submit;
 | 
				
			||||||
 | 
					extern PFN_vkQueueWaitIdle vk_queue_wait_idle;
 | 
				
			||||||
 | 
					extern PFN_vkDeviceWaitIdle vk_device_wait_idle;
 | 
				
			||||||
 | 
					extern PFN_vkCreateFence vk_create_fence;
 | 
				
			||||||
 | 
					extern PFN_vkDestroyFence vk_destroy_fence;
 | 
				
			||||||
 | 
					extern PFN_vkWaitForFences vk_wait_for_fences;
 | 
				
			||||||
 | 
					extern PFN_vkResetFences vk_reset_fences;
 | 
				
			||||||
 | 
					extern PFN_vkCreateSemaphore vk_create_semaphore;
 | 
				
			||||||
 | 
					extern PFN_vkDestroySemaphore vk_destroy_semaphore;
 | 
				
			||||||
 | 
					extern PFN_vkCreateSwapchainKHR vk_create_swapchain_khr;
 | 
				
			||||||
 | 
					extern PFN_vkDestroySwapchainKHR vk_destroy_swapchain_khr;
 | 
				
			||||||
 | 
					extern PFN_vkGetSwapchainImagesKHR vk_get_swapchain_images_khr;
 | 
				
			||||||
 | 
					extern PFN_vkAcquireNextImageKHR vk_acquire_next_image_khr;
 | 
				
			||||||
 | 
					extern PFN_vkQueuePresentKHR vk_queue_present_khr;
 | 
				
			||||||
 | 
					extern PFN_vkCreateImageView vk_create_image_view;
 | 
				
			||||||
 | 
					extern PFN_vkDestroyImageView vk_destroy_image_view;
 | 
				
			||||||
 | 
					extern PFN_vkCreateRenderPass vk_create_render_pass;
 | 
				
			||||||
 | 
					extern PFN_vkDestroyRenderPass vk_destroy_render_pass;
 | 
				
			||||||
 | 
					extern PFN_vkCreateFramebuffer vk_create_frame_buffer;
 | 
				
			||||||
 | 
					extern PFN_vkDestroyFramebuffer vk_destroy_frame_buffer;
 | 
				
			||||||
 | 
					extern PFN_vkCreateShaderModule vk_create_shader_module;
 | 
				
			||||||
 | 
					extern PFN_vkDestroyShaderModule vk_destroy_shader_module;
 | 
				
			||||||
 | 
					extern PFN_vkCreatePipelineLayout vk_create_pipeline_layout;
 | 
				
			||||||
 | 
					extern PFN_vkDestroyPipelineLayout vk_destroy_pipeline_layout;
 | 
				
			||||||
 | 
					extern PFN_vkCreateGraphicsPipelines vk_create_graphics_pipelines;
 | 
				
			||||||
 | 
					extern PFN_vkDestroyPipeline vk_destroy_pipeline;
 | 
				
			||||||
 | 
					extern PFN_vkCmdBeginRenderPass vk_cmd_begin_render_pass;
 | 
				
			||||||
 | 
					extern PFN_vkCmdEndRenderPass vk_cmd_end_render_pass;
 | 
				
			||||||
 | 
					extern PFN_vkCmdBindPipeline vk_cmd_bind_pipeline;
 | 
				
			||||||
 | 
					extern PFN_vkCmdDraw vk_cmd_draw;
 | 
				
			||||||
 | 
					extern PFN_vkCmdSetViewport vk_cmd_set_viewport;
 | 
				
			||||||
 | 
					extern PFN_vkCmdSetScissor vk_cmd_set_scissors;
 | 
				
			||||||
 | 
					// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::renderer::vk
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue