From 32953416a2dea17897496a7316157d3962d0901a Mon Sep 17 00:00:00 2001 From: kj16609 Date: Sun, 6 Apr 2025 11:30:09 -0400 Subject: [PATCH] Get GPU driven rendering mostly working --- dependencies/slang | 2 +- src/editor/src/components/ModelComponent.cpp | 17 +- .../src/components/TransformComponent.cpp | 31 ++++ src/editor/src/gui/FileBrowser.cpp | 4 + src/editor/src/gui/FileBrowser.hpp | 1 + src/editor/src/gui/core.cpp | 4 + src/editor/src/gui/preview.cpp | 19 +-- src/editor/src/main.cpp | 8 +- src/engine/EngineContext.cpp | 58 +++++-- src/engine/EngineContext.hpp | 21 ++- src/engine/FrameInfo.cpp | 4 +- src/engine/FrameInfo.hpp | 24 ++- src/engine/assets/AssetManager.hpp | 2 +- src/engine/assets/MaterialManager.cpp | 1 + src/engine/assets/MaterialManager.hpp | 2 +- src/engine/assets/image/Image.cpp | 4 +- src/engine/assets/image/Image.hpp | 3 +- src/engine/assets/image/ImageView.cpp | 5 + src/engine/assets/image/ImageView.hpp | 6 +- src/engine/assets/image/Sampler.hpp | 2 +- src/engine/assets/material/Material.hpp | 17 +- src/engine/assets/model/InstanceManager.cpp | 25 --- src/engine/assets/model/InstanceManager.hpp | 31 ---- src/engine/assets/model/Model.cpp | 156 +++++++++--------- src/engine/assets/model/Model.hpp | 133 ++++++++++----- src/engine/assets/model/ModelInstance.hpp | 32 ++-- src/engine/assets/model/ModelInstanceInfo.hpp | 17 ++ src/engine/assets/model/ModelManager.cpp | 10 -- src/engine/assets/model/ModelManager.hpp | 24 --- src/engine/assets/model/ModelVertex.cpp | 6 +- src/engine/assets/model/Primitive.cpp | 34 +++- src/engine/assets/model/Primitive.hpp | 42 ++++- .../assets/model/builders/ModelBuilder.cpp | 1 + .../assets/model/builders/SceneBuilder.cpp | 10 +- src/engine/assets/texture/Texture.cpp | 56 +++++-- src/engine/assets/texture/Texture.hpp | 23 +-- src/engine/camera/Camera.cpp | 9 +- src/engine/camera/Camera.hpp | 6 +- src/engine/camera/GBufferRenderer.cpp | 15 +- src/engine/descriptors/DescriptorSet.cpp | 23 ++- src/engine/descriptors/DescriptorSet.hpp | 16 +- .../descriptors/DescriptorSetLayout.hpp | 3 +- .../components/CameraComponent.hpp | 1 + .../gameobjects/components/ModelComponent.cpp | 17 -- .../gameobjects/components/ModelComponent.hpp | 20 ++- .../components/TransformComponent.hpp | 11 +- src/engine/memory/buffers/Buffer.cpp | 19 +-- .../buffers/BufferSuballocationHandle.cpp | 2 +- src/engine/memory/buffers/align.hpp | 54 +++++- .../memory/buffers/vector/BufferVector.cpp | 51 +++++- .../memory/buffers/vector/BufferVector.hpp | 1 + .../memory/buffers/vector/DeviceVector.hpp | 14 +- .../memory/buffers/vector/HostVector.hpp | 3 - .../memory/buffers/vector/IndexedVector.hpp | 79 +++++++-- src/engine/rendering/PresentSwapChain.hpp | 10 +- src/engine/rendering/pipelines/Attachment.hpp | 4 +- src/engine/rendering/pipelines/Shader.hpp | 5 + .../rendering/pipelines/shaders/Compiler.cpp | 23 ++- .../rendering/pipelines/v2/Pipeline.cpp | 10 +- .../rendering/pipelines/v2/Pipeline.hpp | 4 + .../pipelines/v2/PipelineBuilder.cpp | 44 ++++- .../pipelines/v2/PipelineBuilder.hpp | 16 ++ src/engine/scene/World.cpp | 2 + src/engine/scene/World.hpp | 2 + .../systems/prerender/CullingSystem.cpp | 88 ++++++---- .../systems/prerender/CullingSystem.hpp | 24 +-- .../systems/render/EntityRendererSystem.cpp | 32 ++-- .../systems/render/EntityRendererSystem.hpp | 5 +- src/engine/systems/render/LineDrawer.cpp | 3 +- src/engine/systems/render/ShadowRenderer.cpp | 2 +- src/shaders/culling.slang | 87 +++++----- src/shaders/objects/gamemodel.slang | 24 ++- src/shaders/textured.slang | 3 +- 73 files changed, 1007 insertions(+), 560 deletions(-) create mode 100644 src/editor/src/components/TransformComponent.cpp delete mode 100644 src/engine/assets/model/InstanceManager.cpp delete mode 100644 src/engine/assets/model/InstanceManager.hpp create mode 100644 src/engine/assets/model/ModelInstanceInfo.hpp delete mode 100644 src/engine/assets/model/ModelManager.cpp delete mode 100644 src/engine/assets/model/ModelManager.hpp delete mode 100644 src/engine/gameobjects/components/ModelComponent.cpp diff --git a/dependencies/slang b/dependencies/slang index a70113c..680fb0b 160000 --- a/dependencies/slang +++ b/dependencies/slang @@ -1 +1 @@ -Subproject commit a70113c425cbd5bba2e83e04e521fb594143cb9e +Subproject commit 680fb0b4e9cbb65d46677183a3f68630be1f6179 diff --git a/src/editor/src/components/ModelComponent.cpp b/src/editor/src/components/ModelComponent.cpp index aca8246..8279c81 100644 --- a/src/editor/src/components/ModelComponent.cpp +++ b/src/editor/src/components/ModelComponent.cpp @@ -10,11 +10,17 @@ namespace fgl::engine::components { + ModelComponent::ModelComponent( const std::shared_ptr< Model >& model ) : + m_model_instance( model->createInstance() ), + m_transform() + {} + void ModelComponent::drawImGui() { // drawComponentTransform( m_transform ); // TODO: If the model is not set then we should be able to set it to one from the file selection + /* if ( this->m_model == nullptr ) { ImGui::Text( "Undefined model" ); @@ -24,13 +30,14 @@ namespace fgl::engine::components const auto& model { *this->m_model }; ImGui::Text( "%li primitives", model.m_primitives.size() ); + */ } std::string_view ModelComponent::humanName() const { - if ( !m_model ) return "Empty"; - - return m_model->getName(); + if ( !m_model_instance ) return "Empty"; + return "TODO"; + // return m_model_instance->getModel()->getName(); } std::string_view ModelComponent::className() const @@ -38,6 +45,7 @@ namespace fgl::engine::components return "ModelComponent"; } + /* Model* ModelComponent::operator->() { return m_model.get(); @@ -47,4 +55,5 @@ namespace fgl::engine::components { return m_model.get(); } -} // namespace fgl::engine + */ +} // namespace fgl::engine::components diff --git a/src/editor/src/components/TransformComponent.cpp b/src/editor/src/components/TransformComponent.cpp new file mode 100644 index 0000000..f1fea9e --- /dev/null +++ b/src/editor/src/components/TransformComponent.cpp @@ -0,0 +1,31 @@ +// +// Created by kj16609 on 4/5/25. +// +#include "engine/gameobjects/components/TransformComponent.hpp" + +#include "engine/assets/model/Model.hpp" +#include "gui/safe_include.hpp" + +namespace fgl::engine::components +{ + TransformComponent::TransformComponent( const WorldTransform& transform ) : m_transform( transform ) + {} + + void TransformComponent::drawImGui() + {} + + std::string_view TransformComponent::humanName() const + { + return "Transform"; + } + + std::string_view TransformComponent::className() const + { + return "TransformComponent"; + } + + WorldTransform& TransformComponent::operator*() + { + return m_transform; + } +} // namespace fgl::engine::components \ No newline at end of file diff --git a/src/editor/src/gui/FileBrowser.cpp b/src/editor/src/gui/FileBrowser.cpp index 214fe17..592c864 100644 --- a/src/editor/src/gui/FileBrowser.cpp +++ b/src/editor/src/gui/FileBrowser.cpp @@ -218,6 +218,10 @@ namespace fgl::engine::filesystem void FileBrowser::openFolder( const DirInfo& dir ) { + m_old_textures.push( m_file_textures ); + + if ( m_old_textures.size() > constants::MAX_FRAMES_IN_FLIGHT ) m_old_textures.pop(); + m_file_textures.clear(); m_current_dir = std::make_unique< DirInfo >( dir.m_path ); } diff --git a/src/editor/src/gui/FileBrowser.hpp b/src/editor/src/gui/FileBrowser.hpp index c8a228b..7394019 100644 --- a/src/editor/src/gui/FileBrowser.hpp +++ b/src/editor/src/gui/FileBrowser.hpp @@ -21,6 +21,7 @@ namespace fgl::engine::filesystem struct FileBrowser { std::unordered_map< std::filesystem::path, std::shared_ptr< Texture > > m_file_textures {}; + std::queue< std::unordered_map< std::filesystem::path, std::shared_ptr< Texture > > > m_old_textures; std::unique_ptr< DirInfo > m_current_dir { nullptr }; diff --git a/src/editor/src/gui/core.cpp b/src/editor/src/gui/core.cpp index 9642d6c..45a82e7 100644 --- a/src/editor/src/gui/core.cpp +++ b/src/editor/src/gui/core.cpp @@ -99,6 +99,7 @@ namespace fgl::engine::gui void itterateGameObjectNode( FrameInfo& info, OctTreeNode& node ) { + /* if ( node.isLeaf() ) { if ( node.itemCount() == 0 ) return; @@ -143,6 +144,7 @@ namespace fgl::engine::gui } } } + */ } void drawEntityGUI( FrameInfo& info ) @@ -152,6 +154,7 @@ namespace fgl::engine::gui // itterateGameObjectNode( info, info.game_objects ); + /* for ( OctTreeNodeLeaf* leaf : info.game_objects.getAllLeafs() ) { for ( GameObject& entity : *leaf ) @@ -166,6 +169,7 @@ namespace fgl::engine::gui ImGui::PopID(); } } + */ ImGui::End(); } diff --git a/src/editor/src/gui/preview.cpp b/src/editor/src/gui/preview.cpp index ba551db..d1e6cab 100644 --- a/src/editor/src/gui/preview.cpp +++ b/src/editor/src/gui/preview.cpp @@ -44,27 +44,24 @@ namespace fgl::engine::gui // Load model and drop it into the game objects GameObject obj { GameObject::createGameObject() }; - std::shared_ptr< Model > model { - Model:: - createModel( data->m_path, info.model_vertex_buffer, info.model_index_buffer ) - }; + std::shared_ptr< Model > model { Model::createModel( data->m_path ) }; obj.addFlag( IsEntity | IsVisible ); - info.context.models() - .loadModel( data->m_path, info.model_vertex_buffer, info.model_index_buffer ); + // info.context.models().loadModel( data->m_path ); - auto component { std::make_unique< components::ModelComponent >( std::move( model ) ) }; + auto component { std::make_unique< components::ModelComponent >( model ) }; obj.addComponent( std::move( component ) ); - info.game_objects.addGameObject( std::move( obj ) ); + info.game_objects.emplace_back( std::move( obj ) ); break; } case filesystem::SCENE: { - SceneBuilder builder { info.model_vertex_buffer, info.model_index_buffer }; + auto& buffers { getModelBuffers() }; + SceneBuilder builder { buffers.m_vertex_buffer, buffers.m_index_buffer }; builder.loadScene( data->m_path ); @@ -72,7 +69,7 @@ namespace fgl::engine::gui for ( auto& obj : objs ) { - info.game_objects.addGameObject( std::move( obj ) ); + info.game_objects.emplace_back( std::move( obj ) ); } } } @@ -173,7 +170,7 @@ namespace fgl::engine::gui void drawRenderingOutputs( FrameInfo& info, const Camera& camera ) { ZoneScoped; - const auto frame_index { info.frame_idx }; + const auto frame_index { info.in_flight_idx }; static std::uint_fast8_t current { Composite }; diff --git a/src/editor/src/main.cpp b/src/editor/src/main.cpp index 4de2634..18a32c3 100644 --- a/src/editor/src/main.cpp +++ b/src/editor/src/main.cpp @@ -63,7 +63,7 @@ int main() editor_camera->setFOV( glm::radians( 90.0f ) ); // Create a default world to assign to the engine before we load or create a new one. - World world {}; + // World world {}; constexpr bool playing { false }; @@ -74,9 +74,9 @@ int main() engine_ctx.tickDeltaTime(); - engine_ctx.setWorld( world ); + // engine_ctx.setWorld( world ); - if ( playing ) world = engine_ctx.tickSimulation(); + // if ( playing ) world = engine_ctx.tickSimulation(); engine_ctx.handleTransfers(); @@ -86,7 +86,7 @@ int main() // Here we can decide if we want to tick fully or not. // Simulate step - engine_ctx.tickSimulation(); + // engine_ctx.tickSimulation(); // Update the viewer camera diff --git a/src/engine/EngineContext.cpp b/src/engine/EngineContext.cpp index f3b2cae..eae0ad6 100644 --- a/src/engine/EngineContext.cpp +++ b/src/engine/EngineContext.cpp @@ -26,16 +26,39 @@ namespace fgl::engine constexpr float MAX_DELTA_TIME { 0.5 }; inline static EngineContext* instance { nullptr }; + PerFrameArray< std::unique_ptr< descriptors::DescriptorSet > > createDrawCommandsDescriptors( + PerFrameArray< DeviceVector< vk::DrawIndexedIndirectCommand > >& gpu_draw_commands, + PerFrameArray< DeviceVector< PerVertexInstanceInfo > >& per_vertex_info ) + { + PerFrameArray< std::unique_ptr< descriptors::DescriptorSet > > descriptors {}; + + for ( std::uint16_t i = 0; i < gpu_draw_commands.size(); ++i ) + { + auto& command_buffer { gpu_draw_commands[ i ] }; + auto& per_vertex_buffer { per_vertex_info[ i ] }; + auto descriptor { COMMANDS_SET.create() }; + + descriptor->bindStorageBuffer( 0, command_buffer ); + descriptor->bindStorageBuffer( 1, per_vertex_buffer ); + descriptor->update(); + descriptor->setName( "Command Buffer + Vertex Buffer" ); + + descriptors[ i ] = std::move( descriptor ); + } + + return descriptors; + } + EngineContext::EngineContext() : m_ubo_buffer_pool( 1_MiB, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostVisible ), - m_matrix_info_pool( - 256_MiB, - vk::BufferUsageFlagBits::eVertexBuffer, - vk::MemoryPropertyFlagBits::eDeviceLocal | vk::MemoryPropertyFlagBits::eHostVisible ), m_draw_parameter_pool( 128_MiB, - vk::BufferUsageFlagBits::eIndirectBuffer, + vk::BufferUsageFlagBits::eIndirectBuffer | vk::BufferUsageFlagBits::eStorageBuffer, vk::MemoryPropertyFlagBits::eDeviceLocal | vk::MemoryPropertyFlagBits::eHostVisible ), + m_gpu_draw_commands( + constructPerFrame< DeviceVector< vk::DrawIndexedIndirectCommand > >( m_draw_parameter_pool ) ), + m_per_vertex_infos( m_model_buffers.m_generated_instance_info ), + m_gpu_draw_cmds_desc( createDrawCommandsDescriptors( m_gpu_draw_commands, m_per_vertex_infos ) ), m_delta_time( 0.0 ) { ZoneScoped; @@ -45,7 +68,6 @@ namespace fgl::engine // memory::TransferManager::createInstance( device, 128_MiB ); - m_matrix_info_pool.setDebugName( "Matrix info pool" ); m_draw_parameter_pool.setDebugName( "Draw parameter pool" ); } @@ -69,6 +91,7 @@ namespace fgl::engine m_delta_time = time_diff.count(); } + /* World EngineContext::tickSimulation() { ZoneScoped; @@ -80,6 +103,7 @@ namespace fgl::engine return {}; } + */ void EngineContext::renderCameras( FrameInfo frame_info ) { @@ -103,23 +127,29 @@ namespace fgl::engine if ( auto command_buffers_o = m_renderer.beginFrame(); command_buffers_o.has_value() ) { const auto timer = debug::timing::push( "Render Frame" ); - const FrameIndex frame_index { m_renderer.getFrameIndex() }; + const FrameIndex in_flight_idx { m_renderer.getFrameIndex() }; const PresentIndex present_idx { m_renderer.getPresentIndex() }; auto& command_buffers { command_buffers_o.value() }; - FrameInfo frame_info { frame_index, + // Begin by getting every single instance ready. + DeviceVector< PrimitiveInstanceInfo >& instances { m_model_buffers.m_primitive_instances.vec() }; + + m_gpu_draw_commands[ in_flight_idx ].resize( instances.size() ); + m_model_buffers.m_generated_instance_info[ in_flight_idx ].resize( instances.size() ); + + FrameInfo frame_info { in_flight_idx, present_idx, m_delta_time, command_buffers, nullptr, // Camera m_camera_manager.getCameras(), - // global_descriptor_sets[ frame_index ], - m_model_manager, m_renderer.getCurrentTracyCTX(), - m_matrix_info_pool, - m_draw_parameter_pool, - // m_renderer.getSwapChain().getInputDescriptor( present_idx ), + *m_model_buffers.m_primitives_desc, + *m_model_buffers.m_instances_desc, + *m_gpu_draw_cmds_desc[ in_flight_idx ], + m_gpu_draw_commands[ in_flight_idx ], + game_objects, this->m_renderer.getSwapChain() }; { @@ -197,7 +227,7 @@ namespace fgl::engine log::info( "Destroying EngineContext" ); // Destroy all objects - m_game_objects_root.clear(); + // m_game_objects_root.clear(); descriptors::deleteQueuedDescriptors(); diff --git a/src/engine/EngineContext.hpp b/src/engine/EngineContext.hpp index d8b480b..5211efb 100644 --- a/src/engine/EngineContext.hpp +++ b/src/engine/EngineContext.hpp @@ -6,6 +6,7 @@ #include "Window.hpp" #include "assets/MaterialManager.hpp" +#include "assets/model/Model.hpp" #include "camera/CameraManager.hpp" #include "clock.hpp" #include "engine/assets/transfer/TransferManager.hpp" @@ -43,8 +44,6 @@ namespace fgl::engine Renderer m_renderer { m_window, m_device.phyDevice() }; - ModelManager m_model_manager {}; - // GameObject::Map game_objects {}; // OctTreeNode m_game_objects_root { WorldCoordinate( constants::WORLD_CENTER ) }; @@ -69,9 +68,21 @@ namespace fgl::engine memory::Buffer m_ubo_buffer_pool; // Memory pool for matrix info and draw parameters - memory::Buffer m_matrix_info_pool; memory::Buffer m_draw_parameter_pool; + std::vector< GameObject > game_objects {}; + + public: + + ModelGPUBuffers m_model_buffers {}; + + private: + + PerFrameArray< DeviceVector< vk::DrawIndexedIndirectCommand > > m_gpu_draw_commands; + //TODO: Outright remove this. Or the one in model buffers. + PerFrameArray< DeviceVector< PerVertexInstanceInfo > >& m_per_vertex_infos; + PerFrameArray< std::unique_ptr< descriptors::DescriptorSet > > m_gpu_draw_cmds_desc; + MaterialManager m_material_manager {}; CameraManager m_camera_manager {}; @@ -81,11 +92,11 @@ namespace fgl::engine std::chrono::time_point< Clock > m_last_tick { Clock::now() }; DeltaTime m_delta_time; - World m_world; + // World m_world; public: - ModelManager& models() { return m_model_manager; } + // ModelManager& models() { return m_model_manager; } FGL_FORCE_INLINE_FLATTEN void hookInitImGui( const std::function< void( Window&, Renderer& ) >& func ) { diff --git a/src/engine/FrameInfo.cpp b/src/engine/FrameInfo.cpp index a154adf..705e5be 100644 --- a/src/engine/FrameInfo.cpp +++ b/src/engine/FrameInfo.cpp @@ -12,12 +12,12 @@ namespace fgl::engine descriptors::DescriptorSet& FrameInfo::getGBufferDescriptor() const { - return camera->getSwapchain().getGBufferDescriptor( frame_idx ); + return camera->getSwapchain().getGBufferDescriptor( in_flight_idx ); } descriptors::DescriptorSet& FrameInfo::getCameraDescriptor() const { - return camera->getDescriptor( frame_idx ); + return camera->getDescriptor( in_flight_idx ); } void FrameInfo::bindCamera( [[maybe_unused]] Pipeline& pipeline ) diff --git a/src/engine/FrameInfo.hpp b/src/engine/FrameInfo.hpp index 2f6f352..5a79450 100644 --- a/src/engine/FrameInfo.hpp +++ b/src/engine/FrameInfo.hpp @@ -11,6 +11,8 @@ #include "descriptors/Descriptor.hpp" #include "descriptors/DescriptorSetLayout.hpp" +#include "gameobjects/GameObject.hpp" +#include "memory/buffers/vector/DeviceVector.hpp" #include "primitives/Frustum.hpp" #include "rendering/CommandBuffers.hpp" #include "rendering/types.hpp" @@ -19,8 +21,9 @@ namespace fgl::engine { + struct PrimitiveRenderInfo; + struct PrimitiveInstanceInfo; class Pipeline; - class GameObject; namespace descriptors { @@ -72,7 +75,7 @@ namespace fgl::engine struct FrameInfo { - FrameIndex frame_idx; + FrameIndex in_flight_idx; PresentIndex present_idx; DeltaTime delta_time; @@ -86,19 +89,22 @@ namespace fgl::engine // OctTreeNode& game_objects; TracyVkCtx tracy_ctx; - //Buffers - memory::Buffer& model_matrix_info_buffer; - memory::Buffer& draw_parameter_buffer; + descriptors::DescriptorSet& m_primitives_desc; + descriptors::DescriptorSet& m_instances_desc; + descriptors::DescriptorSet& m_command_buffer_desc; + // out for rendering process + + //! Populated commands buffer by the culling pass + DeviceVector< vk::DrawIndexedIndirectCommand >& m_commands; + std::vector< GameObject >& game_objects; // descriptors::DescriptorSet& gui_input_descriptor; - descriptors::DescriptorSet& getGBufferDescriptor() const; - descriptors::DescriptorSet& getCameraDescriptor() const; + [[nodiscard]] descriptors::DescriptorSet& getGBufferDescriptor() const; + [[nodiscard]] descriptors::DescriptorSet& getCameraDescriptor() const; PresentSwapChain& swap_chain; - std::vector< std::vector< GameObject >* > in_view_leafs {}; - //! Binds the camera descriptor to the command buffer void bindCamera( Pipeline& pipeline ); }; diff --git a/src/engine/assets/AssetManager.hpp b/src/engine/assets/AssetManager.hpp index b0c771d..2b7fc27 100644 --- a/src/engine/assets/AssetManager.hpp +++ b/src/engine/assets/AssetManager.hpp @@ -32,7 +32,7 @@ namespace fgl::engine template < typename T, typename... TArgs > concept can_extract_key = requires( TArgs&&... args ) { { - T::extractKey( args... ) + T::extractKey( std::declval< std::remove_reference_t< TArgs > >()... ) } -> std::same_as< typename T::UIDKeyT >; }; diff --git a/src/engine/assets/MaterialManager.cpp b/src/engine/assets/MaterialManager.cpp index 3127e5f..6b8af75 100644 --- a/src/engine/assets/MaterialManager.cpp +++ b/src/engine/assets/MaterialManager.cpp @@ -3,6 +3,7 @@ // #include "MaterialManager.hpp" +#include "engine/debug/logging/logging.hpp" #include "engine/math/literals/size.hpp" #include "material/Material.hpp" diff --git a/src/engine/assets/MaterialManager.hpp b/src/engine/assets/MaterialManager.hpp index 6fc2b79..342aa56 100644 --- a/src/engine/assets/MaterialManager.hpp +++ b/src/engine/assets/MaterialManager.hpp @@ -4,11 +4,11 @@ #pragma once #include "engine/memory/buffers/Buffer.hpp" +#include "material/Material.hpp" #include "memory/buffers/vector/DeviceVector.hpp" namespace fgl::engine { - struct DeviceMaterialData; class MaterialManager { diff --git a/src/engine/assets/image/Image.cpp b/src/engine/assets/image/Image.cpp index 2d7576e..2323188 100644 --- a/src/engine/assets/image/Image.cpp +++ b/src/engine/assets/image/Image.cpp @@ -9,14 +9,14 @@ namespace fgl::engine { - std::shared_ptr< ImageView > Image::getView() + std::shared_ptr< ImageView > Image::getView( Sampler sampler ) { if ( !m_view.expired() ) return m_view.lock(); else { assert( m_handle ); - auto ptr { std::make_shared< ImageView >( m_handle ) }; + auto ptr { std::make_shared< ImageView >( m_handle, std::move( sampler ) ) }; m_view = ptr; return ptr; } diff --git a/src/engine/assets/image/Image.hpp b/src/engine/assets/image/Image.hpp index 1cf4032..abcf57d 100644 --- a/src/engine/assets/image/Image.hpp +++ b/src/engine/assets/image/Image.hpp @@ -9,6 +9,7 @@ #include #include "FGL_DEFINES.hpp" +#include "Sampler.hpp" #include "debug/Track.hpp" namespace fgl::engine @@ -59,7 +60,7 @@ namespace fgl::engine [[nodiscard]] const vk::Extent2D& getExtent() const { return m_extent; } - [[nodiscard]] std::shared_ptr< ImageView > getView(); + [[nodiscard]] std::shared_ptr< ImageView > getView( Sampler sampler = {}); [[nodiscard]] vk::ImageMemoryBarrier transitionTo( vk::ImageLayout old_layout, vk::ImageLayout new_layout, const vk::ImageSubresourceRange& range ) const; diff --git a/src/engine/assets/image/ImageView.cpp b/src/engine/assets/image/ImageView.cpp index 41668ef..e0d2972 100644 --- a/src/engine/assets/image/ImageView.cpp +++ b/src/engine/assets/image/ImageView.cpp @@ -35,6 +35,11 @@ namespace fgl::engine m_descriptor_info.imageView = m_image_view; } + ImageView::ImageView( const std::shared_ptr< ImageHandle >& img, Sampler&& sampler ) : ImageView( img ) + { + m_sampler = std::move( sampler ); + } + vk::DescriptorImageInfo ImageView::descriptorInfo( const vk::Sampler sampler, const vk::ImageLayout layout ) const { vk::DescriptorImageInfo info { descriptorInfo( layout ) }; diff --git a/src/engine/assets/image/ImageView.hpp b/src/engine/assets/image/ImageView.hpp index 7e11305..7108681 100644 --- a/src/engine/assets/image/ImageView.hpp +++ b/src/engine/assets/image/ImageView.hpp @@ -33,6 +33,7 @@ namespace fgl::engine ImageView() = delete; explicit ImageView( const std::shared_ptr< ImageHandle >& img ); + explicit ImageView( const std::shared_ptr< ImageHandle >& img, Sampler&& sampler ); ImageView( const ImageView& ) = delete; ImageView& operator=( const ImageView& ) = delete; @@ -48,9 +49,8 @@ namespace fgl::engine [[nodiscard]] VkImage getVkImage() const { return m_resource->getVkImage(); } - void setSampler( Sampler&& sampler ) { m_sampler = std::forward< Sampler >( sampler ); } - - [[nodiscard]] Sampler& getSampler() { return m_sampler; }; + // void setSampler( Sampler&& sampler ) { m_sampler = std::forward< Sampler >( sampler ); } + [[nodiscard]] const Sampler& getSampler() const { return m_sampler; }; [[nodiscard]] vk::DescriptorImageInfo descriptorInfo( vk::Sampler sampler, vk::ImageLayout layout ) const; [[nodiscard]] vk::DescriptorImageInfo descriptorInfo( vk::ImageLayout layout ) const; diff --git a/src/engine/assets/image/Sampler.hpp b/src/engine/assets/image/Sampler.hpp index a795312..b5e7956 100644 --- a/src/engine/assets/image/Sampler.hpp +++ b/src/engine/assets/image/Sampler.hpp @@ -64,7 +64,7 @@ namespace fgl::engine ~Sampler() {} - vk::raii::Sampler& getVkSampler() { return m_sampler; } + const vk::raii::Sampler& getVkSampler() const { return m_sampler; } void setName( const std::string& str ) const; }; diff --git a/src/engine/assets/material/Material.hpp b/src/engine/assets/material/Material.hpp index 5ee0971..6d73d73 100644 --- a/src/engine/assets/material/Material.hpp +++ b/src/engine/assets/material/Material.hpp @@ -10,13 +10,14 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Weffc++" +#include "glm/vec3.hpp" +#include "glm/vec4.hpp" +#pragma GCC diagnostic pop + #include "engine/constants.hpp" #include "engine/descriptors/Descriptor.hpp" #include "engine/descriptors/DescriptorSetLayout.hpp" #include "engine/memory/buffers/vector/DeviceVector.hpp" -#include "glm/vec3.hpp" -#include "glm/vec4.hpp" -#pragma GCC diagnostic pop namespace fgl::engine { @@ -84,7 +85,7 @@ namespace fgl::engine struct Albedo { TextureID color_texture_id { constants::INVALID_TEXTURE_ID }; - PAD(1, 12); + PAD( 1, 12 ); glm::vec4 color_factors {}; } color; @@ -94,21 +95,21 @@ namespace fgl::engine TextureID metallic_texture_id { constants::INVALID_TEXTURE_ID }; float metallic_factor { 0.0f }; float roughness_factor { 0.0f }; - PAD(1, 4); + PAD( 1, 4 ); } metallic; struct Normal { TextureID normal_texture_id { constants::INVALID_TEXTURE_ID }; float normal_tex_scale { 0.0f }; - PAD(1,8); + PAD( 1, 8 ); } normal; struct Occlusion { TextureID occlusion_texture_id { constants::INVALID_TEXTURE_ID }; float occlusion_tex_strength { 0.0f }; - PAD(1,8); + PAD( 1, 8 ); } occlusion; struct Emissive @@ -116,6 +117,8 @@ namespace fgl::engine TextureID emissive_texture_id { constants::INVALID_TEXTURE_ID }; glm::vec3 emissive_factors { 0.0f, 0.0f, 0.0f }; } emissive; + + DeviceMaterialData() = default; }; /* diff --git a/src/engine/assets/model/InstanceManager.cpp b/src/engine/assets/model/InstanceManager.cpp deleted file mode 100644 index 3355515..0000000 --- a/src/engine/assets/model/InstanceManager.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// -// Created by kj16609 on 3/17/25. -// - -#include "InstanceManager.hpp" - -namespace fgl::engine -{ - using namespace fgl::literals::size_literals; - - inline InstanceArray createInstances( memory::Buffer& buffer ) - { - InstanceArray instances {}; - - std::ranges::generate( instances, [ & ]() -> InstanceVector { return InstanceVector( buffer, 0 ); } ); - - return instances; - } - - inline InstanceManager::InstanceManager() : - m_buffer( 128_MiB, vk::BufferUsageFlagBits::eStorageBuffer, vk::MemoryPropertyFlagBits::eDeviceLocal ), - m_instances( createInstances( m_buffer ) ) - {} - -} // namespace fgl::engine \ No newline at end of file diff --git a/src/engine/assets/model/InstanceManager.hpp b/src/engine/assets/model/InstanceManager.hpp deleted file mode 100644 index 6f10b8b..0000000 --- a/src/engine/assets/model/InstanceManager.hpp +++ /dev/null @@ -1,31 +0,0 @@ -// -// Created by kj16609 on 3/17/25. -// -#pragma once -#include "memory/buffers/Buffer.hpp" -#include "memory/buffers/vector/DeviceVector.hpp" -#include "rendering/PresentSwapChain.hpp" - -namespace fgl::engine -{ - struct ModelGPUInstance; - - using InstanceVector = DeviceVector< ModelGPUInstance >; - using InstanceArray = PerFrameArray< InstanceVector >; - - class InstanceManager - { - //! Buffer for each instance to use - memory::Buffer m_buffer; - - InstanceArray m_instances; - - public: - - //! Constructor to initialize m_buffer and m_instances - [[nodiscard]] InstanceManager(); - - ~InstanceManager() = default; - }; - -} // namespace fgl::engine \ No newline at end of file diff --git a/src/engine/assets/model/Model.cpp b/src/engine/assets/model/Model.cpp index eb8f2ce..a1a1437 100644 --- a/src/engine/assets/model/Model.cpp +++ b/src/engine/assets/model/Model.cpp @@ -6,39 +6,53 @@ #include +#include "EngineContext.hpp" +#include "ModelInstance.hpp" #include "builders/ModelBuilder.hpp" #include "builders/SceneBuilder.hpp" -#include "engine/assets/image/ImageView.hpp" namespace fgl::engine { + using namespace fgl::literals::size_literals; - std::vector< vk::DrawIndexedIndirectCommand > Model::buildParameters( const std::vector< Primitive >& primitives ) + ModelGPUBuffers& getModelBuffers() { - ZoneScoped; - std::vector< vk::DrawIndexedIndirectCommand > draw_parameters {}; - draw_parameters.reserve( primitives.size() ); + return EngineContext::getInstance().m_model_buffers; + } - //TODO: Perhaps building the parameter list using the model instead of keeping a list already here would be better in order to reduce allocations + ModelGPUBuffers::ModelGPUBuffers() : + m_long_buffer( + 32_MiB, + vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eTransferDst, + vk::MemoryPropertyFlagBits::eDeviceLocal ), + m_short_buffer( + 16_MiB, + vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eTransferDst, + vk::MemoryPropertyFlagBits::eDeviceLocal | vk::MemoryPropertyFlagBits::eHostVisible ), + m_vertex_buffer( + 256_MiB, + vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eStorageBuffer + | vk::BufferUsageFlagBits::eTransferDst, + vk::MemoryPropertyFlagBits::eDeviceLocal ), + m_index_buffer( + 1_GiB, + vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eTransferDst, + vk::MemoryPropertyFlagBits::eDeviceLocal ), + m_primitive_info( m_long_buffer ), + m_primitive_instances( m_short_buffer ), + m_model_instances( m_short_buffer ), + m_generated_instance_info( constructPerFrame< DeviceVector< PerVertexInstanceInfo > >( m_vertex_buffer ) ) + { + m_primitives_desc = PRIMITIVE_SET.create(); + m_primitives_desc->bindStorageBuffer( 0, m_primitive_info ); + m_primitives_desc->update(); + m_primitives_desc->setName( "Primitives" ); - for ( const auto& primitive : primitives ) - { - // Skip drawing this primitive if draw flag is not set - if ( !primitive.draw ) continue; - - vk::DrawIndexedIndirectCommand cmd; - cmd.indexCount = primitive.m_index_buffer.size(); - cmd.firstIndex = primitive.m_index_buffer.getOffsetCount(); - - cmd.vertexOffset = static_cast< std::int32_t >( primitive.m_vertex_buffer.getOffsetCount() ); - - cmd.firstInstance = 0; - cmd.instanceCount = 1; - - draw_parameters.emplace_back( cmd ); - } - - return draw_parameters; + m_instances_desc = INSTANCES_SET.create(); + m_instances_desc->bindStorageBuffer( 0, m_primitive_instances ); + m_instances_desc->bindStorageBuffer( 1, m_model_instances ); + m_instances_desc->update(); + m_instances_desc->setName( "Instances, Primitive + Models" ); } OrientedBoundingBox< CoordinateSpace::Model > Model::buildBoundingBox( const std::vector< Primitive >& primitives ) @@ -54,11 +68,6 @@ namespace fgl::engine return box; } - std::shared_ptr< ModelRenderInfo > Model::getRenderHandle() const - { - return m_render_handle.lock(); - } - bool Model::ready() const { //Return true if even a single primitive is ready @@ -69,74 +78,73 @@ namespace fgl::engine return false; } - std::vector< vk::DrawIndexedIndirectCommand > Model::getDrawCommand( const std::uint32_t index ) const - { - ZoneScoped; - std::vector< vk::DrawIndexedIndirectCommand > draw_commands {}; - draw_commands.reserve( m_primitives.size() ); - for ( const auto& cmd : m_draw_parameters ) - { - auto new_cmd { cmd }; - new_cmd.firstInstance = index; - - draw_commands.push_back( new_cmd ); - } - - return draw_commands; - } - - Model::Model( - ModelBuilder& builder, - const OrientedBoundingBox< CoordinateSpace::Model >& bounding_box, - const std::string& name ) : - Model( std::move( builder.m_primitives ), bounding_box, name ) + Model::Model( std::vector< Primitive >&& primitives, const std::string& name ) : + m_name( name ), + m_primitives( std::forward< std::vector< Primitive > >( primitives ) ) {} - Model::Model( - std::vector< Primitive >&& primitives, - const OrientedBoundingBox< CoordinateSpace::Model >& bounding_box, - const std::string& name ) : - m_draw_parameters( buildParameters( primitives ) ), - m_name( name ), - m_bounding_box( bounding_box ) - { - assert( !name.empty() ); - assert( bounding_box.getTransform().translation.vec() != constants::DEFAULT_VEC3 ); - m_primitives = std::move( primitives ); - } - - std::shared_ptr< Model > Model:: - createModel( const std::filesystem::path& path, memory::Buffer& vertex_buffer, memory::Buffer& index_buffer ) + std::shared_ptr< ModelInstance > Model::createInstance() { ZoneScoped; + + auto& buffers { getModelBuffers() }; + + std::vector< PrimitiveInstanceInfoIndex > primitive_instances {}; + + constexpr ModelInstanceInfo model_info {}; + + ModelInstanceInfoIndex model_instance { buffers.m_model_instances.acquire( model_info ) }; + + for ( std::size_t i = 0; i < m_primitives.size(); i++ ) + { + auto render_info { m_primitives[ i ].renderInstanceInfo() }; + + PrimitiveInstanceInfo instance_info {}; + instance_info.m_primitive_info = render_info->idx(); + instance_info.m_model_info = model_instance.idx(); + instance_info.m_material = m_primitives[ i ].default_material->getID(); + + primitive_instances.emplace_back( buffers.m_primitive_instances.acquire( instance_info ) ); + } + + return std::make_shared< + ModelInstance >( std::move( primitive_instances ), std::move( model_instance ), this->shared_from_this() ); + } + + std::shared_ptr< Model > Model::createModel( const std::filesystem::path& path ) + { + ZoneScoped; + + auto& buffers { getModelBuffers() }; + log::debug( "Creating model {}", path ); - ModelBuilder builder { vertex_buffer, index_buffer }; + ModelBuilder builder { buffers.m_vertex_buffer, buffers.m_index_buffer }; builder.loadModel( path ); //Calculate bounding box OrientedBoundingBox bounding_box { buildBoundingBox( builder.m_primitives ) }; - auto model_ptr { std::make_shared< Model >( builder, bounding_box ) }; + auto model_ptr { std::make_shared< Model >( std::move( builder.m_primitives ) ) }; log::debug( "Finished creating model {}", path ); return model_ptr; } - std::shared_ptr< Model > Model::createModelFromVerts( - std::vector< ModelVertex > verts, - std::vector< std::uint32_t > indicies, - memory::Buffer& vertex_buffer, - memory::Buffer& index_buffer ) + std::shared_ptr< Model > Model:: + createModelFromVerts( std::vector< ModelVertex > verts, std::vector< std::uint32_t > indicies ) { ZoneScoped; - ModelBuilder builder { vertex_buffer, index_buffer }; + + auto& buffers { getModelBuffers() }; + + ModelBuilder builder { buffers.m_vertex_buffer, buffers.m_index_buffer }; builder.loadVerts( std::move( verts ), std::move( indicies ) ); OrientedBoundingBox bounding_box { buildBoundingBox( builder.m_primitives ) }; - auto model_ptr { std::make_shared< Model >( builder, bounding_box ) }; + auto model_ptr { std::make_shared< Model >( std::move( builder.m_primitives ) ) }; return model_ptr; } diff --git a/src/engine/assets/model/Model.hpp b/src/engine/assets/model/Model.hpp index 6feac70..2a4f428 100644 --- a/src/engine/assets/model/Model.hpp +++ b/src/engine/assets/model/Model.hpp @@ -15,13 +15,22 @@ #include #include "Primitive.hpp" -#include "assets/AssetManager.hpp" -#include "engine/assets/material/Material.hpp" -#include "engine/primitives/boxes/OrientedBoundingBox.hpp" +#include "assets/material/Material.hpp" +#include "descriptors/Descriptor.hpp" +#include "descriptors/DescriptorSetLayout.hpp" #include "memory/buffers/vector/IndexedVector.hpp" +#include "primitives/boxes/OrientedBoundingBox.hpp" +#include "rendering/PresentSwapChain.hpp" namespace fgl::engine { + struct Primitive; + struct ModelInstanceInfo; + struct PrimitiveInstanceInfo; + struct PrimitiveRenderInfo; + struct ModelGPUBuffers; + class ModelInstance; + struct ModelResourceBuffers; struct ModelRenderInfo; class ModelRenderHandle; @@ -32,61 +41,107 @@ namespace fgl::engine struct ModelBuilder; - struct ModelMatrixInfo + ModelGPUBuffers& getModelBuffers(); + + // Primitive render info, Contains the vertex and index info + constexpr descriptors::Descriptor RENDER_INFO_DESCRIPTOR { 0, + vk::DescriptorType::eStorageBuffer, + vk::ShaderStageFlagBits::eCompute }; + + inline static descriptors::DescriptorSetLayout PRIMITIVE_SET { 0, RENDER_INFO_DESCRIPTOR }; + + // Contains the information for each primitive (material ID, ect) + constexpr descriptors::Descriptor PRIMITIVE_INSTANCE_DESCRIPTOR { 0, + vk::DescriptorType::eStorageBuffer, + vk::ShaderStageFlagBits::eCompute }; + + // contains the model information, Such as model matricies + constexpr descriptors::Descriptor MODEL_INSTANCE_DESCRIPTOR { 1, + vk::DescriptorType::eStorageBuffer, + vk::ShaderStageFlagBits::eCompute }; + + inline static descriptors::DescriptorSetLayout INSTANCES_SET { 1, + PRIMITIVE_INSTANCE_DESCRIPTOR, + MODEL_INSTANCE_DESCRIPTOR }; + + constexpr descriptors::Descriptor COMMANDS_DESCRIPTOR { 0, + vk::DescriptorType::eStorageBuffer, + vk::ShaderStageFlagBits::eCompute }; + + // Contains the per instance vertex info + constexpr descriptors::Descriptor VERTEX_INSTANCE_INFO { 1, + vk::DescriptorType::eStorageBuffer, + vk::ShaderStageFlagBits::eCompute }; + + inline static descriptors::DescriptorSetLayout COMMANDS_SET { 2, COMMANDS_DESCRIPTOR, VERTEX_INSTANCE_INFO }; + + struct PerVertexInstanceInfo { - glm::mat4 model_matrix; - MaterialID material_id { constants::INVALID_TEXTURE_ID }; + glm::mat4x4 m_model_matrix; + MaterialID material_id; }; - class Model final : public AssetInterface< Model > + static_assert( sizeof( glm::mat4x4 ) == 64 ); + static_assert( offsetof( PerVertexInstanceInfo, m_model_matrix ) == 0 ); + + static_assert( offsetof( PerVertexInstanceInfo, material_id ) == 64 ); + static_assert( sizeof( MaterialID ) == 4 ); + + static_assert( sizeof( PerVertexInstanceInfo ) == 64 + 4 ); + + struct ModelGPUBuffers { + // buffer for long-term data. Not commonly updated + memory::Buffer m_long_buffer; + // Buffer for commonly updated data + memory::Buffer m_short_buffer; + + memory::Buffer m_vertex_buffer; + memory::Buffer m_index_buffer; + + //! Generated by the compute shader, This vector contains the instance info for each primitive. + PerFrameArray< DeviceVector< PerVertexInstanceInfo > > m_generated_instance_info; + + //! contains the core primitive info, like vertex and index offsets and counts + IndexedVector< PrimitiveRenderInfo > m_primitive_info; + //! contains a list of all rendered primitives + IndexedVector< PrimitiveInstanceInfo > m_primitive_instances; + //! Contains a list of all models + IndexedVector< ModelInstanceInfo > m_model_instances; + + std::shared_ptr< descriptors::DescriptorSet > m_primitives_desc; + std::shared_ptr< descriptors::DescriptorSet > m_instances_desc; + + ModelGPUBuffers(); + }; + + class Model final : public AssetInterface< Model >, public std::enable_shared_from_this< Model > + { + // Fills the GPU indexed vector with the parameters required for rendering static OrientedBoundingBox< CoordinateSpace::Model > buildBoundingBox( const std::vector< Primitive >& primitives ); std::string m_name { "Unnamed model" }; - //! Bounding box of the model - OrientedBoundingBox< CoordinateSpace::Model > m_bounding_box; - - IndexedVector< ModelMatrixInfo >::Index m_model_info {}; + std::vector< Primitive > m_primitives {}; public: + Model( std::vector< Primitive >&& primitives, const std::string& name = {} ); + + ~Model() = default; + [[nodiscard]] bool ready() const; - //! Returns the bounding box in model space - [[nodiscard]] const OrientedBoundingBox< CoordinateSpace::Model >& getBoundingBox() const - { - return m_bounding_box; - } - - std::vector< Primitive > m_primitives {}; - - [[nodiscard]] std::vector< vk::DrawIndexedIndirectCommand > getDrawCommand( std::uint32_t index ) const; - //TODO: Switch to using shared_ptr instead of unique_ptr - static std::shared_ptr< Model > createModel( - const std::filesystem::path& path, memory::Buffer& vertex_buffer, memory::Buffer& index_buffer ); + static std::shared_ptr< Model > createModel( const std::filesystem::path& path ); - static std::shared_ptr< Model > createModelFromVerts( - std::vector< ModelVertex > verts, - std::vector< std::uint32_t > indicies, - memory::Buffer& vertex_buffer, - memory::Buffer& index_buffer ); + static std::shared_ptr< Model > + createModelFromVerts( std::vector< ModelVertex > verts, std::vector< std::uint32_t > indicies ); const std::string& getName() const { return m_name; } - Model( - ModelBuilder& builder, - const OrientedBoundingBox< CoordinateSpace::Model >& bounding_box, - const std::string& name = {} ); - - Model( - std::vector< Primitive >&& primitives, - const OrientedBoundingBox< CoordinateSpace::Model >& bounding_box, - const std::string& name = {} ); - - ~Model() = default; + std::shared_ptr< ModelInstance > createInstance(); Model( const Model& model ) = delete; Model& operator=( const Model& other ) = delete; diff --git a/src/engine/assets/model/ModelInstance.hpp b/src/engine/assets/model/ModelInstance.hpp index 3a9abb4..8480489 100644 --- a/src/engine/assets/model/ModelInstance.hpp +++ b/src/engine/assets/model/ModelInstance.hpp @@ -6,9 +6,8 @@ #include -#include "memory/buffers/vector/DeviceVector.hpp" -#include "primitives/Transform.hpp" -#include "rendering/PresentSwapChain.hpp" +#include "ModelInstanceInfo.hpp" +#include "Primitive.hpp" namespace fgl::engine { @@ -23,30 +22,31 @@ namespace fgl::engine using InstanceIndex = std::uint32_t; - using namespace fgl::literals::size_literals; + struct ModelMatrixInfo + { + glm::mat4 model_matrix; + }; class ModelInstance { std::shared_ptr< Model > m_model; - InstanceIndex m_index; - //! CPU side data to be modified - ModelGPUInstance m_cpu_data; + ModelInstanceInfoIndex m_model_instance; + std::vector< PrimitiveInstanceInfoIndex > m_primitive_instances; //! True if the last frame changed this instance in any way bool m_updated { false }; public: - //! Returns GPU instance data - ModelGPUInstance gpuInstanceData() const - { - ModelGPUInstance data {}; - - data.m_model_index = m_model->getGPUID(); - - return data; - } + ModelInstance( + std::vector< PrimitiveInstanceInfoIndex >&& primative_instances, + ModelInstanceInfoIndex&& model_instance, + const std::shared_ptr< Model >& model ) noexcept : + m_model( model ), + m_model_instance( std::move( model_instance ) ), + m_primitive_instances( std::move( primative_instances ) ) + {} //! Returns the current update state and sets it to false if it was true. bool acquireNeedsUpdate() diff --git a/src/engine/assets/model/ModelInstanceInfo.hpp b/src/engine/assets/model/ModelInstanceInfo.hpp new file mode 100644 index 0000000..6f024f0 --- /dev/null +++ b/src/engine/assets/model/ModelInstanceInfo.hpp @@ -0,0 +1,17 @@ +// +// Created by kj16609 on 4/5/25. +// +#pragma once +#include "memory/buffers/vector/IndexedVector.hpp" + +namespace fgl::engine +{ + + struct ModelInstanceInfo + { + glm::mat4 m_matrix { constants::MAT4_IDENTITY }; + }; + + using ModelInstanceInfoIndex = IndexedVector< ModelInstanceInfo >::Index; + +} // namespace fgl::engine diff --git a/src/engine/assets/model/ModelManager.cpp b/src/engine/assets/model/ModelManager.cpp deleted file mode 100644 index 1456e71..0000000 --- a/src/engine/assets/model/ModelManager.cpp +++ /dev/null @@ -1,10 +0,0 @@ -// -// Created by kj16609 on 3/12/25. -// -#include "ModelManager.hpp" - - -namespace fgl::engine -{ - -} diff --git a/src/engine/assets/model/ModelManager.hpp b/src/engine/assets/model/ModelManager.hpp deleted file mode 100644 index 6d701fe..0000000 --- a/src/engine/assets/model/ModelManager.hpp +++ /dev/null @@ -1,24 +0,0 @@ -// -// Created by kj16609 on 3/12/25. -// -#pragma once -#include "memory/buffers/vector/DeviceVector.hpp" -#include "rendering/PresentSwapChain.hpp" - -namespace fgl::engine -{ - class ModelManager - { - //! The managed draw command buffer. - /** - * Contains all draw commands for the rendering process. Updated by the CPU whenever a new model is created - */ - DeviceVector< vk::DrawIndexedIndirectCommand > m_draw_commands; - - //! Draw buffers the GPU compute shader writes into - PerFrameArray< DeviceVector< vk::DrawIndexedIndirectCommand > > m_gpu_draw_commands {}; - - //! Contains extra information such as model instance indexes by the compute shader - PerFrameArray<> m_gpu_draw_info {}; - }; -} // namespace fgl::engine \ No newline at end of file diff --git a/src/engine/assets/model/ModelVertex.cpp b/src/engine/assets/model/ModelVertex.cpp index 0978a1b..7c3344d 100644 --- a/src/engine/assets/model/ModelVertex.cpp +++ b/src/engine/assets/model/ModelVertex.cpp @@ -13,6 +13,7 @@ #pragma GCC diagnostic pop #include "Model.hpp" +#include "ModelInstance.hpp" #include "engine/utils.hpp" namespace fgl::engine @@ -28,7 +29,7 @@ namespace fgl::engine { std::vector< vk::VertexInputBindingDescription > binding_descriptions { { 0, sizeof( ModelVertex ), vk::VertexInputRate::eVertex }, - { 1, sizeof( ModelMatrixInfo ), vk::VertexInputRate::eInstance } + { 1, sizeof( PerVertexInstanceInfo ), vk::VertexInputRate::eInstance } }; return binding_descriptions; @@ -55,7 +56,8 @@ namespace fgl::engine attribute_descriptions.emplace_back( 6, 1, vk::Format::eR32G32B32A32Sfloat, 2 * sizeof( glm::vec4 ) ); attribute_descriptions.emplace_back( 7, 1, vk::Format::eR32G32B32A32Sfloat, 3 * sizeof( glm::vec4 ) ); - attribute_descriptions.emplace_back( 8, 1, vk::Format::eR32Uint, offsetof( ModelMatrixInfo, material_id ) ); + attribute_descriptions + .emplace_back( 8, 1, vk::Format::eR32Uint, offsetof( PerVertexInstanceInfo, material_id ) ); return attribute_descriptions; } diff --git a/src/engine/assets/model/Primitive.cpp b/src/engine/assets/model/Primitive.cpp index cc4755b..0a70ebf 100644 --- a/src/engine/assets/model/Primitive.cpp +++ b/src/engine/assets/model/Primitive.cpp @@ -4,7 +4,9 @@ #include "Primitive.hpp" +#include "Model.hpp" #include "engine/assets/material/Material.hpp" +#include "engine/assets/model/ModelVertex.hpp" #include "engine/assets/texture/Texture.hpp" namespace fgl::engine @@ -32,7 +34,20 @@ namespace fgl::engine bool Primitive::ready() const { - return m_material->ready() && m_vertex_buffer.ready() && m_index_buffer.ready(); + return default_material->ready() && m_vertex_buffer.ready() && m_index_buffer.ready(); + } + + std::shared_ptr< PrimitiveRenderInfoIndex > Primitive::buildRenderInfo() + { + auto& buffers { getModelBuffers() }; + + PrimitiveRenderInfo info {}; + info.m_first_vert = m_vertex_buffer.getOffsetCount(); + info.m_first_index = m_index_buffer.getOffsetCount(); + info.m_num_indicies = m_index_buffer.size(); + + auto ptr { std::make_shared< PrimitiveRenderInfoIndex >( buffers.m_primitive_info.acquire( info ) ) }; + return ptr; } Primitive::Primitive( @@ -44,7 +59,8 @@ namespace fgl::engine m_index_buffer( std::move( index_buffer ) ), m_bounding_box( bounding_box ), m_mode( mode ), - m_material() + default_material(), + m_primitive_info( buildRenderInfo() ) { assert( m_bounding_box.getTransform().scale != glm::vec3( 0.0f ) ); } @@ -59,21 +75,25 @@ namespace fgl::engine m_index_buffer( std::move( index_buffer ) ), m_bounding_box( bounding_box ), m_mode( mode ), - m_material( material ) + default_material( material ), + m_primitive_info( buildRenderInfo() ) { assert( m_bounding_box.getTransform().scale != glm::vec3( 0.0f ) ); } Primitive Primitive::fromVerts( - const std::vector< ModelVertex >&& verts, + std::vector< ModelVertex >&& verts, const PrimitiveMode mode, - const std::vector< std::uint32_t >&& indicies, + std::vector< std::uint32_t >&& indicies, memory::Buffer& vertex_buffer, memory::Buffer& index_buffer ) { const auto bounds { generateBoundingFromVerts( verts ) }; - VertexBufferSuballocation vertex_buffer_suballoc { vertex_buffer, std::move( verts ) }; - IndexBufferSuballocation index_buffer_suballoc { index_buffer, std::move( indicies ) }; + VertexBufferSuballocation vertex_buffer_suballoc { vertex_buffer, + std::forward< std::vector< ModelVertex > >( verts ) }; + + IndexBufferSuballocation index_buffer_suballoc { index_buffer, + std::forward< std::vector< std::uint32_t > >( indicies ) }; return { std::move( vertex_buffer_suballoc ), std::move( index_buffer_suballoc ), bounds, mode }; } diff --git a/src/engine/assets/model/Primitive.hpp b/src/engine/assets/model/Primitive.hpp index 712561d..2354cb9 100644 --- a/src/engine/assets/model/Primitive.hpp +++ b/src/engine/assets/model/Primitive.hpp @@ -9,12 +9,15 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" #pragma GCC diagnostic ignored "-Weffc++" -#include "ModelVertex.hpp" -#include "engine/memory/buffers/vector/DeviceVector.hpp" -#include "engine/primitives/boxes/OrientedBoundingBox.hpp" #include "objectloaders/tiny_gltf.h" #pragma GCC diagnostic pop +#include "ModelInstanceInfo.hpp" +#include "assets/material/Material.hpp" +#include "engine/memory/buffers/vector/DeviceVector.hpp" +#include "engine/primitives/boxes/OrientedBoundingBox.hpp" +#include "memory/buffers/vector/IndexedVector.hpp" + namespace fgl::engine { class Material; @@ -46,6 +49,27 @@ namespace fgl::engine bool ready() const; }; + struct PrimitiveRenderInfo + { + //! First vertex in the buffer + std::uint32_t m_first_vert; + //! First index + std::uint32_t m_first_index; + //! Number of indicies + std::uint32_t m_num_indicies; + }; + + using PrimitiveRenderInfoIndex = IndexedVector< PrimitiveRenderInfo >::Index; + + struct PrimitiveInstanceInfo + { + PrimitiveRenderInfoIndex::GPUValue m_primitive_info; + ModelInstanceInfoIndex::GPUValue m_model_info; + MaterialID m_material; + }; + + using PrimitiveInstanceInfoIndex = IndexedVector< PrimitiveInstanceInfo >::Index; + struct Primitive { bool draw { true }; @@ -54,15 +78,17 @@ namespace fgl::engine OrientedBoundingBox< CoordinateSpace::Model > m_bounding_box; PrimitiveMode m_mode; - // PrimitiveTextures m_textures; + std::shared_ptr< PrimitiveRenderInfoIndex > m_primitive_info; - std::shared_ptr< Material > m_material; + std::shared_ptr< Material > default_material; std::string m_name { "Unnamed Primitive" }; //! Returns true if the primitive is ready to be rendered (must have all textures, vertex buffer, and index buffer ready) bool ready() const; + std::shared_ptr< PrimitiveRenderInfoIndex > buildRenderInfo(); + Primitive( VertexBufferSuballocation&& vertex_buffer, IndexBufferSuballocation&& index_buffer, @@ -80,10 +106,12 @@ namespace fgl::engine Primitive( const Primitive& other ) = delete; Primitive( Primitive&& other ) = default; + std::shared_ptr< PrimitiveRenderInfoIndex > renderInstanceInfo() const { return m_primitive_info; } + static Primitive fromVerts( - const std::vector< ModelVertex >&& verts, + std::vector< ModelVertex >&& verts, PrimitiveMode mode, - const std::vector< std::uint32_t >&& indicies, + std::vector< std::uint32_t >&& indicies, memory::Buffer& vertex_buffer, memory::Buffer& index_buffer ); diff --git a/src/engine/assets/model/builders/ModelBuilder.cpp b/src/engine/assets/model/builders/ModelBuilder.cpp index 356301e..cc48949 100644 --- a/src/engine/assets/model/builders/ModelBuilder.cpp +++ b/src/engine/assets/model/builders/ModelBuilder.cpp @@ -7,6 +7,7 @@ #include #include "engine/assets/model/Primitive.hpp" +#include "engine/assets/model/ModelVertex.hpp" namespace fgl::engine { diff --git a/src/engine/assets/model/builders/SceneBuilder.cpp b/src/engine/assets/model/builders/SceneBuilder.cpp index 26acdf1..8a5ecf4 100644 --- a/src/engine/assets/model/builders/SceneBuilder.cpp +++ b/src/engine/assets/model/builders/SceneBuilder.cpp @@ -12,6 +12,7 @@ #include "objectloaders/tiny_gltf.h" #pragma GCC diagnostic pop +#include "assets/model/ModelVertex.hpp" #include "engine/assets/image/ImageView.hpp" #include "engine/assets/stores.hpp" #include "engine/camera/Camera.hpp" @@ -400,7 +401,7 @@ namespace fgl::engine if ( !has_texcoord ) return primitive_mesh; //primitive_mesh.m_textures = loadTextures( prim, root ); - primitive_mesh.m_material = loadMaterial( prim, root ); + primitive_mesh.default_material = loadMaterial( prim, root ); return primitive_mesh; } @@ -510,7 +511,7 @@ namespace fgl::engine const auto bounding_box { createModelBoundingBox( finished_primitives ) }; return std::make_shared< - Model >( std::move( finished_primitives ), bounding_box, mesh.name.empty() ? "Unnamed Model" : mesh.name ); + Model >( std::move( finished_primitives ), mesh.name.empty() ? "Unnamed Model" : mesh.name ); } std::shared_ptr< Texture > SceneBuilder::loadTexture( const int tex_id, const tinygltf::Model& root ) const @@ -533,8 +534,7 @@ namespace fgl::engine Sampler sampler { sampler_info.minFilter, sampler_info.magFilter, sampler_info.wrapS, sampler_info.wrapT }; - std::shared_ptr< Texture > texture { getTextureStore().load( full_path ) }; - texture->getImageView().getSampler() = std::move( sampler ); + std::shared_ptr< Texture > texture { getTextureStore().load( full_path, std::move( sampler ) ) }; //Prepare the texture into the global system Texture::getDescriptorSet().bindTexture( 0, texture ); @@ -605,7 +605,7 @@ namespace fgl::engine const auto transform { loadTransform( node_idx, root ) }; - obj.getTransform() = transform; + // obj.getTransform() = transform; if ( node.name.empty() ) obj.setName( "Unnamed Game Object" ); diff --git a/src/engine/assets/texture/Texture.cpp b/src/engine/assets/texture/Texture.cpp index 925a1f9..f8e5c9b 100644 --- a/src/engine/assets/texture/Texture.cpp +++ b/src/engine/assets/texture/Texture.cpp @@ -28,8 +28,8 @@ namespace fgl::engine static IDPool< TextureID > texture_id_pool { 1 }; - std::tuple< std::vector< std::byte >, int, int, vk::Format > - loadTexture( const std::filesystem::path& path, vk::Format format = vk::Format::eUndefined ) + std::tuple< std::vector< std::byte >, int, int, vk::Format, Sampler > + loadTexture( const std::filesystem::path& path, Sampler&& sampler, vk::Format format = vk::Format::eUndefined ) { ZoneScoped; if ( !std::filesystem::exists( path ) ) throw std::runtime_error( "Failed to open file: " + path.string() ); @@ -54,7 +54,7 @@ namespace fgl::engine //TODO: Write check to ensure the format matches the number of channels - return { std::move( data ), x, y, format }; + return { std::move( data ), x, y, format, std::forward< Sampler >( sampler ) }; } void Texture::drawImGui( vk::Extent2D extent ) @@ -98,16 +98,25 @@ namespace fgl::engine return ImGui::ImageButton( m_name.c_str(), getImGuiDescriptorSet(), imgui_size ); } - Texture::Texture( std::tuple< std::vector< std::byte >, int, int, vk::Format > tuple ) : + Texture::Texture( std::tuple< std::vector< std::byte >, int, int, vk::Format, Sampler > tuple ) : Texture( - std::move( std::get< 0 >( tuple ) ), std::get< 1 >( tuple ), std::get< 2 >( tuple ), std::get< 3 >( tuple ) ) + std::move( std::get< 0 >( tuple ) ), + std::get< 1 >( tuple ), + std::get< 2 >( tuple ), + std::get< 3 >( tuple ), + std::move( std::get< 4 >( tuple ) ) ) {} - Texture::Texture( std::vector< std::byte >&& data, const int x, const int y, const vk::Format format ) : - Texture( std::forward< std::vector< std::byte > >( data ), vk::Extent2D( x, y ), format ) + Texture::Texture( + std::vector< std::byte >&& data, const int x, const int y, const vk::Format format, Sampler&& sampler ) : + Texture( + std::forward< std::vector< std::byte > >( data ), + vk::Extent2D( x, y ), + std::forward< Sampler >( sampler ), + format ) {} - Texture::Texture( std::vector< std::byte >&& data, const vk::Extent2D extent, const vk::Format format ) : + Texture::Texture( std::vector< std::byte >&& data, const vk::Extent2D extent, Sampler&&, const vk::Format format ) : m_texture_id( texture_id_pool.getID() ), m_image( std::make_shared< Image >( @@ -128,16 +137,21 @@ namespace fgl::engine #endif } - Texture::Texture( const std::filesystem::path& path, const vk::Format format ) : - Texture( loadTexture( path, format ) ) + Texture::Texture( const std::filesystem::path& path, Sampler&& sampler, const vk::Format format ) : + Texture( loadTexture( path, std::forward< Sampler >( sampler ), format ) ) { setName( path.filename() ); } - Texture::Texture( const std::filesystem::path& path ) : Texture( loadTexture( path ) ) - { - setName( path.filename() ); - } + Texture::Texture( const std::filesystem::path& path, Sampler&& sampler ) : + Texture( loadTexture( path, std::forward< Sampler >( sampler ) ) ) + {} + + Texture::Texture( const std::filesystem::path& path ) : Texture( path, {} ) + {} + + Texture::Texture( const std::filesystem::path& path, const vk::Format format ) : Texture( path, {}, format ) + {} Texture::~Texture() { @@ -200,13 +214,19 @@ namespace fgl::engine Texture::Texture( const std::shared_ptr< Image >& image, Sampler sampler ) : m_texture_id( texture_id_pool.getID() ), m_image( image ), - m_image_view( image->getView() ), + m_image_view( image->getView( std::move( sampler ) ) ), //TODO: Figure out how to get extents from images. m_extent( image->getExtent() ), m_name( "Default Texture Name" ) - { - m_image_view->getSampler() = std::move( sampler ); - } + {} + + Texture::Texture( const std::shared_ptr< Image >& image, Sampler&& sampler ) : + m_texture_id( texture_id_pool.getID() ), + m_image( image ), + m_image_view( image->getView( std::forward< Sampler >( sampler ) ) ), + m_extent( image->getExtent() ), + m_name( "Default Texture Name" ) + {} bool Texture::ready() const { diff --git a/src/engine/assets/texture/Texture.hpp b/src/engine/assets/texture/Texture.hpp index 5076a53..f022eb9 100644 --- a/src/engine/assets/texture/Texture.hpp +++ b/src/engine/assets/texture/Texture.hpp @@ -65,33 +65,36 @@ namespace fgl::engine std::string m_name; - [[nodiscard]] Texture( std::tuple< std::vector< std::byte >, int, int, vk::Format > ); + [[nodiscard]] Texture( std::tuple< std::vector< std::byte >, int, int, vk::Format, Sampler > ); //! Construct texture with a specific extent and data - [[nodiscard]] Texture( std::vector< std::byte >&& data, int x, int y, vk::Format texture_format ); + [[nodiscard]] Texture( + std::vector< std::byte >&& data, int x, int y, vk::Format texture_format, Sampler&& sampler ); //! Construct texture with a specific extent and data - [[nodiscard]] Texture( std::vector< std::byte >&& data, vk::Extent2D extent, vk::Format texture_format ); + [[nodiscard]] Texture( + std::vector< std::byte >&& data, vk::Extent2D extent, Sampler&& sampler, vk::Format texture_format ); //! Construct with a specific format - [[nodiscard]] Texture( const std::filesystem::path& path, vk::Format format ); + [[nodiscard]] Texture( const std::filesystem::path& path, Sampler&&, vk::Format format ); - //! Construct with no format + [[nodiscard]] Texture( const std::filesystem::path& path, Sampler&& sampler ); [[nodiscard]] Texture( const std::filesystem::path& path ); + [[nodiscard]] Texture( const std::filesystem::path& path, vk::Format format ); public: + static UIDKeyT extractKey( const std::filesystem::path& path, [[maybe_unused]] Sampler&& ) { return path; } + static UIDKeyT extractKey( const std::filesystem::path& path ) { return path; } - static UIDKeyT extractKey( const std::filesystem::path& path, [[maybe_unused]] const vk::Format format ) - { - return path; - } + static UIDKeyT extractKey( const std::filesystem::path& path, [[maybe_unused]] vk::Format ) { return path; } Texture() = delete; ~Texture(); - Texture( const std::shared_ptr& image, Sampler sampler = Sampler() ); + Texture( const std::shared_ptr< Image >& image, Sampler sampler = Sampler() ); + Texture( const std::shared_ptr< Image >& image, Sampler&& sampler ); Image& getImageRef(); diff --git a/src/engine/camera/Camera.cpp b/src/engine/camera/Camera.cpp index df6efc1..68037ca 100644 --- a/src/engine/camera/Camera.cpp +++ b/src/engine/camera/Camera.cpp @@ -92,7 +92,7 @@ namespace fgl::engine remakeSwapchain( m_target_extent ); } - updateInfo( frame_info.frame_idx ); + updateInfo( frame_info.in_flight_idx ); FGL_ASSERT( m_camera_renderer, "Camera renderer should not be nullptr" ); m_camera_renderer->pass( frame_info, *m_gbuffer_swapchain ); frame_info.camera = nullptr; @@ -140,8 +140,11 @@ namespace fgl::engine log::debug( "Camera swapchain recreated" ); - m_old_composite_swapchain = std::move( m_composite_swapchain ); - m_old_gbuffer_swapchain = std::move( m_gbuffer_swapchain ); + m_old_composite_swapchain.push( std::move( m_composite_swapchain ) ); + m_old_gbuffer_swapchain.push( std::move( m_gbuffer_swapchain ) ); + + if ( m_old_composite_swapchain.size() > constants::MAX_FRAMES_IN_FLIGHT ) m_old_composite_swapchain.pop(); + if ( m_old_gbuffer_swapchain.size() > constants::MAX_FRAMES_IN_FLIGHT ) m_old_gbuffer_swapchain.pop(); m_composite_swapchain = std::make_unique< CompositeSwapchain >( extent ); m_gbuffer_swapchain = std::make_unique< GBufferSwapchain >( extent ); diff --git a/src/engine/camera/Camera.hpp b/src/engine/camera/Camera.hpp index cf79d03..089de5a 100644 --- a/src/engine/camera/Camera.hpp +++ b/src/engine/camera/Camera.hpp @@ -14,6 +14,7 @@ #include "../primitives/rotation/QuatRotation.hpp" #include "CompositeSwapchain.hpp" +#include "GBufferSwapchain.hpp" #include "debug/Track.hpp" #include "engine/descriptors/DescriptorSet.hpp" #include "engine/memory/buffers/HostSingleT.hpp" @@ -39,7 +40,6 @@ namespace fgl::engine class GBufferRenderer; struct CameraInfo; - class GBufferSwapchain; class Camera; FrustumBase createFrustum( float aspect, float fovy, float near, float far ); @@ -58,8 +58,8 @@ namespace fgl::engine std::unique_ptr< GBufferSwapchain > m_gbuffer_swapchain; //TODO: Move to deffered deleter - std::unique_ptr< CompositeSwapchain > m_old_composite_swapchain { nullptr }; - std::unique_ptr< GBufferSwapchain > m_old_gbuffer_swapchain { nullptr }; + std::queue< std::unique_ptr< CompositeSwapchain > > m_old_composite_swapchain {}; + std::queue< std::unique_ptr< GBufferSwapchain > > m_old_gbuffer_swapchain {}; std::shared_ptr< GBufferRenderer > m_camera_renderer; diff --git a/src/engine/camera/GBufferRenderer.cpp b/src/engine/camera/GBufferRenderer.cpp index 365501e..e693321 100644 --- a/src/engine/camera/GBufferRenderer.cpp +++ b/src/engine/camera/GBufferRenderer.cpp @@ -56,17 +56,14 @@ namespace fgl::engine void GBufferRenderer::pass( FrameInfo& frame_info, GBufferSwapchain& camera_swapchain ) { ZoneScopedN( "CameraRenderer::pass" ); - m_culling_system.startPass( frame_info ); + + m_culling_system.pass( frame_info ); auto& command_buffer { frame_info.command_buffer.render_cb }; - camera_swapchain.transitionImages( command_buffer, GBufferSwapchain::INITAL, frame_info.frame_idx ); + camera_swapchain.transitionImages( command_buffer, GBufferSwapchain::INITAL, frame_info.in_flight_idx ); - beginRenderPass( command_buffer, camera_swapchain, frame_info.frame_idx ); - - // Transition the gbuffer to it's inital state - - m_culling_system.wait(); + beginRenderPass( command_buffer, camera_swapchain, frame_info.in_flight_idx ); //m_terrain_system.pass( frame_info ); @@ -75,9 +72,9 @@ namespace fgl::engine endRenderPass( command_buffer ); - camera_swapchain.transitionImages( command_buffer, GBufferSwapchain::FINAL, frame_info.frame_idx ); + camera_swapchain.transitionImages( command_buffer, GBufferSwapchain::FINAL, frame_info.in_flight_idx ); - m_compositor.composite( command_buffer, *frame_info.camera, frame_info.frame_idx ); + m_compositor.composite( command_buffer, *frame_info.camera, frame_info.in_flight_idx ); } } // namespace fgl::engine diff --git a/src/engine/descriptors/DescriptorSet.cpp b/src/engine/descriptors/DescriptorSet.cpp index 6ec44fe..9a49c84 100644 --- a/src/engine/descriptors/DescriptorSet.cpp +++ b/src/engine/descriptors/DescriptorSet.cpp @@ -55,6 +55,7 @@ namespace fgl::engine::descriptors void DescriptorSet::bindUniformBuffer( const std::uint32_t binding_idx, const memory::BufferSuballocation& buffer ) { assert( binding_idx < m_infos.size() && "Binding index out of range" ); + if ( buffer.bytesize() == 0 ) return; m_infos[ binding_idx ] = buffer.descriptorInfo(); @@ -64,6 +65,26 @@ namespace fgl::engine::descriptors write.dstArrayElement = 0; write.descriptorCount = 1; write.descriptorType = vk::DescriptorType::eUniformBuffer; + write.pBufferInfo = &( std::get< vk::DescriptorBufferInfo >( m_infos.data()[ binding_idx ] ) ); + write.pImageInfo = VK_NULL_HANDLE; + write.pTexelBufferView = VK_NULL_HANDLE; + + m_descriptor_writes.push_back( write ); + } + + void DescriptorSet::bindStorageBuffer( const std::uint32_t binding_idx, const memory::BufferSuballocation& buffer ) + { + assert( binding_idx < m_infos.size() && "Binding index out of range" ); + if ( buffer.bytesize() == 0 ) return; + + m_infos[ binding_idx ] = buffer.descriptorInfo(); + + vk::WriteDescriptorSet write {}; + write.dstSet = m_set; + write.dstBinding = binding_idx; + write.dstArrayElement = 0; + write.descriptorCount = 1; + write.descriptorType = vk::DescriptorType::eStorageBuffer; write.pBufferInfo = &( std::get< vk::DescriptorBufferInfo >( m_infos[ binding_idx ] ) ); write.pImageInfo = VK_NULL_HANDLE; write.pTexelBufferView = VK_NULL_HANDLE; @@ -143,7 +164,7 @@ namespace fgl::engine::descriptors write.dstArrayElement = tex.getID(); write.descriptorCount = 1; write.descriptorType = vk::DescriptorType::eCombinedImageSampler; - write.pImageInfo = &( std::get< vk::DescriptorImageInfo >( m_infos.data()[ binding_idx ] ) ); + write.pImageInfo = &( std::get< vk::DescriptorImageInfo >( m_infos[ binding_idx ] ) ); m_descriptor_writes.push_back( write ); } diff --git a/src/engine/descriptors/DescriptorSet.hpp b/src/engine/descriptors/DescriptorSet.hpp index ddad99c..8602219 100644 --- a/src/engine/descriptors/DescriptorSet.hpp +++ b/src/engine/descriptors/DescriptorSet.hpp @@ -48,21 +48,26 @@ namespace fgl::engine::descriptors public: + [[nodiscard]] bool hasUpdates() const { return !m_descriptor_writes.empty(); } + //! Updates the descriptor set, updates all pending writes created by using bindImage(), bindUniformBuffer(), bindArray(), bindAttachment(), or bindTexture(). void update(); - VkDescriptorSet operator*() const { return *m_set; } + VkDescriptorSet operator*() const + { + FGL_ASSERT( !hasUpdates(), "Descriptor set has updates but binding was attempted" ); + return *m_set; + } [[nodiscard]] VkDescriptorSet getVkDescriptorSet() const { return *m_set; } [[nodiscard]] DescriptorIDX setIDX() const { return m_set_idx; } - DescriptorSet() = delete; + FGL_DELETE_DEFAULT_CTOR( DescriptorSet ); + DescriptorSet( const vk::raii::DescriptorSetLayout& layout, DescriptorIDX idx, std::size_t binding_count ); - //Copy - DescriptorSet( const DescriptorSet& other ) = delete; - DescriptorSet& operator=( const DescriptorSet& other ) = delete; + FGL_DELETE_COPY( DescriptorSet ); //Move DescriptorSet( DescriptorSet&& other ) noexcept; @@ -77,6 +82,7 @@ namespace fgl::engine::descriptors const vk::raii::Sampler& sampler = VK_NULL_HANDLE ); void bindUniformBuffer( std::uint32_t binding_idx, const memory::BufferSuballocation& buffer ); + void bindStorageBuffer( std::uint32_t binding_idx, const memory::BufferSuballocation& buffer ); void bindArray( std::uint32_t binding_idx, const memory::BufferSuballocation& buffer, diff --git a/src/engine/descriptors/DescriptorSetLayout.hpp b/src/engine/descriptors/DescriptorSetLayout.hpp index 6e916ce..94ae3e0 100644 --- a/src/engine/descriptors/DescriptorSetLayout.hpp +++ b/src/engine/descriptors/DescriptorSetLayout.hpp @@ -47,7 +47,8 @@ namespace fgl::engine::descriptors [[nodiscard]] std::size_t count() const { return m_bindings.size(); } - std::unique_ptr< DescriptorSet > create(); + [[nodiscard]] std::unique_ptr< DescriptorSet > create(); + [[nodiscard]] vk::raii::DescriptorSetLayout createLayout() const; vk::raii::DescriptorSetLayout& layout(); }; diff --git a/src/engine/gameobjects/components/CameraComponent.hpp b/src/engine/gameobjects/components/CameraComponent.hpp index 838317a..b60e734 100644 --- a/src/engine/gameobjects/components/CameraComponent.hpp +++ b/src/engine/gameobjects/components/CameraComponent.hpp @@ -5,6 +5,7 @@ #pragma once #include +#include "ComponentIDS.hpp" #include "engine/gameobjects/components/interface/GameObjectComponent.hpp" namespace fgl::engine diff --git a/src/engine/gameobjects/components/ModelComponent.cpp b/src/engine/gameobjects/components/ModelComponent.cpp deleted file mode 100644 index 9619a1e..0000000 --- a/src/engine/gameobjects/components/ModelComponent.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// -// Created by kj16609 on 3/1/25. -// - -#include "ModelComponent.hpp" - -#include "engine/assets/model/Model.hpp" - -namespace fgl::engine::components -{ - - ModelComponent::ModelComponent( std::shared_ptr< Model >&& model ) : - m_model( std::forward< decltype( m_model ) >( model ) ), - m_render_handle( m_model->getRenderHandle() ) - {} - -} // namespace fgl::engine::components diff --git a/src/engine/gameobjects/components/ModelComponent.hpp b/src/engine/gameobjects/components/ModelComponent.hpp index 7ac2fe8..eec4852 100644 --- a/src/engine/gameobjects/components/ModelComponent.hpp +++ b/src/engine/gameobjects/components/ModelComponent.hpp @@ -6,28 +6,30 @@ #include #include "ComponentIDS.hpp" -#include "assets/model/ModelRenderHandle.hpp" -#include "engine/gameobjects/components/interface/GameObjectComponent.hpp" +#include "TransformComponent.hpp" +#include "interface/GameObjectComponent.hpp" namespace fgl::engine { + class Model; + class ModelInstance; class ModelRenderHandle; -} +} // namespace fgl::engine namespace fgl::engine::components { struct GameModel; - class Model; COMPONENT_CLASS( ModelComponent, ModelComponentID ) { - std::shared_ptr< Model > m_model; - ModelRenderHandle m_render_handle; + std::shared_ptr< ModelInstance > m_model_instance; + TransformComponent m_transform {}; // In the future this should also contain a handle to the pipeline that is going to be used for rendering this model. public: - explicit ModelComponent( std::shared_ptr< Model > && model ); + ModelComponent() = delete; + explicit ModelComponent( const std::shared_ptr< Model >& model ); void drawImGui() override; @@ -37,9 +39,9 @@ namespace fgl::engine::components virtual ~ModelComponent() override {} - Model* operator->(); + // Model* operator->(); - const Model* operator->() const; + // const Model* operator->() const; }; static_assert( is_component< ModelComponent > ); diff --git a/src/engine/gameobjects/components/TransformComponent.hpp b/src/engine/gameobjects/components/TransformComponent.hpp index 29b06bf..1213e92 100644 --- a/src/engine/gameobjects/components/TransformComponent.hpp +++ b/src/engine/gameobjects/components/TransformComponent.hpp @@ -14,19 +14,18 @@ namespace fgl::engine::components public: - explicit TransformComponent( WorldTransform & transform ); + TransformComponent() = default; + explicit TransformComponent( const WorldTransform& transform ); void drawImGui() override; std::string_view humanName() const override; std::string_view className() const override; - WorldTransform& operator*() - { - return m_transform; - } + WorldTransform& operator*(); - virtual ~TransformComponent() override = default; + virtual ~TransformComponent() override + {} }; } // namespace fgl::engine::components diff --git a/src/engine/memory/buffers/Buffer.cpp b/src/engine/memory/buffers/Buffer.cpp index d95ec96..2b53206 100644 --- a/src/engine/memory/buffers/Buffer.cpp +++ b/src/engine/memory/buffers/Buffer.cpp @@ -122,7 +122,12 @@ namespace fgl::engine::memory vk::DeviceSize Buffer::alignment() const { - vk::DeviceSize size { 0 }; + vk::DeviceSize size { 1 }; + + if ( m_usage & vk::BufferUsageFlagBits::eStorageBuffer ) + { + size = std::max( size, Device::getInstance().m_properties.limits.minStorageBufferOffsetAlignment ); + } if ( m_usage & vk::BufferUsageFlagBits::eUniformBuffer ) { @@ -174,14 +179,6 @@ namespace fgl::engine::memory auto itter { findAvailableBlock( desired_memory_size, t_alignment ) }; - if ( itter == m_free_blocks.end() ) - { - //If we can't find a block, then we need to merge the free blocks and try again - mergeFreeBlocks(); - itter = findAvailableBlock( desired_memory_size, t_alignment ); - } - - //TODO: Move this error stuff into the exception message if ( itter == m_free_blocks.end() ) { throw BufferOOM(); @@ -195,6 +192,7 @@ namespace fgl::engine::memory assert( selected_block_size <= this->size() ); const auto aligned_offset { align( selected_block_offset, alignment(), t_alignment ) }; + FGL_ASSERT( aligned_offset % combineAlignment( alignment(), t_alignment ) == 0, "Alignment failed!" ); //Fix the offset and size if they aren't alligned if ( aligned_offset != selected_block_offset ) @@ -359,7 +357,8 @@ namespace fgl::engine::memory } if ( sum != this->size() ) - throw std::runtime_error( std::format( "Memory leaked! Expected {} was {}", this->size(), sum ) ); + throw std::runtime_error( + std::format( "Memory leaked! Expected {} was {}: Lost {}", this->size(), sum, this->size() - sum ) ); #endif } diff --git a/src/engine/memory/buffers/BufferSuballocationHandle.cpp b/src/engine/memory/buffers/BufferSuballocationHandle.cpp index 2650583..987040a 100644 --- a/src/engine/memory/buffers/BufferSuballocationHandle.cpp +++ b/src/engine/memory/buffers/BufferSuballocationHandle.cpp @@ -22,7 +22,7 @@ namespace fgl::engine::memory m_offset( offset ), m_ptr( m_buffer.map( *this ) ) { - assert( memory_size != 0 && "BufferSuballocation::BufferSuballocation() called with memory_size == 0" ); + // assert( memory_size != 0 && "BufferSuballocation::BufferSuballocation() called with memory_size == 0" ); } vk::Buffer BufferSuballocationHandle::getVkBuffer() const diff --git a/src/engine/memory/buffers/align.hpp b/src/engine/memory/buffers/align.hpp index 9cb54af..e60eff9 100644 --- a/src/engine/memory/buffers/align.hpp +++ b/src/engine/memory/buffers/align.hpp @@ -4,11 +4,33 @@ #pragma once +#include #include +#include "FGL_DEFINES.hpp" + namespace fgl::engine::memory { + template < typename T1 > + constexpr T1 combineAlignment( T1 first ) + { + return first; + } + + template < typename T1, typename T2 > + constexpr T1 combineAlignment( T1 first, T2 second ) + { + return std::max( first, static_cast< T1 >( second ) ); + } + + template < typename T1, typename... Ts > + requires( sizeof...( Ts ) > 0 ) + constexpr T1 combineAlignment( T1 first, Ts... extras ) + { + return combineAlignment( first, combineAlignment( extras... ) ); + } + //! Aligns a memory region to a given alignment template < typename T1, typename T2 > requires std::is_integral_v< T1 > && std::is_integral_v< T2 > @@ -16,23 +38,35 @@ namespace fgl::engine::memory { if ( alignment == 0 || alignment == 1 ) return operand; - if ( operand == alignment ) return operand; + const auto offset { operand % alignment }; + if ( offset == 0 ) return operand; + + // only go forward, going back might make us back into an already allocated area + return operand + ( alignment - offset ); + + // bitwise alignments only work for 2^x + /* if constexpr ( std::same_as< T1, T2 > ) { - return ( ( operand + ( alignment - 1 ) ) & ~( alignment - 1 ) ); + return ( ( operand + alignment - 1 ) & ~( alignment - 1 ) ); } else { - return ( ( operand + ( static_cast< T1 >( alignment ) - 1 ) ) & ~( static_cast< T1 >( alignment ) - 1 ) ); + return ( ( operand + static_cast< T1 >( alignment ) - 1 ) & ~( static_cast< T1 >( alignment ) - 1 ) ); } + */ } //! Aligns the operand to multiple alignments - template < typename T1, typename T2, typename... T2s > - constexpr T1 align( const T1 operand, const T2 alignment, const T2s... alignments ) + template < typename T1, typename... T2s > + constexpr T1 align( const T1 operand, const T2s... alignments ) { - return align( align( operand, alignment ), alignments... ); + const auto true_alignment { combineAlignment( alignments... ) }; + + const auto alignment { align( operand, true_alignment ) }; + + return alignment; } static_assert( align( 0, 1 ) == 0 ); @@ -40,5 +74,13 @@ namespace fgl::engine::memory static_assert( align( 256, 256 ) == 256 ); static_assert( align( 6, 32, 128 ) == 128 ); static_assert( align( 6, 1, 1, 6 ) == 6 ); + static_assert( combineAlignment( 44, 4 ) == 44 ); + static_assert( align( 123, 44, 4 ) % 44 == 0 ); + static_assert( align( 278528, 44 ) % 44 == 0 ); + static_assert( align( 278528, 4 ) % 4 == 0 ); + static_assert( align( 278529, 4 ) == 278528 + 4 ); + static_assert( align( 278528, 4 ) == 278528 ); + static_assert( align( 278527, 4 ) == 278528 ); + static_assert( align( 278528, 3 ) % 3 == 0 ); } // namespace fgl::engine::memory diff --git a/src/engine/memory/buffers/vector/BufferVector.cpp b/src/engine/memory/buffers/vector/BufferVector.cpp index 0197bcc..1fb52c4 100644 --- a/src/engine/memory/buffers/vector/BufferVector.cpp +++ b/src/engine/memory/buffers/vector/BufferVector.cpp @@ -10,20 +10,32 @@ namespace fgl::engine::memory { + constexpr std::uint32_t min_capacity { 1024 }; + [[nodiscard]] BufferVector::BufferVector( Buffer& buffer, std::uint32_t count, std::uint32_t stride ) : - BufferSuballocation( buffer.allocate( count * stride ) ), + BufferSuballocation( buffer.allocate( std::max( count, min_capacity ) * stride, stride ) ), m_count( count ), m_stride( stride ), - m_capacity( count ) - {} + m_capacity( std::max( count, min_capacity ) ) + { + FGL_ASSERT( m_stride > 0, "Stride was not greater then zero" ); + FGL_ASSERT( + m_offset % m_stride == 0, + std::format( + "{} % {} != 0 (Was {}). The offset should be aligned with the stride", + m_offset, + m_stride, + m_offset % m_stride ) ); + } //! Returns the offset count from the start of the buffer to the first element [[nodiscard]] std::uint32_t BufferVector::getOffsetCount() const { assert( !std::isnan( m_count ) ); assert( !std::isnan( m_stride ) ); - assert( m_count * m_stride == this->bytesize() ); - assert( m_offset % m_stride == 0 && "Offset must be aligned from the stride" ); + assert( m_capacity * m_stride == this->bytesize() ); + FGL_ASSERT( + m_offset % m_stride == 0, std::format( "{} % {} != 0 (Was {})", m_offset, m_stride, m_offset % m_stride ) ); return static_cast< std::uint32_t >( this->m_offset / m_stride ); } @@ -51,7 +63,6 @@ namespace fgl::engine::memory void BufferVector::resize( const std::uint32_t count ) { - assert( count > 0 ); assert( !std::isnan( m_stride ) ); assert( !std::isnan( m_count ) ); @@ -76,4 +87,32 @@ namespace fgl::engine::memory this->m_count = count; } + void BufferVector::resizeDiscard( const std::uint32_t count ) + { + assert( count > 0 ); + assert( !std::isnan( m_stride ) ); + assert( !std::isnan( m_count ) ); + + // we are reclaiming size + //TODO: Figure out a way to truely reclaim any size + if ( count < capacity() ) + { + m_count = count; + return; + } + + // the capacity is not enough for the new size, we must reallocate. + if ( count > capacity() ) + { + BufferVector other { this->getBuffer(), count, m_stride }; + + // discard doesn't want the old data, so we can safely just discard it + // TransferManager::getInstance().copyToVector( *this, other, 0 ); + + *this = std::move( other ); + } + + this->m_count = count; + } + } // namespace fgl::engine::memory \ No newline at end of file diff --git a/src/engine/memory/buffers/vector/BufferVector.hpp b/src/engine/memory/buffers/vector/BufferVector.hpp index 7a7e47d..bd90051 100644 --- a/src/engine/memory/buffers/vector/BufferVector.hpp +++ b/src/engine/memory/buffers/vector/BufferVector.hpp @@ -46,6 +46,7 @@ namespace fgl::engine::memory std::uint32_t size() const noexcept; std::uint32_t capacity() const noexcept; void resize( std::uint32_t count ); + void resizeDiscard( std::uint32_t count ); // void reserve( std::uint32_t count ); }; diff --git a/src/engine/memory/buffers/vector/DeviceVector.hpp b/src/engine/memory/buffers/vector/DeviceVector.hpp index c0dede5..6f3c235 100644 --- a/src/engine/memory/buffers/vector/DeviceVector.hpp +++ b/src/engine/memory/buffers/vector/DeviceVector.hpp @@ -7,8 +7,6 @@ #include "BufferVector.hpp" #include "concepts.hpp" #include "engine/assets/transfer/TransferManager.hpp" -#include "engine/debug/logging/logging.hpp" -#include "engine/math/literals/size.hpp" namespace fgl::engine::memory { @@ -17,18 +15,19 @@ namespace fgl::engine::memory namespace fgl::engine { + template < typename T > - class DeviceVector final : public memory::BufferVector, public memory::DeviceVectorBase + class DeviceVector : public memory::BufferVector, public memory::DeviceVectorBase { public: using Type = T; - DeviceVector( memory::Buffer& buffer, const std::uint32_t count = 1 ) : + DeviceVector( memory::Buffer& buffer, const std::uint32_t count = 0 ) : BufferVector( buffer, count, sizeof( T ) ) { - const auto size_str { fgl::literals::size_literals::toString( count * sizeof( T ) ) }; - assert( count != 0 && "BufferSuballocationVector::BufferSuballocationVector() called with count == 0" ); + // const auto size_str { literals::size_literals::toString( count * sizeof( T ) ) }; + // assert( count != 0 && "BufferSuballocationVector::BufferSuballocationVector() called with count == 0" ); } FGL_DELETE_COPY( DeviceVector ); @@ -45,7 +44,8 @@ namespace fgl::engine memory::TransferManager::getInstance().copyToVector< T, DeviceVector< T > >( data, *this ); } - void resize( const std::size_t new_size ) { BufferVector::resize( new_size ); } + // void resize( const std::size_t new_size ) { BufferVector::resize( new_size ); } + // void resizeDiscard( const uint32_t size ) { BufferVector::resizeDiscard( new_size ); } void updateData( const std::size_t idx, const T& data ) { diff --git a/src/engine/memory/buffers/vector/HostVector.hpp b/src/engine/memory/buffers/vector/HostVector.hpp index a1c0135..bce265a 100644 --- a/src/engine/memory/buffers/vector/HostVector.hpp +++ b/src/engine/memory/buffers/vector/HostVector.hpp @@ -9,9 +9,6 @@ namespace fgl::engine { - template < typename T > - class DeviceVector; - /** * A vector allocated with HOST memory. * @tparam T diff --git a/src/engine/memory/buffers/vector/IndexedVector.hpp b/src/engine/memory/buffers/vector/IndexedVector.hpp index b916a4d..62e0a42 100644 --- a/src/engine/memory/buffers/vector/IndexedVector.hpp +++ b/src/engine/memory/buffers/vector/IndexedVector.hpp @@ -4,35 +4,83 @@ #pragma once #include "DeviceVector.hpp" +#include "engine/debug/logging/logging.hpp" namespace fgl::engine { template < typename T > - class IndexedVector : DeviceVector< T > + class IndexedVector final : public DeviceVector< T > { std::queue< std::uint32_t > m_free_indexes {}; + std::uint32_t acquireInternal( const T& t ) + { + if ( m_free_indexes.empty() ) + { + log::warn( + "IndexedVector had to resize due to limited space. Size: {} Capacity: {}", + this->size(), + this->capacity() ); + this->resize( this->size() + 1 ); + m_free_indexes.push( this->size() - 1 ); + } + + const auto index { m_free_indexes.front() }; + m_free_indexes.pop(); + + return index; + } + public: + DeviceVector< T >& vec() { return static_cast< DeviceVector< T >& >( *this ); } + class Index { IndexedVector< T >& m_vector; - std::uint32_t m_idx; + std::uint32_t m_idx { std::numeric_limits< std::uint32_t >::max() }; public: - void update( const T& t ) + using GPUValue = std::uint32_t; + + GPUValue idx() const { - memory::TransferManager::getInstance() - .copyToVector< T, DeviceVector< T > >( m_vector.m_data, m_idx, t ); + FGL_ASSERT( m_idx != std::numeric_limits< std::uint32_t >::max(), "Invalid index" ); + return m_idx; + } + + using Vec = IndexedVector; + + void update( const T& t ) { return m_vector.updateData( m_idx, t ); } + + Index& operator=( const Index& other ) = delete; + + Index( const Index& other ) : m_vector( other.m_vector ), m_idx( m_vector.acquireInternal() ) + { + //TODO: Update the data from the original item + } + + Index& operator=( Index&& other ) = delete; + + Index( Index&& other ) noexcept : m_vector( other.m_vector ), m_idx( other.m_idx ) + { + other.m_idx = std::numeric_limits< std::uint32_t >::max(); + } + + // Privated to force returning to the IndexedVector + ~Index() + { + if ( m_idx == std::numeric_limits< std::uint32_t >::max() ) return; + + log::error( "Index must be returned to the IndexedVector" ); + std::terminate(); } private: Index( IndexedVector< T >& vector, const std::uint32_t idx ) : m_vector( vector ), m_idx( idx ) {} - - // Privated to force returning to the IndexedVector - ~Index() = default; + friend class IndexedVector; }; IndexedVector() = delete; @@ -43,15 +91,19 @@ namespace fgl::engine for ( std::uint32_t i = 0; i < desired_count; ++i ) m_free_indexes.push( i ); } - Index< T > acquire( const T& t ) + Index acquire( const T& t ) { if ( m_free_indexes.empty() ) { - resize( this->size() + 1 ); + log::warn( + "IndexedVector had to resize due to limited space. Size: {} Capacity: {}", + this->size(), + this->capacity() ); + this->resize( this->size() + 1 ); m_free_indexes.push( this->size() - 1 ); } - Index< T > index { *this, m_free_indexes.front() }; + Index index { *this, m_free_indexes.front() }; m_free_indexes.pop(); index.update( t ); @@ -59,10 +111,11 @@ namespace fgl::engine return index; } - void release( Index< T >&& index_i ) + void release( Index&& index_i ) { - Index< T > index { std::forward< Index< T > >( index_i ) }; + Index index { std::forward< Index >( index_i ) }; m_free_indexes.push( index.m_idx ); + index.m_idx = std::numeric_limits< std::uint32_t >::max(); } }; diff --git a/src/engine/rendering/PresentSwapChain.hpp b/src/engine/rendering/PresentSwapChain.hpp index 30dfed7..61de71a 100644 --- a/src/engine/rendering/PresentSwapChain.hpp +++ b/src/engine/rendering/PresentSwapChain.hpp @@ -102,8 +102,7 @@ namespace fgl::engine [[nodiscard]] float extentAspectRatio() const; [[nodiscard]] std::pair< vk::Result, PresentIndex > acquireNextImage(); - [[nodiscard]] vk::Result - submitCommandBuffers( const CommandBuffer& buffers, PresentIndex present_index ); + [[nodiscard]] vk::Result submitCommandBuffers( const CommandBuffer& buffers, PresentIndex present_index ); void transitionImages( const CommandBuffer& command_buffer, StageID stage_id, FrameIndex frame_index ); }; @@ -111,4 +110,11 @@ namespace fgl::engine template < typename T > using PerFrameArray = std::array< T, constants::MAX_FRAMES_IN_FLIGHT >; + template < typename T, typename... TArgs > + PerFrameArray< T > constructPerFrame( TArgs&... args ) + { + //TODO: Figure this out + return { { args..., args... } }; + } + } // namespace fgl::engine diff --git a/src/engine/rendering/pipelines/Attachment.hpp b/src/engine/rendering/pipelines/Attachment.hpp index b864127..386284e 100644 --- a/src/engine/rendering/pipelines/Attachment.hpp +++ b/src/engine/rendering/pipelines/Attachment.hpp @@ -117,7 +117,7 @@ namespace fgl::engine usage | vk::ImageUsageFlagBits::eInputAttachment | extra_flags, vk::ImageLayout::eUndefined, final_layout ) ) }; - image_views.emplace_back( itter->getView() ); + image_views.emplace_back( itter->getView( ) ); } } @@ -134,7 +134,7 @@ namespace fgl::engine for ( std::uint32_t i = 0; i < count; ++i ) { m_attachment_resources.m_images.emplace_back( image ); - m_attachment_resources.m_image_views.emplace_back( image->getView() ); + m_attachment_resources.m_image_views.emplace_back( image->getView( ) ); } } diff --git a/src/engine/rendering/pipelines/Shader.hpp b/src/engine/rendering/pipelines/Shader.hpp index 8d6f488..eae7da4 100644 --- a/src/engine/rendering/pipelines/Shader.hpp +++ b/src/engine/rendering/pipelines/Shader.hpp @@ -50,6 +50,11 @@ namespace fgl::engine return loadShader( path, vk::ShaderStageFlagBits::eFragment, ShaderType::Fragment ); } + static std::shared_ptr< Shader > loadCompute( const std::filesystem::path& path ) + { + return loadShader( path, vk::ShaderStageFlagBits::eCompute, ShaderType::Compute ); + } + //! Reloads the shader from disk void reload(); }; diff --git a/src/engine/rendering/pipelines/shaders/Compiler.cpp b/src/engine/rendering/pipelines/shaders/Compiler.cpp index 482e0c5..6586eec 100644 --- a/src/engine/rendering/pipelines/shaders/Compiler.cpp +++ b/src/engine/rendering/pipelines/shaders/Compiler.cpp @@ -93,13 +93,27 @@ namespace fgl::engine std::call_once( once, setupGlobalSession ); SessionDesc session_desc {}; - session_desc.defaultMatrixLayoutMode = SLANG_MATRIX_LAYOUT_COLUMN_MAJOR; +#ifdef NDEBUG std::array< CompilerOptionEntry, 1 > options { - { { CompilerOptionName::VulkanUseEntryPointName, - { .kind = CompilerOptionValueKind::Int, .intValue0 = 1 } } } + { { .name = CompilerOptionName::VulkanUseEntryPointName, + .value = { .kind = CompilerOptionValueKind::Int, .intValue0 = 1 } } } }; +#else + std::array< CompilerOptionEntry, 4 > options { { + { .name = CompilerOptionName::VulkanUseEntryPointName, + .value = { .kind = CompilerOptionValueKind::Int, .intValue0 = true } }, + { .name = CompilerOptionName::Optimization, + .value = { .kind = CompilerOptionValueKind::Int, + .intValue0 = static_cast< int32_t >( SLANG_OPTIMIZATION_LEVEL_NONE ) } }, + { .name = CompilerOptionName::DebugInformation, + .value = { .kind = CompilerOptionValueKind::Int, + .intValue0 = static_cast< int32_t >( SLANG_DEBUG_INFO_LEVEL_MAXIMAL ) } }, + { .name = CompilerOptionName::EmitSpirvDirectly, + .value = { .kind = CompilerOptionValueKind::Int, .intValue0 = static_cast< int32_t >( true ) } }, + } }; +#endif session_desc.compilerOptionEntries = options.data(); session_desc.compilerOptionEntryCount = options.size(); @@ -135,7 +149,7 @@ namespace fgl::engine switch ( type ) { - case ShaderType::Compute: + case Compute: entry_point_name = "computeMain"; break; case Vertex: @@ -171,7 +185,6 @@ namespace fgl::engine layout->toJson( json_glob.writeRef() ); #ifndef NDEBUG - // dump the compilation layout json to a file std::filesystem::create_directory( parent_path / "dumps" ); const std::string file_name { std::format( "{}-{}.json", path.stem().string(), entry_point_name ) }; diff --git a/src/engine/rendering/pipelines/v2/Pipeline.cpp b/src/engine/rendering/pipelines/v2/Pipeline.cpp index 4233c32..917e72d 100644 --- a/src/engine/rendering/pipelines/v2/Pipeline.cpp +++ b/src/engine/rendering/pipelines/v2/Pipeline.cpp @@ -20,10 +20,12 @@ namespace fgl::engine Pipeline::Pipeline( vk::raii::Pipeline&& pipeline_in, vk::raii::PipelineLayout&& layout, + vk::PipelineBindPoint bind_point, std::unique_ptr< PipelineBuilder::BuilderState >&& builder_state ) : m_pipeline( std::move( pipeline_in ) ), m_layout( std::move( layout ) ), - m_builder_state( std::forward< std::unique_ptr< PipelineBuilder::BuilderState > >( builder_state ) ) + m_builder_state( std::forward< std::unique_ptr< PipelineBuilder::BuilderState > >( builder_state ) ), + m_bind_point( bind_point ) {} void Pipeline::bind( CommandBuffer& cmd_buffer ) @@ -40,7 +42,7 @@ namespace fgl::engine } } - cmd_buffer->bindPipeline( vk::PipelineBindPoint::eGraphics, m_pipeline ); + cmd_buffer->bindPipeline( m_bind_point, m_pipeline ); } void Pipeline::bindDescriptor( @@ -51,7 +53,9 @@ namespace fgl::engine const std::vector< vk::DescriptorSet > sets { *set }; constexpr std::vector< std::uint32_t > offsets {}; - command_buffer->bindDescriptorSets( vk::PipelineBindPoint::eGraphics, m_layout, descriptor_idx, sets, offsets ); + FGL_ASSERT( !set.hasUpdates(), "Descriptor set has updates but binding was attempted" ); + + command_buffer->bindDescriptorSets( m_bind_point, m_layout, descriptor_idx, sets, offsets ); } void Pipeline::bindDescriptor( CommandBuffer& comd_buffer, descriptors::DescriptorSet& set ) diff --git a/src/engine/rendering/pipelines/v2/Pipeline.hpp b/src/engine/rendering/pipelines/v2/Pipeline.hpp index 5bc51a4..04a0be8 100644 --- a/src/engine/rendering/pipelines/v2/Pipeline.hpp +++ b/src/engine/rendering/pipelines/v2/Pipeline.hpp @@ -20,6 +20,7 @@ namespace fgl::engine vk::raii::Pipeline m_pipeline; vk::raii::PipelineLayout m_layout; std::unique_ptr< PipelineBuilder::BuilderState > m_builder_state; + vk::PipelineBindPoint m_bind_point; vk::raii::Pipeline rebuildPipeline(); @@ -29,6 +30,7 @@ namespace fgl::engine Pipeline( vk::raii::Pipeline&& pipeline_in, vk::raii::PipelineLayout&& layout, + vk::PipelineBindPoint bind_point, std::unique_ptr< PipelineBuilder::BuilderState >&& builder_state ); void bind( CommandBuffer& cmd_buffer ); @@ -45,6 +47,8 @@ namespace fgl::engine { command_buffer->pushConstants< T >( m_layout, stage, 0, { t } ); } + + const vk::raii::PipelineLayout& layout() const { return m_layout; } }; } // namespace fgl::engine diff --git a/src/engine/rendering/pipelines/v2/PipelineBuilder.cpp b/src/engine/rendering/pipelines/v2/PipelineBuilder.cpp index a919306..4e625e7 100644 --- a/src/engine/rendering/pipelines/v2/PipelineBuilder.cpp +++ b/src/engine/rendering/pipelines/v2/PipelineBuilder.cpp @@ -29,6 +29,11 @@ namespace fgl::engine m_state->shaders.fragment = std::forward< std::shared_ptr< Shader > >( shader ); } + void PipelineBuilder::setComputeShader( std::shared_ptr< Shader >&& shader ) + { + m_state->shaders.compute = std::forward< std::shared_ptr< Shader > >( shader ); + } + vk::raii::Pipeline PipelineBuilder:: createRenderPassPipeline( BuilderState& state, const vk::raii::PipelineLayout& layout ) { @@ -82,7 +87,32 @@ namespace fgl::engine return pipeline; } + vk::raii::Pipeline PipelineBuilder::createComputePipeline( BuilderState& state, vk::raii::PipelineLayout& layout ) + { + vk::StructureChain< vk::ComputePipelineCreateInfo > chain {}; + + vk::ComputePipelineCreateInfo& info { chain.get< vk::ComputePipelineCreateInfo >() }; + + info.pNext = VK_NULL_HANDLE; + info.flags = {}; + + info.stage = state.shaders.compute->stage_info; + info.layout = layout; + info.basePipelineHandle = VK_NULL_HANDLE; + info.basePipelineIndex = -1; + + state.bind_point = vk::PipelineBindPoint::eCompute; + + return Device::getInstance()->createComputePipeline( VK_NULL_HANDLE, info ); + } + vk::raii::Pipeline PipelineBuilder::createDynamicPipeline( BuilderState& state, vk::raii::PipelineLayout& layout ) + { + if ( state.shaders.compute ) return createComputePipeline( state, layout ); + return createGraphicsPipeline( state, layout ); + } + + vk::raii::Pipeline PipelineBuilder::createGraphicsPipeline( BuilderState& state, vk::raii::PipelineLayout& layout ) { vk::StructureChain< vk::GraphicsPipelineCreateInfo, vk::PipelineRenderingCreateInfo > chain {}; vk::GraphicsPipelineCreateInfo& info { chain.get< vk::GraphicsPipelineCreateInfo >() }; @@ -137,6 +167,8 @@ namespace fgl::engine if ( state.m_dynamic_state.size() > 0 ) info.setPDynamicState( &dynamic_state_create_info ); + state.bind_point = vk::PipelineBindPoint::eGraphics; + vk::raii::Pipeline pipeline { Device::getInstance()->createGraphicsPipeline( VK_NULL_HANDLE, info ) }; return pipeline; @@ -210,6 +242,11 @@ namespace fgl::engine m_state->push_constant.stageFlags = flags; } + void PipelineBuilder::setBindPoint( vk::PipelineBindPoint bind_point ) + { + m_state->bind_point = bind_point; + } + PipelineBuilder::BuilderState::Formats::Formats() {} @@ -339,15 +376,16 @@ namespace fgl::engine { // Precheck { - FGL_ASSERT( m_state->shaders.fragment, "Pipeline requires fragment shader" ); - FGL_ASSERT( m_state->shaders.vertex, "Pipeline requires vertex shader" ); + // FGL_ASSERT( m_state->shaders.fragment, "Pipeline requires fragment shader" ); + // FGL_ASSERT( m_state->shaders.vertex, "Pipeline requires vertex shader" ); } vk::raii::PipelineLayout layout { createLayout() }; vk::raii::Pipeline pipeline { createFromState( *m_state, layout ) }; - return std::make_unique< Pipeline >( std::move( pipeline ), std::move( layout ), std::move( m_state ) ); + return std::make_unique< + Pipeline >( std::move( pipeline ), std::move( layout ), m_state->bind_point, std::move( m_state ) ); } void setGBufferOutputAttachments( PipelineBuilder::BuilderState& config ) diff --git a/src/engine/rendering/pipelines/v2/PipelineBuilder.hpp b/src/engine/rendering/pipelines/v2/PipelineBuilder.hpp index 24fe019..2198a2c 100644 --- a/src/engine/rendering/pipelines/v2/PipelineBuilder.hpp +++ b/src/engine/rendering/pipelines/v2/PipelineBuilder.hpp @@ -38,6 +38,15 @@ namespace fgl::engine void addDescriptorSet( descriptors::DescriptorSetLayout& descriptor ); void addDynamicState( vk::DynamicState dynamic_state ); void setPushConstant( vk::ShaderStageFlags flags, std::uint32_t size ); + void setBindPoint( vk::PipelineBindPoint bind_point ); + + template < typename T > + void addPushConstants( vk::ShaderStageFlags stage_flags, const std::uint16_t offset = 0 ) + { + m_state->push_constant.offset = offset; + m_state->push_constant.size = sizeof( T ); + m_state->push_constant.stageFlags = stage_flags; + } struct BuilderState { @@ -55,6 +64,7 @@ namespace fgl::engine { std::shared_ptr< Shader > vertex { nullptr }; std::shared_ptr< Shader > fragment { nullptr }; + std::shared_ptr< Shader > compute { nullptr }; } shaders {}; std::unordered_map< SetID, vk::DescriptorSetLayout > descriptor_set_layouts {}; @@ -78,6 +88,7 @@ namespace fgl::engine } formats {}; uint32_t m_subpass_stage; + vk::PipelineBindPoint bind_point; vk::PipelineColorBlendAttachmentState& addColorAttachment(); @@ -119,11 +130,16 @@ namespace fgl::engine void setVertexShader( std::shared_ptr< Shader >&& shader ); void setFragmentShader( std::shared_ptr< Shader >&& shader ); + void setComputeShader( std::shared_ptr< Shader >&& shader ); static vk::raii::Pipeline createRenderPassPipeline( BuilderState& state, const vk::raii::PipelineLayout& layout ); + static vk::raii::Pipeline createDynamicPipeline( BuilderState& state, vk::raii::PipelineLayout& layout ); + static vk::raii::Pipeline createComputePipeline( BuilderState& state, vk::raii::PipelineLayout& layout ); + static vk::raii::Pipeline createGraphicsPipeline( BuilderState& state, vk::raii::PipelineLayout& layout ); + static vk::raii::Pipeline createFromState( BuilderState& state, vk::raii::PipelineLayout& layout ); static vk::raii::Pipeline rebuildFromState( BuilderState& state, vk::raii::PipelineLayout& layout ); diff --git a/src/engine/scene/World.cpp b/src/engine/scene/World.cpp index d99cd14..49c9a4c 100644 --- a/src/engine/scene/World.cpp +++ b/src/engine/scene/World.cpp @@ -6,6 +6,7 @@ namespace fgl::engine { + /* bool World::sceneExists( const std::string& name ) { return std::ranges:: @@ -40,5 +41,6 @@ namespace fgl::engine World::World( const std::filesystem::path& path ) {} + */ } // namespace fgl::engine diff --git a/src/engine/scene/World.hpp b/src/engine/scene/World.hpp index be773d2..8b0ceaa 100644 --- a/src/engine/scene/World.hpp +++ b/src/engine/scene/World.hpp @@ -14,6 +14,7 @@ namespace fgl::engine * a world is comprised up of multiple scenes. Only one world can be running at any given time * */ + /* class World { std::vector< std::shared_ptr< Scene > > m_scenes {}; @@ -35,5 +36,6 @@ namespace fgl::engine ~World() = default; }; + */ } // namespace fgl::engine \ No newline at end of file diff --git a/src/engine/systems/prerender/CullingSystem.cpp b/src/engine/systems/prerender/CullingSystem.cpp index 86d88da..b069779 100644 --- a/src/engine/systems/prerender/CullingSystem.cpp +++ b/src/engine/systems/prerender/CullingSystem.cpp @@ -6,6 +6,7 @@ #include +#include "assets/model/Model.hpp" #include "engine/FrameInfo.hpp" #include "engine/camera/Camera.hpp" @@ -18,20 +19,30 @@ namespace fgl::engine return enable_culling; } - CullingSystem::CullingSystem() : m_thread( &CullingSystem::runner, this ) - {} + struct CullPushConstants + { + std::uint32_t draw_count; + std::uint32_t start_idx; + }; + + CullingSystem::CullingSystem() + { + PipelineBuilder builder { 0 }; + + builder.addDescriptorSet( PRIMITIVE_SET ); + builder.addDescriptorSet( INSTANCES_SET ); + builder.addDescriptorSet( COMMANDS_SET ); + + builder.addPushConstants< CullPushConstants >( vk::ShaderStageFlagBits::eCompute ); + + builder.setComputeShader( Shader::loadCompute( "shaders/culling.slang" ) ); + + m_cull_compute = builder.create(); + m_cull_compute->setDebugName( "Culling" ); + } CullingSystem::~CullingSystem() - { - m_info = {}; - m_start_sem.release(); - if ( !m_source.request_stop() ) - { - log::critical( "Oh shit" ); - std::terminate(); - } - m_thread.join(); - } + {} void CullingSystem::pass( FrameInfo& info ) { @@ -44,31 +55,42 @@ namespace fgl::engine return; } - auto leafs { info.game_objects.getAllLeafsInFrustum( frustum ) }; + auto& command_buffer { info.command_buffer.render_cb }; - info.in_view_leafs = std::move( leafs ); - } + m_cull_compute->bind( command_buffer ); - void CullingSystem::runner() - { - TracyCSetThreadName( "Culling thread" ); - while ( !m_stop_token.stop_requested() ) - { - m_start_sem.acquire(); - if ( m_info.has_value() ) pass( *m_info.value() ); - m_end_sem.release(); - } - } + m_cull_compute->bindDescriptor( command_buffer, info.m_primitives_desc ); // primitive set + m_cull_compute->bindDescriptor( command_buffer, info.m_instances_desc ); // instances + m_cull_compute->bindDescriptor( command_buffer, info.m_command_buffer_desc ); // commands output - void CullingSystem::startPass( FrameInfo& info ) - { - m_info = &info; - m_start_sem.release(); - } + CullPushConstants push_constants {}; + push_constants.draw_count = info.m_commands.size(); - void CullingSystem::wait() - { - m_end_sem.acquire(); + command_buffer->pushConstants< + CullPushConstants >( m_cull_compute->layout(), vk::ShaderStageFlagBits::eCompute, 0, { push_constants } ); + + constexpr std::uint32_t dispatch_count { 64 }; + + // calculate number of workgroups needed + const std::uint32_t group_count { ( push_constants.draw_count + dispatch_count - 1 ) / dispatch_count }; + + command_buffer->dispatch( group_count, 1, 1 ); + + // Add a memory barrier to ensure synchronization between the compute and subsequent stages + vk::MemoryBarrier memory_barrier { + vk::AccessFlagBits::eShaderWrite, + vk::AccessFlagBits::eVertexAttributeRead | vk::AccessFlagBits::eIndirectCommandRead, + }; + + command_buffer->pipelineBarrier( + vk::PipelineStageFlagBits::eComputeShader, // Source: Compute shader + vk::PipelineStageFlagBits::eDrawIndirect | // Destination: Indirect drawing + vk::PipelineStageFlagBits::eVertexInput, // ... and vertex input + {}, // Dependency flags + { memory_barrier }, // Memory barrier for synchronization + {}, // No buffer barrier + {} // No image barrier + ); } } // namespace fgl::engine diff --git a/src/engine/systems/prerender/CullingSystem.hpp b/src/engine/systems/prerender/CullingSystem.hpp index f6eb344..2478118 100644 --- a/src/engine/systems/prerender/CullingSystem.hpp +++ b/src/engine/systems/prerender/CullingSystem.hpp @@ -7,6 +7,7 @@ #include #include "engine/systems/concepts.hpp" +#include "rendering/pipelines/v2/Pipeline.hpp" namespace fgl::engine { @@ -14,18 +15,20 @@ namespace fgl::engine class CullingSystem { - std::thread m_thread; + // std::thread m_thread; - std::optional< FrameInfo* > m_info { std::nullopt }; - std::stop_source m_source {}; - std::stop_token m_stop_token { m_source.get_token() }; + // std::optional< FrameInfo* > m_info { std::nullopt }; + // std::stop_source m_source {}; + // std::stop_token m_stop_token { m_source.get_token() }; - void runner(); + std::unique_ptr< Pipeline > m_cull_compute { nullptr }; - //Semaphore to signal the thread to start - std::binary_semaphore m_start_sem { 0 }; + // void runner(); - std::binary_semaphore m_end_sem { 0 }; + // Semaphore to signal the thread to start + // std::binary_semaphore m_start_sem { 0 }; + + // std::binary_semaphore m_end_sem { 0 }; public: @@ -36,12 +39,9 @@ namespace fgl::engine ~CullingSystem(); void pass( FrameInfo& info ); - void startPass( FrameInfo& info ); - - void wait(); }; static_assert( is_system< CullingSystem > ); - static_assert( is_threaded_system< CullingSystem > ); + // static_assert( is_threaded_system< CullingSystem > ); } // namespace fgl::engine diff --git a/src/engine/systems/render/EntityRendererSystem.cpp b/src/engine/systems/render/EntityRendererSystem.cpp index 3e3d4b2..ce07c98 100644 --- a/src/engine/systems/render/EntityRendererSystem.cpp +++ b/src/engine/systems/render/EntityRendererSystem.cpp @@ -7,9 +7,10 @@ #include #include +#include "EngineContext.hpp" +#include "assets/model/ModelVertex.hpp" #include "engine/assets/material/Material.hpp" #include "engine/camera/Camera.hpp" -#include "engine/debug/profiling/counters.hpp" #include "engine/debug/timing/FlameGraph.hpp" #include "engine/rendering/pipelines/v2/Pipeline.hpp" #include "engine/rendering/pipelines/v2/PipelineBuilder.hpp" @@ -66,7 +67,7 @@ namespace fgl::engine TracyVkZone( info.tracy_ctx, **command_buffer, "Render entities" ); auto timer = debug::timing::push( "Render entities" ); - texturelessPass( info ); + // texturelessPass( info ); texturedPass( info ); } @@ -84,25 +85,22 @@ namespace fgl::engine m_textured_pipeline->bindDescriptor( command_buffer, Texture::getDescriptorSet() ); m_textured_pipeline->bindDescriptor( command_buffer, Material::getDescriptorSet() ); - auto& model_matrix_info_buffer { m_textured_model_matrix_info_buffers[ info.frame_idx ] }; - model_matrix_info_buffer = - std::make_unique< ModelMatrixInfoBufferSuballocation >( info.model_matrix_info_buffer, model_matricies ); + auto& model_buffers { getModelBuffers() }; - auto& draw_parameter_buffer { m_draw_textured_parameter_buffers[ info.frame_idx ] }; - draw_parameter_buffer = - std::make_unique< DrawParameterBufferSuballocation >( info.draw_parameter_buffer, draw_commands ); + const std::vector< vk::Buffer > vert_buffers { + model_buffers.m_vertex_buffer.getVkBuffer(), + model_buffers.m_generated_instance_info[ info.in_flight_idx ].getVkBuffer() + }; - const std::vector< vk::Buffer > vert_buffers { info.model_vertex_buffer.getVkBuffer(), - model_matrix_info_buffer->getVkBuffer() }; - - command_buffer->bindVertexBuffers( 0, vert_buffers, { 0, model_matrix_info_buffer->getOffset() } ); - command_buffer->bindIndexBuffer( info.model_index_buffer.getVkBuffer(), 0, vk::IndexType::eUint32 ); + command_buffer->bindVertexBuffers( + 0, vert_buffers, { 0, model_buffers.m_generated_instance_info[ info.in_flight_idx ].getOffset() } ); + command_buffer->bindIndexBuffer( model_buffers.m_index_buffer.getVkBuffer(), 0, vk::IndexType::eUint32 ); command_buffer->drawIndexedIndirect( - draw_parameter_buffer->getVkBuffer(), - draw_parameter_buffer->getOffset(), - draw_parameter_buffer->size(), - draw_parameter_buffer->stride() ); + info.m_commands.getVkBuffer(), + info.m_commands.getOffset(), + info.m_commands.size(), + info.m_commands.stride() ); }; } // namespace fgl::engine diff --git a/src/engine/systems/render/EntityRendererSystem.hpp b/src/engine/systems/render/EntityRendererSystem.hpp index b378445..7166485 100644 --- a/src/engine/systems/render/EntityRendererSystem.hpp +++ b/src/engine/systems/render/EntityRendererSystem.hpp @@ -6,6 +6,7 @@ #include +#include "assets/model/ModelInstance.hpp" #include "engine/assets/model/Model.hpp" #include "engine/memory/buffers/vector/HostVector.hpp" #include "engine/rendering/PresentSwapChain.hpp" @@ -25,10 +26,10 @@ namespace fgl::engine class EntityRendererSystem { //! Standard pipeline for textureless models - std::unique_ptr< Pipeline > m_standard_pipeline {}; + std::unique_ptr< Pipeline > m_standard_pipeline; //! Pipeline for basic textured models (Single texture) - std::unique_ptr< Pipeline > m_textured_pipeline {}; + std::unique_ptr< Pipeline > m_textured_pipeline; // std::unique_ptr< ComputePipeline > m_cull_pipeline {}; using DrawParameterBufferSuballocation = HostVector< vk::DrawIndexedIndirectCommand >; diff --git a/src/engine/systems/render/LineDrawer.cpp b/src/engine/systems/render/LineDrawer.cpp index c5eaa8b..8e5450c 100644 --- a/src/engine/systems/render/LineDrawer.cpp +++ b/src/engine/systems/render/LineDrawer.cpp @@ -8,7 +8,6 @@ #include "engine/assets/model/SimpleVertex.hpp" #include "engine/camera/Camera.hpp" #include "engine/debug/drawers.hpp" -#include "engine/memory/buffers/vector/HostVector.hpp" #include "engine/primitives/points/Coordinate.hpp" #include "engine/rendering/pipelines/v2/Pipeline.hpp" #include "engine/rendering/pipelines/v2/PipelineBuilder.hpp" @@ -60,6 +59,7 @@ namespace fgl::engine void LineDrawer::pass( FrameInfo& info ) { + /* ZoneScopedN( "LineDrawer::pass" ); debug::drawAxisHelper(); @@ -79,6 +79,7 @@ namespace fgl::engine command_buffer->draw( static_cast< std::uint32_t >( m_lines.size() * 2 ), static_cast< std::uint32_t >( m_lines.size() ), 0, 0 ); + */ m_lines.clear(); } diff --git a/src/engine/systems/render/ShadowRenderer.cpp b/src/engine/systems/render/ShadowRenderer.cpp index 8d7a91d..b81bea3 100644 --- a/src/engine/systems/render/ShadowRenderer.cpp +++ b/src/engine/systems/render/ShadowRenderer.cpp @@ -16,7 +16,7 @@ namespace fgl::engine auto& command_buffer { setupSystem( info ) }; //TODO: Implement object culling for shadowmaps - if ( draw_commands.empty() ) return; + // if ( draw_commands.empty() ) return; m_pipeline->bind( command_buffer ); } diff --git a/src/shaders/culling.slang b/src/shaders/culling.slang index f419c08..91ed11d 100644 --- a/src/shaders/culling.slang +++ b/src/shaders/culling.slang @@ -6,49 +6,53 @@ import objects.frustum; import objects.gamemodel; +// in(vf) +ConstantBuffer< AxisAlignedBoundingBox > bounding_boxes[] : AA_BOUNDS; -struct ModelInstance -{ - uint32_t model_index; - mat4x4 matrix; -}; - -RWStructuredBuffer< vk::DrawIndexedIndirectCommand > commands : COMMANDS; -RWStructuredBuffer< ModelInstance > instances : COMMAND_INSTANCES; - -ConstantBuffer< AxisAlignedBoundingBox > bounding_boxes[] : BOUNDS; - +// in constant (push constant maybe?:tm:) ConstantBuffer< Frustum > frustum : FRUSTUM; -ConstantBuffer< ModelInstance > model_instances[] : MODEL_INSTANCES; -ConstantBuffer< GameModel > models[] : MODELS; +// in(c) +[[vk::binding(0,0)]] +StructuredBuffer< PrimitiveRenderInfo > primitives : PRIMITIVES; + +// in(vr) +[[vk::binding(0,1)]] +StructuredBuffer< PrimitiveInstanceInfo > primitive_instances : PRIMITIVE_INSTANCES; + +[ [ vk::binding( 1, 1 ) ] ] +StructuredBuffer< ModelInstanceInfo > model_instances : MODEL_INSTANCES; + +// out +[[vk::binding(0,2)]] +RWStructuredBuffer< vk::DrawIndexedIndirectCommand > commands : COMMANDS; + +// vertex info generated from compute shader. This information is used in the rendering process +[ [ vk::binding( 1, 2 ) ] ] +RWStructuredBuffer< InstanceRenderInfo, ScalarDataLayout > out_instances : OUT_INSTANCES; //TODO: shader command constants struct PushConstants { // number of total models and their instances uint32_t draw_count; - uint32_t start_idx; - uint32_t end_idx; }; -ConstantBuffer pc; - +[[push_constant]] +PushConstants pc; [[shader("compute")]] [numthreads(64,1,1)] -void main( uint3 dispatch_id : SV_DispatchThreadID) +void computeMain( uint3 dispatch_id : SV_DispatchThreadID) { // this will be dispatched with 0..N instances, each thread will be 1 instance from `model_instances` - uint instance_index = pc.start_idx + dispatch_id.x; // global thread + // each instance of this represents a unique primitive to be rendered + const uint instance_index = dispatch_id.x; // global thread - if ( dispatch_id.x > pc.end_idx ) return; if ( instance_index > pc.draw_count ) return; - ModelInstance model_instance = model_instances[ instance_index ]; - var model_index = model_instance.model_index; - - GameModel model = models[ model_index ]; + const PrimitiveInstanceInfo instance = primitive_instances[ instance_index ]; + const PrimitiveRenderInfo primitive = primitives[ instance.render_info_id ]; //TODO: Cull (For now we will just pretend it's all in view) @@ -56,30 +60,29 @@ void main( uint3 dispatch_id : SV_DispatchThreadID) if ( in_view ) { - uint32_t old_instance_count = 0; - InterlockedAdd( commands[ model_index ].instance_count, 1, old_instance_count ); + // We instead will use the simpler approach of having a unique draw command for each instance of the model. in the future we might have a seperate processing segment for high-count items. + vk::DrawIndexedIndirectCommand command; + command.first_index = primitive.first_index; + command.index_count = primitive.index_count; - var command = &commands[ model_index ]; + command.first_instance = instance_index; + command.instance_count = 1; - // if the old instance count was zero, we are the first command and need to populate. - if ( old_instance_count == 0 ) - { - // first index, populate the command's data + command.vertex_offset = primitive.first_vertex; - //TODO: Populate from GameModel once i've actually implemented that class properly - command->first_index = 0; - command->index_count = 0; - command->vertex_offset = 0; + commands[ instance_index ] = command; - atomicAdd( command->first_instance, instance_index ); - } + out_instances[instance_index].mat_id = instance.material_id; - barrier(); - - var idx = command->first_instance + old_instance_count; - - instances[ instance_index ] = model_instances[ idx ]; + const ModelInstanceInfo model_instance = model_instances[ instance.model_index ]; + out_instances[ instance_index ].matrix = model_instance.model_matrix; } + else + { + const vk::DrawIndexedIndirectCommand default_command = vk::DrawIndexedIndirectCommand( 0, 0, 0, 0, 0 ); + commands[ instance_index ] = default_command; + } + } diff --git a/src/shaders/objects/gamemodel.slang b/src/shaders/objects/gamemodel.slang index d434b78..cca3d16 100644 --- a/src/shaders/objects/gamemodel.slang +++ b/src/shaders/objects/gamemodel.slang @@ -1,9 +1,29 @@ #version 450 -struct GameModel { - +struct PrimitiveRenderInfo { + //! Where in the buffer the first vertex lies + uint32_t first_vertex; + //! Where in the buffer the first index would be + uint32_t first_index; + //! Number of indicies there are + uint32_t index_count; }; +struct PrimitiveInstanceInfo +{ + uint32_t render_info_id; + uint32_t model_index; + uint32_t material_id; +} +struct InstanceRenderInfo +{ + mat4x4 matrix; + uint32_t mat_id; +} + +struct ModelInstanceInfo { + mat4x4 model_matrix; +}; diff --git a/src/shaders/textured.slang b/src/shaders/textured.slang index 3be8d68..a543a3a 100644 --- a/src/shaders/textured.slang +++ b/src/shaders/textured.slang @@ -59,7 +59,8 @@ GBufferFragment fragmentMain( CoarseVertex vertex ) if ( vertex.material_id == INVALID_TEXTURE_ID ) { - discard; + frag.color = vec4( 227.0 / 255.0, 61. / 255.0, 148.0 / 255.0, 1.0 ); + return frag; } Material material = materials[vertex.material_id];