diff options
| author | ladevieq <ladevie.quentin@gmail.com> | 2021-08-08 23:01:44 +0200 |
|---|---|---|
| committer | ladevieq <ladevie.quentin@gmail.com> | 2021-08-08 23:01:44 +0200 |
| commit | 03fdcb0341d35bb99fccb2e155ee967f932c9961 (patch) | |
| tree | e318a2e755556b299009dd84230705a3f4432efc | |
| parent | db6adfebe08027a49c6b2204683a2b9f3527cd64 (diff) | |
Bindless compute pipelines
| -rw-r--r-- | CMakeLists.txt | 1 | ||||
| -rw-r--r-- | include/scene.hpp | 4 | ||||
| -rw-r--r-- | include/vk-api.hpp | 37 | ||||
| -rw-r--r-- | include/vk-renderer.hpp | 4 | ||||
| -rw-r--r-- | shaders/compute.comp | 23 | ||||
| -rw-r--r-- | shaders/tonemapping.comp | 30 | ||||
| -rw-r--r-- | src/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/main.cpp | 6 | ||||
| -rw-r--r-- | src/vk-api.cpp | 135 | ||||
| -rw-r--r-- | src/vk-context.cpp | 13 | ||||
| -rw-r--r-- | src/vk-renderer.cpp | 108 | ||||
| -rw-r--r-- | src/vulkan-loader.cpp | 4 |
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)); \ |
