aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorladevieq <ladevie.quentin@gmail.com>2021-08-08 23:01:44 +0200
committerladevieq <ladevie.quentin@gmail.com>2021-08-08 23:01:44 +0200
commit03fdcb0341d35bb99fccb2e155ee967f932c9961 (patch)
treee318a2e755556b299009dd84230705a3f4432efc
parentdb6adfebe08027a49c6b2204683a2b9f3527cd64 (diff)
Bindless compute pipelines
-rw-r--r--CMakeLists.txt1
-rw-r--r--include/scene.hpp4
-rw-r--r--include/vk-api.hpp37
-rw-r--r--include/vk-renderer.hpp4
-rw-r--r--shaders/compute.comp23
-rw-r--r--shaders/tonemapping.comp30
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/main.cpp6
-rw-r--r--src/vk-api.cpp135
-rw-r--r--src/vk-context.cpp13
-rw-r--r--src/vk-renderer.cpp108
-rw-r--r--src/vulkan-loader.cpp4
12 files changed, 235 insertions, 132 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 70bcdfa..b8c6ee1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,6 +16,7 @@ project(path-tracer VERSION 1.0 LANGUAGES CXX)
find_package(imgui CONFIG REQUIRED)
find_package(Vulkan REQUIRED)
+find_package(nlohmann_json CONFIG REQUIRED)
if(UNIX AND NOT APPLE)
find_package(X11 REQUIRED)
diff --git a/include/scene.hpp b/include/scene.hpp
index 3346282..3c69425 100644
--- a/include/scene.hpp
+++ b/include/scene.hpp
@@ -13,7 +13,7 @@ class scene {
camera cam;
// uint32_t max_bounce = 50;
- uint32_t max_bounce = 4;
+ uint32_t max_bounce = 3;
// Output image resolution
uint32_t width;
@@ -25,7 +25,7 @@ class scene {
uint32_t triangles_count = 0;
uint32_t enable_dof = false;
uint32_t debug_bvh = false;
- uint32_t padding;
+ uint32_t downscale_factor = 4;
metadata(camera cam, uint32_t width, uint32_t height)
: cam(cam), width(width), height(height) {}
diff --git a/include/vk-api.hpp b/include/vk-api.hpp
index 28173f9..8e4b342 100644
--- a/include/vk-api.hpp
+++ b/include/vk-api.hpp
@@ -15,6 +15,7 @@ struct Buffer {
struct Pipeline {
std::vector<VkShaderModule> shader_modules;
+ // TODO: Remove once all pipelines use bindless layout
VkDescriptorSetLayout descriptor_set_layout;
VkPipelineLayout layout;
VkPipeline handle;
@@ -29,14 +30,29 @@ struct Image {
VkImageSubresourceRange subresource_range;
VkFormat format;
VkExtent3D size;
+ uint32_t bindless_index;
};
struct Swapchain {
- size_t image_count;
- std::vector<Image> images;
- VkSwapchainKHR handle;
- VkSurfaceFormatKHR surface_format;
- VkExtent2D extent;
+ size_t image_count;
+ std::vector<Image> images;
+ VkSwapchainKHR handle;
+ VkSurfaceFormatKHR surface_format;
+ VkExtent2D extent;
+};
+
+struct global_descriptor {
+ VkDescriptorSetLayout set_layout;
+ VkPipelineLayout pipeline_layout;
+ VkDescriptorSet set;
+
+ std::vector<uint32_t> indices;
+
+ global_descriptor() {
+ for (size_t index = 0; index < 1024; index++) {
+ indices.push_back(index);
+ }
+ }
};
class window;
@@ -89,7 +105,7 @@ class vkapi {
void destroy_framebuffers(std::vector<VkFramebuffer>& framebuffers);
- Pipeline create_compute_pipeline(const char* shader_name, std::vector<VkDescriptorSetLayoutBinding>& bindings);
+ Pipeline create_compute_pipeline(const char* shader_name);
Pipeline create_graphics_pipeline(const char* shader_name, std::vector<VkDescriptorSetLayoutBinding>& bindings, VkShaderStageFlagBits shader_stages, VkRenderPass render_pass, std::vector<VkDynamicState> dynamic_states);
void destroy_pipeline(Pipeline &pipeline);
@@ -108,6 +124,7 @@ class vkapi {
void update_descriptor_set_buffer(VkDescriptorSet set, VkDescriptorSetLayoutBinding binding, Buffer& buffer);
void update_descriptor_set_buffer(VkDescriptorSet set, VkDescriptorSetLayoutBinding binding, Buffer& buffer, VkDeviceSize offset, VkDeviceSize range);
void update_descriptor_set_image(VkDescriptorSet set, VkDescriptorSetLayoutBinding binding, VkImageView view, VkSampler sampler);
+ void update_bindless_descriptor_set_images(std::vector<Image> &images, std::vector<VkSampler> &samplers);
void start_record(VkCommandBuffer command_buffer);
@@ -117,7 +134,7 @@ class vkapi {
void begin_render_pass(VkCommandBuffer command_buffer, VkRenderPass render_pass, VkFramebuffer framebuffer, VkExtent2D size, Pipeline pipeline);
void end_render_pass(VkCommandBuffer command_buffer);
- void run_compute_pipeline(VkCommandBuffer command_buffer, Pipeline pipeline, VkDescriptorSet set, size_t group_count_x, size_t group_count_y, size_t group_count_z);
+ void run_compute_pipeline(VkCommandBuffer command_buffer, Pipeline pipeline, size_t group_count_x, size_t group_count_y, size_t group_count_z);
void draw(VkCommandBuffer command_buffer, Pipeline pipeline, VkDescriptorSet set, uint32_t vertex_count, uint32_t vertex_offset);
void draw(VkCommandBuffer command_buffer, Pipeline pipeline, VkDescriptorSet set, Buffer index_buffer, uint32_t primitive_count, uint32_t indices_offset, uint32_t vertices_offset);
@@ -133,12 +150,14 @@ class vkapi {
vkcontext context;
+ global_descriptor bindless_descriptor;
+
private:
const char* shader_stage_extension(VkShaderStageFlags shader_stage);
- VkCommandPool command_pool;
- VkDescriptorPool descriptor_pool;
+ VkCommandPool command_pool;
+ VkDescriptorPool descriptor_pool;
};
diff --git a/include/vk-renderer.hpp b/include/vk-renderer.hpp
index f0a21f6..6b256d3 100644
--- a/include/vk-renderer.hpp
+++ b/include/vk-renderer.hpp
@@ -50,8 +50,6 @@ class vkrenderer {
std::vector<VkCommandBuffer> command_buffers;
- std::vector<VkDescriptorSetLayoutBinding> compute_sets_bindings;
- std::vector<VkDescriptorSet> compute_shader_sets;
Pipeline compute_pipeline;
Buffer scene_buffer;
@@ -59,8 +57,6 @@ class vkrenderer {
Buffer bvh_buffer;
- std::vector<VkDescriptorSetLayoutBinding> tonemapping_sets_bindings;
- std::vector<VkDescriptorSet> tonemapping_shader_sets;
Pipeline tonemapping_pipeline;
std::vector<VkDescriptorSetLayoutBinding> ui_sets_bindings;
diff --git a/shaders/compute.comp b/shaders/compute.comp
index 44e09a2..db5756c 100644
--- a/shaders/compute.comp
+++ b/shaders/compute.comp
@@ -1,4 +1,5 @@
#extension GL_EXT_buffer_reference : require
+#extension GL_EXT_nonuniform_qualifier : require
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
@@ -81,7 +82,7 @@ layout(buffer_reference) readonly buffer scene_metadata {
uint triangles_count;
bool enable_dof;
bool debug_bvh;
- uint padding;
+ uint downscale_factor;
};
layout(buffer_reference) readonly buffer primitives_array {
@@ -93,13 +94,15 @@ layout(buffer_reference) readonly buffer nodes_array {
bvh_node[] nodes;
};
-layout(set = 0, binding = 0, rgba32f) uniform writeonly image2D output_image;
-layout(set = 0, binding = 1, rgba32f) uniform readonly image2D accumulation_image;
+layout(set = 0, binding = 0, rgba32f) uniform image2D images[];
layout(push_constant) uniform buffers {
scene_metadata scene;
primitives_array geometry;
nodes_array bvh;
+ uint output_image_index;
+ uint accumulation_image_index;
+ uint padding[2];
} bufs;
vec3 at(ray r, float t) {
@@ -354,8 +357,8 @@ vec4 ray_color(ray r, uint seed) {
}
void main() {
- uint x = gl_GlobalInvocationID.x;
- uint y = gl_GlobalInvocationID.y;
+ uint x = gl_GlobalInvocationID.x * bufs.scene.downscale_factor;
+ uint y = gl_GlobalInvocationID.y * bufs.scene.downscale_factor;
vec2 uv = vec2(float(x) / (bufs.scene.width - 1), 1.0 - (float(y) / (bufs.scene.height - 1)));
@@ -378,6 +381,12 @@ void main() {
// }
float spp_scale = (1.0 / bufs.scene.sample_index);
- vec4 acc_color = imageLoad(accumulation_image, ivec2(x, y));
- imageStore(output_image, ivec2(x, y), vec4(mix(acc_color, out_color, spp_scale)));
+ vec4 acc_color = imageLoad(images[nonuniformEXT(bufs.accumulation_image_index)], ivec2(x, y));
+ out_color = vec4(mix(acc_color, out_color, spp_scale));
+
+ for (uint i = 0; i < bufs.scene.downscale_factor; i++) {
+ for (uint j = 0; j < bufs.scene.downscale_factor; j++) {
+ imageStore(images[nonuniformEXT(bufs.output_image_index)], ivec2(x + i, y + j), out_color);
+ }
+ }
}
diff --git a/shaders/tonemapping.comp b/shaders/tonemapping.comp
index dde91b8..5613d55 100644
--- a/shaders/tonemapping.comp
+++ b/shaders/tonemapping.comp
@@ -1,12 +1,30 @@
+#extension GL_EXT_buffer_reference : require
+#extension GL_EXT_nonuniform_qualifier : require
+
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
-layout(set = 0, binding = 0, rgba8) uniform writeonly image2D output_image;
-layout(set = 0, binding = 1, rgba8) uniform readonly image2D accumulation_image;
+layout(buffer_reference) readonly buffer scene_metadata {
+ uint[39] unused;
+ uint downscale_factor;
+};
+
+layout(set = 0, binding = 0, rgba32f) uniform image2D images[];
+
+layout(push_constant) uniform constants {
+ scene_metadata scene;
+ uint output_image_index;
+ uint accumulation_image_index;
+} consts;
void main() {
- uint x = gl_GlobalInvocationID.x;
- uint y = gl_GlobalInvocationID.y;
+ uint x = gl_GlobalInvocationID.x * consts.scene.downscale_factor;
+ uint y = gl_GlobalInvocationID.y * consts.scene.downscale_factor;
- vec4 color = imageLoad(accumulation_image, ivec2(x, y));
- imageStore(output_image, ivec2(x, y), sqrt(color));
+ vec4 color = imageLoad(images[nonuniformEXT(consts.accumulation_image_index)], ivec2(x, y));
+ vec4 out_color = sqrt(color);
+ for (uint i = 0; i < consts.scene.downscale_factor; i++) {
+ for (uint j = 0; j < consts.scene.downscale_factor; j++) {
+ imageStore(images[nonuniformEXT(consts.output_image_index)], ivec2(x + i, y + j), out_color);
+ }
+ }
}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b871d67..7bfeb1e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,5 +1,3 @@
-find_package(nlohmann_json CONFIG REQUIRED)
-
add_definitions(-DNOMINMAX -D_USE_MATH_DEFINES)
include_directories(${CMAKE_SOURCE_DIR}/include)
diff --git a/src/main.cpp b/src/main.cpp
index 83d460a..8d79000 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -217,6 +217,9 @@ int main() {
}
ImGui::SliderInt("bounces", (int32_t*)&((scene*) renderer.scene_buffer_ptr())->meta.max_bounce, 1, 250);
+ if (ImGui::SliderInt("downscale factor", (int32_t*)&((scene*) renderer.scene_buffer_ptr())->meta.downscale_factor, 1, 32)) {
+ reset_accumulation = true;
+ }
if (ImGui::Checkbox("debug bvh", (bool*)&((scene*) renderer.scene_buffer_ptr())->meta.debug_bvh)) {
reset_accumulation = true;
@@ -240,7 +243,8 @@ int main() {
renderer.reset_accumulation();
}
- renderer.compute(width, height);
+ float scale = (float)((scene*) renderer.scene_buffer_ptr())->meta.downscale_factor;
+ renderer.compute(width / scale, height / scale);
((scene*) renderer.scene_buffer_ptr())->meta.sample_index++;
diff --git a/src/vk-api.cpp b/src/vk-api.cpp
index c6dcf0b..33b32ee 100644
--- a/src/vk-api.cpp
+++ b/src/vk-api.cpp
@@ -18,23 +18,22 @@ vkapi::vkapi() {
VKRESULT(vkCreateCommandPool(context.device, &cmd_pool_create_info, nullptr, &command_pool))
-
std::vector<VkDescriptorPoolSize> descriptor_pools_sizes = {
{
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
- .descriptorCount = (uint32_t)0xff,
+ .descriptorCount = (uint32_t)1024,
},
{
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
- .descriptorCount = (uint32_t)0xff,
+ .descriptorCount = (uint32_t)1024,
},
{
.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
- .descriptorCount = (uint32_t)0xff,
+ .descriptorCount = (uint32_t)1024,
},
{
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
- .descriptorCount = (uint32_t)0xff,
+ .descriptorCount = (uint32_t)1024,
}
};
@@ -47,9 +46,67 @@ vkapi::vkapi() {
descriptor_pool_create_info.pPoolSizes = descriptor_pools_sizes.data();
VKRESULT(vkCreateDescriptorPool(context.device, &descriptor_pool_create_info, nullptr, &descriptor_pool))
+
+ // Global descriptor
+ VkDescriptorSetLayoutBinding bindless_layout_bindings[] = {
+ {
+ .binding = 0,
+ .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+ .descriptorCount = 1024,
+ .stageFlags = VK_SHADER_STAGE_ALL,
+ },
+ };
+
+ VkDescriptorBindingFlags flag = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT;
+ VkDescriptorSetLayoutBindingFlagsCreateInfo descriptor_set_layout_binding_flags = {};
+ descriptor_set_layout_binding_flags.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO;
+ descriptor_set_layout_binding_flags.pNext = VK_NULL_HANDLE;
+ descriptor_set_layout_binding_flags.bindingCount = 1;
+ descriptor_set_layout_binding_flags.pBindingFlags = &flag;
+
+ 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 = &descriptor_set_layout_binding_flags;
+ descriptor_set_layout_create_info.flags = 0;
+ descriptor_set_layout_create_info.bindingCount = sizeof(bindless_layout_bindings) / sizeof(VkDescriptorSetLayoutBinding);
+ descriptor_set_layout_create_info.pBindings = bindless_layout_bindings;
+
+ VKRESULT(vkCreateDescriptorSetLayout(context.device, &descriptor_set_layout_create_info, nullptr, &bindless_descriptor.set_layout))
+
+
+ VkPushConstantRange push_constant = {};
+ push_constant.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
+ push_constant.offset = 0;
+ push_constant.size = 64;
+
+ 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 = &bindless_descriptor.set_layout;
+ layout_create_info.pushConstantRangeCount = 1;
+ layout_create_info.pPushConstantRanges = &push_constant;
+
+ VKRESULT(vkCreatePipelineLayout(context.device, &layout_create_info, nullptr, &bindless_descriptor.pipeline_layout))
+
+
+ VkDescriptorSetAllocateInfo descriptor_set_allocate_info = {};
+ descriptor_set_allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
+ descriptor_set_allocate_info.pNext = VK_NULL_HANDLE;
+ descriptor_set_allocate_info.descriptorPool = descriptor_pool;
+ descriptor_set_allocate_info.descriptorSetCount = 1;
+ descriptor_set_allocate_info.pSetLayouts = &bindless_descriptor.set_layout;
+
+ vkAllocateDescriptorSets(context.device, &descriptor_set_allocate_info, &bindless_descriptor.set);
}
vkapi::~vkapi() {
+ // Free bindless descriptor stuff
+ vkDestroyDescriptorSetLayout(context.device, bindless_descriptor.set_layout, nullptr);
+ vkDestroyPipelineLayout(context.device, bindless_descriptor.pipeline_layout, nullptr);
+ vkFreeDescriptorSets(context.device, descriptor_pool, 1, &bindless_descriptor.set);
+
vkDestroyCommandPool(context.device, command_pool, nullptr);
vkDestroyDescriptorPool(context.device, descriptor_pool, nullptr);
}
@@ -109,7 +166,6 @@ void vkapi::copy_buffer(VkCommandBuffer cmd_buf, Buffer src, Image dst) {
}
void vkapi::destroy_buffer(Buffer& buffer) {
- // vmaUnmapMemory(context.allocator, buffer.alloc);
vmaDestroyBuffer(context.allocator, buffer.handle, buffer.alloc);
}
@@ -164,9 +220,14 @@ Image vkapi::create_image(VkExtent3D size, VkFormat format, VkImageUsageFlags us
VKRESULT(vkCreateImageView(context.device, &image_view_create_info, VK_NULL_HANDLE, &image.view))
+ image.bindless_index = bindless_descriptor.indices.back();
+ bindless_descriptor.indices.pop_back();
+
return std::move(image);
}
void vkapi::destroy_image(Image &image) {
+ bindless_descriptor.indices.push_back(image.bindless_index);
+
vmaDestroyImage(context.allocator, image.handle, image.alloc);
vkDestroyImageView(context.device, image.view, nullptr);
}
@@ -405,7 +466,7 @@ void vkapi::destroy_framebuffers(std::vector<VkFramebuffer>& framebuffers) {
}
-Pipeline vkapi::create_compute_pipeline(const char* shader_name, std::vector<VkDescriptorSetLayoutBinding>& bindings) {
+Pipeline vkapi::create_compute_pipeline(const char* shader_name) {
Pipeline pipeline {
.bind_point = VK_PIPELINE_BIND_POINT_COMPUTE
};
@@ -438,37 +499,12 @@ Pipeline vkapi::create_compute_pipeline(const char* shader_name, std::vector<VkD
stage_create_info.pSpecializationInfo = VK_NULL_HANDLE;
- 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 = VK_NULL_HANDLE;
- descriptor_set_layout_create_info.flags = 0;
- descriptor_set_layout_create_info.bindingCount = bindings.size();
- descriptor_set_layout_create_info.pBindings = bindings.data();
-
- VKRESULT(vkCreateDescriptorSetLayout(context.device, &descriptor_set_layout_create_info, VK_NULL_HANDLE, &pipeline.descriptor_set_layout))
-
- VkPushConstantRange push_constant = {};
- push_constant.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
- push_constant.offset = 0;
- push_constant.size = 24;
-
- VkPipelineLayoutCreateInfo layout_create_info = {};
- layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
- layout_create_info.pNext = VK_NULL_HANDLE;
- layout_create_info.flags = 0;
- layout_create_info.setLayoutCount = 1;
- layout_create_info.pSetLayouts = &pipeline.descriptor_set_layout;
- layout_create_info.pushConstantRangeCount = 1;
- layout_create_info.pPushConstantRanges = &push_constant;
-
- VKRESULT(vkCreatePipelineLayout(context.device, &layout_create_info, VK_NULL_HANDLE, &pipeline.layout))
-
VkComputePipelineCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
create_info.pNext = VK_NULL_HANDLE;
create_info.flags = 0;
create_info.stage = stage_create_info;
- create_info.layout = pipeline.layout;
+ create_info.layout = bindless_descriptor.pipeline_layout;
VKRESULT(vkCreateComputePipelines(
context.device,
@@ -786,6 +822,9 @@ Swapchain vkapi::create_swapchain(VkSurfaceKHR surface, size_t min_image_count,
};
for (size_t image_index = 0; image_index < swapchain.image_count; image_index++) {
+ swapchain.images[image_index].bindless_index = bindless_descriptor.indices.back();
+ bindless_descriptor.indices.pop_back();
+
swapchain.images[image_index].handle = images[image_index];
swapchain.images[image_index].size = image_size;
swapchain.images[image_index].subresource_range = image_subresource_range;
@@ -813,6 +852,8 @@ Swapchain vkapi::create_swapchain(VkSurfaceKHR surface, size_t min_image_count,
void vkapi::destroy_swapchain(Swapchain& swapchain) {
for(auto &image: swapchain.images) {
+ bindless_descriptor.indices.push_back(image.bindless_index);
+
vkDestroyImageView(context.device, image.view, nullptr);
}
vkDestroySwapchainKHR(context.device, swapchain.handle, nullptr);
@@ -865,6 +906,30 @@ void vkapi::update_descriptor_set_image(VkDescriptorSet set, VkDescriptorSetLayo
vkUpdateDescriptorSets(context.device, 1, &write_descriptor, 0, nullptr);
}
+void vkapi::update_bindless_descriptor_set_images(std::vector<Image> &images, std::vector<VkSampler> &samplers) {
+ std::vector<VkDescriptorImageInfo> descriptor_images_info { images.size() };
+ std::vector<VkWriteDescriptorSet> writes_descriptor { images.size() };
+
+ for (size_t image_index = 0; image_index < images.size(); image_index++) {
+ descriptor_images_info[image_index].sampler = samplers[image_index];
+ descriptor_images_info[image_index].imageView = images[image_index].view;
+ descriptor_images_info[image_index].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
+
+ writes_descriptor[image_index].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
+ writes_descriptor[image_index].pNext = nullptr;
+ writes_descriptor[image_index].dstSet = bindless_descriptor.set;
+ writes_descriptor[image_index].dstBinding = 0;
+ writes_descriptor[image_index].dstArrayElement = images[image_index].bindless_index;
+ writes_descriptor[image_index].descriptorCount = 1;
+ writes_descriptor[image_index].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+ writes_descriptor[image_index].pImageInfo = &descriptor_images_info[image_index];
+ writes_descriptor[image_index].pBufferInfo = VK_NULL_HANDLE;
+ writes_descriptor[image_index].pTexelBufferView = VK_NULL_HANDLE;
+ }
+
+ vkUpdateDescriptorSets(context.device, writes_descriptor.size(), writes_descriptor.data(), 0, nullptr);
+}
+
void vkapi::start_record(VkCommandBuffer command_buffer) {
VkCommandBufferBeginInfo cmd_buf_begin_info = {};
@@ -932,8 +997,8 @@ void vkapi::end_render_pass(VkCommandBuffer command_buffer) {
}
-void vkapi::run_compute_pipeline(VkCommandBuffer command_buffer, Pipeline pipeline, VkDescriptorSet set, size_t group_count_x, size_t group_count_y, size_t group_count_z) {
- vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.layout, 0, 1, &set, 0, nullptr);
+void vkapi::run_compute_pipeline(VkCommandBuffer command_buffer, Pipeline pipeline, size_t group_count_x, size_t group_count_y, size_t group_count_z) {
+ vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, bindless_descriptor.pipeline_layout, 0, 1, &bindless_descriptor.set, 0, nullptr);
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.handle);
diff --git a/src/vk-context.cpp b/src/vk-context.cpp
index 999c762..ff6c493 100644
--- a/src/vk-context.cpp
+++ b/src/vk-context.cpp
@@ -108,10 +108,15 @@ void vkcontext::create_device() {
float queue_priority = 1.f;
queue_create_info.pQueuePriorities = &queue_priority;
- VkPhysicalDeviceVulkan12Features physical_device_12_features = {};
- physical_device_12_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
- physical_device_12_features.pNext = VK_NULL_HANDLE;
- physical_device_12_features.bufferDeviceAddress = VK_TRUE;
+ VkPhysicalDeviceVulkan12Features physical_device_12_features = {};
+ physical_device_12_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
+ physical_device_12_features.pNext = VK_NULL_HANDLE;
+ physical_device_12_features.bufferDeviceAddress = VK_TRUE;
+ physical_device_12_features.runtimeDescriptorArray = VK_TRUE;
+ physical_device_12_features.shaderStorageImageArrayNonUniformIndexing = VK_TRUE;
+ physical_device_12_features.descriptorBindingPartiallyBound = VK_TRUE;
+ physical_device_12_features.descriptorBindingPartiallyBound = VK_TRUE;
+ physical_device_12_features.descriptorBindingUpdateUnusedWhilePending = VK_TRUE;
VkPhysicalDeviceFeatures2 device_features = {};
device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
diff --git a/src/vk-renderer.cpp b/src/vk-renderer.cpp
index f2dff62..4d7646a 100644
--- a/src/vk-renderer.cpp
+++ b/src/vk-renderer.cpp
@@ -35,43 +35,8 @@ vkrenderer::vkrenderer(window& wnd, size_t scene_buffer_size, size_t geometry_bu
VK_NULL_HANDLE
);
- compute_sets_bindings = {
- {
- .binding = 0,
- .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
- .descriptorCount = 1,
- .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
- .pImmutableSamplers = VK_NULL_HANDLE,
- },
- {
- .binding = 1,
- .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
- .descriptorCount = 1,
- .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
- .pImmutableSamplers = VK_NULL_HANDLE,
- }
- };
- compute_pipeline = api.create_compute_pipeline("compute", compute_sets_bindings);
- compute_shader_sets = api.create_descriptor_sets(compute_pipeline.descriptor_set_layout, virtual_frames_count);
-
- tonemapping_sets_bindings = {
- {
- .binding = 0,
- .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
- .descriptorCount = 1,
- .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
- .pImmutableSamplers = VK_NULL_HANDLE,
- },
- {
- .binding = 1,
- .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
- .descriptorCount = 1,
- .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
- .pImmutableSamplers = VK_NULL_HANDLE,
- }
- };
- tonemapping_pipeline = api.create_compute_pipeline("tonemapping", tonemapping_sets_bindings);
- tonemapping_shader_sets = api.create_descriptor_sets(tonemapping_pipeline.descriptor_set_layout, virtual_frames_count);
+ compute_pipeline = api.create_compute_pipeline("compute");
+ tonemapping_pipeline = api.create_compute_pipeline("tonemapping");
command_buffers = api.create_command_buffers(virtual_frames_count);
@@ -171,6 +136,18 @@ vkrenderer::vkrenderer(window& wnd, size_t scene_buffer_size, size_t geometry_bu
api.destroy_buffer(staging_buffer);
+ std::vector<Image> images = {
+ accumulation_images[0],
+ accumulation_images[1],
+
+ swapchain.images[0],
+ swapchain.images[1],
+ swapchain.images[2]
+ };
+ std::vector<VkSampler> samplers { images.size(), VK_NULL_HANDLE };
+
+ api.update_bindless_descriptor_set_images(images, samplers);
+
virtual_frame_index++;
ui_texture_sampler = api.create_sampler(VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE);
@@ -228,8 +205,6 @@ vkrenderer::~vkrenderer() {
api.destroy_pipeline(tonemapping_pipeline);
api.destroy_pipeline(ui_pipeline);
- api.destroy_descriptor_sets(compute_shader_sets);
- api.destroy_descriptor_sets(tonemapping_shader_sets);
api.destroy_descriptor_sets(ui_sets);
api.destroy_swapchain(swapchain);
@@ -282,31 +257,25 @@ void vkrenderer::begin_frame() {
auto acquire_result = vkAcquireNextImageKHR(api.context.device, swapchain.handle, UINT64_MAX, acquire_semaphores[virtual_frame_index], VK_NULL_HANDLE, &swapchain_image_index);
handle_swapchain_result(acquire_result);
- auto cmd_buf = command_buffers[virtual_frame_index];
-
- auto output_image = accumulation_images[0];
- auto accumulation_image = accumulation_images[1];
-
- api.update_descriptor_set_image(compute_shader_sets[virtual_frame_index], compute_sets_bindings[0], output_image.view, VK_NULL_HANDLE);
- api.update_descriptor_set_image(compute_shader_sets[virtual_frame_index], compute_sets_bindings[1], accumulation_image.view, VK_NULL_HANDLE);
-
- api.update_descriptor_set_image(tonemapping_shader_sets[virtual_frame_index], tonemapping_sets_bindings[0], swapchain.images[swapchain_image_index].view, VK_NULL_HANDLE);
- api.update_descriptor_set_image(tonemapping_shader_sets[virtual_frame_index], tonemapping_sets_bindings[1], output_image.view, VK_NULL_HANDLE);
-
- api.start_record(cmd_buf);
+ api.start_record(command_buffers[virtual_frame_index]);
}
void vkrenderer::reset_accumulation() {
auto cmd_buf = command_buffers[virtual_frame_index];
- auto accumulation_image = accumulation_images[1];
VkClearColorValue clear_color = { 0.f, 0.f, 0.f, 1.f };
- api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, accumulation_image);
+ api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, accumulation_images[0]);
+
+ vkCmdClearColorImage(cmd_buf, accumulation_images[0].handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1, &accumulation_images[0].subresource_range);
+
+ api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, accumulation_images[0]);
- vkCmdClearColorImage(cmd_buf, accumulation_image.handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1, &accumulation_image.subresource_range);
+ api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, accumulation_images[1]);
- api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, accumulation_image);
+ vkCmdClearColorImage(cmd_buf, accumulation_images[1].handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1, &accumulation_images[1].subresource_range);
+
+ api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, accumulation_images[1]);
}
void vkrenderer::ui() {
@@ -356,15 +325,21 @@ void vkrenderer::ui() {
void vkrenderer::compute(uint32_t width, uint32_t height) {
auto cmd_buf = command_buffers[virtual_frame_index];
- vkCmdPushConstants(cmd_buf, compute_pipeline.layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, 8, (void*)&scene_buffer.device_address);
- vkCmdPushConstants(cmd_buf, compute_pipeline.layout, VK_SHADER_STAGE_COMPUTE_BIT, 8, 8, (void*)&geometry_buffer.device_address);
- vkCmdPushConstants(cmd_buf, compute_pipeline.layout, VK_SHADER_STAGE_COMPUTE_BIT, 16, 8, (void*)&bvh_buffer.device_address);
- api.run_compute_pipeline(cmd_buf, compute_pipeline, compute_shader_sets[virtual_frame_index], (width / 8) + 1, (height / 8) + 1, 1);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, 8, (void*)&scene_buffer.device_address);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 8, 8, (void*)&geometry_buffer.device_address);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 16, 8, (void*)&bvh_buffer.device_address);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 24, 4, (void*)&accumulation_images[0].bindless_index);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 28, 4, (void*)&accumulation_images[1].bindless_index);
+ api.run_compute_pipeline(cmd_buf, compute_pipeline, (width / 8) + 1, (height / 8) + 1, 1);
api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, swapchain.images[swapchain_image_index]);
- api.run_compute_pipeline(cmd_buf, tonemapping_pipeline, tonemapping_shader_sets[virtual_frame_index], (width / 8) + 1, (height / 8) + 1, 1);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, 8, (void*)&scene_buffer.device_address);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 8, 4, (void*)&swapchain.images[swapchain_image_index].bindless_index);
+ vkCmdPushConstants(cmd_buf, api.bindless_descriptor.pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, 12, 4, (void*)&accumulation_images[0].bindless_index);
+
+ api.run_compute_pipeline(cmd_buf, tonemapping_pipeline, (width / 8) + 1, (height / 8) + 1, 1);
}
void vkrenderer::finish_frame() {
@@ -401,6 +376,7 @@ void vkrenderer::recreate_swapchain() {
.height = swapchain.extent.height,
.depth = 1,
};
+
accumulation_images = api.create_images(image_size, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, 2);
auto cmd_buf = command_buffers[virtual_frame_index];
@@ -417,6 +393,18 @@ void vkrenderer::recreate_swapchain() {
VKRESULT(vkWaitForFences(api.context.device, 1, &submission_fences[0], VK_TRUE, UINT64_MAX))
+ std::vector<Image> images = {
+ accumulation_images[0],
+ accumulation_images[1],
+
+ swapchain.images[0],
+ swapchain.images[1],
+ swapchain.images[2]
+ };
+ std::vector<VkSampler> samplers { images.size(), VK_NULL_HANDLE };
+
+ api.update_bindless_descriptor_set_images(images, samplers);
+
for (auto& framebuffer: framebuffers) {
api.destroy_framebuffer(framebuffer);
}
diff --git a/src/vulkan-loader.cpp b/src/vulkan-loader.cpp
index 2ea2b07..42c018e 100644
--- a/src/vulkan-loader.cpp
+++ b/src/vulkan-loader.cpp
@@ -33,7 +33,7 @@ void *vulkanLibrary = dlopen("libvulkan.1.dylib", RTLD_NOW);
VULKAN_DEVICE_FUNCTIONS
#undef X
-#define X(name) \
+#define X(name) \
void Load_##name() \
{ \
name = reinterpret_cast<PFN_##name>(LoadProcAddress(vulkanLibrary, #name)); \
@@ -44,7 +44,7 @@ void Load_##name()
VULKAN_EXPORTED_FUNCTIONS
#undef X
-#define X(name) \
+#define X(name) \
void Load_##name() \
{ \
name = reinterpret_cast<PFN_##name>(vkGetInstanceProcAddr(nullptr, #name)); \