#pragma once #include #include #include #include #include #include #include #include "Gpu.hpp" #include "props.hpp" #include "Resource.hpp" #include "Recording.hpp" #include #include namespace lft::rg { class ImageResourceDescription { private: std::string m_name; VkFormat m_format; VkExtent2D m_extent; VkClearValue m_clear_value; bool m_is_color; public: REF(m_name, name); GET(m_format, format); GET(m_extent, extent); GET(m_clear_value, clear_value); GET(m_is_color, is_color); inline void set_extent(VkExtent2D extent) { m_extent = extent; } ImageResourceDescription( const std::string& name, VkFormat format, VkExtent2D extent, VkClearValue clear_value, bool is_color ) : m_name(name), m_format(format), m_extent(extent), m_clear_value(clear_value), m_is_color(is_color) { } bool equals(const ImageResourceDescription& other) const { return m_name == other.m_name && m_format == other.m_format && m_extent.width == other.m_extent.width && m_extent.height == other.m_extent.height && m_clear_value.color.uint32[0] == other.m_clear_value.color.uint32[0] && m_clear_value.color.uint32[1] == other.m_clear_value.color.uint32[1] && m_clear_value.color.uint32[2] == other.m_clear_value.color.uint32[2] && m_clear_value.color.uint32[3] == other.m_clear_value.color.uint32[3] && m_clear_value.depthStencil.depth == other.m_clear_value.depthStencil.depth; } }; struct BufferResourceDescription { private: std::string m_name; VkDeviceSize m_size; public: REF(m_name, name); GET(m_size, size); BufferResourceDescription( const std::string& name, VkDeviceSize size ) : m_name(name), m_size(size) { } bool equals(const BufferResourceDescription& other) const { return m_name == other.m_name && m_size == other.m_size; } }; class TaskRecordInfo { const Gpu* m_gpu; lft::Recording m_recording; uint32_t m_buffer_idx; uint32_t m_image_idx; VkViewport m_viewport; public: GET(m_gpu, gpu); REF(m_recording, recording); GET(m_image_idx, image_idx); GET(m_buffer_idx, buffer_idx); GET(m_viewport, viewport); TaskRecordInfo( const Gpu* gpu, lft::Recording recording, uint32_t buffer_idx, uint32_t image_in_flight_idx, VkViewport viewport) : m_recording(recording), m_image_idx(image_in_flight_idx), m_buffer_idx(buffer_idx), m_gpu(gpu), m_viewport(viewport) { } }; class TaskBuildInfo { const Gpu* m_gpu; uint32_t m_buffer_idx; uint32_t m_num_buffers; VkViewport m_viewport; VkRenderPass m_renderpass; std::unordered_map m_resources; public: GET(m_gpu, gpu); GET(m_num_buffers, num_buffers); GET(m_buffer_idx, buffer_idx); GET(m_viewport, viewport); GET(m_renderpass, renderpass); inline ImageResource get_resource( const std::string& name ) const { return m_resources.find(name)->second; } TaskBuildInfo( const Gpu* gpu, uint32_t buffer_idx, uint32_t num_buffers, VkViewport viewport, VkRenderPass renderpass, std::unordered_map resources) : m_gpu(gpu), m_buffer_idx(buffer_idx), m_num_buffers(num_buffers), m_viewport(viewport), m_renderpass(renderpass), m_resources(resources) { } }; enum TaskType { GRAPHICS_TASK, COMPUTE_TASK, RAY_TRACING_TASK }; struct TaskInfo { typedef std::function TaskBuildFunc; typedef std::function TaskRecordFunc; std::string m_name; TaskType m_type; void *m_pContext; TaskBuildFunc m_build_func; TaskRecordFunc m_record_func; std::vector m_dependencies; std::vector m_recording_dependencies; std::vector m_buffer_outputs; std::vector m_color_outputs; std::optional m_depth_output; bool m_is_output_to_final; VkExtent2D m_extent; REF(m_name, name); GET(m_type, type); REF(m_build_func, build_func); REF(m_record_func, record_func); REF(m_dependencies, dependencies); REF(m_recording_dependencies, recording_dependencies); REF(m_buffer_outputs, buffer_outputs); REF(m_color_outputs, color_outputs); REF(m_depth_output, depth_output); GET(m_is_output_to_final, is_output_to_final); TaskInfo() { } template TaskInfo(const std::string& name, TaskType type, T *pContext, std::function build_func, std::function record_func ) : m_name(name), m_type(type), m_pContext(pContext), m_build_func(build_func), m_record_func(record_func), m_extent(0, 0) { } bool has_output(const std::string& name) const { if(m_depth_output.has_value() && m_depth_output->name() == name) { return true; } if(std::any_of(m_buffer_outputs.begin(), m_buffer_outputs.end(), [name](const BufferResourceDescription& output) { return output.name() == name; })) { return true; } if(std::any_of(m_color_outputs.begin(), m_color_outputs.end(), [name](const ImageResourceDescription& output) { return output.name() == name; })) { return true; } return false; } TaskInfo& add_color_output(const std::string& name, VkFormat format, VkExtent2D extent, VkClearColorValue clear_value) { m_color_outputs.emplace_back(name, format, extent, VkClearValue { .color = clear_value }, true); return *this; } TaskInfo& set_depth_output( const std::string& name, VkFormat format, VkExtent2D extent, VkClearDepthStencilValue clear_value ) { m_depth_output = ImageResourceDescription(name, format, extent, VkClearValue { .depthStencil = clear_value }, false); return *this; } TaskInfo& add_dependency(const std::string& dependency) { m_dependencies.emplace_back(dependency); return *this; } TaskInfo& add_recording_dependency(const std::string& dependency) { m_recording_dependencies.emplace_back(dependency); return *this; } TaskInfo& set_extent(VkExtent2D extent) { m_extent = extent; return *this; } bool equals(const TaskInfo& other) const { if(this->name() != other.name()) { std::cout << "Names are not the same: " << name() << " != " << other.name() << std::endl; return false; } if(this->m_type != other.m_type) { std::cout << "Task types are not the same: " << m_type << " != " << other.m_type << std::endl; return false; } if(m_dependencies != other.m_dependencies) { std::cout << "Dependencies are different" << std::endl; return false; } if(m_buffer_outputs.size() != other.m_buffer_outputs.size()) { return false; } for(uint32_t i = 0; i < m_buffer_outputs.size(); i++) { auto output = other.m_buffer_outputs[i]; auto found = std::find_if( m_buffer_outputs.begin(), m_buffer_outputs.end(), [output](const BufferResourceDescription& desc) { return output.equals(desc); }); if(found == other.m_buffer_outputs.end()) { std::cout << "Missing buffer output: " << output.name() << std::endl; return false; } } for(uint32_t i = 0; i < m_color_outputs.size(); i++) { auto output = other.m_color_outputs[i]; auto found = std::find_if( m_color_outputs.begin(), m_color_outputs.end(), [output](const ImageResourceDescription& desc) { return output.equals(desc); }); if(found == other.m_color_outputs.end()) { std::cout << "Missing color output: " << output.name() << std::endl; return false; } } if(m_depth_output.has_value() != other.m_depth_output.has_value()) { std::cout << "Depth output differ" << std::endl; return false; } if(m_depth_output.has_value() && !m_depth_output->equals(other.m_depth_output.value())) { std::cout << "Depth output differ" << std::endl; return false; } if(m_extent.width != other.m_extent.width || m_extent.height != other.m_extent.height) { std::cout << std::format("Extent differ: [{},{}] != [{},{}]", m_extent.width, m_extent.height, other.m_extent.width, other.m_extent.height) << std::endl; return false; } return true; } }; class ComputeTaskBuilder { private: TaskInfo m_task_info; public: ComputeTaskBuilder(const std::string& name, void *pContext, std::function build_func, std::function record_func ) : m_task_info(name, COMPUTE_TASK, pContext, build_func, record_func) { } ComputeTaskBuilder& add_buffer_output(const std::string& name, VkDeviceSize size) { m_task_info.m_buffer_outputs.emplace_back(name, size); return *this; } ComputeTaskBuilder& add_dependency(const std::string& dependency) { m_task_info.m_dependencies.emplace_back(dependency); return *this; } ComputeTaskBuilder& add_recording_dependency(const std::string& dependency) { m_task_info.m_recording_dependencies.emplace_back(dependency); return *this; } TaskInfo build() { return m_task_info; } }; class RenderTaskBuilder { private: TaskInfo m_task_info; public: RenderTaskBuilder(const std::string& name, void* pContext, std::function build_func, std::function record_func ) : m_task_info(name, GRAPHICS_TASK, pContext, build_func, record_func) { } RenderTaskBuilder& add_color_output(const std::string& name, VkFormat format, VkExtent2D extent = VkExtent2D(0.0f, 0.0f), VkClearColorValue clear_value = {0.0f, 0.0f, 0.0f, 0.0f}) { m_task_info.m_color_outputs.emplace_back(name, format, extent, VkClearValue { .color = clear_value }, true); return *this; } RenderTaskBuilder& set_depth_output( const std::string& name, VkFormat format, VkExtent2D extent = VkExtent2D(0.0f, 0.0f), VkClearDepthStencilValue clear_value = {1.0f, 0} ) { m_task_info.m_depth_output = ImageResourceDescription(name, format, extent, VkClearValue { .depthStencil = clear_value }, false); return *this; } RenderTaskBuilder& set_output_to_final() { m_task_info.m_is_output_to_final = true; return *this; } RenderTaskBuilder& add_dependency(const std::string& dependency) { m_task_info.m_dependencies.emplace_back(dependency); return *this; } RenderTaskBuilder& add_recording_dependency(const std::string& dependency) { m_task_info.m_recording_dependencies.emplace_back(dependency); return *this; } RenderTaskBuilder& set_extent(VkExtent2D extent) { m_task_info.m_extent = extent; return *this; } TaskInfo build() { return m_task_info; } }; template RenderTaskBuilder render_task(const std::string& name, T* pContext, std::function build_func, std::function record_func ) { return RenderTaskBuilder(name, (void*)pContext, [build_func, pContext](const TaskBuildInfo& info, void* ctx) { build_func(info, pContext); }, [record_func, pContext](const TaskRecordInfo& info, void* ctx) { record_func(info, pContext); }); } template ComputeTaskBuilder compute_task(const std::string& name, T* pContext, std::function build_func, std::function record_func ) { return ComputeTaskBuilder(name, (void*)pContext, [build_func, pContext](const TaskBuildInfo& info, void* ctx) { build_func(info, pContext); }, [record_func, pContext](const TaskRecordInfo& info, void* ctx) { record_func(info, pContext); }); } }