Add in shader reloading and cleanup

This commit is contained in:
2024-10-20 00:09:28 -04:00
parent 5c4d7281fb
commit 7277c99223
38 changed files with 466 additions and 719 deletions

View File

@@ -4,8 +4,9 @@ add_subdirectory(engine)
add_subdirectory(objectloaders)
add_subdirectory(editor)
add_subdirectory(tests)
add_subdirectory(shaders)
add_subdirectory(assets)
add_dependencies(TitorEditor shaders)
add_dependencies(TitorEditor assets)
message("-- Creating SYMLINK ${CMAKE_BINARY_DIR}/shaders -> ${CMAKE_CURRENT_SOURCE_DIR}/shaders")
file(CREATE_LINK ${CMAKE_CURRENT_SOURCE_DIR}/shaders ${CMAKE_BINARY_DIR}/bin/shaders SYMBOLIC)
message("-- Creating SYMLINK ${CMAKE_BINARY_DIR}/assets -> ${CMAKE_CURRENT_SOURCE_DIR}/assets")
file(CREATE_LINK ${CMAKE_CURRENT_SOURCE_DIR}/assets ${CMAKE_BINARY_DIR}/bin/assets SYMBOLIC)

View File

@@ -1,39 +0,0 @@
file(GLOB_RECURSE ASSETS
${CMAKE_CURRENT_SOURCE_DIR}/**.obj
${CMAKE_CURRENT_SOURCE_DIR}/**.png
${CMAKE_CURRENT_SOURCE_DIR}/**.jpg
${CMAKE_CURRENT_SOURCE_DIR}/**.glb
${CMAKE_CURRENT_SOURCE_DIR}/**.bin
${CMAKE_CURRENT_SOURCE_DIR}/**.gltf
)
foreach (ASSET IN LISTS ASSETS)
get_filename_component(FILENAME ${ASSET} NAME)
get_filename_component(FILE_DIRECTORY ${ASSET} DIRECTORY)
file(RELATIVE_PATH REL_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${FILE_DIRECTORY})
if (NOT REL_PATH STREQUAL "")
set(REL_PATH ${REL_PATH}/)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bin/assets/${REL_PATH})
endif ()
set(OUT_DIR ${CMAKE_BINARY_DIR}/bin/assets/${REL_PATH})
set(OUT_PATH ${OUT_DIR}${FILENAME})
#add_custom_command(OUTPUT ${OUT_DIR}
# COMMAND ${CMAKE_COMMAND} -E make_directory ${OUT_DIR} COMMENT "Creating directory ${OUT_DIR}")
if (EXISTS ${OUT_PATH})
file(REMOVE ${OUT_PATH})
endif ()
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/bin/assets/${FILENAME}
COMMAND ${CMAKE_COMMAND} -E copy ${ASSET} ${OUT_PATH} DEPENDS ${ASSET}
COMMENT "Copying ${ASSET} to ${OUT_PATH}")
list(APPEND OUT_ASSETS ${CMAKE_BINARY_DIR}/bin/assets/${FILENAME})
list(APPEND ADDITIONAL_CLEAN_FILES ${OUT_PATH})
endforeach ()
add_custom_target(assets ALL DEPENDS ${OUT_ASSETS})

View File

@@ -15,9 +15,10 @@
#pragma GCC diagnostic pop
#include "FileBrowser.hpp"
#include "engine/debug/DEBUG_NAMES.hpp"
#include "engine/descriptors/DescriptorPool.hpp"
#include "engine/assets/model/Model.hpp"
#include "engine/debug/DEBUG_NAMES.hpp"
#include "engine/debug/profiling/counters.hpp"
#include "engine/descriptors/DescriptorPool.hpp"
#include "engine/rendering/Renderer.hpp"
#include "engine/tree/octtree/OctTreeNode.hpp"
#include "gui_window_names.hpp"
@@ -88,6 +89,11 @@ namespace fgl::engine::gui
//ImGui::RenderPlatformWindowsDefault();
}
void endDrawImGui( FrameInfo& info )
{
endImGui( info.command_buffer );
}
inline void prepareDock( ImGuiID& primary_id )
{
ImGui::DockBuilderRemoveNode( primary_id );
@@ -161,11 +167,15 @@ namespace fgl::engine::gui
// ImGui::PopStyleVar();
}
void drawMainGUI( FrameInfo& info )
void startDrawImGui( [[maybe_unused]] FrameInfo& info )
{
beginImGui();
profiling::resetCounters();
}
void drawImGui( FrameInfo& info )
{
ZoneScoped;
beginImGui();
// ImGui::ShowDemoWindow();
drawDock();
@@ -176,8 +186,6 @@ namespace fgl::engine::gui
drawFilesystemGUI( info );
drawStats( info );
endImGui( info.command_buffer );
}
static GameObject* selected_object { nullptr };

View File

@@ -15,10 +15,14 @@ namespace fgl::engine
namespace fgl::engine::gui
{
// Setup/Destruction
void initGui( const Window& window, const Renderer& renderer );
void cleanupImGui();
void drawMainGUI( FrameInfo& );
// Draws
void startDrawImGui( FrameInfo& info );
void drawImGui( FrameInfo& );
void drawEntityGUI( FrameInfo& );
void drawEntityInfo( FrameInfo& );
@@ -32,4 +36,6 @@ namespace fgl::engine::gui
void drawStats( const FrameInfo& info );
void endDrawImGui( FrameInfo& info );
} // namespace fgl::engine::gui

View File

@@ -3,6 +3,7 @@
#include "core.hpp"
#include "engine/debug/profiling/counters.hpp"
#include "engine/flags.hpp"
#include "engine/math/literals/size.hpp"
#include "engine/memory/buffers/Buffer.hpp"
#include "engine/tree/octtree/OctTreeNode.hpp"
@@ -102,9 +103,7 @@ namespace fgl::engine::gui
const auto& counters { profiling::getCounters() };
ImGui::Text( "Models drawn: %zu", counters.models_draw );
ImGui::Text( "Verts drawn: %zu", counters.verts_drawn );
//TODO: This should likely be moved to the just before we start rendering again.
profiling::resetCounters();
ImGui::Text( "Draw instances: %zu", counters.instance_count );
if ( ImGui::CollapsingHeader( "Memory" ) )
{
@@ -113,6 +112,11 @@ namespace fgl::engine::gui
imGuiOctTreeSettings( info );
if ( ImGui::Button( "Reload shaders" ) )
{
flags::triggerShaderReload();
}
ImGui::End();
}

View File

@@ -18,8 +18,10 @@ int main()
// We start by hooking into the imgui rendering.
engine_ctx.hookInitImGui( gui::initGui );
engine_ctx.hookCleanupImGui( gui::cleanupImGui );
engine_ctx.TEMPhookGuiRender( gui::drawMainGUI );
engine_ctx.hookPreFrame( gui::startDrawImGui );
engine_ctx.hookEarlyFrame( gui::drawImGui );
engine_ctx.hookLateFrame( gui::endDrawImGui );
engine_ctx.hookDestruction( gui::cleanupImGui );
// Now we need to create the camera for the editor.
CameraManager& camera_manager { engine_ctx.cameraManager() };
@@ -47,9 +49,9 @@ int main()
// Render step
engine_ctx.renderFrame();
}
engine_ctx.run();
engine_ctx.finishFrame();
}
return EXIT_SUCCESS;
}

View File

@@ -18,6 +18,7 @@
#include "camera/CameraRenderer.hpp"
#include "engine/assets/model/builders/SceneBuilder.hpp"
#include "engine/assets/transfer/TransferManager.hpp"
#include "engine/flags.hpp"
#include "engine/math/Average.hpp"
#include "engine/math/literals/size.hpp"
#include "engine/rendering/pipelines/v2/Pipeline.hpp"
@@ -144,6 +145,7 @@ namespace fgl::engine
void EngineContext::renderFrame()
{
ZoneScoped;
if ( auto& command_buffer = m_renderer.beginFrame(); *command_buffer )
{
const FrameIndex frame_index { m_renderer.getFrameIndex() };
@@ -165,26 +167,26 @@ namespace fgl::engine
// m_renderer.getSwapChain().getInputDescriptor( present_idx ),
this->m_renderer.getSwapChain() };
{
ZoneScopedN( "Pre frame hooks" );
for ( const auto& hook : pre_frame_hooks ) hook( frame_info );
}
TracyVkCollect( frame_info.tracy_ctx, *command_buffer );
//TODO: Setup semaphores to make this pass not always required.
memory::TransferManager::getInstance().recordOwnershipTransferDst( command_buffer );
for ( const auto& hook : early_render_hooks ) hook( frame_info );
//TODO: Add some way of 'activating' cameras. We don't need to render cameras that aren't active.
renderCameras( frame_info );
// m_renderer.clearInputImage( command_buffer );
// camera_manager.getPrimary()
// .copyOutput( command_buffer, frame_index, m_renderer.getSwapChain().getInputImage( present_idx ) );
for ( const auto& hook : render_hooks ) hook( frame_info );
m_renderer.beginSwapchainRendererPass( command_buffer );
m_gui_system.pass( frame_info );
// TODO: Implement some way we can record extra things into the command buffer during this stage.
// We'll probably just use multiple command buffers and allow the caller to pass some in with flags on where to put them
renderGui( frame_info );
for ( const auto& hook : late_render_hooks ) hook( frame_info );
m_renderer.endSwapchainRendererPass( command_buffer );
@@ -192,6 +194,13 @@ namespace fgl::engine
memory::TransferManager::getInstance().dump();
{
ZoneScopedN( "Post frame hooks" );
for ( const auto& hook : post_frame_hooks ) hook( frame_info );
}
flags::resetFlags();
FrameMark;
}
@@ -199,6 +208,9 @@ namespace fgl::engine
descriptors::deleteQueuedDescriptors();
}
void EngineContext::finishFrame()
{}
Window& EngineContext::getWindow()
{
return m_window;
@@ -214,68 +226,13 @@ namespace fgl::engine
return m_camera_manager;
}
void EngineContext::run()
{
TracyCZoneN( TRACY_PrepareEngine, "Inital Run", true );
std::cout << "Starting main loop run" << std::endl;
auto viewer { GameObject::createGameObject() };
viewer.getTransform().translation = WorldCoordinate( constants::WORLD_CENTER + glm::vec3( 0.0f, 0.0f, 2.5f ) );
KeyboardMovementController camera_controller {};
auto current_time { fgl::clock::now() };
auto previous_frame_start { fgl::clock::now() };
camera_controller.moveInPlaneXZ( m_window.window(), 0.0, viewer );
TracyCZoneEnd( TRACY_PrepareEngine );
while ( good() )
{
memory::TransferManager::getInstance().submitNow();
{
ZoneScopedN( "Poll" );
glfwPollEvents();
}
const auto new_time { fgl::clock::now() };
auto delta_time { std::chrono::duration< float >( new_time - current_time ).count() };
current_time = new_time;
delta_time = glm::min( delta_time, MAX_DELTA_TIME );
camera_controller.moveInPlaneXZ( m_window.window(), delta_time, viewer );
renderFrame();
using namespace std::chrono_literals;
// std::this_thread::sleep_for( 13ms );
}
Device::getInstance().device().waitIdle();
}
void EngineContext::loadGameObjects()
{
ZoneScoped;
std::cout << "Loading game objects" << std::endl;
auto command_buffer { Device::getInstance().beginSingleTimeCommands() };
Device::getInstance().endSingleTimeCommands( command_buffer );
log::info( "Finished loading game object" );
}
EngineContext::~EngineContext()
{
// Destroy all objects
m_game_objects_root.clear();
destroyMaterialDataVec();
cleanupImGui();
for ( const auto& hook : destruction_hooks ) hook();
}
bool EngineContext::good()

View File

@@ -19,6 +19,13 @@ namespace fgl::engine
using namespace fgl::literals::size_literals;
inline void dummyFrameInfoFunc( [[maybe_unused]] FrameInfo& frame_info )
{
return;
}
using FrameHookFunc = std::function< void( FrameInfo& ) >;
class EngineContext
{
static constexpr int DEFAULT_WIDTH { 1920 };
@@ -51,9 +58,19 @@ namespace fgl::engine
// SubPass 0
GuiSystem m_gui_system { m_renderer.getSwapChainRenderPass() };
// Temp function
std::function< void( FrameInfo& ) > renderGui { []( [[maybe_unused]] FrameInfo& ) noexcept {} };
std::function< void() > cleanupImGui { []() noexcept {} };
// Functions BEFORE a frame is started
std::vector< FrameHookFunc > pre_frame_hooks {};
//! TODO: Make this so we can tell at what stage we should be doing something
std::vector< FrameHookFunc > early_render_hooks {};
std::vector< FrameHookFunc > render_hooks {};
std::vector< FrameHookFunc > late_render_hooks {};
// Functions to call upon the frame ending (This happens AFTER the GPU call is dispatched)
std::vector< FrameHookFunc > post_frame_hooks {};
//! Called before the context is destroyed
std::vector< std::function< void() > > destruction_hooks;
// Memory pool for shader uniforms.
memory::Buffer m_ubo_buffer_pool;
@@ -69,8 +86,6 @@ namespace fgl::engine
std::chrono::time_point< fgl::clock > last_tick { fgl::clock::now() };
double m_delta_time;
void loadGameObjects();
public:
FGL_FORCE_INLINE_FLATTEN void hookInitImGui( const std::function< void( Window&, Renderer& ) >& func )
@@ -78,9 +93,17 @@ namespace fgl::engine
func( m_window, m_renderer );
}
FGL_FORCE_INLINE_FLATTEN void hookCleanupImGui( const std::function< void() >& func ) { cleanupImGui = func; }
void hookPreFrame( const FrameHookFunc& func ) { pre_frame_hooks.emplace_back( func ); }
void TEMPhookGuiRender( const std::function< void( FrameInfo& ) >& func ) { renderGui = func; }
void hookEarlyFrame( const FrameHookFunc& func ) { early_render_hooks.emplace_back( func ); }
void hookFrame( const FrameHookFunc& func ) { render_hooks.emplace_back( func ); }
void hookLateFrame( const FrameHookFunc& func ) { late_render_hooks.emplace_back( func ); }
void hookPostFrame( const FrameHookFunc& func ) { post_frame_hooks.emplace_back( func ); }
void hookDestruction( const std::function< void() >& func ) { destruction_hooks.emplace_back( func ); }
public:
@@ -104,12 +127,13 @@ namespace fgl::engine
void renderFrame();
//! Runs any post-frame processes
void finishFrame();
Window& getWindow();
float getWindowAspectRatio();
CameraManager& cameraManager();
void run();
};
} // namespace fgl::engine

View File

@@ -14,8 +14,18 @@
#define FGL_DELETE_ALL_Ro5( ClassName ) \
FGL_DELETE_DEFAULT_CTOR( ClassName ) FGL_DELETE_COPY( ClassName ) FGL_DELETE_MOVE( ClassName )
#define FGL_PACKED __attribute__(( packed ))
#define FGL_PACKED_ALIGNED( al ) __attribute__(( packed, aligned( al ) ))
#define FGL_DEFAULT_DEFAULT_CTOR( ClassName ) ClassName() = default;
#define FGL_DEFAULT_COPY_ASSIGN( ClassName ) ClassName& operator=( const ClassName& ) = default;
#define FGL_DEFAULT_COPY_CTOR( ClassName ) ClassName( const ClassName& ) = default;
#define FGL_DEFAULT_MOVE_ASSIGN( ClassName ) ClassName& operator=( ClassName&& ) = default;
#define FGL_DEFAULT_MOVE_CTOR( ClassName ) ClassName( ClassName&& ) = default;
#define FGL_DEFAULT_COPY( ClassName ) FGL_DEFAULT_COPY_CTOR( ClassName ) FGL_DEFAULT_COPY_ASSIGN( ClassName )
#define FGL_DEFAULT_MOVE( ClassName ) FGL_DEFAULT_MOVE_CTOR( ClassName ) FGL_DEFAULT_MOVE_ASSIGN( ClassName )
#define FGL_DEFAULT_ALL_Ro5( ClassName ) \
FGL_DEFAULT_DEFAULT_CTOR( ClassName ) FGL_DEFAULT_COPY( ClassName ) FGL_DEFAULT_MOVE( ClassName )
#define FGL_PACKED __attribute__( ( packed ) )
#define FGL_PACKED_ALIGNED( al ) __attribute__( ( packed, aligned( al ) ) )
#define FGL_FLATTEN [[gnu::flatten]]
#define FGL_ARTIFICIAL [[gnu::artificial]]
#define FGL_HOT [[gnu::hot]]

View File

@@ -6,7 +6,6 @@
#include "camera/Camera.hpp"
#include "camera/CameraSwapchain.hpp"
#include "rendering/pipelines/Pipeline.hpp"
namespace fgl::engine
{
@@ -21,7 +20,7 @@ namespace fgl::engine
return camera->getDescriptor( frame_idx );
}
void FrameInfo::bindCamera( [[maybe_unused]] internal::Pipeline& pipeline )
void FrameInfo::bindCamera( [[maybe_unused]] Pipeline& pipeline )
{
//TODO: This
}

View File

@@ -4,8 +4,6 @@
#pragma once
#include <vulkan/vulkan.h>
//clang-format: off
#include <tracy/TracyVulkan.hpp>
//clang-format: on
@@ -13,13 +11,13 @@
#include "descriptors/Descriptor.hpp"
#include "descriptors/DescriptorSetLayout.hpp"
#include "primitives/Frustum.hpp"
#include "rendering/pipelines/Pipeline.hpp"
#include "rendering/types.hpp"
#define MAX_LIGHTS 10
namespace fgl::engine
{
class Pipeline;
class GameObject;
namespace descriptors
@@ -102,7 +100,7 @@ namespace fgl::engine
std::vector< std::vector< GameObject >* > in_view_leafs {};
//! Binds the camera descriptor to the command buffer
void bindCamera( internal::Pipeline& pipeline );
void bindCamera( Pipeline& pipeline );
};
} // namespace fgl::engine

View File

@@ -1,33 +0,0 @@
//
// Created by kj16609 on 12/7/23.
//
#pragma once
#include <vulkan/vulkan.hpp>
#include <vulkan/vulkan_raii.hpp>
namespace fgl::engine
{
template < typename T, vk::ShaderStageFlags stages, std::uint16_t offset = 0 >
struct PushConstant
{
using Type = T;
constexpr static vk::PushConstantRange m_range { stages, offset, sizeof( T ) };
PushConstant()
{
static_assert( sizeof( T ) <= 128, "Push constant range size must be less or equal to 128 bytes" );
}
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 );
}
};
} // namespace fgl::engine

View File

@@ -26,10 +26,16 @@ namespace fgl::engine::profiling
counters.verts_drawn += n;
}
void addInstances( std::size_t n )
{
counters.instance_count += n;
}
void resetCounters()
{
counters.verts_drawn = 0;
counters.models_draw = 0;
counters.instance_count = 0;
}
// In order for resetCounters to work we need to ensure we can just zero the struct.

View File

@@ -12,12 +12,14 @@ namespace fgl::engine::profiling
{
std::size_t verts_drawn;
std::size_t models_draw;
std::size_t instance_count;
};
Counters& getCounters();
void addModelDrawn( std::size_t n = 1 );
void addVertexDrawn( std::size_t n );
void addInstances( std::size_t n = 1 );
void resetCounters();

View File

@@ -31,7 +31,9 @@ namespace fgl::engine::filesystem
nested_dirs_to_scan.push( *itter );
}
else
throw std::runtime_error( "Unknown/Unspported file type" );
{
log::debug( "Weird file at {}", itter->path().string() );
}
}
nested_dirs.reserve( nested_dirs_to_scan.size() );

29
src/engine/flags.cpp Normal file
View File

@@ -0,0 +1,29 @@
//
// Created by kj16609 on 10/18/24.
//
#include "flags.hpp"
#include "engine/debug/logging/logging.hpp"
namespace fgl::engine::flags
{
static bool should_reload_shaders { false };
void triggerShaderReload()
{
log::debug( "Triggering shader reload" );
should_reload_shaders = true;
}
bool shouldReloadShaders()
{
return should_reload_shaders;
}
void resetFlags()
{
should_reload_shaders = false;
}
} // namespace fgl::engine::flags

18
src/engine/flags.hpp Normal file
View File

@@ -0,0 +1,18 @@
//
// Created by kj16609 on 10/18/24.
//
// This file is supposed to contain various global flags used by the program
#pragma once
namespace fgl::engine::flags
{
void triggerShaderReload();
bool shouldReloadShaders();
//! Resets any flags that can be reset after the frame is done
void resetFlags();
} // namespace fgl::engine::flags

View File

@@ -108,7 +108,7 @@ namespace fgl::engine
for ( ComponentEngineInterface* comp : components )
{
if ( comp->id() == T::ID ) temp.emplace_back( dynamic_cast< T* >( comp ) );
if ( comp->id() == T::ID ) temp.emplace_back( static_cast< T* >( comp ) );
}
return temp;

View File

@@ -1,89 +0,0 @@
//
// Created by kj16609 on 11/27/23.
//
#include "Pipeline.hpp"
#include <fstream>
#include "Shader.hpp"
#include "engine/rendering/devices/Device.hpp"
namespace fgl::engine::internal
{
vk::raii::Pipeline Pipeline::createGraphicsPipeline(
std::vector< std::unique_ptr< Shader > >& shaders,
const PipelineConfigInfo& info,
const vk::raii::PipelineLayout& layout )
{
assert( info.render_pass != VK_NULL_HANDLE && "Cannot create graphics pipeline: no render pass provided" );
std::vector< vk::PipelineShaderStageCreateInfo > stages {};
for ( const auto& shader : shaders )
{
stages.emplace_back( shader->stage_info );
}
assert( stages.size() >= 2 );
auto& binding_descriptions { info.binding_descriptions };
auto& attribute_descriptions { info.attribute_descriptions };
vk::PipelineVertexInputStateCreateInfo vertex_input_info {};
vertex_input_info.pNext = VK_NULL_HANDLE;
vertex_input_info.flags = {};
vertex_input_info.vertexBindingDescriptionCount = static_cast< std::uint32_t >( binding_descriptions.size() );
vertex_input_info.pVertexBindingDescriptions = binding_descriptions.data();
vertex_input_info.vertexAttributeDescriptionCount =
static_cast< std::uint32_t >( attribute_descriptions.size() );
vertex_input_info.pVertexAttributeDescriptions = attribute_descriptions.data();
vk::GraphicsPipelineCreateInfo pipeline_info {};
pipeline_info.pNext = VK_NULL_HANDLE;
pipeline_info.flags = {};
pipeline_info.stageCount = static_cast< std::uint32_t >( stages.size() );
pipeline_info.pStages = stages.data();
pipeline_info.pVertexInputState = &vertex_input_info;
pipeline_info.pInputAssemblyState = &info.assembly_info;
pipeline_info.pTessellationState = &info.tesselation_state_info;
pipeline_info.pViewportState = &info.viewport_info;
pipeline_info.pRasterizationState = &info.rasterization_info;
pipeline_info.pMultisampleState = &info.multisample_info;
pipeline_info.pDepthStencilState = &info.depth_stencil_info;
pipeline_info.pColorBlendState = &info.color_blend_info;
pipeline_info.pDynamicState = &info.dynamic_state_info;
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;
return m_device->createGraphicsPipeline( VK_NULL_HANDLE, pipeline_info );
}
Pipeline::Pipeline(
Device& device,
vk::raii::PipelineLayout layout,
PipelineConfigInfo info,
std::vector< std::unique_ptr< Shader > > shaders ) :
m_device( device ),
m_layout( std::move( layout ) ),
m_vk_pipeline( createGraphicsPipeline( shaders, info, m_layout ) )
{}
void Pipeline::bind( vk::raii::CommandBuffer& command_buffer )
{
command_buffer.bindPipeline( vk::PipelineBindPoint::eGraphics, m_vk_pipeline );
}
void Pipeline::setDebugName( const std::string str )
{
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 ) );
Device::getInstance().setDebugUtilsObjectName( info );
}
} // namespace fgl::engine::internal

View File

@@ -1,51 +0,0 @@
//
// Created by kj16609 on 11/27/23.
//
#pragma once
#include <filesystem>
#include <vector>
#include "PipelineConfigInfo.hpp"
namespace fgl::engine
{
class Device;
struct Shader;
}
namespace fgl::engine::internal
{
class Pipeline
{
protected:
Device& m_device;
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 };
vk::raii::Pipeline createGraphicsPipeline(
std::vector< std::unique_ptr< Shader > >& shaders,
const PipelineConfigInfo& info,
const vk::raii::PipelineLayout& layout );
public:
Pipeline(
Device& device,
vk::raii::PipelineLayout layout,
PipelineConfigInfo info,
std::vector< std::unique_ptr< Shader > > shaders );
Pipeline( const Pipeline& other ) = delete;
Pipeline& operator=( const Pipeline& ) = delete;
void bind( vk::raii::CommandBuffer& command_buffer );
void setDebugName( const std::string str );
};
} // namespace fgl::engine::internal

View File

@@ -1,174 +0,0 @@
//
// Created by kj16609 on 12/14/23.
//
#include "PipelineConfigInfo.hpp"
#include "engine/assets/model/Model.hpp"
namespace fgl::engine
{
void PipelineConfigInfo::setTriangleListTopo( PipelineConfigInfo& info )
{
info.assembly_info.topology = vk::PrimitiveTopology::eTriangleList;
}
void PipelineConfigInfo::setTriangleStripTopo( PipelineConfigInfo& info )
{
info.assembly_info.topology = vk::PrimitiveTopology::eTriangleStrip;
}
void PipelineConfigInfo::setLineTopo( PipelineConfigInfo& info )
{
info.assembly_info.topology = vk::PrimitiveTopology::eLineList;
}
void PipelineConfigInfo::setPointPatch( PipelineConfigInfo& info )
{
info.assembly_info.topology = vk::PrimitiveTopology::ePatchList;
}
void PipelineConfigInfo::defaultConfig( PipelineConfigInfo& info )
{
info.viewport_info.viewportCount = 1;
info.viewport_info.pViewports = nullptr;
info.viewport_info.scissorCount = 1;
info.viewport_info.pScissors = nullptr;
info.assembly_info.topology = vk::PrimitiveTopology::eTriangleList;
info.assembly_info.primitiveRestartEnable = VK_FALSE;
info.rasterization_info.depthClampEnable = VK_FALSE;
info.rasterization_info.rasterizerDiscardEnable = VK_FALSE;
info.rasterization_info.polygonMode = vk::PolygonMode::eFill;
info.rasterization_info.cullMode = vk::CullModeFlagBits::eBack;
info.rasterization_info.frontFace = vk::FrontFace::eClockwise;
info.rasterization_info.depthBiasEnable = VK_FALSE;
info.rasterization_info.depthBiasConstantFactor = 0.0f;
info.rasterization_info.depthBiasClamp = 0.0f;
info.rasterization_info.depthBiasSlopeFactor = 0.0f;
info.rasterization_info.lineWidth = 1.0f;
info.multisample_info.rasterizationSamples = vk::SampleCountFlagBits::e1;
info.multisample_info.sampleShadingEnable = VK_FALSE;
info.multisample_info.minSampleShading = 1.0f;
info.multisample_info.pSampleMask = nullptr;
info.multisample_info.alphaToCoverageEnable = VK_FALSE;
info.multisample_info.alphaToOneEnable = VK_FALSE;
info.color_blend_info.logicOpEnable = VK_FALSE;
info.color_blend_info.logicOp = vk::LogicOp::eCopy;
info.color_blend_info.attachmentCount = 0;
info.color_blend_info.pAttachments = nullptr;
info.color_blend_info.blendConstants[ 0 ] = 0.0f;
info.color_blend_info.blendConstants[ 1 ] = 0.0f;
info.color_blend_info.blendConstants[ 2 ] = 0.0f;
info.color_blend_info.blendConstants[ 3 ] = 0.0f;
info.depth_stencil_info.depthTestEnable = VK_TRUE;
info.depth_stencil_info.depthWriteEnable = VK_TRUE;
info.depth_stencil_info.depthCompareOp = vk::CompareOp::eLess;
info.depth_stencil_info.depthBoundsTestEnable = VK_FALSE;
info.depth_stencil_info.stencilTestEnable = VK_FALSE;
//info.depth_stencil_info.front = {};
//info.depth_stencil_info.back = {};
info.depth_stencil_info.minDepthBounds = 0.0f;
info.depth_stencil_info.maxDepthBounds = 1.0f;
info.dynamic_state_enables = { vk::DynamicState::eViewport, vk::DynamicState::eScissor };
info.dynamic_state_info.pDynamicStates = info.dynamic_state_enables.data();
info.dynamic_state_info.dynamicStateCount = static_cast< std::uint32_t >( info.dynamic_state_enables.size() );
//info.dynamic_state_info.flags = 0;
info.binding_descriptions = ModelVertex::getBindingDescriptions();
info.attribute_descriptions = ModelVertex::getAttributeDescriptions();
}
void PipelineConfigInfo::setVertexInputType( PipelineConfigInfo& info, const VertexInputType type )
{
switch ( type )
{
case None:
disableVertexInput( info );
break;
case Simple:
{
info.binding_descriptions = SimpleVertex::getBindingDescriptions();
info.attribute_descriptions = SimpleVertex::getAttributeDescriptions();
}
break;
case Textured:
{
info.binding_descriptions = ModelVertex::getBindingDescriptions();
info.attribute_descriptions = ModelVertex::getAttributeDescriptions();
}
break;
default:;
}
}
void PipelineConfigInfo::disableVertexInput( PipelineConfigInfo& info )
{
info.binding_descriptions = {};
info.attribute_descriptions = {};
}
void PipelineConfigInfo::enableAlphaBlending( PipelineConfigInfo& info )
{
for ( std::size_t i = 0; i < info.color_blend_attachment.size(); ++i )
{
info.color_blend_attachment[ i ].blendEnable = VK_TRUE;
info.color_blend_attachment[ i ].srcColorBlendFactor = vk::BlendFactor::eSrcAlpha;
info.color_blend_attachment[ i ].dstColorBlendFactor = vk::BlendFactor::eOne;
info.color_blend_attachment[ i ].colorBlendOp = vk::BlendOp::eAdd;
info.color_blend_attachment[ i ].srcAlphaBlendFactor = vk::BlendFactor::eOne;
info.color_blend_attachment[ i ].dstAlphaBlendFactor = vk::BlendFactor::eZero;
info.color_blend_attachment[ i ].alphaBlendOp = vk::BlendOp::eAdd;
info.color_blend_attachment[ i ].colorWriteMask =
vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB
| vk::ColorComponentFlagBits::eA;
}
}
void PipelineConfigInfo::addColorAttachmentConfig( PipelineConfigInfo& info )
{
vk::PipelineColorBlendAttachmentState state;
state.blendEnable = VK_FALSE;
state.srcColorBlendFactor = vk::BlendFactor::eOne;
state.dstColorBlendFactor = vk::BlendFactor::eZero;
state.colorBlendOp = vk::BlendOp::eAdd;
state.srcAlphaBlendFactor = vk::BlendFactor::eOne;
state.dstAlphaBlendFactor = vk::BlendFactor::eZero;
state.alphaBlendOp = vk::BlendOp::eAdd;
state.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG
| vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA;
info.color_blend_attachment.emplace_back( state );
info.color_blend_info.pAttachments = info.color_blend_attachment.data();
info.color_blend_info.attachmentCount = static_cast< std::uint32_t >( info.color_blend_attachment.size() );
}
void PipelineConfigInfo::addGBufferAttachmentsConfig( PipelineConfigInfo& config )
{
for ( int i = 0; i < 3; ++i ) addColorAttachmentConfig( config );
}
void PipelineConfigInfo::disableCulling( PipelineConfigInfo& info )
{
info.rasterization_info.cullMode = vk::CullModeFlagBits::eNone;
}
PipelineConfigInfo::PipelineConfigInfo( vk::raii::RenderPass& pass )
{
render_pass = pass;
defaultConfig( *this );
}
void PipelineConfigInfo::setQuadTesselation( PipelineConfigInfo& info )
{
info.tesselation_state_info.patchControlPoints = 4;
}
} // namespace fgl::engine

View File

@@ -1,71 +0,0 @@
//
// Created by kj16609 on 12/14/23.
//
#pragma once
#include <vulkan/vulkan.hpp>
#include <vulkan/vulkan_raii.hpp>
#include <cstdint>
#include <vector>
#include "engine/FGL_DEFINES.hpp"
namespace fgl::engine
{
enum VertexInputType
{
None,
Simple,
Textured
};
struct PipelineConfigInfo
{
vk::PipelineViewportStateCreateInfo viewport_info {};
vk::PipelineInputAssemblyStateCreateInfo assembly_info {};
vk::PipelineTessellationStateCreateInfo tesselation_state_info {};
vk::PipelineTessellationDomainOriginStateCreateInfo tesselation_domain_info {};
vk::PipelineRasterizationStateCreateInfo rasterization_info {};
vk::PipelineMultisampleStateCreateInfo multisample_info {};
std::vector< vk::PipelineColorBlendAttachmentState > color_blend_attachment {};
vk::PipelineColorBlendStateCreateInfo color_blend_info {};
vk::PipelineDepthStencilStateCreateInfo depth_stencil_info {};
std::vector< vk::DynamicState > dynamic_state_enables {};
vk::PipelineDynamicStateCreateInfo dynamic_state_info {};
vk::RenderPass render_pass { VK_NULL_HANDLE };
std::uint32_t subpass { 0 };
std::vector< vk::VertexInputBindingDescription > binding_descriptions {};
std::vector< vk::VertexInputAttributeDescription > attribute_descriptions {};
FGL_DELETE_COPY( PipelineConfigInfo )
PipelineConfigInfo( vk::raii::RenderPass& pass );
PipelineConfigInfo& operator=( PipelineConfigInfo&& other ) = default;
PipelineConfigInfo( PipelineConfigInfo&& other ) = default;
static void setVertexInputType( PipelineConfigInfo& info, const VertexInputType type );
static void disableVertexInput( PipelineConfigInfo& info );
static void setTriangleListTopo( PipelineConfigInfo& info );
static void setTriangleStripTopo( PipelineConfigInfo& info );
static void setLineTopo( PipelineConfigInfo& info );
static void setQuadTesselation( PipelineConfigInfo& info );
static void setPointPatch( PipelineConfigInfo& info );
static void defaultConfig( PipelineConfigInfo& info );
static void enableAlphaBlending( PipelineConfigInfo& config );
static void disableCulling( PipelineConfigInfo& info );
static void addColorAttachmentConfig( PipelineConfigInfo& info );
static void addGBufferAttachmentsConfig( PipelineConfigInfo& config );
};
} // namespace fgl::engine

View File

@@ -45,7 +45,8 @@ namespace fgl::engine
}
Shader::Shader( const std::filesystem::path& path, const vk::PipelineShaderStageCreateInfo& info ) :
shader_data( loadData( path ) ),
m_path( path ),
shader_data( loadData( m_path ) ),
module_create_info( createModuleInfo() ),
stage_info( info ),
shader_module( Device::getInstance()->createShaderModule( module_create_info ) )
@@ -69,4 +70,13 @@ namespace fgl::engine
return shader;
}
void Shader::reload()
{
log::debug( "Reloading shader at {}", m_path.string() );
shader_data = loadData( m_path );
module_create_info = createModuleInfo();
shader_module = Device::getInstance()->createShaderModule( module_create_info );
stage_info.module = shader_module;
}
} // namespace fgl::engine

View File

@@ -14,6 +14,7 @@ namespace fgl::engine
struct Shader
{
std::filesystem::path m_path;
std::vector< std::byte > shader_data;
vk::ShaderModuleCreateInfo module_create_info;
vk::PipelineShaderStageCreateInfo stage_info;
@@ -44,6 +45,9 @@ namespace fgl::engine
{
return loadShader( path, vk::ShaderStageFlagBits::eFragment );
}
//! Reloads the shader from disk
void reload();
};
} // namespace fgl::engine

View File

@@ -31,7 +31,7 @@ namespace fgl::engine
void AttachmentBuilder::finish()
{
parent.config.color_blend_attachment.emplace_back( color_blend_config );
parent.state->color_blend_attachment.emplace_back( color_blend_config );
m_finished = true;
}

View File

@@ -6,17 +6,32 @@
#include "PipelineBuilder.hpp"
#include "engine/descriptors/DescriptorSet.hpp"
#include "engine/flags.hpp"
namespace fgl::engine
{
Pipeline::Pipeline( vk::raii::Pipeline&& pipeline_in, vk::raii::PipelineLayout&& layout ) :
vk::raii::Pipeline Pipeline::rebuildPipeline()
{
return PipelineBuilder::rebuildFromState( *m_builder_state, m_layout );
}
Pipeline::Pipeline(
vk::raii::Pipeline&& pipeline_in,
vk::raii::PipelineLayout&& layout,
std::unique_ptr< PipelineBuilder::BuilderState >&& builder_state ) :
m_pipeline( std::move( pipeline_in ) ),
m_layout( std::move( layout ) )
m_layout( std::move( layout ) ),
m_builder_state( std::forward< std::unique_ptr< PipelineBuilder::BuilderState > >( builder_state ) )
{}
void Pipeline::bind( vk::raii::CommandBuffer& cmd_buffer )
{
if ( flags::shouldReloadShaders() )
{
m_pipeline = rebuildPipeline();
}
cmd_buffer.bindPipeline( vk::PipelineBindPoint::eGraphics, m_pipeline );
}

View File

@@ -2,8 +2,10 @@
// Created by kj16609 on 10/9/24.
//
#pragma once
#include "PipelineBuilder.hpp"
#include "engine/descriptors/DescriptorSet.hpp"
#include "engine/rendering/pipelines/Pipeline.hpp"
namespace fgl::engine
@@ -17,18 +19,32 @@ namespace fgl::engine
{
vk::raii::Pipeline m_pipeline;
vk::raii::PipelineLayout m_layout;
std::unique_ptr< PipelineBuilder::BuilderState > m_builder_state;
vk::raii::Pipeline rebuildPipeline();
public:
Pipeline() = delete;
Pipeline( vk::raii::Pipeline&& pipeline, vk::raii::PipelineLayout&& layout );
Pipeline(
vk::raii::Pipeline&& pipeline_in,
vk::raii::PipelineLayout&& layout,
std::unique_ptr< PipelineBuilder::BuilderState >&& builder_state );
void bind( vk::raii::CommandBuffer& );
void bindDescriptor( vk::raii::CommandBuffer&, descriptors::DescriptorIDX descriptor_idx, descriptors::DescriptorSet& set );
void bindDescriptor(
vk::raii::CommandBuffer&, descriptors::DescriptorIDX descriptor_idx, descriptors::DescriptorSet& set );
void bindDescriptor( vk::raii::CommandBuffer& comd_buffer, descriptors::DescriptorSet& set );
void setDebugName( const char* str );
template < typename T >
requires std::is_trivially_copyable_v< T >
void pushConstant( vk::raii::CommandBuffer& command_buffer, vk::ShaderStageFlags stage, const T& t )
{
command_buffer.pushConstants< T >( m_layout, stage, 0, { t } );
}
};
} // namespace fgl::engine

View File

@@ -12,26 +12,37 @@ namespace fgl::engine
{
PipelineBuilder::PipelineBuilder( vk::raii::RenderPass& renderpass, const std::uint32_t subpass_stage ) :
m_render_pass( renderpass ),
subpass_idx( subpass_stage )
state( std::make_unique< BuilderState >( renderpass, subpass_stage ) )
{
addDynamicState( vk::DynamicState::eViewport );
addDynamicState( vk::DynamicState::eScissor );
}
void PipelineBuilder::setVertexShader( std::shared_ptr< Shader >&& shader )
{
state->shaders.vertex = std::forward< std::shared_ptr< Shader > >( shader );
}
void PipelineBuilder::setFragmentShader( std::shared_ptr< Shader >&& shader )
{
state->shaders.fragment = std::forward< std::shared_ptr< Shader > >( shader );
}
descriptors::DescriptorSetLayout empty_set_layout { descriptors::DescriptorSetLayout::createEmptySet() };
vk::raii::PipelineLayout PipelineBuilder::createLayout()
{
vk::PipelineLayoutCreateInfo info {};
if ( state->push_constant.size > 0 ) info.setPushConstantRanges( state->push_constant );
std::vector< vk::DescriptorSetLayout > set_layouts {};
set_layouts.reserve( descriptor_set_layouts.size() );
set_layouts.reserve( state->descriptor_set_layouts.size() );
SetID max_set_idx { 0 };
for ( const auto& [ set_idx, _ ] : descriptor_set_layouts )
for ( const auto& [ set_idx, _ ] : state->descriptor_set_layouts )
{
max_set_idx = std::max( max_set_idx, set_idx );
}
@@ -41,8 +52,8 @@ namespace fgl::engine
for ( std::size_t i = 0; i < set_layouts.size(); ++i )
{
auto itter { descriptor_set_layouts.find( static_cast< SetID >( i ) ) };
if ( itter == descriptor_set_layouts.end() )
auto itter { state->descriptor_set_layouts.find( static_cast< SetID >( i ) ) };
if ( itter == state->descriptor_set_layouts.end() )
{
// Could not find it. Empty
set_layouts[ i ] = empty_set_layout.layout();
@@ -55,7 +66,7 @@ namespace fgl::engine
}
}
for ( const auto& [ set_idx, layout ] : descriptor_set_layouts )
for ( const auto& [ set_idx, layout ] : state->descriptor_set_layouts )
{
set_layouts[ set_idx ] = layout;
}
@@ -68,8 +79,8 @@ namespace fgl::engine
void PipelineBuilder::
addDescriptorSet( const SetID idx, const vk::raii::DescriptorSetLayout& descriptor_set_layout )
{
FGL_ASSERT( !descriptor_set_layouts.contains( idx ), "Descriptor already set!" );
descriptor_set_layouts.insert( std::make_pair( idx, *descriptor_set_layout ) );
FGL_ASSERT( !state->descriptor_set_layouts.contains( idx ), "Descriptor already set!" );
state->descriptor_set_layouts.insert( std::make_pair( idx, *descriptor_set_layout ) );
}
void PipelineBuilder::addDescriptorSet( descriptors::DescriptorSetLayout& descriptor )
@@ -79,17 +90,24 @@ namespace fgl::engine
void PipelineBuilder::addDynamicState( vk::DynamicState dynamic_state )
{
m_dynamic_state.emplace_back( dynamic_state );
state->m_dynamic_state.emplace_back( dynamic_state );
}
[[nodiscard]] vk::PipelineColorBlendAttachmentState& PipelineBuilder::Config::addColorAttachment()
void PipelineBuilder::setPushConstant( const vk::ShaderStageFlags flags, std::size_t size )
{
state->push_constant.offset = 0;
state->push_constant.size = size;
state->push_constant.stageFlags = flags;
}
[[nodiscard]] vk::PipelineColorBlendAttachmentState& PipelineBuilder::BuilderState::addColorAttachment()
{
color_blend_attachment.emplace_back();
color_blend_info.setAttachments( color_blend_attachment );
return color_blend_attachment.back();
}
PipelineBuilder::Config::Config()
void PipelineBuilder::BuilderState::setDefault()
{
viewport_info.viewportCount = 1;
viewport_info.pViewports = nullptr;
@@ -143,18 +161,18 @@ namespace fgl::engine
void PipelineBuilder::setTopology( const vk::PrimitiveTopology primitive_topology )
{
config.assembly_info.topology = primitive_topology;
state->assembly_info.topology = primitive_topology;
}
void PipelineBuilder::disableVertexInput()
{
vertex_input_descriptions.bindings = {};
vertex_input_descriptions.attributes = {};
state->vertex_input_descriptions.bindings = {};
state->vertex_input_descriptions.attributes = {};
}
void PipelineBuilder::disableCulling()
{
config.rasterization_info.cullMode = vk::CullModeFlagBits::eNone;
state->rasterization_info.cullMode = vk::CullModeFlagBits::eNone;
}
AttachmentBuilder PipelineBuilder::addAttachment()
@@ -170,74 +188,91 @@ namespace fgl::engine
void PipelineBuilder::setBindingDescriptions( const std::vector< vk::VertexInputBindingDescription >& descriptions )
{
vertex_input_descriptions.bindings = descriptions;
state->vertex_input_descriptions.bindings = descriptions;
}
void PipelineBuilder::setAttributeDescriptions( const std::vector< vk::VertexInputAttributeDescription >&
descriptions )
{
vertex_input_descriptions.attributes = descriptions;
state->vertex_input_descriptions.attributes = descriptions;
}
std::unique_ptr< Pipeline > PipelineBuilder::create()
vk::raii::Pipeline PipelineBuilder::createFromState( BuilderState& state, vk::raii::PipelineLayout& layout )
{
// Precheck
{
FGL_ASSERT( shaders.fragment, "Pipeline requires fragment shader" );
FGL_ASSERT( shaders.vertex, "Pipeline requires vertex shader" );
}
vk::raii::PipelineLayout layout { createLayout() };
vk::GraphicsPipelineCreateInfo info {};
info.pNext = VK_NULL_HANDLE;
info.flags = {};
m_stages.clear();
state.m_stages.clear();
if ( shaders.vertex ) m_stages.emplace_back( shaders.vertex->stage_info );
if ( shaders.fragment ) m_stages.emplace_back( shaders.fragment->stage_info );
if ( state.shaders.vertex ) state.m_stages.emplace_back( state.shaders.vertex->stage_info );
if ( state.shaders.fragment ) state.m_stages.emplace_back( state.shaders.fragment->stage_info );
info.setStages( m_stages );
info.setStages( state.m_stages );
vk::PipelineVertexInputStateCreateInfo vertex_input_info {};
vertex_input_info.pNext = VK_NULL_HANDLE;
vertex_input_info.flags = {};
vertex_input_info.setVertexBindingDescriptions( vertex_input_descriptions.bindings );
vertex_input_info.setVertexAttributeDescriptions( vertex_input_descriptions.attributes );
vertex_input_info.setVertexBindingDescriptions( state.vertex_input_descriptions.bindings );
vertex_input_info.setVertexAttributeDescriptions( state.vertex_input_descriptions.attributes );
info.setPVertexInputState( &vertex_input_info );
info.pInputAssemblyState = &config.assembly_info;
info.pTessellationState = &config.tesselation_state_info;
info.pViewportState = &config.viewport_info;
info.pRasterizationState = &config.rasterization_info;
info.pMultisampleState = &config.multisample_info;
info.pDepthStencilState = &config.depth_stencil_info;
info.pInputAssemblyState = &state.assembly_info;
info.pTessellationState = &state.tesselation_state_info;
info.pViewportState = &state.viewport_info;
info.pRasterizationState = &state.rasterization_info;
info.pMultisampleState = &state.multisample_info;
info.pDepthStencilState = &state.depth_stencil_info;
config.color_blend_info.setAttachments( config.color_blend_attachment );
state.color_blend_info.setAttachments( state.color_blend_attachment );
info.pColorBlendState = &config.color_blend_info;
info.pDynamicState = &config.dynamic_state_info;
info.pColorBlendState = &state.color_blend_info;
info.pDynamicState = &state.dynamic_state_info;
info.layout = layout;
info.renderPass = m_render_pass;
info.subpass = subpass_idx;
info.renderPass = state.m_render_pass;
info.subpass = state.m_subpass_stage;
//TODO: Figure out what these do
info.basePipelineHandle = VK_NULL_HANDLE;
info.basePipelineIndex = -1;
vk::PipelineDynamicStateCreateInfo dynamic_state_create_info {};
dynamic_state_create_info.setDynamicStates( m_dynamic_state );
dynamic_state_create_info.setDynamicStates( state.m_dynamic_state );
if ( m_dynamic_state.size() > 0 ) info.setPDynamicState( &dynamic_state_create_info );
if ( state.m_dynamic_state.size() > 0 ) info.setPDynamicState( &dynamic_state_create_info );
vk::raii::Pipeline pipeline { Device::getInstance()->createGraphicsPipeline( VK_NULL_HANDLE, info ) };
return std::make_unique< Pipeline >( std::move( pipeline ), std::move( layout ) );
return pipeline;
}
void setGBufferOutputAttachments( PipelineBuilder::Config& config )
vk::raii::Pipeline PipelineBuilder::rebuildFromState( BuilderState& state, vk::raii::PipelineLayout& layout )
{
auto& shaders { state.shaders };
if ( shaders.vertex ) shaders.vertex->reload();
if ( shaders.fragment ) shaders.fragment->reload();
return createFromState( state, layout );
}
std::unique_ptr< Pipeline > PipelineBuilder::create()
{
// Precheck
{
FGL_ASSERT( state->shaders.fragment, "Pipeline requires fragment shader" );
FGL_ASSERT( state->shaders.vertex, "Pipeline requires vertex shader" );
}
vk::raii::PipelineLayout layout { createLayout() };
vk::raii::Pipeline pipeline { createFromState( *state, layout ) };
return std::make_unique< Pipeline >( std::move( pipeline ), std::move( layout ), std::move( state ) );
}
void setGBufferOutputAttachments( PipelineBuilder::BuilderState& config )
{
// In order for the pipeline to output, We need to ensure that we have enough attachments for the entire gbuffer (3)

View File

@@ -2,6 +2,8 @@
// Created by kj16609 on 10/10/24.
//
#pragma once
#include <vulkan/vulkan_raii.hpp>
#include <cstdint>
@@ -22,26 +24,7 @@ namespace fgl::engine
class PipelineBuilder
{
vk::raii::RenderPass& m_render_pass;
std::uint32_t subpass_idx;
struct
{
std::vector< vk::VertexInputBindingDescription > bindings {};
std::vector< vk::VertexInputAttributeDescription > attributes {};
} vertex_input_descriptions {};
struct
{
std::shared_ptr< Shader > vertex { nullptr };
std::shared_ptr< Shader > fragment { nullptr };
} shaders {};
std::vector< vk::PipelineShaderStageCreateInfo > m_stages {};
std::vector< vk::DynamicState > m_dynamic_state {};
using SetID = std::uint32_t;
std::unordered_map< SetID, vk::DescriptorSetLayout > descriptor_set_layouts {};
vk::raii::PipelineLayout createLayout();
@@ -50,11 +33,33 @@ namespace fgl::engine
void addDescriptorSet( SetID idx, const vk::raii::DescriptorSetLayout& descriptor_set_layout );
void addDescriptorSet( descriptors::DescriptorSetLayout& descriptor );
void addDynamicState( vk::DynamicState dynamic_state );
void setPushConstant( vk::ShaderStageFlags flags, std::size_t size );
PipelineBuilder() = delete;
struct Config
struct BuilderState
{
vk::raii::RenderPass& m_render_pass;
std::uint32_t m_subpass_stage;
vk::PushConstantRange push_constant {};
std::vector< vk::PipelineShaderStageCreateInfo > m_stages {};
std::vector< vk::DynamicState > m_dynamic_state {};
struct
{
std::vector< vk::VertexInputBindingDescription > bindings {};
std::vector< vk::VertexInputAttributeDescription > attributes {};
} vertex_input_descriptions {};
struct
{
std::shared_ptr< Shader > vertex { nullptr };
std::shared_ptr< Shader > fragment { nullptr };
} shaders {};
std::unordered_map< SetID, vk::DescriptorSetLayout > descriptor_set_layouts {};
vk::PipelineViewportStateCreateInfo viewport_info {};
vk::PipelineInputAssemblyStateCreateInfo assembly_info {};
vk::PipelineTessellationStateCreateInfo tesselation_state_info {};
@@ -71,10 +76,20 @@ namespace fgl::engine
std::vector< vk::DynamicState > dynamic_state_enables {};
vk::PipelineDynamicStateCreateInfo dynamic_state_info {};
// Default config
Config();
vk::PipelineLayoutCreateInfo layout_info {};
} config {};
// Default config
void setDefault();
BuilderState( vk::raii::RenderPass& renderpass, const std::size_t subpass_stage ) :
m_render_pass( renderpass ),
m_subpass_stage( subpass_stage )
{
setDefault();
}
};
std::unique_ptr< BuilderState > state;
void setTopology( vk::PrimitiveTopology primitive_topology );
void disableVertexInput();
@@ -84,28 +99,23 @@ namespace fgl::engine
[[nodiscard]] AttachmentBuilder addAttachment();
[[nodiscard]] AttachmentBuilder addColorAttachment();
vk::PipelineLayoutCreateInfo layout_info {};
void setBindingDescriptions( const std::vector< vk::VertexInputBindingDescription >& descriptions );
void setAttributeDescriptions( const std::vector< vk::VertexInputAttributeDescription >& descriptions );
PipelineBuilder( vk::raii::RenderPass& renderpass, std::uint32_t subpass_stage );
void setVertexShader( std::shared_ptr< Shader >&& shader )
{
shaders.vertex = std::forward< std::shared_ptr< Shader > >( shader );
}
void setVertexShader( std::shared_ptr< Shader >&& shader );
void setFragmentShader( std::shared_ptr< Shader >&& shader )
{
shaders.fragment = std::forward< std::shared_ptr< Shader > >( shader );
}
void setFragmentShader( std::shared_ptr< Shader >&& shader );
static vk::raii::Pipeline createFromState( BuilderState& state, vk::raii::PipelineLayout& layout );
static vk::raii::Pipeline rebuildFromState( BuilderState& state, vk::raii::PipelineLayout& layout );
std::unique_ptr< Pipeline > create();
};
//! Adds the GBuffer output attachments to the config for the given pipeline
void setGBufferOutputAttachments( PipelineBuilder::Config& config );
void setGBufferOutputAttachments( PipelineBuilder::BuilderState& config );
} // namespace fgl::engine

View File

@@ -4,6 +4,8 @@
#include "CompositionSystem.hpp"
#include "Control.hpp"
#include "editor/src/gui/safe_include.hpp"
#include "engine/camera/Camera.hpp"
#include "engine/rendering/pipelines/v2/AttachmentBuilder.hpp"
#include "engine/rendering/pipelines/v2/Pipeline.hpp"
@@ -23,6 +25,8 @@ namespace fgl::engine
builder.addColorAttachment().finish();
builder.setPushConstant( vk::ShaderStageFlagBits::eFragment, sizeof( CompositionControl ) );
builder.setVertexShader( Shader::loadVertex( "shaders/fullscreen.vert" ) );
builder.setFragmentShader( Shader::loadFragment( "shaders/composition.frag" ) );
@@ -48,6 +52,14 @@ namespace fgl::engine
m_composite_pipeline->bindDescriptor( command_buffer, info.getGBufferDescriptor() );
m_composite_pipeline->bindDescriptor( command_buffer, info.getCameraDescriptor() );
ImGui::Begin( "Composition" );
ImGui::InputInt( "Selection", &m_control.flags );
ImGui::End();
m_composite_pipeline->pushConstant( command_buffer, vk::ShaderStageFlagBits::eFragment, m_control );
return info.command_buffer;
}

View File

@@ -4,6 +4,7 @@
#pragma once
#include "Control.hpp"
#include "engine/FrameInfo.hpp"
#include "engine/systems/concepts.hpp"
@@ -17,6 +18,8 @@ namespace fgl::engine
vk::raii::CommandBuffer& setupSystem( FrameInfo& info );
CompositionControl m_control {};
public:
CompositionSystem( vk::raii::RenderPass& render_pass );

View File

@@ -0,0 +1,28 @@
//
// Created by kj16609 on 10/18/24.
//
#pragma once
#include <cstdint>
namespace fgl::engine
{
struct CompositionControl
{
enum Values
{
OutColor = 0,
LoRender = 1,
Normal = 2,
CosLo = 3,
F0 = 4,
DirectLighting = 5,
Ambient = 6,
Lh = 7,
MAX
};
int flags { 0 };
};
} // namespace fgl::engine

View File

@@ -15,12 +15,6 @@ namespace fgl::engine
GuiSystem::GuiSystem( vk::raii::RenderPass& render_pass )
{
PipelineConfigInfo info { render_pass };
PipelineConfigInfo::addColorAttachmentConfig( info );
PipelineConfigInfo::disableVertexInput( info );
PipelineConfigInfo::disableCulling( info );
info.subpass = 0;
//descriptors::DescriptorSetCollection descriptors { gui_descriptor_set };
PipelineBuilder builder { render_pass, 0 };
@@ -56,9 +50,6 @@ namespace fgl::engine
auto& command_buffer { setupSystem( info ) };
command_buffer.draw( 3, 1, 0, 0 );
//Handle GUI
// gui::drawMainGUI( info );
}
} // namespace fgl::engine

View File

@@ -10,6 +10,7 @@
#include "engine/assets/model/Model.hpp"
#include "engine/debug/drawers.hpp"
#include "engine/debug/profiling/counters.hpp"
#include "engine/gameobjects/components/ModelComponent.hpp"
#include "engine/tree/octtree/OctTreeNode.hpp"
@@ -87,6 +88,8 @@ namespace fgl::engine
assert( primitive.m_index_buffer.size() > 0 );
profiling::addVertexDrawn( primitive.m_index_buffer.size() );
if ( auto itter = draw_pairs.find( key ); itter != draw_pairs.end() )
{
ZoneScopedN( "Accumulate for draw pair" );

View File

@@ -164,6 +164,7 @@ namespace fgl::engine
m_textured_pipeline->bindDescriptor( command_buffer, Material::getDescriptorSet() );
profiling::addModelDrawn( model_matricies.size() );
profiling::addInstances( draw_commands.size() );
auto& model_matrix_info_buffer { m_textured_model_matrix_info_buffers[ info.frame_idx ] };
model_matrix_info_buffer =

View File

@@ -1,40 +0,0 @@
file(GLOB_RECURSE SHADERS
"${CMAKE_CURRENT_SOURCE_DIR}/**.frag"
"${CMAKE_CURRENT_SOURCE_DIR}/**.vert"
"${CMAKE_CURRENT_SOURCE_DIR}/**.tesc"
"${CMAKE_CURRENT_SOURCE_DIR}/**.tese"
"${CMAKE_CURRENT_SOURCE_DIR}/**.glsl"
)
foreach (SHADER IN LISTS SHADERS)
get_filename_component(FILENAME ${SHADER} NAME)
get_filename_component(FILE_DIRECTORY ${SHADER} DIRECTORY)
file(RELATIVE_PATH REL_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${FILE_DIRECTORY})
if (NOT REL_PATH STREQUAL "")
set(REL_PATH ${REL_PATH}/)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bin/shaders/${REL_PATH})
endif ()
set(OUT_DIR ${CMAKE_BINARY_DIR}/bin/shaders/${REL_PATH})
set(OUT_PATH ${OUT_DIR}${FILENAME})
#add_custom_command(OUTPUT ${OUT_DIR}
# COMMAND ${CMAKE_COMMAND} -E make_directory ${OUT_DIR} COMMENT "Creating directory ${OUT_DIR}")
#add_custom_command(OUTPUT ${OUT_PATH}
# COMMAND ${Vulkan_GLSLC_EXECUTABLE} ${SHADER_DEBUG_FLAGS} ${SHADER} -o ${OUT_PATH} DEPENDS ${SHADER} ${OUT_DIR}
# COMMENT "Compiling ${SHADER} ")
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/bin/shaders/${FILENAME}
COMMAND ${CMAKE_COMMAND} -E copy ${SHADER} ${OUT_PATH} DEPENDS ${SHADER}
COMMENT "Copying ${ASSET} to ${OUT_PATH}")
list(APPEND SPV_SHADERS ${CMAKE_BINARY_DIR}/bin/shaders/${FILENAME})
list(APPEND ADDITIONAL_CLEAN_FILES ${OUT_PATH})
endforeach ()
add_custom_target(shaders ALL DEPENDS ${SPV_SHADERS})

View File

@@ -17,6 +17,10 @@ layout (set = 1, binding = 0) uniform CameraInfo {
mat4 inverse_view;
} camera_info;
layout(push_constant) uniform Constants {
uint flags;
} push;
//TODO: uniform binding with sun information
vec3 getCameraPosition()
@@ -55,9 +59,10 @@ float gaSchlickGGX(float cosLi, float cosLo, float roughness)
return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k);
}
//TODO: Apparently this can be gotten from a texture instead?
vec3 schlick(vec3 F0, float cosTheta)
{
return F0 + (vec3(1.0) - F0) * pow(1.0 - cosTheta, 5.0);
return F0 + (vec3(1.0) - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
}
void main()
@@ -96,28 +101,77 @@ void main()
vec3 direct_lighting = vec3(0.0);
// Do this for each light
{
vec3 Li = -sun_dir;
vec3 Lradiance = vec3(1.0);// color?
// {
vec3 Li = -sun_dir;
vec3 Lradiance = vec3(1.0);// color?
// half vector
vec3 Lh = normalize(Li + Lo);
// half vector
vec3 Lh = normalize(Li + Lo);
float cosLi = max(dot(N, Li), 0.0);
float cosLh = max(dot(N, Lh), 0.0);
float cosLi = max(dot(N, Li), 0.0);
float cosLh = max(dot(N, Lh), 0.0);
vec3 F = schlick(F0, max(dot(Lh, Lo), 0.0));
float D = ndfGGX(cosLh, roughness_value);
float G = gaSchlickGGX(cosLi, cosLo, roughness_value);
vec3 F = schlick(F0, max(dot(Lh, Lo), 0.0));
float D = ndfGGX(cosLh, roughness_value);
float G = gaSchlickGGX(cosLi, cosLo, roughness_value);
vec3 kb = mix(vec3(1.0) - F, vec3(0.0), metallic_value);
vec3 diffuse_BRDF = kb * albedo;
vec3 specular_BRDF = (F * D * G) / max(0.04, 4.0 * cosLi * cosLo);
vec3 kb = mix(vec3(1.0) - F, vec3(0.0), metallic_value);
vec3 diffuse_BRDF = kb * albedo;
vec3 specular_BRDF = (F * D * G) / max(0.04, 4.0 * cosLi * cosLo);
direct_lighting = (diffuse_BRDF + specular_BRDF) * Lradiance * cosLi;
}
direct_lighting = (diffuse_BRDF + specular_BRDF) * Lradiance * cosLi;
// }
vec3 ambient_lighting = albedo * 0.1;
out_color = vec4(direct_lighting + ambient_lighting, 1.0);
switch (push.flags)
{
case 0:
out_color = vec4(direct_lighting + ambient_lighting, 1.0);
return;
case 1:
out_color = vec4(Lo, 1.0);
return;
case 2:
out_color = vec4(N, 1.0);
return;
case 3:
out_color = vec4(cosLo, 0.0, 0.0, 1.0);
return;
case 4:
out_color = vec4(F0, 1.0);
return;
case 5:
out_color = vec4(direct_lighting, 1.0);
return;
case 6:
out_color = vec4(ambient_lighting, 1.0);
return;
case 7:
out_color = vec4(Lh, 1.0);
return;
case 8:
out_color = vec4(cosLi, 0.0, 0.0, 1.0);
return;
case 9:
out_color = vec4(cosLh, 0.0, 0.0, 1.0);
return;
case 10:
out_color = vec4(F, 1.0);
return;
case 11:
out_color = vec4(D, 0.0, 0.0, 1.0);
return;
case 12:
out_color = vec4(G, 0.0, 0.0, 1.0);
return;
case 13:
out_color = vec4(kb, 1.0);
return;
case 14:
out_color = vec4(max(dot(Lh, Lo), 0.0));
return;
}
out_color = vec4(0.0, 0.0, 0.0, 1.0);
}