Program Listing for File VulkanRenderer.cpp
↰ Return to documentation for file (Src/GraphicsEngineVulkan/renderer/VulkanRenderer.cpp)
#include "renderer/VulkanRenderer.hpp"
#include "common/Utilities.hpp"
#include "renderer/QueueFamilyIndices.hpp"
#include "renderer/pushConstants/PushConstantRasterizer.hpp"
#include "renderer/pushConstants/PushConstantRayTracing.hpp"
#include "scene/GUISceneSharedVars.hpp"
#define GLFW_INCLUDE_NONE
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <array>
#include <cstring>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <iostream>
#include <memory>
#include <set>
#include <sstream>
#include <stdexcept>
#include <vector>
#ifndef VMA_IMPLEMENTATION
#define VMA_IMPLEMENTATION
#endif// !VMA_IMPLEMENTATION
#include <vk_mem_alloc.h>
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#include <gsl/gsl>
#include "common/Globals.hpp"
#include "renderer/pushConstants/PushConstantPost.hpp"
#include "util/File.hpp"
#include "vulkan_base/ShaderHelper.hpp"
#include "renderer/VulkanRendererConfig.hpp"
#include "vulkan_base/VulkanDebug.hpp"
Kataglyphis::VulkanRenderer::VulkanRenderer(Kataglyphis::Frontend::Window *window,
Scene *scene,
Kataglyphis::Frontend::GUI *gui,
Camera *camera)
:
window(window), scene(scene), gui(gui)
{
updateUniforms(scene, camera, window);
instance = VulkanInstance();
VkDebugReportFlagsEXT debugReportFlags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
if (Kataglyphis::ENABLE_VALIDATION_LAYERS)
debug::setupDebugging(instance.getVulkanInstance(), debugReportFlags, VK_NULL_HANDLE);
create_surface();
device = std::make_unique<VulkanDevice>(&instance, &surface);
allocator = Allocator(device->getLogicalDevice(), device->getPhysicalDevice(), instance.getVulkanInstance());
create_command_pool();
vulkanSwapChain.initVulkanContext(device.get(), window, surface);
create_uniform_buffers();
create_command_buffers();
createSynchronization();
createSharedRenderDescriptorSetLayouts();
std::vector<VkDescriptorSetLayout> descriptor_set_layouts_rasterizer = { sharedRenderDescriptorSetLayout };
rasterizer.init(device.get(), &vulkanSwapChain, descriptor_set_layouts_rasterizer, graphics_command_pool);
create_post_descriptor_layout();
std::vector<VkDescriptorSetLayout> descriptor_set_layouts_post = { post_descriptor_set_layout };
postStage.init(device.get(), &vulkanSwapChain, descriptor_set_layouts_post);
createDescriptorPoolSharedRenderStages();
createSharedRenderDescriptorSet();
updatePostDescriptorSets();
std::vector<VkDescriptorSetLayout> layouts;
layouts.push_back(sharedRenderDescriptorSetLayout);
if (device->supportsHardwareAcceleratedRRT()) {
createRaytracingDescriptorPool();
createRaytracingDescriptorSetLayouts();
layouts.push_back(raytracingDescriptorSetLayout);
raytracingStage.init(device.get(), layouts);
pathTracing.init(device.get(), layouts);
}
scene->loadModel(device.get(), graphics_command_pool);
updateTexturesInSharedRenderDescriptorSet();
if (device->supportsHardwareAcceleratedRRT()) {
asManager.createASForScene(device.get(), graphics_command_pool, scene);
}
create_object_description_buffer();
if (device->supportsHardwareAcceleratedRRT()) {
createRaytracingDescriptorSets();
updateRaytracingDescriptorSets();
}
gui->initializeVulkanContext(
device.get(), instance.getVulkanInstance(), postStage.getRenderPass(), graphics_command_pool);
gui->setUserSelectionForRRT(device->supportsHardwareAcceleratedRRT());
}
void Kataglyphis::VulkanRenderer::updateUniforms(Scene *scene, Camera *camera, Kataglyphis::Frontend::Window *window)
{
const GUISceneSharedVars guiSceneSharedVars = scene->getGuiSceneSharedVars();
globalUBO.view = camera->calculate_viewmatrix();
globalUBO.projection = glm::perspective(glm::radians(camera->get_fov()),
(float)window->get_width() / (float)window->get_height(),
camera->get_near_plane(),
camera->get_far_plane());
sceneUBO.view_dir = glm::vec4(camera->get_camera_direction(), 1.0f);
sceneUBO.light_dir = glm::vec4(guiSceneSharedVars.directional_light_direction[0],
guiSceneSharedVars.directional_light_direction[1],
guiSceneSharedVars.directional_light_direction[2],
1.0f);
sceneUBO.cam_pos = glm::vec4(camera->get_camera_position(), camera->get_fov());
}
void Kataglyphis::VulkanRenderer::updateStateDueToUserInput(Kataglyphis::Frontend::GUI *gui)
{
Kataglyphis::VulkanRendererInternals::FrontendShared::GUIRendererSharedVars &guiRendererSharedVars =
gui->getGuiRendererSharedVars();
if (guiRendererSharedVars.shader_hot_reload_triggered) {
shaderHotReload();
guiRendererSharedVars.shader_hot_reload_triggered = false;
}
}
void Kataglyphis::VulkanRenderer::finishAllRenderCommands() { vkDeviceWaitIdle(device->getLogicalDevice()); }
void Kataglyphis::VulkanRenderer::shaderHotReload()
{
// wait until no actions being run on device before destroying
vkDeviceWaitIdle(device->getLogicalDevice());
std::vector<VkDescriptorSetLayout> descriptor_set_layouts = { sharedRenderDescriptorSetLayout };
rasterizer.shaderHotReload(descriptor_set_layouts);
std::vector<VkDescriptorSetLayout> descriptor_set_layouts_post = { post_descriptor_set_layout };
postStage.shaderHotReload(descriptor_set_layouts_post);
std::vector<VkDescriptorSetLayout> layouts = { sharedRenderDescriptorSetLayout, raytracingDescriptorSetLayout };
raytracingStage.shaderHotReload(layouts);
pathTracing.shaderHotReload(layouts);
}
void Kataglyphis::VulkanRenderer::drawFrame()
{
// We need to skip one frame
// Due to ImGui need to call ImGui::NewFrame() again
// if we recreated swapchain
if (checkChangedFramebufferSize()) return;
/*1. Get next available image to draw to and set something to signal when
we're finished with the image (a semaphore) wait for given fence to signal
(open) from last draw before continuing*/
VkResult result = vkWaitForFences(
device->getLogicalDevice(), 1, &in_flight_fences[current_frame], VK_TRUE, std::numeric_limits<uint64_t>::max());
ASSERT_VULKAN(result, "Failed to wait for fences!")
// -- GET NEXT IMAGE --
uint32_t image_index;
result = vkAcquireNextImageKHR(device->getLogicalDevice(),
vulkanSwapChain.getSwapChain(),
std::numeric_limits<uint64_t>::max(),
image_available[current_frame],
VK_NULL_HANDLE,
&image_index);
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
// recreate_swap_chain();
return;
} else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
spdlog::error("Failed to acquire next image!");
}
if (images_in_flight_fences[image_index] != VK_NULL_HANDLE) {
vkWaitForFences(device->getLogicalDevice(), 1, &images_in_flight_fences[image_index], VK_TRUE, UINT64_MAX);
}
// mark the image as now being in use by this frame
images_in_flight_fences[image_index] = in_flight_fences[current_frame];
VkCommandBufferBeginInfo buffer_begin_info{};
buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
// start recording commands to command buffer
result = vkBeginCommandBuffer(command_buffers[image_index], &buffer_begin_info);
ASSERT_VULKAN(result, "Failed to start recording a command buffer!")
update_uniform_buffers(image_index);
Kataglyphis::VulkanRendererInternals::FrontendShared::GUIRendererSharedVars &guiRendererSharedVars =
gui->getGuiRendererSharedVars();
if (guiRendererSharedVars.raytracing) update_raytracing_descriptor_set(image_index);
record_commands(image_index);
// stop recording to command buffer
result = vkEndCommandBuffer(command_buffers[image_index]);
ASSERT_VULKAN(result, "Failed to stop recording a command buffer!")
// 2. Submit command buffer to queue for execution, making sure it waits for
// the image to be signalled as available before drawing and signals when it
// has finished rendering
// -- SUBMIT COMMAND BUFFER TO RENDER --
VkSubmitInfo submit_info{};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.waitSemaphoreCount = 1;// number of semaphores to wait on
submit_info.pWaitSemaphores = &image_available[current_frame];// list of semaphores to wait on
VkPipelineStageFlags wait_stages = {
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT /*|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT |
VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR*/
};
submit_info.pWaitDstStageMask = &wait_stages;// stages to check semaphores at
submit_info.commandBufferCount = 1;// number of command buffers to submit
submit_info.pCommandBuffers = &command_buffers[image_index];// command buffer to submit
submit_info.signalSemaphoreCount = 1;// number of semaphores to signal
submit_info.pSignalSemaphores = &render_finished[current_frame];// semaphores to signal when command
// buffer finishes
result = vkResetFences(device->getLogicalDevice(), 1, &in_flight_fences[current_frame]);
ASSERT_VULKAN(result, "Failed to reset fences!")
// submit command buffer to queue
result = vkQueueSubmit(device->getGraphicsQueue(), 1, &submit_info, in_flight_fences[current_frame]);
ASSERT_VULKAN(result, "Failed to submit command buffer to queue!")
// 3. Present image to screen when it has signalled finished rendering
// -- PRESENT RENDERED IMAGE TO SCREEN --
VkPresentInfoKHR present_info{};
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
present_info.waitSemaphoreCount = 1;// number of semaphores to wait on
present_info.pWaitSemaphores = &render_finished[current_frame];// semaphores to wait on
present_info.swapchainCount = 1;// number of swapchains to present to
const VkSwapchainKHR swapchain = vulkanSwapChain.getSwapChain();
present_info.pSwapchains = &swapchain;// swapchains to present images to
present_info.pImageIndices = &image_index;// index of images in swapchain to present
result = vkQueuePresentKHR(device->getPresentationQueue(), &present_info);
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
// recreate_swap_chain();
return;
} else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
spdlog::error("Failed to acquire next image!");
}
if (result != VK_SUCCESS) { spdlog::error("Failed to submit to present queue!"); }
current_frame = (current_frame + 1) % Kataglyphis::MAX_FRAME_DRAWS;
}
void Kataglyphis::VulkanRenderer::create_surface()
{
// create surface (creates a surface create info struct, runs the create
// surface function, returns result)
ASSERT_VULKAN(glfwCreateWindowSurface(instance.getVulkanInstance(), window->get_window(), nullptr, &surface),
"Failed to create a surface!");
}
void Kataglyphis::VulkanRenderer::create_post_descriptor_layout()
{
// UNIFORM VALUES DESCRIPTOR SET LAYOUT
// globalUBO Binding info
VkDescriptorSetLayoutBinding post_sampler_layout_binding{};
post_sampler_layout_binding.binding = 0;// binding point in shader (designated by binding number in shader)
post_sampler_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;// type of descriptor
// (uniform, dynamic uniform,
// image sampler, etc)
post_sampler_layout_binding.descriptorCount = 1;// number of descriptors for binding
post_sampler_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;// we need to say at which shader we bind
// this uniform to
post_sampler_layout_binding.pImmutableSamplers = nullptr;// for texture: can make sampler data unchangeable
// (immutable) by specifying in layout
std::vector<VkDescriptorSetLayoutBinding> layout_bindings = { post_sampler_layout_binding };
// create descriptor set layout with given bindings
VkDescriptorSetLayoutCreateInfo layout_create_info{};
layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layout_create_info.bindingCount = static_cast<uint32_t>(layout_bindings.size());// only have 1 for the globalUBO
layout_create_info.pBindings = layout_bindings.data();// array of binding infos
// create descriptor set layout
VkResult result = vkCreateDescriptorSetLayout(
device->getLogicalDevice(), &layout_create_info, nullptr, &post_descriptor_set_layout);
ASSERT_VULKAN(result, "Failed to create descriptor set layout!")
VkDescriptorPoolSize post_pool_size{};
post_pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
post_pool_size.descriptorCount = static_cast<uint32_t>(1);
// list of pool sizes
std::vector<VkDescriptorPoolSize> descriptor_pool_sizes = { post_pool_size };
VkDescriptorPoolCreateInfo pool_create_info{};
pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
pool_create_info.maxSets = vulkanSwapChain.getNumberSwapChainImages();// maximum number of descriptor sets
// that can be created from pool
pool_create_info.poolSizeCount =
static_cast<uint32_t>(descriptor_pool_sizes.size());// amount of pool sizes being passed
pool_create_info.pPoolSizes = descriptor_pool_sizes.data();// pool sizes to create pool with
// create descriptor pool
result = vkCreateDescriptorPool(device->getLogicalDevice(), &pool_create_info, nullptr, &post_descriptor_pool);
ASSERT_VULKAN(result, "Failed to create a descriptor pool!")
// resize descriptor set list so one for every buffer
post_descriptor_set.resize(vulkanSwapChain.getNumberSwapChainImages());
std::vector<VkDescriptorSetLayout> set_layouts(
vulkanSwapChain.getNumberSwapChainImages(), post_descriptor_set_layout);
// descriptor set allocation info
VkDescriptorSetAllocateInfo set_alloc_info{};
set_alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
set_alloc_info.descriptorPool = post_descriptor_pool;// pool to allocate descriptor set from
set_alloc_info.descriptorSetCount = vulkanSwapChain.getNumberSwapChainImages();// number of sets to allocate
set_alloc_info.pSetLayouts = set_layouts.data();// layouts to use to allocate sets (1:1 relationship)
// allocate descriptor sets (multiple)
result = vkAllocateDescriptorSets(device->getLogicalDevice(), &set_alloc_info, post_descriptor_set.data());
ASSERT_VULKAN(result, "Failed to create descriptor sets!")
}
void Kataglyphis::VulkanRenderer::updatePostDescriptorSets()
{
// update all of descriptor set buffer bindings
for (size_t i = 0; i < vulkanSwapChain.getNumberSwapChainImages(); i++) {
// texture image info
VkDescriptorImageInfo image_info{};
image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
Texture &renderResult = rasterizer.getOffscreenTexture(i);
image_info.imageView = renderResult.getImageView();
image_info.sampler = postStage.getOffscreenSampler();
// descriptor write info
VkWriteDescriptorSet descriptor_write{};
descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptor_write.dstSet = post_descriptor_set[i];
descriptor_write.dstBinding = 0;
descriptor_write.dstArrayElement = 0;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptor_write.descriptorCount = 1;
descriptor_write.pImageInfo = &image_info;
// update new descriptor set
vkUpdateDescriptorSets(device->getLogicalDevice(), 1, &descriptor_write, 0, nullptr);
}
}
void Kataglyphis::VulkanRenderer::createRaytracingDescriptorPool()
{
std::array<VkDescriptorPoolSize, 2> descriptor_pool_sizes{};
descriptor_pool_sizes[0].type = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
descriptor_pool_sizes[0].descriptorCount = 1;
descriptor_pool_sizes[1].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
descriptor_pool_sizes[1].descriptorCount = 1;
VkDescriptorPoolCreateInfo descriptor_pool_create_info{};
descriptor_pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
descriptor_pool_create_info.poolSizeCount = static_cast<uint32_t>(descriptor_pool_sizes.size());
descriptor_pool_create_info.pPoolSizes = descriptor_pool_sizes.data();
descriptor_pool_create_info.maxSets = vulkanSwapChain.getNumberSwapChainImages();
VkResult result = vkCreateDescriptorPool(
device->getLogicalDevice(), &descriptor_pool_create_info, nullptr, &raytracingDescriptorPool);
ASSERT_VULKAN(result, "Failed to create command pool!")
}
void Kataglyphis::VulkanRenderer::cleanUpSync()
{
for (int i = 0; i < Kataglyphis::MAX_FRAME_DRAWS; i++) {
vkDestroySemaphore(device->getLogicalDevice(), render_finished[i], nullptr);
vkDestroySemaphore(device->getLogicalDevice(), image_available[i], nullptr);
vkDestroyFence(device->getLogicalDevice(), in_flight_fences[i], nullptr);
}
}
void Kataglyphis::VulkanRenderer::create_object_description_buffer()
{
std::vector<ObjectDescription> objectDescriptions = scene->getObjectDescriptions();
vulkanBufferManager.createBufferAndUploadVectorOnDevice(device.get(),
graphics_command_pool,
objectDescriptionBuffer,
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT,
objectDescriptions);
// update the object description set
// update all of descriptor set buffer bindings
for (size_t i = 0; i < vulkanSwapChain.getNumberSwapChainImages(); i++) {
VkDescriptorBufferInfo object_descriptions_buffer_info{};
// image_info.sampler = VK_DESCRIPTOR_TYPE_SAMPLER;
object_descriptions_buffer_info.buffer = objectDescriptionBuffer.getBuffer();
object_descriptions_buffer_info.offset = 0;
object_descriptions_buffer_info.range = VK_WHOLE_SIZE;
VkWriteDescriptorSet descriptor_object_descriptions_writer{};
descriptor_object_descriptions_writer.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptor_object_descriptions_writer.pNext = nullptr;
descriptor_object_descriptions_writer.dstSet = sharedRenderDescriptorSet[i];
descriptor_object_descriptions_writer.dstBinding = OBJECT_DESCRIPTION_BINDING;
descriptor_object_descriptions_writer.dstArrayElement = 0;
descriptor_object_descriptions_writer.descriptorCount = 1;
descriptor_object_descriptions_writer.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
descriptor_object_descriptions_writer.pImageInfo = nullptr;
descriptor_object_descriptions_writer.pBufferInfo = &object_descriptions_buffer_info;
descriptor_object_descriptions_writer.pTexelBufferView = nullptr;// information about buffer data to bind
std::vector<VkWriteDescriptorSet> write_descriptor_sets = { descriptor_object_descriptions_writer };
// update the descriptor sets with new buffer/binding info
vkUpdateDescriptorSets(device->getLogicalDevice(),
static_cast<uint32_t>(write_descriptor_sets.size()),
write_descriptor_sets.data(),
0,
nullptr);
}
}
void Kataglyphis::VulkanRenderer::createRaytracingDescriptorSetLayouts()
{
{
std::array<VkDescriptorSetLayoutBinding, 2> descriptor_set_layout_bindings{};
// here comes the top level acceleration structure
descriptor_set_layout_bindings[0].binding = TLAS_BINDING;
descriptor_set_layout_bindings[0].descriptorCount = 1;
descriptor_set_layout_bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
descriptor_set_layout_bindings[0].pImmutableSamplers = nullptr;
// load them into the raygeneration and chlosest hit shader
descriptor_set_layout_bindings[0].stageFlags =
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_COMPUTE_BIT;
// here comes to previous rendered image
descriptor_set_layout_bindings[1].binding = OUT_IMAGE_BINDING;
descriptor_set_layout_bindings[1].descriptorCount = 1;
descriptor_set_layout_bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
descriptor_set_layout_bindings[1].pImmutableSamplers = nullptr;
// load them into the raygeneration and chlosest hit shader
descriptor_set_layout_bindings[1].stageFlags =
VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_COMPUTE_BIT;
VkDescriptorSetLayoutCreateInfo descriptor_set_layout_create_info{};
descriptor_set_layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
descriptor_set_layout_create_info.bindingCount = static_cast<uint32_t>(descriptor_set_layout_bindings.size());
descriptor_set_layout_create_info.pBindings = descriptor_set_layout_bindings.data();
VkResult result = vkCreateDescriptorSetLayout(
device->getLogicalDevice(), &descriptor_set_layout_create_info, nullptr, &raytracingDescriptorSetLayout);
ASSERT_VULKAN(result, "Failed to create raytracing descriptor set layout!")
}
}
void Kataglyphis::VulkanRenderer::createRaytracingDescriptorSets()
{
// resize descriptor set list so one for every buffer
raytracingDescriptorSet.resize(vulkanSwapChain.getNumberSwapChainImages());
std::vector<VkDescriptorSetLayout> set_layouts(
vulkanSwapChain.getNumberSwapChainImages(), raytracingDescriptorSetLayout);
VkDescriptorSetAllocateInfo descriptor_set_allocate_info{};
descriptor_set_allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
;
descriptor_set_allocate_info.descriptorPool = raytracingDescriptorPool;
descriptor_set_allocate_info.descriptorSetCount = vulkanSwapChain.getNumberSwapChainImages();
descriptor_set_allocate_info.pSetLayouts = set_layouts.data();
VkResult result = vkAllocateDescriptorSets(
device->getLogicalDevice(), &descriptor_set_allocate_info, raytracingDescriptorSet.data());
ASSERT_VULKAN(result, "Failed to allocate raytracing descriptor set!")
}
void Kataglyphis::VulkanRenderer::updateRaytracingDescriptorSets()
{
for (size_t i = 0; i < vulkanSwapChain.getNumberSwapChainImages(); i++) {
VkWriteDescriptorSetAccelerationStructureKHR descriptor_set_acceleration_structure{};
descriptor_set_acceleration_structure.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR;
descriptor_set_acceleration_structure.pNext = nullptr;
descriptor_set_acceleration_structure.accelerationStructureCount = 1;
VkAccelerationStructureKHR &vulkanTLAS = asManager.getTLAS();
descriptor_set_acceleration_structure.pAccelerationStructures = &vulkanTLAS;
VkWriteDescriptorSet write_descriptor_set_acceleration_structure{};
write_descriptor_set_acceleration_structure.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write_descriptor_set_acceleration_structure.pNext = &descriptor_set_acceleration_structure;
write_descriptor_set_acceleration_structure.dstSet = raytracingDescriptorSet[i];
write_descriptor_set_acceleration_structure.dstBinding = TLAS_BINDING;
write_descriptor_set_acceleration_structure.dstArrayElement = 0;
write_descriptor_set_acceleration_structure.descriptorCount = 1;
write_descriptor_set_acceleration_structure.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
write_descriptor_set_acceleration_structure.pImageInfo = nullptr;
write_descriptor_set_acceleration_structure.pBufferInfo = nullptr;
write_descriptor_set_acceleration_structure.pTexelBufferView = nullptr;
VkDescriptorImageInfo image_info{};
Texture &renderResult = rasterizer.getOffscreenTexture(i);
image_info.imageView = renderResult.getImageView();
image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
VkWriteDescriptorSet descriptor_image_writer{};
descriptor_image_writer.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptor_image_writer.pNext = nullptr;
descriptor_image_writer.dstSet = raytracingDescriptorSet[i];
descriptor_image_writer.dstBinding = OUT_IMAGE_BINDING;
descriptor_image_writer.dstArrayElement = 0;
descriptor_image_writer.descriptorCount = 1;
descriptor_image_writer.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
descriptor_image_writer.pImageInfo = &image_info;
descriptor_image_writer.pBufferInfo = nullptr;
descriptor_image_writer.pTexelBufferView = nullptr;
std::vector<VkWriteDescriptorSet> write_descriptor_sets = { write_descriptor_set_acceleration_structure,
descriptor_image_writer };
// update the descriptor sets with new buffer/binding info
vkUpdateDescriptorSets(device->getLogicalDevice(),
static_cast<uint32_t>(write_descriptor_sets.size()),
write_descriptor_sets.data(),
0,
nullptr);
}
}
void Kataglyphis::VulkanRenderer::createSharedRenderDescriptorSetLayouts()
{
std::array<VkDescriptorSetLayoutBinding, 5> descriptor_set_layout_bindings{};
// UNIFORM VALUES DESCRIPTOR SET LAYOUT
// globalUBO Binding info
descriptor_set_layout_bindings[0].binding = globalUBO_BINDING;
descriptor_set_layout_bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_set_layout_bindings[0].descriptorCount = 1;
descriptor_set_layout_bindings[0].stageFlags =
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_COMPUTE_BIT;
descriptor_set_layout_bindings[0].pImmutableSamplers = nullptr;
// our model matrix which updates every frame for each object
descriptor_set_layout_bindings[1].binding = sceneUBO_BINDING;
descriptor_set_layout_bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_set_layout_bindings[1].descriptorCount = 1;
descriptor_set_layout_bindings[1].stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
| VK_SHADER_STAGE_RAYGEN_BIT_KHR
| VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_COMPUTE_BIT;
descriptor_set_layout_bindings[1].pImmutableSamplers = nullptr;
descriptor_set_layout_bindings[2].binding = OBJECT_DESCRIPTION_BINDING;
descriptor_set_layout_bindings[2].descriptorCount = 1;
descriptor_set_layout_bindings[2].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
descriptor_set_layout_bindings[2].pImmutableSamplers = nullptr;
// load them into the raygeneration and chlosest hit shader
descriptor_set_layout_bindings[2].stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT
| VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_COMPUTE_BIT;
// CREATE TEXTURE SAMPLER DESCRIPTOR SET LAYOUT
// texture binding info
descriptor_set_layout_bindings[3].binding = SAMPLER_BINDING;
descriptor_set_layout_bindings[3].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
descriptor_set_layout_bindings[3].descriptorCount = MAX_TEXTURE_COUNT;
descriptor_set_layout_bindings[3].stageFlags =
VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_COMPUTE_BIT;
descriptor_set_layout_bindings[3].pImmutableSamplers = nullptr;
descriptor_set_layout_bindings[4].binding = TEXTURES_BINDING;
descriptor_set_layout_bindings[4].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
descriptor_set_layout_bindings[4].descriptorCount = MAX_TEXTURE_COUNT;
descriptor_set_layout_bindings[4].stageFlags =
VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_COMPUTE_BIT;
descriptor_set_layout_bindings[4].pImmutableSamplers = nullptr;
// create descriptor set layout with given bindings
VkDescriptorSetLayoutCreateInfo layout_create_info{};
layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layout_create_info.bindingCount = static_cast<uint32_t>(descriptor_set_layout_bindings.size());
layout_create_info.pBindings = descriptor_set_layout_bindings.data();
// create descriptor set layout
VkResult result = vkCreateDescriptorSetLayout(
device->getLogicalDevice(), &layout_create_info, nullptr, &sharedRenderDescriptorSetLayout);
ASSERT_VULKAN(result, "Failed to create descriptor set layout!")
}
void Kataglyphis::VulkanRenderer::create_command_pool()
{
// get indices of queue familes from device
Kataglyphis::VulkanRendererInternals::QueueFamilyIndices queue_family_indices = device->getQueueFamilies();
{
VkCommandPoolCreateInfo pool_info{};
pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;// we are ready now to
// re-record our
// command buffers
pool_info.queueFamilyIndex = queue_family_indices.graphics_family;// queue family type that buffers from this
// command pool will use
// create a graphics queue family command pool
VkResult result = vkCreateCommandPool(device->getLogicalDevice(), &pool_info, nullptr, &graphics_command_pool);
ASSERT_VULKAN(result, "Failed to create command pool!")
}
{
VkCommandPoolCreateInfo pool_info{};
pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;// we are ready now to
// re-record our
// command buffers
pool_info.queueFamilyIndex = queue_family_indices.compute_family;// queue family type that buffers
// from this command pool will use
// create a graphics queue family command pool
VkResult result = vkCreateCommandPool(device->getLogicalDevice(), &pool_info, nullptr, &compute_command_pool);
ASSERT_VULKAN(result, "Failed to create command pool!")
}
}
void Kataglyphis::VulkanRenderer::cleanUpCommandPools()
{
vkDestroyCommandPool(device->getLogicalDevice(), graphics_command_pool, nullptr);
vkDestroyCommandPool(device->getLogicalDevice(), compute_command_pool, nullptr);
}
void Kataglyphis::VulkanRenderer::create_command_buffers()
{
// resize command buffer count to have one for each framebuffer
command_buffers.resize(vulkanSwapChain.getNumberSwapChainImages());
VkCommandBufferAllocateInfo command_buffer_alloc_info{};
command_buffer_alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
command_buffer_alloc_info.commandPool = graphics_command_pool;
command_buffer_alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
command_buffer_alloc_info.commandBufferCount = static_cast<uint32_t>(command_buffers.size());
VkResult result =
vkAllocateCommandBuffers(device->getLogicalDevice(), &command_buffer_alloc_info, command_buffers.data());
ASSERT_VULKAN(result, "Failed to allocate command buffers!")
}
void Kataglyphis::VulkanRenderer::createSynchronization()
{
image_available.resize(vulkanSwapChain.getNumberSwapChainImages(), VK_NULL_HANDLE);
render_finished.resize(vulkanSwapChain.getNumberSwapChainImages(), VK_NULL_HANDLE);
in_flight_fences.resize(vulkanSwapChain.getNumberSwapChainImages(), VK_NULL_HANDLE);
images_in_flight_fences.resize(vulkanSwapChain.getNumberSwapChainImages(), VK_NULL_HANDLE);
// semaphore creation information
VkSemaphoreCreateInfo semaphore_create_info{};
semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
// fence creation information
VkFenceCreateInfo fence_create_info{};
fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fence_create_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
for (int i = 0; i < Kataglyphis::MAX_FRAME_DRAWS; i++) {
if ((vkCreateSemaphore(device->getLogicalDevice(), &semaphore_create_info, nullptr, &image_available[i])
!= VK_SUCCESS)
|| (vkCreateSemaphore(device->getLogicalDevice(), &semaphore_create_info, nullptr, &render_finished[i])
!= VK_SUCCESS)
|| (vkCreateFence(device->getLogicalDevice(), &fence_create_info, nullptr, &in_flight_fences[i])
!= VK_SUCCESS)) {
spdlog::error("Failed to create a semaphore and/or fence!");
}
}
}
void Kataglyphis::VulkanRenderer::create_uniform_buffers()
{
// one uniform buffer for each image (and by extension, command buffer)
globalUBOBuffer.resize(vulkanSwapChain.getNumberSwapChainImages());
sceneUBOBuffer.resize(vulkanSwapChain.getNumberSwapChainImages());
// VulkanBuffer stagingBuffer;
std::vector<VulkanRendererInternals::GlobalUBO> globalUBOdata;
globalUBOdata.push_back(globalUBO);
std::vector<VulkanRendererInternals::SceneUBO> sceneUBOdata;
sceneUBOdata.push_back(sceneUBO);
// create uniform buffers
for (size_t i = 0; i < vulkanSwapChain.getNumberSwapChainImages(); i++) {
vulkanBufferManager.createBufferAndUploadVectorOnDevice(device.get(),
graphics_command_pool,
globalUBOBuffer[i],
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
globalUBOdata);
vulkanBufferManager.createBufferAndUploadVectorOnDevice(device.get(),
graphics_command_pool,
sceneUBOBuffer[i],
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
sceneUBOdata);
}
}
void Kataglyphis::VulkanRenderer::createDescriptorPoolSharedRenderStages()
{
// CREATE UNIFORM DESCRIPTOR POOL
// type of descriptors + how many descriptors, not descriptor sets (combined
// makes the pool size) ViewProjection Pool
VkDescriptorPoolSize vp_pool_size{};
vp_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
vp_pool_size.descriptorCount = static_cast<uint32_t>(globalUBOBuffer.size());
// DIRECTION POOL
VkDescriptorPoolSize directions_pool_size{};
directions_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
directions_pool_size.descriptorCount = static_cast<uint32_t>(sceneUBOBuffer.size());
VkDescriptorPoolSize object_descriptions_pool_size{};
object_descriptions_pool_size.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
object_descriptions_pool_size.descriptorCount =
static_cast<uint32_t>(sizeof(ObjectDescription) * Kataglyphis::MAX_OBJECTS);
// TEXTURE SAMPLER POOL
VkDescriptorPoolSize sampler_pool_size{};
sampler_pool_size.type = VK_DESCRIPTOR_TYPE_SAMPLER;
sampler_pool_size.descriptorCount = MAX_TEXTURE_COUNT;
VkDescriptorPoolSize sampled_image_pool_size{};
sampled_image_pool_size.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
sampled_image_pool_size.descriptorCount = MAX_TEXTURE_COUNT;
// list of pool sizes
std::vector<VkDescriptorPoolSize> descriptor_pool_sizes = {
vp_pool_size, directions_pool_size, object_descriptions_pool_size, sampler_pool_size, sampled_image_pool_size
};
VkDescriptorPoolCreateInfo pool_create_info{};
pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
pool_create_info.maxSets = vulkanSwapChain.getNumberSwapChainImages();// maximum number of descriptor sets
// that can be created from pool
pool_create_info.poolSizeCount =
static_cast<uint32_t>(descriptor_pool_sizes.size());// amount of pool sizes being passed
pool_create_info.pPoolSizes = descriptor_pool_sizes.data();// pool sizes to create pool with
// create descriptor pool
VkResult result =
vkCreateDescriptorPool(device->getLogicalDevice(), &pool_create_info, nullptr, &descriptorPoolSharedRenderStages);
ASSERT_VULKAN(result, "Failed to create a descriptor pool!")
}
void Kataglyphis::VulkanRenderer::createSharedRenderDescriptorSet()
{
// resize descriptor set list so one for every buffer
sharedRenderDescriptorSet.resize(vulkanSwapChain.getNumberSwapChainImages());
std::vector<VkDescriptorSetLayout> set_layouts(
vulkanSwapChain.getNumberSwapChainImages(), sharedRenderDescriptorSetLayout);
// descriptor set allocation info
VkDescriptorSetAllocateInfo set_alloc_info{};
set_alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
set_alloc_info.descriptorPool = descriptorPoolSharedRenderStages;// pool to allocate descriptor set from
set_alloc_info.descriptorSetCount = vulkanSwapChain.getNumberSwapChainImages();// number of sets to allocate
set_alloc_info.pSetLayouts = set_layouts.data();// layouts to use to allocate sets (1:1 relationship)
// allocate descriptor sets (multiple)
VkResult result =
vkAllocateDescriptorSets(device->getLogicalDevice(), &set_alloc_info, sharedRenderDescriptorSet.data());
ASSERT_VULKAN(result, "Failed to create descriptor sets!")
// update all of descriptor set buffer bindings
for (size_t i = 0; i < vulkanSwapChain.getNumberSwapChainImages(); i++) {
// VIEW PROJECTION DESCRIPTOR
// buffer info and data offset info
VkDescriptorBufferInfo globalUBO_buffer_info{};
globalUBO_buffer_info.buffer = globalUBOBuffer[i].getBuffer();// buffer to get data from
globalUBO_buffer_info.offset = 0;// position of start of data
globalUBO_buffer_info.range = sizeof(globalUBO);// size of data
// data about connection between binding and buffer
VkWriteDescriptorSet globalUBO_set_write{};
globalUBO_set_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
globalUBO_set_write.dstSet = sharedRenderDescriptorSet[i];// descriptor set to update
globalUBO_set_write.dstBinding = 0;// binding to update (matches with binding on layout/shader)
globalUBO_set_write.dstArrayElement = 0;// index in array to update
globalUBO_set_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;// type of descriptor
globalUBO_set_write.descriptorCount = 1;// amount to update
globalUBO_set_write.pBufferInfo = &globalUBO_buffer_info;// information about buffer data to bind
// VIEW PROJECTION DESCRIPTOR
// buffer info and data offset info
VkDescriptorBufferInfo sceneUBO_buffer_info{};
sceneUBO_buffer_info.buffer = sceneUBOBuffer[i].getBuffer();// buffer to get data from
sceneUBO_buffer_info.offset = 0;// position of start of data
sceneUBO_buffer_info.range = sizeof(sceneUBO);// size of data
// data about connection between binding and buffer
VkWriteDescriptorSet sceneUBO_set_write{};
sceneUBO_set_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
sceneUBO_set_write.dstSet = sharedRenderDescriptorSet[i];// descriptor set to update
sceneUBO_set_write.dstBinding = 1;// binding to update (matches with binding on layout/shader)
sceneUBO_set_write.dstArrayElement = 0;// index in array to update
sceneUBO_set_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;// type of descriptor
sceneUBO_set_write.descriptorCount = 1;// amount to update
sceneUBO_set_write.pBufferInfo = &sceneUBO_buffer_info;// information about buffer data to bind
std::vector<VkWriteDescriptorSet> write_descriptor_sets = { globalUBO_set_write, sceneUBO_set_write };
// update the descriptor sets with new buffer/binding info
vkUpdateDescriptorSets(device->getLogicalDevice(),
static_cast<uint32_t>(write_descriptor_sets.size()),
write_descriptor_sets.data(),
0,
nullptr);
}
}
void Kataglyphis::VulkanRenderer::updateTexturesInSharedRenderDescriptorSet()
{
std::vector<Texture> &modelTextures = scene->getTextures(0);
std::vector<VkDescriptorImageInfo> image_info_textures;
image_info_textures.resize(scene->getTextureCount(0));
for (uint32_t i = 0; i < scene->getTextureCount(0); i++) {
image_info_textures[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
image_info_textures[i].imageView = modelTextures[i].getImageView();
image_info_textures[i].sampler = nullptr;
}
std::vector<VkSampler> &modelTextureSampler = scene->getTextureSampler(0);
std::vector<VkDescriptorImageInfo> image_info_texture_sampler;
image_info_texture_sampler.resize(scene->getTextureCount(0));
for (uint32_t i = 0; i < scene->getTextureCount(0); i++) {
image_info_texture_sampler[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
image_info_texture_sampler[i].imageView = nullptr;
image_info_texture_sampler[i].sampler = modelTextureSampler[i];
}
for (uint32_t i = 0; i < vulkanSwapChain.getNumberSwapChainImages(); i++) {
// descriptor write info
VkWriteDescriptorSet descriptor_write{};
descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptor_write.dstSet = sharedRenderDescriptorSet[i];
descriptor_write.dstBinding = TEXTURES_BINDING;
descriptor_write.dstArrayElement = 0;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
descriptor_write.descriptorCount = static_cast<uint32_t>(image_info_textures.size());
descriptor_write.pImageInfo = image_info_textures.data();
/*VkDescriptorImageInfo sampler_info;
sampler_info.imageView = nullptr;
sampler_info.sampler = texture_sampler;*/
// descriptor write info
VkWriteDescriptorSet descriptor_write_sampler{};
descriptor_write_sampler.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptor_write_sampler.dstSet = sharedRenderDescriptorSet[i];
descriptor_write_sampler.dstBinding = SAMPLER_BINDING;
descriptor_write_sampler.dstArrayElement = 0;
descriptor_write_sampler.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
descriptor_write_sampler.descriptorCount = static_cast<uint32_t>(image_info_texture_sampler.size());
descriptor_write_sampler.pImageInfo = image_info_texture_sampler.data();
std::vector<VkWriteDescriptorSet> write_descriptor_sets = { descriptor_write, descriptor_write_sampler };
// update new descriptor set
vkUpdateDescriptorSets(device->getLogicalDevice(),
static_cast<uint32_t>(write_descriptor_sets.size()),
write_descriptor_sets.data(),
0,
nullptr);
}
}
void Kataglyphis::VulkanRenderer::cleanUpUBOs()
{
for (VulkanBuffer vulkanBuffer : globalUBOBuffer) { vulkanBuffer.cleanUp(); }
for (VulkanBuffer vulkanBuffer : sceneUBOBuffer) { vulkanBuffer.cleanUp(); }
}
void Kataglyphis::VulkanRenderer::update_uniform_buffers(uint32_t image_index)
{
auto usage_stage_flags = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR
| VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
VkBufferMemoryBarrier before_barrier_uvp{};
before_barrier_uvp.pNext = nullptr;
before_barrier_uvp.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
before_barrier_uvp.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
before_barrier_uvp.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
before_barrier_uvp.buffer = globalUBOBuffer[image_index].getBuffer();
before_barrier_uvp.offset = 0;
before_barrier_uvp.size = sizeof(globalUBO);
before_barrier_uvp.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
before_barrier_uvp.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
VkBufferMemoryBarrier before_barrier_directions{};
before_barrier_directions.pNext = nullptr;
before_barrier_directions.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
before_barrier_directions.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
before_barrier_directions.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
before_barrier_directions.buffer = globalUBOBuffer[image_index].getBuffer();
before_barrier_directions.offset = 0;
before_barrier_directions.size = sizeof(sceneUBO);
before_barrier_directions.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
before_barrier_directions.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vkCmdPipelineBarrier(command_buffers[image_index],
usage_stage_flags,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0,
nullptr,
1,
&before_barrier_uvp,
0,
nullptr);
vkCmdPipelineBarrier(command_buffers[image_index],
usage_stage_flags,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0,
nullptr,
1,
&before_barrier_directions,
0,
nullptr);
vkCmdUpdateBuffer(command_buffers[image_index],
globalUBOBuffer[image_index].getBuffer(),
0,
sizeof(VulkanRendererInternals::GlobalUBO),
&globalUBO);
vkCmdUpdateBuffer(command_buffers[image_index],
sceneUBOBuffer[image_index].getBuffer(),
0,
sizeof(VulkanRendererInternals::SceneUBO),
&sceneUBO);
VkBufferMemoryBarrier after_barrier_uvp{};
after_barrier_uvp.pNext = nullptr;
after_barrier_uvp.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
after_barrier_uvp.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
after_barrier_uvp.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
after_barrier_uvp.buffer = globalUBOBuffer[image_index].getBuffer();
after_barrier_uvp.offset = 0;
after_barrier_uvp.size = sizeof(VulkanRendererInternals::GlobalUBO);
after_barrier_uvp.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
after_barrier_uvp.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
VkBufferMemoryBarrier after_barrier_directions{};
after_barrier_directions.pNext = nullptr;
after_barrier_directions.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
after_barrier_directions.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
after_barrier_directions.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
after_barrier_directions.buffer = globalUBOBuffer[image_index].getBuffer();
after_barrier_directions.offset = 0;
after_barrier_directions.size = sizeof(VulkanRendererInternals::SceneUBO);
after_barrier_directions.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
after_barrier_directions.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vkCmdPipelineBarrier(command_buffers[image_index],
VK_PIPELINE_STAGE_TRANSFER_BIT,
usage_stage_flags,
0,
0,
nullptr,
1,
&after_barrier_uvp,
0,
nullptr);
vkCmdPipelineBarrier(command_buffers[image_index],
VK_PIPELINE_STAGE_TRANSFER_BIT,
usage_stage_flags,
0,
0,
nullptr,
1,
&after_barrier_directions,
0,
nullptr);
}
void Kataglyphis::VulkanRenderer::update_raytracing_descriptor_set(uint32_t image_index)
{
VkWriteDescriptorSetAccelerationStructureKHR descriptor_set_acceleration_structure{};
descriptor_set_acceleration_structure.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR;
descriptor_set_acceleration_structure.pNext = nullptr;
descriptor_set_acceleration_structure.accelerationStructureCount = 1;
VkAccelerationStructureKHR &tlasAS = asManager.getTLAS();
descriptor_set_acceleration_structure.pAccelerationStructures = &tlasAS;
VkWriteDescriptorSet write_descriptor_set_acceleration_structure{};
write_descriptor_set_acceleration_structure.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write_descriptor_set_acceleration_structure.pNext = &descriptor_set_acceleration_structure;
write_descriptor_set_acceleration_structure.dstSet = raytracingDescriptorSet[image_index];
write_descriptor_set_acceleration_structure.dstBinding = TLAS_BINDING;
write_descriptor_set_acceleration_structure.dstArrayElement = 0;
write_descriptor_set_acceleration_structure.descriptorCount = 1;
write_descriptor_set_acceleration_structure.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
write_descriptor_set_acceleration_structure.pImageInfo = nullptr;
write_descriptor_set_acceleration_structure.pBufferInfo = nullptr;
write_descriptor_set_acceleration_structure.pTexelBufferView = nullptr;
VkDescriptorBufferInfo object_description_buffer_info{};
object_description_buffer_info.buffer = objectDescriptionBuffer.getBuffer();
object_description_buffer_info.offset = 0;
object_description_buffer_info.range = VK_WHOLE_SIZE;
VkWriteDescriptorSet object_description_buffer_write{};
object_description_buffer_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
object_description_buffer_write.dstSet = sharedRenderDescriptorSet[image_index];
object_description_buffer_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
object_description_buffer_write.dstBinding = OBJECT_DESCRIPTION_BINDING;
object_description_buffer_write.pBufferInfo = &object_description_buffer_info;
object_description_buffer_write.descriptorCount = 1;
std::vector<VkWriteDescriptorSet> write_descriptor_sets = { write_descriptor_set_acceleration_structure,
object_description_buffer_write };
vkUpdateDescriptorSets(device->getLogicalDevice(),
static_cast<uint32_t>(write_descriptor_sets.size()),
write_descriptor_sets.data(),
0,
nullptr);
}
void Kataglyphis::VulkanRenderer::record_commands(uint32_t image_index)
{
Texture &renderResult = rasterizer.getOffscreenTexture(image_index);
VulkanImage &vulkanImage = renderResult.getVulkanImage();
Kataglyphis::VulkanRendererInternals::FrontendShared::GUIRendererSharedVars &guiRendererSharedVars =
gui->getGuiRendererSharedVars();
if (guiRendererSharedVars.raytracing) {
std::vector<VkDescriptorSet> sets = { sharedRenderDescriptorSet[image_index],
raytracingDescriptorSet[image_index] };
raytracingStage.recordCommands(command_buffers[image_index], &vulkanSwapChain, sets);
} else if (guiRendererSharedVars.pathTracing) {
std::vector<VkDescriptorSet> sets = { sharedRenderDescriptorSet[image_index],
raytracingDescriptorSet[image_index] };
pathTracing.recordCommands(command_buffers[image_index], image_index, vulkanImage, &vulkanSwapChain, sets);
} else {
std::vector<VkDescriptorSet> descriptorSets = { sharedRenderDescriptorSet[image_index] };
rasterizer.recordCommands(command_buffers[image_index], image_index, scene, descriptorSets);
}
vulkanImage.transitionImageLayout(command_buffers[image_index],
VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
1,
VK_IMAGE_ASPECT_COLOR_BIT);
std::vector<VkDescriptorSet> descriptorSets = { post_descriptor_set[image_index] };
postStage.recordCommands(command_buffers[image_index], image_index, descriptorSets);
vulkanImage.transitionImageLayout(command_buffers[image_index],
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_IMAGE_LAYOUT_GENERAL,
1,
VK_IMAGE_ASPECT_COLOR_BIT);
}
bool Kataglyphis::VulkanRenderer::checkChangedFramebufferSize()
{
if (window->framebuffer_size_has_changed()) {
vkDeviceWaitIdle(device->getLogicalDevice());
vkQueueWaitIdle(device->getGraphicsQueue());
vulkanSwapChain.cleanUp();
vulkanSwapChain.initVulkanContext(device.get(), window, surface);
std::vector<VkDescriptorSetLayout> descriptor_set_layouts = { sharedRenderDescriptorSetLayout };
rasterizer.cleanUp();
rasterizer.init(device.get(), &vulkanSwapChain, descriptor_set_layouts, graphics_command_pool);
// all post
std::vector<VkDescriptorSetLayout> descriptorSets = { post_descriptor_set_layout };
postStage.cleanUp();
postStage.init(device.get(), &vulkanSwapChain, descriptorSets);
gui->cleanUp();
gui->initializeVulkanContext(
device.get(), instance.getVulkanInstance(), postStage.getRenderPass(), graphics_command_pool);
current_frame = 0;
updatePostDescriptorSets();
if (device->supportsHardwareAcceleratedRRT()) { updateRaytracingDescriptorSets(); }
window->reset_framebuffer_has_changed();
return true;
}
return false;
}
void Kataglyphis::VulkanRenderer::cleanUp()
{
cleanUpUBOs();
rasterizer.cleanUp();
raytracingStage.cleanUp();
postStage.cleanUp();
pathTracing.cleanUp();
objectDescriptionBuffer.cleanUp();
asManager.cleanUp();
vkDestroyDescriptorSetLayout(device->getLogicalDevice(), raytracingDescriptorSetLayout, nullptr);
vkDestroyDescriptorSetLayout(device->getLogicalDevice(), post_descriptor_set_layout, nullptr);
vkDestroyDescriptorSetLayout(device->getLogicalDevice(), sharedRenderDescriptorSetLayout, nullptr);
vkDestroyDescriptorPool(device->getLogicalDevice(), post_descriptor_pool, nullptr);
vkDestroyDescriptorPool(device->getLogicalDevice(), descriptorPoolSharedRenderStages, nullptr);
vkDestroyDescriptorPool(device->getLogicalDevice(), raytracingDescriptorPool, nullptr);
vkFreeCommandBuffers(device->getLogicalDevice(),
graphics_command_pool,
static_cast<uint32_t>(command_buffers.size()),
command_buffers.data());
cleanUpCommandPools();
cleanUpSync();
vulkanSwapChain.cleanUp();
vkDestroySurfaceKHR(instance.getVulkanInstance(), surface, nullptr);
allocator.cleanUp();
device->cleanUp();
debug::freeDebugCallback(instance.getVulkanInstance());
instance.cleanUp();
}
Kataglyphis::VulkanRenderer::~VulkanRenderer() {}