Compare commits
	
		
			9 commits
		
	
	
		
			4976773218
			...
			1ce8aed8a2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 1ce8aed8a2 | |||
| c4403b7c90 | |||
| ebf1f54d31 | |||
| 01db551fa9 | |||
| 4ad50122ef | |||
| 0c4b3dd0f9 | |||
| 0fe399a33e | |||
| 85dbe47990 | |||
| 83a872f3f3 | 
					 58 changed files with 1167 additions and 896 deletions
				
			
		| 
						 | 
					@ -1,6 +1,4 @@
 | 
				
			||||||
# Light
 | 
					# Light
 | 
				
			||||||
See docs.light7734.com for a comprehensive project documentation
 | 
					See docs.light7734.com for a comprehensive project documentation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<!---FUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUCK
 | 
					###### “No great thing comes into being all at once, any more than a cluster of grapes or a fig. If you tell me, 'I want a fig,' I will answer that it needs time. Let it flower first, then put forth its fruit and then ripen. I say then, if the fig tree's fruit is not brought to perfection suddenly in a single hour, would you expect to gather the fruit of a person’s mind so soon and so easily? I tell you, you must not expect it.” —Epictetus, Discourses 1.15.7-8
 | 
				
			||||||
MEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
 | 
					 | 
				
			||||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!!!!!!!!-->
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -1,10 +0,0 @@
 | 
				
			||||||
#version 440 core
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
in vec4 vso_FragmentColor;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
out vec4 fso_FragmentColor;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void main()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	fso_FragmentColor = vso_FragmentColor;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -1,17 +0,0 @@
 | 
				
			||||||
#version 440 core
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
layout(location = 0) in vec4 a_Position;
 | 
					 | 
				
			||||||
layout(location = 1) in vec4 a_Color;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
layout(std140, binding = 0) uniform ub_ViewProjection
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	mat4 viewProjection;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
layout(location = 0) out vec4 vso_FragmentColor;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void main()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	gl_Position = viewProjection * a_Position;
 | 
					 | 
				
			||||||
	vso_FragmentColor = a_Color;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -1,12 +0,0 @@
 | 
				
			||||||
#version 450 core
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
in vec2 vso_TexCoord;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uniform sampler2D u_Texture;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
out vec4 fso_FragmentColor;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void main()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	fso_FragmentColor = texture(u_Texture, vso_TexCoord);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -1,19 +0,0 @@
 | 
				
			||||||
#version 450 core
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
layout(location = 0) in vec4 a_Position;
 | 
					 | 
				
			||||||
layout(location = 1) in vec2 a_TexCoord;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
layout(std140, binding = 0) uniform ub_ViewProjection
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	mat4 u_ViewProjection;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
layout(location = 0) out vec2 vso_TexCoord;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void main()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	gl_Position = u_ViewProjection * a_Position;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	vso_TexCoord = a_TexCoord;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -1,14 +0,0 @@
 | 
				
			||||||
#version 450 core
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
in vec4 vso_Tint;
 | 
					 | 
				
			||||||
in vec2 vso_TexCoord;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uniform sampler2D u_Texture;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
out vec4 fso_FragmentColor;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void main()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	fso_FragmentColor = texture(u_Texture, vso_TexCoord) * vso_Tint;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -1,21 +0,0 @@
 | 
				
			||||||
#version 450 core
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
layout(location = 0) in vec4 a_Position;
 | 
					 | 
				
			||||||
layout(location = 1) in vec4 a_Tint;
 | 
					 | 
				
			||||||
layout(location = 2) in vec2 a_TexCoord;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
layout(std140, binding = 0) uniform ub_ViewProjection
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	mat4 u_ViewProjection;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
out vec4 vso_Tint;
 | 
					 | 
				
			||||||
out vec2 vso_TexCoord; 
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void main()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	gl_Position = u_ViewProjection * a_Position;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	vso_Tint = a_Tint;
 | 
					 | 
				
			||||||
	vso_TexCoord = a_TexCoord;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										1
									
								
								data/test_assets/dummytext
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								data/test_assets/dummytext
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					The quick brown fox jumps over the lazy dog
 | 
				
			||||||
							
								
								
									
										10
									
								
								data/test_assets/triangle.frag
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								data/test_assets/triangle.frag
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,10 @@
 | 
				
			||||||
 | 
					#version 450 core
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout(location = 0) in vec3 in_frag_color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout(location = 0) out vec4 out_frag_color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void main()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						out_frag_color =  vec4(in_frag_color, 1.0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										21
									
								
								data/test_assets/triangle.vert
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								data/test_assets/triangle.vert
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,21 @@
 | 
				
			||||||
 | 
					#version 450 core
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vec2 positions[3] = vec2[](
 | 
				
			||||||
 | 
					    vec2(0.0, -0.5),
 | 
				
			||||||
 | 
					    vec2(0.5, 0.5),
 | 
				
			||||||
 | 
					    vec2(-0.5, 0.5)
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vec3 colors[3] = vec3[](
 | 
				
			||||||
 | 
					    vec3(1.0, 0.0, 0.0),
 | 
				
			||||||
 | 
					    vec3(0.0, 1.0, 0.0),
 | 
				
			||||||
 | 
					    vec3(0.0, 0.0, 1.0)
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout(location = 0) out vec3 out_frag_color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void main() 
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
 | 
				
			||||||
 | 
					    out_frag_color = colors[gl_VertexIndex];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -6,9 +6,8 @@ add_subdirectory(./logger)
 | 
				
			||||||
add_subdirectory(./debug)
 | 
					add_subdirectory(./debug)
 | 
				
			||||||
add_subdirectory(./math)
 | 
					add_subdirectory(./math)
 | 
				
			||||||
# 
 | 
					# 
 | 
				
			||||||
# add_subdirectory(./asset_baker)
 | 
					add_subdirectory(./asset_baker)
 | 
				
			||||||
# add_subdirectory(./asset_parser)
 | 
					add_subdirectory(./assets)
 | 
				
			||||||
# add_subdirectory(./asset_manager)
 | 
					 | 
				
			||||||
# 
 | 
					# 
 | 
				
			||||||
add_subdirectory(./camera)
 | 
					add_subdirectory(./camera)
 | 
				
			||||||
add_subdirectory(./input)
 | 
					add_subdirectory(./input)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,17 @@
 | 
				
			||||||
add_executable_module(
 | 
					add_library_module(libasset_baker
 | 
				
			||||||
    asset_baker entrypoint/baker.cpp
 | 
					    bakers.cpp
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					target_link_libraries(libasset_baker
 | 
				
			||||||
 | 
					PUBLIC
 | 
				
			||||||
 | 
					    assets
 | 
				
			||||||
 | 
					    logger
 | 
				
			||||||
 | 
					    lt_debug
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					add_test_module(libasset_baker 
 | 
				
			||||||
 | 
					    bakers.test.cpp
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
target_link_libraries(
 | 
					add_executable_module(asset_baker
 | 
				
			||||||
    asset_baker
 | 
					    entrypoint/baker.cpp
 | 
				
			||||||
    PRIVATE asset_parser
 | 
					 | 
				
			||||||
    PRIVATE logger
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					target_link_libraries(asset_baker PRIVATE libasset_baker)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										0
									
								
								modules/asset_baker/private/bakers.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								modules/asset_baker/private/bakers.cpp
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										7
									
								
								modules/asset_baker/private/bakers.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								modules/asset_baker/private/bakers.test.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					#include <asset_baker/bakers.hpp>
 | 
				
			||||||
 | 
					#include <test/test.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ::lt::test::Case;
 | 
				
			||||||
 | 
					using ::lt::test::Suite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO(Light): add asset baking tests!
 | 
				
			||||||
| 
						 | 
					@ -1,68 +1,5 @@
 | 
				
			||||||
#include <asset_baker/bakers.hpp>
 | 
					#include <asset_baker/bakers.hpp>
 | 
				
			||||||
#include <asset_parser/assets/text.hpp>
 | 
					#include <assets/shader.hpp>
 | 
				
			||||||
#include <asset_parser/assets/texture.hpp>
 | 
					 | 
				
			||||||
#include <asset_parser/parser.hpp>
 | 
					 | 
				
			||||||
#include <filesystem>
 | 
					 | 
				
			||||||
#include <logger/logger.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void try_packing_texture(
 | 
					 | 
				
			||||||
    const std::filesystem::path &in_path,
 | 
					 | 
				
			||||||
    const std::filesystem::path &out_path
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	auto texture_loader = lt::TextureLoaderFactory::create(in_path.extension().string());
 | 
					 | 
				
			||||||
	if (!texture_loader)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		// Don't log anything; this is expected.
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	try
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		Assets::TextureAsset::pack(texture_loader->load(in_path), out_path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		log_inf("Packed a texture asset:");
 | 
					 | 
				
			||||||
		log_inf("\tloader  : {}", texture_loader->get_name());
 | 
					 | 
				
			||||||
		log_inf("\tin  path: {}", in_path.string());
 | 
					 | 
				
			||||||
		log_inf("\tout path: {}", out_path.string());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	catch (const std::exception &exp)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		log_err("Failed to pack texture asset:");
 | 
					 | 
				
			||||||
		log_err("\tloader  : {}", texture_loader->get_name());
 | 
					 | 
				
			||||||
		log_err("\tin path : {}", in_path.string());
 | 
					 | 
				
			||||||
		log_err("\tout path: {}", out_path.string());
 | 
					 | 
				
			||||||
		log_err("\texp.what: {}", exp.what());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void try_packing_text(const std::filesystem::path &in_path, const std::filesystem::path &out_path)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	auto text_loader = lt::TextLoaderFactory::create(in_path.extension().string());
 | 
					 | 
				
			||||||
	if (!text_loader)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		// Don't log anything; this is expected.
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	try
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		Assets::TextAsset::pack(text_loader->load(in_path), out_path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		log_inf("Packed a text asset:");
 | 
					 | 
				
			||||||
		log_inf("\tloader  : {}", text_loader->get_name());
 | 
					 | 
				
			||||||
		log_inf("\tin  path: {}", in_path.string());
 | 
					 | 
				
			||||||
		log_inf("\tout path: {}", out_path.string());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	catch (const std::exception &exp)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		log_err("Failed to pack a text asset:");
 | 
					 | 
				
			||||||
		log_err("\tloader  : {}", text_loader->get_name());
 | 
					 | 
				
			||||||
		log_err("\tin path : {}", in_path.string());
 | 
					 | 
				
			||||||
		log_err("\tout path: {}", out_path.string());
 | 
					 | 
				
			||||||
		log_err("\texp.what: {}", exp.what());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto main(int argc, char *argv[]) -> int32_t
 | 
					auto main(int argc, char *argv[]) -> int32_t
 | 
				
			||||||
try
 | 
					try
 | 
				
			||||||
| 
						 | 
					@ -81,12 +18,16 @@ try
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const auto &in_path = directory_iterator.path();
 | 
							const auto &in_path = directory_iterator.path();
 | 
				
			||||||
 | 
							const auto out_path = std::format("{}.asset", in_path.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		auto out_path = in_path;
 | 
							if (in_path.extension() == ".vert")
 | 
				
			||||||
		out_path.replace_extension(".asset");
 | 
							{
 | 
				
			||||||
 | 
								bake_shader(in_path, out_path, lt::assets::ShaderAsset::Type::vertex);
 | 
				
			||||||
		try_packing_texture(in_path, out_path);
 | 
							}
 | 
				
			||||||
		try_packing_text(in_path, out_path);
 | 
							else if (in_path.extension() == ".frag")
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								bake_shader(in_path, out_path, lt::assets::ShaderAsset::Type::fragment);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return EXIT_SUCCESS;
 | 
						return EXIT_SUCCESS;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,114 +1,64 @@
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asset_parser/assets/text.hpp>
 | 
					#include <assets/shader.hpp>
 | 
				
			||||||
#include <asset_parser/assets/texture.hpp>
 | 
					 | 
				
			||||||
#include <filesystem>
 | 
					 | 
				
			||||||
#include <logger/logger.hpp>
 | 
					 | 
				
			||||||
#include <string_view>
 | 
					 | 
				
			||||||
#include <unordered_set>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace lt {
 | 
					inline void bake_shader(
 | 
				
			||||||
 | 
					    const std::filesystem::path &in_path,
 | 
				
			||||||
class Loader
 | 
					    const std::filesystem::path &out_path,
 | 
				
			||||||
 | 
					    lt::assets::ShaderAsset::Type type
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
						using lt::assets::ShaderAsset;
 | 
				
			||||||
	[[nodiscard]] virtual auto get_name() const -> std::string_view = 0;
 | 
						using enum lt::assets::ShaderAsset::Type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Loader() = default;
 | 
						auto glsl_path = in_path.string();
 | 
				
			||||||
 | 
						auto spv_path = std::format("{}.spv", glsl_path);
 | 
				
			||||||
 | 
						log_trc(
 | 
				
			||||||
 | 
						    "Compiling {} shader {} -> {}",
 | 
				
			||||||
 | 
						    type == vertex ? "vertex" : "fragment",
 | 
				
			||||||
 | 
						    glsl_path,
 | 
				
			||||||
 | 
						    spv_path
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Loader(Loader &&) = default;
 | 
						// Don't bother linking to shaderc, just invoke the command with a system call.
 | 
				
			||||||
 | 
						// NOLINTNEXTLINE(concurrency-mt-unsafe)
 | 
				
			||||||
 | 
						system(
 | 
				
			||||||
 | 
						    std::format(
 | 
				
			||||||
 | 
						        "glslc --target-env=vulkan1.4 -std=450core -fshader-stage={} {} -o {}",
 | 
				
			||||||
 | 
						        type == vertex ? "vert" : "frag",
 | 
				
			||||||
 | 
						        glsl_path,
 | 
				
			||||||
 | 
						        spv_path
 | 
				
			||||||
 | 
						    )
 | 
				
			||||||
 | 
						        .c_str()
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Loader(const Loader &) = delete;
 | 
						auto stream = std::ifstream(spv_path, std::ios::binary);
 | 
				
			||||||
 | 
						lt::ensure(
 | 
				
			||||||
 | 
						    stream.is_open(),
 | 
				
			||||||
 | 
						    "Failed to open compiled {} shader at: {}",
 | 
				
			||||||
 | 
						    type == vertex ? "vert" : "frag",
 | 
				
			||||||
 | 
						    spv_path
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto operator=(Loader &&) -> Loader & = default;
 | 
						stream.seekg(0, std::ios::end);
 | 
				
			||||||
 | 
						const auto size = stream.tellg();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto operator=(const Loader &) -> Loader & = delete;
 | 
						auto bytes = std::vector<std::byte>(size);
 | 
				
			||||||
 | 
						stream.seekg(0, std::ios::beg);
 | 
				
			||||||
 | 
						stream.read((char *)bytes.data(), size); // NOLINT
 | 
				
			||||||
 | 
						log_dbg("BYTES: {}", bytes.size());
 | 
				
			||||||
 | 
						stream.close();
 | 
				
			||||||
 | 
						std::filesystem::remove(spv_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	virtual ~Loader() = default;
 | 
						ShaderAsset::pack(
 | 
				
			||||||
 | 
						    out_path,
 | 
				
			||||||
private:
 | 
						    lt::assets::AssetMetadata {
 | 
				
			||||||
};
 | 
						        .version = lt::assets::current_version,
 | 
				
			||||||
 | 
						        .type = ShaderAsset::asset_type_identifier,
 | 
				
			||||||
class TextureLoader: public Loader
 | 
						    },
 | 
				
			||||||
{
 | 
						    ShaderAsset::Metadata {
 | 
				
			||||||
public:
 | 
						        .type = type,
 | 
				
			||||||
	TextureLoader() = default;
 | 
						    },
 | 
				
			||||||
 | 
						    std::move(bytes)
 | 
				
			||||||
	[[nodiscard]] virtual auto load(std::filesystem::path file_path) const
 | 
						);
 | 
				
			||||||
	    -> Assets::TextureAsset::PackageData
 | 
					}
 | 
				
			||||||
	    = 0;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TextureLoaderFactory
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	static auto create(std::string_view file_extension) -> std::unique_ptr<TextureLoader>
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return {};
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TextLoader: Loader
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	[[nodiscard]] static auto get_supported_extensions() -> std::unordered_set<std::string_view>
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return { ".glsl", ".txt", ".hlsl" };
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_name() const -> std::string_view override
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return "TextLoader";
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto load(const std::filesystem::path &file_path) const
 | 
					 | 
				
			||||||
	    -> Assets::TextAsset::PackageData
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		auto stream = std::ifstream { file_path, std::ios::binary };
 | 
					 | 
				
			||||||
		if (!stream.good())
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			throw std::runtime_error {
 | 
					 | 
				
			||||||
				std::format(
 | 
					 | 
				
			||||||
				    "Failed to open ifstream for text loading of file: {}",
 | 
					 | 
				
			||||||
				    file_path.string()
 | 
					 | 
				
			||||||
				),
 | 
					 | 
				
			||||||
			};
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto file_size = std::filesystem::file_size(file_path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto text_blob = Assets::Blob(file_size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		stream.read((char *)(text_blob.data()), static_cast<long>(file_size)); // NOLINT
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		const auto metadata = Assets::Asset::Metadata {
 | 
					 | 
				
			||||||
			.type = Assets::Asset::Type::Text,
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		const auto text_metadata = Assets::TextAsset::Metadata {
 | 
					 | 
				
			||||||
			.lines = {},
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return Assets::TextAsset::PackageData {
 | 
					 | 
				
			||||||
			.metadata = metadata,
 | 
					 | 
				
			||||||
			.text_metadata = {},
 | 
					 | 
				
			||||||
			.text_blob = std::move(text_blob),
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TextLoaderFactory
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	static auto create(std::string_view file_extension) -> std::unique_ptr<TextLoader>
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		if (TextLoader::get_supported_extensions().contains(file_extension))
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			return std::make_unique<TextLoader>();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return {};
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +0,0 @@
 | 
				
			||||||
add_library_module(asset_manager 
 | 
					 | 
				
			||||||
    asset_manager.cpp
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
target_link_libraries(
 | 
					 | 
				
			||||||
  asset_manager
 | 
					 | 
				
			||||||
  PUBLIC asset_parser
 | 
					 | 
				
			||||||
  PRIVATE logger
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,92 +0,0 @@
 | 
				
			||||||
#include <asset_manager/asset_manager.hpp>
 | 
					 | 
				
			||||||
#include <asset_parser/assets/text.hpp>
 | 
					 | 
				
			||||||
#include <asset_parser/assets/texture.hpp>
 | 
					 | 
				
			||||||
#include <logger/logger.hpp>
 | 
					 | 
				
			||||||
#include <renderer/graphics_context.hpp>
 | 
					 | 
				
			||||||
#include <renderer/shader.hpp>
 | 
					 | 
				
			||||||
#include <renderer/texture.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace lt {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* static */ auto AssetManager::instance() -> AssetManager &
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	static auto instance = AssetManager {};
 | 
					 | 
				
			||||||
	return instance;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void AssetManager::load_shader_impl(
 | 
					 | 
				
			||||||
    const std::string &name,
 | 
					 | 
				
			||||||
    const std::filesystem::path &vertex_path,
 | 
					 | 
				
			||||||
    const std::filesystem::path &pixel_path
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	try
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		log_trc("Loading shader:");
 | 
					 | 
				
			||||||
		log_trc("\tname       : {}", name);
 | 
					 | 
				
			||||||
		log_trc("\tvertex path: {}", vertex_path.string());
 | 
					 | 
				
			||||||
		log_trc("\tpixel path : {}", pixel_path.string());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		m_shaders[name] = Ref<Shader>(Shader::create(
 | 
					 | 
				
			||||||
		    get_or_load_text_asset(vertex_path.string()),
 | 
					 | 
				
			||||||
		    get_or_load_text_asset(pixel_path),
 | 
					 | 
				
			||||||
		    GraphicsContext::get_shared_context()
 | 
					 | 
				
			||||||
		));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	catch (const std::exception &exp)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		log_err("Failed to load shader:");
 | 
					 | 
				
			||||||
		log_err("\tname       : {}", name);
 | 
					 | 
				
			||||||
		log_err("\tvertex path: {}", vertex_path.string());
 | 
					 | 
				
			||||||
		log_err("\tpixel path : {}", pixel_path.string());
 | 
					 | 
				
			||||||
		log_err("\texception  : {}", exp.what());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void AssetManager::load_texture_impl(const std::string &name, const std::filesystem::path &path)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	try
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		log_trc("Loading texture:");
 | 
					 | 
				
			||||||
		log_trc("\tname: {}", name);
 | 
					 | 
				
			||||||
		log_trc("\tpath: {}", path.string());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		m_textures[name] = Ref<Texture>(
 | 
					 | 
				
			||||||
		    Texture::create(get_or_load_texture_asset(path), GraphicsContext::get_shared_context())
 | 
					 | 
				
			||||||
		);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	catch (const std::exception &exp)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		log_err("Failed to load texture:");
 | 
					 | 
				
			||||||
		log_err("\tname     : {}", name);
 | 
					 | 
				
			||||||
		log_err("\tpath     : {}", path.string());
 | 
					 | 
				
			||||||
		log_err("\texception: {}", exp.what());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto AssetManager::get_or_load_text_asset(const std::filesystem::path &path)
 | 
					 | 
				
			||||||
    -> Ref<Assets::TextAsset>
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	const auto key = std::filesystem::canonical(path).string();
 | 
					 | 
				
			||||||
	if (!m_text_assets.contains(key))
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		m_text_assets.emplace(key, create_ref<Assets::TextAsset>(path));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return m_text_assets[key];
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
auto AssetManager::get_or_load_texture_asset(const std::filesystem::path &path)
 | 
					 | 
				
			||||||
    -> Ref<Assets::TextureAsset>
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	const auto key = std::filesystem::canonical(path).string();
 | 
					 | 
				
			||||||
	if (!m_texture_assets.contains(key))
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		m_texture_assets.emplace(key, create_ref<Assets::TextureAsset>(path));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return m_texture_assets[key];
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,78 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <filesystem>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Assets {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TextAsset;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TextureAsset;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace Assets
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace lt {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Shader;
 | 
					 | 
				
			||||||
class Texture;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Asset is the data on the disk.
 | 
					 | 
				
			||||||
 * Resource is the data on the gpu/cpu
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * eg. TextureAsset is the file on the disk
 | 
					 | 
				
			||||||
 * eg. Texture is the representation of it in the GPU
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
class AssetManager
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	static void load_shader(
 | 
					 | 
				
			||||||
	    const std::string &name,
 | 
					 | 
				
			||||||
	    const std::filesystem::path &vertex_path,
 | 
					 | 
				
			||||||
	    const std::filesystem::path &pixel_path
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		instance().load_shader_impl(name, vertex_path, pixel_path);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static void load_texture(const std::string &name, const std::filesystem::path &path)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		instance().load_texture_impl(name, path);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static auto get_shader(const std::string &name) -> Ref<Shader>
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return instance().m_shaders[name];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static auto get_texture(const std::string &name) -> Ref<Texture>
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return instance().m_textures[name];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
	AssetManager() = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static auto instance() -> AssetManager &;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void load_shader_impl(
 | 
					 | 
				
			||||||
	    const std::string &name,
 | 
					 | 
				
			||||||
	    const std::filesystem::path &vertex_path,
 | 
					 | 
				
			||||||
	    const std::filesystem::path &pixel_path
 | 
					 | 
				
			||||||
	);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void load_texture_impl(const std::string &name, const std::filesystem::path &path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto get_or_load_text_asset(const std::filesystem::path &path) -> Ref<Assets::TextAsset>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto get_or_load_texture_asset(const std::filesystem::path &path) -> Ref<Assets::TextureAsset>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::unordered_map<std::string, Ref<Assets::TextAsset>> m_text_assets;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::unordered_map<std::string, Ref<Assets::TextureAsset>> m_texture_assets;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::unordered_map<std::string, Ref<Shader>> m_shaders;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::unordered_map<std::string, Ref<Texture>> m_textures;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace lt
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,10 +0,0 @@
 | 
				
			||||||
add_library_module(asset_parser 
 | 
					 | 
				
			||||||
    parser.cpp
 | 
					 | 
				
			||||||
    assets/texture.cpp
 | 
					 | 
				
			||||||
    assets/text.cpp
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
target_link_libraries(
 | 
					 | 
				
			||||||
    asset_parser
 | 
					 | 
				
			||||||
    PRIVATE logger
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,164 +0,0 @@
 | 
				
			||||||
#include <asset_parser/assets/texture.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Assets {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* static */ void TextureAsset::pack(const PackageData &data, const std::filesystem::path &out_path)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	const auto &[metadata, texture_metadata, pixels] = data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto stream = std::ofstream { out_path, std::ios::binary | std::ios::trunc };
 | 
					 | 
				
			||||||
	if (!stream.is_open())
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		throw std::runtime_error {
 | 
					 | 
				
			||||||
			std::format("Failed to open ofstream for packing texture at: {}", out_path.string())
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	stream.seekp(0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
 | 
					 | 
				
			||||||
	stream.write((char *)¤t_version, sizeof(current_version));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stream.write((char *)&metadata, sizeof(metadata));
 | 
					 | 
				
			||||||
	stream.write((char *)&texture_metadata, sizeof(texture_metadata));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	constexpr auto number_of_blobs = uint32_t { 1 };
 | 
					 | 
				
			||||||
	stream.write((char *)&number_of_blobs, sizeof(number_of_blobs));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto pixels_metadata = BlobMetadata {
 | 
					 | 
				
			||||||
		.tag = BlobMetadata::Tag::color,
 | 
					 | 
				
			||||||
		.offset = static_cast<size_t>(stream.tellp()) + sizeof(BlobMetadata),
 | 
					 | 
				
			||||||
		.compression_type = CompressionType::None,
 | 
					 | 
				
			||||||
		.compressed_size = pixels.size(),
 | 
					 | 
				
			||||||
		.uncompressed_size = pixels.size(),
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stream.write((char *)&pixels_metadata, sizeof(pixels_metadata));
 | 
					 | 
				
			||||||
	stream.write((char *)&pixels[0], static_cast<long>(pixels.size()));
 | 
					 | 
				
			||||||
	// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TextureAsset::TextureAsset(const std::filesystem::path &path)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	m_stream = std::ifstream { path, std::ios::binary };
 | 
					 | 
				
			||||||
	if (!m_stream.is_open())
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		throw std::runtime_error {
 | 
					 | 
				
			||||||
			std::format("Failed to open ifstream for loading texture asset at: {}", path.string())
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
 | 
					 | 
				
			||||||
	m_stream.read((char *)&version, sizeof(version));
 | 
					 | 
				
			||||||
	m_stream.read((char *)&m_asset_metadata, sizeof(m_asset_metadata));
 | 
					 | 
				
			||||||
	m_stream.read((char *)&m_metadata, sizeof(m_metadata));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto num_blobs = uint32_t {};
 | 
					 | 
				
			||||||
	m_stream.read((char *)&num_blobs, sizeof(num_blobs));
 | 
					 | 
				
			||||||
	if (num_blobs != 1)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		throw std::runtime_error {
 | 
					 | 
				
			||||||
			std::format("Failed to load texture asset: invalid number of blobs: {}", num_blobs)
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	m_stream.read((char *)&m_pixel_blob_metadata, sizeof(m_pixel_blob_metadata));
 | 
					 | 
				
			||||||
	if (m_pixel_blob_metadata.tag != BlobMetadata::Tag::color)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		throw std::runtime_error {
 | 
					 | 
				
			||||||
			std::format(
 | 
					 | 
				
			||||||
			    "Failed to load texture asset: invalid blob tag, expected {}, got {}",
 | 
					 | 
				
			||||||
			    std::to_underlying(BlobMetadata::Tag::color),
 | 
					 | 
				
			||||||
			    std::to_underlying(m_pixel_blob_metadata.tag)
 | 
					 | 
				
			||||||
			),
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void TextureAsset::unpack_blob(
 | 
					 | 
				
			||||||
    BlobMetadata::Tag tag,
 | 
					 | 
				
			||||||
    std::byte *destination,
 | 
					 | 
				
			||||||
    size_t destination_capacity
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (tag != BlobMetadata::Tag::color)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		throw std::runtime_error {
 | 
					 | 
				
			||||||
			std::format("Invalid tag for unpack_blob of TextureAsset: {}", std::to_underlying(tag))
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	m_stream.seekg(static_cast<long>(m_pixel_blob_metadata.offset));
 | 
					 | 
				
			||||||
	switch (m_pixel_blob_metadata.compression_type)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
	case Assets::CompressionType::None:
 | 
					 | 
				
			||||||
		if (m_pixel_blob_metadata.uncompressed_size != m_pixel_blob_metadata.compressed_size)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			throw std::runtime_error(
 | 
					 | 
				
			||||||
			    "Failed to unpack blob from TextureAsset: "
 | 
					 | 
				
			||||||
			    "compressed/uncompressed size mismatch for no compression "
 | 
					 | 
				
			||||||
			    "type"
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (m_pixel_blob_metadata.uncompressed_size > destination_capacity)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			throw std::runtime_error(
 | 
					 | 
				
			||||||
			    "Failed to unpack blob from TextureAsset: "
 | 
					 | 
				
			||||||
			    "uncompressed_size > destination_capacity, unpacking "
 | 
					 | 
				
			||||||
			    "would result in segfault"
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!m_stream.is_open())
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			throw std::runtime_error(
 | 
					 | 
				
			||||||
			    "Failed to unpack blob from TextureAsset: ifstream is "
 | 
					 | 
				
			||||||
			    "closed"
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		m_stream.read(
 | 
					 | 
				
			||||||
		    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
 | 
					 | 
				
			||||||
		    (char *)destination,
 | 
					 | 
				
			||||||
		    static_cast<long>(m_pixel_blob_metadata.uncompressed_size)
 | 
					 | 
				
			||||||
		);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		throw std::runtime_error(
 | 
					 | 
				
			||||||
		    std::format(
 | 
					 | 
				
			||||||
		        "Failed to unpack blob from TextureAsset: unsupported "
 | 
					 | 
				
			||||||
		        "compression type: {}",
 | 
					 | 
				
			||||||
		        std::to_underlying(m_pixel_blob_metadata.compression_type)
 | 
					 | 
				
			||||||
		    )
 | 
					 | 
				
			||||||
		);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[nodiscard]] auto TextureAsset::get_asset_metadata() const -> const Asset::Metadata &
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return m_asset_metadata;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[nodiscard]] auto TextureAsset::get_metadata() const -> const Metadata &
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return m_metadata;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[nodiscard]] auto TextureAsset::get_blob_metadata(BlobMetadata::Tag tag) const
 | 
					 | 
				
			||||||
    -> const BlobMetadata &
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (tag != BlobMetadata::Tag::color)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		throw std::runtime_error { std::format(
 | 
					 | 
				
			||||||
			"Invalid tag for get_blob_metadata of TextureAsset: {}",
 | 
					 | 
				
			||||||
			std::to_underlying(tag)
 | 
					 | 
				
			||||||
		) };
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return m_pixel_blob_metadata;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace Assets
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,5 +0,0 @@
 | 
				
			||||||
#include <asset_parser/parser.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Assets {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace Assets
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,58 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <asset_parser/compressors/compressors.hpp>
 | 
					 | 
				
			||||||
#include <asset_parser/parser.hpp>
 | 
					 | 
				
			||||||
#include <cstdint>
 | 
					 | 
				
			||||||
#include <filesystem>
 | 
					 | 
				
			||||||
#include <fstream>
 | 
					 | 
				
			||||||
#include <logger/logger.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Assets {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TextAsset: public Asset
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	struct Metadata
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		uint32_t lines {};
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** Data required to pack a text asset */
 | 
					 | 
				
			||||||
	struct PackageData
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		Asset::Metadata metadata;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Metadata text_metadata;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Blob text_blob;
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static void pack(const PackageData &data, const std::filesystem::path &out_path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	TextAsset(const std::filesystem::path &path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void unpack_blob(
 | 
					 | 
				
			||||||
	    BlobMetadata::Tag tag,
 | 
					 | 
				
			||||||
	    std::byte *destination,
 | 
					 | 
				
			||||||
	    size_t destination_capacity
 | 
					 | 
				
			||||||
	) const;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_asset_metadata() const -> const Asset::Metadata &;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_metadata() const -> const Metadata &;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_blob_metadata(BlobMetadata::Tag tag) const -> const BlobMetadata &;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
	uint32_t version {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Asset::Metadata m_asset_metadata {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Metadata m_metadata {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	BlobMetadata m_text_blob_metadata {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mutable std::ifstream m_stream;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace Assets
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,64 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <asset_parser/compressors/compressors.hpp>
 | 
					 | 
				
			||||||
#include <asset_parser/parser.hpp>
 | 
					 | 
				
			||||||
#include <cstdint>
 | 
					 | 
				
			||||||
#include <filesystem>
 | 
					 | 
				
			||||||
#include <fstream>
 | 
					 | 
				
			||||||
#include <logger/logger.hpp>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Assets {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class TextureAsset: public Asset
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	enum class Format : uint32_t // NOLINT(performance-enum-size)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		None = 0,
 | 
					 | 
				
			||||||
		RGBA8,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct Metadata
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		Format format;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		uint32_t num_components;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		std::array<uint32_t, 3> pixel_size;
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** Data required to pack a texture asset */
 | 
					 | 
				
			||||||
	struct PackageData
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		Asset::Metadata metadata;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Metadata texture_metadata;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Blob pixels;
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static void pack(const PackageData &data, const std::filesystem::path &out_path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	TextureAsset(const std::filesystem::path &path);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void unpack_blob(BlobMetadata::Tag tag, std::byte *destination, size_t destination_capacity);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_asset_metadata() const -> const Asset::Metadata &;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_metadata() const -> const Metadata &;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	[[nodiscard]] auto get_blob_metadata(BlobMetadata::Tag tag) const -> const BlobMetadata &;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
	uint32_t version {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Asset::Metadata m_asset_metadata {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Metadata m_metadata {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	BlobMetadata m_pixel_blob_metadata {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::ifstream m_stream;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace Assets
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,14 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <cstdint>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Assets {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum class CompressionType : uint32_t // NOLINT(performance-enum-size)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	None,
 | 
					 | 
				
			||||||
	LZ4,
 | 
					 | 
				
			||||||
	LZ4HC,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,68 +0,0 @@
 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <asset_parser/compressors/compressors.hpp>
 | 
					 | 
				
			||||||
#include <cstdint>
 | 
					 | 
				
			||||||
#include <filesystem>
 | 
					 | 
				
			||||||
#include <fstream>
 | 
					 | 
				
			||||||
#include <logger/logger.hpp>
 | 
					 | 
				
			||||||
#include <utility>
 | 
					 | 
				
			||||||
#include <vector>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace Assets {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
constexpr auto current_version = uint32_t { 1 };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct BlobMetadata
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	enum class Tag : uint8_t
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		text,
 | 
					 | 
				
			||||||
		color,
 | 
					 | 
				
			||||||
		depth,
 | 
					 | 
				
			||||||
		vertices,
 | 
					 | 
				
			||||||
		indices,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Tag tag;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	size_t offset;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	CompressionType compression_type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	size_t compressed_size;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	size_t uncompressed_size;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using Blob = std::vector<std::byte>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Asset
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
	enum class Type : uint32_t // NOLINT(performance-enum-size)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		None,
 | 
					 | 
				
			||||||
		Texture,
 | 
					 | 
				
			||||||
		Text,
 | 
					 | 
				
			||||||
		Mesh,
 | 
					 | 
				
			||||||
		Material,
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct Metadata
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		Type type;
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Asset() = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** Directly unpacks from disk to the destination.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @note The destination MUST have at least blob_metadata.unpacked_size bytes available for
 | 
					 | 
				
			||||||
	 * writing, otherwise segfault could occur!
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	void unpack_blob(BlobMetadata::Tag blob_tag, std::byte *destination);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} // namespace Assets
 | 
					 | 
				
			||||||
							
								
								
									
										14
									
								
								modules/assets/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								modules/assets/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					add_library_module(assets 
 | 
				
			||||||
 | 
					    shader.cpp
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					target_link_libraries(
 | 
				
			||||||
 | 
					assets 
 | 
				
			||||||
 | 
					PUBLIC
 | 
				
			||||||
 | 
					logger 
 | 
				
			||||||
 | 
					lt_debug
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					add_test_module(assets
 | 
				
			||||||
 | 
					    shader.test.cpp
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
							
								
								
									
										73
									
								
								modules/assets/private/shader.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								modules/assets/private/shader.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,73 @@
 | 
				
			||||||
 | 
					#include <assets/shader.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::assets {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ShaderAsset::ShaderAsset(const std::filesystem::path &path)
 | 
				
			||||||
 | 
					    : m_stream(path, std::ios::binary | std::ios::beg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						constexpr auto total_metadata_size = //
 | 
				
			||||||
 | 
						    sizeof(AssetMetadata)            //
 | 
				
			||||||
 | 
						    + sizeof(Metadata)               //
 | 
				
			||||||
 | 
						    + sizeof(BlobMetadata);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ensure(m_stream.is_open(), "Failed to open shader asset at: {}", path.string());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						m_stream.seekg(0, std::ifstream::end);
 | 
				
			||||||
 | 
						const auto file_size = static_cast<size_t>(m_stream.tellg());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ensure(
 | 
				
			||||||
 | 
						    file_size > total_metadata_size,
 | 
				
			||||||
 | 
						    "Failed to open shader asset at: {}, file smaller than metadata: {} < {}",
 | 
				
			||||||
 | 
						    path.string(),
 | 
				
			||||||
 | 
						    total_metadata_size,
 | 
				
			||||||
 | 
						    file_size
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
 | 
				
			||||||
 | 
						m_stream.seekg(0, std::ifstream::beg);
 | 
				
			||||||
 | 
						m_stream.read((char *)&m_asset_metadata, sizeof(m_asset_metadata));
 | 
				
			||||||
 | 
						m_stream.read((char *)&m_metadata, sizeof(m_metadata));
 | 
				
			||||||
 | 
						m_stream.read((char *)&m_code_blob_metadata, sizeof(m_code_blob_metadata));
 | 
				
			||||||
 | 
						// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ensure(
 | 
				
			||||||
 | 
						    m_asset_metadata.type == asset_type_identifier,
 | 
				
			||||||
 | 
						    "Failed to open shader asset at: {}, incorrect asset type: {} != {}",
 | 
				
			||||||
 | 
						    path.string(),
 | 
				
			||||||
 | 
						    m_asset_metadata.type,
 | 
				
			||||||
 | 
						    asset_type_identifier
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ensure(
 | 
				
			||||||
 | 
						    m_asset_metadata.version == current_version,
 | 
				
			||||||
 | 
						    "Failed to open shader asset at: {}, version mismatch: {} != {}",
 | 
				
			||||||
 | 
						    path.string(),
 | 
				
			||||||
 | 
						    m_asset_metadata.version,
 | 
				
			||||||
 | 
						    current_version
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ensure(
 | 
				
			||||||
 | 
						    std::to_underlying(m_metadata.type) <= std::to_underlying(Type::compute),
 | 
				
			||||||
 | 
						    "Failed to open shader asset at: {}, invalid shader type: {}",
 | 
				
			||||||
 | 
						    path.string(),
 | 
				
			||||||
 | 
						    std::to_underlying(m_metadata.type)
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ensure(
 | 
				
			||||||
 | 
						    m_code_blob_metadata.tag == std::to_underlying(BlobTag::code),
 | 
				
			||||||
 | 
						    "Failed to open shader asset at: {}, invalid blob tag: {}",
 | 
				
			||||||
 | 
						    path.string(),
 | 
				
			||||||
 | 
						    m_code_blob_metadata.tag
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ensure(
 | 
				
			||||||
 | 
						    m_code_blob_metadata.offset + m_code_blob_metadata.compressed_size <= file_size,
 | 
				
			||||||
 | 
						    "Failed to open shader asset at: {}, file smaller than blob: {} > {} + {}",
 | 
				
			||||||
 | 
						    path.string(),
 | 
				
			||||||
 | 
						    file_size,
 | 
				
			||||||
 | 
						    m_code_blob_metadata.offset,
 | 
				
			||||||
 | 
						    m_code_blob_metadata.compressed_size
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::assets
 | 
				
			||||||
							
								
								
									
										89
									
								
								modules/assets/private/shader.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								modules/assets/private/shader.test.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,89 @@
 | 
				
			||||||
 | 
					#include <assets/shader.hpp>
 | 
				
			||||||
 | 
					#include <ranges>
 | 
				
			||||||
 | 
					#include <test/test.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ::lt::assets::AssetMetadata;
 | 
				
			||||||
 | 
					using ::lt::assets::BlobMetadata;
 | 
				
			||||||
 | 
					using ::lt::assets::ShaderAsset;
 | 
				
			||||||
 | 
					using ::lt::test::Case;
 | 
				
			||||||
 | 
					using ::lt::test::expect_eq;
 | 
				
			||||||
 | 
					using ::lt::test::expect_throw;
 | 
				
			||||||
 | 
					using ::lt::test::expect_true;
 | 
				
			||||||
 | 
					using ::lt::test::Suite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const auto test_data_path = std::filesystem::path { "./data/test_assets" };
 | 
				
			||||||
 | 
					const auto tmp_path = std::filesystem::path { "/tmp/lt_assets_tests/" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Suite raii = "shader_raii"_suite = [] {
 | 
				
			||||||
 | 
						std::filesystem::current_path(test_data_path);
 | 
				
			||||||
 | 
						std::filesystem::create_directories(tmp_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "happy path won't throw" } = [] {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "many won't freeze/throw" } = [] {
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "unhappy path throws" } = [] {
 | 
				
			||||||
 | 
							expect_throw([] { ShaderAsset { "random_path" }; });
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NOLINTNEXTLINE(cppcoreguidelines-interfaces-global-init)
 | 
				
			||||||
 | 
					Suite packing = "shader_pack"_suite = [] {
 | 
				
			||||||
 | 
						Case { "" } = [] {
 | 
				
			||||||
 | 
							const auto out_path = tmp_path / "shader_packing";
 | 
				
			||||||
 | 
							auto dummy_blob = lt::assets::Blob {};
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 255))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								dummy_blob.emplace_back(static_cast<std::byte>(idx));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const auto expected_size =          //
 | 
				
			||||||
 | 
							    sizeof(AssetMetadata)           //
 | 
				
			||||||
 | 
							    + sizeof(ShaderAsset::Metadata) //
 | 
				
			||||||
 | 
							    + sizeof(BlobMetadata)          //
 | 
				
			||||||
 | 
							    + dummy_blob.size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ShaderAsset::pack(
 | 
				
			||||||
 | 
							    out_path,
 | 
				
			||||||
 | 
							    lt::assets::AssetMetadata {
 | 
				
			||||||
 | 
							        .version = lt::assets::current_version,
 | 
				
			||||||
 | 
							        .type = ShaderAsset::asset_type_identifier,
 | 
				
			||||||
 | 
							    },
 | 
				
			||||||
 | 
							    ShaderAsset::Metadata {
 | 
				
			||||||
 | 
							        .type = ShaderAsset::Type::vertex,
 | 
				
			||||||
 | 
							    },
 | 
				
			||||||
 | 
							    std::move(dummy_blob)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto stream = std::ifstream {
 | 
				
			||||||
 | 
								out_path,
 | 
				
			||||||
 | 
								std::ios::binary | std::ios::beg,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							expect_true(stream.is_open());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							stream.seekg(0, std::ios::end);
 | 
				
			||||||
 | 
							const auto file_size = static_cast<size_t>(stream.tellg());
 | 
				
			||||||
 | 
							expect_eq(file_size, expected_size);
 | 
				
			||||||
 | 
							stream.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto shader_asset = ShaderAsset { out_path };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const auto &asset_metadata = shader_asset.get_asset_metadata();
 | 
				
			||||||
 | 
							expect_eq(asset_metadata.type, ShaderAsset::asset_type_identifier);
 | 
				
			||||||
 | 
							expect_eq(asset_metadata.version, lt::assets::current_version);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							const auto &metadata = shader_asset.get_metadata();
 | 
				
			||||||
 | 
							expect_eq(metadata.type, ShaderAsset::Type::vertex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto blob = shader_asset.unpack(ShaderAsset::BlobTag::code);
 | 
				
			||||||
 | 
							expect_eq(blob.size(), 255);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 255))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								expect_eq(blob[idx], static_cast<std::byte>(idx));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										3
									
								
								modules/assets/public/compressors/lz4.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								modules/assets/public/compressors/lz4.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TO BE DOOO
 | 
				
			||||||
							
								
								
									
										42
									
								
								modules/assets/public/metadata.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								modules/assets/public/metadata.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,42 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::assets {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Type_T = std::array<const char, 16>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Tag_T = uint8_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Version = uint8_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using Blob = std::vector<std::byte>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					constexpr auto current_version = Version { 1u };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class CompressionType : uint8_t
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						none,
 | 
				
			||||||
 | 
						lz4,
 | 
				
			||||||
 | 
						lz4_hc,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct AssetMetadata
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						Version version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Type_T type;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct BlobMetadata
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						Tag_T tag;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						CompressionType compression_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t compressed_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t uncompressed_size;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::assets
 | 
				
			||||||
							
								
								
									
										132
									
								
								modules/assets/public/shader.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								modules/assets/public/shader.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,132 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <assets/metadata.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::assets {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ShaderAsset
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						static constexpr auto asset_type_identifier = Type_T { "SHADER_________" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum class BlobTag : Tag_T
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							code,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum class Type : uint8_t
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							vertex,
 | 
				
			||||||
 | 
							fragment,
 | 
				
			||||||
 | 
							geometry,
 | 
				
			||||||
 | 
							compute,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct Metadata
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Type type;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void pack(
 | 
				
			||||||
 | 
						    const std::filesystem::path &destination,
 | 
				
			||||||
 | 
						    AssetMetadata asset_metadata,
 | 
				
			||||||
 | 
						    Metadata metadata,
 | 
				
			||||||
 | 
						    Blob code_blob
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							auto stream = std::ofstream {
 | 
				
			||||||
 | 
								destination,
 | 
				
			||||||
 | 
								std::ios::binary | std::ios::trunc,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							ensure(stream.is_open(), "Failed to pack shader asset to {}", destination.string());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
 | 
				
			||||||
 | 
							stream.write((char *)&asset_metadata, sizeof(asset_metadata));
 | 
				
			||||||
 | 
							stream.write((char *)&metadata, sizeof(metadata));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto code_blob_metadata = BlobMetadata {
 | 
				
			||||||
 | 
								.tag = std::to_underlying(BlobTag::code),
 | 
				
			||||||
 | 
								.offset = static_cast<size_t>(stream.tellp()) + sizeof(BlobMetadata),
 | 
				
			||||||
 | 
								.compression_type = CompressionType::none,
 | 
				
			||||||
 | 
								.compressed_size = code_blob.size(),
 | 
				
			||||||
 | 
								.uncompressed_size = code_blob.size(),
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							stream.write((char *)&code_blob_metadata, sizeof(BlobMetadata));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							stream.write((char *)code_blob.data(), static_cast<long long>(code_blob.size()));
 | 
				
			||||||
 | 
							// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ShaderAsset(const std::filesystem::path &path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto get_asset_metadata() const -> const AssetMetadata &
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_asset_metadata;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto get_metadata() const -> const Metadata &
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_metadata;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto get_blob_metadata(BlobTag tag) const -> const BlobMetadata &
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							ensure(
 | 
				
			||||||
 | 
							    tag == BlobTag::code,
 | 
				
			||||||
 | 
							    "Invalid blob tag for shader asset: {}",
 | 
				
			||||||
 | 
							    std::to_underlying(tag)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return m_code_blob_metadata;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void unpack_to(BlobTag tag, std::span<std::byte> destination) const
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							ensure(
 | 
				
			||||||
 | 
							    tag == BlobTag::code,
 | 
				
			||||||
 | 
							    "Invalid blob tag for shader asset: {}",
 | 
				
			||||||
 | 
							    std::to_underlying(tag)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ensure(
 | 
				
			||||||
 | 
							    destination.size() >= m_code_blob_metadata.uncompressed_size,
 | 
				
			||||||
 | 
							    "Failed to unpack shader blob {} to destination ({}) of size {} since it's smaller "
 | 
				
			||||||
 | 
							    "than the blobl's uncompressed size: {}",
 | 
				
			||||||
 | 
							    std::to_underlying(tag),
 | 
				
			||||||
 | 
							    (size_t)(destination.data()), // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
 | 
				
			||||||
 | 
							    destination.size(),
 | 
				
			||||||
 | 
							    m_code_blob_metadata.uncompressed_size
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							m_stream.seekg(static_cast<long long>(m_code_blob_metadata.offset));
 | 
				
			||||||
 | 
							m_stream.read(
 | 
				
			||||||
 | 
							    (char *)destination.data(), // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
 | 
				
			||||||
 | 
							    static_cast<long long>(m_code_blob_metadata.uncompressed_size)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto unpack(BlobTag tag) const -> Blob
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							ensure(
 | 
				
			||||||
 | 
							    tag == BlobTag::code,
 | 
				
			||||||
 | 
							    "Invalid blob tag for shader asset: {}",
 | 
				
			||||||
 | 
							    std::to_underlying(tag)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto blob = Blob(m_code_blob_metadata.uncompressed_size);
 | 
				
			||||||
 | 
							unpack_to(tag, blob);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return blob;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						AssetMetadata m_asset_metadata {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Metadata m_metadata {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BlobMetadata m_code_blob_metadata {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutable std::ifstream m_stream;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::assets
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,8 @@ add_library_module(renderer
 | 
				
			||||||
    vk/context/device.cpp
 | 
					    vk/context/device.cpp
 | 
				
			||||||
    vk/context/swapchain.cpp
 | 
					    vk/context/swapchain.cpp
 | 
				
			||||||
    vk/context/context.cpp
 | 
					    vk/context/context.cpp
 | 
				
			||||||
 | 
					    vk/renderer/pass.cpp
 | 
				
			||||||
 | 
					    vk/renderer/renderer.cpp
 | 
				
			||||||
    vk/pipeline.cpp
 | 
					    vk/pipeline.cpp
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +16,8 @@ PUBLIC
 | 
				
			||||||
    app 
 | 
					    app 
 | 
				
			||||||
    ecs
 | 
					    ecs
 | 
				
			||||||
    memory
 | 
					    memory
 | 
				
			||||||
 | 
					    assets
 | 
				
			||||||
 | 
					    time
 | 
				
			||||||
PRIVATE
 | 
					PRIVATE
 | 
				
			||||||
    surface
 | 
					    surface
 | 
				
			||||||
    pthread
 | 
					    pthread
 | 
				
			||||||
| 
						 | 
					@ -28,6 +32,8 @@ add_test_module(renderer
 | 
				
			||||||
    vk/context/device.test.cpp
 | 
					    vk/context/device.test.cpp
 | 
				
			||||||
    vk/context/swapchain.test.cpp
 | 
					    vk/context/swapchain.test.cpp
 | 
				
			||||||
    vk/context/context.test.cpp
 | 
					    vk/context/context.test.cpp
 | 
				
			||||||
 | 
					    vk/renderer/pass.test.cpp
 | 
				
			||||||
 | 
					    vk/renderer/renderer.test.cpp
 | 
				
			||||||
    vk/pipeline.test.cpp
 | 
					    vk/pipeline.test.cpp
 | 
				
			||||||
) 
 | 
					) 
 | 
				
			||||||
target_link_libraries(renderer_tests
 | 
					target_link_libraries(renderer_tests
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,4 +2,16 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace lt::renderer {
 | 
					namespace lt::renderer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void System::on_register()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void System::on_unregister()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void System::tick(app::TickInfo tick)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::renderer
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,9 +3,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace lt::renderer::vk {
 | 
					namespace lt::renderer::vk {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Context::Context(const ecs::Entity &surface_entity, Ref<app::SystemStats> system_stats)
 | 
					Context::Context(const ecs::Entity &surface_entity)
 | 
				
			||||||
    : m_stats(std::move(system_stats))
 | 
					    : m_surface(surface_entity)
 | 
				
			||||||
    , m_surface(surface_entity)
 | 
					 | 
				
			||||||
    , m_device(m_surface)
 | 
					    , m_device(m_surface)
 | 
				
			||||||
    , m_swapchain(m_device, m_surface)
 | 
					    , m_swapchain(m_device, m_surface)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,7 +18,7 @@ using memory::NullOnMove;
 | 
				
			||||||
class Context
 | 
					class Context
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	Context(const ecs::Entity &surface_entity, Ref<app::SystemStats> system_stats);
 | 
						Context(const ecs::Entity &surface_entity);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] auto instance() const -> VkInstance
 | 
						[[nodiscard]] auto instance() const -> VkInstance
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					@ -36,8 +36,6 @@ public:
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	Ref<app::SystemStats> m_stats;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Surface m_surface;
 | 
						Surface m_surface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Device m_device;
 | 
						Device m_device;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,9 +10,12 @@ Device::Device(const Surface &surface)
 | 
				
			||||||
	ensure(surface.vk(), "Failed to initialize vk::Device: null vulkan surface");
 | 
						ensure(surface.vk(), "Failed to initialize vk::Device: null vulkan surface");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	initialize_physical_device();
 | 
						initialize_physical_device();
 | 
				
			||||||
 | 
						initialize_queue_indices(surface);
 | 
				
			||||||
	initialize_logical_device();
 | 
						initialize_logical_device();
 | 
				
			||||||
	Instance::load_device_functions(m_device);
 | 
						Instance::load_device_functions(m_device);
 | 
				
			||||||
	initialize_queue(surface);
 | 
					
 | 
				
			||||||
 | 
						vk_get_device_queue(m_device, m_graphics_queue_family_index, 0, &m_graphics_queue);
 | 
				
			||||||
 | 
						vk_get_device_queue(m_device, m_present_queue_family_index, 0, &m_present_queue);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Device::~Device()
 | 
					Device::~Device()
 | 
				
			||||||
| 
						 | 
					@ -54,12 +57,20 @@ void Device::initialize_logical_device()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const float priorities = .0f;
 | 
						const float priorities = .0f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto queue_info = VkDeviceQueueCreateInfo {
 | 
						auto queue_infos = std::vector<VkDeviceQueueCreateInfo> {};
 | 
				
			||||||
		.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
 | 
						auto queue_families = std::set { m_graphics_queue_family_index, m_present_queue_family_index };
 | 
				
			||||||
		.queueFamilyIndex = find_suitable_queue_family(),
 | 
					
 | 
				
			||||||
		.queueCount = 1u,
 | 
						for (auto queue_family : queue_families)
 | 
				
			||||||
		.pQueuePriorities = &priorities,
 | 
						{
 | 
				
			||||||
	};
 | 
							queue_infos.emplace_back(
 | 
				
			||||||
 | 
							    VkDeviceQueueCreateInfo {
 | 
				
			||||||
 | 
							        .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
 | 
				
			||||||
 | 
							        .queueFamilyIndex = queue_family,
 | 
				
			||||||
 | 
							        .queueCount = 1u,
 | 
				
			||||||
 | 
							        .pQueuePriorities = &priorities,
 | 
				
			||||||
 | 
							    }
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto physical_device_features = VkPhysicalDeviceFeatures {};
 | 
						auto physical_device_features = VkPhysicalDeviceFeatures {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,8 +80,8 @@ void Device::initialize_logical_device()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto device_info = VkDeviceCreateInfo {
 | 
						auto device_info = VkDeviceCreateInfo {
 | 
				
			||||||
		.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
 | 
							.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
 | 
				
			||||||
		.queueCreateInfoCount = 1,
 | 
							.queueCreateInfoCount = static_cast<uint32_t>(queue_infos.size()),
 | 
				
			||||||
		.pQueueCreateInfos = &queue_info,
 | 
							.pQueueCreateInfos = queue_infos.data(),
 | 
				
			||||||
		.enabledExtensionCount = static_cast<uint32_t>(extensions.size()),
 | 
							.enabledExtensionCount = static_cast<uint32_t>(extensions.size()),
 | 
				
			||||||
		.ppEnabledExtensionNames = extensions.data(),
 | 
							.ppEnabledExtensionNames = extensions.data(),
 | 
				
			||||||
		.pEnabledFeatures = &physical_device_features,
 | 
							.pEnabledFeatures = &physical_device_features,
 | 
				
			||||||
| 
						 | 
					@ -84,30 +95,28 @@ void Device::initialize_logical_device()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[nodiscard]] auto Device::find_suitable_queue_family() const -> uint32_t
 | 
					[[nodiscard]] auto Device::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);
 | 
				
			||||||
	ensure(count != 0u, "Failed to find any physical devices with Vulkan support");
 | 
						// ensure(count != 0u, "Failed to find any physical devices with Vulkan support");
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
	auto families = std::vector<VkQueueFamilyProperties>(count);
 | 
						// auto families = std::vector<VkQueueFamilyProperties>(count);
 | 
				
			||||||
	vk_get_physical_device_queue_family_properties(m_physical_device, &count, families.data());
 | 
						// vk_get_physical_device_queue_family_properties(m_physical_device, &count, families.data());
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
	const auto required_flags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
 | 
						// const auto required_flags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
 | 
				
			||||||
	for (auto idx = 0u; auto &family : families)
 | 
						// for (auto idx = 0u; auto &family : families)
 | 
				
			||||||
	{
 | 
						// {
 | 
				
			||||||
		if ((family.queueFlags & required_flags) == required_flags)
 | 
						// 	if ((family.queueFlags & required_flags) == required_flags)
 | 
				
			||||||
		{
 | 
						// 	{
 | 
				
			||||||
			return idx;
 | 
						// 		return idx;
 | 
				
			||||||
		}
 | 
						// 	}
 | 
				
			||||||
	}
 | 
						// }
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
	ensure(false, "Failed to find a suitable Vulkan queue family");
 | 
						// ensure(false, "Failed to find a suitable Vulkan queue family");
 | 
				
			||||||
	return 0;
 | 
						// return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Device::initialize_queue(const Surface &surface)
 | 
					void Device::initialize_queue_indices(const Surface &surface)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	vk_get_device_queue(m_device, find_suitable_queue_family(), 0, &m_queue);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto count = uint32_t { 0u };
 | 
						auto count = uint32_t { 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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,12 +35,22 @@ public:
 | 
				
			||||||
		return { m_graphics_queue_family_index, m_present_queue_family_index };
 | 
							return { m_graphics_queue_family_index, m_present_queue_family_index };
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto get_graphics_queue() const -> VkQueue
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_graphics_queue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto get_present_queue() const -> VkQueue
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_present_queue;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	void initialize_physical_device();
 | 
						void initialize_physical_device();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void initialize_logical_device();
 | 
						void initialize_logical_device();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void initialize_queue(const class Surface &surface);
 | 
						void initialize_queue_indices(const class Surface &surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] auto find_suitable_queue_family() const -> uint32_t;
 | 
						[[nodiscard]] auto find_suitable_queue_family() const -> uint32_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,7 +59,9 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memory::NullOnMove<VkDevice> m_device = VK_NULL_HANDLE;
 | 
						memory::NullOnMove<VkDevice> m_device = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memory::NullOnMove<VkQueue> m_queue = VK_NULL_HANDLE;
 | 
						memory::NullOnMove<VkQueue> m_graphics_queue = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memory::NullOnMove<VkQueue> m_present_queue = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t m_graphics_queue_family_index = VK_QUEUE_FAMILY_IGNORED;
 | 
						uint32_t m_graphics_queue_family_index = VK_QUEUE_FAMILY_IGNORED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,6 +86,8 @@ 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_vkResetCommandBuffer vk_reset_command_buffer {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PFN_vkGetPhysicalDeviceSurfaceSupportKHR vk_get_physical_device_surface_support {};
 | 
					PFN_vkGetPhysicalDeviceSurfaceSupportKHR vk_get_physical_device_surface_support {};
 | 
				
			||||||
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vk_get_physical_device_surface_capabilities {};
 | 
					PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vk_get_physical_device_surface_capabilities {};
 | 
				
			||||||
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vk_get_physical_device_surface_formats {};
 | 
					PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vk_get_physical_device_surface_formats {};
 | 
				
			||||||
| 
						 | 
					@ -370,6 +372,7 @@ void Instance::load_device_functions_impl(VkDevice device)
 | 
				
			||||||
	load_fn(vk_cmd_draw, "vkCmdDraw");
 | 
						load_fn(vk_cmd_draw, "vkCmdDraw");
 | 
				
			||||||
	load_fn(vk_cmd_set_viewport, "vkCmdSetViewport");
 | 
						load_fn(vk_cmd_set_viewport, "vkCmdSetViewport");
 | 
				
			||||||
	load_fn(vk_cmd_set_scissors, "vkCmdSetScissor");
 | 
						load_fn(vk_cmd_set_scissors, "vkCmdSetScissor");
 | 
				
			||||||
 | 
						load_fn(vk_reset_command_buffer, "vkResetCommandBuffer");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto parse_message_type(VkDebugUtilsMessageTypeFlagsEXT message_types) -> const char *
 | 
					auto parse_message_type(VkDebugUtilsMessageTypeFlagsEXT message_types) -> const char *
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,7 +7,9 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace lt::renderer::vk {
 | 
					namespace lt::renderer::vk {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Swapchain::Swapchain(const Device &device, const Surface &surface): m_device(device.vk())
 | 
					Swapchain::Swapchain(const Device &device, const Surface &surface)
 | 
				
			||||||
 | 
					    : m_device(device.vk())
 | 
				
			||||||
 | 
					    , m_resolution(surface.get_framebuffer_size())
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto *physical_device = device.physical();
 | 
						auto *physical_device = device.physical();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,6 +32,7 @@ Swapchain::Swapchain(const Device &device, const Surface &surface): m_device(dev
 | 
				
			||||||
	constexpr auto desired_swapchain_image_count = uint32_t { 3 };
 | 
						constexpr auto desired_swapchain_image_count = uint32_t { 3 };
 | 
				
			||||||
	const auto surface_format = formats.front();
 | 
						const auto surface_format = formats.front();
 | 
				
			||||||
	const auto queue_indices = device.get_family_indices();
 | 
						const auto queue_indices = device.get_family_indices();
 | 
				
			||||||
 | 
						m_format = surface_format.format;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto create_info = VkSwapchainCreateInfoKHR {
 | 
						auto create_info = VkSwapchainCreateInfoKHR {
 | 
				
			||||||
		.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
 | 
							.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
 | 
				
			||||||
| 
						 | 
					@ -45,7 +48,7 @@ Swapchain::Swapchain(const Device &device, const Surface &surface): m_device(dev
 | 
				
			||||||
		.pQueueFamilyIndices = queue_indices.data(),
 | 
							.pQueueFamilyIndices = queue_indices.data(),
 | 
				
			||||||
		.preTransform = capabilities.currentTransform,
 | 
							.preTransform = capabilities.currentTransform,
 | 
				
			||||||
		.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
 | 
							.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
 | 
				
			||||||
		.presentMode = VK_PRESENT_MODE_FIFO_RELAXED_KHR, // TODO(Light): parameterize
 | 
							.presentMode = VK_PRESENT_MODE_FIFO_KHR, // TODO(Light): parameterize
 | 
				
			||||||
		.clipped = VK_TRUE,
 | 
							.clipped = VK_TRUE,
 | 
				
			||||||
		.oldSwapchain = nullptr,
 | 
							.oldSwapchain = nullptr,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
| 
						 | 
					@ -84,6 +87,7 @@ Swapchain::Swapchain(const Device &device, const Surface &surface): m_device(dev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		vkc(vk_create_image_view(device.vk(), &create_info, nullptr, &view));
 | 
							vkc(vk_create_image_view(device.vk(), &create_info, nullptr, &view));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Swapchain::~Swapchain()
 | 
					Swapchain::~Swapchain()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <memory/pointer_types/null_on_move.hpp>
 | 
					#include <memory/pointer_types/null_on_move.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/debug/validation.hpp>
 | 
				
			||||||
#include <renderer/vk/vulkan.hpp>
 | 
					#include <renderer/vk/vulkan.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace lt::renderer::vk {
 | 
					namespace lt::renderer::vk {
 | 
				
			||||||
| 
						 | 
					@ -20,6 +21,44 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto operator=(const Swapchain &) const -> Swapchain & = delete;
 | 
						auto operator=(const Swapchain &) const -> Swapchain & = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto vk() const -> VkSwapchainKHR
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_swapchain;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto get_resolution() const -> VkExtent2D
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_resolution;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto get_format() const -> VkFormat
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_format;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto create_framebuffers_for_pass(VkRenderPass pass) const
 | 
				
			||||||
 | 
						    -> std::vector<VkFramebuffer>
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							auto framebuffers = std::vector<VkFramebuffer>(m_swapchain_image_views.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto idx = 0u; auto &framebuffer : framebuffers)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								auto info = VkFramebufferCreateInfo {
 | 
				
			||||||
 | 
									.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
 | 
				
			||||||
 | 
									.renderPass = pass,
 | 
				
			||||||
 | 
									.attachmentCount = 1u,
 | 
				
			||||||
 | 
									.pAttachments = &m_swapchain_image_views[idx++],
 | 
				
			||||||
 | 
									.width = m_resolution.width,
 | 
				
			||||||
 | 
									.height = m_resolution.height,
 | 
				
			||||||
 | 
									.layers = 1u
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								vkc(vk_create_frame_buffer(m_device, &info, nullptr, &framebuffer));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return framebuffers;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	[[nodiscard]] auto get_optimal_image_count(
 | 
						[[nodiscard]] auto get_optimal_image_count(
 | 
				
			||||||
	    VkSurfaceCapabilitiesKHR capabilities,
 | 
						    VkSurfaceCapabilitiesKHR capabilities,
 | 
				
			||||||
| 
						 | 
					@ -33,6 +72,10 @@ private:
 | 
				
			||||||
	std::vector<VkImage> m_swapchain_images;
 | 
						std::vector<VkImage> m_swapchain_images;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::vector<VkImageView> m_swapchain_image_views;
 | 
						std::vector<VkImageView> m_swapchain_image_views;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						VkExtent2D m_resolution;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						VkFormat m_format;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace lt::renderer::vk
 | 
					} // namespace lt::renderer::vk
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,7 +24,7 @@ public:
 | 
				
			||||||
		    .resolution = constants::resolution,
 | 
							    .resolution = constants::resolution,
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		m_context = create_ref<Context>(*m_surface_entity, m_stats);
 | 
							m_context = create_ref<Context>(*m_surface_entity);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] auto context() -> Ref<Context>
 | 
						[[nodiscard]] auto context() -> Ref<Context>
 | 
				
			||||||
| 
						 | 
					@ -38,8 +38,6 @@ public:
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	Ref<app::SystemStats> m_stats;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Ref<ecs::Registry> m_registry;
 | 
						Ref<ecs::Registry> m_registry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Ref<surface::System> m_surface_system;
 | 
						Ref<surface::System> m_surface_system;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										0
									
								
								modules/renderer/private/vk/renderer/pass.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								modules/renderer/private/vk/renderer/pass.cpp
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										280
									
								
								modules/renderer/private/vk/renderer/pass.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										280
									
								
								modules/renderer/private/vk/renderer/pass.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,280 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <assets/shader.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/context/context.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/debug/validation.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::renderer::vk {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Pass
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						Pass(
 | 
				
			||||||
 | 
						    Context &context,
 | 
				
			||||||
 | 
						    lt::assets::ShaderAsset vertex_shader,
 | 
				
			||||||
 | 
						    lt::assets::ShaderAsset fragment_shader
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						    : m_device(context.device().vk())
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// auto fragment_blob = vertex_shader.unpack(lt::assets::ShaderAsset::BlobTag::code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto *vertex_module = create_module(
 | 
				
			||||||
 | 
							    vertex_shader.unpack(lt::assets::ShaderAsset::BlobTag::code)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto *fragment_module = create_module(
 | 
				
			||||||
 | 
							    fragment_shader.unpack(lt::assets::ShaderAsset::BlobTag::code)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto shader_stages = std::array<VkPipelineShaderStageCreateInfo, 2> {
 | 
				
			||||||
 | 
								VkPipelineShaderStageCreateInfo {
 | 
				
			||||||
 | 
								    .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
 | 
				
			||||||
 | 
								    .stage = VK_SHADER_STAGE_VERTEX_BIT,
 | 
				
			||||||
 | 
								    .module = vertex_module,
 | 
				
			||||||
 | 
								    .pName = "main",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								VkPipelineShaderStageCreateInfo {
 | 
				
			||||||
 | 
								    .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
 | 
				
			||||||
 | 
								    .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
 | 
				
			||||||
 | 
								    .module = fragment_module,
 | 
				
			||||||
 | 
								    .pName = "main",
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto dynamic_states = std::array<VkDynamicState, 2> {
 | 
				
			||||||
 | 
								VK_DYNAMIC_STATE_VIEWPORT,
 | 
				
			||||||
 | 
								VK_DYNAMIC_STATE_SCISSOR,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto dynamic_state = VkPipelineDynamicStateCreateInfo {
 | 
				
			||||||
 | 
								.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
 | 
				
			||||||
 | 
								.dynamicStateCount = static_cast<uint32_t>(dynamic_states.size()),
 | 
				
			||||||
 | 
								.pDynamicStates = dynamic_states.data(),
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto vertex_input = VkPipelineVertexInputStateCreateInfo {
 | 
				
			||||||
 | 
								.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto input_assembly = VkPipelineInputAssemblyStateCreateInfo {
 | 
				
			||||||
 | 
								.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
 | 
				
			||||||
 | 
								.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
 | 
				
			||||||
 | 
								.primitiveRestartEnable = VK_FALSE,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto viewport = VkViewport {
 | 
				
			||||||
 | 
								.x = 0u,
 | 
				
			||||||
 | 
								.y = 0u,
 | 
				
			||||||
 | 
								.width = static_cast<float>(context.swapchain().get_resolution().width),
 | 
				
			||||||
 | 
								.height = static_cast<float>(context.swapchain().get_resolution().height),
 | 
				
			||||||
 | 
								.minDepth = 0.0f,
 | 
				
			||||||
 | 
								.maxDepth = 0.0f,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto scissor = VkRect2D {
 | 
				
			||||||
 | 
								.offset = { 0u, 0u },
 | 
				
			||||||
 | 
								.extent = context.swapchain().get_resolution(),
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto viewport_state = VkPipelineViewportStateCreateInfo {
 | 
				
			||||||
 | 
								.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
 | 
				
			||||||
 | 
								.viewportCount = 1u,
 | 
				
			||||||
 | 
								.scissorCount = 1u,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto rasterization = VkPipelineRasterizationStateCreateInfo {
 | 
				
			||||||
 | 
								.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
 | 
				
			||||||
 | 
								.depthClampEnable = VK_FALSE,
 | 
				
			||||||
 | 
								.rasterizerDiscardEnable = VK_FALSE,
 | 
				
			||||||
 | 
								.polygonMode = VK_POLYGON_MODE_FILL,
 | 
				
			||||||
 | 
								.cullMode = VK_CULL_MODE_NONE,
 | 
				
			||||||
 | 
								.frontFace = VK_FRONT_FACE_CLOCKWISE,
 | 
				
			||||||
 | 
								.lineWidth = 1.0,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto multisampling = VkPipelineMultisampleStateCreateInfo {
 | 
				
			||||||
 | 
								.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
 | 
				
			||||||
 | 
								.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
 | 
				
			||||||
 | 
								.sampleShadingEnable = VK_FALSE,
 | 
				
			||||||
 | 
								.minSampleShading = 1.0,
 | 
				
			||||||
 | 
								.pSampleMask = nullptr,
 | 
				
			||||||
 | 
								.alphaToCoverageEnable = VK_FALSE,
 | 
				
			||||||
 | 
								.alphaToOneEnable = VK_FALSE,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto color_blend_attachment = VkPipelineColorBlendAttachmentState {
 | 
				
			||||||
 | 
								.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
 | 
				
			||||||
 | 
								                  | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
 | 
				
			||||||
 | 
								.blendEnable = VK_FALSE,
 | 
				
			||||||
 | 
								.srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
 | 
				
			||||||
 | 
								.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
 | 
				
			||||||
 | 
								.colorBlendOp = VK_BLEND_OP_ADD,
 | 
				
			||||||
 | 
								.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
 | 
				
			||||||
 | 
								.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
 | 
				
			||||||
 | 
								.alphaBlendOp = VK_BLEND_OP_ADD,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto color_blend = VkPipelineColorBlendStateCreateInfo {
 | 
				
			||||||
 | 
								.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
 | 
				
			||||||
 | 
								.logicOpEnable = VK_FALSE,
 | 
				
			||||||
 | 
								.logicOp = VK_LOGIC_OP_COPY,
 | 
				
			||||||
 | 
								.attachmentCount = 1,
 | 
				
			||||||
 | 
								.pAttachments = &color_blend_attachment,
 | 
				
			||||||
 | 
								.blendConstants = { 0.0f, 0.0, 0.0, 0.0 },
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto layout_info = VkPipelineLayoutCreateInfo {
 | 
				
			||||||
 | 
								.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
 | 
				
			||||||
 | 
								.setLayoutCount = 0u,
 | 
				
			||||||
 | 
								.pSetLayouts = nullptr,
 | 
				
			||||||
 | 
								.pushConstantRangeCount = 0u,
 | 
				
			||||||
 | 
								.pPushConstantRanges = nullptr,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							vkc(vk_create_pipeline_layout(m_device, &layout_info, nullptr, &m_layout));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto attachment_description = VkAttachmentDescription {
 | 
				
			||||||
 | 
								.format = context.swapchain().get_format(),
 | 
				
			||||||
 | 
								.samples = VK_SAMPLE_COUNT_1_BIT,
 | 
				
			||||||
 | 
								.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
 | 
				
			||||||
 | 
								.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
 | 
				
			||||||
 | 
								.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
 | 
				
			||||||
 | 
								.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
 | 
				
			||||||
 | 
								.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
 | 
				
			||||||
 | 
								.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto color_attachment_ref = VkAttachmentReference {
 | 
				
			||||||
 | 
								.attachment = 0,
 | 
				
			||||||
 | 
								.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto subpass_description = VkSubpassDescription {
 | 
				
			||||||
 | 
								.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
 | 
				
			||||||
 | 
								.colorAttachmentCount = 1u,
 | 
				
			||||||
 | 
								.pColorAttachments = &color_attachment_ref,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto pass_dependency = VkSubpassDependency {
 | 
				
			||||||
 | 
								.srcSubpass = VK_SUBPASS_EXTERNAL,
 | 
				
			||||||
 | 
								.dstSubpass = 0u,
 | 
				
			||||||
 | 
								.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
 | 
				
			||||||
 | 
								.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
 | 
				
			||||||
 | 
								.srcAccessMask = 0u,
 | 
				
			||||||
 | 
								.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto renderpass_info = VkRenderPassCreateInfo {
 | 
				
			||||||
 | 
								.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
 | 
				
			||||||
 | 
								.attachmentCount = 1u,
 | 
				
			||||||
 | 
								.pAttachments = &attachment_description,
 | 
				
			||||||
 | 
								.subpassCount = 1u,
 | 
				
			||||||
 | 
								.pSubpasses = &subpass_description,
 | 
				
			||||||
 | 
								.dependencyCount = 1u,
 | 
				
			||||||
 | 
								.pDependencies = &pass_dependency,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							vkc(vk_create_render_pass(m_device, &renderpass_info, nullptr, &m_pass));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto pipeline_info = VkGraphicsPipelineCreateInfo {
 | 
				
			||||||
 | 
								.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
 | 
				
			||||||
 | 
								.stageCount = static_cast<uint32_t>(shader_stages.size()),
 | 
				
			||||||
 | 
								.pStages = shader_stages.data(),
 | 
				
			||||||
 | 
								.pVertexInputState = &vertex_input,
 | 
				
			||||||
 | 
								.pInputAssemblyState = &input_assembly,
 | 
				
			||||||
 | 
								.pViewportState = &viewport_state,
 | 
				
			||||||
 | 
								.pRasterizationState = &rasterization,
 | 
				
			||||||
 | 
								.pMultisampleState = &multisampling,
 | 
				
			||||||
 | 
								.pDepthStencilState = nullptr,
 | 
				
			||||||
 | 
								.pColorBlendState = &color_blend,
 | 
				
			||||||
 | 
								.pDynamicState = &dynamic_state,
 | 
				
			||||||
 | 
								.layout = m_layout,
 | 
				
			||||||
 | 
								.renderPass = m_pass,
 | 
				
			||||||
 | 
								.subpass = 0u,
 | 
				
			||||||
 | 
								.basePipelineHandle = VK_NULL_HANDLE,
 | 
				
			||||||
 | 
								.basePipelineIndex = -1,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							vkc(vk_create_graphics_pipelines(
 | 
				
			||||||
 | 
							    m_device,
 | 
				
			||||||
 | 
							    VK_NULL_HANDLE,
 | 
				
			||||||
 | 
							    1u,
 | 
				
			||||||
 | 
							    &pipeline_info,
 | 
				
			||||||
 | 
							    nullptr,
 | 
				
			||||||
 | 
							    &m_pipeline
 | 
				
			||||||
 | 
							));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							vk_destroy_shader_module(m_device, vertex_module, nullptr);
 | 
				
			||||||
 | 
							vk_destroy_shader_module(m_device, fragment_module, nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							m_framebuffers = context.swapchain().create_framebuffers_for_pass(m_pass);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						~Pass()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (!m_device)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto &framebuffer : m_framebuffers)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								vk_destroy_frame_buffer(m_device, framebuffer, nullptr);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							vk_destroy_pipeline(m_device, m_pipeline, nullptr);
 | 
				
			||||||
 | 
							vk_destroy_render_pass(m_device, m_pass, nullptr);
 | 
				
			||||||
 | 
							vk_destroy_pipeline_layout(m_device, m_layout, nullptr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Pass(Pass &&) = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Pass(const Pass &) = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto operator=(Pass &&) -> Pass & = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto operator=(const Pass &) -> Pass & = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto get_pass() -> VkRenderPass
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_pass;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto get_pipeline() -> VkPipeline
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_pipeline;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] auto get_framebuffers() -> std::vector<VkFramebuffer> &
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return m_framebuffers;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						auto create_module(lt::assets::Blob blob) -> VkShaderModule
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							log_dbg("BLOB SIZE: {}", blob.size());
 | 
				
			||||||
 | 
							auto info = VkShaderModuleCreateInfo {
 | 
				
			||||||
 | 
								.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
 | 
				
			||||||
 | 
								.codeSize = blob.size(),
 | 
				
			||||||
 | 
								.pCode = reinterpret_cast<const uint32_t *>(blob.data()) // NOLINT
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto *module = VkShaderModule { VK_NULL_HANDLE };
 | 
				
			||||||
 | 
							vkc(vk_create_shader_module(m_device, &info, nullptr, &module));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return module;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memory::NullOnMove<VkDevice> m_device = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memory::NullOnMove<VkPipeline> m_pipeline = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memory::NullOnMove<VkRenderPass> m_pass = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memory::NullOnMove<VkPipelineLayout> m_layout = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::vector<VkFramebuffer> m_framebuffers;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::renderer::vk
 | 
				
			||||||
							
								
								
									
										20
									
								
								modules/renderer/private/vk/renderer/pass.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								modules/renderer/private/vk/renderer/pass.test.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,20 @@
 | 
				
			||||||
 | 
					#include <renderer/vk/renderer/pass.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/test_utils.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ::lt::assets::ShaderAsset;
 | 
				
			||||||
 | 
					using ::lt::renderer::vk::Pass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Suite raii = "pass_raii"_suite = [] {
 | 
				
			||||||
 | 
						Case { "happy path won't throw" } = [] {
 | 
				
			||||||
 | 
							auto observer = ValidationObserver {};
 | 
				
			||||||
 | 
							auto [context, _] = create_context();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							std::ignore = Pass {
 | 
				
			||||||
 | 
								context,
 | 
				
			||||||
 | 
								ShaderAsset { "./data/test_assets/triangle.vert.asset" },
 | 
				
			||||||
 | 
								ShaderAsset { "./data/test_assets/triangle.frag.asset" },
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_false(observer.had_any_messages());
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										0
									
								
								modules/renderer/private/vk/renderer/renderer.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								modules/renderer/private/vk/renderer/renderer.cpp
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										203
									
								
								modules/renderer/private/vk/renderer/renderer.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								modules/renderer/private/vk/renderer/renderer.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,203 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <renderer/vk/context/context.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/debug/validation.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/renderer/pass.hpp>
 | 
				
			||||||
 | 
					#include <time/timer.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::renderer::vk {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Renderer
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						Renderer(Context &context, Ref<Pass> pass)
 | 
				
			||||||
 | 
						    : m_device(context.device().vk())
 | 
				
			||||||
 | 
						    , m_graphics_queue(context.device().get_graphics_queue())
 | 
				
			||||||
 | 
						    , m_present_queue(context.device().get_present_queue())
 | 
				
			||||||
 | 
						    , m_swapchain(context.swapchain().vk())
 | 
				
			||||||
 | 
						    , m_pass(std::move(pass))
 | 
				
			||||||
 | 
						    , m_resolution(context.swapchain().get_resolution())
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							auto pool_info = VkCommandPoolCreateInfo {
 | 
				
			||||||
 | 
								.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
 | 
				
			||||||
 | 
								.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
 | 
				
			||||||
 | 
								.queueFamilyIndex = context.device().get_family_indices()[0],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							vkc(vk_create_command_pool(m_device, &pool_info, nullptr, &m_pool));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto cmd_info = VkCommandBufferAllocateInfo {
 | 
				
			||||||
 | 
								.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
 | 
				
			||||||
 | 
								.commandPool = m_pool,
 | 
				
			||||||
 | 
								.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
 | 
				
			||||||
 | 
								.commandBufferCount = 1u,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							vkc(vk_allocate_command_buffers(m_device, &cmd_info, &m_cmd));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto semaphore_info = VkSemaphoreCreateInfo {
 | 
				
			||||||
 | 
								.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto fence_info = VkFenceCreateInfo {
 | 
				
			||||||
 | 
								.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
 | 
				
			||||||
 | 
								.flags = VK_FENCE_CREATE_SIGNALED_BIT,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							vkc(vk_create_semaphore(m_device, &semaphore_info, nullptr, &m_image_available_semaphore));
 | 
				
			||||||
 | 
							vkc(vk_create_semaphore(m_device, &semaphore_info, nullptr, &m_render_finished_semaphore));
 | 
				
			||||||
 | 
							vkc(vk_create_fence(m_device, &fence_info, nullptr, &m_in_flight_fence));
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void record_cmd(VkCommandBuffer cmd, uint32_t image_idx)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							auto cmd_begin_info = VkCommandBufferBeginInfo {
 | 
				
			||||||
 | 
								.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
 | 
				
			||||||
 | 
								.flags = {},
 | 
				
			||||||
 | 
								.pInheritanceInfo = nullptr,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							vkc(vk_begin_command_buffer(cmd, &cmd_begin_info));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							static auto timer = Timer {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto clear_value = VkClearValue {
 | 
				
			||||||
 | 
								.color = { 
 | 
				
			||||||
 | 
					                0.93,
 | 
				
			||||||
 | 
					                0.93,
 | 
				
			||||||
 | 
					                0.93,
 | 
				
			||||||
 | 
					               1.0,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto pass_begin_info = VkRenderPassBeginInfo {
 | 
				
			||||||
 | 
								.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
 | 
				
			||||||
 | 
								.renderPass = m_pass->get_pass(),
 | 
				
			||||||
 | 
								.framebuffer = m_pass->get_framebuffers()[image_idx],
 | 
				
			||||||
 | 
								.renderArea = { .offset = {}, .extent = m_resolution },
 | 
				
			||||||
 | 
								.clearValueCount = 1u,
 | 
				
			||||||
 | 
								.pClearValues = &clear_value
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							vk_cmd_begin_render_pass(cmd, &pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
 | 
				
			||||||
 | 
							vk_cmd_bind_pipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pass->get_pipeline());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto viewport = VkViewport {
 | 
				
			||||||
 | 
								.x = 0.0f,
 | 
				
			||||||
 | 
								.y = 0.0f,
 | 
				
			||||||
 | 
								.width = static_cast<float>(m_resolution.width),
 | 
				
			||||||
 | 
								.height = static_cast<float>(m_resolution.height),
 | 
				
			||||||
 | 
								.minDepth = 0.0f,
 | 
				
			||||||
 | 
								.maxDepth = 1.0f,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							vk_cmd_set_viewport(cmd, 0, 1, &viewport);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto scissor = VkRect2D {
 | 
				
			||||||
 | 
								.offset = { 0u, 0u },
 | 
				
			||||||
 | 
								.extent = m_resolution,
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							vk_cmd_set_scissors(cmd, 0, 1, &scissor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							vk_cmd_draw(cmd, 3, 1, 0, 0);
 | 
				
			||||||
 | 
							vk_cmd_end_render_pass(cmd);
 | 
				
			||||||
 | 
							vkc(vk_end_command_buffer(cmd));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void draw()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							try
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								vkc(vk_wait_for_fences(m_device, 1u, &m_in_flight_fence, VK_TRUE, UINT64_MAX));
 | 
				
			||||||
 | 
								vkc(vk_reset_fences(m_device, 1u, &m_in_flight_fence));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto image_idx = uint32_t {};
 | 
				
			||||||
 | 
								vkc(vk_acquire_next_image_khr(
 | 
				
			||||||
 | 
								    m_device,
 | 
				
			||||||
 | 
								    m_swapchain,
 | 
				
			||||||
 | 
								    UINT64_MAX,
 | 
				
			||||||
 | 
								    m_image_available_semaphore,
 | 
				
			||||||
 | 
								    VK_NULL_HANDLE,
 | 
				
			||||||
 | 
								    &image_idx
 | 
				
			||||||
 | 
								));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								vkc(vk_reset_command_buffer(m_cmd, {}));
 | 
				
			||||||
 | 
								record_cmd(m_cmd, image_idx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto wait_stage = VkPipelineStageFlags {
 | 
				
			||||||
 | 
									VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
								auto submit_info = VkSubmitInfo {
 | 
				
			||||||
 | 
									.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
 | 
				
			||||||
 | 
									.waitSemaphoreCount = 1u,
 | 
				
			||||||
 | 
									.pWaitSemaphores = &m_image_available_semaphore,
 | 
				
			||||||
 | 
									.pWaitDstStageMask = &wait_stage,
 | 
				
			||||||
 | 
									.commandBufferCount = 1u,
 | 
				
			||||||
 | 
									.pCommandBuffers = &m_cmd,
 | 
				
			||||||
 | 
									.signalSemaphoreCount = 1u,
 | 
				
			||||||
 | 
									.pSignalSemaphores = &m_render_finished_semaphore,
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								vkc(vk_queue_submit(m_graphics_queue, 1u, &submit_info, m_in_flight_fence));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto present_info = VkPresentInfoKHR {
 | 
				
			||||||
 | 
									.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
 | 
				
			||||||
 | 
									.waitSemaphoreCount = 1u,
 | 
				
			||||||
 | 
									.pWaitSemaphores = &m_render_finished_semaphore,
 | 
				
			||||||
 | 
									.swapchainCount = 1u,
 | 
				
			||||||
 | 
									.pSwapchains = &m_swapchain,
 | 
				
			||||||
 | 
									.pImageIndices = &image_idx,
 | 
				
			||||||
 | 
									.pResults = nullptr,
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								vk_queue_present_khr(m_present_queue, &present_info);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							catch (const std::exception &exp)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								log_dbg("EXCEPTION: {}", exp.what());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						~Renderer()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (!m_device)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							vk_destroy_semaphore(m_device, m_render_finished_semaphore, nullptr);
 | 
				
			||||||
 | 
							vk_destroy_semaphore(m_device, m_image_available_semaphore, nullptr);
 | 
				
			||||||
 | 
							vk_destroy_fence(m_device, m_in_flight_fence, nullptr);
 | 
				
			||||||
 | 
							vk_destroy_command_pool(m_device, m_pool, nullptr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Renderer(Renderer &&) = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Renderer(const Renderer &) = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto operator=(Renderer &&) -> Renderer & = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto operator=(const Renderer &) -> Renderer & = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						memory::NullOnMove<VkDevice> m_device = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memory::NullOnMove<VkCommandPool> m_pool = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memory::NullOnMove<VkCommandBuffer> m_cmd = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memory::NullOnMove<VkSemaphore> m_image_available_semaphore = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memory::NullOnMove<VkSemaphore> m_render_finished_semaphore = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memory::NullOnMove<VkFence> m_in_flight_fence = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memory::NullOnMove<VkSwapchainKHR> m_swapchain = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memory::NullOnMove<VkQueue> m_graphics_queue = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memory::NullOnMove<VkQueue> m_present_queue = VK_NULL_HANDLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Ref<Pass> m_pass;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						VkExtent2D m_resolution;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::renderer::vk
 | 
				
			||||||
							
								
								
									
										29
									
								
								modules/renderer/private/vk/renderer/renderer.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								modules/renderer/private/vk/renderer/renderer.test.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,29 @@
 | 
				
			||||||
 | 
					#include <renderer/vk/renderer/renderer.hpp>
 | 
				
			||||||
 | 
					#include <renderer/vk/test_utils.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using ::lt::assets::ShaderAsset;
 | 
				
			||||||
 | 
					using ::lt::renderer::vk::Pass;
 | 
				
			||||||
 | 
					using ::lt::renderer::vk::Renderer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Suite raii = "renderer_raii"_suite = [] {
 | 
				
			||||||
 | 
						Case { "happy path won't throw" } = [] {
 | 
				
			||||||
 | 
							auto observer = ValidationObserver {};
 | 
				
			||||||
 | 
							auto [context, _] = create_context();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto pass = lt::create_ref<Pass>(
 | 
				
			||||||
 | 
							    context,
 | 
				
			||||||
 | 
							    ShaderAsset { "./data/test_assets/triangle.vert.asset" },
 | 
				
			||||||
 | 
							    ShaderAsset { "./data/test_assets/triangle.frag.asset" }
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto renderer = Renderer(context, pass);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (;;)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								renderer.draw();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_false(observer.had_any_messages());
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <ranges>
 | 
					#include <ranges>
 | 
				
			||||||
 | 
					#include <renderer/vk/context/context.hpp>
 | 
				
			||||||
#include <renderer/vk/context/surface.hpp>
 | 
					#include <renderer/vk/context/surface.hpp>
 | 
				
			||||||
#include <renderer/vk/debug/messenger.hpp>
 | 
					#include <renderer/vk/debug/messenger.hpp>
 | 
				
			||||||
#include <surface/components.hpp>
 | 
					#include <surface/components.hpp>
 | 
				
			||||||
| 
						 | 
					@ -32,7 +33,7 @@ public:
 | 
				
			||||||
	ValidationObserver()
 | 
						ValidationObserver()
 | 
				
			||||||
	    : m_messenger(
 | 
						    : m_messenger(
 | 
				
			||||||
	          Messenger::CreateInfo {
 | 
						          Messenger::CreateInfo {
 | 
				
			||||||
	              .severity = all_severity,
 | 
						              .severity = static_cast<Messenger::Severity>(warning | error),
 | 
				
			||||||
	              .type = lt::renderer::vk::Messenger::all_type,
 | 
						              .type = lt::renderer::vk::Messenger::all_type,
 | 
				
			||||||
	              .callback = &callback,
 | 
						              .callback = &callback,
 | 
				
			||||||
	              .user_data = &m_had_any_messages,
 | 
						              .user_data = &m_had_any_messages,
 | 
				
			||||||
| 
						 | 
					@ -67,6 +68,22 @@ private:
 | 
				
			||||||
	bool m_had_any_messages = false;
 | 
						bool m_had_any_messages = false;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[nodiscard]] inline auto create_context()
 | 
				
			||||||
 | 
					    -> std::pair<lt::renderer::vk::Context, lt::surface::System>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						using lt::surface::SurfaceComponent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto registry = lt::create_ref<lt::ecs::Registry>();
 | 
				
			||||||
 | 
						auto entity = lt::ecs::Entity { registry, registry->create_entity() };
 | 
				
			||||||
 | 
						auto surface_system = lt::surface::System(registry);
 | 
				
			||||||
 | 
						entity.add<SurfaceComponent>(SurfaceComponent::CreateInfo {
 | 
				
			||||||
 | 
						    .title = "",
 | 
				
			||||||
 | 
						    .resolution = constants::resolution,
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return { lt::renderer::vk::Context { entity }, std::move(surface_system) };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<>
 | 
					template<>
 | 
				
			||||||
struct std::formatter<VkExtent2D>
 | 
					struct std::formatter<VkExtent2D>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,6 +86,8 @@ 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_vkResetCommandBuffer vk_reset_command_buffer;
 | 
				
			||||||
// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
 | 
					// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace lt::renderer::vk
 | 
					} // namespace lt::renderer::vk
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								modules/renderer/public/components/skybox.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								modules/renderer/public/components/skybox.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::renderer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct SolidColor
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::renderer
 | 
				
			||||||
| 
						 | 
					@ -12,14 +12,16 @@ public:
 | 
				
			||||||
	struct CreateInfo
 | 
						struct CreateInfo
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Ref<ecs::Registry> registry;
 | 
							Ref<ecs::Registry> registry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ecs::Entity surface_entity;
 | 
							ecs::Entity surface_entity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Ref<app::SystemStats> system_stats;
 | 
							Ref<app::SystemStats> system_stats;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] System(CreateInfo info)
 | 
						[[nodiscard]] System(CreateInfo info)
 | 
				
			||||||
	    : m_registry(std::move(info.registry))
 | 
						    : m_registry(std::move(info.registry))
 | 
				
			||||||
	    , m_stats(info.system_stats)
 | 
						    , m_stats(info.system_stats)
 | 
				
			||||||
	    , m_context(info.surface_entity, info.system_stats)
 | 
						    , m_context(info.surface_entity)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		ensure(m_stats, "Failed to initialize system: null stats");
 | 
							ensure(m_stats, "Failed to initialize system: null stats");
 | 
				
			||||||
		ensure(m_registry, "Failed to initialize renderer system: null registry");
 | 
							ensure(m_registry, "Failed to initialize renderer system: null registry");
 | 
				
			||||||
| 
						 | 
					@ -35,19 +37,11 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto operator=(const System &) -> System & = delete;
 | 
						auto operator=(const System &) -> System & = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void on_register() override
 | 
						void on_register() override;
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void on_unregister() override
 | 
						void on_unregister() override;
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void get_validation_state();
 | 
						void tick(app::TickInfo tick) override;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	void tick(app::TickInfo tick) override
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] auto get_stats() const -> const app::SystemStats &
 | 
						[[nodiscard]] auto get_stats() const -> const app::SystemStats &
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue