Skip to content

Commit

Permalink
[*] WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
IAmNotHanni committed Apr 11, 2024
1 parent f249425 commit 9a92d2e
Show file tree
Hide file tree
Showing 13 changed files with 135 additions and 88 deletions.
7 changes: 6 additions & 1 deletion include/inexor/vulkan-renderer/imgui.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,17 @@
#include <memory>
#include <vector>

// Forward declarations
namespace inexor::vulkan_renderer::wrapper {
// Forward declarations
class Device;
class Shader;
} // namespace inexor::vulkan_renderer::wrapper

namespace inexor::vulkan_renderer::render_graph {
// Forward declaration
class RenderGraph;
} // namespace inexor::vulkan_renderer::render_graph

namespace inexor::vulkan_renderer {

/// A wrapper for an ImGui implementation
Expand Down
22 changes: 16 additions & 6 deletions include/inexor/vulkan-renderer/render-graph/buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ enum class BufferType {
class Buffer {
private:
friend class RenderGraph;
friend class GraphicsPass;
friend class wrapper::CommandBuffer;

/// The device wrapper
const wrapper::Device &m_device;
Expand All @@ -40,7 +38,7 @@ class Buffer {
/// The buffer type
BufferType m_type;
/// An optional update function to update the data of the buffer resource
std::function<void()> m_on_update{[]() {}};
std::optional<std::function<void()>> m_on_update{std::nullopt};
/// If this is true, an update can only be carried out with the use of staging buffers
bool m_requires_staging_buffer_update{false};

Expand All @@ -63,15 +61,15 @@ class Buffer {
/// @param new_buffer_size The new size of the buffer
void recreate_buffer(VkDeviceSize new_buffer_size);

public:
/// Default constructor
/// @param device The device wrapper
/// @param name The internal debug name of the buffer (must not be empty)
/// @param usage The internal usage of the buffer in the rendergraph
/// @note The update frequency of a buffer will only be respected when grouping uniform buffers into descriptor sets
/// @param on_update An optional update function (``std::nullopt`` by default, meaning no updates to this buffer)
Buffer(const wrapper::Device &device, std::string name, BufferType type, std::function<void()> on_update);

public:
Buffer(const wrapper::Device &device, std::string name, BufferType type,
std::optional<std::function<void()>> on_update);
Buffer(const Buffer &) = delete;
Buffer(Buffer &&other) noexcept;
~Buffer();
Expand Down Expand Up @@ -117,6 +115,18 @@ class Buffer {
void request_update(std::vector<BufferDataType> &data) {
return request_update(data.data(), sizeof(data) * data.size());
}

[[nodiscard]] auto &buffer() const {
return m_buffer;
}

[[nodiscard]] auto &name() const {
return m_name;
}

[[nodiscard]] auto type() const {
return m_type;
}
};

} // namespace inexor::vulkan_renderer::render_graph
23 changes: 14 additions & 9 deletions include/inexor/vulkan-renderer/render-graph/render_graph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ namespace inexor::vulkan_renderer::render_graph {
enum class BufferType;
class PushConstantRangeResource;

// Namespaces
using namespace wrapper::pipelines;

/// A rendergraph is a generic solution for rendering architecture
/// This is based on Yuriy O'Donnell's talk "FrameGraph: Extensible Rendering Architecture in Frostbite" from GDC 2017
/// Also check out Hans-Kristian Arntzen's blog post "Render graphs and Vulkan - a deep dive" (2017) and
Expand Down Expand Up @@ -69,17 +72,17 @@ class RenderGraph {
wrapper::pipelines::GraphicsPipelineBuilder m_graphics_pipeline_builder;

/// The callables which create the graphics pipelines used in the rendergraph
using GraphicsPipelineCreateCallable = std::function<std::shared_ptr<wrapper::pipelines::GraphicsPipeline>(
using GraphicsPipelineCreateCallable = std::function<std::shared_ptr<GraphicsPipeline>(
wrapper::pipelines::GraphicsPipelineBuilder &, const VkPipelineLayout)>;

/// The callables to create the graphics pipelines used in the rendergraph
std::vector<GraphicsPipelineCreateCallable> m_on_graphics_pipeline_create_callables;

std::vector<std::unique_ptr<wrapper::pipelines::PipelineLayout>> m_graphics_pipeline_layouts;
std::vector<std::unique_ptr<PipelineLayout>> m_graphics_pipeline_layouts;

/// The graphics pipelines used in the rendergraph
/// This will be populated using m_on_graphics_pipeline_create_callables
std::vector<std::shared_ptr<wrapper::pipelines::GraphicsPipeline>> m_graphics_pipelines;
std::vector<std::shared_ptr<GraphicsPipeline>> m_graphics_pipelines;

// TODO: Support compute pipelines and compute passes

Expand Down Expand Up @@ -145,6 +148,9 @@ class RenderGraph {
/// @note If a uniform buffer has been updated, an update of the associated descriptor set will be performed
void update_buffers();

/// Update dynamic textures
void update_textures();

/// Update the descriptor sets
void update_descriptor_sets();

Expand All @@ -171,18 +177,17 @@ class RenderGraph {
/// Add a buffer (vertex, index, or uniform buffer) resource to the rendergraph
/// @param name The internal name of the buffer resource (must not be empty)
/// @param type The internal buffer usage of the buffer
/// @param category The estimated descriptor set category depending on the update frequency of the buffer
/// @note The update frequency of a buffer will be respected when grouping uniform buffers into descriptor sets
/// @param on_update A buffer resource update function
/// @param on_update An optional buffer resource update function (``std::nullopt`` by default)
/// @note Not every buffer must have an update function because index buffers should be updated with vertex buffers
/// @exception std::runtime_error Internal debug name is empty
/// @return A weak pointer to the buffer resource that was just created
[[nodiscard]] std::weak_ptr<Buffer> add_buffer(std::string name, BufferType type, std::function<void()> on_update);
[[nodiscard]] std::weak_ptr<Buffer> add_buffer(std::string name, BufferType type,
std::optional<std::function<void()>> on_update = std::nullopt);

/// Add a new graphics pass to the rendergraph
/// @param on_pass_create A callable to create the graphics pass using GraphicsPassBuilder
void add_graphics_pass(GraphicsPassCreateCallable on_pass_create) {
// TODO: Can this be emplace_back?
m_on_graphics_pass_create_callables.push_back(std::move(on_pass_create));
m_on_graphics_pass_create_callables.emplace_back(std::move(on_pass_create));
}

/// Add a new graphics pipeline to the rendergraph
Expand Down
17 changes: 9 additions & 8 deletions include/inexor/vulkan-renderer/render-graph/texture.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@

namespace inexor::vulkan_renderer::render_graph {

// Forward declaration
class RenderGraph;
enum class DescriptorSetUpdateFrequencyGroup;

/// Specifies the use of the texture inside of the rendergraph
enum class TextureUsage {
/// Specifies that this texture is the output of the render graph
Expand All @@ -27,13 +23,14 @@ enum class TextureUsage {
NORMAL,
};

// TODO: Implement texture updates and use DescriptorSetUpdateFrequencyGroup
// Forward declaration
class RenderGraph;

/// Wrapper for texture resources in the rendergraph
class Texture {
private:
friend RenderGraph;

private:
std::string m_name;
TextureUsage m_usage;
VkFormat m_format{VK_FORMAT_UNDEFINED};
Expand All @@ -45,15 +42,19 @@ class Texture {
std::uint32_t m_height{0};
std::uint32_t m_channels{0};
std::uint32_t m_mip_levels{0};
std::optional<std::function<void()>> m_on_update{[]() {}};

std::optional<std::function<void()>> m_on_init{std::nullopt};
std::optional<std::function<void()>> m_on_update{std::nullopt};

public:
/// Default constructor
/// @param name The internal denug name of the texture inside of the rendergraph (must not be empty)
/// @param usage The internal usage of the texture inside of the rendergraph
/// @param format The format of the texture
/// @param on_init The init function of the texture
/// @param on_update An optional update function (``std::nullopt`` by default, meaning no updates to this buffer)
Texture(std::string name, TextureUsage usage, VkFormat format, std::optional<std::function<void()>> on_update);
Texture(std::string name, TextureUsage usage, VkFormat format, std::optional<std::function<void()>> on_init,
std::optional<std::function<void()>> on_update);

Texture(const Texture &) = delete;
Texture(Texture &&other) noexcept;
Expand Down
2 changes: 1 addition & 1 deletion include/inexor/vulkan-renderer/wrapper/command_buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ class CommandBuffer {
/// Call vkCmdInsertDebugUtilsLabelEXT
/// @param name The name of the debug label to insert
/// @return A const reference to the dereferenced ``this`` pointer (allowing for method calls to be chained)
const CommandBuffer &insert_debug_label(std::string name, float color[4]) const;
const CommandBuffer &insert_debug_label(std::string name, std::array<float, 4> color) const;

/// Call vkCmdPushConstants
/// @param layout The pipeline layout
Expand Down
6 changes: 6 additions & 0 deletions include/inexor/vulkan-renderer/wrapper/pipelines/pipeline.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,19 @@ class CommandBuffer;
class Device;
} // namespace inexor::vulkan_renderer::wrapper

namespace inexor::vulkan_renderer::render_graph {
// Forward declaration
class RenderGraph;
} // namespace inexor::vulkan_renderer::render_graph

namespace inexor::vulkan_renderer::wrapper::pipelines {

/// RAII wrapper for VkPipeline
// TODO: Compute pipelines
class GraphicsPipeline {
// The CommandBuffer wrapper needs to access m_pipeline
friend CommandBuffer;
friend render_graph::RenderGraph;

private:
const Device &m_device;
Expand Down
18 changes: 14 additions & 4 deletions src/vulkan-renderer/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -454,16 +454,15 @@ void Application::setup_render_graph() {
});

// Note that the index buffer is updated together with the vertex buffer to keep data consistent
// TODO: FIX ME!
m_index_buffer = m_render_graph->add_buffer("Octree", BufferType::INDEX_BUFFER, [] {});
m_index_buffer = m_render_graph->add_buffer("Octree", BufferType::INDEX_BUFFER);

// Update the vertex buffer and index buffer at initialization
// Note that we update the vertex buffer together with the index buffer to keep data consistent
m_vertex_buffer.lock()->request_update(m_octree_vertices);
m_index_buffer.lock()->request_update(m_octree_indices);

m_uniform_buffer = m_render_graph->add_buffer("Matrices", BufferType::UNIFORM_BUFFER, [&]() {
// The m_mvp_matrices.model matrix doesn't need to be updated
// The model matrix is constant and doesn't need to be updated
m_mvp_matrices.view = m_camera->view_matrix();
m_mvp_matrices.proj = m_camera->perspective_matrix();
m_mvp_matrices.proj[1][1] *= -1;
Expand Down Expand Up @@ -516,7 +515,6 @@ void Application::setup_render_graph() {
})
.set_depth_test(true)
.set_on_record([&](const wrapper::CommandBuffer &cmd_buf) {
// Render octree
cmd_buf.bind_pipeline(*m_octree_pipeline)
.bind_vertex_buffer(m_vertex_buffer)
.bind_index_buffer(m_index_buffer)
Expand All @@ -533,6 +531,18 @@ void Application::setup_render_graph() {
}

void Application::setup_window_and_input_callbacks() {
// The following code requires some explanation
// Because glfw is a C-style API, we can't use a pointer to non-static class methods as window or input callbacks.
// For example, we can't use Application::key_callback in glfwSetKeyCallback as key callback directly.
// A good explanation can be found on Stack Overflow:
// https://stackoverflow.com/questions/7676971/pointing-to-a-function-that-is-a-class-member-glfw-setkeycallback
// In order to fix this, we can pass a lambda to glfwSetKeyCallback, which calls Application::key_callback
// internally. But there is another problem: Inside of the template, we need to call Application::Key_callback. In
// order to do so, we need to have access to the this-pointer. Unfortunately, the this-pointer can't be captured
// in the lambda capture like [this](){}, because the glfw would not accept the lambda then. To work around this
// problem, we store the this pointer using glfwSetWindowUserPointer. Inside of these lambdas, we then cast the
// pointer to Application* again, allowing us to finally use the callbacks.

m_window->set_user_ptr(this);

spdlog::trace("Setting up window callback:");
Expand Down
7 changes: 5 additions & 2 deletions src/vulkan-renderer/render-graph/buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

namespace inexor::vulkan_renderer::render_graph {

Buffer::Buffer(const wrapper::Device &device, std::string name, const BufferType type, std::function<void()> on_update)
Buffer::Buffer(const wrapper::Device &device, std::string name, const BufferType type,
std::optional<std::function<void()>> on_update)
: m_device(device), m_name(std::move(name)), m_type(type), m_on_update(std::move(on_update)) {
// Uniform buffer can be updated by std::memcpy, other types of memory require staging buffer updates
m_requires_staging_buffer_update = (type != BufferType::UNIFORM_BUFFER);
Expand Down Expand Up @@ -47,13 +48,14 @@ void Buffer::create_buffer(const VkDeviceSize buffer_size, const VkBufferUsageFl
throw VulkanException("Error: vmaCreateBuffer failed for buffer " + m_name + " !", result);
}

// We are basically storing things duplicately here, but whatever
m_buf_usage = buffer_usage;
m_mem_usage = memory_usage;

// Set the buffer's internal debug name in Vulkan Memory Allocator (VMA)
vmaSetAllocationName(m_device.allocator(), m_alloc, m_name.c_str());

// Set the buffer's internal denug name through Vulkan debug utils
// Set the buffer's internal debug name through Vulkan debug utils
m_device.set_debug_name(m_buffer, m_name);
}

Expand All @@ -66,6 +68,7 @@ void Buffer::destroy_buffer() {

void Buffer::recreate_buffer(const VkDeviceSize new_buffer_size) {
destroy_buffer();
// We are basically storing things duplicately here, but whatever
create_buffer(new_buffer_size, m_buf_usage, m_mem_usage);
}

Expand Down
2 changes: 1 addition & 1 deletion src/vulkan-renderer/render-graph/graphics_pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ GraphicsPass::GraphicsPass(std::string name, BufferReads buffer_reads, TextureRe
bool index_buffer_present = false;
for (const auto buffer : m_buffer_reads) {
// Is this buffer resource an index buffer?
if (buffer.first.lock()->m_type == BufferType::INDEX_BUFFER) {
if (buffer.first.lock()->type() == BufferType::INDEX_BUFFER) {
// Is an index buffer already specified?
if (index_buffer_present) {
throw std::runtime_error("Error: More than one index buffer in graphics pass " + m_name + "!");
Expand Down
6 changes: 0 additions & 6 deletions src/vulkan-renderer/render-graph/graphics_pass_builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,6 @@ std::shared_ptr<GraphicsPass> GraphicsPassBuilder::build(std::string name) {
std::move(m_clear_value));
}

/*
GraphicsPass(std::string name, BufferReads buffer_reads, TextureReads texture_reads, TextureWrites texture_writes,
std::function<void(const wrapper::CommandBuffer &)> on_record,
std::optional<VkClearValue> clear_values);
*/

void GraphicsPassBuilder::reset() {
m_clear_value = std::nullopt;
m_on_record = [](auto &) {};
Expand Down
Loading

0 comments on commit 9a92d2e

Please sign in to comment.