Get GPU driven rendering mostly working
This commit is contained in:
2
dependencies/slang
vendored
2
dependencies/slang
vendored
Submodule dependencies/slang updated: a70113c425...680fb0b4e9
@@ -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
|
||||
|
||||
31
src/editor/src/components/TransformComponent.cpp
Normal file
31
src/editor/src/components/TransformComponent.cpp
Normal file
@@ -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
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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 };
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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 };
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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 )
|
||||
{
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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 );
|
||||
};
|
||||
|
||||
@@ -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 >;
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
//
|
||||
#include "MaterialManager.hpp"
|
||||
|
||||
#include "engine/debug/logging/logging.hpp"
|
||||
#include "engine/math/literals/size.hpp"
|
||||
#include "material/Material.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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <memory>
|
||||
|
||||
#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;
|
||||
|
||||
@@ -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 ) };
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -6,39 +6,53 @@
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -15,13 +15,22 @@
|
||||
#include <vector>
|
||||
|
||||
#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;
|
||||
|
||||
@@ -6,9 +6,8 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#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()
|
||||
|
||||
17
src/engine/assets/model/ModelInstanceInfo.hpp
Normal file
17
src/engine/assets/model/ModelInstanceInfo.hpp
Normal file
@@ -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
|
||||
@@ -1,10 +0,0 @@
|
||||
//
|
||||
// Created by kj16609 on 3/12/25.
|
||||
//
|
||||
#include "ModelManager.hpp"
|
||||
|
||||
|
||||
namespace fgl::engine
|
||||
{
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <tracy/Tracy.hpp>
|
||||
|
||||
#include "engine/assets/model/Primitive.hpp"
|
||||
#include "engine/assets/model/ModelVertex.hpp"
|
||||
|
||||
namespace fgl::engine
|
||||
{
|
||||
|
||||
@@ -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" );
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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>& 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();
|
||||
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
|
||||
#include "ComponentIDS.hpp"
|
||||
#include "engine/gameobjects/components/interface/GameObjectComponent.hpp"
|
||||
|
||||
namespace fgl::engine
|
||||
|
||||
@@ -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
|
||||
@@ -6,28 +6,30 @@
|
||||
#include <memory>
|
||||
|
||||
#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 > );
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -4,11 +4,33 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <type_traits>
|
||||
|
||||
#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
|
||||
|
||||
@@ -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
|
||||
@@ -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 );
|
||||
};
|
||||
|
||||
|
||||
@@ -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 )
|
||||
{
|
||||
|
||||
@@ -9,9 +9,6 @@
|
||||
namespace fgl::engine
|
||||
{
|
||||
|
||||
template < typename T >
|
||||
class DeviceVector;
|
||||
|
||||
/**
|
||||
* A vector allocated with HOST memory.
|
||||
* @tparam T
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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( ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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 ) };
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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 );
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <tracy/TracyC.h>
|
||||
|
||||
#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
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <thread>
|
||||
|
||||
#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
|
||||
|
||||
@@ -7,9 +7,10 @@
|
||||
#include <tracy/TracyC.h>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#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
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#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 >;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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<PushConstants> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user