Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 141 additions & 0 deletions VkRenderer/postprocess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,28 @@ void PostProcessor::init(VulkanEngine *engine) {
_compositorData.useRayTracer = 0;
_compositorData.exposure = 4.0f;
_compositorData.showGrid = 0;
_compositorData.useFXAA = 0; // TODO: Keeping this on by default doesnt load because of rt accell structure
// validation error. Should debug this later.

// init FXAA data
_fxaaData.R_inverseFilterTextureSize =
glm::vec3(1.0f / engine->_windowExtent.width, 1.0f / engine->_windowExtent.height, 0.0f);
_fxaaData.R_fxaaSpanMax = 8.0f;
_fxaaData.R_fxaaReduceMin = 1.0f / 128.0f;
_fxaaData.R_fxaaReduceMul = 1.0f / 8.0f;

_fullscreenImage = vkutil::create_image(
engine, VkExtent3D{engine->_windowExtent.width, engine->_windowExtent.height, 1}, VK_FORMAT_R32G32B32A32_SFLOAT,
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT,
false, "Post Process Image");

_fxaaImage = vkutil::create_image(engine, VkExtent3D{engine->_windowExtent.width, engine->_windowExtent.height, 1},
VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
false, "FXAA Image");

// Create a sampler for the image
VkSamplerCreateInfo samplerInfo{};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
Expand Down Expand Up @@ -88,6 +103,62 @@ void PostProcessor::init(VulkanEngine *engine) {
vkDestroyShaderModule(engine->_device, fullscreenDrawFragShader, nullptr);
vkDestroyShaderModule(engine->_device, fullscreenDrawVertShader, nullptr);

// FXAA PIPELINE
{
DescriptorLayoutBuilder fxaaBuilder;
fxaaBuilder.add_binding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
fxaaBuilder.add_binding(1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
_fxaaDescriptorSetLayout = fxaaBuilder.build(engine->_device, VK_SHADER_STAGE_FRAGMENT_BIT);
}

// allocate a descriptor set for our FXAA input
_fxaaDescriptorSet = engine->globalDescriptorAllocator.allocate(engine->_device, _fxaaDescriptorSetLayout);

engine->_mainDeletionQueue.push_function(
[=] { vkDestroyDescriptorSetLayout(engine->_device, _fxaaDescriptorSetLayout, nullptr); });

VkPipelineLayoutCreateInfo fxaa_layout_info{};
fxaa_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
fxaa_layout_info.pNext = nullptr;
fxaa_layout_info.setLayoutCount = 1;
fxaa_layout_info.pSetLayouts = &_fxaaDescriptorSetLayout;

VK_CHECK(vkCreatePipelineLayout(engine->_device, &fxaa_layout_info, nullptr, &_fxaaPipelineLayout));

engine->_mainDeletionQueue.push_function(
[=] { vkDestroyPipelineLayout(engine->_device, _fxaaPipelineLayout, nullptr); });

// FXAA shaders
VkShaderModule fxaaVertShader;
if (!vkutil::load_shader_module("Fullscreen.vert.spv", engine->_device, &fxaaVertShader)) {
spdlog::error("Error when building the FXAA Vertex shader");
}
VkShaderModule fxaaFragShader;
if (!vkutil::load_shader_module("FXAA.frag.spv", engine->_device, &fxaaFragShader)) {
spdlog::error("Error when building the FXAA Fragment shader");
}

// Build FXAA pipeline
PipelineBuilder fxaaPipelineBuilder;
fxaaPipelineBuilder.set_shaders(fxaaVertShader, fxaaFragShader);
fxaaPipelineBuilder.set_input_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
fxaaPipelineBuilder.set_polygon_mode(VK_POLYGON_MODE_FILL);
fxaaPipelineBuilder.set_cull_mode(VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE);
fxaaPipelineBuilder.set_multisampling_none();
fxaaPipelineBuilder.enable_depthtest(false, VK_COMPARE_OP_GREATER_OR_EQUAL);

// render format
fxaaPipelineBuilder.add_color_attachment(_fxaaImage.imageFormat, PipelineBuilder::BlendMode::NO_BLEND);

// use the FXAA layout we created
fxaaPipelineBuilder._pipelineLayout = _fxaaPipelineLayout;

// create the pipeline
_fxaaPipeline = fxaaPipelineBuilder.build_pipeline(engine->_device);

vkDestroyShaderModule(engine->_device, fxaaFragShader, nullptr);
vkDestroyShaderModule(engine->_device, fxaaVertShader, nullptr);

// GRID PIPELINE
{
DescriptorLayoutBuilder gridBuilder;
Expand Down Expand Up @@ -140,9 +211,11 @@ void PostProcessor::init(VulkanEngine *engine) {

engine->_mainDeletionQueue.push_function([=] {
vkDestroyPipeline(engine->_device, _postProcessPipeline, nullptr);
vkDestroyPipeline(engine->_device, _fxaaPipeline, nullptr);
vkDestroyPipeline(engine->_device, _gridPipeline, nullptr);
vkDestroySampler(engine->_device, _fullscreenImageSampler, nullptr);
vkutil::destroy_image(engine, _fullscreenImage);
vkutil::destroy_image(engine, _fxaaImage);
});
}

Expand Down Expand Up @@ -220,6 +293,74 @@ void PostProcessor::draw(VulkanEngine *engine, VkCommandBuffer cmd) {
vkCmdEndRendering(cmd);
}

void PostProcessor::draw_fxaa(VulkanEngine *engine, VkCommandBuffer cmd) {
VkClearValue clearVal = {.color = {0.0f, 0.0f, 0.0f, 1.0f}};

std::array<VkRenderingAttachmentInfo, 1> colorAttachments = {
vkinit::attachment_info(_fxaaImage.imageView, &clearVal, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL),
};

// Pass the color attachments directly to rendering_info
VkRenderingInfo renderInfo = vkinit::rendering_info(engine->_windowExtent,
colorAttachments.data(), // Pass your color attachments directly
nullptr // No depth attachment
);

vkCmdBeginRendering(cmd, &renderInfo);

_fxaaDescriptorSet =
engine->get_current_frame()._frameDescriptors.allocate(engine->_device, _fxaaDescriptorSetLayout);

// Allocate a new uniform buffer for the FXAA data
AllocatedBuffer fxaaDataBuffer = vkutil::create_buffer(engine, sizeof(FXAAData), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
VMA_MEMORY_USAGE_CPU_TO_GPU, "FXAA Data Buffer");

// Add it to the deletion queue
engine->get_current_frame()._deletionQueue.push_function([=] { vkutil::destroy_buffer(engine, fxaaDataBuffer); });

// Write the FXAA data
FXAAData *fxaaUniformBuffer;
VK_CHECK(
vmaMapMemory(engine->_allocator, fxaaDataBuffer.allocation, reinterpret_cast<void **>(&fxaaUniformBuffer)));
*fxaaUniformBuffer = _fxaaData;
vmaUnmapMemory(engine->_allocator, fxaaDataBuffer.allocation);

{
DescriptorWriter writer;
writer.write_image(0, _fullscreenImage.imageView, _fullscreenImageSampler,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
writer.write_buffer(1, fxaaDataBuffer.buffer, sizeof(FXAAData), 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
writer.update_set(engine->_device, _fxaaDescriptorSet);
}

// Bind pipeline and descriptors
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, _fxaaPipeline);
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, _fxaaPipelineLayout, 0, 1, &_fxaaDescriptorSet, 0,
nullptr);

// Set viewport and scissor
VkViewport viewport = {};
viewport.x = 0;
viewport.y = 0;
viewport.width = static_cast<float>(engine->_windowExtent.width);
viewport.height = static_cast<float>(engine->_windowExtent.height);
viewport.minDepth = 0.f;
viewport.maxDepth = 1.f;

vkCmdSetViewport(cmd, 0, 1, &viewport);

VkRect2D scissor = {};
scissor.offset.x = 0;
scissor.offset.y = 0;
scissor.extent = engine->_windowExtent;

vkCmdSetScissor(cmd, 0, 1, &scissor);

vkCmdDraw(cmd, 3, 1, 0, 0); // 1 triangle, 3 vertices

vkCmdEndRendering(cmd);
}

void PostProcessor::draw_grid_only(VulkanEngine *engine, VkCommandBuffer cmd) {
// Only draw grid, not the fullscreen composition
if (!_compositorData.showGrid) {
Expand Down
26 changes: 26 additions & 0 deletions VkRenderer/postprocess.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <glm/glm.hpp>
#include <vk_types.h>
#include <vulkan/vulkan.h>
#include "vk_mem_alloc.h"
Expand All @@ -8,6 +9,14 @@ struct CompositorData {
int useRayTracer;
float exposure;
int showGrid;
int useFXAA;
};

struct FXAAData {
alignas(16) glm::vec3 R_inverseFilterTextureSize;
float R_fxaaSpanMax;
float R_fxaaReduceMin;
float R_fxaaReduceMul;
};

class VulkanEngine;
Expand All @@ -16,16 +25,27 @@ class PostProcessor {
public:
void init(VulkanEngine *engine);
void draw(VulkanEngine *engine, VkCommandBuffer cmd);
void draw_fxaa(VulkanEngine *engine, VkCommandBuffer cmd);
void draw_grid_only(VulkanEngine *engine, VkCommandBuffer cmd);
void draw_grid_geometry(VulkanEngine *engine, VkCommandBuffer cmd);

// Fullscreen resources
AllocatedImage _fullscreenImage{};
AllocatedImage _fxaaImage{};
CompositorData _compositorData{};
FXAAData _fxaaData{};

// Getter for the sampler
VkSampler getFullscreenImageSampler() const { return _fullscreenImageSampler; }

// Get the final processed image (FXAA output if enabled, otherwise fullscreen image)
const AllocatedImage &getFinalImage() const { return _compositorData.useFXAA ? _fxaaImage : _fullscreenImage; }

// Get the final image view for UI display
VkImageView getFinalImageView() const {
return _compositorData.useFXAA ? _fxaaImage.imageView : _fullscreenImage.imageView;
}

private:
VkPipelineLayout _postProcessPipelineLayout = nullptr;
VkPipeline _postProcessPipeline = nullptr;
Expand All @@ -34,6 +54,12 @@ class PostProcessor {
VkDescriptorSetLayout _postProcessDescriptorSetLayout = nullptr;
VkSampler _fullscreenImageSampler = nullptr;

// FXAA pipeline
VkPipelineLayout _fxaaPipelineLayout = nullptr;
VkPipeline _fxaaPipeline = nullptr;
VkDescriptorSet _fxaaDescriptorSet = nullptr;
VkDescriptorSetLayout _fxaaDescriptorSetLayout = nullptr;

VkPipelineLayout _gridPipelineLayout = nullptr;
VkPipeline _gridPipeline = nullptr;
VkDescriptorSetLayout _gridDescriptorSetLayout = nullptr;
Expand Down
11 changes: 10 additions & 1 deletion VkRenderer/ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@ void ui::init_imgui(VulkanEngine *engine) {
engine->postProcessor.getFullscreenImageSampler(), engine->postProcessor._fullscreenImage.imageView,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);

// For Drawing FXAA output in viewport
engine->_fxaaViewportTextureDescriptorSet = ImGui_ImplVulkan_AddTexture(
engine->postProcessor.getFullscreenImageSampler(), engine->postProcessor._fxaaImage.imageView,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);

// add the destroy the imgui created structures
engine->_mainDeletionQueue.push_function([=] {
ImGui_ImplVulkan_Shutdown();
Expand Down Expand Up @@ -315,6 +320,7 @@ void ui::create_settings_panel(VulkanEngine *engine) {
if (ImGui::CollapsingHeader("Compositor Settings")) {
ImGui::SliderFloat("Exposure", &engine->postProcessor._compositorData.exposure, 0.1f, 10.0f);
ImGui::Checkbox("Show Grid Helper", reinterpret_cast<bool *>(&engine->postProcessor._compositorData.showGrid));
ImGui::Checkbox("FXAA", reinterpret_cast<bool *>(&engine->postProcessor._compositorData.useFXAA));
}

if (ImGui::CollapsingHeader("Lighting Settings")) {
Expand Down Expand Up @@ -474,7 +480,10 @@ void ui::create_viewport_panel(VulkanEngine *engine) {
}

// Display the rendered scene texture with proper scaling
ImGui::Image(reinterpret_cast<ImTextureID>(engine->_viewportTextureDescriptorSet), displaySize);
VkDescriptorSet textureToDisplay = engine->postProcessor._compositorData.useFXAA
? engine->_fxaaViewportTextureDescriptorSet
: engine->_viewportTextureDescriptorSet;
ImGui::Image(reinterpret_cast<ImTextureID>(textureToDisplay), displaySize);

// Display info below the image
ImGui::Text("Render: %dx%d (%.1fx scale)", engine->_drawExtent.width, engine->_drawExtent.height,
Expand Down
Loading