Add support for immutable samplers, some small changes (#1688)

This commit is contained in:
Rua 2021-09-04 06:20:05 +02:00 committed by GitHub
parent 8a9c617a19
commit ebf3ace481
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 1038 additions and 538 deletions

View File

@ -113,7 +113,14 @@ fn main() {
}
}
let shader = cs::Shader::load(device.clone()).unwrap();
ComputePipeline::new(device.clone(), &shader.main_entry_point(), &(), None).unwrap()
ComputePipeline::new(
device.clone(),
&shader.main_entry_point(),
&(),
None,
|_| {},
)
.unwrap()
});
// We start by creating the buffer that will store the data.
@ -144,15 +151,9 @@ fn main() {
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
set_builder
.add_buffer(data_buffer.clone())
.unwrap();
set_builder.add_buffer(data_buffer.clone()).unwrap();
let set = Arc::new(
set_builder
.build()
.unwrap()
);
let set = Arc::new(set_builder.build().unwrap());
// In order to execute our operation, we have to build a command buffer.
let mut builder = AutoCommandBufferBuilder::primary(

View File

@ -18,17 +18,13 @@ use std::mem;
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::layout::{DescriptorSetDesc, DescriptorSetLayout};
use vulkano::descriptor_set::{DescriptorSet, PersistentDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::instance::{Instance, InstanceExtensions};
use vulkano::pipeline::layout::PipelineLayout;
use vulkano::pipeline::shader::EntryPointAbstract;
use vulkano::pipeline::{ComputePipeline, PipelineBindPoint};
use vulkano::sync;
use vulkano::sync::GpuFuture;
use vulkano::descriptor_set::layout::DescriptorSetLayoutError;
use vulkano::Version;
fn main() {
@ -101,52 +97,15 @@ fn main() {
}
let shader = shader::Shader::load(device.clone()).unwrap();
// For Graphics pipelines, use the `with_auto_layout` method
// instead of the `build` method to specify dynamic buffers.
// `with_auto_layout` will automatically handle tweaking the
// pipeline.
let pipeline = Arc::new(
ComputePipeline::with_pipeline_layout(
ComputePipeline::new(
device.clone(),
&shader.main_entry_point(),
&(),
{
let mut descriptor_set_layout_descs: Vec<_> = shader
.main_entry_point()
.descriptor_set_layout_descs()
.iter()
.cloned()
.collect();
DescriptorSetDesc::tweak_multiple(
&mut descriptor_set_layout_descs,
[(0, 0)], // The dynamic uniform buffer is at set 0, descriptor 0
);
let descriptor_set_layouts = descriptor_set_layout_descs
.into_iter()
.map(|desc| {
Ok(Arc::new(DescriptorSetLayout::new(
device.clone(),
desc.clone(),
)?))
})
.collect::<Result<Vec<_>, DescriptorSetLayoutError>>()
.unwrap();
Arc::new(
PipelineLayout::new(
device.clone(),
descriptor_set_layouts,
shader
.main_entry_point()
.push_constant_range()
.iter()
.cloned(),
)
.unwrap(),
)
},
None,
|set_descs| {
set_descs[0].set_buffer_dynamic(0);
},
)
.unwrap(),
);
@ -207,11 +166,7 @@ fn main() {
.add_buffer(output_buffer.clone())
.unwrap();
let set = Arc::new(
set_builder
.build()
.unwrap()
);
let set = Arc::new(set_builder.build().unwrap());
// Build the command buffer, using different offsets for each call.
let mut builder = AutoCommandBufferBuilder::primary(

View File

@ -180,6 +180,7 @@ fn main() {
&shader.main_entry_point(),
&spec_consts,
None,
|_| {},
)
.unwrap(),
);
@ -200,15 +201,9 @@ fn main() {
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
set_builder
.add_image(view.clone())
.unwrap();
set_builder.add_image(view.clone()).unwrap();
let set = Arc::new(
set_builder
.build()
.unwrap()
);
let set = Arc::new(set_builder.build().unwrap());
let buf = CpuAccessibleBuffer::from_iter(
device.clone(),

View File

@ -90,7 +90,14 @@ void main() {
}
}
let shader = cs::Shader::load(device.clone()).unwrap();
ComputePipeline::new(device.clone(), &shader.main_entry_point(), &(), None).unwrap()
ComputePipeline::new(
device.clone(),
&shader.main_entry_point(),
&(),
None,
|_| {},
)
.unwrap()
});
let data_buffer = {
@ -148,11 +155,7 @@ void main() {
.add_buffer(immutable_data_buffer.clone())
.unwrap();
let set = Arc::new(
set_builder
.build()
.unwrap()
);
let set = Arc::new(set_builder.build().unwrap());
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,390 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
// An immutable sampler is a sampler that is integrated into the descriptor set layout
// (and thus pipeline layout), instead of being written to an individual descriptor set.
// Consequently, all descriptor sets with this layout will share the same sampler.
//
// This example is almost identical to the image example, but with two differences, which have
// been commented:
// - The sampler is added to the descriptor set layout at pipeline creation.
// - No sampler is included when building a descriptor set.
use png;
use std::io::Cursor;
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::format::Format;
use vulkano::image::{
view::ImageView, ImageDimensions, ImageUsage, ImmutableImage, MipmapsCount, SwapchainImage,
};
use vulkano::instance::Instance;
use vulkano::pipeline::viewport::Viewport;
use vulkano::pipeline::{GraphicsPipeline, PipelineBindPoint};
use vulkano::render_pass::{Framebuffer, FramebufferAbstract, RenderPass, Subpass};
use vulkano::sampler::{Filter, MipmapMode, Sampler, SamplerAddressMode};
use vulkano::swapchain;
use vulkano::swapchain::{AcquireError, Swapchain, SwapchainCreationError};
use vulkano::sync;
use vulkano::sync::{FlushError, GpuFuture};
use vulkano::Version;
use vulkano_win::VkSurfaceBuild;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder};
fn main() {
let required_extensions = vulkano_win::required_extensions();
let instance = Instance::new(None, Version::V1_1, &required_extensions, None).unwrap();
let event_loop = EventLoop::new();
let surface = WindowBuilder::new()
.build_vk_surface(&event_loop, instance.clone())
.unwrap();
let device_extensions = DeviceExtensions {
khr_swapchain: true,
..DeviceExtensions::none()
};
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
.filter_map(|p| {
p.queue_families()
.find(|&q| q.supports_graphics() && surface.is_supported(q).unwrap_or(false))
.map(|q| (p, q))
})
.min_by_key(|(p, _)| match p.properties().device_type {
PhysicalDeviceType::DiscreteGpu => 0,
PhysicalDeviceType::IntegratedGpu => 1,
PhysicalDeviceType::VirtualGpu => 2,
PhysicalDeviceType::Cpu => 3,
PhysicalDeviceType::Other => 4,
})
.unwrap();
println!(
"Using device: {} (type: {:?})",
physical_device.properties().device_name,
physical_device.properties().device_type,
);
let (device, mut queues) = Device::new(
physical_device,
&Features::none(),
&physical_device
.required_extensions()
.union(&device_extensions),
[(queue_family, 0.5)].iter().cloned(),
)
.unwrap();
let queue = queues.next().unwrap();
let (mut swapchain, images) = {
let caps = surface.capabilities(physical_device).unwrap();
let composite_alpha = caps.supported_composite_alpha.iter().next().unwrap();
let format = caps.supported_formats[0].0;
let dimensions: [u32; 2] = surface.window().inner_size().into();
Swapchain::start(device.clone(), surface.clone())
.num_images(caps.min_image_count)
.format(format)
.dimensions(dimensions)
.usage(ImageUsage::color_attachment())
.sharing_mode(&queue)
.composite_alpha(composite_alpha)
.build()
.unwrap()
};
#[derive(Default, Debug, Clone)]
struct Vertex {
position: [f32; 2],
}
vulkano::impl_vertex!(Vertex, position);
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
device.clone(),
BufferUsage::all(),
false,
[
Vertex {
position: [-0.5, -0.5],
},
Vertex {
position: [-0.5, 0.5],
},
Vertex {
position: [0.5, -0.5],
},
Vertex {
position: [0.5, 0.5],
},
]
.iter()
.cloned(),
)
.unwrap();
let vs = vs::Shader::load(device.clone()).unwrap();
let fs = fs::Shader::load(device.clone()).unwrap();
let render_pass = Arc::new(
vulkano::single_pass_renderpass!(device.clone(),
attachments: {
color: {
load: Clear,
store: Store,
format: swapchain.format(),
samples: 1,
}
},
pass: {
color: [color],
depth_stencil: {}
}
)
.unwrap(),
);
let (texture, tex_future) = {
let png_bytes = include_bytes!("image_img.png").to_vec();
let cursor = Cursor::new(png_bytes);
let decoder = png::Decoder::new(cursor);
let (info, mut reader) = decoder.read_info().unwrap();
let dimensions = ImageDimensions::Dim2d {
width: info.width,
height: info.height,
array_layers: 1,
};
let mut image_data = Vec::new();
image_data.resize((info.width * info.height * 4) as usize, 0);
reader.next_frame(&mut image_data).unwrap();
let (image, future) = ImmutableImage::from_iter(
image_data.iter().cloned(),
dimensions,
MipmapsCount::One,
Format::R8G8B8A8_SRGB,
queue.clone(),
)
.unwrap();
(ImageView::new(image).unwrap(), future)
};
let sampler = Sampler::new(
device.clone(),
Filter::Linear,
Filter::Linear,
MipmapMode::Nearest,
SamplerAddressMode::Repeat,
SamplerAddressMode::Repeat,
SamplerAddressMode::Repeat,
0.0,
1.0,
0.0,
0.0,
)
.unwrap();
let pipeline = Arc::new(
GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex>()
.vertex_shader(vs.main_entry_point(), ())
.triangle_strip()
.viewports_dynamic_scissors_irrelevant(1)
.fragment_shader(fs.main_entry_point(), ())
.blend_alpha_blending()
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
.with_auto_layout(device.clone(), |set_descs| {
// Modify the auto-generated layout by setting an immutable sampler to
// set 0 binding 0.
set_descs[0].set_immutable_samplers(0, [sampler]);
})
.unwrap(),
);
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
// Use `add_image` instead of `add_sampled_image`, since the sampler is already in the layout.
set_builder.add_image(texture.clone()).unwrap();
let set = Arc::new(set_builder.build().unwrap());
let mut viewport = Viewport {
origin: [0.0, 0.0],
dimensions: [0.0, 0.0],
depth_range: 0.0..1.0,
};
let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport);
let mut recreate_swapchain = false;
let mut previous_frame_end = Some(tex_future.boxed());
event_loop.run(move |event, _, control_flow| match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => {
*control_flow = ControlFlow::Exit;
}
Event::WindowEvent {
event: WindowEvent::Resized(_),
..
} => {
recreate_swapchain = true;
}
Event::RedrawEventsCleared => {
previous_frame_end.as_mut().unwrap().cleanup_finished();
if recreate_swapchain {
let dimensions: [u32; 2] = surface.window().inner_size().into();
let (new_swapchain, new_images) =
match swapchain.recreate().dimensions(dimensions).build() {
Ok(r) => r,
Err(SwapchainCreationError::UnsupportedDimensions) => return,
Err(e) => panic!("Failed to recreate swapchain: {:?}", e),
};
swapchain = new_swapchain;
framebuffers =
window_size_dependent_setup(&new_images, render_pass.clone(), &mut viewport);
recreate_swapchain = false;
}
let (image_num, suboptimal, acquire_future) =
match swapchain::acquire_next_image(swapchain.clone(), None) {
Ok(r) => r,
Err(AcquireError::OutOfDate) => {
recreate_swapchain = true;
return;
}
Err(e) => panic!("Failed to acquire next image: {:?}", e),
};
if suboptimal {
recreate_swapchain = true;
}
let clear_values = vec![[0.0, 0.0, 1.0, 1.0].into()];
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),
queue.family(),
CommandBufferUsage::OneTimeSubmit,
)
.unwrap();
builder
.begin_render_pass(
framebuffers[image_num].clone(),
SubpassContents::Inline,
clear_values,
)
.unwrap()
.set_viewport(0, [viewport.clone()])
.bind_pipeline_graphics(pipeline.clone())
.bind_descriptor_sets(
PipelineBindPoint::Graphics,
pipeline.layout().clone(),
0,
set.clone(),
)
.bind_vertex_buffers(0, vertex_buffer.clone())
.draw(vertex_buffer.len() as u32, 1, 0, 0)
.unwrap()
.end_render_pass()
.unwrap();
let command_buffer = builder.build().unwrap();
let future = previous_frame_end
.take()
.unwrap()
.join(acquire_future)
.then_execute(queue.clone(), command_buffer)
.unwrap()
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_signal_fence_and_flush();
match future {
Ok(future) => {
previous_frame_end = Some(future.boxed());
}
Err(FlushError::OutOfDate) => {
recreate_swapchain = true;
previous_frame_end = Some(sync::now(device.clone()).boxed());
}
Err(e) => {
println!("Failed to flush future: {:?}", e);
previous_frame_end = Some(sync::now(device.clone()).boxed());
}
}
}
_ => (),
});
}
/// This method is called once during initialization, then again whenever the window is resized
fn window_size_dependent_setup(
images: &[Arc<SwapchainImage<Window>>],
render_pass: Arc<RenderPass>,
viewport: &mut Viewport,
) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
let dimensions = images[0].dimensions();
viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32];
images
.iter()
.map(|image| {
let view = ImageView::new(image.clone()).unwrap();
Arc::new(
Framebuffer::start(render_pass.clone())
.add(view)
.unwrap()
.build()
.unwrap(),
) as Arc<dyn FramebufferAbstract + Send + Sync>
})
.collect::<Vec<_>>()
}
mod vs {
vulkano_shaders::shader! {
ty: "vertex",
src: "
#version 450
layout(location = 0) in vec2 position;
layout(location = 0) out vec2 tex_coords;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
tex_coords = position + vec2(0.5);
}"
}
}
mod fs {
vulkano_shaders::shader! {
ty: "fragment",
src: "
#version 450
layout(location = 0) in vec2 tex_coords;
layout(location = 0) out vec4 f_color;
layout(set = 0, binding = 0) uniform sampler2D tex;
void main() {
f_color = texture(tex, tex_coords);
}"
}
}

View File

@ -210,8 +210,9 @@ fn main() {
CpuBufferPool::new(device.clone(), BufferUsage::all());
let vertex_pool: CpuBufferPool<Vertex> = CpuBufferPool::new(device.clone(), BufferUsage::all());
let compute_pipeline =
Arc::new(ComputePipeline::new(device.clone(), &cs.main_entry_point(), &(), None).unwrap());
let compute_pipeline = Arc::new(
ComputePipeline::new(device.clone(), &cs.main_entry_point(), &(), None, |_| {}).unwrap(),
);
let render_pass = Arc::new(
single_pass_renderpass!(
@ -306,20 +307,24 @@ fn main() {
// Allocate a GPU buffer to hold the arguments for this frames draw call. The compute
// shader will only update vertex_count, so set the other parameters correctly here.
let indirect_args = Arc::new(indirect_args_pool
.chunk(iter::once(DrawIndirectCommand {
vertex_count: 0,
instance_count: 1,
first_vertex: 0,
first_instance: 0,
}))
.unwrap());
let indirect_args = Arc::new(
indirect_args_pool
.chunk(iter::once(DrawIndirectCommand {
vertex_count: 0,
instance_count: 1,
first_vertex: 0,
first_instance: 0,
}))
.unwrap(),
);
// Allocate a GPU buffer to hold this frames vertices. This needs to be large enough to hold
// the worst case number of vertices generated by the compute shader
let vertices = Arc::new(vertex_pool
.chunk((0..(6 * 16)).map(|_| Vertex { position: [0.0; 2] }))
.unwrap());
let vertices = Arc::new(
vertex_pool
.chunk((0..(6 * 16)).map(|_| Vertex { position: [0.0; 2] }))
.unwrap(),
);
// Pass the two buffers to the compute shader
let layout = compute_pipeline
@ -335,11 +340,7 @@ fn main() {
.add_buffer(indirect_args.clone())
.unwrap();
let cs_desciptor_set = Arc::new(
cs_desciptor_set_builder
.build()
.unwrap()
);
let cs_desciptor_set = Arc::new(cs_desciptor_set_builder.build().unwrap());
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),

View File

@ -119,6 +119,7 @@ fn main() {
&shader.main_entry_point(),
&(),
Some(pipeline_cache.clone()),
|_| {},
)
.unwrap()
});

View File

@ -92,7 +92,14 @@ fn main() {
let shader = cs::Shader::load(device.clone()).unwrap();
let pipeline = Arc::new(
ComputePipeline::new(device.clone(), &shader.main_entry_point(), &(), None).unwrap(),
ComputePipeline::new(
device.clone(),
&shader.main_entry_point(),
&(),
None,
|_| {},
)
.unwrap(),
);
let data_buffer = {
@ -104,15 +111,9 @@ fn main() {
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
set_builder
.add_buffer(data_buffer.clone())
.unwrap();
set_builder.add_buffer(data_buffer.clone()).unwrap();
let set = Arc::new(
set_builder
.build()
.unwrap()
);
let set = Arc::new(set_builder.build().unwrap());
// The `vulkano_shaders::shaders!` macro generates a struct with the correct representation of the push constants struct specified in the shader.
// Here we create an instance of the generated struct.

View File

@ -92,7 +92,14 @@ fn main() {
}
}
let shader = cs::Shader::load(device.clone()).unwrap();
ComputePipeline::new(device.clone(), &shader.main_entry_point(), &(), None).unwrap()
ComputePipeline::new(
device.clone(),
&shader.main_entry_point(),
&(),
None,
|_| {},
)
.unwrap()
});
let data_buffer = {
@ -104,15 +111,9 @@ fn main() {
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
set_builder
.add_buffer(data_buffer.clone())
.unwrap();
set_builder.add_buffer(data_buffer.clone()).unwrap();
let set = Arc::new(
set_builder
.build()
.unwrap()
);
let set = Arc::new(set_builder.build().unwrap());
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),

View File

@ -101,6 +101,7 @@ fn main() {
&shader.main_entry_point(),
&spec_consts,
None,
|_| {},
)
.unwrap(),
);
@ -114,15 +115,9 @@ fn main() {
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
set_builder
.add_buffer(data_buffer.clone())
.unwrap();
set_builder.add_buffer(data_buffer.clone()).unwrap();
let set = Arc::new(
set_builder
.build()
.unwrap()
);
let set = Arc::new(set_builder.build().unwrap());
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),

View File

@ -466,20 +466,6 @@ fn descriptor_infos(
Some((desc, mutable, 1, false))
}
_ => {
let (ty, mutable) = if force_combined_image_sampled {
// VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
// Never writable.
assert!(sampled, "A combined image sampler must not reference a storage image");
(quote! { DescriptorDescTy::CombinedImageSampler }, false) // Sampled images are never mutable.
} else {
if sampled {
// VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE
(quote! { DescriptorDescTy::SampledImage }, false) // Sampled images are never mutable.
} else {
// VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
(quote! { DescriptorDescTy::StorageImage }, true)
}
};
let view_type = match (dim, arrayed) {
(Dim::Dim1D, false) => quote! { ImageViewType::Dim1d },
(Dim::Dim1D, true) => quote! { ImageViewType::Dim1dArray },
@ -493,12 +479,45 @@ fn descriptor_infos(
_ => unreachable!(),
};
let desc = quote! {
#ty(DescriptorDescImage {
let image_desc = quote! {
DescriptorDescImage {
format: #vulkan_format,
multisampled: #ms,
view_type: #view_type,
})
}
};
let (desc, mutable) = if force_combined_image_sampled {
// VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
// Never writable.
assert!(sampled, "A combined image sampler must not reference a storage image");
(
quote! {
DescriptorDescTy::CombinedImageSampler {
image_desc: #image_desc,
immutable_samplers: Vec::new(),
}
},
false, // Sampled images are never mutable.
)
} else {
let (ty, mutable) = if sampled {
// VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE
(quote! { DescriptorDescTy::SampledImage }, false) // Sampled images are never mutable.
} else {
// VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
(quote! { DescriptorDescTy::StorageImage }, true)
};
(
quote! {
#ty {
image_desc: #image_desc,
}
},
mutable,
)
};
Some((desc, mutable, 1, false))
@ -514,7 +533,7 @@ fn descriptor_infos(
}
&Instruction::TypeSampler { result_id } if result_id == pointed_ty => {
let desc = quote! { DescriptorDescTy::Sampler };
let desc = quote! { DescriptorDescTy::Sampler { immutable_samplers: Vec::new() } };
Some((desc, false, 1, false))
}
&Instruction::TypeArray {

View File

@ -2859,9 +2859,9 @@ impl SyncCommandBufferBuilder {
.descriptor_layouts()
.expect("descriptor_layouts must return Some when used in an image view");
let layout = match desc.ty {
DescriptorDescTy::CombinedImageSampler(_) => layouts.combined_image_sampler,
DescriptorDescTy::SampledImage(_) => layouts.sampled_image,
DescriptorDescTy::StorageImage(_) => layouts.storage_image,
DescriptorDescTy::CombinedImageSampler { .. } => layouts.combined_image_sampler,
DescriptorDescTy::SampledImage { .. } => layouts.sampled_image,
DescriptorDescTy::StorageImage { .. } => layouts.storage_image,
DescriptorDescTy::InputAttachment { .. } => {
// FIXME: This is tricky. Since we read from the input attachment
// and this input attachment is being written in an earlier pass,

View File

@ -712,7 +712,9 @@ mod tests {
DescriptorSetLayout::new(
device.clone(),
[Some(DescriptorDesc {
ty: DescriptorDescTy::Sampler,
ty: DescriptorDescTy::Sampler {
immutable_samplers: vec![],
},
descriptor_count: 1,
stages: ShaderStages::all(),
mutable: false,

View File

@ -33,15 +33,19 @@ struct BuilderDescriptor {
array_element: u32,
}
/// A builder for constructing a new descriptor set.
pub struct DescriptorSetBuilder {
layout: Arc<DescriptorSetLayout>,
in_array: bool,
descriptors: Vec<BuilderDescriptor>,
cur_binding: usize,
cur_binding: u32,
resources: DescriptorSetResources,
desc_writes: Vec<DescriptorWrite>,
}
/// The output of the descriptor set builder.
///
/// This is not a descriptor set yet, but can be used to write the descriptors to one.
pub struct DescriptorSetBuilderOutput {
pub layout: Arc<DescriptorSetLayout>,
pub writes: Vec<DescriptorWrite>,
@ -49,6 +53,11 @@ pub struct DescriptorSetBuilderOutput {
}
impl DescriptorSetBuilder {
/// Starts the process of building a descriptor set. Returns a builder.
///
/// # Panic
///
/// - Panics if the set id is out of range.
pub fn start(layout: Arc<DescriptorSetLayout>) -> Self {
let mut descriptors = Vec::with_capacity(layout.num_bindings() as usize);
let mut desc_writes_capacity = 0;
@ -60,11 +69,11 @@ impl DescriptorSetBuilder {
if let Some(desc) = layout.descriptor(binding_i) {
let descriptor_count = desc.descriptor_count as usize;
let (num_bufs, num_imgs, num_samplers) = match desc.ty {
DescriptorDescTy::Sampler => (0, 0, 1),
DescriptorDescTy::CombinedImageSampler(_) => (0, 1, 1),
DescriptorDescTy::SampledImage(_) => (0, 1, 0),
DescriptorDescTy::Sampler { .. } => (0, 0, 1),
DescriptorDescTy::CombinedImageSampler { .. } => (0, 1, 1),
DescriptorDescTy::SampledImage { .. } => (0, 1, 0),
DescriptorDescTy::InputAttachment { .. } => (0, 1, 0),
DescriptorDescTy::StorageImage(_) => (0, 1, 0),
DescriptorDescTy::StorageImage { .. } => (0, 1, 0),
DescriptorDescTy::UniformTexelBuffer { .. } => (1, 0, 0),
DescriptorDescTy::StorageTexelBuffer { .. } => (1, 0, 0),
DescriptorDescTy::UniformBuffer => (1, 0, 0),
@ -100,10 +109,11 @@ impl DescriptorSetBuilder {
}
}
/// Finalizes the building process and returns the generated output.
pub fn output(self) -> Result<DescriptorSetBuilderOutput, DescriptorSetError> {
if self.cur_binding != self.descriptors.len() {
if self.cur_binding != self.descriptors.len() as u32 {
Err(DescriptorSetError::DescriptorsMissing {
expected: self.descriptors.len(),
expected: self.descriptors.len() as u32,
obtained: self.cur_binding,
})
} else {
@ -115,12 +125,17 @@ impl DescriptorSetBuilder {
}
}
/// Call this function if the next element of the set is an array in order to set the value of
/// each element.
///
/// This function can be called even if the descriptor isn't an array, and it is valid to enter
/// the "array", add one element, then leave.
pub fn enter_array(&mut self) -> Result<(), DescriptorSetError> {
if self.in_array {
Err(DescriptorSetError::AlreadyInArray)
} else if self.cur_binding >= self.descriptors.len() {
} else if self.cur_binding >= self.descriptors.len() as u32 {
Err(DescriptorSetError::TooManyDescriptors)
} else if self.descriptors[self.cur_binding].desc.is_none() {
} else if self.descriptors[self.cur_binding as usize].desc.is_none() {
Err(DescriptorSetError::DescriptorIsEmpty)
} else {
self.in_array = true;
@ -128,11 +143,12 @@ impl DescriptorSetBuilder {
}
}
/// Leaves the array. Call this once you added all the elements of the array.
pub fn leave_array(&mut self) -> Result<(), DescriptorSetError> {
if !self.in_array {
Err(DescriptorSetError::NotInArray)
} else {
let descriptor = &self.descriptors[self.cur_binding];
let descriptor = &self.descriptors[self.cur_binding as usize];
let inner_desc = match descriptor.desc.as_ref() {
Some(some) => some,
None => unreachable!(),
@ -158,11 +174,12 @@ impl DescriptorSetBuilder {
}
}
/// Skips the current descriptor if it is empty.
pub fn add_empty(&mut self) -> Result<(), DescriptorSetError> {
// Should be unreahable as enter_array prevents entering an array for empty descriptors.
assert!(!self.in_array);
if self.descriptors[self.cur_binding].desc.is_some() {
if self.descriptors[self.cur_binding as usize].desc.is_some() {
return Err(DescriptorSetError::WrongDescriptorType);
}
@ -170,6 +187,7 @@ impl DescriptorSetBuilder {
Ok(())
}
/// Binds a buffer as the next descriptor or array element.
pub fn add_buffer(
&mut self,
buffer: Arc<dyn BufferAccess + 'static>,
@ -187,7 +205,7 @@ impl DescriptorSetBuilder {
false
};
let descriptor = &mut self.descriptors[self.cur_binding];
let descriptor = &mut self.descriptors[self.cur_binding as usize];
let inner_desc = match descriptor.desc.as_ref() {
Some(some) => some,
None => return Err(DescriptorSetError::WrongDescriptorType),
@ -215,7 +233,7 @@ impl DescriptorSetBuilder {
unsafe {
DescriptorWrite::storage_buffer(
self.cur_binding as u32,
self.cur_binding,
descriptor.array_element,
&buffer,
)
@ -232,7 +250,7 @@ impl DescriptorSetBuilder {
unsafe {
DescriptorWrite::uniform_buffer(
self.cur_binding as u32,
self.cur_binding,
descriptor.array_element,
&buffer,
)
@ -249,7 +267,7 @@ impl DescriptorSetBuilder {
unsafe {
DescriptorWrite::dynamic_uniform_buffer(
self.cur_binding as u32,
self.cur_binding,
descriptor.array_element,
&buffer,
)
@ -258,7 +276,7 @@ impl DescriptorSetBuilder {
_ => return Err(DescriptorSetError::WrongDescriptorType),
});
self.resources.add_buffer(self.cur_binding as u32, buffer);
self.resources.add_buffer(self.cur_binding, buffer);
descriptor.array_element += 1;
if leave_array {
@ -268,6 +286,7 @@ impl DescriptorSetBuilder {
}
}
/// Binds a buffer view as the next descriptor or array element.
pub fn add_buffer_view<B>(&mut self, view: Arc<BufferView<B>>) -> Result<(), DescriptorSetError>
where
B: BufferAccess + 'static,
@ -283,7 +302,7 @@ impl DescriptorSetBuilder {
false
};
let descriptor = &mut self.descriptors[self.cur_binding];
let descriptor = &mut self.descriptors[self.cur_binding as usize];
let inner_desc = match descriptor.desc.as_ref() {
Some(some) => some,
None => return Err(DescriptorSetError::WrongDescriptorType),
@ -300,7 +319,7 @@ impl DescriptorSetBuilder {
}
DescriptorWrite::storage_texel_buffer(
self.cur_binding as u32,
self.cur_binding,
descriptor.array_element,
&view,
)
@ -313,7 +332,7 @@ impl DescriptorSetBuilder {
}
DescriptorWrite::uniform_texel_buffer(
self.cur_binding as u32,
self.cur_binding,
descriptor.array_element,
&view,
)
@ -321,8 +340,7 @@ impl DescriptorSetBuilder {
_ => return Err(DescriptorSetError::WrongDescriptorType),
});
self.resources
.add_buffer_view(self.cur_binding as u32, view);
self.resources.add_buffer_view(self.cur_binding, view);
if leave_array {
self.leave_array()
@ -331,6 +349,7 @@ impl DescriptorSetBuilder {
}
}
/// Binds an image view as the next descriptor or array element.
pub fn add_image(
&mut self,
image_view: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
@ -348,43 +367,66 @@ impl DescriptorSetBuilder {
false
};
let descriptor = &mut self.descriptors[self.cur_binding];
let descriptor = &mut self.descriptors[self.cur_binding as usize];
let inner_desc = match descriptor.desc.as_ref() {
Some(some) => some,
None => return Err(DescriptorSetError::WrongDescriptorType),
};
self.desc_writes.push(match inner_desc.ty {
DescriptorDescTy::SampledImage(ref desc) => {
self.desc_writes.push(match &inner_desc.ty {
DescriptorDescTy::CombinedImageSampler {
image_desc,
immutable_samplers,
} if !immutable_samplers.is_empty() => {
if !image_view.image().inner().image.usage().sampled {
return Err(DescriptorSetError::MissingImageUsage(
MissingImageUsage::Sampled,
));
}
image_match_desc(&image_view, &desc)?;
if !image_view.can_be_sampled(&immutable_samplers[self.cur_binding as usize]) {
return Err(DescriptorSetError::IncompatibleImageViewSampler);
}
image_match_desc(&image_view, image_desc)?;
DescriptorWrite::combined_image_sampler(
self.cur_binding,
descriptor.array_element,
None,
&image_view,
)
}
DescriptorDescTy::SampledImage { ref image_desc, .. } => {
if !image_view.image().inner().image.usage().sampled {
return Err(DescriptorSetError::MissingImageUsage(
MissingImageUsage::Sampled,
));
}
image_match_desc(&image_view, image_desc)?;
DescriptorWrite::sampled_image(
self.cur_binding as u32,
self.cur_binding,
descriptor.array_element,
&image_view,
)
}
DescriptorDescTy::StorageImage(ref desc) => {
DescriptorDescTy::StorageImage { ref image_desc, .. } => {
if !image_view.image().inner().image.usage().storage {
return Err(DescriptorSetError::MissingImageUsage(
MissingImageUsage::Storage,
));
}
image_match_desc(&image_view, &desc)?;
image_match_desc(&image_view, image_desc)?;
if !image_view.component_mapping().is_identity() {
return Err(DescriptorSetError::NotIdentitySwizzled);
}
DescriptorWrite::storage_image(
self.cur_binding as u32,
self.cur_binding,
descriptor.array_element,
&image_view,
)
@ -400,7 +442,7 @@ impl DescriptorSetBuilder {
return Err(DescriptorSetError::NotIdentitySwizzled);
}
if multisampled && image_view.image().samples() == SampleCount::Sample1 {
if *multisampled && image_view.image().samples() == SampleCount::Sample1 {
return Err(DescriptorSetError::ExpectedMultisampled);
} else if !multisampled && image_view.image().samples() != SampleCount::Sample1 {
return Err(DescriptorSetError::UnexpectedMultisampled);
@ -414,7 +456,7 @@ impl DescriptorSetBuilder {
}
DescriptorWrite::input_attachment(
self.cur_binding as u32,
self.cur_binding,
descriptor.array_element,
&image_view,
)
@ -423,8 +465,7 @@ impl DescriptorSetBuilder {
});
descriptor.array_element += 1;
self.resources
.add_image(self.cur_binding as u32, image_view);
self.resources.add_image(self.cur_binding, image_view);
if leave_array {
self.leave_array()
@ -433,6 +474,10 @@ impl DescriptorSetBuilder {
}
}
/// Binds an image view with a sampler as the next descriptor or array element.
///
/// If the descriptor set layout contains immutable samplers for this descriptor, use
/// `add_image` instead.
pub fn add_sampled_image(
&mut self,
image_view: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
@ -465,20 +510,27 @@ impl DescriptorSetBuilder {
false
};
let descriptor = &mut self.descriptors[self.cur_binding];
let descriptor = &mut self.descriptors[self.cur_binding as usize];
let inner_desc = match descriptor.desc.as_ref() {
Some(some) => some,
None => return Err(DescriptorSetError::WrongDescriptorType),
};
self.desc_writes.push(match inner_desc.ty {
DescriptorDescTy::CombinedImageSampler(ref desc) => {
image_match_desc(&image_view, &desc)?;
self.desc_writes.push(match &inner_desc.ty {
DescriptorDescTy::CombinedImageSampler {
image_desc,
immutable_samplers,
} => {
if !immutable_samplers.is_empty() {
return Err(DescriptorSetError::SamplerIsImmutable);
}
image_match_desc(&image_view, image_desc)?;
DescriptorWrite::combined_image_sampler(
self.cur_binding as u32,
self.cur_binding,
descriptor.array_element,
&sampler,
Some(&sampler),
&image_view,
)
}
@ -486,9 +538,8 @@ impl DescriptorSetBuilder {
});
descriptor.array_element += 1;
self.resources
.add_image(self.cur_binding as u32, image_view);
self.resources.add_sampler(self.cur_binding as u32, sampler);
self.resources.add_image(self.cur_binding, image_view);
self.resources.add_sampler(self.cur_binding, sampler);
if leave_array {
self.leave_array()
@ -497,6 +548,7 @@ impl DescriptorSetBuilder {
}
}
/// Binds a sampler as the next descriptor or array element.
pub fn add_sampler(&mut self, sampler: Arc<Sampler>) -> Result<(), DescriptorSetError> {
if sampler.device().internal_object() != self.layout.device().internal_object() {
return Err(DescriptorSetError::ResourceWrongDevice);
@ -509,23 +561,25 @@ impl DescriptorSetBuilder {
false
};
let descriptor = &mut self.descriptors[self.cur_binding];
let descriptor = &mut self.descriptors[self.cur_binding as usize];
let inner_desc = match descriptor.desc.as_ref() {
Some(some) => some,
None => return Err(DescriptorSetError::WrongDescriptorType),
};
self.desc_writes.push(match inner_desc.ty {
DescriptorDescTy::Sampler => DescriptorWrite::sampler(
self.cur_binding as u32,
descriptor.array_element,
&sampler,
),
self.desc_writes.push(match &inner_desc.ty {
DescriptorDescTy::Sampler { immutable_samplers } => {
if !immutable_samplers.is_empty() {
return Err(DescriptorSetError::SamplerIsImmutable);
}
DescriptorWrite::sampler(self.cur_binding, descriptor.array_element, &sampler)
}
_ => return Err(DescriptorSetError::WrongDescriptorType),
});
descriptor.array_element += 1;
self.resources.add_sampler(self.cur_binding as u32, sampler);
self.resources.add_sampler(self.cur_binding, sampler);
if leave_array {
self.leave_array()

View File

@ -44,12 +44,14 @@
use crate::format::Format;
use crate::image::view::ImageViewType;
use crate::pipeline::shader::ShaderStages;
use crate::sampler::Sampler;
use crate::sync::AccessFlags;
use crate::sync::PipelineStages;
use smallvec::SmallVec;
use std::cmp;
use std::error;
use std::fmt;
use std::sync::Arc;
#[derive(Clone, Debug, Default)]
pub struct DescriptorSetDesc {
@ -87,8 +89,8 @@ impl DescriptorSetDesc {
/// Returns the descriptor with the given binding number, or `None` if the binding is empty.
#[inline]
pub fn descriptor(&self, num: usize) -> Option<&DescriptorDesc> {
self.descriptors.get(num).and_then(|b| b.as_ref())
pub fn descriptor(&self, num: u32) -> Option<&DescriptorDesc> {
self.descriptors.get(num as usize).and_then(|b| b.as_ref())
}
/// Builds the union of this layout description and another.
@ -136,72 +138,82 @@ impl DescriptorSetDesc {
.collect()
}
/// Transforms a `DescriptorSetDesc`.
/// Changes a buffer descriptor's type to dynamic.
pub fn set_buffer_dynamic(&mut self, binding_num: u32) {
assert!(
self.descriptor(binding_num).map_or(false, |desc| matches!(
desc.ty,
DescriptorDescTy::StorageBuffer | DescriptorDescTy::UniformBuffer
)),
"tried to make the non-buffer descriptor at binding {} a dynamic buffer",
binding_num
);
let binding = self
.descriptors
.get_mut(binding_num as usize)
.and_then(|b| b.as_mut());
if let Some(desc) = binding {
match &desc.ty {
DescriptorDescTy::StorageBuffer => {
desc.ty = DescriptorDescTy::StorageBufferDynamic;
}
DescriptorDescTy::UniformBuffer => {
desc.ty = DescriptorDescTy::UniformBufferDynamic;
}
_ => (),
};
}
}
/// Sets the immutable samplers for a sampler or combined image sampler descriptor.
///
/// Used to adjust automatically inferred `DescriptorSetDesc`s with information that cannot be inferred.
pub fn tweak<I>(&mut self, dynamic_buffers: I)
where
I: IntoIterator<Item = usize>,
{
for binding_num in dynamic_buffers {
debug_assert!(
self.descriptor(binding_num).map_or(false, |desc| matches!(
desc.ty,
DescriptorDescTy::StorageBuffer | DescriptorDescTy::UniformBuffer
)),
"tried to make the non-buffer descriptor at binding {} a dynamic buffer",
binding_num
);
/// # Panics
///
/// - Panics if the binding number does not refer to a sampler or combined image sampler
/// descriptor.
pub fn set_immutable_samplers(
&mut self,
binding_num: u32,
samplers: impl IntoIterator<Item = Arc<Sampler>>,
) {
let immutable_samplers = self
.descriptors
.get_mut(binding_num as usize)
.and_then(|b| b.as_mut())
.and_then(|desc| match &mut desc.ty {
DescriptorDescTy::Sampler {
immutable_samplers, ..
}
| DescriptorDescTy::CombinedImageSampler {
immutable_samplers, ..
} => Some(immutable_samplers),
_ => None,
})
.expect("binding_num does not refer to a sampler or combined image sampler descriptor");
let binding = self
.descriptors
.get_mut(binding_num)
.and_then(|b| b.as_mut());
if let Some(desc) = binding {
match &desc.ty {
DescriptorDescTy::StorageBuffer => {
desc.ty = DescriptorDescTy::StorageBufferDynamic;
}
DescriptorDescTy::UniformBuffer => {
desc.ty = DescriptorDescTy::UniformBufferDynamic;
}
_ => (),
};
}
}
}
pub fn tweak_multiple<I>(sets: &mut [DescriptorSetDesc], dynamic_buffers: I)
where
I: IntoIterator<Item = (usize, usize)>,
{
for (set_num, binding_num) in dynamic_buffers {
debug_assert!(
set_num < sets.len(),
"tried to make a dynamic buffer in the nonexistent set {}",
set_num,
);
sets.get_mut(set_num).map(|set| set.tweak([binding_num]));
}
immutable_samplers.clear();
immutable_samplers.extend(samplers.into_iter());
}
/// Sets the descriptor count for a descriptor that has a variable count.
pub fn set_variable_descriptor_count(&mut self, binding_num: u32, descriptor_count: u32) {
// TODO: Errors instead of panic
match self.descriptors.get_mut(binding_num as usize) {
Some(desc_op) => match desc_op.as_mut() {
Some(desc) => {
if desc.variable_count {
desc.descriptor_count = descriptor_count;
} else {
panic!("descriptor isn't variable count")
}
match self
.descriptors
.get_mut(binding_num as usize)
.and_then(|b| b.as_mut())
{
Some(desc) => {
if desc.variable_count {
desc.descriptor_count = descriptor_count;
} else {
panic!("descriptor isn't variable count")
}
None => panic!("descriptor is empty"),
},
None => panic!("descriptor doesn't exist"),
}
None => panic!("descriptor is empty"),
}
}
@ -212,7 +224,7 @@ impl DescriptorSetDesc {
/// meaning that all descriptors are compatible.
#[inline]
pub fn is_compatible_with(&self, other: &DescriptorSetDesc) -> bool {
let num_bindings = cmp::max(self.descriptors.len(), other.descriptors.len());
let num_bindings = cmp::max(self.descriptors.len(), other.descriptors.len()) as u32;
(0..num_bindings).all(|binding_num| {
match (self.descriptor(binding_num), other.descriptor(binding_num)) {
(None, None) => true,
@ -235,7 +247,7 @@ impl DescriptorSetDesc {
});
}
for binding_num in 0..other.descriptors.len() {
for binding_num in 0..other.descriptors.len() as u32 {
let self_desc = self.descriptor(binding_num);
let other_desc = self.descriptor(binding_num);
@ -277,7 +289,7 @@ impl DescriptorSetDesc {
});
}
for binding_num in 0..other.descriptors.len() {
for binding_num in 0..other.descriptors.len() as u32 {
let self_desc = self.descriptor(binding_num);
let other_desc = self.descriptor(binding_num);
@ -353,6 +365,7 @@ impl DescriptorDesc {
#[inline]
pub fn is_compatible_with(&self, other: &DescriptorDesc) -> bool {
self.ty.ty() == other.ty.ty()
&& self.ty.immutable_samplers() == other.ty.immutable_samplers()
&& self.stages == other.stages
&& self.descriptor_count == other.descriptor_count
&& self.variable_count == other.variable_count
@ -455,7 +468,7 @@ impl DescriptorDesc {
///use vulkano::descriptor_set::layout::DescriptorDescTy::*;
///use vulkano::pipeline::shader::ShaderStages;
///
///let desc_part1 = DescriptorDesc{ ty: Sampler, descriptor_count: 2, stages: ShaderStages{
///let desc_part1 = DescriptorDesc{ ty: Sampler { immutable_samplers: vec![] }, descriptor_count: 2, stages: ShaderStages{
/// vertex: true,
/// tessellation_control: true,
/// tessellation_evaluation: false,
@ -464,7 +477,7 @@ impl DescriptorDesc {
/// compute: true
///}, mutable: true, variable_count: false };
///
///let desc_part2 = DescriptorDesc{ ty: Sampler, descriptor_count: 1, stages: ShaderStages{
///let desc_part2 = DescriptorDesc{ ty: Sampler { immutable_samplers: vec![] }, descriptor_count: 1, stages: ShaderStages{
/// vertex: true,
/// tessellation_control: false,
/// tessellation_evaluation: true,
@ -473,7 +486,7 @@ impl DescriptorDesc {
/// compute: true
///}, mutable: false, variable_count: false };
///
///let desc_union = DescriptorDesc{ ty: Sampler, descriptor_count: 2, stages: ShaderStages{
///let desc_union = DescriptorDesc{ ty: Sampler { immutable_samplers: vec![] }, descriptor_count: 2, stages: ShaderStages{
/// vertex: true,
/// tessellation_control: true,
/// tessellation_evaluation: true,
@ -579,10 +592,28 @@ impl From<DescriptorType> for ash::vk::DescriptorType {
/// Describes the content and layout of each array element of a descriptor.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DescriptorDescTy {
Sampler, // TODO: the sampler has some restrictions as well
CombinedImageSampler(DescriptorDescImage), // TODO: the sampler has some restrictions as well
SampledImage(DescriptorDescImage),
StorageImage(DescriptorDescImage),
Sampler {
/// Samplers that are included as a fixed part of the descriptor set layout. Once bound, they
/// do not need to be provided when creating a descriptor set.
///
/// The list must be either empty, or contain exactly `descriptor_count` samplers.
immutable_samplers: Vec<Arc<Sampler>>,
},
CombinedImageSampler {
image_desc: DescriptorDescImage,
/// Samplers that are included as a fixed part of the descriptor set layout. Once bound, they
/// do not need to be provided when creating a descriptor set.
///
/// The list must be either empty, or contain exactly `descriptor_count` samplers.
immutable_samplers: Vec<Arc<Sampler>>,
},
SampledImage {
image_desc: DescriptorDescImage,
},
StorageImage {
image_desc: DescriptorDescImage,
},
UniformTexelBuffer {
/// The format of the content, or `None` if the format is unknown. Depending on the
/// context, it may be invalid to have a `None` value here. If the format is `Some`, only
@ -612,27 +643,63 @@ impl DescriptorDescTy {
#[inline]
pub fn ty(&self) -> DescriptorType {
match *self {
DescriptorDescTy::Sampler => DescriptorType::Sampler,
DescriptorDescTy::CombinedImageSampler(_) => DescriptorType::CombinedImageSampler,
DescriptorDescTy::SampledImage(_) => DescriptorType::SampledImage,
DescriptorDescTy::StorageImage(_) => DescriptorType::StorageImage,
DescriptorDescTy::UniformTexelBuffer { .. } => DescriptorType::UniformTexelBuffer,
DescriptorDescTy::StorageTexelBuffer { .. } => DescriptorType::StorageTexelBuffer,
DescriptorDescTy::UniformBuffer => DescriptorType::UniformBuffer,
DescriptorDescTy::StorageBuffer => DescriptorType::StorageBuffer,
DescriptorDescTy::UniformBufferDynamic => DescriptorType::UniformBufferDynamic,
DescriptorDescTy::StorageBufferDynamic => DescriptorType::StorageBufferDynamic,
DescriptorDescTy::InputAttachment { .. } => DescriptorType::InputAttachment,
Self::Sampler { .. } => DescriptorType::Sampler,
Self::CombinedImageSampler { .. } => DescriptorType::CombinedImageSampler,
Self::SampledImage { .. } => DescriptorType::SampledImage,
Self::StorageImage { .. } => DescriptorType::StorageImage,
Self::UniformTexelBuffer { .. } => DescriptorType::UniformTexelBuffer,
Self::StorageTexelBuffer { .. } => DescriptorType::StorageTexelBuffer,
Self::UniformBuffer => DescriptorType::UniformBuffer,
Self::StorageBuffer => DescriptorType::StorageBuffer,
Self::UniformBufferDynamic => DescriptorType::UniformBufferDynamic,
Self::StorageBufferDynamic => DescriptorType::StorageBufferDynamic,
Self::InputAttachment { .. } => DescriptorType::InputAttachment,
}
}
#[inline]
fn format(&self) -> Option<Format> {
match self {
Self::UniformTexelBuffer { format } | Self::StorageTexelBuffer { format } => *format,
_ => None,
}
}
#[inline]
fn image_desc(&self) -> Option<&DescriptorDescImage> {
match self {
Self::CombinedImageSampler { image_desc, .. }
| Self::SampledImage { image_desc, .. }
| Self::StorageImage { image_desc, .. } => Some(image_desc),
_ => None,
}
}
#[inline]
pub(super) fn immutable_samplers(&self) -> &[Arc<Sampler>] {
match self {
Self::Sampler {
immutable_samplers, ..
} => immutable_samplers,
Self::CombinedImageSampler {
immutable_samplers, ..
} => immutable_samplers,
_ => &[],
}
}
#[inline]
fn multisampled(&self) -> bool {
match self {
DescriptorDescTy::InputAttachment { multisampled } => *multisampled,
_ => false,
}
}
/// Checks whether we are a superset of another descriptor type.
// TODO: add example
#[inline]
pub fn ensure_superset_of(
&self,
other: &DescriptorDescTy,
) -> Result<(), DescriptorCompatibilityError> {
pub fn ensure_superset_of(&self, other: &Self) -> Result<(), DescriptorCompatibilityError> {
if self.ty() != other.ty() {
return Err(DescriptorCompatibilityError::Type {
first: self.ty(),
@ -640,51 +707,28 @@ impl DescriptorDescTy {
});
}
match (self, other) {
(
DescriptorDescTy::CombinedImageSampler(ref me)
| DescriptorDescTy::SampledImage(ref me)
| DescriptorDescTy::StorageImage(ref me),
DescriptorDescTy::CombinedImageSampler(ref other)
| DescriptorDescTy::SampledImage(ref other)
| DescriptorDescTy::StorageImage(ref other),
) => me.ensure_superset_of(other)?,
if self.immutable_samplers() != other.immutable_samplers() {
return Err(DescriptorCompatibilityError::ImmutableSamplers);
}
(
DescriptorDescTy::UniformTexelBuffer { format: me_format }
| DescriptorDescTy::StorageTexelBuffer { format: me_format },
DescriptorDescTy::UniformTexelBuffer {
format: other_format,
}
| DescriptorDescTy::StorageTexelBuffer {
format: other_format,
},
) => {
if other_format.is_some() && me_format != other_format {
return Err(DescriptorCompatibilityError::Format {
first: *me_format,
second: other_format.unwrap(),
});
}
if let (Some(me), Some(other)) = (self.image_desc(), other.image_desc()) {
me.ensure_superset_of(other)?;
}
if let (me, other @ Some(_)) = (self.format(), other.format()) {
if me != other {
return Err(DescriptorCompatibilityError::Format {
first: me,
second: other.unwrap(),
});
}
}
(
DescriptorDescTy::InputAttachment {
multisampled: me_multisampled,
},
DescriptorDescTy::InputAttachment {
multisampled: other_multisampled,
},
) => {
if me_multisampled != other_multisampled {
return Err(DescriptorCompatibilityError::Multisampling {
first: *me_multisampled,
second: *other_multisampled,
});
}
}
_ => (),
if self.multisampled() != other.multisampled() {
return Err(DescriptorCompatibilityError::Multisampling {
first: self.multisampled(),
second: other.multisampled(),
});
}
Ok(())
@ -782,46 +826,34 @@ impl fmt::Display for DescriptorSetCompatibilityError {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DescriptorCompatibilityError {
/// The number of descriptors is not compatible.
DescriptorCount {
first: u32,
second: u32,
},
DescriptorCount { first: u32, second: u32 },
/// The variable counts of the descriptors is not compatible.
VariableCount {
first: bool,
second: bool,
},
VariableCount { first: bool, second: bool },
/// The presence or absence of a descriptor in a binding is not compatible.
Empty {
first: bool,
second: bool,
},
Empty { first: bool, second: bool },
// The formats of an image descriptor are not compatible.
/// The formats of an image descriptor are not compatible.
Format {
first: Option<Format>,
second: Format,
},
// The image view types of an image descriptor are not compatible.
/// The image view types of an image descriptor are not compatible.
ImageViewType {
first: ImageViewType,
second: ImageViewType,
},
// The multisampling of an image descriptor is not compatible.
Multisampling {
first: bool,
second: bool,
},
/// The immutable samplers of the descriptors are not compatible.
ImmutableSamplers,
/// The multisampling of an image descriptor is not compatible.
Multisampling { first: bool, second: bool },
/// The mutability of the descriptors is not compatible.
Mutability {
first: bool,
second: bool,
},
Mutability { first: bool, second: bool },
/// The shader stages of the descriptors are not compatible.
ShaderStages {
@ -860,6 +892,9 @@ impl fmt::Display for DescriptorCompatibilityError {
DescriptorCompatibilityError::ImageViewType { .. } => {
"the image view types of an image descriptor are not compatible"
}
DescriptorCompatibilityError::ImmutableSamplers { .. } => {
"the immutable samplers of the descriptors are not compatible"
}
DescriptorCompatibilityError::Multisampling { .. } => {
"the multisampling of an image descriptor is not compatible"
}

View File

@ -18,7 +18,6 @@ use crate::device::DeviceOwned;
use crate::OomError;
use crate::Version;
use crate::VulkanObject;
use smallvec::SmallVec;
use std::mem::MaybeUninit;
use std::ptr;
use std::sync::Arc;
@ -51,9 +50,10 @@ impl DescriptorSetLayout {
{
let desc = desc.into();
let mut descriptors_count = DescriptorsCount::zero();
let mut variable_descriptor_count = false;
let bindings = desc.bindings();
let mut bindings_vk: SmallVec<[_; 32]> = SmallVec::new();
let mut bindings_vk = Vec::with_capacity(bindings.len());
let mut binding_flags_vk = Vec::with_capacity(bindings.len());
let mut immutable_samplers_vk: Vec<Box<[ash::vk::Sampler]>> = Vec::new(); // only to keep the arrays of handles alive
for (binding, desc) in bindings.iter().enumerate() {
let desc = match desc {
@ -66,6 +66,33 @@ impl DescriptorSetLayout {
let ty = desc.ty.ty();
descriptors_count.add_num(ty, desc.descriptor_count);
let mut binding_flags = ash::vk::DescriptorBindingFlags::empty();
let immutable_samplers = desc.ty.immutable_samplers();
let p_immutable_samplers = if !immutable_samplers.is_empty() {
if desc.descriptor_count != immutable_samplers.len() as u32 {
return Err(DescriptorSetLayoutError::ImmutableSamplersCountMismatch {
descriptor_count: desc.descriptor_count,
sampler_count: immutable_samplers.len() as u32,
});
}
// TODO: VUID-VkDescriptorSetLayoutBinding-pImmutableSamplers-04009
// The sampler objects indicated by pImmutableSamplers must not have a borderColor
// with one of the values VK_BORDER_COLOR_FLOAT_CUSTOM_EXT or
// VK_BORDER_COLOR_INT_CUSTOM_EXT
let sampler_handles = immutable_samplers
.iter()
.map(|s| s.internal_object())
.collect::<Vec<_>>()
.into_boxed_slice();
let p_immutable_samplers = sampler_handles.as_ptr();
immutable_samplers_vk.push(sampler_handles);
p_immutable_samplers
} else {
ptr::null()
};
if desc.variable_count {
if binding != bindings.len() - 1 {
@ -78,48 +105,16 @@ impl DescriptorSetLayout {
return Err(DescriptorSetLayoutError::VariableCountDescMustNotBeDynamic);
}
variable_descriptor_count = true;
}
bindings_vk.push(ash::vk::DescriptorSetLayoutBinding {
binding: binding as u32,
descriptor_type: ty.into(),
descriptor_count: desc.descriptor_count,
stage_flags: desc.stages.into(),
p_immutable_samplers: ptr::null(), // FIXME: not yet implemented
});
}
// Note that it seems legal to have no descriptor at all in the set.
let handle = unsafe {
if variable_descriptor_count {
let enabled_features = device.enabled_features();
let api_version = device.api_version();
let enabled_extensions = device.enabled_extensions();
if api_version.major < 1 {
return Err(DescriptorSetLayoutError::VariableCountIncompatibleDevice(
IncompatibleDevice::InsufficientApiVersion {
required: Version::major_minor(1, 1),
obtained: api_version,
},
));
}
if api_version.minor < 2 && !enabled_extensions.ext_descriptor_indexing {
return Err(DescriptorSetLayoutError::VariableCountIncompatibleDevice(
IncompatibleDevice::MissingExtension(MissingExtension::DescriptorIndexing),
));
}
if !enabled_features.runtime_descriptor_array {
if !device.enabled_features().runtime_descriptor_array {
return Err(DescriptorSetLayoutError::VariableCountIncompatibleDevice(
IncompatibleDevice::MissingFeature(MissingFeature::RuntimeDescriptorArray),
));
}
if !enabled_features.descriptor_binding_variable_descriptor_count {
if !device
.enabled_features()
.descriptor_binding_variable_descriptor_count
{
return Err(DescriptorSetLayoutError::VariableCountIncompatibleDevice(
IncompatibleDevice::MissingFeature(
MissingFeature::DescriptorBindingVariableDescriptorCount,
@ -127,7 +122,7 @@ impl DescriptorSetLayout {
));
}
if !enabled_features.descriptor_binding_partially_bound {
if !device.enabled_features().descriptor_binding_partially_bound {
return Err(DescriptorSetLayoutError::VariableCountIncompatibleDevice(
IncompatibleDevice::MissingFeature(
MissingFeature::DescriptorBindingPartiallyBound,
@ -135,58 +130,60 @@ impl DescriptorSetLayout {
));
}
let mut flags = vec![ash::vk::DescriptorBindingFlags::empty(); bindings_vk.len()];
*flags.last_mut().unwrap() =
ash::vk::DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT
| ash::vk::DescriptorBindingFlags::PARTIALLY_BOUND;
let binding_flags = ash::vk::DescriptorSetLayoutBindingFlagsCreateInfo {
binding_count: bindings_vk.len() as u32,
p_binding_flags: flags.as_ptr(),
..Default::default()
};
let infos = ash::vk::DescriptorSetLayoutCreateInfo {
flags: ash::vk::DescriptorSetLayoutCreateFlags::empty(),
binding_count: bindings_vk.len() as u32,
p_bindings: bindings_vk.as_ptr(),
p_next: &binding_flags as *const _ as *const _,
..Default::default()
};
let mut output = MaybeUninit::uninit();
let fns = device.fns();
check_errors(fns.v1_0.create_descriptor_set_layout(
device.internal_object(),
&infos,
ptr::null(),
output.as_mut_ptr(),
))
.map_err(|e| OomError::from(e))?;
output.assume_init()
} else {
let infos = ash::vk::DescriptorSetLayoutCreateInfo {
flags: ash::vk::DescriptorSetLayoutCreateFlags::empty(),
binding_count: bindings_vk.len() as u32,
p_bindings: bindings_vk.as_ptr(),
..Default::default()
};
let mut output = MaybeUninit::uninit();
let fns = device.fns();
check_errors(fns.v1_0.create_descriptor_set_layout(
device.internal_object(),
&infos,
ptr::null(),
output.as_mut_ptr(),
))
.map_err(|e| OomError::from(e))?;
output.assume_init()
// TODO: should these be settable separately by the user?
binding_flags |= ash::vk::DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT;
binding_flags |= ash::vk::DescriptorBindingFlags::PARTIALLY_BOUND;
}
bindings_vk.push(ash::vk::DescriptorSetLayoutBinding {
binding: binding as u32,
descriptor_type: ty.into(),
descriptor_count: desc.descriptor_count,
stage_flags: desc.stages.into(),
p_immutable_samplers,
});
binding_flags_vk.push(binding_flags);
}
// Note that it seems legal to have no descriptor at all in the set.
let handle = unsafe {
let binding_flags_infos = if device.api_version() >= Version::V1_2
|| device.enabled_extensions().ext_descriptor_indexing
{
Some(ash::vk::DescriptorSetLayoutBindingFlagsCreateInfo {
binding_count: binding_flags_vk.len() as u32,
p_binding_flags: binding_flags_vk.as_ptr(),
..Default::default()
})
} else {
None
};
let infos = ash::vk::DescriptorSetLayoutCreateInfo {
flags: ash::vk::DescriptorSetLayoutCreateFlags::empty(),
binding_count: bindings_vk.len() as u32,
p_bindings: bindings_vk.as_ptr(),
p_next: if let Some(next) = binding_flags_infos.as_ref() {
next as *const _ as *const _
} else {
ptr::null()
},
..Default::default()
};
let mut output = MaybeUninit::uninit();
let fns = device.fns();
check_errors(fns.v1_0.create_descriptor_set_layout(
device.internal_object(),
&infos,
ptr::null(),
output.as_mut_ptr(),
))
.map_err(|e| OomError::from(e))?;
output.assume_init()
};
Ok(DescriptorSetLayout {
@ -283,6 +280,12 @@ pub enum DescriptorSetLayoutError {
/// Out of Memory
OomError(OomError),
/// The number of immutable samplers does not match the descriptor count.
ImmutableSamplersCountMismatch {
descriptor_count: u32,
sampler_count: u32,
},
/// Variable count descriptor must be last binding
VariableCountDescMustBeLast,
@ -337,6 +340,8 @@ impl std::fmt::Display for DescriptorSetLayoutError {
"{}",
match *self {
Self::OomError(_) => "out of memory",
Self::ImmutableSamplersCountMismatch { .. } =>
"the number of immutable samplers does not match the descriptor count",
Self::VariableCountDescMustBeLast =>
"variable count descriptor must be last binding",
Self::VariableCountDescMustNotBeDynamic =>

View File

@ -298,8 +298,16 @@ pub enum DescriptorSetError {
/// Builder is already within an array.
AlreadyInArray,
/// Builder is not in an array.
NotInArray,
/// The builder has previously return an error and is an unknown state.
BuilderPoisoned,
/// The number of array layers of an image doesn't match what was expected.
ArrayLayersMismatch {
/// Number of expected array layers for the image.
expected: u32,
/// Number of array layers of the image that was added.
obtained: u32,
},
/// Array doesn't contain the correct amount of descriptors
ArrayLengthMismatch {
@ -317,29 +325,20 @@ pub enum DescriptorSetError {
obtained: u32,
},
/// Builder doesn't expect anymore descriptors
TooManyDescriptors,
/// Expected a multisampled image, but got a single-sampled image.
ExpectedMultisampled,
/// Operation can not be performed on an empty descriptor.
DescriptorIsEmpty,
/// Not all descriptors have been added.
DescriptorsMissing {
/// Expected bindings
expected: usize,
expected: u32,
/// Obtained bindings
obtained: usize,
obtained: u32,
},
/// The buffer is missing the correct usage.
MissingBufferUsage(MissingBufferUsage),
/// The image is missing the correct usage.
MissingImageUsage(MissingImageUsage),
/// Expected one type of resource but got another.
WrongDescriptorType,
/// Resource belongs to another device.
ResourceWrongDevice,
/// The format of an image view doesn't match what was expected.
ImageViewFormatMismatch {
/// Expected format.
@ -356,37 +355,41 @@ pub enum DescriptorSetError {
obtained: ImageViewType,
},
/// Expected a multisampled image, but got a single-sampled image.
ExpectedMultisampled,
/// The image view isn't compatible with the sampler.
IncompatibleImageViewSampler,
/// Expected a single-sampled image, but got a multisampled image.
UnexpectedMultisampled,
/// The buffer is missing the correct usage.
MissingBufferUsage(MissingBufferUsage),
/// The number of array layers of an image doesn't match what was expected.
ArrayLayersMismatch {
/// Number of expected array layers for the image.
expected: u32,
/// Number of array layers of the image that was added.
obtained: u32,
},
/// The image is missing the correct usage.
MissingImageUsage(MissingImageUsage),
/// The image view has a component swizzle that is different from identity.
NotIdentitySwizzled,
/// The image view isn't compatible with the sampler.
IncompatibleImageViewSampler,
/// The builder has previously return an error and is an unknown state.
BuilderPoisoned,
/// Builder is not in an array.
NotInArray,
/// Out of memory
OomError(OomError),
/// Operation can not be performed on an empty descriptor.
DescriptorIsEmpty,
/// Resource belongs to another device.
ResourceWrongDevice,
/// Provided a dynamically assigned sampler, but the descriptor has an immutable sampler.
SamplerIsImmutable,
/// Builder doesn't expect anymore descriptors
TooManyDescriptors,
/// Expected a non-arrayed image, but got an arrayed image.
UnexpectedArrayed,
/// Expected a single-sampled image, but got a multisampled image.
UnexpectedMultisampled,
/// Expected one type of resource but got another.
WrongDescriptorType,
}
impl From<OomError> for DescriptorSetError {
@ -405,36 +408,37 @@ impl fmt::Display for DescriptorSetError {
"{}",
match *self {
Self::AlreadyInArray => "builder is already within an array",
Self::NotInArray => "builder is not in an array",
Self::ArrayLayersMismatch { .. } =>
"the number of array layers of an image doesn't match what was expected",
Self::ArrayLengthMismatch { .. } =>
"array doesn't contain the correct amount of descriptors",
Self::TooManyDescriptors => "builder doesn't expect anymore descriptors",
Self::ArrayTooManyDescriptors { .. } =>
"runtime array contains too many descriptors",
Self::BuilderPoisoned =>
"the builder has previously return an error and is an unknown state",
Self::DescriptorIsEmpty => "operation can not be performed on an empty descriptor",
Self::DescriptorsMissing { .. } => "not all descriptors have been added",
Self::MissingBufferUsage(_) => "the buffer is missing the correct usage",
Self::MissingImageUsage(_) => "the image is missing the correct usage",
Self::WrongDescriptorType => "expected one type of resource but got another",
Self::ResourceWrongDevice => "resource belongs to another device",
Self::ExpectedMultisampled =>
"expected a multisampled image, but got a single-sampled image",
Self::ImageViewFormatMismatch { .. } =>
"the format of an image view doesn't match what was expected",
Self::ImageViewTypeMismatch { .. } =>
"the type of an image view doesn't match what was expected",
Self::ExpectedMultisampled =>
"expected a multisampled image, but got a single-sampled image",
Self::UnexpectedMultisampled =>
"expected a single-sampled image, but got a multisampled image",
Self::ArrayLayersMismatch { .. } =>
"the number of array layers of an image doesn't match what was expected",
Self::NotIdentitySwizzled =>
"the image view has a component swizzle that is different from identity",
Self::IncompatibleImageViewSampler =>
"the image view isn't compatible with the sampler",
Self::BuilderPoisoned =>
"the builder has previously return an error and is an unknown state",
Self::MissingBufferUsage(_) => "the buffer is missing the correct usage",
Self::MissingImageUsage(_) => "the image is missing the correct usage",
Self::NotIdentitySwizzled =>
"the image view has a component swizzle that is different from identity",
Self::NotInArray => "builder is not in an array",
Self::OomError(_) => "out of memory",
Self::DescriptorIsEmpty => "operation can not be performed on an empty descriptor",
Self::ResourceWrongDevice => "resource belongs to another device",
Self::SamplerIsImmutable => "provided a dynamically assigned sampler, but the descriptor has an immutable sampler",
Self::TooManyDescriptors => "builder doesn't expect anymore descriptors",
Self::UnexpectedArrayed => "expected a non-arrayed image, but got an arrayed image",
Self::ArrayTooManyDescriptors { .. } =>
"runtime array contains too many descriptors",
Self::UnexpectedMultisampled =>
"expected a single-sampled image, but got a multisampled image",
Self::WrongDescriptorType => "expected one type of resource but got another",
}
)
}

View File

@ -257,6 +257,9 @@ impl PersistentDescriptorSetBuilder {
/// Binds an image view with a sampler as the next descriptor.
///
/// If the descriptor set layout contains immutable samplers for this descriptor, use
/// `add_image` instead.
///
/// An error is returned if the image view isn't compatible with the descriptor.
#[inline]
pub fn add_sampled_image(

View File

@ -193,7 +193,9 @@ mod tests {
let (device, _) = gfx_dev_and_queue!();
let desc = DescriptorDesc {
ty: DescriptorDescTy::Sampler,
ty: DescriptorDescTy::Sampler {
immutable_samplers: vec![],
},
descriptor_count: 1,
stages: ShaderStages::all(),
mutable: true,

View File

@ -368,6 +368,9 @@ impl<'a> SingleLayoutDescSetBuilder<'a> {
/// Binds an image view with a sampler as the next descriptor.
///
/// If the descriptor set layout contains immutable samplers for this descriptor, use
/// `add_image` instead.
///
/// An error is returned if the image view isn't compatible with the descriptor.
#[inline]
pub fn add_sampled_image(

View File

@ -328,7 +328,7 @@ impl DescriptorWrite {
pub fn combined_image_sampler<I>(
binding: u32,
array_element: u32,
sampler: &Arc<Sampler>,
sampler: Option<&Arc<Sampler>>, // Some for dynamic sampler, None for immutable
image_view: &I,
) -> DescriptorWrite
where
@ -344,7 +344,7 @@ impl DescriptorWrite {
first_array_element: array_element,
inner: smallvec!({
DescriptorWriteInner::CombinedImageSampler(
sampler.internal_object(),
sampler.map(|s| s.internal_object()).unwrap_or_default(),
image_view.inner().internal_object(),
layouts.combined_image_sampler.into(),
)

View File

@ -296,7 +296,8 @@ mod tests {
};
let pipeline = Arc::new(
ComputePipeline::new(device.clone(), &shader, &(), Some(cache.clone())).unwrap(),
ComputePipeline::new(device.clone(), &shader, &(), Some(cache.clone()), |_| {})
.unwrap(),
);
let cache_data = cache.get_data().unwrap();
@ -382,13 +383,27 @@ mod tests {
};
let pipeline = Arc::new(
ComputePipeline::new(device.clone(), &first_shader, &(), Some(cache.clone())).unwrap(),
ComputePipeline::new(
device.clone(),
&first_shader,
&(),
Some(cache.clone()),
|_| {},
)
.unwrap(),
);
let cache_data = cache.get_data().unwrap();
let second_pipeline = Arc::new(
ComputePipeline::new(device.clone(), &second_shader, &(), Some(cache.clone())).unwrap(),
ComputePipeline::new(
device.clone(),
&second_shader,
&(),
Some(cache.clone()),
|_| {},
)
.unwrap(),
);
let second_data = cache.get_data().unwrap();
@ -436,13 +451,15 @@ mod tests {
};
let pipeline = Arc::new(
ComputePipeline::new(device.clone(), &shader, &(), Some(cache.clone())).unwrap(),
ComputePipeline::new(device.clone(), &shader, &(), Some(cache.clone()), |_| {})
.unwrap(),
);
let cache_data = cache.get_data().unwrap();
let second_pipeline = Arc::new(
ComputePipeline::new(device.clone(), &shader, &(), Some(cache.clone())).unwrap(),
ComputePipeline::new(device.clone(), &shader, &(), Some(cache.clone()), |_| {})
.unwrap(),
);
let second_data = cache.get_data().unwrap();

View File

@ -8,6 +8,7 @@
// according to those terms.
use crate::check_errors;
use crate::descriptor_set::layout::DescriptorSetDesc;
use crate::descriptor_set::layout::DescriptorSetLayout;
use crate::device::Device;
use crate::device::DeviceOwned;
@ -51,32 +52,41 @@ struct Inner {
impl ComputePipeline {
/// Builds a new `ComputePipeline`.
pub fn new<Cs, Css>(
///
/// `func` is a closure that is given a mutable reference to the inferred descriptor set
/// definitions. This can be used to make changes to the layout before it's created, for example
/// to add dynamic buffers or immutable samplers.
pub fn new<Cs, Css, F>(
device: Arc<Device>,
shader: &Cs,
spec_constants: &Css,
cache: Option<Arc<PipelineCache>>,
func: F,
) -> Result<ComputePipeline, ComputePipelineCreationError>
where
Cs: EntryPointAbstract,
Css: SpecializationConstants,
F: FnOnce(&mut [DescriptorSetDesc]),
{
let mut descriptor_set_layout_descs = shader.descriptor_set_layout_descs().to_owned();
func(&mut descriptor_set_layout_descs);
let descriptor_set_layouts = descriptor_set_layout_descs
.iter()
.map(|desc| {
Ok(Arc::new(DescriptorSetLayout::new(
device.clone(),
desc.clone(),
)?))
})
.collect::<Result<Vec<_>, PipelineLayoutCreationError>>()?;
let pipeline_layout = Arc::new(PipelineLayout::new(
device.clone(),
descriptor_set_layouts,
shader.push_constant_range().iter().cloned(),
)?);
unsafe {
let descriptor_set_layouts = shader
.descriptor_set_layout_descs()
.iter()
.map(|desc| {
Ok(Arc::new(DescriptorSetLayout::new(
device.clone(),
desc.clone(),
)?))
})
.collect::<Result<Vec<_>, PipelineLayoutCreationError>>()?;
let pipeline_layout = Arc::new(PipelineLayout::new(
device.clone(),
descriptor_set_layouts,
shader.push_constant_range().iter().cloned(),
)?);
ComputePipeline::with_unchecked_pipeline_layout(
device,
shader,
@ -460,6 +470,7 @@ mod tests {
&shader,
&SpecConsts { VALUE: 0x12345678 },
None,
|_| {},
)
.unwrap(),
);

View File

@ -139,18 +139,20 @@ where
self,
device: Arc<Device>,
) -> Result<GraphicsPipeline, GraphicsPipelineCreationError> {
self.with_auto_layout(device, &[])
self.with_auto_layout(device, |_| {})
}
/// Builds the graphics pipeline, using an inferred pipeline layout with some dynamic buffers.
///
/// Configures the inferred layout for each descriptor `(set, binding)` in `dynamic_buffers` to accept dynamic
/// buffers.
pub fn with_auto_layout(
/// The same as `new`, but allows you to provide a closure that is given a mutable reference to
/// the inferred descriptor set definitions. This can be used to make changes to the layout
/// before it's created, for example to add dynamic buffers or immutable samplers.
pub fn with_auto_layout<F>(
self,
device: Arc<Device>,
dynamic_buffers: &[(usize, usize)],
) -> Result<GraphicsPipeline, GraphicsPipelineCreationError> {
func: F,
) -> Result<GraphicsPipeline, GraphicsPipelineCreationError>
where
F: FnOnce(&mut [DescriptorSetDesc]),
{
let (descriptor_set_layout_descs, push_constant_ranges) = {
let stages: SmallVec<[&GraphicsEntryPoint; 5]> = std::array::IntoIter::new([
self.vertex_shader.as_ref().map(|s| &s.0),
@ -178,10 +180,7 @@ where
DescriptorSetDesc::union_multiple(&total, shader.descriptor_set_layout_descs())
})
.expect("Can't be union'd");
DescriptorSetDesc::tweak_multiple(
&mut descriptor_set_layout_descs,
dynamic_buffers.into_iter().cloned(),
);
func(&mut descriptor_set_layout_descs);
// We want to union each push constant range into a set of ranges that do not have intersecting stage flags.
// e.g. The range [0, 16) is either made available to Vertex | Fragment or we only make [0, 16) available to

View File

@ -77,7 +77,7 @@ use std::sync::Arc;
/// Describes how to retrieve data from an image within a shader.
pub struct Sampler {
sampler: ash::vk::Sampler,
handle: ash::vk::Sampler,
device: Arc<Device>,
compare_mode: bool,
unnormalized: bool,
@ -266,10 +266,7 @@ impl Sampler {
return Err(SamplerCreationError::SamplerAnisotropyFeatureNotEnabled);
}
let limit = device
.physical_device()
.properties()
.max_sampler_anisotropy;
let limit = device.physical_device().properties().max_sampler_anisotropy;
if max_anisotropy > limit {
return Err(SamplerCreationError::AnisotropyLimitExceeded {
requested: max_anisotropy,
@ -280,10 +277,7 @@ impl Sampler {
// Check mip_lod_bias value.
{
let limit = device
.physical_device()
.properties()
.max_sampler_lod_bias;
let limit = device.physical_device().properties().max_sampler_lod_bias;
if mip_lod_bias > limit {
return Err(SamplerCreationError::MipLodBiasLimitExceeded {
requested: mip_lod_bias,
@ -322,7 +316,7 @@ impl Sampler {
};
let fns = device.fns();
let sampler = unsafe {
let handle = unsafe {
let infos = ash::vk::SamplerCreateInfo {
flags: ash::vk::SamplerCreateFlags::empty(),
mag_filter: mag_filter.into(),
@ -366,7 +360,7 @@ impl Sampler {
};
Ok(Arc::new(Sampler {
sampler: sampler,
handle,
device: device.clone(),
compare_mode: compare.is_some(),
unnormalized: false,
@ -424,7 +418,7 @@ impl Sampler {
(b, None) => b,
};
let sampler = unsafe {
let handle = unsafe {
let infos = ash::vk::SamplerCreateInfo {
flags: ash::vk::SamplerCreateFlags::empty(),
mag_filter: filter.into(),
@ -458,7 +452,7 @@ impl Sampler {
};
Ok(Arc::new(Sampler {
sampler: sampler,
handle,
device: device.clone(),
compare_mode: false,
unnormalized: true,
@ -530,24 +524,33 @@ unsafe impl VulkanObject for Sampler {
#[inline]
fn internal_object(&self) -> ash::vk::Sampler {
self.sampler
self.handle
}
}
impl fmt::Debug for Sampler {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "<Vulkan sampler {:?}>", self.sampler)
write!(fmt, "<Vulkan sampler {:?}>", self.handle)
}
}
impl PartialEq for Sampler {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.handle == other.handle
}
}
impl Eq for Sampler {}
impl Drop for Sampler {
#[inline]
fn drop(&mut self) {
unsafe {
let fns = self.device.fns();
fns.v1_0
.destroy_sampler(self.device.internal_object(), self.sampler, ptr::null());
.destroy_sampler(self.device.internal_object(), self.handle, ptr::null());
}
}
}