Add post processing pass
This commit is contained in:
parent
b5dcebe55e
commit
a084d8fe45
8 changed files with 252 additions and 2 deletions
|
@ -16,7 +16,8 @@ endif()
|
||||||
add_executable(Graph
|
add_executable(Graph
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/renderer.cpp
|
src/renderer.cpp
|
||||||
src/worldpass.cpp)
|
src/worldpass.cpp
|
||||||
|
src/postpass.cpp)
|
||||||
target_link_libraries(Graph PUBLIC SDL2::SDL2 SDL2::SDL2main Vulkan::Vulkan assimp::assimp)
|
target_link_libraries(Graph PUBLIC SDL2::SDL2 SDL2::SDL2main Vulkan::Vulkan assimp::assimp)
|
||||||
target_include_directories(Graph PUBLIC include)
|
target_include_directories(Graph PUBLIC include)
|
||||||
|
|
||||||
|
@ -32,6 +33,8 @@ endmacro()
|
||||||
|
|
||||||
compile_shader(triangle.vert)
|
compile_shader(triangle.vert)
|
||||||
compile_shader(triangle.frag)
|
compile_shader(triangle.frag)
|
||||||
|
compile_shader(post.vert)
|
||||||
|
compile_shader(post.frag)
|
||||||
|
|
||||||
add_custom_target(BuildShaders DEPENDS ${SPV_FILES})
|
add_custom_target(BuildShaders DEPENDS ${SPV_FILES})
|
||||||
add_dependencies(Graph BuildShaders)
|
add_dependencies(Graph BuildShaders)
|
||||||
|
|
29
include/postpass.h
Normal file
29
include/postpass.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
class Renderer;
|
||||||
|
struct RenderTarget;
|
||||||
|
|
||||||
|
class PostPass {
|
||||||
|
public:
|
||||||
|
PostPass(Renderer& renderer);
|
||||||
|
|
||||||
|
void render(VkCommandBuffer commandBuffer, RenderTarget* target);
|
||||||
|
|
||||||
|
void createDescriptorSet(RenderTarget* target);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void createDescriptorSetLayout();
|
||||||
|
void createPipeline();
|
||||||
|
void createSampler();
|
||||||
|
|
||||||
|
Renderer& renderer_;
|
||||||
|
|
||||||
|
VkDescriptorSetLayout setLayout_ = nullptr;
|
||||||
|
|
||||||
|
VkPipelineLayout pipelineLayout_ = nullptr;
|
||||||
|
VkPipeline pipeline_ = nullptr;
|
||||||
|
|
||||||
|
VkSampler offscreenSampler_ = nullptr;
|
||||||
|
};
|
|
@ -3,6 +3,7 @@
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
#include "worldpass.h"
|
#include "worldpass.h"
|
||||||
|
#include "postpass.h"
|
||||||
|
|
||||||
struct RenderTarget {
|
struct RenderTarget {
|
||||||
VkSurfaceKHR surface = nullptr;
|
VkSurfaceKHR surface = nullptr;
|
||||||
|
@ -25,6 +26,8 @@ struct RenderTarget {
|
||||||
VkSemaphore imageAvailableSemaphore = nullptr;
|
VkSemaphore imageAvailableSemaphore = nullptr;
|
||||||
VkSemaphore renderFinishedSemaphore = nullptr;
|
VkSemaphore renderFinishedSemaphore = nullptr;
|
||||||
VkFence* fences = nullptr;
|
VkFence* fences = nullptr;
|
||||||
|
|
||||||
|
VkDescriptorSet* postSets = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
class World;
|
class World;
|
||||||
|
@ -59,6 +62,10 @@ public:
|
||||||
return presentationRenderPass_;
|
return presentationRenderPass_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkDescriptorPool getDescriptorPool() const {
|
||||||
|
return descriptorPool_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createInstance();
|
void createInstance();
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -67,6 +74,7 @@ private:
|
||||||
void createLogicalDevice();
|
void createLogicalDevice();
|
||||||
void createCommandPool();
|
void createCommandPool();
|
||||||
void createPresentationRenderPass();
|
void createPresentationRenderPass();
|
||||||
|
void createDescriptorPool();
|
||||||
|
|
||||||
VkInstance instance_ = nullptr;
|
VkInstance instance_ = nullptr;
|
||||||
|
|
||||||
|
@ -94,5 +102,8 @@ private:
|
||||||
|
|
||||||
VkRenderPass presentationRenderPass_ = nullptr;
|
VkRenderPass presentationRenderPass_ = nullptr;
|
||||||
|
|
||||||
|
VkDescriptorPool descriptorPool_ = nullptr;
|
||||||
|
|
||||||
WorldPass* worldPass_ = nullptr;
|
WorldPass* worldPass_ = nullptr;
|
||||||
|
PostPass* postPass_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
11
shaders/post.frag
Normal file
11
shaders/post.frag
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#version 460 core
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 inUV;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
layout(binding = 0) uniform sampler2D offscreenSampler;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
outColor = texture(offscreenSampler, inUV);
|
||||||
|
}
|
9
shaders/post.vert
Normal file
9
shaders/post.vert
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#version 460 core
|
||||||
|
|
||||||
|
layout(location = 0) out vec2 outUV;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
||||||
|
gl_Position = vec4(outUV * 2.0f + -1.0f, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
167
src/postpass.cpp
Normal file
167
src/postpass.cpp
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
#include "postpass.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "renderer.h"
|
||||||
|
|
||||||
|
PostPass::PostPass(Renderer& renderer) : renderer_(renderer) {
|
||||||
|
createDescriptorSetLayout();
|
||||||
|
createPipeline();
|
||||||
|
createSampler();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostPass::render(VkCommandBuffer commandBuffer, RenderTarget* target) {
|
||||||
|
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_);
|
||||||
|
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &target->postSets[target->currentImage], 0, nullptr);
|
||||||
|
vkCmdDraw(commandBuffer, 3, 1, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostPass::createDescriptorSet(RenderTarget* target) {
|
||||||
|
VkDescriptorSetAllocateInfo allocInfo = {};
|
||||||
|
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||||
|
allocInfo.descriptorPool = renderer_.getDescriptorPool();
|
||||||
|
allocInfo.descriptorSetCount = target->numImages;
|
||||||
|
|
||||||
|
// FIXME: lol what
|
||||||
|
VkDescriptorSetLayout* layouts = new VkDescriptorSetLayout[target->numImages];
|
||||||
|
for(uint32_t i = 0; i < target->numImages; i++)
|
||||||
|
layouts[i] = setLayout_;
|
||||||
|
|
||||||
|
allocInfo.pSetLayouts = layouts;
|
||||||
|
|
||||||
|
target->postSets = new VkDescriptorSet[target->numImages];
|
||||||
|
vkAllocateDescriptorSets(renderer_.getDevice(), &allocInfo, target->postSets);
|
||||||
|
|
||||||
|
delete[] layouts;
|
||||||
|
|
||||||
|
for(uint32_t i = 0; i < target->numImages; i++) {
|
||||||
|
VkDescriptorImageInfo imageInfo = {};
|
||||||
|
imageInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
imageInfo.imageView = target->offscreenImageViews[i];
|
||||||
|
imageInfo.sampler = offscreenSampler_;
|
||||||
|
|
||||||
|
VkWriteDescriptorSet descriptorWrite = {};
|
||||||
|
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
|
descriptorWrite.descriptorCount = 1;
|
||||||
|
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
descriptorWrite.dstSet = target->postSets[i];
|
||||||
|
descriptorWrite.pImageInfo = &imageInfo;
|
||||||
|
|
||||||
|
vkUpdateDescriptorSets(renderer_.getDevice(), 1, &descriptorWrite, 0, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostPass::createDescriptorSetLayout() {
|
||||||
|
VkDescriptorSetLayoutBinding offscreenSamplerBinding = {};
|
||||||
|
offscreenSamplerBinding.descriptorCount = 1;
|
||||||
|
offscreenSamplerBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
offscreenSamplerBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutCreateInfo createInfo = {};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||||
|
createInfo.bindingCount = 1;
|
||||||
|
createInfo.pBindings = &offscreenSamplerBinding;
|
||||||
|
|
||||||
|
vkCreateDescriptorSetLayout(renderer_.getDevice(), &createInfo, nullptr, &setLayout_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostPass::createPipeline() {
|
||||||
|
VkShaderModule vertShaderModule = renderer_.createShader("post.vert.spv");
|
||||||
|
VkShaderModule fragShaderModule = renderer_.createShader("post.frag.spv");
|
||||||
|
|
||||||
|
VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
|
||||||
|
vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
vertShaderStageInfo.module = vertShaderModule;
|
||||||
|
vertShaderStageInfo.pName = "main";
|
||||||
|
|
||||||
|
VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
|
||||||
|
fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
fragShaderStageInfo.module = fragShaderModule;
|
||||||
|
fragShaderStageInfo.pName = "main";
|
||||||
|
|
||||||
|
const std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages = {vertShaderStageInfo, fragShaderStageInfo};
|
||||||
|
|
||||||
|
VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
|
||||||
|
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||||
|
|
||||||
|
VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
|
||||||
|
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||||
|
inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||||
|
|
||||||
|
VkPipelineViewportStateCreateInfo viewportState = {};
|
||||||
|
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||||
|
viewportState.viewportCount = 1;
|
||||||
|
viewportState.scissorCount = 1;
|
||||||
|
|
||||||
|
VkPipelineRasterizationStateCreateInfo rasterizer = {};
|
||||||
|
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||||
|
rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
|
||||||
|
rasterizer.lineWidth = 1.0f;
|
||||||
|
rasterizer.cullMode = VK_CULL_MODE_FRONT_BIT;
|
||||||
|
rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
||||||
|
|
||||||
|
VkPipelineMultisampleStateCreateInfo multisampling = {};
|
||||||
|
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||||
|
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
|
||||||
|
VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
|
||||||
|
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||||
|
colorBlendAttachment.blendEnable = VK_FALSE;
|
||||||
|
|
||||||
|
VkPipelineColorBlendStateCreateInfo colorBlending = {};
|
||||||
|
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||||
|
colorBlending.attachmentCount = 1;
|
||||||
|
colorBlending.pAttachments = &colorBlendAttachment;
|
||||||
|
|
||||||
|
const std::array<VkDynamicState, 2> dynamicStates = {
|
||||||
|
VK_DYNAMIC_STATE_VIEWPORT,
|
||||||
|
VK_DYNAMIC_STATE_SCISSOR
|
||||||
|
};
|
||||||
|
|
||||||
|
VkPipelineDynamicStateCreateInfo dynamicState = {};
|
||||||
|
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||||
|
dynamicState.dynamicStateCount = dynamicStates.size();
|
||||||
|
dynamicState.pDynamicStates = dynamicStates.data();
|
||||||
|
|
||||||
|
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
|
||||||
|
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||||
|
pipelineLayoutInfo.setLayoutCount = 1;
|
||||||
|
pipelineLayoutInfo.pSetLayouts = &setLayout_;
|
||||||
|
|
||||||
|
vkCreatePipelineLayout(renderer_.getDevice(), &pipelineLayoutInfo, nullptr, &pipelineLayout_);
|
||||||
|
|
||||||
|
VkGraphicsPipelineCreateInfo pipelineInfo = {};
|
||||||
|
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||||
|
pipelineInfo.stageCount = shaderStages.size();
|
||||||
|
pipelineInfo.pStages = shaderStages.data();
|
||||||
|
pipelineInfo.pVertexInputState = &vertexInputInfo;
|
||||||
|
pipelineInfo.pInputAssemblyState = &inputAssembly;
|
||||||
|
pipelineInfo.pViewportState = &viewportState;
|
||||||
|
pipelineInfo.pRasterizationState = &rasterizer;
|
||||||
|
pipelineInfo.pMultisampleState = &multisampling;
|
||||||
|
pipelineInfo.pColorBlendState = &colorBlending;
|
||||||
|
pipelineInfo.pDynamicState = &dynamicState;
|
||||||
|
pipelineInfo.layout = pipelineLayout_;
|
||||||
|
pipelineInfo.renderPass = renderer_.getRenderPass();
|
||||||
|
|
||||||
|
vkCreateGraphicsPipelines(renderer_.getDevice(), nullptr, 1, &pipelineInfo, nullptr, &pipeline_);
|
||||||
|
|
||||||
|
vkDestroyShaderModule(renderer_.getDevice(), fragShaderModule, nullptr);
|
||||||
|
vkDestroyShaderModule(renderer_.getDevice(), vertShaderModule, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PostPass::createSampler() {
|
||||||
|
VkSamplerCreateInfo samplerInfo = {};
|
||||||
|
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||||
|
samplerInfo.magFilter = VK_FILTER_LINEAR;
|
||||||
|
samplerInfo.minFilter = VK_FILTER_LINEAR;
|
||||||
|
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||||
|
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||||
|
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||||
|
samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
|
||||||
|
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||||
|
|
||||||
|
vkCreateSampler(renderer_.getDevice(), &samplerInfo, nullptr, &offscreenSampler_);
|
||||||
|
}
|
|
@ -19,8 +19,10 @@ Renderer::Renderer() {
|
||||||
createLogicalDevice();
|
createLogicalDevice();
|
||||||
createCommandPool();
|
createCommandPool();
|
||||||
createPresentationRenderPass();
|
createPresentationRenderPass();
|
||||||
|
createDescriptorPool();
|
||||||
|
|
||||||
worldPass_ = new WorldPass(*this);
|
worldPass_ = new WorldPass(*this);
|
||||||
|
postPass_ = new PostPass(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer::~Renderer() {
|
Renderer::~Renderer() {
|
||||||
|
@ -80,6 +82,8 @@ void Renderer::render(World& world, RenderTarget* target) {
|
||||||
|
|
||||||
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||||
|
|
||||||
|
postPass_->render(commandBuffer, target);
|
||||||
|
|
||||||
vkCmdEndRenderPass(commandBuffer);
|
vkCmdEndRenderPass(commandBuffer);
|
||||||
|
|
||||||
vkEndCommandBuffer(commandBuffer);
|
vkEndCommandBuffer(commandBuffer);
|
||||||
|
@ -263,6 +267,8 @@ RenderTarget* Renderer::createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
postPass_->createDescriptorSet(target);
|
||||||
|
|
||||||
VkCommandBufferAllocateInfo allocateInfo = {};
|
VkCommandBufferAllocateInfo allocateInfo = {};
|
||||||
allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
|
@ -581,3 +587,17 @@ void Renderer::createPresentationRenderPass() {
|
||||||
|
|
||||||
vkCreateRenderPass(device_, &renderPassInfo, nullptr, &presentationRenderPass_);
|
vkCreateRenderPass(device_, &renderPassInfo, nullptr, &presentationRenderPass_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::createDescriptorPool() {
|
||||||
|
VkDescriptorPoolSize poolSize = {};
|
||||||
|
poolSize.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
poolSize.descriptorCount = 15;
|
||||||
|
|
||||||
|
VkDescriptorPoolCreateInfo poolInfo = {};
|
||||||
|
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||||
|
poolInfo.poolSizeCount = 1;
|
||||||
|
poolInfo.pPoolSizes = &poolSize;
|
||||||
|
poolInfo.maxSets = 15;
|
||||||
|
|
||||||
|
vkCreateDescriptorPool(device_, &poolInfo, nullptr, &descriptorPool_);
|
||||||
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ void WorldPass::createRenderPass() {
|
||||||
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||||
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
|
||||||
VkAttachmentReference colorAttachmentRef = {};
|
VkAttachmentReference colorAttachmentRef = {};
|
||||||
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
|
|
Reference in a new issue