Rework swapchain to no longer init inside of ctor body

This commit is contained in:
2024-07-11 01:32:57 -04:00
parent 2fddf66153
commit 21268f2d4d
8 changed files with 233 additions and 243 deletions

View File

@@ -30,8 +30,8 @@ namespace fgl::engine
a.linkImage( std::declval< std::uint16_t >(), std::declval< Image& >() )
};
{
a.resources()
} -> std::same_as< AttachmentResources >;
a.getView( std::declval< std::uint8_t >() )
} -> std::same_as< ImageView& >;
{
a.m_clear_value
} -> std::same_as< vk::ClearValue& >;

View File

@@ -76,6 +76,7 @@ namespace fgl::engine
void linkImages( std::vector< Image >& images )
{
assert( images.size() > 0 );
for ( std::uint16_t i = 0; i < images.size(); ++i )
{
linkImage( i, images[ i ] );
@@ -115,7 +116,11 @@ namespace fgl::engine
}
}
AttachmentResources resources() { return m_attachment_resources; }
ImageView& getView( std::uint8_t frame_idx )
{
assert( frame_idx < m_attachment_resources.m_image_views.size() );
return *m_attachment_resources.m_image_views[ frame_idx ];
}
vk::AttachmentDescription& desc() { return description; }
@@ -127,7 +132,7 @@ namespace fgl::engine
return index;
}
friend class RenderPass;
friend class RenderPassBuilder;
};
template < is_attachment AttachmentT, vk::ImageLayout layout >

View File

@@ -1,103 +0,0 @@
//
// Created by kj16609 on 12/30/23.
//
#pragma once
#include "Subpass.hpp"
#include "engine/image/ImageView.hpp"
namespace fgl::engine
{
struct RenderPassResources
{
std::vector< std::vector< std::shared_ptr< ImageView > > > m_image_views;
RenderPassResources() = delete;
RenderPassResources( const RenderPassResources& ) = delete;
RenderPassResources( std::vector< std::vector< std::shared_ptr< ImageView > > >&& image_views ) :
m_image_views( std::move( image_views ) )
{}
std::vector< vk::ImageView > forFrame( std::uint32_t frame ) const
{
std::vector< vk::ImageView > views;
for ( auto& view : m_image_views.at( frame ) ) views.push_back( view->getVkView() );
return views;
}
};
class RenderPass
{
std::vector< vk::AttachmentDescription > attachment_descriptions {};
std::vector< vk::ClearValue > m_clear_values {};
std::vector< vk::SubpassDescription > subpass_descriptions {};
std::vector< vk::SubpassDependency > dependencies {};
std::vector< AttachmentResources > m_attachment_resources {};
public:
std::vector< vk::ClearValue > getClearValues() const { return m_clear_values; }
template < typename SubpassT >
requires is_subpass< SubpassT >
void registerSubpass( SubpassT& subpass )
{
subpass_descriptions.emplace_back( subpass.description() );
for ( auto& dependency : subpass.dependencies )
{
dependencies.push_back( dependency );
}
}
template < is_attachment... Attachments >
void registerAttachments( Attachments&... attachments )
{
attachment_descriptions.reserve( sizeof...( Attachments ) );
m_clear_values.reserve( sizeof...( Attachments ) );
( ( attachments.setIndex( static_cast< std::uint32_t >( attachment_descriptions.size() ) ),
attachment_descriptions.push_back( attachments.desc() ),
m_clear_values.push_back( attachments.m_clear_value ) ),
... );
m_attachment_resources.reserve( sizeof...( Attachments ) );
( ( m_attachment_resources.emplace_back( attachments.m_attachment_resources ) ), ... );
}
std::unique_ptr< RenderPassResources > resources( std::uint16_t frame_count )
{
assert( m_attachment_resources.size() > 0 && "Must register attachments before getting resources" );
//Each attachment will have a vector of image views, one for each frame
// We need to seperate them out so that we have a vector of image views for each frame
std::vector< std::vector< std::shared_ptr< ImageView > > > views;
views.resize( frame_count );
for ( auto& attachment : m_attachment_resources )
{
assert(
attachment.m_image_views.size() == frame_count
&& "Attachment image views must be equal to frame count" );
for ( std::uint16_t frame_idx = 0; frame_idx < attachment.m_image_views.size(); ++frame_idx )
{
views[ frame_idx ].emplace_back( attachment.m_image_views[ frame_idx ] );
}
}
return std::make_unique< RenderPassResources >( std::move( views ) );
}
vk::raii::RenderPass create();
};
} // namespace fgl::engine

View File

@@ -2,14 +2,13 @@
// Created by kj16609 on 12/31/23.
//
#include "RenderPass.hpp"
#include "Device.hpp"
#include "RenderPassBuilder.hpp"
namespace fgl::engine
{
vk::raii::RenderPass RenderPass::create()
vk::raii::RenderPass RenderPassBuilder::create()
{
auto& device { Device::getInstance() };

View File

@@ -0,0 +1,52 @@
//
// Created by kj16609 on 12/30/23.
//
#pragma once
#include "Subpass.hpp"
#include "engine/image/ImageView.hpp"
namespace fgl::engine
{
class RenderPassBuilder
{
std::vector< vk::AttachmentDescription > attachment_descriptions {};
std::vector< vk::ClearValue > m_clear_values {};
std::vector< vk::SubpassDescription > subpass_descriptions {};
std::vector< vk::SubpassDependency > dependencies {};
public:
std::vector< vk::ClearValue > getClearValues() const { return m_clear_values; }
template < typename SubpassT >
requires is_subpass< SubpassT >
void registerSubpass( SubpassT& subpass )
{
subpass_descriptions.emplace_back( subpass.description() );
for ( auto& dependency : subpass.dependencies )
{
dependencies.push_back( dependency );
}
}
template < is_attachment... Attachments >
void registerAttachments( Attachments&... attachments )
{
attachment_descriptions.reserve( sizeof...( Attachments ) );
m_clear_values.reserve( sizeof...( Attachments ) );
( ( attachments.setIndex( static_cast< std::uint32_t >( attachment_descriptions.size() ) ),
attachment_descriptions.push_back( attachments.desc() ),
m_clear_values.push_back( attachments.m_clear_value ) ),
... );
}
vk::raii::RenderPass create();
};
} // namespace fgl::engine

View File

@@ -109,7 +109,7 @@ namespace fgl::engine
vk::SubpassDescription description() { return subpass_description; }
friend class RenderPass;
friend class RenderPassBuilder;
void registerDependency(
std::uint32_t src_subpass,

View File

@@ -8,7 +8,7 @@
#include <stdexcept>
#include "Attachment.hpp"
#include "RenderPass.hpp"
#include "RenderPassBuilder.hpp"
#include "Subpass.hpp"
#include "engine/assets/TransferManager.hpp"
@@ -26,7 +26,18 @@ namespace fgl::engine
old_swap_chain( nullptr ),
m_swapchain( createSwapChain() ),
m_swap_chain_images( createSwapchainImages() ),
render_attachments( getSwapChainImageFormat(), findDepthFormat() )
render_attachments( getSwapChainImageFormat(), findDepthFormat() ),
m_render_pass( createRenderPass() ),
m_swap_chain_buffers( createFramebuffers() ),
m_clear_values( gatherClearValues(
render_attachments.color,
render_attachments.depth,
gbuffer.position,
gbuffer.normal,
gbuffer.albedo,
gbuffer.composite ) ),
m_gbuffer_descriptor_set( createGBufferDescriptors() ),
m_gbuffer_composite_descriptor_set( createCompositeDescriptors() )
{
init();
}
@@ -42,7 +53,18 @@ namespace fgl::engine
old_swap_chain( previous ),
m_swapchain( createSwapChain() ),
m_swap_chain_images( createSwapchainImages() ),
render_attachments( getSwapChainImageFormat(), findDepthFormat() )
render_attachments( getSwapChainImageFormat(), findDepthFormat() ),
m_render_pass( createRenderPass() ),
m_swap_chain_buffers( createFramebuffers() ),
m_clear_values( gatherClearValues(
render_attachments.color,
render_attachments.depth,
gbuffer.position,
gbuffer.normal,
gbuffer.albedo,
gbuffer.composite ) ),
m_gbuffer_descriptor_set( createGBufferDescriptors() ),
m_gbuffer_composite_descriptor_set( createCompositeDescriptors() )
{
init();
old_swap_chain.reset();
@@ -50,8 +72,6 @@ namespace fgl::engine
void SwapChain::init()
{
createRenderPass();
createFramebuffers();
createSyncObjects();
}
@@ -67,7 +87,7 @@ namespace fgl::engine
auto result { m_swapchain.acquireNextImage(
std::numeric_limits< uint64_t >::max(),
imageAvailableSemaphores[ m_current_frame_index ] // must be a not signaled semaphore
image_available_sem[ m_current_frame_index ] // must be a not signaled semaphore
) };
return result;
@@ -87,7 +107,7 @@ namespace fgl::engine
vk::SubmitInfo m_submit_info {};
std::vector< vk::Semaphore > wait_sems { imageAvailableSemaphores[ m_current_frame_index ],
std::vector< vk::Semaphore > wait_sems { image_available_sem[ m_current_frame_index ],
memory::TransferManager::getInstance().getFinishedSem() };
std::vector< vk::PipelineStageFlags > wait_stages { vk::PipelineStageFlagBits::eColorAttachmentOutput,
@@ -99,7 +119,7 @@ namespace fgl::engine
m_submit_info.commandBufferCount = 1;
m_submit_info.pCommandBuffers = &( *buffers );
std::vector< vk::Semaphore > signaled_semaphores { renderFinishedSemaphores[ m_current_frame_index ] };
std::vector< vk::Semaphore > signaled_semaphores { render_finished_sem[ m_current_frame_index ] };
m_submit_info.setSignalSemaphores( signaled_semaphores );
Device::getInstance().device().resetFences( fences );
@@ -201,45 +221,18 @@ namespace fgl::engine
return images;
}
void SwapChain::createRenderPass()
vk::raii::RenderPass SwapChain::createRenderPass()
{
ZoneScoped;
//Present attachment
for ( int i = 0; i < imageCount(); ++i )
{
auto& image { m_swap_chain_images[ i ] };
image.setName( "SwapChainImage: " + std::to_string( i ) );
}
render_attachments.color.linkImages( m_swap_chain_images );
gbuffer.position.createResourceSpread( imageCount(), getSwapChainExtent(), vk::ImageUsageFlagBits::eSampled );
gbuffer.normal.createResourceSpread( imageCount(), getSwapChainExtent(), vk::ImageUsageFlagBits::eSampled );
gbuffer.albedo.createResourceSpread( imageCount(), getSwapChainExtent(), vk::ImageUsageFlagBits::eSampled );
gbuffer.composite.createResourceSpread( imageCount(), getSwapChainExtent(), vk::ImageUsageFlagBits::eSampled );
render_attachments.depth.setClear( vk::ClearDepthStencilValue( 1.0f, 0 ) );
gbuffer.position.setClear( vk::ClearColorValue( std::array< float, 4 > { { 0.0f, 0.0f, 0.0f, 0.0f } } ) );
gbuffer.normal.setClear( vk::ClearColorValue( std::array< float, 4 > { { 0.0f, 0.0f, 0.0f, 0.0f } } ) );
gbuffer.albedo.setClear( vk::ClearColorValue( std::array< float, 4 > { { 0.0f, 0.0f, 0.0f, 0.0f } } ) );
gbuffer.composite.setClear( vk::ClearColorValue( std::array< float, 4 > { { 0.0f, 0.0f, 0.0f, 0.0f } } ) );
g_buffer_position_img = std::make_unique< Texture >( gbuffer.position.m_attachment_resources.m_images[ 0 ]
->setName( "GBufferPosition" ) );
g_buffer_normal_img = std::make_unique< Texture >( gbuffer.normal.m_attachment_resources.m_images[ 0 ]
->setName( "GBufferNormal" ) );
g_buffer_albedo_img = std::make_unique< Texture >( gbuffer.albedo.m_attachment_resources.m_images[ 0 ]
->setName( "GBufferAlbedo" ) );
g_buffer_composite_img = std::make_unique< Texture >( gbuffer.composite.m_attachment_resources.m_images[ 0 ]
->setName( "GBufferComposite" ) );
RenderPass render_pass {};
render_attachments.depth.createResources( imageCount(), getSwapChainExtent() );
render_attachments.depth.setClear( vk::ClearDepthStencilValue( 1.0f, 0 ) );
render_pass.registerAttachments(
render_pass_builder.registerAttachments(
render_attachments.color,
render_attachments.depth,
gbuffer.position,
@@ -247,50 +240,6 @@ namespace fgl::engine
gbuffer.albedo,
gbuffer.composite );
for ( int i = 0; i < SwapChain::MAX_FRAMES_IN_FLIGHT; ++i )
{
{
auto set { std::make_unique< descriptors::DescriptorSet >( GBufferDescriptorSet::createLayout() ) };
set->setMaxIDX( 2 );
set->bindAttachment(
0,
*( gbuffer.position.resources().m_image_views[ i ].get() ),
vk::ImageLayout::eShaderReadOnlyOptimal );
set->bindAttachment(
1,
*( gbuffer.normal.resources().m_image_views[ i ].get() ),
vk::ImageLayout::eShaderReadOnlyOptimal );
set->bindAttachment(
2,
*( gbuffer.albedo.resources().m_image_views[ i ].get() ),
vk::ImageLayout::eShaderReadOnlyOptimal );
set->update();
m_gbuffer_descriptor_set[ i ] = std::move( set );
}
{
auto composite_set {
std::make_unique< descriptors::DescriptorSet >( GBufferCompositeDescriptorSet::createLayout() )
};
composite_set->setMaxIDX( 1 );
composite_set->bindAttachment(
0,
*( gbuffer.composite.resources().m_image_views[ i ].get() ),
vk::ImageLayout::eShaderReadOnlyOptimal );
composite_set->update();
m_gbuffer_composite_descriptor_set[ i ] = std::move( composite_set );
}
}
static_assert( is_attachment< ColoredPresentAttachment > );
static_assert( is_attachment< DepthAttachment > );
@@ -341,16 +290,6 @@ namespace fgl::engine
vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests,
vk::DependencyFlagBits::eByRegion );
/*
composite_subpass.registerDependencyFrom(
g_buffer_subpass,
vk::AccessFlagBits::eColorAttachmentWrite,
vk::PipelineStageFlagBits::eColorAttachmentOutput,
vk::AccessFlagBits::eTransferWrite,
vk::PipelineStageFlagBits::eTopOfPipe,
vk::DependencyFlagBits::eByRegion );
*/
// To prevent the composite buffer from getting obliterated by the gui pass and so we can use it to render to the GUI in certian areas, We need to keep them seperate and the composite image to be unmodified.
Subpass<
vk::PipelineBindPoint::eGraphics,
@@ -362,10 +301,6 @@ namespace fgl::engine
gui_subpass.registerDependencyFromExternal(
vk::AccessFlagBits::eColorAttachmentWrite, vk::PipelineStageFlagBits::eColorAttachmentOutput );
/*
g_buffer_subpass -> composite_subpass -> gui_subpass
*/
gui_subpass.registerDependencyFrom(
composite_subpass,
vk::AccessFlagBits::eColorAttachmentWrite,
@@ -374,9 +309,6 @@ namespace fgl::engine
vk::PipelineStageFlagBits::eFragmentShader,
vk::DependencyFlagBits::eByRegion );
//composite_subpass.registerFullDependency( g_buffer_subpass );
//gui_subpass.registerFullDependency( composite_subpass );
gui_subpass.registerDependencyFrom(
composite_subpass,
vk::AccessFlagBits::eColorAttachmentWrite,
@@ -392,24 +324,51 @@ namespace fgl::engine
vk::PipelineStageFlagBits::eBottomOfPipe,
vk::DependencyFlagBits::eByRegion );
render_pass.registerSubpass( g_buffer_subpass );
render_pass.registerSubpass( composite_subpass );
render_pass.registerSubpass( gui_subpass );
render_pass_builder.registerSubpass( g_buffer_subpass );
render_pass_builder.registerSubpass( composite_subpass );
render_pass_builder.registerSubpass( gui_subpass );
m_render_pass = render_pass.create();
m_clear_values = render_pass_builder.getClearValues();
m_render_pass_resources = render_pass.resources( imageCount() );
m_clear_values = render_pass.getClearValues();
return render_pass_builder.create();
}
void SwapChain::createFramebuffers()
std::vector< vk::raii::Framebuffer > SwapChain::createFramebuffers()
{
ZoneScoped;
m_swap_chain_buffers.clear();
m_swap_chain_buffers.reserve( imageCount() );
render_attachments.depth.createResources( imageCount(), getSwapChainExtent() );
render_attachments.color.linkImages( m_swap_chain_images );
gbuffer.position.createResourceSpread( imageCount(), getSwapChainExtent(), vk::ImageUsageFlagBits::eSampled );
gbuffer.normal.createResourceSpread( imageCount(), getSwapChainExtent(), vk::ImageUsageFlagBits::eSampled );
gbuffer.albedo.createResourceSpread( imageCount(), getSwapChainExtent(), vk::ImageUsageFlagBits::eSampled );
gbuffer.composite.createResourceSpread( imageCount(), getSwapChainExtent(), vk::ImageUsageFlagBits::eSampled );
g_buffer_position_img = std::make_unique< Texture >( gbuffer.position.m_attachment_resources.m_images[ 0 ]
->setName( "GBufferPosition" ) );
g_buffer_normal_img = std::make_unique< Texture >( gbuffer.normal.m_attachment_resources.m_images[ 0 ]
->setName( "GBufferNormal" ) );
g_buffer_albedo_img = std::make_unique< Texture >( gbuffer.albedo.m_attachment_resources.m_images[ 0 ]
->setName( "GBufferAlbedo" ) );
g_buffer_composite_img = std::make_unique< Texture >( gbuffer.composite.m_attachment_resources.m_images[ 0 ]
->setName( "GBufferComposite" ) );
std::vector< vk::raii::Framebuffer > framebuffers {};
framebuffers.reserve( imageCount() );
for ( uint8_t i = 0; i < imageCount(); i++ )
{
std::vector< vk::ImageView > attachments { m_render_pass_resources->forFrame( i ) };
std::vector< vk::ImageView > attachments { getViewsForFrame(
i,
render_attachments.color,
render_attachments.depth,
gbuffer.position,
gbuffer.normal,
gbuffer.albedo,
gbuffer.composite ) };
//Fill attachments for this frame
const vk::Extent2D swapChainExtent { getSwapChainExtent() };
@@ -421,15 +380,17 @@ namespace fgl::engine
framebufferInfo.height = swapChainExtent.height;
framebufferInfo.layers = 1;
m_swap_chain_buffers.push_back( Device::getInstance()->createFramebuffer( framebufferInfo ) );
framebuffers.push_back( Device::getInstance()->createFramebuffer( framebufferInfo ) );
}
return framebuffers;
}
void SwapChain::createSyncObjects()
{
ZoneScoped;
imageAvailableSemaphores.reserve( MAX_FRAMES_IN_FLIGHT );
renderFinishedSemaphores.reserve( MAX_FRAMES_IN_FLIGHT );
image_available_sem.reserve( MAX_FRAMES_IN_FLIGHT );
render_finished_sem.reserve( MAX_FRAMES_IN_FLIGHT );
in_flight_fence.reserve( MAX_FRAMES_IN_FLIGHT );
images_in_flight.resize( imageCount(), VK_NULL_HANDLE );
@@ -442,8 +403,8 @@ namespace fgl::engine
{
auto& device { Device::getInstance() };
imageAvailableSemaphores.push_back( device->createSemaphore( semaphoreInfo ) );
renderFinishedSemaphores.push_back( device->createSemaphore( semaphoreInfo ) );
image_available_sem.push_back( device->createSemaphore( semaphoreInfo ) );
render_finished_sem.push_back( device->createSemaphore( semaphoreInfo ) );
in_flight_fence.push_back( device->createFence( fenceInfo ) );
}
}
@@ -534,6 +495,53 @@ namespace fgl::engine
}
}
std::array< std::unique_ptr< descriptors::DescriptorSet >, SwapChain::MAX_FRAMES_IN_FLIGHT > SwapChain::
createGBufferDescriptors()
{
std::array< std::unique_ptr< descriptors::DescriptorSet >, SwapChain::MAX_FRAMES_IN_FLIGHT > data;
for ( int i = 0; i < SwapChain::MAX_FRAMES_IN_FLIGHT; ++i )
{
auto set { std::make_unique< descriptors::DescriptorSet >( GBufferDescriptorSet::createLayout() ) };
set->setMaxIDX( 2 );
set->bindAttachment( 0, gbuffer.position.getView( i ), vk::ImageLayout::eShaderReadOnlyOptimal );
set->bindAttachment( 1, gbuffer.normal.getView( i ), vk::ImageLayout::eShaderReadOnlyOptimal );
set->bindAttachment( 2, gbuffer.albedo.getView( i ), vk::ImageLayout::eShaderReadOnlyOptimal );
set->update();
data[ i ] = std::move( set );
}
return data;
}
std::array< std::unique_ptr< descriptors::DescriptorSet >, SwapChain::MAX_FRAMES_IN_FLIGHT > SwapChain::
createCompositeDescriptors()
{
std::array< std::unique_ptr< descriptors::DescriptorSet >, SwapChain::MAX_FRAMES_IN_FLIGHT > data;
for ( int i = 0; i < SwapChain::MAX_FRAMES_IN_FLIGHT; ++i )
{
auto composite_set {
std::make_unique< descriptors::DescriptorSet >( GBufferCompositeDescriptorSet::createLayout() )
};
composite_set->setMaxIDX( 1 );
composite_set->bindAttachment( 0, gbuffer.composite.getView( i ), vk::ImageLayout::eShaderReadOnlyOptimal );
composite_set->update();
data[ i ] = std::move( composite_set );
}
return data;
}
vk::Format SwapChain::findDepthFormat()
{
ZoneScoped;

View File

@@ -6,7 +6,7 @@
#include <vector>
#include "Device.hpp"
#include "RenderPass.hpp"
#include "RenderPassBuilder.hpp"
#include "engine/FrameInfo.hpp"
#include "engine/texture/Texture.hpp"
@@ -49,18 +49,6 @@ namespace fgl::engine
ColorAttachment composite { vk::Format::eR8G8B8A8Unorm };
} gbuffer {};
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< vk::raii::Semaphore > imageAvailableSemaphores {};
std::vector< vk::raii::Semaphore > renderFinishedSemaphores {};
std::vector< vk::raii::Fence > in_flight_fence {};
std::vector< vk::Fence > images_in_flight {};
size_t m_current_frame_index { 0 };
std::vector< vk::ClearValue > m_clear_values {};
public:
std::unique_ptr< Texture > g_buffer_position_img { nullptr };
@@ -70,11 +58,31 @@ namespace fgl::engine
private:
RenderPassBuilder render_pass_builder {};
vk::raii::RenderPass m_render_pass;
std::vector< vk::raii::Framebuffer > m_swap_chain_buffers;
std::vector< vk::ClearValue > m_clear_values;
std::array< std::unique_ptr< descriptors::DescriptorSet >, SwapChain::MAX_FRAMES_IN_FLIGHT >
m_gbuffer_descriptor_set;
std::array< std::unique_ptr< descriptors::DescriptorSet >, SwapChain::MAX_FRAMES_IN_FLIGHT >
m_gbuffer_composite_descriptor_set;
std::vector< vk::raii::Semaphore > image_available_sem {};
std::vector< vk::raii::Semaphore > render_finished_sem {};
std::vector< vk::raii::Fence > in_flight_fence {};
std::vector< vk::Fence > images_in_flight {};
size_t m_current_frame_index { 0 };
void init();
[[nodiscard]] vk::raii::SwapchainKHR createSwapChain();
[[nodiscard]] std::vector< Image > createSwapchainImages();
void createRenderPass();
void createFramebuffers();
[[nodiscard]] vk::raii::RenderPass createRenderPass();
[[nodiscard]] std::vector< vk::raii::Framebuffer > createFramebuffers();
void createSyncObjects();
// Helper functions
@@ -82,11 +90,32 @@ namespace fgl::engine
vk::PresentModeKHR chooseSwapPresentMode( const std::vector< vk::PresentModeKHR >& availablePresentModes );
vk::Extent2D chooseSwapExtent( const vk::SurfaceCapabilitiesKHR& capabilities );
std::array< std::unique_ptr< descriptors::DescriptorSet >, SwapChain::MAX_FRAMES_IN_FLIGHT >
m_gbuffer_descriptor_set {};
template < is_attachment... Attachments >
static std::vector< vk::ImageView > getViewsForFrame( const std::uint8_t frame_idx, Attachments... attachments )
{
std::vector< vk::ImageView > view {};
view.resize( sizeof...( Attachments ) );
( ( view[ attachments.getIndex() ] = *attachments.getView( frame_idx ) ), ... );
return view;
}
template < is_attachment... Attachments >
static std::vector< vk::ClearValue > gatherClearValues( Attachments... attachments )
{
std::vector< vk::ClearValue > clear_values {};
clear_values.resize( sizeof...( Attachments ) );
( ( clear_values[ attachments.getIndex() ] = attachments.m_clear_value ), ... );
return clear_values;
}
std::array< std::unique_ptr< descriptors::DescriptorSet >, SwapChain::MAX_FRAMES_IN_FLIGHT >
m_gbuffer_composite_descriptor_set {};
createGBufferDescriptors();
std::array< std::unique_ptr< descriptors::DescriptorSet >, SwapChain::MAX_FRAMES_IN_FLIGHT >
createCompositeDescriptors();
public: