diff --git a/src/engine/CMakeLists.txt b/src/engine/CMakeLists.txt index 648b9c4..15fe547 100644 --- a/src/engine/CMakeLists.txt +++ b/src/engine/CMakeLists.txt @@ -9,11 +9,6 @@ add_library(FGLEngine STATIC ${CPP_SOURCES} ${HPP_SOURCES}) set(CMAKE_CXX_STANDARD 23) target_precompile_headers(FGLEngine PRIVATE - - - - - diff --git a/src/engine/EngineContext.cpp b/src/engine/EngineContext.cpp index 67aa310..68b692f 100644 --- a/src/engine/EngineContext.cpp +++ b/src/engine/EngineContext.cpp @@ -40,7 +40,7 @@ namespace fgl::engine static Average< float, 60 * 15 > rolling_ms_average; - void preStage( vk::CommandBuffer& cmd_buffer ) + void preStage( vk::raii::CommandBuffer& cmd_buffer ) { ZoneScopedN( "Pre-Stage" ); @@ -155,7 +155,7 @@ namespace fgl::engine camera_controller.moveInPlaneXZ( m_window.window(), delta_time, viewer ); camera.setView( viewer.getPosition(), viewer.getRotation() ); - if ( auto command_buffer = m_renderer.beginFrame(); command_buffer ) + if ( auto& command_buffer = m_renderer.beginFrame(); *command_buffer ) { preStage( command_buffer ); @@ -188,7 +188,7 @@ namespace fgl::engine camera_info[ frame_index ] = current_camera_info; m_culling_system.startPass( frame_info ); - TracyVkCollect( frame_info.tracy_ctx, command_buffer ); + TracyVkCollect( frame_info.tracy_ctx, *command_buffer ); m_culling_system.wait(); m_renderer.beginSwapchainRendererPass( command_buffer ); diff --git a/src/engine/EngineContext.hpp b/src/engine/EngineContext.hpp index ee207a5..5b2b029 100644 --- a/src/engine/EngineContext.hpp +++ b/src/engine/EngineContext.hpp @@ -30,7 +30,7 @@ namespace fgl::engine Device device { m_window, m_instance }; - Renderer m_renderer { m_window }; + Renderer m_renderer { m_window, device.phyDevice() }; //GameObject::Map game_objects {}; OctTreeNode m_game_objects_root { WorldCoordinate( constants::WORLD_CENTER ) }; diff --git a/src/engine/FGL_DEFINES.hpp b/src/engine/FGL_DEFINES.hpp index 844d2c3..5050ae9 100644 --- a/src/engine/FGL_DEFINES.hpp +++ b/src/engine/FGL_DEFINES.hpp @@ -11,6 +11,8 @@ #define FGL_DELETE_MOVE_CTOR( ClassName ) ClassName( ClassName&& ) = delete; #define FGL_DELETE_COPY( ClassName ) FGL_DELETE_COPY_CTOR( ClassName ) FGL_DELETE_COPY_ASSIGN( ClassName ) #define FGL_DELETE_MOVE( ClassName ) FGL_DELETE_MOVE_CTOR( ClassName ) FGL_DELETE_MOVE_ASSIGN( ClassName ) +#define FGL_DELETE_ALL_Ro5( ClassName ) \ + FGL_DELETE_DEFAULT_CTOR( ClassName ) FGL_DELETE_COPY( ClassName ) FGL_DELETE_MOVE( ClassName ) #ifndef FGL_FORCE_NOTHING diff --git a/src/engine/FrameInfo.hpp b/src/engine/FrameInfo.hpp index 58d75b1..91e5296 100644 --- a/src/engine/FrameInfo.hpp +++ b/src/engine/FrameInfo.hpp @@ -70,7 +70,7 @@ namespace fgl::engine { std::uint16_t frame_idx; float frame_time; - vk::CommandBuffer command_buffer; + vk::raii::CommandBuffer& command_buffer; struct { diff --git a/src/engine/PushConstant.hpp b/src/engine/PushConstant.hpp index 6c458db..162de2a 100644 --- a/src/engine/PushConstant.hpp +++ b/src/engine/PushConstant.hpp @@ -6,6 +6,7 @@ #include +#include namespace fgl::engine { @@ -21,7 +22,7 @@ namespace fgl::engine static_assert( sizeof( T ) <= 128, "Push constant range size must be less or equal to 128 bytes" ); } - static void push( vk::CommandBuffer command_buffer, vk::PipelineLayout m_pipeline_layout, T& data ) + static void push( vk::raii::CommandBuffer& command_buffer, vk::PipelineLayout m_pipeline_layout, T& data ) { command_buffer.pushConstants( m_pipeline_layout, stages, offset, sizeof( T ), &data ); } diff --git a/src/engine/Window.cpp b/src/engine/Window.cpp index 259bf53..fc3a62b 100644 --- a/src/engine/Window.cpp +++ b/src/engine/Window.cpp @@ -5,7 +5,6 @@ #include "Window.hpp" #include -#include #include @@ -42,13 +41,15 @@ namespace fgl::engine glfwSetFramebufferSizeCallback( m_window, framebufferResizeCallback ); } - vk::SurfaceKHR Window::createWindowSurface( vk::Instance instance ) + vk::raii::SurfaceKHR Window::createWindowSurface( Instance& instance ) { VkSurfaceKHR temp_surface { VK_NULL_HANDLE }; if ( glfwCreateWindowSurface( instance, m_window, nullptr, &temp_surface ) != VK_SUCCESS ) throw std::runtime_error( "Failed to create window surface" ); - return vk::SurfaceKHR( temp_surface ); + vk::raii::SurfaceKHR surface { instance.handle(), temp_surface }; + + return surface; } void Window::framebufferResizeCallback( GLFWwindow* glfw_window, int width, int height ) diff --git a/src/engine/Window.hpp b/src/engine/Window.hpp index d6e5a0e..befca81 100644 --- a/src/engine/Window.hpp +++ b/src/engine/Window.hpp @@ -6,12 +6,12 @@ #define GLFW_INCLUDE_VULKAN #include -#include -#include #include #include +#include "rendering/Surface.hpp" + namespace fgl::engine { @@ -37,7 +37,7 @@ namespace fgl::engine bool shouldClose() { return glfwWindowShouldClose( m_window ); } - vk::SurfaceKHR createWindowSurface( vk::Instance instance ); + vk::raii::SurfaceKHR createWindowSurface( Instance& instance ); VkExtent2D getExtent() { diff --git a/src/engine/assets/AssetManager.hpp b/src/engine/assets/AssetManager.hpp index 095e301..30ec286 100644 --- a/src/engine/assets/AssetManager.hpp +++ b/src/engine/assets/AssetManager.hpp @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include @@ -20,7 +21,7 @@ namespace fgl::engine struct AssetInterface { //! Stages the asset to the device (GPU) - virtual void stage( vk::CommandBuffer& buffer ) = 0; + virtual void stage( vk::raii::CommandBuffer& buffer ) = 0; friend class AssetStore< T >; @@ -76,7 +77,7 @@ namespace fgl::engine //! Returns true if all items to be staged were submitted to the queue //! Returns false if more items remain - bool stage( vk::CommandBuffer& buffer ) + bool stage( vk::raii::CommandBuffer& buffer ) { ZoneScoped; std::lock_guard guard { queue_mtx }; diff --git a/src/engine/buffers/BufferSuballocation.cpp b/src/engine/buffers/BufferSuballocation.cpp index 36f1855..e9a88f7 100644 --- a/src/engine/buffers/BufferSuballocation.cpp +++ b/src/engine/buffers/BufferSuballocation.cpp @@ -71,8 +71,9 @@ namespace fgl::engine if ( range.size > m_byte_size ) range.size = VK_WHOLE_SIZE; - if ( Device::getInstance().device().flushMappedMemoryRanges( 1, &range ) != vk::Result::eSuccess ) - throw std::runtime_error( "Failed to flush memory" ); + std::vector< vk::MappedMemoryRange > ranges { range }; + + Device::getInstance()->flushMappedMemoryRanges( ranges ); } Buffer& BufferSuballocation::getBuffer() const diff --git a/src/engine/buffers/UniqueFrameSuballocation.hpp b/src/engine/buffers/UniqueFrameSuballocation.hpp index 69a04f9..1f49806 100644 --- a/src/engine/buffers/UniqueFrameSuballocation.hpp +++ b/src/engine/buffers/UniqueFrameSuballocation.hpp @@ -38,7 +38,7 @@ namespace fgl::engine return *m_suballocations[ index ]; } - void bindForFrame( vk::CommandBuffer& cmd_buffer, std::uint16_t frame_idx ) + void bindForFrame( vk::raii::CommandBuffer& cmd_buffer, std::uint16_t frame_idx ) { m_suballocations[ frame_idx ].bind( cmd_buffer ); } diff --git a/src/engine/buffers/vector/DeviceVector.hpp b/src/engine/buffers/vector/DeviceVector.hpp index a39862b..ec01988 100644 --- a/src/engine/buffers/vector/DeviceVector.hpp +++ b/src/engine/buffers/vector/DeviceVector.hpp @@ -34,7 +34,7 @@ namespace fgl::engine HostVector< T >& getStaging() { return *m_staging_buffer; } - void stage( vk::CommandBuffer& command_buffer ) + void stage( vk::raii::CommandBuffer& command_buffer ) { assert( m_staging_buffer && "DeviceVector::stage() called without staging buffer" ); diff --git a/src/engine/concepts/is_descriptor_set.hpp b/src/engine/concepts/is_descriptor_set.hpp index 5fed31f..599e19d 100644 --- a/src/engine/concepts/is_descriptor_set.hpp +++ b/src/engine/concepts/is_descriptor_set.hpp @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include @@ -18,6 +19,6 @@ namespace fgl::engine } -> std::same_as< const std::uint16_t& >; { T::createLayout() - } -> std::same_as< vk::DescriptorSetLayout >; + } -> std::same_as< vk::raii::DescriptorSetLayout >; }; } // namespace fgl::engine diff --git a/src/engine/descriptors/DescriptorPool.cpp b/src/engine/descriptors/DescriptorPool.cpp index 070337a..0a6f8ff 100644 --- a/src/engine/descriptors/DescriptorPool.cpp +++ b/src/engine/descriptors/DescriptorPool.cpp @@ -8,7 +8,8 @@ namespace fgl::engine { - DescriptorPool::DescriptorPool( Device& device, std::uint32_t set_count ) + + vk::raii::DescriptorPool createPool( Device& device, std::uint32_t set_count ) { std::vector< vk::DescriptorPoolSize > pool_sizes {}; for ( auto& [ type, ratio ] : descriptor_allocation_ratios ) @@ -23,22 +24,24 @@ namespace fgl::engine pool_info.setFlags( vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet | vk::DescriptorPoolCreateFlagBits::eUpdateAfterBind ); - vk::Device vk_device { device.device() }; - if ( vk_device.createDescriptorPool( &pool_info, nullptr, &m_pool ) != vk::Result::eSuccess ) - throw std::runtime_error( "Failed to create descriptor pool" ); + return device->createDescriptorPool( pool_info ); } - [[nodiscard]] vk::DescriptorSet DescriptorPool::allocateSet( vk::DescriptorSetLayout& layout ) + DescriptorPool::DescriptorPool( Device& device, std::uint32_t set_count ) : + m_pool( createPool( device, set_count ) ) + {} + + [[nodiscard]] vk::raii::DescriptorSet DescriptorPool::allocateSet( vk::raii::DescriptorSetLayout& layout ) { - vk::DescriptorSet set; vk::DescriptorSetAllocateInfo alloc_info {}; alloc_info.setDescriptorPool( m_pool ); alloc_info.setDescriptorSetCount( 1 ); - alloc_info.setPSetLayouts( &layout ); + alloc_info.setPSetLayouts( &( *layout ) ); - vk::Device vk_device { Device::getInstance().device() }; - if ( vk_device.allocateDescriptorSets( &alloc_info, &set ) != vk::Result::eSuccess ) - throw std::runtime_error( "Failed to allocate descriptor set" ); + std::vector< vk::raii::DescriptorSet > sets { Device::getInstance()->allocateDescriptorSets( alloc_info ) }; + assert( sets.size() == 1 ); + + vk::raii::DescriptorSet set { std::move( sets[ 0 ] ) }; return set; } @@ -58,10 +61,4 @@ namespace fgl::engine return *s_pool; } - void DescriptorPool::deallocSet( vk::DescriptorSet& set ) - { - vk::Device vk_device { Device::getInstance().device() }; - vk_device.freeDescriptorSets( m_pool, 1, &set ); - } - } // namespace fgl::engine \ No newline at end of file diff --git a/src/engine/descriptors/DescriptorPool.hpp b/src/engine/descriptors/DescriptorPool.hpp index cf6fee6..4a5b5e5 100644 --- a/src/engine/descriptors/DescriptorPool.hpp +++ b/src/engine/descriptors/DescriptorPool.hpp @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include @@ -19,7 +20,7 @@ namespace fgl::engine class DescriptorPool { - vk::DescriptorPool m_pool {}; + vk::raii::DescriptorPool m_pool; DescriptorPool( Device& device, std::uint32_t set_count ); @@ -30,24 +31,13 @@ namespace fgl::engine DescriptorPool& operator=( const DescriptorPool& other ) = delete; DescriptorPool& operator=( DescriptorPool&& other ) = delete; - vk::DescriptorPool getPool() const - { - assert( m_pool && "DescriptorPool::getVkPool() called on null pool" ); + vk::raii::DescriptorPool& getPool() { return m_pool; } - return m_pool; - } - - VkDescriptorPool getVkPool() const - { - assert( m_pool && "DescriptorPool::getVkPool() called on null pool" ); - - return m_pool; - } + VkDescriptorPool operator*() { return *m_pool; } static DescriptorPool& init( Device& device ); [[nodiscard]] static DescriptorPool& getInstance(); - [[nodiscard]] vk::DescriptorSet allocateSet( vk::DescriptorSetLayout& layout ); - void deallocSet( vk::DescriptorSet& set ); + [[nodiscard]] vk::raii::DescriptorSet allocateSet( vk::raii::DescriptorSetLayout& layout ); }; } // namespace fgl::engine \ No newline at end of file diff --git a/src/engine/descriptors/DescriptorSet.cpp b/src/engine/descriptors/DescriptorSet.cpp index 9786c28..a849381 100644 --- a/src/engine/descriptors/DescriptorSet.cpp +++ b/src/engine/descriptors/DescriptorSet.cpp @@ -14,16 +14,11 @@ namespace fgl::engine { - DescriptorSet::DescriptorSet( vk::DescriptorSetLayout layout ) : - m_layout( layout ), - m_set( DescriptorPool::getInstance().allocateSet( layout ) ) + DescriptorSet::DescriptorSet( vk::raii::DescriptorSetLayout&& layout ) : + m_layout( std::forward< vk::raii::DescriptorSetLayout >( layout ) ), + m_set( DescriptorPool::getInstance().allocateSet( m_layout ) ) {} - DescriptorSet::~DescriptorSet() - { - if ( m_set != VK_NULL_HANDLE ) DescriptorPool::getInstance().deallocSet( m_set ); - } - DescriptorSet::DescriptorSet( DescriptorSet&& other ) : m_infos( std::move( other.m_infos ) ), descriptor_writes( std::move( other.descriptor_writes ) ), @@ -67,7 +62,7 @@ namespace fgl::engine } void DescriptorSet:: - bindImage( std::uint32_t binding_idx, ImageView& view, vk::ImageLayout layout, vk::Sampler sampler ) + bindImage( std::uint32_t binding_idx, ImageView& view, vk::ImageLayout layout, vk::raii::Sampler sampler ) { assert( binding_idx < m_infos.size() && "Binding index out of range" ); @@ -138,7 +133,7 @@ namespace fgl::engine } void DescriptorSet:: - bindAttachment( std::uint32_t binding_idx, ImageView& view, vk::ImageLayout layout, vk::Sampler sampler ) + bindAttachment( std::uint32_t binding_idx, ImageView& view, vk::ImageLayout layout, vk::raii::Sampler sampler ) { assert( binding_idx < m_infos.size() && "Binding index out of range" ); @@ -163,7 +158,7 @@ namespace fgl::engine vk::DebugUtilsObjectNameInfoEXT info {}; info.objectType = vk::ObjectType::eDescriptorSet; info.pObjectName = str.c_str(); - info.setObjectHandle( reinterpret_cast< std::uint64_t >( static_cast< VkDescriptorSet >( m_set ) ) ); + info.setObjectHandle( reinterpret_cast< std::uint64_t >( getVkDescriptorSet() ) ); Device::getInstance().setDebugUtilsObjectName( info ); } diff --git a/src/engine/descriptors/DescriptorSet.hpp b/src/engine/descriptors/DescriptorSet.hpp index b9c8ee1..d44a2f8 100644 --- a/src/engine/descriptors/DescriptorSet.hpp +++ b/src/engine/descriptors/DescriptorSet.hpp @@ -26,8 +26,8 @@ namespace fgl::engine std::vector< std::variant< std::shared_ptr< ImageView >, std::shared_ptr< BufferSuballocation > > > m_resources {}; - vk::DescriptorSetLayout m_layout; - vk::DescriptorSet m_set; + vk::raii::DescriptorSetLayout m_layout; + vk::raii::DescriptorSet m_set; std::uint32_t m_max_idx { 0 }; @@ -39,11 +39,12 @@ namespace fgl::engine void setMaxIDX( std::uint32_t max_idx ); - vk::DescriptorSet& getSet() { return m_set; } + VkDescriptorSet operator*() { return *m_set; } + + VkDescriptorSet getVkDescriptorSet() { return *m_set; } DescriptorSet() = delete; - DescriptorSet( vk::DescriptorSetLayout layout ); - ~DescriptorSet(); + DescriptorSet( vk::raii::DescriptorSetLayout&& layout ); //Copy DescriptorSet( const DescriptorSet& other ) = delete; @@ -54,12 +55,18 @@ namespace fgl::engine DescriptorSet& operator=( DescriptorSet&& other ); void bindImage( - std::uint32_t binding_idx, ImageView& view, vk::ImageLayout layout, vk::Sampler sampler = VK_NULL_HANDLE ); + std::uint32_t binding_idx, + ImageView& view, + vk::ImageLayout layout, + vk::raii::Sampler sampler = VK_NULL_HANDLE ); void bindUniformBuffer( std::uint32_t binding_idx, BufferSuballocation& buffer ); void bindAttachment( - std::uint32_t binding_idx, ImageView& view, vk::ImageLayout layout, vk::Sampler sampler = VK_NULL_HANDLE ); + std::uint32_t binding_idx, + ImageView& view, + vk::ImageLayout layout, + vk::raii::Sampler sampler = VK_NULL_HANDLE ); void bindTexture( std::uint32_t binding_idx, std::shared_ptr< Texture >& tex_ptr ); diff --git a/src/engine/descriptors/DescriptorSetCollection.hpp b/src/engine/descriptors/DescriptorSetCollection.hpp index 089b044..da0fa2b 100644 --- a/src/engine/descriptors/DescriptorSetCollection.hpp +++ b/src/engine/descriptors/DescriptorSetCollection.hpp @@ -37,6 +37,7 @@ namespace fgl::engine struct DescriptorSetCollection { using DescriptorSetTuple = std::tuple< DescriptorSets... >; + static constexpr auto SIZE { sizeof...( DescriptorSets ) }; constexpr static std::uint64_t DescriptorSetCount { sizeof...( DescriptorSets ) }; @@ -53,13 +54,13 @@ namespace fgl::engine constexpr static std::uint16_t empty_sets { ( is_empty_descriptor_set< DescriptorSets > + ... ) }; - using LayoutArray = std::array< vk::DescriptorSetLayout, DescriptorSetCount - has_constant_range >; - - static LayoutArray createDescriptorSets() + static std::vector< vk::raii::DescriptorSetLayout > createDescriptorSets() { - LayoutArray layouts; - createDescriptorSetsT< layouts.size(), 0, DescriptorSets... >( layouts ); - return layouts; + auto vec { createDescriptorSetsT< DescriptorSets... >() }; + assert( vec.size() > 0 ); + assert( vec.size() == binding_sets ); + + return createDescriptorSetsT< DescriptorSets... >(); } template < std::uint64_t IDX > diff --git a/src/engine/descriptors/DescriptorSetLayout.hpp b/src/engine/descriptors/DescriptorSetLayout.hpp index edcda81..8ec88e3 100644 --- a/src/engine/descriptors/DescriptorSetLayout.hpp +++ b/src/engine/descriptors/DescriptorSetLayout.hpp @@ -129,10 +129,8 @@ namespace fgl::engine return extractBindingFlags< 0, 0 >(); } - static vk::DescriptorSetLayout createDescriptorSetLayout() + static vk::raii::DescriptorSetLayout createDescriptorSetLayout() { - vk::DescriptorSetLayout layout { VK_NULL_HANDLE }; - static constinit std::array< vk::DescriptorSetLayoutBinding, used_descriptor_count > bindings { getLayoutBindings() }; @@ -154,18 +152,14 @@ namespace fgl::engine layout_info.pBindings = bindings.data(); layout_info.pNext = &flags_info; - if ( Device::getInstance().device().createDescriptorSetLayout( &layout_info, nullptr, &layout ) - != vk::Result::eSuccess ) - throw std::runtime_error( "Failed to create descriptor set layout" ); - - return layout; + return Device::getInstance()->createDescriptorSetLayout( layout_info ); } public: DescriptorSetLayout() = delete; - static vk::DescriptorSetLayout createLayout() { return createDescriptorSetLayout(); } + static vk::raii::DescriptorSetLayout createLayout() { return createDescriptorSetLayout(); } }; template < std::uint16_t set_idx > diff --git a/src/engine/descriptors/createDescriptorSets.hpp b/src/engine/descriptors/createDescriptorSets.hpp index e14c636..af119c4 100644 --- a/src/engine/descriptors/createDescriptorSets.hpp +++ b/src/engine/descriptors/createDescriptorSets.hpp @@ -4,46 +4,62 @@ #pragma once -#include -#include - #include "engine/concepts/is_valid_pipeline_input.hpp" namespace fgl::engine { - template < - std::uint16_t size, - std::uint16_t current_idx, - is_valid_pipeline_input CurrentSet, - is_valid_pipeline_input... Sets > - void createDescriptorSetsT( std::array< vk::DescriptorSetLayout, size >& out ) + template < is_valid_pipeline_input CurrentSet, is_valid_pipeline_input... Sets > + std::vector< vk::raii::DescriptorSetLayout > createDescriptorSetsT( std::vector< vk::raii::DescriptorSetLayout > + out ) { - if constexpr ( size == 0 ) - return; + if constexpr ( is_descriptor_set< CurrentSet > ) + { + vk::raii::DescriptorSetLayout layout { CurrentSet::createDescriptorSetLayout() }; + out.emplace_back( std::move( layout ) ); + } + else if constexpr ( is_constant_range< CurrentSet > ) + { + //noop + } else { - static_assert( size > 0, "Size must be greater than 0" ); - static_assert( current_idx < size, "Current index must be less than size" ); - - if constexpr ( is_descriptor_set< CurrentSet > ) - { - out[ current_idx ] = CurrentSet::createDescriptorSetLayout(); - assert( out[ current_idx ] != VK_NULL_HANDLE && "createDescriptorSetLayout returned VK_NULL_HANDLE" ); - std::cout << "Created descriptor set layout for binding set " << current_idx << std::endl; - if constexpr ( sizeof...( Sets ) > 0 ) createDescriptorSetsT< size, current_idx + 1, Sets... >( out ); - } - else if constexpr ( is_constant_range< CurrentSet > ) - { - if constexpr ( sizeof...( Sets ) > 0 ) // We don't want to increase the size - createDescriptorSetsT< size, current_idx, Sets... >( out ); - else - return; - } - else - { - static_assert( false, "Invalid input" ); - } + static_assert( false, "Invalid input" ); } + + if constexpr ( sizeof...( Sets ) > 0 ) + { + return createDescriptorSetsT< Sets... >( std::move( out ) ); + } + + return out; } + + template < is_valid_pipeline_input CurrentSet, is_valid_pipeline_input... Sets > + std::vector< vk::raii::DescriptorSetLayout > createDescriptorSetsT() + { + std::vector< vk::raii::DescriptorSetLayout > out {}; + + if constexpr ( is_descriptor_set< CurrentSet > ) + { + vk::raii::DescriptorSetLayout layout { CurrentSet::createDescriptorSetLayout() }; + out.emplace_back( std::move( layout ) ); + } + else if constexpr ( is_constant_range< CurrentSet > ) + { + //noop + } + else + { + static_assert( false, "Invalid input" ); + } + + if constexpr ( sizeof...( Sets ) > 0 ) + { + return createDescriptorSetsT< Sets... >( std::move( out ) ); + } + + return out; + } + } // namespace fgl::engine \ No newline at end of file diff --git a/src/engine/filesystem/FileBrowser.cpp b/src/engine/filesystem/FileBrowser.cpp index 4ab168a..a95c7d2 100644 --- a/src/engine/filesystem/FileBrowser.cpp +++ b/src/engine/filesystem/FileBrowser.cpp @@ -36,10 +36,6 @@ namespace fgl::engine::filesystem file_texture = getTextureStore().load( "./assets/file.png", vk::Format::eR8G8B8A8Unorm ); up_texture = getTextureStore().load( "./assets/up.png", vk::Format::eR8G8B8A8Unorm ); - auto cmd_buffer { Device::getInstance().beginSingleTimeCommands() }; - - Device::getInstance().endSingleTimeCommands( cmd_buffer ); - current = DirInfo( test_path ); } diff --git a/src/engine/gui/core.cpp b/src/engine/gui/core.cpp index a986d2c..85f0a59 100644 --- a/src/engine/gui/core.cpp +++ b/src/engine/gui/core.cpp @@ -39,26 +39,28 @@ namespace fgl::engine::gui Device& device { Device::getInstance() }; ImGui_ImplGlfw_InitForVulkan( window.window(), true ); - ImGui_ImplVulkan_InitInfo init_info { .Instance = device.instance(), - .PhysicalDevice = device.phyDevice(), - .Device = device.device(), - .QueueFamily = device.findPhysicalQueueFamilies().graphicsFamily, - .Queue = device.graphicsQueue(), - .DescriptorPool = DescriptorPool::getInstance().getVkPool(), - .RenderPass = renderer.getSwapChainRenderPass(), - .MinImageCount = 2, - .ImageCount = 2, - .MSAASamples = VK_SAMPLE_COUNT_1_BIT, + ImGui_ImplVulkan_InitInfo init_info { + .Instance = device.instance(), + .PhysicalDevice = *device.phyDevice().handle(), + .Device = *device, + .QueueFamily = device.phyDevice().queueInfo().getIndex( vk::QueueFlagBits::eGraphics ), + .Queue = *device.graphicsQueue(), + .DescriptorPool = *DescriptorPool::getInstance().getPool(), + .RenderPass = *renderer.getSwapChainRenderPass(), + .MinImageCount = 2, + .ImageCount = 2, + .MSAASamples = VK_SAMPLE_COUNT_1_BIT, - .PipelineCache = VK_NULL_HANDLE, - .Subpass = 1, + .PipelineCache = VK_NULL_HANDLE, + .Subpass = 1, - .UseDynamicRendering = VK_FALSE, - .PipelineRenderingCreateInfo = {}, + .UseDynamicRendering = VK_FALSE, + .PipelineRenderingCreateInfo = {}, - .Allocator = VK_NULL_HANDLE, - .CheckVkResultFn = VK_NULL_HANDLE, - .MinAllocationSize = 1024 * 1024 }; + .Allocator = VK_NULL_HANDLE, + .CheckVkResultFn = VK_NULL_HANDLE, + .MinAllocationSize = 1024 * 1024 + }; ImGui_ImplVulkan_Init( &init_info ); } @@ -74,19 +76,18 @@ namespace fgl::engine::gui ImGui::Begin( "Main" ); } - void endImGui( vk::CommandBuffer& command_buffer ) + void endImGui( vk::raii::CommandBuffer& command_buffer ) { ImGui::End(); ImGui::Render(); ImDrawData* data { ImGui::GetDrawData() }; - ImGui_ImplVulkan_RenderDrawData( data, command_buffer ); + ImGui_ImplVulkan_RenderDrawData( data, *command_buffer ); //ImGui::UpdatePlatformWindows(); //ImGui::RenderPlatformWindowsDefault(); } - void drawMainGUI( FrameInfo& info ) { ZoneScoped; diff --git a/src/engine/image/Image.cpp b/src/engine/image/Image.cpp index 0b03762..0ee662e 100644 --- a/src/engine/image/Image.cpp +++ b/src/engine/image/Image.cpp @@ -26,9 +26,4 @@ namespace fgl::engine m_handle->setName( str ); } - vk::Image& Image::getVkImage() - { - return m_handle->m_image; - } - } // namespace fgl::engine \ No newline at end of file diff --git a/src/engine/image/ImageHandle.cpp b/src/engine/image/ImageHandle.cpp index 8c494cb..f7da71f 100644 --- a/src/engine/image/ImageHandle.cpp +++ b/src/engine/image/ImageHandle.cpp @@ -7,41 +7,19 @@ namespace fgl::engine { - ImageHandle::ImageHandle( fgl::engine::ImageHandle&& other ) noexcept : - m_allocation( other.m_allocation ), - m_allocation_info( other.m_allocation_info ), - m_image( other.m_image ), - m_extent( other.m_extent ), - m_format( other.m_format ), - m_usage( other.m_usage ) - { - other.m_allocation = VK_NULL_HANDLE; - other.m_image = VK_NULL_HANDLE; - other.m_allocation_info = {}; - other.m_image = VK_NULL_HANDLE; - } - ImageHandle::ImageHandle( const vk::Extent2D extent, const vk::Format format, vk::Image image, vk::ImageUsageFlags usage ) noexcept : - m_image( image ), - m_extent( extent ), - m_format( format ), - m_usage( usage ) - {} - - ImageHandle::ImageHandle( - const vk::Extent2D extent, - const vk::Format format, - vk::ImageUsageFlags usage, - vk::ImageLayout inital_layout, - vk::ImageLayout final_layout ) : m_extent( extent ), m_format( format ), m_usage( usage ), - m_initial_layout( inital_layout ), - m_final_layout( final_layout ) + m_image( image ) + { + assert( std::get< vk::Image >( m_image ) != VK_NULL_HANDLE ); + } + + vk::raii::Image createImage( + const vk::Extent2D extent, const vk::Format format, vk::ImageLayout inital_layout, vk::ImageUsageFlags usage ) { - ZoneScoped; vk::ImageCreateInfo image_info {}; image_info.imageType = vk::ImageType::e2D; @@ -61,9 +39,28 @@ namespace fgl::engine image_info.samples = vk::SampleCountFlagBits::e1; image_info.sharingMode = vk::SharingMode::eExclusive; - if ( Device::getInstance().device().createImage( &image_info, nullptr, &m_image ) != vk::Result::eSuccess ) - throw std::runtime_error( "Failed to create image" ); + return Device::getInstance()->createImage( image_info ); + } + ImageHandle::ImageHandle( + const vk::Extent2D extent, + const vk::Format format, + vk::ImageUsageFlags usage, + vk::ImageLayout inital_layout, + vk::ImageLayout final_layout ) : + m_extent( extent ), + m_format( format ), + m_usage( usage ), + m_initial_layout( inital_layout ), + m_final_layout( final_layout ), + m_image( createImage( extent, format, inital_layout, usage ) ) + + { + assert( std::holds_alternative< vk::raii::Image >( m_image ) ); + assert( *std::get< vk::raii::Image >( m_image ) != VK_NULL_HANDLE ); + + ZoneScoped; + //Allocate memory for image VmaAllocationCreateInfo alloc_info {}; alloc_info.usage = VMA_MEMORY_USAGE_GPU_ONLY; @@ -82,7 +79,7 @@ namespace fgl::engine info.objectType = vk::ObjectType::eImage; info.pObjectName = str.c_str(); - info.setObjectHandle( reinterpret_cast< uint64_t >( static_cast< VkImage >( m_image ) ) ); + info.setObjectHandle( reinterpret_cast< uint64_t >( getVkImage() ) ); Device::getInstance().setDebugUtilsObjectName( info ); } diff --git a/src/engine/image/ImageHandle.hpp b/src/engine/image/ImageHandle.hpp index dfb8061..a686fb3 100644 --- a/src/engine/image/ImageHandle.hpp +++ b/src/engine/image/ImageHandle.hpp @@ -6,6 +6,7 @@ #include +#include "engine/logging/logging.hpp" #include "engine/rendering/Device.hpp" #include "vma/vma_impl.hpp" #include "vulkan/vulkan.hpp" @@ -19,8 +20,6 @@ namespace fgl::engine VmaAllocation m_allocation { VK_NULL_HANDLE }; VmaAllocationInfo m_allocation_info {}; - vk::Image m_image { VK_NULL_HANDLE }; - vk::Extent2D m_extent; vk::Format m_format; vk::ImageUsageFlags m_usage; @@ -28,17 +27,15 @@ namespace fgl::engine vk::ImageLayout m_initial_layout { vk::ImageLayout::eUndefined }; vk::ImageLayout m_final_layout { vk::ImageLayout::eUndefined }; + // Because of the way the swapchain works we need to be able to storage a `VkImage` handle. + std::variant< vk::raii::Image, vk::Image > m_image; + friend class ImageView; friend class Image; public: - ImageHandle() = delete; - - ImageHandle( const ImageHandle& other ) = delete; - ImageHandle& operator=( const ImageHandle& other ) = delete; - - ImageHandle( ImageHandle&& other ) noexcept; + FGL_DELETE_ALL_Ro5( ImageHandle ); ImageHandle( const vk::Extent2D extent, const vk::Format format, vk::Image image, vk::ImageUsageFlags usage ) noexcept; @@ -52,7 +49,18 @@ namespace fgl::engine void setName( const std::string str ); - vk::Image& getVkImage() { return m_image; } + VkImage operator*() + { + ZoneScoped; + if ( std::holds_alternative< vk::raii::Image >( m_image ) ) + { + return *std::get< vk::raii::Image >( m_image ); + } + else + return std::get< vk::Image >( m_image ); + } + + VkImage getVkImage() { return **this; } vk::Format format() const { return m_format; } @@ -77,7 +85,9 @@ namespace fgl::engine ~ImageHandle() { if ( m_allocation != VK_NULL_HANDLE ) - vmaDestroyImage( Device::getInstance().allocator(), m_image, m_allocation ); + { + vmaFreeMemory( Device::getInstance().allocator(), m_allocation ); + } } }; diff --git a/src/engine/image/ImageView.cpp b/src/engine/image/ImageView.cpp index b9af2b8..e3d8b55 100644 --- a/src/engine/image/ImageView.cpp +++ b/src/engine/image/ImageView.cpp @@ -7,30 +7,31 @@ namespace fgl::engine { + vk::raii::ImageView ImageView::createImageView( const std::shared_ptr< ImageHandle >& img ) + { + vk::ImageViewCreateInfo info {}; + info.image = **img; + info.viewType = vk::ImageViewType::e2D; + info.format = img->format(); + + info.subresourceRange.aspectMask = img->aspectMask(); + + info.subresourceRange.baseMipLevel = 0; + info.subresourceRange.levelCount = 1; + info.subresourceRange.baseArrayLayer = 0; + info.subresourceRange.layerCount = 1; + + return Device::getInstance()->createImageView( info ); + } + ImageView::ImageView( std::shared_ptr< ImageHandle >& img ) : m_resource( img ), m_descriptor_info(), - m_image_view( VK_NULL_HANDLE ), - m_sampler() + m_sampler(), + m_image_view( createImageView( img ) ) { - vk::ImageViewCreateInfo view_info {}; - view_info.image = img->getVkImage(); - view_info.viewType = vk::ImageViewType::e2D; - view_info.format = img->format(); - - view_info.subresourceRange.aspectMask = img->aspectMask(); - - view_info.subresourceRange.baseMipLevel = 0; - view_info.subresourceRange.levelCount = 1; - view_info.subresourceRange.baseArrayLayer = 0; - view_info.subresourceRange.layerCount = 1; - m_descriptor_info.imageLayout = img->m_final_layout; m_descriptor_info.imageView = m_image_view; - - if ( Device::getInstance().device().createImageView( &view_info, nullptr, &m_image_view ) - != vk::Result::eSuccess ) - throw std::runtime_error( "Failed to create image view" ); } vk::DescriptorImageInfo ImageView::descriptorInfo( vk::Sampler sampler, vk::ImageLayout layout ) const @@ -51,16 +52,11 @@ namespace fgl::engine return info; } - vk::ImageView& ImageView::getVkView() + vk::raii::ImageView& ImageView::getVkView() { return m_image_view; } - vk::Image& ImageView::getVkImage() - { - return m_resource->getVkImage(); - } - vk::Extent2D ImageView::getExtent() const { return m_resource->extent(); diff --git a/src/engine/image/ImageView.hpp b/src/engine/image/ImageView.hpp index b0edd98..2c9e698 100644 --- a/src/engine/image/ImageView.hpp +++ b/src/engine/image/ImageView.hpp @@ -6,12 +6,9 @@ #include -#include - #include "Image.hpp" #include "ImageHandle.hpp" #include "Sampler.hpp" -#include "engine/concepts/is_image.hpp" #include "engine/rendering/Device.hpp" namespace fgl::engine @@ -23,7 +20,7 @@ namespace fgl::engine vk::DescriptorImageInfo m_descriptor_info; - vk::ImageView m_image_view; + vk::raii::ImageView m_image_view; Sampler m_sampler; @@ -48,21 +45,16 @@ namespace fgl::engine other.m_image_view = VK_NULL_HANDLE; } - ~ImageView() - { - if ( m_image_view ) - { - Device::getInstance().device().destroyImageView( m_image_view ); - } - } - + vk::raii::ImageView createImageView( const std::shared_ptr< ImageHandle >& img ); ImageView( std::shared_ptr< ImageHandle >& img ); vk::Extent2D getExtent() const; - vk::ImageView& getVkView(); + vk::raii::ImageView& getVkView(); - vk::Image& getVkImage(); + VkImageView operator*() { return *m_image_view; } + + VkImage getVkImage() { return m_resource->getVkImage(); } Sampler& getSampler() { return m_sampler; }; diff --git a/src/engine/image/Sampler.cpp b/src/engine/image/Sampler.cpp index b41dbe1..134f715 100644 --- a/src/engine/image/Sampler.cpp +++ b/src/engine/image/Sampler.cpp @@ -11,35 +11,40 @@ namespace fgl::engine { - Sampler::Sampler( + vk::raii::Sampler createSampler( vk::Filter min_filter, vk::Filter mag_filter, - vk::SamplerMipmapMode mipmap_mode, - vk::SamplerAddressMode sampler_mode ) : - valid( true ) + vk::SamplerMipmapMode mipmode, + vk::SamplerAddressMode address_mode ) { vk::SamplerCreateInfo info; info.magFilter = mag_filter; info.minFilter = min_filter; - info.mipmapMode = mipmap_mode; + info.mipmapMode = mipmode; - info.addressModeU = sampler_mode; - info.addressModeV = sampler_mode; - info.addressModeW = sampler_mode; + info.addressModeU = address_mode; + info.addressModeV = address_mode; + info.addressModeW = address_mode; info.minLod = -1000; info.maxLod = 1000; info.maxAnisotropy = 1.0f; - if ( Device::getInstance().device().createSampler( &info, nullptr, &m_sampler ) != vk::Result::eSuccess ) - { - throw std::runtime_error( "Failed to create sampler" ); - } + return Device::getInstance()->createSampler( info ); } + Sampler::Sampler( + vk::Filter min_filter, + vk::Filter mag_filter, + vk::SamplerMipmapMode mipmap_mode, + vk::SamplerAddressMode sampler_mode ) : + valid( true ), + m_sampler( createSampler( mag_filter, min_filter, mipmap_mode, sampler_mode ) ) + {} + Sampler::Sampler( Sampler&& other ) : valid( other.valid ), m_sampler( std::move( other.m_sampler ) ) { other.valid = false; @@ -53,9 +58,4 @@ namespace fgl::engine return *this; } - Sampler::~Sampler() - { - if ( valid ) Device::getInstance().device().destroySampler( m_sampler ); - } - } // namespace fgl::engine diff --git a/src/engine/image/Sampler.hpp b/src/engine/image/Sampler.hpp index cb2c92a..6e9edf8 100644 --- a/src/engine/image/Sampler.hpp +++ b/src/engine/image/Sampler.hpp @@ -5,14 +5,15 @@ #pragma once #include +#include namespace fgl::engine { class Sampler { - bool valid { false }; - vk::Sampler m_sampler { VK_NULL_HANDLE }; + bool valid; + vk::raii::Sampler m_sampler; public: @@ -30,14 +31,14 @@ namespace fgl::engine vk::SamplerMipmapMode mipmap_mode, vk::SamplerAddressMode sampler_mode ); + VkSampler operator*() { return *m_sampler; } + Sampler( const Sampler& ) = delete; Sampler& operator=( const Sampler& ) = delete; Sampler( Sampler&& other ); Sampler& operator=( Sampler&& ); - ~Sampler(); - - vk::Sampler& getVkSampler() { return m_sampler; } + vk::raii::Sampler& getVkSampler() { return m_sampler; } }; } // namespace fgl::engine \ No newline at end of file diff --git a/src/engine/model/Model.cpp b/src/engine/model/Model.cpp index 608cf82..69aa1f2 100644 --- a/src/engine/model/Model.cpp +++ b/src/engine/model/Model.cpp @@ -133,7 +133,7 @@ namespace fgl::engine return model_ptr; } - void Model::stage( vk::CommandBuffer& cmd_buffer ) + void Model::stage( vk::raii::CommandBuffer& cmd_buffer ) { assert( !m_primitives.empty() ); for ( auto& primitive : m_primitives ) diff --git a/src/engine/model/Model.hpp b/src/engine/model/Model.hpp index 212c00f..24b9bde 100644 --- a/src/engine/model/Model.hpp +++ b/src/engine/model/Model.hpp @@ -64,7 +64,7 @@ namespace fgl::engine static std::vector< std::shared_ptr< Model > > createModelsFromScene( Device& device, const std::filesystem::path& path, Buffer& vertex_buffer, Buffer& index_buffer ); - void stage( vk::CommandBuffer& cmd_buffer ); + void stage( vk::raii::CommandBuffer& cmd_buffer ); const std::string& getName() const { return m_name; } diff --git a/src/engine/pipeline/Pipeline.cpp b/src/engine/pipeline/Pipeline.cpp index 5e0e5e7..ba19a8d 100644 --- a/src/engine/pipeline/Pipeline.cpp +++ b/src/engine/pipeline/Pipeline.cpp @@ -4,7 +4,6 @@ #include "Pipeline.hpp" -#include #include #include "Shader.hpp" @@ -13,8 +12,10 @@ namespace fgl::engine::internal { - void Pipeline::createGraphicsPipeline( - std::vector< std::unique_ptr< ShaderHandle > >& shaders, const PipelineConfigInfo& info ) + vk::raii::Pipeline Pipeline::createGraphicsPipeline( + std::vector< std::unique_ptr< ShaderHandle > >& shaders, + const PipelineConfigInfo& info, + vk::raii::PipelineLayout& layout ) { assert( info.render_pass != VK_NULL_HANDLE && "Cannot create graphics pipeline: no render pass provided" ); @@ -52,26 +53,16 @@ namespace fgl::engine::internal pipeline_info.pDepthStencilState = &info.depth_stencil_info; pipeline_info.pColorBlendState = &info.color_blend_info; pipeline_info.pDynamicState = &info.dynamic_state_info; - pipeline_info.layout = info.layout; + pipeline_info.layout = *layout; pipeline_info.renderPass = info.render_pass; pipeline_info.subpass = info.subpass; pipeline_info.basePipelineHandle = VK_NULL_HANDLE; pipeline_info.basePipelineIndex = -1; - if ( auto temp = m_device.device().createGraphicsPipeline( VK_NULL_HANDLE, pipeline_info ); - temp.result != vk::Result::eSuccess ) - throw std::runtime_error( "Failed to create graphics pipeline" ); - else - m_vk_pipeline = temp.value; + return m_device->createGraphicsPipeline( VK_NULL_HANDLE, pipeline_info ); } - Pipeline::~Pipeline() - { - m_device.device().destroyPipelineLayout( m_layout, nullptr ); - m_device.device().destroyPipeline( m_vk_pipeline, nullptr ); - } - - void Pipeline::bind( vk::CommandBuffer& command_buffer ) + void Pipeline::bind( vk::raii::CommandBuffer& command_buffer ) { command_buffer.bindPipeline( vk::PipelineBindPoint::eGraphics, m_vk_pipeline ); } @@ -81,7 +72,7 @@ namespace fgl::engine::internal vk::DebugUtilsObjectNameInfoEXT info {}; info.objectType = vk::ObjectType::ePipeline; info.pObjectName = str.c_str(); - info.objectHandle = reinterpret_cast< std::uint64_t >( static_cast< VkPipeline >( this->m_vk_pipeline ) ); + info.objectHandle = reinterpret_cast< std::uint64_t >( static_cast< VkPipeline >( *this->m_vk_pipeline ) ); Device::getInstance().setDebugUtilsObjectName( info ); } diff --git a/src/engine/pipeline/Pipeline.hpp b/src/engine/pipeline/Pipeline.hpp index 79bdc23..fec1c7b 100644 --- a/src/engine/pipeline/Pipeline.hpp +++ b/src/engine/pipeline/Pipeline.hpp @@ -23,24 +23,32 @@ namespace fgl::engine::internal protected: Device& m_device; - vk::Pipeline m_vk_pipeline { VK_NULL_HANDLE }; - vk::PipelineLayout m_layout { VK_NULL_HANDLE }; + vk::raii::PipelineLayout m_layout; + vk::raii::Pipeline m_vk_pipeline; vk::ShaderModule m_vert_shader { VK_NULL_HANDLE }; vk::ShaderModule m_frag_shader { VK_NULL_HANDLE }; - void createGraphicsPipeline( - std::vector< std::unique_ptr< ShaderHandle > >& shaders, const PipelineConfigInfo& info ); + vk::raii::Pipeline createGraphicsPipeline( + std::vector< std::unique_ptr< ShaderHandle > >& shaders, + const PipelineConfigInfo& info, + vk::raii::PipelineLayout& layout ); public: - Pipeline( Device& device ) : m_device( device ) {} - - ~Pipeline(); + Pipeline( + Device& device, + vk::raii::PipelineLayout layout, + PipelineConfigInfo info, + std::vector< std::unique_ptr< ShaderHandle > > shaders ) : + m_device( device ), + m_layout( std::move( layout ) ), + m_vk_pipeline( createGraphicsPipeline( shaders, info, m_layout ) ) + {} Pipeline( const Pipeline& other ) = delete; Pipeline& operator=( const Pipeline& ) = delete; - void bind( vk::CommandBuffer& command_buffer ); + void bind( vk::raii::CommandBuffer& command_buffer ); void setDebugName( const std::string str ); }; diff --git a/src/engine/pipeline/PipelineConfigInfo.cpp b/src/engine/pipeline/PipelineConfigInfo.cpp index 3c3b244..f8a55db 100644 --- a/src/engine/pipeline/PipelineConfigInfo.cpp +++ b/src/engine/pipeline/PipelineConfigInfo.cpp @@ -127,7 +127,7 @@ namespace fgl::engine info.rasterization_info.cullMode = vk::CullModeFlagBits::eNone; } - PipelineConfigInfo::PipelineConfigInfo( vk::RenderPass pass ) + PipelineConfigInfo::PipelineConfigInfo( vk::raii::RenderPass& pass ) { render_pass = pass; defaultConfig( *this ); diff --git a/src/engine/pipeline/PipelineConfigInfo.hpp b/src/engine/pipeline/PipelineConfigInfo.hpp index bdee37b..4ec24e5 100644 --- a/src/engine/pipeline/PipelineConfigInfo.hpp +++ b/src/engine/pipeline/PipelineConfigInfo.hpp @@ -5,10 +5,13 @@ #pragma once #include +#include #include #include +#include "engine/FGL_DEFINES.hpp" + namespace fgl::engine { @@ -27,16 +30,18 @@ namespace fgl::engine std::vector< vk::DynamicState > dynamic_state_enables {}; vk::PipelineDynamicStateCreateInfo dynamic_state_info {}; - vk::PipelineLayout layout { nullptr }; - vk::RenderPass render_pass { nullptr }; + vk::RenderPass render_pass { VK_NULL_HANDLE }; std::uint32_t subpass { 0 }; std::vector< vk::VertexInputBindingDescription > binding_descriptions {}; std::vector< vk::VertexInputAttributeDescription > attribute_descriptions {}; - PipelineConfigInfo( vk::RenderPass pass ); - PipelineConfigInfo( const PipelineConfigInfo& other ) = delete; - PipelineConfigInfo& operator=( const PipelineConfigInfo& ) = delete; + FGL_DELETE_COPY( PipelineConfigInfo ) + + PipelineConfigInfo( vk::raii::RenderPass& pass ); + + PipelineConfigInfo& operator=( PipelineConfigInfo&& other ) = default; + PipelineConfigInfo( PipelineConfigInfo&& other ) = default; static void disableVertexInput( PipelineConfigInfo& info ); static void setTriangleListTopo( PipelineConfigInfo& info ); diff --git a/src/engine/pipeline/PipelineT.hpp b/src/engine/pipeline/PipelineT.hpp index d2f043d..c2ddca7 100644 --- a/src/engine/pipeline/PipelineT.hpp +++ b/src/engine/pipeline/PipelineT.hpp @@ -83,44 +83,38 @@ namespace fgl::engine return emptySetsBeforeIDX< start_idx - 1 >() + is_empty_descriptor_set< BindingSet< start_idx > >; } - vk::PipelineLayout createLayout( Device& device ) + vk::raii::PipelineLayout createLayout( [[maybe_unused]] Device& device ) { - if ( m_layout != VK_NULL_HANDLE ) return m_layout; + std::vector< vk::raii::DescriptorSetLayout > layouts { DescriptorSetCollection::createDescriptorSets() }; + std::vector< vk::DescriptorSetLayout > vk_layouts {}; + vk_layouts.reserve( layouts.size() ); - typename DescriptorSetCollection::LayoutArray layouts { DescriptorSetCollection::createDescriptorSets() }; + for ( vk::raii::DescriptorSetLayout& layout : layouts ) + { + vk_layouts.emplace_back( *layout ); + } vk::PipelineLayoutCreateInfo pipeline_layout_info {}; - pipeline_layout_info.setLayoutCount = has_binding_sets ? static_cast< uint32_t >( layouts.size() ) : 0; - pipeline_layout_info.pSetLayouts = has_binding_sets ? layouts.data() : VK_NULL_HANDLE; + pipeline_layout_info.setLayoutCount = has_binding_sets ? static_cast< uint32_t >( vk_layouts.size() ) : 0; + pipeline_layout_info.pSetLayouts = has_binding_sets ? vk_layouts.data() : VK_NULL_HANDLE; pipeline_layout_info.pushConstantRangeCount = has_constant_range ? 1 : 0; pipeline_layout_info.pPushConstantRanges = has_constant_range ? getRange() : VK_NULL_HANDLE; - if ( device.device().createPipelineLayout( &pipeline_layout_info, nullptr, &m_layout ) - != vk::Result::eSuccess ) - throw std::runtime_error( "Failed to create pipeline layout" ); - - return m_layout; - } - - PipelineConfigInfo& populate( PipelineConfigInfo& info, Device& device ) - { - info.layout = createLayout( device ); - - return info; + return Device::getInstance()->createPipelineLayout( pipeline_layout_info ); } public: - vk::PipelineLayout getLayout() { return m_layout; } - - void bindDescriptor( vk::CommandBuffer cmd_buffer, std::uint16_t set_idx, DescriptorSet& descriptor ) + void bindDescriptor( vk::raii::CommandBuffer& cmd_buffer, std::uint16_t set_idx, DescriptorSet& descriptor ) { - cmd_buffer.bindDescriptorSets( - vk::PipelineBindPoint::eGraphics, m_layout, set_idx, 1, &( descriptor.getSet() ), 0, nullptr ); + const std::vector< vk::DescriptorSet > sets { *descriptor }; + const std::vector< std::uint32_t > offsets {}; + + cmd_buffer.bindDescriptorSets( vk::PipelineBindPoint::eGraphics, m_layout, set_idx, sets, offsets ); } template < typename TPushData > - void pushConstant( vk::CommandBuffer cmd_buffer, TPushData& data ) + void pushConstant( vk::raii::CommandBuffer& cmd_buffer, TPushData& data ) { if constexpr ( has_constant_range ) { @@ -135,14 +129,13 @@ namespace fgl::engine assert( "Attempted to push constant to pipeline without push constant range" ); } - PipelineT( Device& device, PipelineConfigInfo& info ) : Pipeline( device ) - { - populate( info, device ); - - auto shaders { ShaderCollection::loadShaders() }; - - createGraphicsPipeline( shaders, info ); - } + PipelineT( Device& device, PipelineConfigInfo&& info ) : + Pipeline( + device, + createLayout( device ), + std::forward< PipelineConfigInfo >( info ), + ShaderCollection::loadShaders() ) + {} }; } // namespace fgl::engine \ No newline at end of file diff --git a/src/engine/pipeline/Shader.cpp b/src/engine/pipeline/Shader.cpp new file mode 100644 index 0000000..80df598 --- /dev/null +++ b/src/engine/pipeline/Shader.cpp @@ -0,0 +1,52 @@ +// +// Created by kj16609 on 6/21/24. +// + +#include "Shader.hpp" + +#include "engine/rendering/Device.hpp" + +namespace fgl::engine +{ + + std::vector< std::byte > ShaderHandle::loadData( const std::filesystem::path& path ) + { + if ( auto ifs = std::ifstream( path, std::ios::binary | std::ios::ate ); ifs ) + { + std::vector< std::byte > data; + data.resize( ifs.tellg() ); + ifs.seekg( 0, std::ios::beg ); + + static_assert( sizeof( std::ifstream::char_type ) == sizeof( std::byte ) ); + + ifs.read( reinterpret_cast< std::ifstream::char_type* >( data.data() ), data.size() ); + + return data; + } + else + { + log::critical( "Failed to load shader module {}. Path not found", path.string() ); + throw std::runtime_error( "Failed to load shader module. Path not found" ); + } + } + + vk::ShaderModuleCreateInfo ShaderHandle::createModuleInfo() + { + vk::ShaderModuleCreateInfo module_info {}; + module_info.flags = {}; + module_info.codeSize = shader_data.size(); + module_info.pCode = reinterpret_cast< const std::uint32_t* >( shader_data.data() ); + + return module_info; + } + + ShaderHandle::ShaderHandle( const std::filesystem::path path, const vk::PipelineShaderStageCreateInfo info ) : + shader_data( loadData( path ) ), + module_create_info( createModuleInfo() ), + shader_module( Device::getInstance()->createShaderModule( module_create_info ) ), + stage_info( info ) + { + stage_info.module = shader_module; + } + +} // namespace fgl::engine diff --git a/src/engine/pipeline/Shader.hpp b/src/engine/pipeline/Shader.hpp index 39f901f..93b688e 100644 --- a/src/engine/pipeline/Shader.hpp +++ b/src/engine/pipeline/Shader.hpp @@ -4,6 +4,8 @@ #pragma once +#include + #include #include "engine/logging/logging.hpp" @@ -31,41 +33,16 @@ namespace fgl::engine struct ShaderHandle { + std::vector< std::byte > shader_data; + vk::ShaderModuleCreateInfo module_create_info; vk::PipelineShaderStageCreateInfo stage_info; - vk::ShaderModule shader_module; - ShaderHandle( const std::filesystem::path path, const vk::PipelineShaderStageCreateInfo info ) : - stage_info( info ), - shader_module( VK_NULL_HANDLE ) - { - if ( auto ifs = std::ifstream( path, std::ios::binary | std::ios::ate ); ifs ) - { - std::vector< std::byte > data; - data.resize( ifs.tellg() ); - ifs.seekg( 0, std::ios::beg ); + vk::raii::ShaderModule shader_module; - static_assert( sizeof( std::ifstream::char_type ) == sizeof( std::byte ) ); - ifs.read( reinterpret_cast< std::ifstream::char_type* >( data.data() ), data.size() ); + std::vector< std::byte > loadData( const std::filesystem::path& ); + vk::ShaderModuleCreateInfo createModuleInfo(); - vk::ShaderModuleCreateInfo module_info {}; - module_info.flags = {}; - module_info.codeSize = data.size(); - module_info.pCode = reinterpret_cast< const std::uint32_t* >( data.data() ); - - if ( Device::getInstance().device().createShaderModule( &module_info, nullptr, &shader_module ) - != vk::Result::eSuccess ) - throw std::runtime_error( "Failed to create shader module" ); - - std::cout << "Created shader module for: " << path << std::endl; - - stage_info.module = shader_module; - } - else - { - log::critical( "Failed to load shader module {}. Path not found", path.string() ); - throw std::runtime_error( "Failed to load shader module. Path not found" ); - } - } + ShaderHandle( const std::filesystem::path path, const vk::PipelineShaderStageCreateInfo info ); ShaderHandle( const ShaderHandle& other ) = delete; @@ -74,11 +51,6 @@ namespace fgl::engine ShaderHandle( ShaderHandle&& other ) = delete; ShaderHandle& operator=( ShaderHandle&& other ) = delete; - - ~ShaderHandle() - { - if ( shader_module != VK_NULL_HANDLE ) Device::getInstance().device().destroyShaderModule( shader_module ); - } }; vk::ShaderModule loadShaderModule( const std::string_view path ); diff --git a/src/engine/rendering/Device.cpp b/src/engine/rendering/Device.cpp index 856a2f1..3764215 100644 --- a/src/engine/rendering/Device.cpp +++ b/src/engine/rendering/Device.cpp @@ -21,65 +21,62 @@ namespace fgl::engine return *global_device; } - // class member functions - Device::Device( Window& window, Instance& instance ) : m_instance( instance ) + vk::PhysicalDeviceFeatures Device::DeviceCreateInfo::getDeviceFeatures( PhysicalDevice& physical_device ) { - assert( !global_device ); + const vk::PhysicalDeviceFeatures available_features { physical_device->getFeatures() }; - createSurface( window ); - pickPhysicalDevice(); - createLogicalDevice(); - createVMAAllocator(); - createCommandPool(); + if ( available_features.samplerAnisotropy != VK_TRUE ) + { + throw std::runtime_error( "samplerAnsitrophy not supported by device" ); + } - global_device = this; + if ( available_features.multiDrawIndirect != VK_TRUE ) + { + throw std::runtime_error( "multiDrawIndirect not supported by device" ); + } - DescriptorPool::init( *global_device ); + if ( available_features.tessellationShader != VK_TRUE ) + { + throw std::runtime_error( "Tesselation shader not supported by device" ); + } + + if ( available_features.drawIndirectFirstInstance != VK_TRUE ) + { + throw std::runtime_error( "drawIndirectFirstInstance not supported by device" ); + } + + //Set enabled features + vk::PhysicalDeviceFeatures deviceFeatures = {}; + deviceFeatures.samplerAnisotropy = VK_TRUE; + deviceFeatures.multiDrawIndirect = VK_TRUE; + deviceFeatures.tessellationShader = VK_TRUE; + deviceFeatures.drawIndirectFirstInstance = VK_TRUE; + + return deviceFeatures; } - Device::~Device() + vk::PhysicalDeviceDescriptorIndexingFeatures Device::DeviceCreateInfo::getIndexingFeatures() { - vkDestroyCommandPool( m_device, m_commandPool, nullptr ); - vkDestroyDevice( m_device, nullptr ); + vk::PhysicalDeviceDescriptorIndexingFeatures indexing_features {}; + indexing_features.setRuntimeDescriptorArray( VK_TRUE ); + indexing_features.setDescriptorBindingPartiallyBound( VK_TRUE ); + indexing_features.setShaderSampledImageArrayNonUniformIndexing( VK_TRUE ); + indexing_features.setDescriptorBindingSampledImageUpdateAfterBind( VK_TRUE ); - vkDestroySurfaceKHR( m_instance, m_surface_khr, nullptr ); - vkDestroyInstance( m_instance, nullptr ); + return indexing_features; } - void Device::pickPhysicalDevice() + std::vector< vk::DeviceQueueCreateInfo > Device::DeviceCreateInfo::getQueueCreateInfos( PhysicalDevice& + physical_device ) { - std::vector< vk::PhysicalDevice > devices { - static_cast< vk::Instance >( m_instance ).enumeratePhysicalDevices() + std::vector< vk::DeviceQueueCreateInfo > queueCreateInfos; + std::set< std::uint32_t > uniqueQueueFamilies = { + physical_device.queueInfo().getIndex( vk::QueueFlagBits::eGraphics ), + physical_device.queueInfo().getPresentIndex(), }; - bool found { false }; - - for ( const auto& device : devices ) - { - if ( isDeviceSuitable( device ) ) - { - m_physical_device = device; - found = true; - break; - } - } - - m_properties = m_physical_device.getProperties(); - - if ( !found ) - { - throw std::runtime_error( "failed to find a suitable GPU!" ); - } - } - - void Device::createLogicalDevice() - { - const QueueFamilyIndices indices { findQueueFamilies( m_physical_device ) }; - - std::vector< vk::DeviceQueueCreateInfo > queueCreateInfos; - std::set< uint32_t > uniqueQueueFamilies = { indices.graphicsFamily, indices.presentFamily }; - - float queuePriority = 1.0f; + //TODO: Store this somewhere where it doesn't need to be static + static float queuePriority = 1.0f; for ( uint32_t queueFamily : uniqueQueueFamilies ) { vk::DeviceQueueCreateInfo queueCreateInfo = {}; @@ -89,30 +86,23 @@ namespace fgl::engine queueCreateInfos.push_back( queueCreateInfo ); } - vk::PhysicalDeviceFeatures deviceFeatures = {}; - deviceFeatures.samplerAnisotropy = VK_TRUE; - deviceFeatures.multiDrawIndirect = VK_TRUE; - deviceFeatures.tessellationShader = VK_TRUE; - deviceFeatures.drawIndirectFirstInstance = VK_TRUE; - - vk::PhysicalDeviceDescriptorIndexingFeatures indexing_features {}; - indexing_features.setRuntimeDescriptorArray( true ); - indexing_features.setDescriptorBindingPartiallyBound( true ); - indexing_features.setShaderSampledImageArrayNonUniformIndexing( true ); - indexing_features.setDescriptorBindingSampledImageUpdateAfterBind( true ); + return queueCreateInfos; + } + vk::DeviceCreateInfo Device::DeviceCreateInfo::getCreateInfo( PhysicalDevice& physical_device ) + { vk::DeviceCreateInfo createInfo {}; - createInfo.queueCreateInfoCount = static_cast< uint32_t >( queueCreateInfos.size() ); - createInfo.pQueueCreateInfos = queueCreateInfos.data(); + createInfo.queueCreateInfoCount = static_cast< uint32_t >( m_queue_create_infos.size() ); + createInfo.pQueueCreateInfos = m_queue_create_infos.data(); - createInfo.pEnabledFeatures = &deviceFeatures; + createInfo.pEnabledFeatures = &m_requested_features; createInfo.enabledExtensionCount = static_cast< uint32_t >( deviceExtensions.size() ); createInfo.ppEnabledExtensionNames = deviceExtensions.data(); - createInfo.setPNext( &indexing_features ); + createInfo.setPNext( &m_indexing_features ); //Get device extension list - const auto supported_extensions { m_physical_device.enumerateDeviceExtensionProperties() }; + const auto supported_extensions { physical_device.handle().enumerateDeviceExtensionProperties() }; std::cout << "Supported device extensions:" << std::endl; for ( auto& desired_ext : deviceExtensions ) { @@ -131,7 +121,7 @@ namespace fgl::engine // might not really be necessary anymore because device specific validation layers // have been deprecated - if ( enableValidationLayers ) + if ( true ) { createInfo.enabledLayerCount = static_cast< uint32_t >( validationLayers.size() ); createInfo.ppEnabledLayerNames = validationLayers.data(); @@ -141,59 +131,47 @@ namespace fgl::engine createInfo.enabledLayerCount = 0; } - if ( auto res = m_physical_device.createDevice( &createInfo, nullptr, &m_device ); res != vk::Result::eSuccess ) - { - throw std::runtime_error( "failed to create logical device!" ); - } - - m_device.getQueue( indices.graphicsFamily, 0, &m_graphics_queue ); - m_device.getQueue( indices.presentFamily, 0, &m_present_queue ); + return createInfo; } - void Device::createCommandPool() - { - QueueFamilyIndices queueFamilyIndices = findPhysicalQueueFamilies(); + Device::DeviceCreateInfo::DeviceCreateInfo( PhysicalDevice& physical_device ) : + m_requested_features( getDeviceFeatures( physical_device ) ), + m_indexing_features( getIndexingFeatures() ), + m_queue_create_infos( getQueueCreateInfos( physical_device ) ), + m_create_info( getCreateInfo( physical_device ) ) + {} + vk::CommandPoolCreateInfo Device::commandPoolInfo() + { vk::CommandPoolCreateInfo poolInfo = {}; - poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily; + poolInfo.queueFamilyIndex = m_physical_device.queueInfo().getIndex( vk::QueueFlagBits::eGraphics ); poolInfo.flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer | vk::CommandPoolCreateFlagBits::eTransient; - if ( m_device.createCommandPool( &poolInfo, nullptr, &m_commandPool ) != vk::Result::eSuccess ) - { - throw std::runtime_error( "failed to create command pool!" ); - } + return poolInfo; } - void Device::createSurface( Window& window ) + // class member functions + Device::Device( Window& window, Instance& instance ) : + m_instance( instance ), + m_surface_khr( window, instance ), + m_physical_device( m_instance, m_surface_khr ), + device_creation_info( m_physical_device ), + m_device( m_physical_device, device_creation_info.m_create_info ), + m_commandPool( m_device.createCommandPool( commandPoolInfo() ) ), + m_graphics_queue( m_device + .getQueue( m_physical_device.queueInfo().getIndex( vk::QueueFlagBits::eGraphics ), 0 ) ), + m_present_queue( m_device.getQueue( m_physical_device.queueInfo().getPresentIndex(), 0 ) ), + m_allocator( createVMAAllocator() ) { - m_surface_khr = window.createWindowSurface( m_instance ); + assert( !global_device ); + + global_device = this; + + DescriptorPool::init( *global_device ); } - bool Device::isDeviceSuitable( vk::PhysicalDevice device ) - { - const QueueFamilyIndices indices { findQueueFamilies( device ) }; - - const bool extensionsSupported { checkDeviceExtensionSupport( device ) }; - - bool swapChainAdequate { false }; - if ( extensionsSupported ) - { - const SwapChainSupportDetails swapChainSupport { querySwapChainSupport( device ) }; - swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty(); - } - - vk::PhysicalDeviceFeatures supportedFeatures; - device.getFeatures( &supportedFeatures ); - - std::cout << "Device: " << device.getProperties().deviceName << std::endl; - std::cout << "\tgraphicsFamily: " << indices.graphicsFamily << std::endl; - std::cout << "\tpresentFamily: " << indices.presentFamily << std::endl; - std::cout << "\textensionsSupported: " << extensionsSupported << std::endl; - std::cout << "\tswapChainAdequate: " << swapChainAdequate << std::endl; - std::cout << "\tsamplerAnisotropy: " << supportedFeatures.samplerAnisotropy << std::endl; - - return indices.isComplete() && extensionsSupported && swapChainAdequate && supportedFeatures.samplerAnisotropy; - } + Device::~Device() + {} bool Device::checkValidationLayerSupport() { @@ -221,28 +199,7 @@ namespace fgl::engine return true; } - std::vector< const char* > Device::getRequiredInstanceExtensions() - { - uint32_t glfwExtensionCount = 0; - const char** glfwExtensions; - glfwExtensions = glfwGetRequiredInstanceExtensions( &glfwExtensionCount ); - - if ( glfwExtensions == nullptr ) throw std::runtime_error( "Failed to get required extensions from glfw" ); - - std::vector< const char* > extensions( glfwExtensions, glfwExtensions + glfwExtensionCount ); - - // "VK_KHR_surface" is guaranteed to be in this list - assert( extensions.size() >= 1 ); - - if ( enableValidationLayers ) - { - extensions.push_back( VK_EXT_DEBUG_UTILS_EXTENSION_NAME ); - } - - return extensions; - } - - bool Device::checkDeviceExtensionSupport( vk::PhysicalDevice device ) + bool Device::checkDeviceExtensionSupport( vk::raii::PhysicalDevice device ) { const std::vector< vk::ExtensionProperties > availableExtensions { device.enumerateDeviceExtensionProperties() @@ -267,68 +224,14 @@ namespace fgl::engine return found_count == required_count; } - QueueFamilyIndices Device::findQueueFamilies( vk::PhysicalDevice device ) - { - QueueFamilyIndices indices {}; - - std::vector< vk::QueueFamilyProperties > queueFamilies { device.getQueueFamilyProperties() }; - - int i { 0 }; - for ( const auto& queueFamily : queueFamilies ) - { - if ( queueFamily.queueCount > 0 && queueFamily.queueFlags & vk::QueueFlagBits::eGraphics ) - { - indices.graphicsFamily = i; - indices.graphicsFamilyHasValue = true; - } - vk::Bool32 presentSupport { VK_FALSE }; - vkGetPhysicalDeviceSurfaceSupportKHR( device, i, m_surface_khr, &presentSupport ); - if ( queueFamily.queueCount > 0 && presentSupport ) - { - indices.presentFamily = i; - indices.presentFamilyHasValue = true; - } - if ( indices.isComplete() ) - { - break; - } - - i++; - } - - return indices; - } - - SwapChainSupportDetails Device::querySwapChainSupport( vk::PhysicalDevice device ) + SwapChainSupportDetails Device::querySwapChainSupport( vk::raii::PhysicalDevice device ) { SwapChainSupportDetails details; - if ( device.getSurfaceCapabilitiesKHR( m_surface_khr, &details.capabilities ) != vk::Result::eSuccess ) - throw std::runtime_error( "failed to get surface capabilities" ); + details.capabilities = device.getSurfaceCapabilitiesKHR( m_surface_khr ); + details.formats = device.getSurfaceFormatsKHR( m_surface_khr ); + details.presentModes = device.getSurfacePresentModesKHR( m_surface_khr ); - uint32_t formatCount { 0 }; - if ( device.getSurfaceFormatsKHR( m_surface_khr, &formatCount, nullptr ) != vk::Result::eSuccess ) - throw std::runtime_error( "failed to get surface formats" ); - - if ( formatCount != 0 ) - { - details.formats.resize( formatCount ); - if ( device.getSurfaceFormatsKHR( m_surface_khr, &formatCount, details.formats.data() ) - != vk::Result::eSuccess ) - throw std::runtime_error( "failed to get surface formats" ); - } - - uint32_t presentModeCount { 0 }; - if ( device.getSurfacePresentModesKHR( m_surface_khr, &presentModeCount, nullptr ) != vk::Result::eSuccess ) - throw std::runtime_error( "failed to get surface present modes" ); - - if ( presentModeCount != 0 ) - { - details.presentModes.resize( presentModeCount ); - if ( device.getSurfacePresentModesKHR( m_surface_khr, &presentModeCount, details.presentModes.data() ) - != vk::Result::eSuccess ) - throw std::runtime_error( "failed to get surface present modes" ); - } return details; } @@ -337,8 +240,7 @@ namespace fgl::engine { for ( vk::Format format : candidates ) { - vk::FormatProperties props; - m_physical_device.getFormatProperties( format, &props ); + vk::FormatProperties props { m_physical_device.handle().getFormatProperties( format ) }; if ( tiling == vk::ImageTiling::eLinear && ( props.linearTilingFeatures & features ) == features ) { @@ -354,8 +256,7 @@ namespace fgl::engine uint32_t Device::findMemoryType( uint32_t typeFilter, vk::MemoryPropertyFlags properties ) { - vk::PhysicalDeviceMemoryProperties memProperties; - m_physical_device.getMemoryProperties( &memProperties ); + vk::PhysicalDeviceMemoryProperties memProperties { m_physical_device.handle().getMemoryProperties() }; for ( uint32_t i = 0; i < memProperties.memoryTypeCount; i++ ) { if ( ( typeFilter & ( 1 << i ) ) @@ -368,7 +269,7 @@ namespace fgl::engine throw std::runtime_error( "failed to find suitable memory type!" ); } - vk::CommandBuffer Device::beginSingleTimeCommands() + vk::raii::CommandBuffer Device::beginSingleTimeCommands() { ZoneScoped; vk::CommandBufferAllocateInfo allocInfo {}; @@ -376,40 +277,43 @@ namespace fgl::engine allocInfo.commandPool = m_commandPool; allocInfo.commandBufferCount = 1; - vk::CommandBuffer commandBuffer {}; - if ( m_device.allocateCommandBuffers( &allocInfo, &commandBuffer ) != vk::Result::eSuccess ) - throw std::runtime_error( "failed to allocate command buffers!" ); + auto command_buffers { m_device.allocateCommandBuffers( allocInfo ) }; + + assert( command_buffers.size() == 1 ); + + vk::raii::CommandBuffer command_buffer { std::move( command_buffers[ 0 ] ) }; vk::CommandBufferBeginInfo beginInfo {}; beginInfo.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit; - commandBuffer.begin( beginInfo ); + command_buffer.begin( beginInfo ); - return commandBuffer; + return command_buffer; } - void Device::endSingleTimeCommands( vk::CommandBuffer commandBuffer ) + void Device::endSingleTimeCommands( vk::raii::CommandBuffer& commandBuffer ) { ZoneScoped; - vkEndCommandBuffer( commandBuffer ); + commandBuffer.end(); vk::SubmitInfo submitInfo {}; submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &commandBuffer; + submitInfo.pCommandBuffers = &( *commandBuffer ); - if ( m_graphics_queue.submit( 1, &submitInfo, VK_NULL_HANDLE ) != vk::Result::eSuccess ) - throw std::runtime_error( "failed to submit single time command buffer!" ); + std::vector< vk::SubmitInfo > submit_infos { submitInfo }; + + m_graphics_queue.submit( submit_infos ); m_graphics_queue.waitIdle(); - m_device.freeCommandBuffers( m_commandPool, 1, &commandBuffer ); + //m_device.freeCommandBuffers( m_commandPool, 1, &commandBuffer ); } void Device:: copyBufferToImage( vk::Buffer buffer, vk::Image image, uint32_t width, uint32_t height, uint32_t layerCount ) { ZoneScoped; - vk::CommandBuffer commandBuffer { beginSingleTimeCommands() }; + vk::raii::CommandBuffer commandBuffer { beginSingleTimeCommands() }; vk::BufferImageCopy region {}; region.bufferOffset = 0; @@ -424,50 +328,55 @@ namespace fgl::engine region.imageOffset = vk::Offset3D { 0, 0, 0 }; region.imageExtent = vk::Extent3D { width, height, 1 }; - commandBuffer.copyBufferToImage( buffer, image, vk::ImageLayout::eTransferDstOptimal, 1, ®ion ); + std::vector< vk::BufferImageCopy > regions { region }; + + commandBuffer.copyBufferToImage( buffer, image, vk::ImageLayout::eTransferDstOptimal, regions ); + endSingleTimeCommands( commandBuffer ); } - void Device::createVMAAllocator() + VmaAllocator Device::createVMAAllocator() { VmaVulkanFunctions vk_func {}; vk_func.vkGetInstanceProcAddr = vkGetInstanceProcAddr; vk_func.vkGetDeviceProcAddr = vkGetDeviceProcAddr; VmaAllocatorCreateInfo create_info {}; - create_info.physicalDevice = m_physical_device; - create_info.device = m_device; + create_info.physicalDevice = *m_physical_device.handle(); + create_info.device = *m_device; create_info.pVulkanFunctions = &vk_func; create_info.instance = m_instance; create_info.vulkanApiVersion = VK_API_VERSION_1_0; - if ( vmaCreateAllocator( &create_info, &m_allocator ) != VK_SUCCESS ) + VmaAllocator allocator; + + if ( vmaCreateAllocator( &create_info, &allocator ) != VK_SUCCESS ) throw std::runtime_error( "Failed to create VMA allocator" ); + + return allocator; } void Device::copyBuffer( vk::Buffer dst, vk::Buffer src, vk::DeviceSize dst_offset, vk::DeviceSize src_offset, vk::DeviceSize size ) { - vk::CommandBuffer commandBuffer { beginSingleTimeCommands() }; + vk::raii::CommandBuffer commandBuffer { beginSingleTimeCommands() }; vk::BufferCopy copyRegion {}; copyRegion.size = size; copyRegion.srcOffset = src_offset; copyRegion.dstOffset = dst_offset; - commandBuffer.copyBuffer( src, dst, 1, ©Region ); + std::vector< vk::BufferCopy > copy_regions { copyRegion }; + + commandBuffer.copyBuffer( src, dst, copy_regions ); endSingleTimeCommands( commandBuffer ); } - vk::Result Device::setDebugUtilsObjectName( [[maybe_unused]] const vk::DebugUtilsObjectNameInfoEXT& nameInfo ) + vk::Result Device::setDebugUtilsObjectName( const vk::DebugUtilsObjectNameInfoEXT& nameInfo ) { #ifndef NDEBUG - if ( device().setDebugUtilsObjectNameEXT( &nameInfo ) != vk::Result::eSuccess ) - { - std::cout << "Failed to set debug object name" << std::endl; - throw std::runtime_error( "Failed to set debug object name" ); - } + device().setDebugUtilsObjectNameEXT( nameInfo ); #endif return vk::Result::eSuccess; } diff --git a/src/engine/rendering/Device.hpp b/src/engine/rendering/Device.hpp index 113ab87..58ea07a 100644 --- a/src/engine/rendering/Device.hpp +++ b/src/engine/rendering/Device.hpp @@ -7,6 +7,7 @@ #include #include "Instance.hpp" +#include "PhysicalDevice.hpp" #include "engine/Window.hpp" #include "engine/concepts/is_suballocation.hpp" #include "vma/vma_impl.hpp" @@ -35,19 +36,38 @@ namespace fgl::engine { Instance& m_instance; - vk::PhysicalDevice m_physical_device { VK_NULL_HANDLE }; - vk::CommandPool m_commandPool { VK_NULL_HANDLE }; + Surface m_surface_khr; - VmaAllocator m_allocator { VK_NULL_HANDLE }; + PhysicalDevice m_physical_device; - vk::Device m_device { VK_NULL_HANDLE }; - vk::SurfaceKHR m_surface_khr { VK_NULL_HANDLE }; - vk::Queue m_graphics_queue { VK_NULL_HANDLE }; - vk::Queue m_present_queue { VK_NULL_HANDLE }; + inline static std::vector< const char* > validationLayers { "VK_LAYER_KHRONOS_validation" }; + inline static std::vector< const char* > deviceExtensions { VK_KHR_SWAPCHAIN_EXTENSION_NAME, + VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME }; - std::vector< const char* > validationLayers { "VK_LAYER_KHRONOS_validation" }; - std::vector< const char* > deviceExtensions { VK_KHR_SWAPCHAIN_EXTENSION_NAME, - VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME }; + struct DeviceCreateInfo + { + vk::PhysicalDeviceFeatures m_requested_features; + vk::PhysicalDeviceDescriptorIndexingFeatures m_indexing_features; + std::vector< vk::DeviceQueueCreateInfo > m_queue_create_infos; + vk::DeviceCreateInfo m_create_info; + + vk::PhysicalDeviceFeatures getDeviceFeatures( PhysicalDevice& ); + vk::PhysicalDeviceDescriptorIndexingFeatures getIndexingFeatures(); + std::vector< vk::DeviceQueueCreateInfo > getQueueCreateInfos( PhysicalDevice& ); + vk::DeviceCreateInfo getCreateInfo( PhysicalDevice& ); + + DeviceCreateInfo( PhysicalDevice& ); + + } device_creation_info; + + vk::raii::Device m_device; + + vk::raii::CommandPool m_commandPool; + + vk::raii::Queue m_graphics_queue; + vk::raii::Queue m_present_queue; + + VmaAllocator m_allocator; void copyBuffer( vk::Buffer dst, @@ -60,7 +80,10 @@ namespace fgl::engine vk::PhysicalDeviceProperties m_properties {}; - Device( Window& window, Instance& ); + vk::CommandPoolCreateInfo commandPoolInfo(); + + Device( Window&, Instance& ); + ~Device(); static Device& getInstance(); @@ -85,20 +108,12 @@ namespace fgl::engine private: - void setupDebugMessenger(); - void createSurface( Window& window ); - void pickPhysicalDevice(); - void createLogicalDevice(); - void createVMAAllocator(); - void createCommandPool(); + VmaAllocator createVMAAllocator(); // helper functions - bool isDeviceSuitable( vk::PhysicalDevice device ); - std::vector< const char* > getRequiredInstanceExtensions(); bool checkValidationLayerSupport(); - QueueFamilyIndices findQueueFamilies( vk::PhysicalDevice device ); - bool checkDeviceExtensionSupport( vk::PhysicalDevice device ); - SwapChainSupportDetails querySwapChainSupport( vk::PhysicalDevice device ); + bool checkDeviceExtensionSupport( vk::raii::PhysicalDevice device ); + SwapChainSupportDetails querySwapChainSupport( vk::raii::PhysicalDevice device ); public: @@ -112,28 +127,24 @@ namespace fgl::engine public: - Device( Window& window ); - ~Device(); - // Not copyable or movable - Device( const Device& ) = delete; - Device& operator=( const Device& ) = delete; - Device( Device&& ) = delete; - Device& operator=( Device&& ) = delete; + FGL_DELETE_DEFAULT_CTOR( Device ) + FGL_DELETE_COPY( Device ) + FGL_DELETE_MOVE( Device ) vk::CommandPool getCommandPool() { return m_commandPool; } - vk::Device device() { return m_device; } + vk::raii::Device& device() { return m_device; } - vk::Instance instance() { return m_instance; } + Instance& instance() { return m_instance; } - vk::PhysicalDevice phyDevice() { return m_physical_device; } + PhysicalDevice& phyDevice() { return m_physical_device; } vk::SurfaceKHR surface() { return m_surface_khr; } - vk::Queue graphicsQueue() { return m_graphics_queue; } + vk::raii::Queue& graphicsQueue() { return m_graphics_queue; } - vk::Queue presentQueue() { return m_present_queue; } + vk::raii::Queue& presentQueue() { return m_present_queue; } VmaAllocator allocator() { return m_allocator; } @@ -141,16 +152,18 @@ namespace fgl::engine uint32_t findMemoryType( uint32_t typeFilter, vk::MemoryPropertyFlags properties ); - QueueFamilyIndices findPhysicalQueueFamilies() { return findQueueFamilies( m_physical_device ); } - vk::Format findSupportedFormat( const std::vector< vk::Format >& candidates, vk::ImageTiling tiling, vk::FormatFeatureFlags features ); - vk::CommandBuffer beginSingleTimeCommands(); - void endSingleTimeCommands( vk::CommandBuffer commandBuffer ); + vk::raii::CommandBuffer beginSingleTimeCommands(); + void endSingleTimeCommands( vk::raii::CommandBuffer& commandBuffer ); void copyBufferToImage( vk::Buffer buffer, vk::Image image, uint32_t width, uint32_t height, uint32_t layerCount ); + + VkDevice operator*() { return *m_device; } + + vk::raii::Device* operator->() { return &m_device; } }; } // namespace fgl::engine \ No newline at end of file diff --git a/src/engine/rendering/Instance.hpp b/src/engine/rendering/Instance.hpp index c50c5f7..2054a8a 100644 --- a/src/engine/rendering/Instance.hpp +++ b/src/engine/rendering/Instance.hpp @@ -44,6 +44,8 @@ namespace fgl::engine ~Instance(); + inline vk::raii::Instance& handle() { return m_instance; } + inline operator vk::Instance() { return m_instance; } inline operator VkInstance() { return *m_instance; } diff --git a/src/engine/rendering/PhysicalDevice.cpp b/src/engine/rendering/PhysicalDevice.cpp new file mode 100644 index 0000000..15b0b31 --- /dev/null +++ b/src/engine/rendering/PhysicalDevice.cpp @@ -0,0 +1,104 @@ +// +// Created by kj16609 on 6/20/24. +// + +#include "PhysicalDevice.hpp" + +#include "Instance.hpp" +#include "Surface.hpp" +#include "engine/logging/logging.hpp" + +namespace fgl::engine +{ + + PhysicalDevice::PhysicalDevice( Instance& instance, Surface& surface ) : + m_phy_device( pickPhysicalDevice( instance, surface ) ), + queue_pool( m_phy_device, surface ) + {} + + //! Checks that a device has a graphics capable queue and can present to the given surface. + bool isDeviceSupported( const vk::raii::PhysicalDevice& device, Surface& surface ) + { + const std::vector< vk::QueueFamilyProperties > family_props { device.getQueueFamilyProperties() }; + + bool has_graphics_queue { false }; + bool has_present_queue { false }; + + int idx { 0 }; + for ( const auto& queue_family : family_props ) + { + if ( queue_family.queueCount <= 0 ) + { + ++idx; + continue; + } + + // We need at least 1 queue that can do graphics. + if ( queue_family.queueFlags & vk::QueueFlagBits::eGraphics ) + { + log::debug( "Graphics capable queue found at idx: {}", idx ); + has_graphics_queue = true; + } + + // Check if the device can present to the surface. + vk::Bool32 can_present { device.getSurfaceSupportKHR( idx, surface ) }; + if ( can_present == VK_TRUE ) + { + log::debug( "Present capable queue found at idx: {}", idx ); + has_present_queue = true; + } + + if ( has_graphics_queue && has_present_queue ) return true; + + ++idx; + } + + return false; + } + + vk::raii::PhysicalDevice PhysicalDevice::pickPhysicalDevice( Instance& instance, Surface& surface ) + { + std::vector< vk::raii::PhysicalDevice > devices { instance.handle().enumeratePhysicalDevices() }; + + for ( auto& device : devices ) + { + if ( isDeviceSupported( device, surface ) ) + { + //We found a device we can use. + log::info( "Found device for surface" ); + + vk::raii::PhysicalDevice selected_device { std::move( device ) }; + + return selected_device; + } + } + + throw std::runtime_error( "Failed to find a valid device" ); + } + + const static std::vector< const char* > required_device_extensions { VK_KHR_SWAPCHAIN_EXTENSION_NAME, + VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME }; + + bool PhysicalDevice::supportsRequiredExtensions() + { + const std::vector< vk::ExtensionProperties > device_extentions { + m_phy_device.enumerateDeviceExtensionProperties() + }; + + for ( const auto required : required_device_extensions ) + { + if ( std::find_if( + device_extentions.begin(), + device_extentions.end(), + [ &required ]( const vk::ExtensionProperties& props ) + { return std::strcmp( props.extensionName, required ); } ) + == device_extentions.end() ) + { + return false; + } + } + + return true; + } + +} // namespace fgl::engine diff --git a/src/engine/rendering/PhysicalDevice.hpp b/src/engine/rendering/PhysicalDevice.hpp new file mode 100644 index 0000000..0dcc8de --- /dev/null +++ b/src/engine/rendering/PhysicalDevice.hpp @@ -0,0 +1,43 @@ +// +// Created by kj16609 on 6/20/24. +// + +#pragma once + +#include + +#include "QueuePool.hpp" +#include "engine/FGL_DEFINES.hpp" + +namespace fgl::engine +{ + class Instance; + class Surface; + + class PhysicalDevice + { + vk::raii::PhysicalDevice m_phy_device; + QueuePool queue_pool; + + FGL_DELETE_ALL_Ro5( PhysicalDevice ); + + //! Picks a device that can render to the desired output window + vk::raii::PhysicalDevice pickPhysicalDevice( Instance& dev, Surface& surface ); + bool supportsRequiredExtensions(); + + public: + + QueuePool& queueInfo() { return queue_pool; } + + PhysicalDevice( Instance& instance, Surface& surface ); + + vk::raii::PhysicalDevice& handle() { return m_phy_device; } + + operator vk::raii::PhysicalDevice() { return m_phy_device; } + + VkPhysicalDevice operator*() { return *m_phy_device; } + + vk::raii::PhysicalDevice* operator->() { return &m_phy_device; } + }; + +} // namespace fgl::engine \ No newline at end of file diff --git a/src/engine/rendering/QueuePool.cpp b/src/engine/rendering/QueuePool.cpp new file mode 100644 index 0000000..e4be9d0 --- /dev/null +++ b/src/engine/rendering/QueuePool.cpp @@ -0,0 +1,49 @@ +// +// Created by kj16609 on 6/20/24. +// + +#include "QueuePool.hpp" + +#include "Attachment.hpp" +#include "PhysicalDevice.hpp" + +namespace fgl::engine +{ + + QueuePool::QueuePool( vk::raii::PhysicalDevice& physical_device, Surface& surface ) + { + const auto family_props { physical_device.getQueueFamilyProperties() }; + + for ( std::uint32_t i = 0; i < family_props.size(); ++i ) + { + auto& props { family_props[ i ] }; + if ( props.queueCount > 0 ) + { + vk::Bool32 can_present { physical_device.getSurfaceSupportKHR( i, surface ) }; + + queue_info.emplace_back( props, can_present == VK_TRUE, 0 ); + } + } + } + + QueuePool::QueueIndex QueuePool::getIndex( const vk::QueueFlags flags ) + { + for ( std::uint32_t i = 0; i < queue_info.size(); ++i ) + { + const auto& [ props, can_present, num_allocated ] = queue_info[ i ]; + + if ( props.queueFlags & flags && props.queueCount > 0 ) return i; + } + + throw std::runtime_error( "Failed to get index of queue family with given flags" ); + } + + std::uint32_t QueuePool::getPresentIndex() + { + for ( std::uint32_t i = 0; i < queue_info.size(); ++i ) + { + if ( queue_info[ i ].can_present ) return i; + } + } + +} // namespace fgl::engine diff --git a/src/engine/rendering/QueuePool.hpp b/src/engine/rendering/QueuePool.hpp new file mode 100644 index 0000000..f4ed2d9 --- /dev/null +++ b/src/engine/rendering/QueuePool.hpp @@ -0,0 +1,48 @@ +// +// Created by kj16609 on 6/20/24. +// + +#pragma once +#include +#include + +#include + +#include "engine/FGL_DEFINES.hpp" + +namespace fgl::engine +{ + class Surface; + class PhysicalDevice; + + class Queue; + + class QueuePool + { + struct QueueInfo + { + vk::QueueFamilyProperties props; + bool can_present; + std::uint8_t allocated { 0 }; + }; + + std::vector< QueueInfo > queue_info {}; + + public: + + QueuePool( vk::raii::PhysicalDevice&, Surface& ); + + FGL_DELETE_ALL_Ro5( QueuePool ); + + Queue allocate(); + Queue allocateIndex( const std::uint32_t idx ); + + using QueueIndex = std::uint32_t; + + //! Returns a unique list of indexes with the matching flags + QueueIndex getIndex( const vk::QueueFlags flags ); + + std::uint32_t getPresentIndex(); + }; + +} // namespace fgl::engine diff --git a/src/engine/rendering/RenderPass.cpp b/src/engine/rendering/RenderPass.cpp index 553eda1..a0cfd77 100644 --- a/src/engine/rendering/RenderPass.cpp +++ b/src/engine/rendering/RenderPass.cpp @@ -9,9 +9,9 @@ namespace fgl::engine { - vk::RenderPass RenderPass::create() + vk::raii::RenderPass RenderPass::create() { - auto device { Device::getInstance().device() }; + auto& device { Device::getInstance() }; vk::RenderPassCreateInfo info; @@ -24,12 +24,7 @@ namespace fgl::engine vk::RenderPass render_pass {}; - if ( device.createRenderPass( &info, nullptr, &render_pass ) != vk::Result::eSuccess ) [[unlikely]] - { - throw std::runtime_error( "failed to create render pass!" ); - } - else - return render_pass; + return device->createRenderPass( info ); } } // namespace fgl::engine diff --git a/src/engine/rendering/RenderPass.hpp b/src/engine/rendering/RenderPass.hpp index 2431137..5e1e234 100644 --- a/src/engine/rendering/RenderPass.hpp +++ b/src/engine/rendering/RenderPass.hpp @@ -101,7 +101,7 @@ namespace fgl::engine return std::make_unique< RenderPassResources >( std::move( views ) ); } - vk::RenderPass create(); + vk::raii::RenderPass create(); }; } // namespace fgl::engine \ No newline at end of file diff --git a/src/engine/rendering/Renderer.cpp b/src/engine/rendering/Renderer.cpp index d760b6e..c02fde6 100644 --- a/src/engine/rendering/Renderer.cpp +++ b/src/engine/rendering/Renderer.cpp @@ -25,36 +25,35 @@ namespace fgl::engine { - Renderer::Renderer( Window& window ) : m_window( window ) + Renderer::Renderer( Window& window, PhysicalDevice& phy_device ) : + m_window( window ), + m_phy_device( phy_device ), + m_swapchain( std::make_unique< SwapChain >( m_window.getExtent(), m_phy_device ) ) { recreateSwapchain(); createCommandBuffers(); } Renderer::~Renderer() + {} + + TracyVkCtx createContext( PhysicalDevice& physical_device, Device& device, vk::raii::CommandBuffer& cmd_buffer ) { - freeCommandBuffers(); + return TracyVkContext( *physical_device, *device, *device.graphicsQueue(), *cmd_buffer ); } void Renderer::createCommandBuffers() { - m_command_buffer.resize( SwapChain::MAX_FRAMES_IN_FLIGHT ); - vk::CommandBufferAllocateInfo alloc_info {}; alloc_info.pNext = VK_NULL_HANDLE; alloc_info.commandPool = Device::getInstance().getCommandPool(); alloc_info.level = vk::CommandBufferLevel::ePrimary; - alloc_info.commandBufferCount = static_cast< std::uint32_t >( m_command_buffer.size() ); + alloc_info.commandBufferCount = SwapChain::MAX_FRAMES_IN_FLIGHT; - if ( Device::getInstance().device().allocateCommandBuffers( &alloc_info, m_command_buffer.data() ) - != vk::Result::eSuccess ) - throw std::runtime_error( "Failed to allocate command buffers" ); + m_command_buffer = Device::getInstance().device().allocateCommandBuffers( alloc_info ); #if TRACY_ENABLE - VkPhysicalDevice phy_dev { Device::getInstance().phyDevice() }; - VkDevice dev { Device::getInstance().device() }; - - m_tracy_ctx = TracyVkContext( phy_dev, dev, Device::getInstance().graphicsQueue(), m_command_buffer[ 0 ] ); + m_tracy_ctx = createContext( m_phy_device, Device::getInstance(), m_command_buffer[ 0 ] ); /* m_tracy_ctx = TracyVkContextCalibrated( @@ -83,7 +82,7 @@ namespace fgl::engine Device::getInstance().device().waitIdle(); if ( m_swapchain == nullptr ) - m_swapchain = std::make_unique< SwapChain >( extent ); + m_swapchain = std::make_unique< SwapChain >( extent, m_phy_device ); else { std::shared_ptr< SwapChain > old_swap_chain { std::move( m_swapchain ) }; @@ -94,17 +93,7 @@ namespace fgl::engine } } - void Renderer::freeCommandBuffers() - { - if ( m_command_buffer.size() == 0 ) return; - - Device::getInstance().device().freeCommandBuffers( - Device::getInstance().getCommandPool(), - static_cast< std::uint32_t >( m_command_buffer.size() ), - m_command_buffer.data() ); - } - - vk::CommandBuffer Renderer::beginFrame() + vk::raii::CommandBuffer& Renderer::beginFrame() { assert( !is_frame_started && "Cannot begin frame while frame is already in progress" ); auto [ result, image_idx ] = m_swapchain->acquireNextImage(); @@ -113,7 +102,6 @@ namespace fgl::engine if ( result == vk::Result::eErrorOutOfDateKHR ) { recreateSwapchain(); - return nullptr; } if ( result != vk::Result::eSuccess && result != vk::Result::eSuboptimalKHR ) @@ -137,12 +125,11 @@ namespace fgl::engine ZoneScopedN( "Ending frame" ); assert( is_frame_started && "Cannot call end frame while frame is not in progress" ); - auto command_buffer { getCurrentCommandbuffer() }; + auto& command_buffer { getCurrentCommandbuffer() }; - if ( vkEndCommandBuffer( command_buffer ) != VK_SUCCESS ) - throw std::runtime_error( "Failed to end recording command buffer" ); + command_buffer.end(); - const auto result { m_swapchain->submitCommandBuffers( &command_buffer, current_image_idx ) }; + const auto result { m_swapchain->submitCommandBuffers( command_buffer, current_image_idx ) }; if ( result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR || m_window.wasWindowResized() ) @@ -157,11 +144,11 @@ namespace fgl::engine current_frame_idx = static_cast< std::uint16_t >( ( current_frame_idx + 1 ) % SwapChain::MAX_FRAMES_IN_FLIGHT ); } - void Renderer::beginSwapchainRendererPass( vk::CommandBuffer buffer ) + void Renderer::beginSwapchainRendererPass( vk::raii::CommandBuffer& buffer ) { assert( is_frame_started && "Cannot call beginSwapChainRenderPass if frame is not in progress" ); assert( - buffer == getCurrentCommandbuffer() + *buffer == *getCurrentCommandbuffer() && "Cannot begin render pass on command buffer from a different frame" ); std::vector< vk::ClearValue > clear_values { m_swapchain->getClearValues() }; @@ -174,7 +161,7 @@ namespace fgl::engine render_pass_info.clearValueCount = static_cast< std::uint32_t >( clear_values.size() ); render_pass_info.pClearValues = clear_values.data(); - buffer.beginRenderPass( &render_pass_info, vk::SubpassContents::eInline ); + buffer.beginRenderPass( render_pass_info, vk::SubpassContents::eInline ); vk::Viewport viewport {}; viewport.x = 0.0f; @@ -185,16 +172,21 @@ namespace fgl::engine viewport.maxDepth = 1.0f; vk::Rect2D scissor { { 0, 0 }, m_swapchain->getSwapChainExtent() }; - buffer.setViewport( 0, 1, &viewport ); - buffer.setScissor( 0, 1, &scissor ); + + std::vector< vk::Viewport > viewports { viewport }; + std::vector< vk::Rect2D > scissors { scissor }; + + buffer.setViewport( 0, viewports ); + buffer.setScissor( 0, scissors ); } - void Renderer::endSwapchainRendererPass( vk::CommandBuffer buffer ) + void Renderer::endSwapchainRendererPass( vk::raii::CommandBuffer& buffer ) { assert( is_frame_started && "Cannot call endSwapChainRenderPass if frame is not in progress" ); assert( - buffer == getCurrentCommandbuffer() && "Cannot end render pass on command buffer from a different frame" ); + *buffer == *getCurrentCommandbuffer() + && "Cannot end render pass on command buffer from a different frame" ); - vkCmdEndRenderPass( buffer ); + buffer.endRenderPass(); } } // namespace fgl::engine diff --git a/src/engine/rendering/Renderer.hpp b/src/engine/rendering/Renderer.hpp index abf4466..6163872 100644 --- a/src/engine/rendering/Renderer.hpp +++ b/src/engine/rendering/Renderer.hpp @@ -25,14 +25,14 @@ namespace fgl::engine class Renderer { Window& m_window; - std::unique_ptr< SwapChain > m_swapchain { std::make_unique< SwapChain >( m_window.getExtent() ) }; + PhysicalDevice& m_phy_device; + std::unique_ptr< SwapChain > m_swapchain; - std::vector< vk::CommandBuffer > m_command_buffer {}; + std::vector< vk::raii::CommandBuffer> m_command_buffer {}; std::optional< TracyVkCtx > m_tracy_ctx { std::nullopt }; void createCommandBuffers(); - void freeCommandBuffers(); void recreateSwapchain(); uint32_t current_image_idx { std::numeric_limits< std::uint32_t >::max() }; @@ -54,7 +54,7 @@ namespace fgl::engine bool isFrameInProgress() const { return is_frame_started; } - vk::CommandBuffer& getCurrentCommandbuffer() + vk::raii::CommandBuffer& getCurrentCommandbuffer() { assert( is_frame_started && "Cannot get command buffer while frame not in progress" ); return m_command_buffer[ current_frame_idx ]; @@ -70,16 +70,16 @@ namespace fgl::engine #endif } - vk::RenderPass getSwapChainRenderPass() const { return m_swapchain->getRenderPass(); } + vk::raii::RenderPass& getSwapChainRenderPass() const { return m_swapchain->getRenderPass(); } float getAspectRatio() const { return m_swapchain->extentAspectRatio(); } - vk::CommandBuffer beginFrame(); + vk::raii::CommandBuffer& beginFrame(); void endFrame(); - void beginSwapchainRendererPass( vk::CommandBuffer buffer ); - void endSwapchainRendererPass( vk::CommandBuffer buffer ); + void beginSwapchainRendererPass( vk::raii::CommandBuffer& buffer ); + void endSwapchainRendererPass( vk::raii::CommandBuffer& buffer ); - Renderer( Window& window ); + Renderer( Window& window, PhysicalDevice& phy_device ); ~Renderer(); Renderer( Renderer&& other ) = delete; Renderer( const Renderer& other ) = delete; diff --git a/src/engine/rendering/Surface.cpp b/src/engine/rendering/Surface.cpp new file mode 100644 index 0000000..8675e4e --- /dev/null +++ b/src/engine/rendering/Surface.cpp @@ -0,0 +1,15 @@ +// +// Created by kj16609 on 6/20/24. +// + +#include "Surface.hpp" + +#include "engine/Window.hpp" + +namespace fgl::engine +{ + + Surface::Surface( Window& window, Instance& instance ) : m_surface( window.createWindowSurface( instance ) ) + {} + +} // namespace fgl::engine diff --git a/src/engine/rendering/Surface.hpp b/src/engine/rendering/Surface.hpp new file mode 100644 index 0000000..2d01539 --- /dev/null +++ b/src/engine/rendering/Surface.hpp @@ -0,0 +1,31 @@ +// +// Created by kj16609 on 6/20/24. +// + +#pragma once +#include + +#include "engine/FGL_DEFINES.hpp" + +namespace fgl::engine +{ + class Window; + class Instance; + + class Surface + { + vk::raii::SurfaceKHR m_surface; + + public: + + Surface( Window& window, Instance& instance ); + + FGL_DELETE_ALL_Ro5( Surface ); + + vk::raii::SurfaceKHR& handle() { return m_surface; } + + operator vk::SurfaceKHR() { return m_surface; } + + operator VkSurfaceKHR() { return *m_surface; } + }; +} // namespace fgl::engine \ No newline at end of file diff --git a/src/engine/rendering/SwapChain.cpp b/src/engine/rendering/SwapChain.cpp index e847bd1..ff12736 100644 --- a/src/engine/rendering/SwapChain.cpp +++ b/src/engine/rendering/SwapChain.cpp @@ -16,12 +16,15 @@ namespace fgl::engine { - SwapChain::SwapChain( vk::Extent2D extent ) : windowExtent( extent ) + SwapChain::SwapChain( vk::Extent2D extent, PhysicalDevice& phy_device ) : + m_phy_device( phy_device ), + windowExtent( extent ) { init(); } SwapChain::SwapChain( vk::Extent2D extent, std::shared_ptr< SwapChain > previous ) : + m_phy_device( previous->m_phy_device ), windowExtent( extent ), old_swap_chain( previous ) { @@ -37,65 +40,38 @@ namespace fgl::engine createSyncObjects(); } - SwapChain::~SwapChain() - { - ZoneScoped; - if ( swapChain != nullptr ) - { - vkDestroySwapchainKHR( Device::getInstance().device(), swapChain, nullptr ); - swapChain = nullptr; - } - - for ( auto framebuffer : m_swap_chain_buffers ) - { - vkDestroyFramebuffer( Device::getInstance().device(), framebuffer, nullptr ); - } - - vkDestroyRenderPass( Device::getInstance().device(), m_render_pass, nullptr ); - - // cleanup synchronization objects - for ( size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++ ) - { - vkDestroySemaphore( Device::getInstance().device(), renderFinishedSemaphores[ i ], nullptr ); - vkDestroySemaphore( Device::getInstance().device(), imageAvailableSemaphores[ i ], nullptr ); - vkDestroyFence( Device::getInstance().device(), inFlightFences[ i ], nullptr ); - } - } - std::pair< vk::Result, std::uint32_t > SwapChain::acquireNextImage() { ZoneScoped; - if ( Device::getInstance() - .device() - .waitForFences( 1, &inFlightFences[ currentFrame ], VK_TRUE, std::numeric_limits< uint64_t >::max() ) + + std::vector< vk::Fence > fences { inFlightFences[ currentFrame ] }; + + if ( Device::getInstance().device().waitForFences( fences, VK_TRUE, std::numeric_limits< uint64_t >::max() ) != vk::Result::eSuccess ) throw std::runtime_error( "failed to wait for fences!" ); std::uint32_t image_idx { 0 }; - vk::Result result { Device::getInstance().device().acquireNextImageKHR( - swapChain, + auto result { swapChain.acquireNextImage( std::numeric_limits< uint64_t >::max(), - imageAvailableSemaphores[ currentFrame ], // must be a not signaled semaphore - VK_NULL_HANDLE, - &image_idx ) }; + imageAvailableSemaphores[ currentFrame ] // must be a not signaled semaphore + ) }; - return { result, image_idx }; + return result; } - vk::Result SwapChain::submitCommandBuffers( const vk::CommandBuffer* buffers, std::uint32_t imageIndex ) + vk::Result SwapChain::submitCommandBuffers( const vk::raii::CommandBuffer& buffers, std::uint32_t imageIndex ) { ZoneScoped; - if ( imagesInFlight[ imageIndex ] != VK_NULL_HANDLE ) - { - if ( Device::getInstance() - .device() - .waitForFences( 1, &imagesInFlight[ imageIndex ], VK_TRUE, std::numeric_limits< uint64_t >::max() ) - != vk::Result::eSuccess ) - throw std::runtime_error( "failed to wait for fences!" ); - } + imagesInFlight[ imageIndex ] = inFlightFences[ currentFrame ]; + std::vector< vk::Fence > fences { imagesInFlight[ imageIndex ] }; + + if ( Device::getInstance().device().waitForFences( fences, VK_TRUE, std::numeric_limits< uint64_t >::max() ) + != vk::Result::eSuccess ) + throw std::runtime_error( "failed to wait for fences!" ); + vk::SubmitInfo submitInfo {}; vk::Semaphore waitSemaphores[] = { imageAvailableSemaphores[ currentFrame ] }; @@ -105,36 +81,17 @@ namespace fgl::engine submitInfo.pWaitDstStageMask = waitStages; submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = buffers; + submitInfo.pCommandBuffers = &( *buffers ); vk::Semaphore signalSemaphores[] = { renderFinishedSemaphores[ currentFrame ] }; submitInfo.signalSemaphoreCount = 1; submitInfo.pSignalSemaphores = signalSemaphores; - if ( Device::getInstance().device().resetFences( 1, &inFlightFences[ currentFrame ] ) != vk::Result::eSuccess ) - throw std::runtime_error( "failed to reset fences!" ); + Device::getInstance().device().resetFences( fences ); - if ( auto result = - Device::getInstance().graphicsQueue().submit( 1, &submitInfo, inFlightFences[ currentFrame ] ); - result != vk::Result::eSuccess ) - { -#pragma GCC diagnostic push - //Can't possibly handle all of these. It will add like....100 lines of just empty cases -#pragma GCC diagnostic ignored "-Wswitch-enum" - switch ( result ) - { - case vk::Result::eErrorOutOfDateKHR: - return vk::Result::eErrorOutOfDateKHR; - case vk::Result::eSuboptimalKHR: - return vk::Result::eSuboptimalKHR; - case vk::Result::eErrorDeviceLost: - throw std::runtime_error( "Device lost!" ); - default: - throw std::runtime_error( - "failed to submit draw command buffer!: ID" + std::to_string( static_cast< int >( result ) ) ); - } -#pragma GCC diagnostic pop - } + std::vector< vk::SubmitInfo > submit_infos { submitInfo }; + + Device::getInstance().graphicsQueue().submit( submitInfo, inFlightFences[ currentFrame ] ); vk::PresentInfoKHR presentInfo = {}; @@ -148,7 +105,7 @@ namespace fgl::engine std::array< std::uint32_t, 1 > indicies { { imageIndex } }; presentInfo.setImageIndices( indicies ); - if ( auto present_result = Device::getInstance().presentQueue().presentKHR( &presentInfo ); + if ( auto present_result = Device::getInstance().presentQueue().presentKHR( presentInfo ); present_result != vk::Result::eSuccess ) { if ( present_result == vk::Result::eSuboptimalKHR ) return vk::Result::eSuboptimalKHR; @@ -187,11 +144,15 @@ namespace fgl::engine createInfo.imageArrayLayers = 1; createInfo.imageUsage = vk::ImageUsageFlagBits::eColorAttachment; - QueueFamilyIndices indices = Device::getInstance().findPhysicalQueueFamilies(); - uint32_t queueFamilyIndices[] = { indices.graphicsFamily, indices.presentFamily }; + std::uint32_t graphics_family { m_phy_device.queueInfo().getIndex( vk::QueueFlagBits::eGraphics ) }; + std::uint32_t present_family { m_phy_device.queueInfo().getPresentIndex() }; - if ( indices.graphicsFamily != indices.presentFamily ) + const uint32_t queueFamilyIndices[] = { graphics_family, present_family }; + + if ( graphics_family != present_family ) { + // If the familys are not the same then the swapchain must be shared between + // both queues. createInfo.imageSharingMode = vk::SharingMode::eConcurrent; createInfo.queueFamilyIndexCount = 2; createInfo.pQueueFamilyIndices = queueFamilyIndices; @@ -209,17 +170,11 @@ namespace fgl::engine createInfo.presentMode = presentMode; createInfo.clipped = VK_TRUE; - createInfo.oldSwapchain = old_swap_chain == nullptr ? VK_NULL_HANDLE : old_swap_chain->swapChain; + createInfo.oldSwapchain = old_swap_chain == nullptr ? VK_NULL_HANDLE : *old_swap_chain->swapChain; - if ( Device::getInstance().device().createSwapchainKHR( &createInfo, nullptr, &swapChain ) - != vk::Result::eSuccess ) - { - throw std::runtime_error( "failed to create swap chain!" ); - } + swapChain = Device::getInstance()->createSwapchainKHR( createInfo ); - std::vector< vk::Image > swap_chain_images { - Device::getInstance().device().getSwapchainImagesKHR( swapChain ) - }; + std::vector< vk::Image > swap_chain_images { swapChain.getImages() }; for ( std::uint64_t i = 0; i < swap_chain_images.size(); i++ ) { @@ -352,7 +307,8 @@ namespace fgl::engine void SwapChain::createFramebuffers() { ZoneScoped; - m_swap_chain_buffers.resize( imageCount() ); + m_swap_chain_buffers.clear(); + m_swap_chain_buffers.reserve( imageCount() ); for ( uint8_t i = 0; i < imageCount(); i++ ) { std::vector< vk::ImageView > attachments { m_render_pass_resources->forFrame( i ) }; @@ -367,22 +323,16 @@ namespace fgl::engine framebufferInfo.height = swapChainExtent.height; framebufferInfo.layers = 1; - if ( Device::getInstance() - .device() - .createFramebuffer( &framebufferInfo, nullptr, &( m_swap_chain_buffers[ i ] ) ) - != vk::Result::eSuccess ) - { - throw std::runtime_error( "failed to create framebuffer!" ); - } + m_swap_chain_buffers.push_back( Device::getInstance()->createFramebuffer( framebufferInfo ) ); } } void SwapChain::createSyncObjects() { ZoneScoped; - imageAvailableSemaphores.resize( MAX_FRAMES_IN_FLIGHT ); - renderFinishedSemaphores.resize( MAX_FRAMES_IN_FLIGHT ); - inFlightFences.resize( MAX_FRAMES_IN_FLIGHT ); + imageAvailableSemaphores.reserve( MAX_FRAMES_IN_FLIGHT ); + renderFinishedSemaphores.reserve( MAX_FRAMES_IN_FLIGHT ); + inFlightFences.reserve( MAX_FRAMES_IN_FLIGHT ); imagesInFlight.resize( imageCount(), VK_NULL_HANDLE ); vk::SemaphoreCreateInfo semaphoreInfo {}; @@ -392,15 +342,11 @@ namespace fgl::engine for ( size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++ ) { - auto vk_device { Device::getInstance().device() }; - if ( vk_device.createSemaphore( &semaphoreInfo, nullptr, &imageAvailableSemaphores[ i ] ) - != vk::Result::eSuccess ) - throw std::runtime_error( "failed to create image available semaphore!" ); - if ( vk_device.createSemaphore( &semaphoreInfo, nullptr, &renderFinishedSemaphores[ i ] ) - != vk::Result::eSuccess ) - throw std::runtime_error( "failed to create render finished semaphore!" ); - if ( vk_device.createFence( &fenceInfo, nullptr, &inFlightFences[ i ] ) != vk::Result::eSuccess ) - throw std::runtime_error( "failed to create in flight fence!" ); + auto& device { Device::getInstance() }; + + imageAvailableSemaphores.push_back( device->createSemaphore( semaphoreInfo ) ); + renderFinishedSemaphores.push_back( device->createSemaphore( semaphoreInfo ) ); + inFlightFences.push_back( device->createFence( fenceInfo ) ); } } diff --git a/src/engine/rendering/SwapChain.hpp b/src/engine/rendering/SwapChain.hpp index 6a234e9..3b64e87 100644 --- a/src/engine/rendering/SwapChain.hpp +++ b/src/engine/rendering/SwapChain.hpp @@ -24,24 +24,26 @@ namespace fgl::engine private: + PhysicalDevice& m_phy_device; + vk::Format m_swap_chain_format { vk::Format::eUndefined }; vk::Format m_swap_chain_depth_format { findDepthFormat() }; vk::Extent2D m_swap_chain_extent { 0, 0 }; - std::vector< vk::Framebuffer > m_swap_chain_buffers {}; - vk::RenderPass m_render_pass { VK_NULL_HANDLE }; + std::vector< vk::raii::Framebuffer > m_swap_chain_buffers {}; + vk::raii::RenderPass m_render_pass { VK_NULL_HANDLE }; std::unique_ptr< RenderPassResources > m_render_pass_resources { nullptr }; std::vector< Image > m_swap_chain_images {}; vk::Extent2D windowExtent; - vk::SwapchainKHR swapChain { VK_NULL_HANDLE }; + vk::raii::SwapchainKHR swapChain { VK_NULL_HANDLE }; std::shared_ptr< SwapChain > old_swap_chain {}; - std::vector< vk::Semaphore > imageAvailableSemaphores {}; - std::vector< vk::Semaphore > renderFinishedSemaphores {}; - std::vector< vk::Fence > inFlightFences {}; + std::vector< vk::raii::Semaphore > imageAvailableSemaphores {}; + std::vector< vk::raii::Semaphore > renderFinishedSemaphores {}; + std::vector< vk::raii::Fence > inFlightFences {}; std::vector< vk::Fence > imagesInFlight {}; size_t currentFrame { 0 }; @@ -73,19 +75,18 @@ namespace fgl::engine return *m_gbuffer_descriptor_set[ frame_idx ]; } - SwapChain( vk::Extent2D windowExtent ); + SwapChain( vk::Extent2D windowExtent, PhysicalDevice& phy_dev ); SwapChain( vk::Extent2D windowExtent, std::shared_ptr< SwapChain > previous ); - ~SwapChain(); SwapChain( const SwapChain& ) = delete; SwapChain& operator=( const SwapChain& ) = delete; - vk::Framebuffer getFrameBuffer( std::uint32_t index ) const + vk::raii::Framebuffer& getFrameBuffer( std::uint32_t index ) { return m_swap_chain_buffers[ static_cast< std::size_t >( index ) ]; } - vk::RenderPass getRenderPass() const { return m_render_pass; } + vk::raii::RenderPass& getRenderPass() { return m_render_pass; } std::uint16_t imageCount() const { return static_cast< std::uint16_t >( m_swap_chain_images.size() ); } @@ -112,7 +113,8 @@ namespace fgl::engine vk::Format findDepthFormat(); [[nodiscard]] std::pair< vk::Result, std::uint32_t > acquireNextImage(); - [[nodiscard]] vk::Result submitCommandBuffers( const vk::CommandBuffer* buffers, std::uint32_t imageIndex ); + [[nodiscard]] vk::Result + submitCommandBuffers( const vk::raii::CommandBuffer& buffers, std::uint32_t imageIndex ); }; } // namespace fgl::engine diff --git a/src/engine/systems/CompositionSystem.cpp b/src/engine/systems/CompositionSystem.cpp index 7408343..6ebd7d1 100644 --- a/src/engine/systems/CompositionSystem.cpp +++ b/src/engine/systems/CompositionSystem.cpp @@ -9,7 +9,7 @@ namespace fgl::engine { - CompositionSystem::CompositionSystem( [[maybe_unused]] Device& device, VkRenderPass render_pass ) + CompositionSystem::CompositionSystem( [[maybe_unused]] Device& device, vk::raii::RenderPass& render_pass ) { PipelineConfigInfo composition_info { render_pass }; PipelineConfigInfo::addColorAttachmentConfig( composition_info ); @@ -17,11 +17,11 @@ namespace fgl::engine PipelineConfigInfo::disableCulling( composition_info ); composition_info.subpass = 1; - m_pipeline = std::make_unique< CompositionPipeline >( Device::getInstance(), composition_info ); + m_pipeline = std::make_unique< CompositionPipeline >( Device::getInstance(), std::move( composition_info ) ); m_pipeline->setDebugName( "Composition pipeline" ); } - vk::CommandBuffer& CompositionSystem::setupSystem( FrameInfo& info ) + vk::raii::CommandBuffer& CompositionSystem::setupSystem( FrameInfo& info ) { auto& command_buffer { info.command_buffer }; m_pipeline->bind( command_buffer ); diff --git a/src/engine/systems/CompositionSystem.hpp b/src/engine/systems/CompositionSystem.hpp index fe7985c..782cc86 100644 --- a/src/engine/systems/CompositionSystem.hpp +++ b/src/engine/systems/CompositionSystem.hpp @@ -25,11 +25,11 @@ namespace fgl::engine std::unique_ptr< CompositionPipeline > m_pipeline { nullptr }; - vk::CommandBuffer& setupSystem( FrameInfo& info ); + vk::raii::CommandBuffer& setupSystem( FrameInfo& info ); public: - CompositionSystem( Device& device, VkRenderPass render_pass ); + CompositionSystem( Device& device, vk::raii::RenderPass& render_pass ); ~CompositionSystem() = default; void pass( FrameInfo& info ); diff --git a/src/engine/systems/CullingSystem.hpp b/src/engine/systems/CullingSystem.hpp index 5bf08c5..cf73fdd 100644 --- a/src/engine/systems/CullingSystem.hpp +++ b/src/engine/systems/CullingSystem.hpp @@ -28,7 +28,7 @@ namespace fgl::engine public: - [[maybe_unused]] vk::CommandBuffer& setupSystem( FrameInfo& info ); + [[maybe_unused]] vk::raii::CommandBuffer& setupSystem( FrameInfo& info ); CullingSystem() : m_thread( &CullingSystem::runner, this ) {} diff --git a/src/engine/systems/EntityRendererSystem.cpp b/src/engine/systems/EntityRendererSystem.cpp index a9c58b9..61a0a54 100644 --- a/src/engine/systems/EntityRendererSystem.cpp +++ b/src/engine/systems/EntityRendererSystem.cpp @@ -12,6 +12,7 @@ #include "DrawPair.hpp" #include "engine/literals/size.hpp" #include "engine/tree/octtree/OctTreeNode.hpp" +#include "spdlog/fmt/bundled/compile.h" namespace fgl::engine { @@ -25,22 +26,19 @@ namespace fgl::engine vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eDeviceLocal ); } - EntityRendererSystem::EntityRendererSystem( Device& device, VkRenderPass render_pass ) : m_device( device ) + EntityRendererSystem::EntityRendererSystem( Device& device, vk::raii::RenderPass& render_pass ) : m_device( device ) { ZoneScoped; - PipelineConfigInfo info { render_pass }; - - for ( int i = 0; i < 4; ++i ) PipelineConfigInfo::addColorAttachmentConfig( info ); - - info.subpass = 0; - - //m_pipeline = std::make_unique< Pipeline >( m_device, info ); - //m_pipeline->setDebugName( "Entity pipeline" ); - - m_standard_pipeline = std::make_unique< StandardPipeline >( m_device, info ); - m_textured_pipeline = std::make_unique< TexturedPipeline >( m_device, info ); - + PipelineConfigInfo standard_info { render_pass }; + for ( int i = 0; i < 4; ++i ) PipelineConfigInfo::addColorAttachmentConfig( standard_info ); + standard_info.subpass = 0; + m_standard_pipeline = std::make_unique< StandardPipeline >( m_device, std::move( standard_info ) ); m_standard_pipeline->setDebugName( "Standard entity pipeline" ); + + PipelineConfigInfo textured_info { render_pass }; + for ( int i = 0; i < 4; ++i ) PipelineConfigInfo::addColorAttachmentConfig( textured_info ); + textured_info.subpass = 0; + m_textured_pipeline = std::make_unique< TexturedPipeline >( m_device, std::move( textured_info ) ); m_textured_pipeline->setDebugName( "Textured entity pipeline" ); using namespace fgl::literals::size_literals; @@ -50,7 +48,7 @@ namespace fgl::engine initDrawParameterBuffer( 1_KiB ); } - vk::CommandBuffer& EntityRendererSystem::setupSystem( FrameInfo& info ) + vk::raii::CommandBuffer& EntityRendererSystem::setupSystem( FrameInfo& info ) { auto& command_buffer { info.command_buffer }; @@ -69,7 +67,7 @@ namespace fgl::engine { ZoneScopedN( "Entity pass" ); auto& command_buffer { setupSystem( info ) }; - TracyVkZone( info.tracy_ctx, command_buffer, "Render entities" ); + TracyVkZone( info.tracy_ctx, *command_buffer, "Render entities" ); texturelessPass( info ); //texturedPass( info ); @@ -120,7 +118,7 @@ namespace fgl::engine { ZoneScopedN( "Textureless pass" ); auto& command_buffer { info.command_buffer }; - TracyVkZone( info.tracy_ctx, command_buffer, "Render textureless entities" ); + TracyVkZone( info.tracy_ctx, *command_buffer, "Render textureless entities" ); //Bind pipeline m_standard_pipeline->bind( command_buffer ); diff --git a/src/engine/systems/EntityRendererSystem.hpp b/src/engine/systems/EntityRendererSystem.hpp index b148bfc..54f8700 100644 --- a/src/engine/systems/EntityRendererSystem.hpp +++ b/src/engine/systems/EntityRendererSystem.hpp @@ -75,7 +75,7 @@ namespace fgl::engine vk::MemoryPropertyFlagBits::eDeviceLocal ); } - vk::CommandBuffer& setupSystem( FrameInfo& ); + vk::raii::CommandBuffer& setupSystem( FrameInfo& ); public: @@ -87,7 +87,7 @@ namespace fgl::engine void texturelessPass( FrameInfo& info ); void texturedPass( FrameInfo& info ); - EntityRendererSystem( Device& device, VkRenderPass render_pass ); + EntityRendererSystem( Device& device, vk::raii::RenderPass& render_pass ); ~EntityRendererSystem() = default; EntityRendererSystem( EntityRendererSystem&& other ) = delete; EntityRendererSystem( const EntityRendererSystem& other ) = delete; diff --git a/src/engine/systems/TerrainSystem.cpp b/src/engine/systems/TerrainSystem.cpp index 1bb704d..2825124 100644 --- a/src/engine/systems/TerrainSystem.cpp +++ b/src/engine/systems/TerrainSystem.cpp @@ -11,7 +11,7 @@ namespace fgl::engine { - TerrainSystem::TerrainSystem( Device& device, VkRenderPass render_pass ) + TerrainSystem::TerrainSystem( Device& device, vk::raii::RenderPass& render_pass ) { ZoneScoped; PipelineConfigInfo info { render_pass }; @@ -25,7 +25,7 @@ namespace fgl::engine info.subpass = 0; - m_pipeline = std::make_unique< Pipeline >( device, info ); + m_pipeline = std::make_unique< Pipeline >( device, std::move( info ) ); m_pipeline->setDebugName( "Terrain pipeline" ); using namespace fgl::literals::size_literals; @@ -37,7 +37,7 @@ namespace fgl::engine this->m_vertex_buffer->setDebugName( "Terrain vertex buffer" ); } - vk::CommandBuffer& TerrainSystem::setupSystem( FrameInfo& info ) + vk::raii::CommandBuffer& TerrainSystem::setupSystem( FrameInfo& info ) { auto& command_buffer { info.command_buffer }; m_pipeline->bind( command_buffer ); @@ -52,7 +52,7 @@ namespace fgl::engine { ZoneScopedN( "Terrain pass" ); auto& command_buffer { setupSystem( info ) }; - TracyVkZone( info.tracy_ctx, command_buffer, "Render terrain" ); + TracyVkZone( info.tracy_ctx, *command_buffer, "Render terrain" ); auto [ draw_commands, model_matricies ] = getDrawCallsFromTree( info.game_objects, info.camera_frustum, IS_VISIBLE | IS_TERRAIN ); diff --git a/src/engine/systems/TerrainSystem.hpp b/src/engine/systems/TerrainSystem.hpp index 7000e1d..6e0d292 100644 --- a/src/engine/systems/TerrainSystem.hpp +++ b/src/engine/systems/TerrainSystem.hpp @@ -42,7 +42,7 @@ namespace fgl::engine std::array< std::unique_ptr< ModelMatrixInfoBufferSuballocation >, SwapChain::MAX_FRAMES_IN_FLIGHT > m_model_matrix_info_buffers {}; - vk::CommandBuffer& setupSystem( FrameInfo& info ); + vk::raii::CommandBuffer& setupSystem( FrameInfo& info ); void initVertexBuffer( std::uint32_t size ) { @@ -66,7 +66,7 @@ namespace fgl::engine inline Buffer& getIndexBuffer() { return *m_index_buffer; } - TerrainSystem( Device& device, VkRenderPass render_pass ); + TerrainSystem( Device& device, vk::raii::RenderPass& render_pass ); ~TerrainSystem() = default; void pass( FrameInfo& info ); diff --git a/src/engine/systems/concepts.hpp b/src/engine/systems/concepts.hpp index 50cf09c..7730164 100644 --- a/src/engine/systems/concepts.hpp +++ b/src/engine/systems/concepts.hpp @@ -4,16 +4,12 @@ #pragma once -#include +#include -namespace vk -{ - class CommandBuffer; -} +#include namespace fgl::engine { - struct FrameInfo; template < typename T > @@ -34,7 +30,7 @@ namespace fgl::engine }; { t.setupSystem( info ) - } -> std::same_as< vk::CommandBuffer& >; + } -> std::same_as< vk::raii::CommandBuffer& >; }; } // namespace fgl::engine diff --git a/src/engine/texture/Texture.cpp b/src/engine/texture/Texture.cpp index c32f911..e949abe 100644 --- a/src/engine/texture/Texture.cpp +++ b/src/engine/texture/Texture.cpp @@ -53,7 +53,7 @@ namespace fgl::engine void Texture::drawImGui( vk::Extent2D extent ) { - if ( this->m_imgui_set == VK_NULL_HANDLE ) createImGuiSet(); + if ( m_imgui_set == VK_NULL_HANDLE ) createImGuiSet(); if ( extent == vk::Extent2D() ) { @@ -125,7 +125,7 @@ namespace fgl::engine if ( m_imgui_set != VK_NULL_HANDLE ) ImGui_ImplVulkan_RemoveTexture( m_imgui_set ); } - void Texture::stage( vk::CommandBuffer& cmd ) + void Texture::stage( vk::raii::CommandBuffer& cmd ) { ZoneScoped; @@ -172,8 +172,10 @@ namespace fgl::engine region.imageOffset = vk::Offset3D( 0, 0, 0 ); region.imageExtent = vk::Extent3D( m_extent, 1 ); + std::vector< vk::BufferImageCopy > regions { region }; + cmd.copyBufferToImage( - m_staging->getVkBuffer(), m_image_view->getVkImage(), vk::ImageLayout::eTransferDstOptimal, 1, ®ion ); + m_staging->getVkBuffer(), m_image_view->getVkImage(), vk::ImageLayout::eTransferDstOptimal, regions ); //Transfer back to eGeneral @@ -227,10 +229,10 @@ namespace fgl::engine assert( view ); - VkImageView vk_view { view->getVkView() }; + VkImageView vk_view { **view }; assert( vk_view ); - VkSampler vk_sampler { view->getSampler().getVkSampler() }; + VkSampler vk_sampler { *( view->getSampler() ) }; m_imgui_set = ImGui_ImplVulkan_AddTexture( vk_sampler, vk_view, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ); #endif @@ -252,14 +254,17 @@ namespace fgl::engine DescriptorSet& Texture::getTextureDescriptorSet() { static std::unique_ptr< DescriptorSet > set { nullptr }; - static std::optional< vk::DescriptorSetLayout > set_layout { std::nullopt }; + static std::optional< vk::raii::DescriptorSetLayout > set_layout { std::nullopt }; if ( set ) return *set; else { set_layout = TextureDescriptorSet::createLayout(); - set = std::make_unique< DescriptorSet >( set_layout.value() ); + + if ( !set_layout.has_value() ) throw std::runtime_error( "No set layout made" ); + + set = std::make_unique< DescriptorSet >( std::move( set_layout.value() ) ); set->setMaxIDX( 1 ); set->setName( "Texture descriptor set" ); return *set; diff --git a/src/engine/texture/Texture.hpp b/src/engine/texture/Texture.hpp index 197ae0f..c7097ad 100644 --- a/src/engine/texture/Texture.hpp +++ b/src/engine/texture/Texture.hpp @@ -50,7 +50,7 @@ namespace fgl::engine [[nodiscard]] Texture( const std::filesystem::path& path, const vk::Format format ); - void stage( vk::CommandBuffer& cmd ) override; + void stage( vk::raii::CommandBuffer& cmd ) override; void dropStaging(); public: