diff --git a/CMakeLists.txt b/CMakeLists.txt index 0415223..c2372e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,24 +57,28 @@ foreach (MODEL IN LISTS MODELS) list(APPEND OBJ_MODELS ${CMAKE_BINARY_DIR}/bin/models/${FILENAME}) endforeach () -file(GLOB FRAG_SHADERS "${CMAKE_CURRENT_SOURCE_DIR}/shaders/*.frag") -file(GLOB VERT_SHADERS "${CMAKE_CURRENT_SOURCE_DIR}/shaders/*.vert") +file(GLOB_RECURSE SHADERS + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/**.frag" + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/**.vert" + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/**.tesc" + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/**.tese" +) -foreach (SHADER IN LISTS FRAG_SHADERS) +foreach (SHADER IN LISTS SHADERS) get_filename_component(FILENAME ${SHADER} NAME) + get_filename_component(FILE_DIRECTORY ${SHADER} DIRECTORY) + file(RELATIVE_PATH REL_PATH ${CMAKE_CURRENT_SOURCE_DIR}/shaders ${FILE_DIRECTORY}) + + if (NOT REL_PATH STREQUAL "") + set(REL_PATH ${REL_PATH}/) + file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bin/shaders/${REL_PATH}) + endif () add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/bin/shaders/${FILENAME}.spv - COMMAND ${Vulkan_GLSLC_EXECUTABLE} ${SHADER_DEBUG_FLAGS} ${SHADER} -o ${CMAKE_BINARY_DIR}/bin/shaders/${FILENAME}.spv DEPENDS ${SHADER} + COMMAND ${Vulkan_GLSLC_EXECUTABLE} ${SHADER_DEBUG_FLAGS} ${SHADER} -o ${CMAKE_BINARY_DIR}/bin/shaders/${REL_PATH}${FILENAME}.spv DEPENDS ${SHADER} COMMENT " Compiling ${SHADER} ") list(APPEND SPV_SHADERS ${CMAKE_BINARY_DIR}/bin/shaders/${FILENAME}.spv) endforeach () -foreach (SHADER IN LISTS VERT_SHADERS) - get_filename_component(FILENAME ${SHADER} NAME) - add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/bin/shaders/${FILENAME}.spv - COMMAND ${Vulkan_GLSLC_EXECUTABLE} ${SHADER_DEBUG_FLAGS} ${SHADER} -o ${CMAKE_BINARY_DIR}/bin/shaders/${FILENAME}.spv DEPENDS ${SHADER} - COMMENT " Compiling ${SHADER} ") - list(APPEND SPV_SHADERS ${CMAKE_BINARY_DIR}/bin/shaders/${FILENAME}.spv) -endforeach () add_custom_target(shaders ALL DEPENDS ${SPV_SHADERS}) add_custom_target(models ALL DEPENDS ${OBJ_MODELS}) diff --git a/cmake_modules/gcc.cmake b/cmake_modules/gcc.cmake index e224855..8097ae2 100644 --- a/cmake_modules/gcc.cmake +++ b/cmake_modules/gcc.cmake @@ -116,7 +116,7 @@ # TODO: Figure out LTO with Alaestor's retarded compiler set(FGL_SHARED_OPTIMIZATION_FLAGS "") - set(FGL_GENERAL_OPTIMIZATION_FLAGS "-fdevirtualize-at-ltrans -fdevirtualize-speculatively -funroll-loops -floop-nest-optimize -floop-parallelize-all -fsplit-paths -fstrict-aliasing -ftree-vectorize -fopt-info-vec-missed") + set(FGL_GENERAL_OPTIMIZATION_FLAGS "-fdevirtualize-at-ltrans -fdevirtualize-speculatively -funroll-loops -floop-nest-optimize -floop-parallelize-all -fsplit-paths -fstrict-aliasing -ftree-vectorize") set(FGL_SHARED_DEBUG "-gdwarf-4 -fvar-tracking-assignments") diff --git a/shaders/terrain/terrain.frag b/shaders/terrain/terrain.frag new file mode 100644 index 0000000..ffdefbe --- /dev/null +++ b/shaders/terrain/terrain.frag @@ -0,0 +1,57 @@ +#version 450 +#extension GL_EXT_nonuniform_qualifier: enable +#extension GL_EXT_debug_printf: enable + +layout (location = 0) in vec3 in_normal; +layout (location = 1) in vec3 in_color; +layout (location = 2) in vec3 in_world_pos; +layout (location = 3) in vec2 in_tex_coord; +layout (location = 4) in flat uint in_tex_idx; + +layout (location = 0) out vec4 out_color; +layout (location = 1) out vec4 out_position; +layout (location = 2) out vec4 out_normal; +layout (location = 3) out vec4 out_albedo; + +layout (set = 0, binding = 0) uniform CameraInfo { + mat4 projection; + mat4 view; + mat4 inverse_view; +} ubo; + +layout (set = 1, binding = 0) uniform sampler2D tex[]; + +#define NEAR_PLANE 0.01f +#define FAR_PLANE 1000.0f + +float linearDepth(float depth) +{ + float z = depth * 2.0f - 1.0f; + return (2.0f * NEAR_PLANE * FAR_PLANE) / (FAR_PLANE + NEAR_PLANE - z * (FAR_PLANE - NEAR_PLANE)); +} + +void main() +{ + + out_position = vec4(in_world_pos, 1.0f); + + vec3 N = normalize(in_normal); + + out_normal = vec4(N, 1.0); + + vec4 tex_value = texture(tex[in_tex_idx], in_tex_coord); + + if (tex_value.a < 1.0) + { + discard; + } + + + out_albedo = tex_value; + + out_position.a = linearDepth(out_position.z); + + //out_color = vec4(0.0); + //out_color = vec4(in_tex_coord, 0.0f, 0.0f); + //out_color = texture(tex[0], in_tex_coord); +} \ No newline at end of file diff --git a/shaders/terrain/terrain.tesc b/shaders/terrain/terrain.tesc new file mode 100644 index 0000000..e771beb --- /dev/null +++ b/shaders/terrain/terrain.tesc @@ -0,0 +1,27 @@ +#version 450 + +layout(location = 0) in vec3 in_pos[]; +layout(location = 1) in vec3 in_color[]; +layout(location = 2) in vec3 in_normal[]; +layout(location = 3) in vec2 in_uv[]; + +layout(location = 8) in uint in_tex_id[]; + +layout(location = 2) out vec3 out_normal[4]; +layout(location = 3) out vec2 out_uv[4]; + +layout(vertices = 4) out; + +void main() +{ + gl_TessLevelInner[0] = 2.0f; + gl_TessLevelInner[1] = 2.0f; + gl_TessLevelOuter[0] = 2.0f; + gl_TessLevelOuter[1] = 2.0f; + gl_TessLevelOuter[2] = 2.0f; + gl_TessLevelOuter[3] = 2.0f; + + gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; + out_normal[gl_InvocationID] = in_normal[gl_InvocationID]; + out_uv[gl_InvocationID] = in_uv[gl_InvocationID]; +} \ No newline at end of file diff --git a/shaders/terrain/terrain.tese b/shaders/terrain/terrain.tese new file mode 100644 index 0000000..8f044f1 --- /dev/null +++ b/shaders/terrain/terrain.tese @@ -0,0 +1,43 @@ +#version 450 + + +layout(quads, equal_spacing, cw) in; + +layout(location = 2) in vec3 in_normal[]; +layout(location = 3) in vec2 in_uv[]; + +layout(location = 8) in uint in_tex_id[]; + +layout(location = 0) out vec3 out_normal; +layout(location = 3) out vec2 out_uv; + +struct FrustumPlane +{ + vec3 pos; + float dist; +}; + +layout(set = 0, binding = 0) uniform CameraInfo +{ + mat4 projection; + mat4 view; + mat4 inverse_view; + FrustumPlane frustum_planes[6]; +} ubo; + +void main() +{ + vec2 uv1 = mix(in_uv[0], in_uv[1], gl_TessCoord.x); + vec2 uv2 = mix(in_uv[3], in_uv[2], gl_TessCoord.x); + out_uv = mix(uv1, uv2, gl_TessCoord.y); + + vec3 n1 = mix(in_normal[0], in_normal[1], gl_TessCoord.x); + vec3 n2 = mix(in_normal[3], in_normal[2], gl_TessCoord.x); + out_normal = mix(n1, n2, gl_TessCoord.y); + + vec4 pos1 = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x); + vec4 pos2 = mix(gl_in[3].gl_Position, gl_in[2].gl_Position, gl_TessCoord.x); + vec4 pos = mix(pos1, pos2, gl_TessCoord.y); + + gl_Position = ubo.projection * ubo.view * pos; +} \ No newline at end of file diff --git a/shaders/terrain/terrain.vert b/shaders/terrain/terrain.vert new file mode 100644 index 0000000..bf4517f --- /dev/null +++ b/shaders/terrain/terrain.vert @@ -0,0 +1,46 @@ +#version 450 +#extension GL_EXT_debug_printf: enable + +layout (location = 0) in vec3 position; +layout (location = 1) in vec3 color; +layout (location = 2) in vec3 normal; +layout (location = 3) in vec2 uv; + +layout (location = 4) in mat4 instance_model_matrix;// 4, 5, 6, 7 +layout (location = 8) in uint in_texture_id; + +layout (location = 0) out vec3 out_normal; +layout (location = 1) out vec3 out_color; +layout (location = 2) out vec3 out_world_pos; +layout (location = 3) out vec2 out_tex_coord; +layout (location = 4) out uint out_texture_idx; + + +struct FrustumPlane +{ + vec3 pos; + float dist; +}; + + +layout (set = 0, binding = 0) uniform CameraInfo { + mat4 projection; + mat4 view; + mat4 inverse_view; + FrustumPlane frustum_planes[6]; +} ubo; + +void main() { + + gl_Position = instance_model_matrix * vec4(position, 1.0f); + + mat3 normal_matrix = transpose(inverse(mat3(instance_model_matrix))); + + out_normal = normalize(normal_matrix * normal); + + out_color = color; + + out_tex_coord = uv; + + out_texture_idx = in_texture_id; +} \ No newline at end of file diff --git a/src/engine/EngineContext.cpp b/src/engine/EngineContext.cpp index 962b1d6..398b597 100644 --- a/src/engine/EngineContext.cpp +++ b/src/engine/EngineContext.cpp @@ -185,18 +185,18 @@ namespace fgl::engine camera_info[ frame_index ] = current_camera_info; -#if TRACY_ENABLE m_culling_system.startPass( frame_info ); TracyVkCollect( frame_info.tracy_ctx, command_buffer ); m_culling_system.wait(); -#else - m_culling_system.pass( frame_info ); -#endif m_renderer.beginSwapchainRendererPass( command_buffer ); + // m_terrain_system.pass( frame_info ); + m_entity_renderer.pass( frame_info ); + m_composition_system.pass( frame_info ); + #if ENABLE_IMGUI { TracyVkZone( tracy_ctx, command_buffer, "ImGui Rendering" ); diff --git a/src/engine/EngineContext.hpp b/src/engine/EngineContext.hpp index a915c01..9045b92 100644 --- a/src/engine/EngineContext.hpp +++ b/src/engine/EngineContext.hpp @@ -9,6 +9,8 @@ #include "engine/systems/CullingSystem.hpp" #include "engine/systems/EntityRendererSystem.hpp" #include "engine/tree/octtree/OctTreeNode.hpp" +#include "systems/CompositionSystem.hpp" +#include "systems/TerrainSystem.hpp" namespace fgl::engine { @@ -25,7 +27,9 @@ namespace fgl::engine OctTreeNode m_game_objects_root { WorldCoordinate( constants::WORLD_CENTER ) }; CullingSystem m_culling_system {}; + //TerrainSystem m_terrain_system { Device::getInstance(), m_renderer.getSwapChainRenderPass() }; EntityRendererSystem m_entity_renderer { Device::getInstance(), m_renderer.getSwapChainRenderPass() }; + CompositionSystem m_composition_system { Device::getInstance(), m_renderer.getSwapChainRenderPass() }; void loadGameObjects(); diff --git a/src/engine/PushConstant.hpp b/src/engine/PushConstant.hpp index a3cd356..6c458db 100644 --- a/src/engine/PushConstant.hpp +++ b/src/engine/PushConstant.hpp @@ -27,11 +27,6 @@ namespace fgl::engine } }; - template < typename T > - concept is_constant_range = requires( T t ) { - { - t.m_range - } -> std::same_as< const vk::PushConstantRange& >; - }; + } // namespace fgl::engine \ No newline at end of file diff --git a/src/engine/descriptors/DescriptorSetLayout.hpp b/src/engine/descriptors/DescriptorSetLayout.hpp index f11c7e4..cc28c1f 100644 --- a/src/engine/descriptors/DescriptorSetLayout.hpp +++ b/src/engine/descriptors/DescriptorSetLayout.hpp @@ -4,8 +4,11 @@ #pragma once +#include "Descriptor.hpp" #include "DescriptorPool.hpp" +#include "concepts.hpp" #include "engine/concepts/is_bindable.hpp" +#include "engine/concepts/is_descriptor.hpp" namespace fgl::engine { @@ -183,19 +186,7 @@ namespace fgl::engine static_assert( TestSet::descriptor_count == 7 ); } // namespace internal - template < typename T > - concept is_descriptor_set = requires( std::remove_reference_t< T > t ) { - { - t.descriptor_count - } -> std::same_as< const std::uint16_t& >; - { - T::createLayout() - } -> std::same_as< vk::DescriptorSetLayout >; - }; - template < typename T > - concept is_empty_descriptor_set = is_descriptor_set< T > && ( T::descriptor_count == 1 ) - && is_empty_descriptor< typename T::template Binding< 0 > >; static_assert( is_descriptor_set< EmptyDescriptorSet< 0 > > && is_empty_descriptor_set< EmptyDescriptorSet< 0 > > ); static_assert( is_descriptor_set< internal::TestSet > && !is_empty_descriptor_set< internal::TestSet > ); diff --git a/src/engine/descriptors/concepts.hpp b/src/engine/descriptors/concepts.hpp new file mode 100644 index 0000000..0a0935d --- /dev/null +++ b/src/engine/descriptors/concepts.hpp @@ -0,0 +1,34 @@ +// +// Created by kj16609 on 3/13/24. +// + +#pragma once + +#include "engine/concepts/is_descriptor.hpp" + +namespace fgl::engine +{ + + template < typename T > + concept is_descriptor_set = requires( std::remove_reference_t< T > t ) { + { + t.descriptor_count + } -> std::same_as< const std::uint16_t& >; + { + T::createLayout() + } -> std::same_as< vk::DescriptorSetLayout >; + }; + + template < typename T > + concept is_empty_descriptor_set = is_descriptor_set< T > && ( T::descriptor_count == 1 ) + && is_empty_descriptor< typename T::template Binding< 0 > >; + + template < typename T > + concept is_constant_range = requires( T t ) { + { + t.m_range + } -> std::same_as< const vk::PushConstantRange& >; + }; + + template < typename T > concept is_valid_pipeline_input = is_constant_range< T > || is_descriptor_set< T >; +} // namespace fgl::engine diff --git a/src/engine/pipeline/Pipeline.cpp b/src/engine/pipeline/Pipeline.cpp index 8720078..bcb0fa8 100644 --- a/src/engine/pipeline/Pipeline.cpp +++ b/src/engine/pipeline/Pipeline.cpp @@ -7,53 +7,24 @@ #include #include +#include "Shader.hpp" #include "engine/model/Model.hpp" -namespace fgl::engine +namespace fgl::engine::internal { - std::vector< std::byte > Pipeline::readFile( const std::filesystem::path& path ) - { - if ( std::ifstream ifs( path, std::ios::binary | std::ios::ate ); ifs ) - { - std::vector< std::byte > data; - - data.resize( static_cast< std::size_t >( ifs.tellg() ) ); - ifs.seekg( 0, std::ios::beg ); - - ifs.read( reinterpret_cast< char* >( data.data() ), static_cast< long >( data.size() ) ); - - return data; - } - else - throw std::runtime_error( "Failed to load file: " + path.string() ); - } - void Pipeline::createGraphicsPipeline( - const std::filesystem::path& vert, const std::filesystem::path& frag, const PipelineConfigInfo& info ) + std::vector< std::unique_ptr< ShaderHandle > >& shaders, const PipelineConfigInfo& info ) { assert( info.render_pass != VK_NULL_HANDLE && "Cannot create graphics pipeline: no render pass provided" ); - const std::vector< std::byte > vert_data { readFile( vert ) }; - const std::vector< std::byte > frag_data { readFile( frag ) }; + std::vector< vk::PipelineShaderStageCreateInfo > stages {}; - createShaderModule( vert_data, &m_vert_shader ); - createShaderModule( frag_data, &m_frag_shader ); - - vk::PipelineShaderStageCreateInfo shaderStages[ 2 ] {}; - shaderStages[ 0 ].pNext = nullptr; - shaderStages[ 0 ].flags = {}; - shaderStages[ 0 ].stage = vk::ShaderStageFlagBits::eVertex; - shaderStages[ 0 ].module = m_vert_shader; - shaderStages[ 0 ].pName = "main"; - shaderStages[ 0 ].pSpecializationInfo = nullptr; - - shaderStages[ 1 ].pNext = nullptr; - shaderStages[ 1 ].flags = {}; - shaderStages[ 1 ].stage = vk::ShaderStageFlagBits::eFragment; - shaderStages[ 1 ].module = m_frag_shader; - shaderStages[ 1 ].pName = "main"; - shaderStages[ 1 ].pSpecializationInfo = nullptr; + for ( const auto& shader : shaders ) + { + stages.emplace_back( shader->stage_info ); + } + assert( stages.size() >= 2 ); auto& binding_descriptions { info.binding_descriptions }; auto& attribute_descriptions { info.attribute_descriptions }; @@ -70,8 +41,8 @@ namespace fgl::engine vk::GraphicsPipelineCreateInfo pipeline_info {}; pipeline_info.pNext = VK_NULL_HANDLE; pipeline_info.flags = {}; - pipeline_info.stageCount = 2; - pipeline_info.pStages = shaderStages; + pipeline_info.stageCount = static_cast< std::uint32_t >( stages.size() ); + pipeline_info.pStages = stages.data(); pipeline_info.pVertexInputState = &vertex_input_info; pipeline_info.pInputAssemblyState = &info.assembly_info; pipeline_info.pTessellationState = VK_NULL_HANDLE; @@ -94,33 +65,8 @@ namespace fgl::engine m_vk_pipeline = temp.value; } - void Pipeline::createShaderModule( const std::vector< std::byte >& code, vk::ShaderModule* module ) - { - vk::ShaderModuleCreateInfo create_info {}; - create_info.pNext = VK_NULL_HANDLE; - create_info.flags = {}; - create_info.codeSize = code.size(); - create_info.pCode = reinterpret_cast< const std::uint32_t* >( code.data() ); - - if ( m_device.device().createShaderModule( &create_info, nullptr, module ) != vk::Result::eSuccess ) - throw std::runtime_error( "Failed to create shader module" ); - } - - Pipeline::Pipeline( - Device& device, - const std::filesystem::path& vert, - const std::filesystem::path& frag, - const PipelineConfigInfo& info ) : - m_device( device ) - { - createGraphicsPipeline( vert, frag, info ); - } - Pipeline::~Pipeline() { - m_device.device().destroyShaderModule( m_vert_shader, nullptr ); - m_device.device().destroyShaderModule( m_frag_shader, nullptr ); - m_device.device().destroyPipelineLayout( m_layout, nullptr ); m_device.device().destroyPipeline( m_vk_pipeline, nullptr ); } @@ -130,4 +76,4 @@ namespace fgl::engine command_buffer.bindPipeline( vk::PipelineBindPoint::eGraphics, m_vk_pipeline ); } -} // namespace fgl::engine +} // namespace fgl::engine::internal diff --git a/src/engine/pipeline/Pipeline.hpp b/src/engine/pipeline/Pipeline.hpp index a241172..808eaa7 100644 --- a/src/engine/pipeline/Pipeline.hpp +++ b/src/engine/pipeline/Pipeline.hpp @@ -11,6 +11,11 @@ #include "engine/rendering/Device.hpp" namespace fgl::engine +{ + struct ShaderHandle; +} + +namespace fgl::engine::internal { class Pipeline @@ -23,21 +28,11 @@ namespace fgl::engine vk::ShaderModule m_vert_shader { VK_NULL_HANDLE }; vk::ShaderModule m_frag_shader { VK_NULL_HANDLE }; - static std::vector< std::byte > readFile( const std::filesystem::path& path ); - void createGraphicsPipeline( - const std::filesystem::path& vert, const std::filesystem::path& frag, const PipelineConfigInfo& info ); - - void createShaderModule( const std::vector< std::byte >& code, vk::ShaderModule* module ); + std::vector< std::unique_ptr< ShaderHandle > >& shaders, const PipelineConfigInfo& info ); public: - Pipeline( - Device& device, - const std::filesystem::path& vert, - const std::filesystem::path& frag, - const PipelineConfigInfo& info ); - Pipeline( Device& device ) : m_device( device ) {} ~Pipeline(); @@ -47,4 +42,4 @@ namespace fgl::engine void bind( vk::CommandBuffer command_buffer ); }; -} // namespace fgl::engine \ No newline at end of file +} // namespace fgl::engine::internal \ No newline at end of file diff --git a/src/engine/pipeline/PipelineConfigInfo.cpp b/src/engine/pipeline/PipelineConfigInfo.cpp index d3a4d0e..6fca198 100644 --- a/src/engine/pipeline/PipelineConfigInfo.cpp +++ b/src/engine/pipeline/PipelineConfigInfo.cpp @@ -9,6 +9,21 @@ namespace fgl::engine { + void PipelineConfigInfo::setTriangleListTopo( PipelineConfigInfo& info ) + { + info.assembly_info.topology = vk::PrimitiveTopology::eTriangleList; + } + + void PipelineConfigInfo::setTriangleStripTopo( PipelineConfigInfo& info ) + { + info.assembly_info.topology = vk::PrimitiveTopology::eTriangleStrip; + } + + void PipelineConfigInfo::setPointPatch( PipelineConfigInfo& info ) + { + info.assembly_info.topology = vk::PrimitiveTopology::ePatchList; + } + void PipelineConfigInfo::defaultConfig( PipelineConfigInfo& info ) { info.viewport_info.viewportCount = 1; diff --git a/src/engine/pipeline/PipelineConfigInfo.hpp b/src/engine/pipeline/PipelineConfigInfo.hpp index c0927e1..5efd3b4 100644 --- a/src/engine/pipeline/PipelineConfigInfo.hpp +++ b/src/engine/pipeline/PipelineConfigInfo.hpp @@ -16,6 +16,8 @@ namespace fgl::engine { vk::PipelineViewportStateCreateInfo viewport_info {}; vk::PipelineInputAssemblyStateCreateInfo assembly_info {}; + vk::PipelineTessellationStateCreateInfo tesselation_state_info {}; + vk::PipelineTessellationDomainOriginStateCreateInfo tesselation_domain_info {}; vk::PipelineRasterizationStateCreateInfo rasterization_info {}; vk::PipelineMultisampleStateCreateInfo multisample_info {}; std::vector< vk::PipelineColorBlendAttachmentState > color_blend_attachment {}; @@ -37,6 +39,9 @@ namespace fgl::engine PipelineConfigInfo& operator=( const PipelineConfigInfo& ) = delete; static void disableVertexInput( PipelineConfigInfo& info ); + static void setTriangleListTopo( PipelineConfigInfo& info ); + static void setTriangleStripTopo( PipelineConfigInfo& info ); + static void setPointPatch( PipelineConfigInfo& info ); static void defaultConfig( PipelineConfigInfo& info ); static void enableAlphaBlending( PipelineConfigInfo& config ); static void addColorAttachmentConfig( PipelineConfigInfo& info ); diff --git a/src/engine/pipeline/PipelineT.hpp b/src/engine/pipeline/PipelineT.hpp index 8fd7dd7..82b69cd 100644 --- a/src/engine/pipeline/PipelineT.hpp +++ b/src/engine/pipeline/PipelineT.hpp @@ -5,22 +5,18 @@ #pragma once #include "Pipeline.hpp" -#include "engine/PushConstant.hpp" -#include "engine/descriptors/Descriptor.hpp" +#include "Shader.hpp" #include "engine/descriptors/DescriptorSet.hpp" -#include "engine/descriptors/DescriptorSetLayout.hpp" namespace fgl::engine { - template < typename T > concept is_valid_pipeline_input = is_constant_range< T > || is_descriptor_set< T >; - template < std::uint16_t size, std::uint16_t current_idx, is_valid_pipeline_input CurrentSet, is_valid_pipeline_input... Sets > - void createDescriptorSets( std::array< vk::DescriptorSetLayout, size >& out ) + void createDescriptorSetsT( std::array< vk::DescriptorSetLayout, size >& out ) { if constexpr ( size == 0 ) return; @@ -34,12 +30,12 @@ namespace fgl::engine out[ current_idx ] = CurrentSet::createDescriptorSetLayout(); assert( out[ current_idx ] != VK_NULL_HANDLE && "createDescriptorSetLayout returned VK_NULL_HANDLE" ); std::cout << "Created descriptor set layout for binding set " << current_idx << std::endl; - if constexpr ( sizeof...( Sets ) > 0 ) createDescriptorSets< size, current_idx + 1, Sets... >( out ); + if constexpr ( sizeof...( Sets ) > 0 ) createDescriptorSetsT< size, current_idx + 1, Sets... >( out ); } else if constexpr ( is_constant_range< CurrentSet > ) { if constexpr ( sizeof...( Sets ) > 0 ) // We don't want to increase the size - createDescriptorSets< size, current_idx, Sets... >( out ); + createDescriptorSetsT< size, current_idx, Sets... >( out ); else return; } @@ -72,21 +68,19 @@ namespace fgl::engine return getMaxBindingSetIDX< Sets... >(); } - template < typename... DescriptorSets > - requires( (is_valid_pipeline_input< DescriptorSets >) && ... ) - class PipelineT : public Pipeline + template < is_valid_pipeline_input... DescriptorSets > + struct DescriptorSetCollection { + using DescriptorSetTuple = std::tuple< DescriptorSets... >; + + constexpr static std::uint64_t DescriptorSetCount { sizeof...( DescriptorSets ) }; + //If the first descriptor set is a constant range, then the pipeline has a constant range constexpr static bool has_constant_range { is_constant_range< std::tuple_element_t< 0, std::tuple< DescriptorSets... > > > }; - constexpr static std::uint16_t binding_sets { ( is_descriptor_set< DescriptorSets > + ... ) }; - constexpr static bool has_binding_sets { binding_sets != 0 }; - //! Returns the binding type assocaited with the index - template < std::uint16_t binding_set_idx > - using BindingSet = - std::tuple_element_t< binding_set_idx + ( has_constant_range ? 1 : 0 ), std::tuple< DescriptorSets... > >; + constexpr static std::uint16_t binding_sets { ( is_descriptor_set< DescriptorSets > + ... ) }; constexpr static std::uint16_t max_binding_set { getMaxBindingSetIDX< DescriptorSets... >() }; @@ -94,6 +88,51 @@ namespace fgl::engine constexpr static std::uint16_t empty_sets { ( is_empty_descriptor_set< DescriptorSets > + ... ) }; + using LayoutArray = std::array< vk::DescriptorSetLayout, DescriptorSetCount - has_constant_range >; + + static LayoutArray createDescriptorSets() + { + LayoutArray layouts; + createDescriptorSetsT< layouts.size(), 0, DescriptorSets... >( layouts ); + return layouts; + } + + template < std::uint64_t IDX > + requires( IDX < DescriptorSetCount ) + using DescriptorSet = std::tuple_element_t< IDX, DescriptorSetTuple >; + + template < std::uint64_t BindingIDX > + using BindingSet = DescriptorSet< BindingIDX + ( has_constant_range ? 1 : 0 ) >; + + using PushConstantT = BindingSet< 0 >; + }; + + template < typename T > + concept is_descriptor_set_collection = requires( T t ) { + typename T::DescriptorSetTuple; + { + t.DescriptorSetCount + } -> std::same_as< const std::uint64_t& >; + }; + + template < is_shader_collection ShaderCollection, is_descriptor_set_collection DescriptorSetCollection > + class PipelineT : public internal::Pipeline + { + //If the first descriptor set is a constant range, then the pipeline has a constant range + constexpr static bool has_constant_range { DescriptorSetCollection::has_constant_range }; + constexpr static std::uint16_t binding_sets { DescriptorSetCollection::binding_sets }; + constexpr static bool has_binding_sets { binding_sets != 0 }; + + //! Returns the binding type assocaited with the index + template < std::uint16_t binding_set_idx > + using BindingSet = DescriptorSetCollection::template BindingSet< binding_set_idx >; + + constexpr static std::uint16_t max_binding_set { DescriptorSetCollection::max_binding_set }; + + constexpr static std::uint16_t set_count { DescriptorSetCollection::set_count }; + + constexpr static std::uint16_t empty_sets { DescriptorSetCollection::empty_sets }; + static_assert( ( set_count == 0 && has_constant_range ) || ( set_count == ( max_binding_set + 1 ) ), "Binding sets must not have any spaces (Use EmptySet)" ); @@ -113,7 +152,7 @@ namespace fgl::engine { if constexpr ( has_constant_range ) { - return &std::tuple_element_t< 0, std::tuple< DescriptorSets... > >::m_range; + return &DescriptorSetCollection::template DescriptorSet< 0 >::m_range; } else { @@ -148,9 +187,7 @@ namespace fgl::engine { if ( m_layout != VK_NULL_HANDLE ) return m_layout; - std::array< vk::DescriptorSetLayout, sizeof...( DescriptorSets ) - has_constant_range > layouts; - - createDescriptorSets< layouts.size(), 0, DescriptorSets... >( layouts ); + typename DescriptorSetCollection::LayoutArray layouts { DescriptorSetCollection::createDescriptorSets() }; vk::PipelineLayoutCreateInfo pipeline_layout_info {}; pipeline_layout_info.setLayoutCount = has_binding_sets ? static_cast< uint32_t >( layouts.size() ) : 0; @@ -186,7 +223,7 @@ namespace fgl::engine { if constexpr ( has_constant_range ) { - using PushConstantType = typename std::tuple_element_t< 0, std::tuple< DescriptorSets... > >; + using PushConstantType = typename DescriptorSetCollection::PushConstantT; static_assert( std::same_as< TPushData, typename PushConstantType::DataType >, "Push constant data type mismatch" ); @@ -197,15 +234,13 @@ namespace fgl::engine assert( "Attempted to push constant to pipeline without push constant range" ); } - PipelineT( - Device& device, - PipelineConfigInfo& info, - std::filesystem::path vertex_shader, - std::filesystem::path frag_shader ) : - Pipeline( device ) + PipelineT( Device& device, PipelineConfigInfo& info ) : Pipeline( device ) { populate( info, device ); - createGraphicsPipeline( vertex_shader, frag_shader, info ); + + auto shaders { ShaderCollection::loadShaders() }; + + createGraphicsPipeline( shaders, info ); } }; diff --git a/src/engine/pipeline/Shader.hpp b/src/engine/pipeline/Shader.hpp new file mode 100644 index 0000000..434fa24 --- /dev/null +++ b/src/engine/pipeline/Shader.hpp @@ -0,0 +1,152 @@ +// +// Created by kj16609 on 3/13/24. +// + +#ifndef SHADER_HPP +#define SHADER_HPP + +#include + +#include "engine/descriptors/concepts.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 + 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 < 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 + +#endif //SHADER_HPP diff --git a/src/engine/systems/CullingSystem.hpp b/src/engine/systems/CullingSystem.hpp index e0d932a..5bf08c5 100644 --- a/src/engine/systems/CullingSystem.hpp +++ b/src/engine/systems/CullingSystem.hpp @@ -28,6 +28,8 @@ namespace fgl::engine public: + [[maybe_unused]] vk::CommandBuffer& setupSystem( FrameInfo& info ); + CullingSystem() : m_thread( &CullingSystem::runner, this ) {} void pass( FrameInfo& info ); diff --git a/src/engine/systems/EntityRendererSystem.cpp b/src/engine/systems/EntityRendererSystem.cpp index d662ac6..d71095f 100644 --- a/src/engine/systems/EntityRendererSystem.cpp +++ b/src/engine/systems/EntityRendererSystem.cpp @@ -61,16 +61,7 @@ namespace fgl::engine info.subpass = 0; - m_pipeline = - std::make_unique< Pipeline >( m_device, info, "shaders/gbuffer.vert.spv", "shaders/gbuffer.frag.spv" ); - - PipelineConfigInfo composition_info { render_pass }; - PipelineConfigInfo::addColorAttachmentConfig( composition_info ); - PipelineConfigInfo::disableVertexInput( composition_info ); - composition_info.subpass = 1; - - m_composition_pipeline = std::make_unique< CompositionPipeline >( - m_device, composition_info, "shaders/composition.vert.spv", "shaders/composition.frag.spv" ); + m_pipeline = std::make_unique< Pipeline >( m_device, info ); using namespace fgl::literals::size_literals; @@ -79,9 +70,6 @@ namespace fgl::engine initDrawParameterBuffer( 1_KiB ); } - EntityRendererSystem::~EntityRendererSystem() - {} - using DrawPair = std::pair< vk::DrawIndexedIndirectCommand, std::vector< ModelMatrixInfo > >; bool operator<( const DrawPair& left, const DrawPair& right ) @@ -94,168 +82,159 @@ namespace fgl::engine return left.first.firstIndex == right.first.firstIndex && left.first.indexCount && right.first.indexCount; } + vk::CommandBuffer& EntityRendererSystem::setupSystem( FrameInfo& info ) + { + auto& command_buffer { info.command_buffer }; + m_pipeline->bind( command_buffer ); + + m_pipeline->bindDescriptor( command_buffer, 0, info.global_descriptor_set ); + m_pipeline->bindDescriptor( command_buffer, 1, Texture::getTextureDescriptorSet() ); + return command_buffer; + } + void EntityRendererSystem::pass( FrameInfo& info ) { ZoneScopedN( "Entity pass" ); - auto& command_buffer { info.command_buffer }; + auto& command_buffer { setupSystem( info ) }; + TracyVkZone( info.tracy_ctx, command_buffer, "Render game objects" ); + + //TracyVkZone( m_device.getCurrentTracyCTX(), command_buffer, "Render game objects" ); + + std::unordered_map< DrawKey, DrawPair > draw_pairs; + + std::uint64_t tri_counter { 0 }; + std::uint64_t object_counter { 0 }; + std::uint64_t primitive_counter { 0 }; + + for ( auto* node : info.in_view_leafs ) { - TracyVkZone( info.tracy_ctx, command_buffer, "Render game objects" ); - - //TracyVkZone( m_device.getCurrentTracyCTX(), command_buffer, "Render game objects" ); - m_pipeline->bind( command_buffer ); - - m_pipeline->bindDescriptor( command_buffer, 0, info.global_descriptor_set ); - m_pipeline->bindDescriptor( command_buffer, 1, Texture::getTextureDescriptorSet() ); - - std::unordered_map< DrawKey, DrawPair > draw_pairs; - - std::uint64_t tri_counter { 0 }; - std::uint64_t object_counter { 0 }; - std::uint64_t primitive_counter { 0 }; - - for ( auto* node : info.in_view_leafs ) + ZoneScopedN( "Process leaf" ); + for ( const auto& obj : *node ) { - ZoneScopedN( "Process leaf" ); - for ( const auto& obj : *node ) + ZoneScopedN( "Process object" ); + if ( obj.m_model == nullptr ) continue; + + if ( !obj.m_is_visible ) continue; + + // debug::world::drawBoundingBox( obj.getBoundingBox() ); + + ++object_counter; + + for ( const auto& primitive : obj.m_model->m_primitives ) { - ZoneScopedN( "Process object" ); - if ( obj.m_model == nullptr ) continue; + ++primitive_counter; + tri_counter += ( primitive.m_index_buffer.size() / 3 ); - if ( !obj.m_is_visible ) continue; + const ModelMatrixInfo matrix_info { .model_matrix = obj.m_transform.mat4(), + .texture_idx = primitive.m_texture->getID() }; - // debug::world::drawBoundingBox( obj.getBoundingBox() ); + const auto key { + std::make_pair( primitive.m_texture->getID(), primitive.m_index_buffer.getOffset() ) + }; - ++object_counter; - - for ( const auto& primitive : obj.m_model->m_primitives ) + if ( auto itter = draw_pairs.find( key ); itter != draw_pairs.end() ) { - ++primitive_counter; - tri_counter += ( primitive.m_index_buffer.size() / 3 ); + //Draw command for this mesh already exists. Simply add a count to it + auto& [ itter_key, pair ] = *itter; + auto& [ existing_cmd, model_matrix ] = pair; - const ModelMatrixInfo matrix_info { .model_matrix = obj.m_transform.mat4(), - .texture_idx = primitive.m_texture->getID() }; + existing_cmd.instanceCount += 1; + model_matrix.emplace_back( matrix_info ); + assert( model_matrix.size() == existing_cmd.instanceCount ); + } + else + { + vk::DrawIndexedIndirectCommand cmd {}; - const auto key { - std::make_pair( primitive.m_texture->getID(), primitive.m_index_buffer.getOffset() ) - }; + cmd.firstIndex = primitive.m_index_buffer.getOffsetCount(); + cmd.indexCount = primitive.m_index_buffer.size(); - if ( auto itter = draw_pairs.find( key ); itter != draw_pairs.end() ) - { - //Draw command for this mesh already exists. Simply add a count to it - auto& [ itter_key, pair ] = *itter; - auto& [ existing_cmd, model_matrix ] = pair; + cmd.vertexOffset = static_cast< int32_t >( primitive.m_vertex_buffer.getOffsetCount() ); - existing_cmd.instanceCount += 1; - model_matrix.emplace_back( matrix_info ); - assert( model_matrix.size() == existing_cmd.instanceCount ); - } - else - { - vk::DrawIndexedIndirectCommand cmd {}; + cmd.instanceCount = 1; - cmd.firstIndex = primitive.m_index_buffer.getOffsetCount(); - cmd.indexCount = primitive.m_index_buffer.size(); - - cmd.vertexOffset = static_cast< int32_t >( primitive.m_vertex_buffer.getOffsetCount() ); - - cmd.instanceCount = 1; - - std::vector< ModelMatrixInfo > matrix_infos {}; - matrix_infos.reserve( 128 ); - matrix_infos.emplace_back( matrix_info ); - draw_pairs.emplace( key, std::make_pair( cmd, std::move( matrix_infos ) ) ); - } + std::vector< ModelMatrixInfo > matrix_infos {}; + matrix_infos.reserve( 128 ); + matrix_infos.emplace_back( matrix_info ); + draw_pairs.emplace( key, std::make_pair( cmd, std::move( matrix_infos ) ) ); } } } - -#if ENABLE_IMGUI - ImGui::Text( "Tris: %lu", tri_counter ); - ImGui::Text( "Models: %lu", object_counter ); - ImGui::Text( "Primitives: %lu", primitive_counter ); -#endif - - if ( draw_pairs.empty() ) - { - std::cout << "Nothing to draw!" << std::endl; - command_buffer.nextSubpass( vk::SubpassContents::eInline ); - return; - } - - std::vector< vk::DrawIndexedIndirectCommand > draw_commands {}; - std::vector< ModelMatrixInfo > model_matrices {}; - - draw_commands.reserve( draw_pairs.size() ); - model_matrices.reserve( draw_pairs.size() * 2 ); - - TracyCZoneN( filter_zone_TRACY, "Reorganize draw commands", true ); - for ( auto& [ key, pair ] : draw_pairs ) - { - auto cmd { pair.first }; - assert( cmd != vk::DrawIndexedIndirectCommand() ); - cmd.firstInstance = static_cast< std::uint32_t >( model_matrices.size() ); - - assert( cmd.instanceCount == pair.second.size() ); - - assert( pair.second.size() > 0 ); - - draw_commands.emplace_back( cmd ); - model_matrices.insert( model_matrices.end(), pair.second.begin(), pair.second.end() ); - } - - TracyCZoneEnd( filter_zone_TRACY ); - - //Setup model matrix info buffers - auto& model_matrix_info_buffer { m_model_matrix_info_buffers[ info.frame_idx ] }; - - model_matrix_info_buffer = - std::make_unique< ModelMatrixInfoBufferSuballocation >( info.model_matrix_info_buffer, model_matrices ); - - model_matrix_info_buffer->flush(); - - const auto& model_matricies_suballoc { model_matrix_info_buffer }; - - assert( model_matrix_info_buffer->size() == model_matrices.size() ); - - // Setup draw parameter buffer - TracyCZoneN( draw_zone_TRACY, "Submit draw data", true ); - auto& draw_parameter_buffer { m_draw_parameter_buffers[ info.frame_idx ] }; - - draw_parameter_buffer = - std::make_unique< DrawParameterBufferSuballocation >( info.draw_parameter_buffer, draw_commands ); - - const auto& draw_params { draw_parameter_buffer }; - assert( draw_params->size() == draw_commands.size() ); - assert( draw_params->stride() == sizeof( vk::DrawIndexedIndirectCommand ) ); - - TracyCZoneEnd( draw_zone_TRACY ); - - draw_parameter_buffer->flush(); - const std::vector< vk::Buffer > vertex_buffers { m_vertex_buffer->getVkBuffer(), - model_matricies_suballoc->getVkBuffer() }; - - command_buffer.bindVertexBuffers( 0, vertex_buffers, { 0, model_matricies_suballoc->getOffset() } ); - command_buffer.bindIndexBuffer( m_index_buffer->getVkBuffer(), 0, vk::IndexType::eUint32 ); - -#if ENABLE_IMGUI - ImGui::Text( "Indirect draws: %lu", static_cast< std::size_t >( draw_params->size() ) ); -#endif - - command_buffer.drawIndexedIndirect( - draw_params->getVkBuffer(), draw_params->getOffset(), draw_params->size(), draw_params->stride() ); - - command_buffer.nextSubpass( vk::SubpassContents::eInline ); } +#if ENABLE_IMGUI + ImGui::Text( "Tris: %lu", tri_counter ); + ImGui::Text( "Models: %lu", object_counter ); + ImGui::Text( "Primitives: %lu", primitive_counter ); +#endif + + if ( draw_pairs.empty() ) { - //Composition pass - TracyVkZone( info.tracy_ctx, command_buffer, "Composition pass" ); - m_composition_pipeline->bind( command_buffer ); - - m_composition_pipeline->bindDescriptor( command_buffer, 0, info.gbuffer_descriptor_set ); - - command_buffer.draw( 3, 1, 0, 0 ); + std::cout << "Nothing to draw!" << std::endl; + return; } + + std::vector< vk::DrawIndexedIndirectCommand > draw_commands {}; + std::vector< ModelMatrixInfo > model_matrices {}; + + draw_commands.reserve( draw_pairs.size() ); + model_matrices.reserve( draw_pairs.size() * 2 ); + + TracyCZoneN( filter_zone_TRACY, "Reorganize draw commands", true ); + for ( auto& [ key, pair ] : draw_pairs ) + { + auto cmd { pair.first }; + assert( cmd != vk::DrawIndexedIndirectCommand() ); + cmd.firstInstance = static_cast< std::uint32_t >( model_matrices.size() ); + + assert( cmd.instanceCount == pair.second.size() ); + + assert( pair.second.size() > 0 ); + + draw_commands.emplace_back( cmd ); + model_matrices.insert( model_matrices.end(), pair.second.begin(), pair.second.end() ); + } + + TracyCZoneEnd( filter_zone_TRACY ); + + //Setup model matrix info buffers + auto& model_matrix_info_buffer { m_model_matrix_info_buffers[ info.frame_idx ] }; + + model_matrix_info_buffer = + std::make_unique< ModelMatrixInfoBufferSuballocation >( info.model_matrix_info_buffer, model_matrices ); + + model_matrix_info_buffer->flush(); + + const auto& model_matricies_suballoc { model_matrix_info_buffer }; + + assert( model_matrix_info_buffer->size() == model_matrices.size() ); + + // Setup draw parameter buffer + TracyCZoneN( draw_zone_TRACY, "Submit draw data", true ); + auto& draw_parameter_buffer { m_draw_parameter_buffers[ info.frame_idx ] }; + + draw_parameter_buffer = + std::make_unique< DrawParameterBufferSuballocation >( info.draw_parameter_buffer, draw_commands ); + + const auto& draw_params { draw_parameter_buffer }; + assert( draw_params->size() == draw_commands.size() ); + assert( draw_params->stride() == sizeof( vk::DrawIndexedIndirectCommand ) ); + + TracyCZoneEnd( draw_zone_TRACY ); + + draw_parameter_buffer->flush(); + const std::vector< vk::Buffer > vertex_buffers { m_vertex_buffer->getVkBuffer(), + model_matricies_suballoc->getVkBuffer() }; + + command_buffer.bindVertexBuffers( 0, vertex_buffers, { 0, model_matricies_suballoc->getOffset() } ); + command_buffer.bindIndexBuffer( m_index_buffer->getVkBuffer(), 0, vk::IndexType::eUint32 ); + +#if ENABLE_IMGUI + ImGui::Text( "Indirect draws: %lu", static_cast< std::size_t >( draw_params->size() ) ); +#endif + + command_buffer.drawIndexedIndirect( + draw_params->getVkBuffer(), draw_params->getOffset(), draw_params->size(), draw_params->stride() ); } } // namespace fgl::engine diff --git a/src/engine/systems/EntityRendererSystem.hpp b/src/engine/systems/EntityRendererSystem.hpp index e818c72..85becd4 100644 --- a/src/engine/systems/EntityRendererSystem.hpp +++ b/src/engine/systems/EntityRendererSystem.hpp @@ -22,11 +22,15 @@ namespace fgl::engine { Device& m_device; - using Pipeline = PipelineT< GlobalDescriptorSet, TextureDescriptorSet >; - using CompositionPipeline = PipelineT< GBufferDescriptorSet >; + using VertexShader = VertexShaderT< "shaders/gbuffer.vert.spv" >; + using FragmentShader = FragmentShaderT< "shaders/gbuffer.frag.spv" >; + using Shaders = ShaderCollection< VertexShader, FragmentShader >; + + using DescriptorSets = DescriptorSetCollection< GlobalDescriptorSet, TextureDescriptorSet >; + + using Pipeline = PipelineT< Shaders, DescriptorSets >; std::unique_ptr< Pipeline > m_pipeline {}; - std::unique_ptr< CompositionPipeline > m_composition_pipeline {}; std::unique_ptr< Buffer > m_vertex_buffer { nullptr }; std::unique_ptr< Buffer > m_index_buffer { nullptr }; @@ -57,6 +61,8 @@ namespace fgl::engine vk::MemoryPropertyFlagBits::eDeviceLocal ); } + vk::CommandBuffer& setupSystem( FrameInfo& ); + public: Buffer& getVertexBuffer() { return *m_vertex_buffer; } @@ -66,7 +72,7 @@ namespace fgl::engine void pass( FrameInfo& info ); EntityRendererSystem( Device& device, VkRenderPass render_pass ); - ~EntityRendererSystem(); + ~EntityRendererSystem() = default; EntityRendererSystem( EntityRendererSystem&& other ) = delete; EntityRendererSystem( const EntityRendererSystem& other ) = delete; EntityRendererSystem& operator=( const EntityRendererSystem& other ) = delete; diff --git a/src/engine/systems/concepts.hpp b/src/engine/systems/concepts.hpp index b0a5d25..4acbff4 100644 --- a/src/engine/systems/concepts.hpp +++ b/src/engine/systems/concepts.hpp @@ -5,6 +5,11 @@ #ifndef GAME_CONCEPTS_HPP #define GAME_CONCEPTS_HPP +namespace vk +{ + class CommandBuffer; +} + namespace fgl::engine { @@ -26,6 +31,9 @@ namespace fgl::engine { t.wait() }; + { + t.setupSystem( info ) + } -> std::same_as< vk::CommandBuffer& >; }; } // namespace fgl::engine