Files
FGL-Engine/src/engine/pipeline/Shader.hpp

159 lines
4.3 KiB
C++

//
// Created by kj16609 on 3/13/24.
//
#pragma once
#include <fstream>
#include "engine/logging.hpp"
namespace fgl::engine
{
template < std::size_t N >
requires( N > 0 )
struct TString
{
using Character = std::string::value_type;
Character str[ N ];
constexpr TString( const char ( &literal )[ N ] ) { std::ranges::copy( literal, str ); }
consteval operator std::string_view() const noexcept { return std::string_view( str, N - 1 ); }
operator std::filesystem::path() const noexcept
{
return std::filesystem::path( std::string_view( str, N - 1 ) );
}
};
struct ShaderHandle
{
vk::PipelineShaderStageCreateInfo stage_info;
vk::ShaderModule shader_module;
ShaderHandle( const std::filesystem::path path, const vk::PipelineShaderStageCreateInfo info ) :
stage_info( info ),
shader_module( VK_NULL_HANDLE )
{
if ( auto ifs = std::ifstream( path, std::ios::binary | std::ios::ate ); ifs )
{
std::vector< std::byte > data;
data.resize( ifs.tellg() );
ifs.seekg( 0, std::ios::beg );
static_assert( sizeof( std::ifstream::char_type ) == sizeof( std::byte ) );
ifs.read( reinterpret_cast< std::ifstream::char_type* >( data.data() ), data.size() );
vk::ShaderModuleCreateInfo module_info {};
module_info.flags = {};
module_info.codeSize = data.size();
module_info.pCode = reinterpret_cast< const std::uint32_t* >( data.data() );
if ( Device::getInstance().device().createShaderModule( &module_info, nullptr, &shader_module )
!= vk::Result::eSuccess )
throw std::runtime_error( "Failed to create shader module" );
std::cout << "Created shader module for: " << path << std::endl;
stage_info.module = shader_module;
}
else
{
spdlog::critical( "Failed to load shader module {}. Path not found", path.string() );
throw std::runtime_error( "Failed to load shader module. Path not found" );
}
}
ShaderHandle( const ShaderHandle& other ) = delete;
ShaderHandle& operator=( const ShaderHandle& other ) = delete;
ShaderHandle( ShaderHandle&& other ) = delete;
ShaderHandle& operator=( ShaderHandle&& other ) = delete;
~ShaderHandle()
{
if ( shader_module != VK_NULL_HANDLE ) Device::getInstance().device().destroyShaderModule( shader_module );
}
};
vk::ShaderModule loadShaderModule( const std::string_view path );
template < TString filepath, vk::ShaderStageFlagBits stage_flags >
struct Shader
{
consteval static vk::PipelineShaderStageCreateInfo defaultShaderInfo()
{
vk::PipelineShaderStageCreateInfo info {};
info.flags = {};
info.stage = stage_flags;
info.pName = "main";
info.pSpecializationInfo = nullptr;
return info;
}
static std::unique_ptr< ShaderHandle > load()
{
return std::make_unique< ShaderHandle >( filepath, defaultShaderInfo() );
}
virtual ~Shader() = default;
};
template < TString filepath >
using VertexShaderT = Shader< filepath, vk::ShaderStageFlagBits::eVertex >;
template < TString filepath >
using FragmentShaderT = Shader< filepath, vk::ShaderStageFlagBits::eFragment >;
template < TString filepath >
using TesselationControlShaderT = Shader< filepath, vk::ShaderStageFlagBits::eTessellationControl >;
template < TString filepath >
using TesselationEvaluationShaderT = Shader< filepath, vk::ShaderStageFlagBits::eTessellationEvaluation >;
template < typename T >
concept is_shader = requires( T t ) {
{
t.defaultShaderInfo()
} -> std::same_as< vk::PipelineShaderStageCreateInfo >;
};
template < is_shader... Shaders >
struct ShaderCollection
{
using ShaderTuple = std::tuple< Shaders... >;
constexpr static std::uint64_t ShaderCount { sizeof...( Shaders ) };
template < std::uint64_t IDX >
requires( IDX < ShaderCount )
using Shader = std::tuple_element_t< IDX, ShaderTuple >;
static_assert( ShaderCount >= 2, "Shader count must be two, Missing vertex or fragment?" );
static std::vector< std::unique_ptr< ShaderHandle > > loadShaders()
{
std::vector< std::unique_ptr< ShaderHandle > > shaders;
( ( shaders.push_back( Shaders::load() ) ), ... );
return shaders;
}
};
template < typename T >
concept is_shader_collection = requires( T t ) {
typename T::ShaderTuple;
{
t.ShaderCount
} -> std::same_as< const std::uint64_t& >;
};
} // namespace fgl::engine