RAIIify most of the logical device setup and usage
This commit is contained in:
@@ -9,11 +9,6 @@ add_library(FGLEngine STATIC ${CPP_SOURCES} ${HPP_SOURCES})
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
|
||||
target_precompile_headers(FGLEngine PRIVATE
|
||||
<vector>
|
||||
<iostream>
|
||||
<array>
|
||||
<chrono>
|
||||
<optional>
|
||||
|
||||
<vulkan/vulkan.h>
|
||||
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 ) };
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
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 );
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "Window.hpp"
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <vulkan/vulkan_handles.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <vulkan/vulkan_handles.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#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()
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
@@ -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 };
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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" );
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
@@ -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
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
|
||||
|
||||
@@ -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 >
|
||||
|
||||
@@ -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 >
|
||||
|
||||
@@ -4,46 +4,62 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
|
||||
#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
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -26,9 +26,4 @@ namespace fgl::engine
|
||||
m_handle->setName( str );
|
||||
}
|
||||
|
||||
vk::Image& Image::getVkImage()
|
||||
{
|
||||
return m_handle->m_image;
|
||||
}
|
||||
|
||||
} // namespace fgl::engine
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#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 );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -6,12 +6,9 @@
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#include <optional>
|
||||
|
||||
#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; };
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5,14 +5,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
|
||||
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
|
||||
@@ -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 )
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include "Pipeline.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <fstream>
|
||||
|
||||
#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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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 );
|
||||
};
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -5,10 +5,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#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 );
|
||||
|
||||
@@ -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
|
||||
52
src/engine/pipeline/Shader.cpp
Normal file
52
src/engine/pipeline/Shader.cpp
Normal file
@@ -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
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#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 );
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <vector>
|
||||
|
||||
#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
|
||||
@@ -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; }
|
||||
|
||||
104
src/engine/rendering/PhysicalDevice.cpp
Normal file
104
src/engine/rendering/PhysicalDevice.cpp
Normal file
@@ -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
|
||||
43
src/engine/rendering/PhysicalDevice.hpp
Normal file
43
src/engine/rendering/PhysicalDevice.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// Created by kj16609 on 6/20/24.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
|
||||
#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
|
||||
49
src/engine/rendering/QueuePool.cpp
Normal file
49
src/engine/rendering/QueuePool.cpp
Normal file
@@ -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
|
||||
48
src/engine/rendering/QueuePool.hpp
Normal file
48
src/engine/rendering/QueuePool.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// Created by kj16609 on 6/20/24.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
|
||||
#include <set>
|
||||
|
||||
#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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
15
src/engine/rendering/Surface.cpp
Normal file
15
src/engine/rendering/Surface.cpp
Normal file
@@ -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
|
||||
31
src/engine/rendering/Surface.hpp
Normal file
31
src/engine/rendering/Surface.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// Created by kj16609 on 6/20/24.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
|
||||
#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
|
||||
@@ -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 ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 ) {}
|
||||
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -4,16 +4,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <concepts>
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
|
||||
namespace vk
|
||||
{
|
||||
class CommandBuffer;
|
||||
}
|
||||
#include <concepts>
|
||||
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user