aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/rt.hpp2
-rw-r--r--include/vk-renderer.hpp75
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/main.cpp370
-rw-r--r--src/vk-renderer.cpp346
5 files changed, 428 insertions, 366 deletions
diff --git a/include/rt.hpp b/include/rt.hpp
index d368ba5..570fc42 100644
--- a/include/rt.hpp
+++ b/include/rt.hpp
@@ -35,6 +35,6 @@ inline double clamp(double x, double min, double max) {
#include "lambertian.hpp"
#include "metal.hpp"
#include "dielectric.hpp"
-#include "utils.hpp"
+#include "hittable_list.hpp"
#endif // !__RT_HPP_
diff --git a/include/vk-renderer.hpp b/include/vk-renderer.hpp
new file mode 100644
index 0000000..c54009f
--- /dev/null
+++ b/include/vk-renderer.hpp
@@ -0,0 +1,75 @@
+#ifndef __VK_RENDERER_HPP_
+#define __VK_RENDERER_HPP_
+
+#include "vulkan-loader.hpp"
+#include "thirdparty/vk_mem_alloc.h"
+
+#include "vec3.hpp"
+
+struct input_data {
+ color sky_color;
+ color ground_color;
+
+ float viewport_width;
+ float viewport_height;
+ float pad1;
+ float pad2;
+};
+struct path_tracer_data {
+ struct input_data inputs;
+ color output_image[1920 * 1080];
+};
+
+class vkrenderer {
+ public:
+ vkrenderer();
+
+ void compute(const input_data& inputs, size_t width, size_t height);
+
+ const color* const output_image();
+
+ private:
+ void create_instance();
+
+ void create_debugger();
+
+ void create_device();
+
+ void create_pipeline();
+
+ void create_memory_allocator();
+
+ void create_command_buffer();
+
+ void create_descriptor_set();
+
+ void select_physical_device();
+
+ void select_compute_queue();
+
+ void fill_descriptor_set(const input_data& data);
+
+ uint32_t compute_queue_index;
+
+ VkInstance instance;
+ VkPhysicalDevice physical_device;
+ VkDevice device;
+ VkQueue compute_queue;
+
+ VmaAllocator allocator;
+ VkBuffer compute_shader_buffer;
+
+ VkCommandPool command_pool;
+ VkCommandBuffer command_buffer;
+
+ VkDescriptorPool descriptor_pool;
+ VkDescriptorSet compute_shader_input_set;
+
+ VkDescriptorSetLayout compute_shader_input_layout;
+ VkPipelineLayout compute_pipeline_layout;
+ VkPipeline compute_pipeline;
+
+ struct path_tracer_data* mapped_data;
+};
+
+#endif // !__VK_RENDERER_HPP_
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 801d4f1..c185ebe 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -15,6 +15,7 @@ add_executable(
dielectric.cpp
vulkan-loader.cpp
utils.cpp
+ vk-renderer.cpp
)
if(UNIX)
diff --git a/src/main.cpp b/src/main.cpp
index 53d116c..7dcf801 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -3,13 +3,9 @@
#include <cstring>
#include <cstdio>
-#include "vulkan-loader.hpp"
-
-#define VMA_IMPLEMENTATION
-#include "thirdparty/vk_mem_alloc.h"
+#include "vk-renderer.hpp"
#include "rt.hpp"
-#include "hittable_list.hpp"
color ground_color { 1.0, 1.0, 1.0 };
color sky_color { 0.5, 0.7, 1.0 };
@@ -81,362 +77,8 @@ color ray_color(ray& r, const hittable& world, uint32_t depth) {
return lerp(ground_color, sky_color, t);
}
-VkInstance instance = nullptr;
-VkPhysicalDevice physical_device = nullptr;
-int32_t compute_queue_index = -1;
-VkDevice device = nullptr;
-VkQueue compute_queue = nullptr;
-
-VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT _severity,
- VkDebugUtilsMessageTypeFlagsEXT _type,
- const VkDebugUtilsMessengerCallbackDataEXT *_data,
- void *_userData)
-{
- std::cerr << _data->pMessage << std::endl;
- return VK_FALSE;
-}
-
-void create_debugger(VkInstance instance) {
- VkDebugUtilsMessengerEXT debugMessenger;
- VkDebugUtilsMessengerCreateInfoEXT debugUtilsMessengeCreateInfo {
- VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
- nullptr,
- 0,
- VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT,
- VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT
- | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
- DebugCallback,
- nullptr,
- };
-
- vkCreateDebugUtilsMessengerEXT(
- instance,
- &debugUtilsMessengeCreateInfo,
- nullptr,
- &debugMessenger
- );
-}
-
-void create_instance() {
- VkApplicationInfo app_info = {};
- app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
- app_info.pApplicationName = "path-tracer";
- app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
- app_info.pEngineName = "gpu-path-tracer";
- app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0);
- app_info.apiVersion = VK_API_VERSION_1_2;
-
-
- const char* layers[1] = {
- "VK_LAYER_KHRONOS_validation",
- };
- const char* ext[1] = {
- VK_EXT_DEBUG_UTILS_EXTENSION_NAME
- };
- VkInstanceCreateInfo instance_create_info = {};
- instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
- instance_create_info.pApplicationInfo = &app_info;
- instance_create_info.enabledLayerCount = 1;
- instance_create_info.ppEnabledLayerNames = layers;
- instance_create_info.enabledExtensionCount = 1;
- instance_create_info.ppEnabledExtensionNames = ext;
-
- vkCreateInstance(&instance_create_info, nullptr, &instance);
-
- load_instance_functions(instance);
- create_debugger(instance);
-
- std::cerr << "Instance ready" << std::endl;
-}
-
-void select_physical_device() {
- uint32_t physical_devices_count = 0;
- vkEnumeratePhysicalDevices(instance, &physical_devices_count, nullptr);
-
- if (physical_devices_count < 1) {
- std::cerr << "No physical device found !" << std::endl;
- exit(1);
- }
-
- std::vector<VkPhysicalDevice> physical_devices { physical_devices_count };
- vkEnumeratePhysicalDevices(instance, &physical_devices_count, physical_devices.data());
-
- physical_device = physical_devices[0];
-}
-
-int32_t get_compute_queue_index() {
- uint32_t queue_properties_count = 0;
- vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_properties_count, nullptr);
-
- std::vector<VkQueueFamilyProperties> queue_properties { queue_properties_count };
- vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_properties_count, queue_properties.data());
-
- for (uint32_t properties_index = 0; properties_index < queue_properties_count; properties_index++) {
- if (queue_properties[properties_index].queueFlags & VK_QUEUE_COMPUTE_BIT) {
- return properties_index;
- }
- }
-
- return -1;
-}
-
-void create_device() {
- select_physical_device();
-
- compute_queue_index = get_compute_queue_index();
- VkDeviceQueueCreateInfo queue_create_info = {};
- queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
- queue_create_info.queueFamilyIndex = compute_queue_index;
- queue_create_info.queueCount = 1;
-
- float queue_priority = 1.f;
- queue_create_info.pQueuePriorities = &queue_priority;
-
- VkPhysicalDeviceFeatures device_features = {};
-
- VkDeviceCreateInfo device_create_info = {};
- device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
- device_create_info.pQueueCreateInfos = &queue_create_info;
- device_create_info.queueCreateInfoCount = 1;
- device_create_info.pEnabledFeatures = &device_features;
- device_create_info.enabledExtensionCount = 0; // None yet
- device_create_info.enabledLayerCount = 0; // https://www.khronos.org/registry/vulkan/specs/1.2/html/chap31.html#extendingvulkan-layers-devicelayerdeprecation
-
- vkCreateDevice(physical_device, &device_create_info, nullptr, &device);
-
- load_device_functions(device);
-
- vkGetDeviceQueue(device, compute_queue_index, 0, &compute_queue);
-
- std::cerr << "Device ready" << std::endl;
-}
-
-VkPipeline compute_pipeline = nullptr;
-VkDescriptorSetLayout compute_shader_input_layout = nullptr;
-VkPipelineLayout compute_pipeline_layout = nullptr;
-void create_pipeline() {
- std::vector<uint8_t> shader_code = get_shader_code("./shaders/compute.comp.spv");
- if (shader_code.size() == 0) {
- exit(1);
- }
-
- VkShaderModule compute_shader_module;
- VkShaderModuleCreateInfo shader_create_info = {};
- shader_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
- shader_create_info.pNext = nullptr;
- shader_create_info.flags = 0;
- shader_create_info.codeSize = shader_code.size();
- shader_create_info.pCode = (uint32_t*)shader_code.data();
-
- vkCreateShaderModule(device, &shader_create_info, nullptr, &compute_shader_module);
-
- VkPipelineShaderStageCreateInfo stage_create_info = {};
- stage_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- stage_create_info.pNext = nullptr;
- stage_create_info.flags = 0;
- stage_create_info.stage = VK_SHADER_STAGE_COMPUTE_BIT;
- stage_create_info.module = compute_shader_module;
- stage_create_info.pName = "main";
- stage_create_info.pSpecializationInfo = nullptr;
-
- VkDescriptorSetLayoutBinding binding = {};
- binding.binding = 0;
- binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- binding.descriptorCount = 1;
- binding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
- binding.pImmutableSamplers = 0;
-
- 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.pNext = nullptr;
- descriptor_set_layout_create_info.flags = 0;
- descriptor_set_layout_create_info.bindingCount = 1;
- descriptor_set_layout_create_info.pBindings = &binding;
-
- vkCreateDescriptorSetLayout(device, &descriptor_set_layout_create_info, nullptr, &compute_shader_input_layout);
-
- VkPipelineLayoutCreateInfo layout_create_info = {};
- layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
- layout_create_info.pNext = nullptr;
- layout_create_info.flags = 0;
- layout_create_info.setLayoutCount = 1;
- layout_create_info.pSetLayouts = &compute_shader_input_layout;
- layout_create_info.pushConstantRangeCount = 0;
- layout_create_info.pPushConstantRanges = nullptr;
-
- vkCreatePipelineLayout(device, &layout_create_info, nullptr, &compute_pipeline_layout);
-
- VkComputePipelineCreateInfo create_info = {};
- create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
- create_info.pNext = nullptr;
- create_info.flags = 0;
- create_info.stage = stage_create_info;
- create_info.layout = compute_pipeline_layout;
-
- vkCreateComputePipelines(
- device,
- VK_NULL_HANDLE,
- 1,
- &create_info,
- nullptr,
- &compute_pipeline
- );
-
- std::cerr << "Compute pipeline ready" << std::endl;
-}
-
-VmaAllocator allocator = nullptr;
-void create_memory_allocator() {
- VmaAllocatorCreateInfo allocator_info = {};
- allocator_info.vulkanApiVersion = VK_API_VERSION_1_2;
- allocator_info.physicalDevice = physical_device;
- allocator_info.device = device;
- allocator_info.instance = instance;
-
- vmaCreateAllocator(&allocator_info, &allocator);
-}
-
-VkCommandPool command_pool = nullptr;
-VkCommandBuffer cmd_buf = nullptr;
-void create_command_buffer() {
- VkCommandPoolCreateInfo cmd_pool_create_info = {};
- cmd_pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
- cmd_pool_create_info.pNext = nullptr;
- cmd_pool_create_info.flags = 0;
- cmd_pool_create_info.queueFamilyIndex = compute_queue_index;
-
- vkCreateCommandPool(device, &cmd_pool_create_info, nullptr, &command_pool);
-
- VkCommandBufferAllocateInfo cmd_buf_allocate_info = {};
- cmd_buf_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
- cmd_buf_allocate_info.pNext = nullptr;
- cmd_buf_allocate_info.commandPool = command_pool;
- cmd_buf_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
- cmd_buf_allocate_info.commandBufferCount = 1;
-
- vkAllocateCommandBuffers(device, &cmd_buf_allocate_info, &cmd_buf);
-}
-
-VkDescriptorPool descriptor_pool = nullptr;
-VkDescriptorSet compute_shader_input_set = nullptr;
-void create_descriptor_set() {
- VkDescriptorPoolSize descriptor_pool_size = {};
- descriptor_pool_size.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- descriptor_pool_size.descriptorCount = 1;
-
- VkDescriptorPoolCreateInfo descriptor_pool_create_info = {};
- descriptor_pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
- descriptor_pool_create_info.pNext = nullptr;
- descriptor_pool_create_info.flags = 0;
- descriptor_pool_create_info.maxSets = 1;
- descriptor_pool_create_info.poolSizeCount = 1;
- descriptor_pool_create_info.pPoolSizes = &descriptor_pool_size;
-
- vkCreateDescriptorPool(device, &descriptor_pool_create_info, nullptr, &descriptor_pool);
-
- VkDescriptorSetAllocateInfo descriptor_set_allocate_info = {};
- descriptor_set_allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
- descriptor_set_allocate_info.pNext = nullptr;
- descriptor_set_allocate_info.descriptorPool = descriptor_pool;
- descriptor_set_allocate_info.descriptorSetCount = 1;
- descriptor_set_allocate_info.pSetLayouts = &compute_shader_input_layout;
-
- vkAllocateDescriptorSets(device, &descriptor_set_allocate_info, &compute_shader_input_set);
-}
-
-struct input_data {
- color sky_color;
- color ground_color;
- float viewport_width;
- float viewport_height;
- float pad1;
- float pad2;
-};
-struct path_tracer_data {
- struct input_data inputs;
- color output_image[1920 * 1080];
-};
-
-struct path_tracer_data* mapped_data;
-VkBuffer compute_shader_input_buffer;
-void fill_descriptor_set(const input_data& inputs) {
- VkBufferCreateInfo buffer_info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
- buffer_info.size = sizeof(path_tracer_data);
- buffer_info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
-
- VmaAllocationCreateInfo alloc_create_info = {};
- alloc_create_info.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
-
- VmaAllocation allocation;
- vmaCreateBuffer(allocator, &buffer_info, &alloc_create_info, &compute_shader_input_buffer, &allocation, nullptr);
-
- vmaMapMemory(allocator, allocation, (void**) &mapped_data);
- std::memcpy(&mapped_data->inputs, &inputs, sizeof(inputs));
-
- VkDescriptorBufferInfo descriptor_buf_info = {};
- descriptor_buf_info.buffer = compute_shader_input_buffer;
- descriptor_buf_info.offset = 0;
- descriptor_buf_info.range = VK_WHOLE_SIZE;
-
- VkWriteDescriptorSet write_descriptor_set = {};
- write_descriptor_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- write_descriptor_set.pNext = nullptr;
- write_descriptor_set.dstSet = compute_shader_input_set;
- write_descriptor_set.dstBinding = 0;
- write_descriptor_set.dstArrayElement = 0;
- write_descriptor_set.descriptorCount = 1;
- write_descriptor_set.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
- write_descriptor_set.pImageInfo = nullptr;
- write_descriptor_set.pBufferInfo = &descriptor_buf_info;
- write_descriptor_set.pTexelBufferView = nullptr;
-
- vkUpdateDescriptorSets(device, 1, &write_descriptor_set, 0, nullptr);
-}
-
-void init_vk() {
- create_instance();
- create_device();
- create_pipeline();
- create_command_buffer();
- create_descriptor_set();
- create_memory_allocator();
-}
-
-void compute(size_t width, size_t height) {
- VkCommandBufferBeginInfo cmd_buf_begin_info = {};
- cmd_buf_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- cmd_buf_begin_info.pNext = nullptr;
- cmd_buf_begin_info.flags = 0;
- cmd_buf_begin_info.pInheritanceInfo = nullptr;
-
- vkBeginCommandBuffer(cmd_buf, &cmd_buf_begin_info);
-
- vkCmdBindDescriptorSets(cmd_buf, VK_PIPELINE_BIND_POINT_COMPUTE, compute_pipeline_layout, 0, 1, &compute_shader_input_set, 0, nullptr);
-
- vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_COMPUTE, compute_pipeline);
-
- vkCmdDispatch(cmd_buf, width, height, 1);
-
- vkEndCommandBuffer(cmd_buf);
-
- VkSubmitInfo submit_info = {};
- submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submit_info.pNext = nullptr;
- submit_info.waitSemaphoreCount = 0;
- submit_info.pWaitSemaphores = nullptr;
- submit_info.signalSemaphoreCount = 0;
- submit_info.pSignalSemaphores = nullptr;
- submit_info.commandBufferCount = 1;
- submit_info.pCommandBuffers = &cmd_buf;
-
- vkQueueSubmit(compute_queue, 1, &submit_info, VK_NULL_HANDLE);
-
- vkDeviceWaitIdle(device);
-}
-
int main() {
- load_vulkan();
- init_vk();
+ vkrenderer renderer {};
// Image dimensions
const double aspect_ratio = 16.0 / 9.0;
@@ -453,26 +95,24 @@ int main() {
struct input_data inputs = {
.sky_color = sky_color,
.ground_color = ground_color,
- .viewport_width = camera.viewport_width,
- .viewport_height = camera.viewport_height
};
// World hittable objects
hittable_list world = random_scene();
- fill_descriptor_set(inputs);
// PPM format header
std::cout << "P3\n" << width << '\n' << height << "\n255" << std::endl;
std::cerr << "Generating image" << std::endl;
- compute(width, height);
+ renderer.compute(inputs, width, height);
//-------------------------
// GPU path tracer
//-------------------------
+ auto output_image = renderer.output_image();
for (size_t index = 0; index < height * width; index++) {
- write_color(std::cout, mapped_data->output_image[index], samples_per_pixel);
+ write_color(std::cout, output_image[index], samples_per_pixel);
}
//---------------------------
diff --git a/src/vk-renderer.cpp b/src/vk-renderer.cpp
new file mode 100644
index 0000000..7156850
--- /dev/null
+++ b/src/vk-renderer.cpp
@@ -0,0 +1,346 @@
+#include "vk-renderer.hpp"
+#include "utils.hpp"
+
+#define VMA_IMPLEMENTATION
+#include "thirdparty/vk_mem_alloc.h"
+
+#include <iostream>
+#include <vector>
+#include <cstring>
+
+VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT _severity,
+ VkDebugUtilsMessageTypeFlagsEXT _type,
+ const VkDebugUtilsMessengerCallbackDataEXT *_data,
+ void *_userData)
+{
+ std::cerr << _data->pMessage << std::endl;
+ return VK_FALSE;
+}
+
+
+vkrenderer::vkrenderer() {
+ load_vulkan();
+
+ create_instance();
+ create_device();
+ create_pipeline();
+ create_memory_allocator();
+ create_command_buffer();
+ create_descriptor_set();
+}
+
+void vkrenderer::compute(const input_data& inputs, size_t width, size_t height) {
+ fill_descriptor_set(inputs);
+
+ VkCommandBufferBeginInfo cmd_buf_begin_info = {};
+ cmd_buf_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+ cmd_buf_begin_info.pNext = nullptr;
+ cmd_buf_begin_info.flags = 0;
+ cmd_buf_begin_info.pInheritanceInfo = nullptr;
+
+ vkBeginCommandBuffer(command_buffer, &cmd_buf_begin_info);
+
+ vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, compute_pipeline_layout, 0, 1, &compute_shader_input_set, 0, nullptr);
+
+ vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, compute_pipeline);
+
+ vkCmdDispatch(command_buffer, width, height, 1);
+
+ vkEndCommandBuffer(command_buffer);
+
+ VkSubmitInfo submit_info = {};
+ submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ submit_info.pNext = nullptr;
+ submit_info.waitSemaphoreCount = 0;
+ submit_info.pWaitSemaphores = nullptr;
+ submit_info.signalSemaphoreCount = 0;
+ submit_info.pSignalSemaphores = nullptr;
+ submit_info.commandBufferCount = 1;
+ submit_info.pCommandBuffers = &command_buffer;
+
+ vkQueueSubmit(compute_queue, 1, &submit_info, VK_NULL_HANDLE);
+
+ vkDeviceWaitIdle(device);
+}
+
+const color* const vkrenderer::output_image() {
+ return mapped_data->output_image;
+}
+
+
+void vkrenderer::create_instance() {
+ VkApplicationInfo app_info = {};
+ app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+ app_info.pApplicationName = "path-tracer";
+ app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
+ app_info.pEngineName = "gpu-path-tracer";
+ app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0);
+ app_info.apiVersion = VK_API_VERSION_1_2;
+
+
+ std::vector<const char*> layers = {
+ "VK_LAYER_KHRONOS_validation",
+ };
+ std::vector<const char*> extensions = {
+ VK_EXT_DEBUG_UTILS_EXTENSION_NAME
+ };
+
+ VkInstanceCreateInfo instance_create_info = {};
+ instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+ instance_create_info.pApplicationInfo = &app_info;
+ instance_create_info.enabledLayerCount = layers.size();
+ instance_create_info.ppEnabledLayerNames = layers.data();
+ instance_create_info.enabledExtensionCount = extensions.size();
+ instance_create_info.ppEnabledExtensionNames = extensions.data();
+
+ vkCreateInstance(&instance_create_info, nullptr, &instance);
+
+ load_instance_functions(instance);
+
+ create_debugger();
+
+ std::cerr << "Instance ready" << std::endl;
+}
+
+void vkrenderer::create_debugger() {
+ VkDebugUtilsMessengerEXT debugMessenger;
+ VkDebugUtilsMessengerCreateInfoEXT debugUtilsMessengeCreateInfo {
+ VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
+ nullptr,
+ 0,
+ VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT,
+ VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT
+ | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
+ DebugCallback,
+ nullptr,
+ };
+
+ vkCreateDebugUtilsMessengerEXT(
+ instance,
+ &debugUtilsMessengeCreateInfo,
+ nullptr,
+ &debugMessenger
+ );
+}
+
+void vkrenderer::create_device() {
+ select_physical_device();
+ select_compute_queue();
+
+ VkDeviceQueueCreateInfo queue_create_info = {};
+ queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+ queue_create_info.queueFamilyIndex = compute_queue_index;
+ queue_create_info.queueCount = 1;
+
+ float queue_priority = 1.f;
+ queue_create_info.pQueuePriorities = &queue_priority;
+
+ VkPhysicalDeviceFeatures device_features = {};
+
+ VkDeviceCreateInfo device_create_info = {};
+ device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
+ device_create_info.pQueueCreateInfos = &queue_create_info;
+ device_create_info.queueCreateInfoCount = 1;
+ device_create_info.pEnabledFeatures = &device_features;
+ device_create_info.enabledExtensionCount = 0; // None yet
+ device_create_info.enabledLayerCount = 0; // Deprecated https://www.khronos.org/registry/vulkan/specs/1.2/html/chap31.html#extendingvulkan-layers-devicelayerdeprecation
+
+ vkCreateDevice(physical_device, &device_create_info, nullptr, &device);
+
+ load_device_functions(device);
+
+ vkGetDeviceQueue(device, compute_queue_index, 0, &compute_queue);
+
+ std::cerr << "Device ready" << std::endl;
+}
+
+void vkrenderer::create_pipeline() {
+ std::vector<uint8_t> shader_code = get_shader_code("./shaders/compute.comp.spv");
+ if (shader_code.size() == 0) {
+ exit(1);
+ }
+
+ VkShaderModule compute_shader_module;
+ VkShaderModuleCreateInfo shader_create_info = {};
+ shader_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+ shader_create_info.pNext = nullptr;
+ shader_create_info.flags = 0;
+ shader_create_info.codeSize = shader_code.size();
+ shader_create_info.pCode = (uint32_t*)shader_code.data();
+
+ vkCreateShaderModule(device, &shader_create_info, nullptr, &compute_shader_module);
+
+ VkPipelineShaderStageCreateInfo stage_create_info = {};
+ stage_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+ stage_create_info.pNext = nullptr;
+ stage_create_info.flags = 0;
+ stage_create_info.stage = VK_SHADER_STAGE_COMPUTE_BIT;
+ stage_create_info.module = compute_shader_module;
+ stage_create_info.pName = "main";
+ stage_create_info.pSpecializationInfo = nullptr;
+
+ VkDescriptorSetLayoutBinding binding = {};
+ binding.binding = 0;
+ binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ binding.descriptorCount = 1;
+ binding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
+ binding.pImmutableSamplers = 0;
+
+ 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.pNext = nullptr;
+ descriptor_set_layout_create_info.flags = 0;
+ descriptor_set_layout_create_info.bindingCount = 1;
+ descriptor_set_layout_create_info.pBindings = &binding;
+
+ vkCreateDescriptorSetLayout(device, &descriptor_set_layout_create_info, nullptr, &compute_shader_input_layout);
+
+ VkPipelineLayoutCreateInfo layout_create_info = {};
+ layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+ layout_create_info.pNext = nullptr;
+ layout_create_info.flags = 0;
+ layout_create_info.setLayoutCount = 1;
+ layout_create_info.pSetLayouts = &compute_shader_input_layout;
+ layout_create_info.pushConstantRangeCount = 0;
+ layout_create_info.pPushConstantRanges = nullptr;
+
+ vkCreatePipelineLayout(device, &layout_create_info, nullptr, &compute_pipeline_layout);
+
+ VkComputePipelineCreateInfo create_info = {};
+ create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
+ create_info.pNext = nullptr;
+ create_info.flags = 0;
+ create_info.stage = stage_create_info;
+ create_info.layout = compute_pipeline_layout;
+
+ vkCreateComputePipelines(
+ device,
+ VK_NULL_HANDLE,
+ 1,
+ &create_info,
+ nullptr,
+ &compute_pipeline
+ );
+
+ std::cerr << "Compute pipeline ready" << std::endl;
+}
+
+void vkrenderer::create_memory_allocator() {
+ VmaAllocatorCreateInfo allocator_info = {};
+ allocator_info.vulkanApiVersion = VK_API_VERSION_1_2;
+ allocator_info.physicalDevice = physical_device;
+ allocator_info.device = device;
+ allocator_info.instance = instance;
+
+ vmaCreateAllocator(&allocator_info, &allocator);
+}
+
+void vkrenderer::create_command_buffer() {
+ VkCommandPoolCreateInfo cmd_pool_create_info = {};
+ cmd_pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+ cmd_pool_create_info.pNext = nullptr;
+ cmd_pool_create_info.flags = 0;
+ cmd_pool_create_info.queueFamilyIndex = compute_queue_index;
+
+ vkCreateCommandPool(device, &cmd_pool_create_info, nullptr, &command_pool);
+
+ VkCommandBufferAllocateInfo cmd_buf_allocate_info = {};
+ cmd_buf_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+ cmd_buf_allocate_info.pNext = nullptr;
+ cmd_buf_allocate_info.commandPool = command_pool;
+ cmd_buf_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+ cmd_buf_allocate_info.commandBufferCount = 1;
+
+ vkAllocateCommandBuffers(device, &cmd_buf_allocate_info, &command_buffer);
+}
+void vkrenderer::create_descriptor_set() {
+ VkDescriptorPoolSize descriptor_pool_size = {};
+ descriptor_pool_size.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ descriptor_pool_size.descriptorCount = 1;
+
+ VkDescriptorPoolCreateInfo descriptor_pool_create_info = {};
+ descriptor_pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
+ descriptor_pool_create_info.pNext = nullptr;
+ descriptor_pool_create_info.flags = 0;
+ descriptor_pool_create_info.maxSets = 1;
+ descriptor_pool_create_info.poolSizeCount = 1;
+ descriptor_pool_create_info.pPoolSizes = &descriptor_pool_size;
+
+ vkCreateDescriptorPool(device, &descriptor_pool_create_info, nullptr, &descriptor_pool);
+
+ VkDescriptorSetAllocateInfo descriptor_set_allocate_info = {};
+ descriptor_set_allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+ descriptor_set_allocate_info.pNext = nullptr;
+ descriptor_set_allocate_info.descriptorPool = descriptor_pool;
+ descriptor_set_allocate_info.descriptorSetCount = 1;
+ descriptor_set_allocate_info.pSetLayouts = &compute_shader_input_layout;
+
+ vkAllocateDescriptorSets(device, &descriptor_set_allocate_info, &compute_shader_input_set);
+}
+
+void vkrenderer::select_physical_device() {
+ uint32_t physical_devices_count = 0;
+ vkEnumeratePhysicalDevices(instance, &physical_devices_count, nullptr);
+
+ if (physical_devices_count < 1) {
+ std::cerr << "No physical device found !" << std::endl;
+ exit(1);
+ }
+
+ std::vector<VkPhysicalDevice> physical_devices { physical_devices_count };
+ vkEnumeratePhysicalDevices(instance, &physical_devices_count, physical_devices.data());
+
+ physical_device = physical_devices[0];
+}
+
+void vkrenderer::select_compute_queue() {
+ uint32_t queue_properties_count = 0;
+ vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_properties_count, nullptr);
+
+ std::vector<VkQueueFamilyProperties> queue_properties { queue_properties_count };
+ vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_properties_count, queue_properties.data());
+
+ for (uint32_t properties_index = 0; properties_index < queue_properties_count; properties_index++) {
+ if (queue_properties[properties_index].queueFlags & VK_QUEUE_COMPUTE_BIT) {
+ compute_queue_index = properties_index;
+ return;
+ }
+ }
+
+ std::cerr << "No compute queue found !" << std::endl;
+ exit(1);
+}
+
+void vkrenderer::fill_descriptor_set(const input_data& inputs) {
+ VkBufferCreateInfo buffer_info = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
+ buffer_info.size = sizeof(path_tracer_data);
+ buffer_info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+
+ VmaAllocationCreateInfo alloc_create_info = {};
+ alloc_create_info.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
+
+ VmaAllocation allocation;
+ vmaCreateBuffer(allocator, &buffer_info, &alloc_create_info, &compute_shader_buffer, &allocation, nullptr);
+
+ vmaMapMemory(allocator, allocation, (void**) &mapped_data);
+ std::memcpy(&mapped_data->inputs, &inputs, sizeof(inputs));
+
+ VkDescriptorBufferInfo descriptor_buf_info = {};
+ descriptor_buf_info.buffer = compute_shader_buffer;
+ descriptor_buf_info.offset = 0;
+ descriptor_buf_info.range = VK_WHOLE_SIZE;
+
+ VkWriteDescriptorSet write_descriptor_set = {};
+ write_descriptor_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ write_descriptor_set.pNext = nullptr;
+ write_descriptor_set.dstSet = compute_shader_input_set;
+ write_descriptor_set.dstBinding = 0;
+ write_descriptor_set.dstArrayElement = 0;
+ write_descriptor_set.descriptorCount = 1;
+ write_descriptor_set.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
+ write_descriptor_set.pImageInfo = nullptr;
+ write_descriptor_set.pBufferInfo = &descriptor_buf_info;
+ write_descriptor_set.pTexelBufferView = nullptr;
+
+ vkUpdateDescriptorSets(device, 1, &write_descriptor_set, 0, nullptr);
+}