get runtime shader compilation working

This commit is contained in:
2024-08-05 10:25:08 -04:00
parent fdcd6a6c31
commit 8a055b28a0
25 changed files with 111 additions and 45 deletions

12
.gitmodules vendored
View File

@@ -40,3 +40,15 @@
[submodule "dependencies/imgui"]
path = dependencies/imgui
url = https://github.com/ocornut/imgui.git
[submodule "dependencies/shaderc"]
path = dependencies/shaderc
url = https://github.com/google/shaderc.git
[submodule "dependencies/SPIRV-Tools"]
path = dependencies/SPIRV-Tools
url = https://github.com/KhronosGroup/SPIRV-Tools.git
[submodule "dependencies/SPIRV-Headers"]
path = dependencies/SPIRV-Headers
url = https://github.com/KhronosGroup/SPIRV-Headers.git
[submodule "dependencies/glslang"]
path = dependencies/glslang
url = https://github.com/KhronosGroup/glslang.git

View File

@@ -32,6 +32,7 @@ include(dependencies/glm)
include(cmake_modules/dependencies/tracy.cmake)
include(dependencies/vulkan)
include(dependencies/catch2)
include(dependencies/shaderc)
add_subdirectory(src)

View File

@@ -0,0 +1,8 @@
#set(SPIRV-Headers_SOURCE_DIR ${CMAKE_SOURCE_DIR}/dependencies/SPIRV-Headers)
add_subdirectory(${CMAKE_SOURCE_DIR}/dependencies/SPIRV-Headers)
add_subdirectory(${CMAKE_SOURCE_DIR}/dependencies/SPIRV-Tools)
add_subdirectory(${CMAKE_SOURCE_DIR}/dependencies/glslang)
set(SHADERC_SKIP_TESTS ON)
add_subdirectory(${CMAKE_SOURCE_DIR}/dependencies/shaderc)

1
dependencies/SPIRV-Headers vendored Submodule

1
dependencies/SPIRV-Tools vendored Submodule

1
dependencies/glslang vendored Submodule

Submodule dependencies/glslang added at e40c14a3e0

1
dependencies/shaderc vendored Submodule

Submodule dependencies/shaderc added at 5d0f6ed6e4

View File

@@ -33,7 +33,7 @@ target_compile_definitions(FGLEngine PUBLIC VULKAN_HPP_FLAGS_MASK_TYPE_AS_PUBLIC
include(dependencies/spdlog)
include(dependencies/imgui)
target_link_libraries(FGLEngine PUBLIC Vulkan::Vulkan glfw glm ImGui Tracy::TracyClient VMA FGLLoader spdlog)
target_link_libraries(FGLEngine PUBLIC Vulkan::Vulkan glfw glm ImGui Tracy::TracyClient VMA FGLLoader spdlog shaderc)
target_include_directories(FGLEngine PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/..)
set_target_properties(FGLEngine PROPERTIES COMPILE_FLAGS ${FGL_FLAGS})
target_compile_features(FGLEngine PRIVATE cxx_std_23)

View File

@@ -100,8 +100,6 @@ namespace fgl::engine::descriptors
m_infos[ binding_idx ] = tex.getImageView().descriptorInfo(
tex.getImageView().getSampler().getVkSampler(), vk::ImageLayout::eShaderReadOnlyOptimal );
log::info( "Bound texture {} to global texture array", tex.getID() );
vk::WriteDescriptorSet write {};
write.dstSet = m_set;
write.dstBinding = binding_idx;
@@ -110,8 +108,6 @@ namespace fgl::engine::descriptors
write.descriptorType = vk::DescriptorType::eCombinedImageSampler;
write.pImageInfo = &( std::get< vk::DescriptorImageInfo >( m_infos.data()[ binding_idx ] ) );
std::cout << "Bound texture: " << tex.getID() << std::endl;
descriptor_writes.push_back( write );
}

View File

@@ -30,7 +30,9 @@ namespace fgl::engine
struct ModelMatrixInfo
{
glm::mat4 model_matrix;
std::uint32_t texture_idx;
std::uint32_t albedo_id;
std::uint32_t normal_id;
std::uint32_t metallic_roughness;
};
class Model

View File

@@ -26,7 +26,15 @@ namespace fgl::engine
if ( m_textures.albedo )
return m_textures.albedo->getID();
else
return std::numeric_limits< TextureID >::max();
return INVALID_TEXTURE_ID;
}
TextureID Primitive::getNormalTextureID() const
{
if ( m_textures.normal )
return m_textures.normal->getID();
else
return INVALID_TEXTURE_ID;
}
} // namespace fgl::engine

View File

@@ -40,6 +40,7 @@ namespace fgl::engine
{
std::shared_ptr< Texture > albedo { nullptr };
std::shared_ptr< Texture > normal { nullptr };
std::shared_ptr< Texture > metallic_roughness { nullptr };
bool hasTextures() const { return albedo || normal; }
@@ -55,6 +56,11 @@ namespace fgl::engine
if ( !normal->ready() ) return false;
}
if ( metallic_roughness )
{
if ( !metallic_roughness->ready() ) return false;
}
return true;
}
};
@@ -112,6 +118,7 @@ namespace fgl::engine
memory::Buffer& index_buffer );
TextureID getAlbedoTextureID() const;
TextureID getNormalTextureID() const;
};
} // namespace fgl::engine

View File

@@ -8,8 +8,8 @@
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
#pragma GCC diagnostic ignored "-Wduplicated-branches"
#include <glm/vec2.hpp>
#include <glm/gtx/hash.hpp>
#include <glm/vec2.hpp>
#pragma GCC diagnostic pop
#include "Model.hpp"
@@ -50,8 +50,12 @@ namespace fgl::engine
attribute_descriptions.emplace_back( 7, 1, vk::Format::eR32G32B32A32Sfloat, 3 * sizeof( glm::vec4 ) );
attribute_descriptions.emplace_back( 8, 1, vk::Format::eR32Uint, 4 * sizeof( glm::vec4 ) );
attribute_descriptions.emplace_back( 9, 1, vk::Format::eR32Uint, 5 * sizeof( glm::vec4 ) );
attribute_descriptions.emplace_back( 10, 1, vk::Format::eR32Uint, 6 * sizeof( glm::vec4 ) );
static_assert( 4 * sizeof( glm::vec4 ) + sizeof( unsigned int ) == sizeof( ModelMatrixInfo ) );
static_assert(
4 * sizeof( glm::vec4 ) + sizeof( unsigned int ) + sizeof( unsigned int ) + sizeof( unsigned int )
== sizeof( ModelMatrixInfo ) );
return attribute_descriptions;
}

View File

@@ -179,11 +179,6 @@ namespace fgl::engine
const tinygltf::Material& materials { root.materials[ mat_idx ] };
for ( const auto& [ key, value ] : materials.values )
{
log::debug( "Found key: {}", key );
}
auto findParameter = [ &materials ]( const std::string name ) -> std::optional< tinygltf::Parameter >
{
const auto& itter { materials.values.find( name ) };
@@ -194,22 +189,41 @@ namespace fgl::engine
return { itter->second };
};
const auto albedo { findParameter( "baseColorTexture" ) };
const auto normal { findParameter( "normalTexture" ) };
const auto occlusion_texture { findParameter( "occlusionTexture" ) };
std::string str;
std::size_t counter { 0 };
for ( const auto& [ name, parameter ] : materials.values )
{
str += name;
if ( counter + 1 != materials.values.size() ) str += ", ";
++counter;
}
log::debug( "Found materials: {}", str );
PrimitiveTextures textures {};
const auto albedo { findParameter( "baseColorTexture" ) };
if ( albedo.has_value() )
{
textures.albedo = getTextureForParameter( *albedo, root );
}
const auto normal { findParameter( "normalTexture" ) };
if ( normal.has_value() )
{
textures.normal = getTextureForParameter( *normal, root );
}
const auto occlusion_texture { findParameter( "occlusionTexture" ) };
const auto mettalic_roughness_texture { findParameter( "mettalicRoughnessTexture" ) };
if ( mettalic_roughness_texture.has_value() )
{
textures.metallic_roughness = getTextureForParameter( *mettalic_roughness_texture, root );
}
return textures;
}
@@ -290,7 +304,7 @@ namespace fgl::engine
}
log::debug(
"Found {} verts.\n\t- Has UV info: {}\n\t- Has normals: {}",
"Found {} verts. Has UV info: {}, Has normals: {}",
verts.size(),
has_uv ? "Yes" : "No",
has_normals ? "Yes" : "No" );
@@ -301,12 +315,13 @@ namespace fgl::engine
Primitive SceneBuilder::loadPrimitive( const tinygltf::Primitive& prim, const tinygltf::Model& root )
{
ZoneScoped;
std::string att_str;
std::string att_str { "" };
for ( const auto& attrib : prim.attributes )
{
att_str += "Attribute: " + attrib.first + "\n";
att_str += attrib.first + ", ";
}
log::debug( "Attributes for primitive:\n{}", att_str );
log::debug( "Attributes for primitive: [{}]", att_str );
//TODO: Get normal colors from texture
[[maybe_unused]] const bool has_normal { hasAttribute( prim, "NORMAL" ) };

View File

@@ -5,6 +5,7 @@
#include "Shader.hpp"
#include "engine/rendering/Device.hpp"
#include "engine/shaders/Compiler.hpp"
namespace fgl::engine
{
@@ -21,7 +22,9 @@ namespace fgl::engine
ifs.read( reinterpret_cast< std::ifstream::char_type* >( data.data() ), data.size() );
return data;
// We now need to compile the shader before we use it.
return compileShader( path.filename().string(), data );
}
else
{
@@ -40,7 +43,7 @@ namespace fgl::engine
return module_info;
}
ShaderHandle::ShaderHandle( const std::filesystem::path path, const vk::PipelineShaderStageCreateInfo info ) :
ShaderHandle::ShaderHandle( const std::filesystem::path& path, const vk::PipelineShaderStageCreateInfo& info ) :
shader_data( loadData( path ) ),
module_create_info( createModuleInfo() ),
stage_info( info ),

View File

@@ -42,7 +42,7 @@ namespace fgl::engine
std::vector< std::byte > loadData( const std::filesystem::path& );
vk::ShaderModuleCreateInfo createModuleInfo();
ShaderHandle( const std::filesystem::path path, const vk::PipelineShaderStageCreateInfo info );
ShaderHandle( const std::filesystem::path& path, const vk::PipelineShaderStageCreateInfo& info );
ShaderHandle( const ShaderHandle& other ) = delete;

View File

@@ -34,9 +34,12 @@ namespace fgl::engine
throw std::runtime_error( "Unknown shader type!" );
}
std::vector< std::byte > compilerShader( const std::string_view input_name, std::vector< std::byte >& input )
std::vector< std::byte > compileShader( const std::string_view input_name, const std::vector< std::byte >& input )
{
shaderc::CompileOptions options;
options.SetTargetEnvironment( shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_3 );
#ifndef NDEBUG
options.SetOptimizationLevel( shaderc_optimization_level_zero );
#else
@@ -45,7 +48,7 @@ namespace fgl::engine
const shaderc_shader_kind kind { getShaderKindFromName( input_name ) };
const auto result { compiler->CompileGlslToSpvAssembly(
const auto result { getInstance().CompileGlslToSpv(
reinterpret_cast< const char* >( input.data() ), input.size(), kind, input_name.data(), "main", options ) };
switch ( result.GetCompilationStatus() )
@@ -74,6 +77,8 @@ namespace fgl::engine
break;
}
log::debug( "Compiled shader {}", input_name );
std::vector< std::byte > output {};
output.reserve( result.cend() - result.cbegin() );
@@ -87,6 +92,7 @@ namespace fgl::engine
// Should be a multiple of 4
assert( output.size() % 4 == 0 );
assert( output.size() > 0 );
return output;
}

View File

@@ -11,6 +11,6 @@ namespace fgl::engine
shaderc::Compiler& getInstance();
std::vector< std::byte > compileShader( const std::string_view str, std::vector< std::byte >& input );
std::vector< std::byte > compileShader( const std::string_view str, const std::vector< std::byte >& input );
} // namespace fgl::engine

View File

@@ -17,8 +17,8 @@ namespace fgl::engine
{
using DescriptorSets = descriptors::DescriptorSetCollection< GBufferDescriptorSet >;
using VertexShader = VertexShaderT< "shaders/fullscreen.vert.spv" >;
using FragmentShader = FragmentShaderT< "shaders/composition.frag.spv" >;
using VertexShader = VertexShaderT< "shaders/fullscreen.vert" >;
using FragmentShader = FragmentShaderT< "shaders/composition.frag" >;
using Shaders = ShaderCollection< VertexShader, FragmentShader >;

View File

@@ -51,7 +51,8 @@ namespace fgl::engine
//assert( primitive.m_texture );
const ModelMatrixInfo matrix_info { .model_matrix = obj.getTransform().mat4(),
.texture_idx = primitive.getAlbedoTextureID() };
.albedo_id = primitive.getAlbedoTextureID(),
.normal_id = primitive.getNormalTextureID() };
// If the textureless flag is on and we have a texture then skip the primitive.c
if ( tree_flags & IS_TEXTURELESS )
@@ -65,7 +66,7 @@ namespace fgl::engine
}
const auto key {
std::make_pair( matrix_info.texture_idx, primitive.m_index_buffer.getOffset() )
std::make_pair( matrix_info.albedo_id, primitive.m_index_buffer.getOffset() )
};
assert( primitive.m_index_buffer.size() > 0 );

View File

@@ -21,8 +21,8 @@ namespace fgl::engine
// Attachment 0 will be the composited image
using CompositeDescriptorSets = descriptors::DescriptorSetCollection< GuiInputDescriptorSet >;
using VertexShader = VertexShaderT< "shaders/fullscreen.vert.spv" >;
using FragmentShader = FragmentShaderT< "shaders/gui-compose.frag.spv" >;
using VertexShader = VertexShaderT< "shaders/fullscreen.vert" >;
using FragmentShader = FragmentShaderT< "shaders/gui-compose.frag" >;
using Shaders = ShaderCollection< VertexShader, FragmentShader >;
using Pipeline = PipelineT< Shaders, CompositeDescriptorSets >;

View File

@@ -12,8 +12,8 @@
namespace fgl::engine
{
using StandardPipelineVertexShader = VertexShaderT< "shaders/textureless-gbuffer.vert.spv" >;
using StandardPipelineFragShader = FragmentShaderT< "shaders/textureless-gbuffer.frag.spv" >;
using StandardPipelineVertexShader = VertexShaderT< "shaders/textureless-gbuffer.vert" >;
using StandardPipelineFragShader = FragmentShaderT< "shaders/textureless-gbuffer.frag" >;
using StandardPipelineShaders = ShaderCollection< StandardPipelineVertexShader, StandardPipelineFragShader >;
// using StandardPipelineDescriptorSets = descriptors::DescriptorSetCollection< GlobalDescriptorSet >;

View File

@@ -11,8 +11,8 @@
namespace fgl::engine
{
using TexturedPipelineVertexShader = VertexShaderT< "shaders/textured-gbuffer.vert.spv" >;
using TexturedPipelineFragShader = FragmentShaderT< "shaders/textured-gbuffer.frag.spv" >;
using TexturedPipelineVertexShader = VertexShaderT< "shaders/textured-gbuffer.vert" >;
using TexturedPipelineFragShader = FragmentShaderT< "shaders/textured-gbuffer.frag" >;
using TexturedPipelineShaders = ShaderCollection< TexturedPipelineVertexShader, TexturedPipelineFragShader >;
//using TexturedPipelineDescriptorSets =

View File

@@ -24,12 +24,12 @@
namespace fgl::engine
{
using TextureID = std::uint32_t;
static std::queue< TextureID > unused_ids {};
TextureID getNextID()
{
static TextureID id { 0 };
static TextureID id { 1 };
if ( unused_ids.size() > 0 )
{
@@ -40,10 +40,8 @@ namespace fgl::engine
return pulled_id;
}
else
{
return id++;
}
return id++;
}
std::tuple< std::vector< std::byte >, int, int, vk::Format >

View File

@@ -31,12 +31,13 @@ namespace fgl::engine
class TextureHandle;
using TextureID = std::uint32_t;
class Texture;
using TextureStore = AssetStore< Texture >;
using TextureID = std::uint32_t;
constexpr TextureID INVALID_TEXTURE_ID { 0 };
//TODO: Implement texture handle map to avoid loading the same texture multiple times
class Texture final : public AssetInterface< Texture >
{