feat(renderer): wip hello triangle
This commit is contained in:
		
							parent
							
								
									dd0f8ebf0a
								
							
						
					
					
						commit
						a58b0c030f
					
				
					 85 changed files with 484 additions and 148 deletions
				
			
		| 
						 | 
					@ -1,45 +1,17 @@
 | 
				
			||||||
add_library_module(renderer
 | 
					add_library_module(renderer
 | 
				
			||||||
    system.cpp
 | 
					    system.cpp
 | 
				
			||||||
    blender.cpp
 | 
					    vk/context.cpp
 | 
				
			||||||
    buffers.cpp
 | 
					 | 
				
			||||||
    framebuffer.cpp
 | 
					 | 
				
			||||||
    graphics_context.cpp
 | 
					 | 
				
			||||||
    render_command.cpp
 | 
					 | 
				
			||||||
    renderer.cpp
 | 
					 | 
				
			||||||
    shader.cpp
 | 
					 | 
				
			||||||
    texture.cpp
 | 
					 | 
				
			||||||
    vertex_layout.cpp
 | 
					 | 
				
			||||||
    programs/quad.cpp
 | 
					 | 
				
			||||||
    programs/texture.cpp
 | 
					 | 
				
			||||||
    programs/tinted_texture.cpp
 | 
					 | 
				
			||||||
    gl/blender.cpp
 | 
					 | 
				
			||||||
    gl/buffers.cpp
 | 
					 | 
				
			||||||
    gl/framebuffers.cpp
 | 
					 | 
				
			||||||
    gl/graphics_context.cpp
 | 
					 | 
				
			||||||
    gl/render_command.cpp
 | 
					 | 
				
			||||||
    gl/shader.cpp
 | 
					 | 
				
			||||||
    gl/texture.cpp
 | 
					 | 
				
			||||||
    gl/vertex_layout.cpp
 | 
					 | 
				
			||||||
    vk/instance.cpp
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
target_link_libraries(
 | 
					target_link_libraries(renderer
 | 
				
			||||||
  renderer
 | 
					PUBLIC 
 | 
				
			||||||
  PUBLIC camera
 | 
					    app 
 | 
				
			||||||
  PUBLIC input
 | 
					    ecs
 | 
				
			||||||
  PUBLIC logger
 | 
					    vulkan
 | 
				
			||||||
  PUBLIC imgui
 | 
					    memory
 | 
				
			||||||
  PUBLIC asset_parser
 | 
					    surface
 | 
				
			||||||
  PRIVATE lt_debug 
 | 
					 | 
				
			||||||
  PRIVATE window
 | 
					 | 
				
			||||||
  PUBLIC vulkan
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_test_module(renderer 
 | 
					add_test_module(renderer 
 | 
				
			||||||
    system.test.cpp
 | 
					    system.test.cpp
 | 
				
			||||||
) 
 | 
					) 
 | 
				
			||||||
target_link_libraries(
 | 
					 | 
				
			||||||
  renderer_tests
 | 
					 | 
				
			||||||
  PRIVATE lt_debug 
 | 
					 | 
				
			||||||
  PRIVATE window
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										17
									
								
								modules/renderer/legacy/private/system.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								modules/renderer/legacy/private/system.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					#include <lt_debug/assertions.hpp>
 | 
				
			||||||
 | 
					#include <renderer/system.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::renderer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					System::System(InitRequirements requirements): m_registry(std::move(requirements.registry))
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						ensure(m_registry, "null registry");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					System::~System() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void System::tick(TickRequirements requirements)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::renderer
 | 
				
			||||||
							
								
								
									
										44
									
								
								modules/renderer/legacy/private/system.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								modules/renderer/legacy/private/system.test.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,44 @@
 | 
				
			||||||
 | 
					#include <ranges>
 | 
				
			||||||
 | 
					#include <renderer/system.hpp>
 | 
				
			||||||
 | 
					#include <test/test.hpp>
 | 
				
			||||||
 | 
					#include <window/window.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace lt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using lt::test::Case;
 | 
				
			||||||
 | 
					using lt::test::Suite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Suite raii = [] {
 | 
				
			||||||
 | 
						using lt::test::expect_true;
 | 
				
			||||||
 | 
						using lt::test::expect_throw;
 | 
				
			||||||
 | 
						using renderer::System;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "happy" } = [=] {
 | 
				
			||||||
 | 
							std::ignore = System { {
 | 
				
			||||||
 | 
								.registry = create_ref<ecs::Registry>(),
 | 
				
			||||||
 | 
							} };
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "unhappy" } = [=] {
 | 
				
			||||||
 | 
							expect_throw([=] {
 | 
				
			||||||
 | 
								std::ignore = System { {
 | 
				
			||||||
 | 
									.registry = {},
 | 
				
			||||||
 | 
								} };
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_throw([=] {
 | 
				
			||||||
 | 
								std::ignore = System { {
 | 
				
			||||||
 | 
									.registry = create_ref<ecs::Registry>(),
 | 
				
			||||||
 | 
								} };
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "plenty" } = [=] {
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 100'001))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								std::ignore = System { {
 | 
				
			||||||
 | 
									.registry = create_ref<ecs::Registry>(),
 | 
				
			||||||
 | 
								} };
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										56
									
								
								modules/renderer/legacy/public/system.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								modules/renderer/legacy/public/system.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,56 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <base/base.hpp>
 | 
				
			||||||
 | 
					#include <ecs/registry.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::renderer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** The system for putting gore on your display
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Exclusively operates on components:
 | 
				
			||||||
 | 
					 * - RendererComponent
 | 
				
			||||||
 | 
					 * - PostEffectsComponent
 | 
				
			||||||
 | 
					 * - UserInterfaceComponent
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Requires read acces on components:
 | 
				
			||||||
 | 
					 * - TransformComponent
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class System
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						/** The configurations of this system. */
 | 
				
			||||||
 | 
						struct Properties
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** The requirements for this system to initialize. */
 | 
				
			||||||
 | 
						struct InitRequirements
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Ref<ecs::Registry> registry;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** The requirements for this system to tick. */
 | 
				
			||||||
 | 
						struct TickRequirements
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							double delta_time;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] System(InitRequirements requirements);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						System(System &&) = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						System(const System &) = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto operator=(System &&) -> System & = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto operator=(const System &) -> System & = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						~System();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void tick(TickRequirements requirements);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						Ref<ecs::Registry> m_registry;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::renderer
 | 
				
			||||||
| 
						 | 
					@ -1,17 +1,5 @@
 | 
				
			||||||
#include <lt_debug/assertions.hpp>
 | 
					 | 
				
			||||||
#include <renderer/system.hpp>
 | 
					#include <renderer/system.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace lt::renderer {
 | 
					namespace lt::renderer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
System::System(InitRequirements requirements): m_registry(std::move(requirements.registry))
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	ensure(m_registry, "null registry");
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
System::~System() = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void System::tick(TickRequirements requirements)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt::renderer
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,44 +1,123 @@
 | 
				
			||||||
#include <ranges>
 | 
					#include <ranges>
 | 
				
			||||||
#include <renderer/system.hpp>
 | 
					#include <renderer/system.hpp>
 | 
				
			||||||
 | 
					#include <surface/system.hpp>
 | 
				
			||||||
#include <test/test.hpp>
 | 
					#include <test/test.hpp>
 | 
				
			||||||
#include <window/window.hpp>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace lt;
 | 
					using namespace lt;
 | 
				
			||||||
 | 
					using std::ignore;
 | 
				
			||||||
 | 
					using test::Case;
 | 
				
			||||||
 | 
					using test::expect_eq;
 | 
				
			||||||
 | 
					using test::expect_ne;
 | 
				
			||||||
 | 
					using test::expect_not_nullptr;
 | 
				
			||||||
 | 
					using test::expect_throw;
 | 
				
			||||||
 | 
					using test::expect_true;
 | 
				
			||||||
 | 
					using test::Suite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using lt::test::Case;
 | 
					using renderer::System;
 | 
				
			||||||
using lt::test::Suite;
 | 
					
 | 
				
			||||||
 | 
					constexpr auto resolution = math::uvec2 { 800, 600 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct SurfaceContext
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						surface::System system;
 | 
				
			||||||
 | 
						ecs::Entity entity;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct RendererContext
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						Ref<ecs::Registry> registry;
 | 
				
			||||||
 | 
						System system;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[nodiscard]] auto create_surface() -> SurfaceContext
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						using surface::SurfaceComponent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto surface_registry = create_ref<ecs::Registry>();
 | 
				
			||||||
 | 
						auto surface_entity = surface_registry->create_entity();
 | 
				
			||||||
 | 
						auto surface_system = surface::System(surface_registry);
 | 
				
			||||||
 | 
						surface_registry->add<SurfaceComponent>(
 | 
				
			||||||
 | 
						    surface_entity,
 | 
				
			||||||
 | 
						    SurfaceComponent::CreateInfo {
 | 
				
			||||||
 | 
						        .title = "",
 | 
				
			||||||
 | 
						        .resolution = resolution,
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return {
 | 
				
			||||||
 | 
							.system = std::move(surface_system),
 | 
				
			||||||
 | 
							.entity = ecs::Entity { surface_registry, surface_entity },
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[nodiscard]] auto create_system() -> std::pair<RendererContext, SurfaceContext>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						auto surface_context = create_surface();
 | 
				
			||||||
 | 
						auto &[surface_system, surface_entity] = surface_context;
 | 
				
			||||||
 | 
						auto registry = create_ref<ecs::Registry>();
 | 
				
			||||||
 | 
						auto stats = create_ref<app::SystemStats>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return {
 | 
				
			||||||
 | 
							RendererContext {
 | 
				
			||||||
 | 
							    .registry = registry,
 | 
				
			||||||
 | 
							    .system = System(
 | 
				
			||||||
 | 
							        {
 | 
				
			||||||
 | 
							            .registry = registry,
 | 
				
			||||||
 | 
							            .surface_entity = surface_entity,
 | 
				
			||||||
 | 
							            .system_stats = stats,
 | 
				
			||||||
 | 
							        }
 | 
				
			||||||
 | 
							    ),
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							std::move(surface_context),
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Suite raii = [] {
 | 
					Suite raii = [] {
 | 
				
			||||||
	using lt::test::expect_true;
 | 
						Case { "happy path won't throw" } = [&] {
 | 
				
			||||||
	using lt::test::expect_throw;
 | 
							std::ignore = create_system();
 | 
				
			||||||
	using renderer::System;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Case { "happy" } = [=] {
 | 
					 | 
				
			||||||
		std::ignore = System { {
 | 
					 | 
				
			||||||
			.registry = create_ref<ecs::Registry>(),
 | 
					 | 
				
			||||||
		} };
 | 
					 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Case { "unhappy" } = [=] {
 | 
						Case { "happy path has no validation errors" } = [&] {
 | 
				
			||||||
		expect_throw([=] {
 | 
							auto [renderer, surface] = create_system();
 | 
				
			||||||
			std::ignore = System { {
 | 
							expect_true(renderer.system.get_stats().empty_diagnosis());
 | 
				
			||||||
				.registry = {},
 | 
					 | 
				
			||||||
			} };
 | 
					 | 
				
			||||||
		});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		expect_throw([=] {
 | 
					 | 
				
			||||||
			std::ignore = System { {
 | 
					 | 
				
			||||||
				.registry = create_ref<ecs::Registry>(),
 | 
					 | 
				
			||||||
			} };
 | 
					 | 
				
			||||||
		});
 | 
					 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Case { "plenty" } = [=] {
 | 
						Case { "unhappy path throws" } = [] {
 | 
				
			||||||
		for (auto idx : std::views::iota(0, 100'001))
 | 
							auto [surface_system, surface_entity] = create_surface();
 | 
				
			||||||
 | 
							auto empty_registry = create_ref<ecs::Registry>();
 | 
				
			||||||
 | 
							auto empty_entity = ecs::Entity { empty_registry, empty_registry->create_entity() };
 | 
				
			||||||
 | 
							auto registry = create_ref<ecs::Registry>();
 | 
				
			||||||
 | 
							auto stats = create_ref<app::SystemStats>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_throw([&] {
 | 
				
			||||||
 | 
								std::ignore = System(
 | 
				
			||||||
			    {
 | 
								    {
 | 
				
			||||||
			std::ignore = System { {
 | 
								        .registry = {},
 | 
				
			||||||
				.registry = create_ref<ecs::Registry>(),
 | 
								        .surface_entity = surface_entity,
 | 
				
			||||||
			} };
 | 
								        .system_stats = stats,
 | 
				
			||||||
			    }
 | 
								    }
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_throw([&] {
 | 
				
			||||||
 | 
								std::ignore = System(
 | 
				
			||||||
 | 
								    System::CreateInfo {
 | 
				
			||||||
 | 
								        .registry = surface_entity.get_registry(),
 | 
				
			||||||
 | 
								        .surface_entity = empty_entity,
 | 
				
			||||||
 | 
								        .system_stats = stats,
 | 
				
			||||||
 | 
								    }
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_throw([&] {
 | 
				
			||||||
 | 
								std::ignore = System(
 | 
				
			||||||
 | 
								    System::CreateInfo {
 | 
				
			||||||
 | 
								        .registry = surface_entity.get_registry(),
 | 
				
			||||||
 | 
								        .surface_entity = surface_entity,
 | 
				
			||||||
 | 
								        .system_stats = {},
 | 
				
			||||||
 | 
								    }
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
#include <renderer/vk/backend.hpp>
 | 
					#include <renderer/vk/context.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(_WIN32)
 | 
					#if defined(_WIN32)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,10 +83,16 @@ PFN_vkCmdBindPipeline vk_cmd_bind_pipeline;
 | 
				
			||||||
PFN_vkCmdDraw vk_cmd_draw;
 | 
					PFN_vkCmdDraw vk_cmd_draw;
 | 
				
			||||||
PFN_vkCmdSetViewport vk_cmd_set_viewport;
 | 
					PFN_vkCmdSetViewport vk_cmd_set_viewport;
 | 
				
			||||||
PFN_vkCmdSetScissor vk_cmd_set_scissors;
 | 
					PFN_vkCmdSetScissor vk_cmd_set_scissors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PFN_vkCreateXlibSurfaceKHR vk_create_xlib_surface_khr;
 | 
				
			||||||
 | 
					PFN_vkDestroySurfaceKHR vk_destroy_surface_khr;
 | 
				
			||||||
// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
 | 
					// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Backend::Backend()
 | 
					Context::Context(const ecs::Entity &surface_entity, Ref<app::SystemStats> system_stats)
 | 
				
			||||||
 | 
					    : m_stats(std::move(system_stats))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						ensure(m_stats, "Failed to create Vulkan Context: null stats");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	load_library();
 | 
						load_library();
 | 
				
			||||||
	load_global_functions();
 | 
						load_global_functions();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -100,16 +106,31 @@ Backend::Backend()
 | 
				
			||||||
	load_device_functions();
 | 
						load_device_functions();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	initialize_queue();
 | 
						initialize_queue();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const auto &component = surface_entity.get<surface::SurfaceComponent>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto xlib_surface_create_info = VkXlibSurfaceCreateInfoKHR {
 | 
				
			||||||
 | 
							.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
 | 
				
			||||||
 | 
							.dpy = component.get_native_data().display,
 | 
				
			||||||
 | 
							.window = component.get_native_data().window,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vk_create_xlib_surface_khr(m_instance, &xlib_surface_create_info, nullptr, &m_surface);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Backend::~Backend()
 | 
					Context::~Context()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	vk_destroy_device(m_device, nullptr);
 | 
						vk_destroy_device(m_device, nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (m_instance)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							vk_destroy_surface_khr(m_instance, m_surface, nullptr);
 | 
				
			||||||
		vk_destroy_debug_messenger(m_instance, m_debug_messenger, nullptr);
 | 
							vk_destroy_debug_messenger(m_instance, m_debug_messenger, nullptr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vk_destroy_instance(m_instance, nullptr);
 | 
						vk_destroy_instance(m_instance, nullptr);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
auto parse_message_type(VkDebugUtilsMessageTypeFlagsEXT message_types) -> const char *
 | 
					auto parse_message_type(VkDebugUtilsMessageTypeFlagsEXT message_types) -> const char *
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (message_types == VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT)
 | 
						if (message_types == VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT)
 | 
				
			||||||
| 
						 | 
					@ -132,14 +153,17 @@ auto parse_message_type(VkDebugUtilsMessageTypeFlagsEXT message_types) -> const
 | 
				
			||||||
	return "PERFORMANCE";
 | 
						return "PERFORMANCE";
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto parse_message_severity(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity) -> LogLvl
 | 
					auto parse_message_severity(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity)
 | 
				
			||||||
 | 
					    -> app::SystemDiagnosis::Severity
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						using enum app::SystemDiagnosis::Severity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (message_severity)
 | 
						switch (message_severity)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: return LogLvl::trace;
 | 
						case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: return verbose;
 | 
				
			||||||
	case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: return LogLvl::info;
 | 
						case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: return info;
 | 
				
			||||||
	case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: return LogLvl::warn;
 | 
						case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: return warning;
 | 
				
			||||||
	case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: return LogLvl::error;
 | 
						case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: return error;
 | 
				
			||||||
	default: ensure(false, "Invalid message severity: {}", static_cast<int>(message_severity));
 | 
						default: ensure(false, "Invalid message severity: {}", static_cast<int>(message_severity));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -153,16 +177,34 @@ auto validation_layers_callback(
 | 
				
			||||||
    void *const vulkan_user_data
 | 
					    void *const vulkan_user_data
 | 
				
			||||||
) -> VkBool32
 | 
					) -> VkBool32
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	std::ignore = vulkan_user_data;
 | 
						auto stats = *(Ref<app::SystemStats> *)vulkan_user_data; // NOLINT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const auto &type = parse_message_type(message_types);
 | 
						const auto &type = parse_message_type(message_types);
 | 
				
			||||||
	const auto level = parse_message_severity(message_severity);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Logger::log(level, ":: <{}> :: {}", type, callback_data->pMessage);
 | 
						auto message = std::format(
 | 
				
			||||||
 | 
						    "Vulkan Validation Message:\ntype: {}\nseverity: {}\nmessage: {}",
 | 
				
			||||||
 | 
						    type,
 | 
				
			||||||
 | 
						    std::to_underlying(parse_message_severity(message_severity)),
 | 
				
			||||||
 | 
						    callback_data->pMessage
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto severity = parse_message_severity(message_severity);
 | 
				
			||||||
 | 
						if (std::to_underlying(severity) < 2)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return static_cast<VkBool32>(VK_FALSE);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						stats->push_diagnosis(
 | 
				
			||||||
 | 
						    app::SystemDiagnosis {
 | 
				
			||||||
 | 
						        .message = message,
 | 
				
			||||||
 | 
						        .code = {}, // TODO(Light): extract vulkan validation-layers code from the message
 | 
				
			||||||
 | 
						        .severity = severity,
 | 
				
			||||||
 | 
						    }
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
	return static_cast<VkBool32>(VK_FALSE);
 | 
						return static_cast<VkBool32>(VK_FALSE);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Backend::initialize_instance()
 | 
					void Context::initialize_instance()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto app_info = VkApplicationInfo {
 | 
						auto app_info = VkApplicationInfo {
 | 
				
			||||||
		.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
 | 
							.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
 | 
				
			||||||
| 
						 | 
					@ -198,10 +240,10 @@ void Backend::initialize_instance()
 | 
				
			||||||
		auto extensions = std::vector<VkExtensionProperties>(count);
 | 
							auto extensions = std::vector<VkExtensionProperties>(count);
 | 
				
			||||||
		vk_enumerate_instance_extension_properties(nullptr, &count, extensions.data());
 | 
							vk_enumerate_instance_extension_properties(nullptr, &count, extensions.data());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		log_inf("Available vulkan instance extensions:");
 | 
							// log_inf("Available vulkan instance extensions:");
 | 
				
			||||||
		for (auto &ext : extensions)
 | 
							for (auto &ext : extensions)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			log_inf("\t{} @ {}", ext.extensionName, ext.specVersion);
 | 
								// log_inf("\t{} @ {}", ext.extensionName, ext.specVersion);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -210,7 +252,7 @@ void Backend::initialize_instance()
 | 
				
			||||||
	ensure(m_instance, "Failed to create vulkan instance");
 | 
						ensure(m_instance, "Failed to create vulkan instance");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Backend::initialize_debug_messenger()
 | 
					void Context::initialize_debug_messenger()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const auto info = VkDebugUtilsMessengerCreateInfoEXT {
 | 
						const auto info = VkDebugUtilsMessengerCreateInfoEXT {
 | 
				
			||||||
		.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
 | 
							.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
 | 
				
			||||||
| 
						 | 
					@ -226,6 +268,8 @@ void Backend::initialize_debug_messenger()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		.pfnUserCallback = &validation_layers_callback,
 | 
							.pfnUserCallback = &validation_layers_callback,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							.pUserData = &m_stats,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ensure(
 | 
						ensure(
 | 
				
			||||||
| 
						 | 
					@ -234,7 +278,7 @@ void Backend::initialize_debug_messenger()
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Backend::initialize_physical_device()
 | 
					void Context::initialize_physical_device()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto count = 0u;
 | 
						auto count = 0u;
 | 
				
			||||||
	vk_enumerate_physical_devices(m_instance, &count, nullptr);
 | 
						vk_enumerate_physical_devices(m_instance, &count, nullptr);
 | 
				
			||||||
| 
						 | 
					@ -260,7 +304,7 @@ void Backend::initialize_physical_device()
 | 
				
			||||||
	ensure(m_physical_device, "Failed to find any suitable Vulkan physical device");
 | 
						ensure(m_physical_device, "Failed to find any suitable Vulkan physical device");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Backend::initialize_logical_device()
 | 
					void Context::initialize_logical_device()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const float priorities = .0f;
 | 
						const float priorities = .0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -292,12 +336,12 @@ void Backend::initialize_logical_device()
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Backend::initialize_queue()
 | 
					void Context::initialize_queue()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	vk_get_device_queue(m_device, find_suitable_queue_family(), 0, &m_queue);
 | 
						vk_get_device_queue(m_device, find_suitable_queue_family(), 0, &m_queue);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Backend::load_library()
 | 
					void Context::load_library()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	library = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
 | 
						library = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
 | 
				
			||||||
	ensure(library, "Failed to dlopen libvulkan.so");
 | 
						ensure(library, "Failed to dlopen libvulkan.so");
 | 
				
			||||||
| 
						 | 
					@ -309,13 +353,13 @@ void Backend::load_library()
 | 
				
			||||||
	ensure(vk_get_instance_proc_address, "Failed to load vulkan function: vkGetInstanceProcAddr");
 | 
						ensure(vk_get_instance_proc_address, "Failed to load vulkan function: vkGetInstanceProcAddr");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Backend::load_global_functions()
 | 
					void Context::load_global_functions()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	constexpr auto load_fn = []<typename T>(T &pfn, const char *fn_name) {
 | 
						constexpr auto load_fn = []<typename T>(T &pfn, const char *fn_name) {
 | 
				
			||||||
		// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
 | 
							// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
 | 
				
			||||||
		pfn = reinterpret_cast<T>(vk_get_instance_proc_address(nullptr, fn_name));
 | 
							pfn = reinterpret_cast<T>(vk_get_instance_proc_address(nullptr, fn_name));
 | 
				
			||||||
		ensure(pfn, "Failed to load vulkan global function: {}", fn_name);
 | 
							ensure(pfn, "Failed to load vulkan global function: {}", fn_name);
 | 
				
			||||||
		log_trc("Loaded global function: {}", fn_name);
 | 
							// log_trc("Loaded global function: {}", fn_name);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	load_fn(vk_create_instance, "vkCreateInstance");
 | 
						load_fn(vk_create_instance, "vkCreateInstance");
 | 
				
			||||||
| 
						 | 
					@ -323,13 +367,13 @@ void Backend::load_global_functions()
 | 
				
			||||||
	load_fn(vk_enumerate_instance_layer_properties, "vkEnumerateInstanceLayerProperties");
 | 
						load_fn(vk_enumerate_instance_layer_properties, "vkEnumerateInstanceLayerProperties");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Backend::load_instance_functions()
 | 
					void Context::load_instance_functions()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const auto load_fn = [&]<typename T>(T &pfn, const char *fn_name) {
 | 
						const auto load_fn = [&]<typename T>(T &pfn, const char *fn_name) {
 | 
				
			||||||
		// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
 | 
							// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
 | 
				
			||||||
		pfn = reinterpret_cast<T>(vk_get_instance_proc_address(m_instance, fn_name));
 | 
							pfn = reinterpret_cast<T>(vk_get_instance_proc_address(m_instance, fn_name));
 | 
				
			||||||
		ensure(pfn, "Failed to load vulkan instance function: {}", fn_name);
 | 
							ensure(pfn, "Failed to load vulkan instance function: {}", fn_name);
 | 
				
			||||||
		log_trc("Loaded instance function: {}", fn_name);
 | 
							// log_trc("Loaded instance function: {}", fn_name);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	load_fn(vk_destroy_instance, "vkDestroyInstance");
 | 
						load_fn(vk_destroy_instance, "vkDestroyInstance");
 | 
				
			||||||
| 
						 | 
					@ -356,15 +400,18 @@ void Backend::load_instance_functions()
 | 
				
			||||||
	load_fn(vk_set_debug_object_name, "vkSetDebugUtilsObjectNameEXT");
 | 
						load_fn(vk_set_debug_object_name, "vkSetDebugUtilsObjectNameEXT");
 | 
				
			||||||
	load_fn(vk_set_debug_object_tag, "vkSetDebugUtilsObjectTagEXT");
 | 
						load_fn(vk_set_debug_object_tag, "vkSetDebugUtilsObjectTagEXT");
 | 
				
			||||||
	load_fn(vk_submit_debug_message, "vkSubmitDebugUtilsMessageEXT");
 | 
						load_fn(vk_submit_debug_message, "vkSubmitDebugUtilsMessageEXT");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						load_fn(vk_create_xlib_surface_khr, "vkCreateXlibSurfaceKHR");
 | 
				
			||||||
 | 
						load_fn(vk_destroy_surface_khr, "vkDestroySurfaceKHR");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Backend::load_device_functions()
 | 
					void Context::load_device_functions()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const auto load_fn = [&]<typename T>(T &pfn, const char *fn_name) {
 | 
						const auto load_fn = [&]<typename T>(T &pfn, const char *fn_name) {
 | 
				
			||||||
		// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
 | 
							// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
 | 
				
			||||||
		pfn = reinterpret_cast<T>(vk_get_device_proc_address(m_device, fn_name));
 | 
							pfn = reinterpret_cast<T>(vk_get_device_proc_address(m_device, fn_name));
 | 
				
			||||||
		ensure(pfn, "Failed to load vulkan device function: {}", fn_name);
 | 
							ensure(pfn, "Failed to load vulkan device function: {}", fn_name);
 | 
				
			||||||
		log_trc("Loaded device function: {}", fn_name);
 | 
							// log_trc("Loaded device function: {}", fn_name);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	load_fn(vk_get_device_queue, "vkGetDeviceQueue");
 | 
						load_fn(vk_get_device_queue, "vkGetDeviceQueue");
 | 
				
			||||||
| 
						 | 
					@ -409,7 +456,7 @@ void Backend::load_device_functions()
 | 
				
			||||||
	load_fn(vk_cmd_set_scissors, "vkCmdSetScissor");
 | 
						load_fn(vk_cmd_set_scissors, "vkCmdSetScissor");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[nodiscard]] auto Backend::find_suitable_queue_family() const -> uint32_t
 | 
					[[nodiscard]] auto Context::find_suitable_queue_family() const -> uint32_t
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto count = 0u;
 | 
						auto count = 0u;
 | 
				
			||||||
	vk_get_physical_device_queue_family_properties(m_physical_device, &count, nullptr);
 | 
						vk_get_physical_device_queue_family_properties(m_physical_device, &count, nullptr);
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,20 @@
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VK_NO_PROTOTYPES
 | 
					#define VK_NO_PROTOTYPES
 | 
				
			||||||
#include <renderer/backend.hpp>
 | 
					#define VK_USE_PLATFORM_XLIB_KHR
 | 
				
			||||||
#include <vulkan/vulkan.h>
 | 
					#include <vulkan/vulkan.h>
 | 
				
			||||||
 | 
					#include <vulkan/vulkan_xlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#include <app/system.hpp>
 | 
				
			||||||
 | 
					#include <ecs/entity.hpp>
 | 
				
			||||||
 | 
					#include <memory/pointer_types/null_on_move.hpp>
 | 
				
			||||||
 | 
					#include <surface/components.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace lt::renderer::vk {
 | 
					namespace lt::renderer::vk {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using memory::NullOnMove;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables)
 | 
					// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables)
 | 
				
			||||||
// global functions
 | 
					// global functions
 | 
				
			||||||
extern PFN_vkGetInstanceProcAddr vk_get_instance_proc_address;
 | 
					extern PFN_vkGetInstanceProcAddr vk_get_instance_proc_address;
 | 
				
			||||||
| 
						 | 
					@ -78,26 +87,54 @@ extern PFN_vkCmdBindPipeline vk_cmd_bind_pipeline;
 | 
				
			||||||
extern PFN_vkCmdDraw vk_cmd_draw;
 | 
					extern PFN_vkCmdDraw vk_cmd_draw;
 | 
				
			||||||
extern PFN_vkCmdSetViewport vk_cmd_set_viewport;
 | 
					extern PFN_vkCmdSetViewport vk_cmd_set_viewport;
 | 
				
			||||||
extern PFN_vkCmdSetScissor vk_cmd_set_scissors;
 | 
					extern PFN_vkCmdSetScissor vk_cmd_set_scissors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern PFN_vkCreateXlibSurfaceKHR vk_create_xlib_surface_khr;
 | 
				
			||||||
 | 
					extern PFN_vkDestroySurfaceKHR vk_destroy_surface_khr;
 | 
				
			||||||
// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
 | 
					// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Backend: public ::lt::renderer::Backend
 | 
					class Context
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	Backend();
 | 
						Context(const ecs::Entity &surface_entity, Ref<app::SystemStats> system_stats);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Backend(Backend &&) = default;
 | 
						~Context();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto operator=(Backend &&) -> Backend & = default;
 | 
						Context(Context &&other) noexcept = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Backend(const Backend &) = delete;
 | 
						auto operator=(Context &&other) noexcept -> Context & = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto operator=(const Backend &) -> Backend & = delete;
 | 
						Context(const Context &) = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	~Backend() override;
 | 
						auto operator=(const Context &) -> Context & = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] constexpr auto get_api() const -> API override
 | 
						[[nodiscard]] auto instance() -> VkInstance
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return API::vulkan;
 | 
							return m_instance;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto physical_device() -> VkPhysicalDevice
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_physical_device;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto device() -> VkDevice
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_device;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto queue() -> VkQueue
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_queue;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto debug_messenger() -> VkDebugUtilsMessengerEXT
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_debug_messenger;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto get_stats() const -> const app::SystemStats &
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return *m_stats;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
| 
						 | 
					@ -121,15 +158,23 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] auto find_suitable_queue_family() const -> uint32_t;
 | 
						[[nodiscard]] auto find_suitable_queue_family() const -> uint32_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	VkInstance m_instance {};
 | 
						Ref<ecs::Registry> m_registry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	VkPhysicalDevice m_physical_device {};
 | 
						NullOnMove<VkInstance> m_instance = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	VkDevice m_device {};
 | 
						NullOnMove<VkPhysicalDevice> m_physical_device = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	VkQueue m_queue {};
 | 
						NullOnMove<VkDevice> m_device = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	VkDebugUtilsMessengerEXT m_debug_messenger {};
 | 
						NullOnMove<VkQueue> m_queue = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						NullOnMove<VkSwapchainKHR> m_swapcha = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						NullOnMove<VkDebugUtilsMessengerEXT> m_debug_messenger = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						NullOnMove<VkSurfaceKHR> m_surface = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Ref<app::SystemStats> m_stats;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace lt::renderer::vk
 | 
					} // namespace lt::renderer::vk
 | 
				
			||||||
							
								
								
									
										26
									
								
								modules/renderer/private/vk/surface.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								modules/renderer/private/vk/surface.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define VK_NO_PROTOTYPES
 | 
				
			||||||
 | 
					#define VK_USE_PLATFORM_XLIB_KHR
 | 
				
			||||||
 | 
					#include <vulkan/vulkan.h>
 | 
				
			||||||
 | 
					#include <vulkan/vulkan_xlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#include <ecs/entity.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::renderer::vk {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Surface
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						Surface(ecs::Entity entity)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						~Surface();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						VkSurfaceKHR m_surface = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::renderer::vk
 | 
				
			||||||
							
								
								
									
										22
									
								
								modules/renderer/private/vk/swapchain.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								modules/renderer/private/vk/swapchain.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define VK_NO_PROTOTYPES
 | 
				
			||||||
 | 
					#include <vulkan/vulkan.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::renderer::vk {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Swapchain
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						Swapchain()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						VkSwapchainKHR m_swapchain {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::vector<VkImage> images;
 | 
				
			||||||
 | 
						std::vector<VkImageView> image_views;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::renderer::vk
 | 
				
			||||||
| 
						 | 
					@ -1,41 +1,30 @@
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <base/base.hpp>
 | 
					#include <app/system.hpp>
 | 
				
			||||||
#include <ecs/registry.hpp>
 | 
					#include <ecs/entity.hpp>
 | 
				
			||||||
 | 
					#include <renderer/validation.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/context.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace lt::renderer {
 | 
					namespace lt::renderer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** The system for putting gore on your display
 | 
					class System: app::ISystem
 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Exclusively operates on components:
 | 
					 | 
				
			||||||
 * - RendererComponent
 | 
					 | 
				
			||||||
 * - PostEffectsComponent
 | 
					 | 
				
			||||||
 * - UserInterfaceComponent
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Requires read acces on components:
 | 
					 | 
				
			||||||
 * - TransformComponent
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
class System
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	/** The configurations of this system. */
 | 
						struct CreateInfo
 | 
				
			||||||
	struct Properties
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** The requirements for this system to initialize. */
 | 
					 | 
				
			||||||
	struct InitRequirements
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Ref<ecs::Registry> registry;
 | 
							Ref<ecs::Registry> registry;
 | 
				
			||||||
 | 
							ecs::Entity surface_entity;
 | 
				
			||||||
 | 
							Ref<app::SystemStats> system_stats;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** The requirements for this system to tick. */
 | 
						[[nodiscard]] System(CreateInfo info)
 | 
				
			||||||
	struct TickRequirements
 | 
						    : m_registry(std::move(info.registry))
 | 
				
			||||||
 | 
						    , m_context(info.surface_entity, std::move(info.system_stats))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		double delta_time;
 | 
							ensure(m_registry, "Failed to initialize renderer system: null registry");
 | 
				
			||||||
	};
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] System(InitRequirements requirements);
 | 
						~System() override = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	System(System &&) = default;
 | 
						System(System &&) = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,12 +34,38 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto operator=(const System &) -> System & = delete;
 | 
						auto operator=(const System &) -> System & = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	~System();
 | 
						void on_register() override
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void tick(TickRequirements requirements);
 | 
						void on_unregister() override
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void get_validation_state();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void tick(app::TickInfo tick) override
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto get_stats() const -> const app::SystemStats &
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_context.get_stats();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto get_last_tick_result() const -> const app::TickResult & override
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_last_tick_result;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	Ref<ecs::Registry> m_registry;
 | 
						Ref<ecs::Registry> m_registry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						renderer::Validation m_validation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vk::Context m_context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						app::TickResult m_last_tick_result {};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace lt::renderer
 | 
					} // namespace lt::renderer
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										25
									
								
								modules/renderer/public/validation.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								modules/renderer/public/validation.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,25 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::renderer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class Severity : uint8_t
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						off,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						very_verbose,
 | 
				
			||||||
 | 
						verbose,
 | 
				
			||||||
 | 
						info,
 | 
				
			||||||
 | 
						warning,
 | 
				
			||||||
 | 
						error,
 | 
				
			||||||
 | 
						critical,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Validation
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						void push_diagnosis();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::renderer
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue