diff --git a/piet-gpu-hal/examples/collatz.rs b/piet-gpu-hal/examples/collatz.rs index 3a261ad..84a6fed 100644 --- a/piet-gpu-hal/examples/collatz.rs +++ b/piet-gpu-hal/examples/collatz.rs @@ -14,9 +14,9 @@ fn main() { .unwrap(); buffer.write(&src).unwrap(); let code = include_bytes!("./shader/collatz.spv"); - let pipeline = session.create_simple_compute_pipeline(code, 1, 0).unwrap(); + let pipeline = session.create_simple_compute_pipeline(code, 1).unwrap(); let descriptor_set = session - .create_descriptor_set(&pipeline, &[buffer.vk_buffer()], &[]) + .create_simple_descriptor_set(&pipeline, &[&buffer]) .unwrap(); let query_pool = session.create_query_pool(2).unwrap(); let mut cmd_buf = session.cmd_buf().unwrap(); diff --git a/piet-gpu-hal/src/hub.rs b/piet-gpu-hal/src/hub.rs index 61ca8e9..a16d86f 100644 --- a/piet-gpu-hal/src/hub.rs +++ b/piet-gpu-hal/src/hub.rs @@ -8,6 +8,8 @@ use std::any::Any; use std::sync::{Arc, Mutex, Weak}; use crate::vulkan; +use crate::DescriptorSetBuilder as DescriptorSetBuilderTrait; +use crate::PipelineBuilder as PipelineBuilderTrait; use crate::{Device, Error}; pub type MemFlags = ::MemFlags; @@ -63,6 +65,10 @@ struct BufferInner { session: Weak, } +pub struct PipelineBuilder(vulkan::PipelineBuilder); + +pub struct DescriptorSetBuilder(vulkan::DescriptorSetBuilder); + impl Session { pub fn new(device: vulkan::VkDevice) -> Session { Session(Arc::new(SessionInner { @@ -158,31 +164,28 @@ impl Session { self.0.device.create_semaphore() } - /// This creates a pipeline that runs over the buffer. + /// This creates a pipeline that operates on some buffers and images. /// /// The descriptor set layout is just some number of storage buffers and storage images (this might change). pub unsafe fn create_simple_compute_pipeline( &self, code: &[u8], n_buffers: u32, - n_images: u32, ) -> Result { - self.0 - .device - .create_simple_compute_pipeline(code, n_buffers, n_images) + self.pipeline_builder() + .add_buffers(n_buffers) + .create_compute_pipeline(self, code) } - /// Create a descriptor set for a simple pipeline that just references buffers and images. - /// - /// Note: when we do portability, the signature will change to not reference the Vulkan types - /// directly. - pub unsafe fn create_descriptor_set( + /// Create a descriptor set for a simple pipeline that just references buffers. + pub unsafe fn create_simple_descriptor_set<'a>( &self, pipeline: &Pipeline, - bufs: &[&vulkan::Buffer], - images: &[&vulkan::Image], + buffers: impl IntoRefs<'a, Buffer>, ) -> Result { - self.0.device.create_descriptor_set(pipeline, bufs, images) + self.descriptor_set_builder() + .add_buffers(buffers) + .build(self, pipeline) } /// Create a query pool for timestamp queries. @@ -193,6 +196,14 @@ impl Session { pub unsafe fn fetch_query_pool(&self, pool: &QueryPool) -> Result, Error> { self.0.device.fetch_query_pool(pool) } + + pub unsafe fn pipeline_builder(&self) -> PipelineBuilder { + PipelineBuilder(self.0.device.pipeline_builder()) + } + + pub unsafe fn descriptor_set_builder(&self) -> DescriptorSetBuilder { + DescriptorSetBuilder(self.0.device.descriptor_set_builder()) + } } impl CmdBuf { @@ -299,3 +310,122 @@ impl Buffer { Ok(()) } } + +impl PipelineBuilder { + /// Add buffers to the pipeline. Each has its own binding. + pub fn add_buffers(mut self, n_buffers: u32) -> Self { + self.0.add_buffers(n_buffers); + self + } + + /// Add storage images to the pipeline. Each has its own binding. + pub fn add_images(mut self, n_images: u32) -> Self { + self.0.add_images(n_images); + self + } + + pub unsafe fn create_compute_pipeline( + self, + session: &Session, + code: &[u8], + ) -> Result { + self.0.create_compute_pipeline(&session.0.device, code) + } +} + +impl DescriptorSetBuilder { + pub fn add_buffers<'a>(mut self, buffers: impl IntoRefs<'a, Buffer>) -> Self { + let vk_buffers = buffers + .into_refs() + .map(|b| b.vk_buffer()) + .collect::>(); + self.0.add_buffers(&vk_buffers); + self + } + + pub fn add_images<'a>(mut self, images: impl IntoRefs<'a, Image>) -> Self { + let vk_images = images.into_refs().map(|i| i.vk_image()).collect::>(); + self.0.add_images(&vk_images); + self + } + + pub unsafe fn build( + self, + session: &Session, + pipeline: &Pipeline, + ) -> Result { + self.0.build(&session.0.device, pipeline) + } +} + +// This lets us use either a slice or a vector. The type is clunky but it +// seems fine enough to use. +pub trait IntoRefs<'a, T: 'a> { + type Iterator: Iterator; + + fn into_refs(self) -> Self::Iterator; +} + +impl<'a, T> IntoRefs<'a, T> for &'a [T] { + type Iterator = std::slice::Iter<'a, T>; + fn into_refs(self) -> Self::Iterator { + self.into_iter() + } +} + +impl<'a, T> IntoRefs<'a, T> for &'a [&'a T] { + type Iterator = std::iter::Copied>; + fn into_refs(self) -> Self::Iterator { + self.into_iter().copied() + } +} + +// TODO: this will benefit from const generics! +impl<'a, T> IntoRefs<'a, T> for &'a [&'a T; 1] { + type Iterator = std::iter::Copied>; + fn into_refs(self) -> Self::Iterator { + self.into_iter().copied() + } +} + +impl<'a, T> IntoRefs<'a, T> for &'a [&'a T; 2] { + type Iterator = std::iter::Copied>; + fn into_refs(self) -> Self::Iterator { + self.into_iter().copied() + } +} + +impl<'a, T> IntoRefs<'a, T> for &'a [&'a T; 3] { + type Iterator = std::iter::Copied>; + fn into_refs(self) -> Self::Iterator { + self.into_iter().copied() + } +} + +impl<'a, T> IntoRefs<'a, T> for &'a [&'a T; 4] { + type Iterator = std::iter::Copied>; + fn into_refs(self) -> Self::Iterator { + self.into_iter().copied() + } +} + +impl<'a, T> IntoRefs<'a, T> for &'a [&'a T; 5] { + type Iterator = std::iter::Copied>; + fn into_refs(self) -> Self::Iterator { + self.into_iter().copied() + } +} + +impl<'a, T> IntoRefs<'a, T> for &'a [&'a T; 6] { + type Iterator = std::iter::Copied>; + fn into_refs(self) -> Self::Iterator { + self.into_iter().copied() + } +} + +impl<'a, T> IntoRefs<'a, T> for Vec<&'a T> { + type Iterator = std::vec::IntoIter<&'a T>; + fn into_refs(self) -> Self::Iterator { + self.into_iter() + } +} diff --git a/piet-gpu-hal/src/lib.rs b/piet-gpu-hal/src/lib.rs index 1e04b8d..6ac7766 100644 --- a/piet-gpu-hal/src/lib.rs +++ b/piet-gpu-hal/src/lib.rs @@ -19,7 +19,7 @@ pub enum ImageLayout { } pub trait Device: Sized { - type Buffer; + type Buffer: 'static; type Image; type MemFlags: MemFlags; type Pipeline; @@ -28,6 +28,8 @@ pub trait Device: Sized { type CmdBuf: CmdBuf; type Fence; type Semaphore; + type PipelineBuilder: PipelineBuilder; + type DescriptorSetBuilder: DescriptorSetBuilder; fn create_buffer(&self, size: u64, mem_flags: Self::MemFlags) -> Result; @@ -56,19 +58,48 @@ pub trait Device: Sized { /// Maybe doesn't need result return? unsafe fn destroy_image(&self, image: &Self::Image) -> Result<(), Error>; + /// Start building a pipeline. + /// + /// A pipeline is a bit of shader IR plus a signature for what kinds of resources + /// it expects. + unsafe fn pipeline_builder(&self) -> Self::PipelineBuilder; + + /// Start building a descriptor set. + /// + /// A descriptor set is a binding of resources for a given pipeline. + unsafe fn descriptor_set_builder(&self) -> Self::DescriptorSetBuilder; + + /// Create a simple compute pipeline that operates on buffers and storage images. + /// + /// This is provided as a convenience but will probably go away, as the functionality + /// is subsumed by the builder. unsafe fn create_simple_compute_pipeline( &self, code: &[u8], n_buffers: u32, n_images: u32, - ) -> Result; + ) -> Result { + let mut builder = self.pipeline_builder(); + builder.add_buffers(n_buffers); + builder.add_images(n_images); + builder.create_compute_pipeline(self, code) + } + /// Create a descriptor set for a given pipeline, binding buffers and images. + /// + /// This is provided as a convenience but will probably go away, as the functionality + /// is subsumed by the builder. unsafe fn create_descriptor_set( &self, pipeline: &Self::Pipeline, bufs: &[&Self::Buffer], images: &[&Self::Image], - ) -> Result; + ) -> Result { + let mut builder = self.descriptor_set_builder(); + builder.add_buffers(bufs); + builder.add_images(images); + builder.build(self, pipeline) + } fn create_cmd_buf(&self) -> Result; @@ -174,3 +205,18 @@ pub trait MemFlags: Sized + Clone + Copy { fn host_coherent() -> Self; } + +/// A builder for pipelines with more complex layouts. +pub trait PipelineBuilder { + /// Add buffers to the pipeline. Each has its own binding. + fn add_buffers(&mut self, n_buffers: u32); + /// Add storage images to the pipeline. Each has its own binding. + fn add_images(&mut self, n_images: u32); + unsafe fn create_compute_pipeline(self, device: &D, code: &[u8]) -> Result; +} + +pub trait DescriptorSetBuilder { + fn add_buffers(&mut self, buffers: &[&D::Buffer]); + fn add_images(&mut self, images: &[&D::Image]); + unsafe fn build(self, device: &D, pipeline: &D::Pipeline) -> Result; +} diff --git a/piet-gpu-hal/src/vulkan.rs b/piet-gpu-hal/src/vulkan.rs index 53d575b..a269b6b 100644 --- a/piet-gpu-hal/src/vulkan.rs +++ b/piet-gpu-hal/src/vulkan.rs @@ -90,6 +90,15 @@ pub struct QueryPool { #[derive(Clone, Copy)] pub struct MemFlags(vk::MemoryPropertyFlags); +pub struct PipelineBuilder { + bindings: Vec, +} + +pub struct DescriptorSetBuilder { + buffers: Vec, + images: Vec, +} + unsafe extern "system" fn vulkan_debug_callback( message_severity: vk::DebugUtilsMessageSeverityFlagsEXT, message_type: vk::DebugUtilsMessageTypeFlagsEXT, @@ -375,6 +384,8 @@ impl crate::Device for VkDevice { type MemFlags = MemFlags; type Fence = vk::Fence; type Semaphore = vk::Semaphore; + type PipelineBuilder = PipelineBuilder; + type DescriptorSetBuilder = DescriptorSetBuilder; fn create_buffer(&self, size: u64, mem_flags: MemFlags) -> Result { unsafe { @@ -527,151 +538,17 @@ impl crate::Device for VkDevice { Ok(device.get_fence_status(fence)?) } - /// This creates a pipeline that runs over the buffer. - /// - /// The descriptor set layout is just some number of storage buffers and storage images (this might change). - unsafe fn create_simple_compute_pipeline( - &self, - code: &[u8], - n_buffers: u32, - n_images: u32, - ) -> Result { - let device = &self.device.device; - let mut bindings = Vec::new(); - for i in 0..n_buffers { - bindings.push( - vk::DescriptorSetLayoutBinding::builder() - .binding(i) - .descriptor_type(vk::DescriptorType::STORAGE_BUFFER) - .descriptor_count(1) - .stage_flags(vk::ShaderStageFlags::COMPUTE) - .build(), - ); + unsafe fn pipeline_builder(&self) -> PipelineBuilder { + PipelineBuilder { + bindings: Vec::new(), } - for i in n_buffers..n_buffers + n_images { - bindings.push( - vk::DescriptorSetLayoutBinding::builder() - .binding(i) - .descriptor_type(vk::DescriptorType::STORAGE_IMAGE) - .descriptor_count(1) - .stage_flags(vk::ShaderStageFlags::COMPUTE) - .build(), - ); - } - let descriptor_set_layout = device.create_descriptor_set_layout( - &vk::DescriptorSetLayoutCreateInfo::builder().bindings(&bindings), - None, - )?; - - let descriptor_set_layouts = [descriptor_set_layout]; - - // Create compute pipeline. - let code_u32 = convert_u32_vec(code); - let compute_shader_module = device - .create_shader_module(&vk::ShaderModuleCreateInfo::builder().code(&code_u32), None)?; - let entry_name = CString::new("main").unwrap(); - let pipeline_layout = device.create_pipeline_layout( - &vk::PipelineLayoutCreateInfo::builder().set_layouts(&descriptor_set_layouts), - None, - )?; - - let pipeline = device - .create_compute_pipelines( - vk::PipelineCache::null(), - &[vk::ComputePipelineCreateInfo::builder() - .stage( - vk::PipelineShaderStageCreateInfo::builder() - .stage(vk::ShaderStageFlags::COMPUTE) - .module(compute_shader_module) - .name(&entry_name) - .build(), - ) - .layout(pipeline_layout) - .build()], - None, - ) - .map_err(|(_pipeline, err)| err)?[0]; - Ok(Pipeline { - pipeline, - pipeline_layout, - descriptor_set_layout, - }) } - unsafe fn create_descriptor_set( - &self, - pipeline: &Pipeline, - bufs: &[&Buffer], - images: &[&Image], - ) -> Result { - let device = &self.device.device; - let mut descriptor_pool_sizes = Vec::new(); - if !bufs.is_empty() { - descriptor_pool_sizes.push( - vk::DescriptorPoolSize::builder() - .ty(vk::DescriptorType::STORAGE_BUFFER) - .descriptor_count(bufs.len() as u32) - .build(), - ); + unsafe fn descriptor_set_builder(&self) -> DescriptorSetBuilder { + DescriptorSetBuilder { + buffers: Vec::new(), + images: Vec::new(), } - if !images.is_empty() { - descriptor_pool_sizes.push( - vk::DescriptorPoolSize::builder() - .ty(vk::DescriptorType::STORAGE_IMAGE) - .descriptor_count(images.len() as u32) - .build(), - ); - } - let descriptor_pool = device.create_descriptor_pool( - &vk::DescriptorPoolCreateInfo::builder() - .pool_sizes(&descriptor_pool_sizes) - .max_sets(1), - None, - )?; - let descriptor_set_layouts = [pipeline.descriptor_set_layout]; - let descriptor_sets = device - .allocate_descriptor_sets( - &vk::DescriptorSetAllocateInfo::builder() - .descriptor_pool(descriptor_pool) - .set_layouts(&descriptor_set_layouts), - ) - .unwrap(); - for (i, buf) in bufs.iter().enumerate() { - let buf_info = vk::DescriptorBufferInfo::builder() - .buffer(buf.buffer) - .offset(0) - .range(vk::WHOLE_SIZE) - .build(); - device.update_descriptor_sets( - &[vk::WriteDescriptorSet::builder() - .dst_set(descriptor_sets[0]) - .dst_binding(i as u32) - .descriptor_type(vk::DescriptorType::STORAGE_BUFFER) - .buffer_info(&[buf_info]) - .build()], - &[], - ); - } - for (i, image) in images.iter().enumerate() { - let binding = i + bufs.len(); - let image_info = vk::DescriptorImageInfo::builder() - .sampler(vk::Sampler::null()) - .image_view(image.image_view) - .image_layout(vk::ImageLayout::GENERAL) - .build(); - device.update_descriptor_sets( - &[vk::WriteDescriptorSet::builder() - .dst_set(descriptor_sets[0]) - .dst_binding(binding as u32) - .descriptor_type(vk::DescriptorType::STORAGE_IMAGE) - .image_info(&[image_info]) - .build()], - &[], - ); - } - Ok(DescriptorSet { - descriptor_set: descriptor_sets[0], - }) } fn create_cmd_buf(&self) -> Result { @@ -1033,6 +910,165 @@ impl crate::MemFlags for MemFlags { } } +impl crate::PipelineBuilder for PipelineBuilder { + fn add_buffers(&mut self, n_buffers: u32) { + let start = self.bindings.len() as u32; + for i in 0..n_buffers { + self.bindings.push( + vk::DescriptorSetLayoutBinding::builder() + .binding(start + i) + .descriptor_type(vk::DescriptorType::STORAGE_BUFFER) + .descriptor_count(1) + .stage_flags(vk::ShaderStageFlags::COMPUTE) + .build(), + ); + } + } + + fn add_images(&mut self, n_images: u32) { + let start = self.bindings.len() as u32; + for i in 0..n_images { + self.bindings.push( + vk::DescriptorSetLayoutBinding::builder() + .binding(start + i) + .descriptor_type(vk::DescriptorType::STORAGE_IMAGE) + .descriptor_count(1) + .stage_flags(vk::ShaderStageFlags::COMPUTE) + .build(), + ); + } + } + + unsafe fn create_compute_pipeline( + self, + device: &VkDevice, + code: &[u8], + ) -> Result { + let device = &device.device.device; + let descriptor_set_layout = device.create_descriptor_set_layout( + &vk::DescriptorSetLayoutCreateInfo::builder().bindings(&self.bindings), + None, + )?; + let descriptor_set_layouts = [descriptor_set_layout]; + + // Create compute pipeline. + let code_u32 = convert_u32_vec(code); + let compute_shader_module = device + .create_shader_module(&vk::ShaderModuleCreateInfo::builder().code(&code_u32), None)?; + let entry_name = CString::new("main").unwrap(); + let pipeline_layout = device.create_pipeline_layout( + &vk::PipelineLayoutCreateInfo::builder().set_layouts(&descriptor_set_layouts), + None, + )?; + + let pipeline = device + .create_compute_pipelines( + vk::PipelineCache::null(), + &[vk::ComputePipelineCreateInfo::builder() + .stage( + vk::PipelineShaderStageCreateInfo::builder() + .stage(vk::ShaderStageFlags::COMPUTE) + .module(compute_shader_module) + .name(&entry_name) + .build(), + ) + .layout(pipeline_layout) + .build()], + None, + ) + .map_err(|(_pipeline, err)| err)?[0]; + Ok(Pipeline { + pipeline, + pipeline_layout, + descriptor_set_layout, + }) + } +} + +impl crate::DescriptorSetBuilder for DescriptorSetBuilder { + fn add_buffers(&mut self, buffers: &[&Buffer]) { + self.buffers.extend(buffers.iter().map(|b| b.buffer)); + } + + fn add_images(&mut self, images: &[&Image]) { + self.images.extend(images.iter().map(|i| i.image_view)); + } + + unsafe fn build(self, device: &VkDevice, pipeline: &Pipeline) -> Result { + let device = &device.device.device; + let mut descriptor_pool_sizes = Vec::new(); + if !self.buffers.is_empty() { + descriptor_pool_sizes.push( + vk::DescriptorPoolSize::builder() + .ty(vk::DescriptorType::STORAGE_BUFFER) + .descriptor_count(self.buffers.len() as u32) + .build(), + ); + } + if !self.images.is_empty() { + descriptor_pool_sizes.push( + vk::DescriptorPoolSize::builder() + .ty(vk::DescriptorType::STORAGE_IMAGE) + .descriptor_count(self.images.len() as u32) + .build(), + ); + } + let descriptor_pool = device.create_descriptor_pool( + &vk::DescriptorPoolCreateInfo::builder() + .pool_sizes(&descriptor_pool_sizes) + .max_sets(1), + None, + )?; + let descriptor_set_layouts = [pipeline.descriptor_set_layout]; + let descriptor_sets = device + .allocate_descriptor_sets( + &vk::DescriptorSetAllocateInfo::builder() + .descriptor_pool(descriptor_pool) + .set_layouts(&descriptor_set_layouts), + ) + .unwrap(); + let mut binding = 0; + // Maybe one call to update_descriptor_sets with an array of descriptor_writes? + for buf in &self.buffers { + let buf_info = vk::DescriptorBufferInfo::builder() + .buffer(*buf) + .offset(0) + .range(vk::WHOLE_SIZE) + .build(); + device.update_descriptor_sets( + &[vk::WriteDescriptorSet::builder() + .dst_set(descriptor_sets[0]) + .dst_binding(binding) + .descriptor_type(vk::DescriptorType::STORAGE_BUFFER) + .buffer_info(&[buf_info]) + .build()], + &[], + ); + binding += 1; + } + for image in &self.images { + let image_info = vk::DescriptorImageInfo::builder() + .sampler(vk::Sampler::null()) + .image_view(*image) + .image_layout(vk::ImageLayout::GENERAL) + .build(); + device.update_descriptor_sets( + &[vk::WriteDescriptorSet::builder() + .dst_set(descriptor_sets[0]) + .dst_binding(binding) + .descriptor_type(vk::DescriptorType::STORAGE_IMAGE) + .image_info(&[image_info]) + .build()], + &[], + ); + binding += 1; + } + Ok(DescriptorSet { + descriptor_set: descriptor_sets[0], + }) + } +} + impl VkSwapchain { pub unsafe fn next(&mut self) -> Result<(usize, vk::Semaphore), Error> { let acquisition_semaphore = self.acquisition_semaphores[self.acquisition_idx]; diff --git a/piet-gpu/src/lib.rs b/piet-gpu/src/lib.rs index 0a6152d..cd7bfbe 100644 --- a/piet-gpu/src/lib.rs +++ b/piet-gpu/src/lib.rs @@ -234,16 +234,10 @@ impl Renderer { let image_dev = session.create_image2d(WIDTH as u32, HEIGHT as u32, dev)?; let el_code = include_bytes!("../shader/elements.spv"); - let el_pipeline = session.create_simple_compute_pipeline(el_code, 4, 0)?; - let el_ds = session.create_descriptor_set( + let el_pipeline = session.create_simple_compute_pipeline(el_code, 4)?; + let el_ds = session.create_simple_descriptor_set( &el_pipeline, - &[ - scene_dev.vk_buffer(), - state_buf.vk_buffer(), - anno_buf.vk_buffer(), - pathseg_buf.vk_buffer(), - ], - &[], + &[&scene_dev, &state_buf, &anno_buf, &pathseg_buf], )?; let mut tile_alloc_buf_host = session.create_buffer(12, host)?; @@ -254,40 +248,24 @@ impl Renderer { let tile_alloc_start = ((n_paths + 31) & !31) * PATH_SIZE; tile_alloc_buf_host.write(&[n_paths as u32, n_pathseg as u32, tile_alloc_start as u32])?; let tile_alloc_code = include_bytes!("../shader/tile_alloc.spv"); - let tile_pipeline = session.create_simple_compute_pipeline(tile_alloc_code, 3, 0)?; - let tile_ds = session.create_descriptor_set( + let tile_pipeline = session.create_simple_compute_pipeline(tile_alloc_code, 3)?; + let tile_ds = session.create_simple_descriptor_set( &tile_pipeline, - &[ - anno_buf.vk_buffer(), - tile_alloc_buf_dev.vk_buffer(), - tile_buf.vk_buffer(), - ], - &[], + &[&anno_buf, &tile_alloc_buf_dev, &tile_buf], )?; let path_alloc_code = include_bytes!("../shader/path_coarse.spv"); - let path_pipeline = session.create_simple_compute_pipeline(path_alloc_code, 3, 0)?; - let path_ds = session.create_descriptor_set( + let path_pipeline = session.create_simple_compute_pipeline(path_alloc_code, 3)?; + let path_ds = session.create_simple_descriptor_set( &path_pipeline, - &[ - pathseg_buf.vk_buffer(), - tile_alloc_buf_dev.vk_buffer(), - tile_buf.vk_buffer(), - ], - &[], + &[&pathseg_buf, &tile_alloc_buf_dev, &tile_buf], )?; let backdrop_alloc_code = include_bytes!("../shader/backdrop.spv"); - let backdrop_pipeline = - session.create_simple_compute_pipeline(backdrop_alloc_code, 3, 0)?; - let backdrop_ds = session.create_descriptor_set( + let backdrop_pipeline = session.create_simple_compute_pipeline(backdrop_alloc_code, 3)?; + let backdrop_ds = session.create_simple_descriptor_set( &backdrop_pipeline, - &[ - anno_buf.vk_buffer(), - tile_alloc_buf_dev.vk_buffer(), - tile_buf.vk_buffer(), - ], - &[], + &[&anno_buf, &tile_alloc_buf_dev, &tile_buf], )?; let mut bin_alloc_buf_host = session.create_buffer(8, host)?; @@ -297,15 +275,10 @@ impl Renderer { let bin_alloc_start = ((n_paths + 255) & !255) * 8; bin_alloc_buf_host.write(&[n_paths as u32, bin_alloc_start as u32])?; let bin_code = include_bytes!("../shader/binning.spv"); - let bin_pipeline = session.create_simple_compute_pipeline(bin_code, 3, 0)?; - let bin_ds = session.create_descriptor_set( + let bin_pipeline = session.create_simple_compute_pipeline(bin_code, 3)?; + let bin_ds = session.create_simple_descriptor_set( &bin_pipeline, - &[ - anno_buf.vk_buffer(), - bin_alloc_buf_dev.vk_buffer(), - bin_buf.vk_buffer(), - ], - &[], + &[&anno_buf, &bin_alloc_buf_dev, &bin_buf], )?; let clip_scratch_buf = session.create_buffer(1024 * 1024, dev)?; @@ -316,30 +289,29 @@ impl Renderer { let coarse_alloc_start = WIDTH_IN_TILES * HEIGHT_IN_TILES * PTCL_INITIAL_ALLOC; coarse_alloc_buf_host.write(&[n_paths as u32, coarse_alloc_start as u32])?; let coarse_code = include_bytes!("../shader/coarse.spv"); - let coarse_pipeline = session.create_simple_compute_pipeline(coarse_code, 5, 0)?; - let coarse_ds = session.create_descriptor_set( + let coarse_pipeline = session.create_simple_compute_pipeline(coarse_code, 5)?; + let coarse_ds = session.create_simple_descriptor_set( &coarse_pipeline, &[ - anno_buf.vk_buffer(), - bin_buf.vk_buffer(), - tile_buf.vk_buffer(), - coarse_alloc_buf_dev.vk_buffer(), - ptcl_buf.vk_buffer(), + &anno_buf, + &bin_buf, + &tile_buf, + &coarse_alloc_buf_dev, + &ptcl_buf, ], - &[], )?; let k4_code = include_bytes!("../shader/kernel4.spv"); - let k4_pipeline = session.create_simple_compute_pipeline(k4_code, 3, 1)?; - let k4_ds = session.create_descriptor_set( - &k4_pipeline, - &[ - ptcl_buf.vk_buffer(), - tile_buf.vk_buffer(), - clip_scratch_buf.vk_buffer(), - ], - &[image_dev.vk_image()], - )?; + let k4_pipeline = session + .pipeline_builder() + .add_buffers(3) + .add_images(1) + .create_compute_pipeline(&session, k4_code)?; + let k4_ds = session + .descriptor_set_builder() + .add_buffers(&[&ptcl_buf, &tile_buf, &clip_scratch_buf]) + .add_images(&[&image_dev]) + .build(&session, &k4_pipeline)?; Ok(Renderer { scene_buf,