This commit is contained in:
2024-03-06 22:57:37 -05:00
parent a7bed8e4e6
commit 2550815d37
23 changed files with 318 additions and 138 deletions

View File

@@ -462,6 +462,8 @@ namespace fgl::engine
m_renderer.endFrame();
FrameMark;
using namespace std::chrono_literals;
std::this_thread::sleep_until( new_time + 16ms );
}
}
@@ -502,7 +504,7 @@ namespace fgl::engine
model->syncBuffers( command_buffer );
int val { 16 };
int val { 64 };
for ( int x = 0; x < val; ++x )
{
@@ -511,7 +513,9 @@ namespace fgl::engine
auto sponza = GameObject::createGameObject();
sponza.m_model = model;
sponza.m_transform.translation = WorldCoordinate(
0.0f + ( static_cast< float >( y ) * 30.0f ), 0.0f + ( static_cast< float >( x ) * 20.0f ), 0.0f );
-900.0f + ( static_cast< float >( y ) * 30.0f ),
-900.0f + ( static_cast< float >( x ) * 20.0f ),
0.0f );
sponza.m_transform.scale = { 0.007f, 0.007f, 0.007f };
sponza.m_transform.rotation = Rotation( 0.0f, 0.0f, 0.0f );

View File

@@ -284,10 +284,40 @@ namespace fgl::engine
return;
}
void Buffer::free( fgl::engine::BufferSuballocationHandle& info )
void Buffer::free( BufferSuballocationHandle& info )
{
ZoneScoped;
#ifndef NDEBUG
//Overwrite the bytes with 0xDEADBEEF
if ( info.mapped )
{
std::memset( info.mapped, 0xDEADBEEF, info.m_size );
vk::MappedMemoryRange range {};
range.memory = info.buffer.getMemory();
range.offset = info.m_offset;
const vk::DeviceSize min_atom_size { Device::getInstance().m_properties.limits.nonCoherentAtomSize };
const auto size { info.m_size };
range.size = align( size, min_atom_size );
if ( range.size > info.m_size ) range.size = VK_WHOLE_SIZE;
if ( Device::getInstance().device().flushMappedMemoryRanges( 1, &range ) != vk::Result::eSuccess )
{
throw std::runtime_error( "Failed to flush memory" );
}
//Flush memory
}
else
throw std::runtime_error( "Unable to give back memory" );
#endif
//Find the suballocation
auto itter = m_suballocations.find( info.m_offset );

View File

@@ -125,17 +125,40 @@ namespace fgl::engine
public:
//! Returns the vulkan buffer handle for this buffer
vk::Buffer getBuffer() const { return m_handle->m_buffer; }
vk::Buffer getBuffer() const
{
assert( m_handle );
assert( m_handle->m_buffer != VK_NULL_HANDLE );
return m_handle->m_buffer;
}
//! Returns the vulkan memory handle for this buffer
vk::DeviceMemory getMemory() const { return m_handle->m_alloc_info.deviceMemory; }
vk::DeviceMemory getMemory() const
{
assert( m_handle );
assert( m_handle->m_alloc_info.deviceMemory != VK_NULL_HANDLE );
return m_handle->m_alloc_info.deviceMemory;
}
//! Total memory size of the buffer
vk::DeviceSize size() const { return m_handle->m_memory_size; }
vk::DeviceSize size() const
{
assert( m_handle );
assert( !std::isnan( m_handle->m_memory_size ) );
return m_handle->m_memory_size;
}
void* map( BufferSuballocationHandle& info );
bool isMappable() const { return m_handle->m_alloc_info.pMappedData != nullptr; }
bool isMappable() const
{
assert( m_handle );
return m_handle->m_alloc_info.pMappedData != nullptr;
}
//! Returns a allocation block from this buffer. Block will be aligned with nonUniformBufferOffsetAlignment
//! and nonCoherentAtomSize if required (is_uniform_buffer and is_host_visible respectively)

View File

@@ -21,33 +21,39 @@ namespace fgl::engine
other.m_offset = 0;
other.m_size = 0;
other.m_handle = nullptr;
return *this;
}
BufferSuballocation::BufferSuballocation( std::shared_ptr< BufferSuballocationHandle > handle ) :
m_handle( std::move( handle ) )
{
m_offset = m_handle->m_offset;
m_size = m_handle->m_size;
}
m_handle( std::move( handle ) ),
m_offset( m_handle->m_offset ),
m_size( m_handle->m_size )
{}
BufferSuballocation::BufferSuballocation( BufferSuballocation&& other ) : m_handle( std::move( other.m_handle ) )
BufferSuballocation::BufferSuballocation( BufferSuballocation&& other ) :
m_handle( std::move( other.m_handle ) ),
m_offset( m_handle->m_offset ),
m_size( m_handle->m_size )
{
m_offset = m_handle->m_offset;
m_size = m_handle->m_size;
other.m_offset = 0;
other.m_size = 0;
other.m_handle = nullptr;
}
void* BufferSuballocation::ptr() const
{
assert( m_handle != nullptr );
return m_handle->mapped;
}
void BufferSuballocation::flush( vk::DeviceSize beg, vk::DeviceSize end )
{
assert( m_handle != nullptr );
assert( m_handle->mapped != nullptr && "BufferSuballocationT::flush() called before map()" );
vk::MappedMemoryRange range {};
range.memory = m_handle->buffer.getMemory();
range.offset = m_offset + beg;
@@ -65,21 +71,29 @@ namespace fgl::engine
Buffer& BufferSuballocation::getBuffer() const
{
assert( m_handle != nullptr );
return m_handle->buffer;
}
vk::Buffer BufferSuballocation::getVkBuffer() const
{
assert( m_handle != nullptr );
return m_handle->buffer.getVkBuffer();
}
vk::DescriptorBufferInfo BufferSuballocation::descriptorInfo() const
{
assert( !std::isnan( m_offset ) );
assert( !std::isnan( m_size ) );
return vk::DescriptorBufferInfo( getVkBuffer(), m_offset, m_size );
}
SuballocationView BufferSuballocation::view( const vk::DeviceSize offset, const vk::DeviceSize size ) const
{
assert( m_handle != nullptr );
assert( offset + size <= m_size && "BufferSuballocation::view() called with offset + size > m_size" );
return { m_handle, offset, size };

View File

@@ -21,8 +21,8 @@ namespace fgl::engine
std::shared_ptr< BufferSuballocationHandle > m_handle;
vk::DeviceSize m_offset { 0 };
vk::DeviceSize m_size { 0 };
vk::DeviceSize m_offset;
vk::DeviceSize m_size;
void flush( vk::DeviceSize beg, vk::DeviceSize end );

View File

@@ -15,8 +15,11 @@ namespace fgl::engine
{
protected:
std::uint32_t m_count;
std::uint32_t m_stride;
//! Number of items in the vector
std::uint32_t m_count { std::numeric_limits< std::uint32_t >::quiet_NaN() };
//! Bytes for each item
std::uint32_t m_stride { std::numeric_limits< std::uint32_t >::quiet_NaN() };
//TODO: Implement spare
//std::uint32_t m_spare_count { 0 };
@@ -30,34 +33,41 @@ namespace fgl::engine
{}
BufferVector( const BufferVector& ) = delete;
BufferVector( BufferVector&& ) = default;
BufferVector& operator=( BufferVector&& other )
{
m_count = other.m_count;
m_stride = other.m_stride;
BufferSuballocation::operator=( std::move( other ) );
return *this;
}
BufferVector& operator=( const BufferVector& ) = delete;
BufferVector( BufferVector&& ) = default;
BufferVector& operator=( BufferVector&& other ) = default;
public:
//! Returns the offset count from the start of the buffer to the first element
[[nodiscard]] std::uint32_t getOffsetCount() const
{
assert( !std::isnan( m_count ) );
assert( !std::isnan( m_stride ) );
return static_cast< std::uint32_t >( this->m_offset / m_stride );
}
[[nodiscard]] std::uint32_t count() const noexcept { return m_count; }
[[nodiscard]] std::uint32_t count() const noexcept
{
assert( !std::isnan( m_count ) );
return m_count;
}
[[nodiscard]] std::uint32_t stride() const noexcept { return m_stride; }
[[nodiscard]] std::uint32_t stride() const noexcept
{
assert( !std::isnan( m_stride ) );
return m_stride;
}
void resize( const std::uint32_t count )
{
assert( m_handle != nullptr );
assert( !std::isnan( m_stride ) );
assert( !std::isnan( m_count ) );
BufferVector other { this->getBuffer(), count, m_stride };
Device::getInstance().copyBuffer( this->getBuffer(), other.getBuffer(), 0, 0, this->size() );

View File

@@ -30,10 +30,7 @@ namespace fgl::engine
HostVector& operator=( HostVector&& ) = delete;
HostVector( HostVector&& other ) = delete;
HostVector( Buffer& buffer, const std::uint32_t count = 1 ) : BufferVector( buffer, count, sizeof( T ) )
{
assert( count != 0 && "BufferSuballocationVector::BufferSuballocationVector() called with count == 0" );
}
HostVector( Buffer& buffer, const std::uint32_t count = 1 ) : BufferVector( buffer, count, sizeof( T ) ) {}
HostVector( Buffer& buffer, const std::vector< T >& vec ) :
HostVector( buffer, static_cast< std::uint32_t >( vec.size() ) )
@@ -52,6 +49,9 @@ namespace fgl::engine
void flushRange( const std::uint32_t start_idx, const std::uint32_t end_idx )
{
if ( this->m_count == 0 ) [[unlikely]]
return;
assert(
start_idx < this->m_count && "BufferSuballocationVector::flushRange start_idx index out of bounds" );
assert( end_idx <= this->m_count && "BufferSuballocationVector::flushRange end_idx index out of bounds" );
@@ -62,7 +62,10 @@ namespace fgl::engine
( end_idx - start_idx ) != 0
&& "BufferSuballocationVector::flushRange end_idx must be at least +1 from start_idx" );
BufferSuballocation::flush( start_idx * this->m_stride, ( end_idx - start_idx ) * this->m_stride );
const auto count { end_idx - start_idx };
assert( count > 0 && "Count must be larger then 0" );
BufferSuballocation::flush( start_idx * this->m_stride, count * this->m_stride );
}
HostVector& operator=( const std::vector< T >& vec )

View File

@@ -29,7 +29,7 @@ namespace fgl::engine::constants
constexpr float DEFAULT_FLOAT { std::numeric_limits< float >::max() };
constexpr float NEAR_PLANE { 0.1f };
constexpr float FAR_PLANE { 100.0f };
constexpr float FAR_PLANE { 1000.0f };
constexpr glm::vec3 CENTER { 0.0f, 0.0f, 0.0f };
constexpr auto EPSILON { std::numeric_limits< float >::epsilon() * 2 };

View File

@@ -0,0 +1,3 @@
//
// Created by kj16609 on 3/6/24.
//

View File

@@ -0,0 +1,25 @@
//
// Created by kj16609 on 3/6/24.
//
#pragma once
namespace fgl::debug
{
class DrawQueue
{
std::thread draw_consumer;
//TODO: Replace with ring buffer
std::mutex mtx;
std::queue< >
};
}

View File

@@ -98,6 +98,11 @@ namespace fgl::engine
{
primitive.m_vertex_buffer.stage( cmd_buffer );
primitive.m_index_buffer.stage( cmd_buffer );
if ( primitive.m_texture.has_value() )
{
primitive.m_texture->stage( cmd_buffer );
}
}
}

View File

@@ -6,21 +6,14 @@
#include <glm/glm.hpp>
#include <algorithm>
#include <filesystem>
#include <memory>
#include <optional>
#include <vector>
#include "Primitive.hpp"
#include "Vertex.hpp"
#include "engine/buffers/Buffer.hpp"
#include "engine/buffers/BufferSuballocation.hpp"
#include "engine/buffers/vector/DeviceVector.hpp"
#include "engine/buffers/vector/HostVector.hpp"
#include "engine/primitives/boxes/OrientedBoundingBox.hpp"
#include "engine/rendering/Device.hpp"
#include "engine/utils.hpp"
namespace fgl::engine
{
@@ -77,7 +70,7 @@ namespace fgl::engine
return matrix * m_bounding_box;
}
std::vector< ::fgl::engine::Primitive > m_primitives {};
std::vector< Primitive > m_primitives {};
std::vector< vk::DrawIndexedIndirectCommand > getDrawCommand( const std::uint32_t index ) const;

View File

@@ -114,13 +114,6 @@ namespace fgl::engine
{
//TODO: Implement modes
std::cout << "Attributes: \n";
for ( const auto& thing : primitive.attributes )
{
std::cout << "\t" << thing.first << "\n";
}
std::cout << std::endl;
//Load indicies
auto& indicies_accessor { model.accessors.at( primitive.indices ) };

View File

@@ -19,7 +19,10 @@ static VKAPI_ATTR vk::Bool32 VKAPI_CALL debugCallback(
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
[[maybe_unused]] void* pUserData )
{
std::cerr << "validation layer: " << pCallbackData->pMessage << std::endl;
if ( pCallbackData->flags & VkDebugUtilsMessageSeverityFlagBitsEXT::VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT )
throw std::runtime_error( pCallbackData->pMessage );
else
std::cout << pCallbackData->pMessage << std::endl;
return VK_FALSE;
}
@@ -126,10 +129,13 @@ namespace fgl::engine
vk::InstanceCreateInfo createInfo {};
createInfo.pApplicationInfo = &appInfo;
auto extensions = getRequiredExtensions();
auto extensions { getRequiredInstanceExtensions() };
assert( extensions.size() >= 1 );
createInfo.enabledExtensionCount = static_cast< uint32_t >( extensions.size() );
createInfo.ppEnabledExtensionNames = extensions.data();
hasGlfwRequiredInstanceExtensions();
vk::DebugUtilsMessengerCreateInfoEXT debugCreateInfo {};
if ( enableValidationLayers )
{
@@ -147,8 +153,6 @@ namespace fgl::engine
if ( vk::createInstance( &createInfo, nullptr, &m_instance ) != vk::Result::eSuccess )
throw std::runtime_error( "Failed to create Vulkan instance" );
hasGflwRequiredInstanceExtensions();
}
void Device::pickPhysicalDevice()
@@ -195,6 +199,10 @@ namespace fgl::engine
vk::PhysicalDeviceFeatures deviceFeatures = {};
deviceFeatures.samplerAnisotropy = VK_TRUE;
deviceFeatures.multiDrawIndirect = VK_TRUE;
deviceFeatures.drawIndirectFirstInstance = VK_TRUE;
#ifndef NDEBUG
//deviceFeatures.robustBufferAccess = VK_TRUE;
#endif
vk::PhysicalDeviceDescriptorIndexingFeatures indexing_features {};
indexing_features.setRuntimeDescriptorArray( true );
@@ -214,7 +222,7 @@ namespace fgl::engine
//Get device extension list
const auto supported_extensions { m_physical_device.enumerateDeviceExtensionProperties() };
std::cout << "Supported extensions:" << std::endl;
std::cout << "Supported device extensions:" << std::endl;
for ( auto& desired_ext : deviceExtensions )
{
bool found { false };
@@ -227,6 +235,7 @@ namespace fgl::engine
}
}
std::cout << "\t" << desired_ext << ": " << found << std::endl;
if ( !found ) throw std::runtime_error( "Failed to find required extension" );
}
// might not really be necessary anymore because device specific validation layers
@@ -241,7 +250,7 @@ namespace fgl::engine
createInfo.enabledLayerCount = 0;
}
if ( m_physical_device.createDevice( &createInfo, nullptr, &device_ ) != vk::Result::eSuccess )
if ( auto res = m_physical_device.createDevice( &createInfo, nullptr, &device_ ); res != vk::Result::eSuccess )
{
throw std::runtime_error( "failed to create logical device!" );
}
@@ -308,7 +317,13 @@ namespace fgl::engine
void Device::setupDebugMessenger()
{
if ( !enableValidationLayers ) return;
std::cout << "Setting up debug messenger: " << std::endl;
if ( !enableValidationLayers )
{
std::cout << "-- Validation disabled" << std::endl;
return;
}
pfnVkCreateDebugUtilsMessengerEXT = reinterpret_cast<
PFN_vkCreateDebugUtilsMessengerEXT >( m_instance.getProcAddr( "vkCreateDebugUtilsMessengerEXT" ) );
@@ -336,6 +351,8 @@ namespace fgl::engine
{
throw std::runtime_error( "failed to set up debug messenger!" );
}
std::cout << "-- Debug callback setup" << std::endl;
}
bool Device::checkValidationLayerSupport()
@@ -364,14 +381,19 @@ namespace fgl::engine
return true;
}
std::vector< const char* > Device::getRequiredExtensions()
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 );
@@ -380,29 +402,31 @@ namespace fgl::engine
return extensions;
}
void Device::hasGflwRequiredInstanceExtensions()
void Device::hasGlfwRequiredInstanceExtensions()
{
std::vector< vk::ExtensionProperties > extensions { vk::enumerateInstanceExtensionProperties() };
std::vector< vk::ExtensionProperties > instance_extensions { vk::enumerateInstanceExtensionProperties() };
std::cout << "available extensions:" << std::endl;
std::cout << "available instance instance_extensions:" << std::endl;
std::unordered_set< std::string > available;
for ( const auto& extension : extensions )
for ( const auto& extension : instance_extensions )
{
std::cout << "\t" << extension.extensionName << std::endl;
available.insert( extension.extensionName );
}
std::cout << "required extensions:" << std::endl;
auto requiredExtensions = getRequiredExtensions();
std::cout << "required instance instance_extensions:" << std::endl;
auto requiredExtensions { getRequiredInstanceExtensions() };
for ( const char* required : requiredExtensions )
{
if ( std::find_if(
extensions.begin(),
extensions.end(),
instance_extensions.begin(),
instance_extensions.end(),
[ required ]( const vk::ExtensionProperties& prop )
{ return std::strcmp( prop.extensionName, required ); } )
== extensions.end() )
== instance_extensions.end() )
throw std::runtime_error( "Missing required glfw extension" );
else
std::cout << required << std::endl;
}
}

View File

@@ -45,9 +45,9 @@ namespace fgl::engine
vk::Queue graphicsQueue_ { VK_NULL_HANDLE };
vk::Queue presentQueue_ { VK_NULL_HANDLE };
const std::vector< const char* > validationLayers { "VK_LAYER_KHRONOS_validation" };
const 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 };
void copyBuffer(
vk::Buffer dst,
@@ -94,11 +94,11 @@ namespace fgl::engine
// helper functions
bool isDeviceSuitable( vk::PhysicalDevice device );
std::vector< const char* > getRequiredExtensions();
std::vector< const char* > getRequiredInstanceExtensions();
bool checkValidationLayerSupport();
QueueFamilyIndices findQueueFamilies( vk::PhysicalDevice device );
void populateDebugMessengerCreateInfo( vk::DebugUtilsMessengerCreateInfoEXT& createInfo );
void hasGflwRequiredInstanceExtensions();
void hasGlfwRequiredInstanceExtensions();
bool checkDeviceExtensionSupport( vk::PhysicalDevice device );
SwapChainSupportDetails querySwapChainSupport( vk::PhysicalDevice device );
@@ -106,10 +106,10 @@ namespace fgl::engine
public:
#ifdef NDEBUG
const bool enableValidationLayers = false;
#ifndef NDEBUG
const bool enableValidationLayers { true };
#else
const bool enableValidationLayers = true;
const bool enableValidationLayers { false };
#endif
vk::Result setDebugUtilsObjectName( const vk::DebugUtilsObjectNameInfoEXT& nameInfo );

View File

@@ -136,7 +136,7 @@ namespace fgl::engine
}
template < is_subpass SrcT >
void registerDependency(
void registerDependencyFrom(
SrcT& parent,
const vk::AccessFlags src_access_flags,
const vk::PipelineStageFlags src_stage_flags,
@@ -154,7 +154,7 @@ namespace fgl::engine
dependency_flags );
}
void registerExternalDependency(
void registerDependencyFromExternal(
const vk::AccessFlags access_flags,
const vk::PipelineStageFlags stage_flags,
const vk::DependencyFlags dependency_flags = {} )
@@ -164,10 +164,27 @@ namespace fgl::engine
this->index,
access_flags,
stage_flags,
vk::AccessFlags( 0 ),
access_flags,
stage_flags,
dependency_flags );
}
void registerDependencyToExternal(
const vk::AccessFlags src_access_flags,
const vk::PipelineStageFlags src_stage_flags,
const vk::AccessFlags dst_access_flags,
const vk::PipelineStageFlags dst_stage_flags,
const vk::DependencyFlags dependency_flags )
{
registerDependency(
this->getIndex(),
VK_SUBPASS_EXTERNAL,
src_access_flags,
src_stage_flags,
dst_access_flags,
dst_stage_flags,
dependency_flags );
}
};
} // namespace fgl::engine

View File

@@ -223,8 +223,10 @@ namespace fgl::engine
for ( std::uint64_t i = 0; i < swap_chain_images.size(); i++ )
{
m_swap_chain_images
.emplace_back( extent, surfaceFormat.format, swap_chain_images[ i ], createInfo.imageUsage );
auto& itter =
m_swap_chain_images
.emplace_back( extent, surfaceFormat.format, swap_chain_images[ i ], createInfo.imageUsage );
itter.setName( "Swapchain image: " + std::to_string( i ) );
}
m_swap_chain_format = surfaceFormat.format;
@@ -305,11 +307,11 @@ namespace fgl::engine
0, depthAttachment, colorAttachment, g_buffer_position, g_buffer_normal, g_buffer_albedo
};
g_buffer_subpass.registerExternalDependency(
g_buffer_subpass.registerDependencyFromExternal(
vk::AccessFlagBits::eDepthStencilAttachmentWrite,
vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests );
g_buffer_subpass.registerExternalDependency(
g_buffer_subpass.registerDependencyFromExternal(
vk::AccessFlagBits::eColorAttachmentWrite, vk::PipelineStageFlagBits::eColorAttachmentOutput );
Subpass<
@@ -323,18 +325,7 @@ namespace fgl::engine
1, depthAttachment, colorAttachment, g_buffer_position, g_buffer_normal, g_buffer_albedo
};
/*
// This dependency transitions the input attachment from color attachment to input attachment read
dependencies[ 2 ].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[ 2 ].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[ 2 ].dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
dependencies[ 2 ].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[ 2 ].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
*/
present_subpass.registerDependency(
present_subpass.registerDependencyFrom(
g_buffer_subpass,
vk::AccessFlagBits::eColorAttachmentWrite,
vk::PipelineStageFlagBits::eColorAttachmentOutput,
@@ -342,9 +333,7 @@ namespace fgl::engine
vk::PipelineStageFlagBits::eFragmentShader,
vk::DependencyFlagBits::eByRegion );
present_subpass.registerDependency(
present_subpass.getIndex(),
VK_SUBPASS_EXTERNAL,
present_subpass.registerDependencyToExternal(
vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite,
vk::PipelineStageFlagBits::eColorAttachmentOutput,
vk::AccessFlagBits::eMemoryRead,

View File

@@ -39,7 +39,7 @@ namespace fgl::engine
if ( obj.m_is_visible )
{
//Draw the bounding box for debug
debug::world::drawBoundingBox( model_bounding_box );
//debug::world::drawBoundingBox( model_bounding_box );
}
}
}

View File

@@ -4,6 +4,7 @@
#include "EntityRendererSystem.hpp"
#include <engine/utils.hpp>
#include <imgui/imgui.h>
#include <tracy/TracyC.h>
#include <vulkan/vulkan.hpp>
@@ -14,6 +15,31 @@
#include "engine/literals/size.hpp"
#include "engine/tree/octtree/OctTreeNode.hpp"
namespace fgl::engine
{
// <TextureID, MemoryOffset>
using DrawKey = std::pair< TextureID, vk::DeviceSize >;
} // namespace fgl::engine
namespace std
{
template <>
struct hash< fgl::engine::DrawKey >
{
size_t operator()( const fgl::engine::DrawKey& key ) const
{
const auto id_hash { std::hash< fgl::engine::TextureID >()( key.first ) };
const auto offset_hash { std::hash< vk::DeviceSize >()( key.second ) };
size_t seed { 0 };
fgl::engine::hashCombine( seed, id_hash, offset_hash );
return seed;
}
};
} // namespace std
namespace fgl::engine
{
std::unique_ptr< Buffer > m_global_draw_parameter_buffer { nullptr };
@@ -81,53 +107,59 @@ namespace fgl::engine
m_pipeline->bindDescriptor( command_buffer, 0, info.global_descriptor_set );
m_pipeline->bindDescriptor( command_buffer, 1, Texture::getTextureDescriptorSet() );
std::set< DrawPair > draw_pairs;
std::unordered_map< DrawKey, DrawPair > draw_pairs;
std::uint64_t tri_counter { 0 };
std::uint64_t object_counter { 0 };
std::uint64_t primitive_counter { 0 };
for ( auto* node : info.game_objects.getAllLeafsInFrustum( info.camera_frustum ) )
{
ZoneScopedN( "Process leaf" );
for ( const auto& obj : *node )
{
ZoneScopedN( "Process object" );
if ( obj.m_model == nullptr ) continue;
if ( !obj.m_is_visible ) continue;
++object_counter;
for ( const auto& primitive : obj.m_model->m_primitives )
{
++primitive_counter;
tri_counter += ( primitive.m_index_buffer.count() / 3 );
const ModelMatrixInfo matrix_info { .model_matrix = obj.m_transform.mat4(),
.texture_idx = primitive.m_texture->getID() };
//.normal_matrix = obj.transform.normalMatrix() };
vk::DrawIndexedIndirectCommand cmd;
const auto key {
std::make_pair( primitive.m_texture->getID(), primitive.m_index_buffer.getOffset() )
};
cmd.firstIndex = primitive.m_index_buffer.getOffsetCount();
cmd.indexCount = primitive.m_index_buffer.count();
cmd.vertexOffset = primitive.m_vertex_buffer.getOffsetCount();
cmd.instanceCount = 1;
auto itter = std::find(
draw_pairs.begin(),
draw_pairs.end(),
std::make_pair( cmd, std::vector< ModelMatrixInfo >() ) );
if ( itter != draw_pairs.end() )
if ( auto itter = draw_pairs.find( key ); itter != draw_pairs.end() )
{
//Draw command for this mesh already exists. Simply add a count to it
auto [ existing_cmd, model_matrix ] = *itter;
auto& [ itter_key, pair ] = *itter;
auto& [ existing_cmd, model_matrix ] = pair;
draw_pairs.erase( itter );
existing_cmd.instanceCount++;
model_matrix.emplace_back( matrix_info );
draw_pairs.emplace( existing_cmd, std::move( model_matrix ) );
}
else
{
draw_pairs.emplace( cmd, std::vector< ModelMatrixInfo > { matrix_info } );
vk::DrawIndexedIndirectCommand cmd {};
cmd.firstIndex = primitive.m_index_buffer.getOffsetCount();
cmd.indexCount = primitive.m_index_buffer.count();
cmd.vertexOffset = static_cast< int32_t >( primitive.m_vertex_buffer.getOffsetCount() );
cmd.instanceCount = 1;
std::vector< ModelMatrixInfo > matrix_infos {};
matrix_infos.reserve( 1024 );
draw_pairs.emplace( key, std::make_pair( cmd, std::move( matrix_infos ) ) );
}
}
}
@@ -135,6 +167,8 @@ namespace fgl::engine
#if ENABLE_IMGUI
ImGui::Text( "Tris: %lu", tri_counter );
ImGui::Text( "Models: %lu", object_counter );
ImGui::Text( "Primitives: %lu", primitive_counter );
#endif
if ( draw_pairs.empty() )
@@ -147,12 +181,15 @@ namespace fgl::engine
std::vector< vk::DrawIndexedIndirectCommand > draw_commands;
std::vector< ModelMatrixInfo > model_matrices;
draw_commands.reserve( draw_pairs.size() );
model_matrices.reserve( draw_pairs.size() * 2 );
TracyCZoneN( filter_zone_TRACY, "Reorganize draw commands", true );
for ( auto& itter : draw_pairs )
for ( auto& [ key, pair ] : draw_pairs )
{
auto cmd { itter.first };
auto cmd { pair.first };
cmd.firstInstance = static_cast< std::uint32_t >( model_matrices.size() );
auto matricies { std::move( itter.second ) };
auto matricies { std::move( pair.second ) };
draw_commands.emplace_back( cmd );
model_matrices.insert( model_matrices.end(), matricies.begin(), matricies.end() );
@@ -183,15 +220,19 @@ namespace fgl::engine
model_matrix_info_buffer->flush();
auto& model_matricies_suballoc { model_matrix_info_buffer };
auto& draw_params { draw_parameter_buffer };
const auto& model_matricies_suballoc { model_matrix_info_buffer };
const auto& draw_params { draw_parameter_buffer };
std::vector< vk::Buffer > vertex_buffers { m_vertex_buffer->getVkBuffer(),
model_matricies_suballoc->getVkBuffer() };
const std::vector< vk::Buffer > vertex_buffers { m_vertex_buffer->getVkBuffer(),
model_matricies_suballoc->getVkBuffer() };
command_buffer.bindVertexBuffers( 0, vertex_buffers, { 0, model_matricies_suballoc->getOffset() } );
command_buffer.bindIndexBuffer( m_index_buffer->getVkBuffer(), 0, vk::IndexType::eUint32 );
#if ENABLE_IMGUI
ImGui::Text( "Indirect draws: %lu", static_cast< std::size_t >( draw_params->count() ) );
#endif
command_buffer.drawIndexedIndirect(
draw_params->getVkBuffer(), draw_params->getOffset(), draw_params->count(), draw_params->stride() );

View File

@@ -119,7 +119,7 @@ namespace fgl::engine
barrier.srcAccessMask = {};
barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite;
std::vector< vk::ImageMemoryBarrier > barriers_to { barrier };
const std::vector< vk::ImageMemoryBarrier > barriers_to { barrier };
cmd.pipelineBarrier(
vk::PipelineStageFlagBits::eTopOfPipe,
@@ -153,13 +153,13 @@ namespace fgl::engine
vk::ImageMemoryBarrier barrier_from {};
barrier_from.oldLayout = barrier.newLayout;
barrier_from.newLayout = vk::ImageLayout::eGeneral;
barrier_from.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
barrier_from.image = m_handle->m_image_view->getVkImage();
barrier_from.subresourceRange = range;
barrier_from.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
barrier_from.dstAccessMask = vk::AccessFlagBits::eShaderRead;
std::vector< vk::ImageMemoryBarrier > barriers_from { barrier_from };
const std::vector< vk::ImageMemoryBarrier > barriers_from { barrier_from };
cmd.pipelineBarrier(
vk::PipelineStageFlagBits::eTransfer,

View File

@@ -19,6 +19,8 @@ namespace fgl::engine
class Texture
{
std::shared_ptr< TextureHandle > m_handle;
//! Has this texture been submitted to the GPU?
bool submitte_to_gpu { false };
Texture( std::tuple< std::vector< unsigned char >, int, int, int > );
Texture( std::shared_ptr< TextureHandle > handle );

View File

@@ -15,6 +15,7 @@ namespace fgl::engine
std::vector< NodeLeaf* > OctTreeNode::getAllLeafsInFrustum( const Frustum< CoordinateSpace::World >& frustum )
{
ZoneScoped;
std::vector< NodeLeaf* > leafs {};
//Check if we are inside of the frustum.
@@ -29,7 +30,7 @@ namespace fgl::engine
{
const auto ret { node_array[ LEFT ][ FORWARD ][ TOP ]->getAllLeafsInFrustum( frustum ) };
leafs.insert( leafs.end(), ret.begin(), ret.end() );
leafs = std::move( ret );
}
{
const auto ret { node_array[ LEFT ][ FORWARD ][ BOTTOM ]->getAllLeafsInFrustum( frustum ) };
@@ -66,9 +67,10 @@ namespace fgl::engine
}
case 1: // NodeLeaf
{
leafs.reserve( 4096 );
leafs.emplace_back( &std::get< NodeLeaf >( m_node_data ) );
debug::world::drawBoundingBox( m_bounds );
// debug::world::drawBoundingBox( m_bounds );
return leafs;
}
@@ -84,12 +86,12 @@ namespace fgl::engine
m_bounds( center, span ),
m_node_data( NodeLeaf() ),
m_parent( parent )
{}
{
std::get< NodeLeaf >( m_node_data ).reserve( MAX_NODES_IN_LEAF );
}
void OctTreeNode::split( int depth )
{
std::cout << "Splitting node: " << glm::to_string( this->m_bounds.getPosition().vec() ) << std::endl;
if ( std::holds_alternative< NodeArray >( m_node_data ) ) return;
auto& game_objects { std::get< NodeLeaf >( m_node_data ) };
@@ -192,6 +194,7 @@ namespace fgl::engine
OctTreeNode* OctTreeNode::findID( const GameObject::ID id )
{
ZoneScoped;
if ( std::holds_alternative< NodeLeaf >( this->m_node_data ) )
{
//We are the last node. Check if we have the ID
@@ -264,6 +267,7 @@ namespace fgl::engine
std::vector< NodeLeaf* > OctTreeNode::getAllLeafs()
{
ZoneScoped;
std::vector< NodeLeaf* > objects {};
if ( std::holds_alternative< NodeLeaf >( m_node_data ) )