From 670df3d373ed096a4954865bb36a04df40b1faca Mon Sep 17 00:00:00 2001 From: Jens Koenen <koenen@vr.rwth-aachen.de> Date: Wed, 14 Sep 2022 17:22:32 +0200 Subject: [PATCH] Started implementing the geometry capturing for light propagating volumes. --- CMakeLists.txt | 4 + res/dpr/data/indirect_data.inc | 9 +- res/dpr/utility/indirect_geometry.frag | 58 ++++ res/dpr/utility/indirect_geometry.geom | 67 ++++ res/dpr/utility/indirect_geometry.vert | 23 ++ res/dpr/utility/indirect_injection.geom | 2 +- res/dpr/utility/indirect_propagation.comp | 2 +- src/utility/indirect_cache.cpp | 368 ++++++++++++++++++++-- src/utility/indirect_cache.hpp | 20 +- 9 files changed, 512 insertions(+), 41 deletions(-) create mode 100644 res/dpr/utility/indirect_geometry.frag create mode 100644 res/dpr/utility/indirect_geometry.geom create mode 100644 res/dpr/utility/indirect_geometry.vert diff --git a/CMakeLists.txt b/CMakeLists.txt index e2418971..5adb0e03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -759,6 +759,10 @@ message("======================================================================= utility/indirect_capture.vert utility/indirect_capture.frag + utility/indirect_geometry.vert + utility/indirect_geometry.geom + utility/indirect_geometry.frag + utility/indirect_injection.vert utility/indirect_injection.geom utility/indirect_injection.frag diff --git a/res/dpr/data/indirect_data.inc b/res/dpr/data/indirect_data.inc index 6e4a5246..0b774ae4 100644 --- a/res/dpr/data/indirect_data.inc +++ b/res/dpr/data/indirect_data.inc @@ -3,14 +3,17 @@ struct IndirectDomain { - uvec3 resolution; + uvec3 indirect_resolution; float cell_size; - vec3 min; + uvec3 geometry_resolution; uint padding1; - vec3 max; + vec3 min; uint padding2; + + vec3 max; + uint padding3; }; #endif \ No newline at end of file diff --git a/res/dpr/utility/indirect_geometry.frag b/res/dpr/utility/indirect_geometry.frag new file mode 100644 index 00000000..3aa83d02 --- /dev/null +++ b/res/dpr/utility/indirect_geometry.frag @@ -0,0 +1,58 @@ +#version 450 core +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_shader_atomic_float : require + +#include "indirect_data.inc" +#include "indirect_library.glsl" + +layout(set = 1, binding = 0) uniform IndirectDomainBuffer +{ + IndirectDomain indirect_domain; +}; + +layout(set = 1, binding = 1, r32f) uniform image3D image_geometry_x_distribution; +layout(set = 1, binding = 2, r32f) uniform image3D image_geometry_y_distribution; +layout(set = 1, binding = 3, r32f) uniform image3D image_geometry_z_distribution; +layout(set = 1, binding = 4, r32f) uniform image3D image_geometry_w_distribution; + +layout(push_constant) uniform Constants +{ + uvec3 voxel_resolution; +}; + +layout(location = 0) in vec3 inCoord; +layout(location = 1) in vec3 inNormal; + +void main() +{ + ivec3 cell_coord = ivec3(inCoord * indirect_domain.geometry_resolution); + + vec3 normal = normalize(inNormal); + vec4 distribution = spherical_harmonic_cosine_lobe(normal); + + vec3 coverage = vec3(indirect_domain.geometry_resolution) / vec3(voxel_resolution); + float opacity = 0.0; + + if(gl_ViewportIndex == 0) + { + opacity = coverage.y * coverage.z; + } + + else if(gl_ViewportIndex == 1) + { + opacity = coverage.x * coverage.z; + } + + else + { + opacity = coverage.x * coverage.y; + } + + //NOTE: Where opacity is in percent + vec4 geometry_distribution = opacity * distribution; + + imageAtomicAdd(image_geometry_x_distribution, cell_coord, geometry_distribution.x); + imageAtomicAdd(image_geometry_y_distribution, cell_coord, geometry_distribution.y); + imageAtomicAdd(image_geometry_z_distribution, cell_coord, geometry_distribution.z); + imageAtomicAdd(image_geometry_w_distribution, cell_coord, geometry_distribution.w); +} \ No newline at end of file diff --git a/res/dpr/utility/indirect_geometry.geom b/res/dpr/utility/indirect_geometry.geom new file mode 100644 index 00000000..b63bf132 --- /dev/null +++ b/res/dpr/utility/indirect_geometry.geom @@ -0,0 +1,67 @@ +#version 450 core +#extension GL_GOOGLE_include_directive : require + +#include "indirect_data.inc" + +layout(triangles) in; +layout(triangle_strip, max_vertices = 3) out; + +layout(set = 1, binding = 0) uniform IndirectDomainBuffer +{ + IndirectDomain indirect_domain; +}; + +layout(location = 0) in vec3 inNormal[]; + +layout(location = 0) out vec3 outCoord; +layout(location = 1) out vec3 outNormal; + +void main() +{ + vec3 position1 = gl_in[0].gl_Position.xyz; + vec3 position2 = gl_in[1].gl_Position.xyz; + vec3 position3 = gl_in[2].gl_Position.xyz; + + vec3 normal_abs = abs(cross(position2 - position1, position3 - position1)); + float normal_max = max(normal_abs.x, max(normal_abs.y, normal_abs.z)); + + if(normal_abs.x == normal_max) + { + position1 = position1.yzx; + position2 = position2.yzx; + position3 = position3.yzx; + + gl_ViewportIndex = 0; + } + + else if(normal_abs.y == normal_max) + { + position1 = position1.xzy; + position2 = position2.xzy; + position3 = position3.xzy; + + gl_ViewportIndex = 1; + } + + else + { + gl_ViewportIndex = 2; + } + + outCoord = (position1 - indirect_domain.min) / (indirect_domain.max - indirect_domain.min); + outNormal = inNormal[0]; + gl_Position = vec4(outCoord.xy * 2.0 - 1.0, 0.5, 1.0); + EmitVertex(); + + outCoord = (position2 - indirect_domain.min) / (indirect_domain.max - indirect_domain.min); + outNormal = inNormal[1]; + gl_Position = vec4(outCoord.xy * 2.0 - 1.0, 0.5, 1.0); + EmitVertex(); + + outCoord = (position3 - indirect_domain.min) / (indirect_domain.max - indirect_domain.min); + outNormal = inNormal[2]; + gl_Position = vec4(outCoord.xy * 2.0 - 1.0, 0.5, 1.0); + EmitVertex(); + + EndPrimitive(); +} \ No newline at end of file diff --git a/res/dpr/utility/indirect_geometry.vert b/res/dpr/utility/indirect_geometry.vert new file mode 100644 index 00000000..28416734 --- /dev/null +++ b/res/dpr/utility/indirect_geometry.vert @@ -0,0 +1,23 @@ +#version 450 core +#extension GL_GOOGLE_include_directive : require + +#include "mesh_data.inc" + +layout(set = 0, binding = 0) uniform MeshBuffer +{ + MeshData mesh; +}; + +layout(location = 0) in vec3 inPos; +layout(location = 1) in vec3 inNormal; +layout(location = 2) in vec3 inTangent; +layout(location = 3) in vec2 inUV; + +layout(location = 0) out vec3 outNormal; + +void main() +{ + outNormal = normalize((mesh.vectorToWorldSpace * vec4(inNormal, 0.0)).xyz); + + gl_Position = mesh.localToWorldSpace * vec4(inPos, 1.0); +} diff --git a/res/dpr/utility/indirect_injection.geom b/res/dpr/utility/indirect_injection.geom index 386e1677..93ca3bbf 100644 --- a/res/dpr/utility/indirect_injection.geom +++ b/res/dpr/utility/indirect_injection.geom @@ -22,7 +22,7 @@ void main() vec3 position = gl_in[0].gl_Position.xyz; position = (position - indirect_domain.min) / (indirect_domain.max - indirect_domain.min); position.xy = position.xy * 2.0 - 1.0; - position.z = position.z * indirect_domain.resolution.z; + position.z = position.z * indirect_domain.indirect_resolution.z; outFlux = inFlux[0]; outNormal = inNormal[0]; diff --git a/res/dpr/utility/indirect_propagation.comp b/res/dpr/utility/indirect_propagation.comp index 5bfc3b82..f77b617b 100644 --- a/res/dpr/utility/indirect_propagation.comp +++ b/res/dpr/utility/indirect_propagation.comp @@ -70,7 +70,7 @@ const float side_solid_angle = 0.42343135; bool check_bounds(ivec3 coord) { - return all(lessThanEqual(ivec3(0), coord)) && all(lessThan(coord, indirect_domain.resolution)); + return all(lessThanEqual(ivec3(0), coord)) && all(lessThan(coord, indirect_domain.indirect_resolution)); } void propagate_neighbour(ivec3 cell_coord, uint neighbour, inout vec4 red_distribution, inout vec4 green_distribution, inout vec4 blue_distribution) diff --git a/src/utility/indirect_cache.cpp b/src/utility/indirect_cache.cpp index 1eb521f8..b13858db 100644 --- a/src/utility/indirect_cache.cpp +++ b/src/utility/indirect_cache.cpp @@ -15,7 +15,10 @@ bool IndirectCache::create(Scene::Ptr scene, const IndirectCacheSettings& settin this->scene = scene; this->settings = settings; - this->compute_domain(scene, settings); + if(!this->compute_domain(scene, settings)) + { + return false; + } if (!this->create_buffers(device, settings)) { @@ -42,6 +45,16 @@ bool IndirectCache::create(Scene::Ptr scene, const IndirectCacheSettings& settin return false; } + if (!this->create_geometry_pass(device)) + { + return false; + } + + if (!this->create_geometry_pipeline(device)) + { + return false; + } + if (!this->create_capture_pass(device, settings)) { return false; @@ -185,12 +198,10 @@ void IndirectCache::compute_indirect(VkCommandBuffer command_buffer, lava::index { const std::vector<SceneLight>& lights = this->scene->get_lights(); - std::array<VkImageMemoryBarrier, 3> clear_begin_barriers = IndirectCache::build_barriers(0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - clear_begin_barriers[0].image = this->distribution_red_image[0]; - clear_begin_barriers[1].image = this->distribution_green_image[0]; - clear_begin_barriers[2].image = this->distribution_blue_image[0]; + VkImageMemoryBarrier clear_geometry_begin_barrier = IndirectCache::build_barrier(0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + clear_geometry_begin_barrier.image = this->distribution_geometry_image; - vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, clear_begin_barriers.size(), clear_begin_barriers.data()); + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &clear_geometry_begin_barrier); VkClearColorValue clear_color; clear_color.float32[0] = 0.0f; @@ -205,6 +216,25 @@ void IndirectCache::compute_indirect(VkCommandBuffer command_buffer, lava::index subresource_range.baseArrayLayer = 0; subresource_range.layerCount = 1; + vkCmdClearColorImage(command_buffer, this->distribution_geometry_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1, &subresource_range); + + VkImageMemoryBarrier clear_geometry_end_barrier = IndirectCache::build_barrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL); + clear_geometry_end_barrier.image = this->distribution_geometry_image; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &clear_geometry_end_barrier); + + this->geometry_pass->process(command_buffer, 0); + + + //TODO: Another layout transition to shader ead only optimal + + std::array<VkImageMemoryBarrier, 3> clear_begin_barriers = IndirectCache::build_barriers(0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + clear_begin_barriers[0].image = this->distribution_red_image[0]; + clear_begin_barriers[1].image = this->distribution_green_image[0]; + clear_begin_barriers[2].image = this->distribution_blue_image[0]; + + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, clear_begin_barriers.size(), clear_begin_barriers.data()); + vkCmdClearColorImage(command_buffer, this->distribution_red_image[0], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1, &subresource_range); vkCmdClearColorImage(command_buffer, this->distribution_green_image[0], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1, &subresource_range); vkCmdClearColorImage(command_buffer, this->distribution_blue_image[0], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1, &subresource_range); @@ -253,9 +283,9 @@ void IndirectCache::compute_indirect(VkCommandBuffer command_buffer, lava::index offset.z = 0; VkExtent3D extend; - extend.width = this->domain_resolution.x; - extend.height = this->domain_resolution.y; - extend.depth = this->domain_resolution.z; + extend.width = this->domain_indirect_resolution.x; + extend.height = this->domain_indirect_resolution.y; + extend.depth = this->domain_indirect_resolution.z; VkImageCopy image_copy; image_copy.srcSubresource = subresource_layers; @@ -345,8 +375,15 @@ const IndirectCacheSettings& IndirectCache::get_settings() const return this->settings; } -void IndirectCache::compute_domain(Scene::Ptr scene, const IndirectCacheSettings& settings) +bool IndirectCache::compute_domain(Scene::Ptr scene, const IndirectCacheSettings& settings) { + if (settings.voxel_resolution_scale <= 0) + { + lava::log()->error("Voxel resolution scale needs to be greater or equal to one!"); + + return false; + } + glm::vec3 scene_min = scene->get_scene_min(); glm::vec3 scene_max = scene->get_scene_max(); @@ -355,38 +392,44 @@ void IndirectCache::compute_domain(Scene::Ptr scene, const IndirectCacheSettings const glm::uvec3 work_group_size = glm::uvec3(16, 16, 2); - this->domain_resolution = glm::uvec3(glm::max(glm::ceil(scene_size / settings.cell_size), glm::vec3(1.0f))); - this->domain_min = scene_center - 0.5f * settings.cell_size * glm::vec3(this->domain_resolution); - this->domain_max = scene_center + 0.5f * settings.cell_size * glm::vec3(this->domain_resolution); - this->domain_work_groups = this->domain_resolution / work_group_size; + this->domain_indirect_resolution = glm::uvec3(glm::max(glm::ceil(scene_size / settings.cell_size), glm::vec3(1.0f))); + this->domain_geometry_resolution = this->domain_indirect_resolution + glm::uvec3(1); + this->domain_voxel_resolution = this->domain_geometry_resolution * settings.voxel_resolution_scale; + this->domain_min = scene_center - 0.5f * settings.cell_size * glm::vec3(this->domain_indirect_resolution); + this->domain_max = scene_center + 0.5f * settings.cell_size * glm::vec3(this->domain_indirect_resolution); + this->domain_work_groups = this->domain_indirect_resolution / work_group_size; - if ((this->domain_resolution.x % work_group_size.x) > 0) + if ((this->domain_indirect_resolution.x % work_group_size.x) > 0) { this->domain_work_groups.x += 1; } - if ((this->domain_resolution.y % work_group_size.y) > 0) + if ((this->domain_indirect_resolution.y % work_group_size.y) > 0) { this->domain_work_groups.y += 1; } - if ((this->domain_resolution.z % work_group_size.z) > 0) + if ((this->domain_indirect_resolution.z % work_group_size.z) > 0) { this->domain_work_groups.z += 1; } - this->propagation_iterations = 2 * glm::max(this->domain_resolution.x, glm::max(this->domain_resolution.y, this->domain_resolution.z)); + this->propagation_iterations = 2 * glm::max(this->domain_indirect_resolution.x, glm::max(this->domain_indirect_resolution.y, this->domain_indirect_resolution.z)); + + return true; } bool IndirectCache::create_buffers(lava::device_ptr device, const IndirectCacheSettings& settings) { glsl::IndirectDomain indirect_domain; - indirect_domain.resolution = this->domain_resolution; + indirect_domain.indirect_resolution = this->domain_indirect_resolution; indirect_domain.cell_size = settings.cell_size; - indirect_domain.min = this->domain_min; + indirect_domain.geometry_resolution = this->domain_geometry_resolution; indirect_domain.padding1 = 0; - indirect_domain.max = this->domain_max; + indirect_domain.min = this->domain_min; indirect_domain.padding2 = 0; + indirect_domain.max = this->domain_max; + indirect_domain.padding3 = 0; this->domain_buffer = lava::make_buffer(); @@ -448,9 +491,9 @@ bool IndirectCache::create_images(lava::device_ptr device, const IndirectCacheSe image_create_info.flags = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; image_create_info.imageType = VK_IMAGE_TYPE_3D; image_create_info.format = VK_FORMAT_R16G16B16A16_SFLOAT; - image_create_info.extent.width = this->domain_resolution.x; - image_create_info.extent.height = this->domain_resolution.y; - image_create_info.extent.depth = this->domain_resolution.z; + image_create_info.extent.width = this->domain_indirect_resolution.x; + image_create_info.extent.height = this->domain_indirect_resolution.y; + image_create_info.extent.depth = this->domain_indirect_resolution.z; image_create_info.mipLevels = 1; image_create_info.arrayLayers = 1; image_create_info.samples = VK_SAMPLE_COUNT_1_BIT; @@ -493,7 +536,7 @@ bool IndirectCache::create_images(lava::device_ptr device, const IndirectCacheSe array_view_create_info.subresourceRange.baseMipLevel = 0; array_view_create_info.subresourceRange.levelCount = 1; array_view_create_info.subresourceRange.baseArrayLayer = 0; - array_view_create_info.subresourceRange.layerCount = this->domain_resolution.z; + array_view_create_info.subresourceRange.layerCount = this->domain_indirect_resolution.z; for (uint32_t index = 0; index < this->distribution_red_image.size(); index++) { @@ -602,6 +645,73 @@ bool IndirectCache::create_images(lava::device_ptr device, const IndirectCacheSe this->distribution_blue_image_array_view[index] = blue_image_array_view; } + image_create_info.format = VK_FORMAT_R32_SFLOAT; + image_create_info.extent.width = this->domain_geometry_resolution.x; + image_create_info.extent.height = this->domain_geometry_resolution.y; + image_create_info.extent.depth = this->domain_geometry_resolution.z; + + for (uint32_t index = 0; index < this->distribution_geometry_image.size(); index++) + { + + } + + if (vmaCreateImage(device->get_allocator()->get(), &image_create_info, &allocation_info, &this->distribution_geometry_image, &this->distribution_geometry_image_memory, nullptr) != VK_SUCCESS) + { + lava::log()->error("Can't create geometry distribution image for indirect cache!"); + + return false; + } + + view_create_info.image = this->distribution_geometry_image; + + if (vkCreateImageView(device->get(), &view_create_info, lava::memory::alloc(), &this->distribution_geometry_image_view) != VK_SUCCESS) + { + lava::log()->error("Can't create geometry distribution image view for indirect cache!"); + + return false; + } + + VkImageViewCreateInfo component_view_create_info; + component_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + component_view_create_info.pNext = nullptr; + component_view_create_info.flags = 0; + component_view_create_info.image = this->distribution_geometry_image; + component_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_3D; + component_view_create_info.format = VK_FORMAT_R16G16B16A16_SFLOAT; + component_view_create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + component_view_create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + component_view_create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + component_view_create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + component_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + component_view_create_info.subresourceRange.baseMipLevel = 0; + component_view_create_info.subresourceRange.levelCount = 1; + component_view_create_info.subresourceRange.baseArrayLayer = 0; + component_view_create_info.subresourceRange.layerCount = 1; + + VkComponentMapping zero_component; + zero_component.r = VK_COMPONENT_SWIZZLE_ZERO; + zero_component.g = VK_COMPONENT_SWIZZLE_ZERO; + zero_component.b = VK_COMPONENT_SWIZZLE_ZERO; + zero_component.a = VK_COMPONENT_SWIZZLE_ZERO; + + std::vector<VkComponentMapping> component_list(4, zero_component); + component_list[0].r = VK_COMPONENT_SWIZZLE_R; + component_list[1].r = VK_COMPONENT_SWIZZLE_G; + component_list[2].r = VK_COMPONENT_SWIZZLE_B; + component_list[3].r = VK_COMPONENT_SWIZZLE_A; + + for (uint32_t index = 0; index < this->distribution_geometry_image_component_view.size(); index++) + { + component_view_create_info.components = component_list[index]; + + if (vkCreateImageView(device->get(), &component_view_create_info, lava::memory::alloc(), &this->distribution_geometry_image_component_view[index]) != VK_SUCCESS) + { + lava::log()->error("Can't create geometry distribution image component view for indirect cache!"); + + return false; + } + } + return true; } @@ -633,6 +743,13 @@ bool IndirectCache::create_samplers(lava::device_ptr device) return false; } + + if (vkCreateSampler(device->get(), &sampler_info, lava::memory::alloc(), &this->geometry_sampler) != VK_SUCCESS) + { + lava::log()->error("Can't create geometry sampler for indirect cache!"); + + return false; + } sampler_info.magFilter = VK_FILTER_NEAREST; sampler_info.minFilter = VK_FILTER_NEAREST; @@ -652,14 +769,14 @@ bool IndirectCache::create_descriptors(lava::device_ptr device) { lava::VkDescriptorPoolSizes descriptor_type_count = { - { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 4 }, + { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 5 }, { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 6 }, - { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 18 } + { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 22 } }; this->descriptor_pool = lava::make_descriptor_pool(); - if (!this->descriptor_pool->create(device, descriptor_type_count, 4)) + if (!this->descriptor_pool->create(device, descriptor_type_count, 5)) { lava::log()->error("Can't create descriptor pool for indirect cache!"); @@ -679,6 +796,21 @@ bool IndirectCache::create_descriptors(lava::device_ptr device) return false; } + this->geometry_descriptor = lava::make_descriptor(); + this->geometry_descriptor->add_binding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT); //descriptor-binding index 0: indirect domain + + this->geometry_descriptor->add_binding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_FRAGMENT_BIT); //descriptor-binding index 1: geometry distribution x + this->geometry_descriptor->add_binding(2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_FRAGMENT_BIT); //descriptor-binding index 2: geometry distribution y + this->geometry_descriptor->add_binding(3, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_FRAGMENT_BIT); //descriptor-binding index 3: geometry distribution z + this->geometry_descriptor->add_binding(4, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_FRAGMENT_BIT); //descriptor-binding index 4: geometry distribution w + + if (!this->geometry_descriptor->create(device)) + { + lava::log()->error("Can't create geometry descriptor set layout for indirect cache!"); + + return false; + } + this->injection_descriptor = lava::make_descriptor(); this->injection_descriptor->add_binding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_VERTEX_BIT); //descriptor-binding index 0: capture depth this->injection_descriptor->add_binding(1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_VERTEX_BIT); //descriptor-binding index 1: capture flux @@ -715,6 +847,7 @@ bool IndirectCache::create_descriptors(lava::device_ptr device) } this->indirect_descriptor_set = this->indirect_descriptor->allocate(this->descriptor_pool->get()); + this->geometry_descriptor_set = this->geometry_descriptor->allocate(this->descriptor_pool->get()); this->injection_descriptor_set = this->injection_descriptor->allocate(this->descriptor_pool->get()); this->propagation_descriptor_set[0] = this->propagation_descriptor->allocate(this->descriptor_pool->get()); this->propagation_descriptor_set[1] = this->propagation_descriptor->allocate(this->descriptor_pool->get()); @@ -722,8 +855,8 @@ bool IndirectCache::create_descriptors(lava::device_ptr device) std::vector<VkWriteDescriptorSet> descriptor_writes; std::vector<VkDescriptorImageInfo> image_infos; - descriptor_writes.reserve(28); - image_infos.reserve(24); + descriptor_writes.reserve(33); + image_infos.reserve(28); std::vector<VkImageView> indirect_images = { @@ -752,6 +885,26 @@ bool IndirectCache::create_descriptors(lava::device_ptr device) descriptor_write.pTexelBufferView = nullptr; } + for (uint32_t index = 0; index < this->distribution_geometry_image_component_view.size(); index++) + { + VkDescriptorImageInfo& image_info = image_infos.emplace_back(); + image_info.sampler = nullptr; + image_info.imageView = this->distribution_geometry_image_component_view[index]; + image_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + + VkWriteDescriptorSet& descriptor_write = descriptor_writes.emplace_back(); + descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptor_write.pNext = nullptr; + descriptor_write.dstSet = this->geometry_descriptor_set; + descriptor_write.dstBinding = index + 1; + descriptor_write.dstArrayElement = 0; + descriptor_write.descriptorCount = 1; + descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + descriptor_write.pImageInfo = &image_info; + descriptor_write.pBufferInfo = nullptr; + descriptor_write.pTexelBufferView = nullptr; + } + std::vector<VkImageView> injection_images = { this->capture_depth_image->get_view(), @@ -846,6 +999,18 @@ bool IndirectCache::create_descriptors(lava::device_ptr device) indirect_domain_write.pBufferInfo = this->domain_buffer->get_descriptor_info(); indirect_domain_write.pTexelBufferView = nullptr; + VkWriteDescriptorSet& geometry_domain_write = descriptor_writes.emplace_back(); + geometry_domain_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + geometry_domain_write.pNext = nullptr; + geometry_domain_write.dstSet = this->geometry_descriptor_set; + geometry_domain_write.dstBinding = 0; + geometry_domain_write.dstArrayElement = 0; + geometry_domain_write.descriptorCount = 1; + geometry_domain_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + geometry_domain_write.pImageInfo = nullptr; + geometry_domain_write.pBufferInfo = this->domain_buffer->get_descriptor_info(); + geometry_domain_write.pTexelBufferView = nullptr; + VkWriteDescriptorSet& injection_domain_write = descriptor_writes.emplace_back(); injection_domain_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; injection_domain_write.pNext = nullptr; @@ -865,6 +1030,23 @@ bool IndirectCache::create_descriptors(lava::device_ptr device) bool IndirectCache::create_layouts(lava::device_ptr device, Scene::Ptr scene) { + VkPushConstantRange geometry_range; + geometry_range.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + geometry_range.offset = 0; + geometry_range.size = sizeof(uint32_t) * 3; + + this->geometry_layout = lava::make_pipeline_layout(); + this->geometry_layout->add(scene->get_mesh_descriptor()); //set 0: mesh descriptor + this->geometry_layout->add(this->geometry_descriptor); //set 1: geometry descriptor + this->geometry_layout->add(geometry_range); + + if (!this->geometry_layout->create(device)) + { + lava::log()->error("Can't create geometry pipeline layout for indirect cache!"); + + return false; + } + VkPushConstantRange capture_range; capture_range.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; capture_range.offset = 0; @@ -913,6 +1095,71 @@ bool IndirectCache::create_layouts(lava::device_ptr device, Scene::Ptr scene) return true; } +bool IndirectCache::create_geometry_pass(lava::device_ptr device) +{ + lava::subpass::ptr subpass = lava::make_subpass(); + + this->geometry_pass = lava::make_render_pass(device); + this->geometry_pass->add(subpass); + + uint32_t voxel_max_dimension = glm::max(this->domain_voxel_resolution.x, glm::max(this->domain_voxel_resolution.y, this->domain_voxel_resolution.z)); + + lava::rect framebuffer_area = + { + glm::vec2(0.0f), + glm::vec2(voxel_max_dimension) + }; + + lava::VkImageViews framebuffer_views = {}; + + if (!this->geometry_pass->create({ framebuffer_views }, framebuffer_area)) + { + lava::log()->error("Can't create geometry pass for indirect cache!"); + + return false; + } + + return true; +} + +bool IndirectCache::create_geometry_pipeline(lava::device_ptr device) +{ + this->geometry_pipeline = lava::make_graphics_pipeline(device); + this->geometry_pipeline->set_layout(this->geometry_layout); + this->geometry_pipeline->set_auto_size(false); + + scene->set_vertex_input(this->geometry_pipeline.get()); + + if (!this->geometry_pipeline->add_shader(lava::file_data("dpr/binary/indirect_geometry_vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT)) + { + return false; + } + + if (!this->geometry_pipeline->add_shader(lava::file_data("dpr/binary/indirect_geometry_geometry.spirv"), VK_SHADER_STAGE_GEOMETRY_BIT)) + { + return false; + } + + if (!this->geometry_pipeline->add_shader(lava::file_data("dpr/binary/indirect_geometry_fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT)) + { + return false; + } + + this->geometry_pipeline->on_process = [this](VkCommandBuffer command_buffer) + { + this->pipeline_geometry(command_buffer); + }; + + if (!this->geometry_pipeline->create(this->geometry_pass->get())) + { + return false; + } + + this->geometry_pass->add_front(this->geometry_pipeline); + + return true; +} + bool IndirectCache::create_capture_pass(lava::device_ptr device, const IndirectCacheSettings& settings) { VkClearValue clear_depth; @@ -1101,12 +1348,12 @@ bool IndirectCache::create_injection_pass(lava::device_ptr device) this->injection_pass->add(attachment_red); //location 0: distribution red this->injection_pass->add(attachment_green); //location 1: distribution green this->injection_pass->add(attachment_blue); //location 2: distribution blue - this->injection_pass->set_layers(this->domain_resolution.z); + this->injection_pass->set_layers(this->domain_indirect_resolution.z); lava::rect framebuffer_area = { glm::vec2(0.0f), - glm::vec2(this->domain_resolution.x, this->domain_resolution.y) + glm::vec2(this->domain_indirect_resolution.x, this->domain_indirect_resolution.y) }; lava::VkImageViews framebuffer_views = @@ -1193,6 +1440,54 @@ bool IndirectCache::create_propagation_pipeline(lava::device_ptr device) return true; } +void IndirectCache::pipeline_geometry(VkCommandBuffer command_buffer) +{ + std::array<uint32_t, 3> push_constants; + push_constants[0] = this->domain_voxel_resolution.x; + push_constants[1] = this->domain_voxel_resolution.y; + push_constants[2] = this->domain_voxel_resolution.z; + + vkCmdPushConstants(command_buffer, this->geometry_layout->get(), VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(uint32_t) * push_constants.size(), push_constants.data()); + + std::array<VkViewport, 3> viewports; + viewports[0].x = 0.0f; + viewports[0].y = 0.0f; + viewports[0].width = this->domain_voxel_resolution.y; + viewports[0].height = this->domain_voxel_resolution.z; + viewports[0].minDepth = 0.0f; + viewports[0].maxDepth = 1.0f; + + viewports[1].x = 0.0f; + viewports[1].y = 0.0f; + viewports[1].width = this->domain_voxel_resolution.x; + viewports[1].height = this->domain_voxel_resolution.z; + viewports[1].minDepth = 0.0f; + viewports[1].maxDepth = 1.0f; + + viewports[2].x = 0.0f; + viewports[2].y = 0.0f; + viewports[2].width = this->domain_voxel_resolution.x; + viewports[2].height = this->domain_voxel_resolution.y; + viewports[2].minDepth = 0.0f; + viewports[2].maxDepth = 1.0f; + + vkCmdSetViewport(command_buffer, 0, 3, viewports.data()); + + this->geometry_layout->bind(command_buffer, this->geometry_descriptor_set, 1); + + for (const SceneMesh& mesh : this->scene->get_meshes()) + { + if (!mesh.cast_shadow) + { + continue; + } + + this->geometry_layout->bind(command_buffer, mesh.descriptor_set[this->frame], 0); + + mesh.mesh->bind_draw(command_buffer, this->domain_geometry_resolution.z); + } +} + void IndirectCache::pipeline_capture(VkCommandBuffer command_buffer) { std::array<uint32_t, 2> push_constants; @@ -1238,7 +1533,7 @@ void IndirectCache::pipeline_injection(VkCommandBuffer command_buffer) vkCmdDraw(command_buffer, point_count, 1, 0, 0); } -std::array<VkImageMemoryBarrier, 3> IndirectCache::build_barriers(VkAccessFlags src_access, VkAccessFlags dst_access, VkImageLayout old_layout, VkImageLayout new_layout) +VkImageMemoryBarrier IndirectCache::build_barrier(VkAccessFlags src_access, VkAccessFlags dst_access, VkImageLayout old_layout, VkImageLayout new_layout) { VkImageMemoryBarrier barrier; barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; @@ -1256,8 +1551,13 @@ std::array<VkImageMemoryBarrier, 3> IndirectCache::build_barriers(VkAccessFlags barrier.subresourceRange.baseArrayLayer = 0; barrier.subresourceRange.layerCount = 1; + return barrier; +} + +std::array<VkImageMemoryBarrier, 3> IndirectCache::build_barriers(VkAccessFlags src_access, VkAccessFlags dst_access, VkImageLayout old_layout, VkImageLayout new_layout) +{ std::array<VkImageMemoryBarrier, 3> barriers; - barriers.fill(barrier); + barriers.fill(build_barrier(src_access, dst_access, old_layout, new_layout)); return barriers; } diff --git a/src/utility/indirect_cache.hpp b/src/utility/indirect_cache.hpp index df471b1a..5cc5ccc9 100644 --- a/src/utility/indirect_cache.hpp +++ b/src/utility/indirect_cache.hpp @@ -11,6 +11,7 @@ struct IndirectCacheSettings { uint32_t capture_resolution = 1024; + uint32_t voxel_resolution_scale = 1; //Needs to be greater or equal to one float cell_size = 1.0f; //Where cell size is in meters }; @@ -33,22 +34,26 @@ public: const IndirectCacheSettings& get_settings() const; private: - void compute_domain(Scene::Ptr scene, const IndirectCacheSettings& settings); + bool compute_domain(Scene::Ptr scene, const IndirectCacheSettings& settings); bool create_buffers(lava::device_ptr device, const IndirectCacheSettings& settings); bool create_images(lava::device_ptr device, const IndirectCacheSettings& settings); bool create_samplers(lava::device_ptr device); bool create_descriptors(lava::device_ptr device); bool create_layouts(lava::device_ptr device, Scene::Ptr scene); + bool create_geometry_pass(lava::device_ptr device); + bool create_geometry_pipeline(lava::device_ptr device); bool create_capture_pass(lava::device_ptr device, const IndirectCacheSettings& settings); bool create_capture_pipeline(lava::device_ptr device); bool create_injection_pass(lava::device_ptr device); bool create_injection_pipeline(lava::device_ptr device); bool create_propagation_pipeline(lava::device_ptr device); + void pipeline_geometry(VkCommandBuffer command_buffer); void pipeline_capture(VkCommandBuffer command_buffer); void pipeline_injection(VkCommandBuffer command_buffer); + static VkImageMemoryBarrier build_barrier(VkAccessFlags src_access, VkAccessFlags dst_access, VkImageLayout old_layout, VkImageLayout new_layout); static std::array<VkImageMemoryBarrier, 3> build_barriers(VkAccessFlags src_access, VkAccessFlags dst_access, VkImageLayout old_layout, VkImageLayout new_layout); private: @@ -62,30 +67,38 @@ private: glm::vec3 domain_min = glm::vec3(0.0f); glm::vec3 domain_max = glm::vec3(0.0f); - glm::uvec3 domain_resolution = glm::uvec3(0); + glm::uvec3 domain_indirect_resolution = glm::uvec3(0); + glm::uvec3 domain_geometry_resolution = glm::uvec3(0); + glm::uvec3 domain_voxel_resolution = glm::uvec3(0); glm::uvec3 domain_work_groups = glm::uvec3(0); lava::descriptor::pool::ptr descriptor_pool; lava::descriptor::ptr indirect_descriptor; + lava::descriptor::ptr geometry_descriptor; lava::descriptor::ptr injection_descriptor; lava::descriptor::ptr propagation_descriptor; VkDescriptorSet indirect_descriptor_set = VK_NULL_HANDLE; + VkDescriptorSet geometry_descriptor_set = VK_NULL_HANDLE; VkDescriptorSet injection_descriptor_set = VK_NULL_HANDLE; std::array<VkDescriptorSet, 2> propagation_descriptor_set; + lava::pipeline_layout::ptr geometry_layout; lava::pipeline_layout::ptr capture_layout; lava::pipeline_layout::ptr injection_layout; lava::pipeline_layout::ptr propagation_layout; + lava::render_pass::ptr geometry_pass; lava::render_pass::ptr capture_pass; lava::render_pass::ptr injection_pass; + lava::graphics_pipeline::ptr geometry_pipeline; lava::graphics_pipeline::ptr capture_pipeline; lava::graphics_pipeline::ptr injection_pipeline; lava::compute_pipeline::ptr propagation_pipeline; VkSampler indirect_sampler = VK_NULL_HANDLE; + VkSampler geometry_sampler = VK_NULL_HANDLE; VkSampler injection_sampler = VK_NULL_HANDLE; lava::image::ptr capture_depth_image; @@ -96,14 +109,17 @@ private: std::array<VmaAllocation, 3> distribution_red_image_memory; std::array<VmaAllocation, 3> distribution_green_image_memory; std::array<VmaAllocation, 3> distribution_blue_image_memory; + std::array<VmaAllocation, 4> distribution_geometry_image_memory; std::array<VkImage, 3> distribution_red_image; std::array<VkImage, 3> distribution_green_image; std::array<VkImage, 3> distribution_blue_image; + std::array<VkImage, 4> distribution_geometry_image; std::array<VkImageView, 3> distribution_red_image_view; std::array<VkImageView, 3> distribution_green_image_view; std::array<VkImageView, 3> distribution_blue_image_view; + std::array<VkImageView, 4> distribution_geometry_image_view; std::array<VkImageView, 3> distribution_red_image_array_view; std::array<VkImageView, 3> distribution_green_image_array_view; -- GitLab