Builder pattern for pipelines

Use a builder pattern for pipelines and descriptor sets, so we can go
richer without hugely complicating existing code.

WIP
This commit is contained in:
Raph Levien 2020-11-24 12:36:27 -08:00
parent 4bbc7dee1d
commit 6b06d249ab
5 changed files with 403 additions and 219 deletions

View file

@ -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();

View file

@ -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 = <vulkan::VkDevice as Device>::MemFlags;
@ -63,6 +65,10 @@ struct BufferInner {
session: Weak<SessionInner>,
}
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<Pipeline, Error> {
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<DescriptorSet, Error> {
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<Vec<f64>, 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<Pipeline, Error> {
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::<Vec<_>>();
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::<Vec<_>>();
self.0.add_images(&vk_images);
self
}
pub unsafe fn build(
self,
session: &Session,
pipeline: &Pipeline,
) -> Result<DescriptorSet, Error> {
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<Item = &'a T>;
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<std::slice::Iter<'a, &'a T>>;
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<std::slice::Iter<'a, &'a T>>;
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<std::slice::Iter<'a, &'a T>>;
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<std::slice::Iter<'a, &'a T>>;
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<std::slice::Iter<'a, &'a T>>;
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<std::slice::Iter<'a, &'a T>>;
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<std::slice::Iter<'a, &'a T>>;
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()
}
}

View file

@ -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<Self>;
type Fence;
type Semaphore;
type PipelineBuilder: PipelineBuilder<Self>;
type DescriptorSetBuilder: DescriptorSetBuilder<Self>;
fn create_buffer(&self, size: u64, mem_flags: Self::MemFlags) -> Result<Self::Buffer, Error>;
@ -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<Self::Pipeline, Error>;
) -> Result<Self::Pipeline, Error> {
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<Self::DescriptorSet, Error>;
) -> Result<Self::DescriptorSet, Error> {
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<Self::CmdBuf, Error>;
@ -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<D: Device> {
/// 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<D::Pipeline, Error>;
}
pub trait DescriptorSetBuilder<D: Device> {
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<D::DescriptorSet, Error>;
}

View file

@ -90,6 +90,15 @@ pub struct QueryPool {
#[derive(Clone, Copy)]
pub struct MemFlags(vk::MemoryPropertyFlags);
pub struct PipelineBuilder {
bindings: Vec<vk::DescriptorSetLayoutBinding>,
}
pub struct DescriptorSetBuilder {
buffers: Vec<vk::Buffer>,
images: Vec<vk::ImageView>,
}
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<Buffer, Error> {
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<Pipeline, Error> {
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<DescriptorSet, Error> {
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<CmdBuf, Error> {
@ -1033,6 +910,165 @@ impl crate::MemFlags for MemFlags {
}
}
impl crate::PipelineBuilder<VkDevice> 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<Pipeline, Error> {
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<VkDevice> 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<DescriptorSet, Error> {
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];

View file

@ -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,