diff --git a/src/command_buffer/incomplete.rs b/src/command_buffer/incomplete.rs index c2d8112..2ea410d 100644 --- a/src/command_buffer/incomplete.rs +++ b/src/command_buffer/incomplete.rs @@ -8,22 +8,22 @@ use std::sync::{Arc, MutexGuard}; use anyhow::{anyhow, ensure, Result}; use ash::vk; -use crate::{ - Allocator, BufferView, DebugMessenger, DescriptorCache, DescriptorSet, Device, ImageView, - IncompleteCmdBuffer, PhysicalResourceBindings, PipelineCache, PipelineStage, Sampler, - VirtualResource, -}; -use crate::command_buffer::{CommandBuffer, IncompleteCommandBuffer}; use crate::command_buffer::state::{RenderingAttachmentInfo, RenderingInfo}; +use crate::command_buffer::{CommandBuffer, IncompleteCommandBuffer}; use crate::core::queue::Queue; use crate::descriptor::builder::DescriptorSetBuilder; use crate::pipeline::create_info::PipelineRenderingInfo; use crate::query_pool::{QueryPool, ScopedQuery, TimestampQuery}; use crate::raytracing::acceleration_structure::AccelerationStructure; use crate::sync::domain::ExecutionDomain; +use crate::{ + Allocator, BufferView, DebugMessenger, DescriptorCache, DescriptorSet, Device, ImageView, + IncompleteCmdBuffer, PhysicalResourceBindings, PipelineCache, PipelineStage, Sampler, + VirtualResource, +}; impl<'q, D: ExecutionDomain, A: Allocator> IncompleteCmdBuffer<'q, A> -for IncompleteCommandBuffer<'q, D, A> + for IncompleteCommandBuffer<'q, D, A> { type Domain = D; @@ -284,6 +284,21 @@ impl IncompleteCommandBuffer<'_, D, A> { Ok(self) } + /// Bind an entire array of sampled images using the same sampler. + pub fn bind_sampled_image_array( + mut self, + set: u32, + binding: u32, + images: &[ImageView], + sampler: &Sampler, + ) -> Result { + self.modify_descriptor_set(set, |builder| { + builder.bind_sampled_image_array(binding, images, sampler); + Ok(()) + })?; + Ok(self) + } + /// Binds a new descriptor with type [`vk::DescriptorType::UNIFORM_BUFFER`]. /// This binding is not actually flushed to the command buffer until the next draw or dispatch call. /// # Errors diff --git a/src/core/device.rs b/src/core/device.rs index b478464..d163471 100644 --- a/src/core/device.rs +++ b/src/core/device.rs @@ -216,6 +216,7 @@ impl Device { features.pipeline_statistics_query = vk::TRUE; features_1_2.buffer_device_address = vk::TRUE; features_1_2.host_query_reset = vk::TRUE; + features_1_2.descriptor_indexing = vk::TRUE; features_1_3.synchronization2 = vk::TRUE; features_1_3.dynamic_rendering = vk::TRUE; features_1_3.maintenance4 = vk::TRUE; diff --git a/src/descriptor/builder.rs b/src/descriptor/builder.rs index 059a7d4..bfde29b 100644 --- a/src/descriptor/builder.rs +++ b/src/descriptor/builder.rs @@ -123,6 +123,21 @@ impl<'r> DescriptorSetBuilder<'r> { }); } + /// Bind an entire array of sampled images using the same sampler. + pub fn bind_sampled_image_array(&mut self, binding: u32, images: &[ImageView], sampler: &Sampler) { + self.inner.bindings.push(DescriptorBinding { + binding, + ty: vk::DescriptorType::COMBINED_IMAGE_SAMPLER, + descriptors: images.iter().map(|image| { + DescriptorContents::Image(DescriptorImageInfo { + sampler: unsafe { sampler.handle() }, + view: image.clone(), + layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL + }) + }).collect() + }); + } + /// Bind an image view to the given binding as a [`vk::DescriptorType::COMBINED_IMAGE_SAMPLER`]. /// Uses the reflection information provided at construction to look up the correct binding slot by its name /// defined in the shader. diff --git a/src/pipeline/set_layout.rs b/src/pipeline/set_layout.rs index 7355f3d..96522b2 100644 --- a/src/pipeline/set_layout.rs +++ b/src/pipeline/set_layout.rs @@ -35,6 +35,8 @@ pub struct DescriptorSetLayoutCreateInfo { /// Whether this descriptor set layout is persistent. Should only be true if the pipeline layout /// this belongs to is also persistent. pub persistent: bool, + /// The binding flags for each binding, these are set separately because they go in a separate vulkan struct. + pub flags: Vec, } impl ResourceKey for DescriptorSetLayoutCreateInfo { @@ -50,8 +52,16 @@ impl Resource for DescriptorSetLayout { const MAX_TIME_TO_LIVE: u32 = 8; fn create(device: Device, key: &Self::Key, _: Self::ExtraParams<'_>) -> Result { + let mut flags = vk::DescriptorSetLayoutBindingFlagsCreateInfo { + s_type: vk::StructureType::DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO, + p_next: std::ptr::null(), + binding_count: key.bindings.len() as u32, + p_binding_flags: key.flags.as_ptr(), + }; + let info = vk::DescriptorSetLayoutCreateInfo::builder() .bindings(key.bindings.as_slice()) + .push_next(&mut flags) .build(); let handle = unsafe { device.create_descriptor_set_layout(&info, None)? }; #[cfg(feature = "log-objects")] diff --git a/src/pipeline/shader_reflection.rs b/src/pipeline/shader_reflection.rs index 43802dd..0a059fe 100644 --- a/src/pipeline/shader_reflection.rs +++ b/src/pipeline/shader_reflection.rs @@ -26,6 +26,7 @@ pub(crate) struct BindingInfo { pub stage: vk::ShaderStageFlags, pub count: u32, pub ty: vk::DescriptorType, + pub flags: vk::DescriptorBindingFlags, } /// Stores reflection information about a pipeline. Can be used to derive a pipeline layout @@ -76,14 +77,14 @@ fn find_sampled_images( let set = ast.get_decoration(image.id, Decoration::DescriptorSet)?; let ty = ast.get_type(image.type_id)?; let Type::SampledImage { array, .. } = ty else { unimplemented!() }; - let count = if !array.is_empty() { + let (count, flags) = if !array.is_empty() { if array[0] == 0 { - 4096 // Max unbounded array size. If this is ever exceeded, I'll fix it. + (4096, vk::DescriptorBindingFlags::PARTIALLY_BOUND) } else { - array[0] + (array[0], vk::DescriptorBindingFlags::PARTIALLY_BOUND) } } else { - 1 + (1, vk::DescriptorBindingFlags::empty()) }; info.bindings.insert( @@ -94,6 +95,7 @@ fn find_sampled_images( stage, count, ty: vk::DescriptorType::COMBINED_IMAGE_SAMPLER, + flags, }, ); } @@ -118,6 +120,7 @@ fn find_uniform_buffers( stage, count: 1, ty: vk::DescriptorType::UNIFORM_BUFFER, + flags: vk::DescriptorBindingFlags::empty(), }, ); } @@ -142,6 +145,7 @@ fn find_storage_buffers( stage, count: 1, ty: vk::DescriptorType::STORAGE_BUFFER, + flags: vk::DescriptorBindingFlags::empty(), }, ); } @@ -166,6 +170,7 @@ fn find_storage_images( stage, count: 1, ty: vk::DescriptorType::STORAGE_IMAGE, + flags: vk::DescriptorBindingFlags::empty(), }, ); } @@ -190,6 +195,7 @@ fn find_acceleration_structures( stage, count: 1, ty: vk::DescriptorType::ACCELERATION_STRUCTURE_KHR, + flags: vk::DescriptorBindingFlags::empty(), }, ); } @@ -318,6 +324,7 @@ pub(crate) fn build_pipeline_layout(info: &ReflectionInfo) -> PipelineLayoutCrea stage_flags: binding.stage, p_immutable_samplers: std::ptr::null(), }); + set.flags.push(binding.flags); } Entry::Vacant(entry) => { entry.insert(DescriptorSetLayoutCreateInfo { @@ -328,6 +335,7 @@ pub(crate) fn build_pipeline_layout(info: &ReflectionInfo) -> PipelineLayoutCrea stage_flags: binding.stage, p_immutable_samplers: std::ptr::null(), }], + flags: vec![binding.flags], persistent: false, }); }