Support for Runtime Descriptor Arrays (#1674)

This commit is contained in:
Austin Johnson 2021-09-02 03:29:27 -05:00 committed by GitHub
parent f79814c2f2
commit 0a3791c303
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 2641 additions and 1944 deletions

1
.gitignore vendored
View File

@ -5,5 +5,6 @@ examples/**/triangle.png
examples/**/mandelbrot.png
examples/**/multiview1.png
examples/**/multiview2.png
examples/**/pipeline_cache.bin
.idea
*.swp

View File

@ -142,12 +142,16 @@ fn main() {
// If you want to run the pipeline on multiple different buffers, you need to create multiple
// descriptor sets that each contain the buffer you want to run the shader on.
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();
let set = Arc::new(
PersistentDescriptorSet::start(layout.clone())
.add_buffer(data_buffer.clone())
.unwrap()
set_builder
.build()
.unwrap(),
.unwrap()
);
// In order to execute our operation, we have to build a command buffer.

View File

@ -110,15 +110,12 @@ impl AmbientLightingSystem {
/// result of the deferred pass.
/// - `ambient_color` is the color to apply.
///
pub fn draw<C>(
pub fn draw(
&self,
viewport_dimensions: [u32; 2],
color_input: C,
color_input: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
ambient_color: [f32; 3],
) -> SecondaryAutoCommandBuffer
where
C: ImageViewAbstract + Send + Sync + 'static,
{
) -> SecondaryAutoCommandBuffer {
let push_constants = fs::ty::PushConstants {
color: [ambient_color[0], ambient_color[1], ambient_color[2], 1.0],
};
@ -129,9 +126,13 @@ impl AmbientLightingSystem {
.descriptor_set_layouts()
.get(0)
.unwrap();
let descriptor_set = PersistentDescriptorSet::start(layout.clone())
let mut descriptor_set_builder = PersistentDescriptorSet::start(layout.clone());
descriptor_set_builder
.add_image(color_input)
.unwrap()
.unwrap();
let descriptor_set = descriptor_set_builder
.build()
.unwrap();

View File

@ -118,18 +118,14 @@ impl DirectionalLightingSystem {
/// - `direction` is the direction of the light in world coordinates.
/// - `color` is the color to apply.
///
pub fn draw<C, N>(
pub fn draw(
&self,
viewport_dimensions: [u32; 2],
color_input: C,
normals_input: N,
color_input: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
normals_input: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
direction: Vector3<f32>,
color: [f32; 3],
) -> SecondaryAutoCommandBuffer
where
C: ImageViewAbstract + Send + Sync + 'static,
N: ImageViewAbstract + Send + Sync + 'static,
{
) -> SecondaryAutoCommandBuffer {
let push_constants = fs::ty::PushConstants {
color: [color[0], color[1], color[2], 1.0],
direction: direction.extend(0.0).into(),
@ -141,11 +137,15 @@ impl DirectionalLightingSystem {
.descriptor_set_layouts()
.get(0)
.unwrap();
let descriptor_set = PersistentDescriptorSet::start(layout.clone())
let mut descriptor_set_builder = PersistentDescriptorSet::start(layout.clone());
descriptor_set_builder
.add_image(color_input)
.unwrap()
.add_image(normals_input)
.unwrap()
.unwrap();
let descriptor_set = descriptor_set_builder
.build()
.unwrap();

View File

@ -127,21 +127,16 @@ impl PointLightingSystem {
/// - `position` is the position of the spot light in world coordinates.
/// - `color` is the color of the light.
///
pub fn draw<C, N, D>(
pub fn draw(
&self,
viewport_dimensions: [u32; 2],
color_input: C,
normals_input: N,
depth_input: D,
color_input: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
normals_input: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
depth_input: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
screen_to_world: Matrix4<f32>,
position: Vector3<f32>,
color: [f32; 3],
) -> SecondaryAutoCommandBuffer
where
C: ImageViewAbstract + Send + Sync + 'static,
N: ImageViewAbstract + Send + Sync + 'static,
D: ImageViewAbstract + Send + Sync + 'static,
{
) -> SecondaryAutoCommandBuffer {
let push_constants = fs::ty::PushConstants {
screen_to_world: screen_to_world.into(),
color: [color[0], color[1], color[2], 1.0],
@ -154,13 +149,17 @@ impl PointLightingSystem {
.descriptor_set_layouts()
.get(0)
.unwrap();
let descriptor_set = PersistentDescriptorSet::start(layout.clone())
let mut descriptor_set_builder = PersistentDescriptorSet::start(layout.clone());
descriptor_set_builder
.add_image(color_input)
.unwrap()
.add_image(normals_input)
.unwrap()
.add_image(depth_input)
.unwrap()
.unwrap();
let descriptor_set = descriptor_set_builder
.build()
.unwrap();

View File

@ -225,15 +225,14 @@ impl FrameSystem {
/// - `world_to_framebuffer` is the matrix that will be used to convert from 3D coordinates in
/// the world into 2D coordinates on the framebuffer.
///
pub fn frame<F, I>(
pub fn frame<F>(
&mut self,
before_future: F,
final_image: I,
final_image: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
world_to_framebuffer: Matrix4<f32>,
) -> Frame
where
F: GpuFuture + 'static,
I: ImageViewAbstract + Clone + Send + Sync + 'static,
{
// First of all we recreate `self.diffuse_buffer`, `self.normals_buffer` and
// `self.depth_buffer` if their dimensions doesn't match the dimensions of the final image.

View File

@ -28,7 +28,7 @@ use vulkano::pipeline::shader::EntryPointAbstract;
use vulkano::pipeline::{ComputePipeline, PipelineBindPoint};
use vulkano::sync;
use vulkano::sync::GpuFuture;
use vulkano::OomError;
use vulkano::descriptor_set::layout::DescriptorSetLayoutError;
use vulkano::Version;
fn main() {
@ -130,7 +130,7 @@ fn main() {
desc.clone(),
)?))
})
.collect::<Result<Vec<_>, OomError>>()
.collect::<Result<Vec<_>, DescriptorSetLayoutError>>()
.unwrap();
Arc::new(
@ -199,14 +199,18 @@ fn main() {
.unwrap();
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
set_builder
.add_buffer(input_buffer.clone())
.unwrap()
.add_buffer(output_buffer.clone())
.unwrap();
let set = Arc::new(
PersistentDescriptorSet::start(layout.clone())
.add_buffer(input_buffer.clone())
.unwrap()
.add_buffer(output_buffer.clone())
.unwrap()
set_builder
.build()
.unwrap(),
.unwrap()
);
// Build the command buffer, using different offsets for each call.

View File

@ -198,12 +198,16 @@ fn main() {
let view = ImageView::new(image.clone()).unwrap();
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();
let set = Arc::new(
PersistentDescriptorSet::start(layout.clone())
.add_image(view.clone())
.unwrap()
set_builder
.build()
.unwrap(),
.unwrap()
);
let buf = CpuAccessibleBuffer::from_iter(

View File

@ -204,12 +204,16 @@ fn main() {
);
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
set_builder
.add_sampled_image(texture.clone(), sampler.clone())
.unwrap();
let set = Arc::new(
PersistentDescriptorSet::start(layout.clone())
.add_sampled_image(texture.clone(), sampler.clone())
.unwrap()
set_builder
.build()
.unwrap(),
.unwrap()
);
let mut viewport = Viewport {

View File

@ -139,15 +139,19 @@ void 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()
// Now you can just add immutable buffer like other buffers.
.add_buffer(immutable_data_buffer.clone())
.unwrap();
let set = Arc::new(
PersistentDescriptorSet::start(layout.clone())
.add_buffer(data_buffer.clone())
.unwrap()
// Now you can just add immutable buffer like other buffers.
.add_buffer(immutable_data_buffer.clone())
.unwrap()
set_builder
.build()
.unwrap(),
.unwrap()
);
let mut builder = AutoCommandBufferBuilder::primary(

View File

@ -30,6 +30,7 @@ extern crate vulkano_shaders;
extern crate vulkano_win;
extern crate winit;
use std::iter;
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuBufferPool};
use vulkano::command_buffer::{
@ -305,20 +306,20 @@ 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 = indirect_args_pool
.chunk([DrawIndirectCommand {
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();
}))
.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 = vertex_pool
let vertices = Arc::new(vertex_pool
.chunk((0..(6 * 16)).map(|_| Vertex { position: [0.0; 2] }))
.unwrap();
.unwrap());
// Pass the two buffers to the compute shader
let layout = compute_pipeline
@ -326,14 +327,18 @@ fn main() {
.descriptor_set_layouts()
.get(0)
.unwrap();
let mut cs_desciptor_set_builder = PersistentDescriptorSet::start(layout.clone());
cs_desciptor_set_builder
.add_buffer(vertices.clone())
.unwrap()
.add_buffer(indirect_args.clone())
.unwrap();
let cs_desciptor_set = Arc::new(
PersistentDescriptorSet::start(layout.clone())
.add_buffer(vertices.clone())
.unwrap()
.add_buffer(indirect_args.clone())
.unwrap()
cs_desciptor_set_builder
.build()
.unwrap(),
.unwrap()
);
let mut builder = AutoCommandBufferBuilder::primary(

View File

@ -102,12 +102,16 @@ 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();
let set = Arc::new(
PersistentDescriptorSet::start(layout.clone())
.add_buffer(data_buffer.clone())
.unwrap()
set_builder
.build()
.unwrap(),
.unwrap()
);
// The `vulkano_shaders::shaders!` macro generates a struct with the correct representation of the push constants struct specified in the shader.

View File

@ -0,0 +1,525 @@
// 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.
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};
use vulkano::pipeline::shader::EntryPointAbstract;
use vulkano::pipeline::layout::PipelineLayout;
use vulkano::descriptor_set::layout::DescriptorSetLayoutError;
use vulkano::descriptor_set::layout::DescriptorSetLayout;
fn main() {
// The start of this example is exactly the same as `triangle`. You should read the
// `triangle` example if you haven't done so yet.
let required_extensions = vulkano_win::required_extensions();
let instance = Instance::new(None, Version::V1_2, &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 {
descriptor_indexing: true,
shader_uniform_buffer_array_non_uniform_indexing: true,
runtime_descriptor_array: true,
descriptor_binding_variable_descriptor_count: true,
descriptor_binding_partially_bound: true,
..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],
tex_i: u32,
coords: [f32; 2],
}
vulkano::impl_vertex!(Vertex, position, tex_i, coords);
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
device.clone(),
BufferUsage::all(),
false,
[
Vertex {
position: [-0.1, -0.9],
tex_i: 0,
coords: [1.0, 0.0],
},
Vertex {
position: [-0.9, -0.9],
tex_i: 0,
coords: [0.0, 0.0],
},
Vertex {
position: [-0.9, -0.1],
tex_i: 0,
coords: [0.0, 1.0],
},
Vertex {
position: [-0.1, -0.9],
tex_i: 0,
coords: [1.0, 0.0],
},
Vertex {
position: [-0.9, -0.1],
tex_i: 0,
coords: [0.0, 1.0],
},
Vertex {
position: [-0.1, -0.1],
tex_i: 0,
coords: [1.0, 1.0],
},
Vertex {
position: [0.9, -0.9],
tex_i: 1,
coords: [1.0, 0.0],
},
Vertex {
position: [0.1, -0.9],
tex_i: 1,
coords: [0.0, 0.0],
},
Vertex {
position: [0.1, -0.1],
tex_i: 1,
coords: [0.0, 1.0],
},
Vertex {
position: [0.9, -0.9],
tex_i: 1,
coords: [1.0, 0.0],
},
Vertex {
position: [0.1, -0.1],
tex_i: 1,
coords: [0.0, 1.0],
},
Vertex {
position: [0.9, -0.1],
tex_i: 1,
coords: [1.0, 1.0],
},
]
.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 mascot_texture = {
let png_bytes = include_bytes!("rust_mascot.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 = ImmutableImage::from_iter(
image_data.iter().cloned(),
dimensions,
MipmapsCount::One,
Format::R8G8B8A8Srgb,
queue.clone(),
)
.unwrap()
.0;
ImageView::new(image).unwrap()
};
let vulkano_texture = {
let png_bytes = include_bytes!("vulkano_logo.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 = ImmutableImage::from_iter(
image_data.iter().cloned(),
dimensions,
MipmapsCount::One,
Format::R8G8B8A8Srgb,
queue.clone(),
)
.unwrap()
.0;
ImageView::new(image).unwrap()
};
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_layout = {
let mut descriptor_set_descs: Vec<_> =
(&fs.main_entry_point() as &dyn EntryPointAbstract)
.descriptor_set_layout_descs()
.iter()
.cloned()
.collect();
// Set 0, Binding 0
descriptor_set_descs[0].set_variable_descriptor_count(0, 2);
let descriptor_set_layouts = descriptor_set_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,
(&fs.main_entry_point() as &dyn EntryPointAbstract)
.push_constant_range()
.iter()
.cloned(),
)
.unwrap()
)
};
let pipeline = Arc::new(
GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex>()
.vertex_shader(vs.main_entry_point(), ())
.viewports_dynamic_scissors_irrelevant(1)
.fragment_shader(fs.main_entry_point(), ())
.blend_alpha_blending()
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
.with_pipeline_layout(device.clone(), pipeline_layout)
.unwrap(),
);
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
set_builder
.enter_array()
.unwrap()
.add_sampled_image(mascot_texture.clone(), sampler.clone())
.unwrap()
.add_sampled_image(vulkano_texture.clone(), sampler.clone())
.unwrap()
.leave_array()
.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: Option<Box<dyn GpuFuture>> =
Some(Box::new(vulkano::sync::now(device.clone())));
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",
vulkan_version: "1.2",
spirv_version: "1.5",
src: "
#version 450
layout(location = 0) in vec2 position;
layout(location = 1) in uint tex_i;
layout(location = 2) in vec2 coords;
layout(location = 0) out flat uint out_tex_i;
layout(location = 1) out vec2 out_coords;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
out_tex_i = tex_i;
out_coords = coords;
}"
}
}
mod fs {
vulkano_shaders::shader! {
ty: "fragment",
vulkan_version: "1.2",
spirv_version: "1.5",
src: "
#version 450
#extension GL_EXT_nonuniform_qualifier : enable
layout(location = 0) in flat uint tex_i;
layout(location = 1) in vec2 coords;
layout(location = 0) out vec4 f_color;
layout(set = 0, binding = 0) uniform sampler2D tex[];
void main() {
f_color = texture(tex[tex_i], coords);
}"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -100,14 +100,20 @@ fn main() {
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, data_iter)
.unwrap()
};
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();
let set = Arc::new(
PersistentDescriptorSet::start(layout.clone())
.add_buffer(data_buffer.clone())
.unwrap()
set_builder
.build()
.unwrap(),
.unwrap()
);
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),
queue.family(),

View File

@ -112,12 +112,16 @@ 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();
let set = Arc::new(
PersistentDescriptorSet::start(layout.clone())
.add_buffer(data_buffer.clone())
.unwrap()
set_builder
.build()
.unwrap(),
.unwrap()
);
let mut builder = AutoCommandBufferBuilder::primary(

View File

@ -221,16 +221,20 @@ fn main() {
proj: proj.into(),
};
uniform_buffer.next(uniform_data).unwrap()
Arc::new(uniform_buffer.next(uniform_data).unwrap())
};
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
set_builder
.add_buffer(uniform_buffer_subbuffer)
.unwrap();
let set = Arc::new(
PersistentDescriptorSet::start(layout.clone())
.add_buffer(uniform_buffer_subbuffer)
.unwrap()
set_builder
.build()
.unwrap(),
.unwrap()
);
let (image_num, suboptimal, acquire_future) =

View File

@ -20,6 +20,7 @@ struct Descriptor {
binding: u32,
desc_ty: TokenStream,
descriptor_count: u64,
variable_count: bool,
mutable: bool,
}
@ -53,11 +54,13 @@ pub(super) fn write_descriptor_set_layout_descs(
let desc_ty = &d.desc_ty;
let descriptor_count = d.descriptor_count as u32;
let mutable = d.mutable;
let variable_count = d.variable_count;
quote! {
Some(DescriptorDesc {
ty: #desc_ty,
descriptor_count: #descriptor_count,
stages: #stages,
variable_count: #variable_count,
mutable: #mutable,
}),
}
@ -177,7 +180,7 @@ fn find_descriptors(
.is_some();
// Find information about the kind of binding for this descriptor.
let (desc_ty, mutable, descriptor_count) =
let (desc_ty, mutable, descriptor_count, variable_count) =
descriptor_infos(doc, pointed_ty, storage_class, false).expect(&format!(
"Couldn't find relevant type for uniform `{}` (type {}, maybe unimplemented)",
name, pointed_ty
@ -188,6 +191,7 @@ fn find_descriptors(
binding,
descriptor_count,
mutable: !nonwritable && mutable,
variable_count: variable_count,
});
}
@ -372,7 +376,7 @@ fn descriptor_infos(
pointed_ty: u32,
pointer_storage: StorageClass,
force_combined_image_sampled: bool,
) -> Option<(TokenStream, bool, u64)> {
) -> Option<(TokenStream, bool, u64, bool)> {
doc.instructions
.iter()
.filter_map(|i| {
@ -401,8 +405,8 @@ fn descriptor_infos(
// VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
(quote! { DescriptorDescTy::UniformBuffer }, false) // Uniforms are never mutable.
};
Some((ty, mutable, 1))
Some((ty, mutable, 1, false))
}
&Instruction::TypeImage {
result_id,
@ -442,7 +446,7 @@ fn descriptor_infos(
}
};
Some((desc, true, 1)) // Never writable.
Some((desc, true, 1, false)) // Never writable.
}
Dim::DimBuffer => {
let (ty, mutable) = if sampled {
@ -459,8 +463,7 @@ fn descriptor_infos(
}
};
Some((desc, mutable, 1))
Some((desc, mutable, 1, false))
}
_ => {
let (ty, mutable) = if force_combined_image_sampled {
@ -498,7 +501,7 @@ fn descriptor_infos(
})
};
Some((desc, mutable, 1))
Some((desc, mutable, 1, false))
}
}
}
@ -512,19 +515,20 @@ fn descriptor_infos(
&Instruction::TypeSampler { result_id } if result_id == pointed_ty => {
let desc = quote! { DescriptorDescTy::Sampler };
Some((desc, false, 1))
Some((desc, false, 1, false))
}
&Instruction::TypeArray {
result_id,
type_id,
length_id,
} if result_id == pointed_ty => {
let (desc, mutable, arr) =
let (desc, mutable, arr, variable_count) =
match descriptor_infos(doc, type_id, pointer_storage.clone(), false) {
None => return None,
Some(v) => v,
};
assert_eq!(arr, 1); // TODO: implement?
assert!(!variable_count); // TODO: Is this even a thing?
let len = doc
.instructions
.iter()
@ -539,8 +543,25 @@ fn descriptor_infos(
.next()
.expect("failed to find array length");
let len = len.iter().rev().fold(0, |a, &b| (a << 32) | b as u64);
Some((desc, mutable, len))
Some((desc, mutable, len, false))
}
&Instruction::TypeRuntimeArray {
result_id,
type_id,
} if result_id == pointed_ty => {
let (desc, mutable, arr, variable_count) =
match descriptor_infos(doc, type_id, pointer_storage.clone(), false) {
None => return None,
Some(v) => v,
};
assert_eq!(arr, 1); // TODO: implement?
assert!(!variable_count); // TODO: Don't think this is possible?
Some((desc, mutable, 1, true))
}
_ => None, // TODO: other types
}
})

View File

@ -368,6 +368,7 @@ where
unsafe impl<T: ?Sized, A> BufferAccess for CpuAccessibleBuffer<T, A>
where
T: 'static + Send + Sync,
A: Send + Sync,
{
#[inline]
fn inner(&self) -> BufferInner {
@ -484,6 +485,7 @@ where
unsafe impl<T: ?Sized, A> TypedBufferAccess for CpuAccessibleBuffer<T, A>
where
T: 'static + Send + Sync,
A: Send + Sync,
{
type Content = T;
}
@ -498,6 +500,7 @@ unsafe impl<T: ?Sized, A> DeviceOwned for CpuAccessibleBuffer<T, A> {
impl<T: ?Sized, A> PartialEq for CpuAccessibleBuffer<T, A>
where
T: 'static + Send + Sync,
A: Send + Sync,
{
#[inline]
fn eq(&self, other: &Self) -> bool {
@ -505,11 +508,17 @@ where
}
}
impl<T: ?Sized, A> Eq for CpuAccessibleBuffer<T, A> where T: 'static + Send + Sync {}
impl<T: ?Sized, A> Eq for CpuAccessibleBuffer<T, A>
where
T: 'static + Send + Sync,
A: Send + Sync,
{
}
impl<T: ?Sized, A> Hash for CpuAccessibleBuffer<T, A>
where
T: 'static + Send + Sync,
A: Send + Sync,
{
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {

View File

@ -620,7 +620,9 @@ where
unsafe impl<T, A> BufferAccess for CpuBufferPoolChunk<T, A>
where
T: Send + Sync,
A: MemoryPool,
<A as MemoryPool>::Alloc: Send + Sync,
{
#[inline]
fn inner(&self) -> BufferInner {
@ -731,7 +733,9 @@ where
unsafe impl<T, A> TypedBufferAccess for CpuBufferPoolChunk<T, A>
where
T: Send + Sync,
A: MemoryPool,
<A as MemoryPool>::Alloc: Send + Sync,
{
type Content = [T];
}
@ -748,7 +752,9 @@ where
impl<T, A> PartialEq for CpuBufferPoolChunk<T, A>
where
T: Send + Sync,
A: MemoryPool,
<A as MemoryPool>::Alloc: Send + Sync,
{
#[inline]
fn eq(&self, other: &Self) -> bool {
@ -756,11 +762,19 @@ where
}
}
impl<T, A> Eq for CpuBufferPoolChunk<T, A> where A: MemoryPool {}
impl<T, A> Eq for CpuBufferPoolChunk<T, A>
where
T: Send + Sync,
A: MemoryPool,
<A as MemoryPool>::Alloc: Send + Sync,
{
}
impl<T, A> Hash for CpuBufferPoolChunk<T, A>
where
T: Send + Sync,
A: MemoryPool,
<A as MemoryPool>::Alloc: Send + Sync,
{
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
@ -782,7 +796,9 @@ where
unsafe impl<T, A> BufferAccess for CpuBufferPoolSubbuffer<T, A>
where
T: Send + Sync,
A: MemoryPool,
<A as MemoryPool>::Alloc: Send + Sync,
{
#[inline]
fn inner(&self) -> BufferInner {
@ -817,7 +833,9 @@ where
unsafe impl<T, A> TypedBufferAccess for CpuBufferPoolSubbuffer<T, A>
where
T: Send + Sync,
A: MemoryPool,
<A as MemoryPool>::Alloc: Send + Sync,
{
type Content = T;
}
@ -834,7 +852,9 @@ where
impl<T, A> PartialEq for CpuBufferPoolSubbuffer<T, A>
where
T: Send + Sync,
A: MemoryPool,
<A as MemoryPool>::Alloc: Send + Sync,
{
#[inline]
fn eq(&self, other: &Self) -> bool {
@ -842,11 +862,19 @@ where
}
}
impl<T, A> Eq for CpuBufferPoolSubbuffer<T, A> where A: MemoryPool {}
impl<T, A> Eq for CpuBufferPoolSubbuffer<T, A>
where
T: Send + Sync,
A: MemoryPool,
<A as MemoryPool>::Alloc: Send + Sync,
{
}
impl<T, A> Hash for CpuBufferPoolSubbuffer<T, A>
where
T: Send + Sync,
A: MemoryPool,
<A as MemoryPool>::Alloc: Send + Sync,
{
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {

View File

@ -293,6 +293,7 @@ unsafe impl<T: ?Sized, A> DeviceOwned for DeviceLocalBuffer<T, A> {
unsafe impl<T: ?Sized, A> BufferAccess for DeviceLocalBuffer<T, A>
where
T: 'static + Send + Sync,
A: Send + Sync,
{
#[inline]
fn inner(&self) -> BufferInner {
@ -382,6 +383,7 @@ where
unsafe impl<T: ?Sized, A> TypedBufferAccess for DeviceLocalBuffer<T, A>
where
T: 'static + Send + Sync,
A: Send + Sync,
{
type Content = T;
}
@ -389,6 +391,7 @@ where
impl<T: ?Sized, A> PartialEq for DeviceLocalBuffer<T, A>
where
T: 'static + Send + Sync,
A: Send + Sync,
{
#[inline]
fn eq(&self, other: &Self) -> bool {
@ -396,11 +399,17 @@ where
}
}
impl<T: ?Sized, A> Eq for DeviceLocalBuffer<T, A> where T: 'static + Send + Sync {}
impl<T: ?Sized, A> Eq for DeviceLocalBuffer<T, A>
where
T: 'static + Send + Sync,
A: Send + Sync,
{
}
impl<T: ?Sized, A> Hash for DeviceLocalBuffer<T, A>
where
T: 'static + Send + Sync,
A: Send + Sync,
{
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {

View File

@ -353,7 +353,11 @@ impl<T: ?Sized, A> ImmutableBuffer<T, A> {
}
}
unsafe impl<T: ?Sized, A> BufferAccess for ImmutableBuffer<T, A> {
unsafe impl<T, A> BufferAccess for ImmutableBuffer<T, A>
where
T: Send + Sync + ?Sized,
A: Send + Sync,
{
#[inline]
fn inner(&self) -> BufferInner {
BufferInner {
@ -392,7 +396,11 @@ unsafe impl<T: ?Sized, A> BufferAccess for ImmutableBuffer<T, A> {
unsafe fn unlock(&self) {}
}
unsafe impl<T: ?Sized, A> TypedBufferAccess for ImmutableBuffer<T, A> {
unsafe impl<T, A> TypedBufferAccess for ImmutableBuffer<T, A>
where
T: Send + Sync + ?Sized,
A: Send + Sync,
{
type Content = T;
}
@ -403,16 +411,29 @@ unsafe impl<T: ?Sized, A> DeviceOwned for ImmutableBuffer<T, A> {
}
}
impl<T: ?Sized, A> PartialEq for ImmutableBuffer<T, A> {
impl<T: ?Sized, A> PartialEq for ImmutableBuffer<T, A>
where
T: Send + Sync,
A: Send + Sync,
{
#[inline]
fn eq(&self, other: &Self) -> bool {
self.inner() == other.inner() && self.size() == other.size()
}
}
impl<T: ?Sized, A> Eq for ImmutableBuffer<T, A> {}
impl<T: ?Sized, A> Eq for ImmutableBuffer<T, A>
where
T: Send + Sync,
A: Send + Sync,
{
}
impl<T: ?Sized, A> Hash for ImmutableBuffer<T, A> {
impl<T: ?Sized, A> Hash for ImmutableBuffer<T, A>
where
T: Send + Sync,
A: Send + Sync,
{
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.inner().hash(state);
@ -430,7 +451,11 @@ pub struct ImmutableBufferInitialization<
used: Arc<AtomicBool>,
}
unsafe impl<T: ?Sized, A> BufferAccess for ImmutableBufferInitialization<T, A> {
unsafe impl<T, A> BufferAccess for ImmutableBufferInitialization<T, A>
where
T: Send + Sync + ?Sized,
A: Send + Sync,
{
#[inline]
fn inner(&self) -> BufferInner {
self.buffer.inner()
@ -474,7 +499,11 @@ unsafe impl<T: ?Sized, A> BufferAccess for ImmutableBufferInitialization<T, A> {
}
}
unsafe impl<T: ?Sized, A> TypedBufferAccess for ImmutableBufferInitialization<T, A> {
unsafe impl<T, A> TypedBufferAccess for ImmutableBufferInitialization<T, A>
where
T: Send + Sync + ?Sized,
A: Send + Sync,
{
type Content = T;
}
@ -495,16 +524,29 @@ impl<T: ?Sized, A> Clone for ImmutableBufferInitialization<T, A> {
}
}
impl<T: ?Sized, A> PartialEq for ImmutableBufferInitialization<T, A> {
impl<T: ?Sized, A> PartialEq for ImmutableBufferInitialization<T, A>
where
T: Send + Sync,
A: Send + Sync,
{
#[inline]
fn eq(&self, other: &Self) -> bool {
self.inner() == other.inner() && self.size() == other.size()
}
}
impl<T: ?Sized, A> Eq for ImmutableBufferInitialization<T, A> {}
impl<T: ?Sized, A> Eq for ImmutableBufferInitialization<T, A>
where
T: Send + Sync,
A: Send + Sync,
{
}
impl<T: ?Sized, A> Hash for ImmutableBufferInitialization<T, A> {
impl<T: ?Sized, A> Hash for ImmutableBufferInitialization<T, A>
where
T: Send + Sync,
A: Send + Sync,
{
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.inner().hash(state);

View File

@ -213,9 +213,10 @@ impl<T, B> BufferSlice<[T], B> {
}
}
unsafe impl<T: ?Sized, B> BufferAccess for BufferSlice<T, B>
unsafe impl<T, B> BufferAccess for BufferSlice<T, B>
where
B: BufferAccess,
T: Send + Sync + ?Sized,
{
#[inline]
fn inner(&self) -> BufferInner {
@ -252,8 +253,9 @@ where
}
}
unsafe impl<T: ?Sized, B> TypedBufferAccess for BufferSlice<T, B>
unsafe impl<T, B> TypedBufferAccess for BufferSlice<T, B>
where
T: ?Sized + Send + Sync,
B: BufferAccess,
{
type Content = T;
@ -283,6 +285,7 @@ impl<T, B> From<BufferSlice<T, B>> for BufferSlice<[T], B> {
impl<T: ?Sized, B> PartialEq for BufferSlice<T, B>
where
T: Send + Sync,
B: BufferAccess,
{
#[inline]
@ -291,10 +294,16 @@ where
}
}
impl<T: ?Sized, B> Eq for BufferSlice<T, B> where B: BufferAccess {}
impl<T: ?Sized, B> Eq for BufferSlice<T, B>
where
B: BufferAccess,
T: Send + Sync,
{
}
impl<T: ?Sized, B> Hash for BufferSlice<T, B>
where
T: Send + Sync,
B: BufferAccess,
{
#[inline]

View File

@ -24,7 +24,7 @@ use std::ops::Range;
/// buffer.
///
/// See also `TypedBufferAccess`.
pub unsafe trait BufferAccess: DeviceOwned {
pub unsafe trait BufferAccess: DeviceOwned + Send + Sync {
/// Returns the inner information about this buffer.
fn inner(&self) -> BufferInner;
@ -166,7 +166,7 @@ pub struct BufferInner<'a> {
unsafe impl<T> BufferAccess for T
where
T: SafeDeref,
T: SafeDeref + Send + Sync,
T::Target: BufferAccess,
{
#[inline]
@ -219,31 +219,22 @@ pub unsafe trait TypedBufferAccess: BufferAccess {
unsafe impl<T> TypedBufferAccess for T
where
T: SafeDeref,
T: SafeDeref + Send + Sync,
T::Target: TypedBufferAccess,
{
type Content = <T::Target as TypedBufferAccess>::Content;
}
impl PartialEq for &dyn BufferAccess {
impl PartialEq for dyn BufferAccess {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.inner() == other.inner() && self.size() == other.size()
}
}
impl Eq for &dyn BufferAccess {}
impl Eq for dyn BufferAccess {}
impl PartialEq for dyn BufferAccess + Send + Sync {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.inner() == other.inner() && self.size() == other.size()
}
}
impl Eq for dyn BufferAccess + Send + Sync {}
impl Hash for dyn BufferAccess + Send + Sync {
impl Hash for dyn BufferAccess {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.inner().hash(state);

View File

@ -58,10 +58,10 @@ use std::sync::Arc;
/// `view` module.
pub struct BufferView<B>
where
B: BufferAccess,
B: BufferAccess + ?Sized,
{
view: ash::vk::BufferView,
buffer: B,
buffer: Box<B>,
atomic_accesses: bool,
}
@ -167,7 +167,7 @@ where
Ok(BufferView {
view,
buffer: org_buffer,
buffer: Box::new(org_buffer),
atomic_accesses: !(format_props
& ash::vk::FormatFeatureFlags::STORAGE_TEXEL_BUFFER_ATOMIC)
.is_empty(),
@ -235,7 +235,7 @@ where
impl<B> Drop for BufferView<B>
where
B: BufferAccess,
B: BufferAccess + ?Sized,
{
#[inline]
fn drop(&mut self) {

View File

@ -1606,7 +1606,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
#[inline]
pub fn fill_buffer<B>(&mut self, buffer: B, data: u32) -> Result<&mut Self, FillBufferError>
where
B: BufferAccess + Send + Sync + 'static,
B: BufferAccess + 'static,
{
unsafe {
self.ensure_outside_render_pass()?;

View File

@ -285,7 +285,7 @@ impl SyncCommandBufferBuilder {
#[inline]
pub unsafe fn bind_index_buffer<B>(&mut self, buffer: B, index_ty: IndexType)
where
B: BufferAccess + Send + Sync + 'static,
B: BufferAccess + 'static,
{
struct Cmd<B> {
buffer: B,
@ -294,7 +294,7 @@ impl SyncCommandBufferBuilder {
impl<B> Command for Cmd<B>
where
B: BufferAccess + Send + Sync + 'static,
B: BufferAccess + 'static,
{
fn name(&self) -> &'static str {
"vkCmdBindIndexBuffer"
@ -748,8 +748,8 @@ impl SyncCommandBufferBuilder {
regions: R,
) -> Result<(), SyncCommandBufferBuilderError>
where
S: BufferAccess + Send + Sync + 'static,
D: BufferAccess + Send + Sync + 'static,
S: BufferAccess + 'static,
D: BufferAccess + 'static,
R: IntoIterator<Item = (DeviceSize, DeviceSize, DeviceSize)> + Send + Sync + 'static,
{
struct Cmd<S, D, R> {
@ -760,8 +760,8 @@ impl SyncCommandBufferBuilder {
impl<S, D, R> Command for Cmd<S, D, R>
where
S: BufferAccess + Send + Sync + 'static,
D: BufferAccess + Send + Sync + 'static,
S: BufferAccess + 'static,
D: BufferAccess + 'static,
R: IntoIterator<Item = (DeviceSize, DeviceSize, DeviceSize)>,
{
fn name(&self) -> &'static str {
@ -857,7 +857,7 @@ impl SyncCommandBufferBuilder {
regions: R,
) -> Result<(), SyncCommandBufferBuilderError>
where
S: BufferAccess + Send + Sync + 'static,
S: BufferAccess + 'static,
D: ImageAccess + Send + Sync + 'static,
R: IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy> + Send + Sync + 'static,
{
@ -870,7 +870,7 @@ impl SyncCommandBufferBuilder {
impl<S, D, R> Command for Cmd<S, D, R>
where
S: BufferAccess + Send + Sync + 'static,
S: BufferAccess + 'static,
D: ImageAccess + Send + Sync + 'static,
R: IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy>,
{
@ -974,7 +974,7 @@ impl SyncCommandBufferBuilder {
) -> Result<(), SyncCommandBufferBuilderError>
where
S: ImageAccess + Send + Sync + 'static,
D: BufferAccess + Send + Sync + 'static,
D: BufferAccess + 'static,
R: IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy> + Send + Sync + 'static,
{
struct Cmd<S, D, R> {
@ -987,7 +987,7 @@ impl SyncCommandBufferBuilder {
impl<S, D, R> Command for Cmd<S, D, R>
where
S: ImageAccess + Send + Sync + 'static,
D: BufferAccess + Send + Sync + 'static,
D: BufferAccess + 'static,
R: IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy>,
{
fn name(&self) -> &'static str {
@ -1346,7 +1346,7 @@ impl SyncCommandBufferBuilder {
indirect_buffer: B,
) -> Result<(), SyncCommandBufferBuilderError>
where
B: BufferAccess + Send + Sync + 'static,
B: BufferAccess + 'static,
{
struct Cmd<B> {
descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]>,
@ -1355,7 +1355,7 @@ impl SyncCommandBufferBuilder {
impl<B> Command for Cmd<B>
where
B: BufferAccess + Send + Sync + 'static,
B: BufferAccess + 'static,
{
fn name(&self) -> &'static str {
"vkCmdDispatchIndirect"
@ -1782,7 +1782,7 @@ impl SyncCommandBufferBuilder {
stride: u32,
) -> Result<(), SyncCommandBufferBuilderError>
where
B: BufferAccess + Send + Sync + 'static,
B: BufferAccess + 'static,
{
struct Cmd<B> {
descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]>,
@ -1794,7 +1794,7 @@ impl SyncCommandBufferBuilder {
impl<B> Command for Cmd<B>
where
B: BufferAccess + Send + Sync + 'static,
B: BufferAccess + 'static,
{
fn name(&self) -> &'static str {
"vkCmdDrawIndirect"
@ -1939,7 +1939,7 @@ impl SyncCommandBufferBuilder {
stride: u32,
) -> Result<(), SyncCommandBufferBuilderError>
where
B: BufferAccess + Send + Sync + 'static,
B: BufferAccess + 'static,
{
struct Cmd<B> {
descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]>,
@ -1952,7 +1952,7 @@ impl SyncCommandBufferBuilder {
impl<B> Command for Cmd<B>
where
B: BufferAccess + Send + Sync + 'static,
B: BufferAccess + 'static,
{
fn name(&self) -> &'static str {
"vkCmdDrawIndexedIndirect"
@ -2149,7 +2149,7 @@ impl SyncCommandBufferBuilder {
#[inline]
pub unsafe fn fill_buffer<B>(&mut self, buffer: B, data: u32)
where
B: BufferAccess + Send + Sync + 'static,
B: BufferAccess + 'static,
{
struct Cmd<B> {
buffer: B,
@ -2158,7 +2158,7 @@ impl SyncCommandBufferBuilder {
impl<B> Command for Cmd<B>
where
B: BufferAccess + Send + Sync + 'static,
B: BufferAccess + 'static,
{
fn name(&self) -> &'static str {
"vkCmdFillBuffer"
@ -2706,7 +2706,7 @@ impl SyncCommandBufferBuilder {
#[inline]
pub unsafe fn update_buffer<B, D, Dd>(&mut self, buffer: B, data: Dd)
where
B: BufferAccess + Send + Sync + 'static,
B: BufferAccess + 'static,
D: ?Sized,
Dd: SafeDeref<Target = D> + Send + Sync + 'static,
{
@ -2717,7 +2717,7 @@ impl SyncCommandBufferBuilder {
impl<B, D, Dd> Command for Cmd<B, Dd>
where
B: BufferAccess + Send + Sync + 'static,
B: BufferAccess + 'static,
D: ?Sized,
Dd: SafeDeref<Target = D> + Send + Sync + 'static,
{
@ -3149,7 +3149,7 @@ impl<'b> SyncCommandBufferBuilderBindDescriptorSets<'b> {
pub struct SyncCommandBufferBuilderBindVertexBuffer<'a> {
builder: &'a mut SyncCommandBufferBuilder,
inner: UnsafeCommandBufferBuilderBindVertexBuffer,
buffers: SmallVec<[Box<dyn BufferAccess + Send + Sync>; 4]>,
buffers: SmallVec<[Box<dyn BufferAccess>; 4]>,
}
impl<'a> SyncCommandBufferBuilderBindVertexBuffer<'a> {
@ -3157,7 +3157,7 @@ impl<'a> SyncCommandBufferBuilderBindVertexBuffer<'a> {
#[inline]
pub fn add<B>(&mut self, buffer: B)
where
B: BufferAccess + Send + Sync + 'static,
B: BufferAccess + 'static,
{
self.inner.add(&buffer);
self.buffers.push(Box::new(buffer));
@ -3168,7 +3168,7 @@ impl<'a> SyncCommandBufferBuilderBindVertexBuffer<'a> {
struct Cmd {
first_set: u32,
inner: Mutex<Option<UnsafeCommandBufferBuilderBindVertexBuffer>>,
buffers: SmallVec<[Box<dyn BufferAccess + Send + Sync>; 4]>,
buffers: SmallVec<[Box<dyn BufferAccess>; 4]>,
}
impl Command for Cmd {

View File

@ -716,6 +716,7 @@ mod tests {
descriptor_count: 1,
stages: ShaderStages::all(),
mutable: false,
variable_count: false,
})],
)
.unwrap(),
@ -724,13 +725,14 @@ mod tests {
PipelineLayout::new(device.clone(), [set_layout.clone(), set_layout.clone()], [])
.unwrap(),
);
let set = Arc::new(
PersistentDescriptorSet::start(set_layout.clone())
let set = {
let mut builder = PersistentDescriptorSet::start(set_layout.clone());
builder
.add_sampler(Sampler::simple_repeat_linear(device.clone()))
.unwrap()
.build()
.unwrap(),
);
.unwrap();
Arc::new(builder.build().unwrap())
};
let mut set_builder = sync.bind_descriptor_sets();
set_builder.add(set.clone());
@ -771,13 +773,14 @@ mod tests {
)
.unwrap(),
);
let set = Arc::new(
PersistentDescriptorSet::start(set_layout.clone())
let set = {
let mut builder = PersistentDescriptorSet::start(set_layout.clone());
builder
.add_sampler(Sampler::simple_repeat_linear(device.clone()))
.unwrap()
.build()
.unwrap(),
);
.unwrap();
Arc::new(builder.build().unwrap())
};
let mut set_builder = sync.bind_descriptor_sets();
set_builder.add(set);

View File

@ -20,7 +20,7 @@ pub fn check_indirect_buffer<Inb>(
buffer: &Inb,
) -> Result<(), CheckIndirectBufferError>
where
Inb: BufferAccess + Send + Sync + 'static,
Inb: BufferAccess + 'static,
{
assert_eq!(
buffer.inner().buffer.device().internal_object(),

View File

@ -0,0 +1,579 @@
// Copyright (c) 2017 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.
use super::resources::DescriptorSetResources;
use super::DescriptorSetError;
use super::MissingBufferUsage;
use super::MissingImageUsage;
use crate::buffer::BufferView;
use crate::descriptor_set::layout::DescriptorDesc;
use crate::descriptor_set::layout::DescriptorDescImage;
use crate::descriptor_set::layout::DescriptorDescTy;
use crate::descriptor_set::sys::DescriptorWrite;
use crate::descriptor_set::BufferAccess;
use crate::descriptor_set::DescriptorSetLayout;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::image::view::ImageViewType;
use crate::image::ImageViewAbstract;
use crate::image::SampleCount;
use crate::sampler::Sampler;
use crate::VulkanObject;
use std::sync::Arc;
struct BuilderDescriptor {
desc: Option<DescriptorDesc>,
array_element: u32,
}
pub struct DescriptorSetBuilder {
layout: Arc<DescriptorSetLayout>,
in_array: bool,
descriptors: Vec<BuilderDescriptor>,
cur_binding: usize,
resources: DescriptorSetResources,
desc_writes: Vec<DescriptorWrite>,
}
pub struct DescriptorSetBuilderOutput {
pub layout: Arc<DescriptorSetLayout>,
pub writes: Vec<DescriptorWrite>,
pub resources: DescriptorSetResources,
}
impl DescriptorSetBuilder {
pub fn start(layout: Arc<DescriptorSetLayout>) -> Self {
let mut descriptors = Vec::with_capacity(layout.num_bindings() as usize);
let mut desc_writes_capacity = 0;
let mut t_num_bufs = 0;
let mut t_num_imgs = 0;
let mut t_num_samplers = 0;
for binding_i in 0..layout.num_bindings() {
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::InputAttachment { .. } => (0, 1, 0),
DescriptorDescTy::StorageImage(_) => (0, 1, 0),
DescriptorDescTy::UniformTexelBuffer { .. } => (1, 0, 0),
DescriptorDescTy::StorageTexelBuffer { .. } => (1, 0, 0),
DescriptorDescTy::UniformBuffer => (1, 0, 0),
DescriptorDescTy::StorageBuffer => (1, 0, 0),
DescriptorDescTy::UniformBufferDynamic => (1, 0, 0),
DescriptorDescTy::StorageBufferDynamic => (1, 0, 0),
};
t_num_bufs += num_bufs * descriptor_count;
t_num_imgs += num_imgs * descriptor_count;
t_num_samplers += num_samplers * descriptor_count;
desc_writes_capacity += descriptor_count;
descriptors.push(BuilderDescriptor {
desc: Some(desc),
array_element: 0,
});
} else {
descriptors.push(BuilderDescriptor {
desc: None,
array_element: 0,
});
}
}
Self {
layout,
in_array: false,
cur_binding: 0,
descriptors,
resources: DescriptorSetResources::new(t_num_bufs, t_num_imgs, t_num_samplers),
desc_writes: Vec::with_capacity(desc_writes_capacity),
}
}
pub fn output(self) -> Result<DescriptorSetBuilderOutput, DescriptorSetError> {
if self.cur_binding != self.descriptors.len() {
Err(DescriptorSetError::DescriptorsMissing {
expected: self.descriptors.len(),
obtained: self.cur_binding,
})
} else {
Ok(DescriptorSetBuilderOutput {
layout: self.layout,
writes: self.desc_writes,
resources: self.resources,
})
}
}
pub fn enter_array(&mut self) -> Result<(), DescriptorSetError> {
if self.in_array {
Err(DescriptorSetError::AlreadyInArray)
} else if self.cur_binding >= self.descriptors.len() {
Err(DescriptorSetError::TooManyDescriptors)
} else if self.descriptors[self.cur_binding].desc.is_none() {
Err(DescriptorSetError::DescriptorIsEmpty)
} else {
self.in_array = true;
Ok(())
}
}
pub fn leave_array(&mut self) -> Result<(), DescriptorSetError> {
if !self.in_array {
Err(DescriptorSetError::NotInArray)
} else {
let descriptor = &self.descriptors[self.cur_binding];
let inner_desc = match descriptor.desc.as_ref() {
Some(some) => some,
None => unreachable!(),
};
if inner_desc.variable_count {
if descriptor.array_element > inner_desc.descriptor_count {
return Err(DescriptorSetError::ArrayTooManyDescriptors {
capacity: inner_desc.descriptor_count,
obtained: descriptor.array_element,
});
}
} else if descriptor.array_element != inner_desc.descriptor_count {
return Err(DescriptorSetError::ArrayLengthMismatch {
expected: inner_desc.descriptor_count,
obtained: descriptor.array_element,
});
}
self.in_array = false;
self.cur_binding += 1;
Ok(())
}
}
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() {
return Err(DescriptorSetError::WrongDescriptorType);
}
self.cur_binding += 1;
Ok(())
}
pub fn add_buffer(
&mut self,
buffer: Arc<dyn BufferAccess + 'static>,
) -> Result<(), DescriptorSetError> {
if buffer.inner().buffer.device().internal_object()
!= self.layout.device().internal_object()
{
return Err(DescriptorSetError::ResourceWrongDevice);
}
let leave_array = if !self.in_array {
self.enter_array()?;
true
} else {
false
};
let descriptor = &mut self.descriptors[self.cur_binding];
let inner_desc = match descriptor.desc.as_ref() {
Some(some) => some,
None => return Err(DescriptorSetError::WrongDescriptorType),
};
// Note that the buffer content is not checked. This is technically not unsafe as
// long as the data in the buffer has no invalid memory representation (ie. no
// bool, no enum, no pointer, no str) and as long as the robust buffer access
// feature is enabled.
// TODO: this is not checked ^
// TODO: eventually shouldn't be an assert ; for now robust_buffer_access is always
// enabled so this assert should never fail in practice, but we put it anyway
// in case we forget to adjust this code
self.desc_writes.push(match inner_desc.ty {
DescriptorDescTy::StorageBuffer | DescriptorDescTy::StorageBufferDynamic => {
assert!(self.layout.device().enabled_features().robust_buffer_access);
if !buffer.inner().buffer.usage().storage_buffer {
return Err(DescriptorSetError::MissingBufferUsage(
MissingBufferUsage::StorageBuffer,
));
}
unsafe {
DescriptorWrite::storage_buffer(
self.cur_binding as u32,
descriptor.array_element,
&buffer,
)
}
}
DescriptorDescTy::UniformBuffer => {
assert!(self.layout.device().enabled_features().robust_buffer_access);
if !buffer.inner().buffer.usage().uniform_buffer {
return Err(DescriptorSetError::MissingBufferUsage(
MissingBufferUsage::UniformBuffer,
));
}
unsafe {
DescriptorWrite::uniform_buffer(
self.cur_binding as u32,
descriptor.array_element,
&buffer,
)
}
}
DescriptorDescTy::UniformBufferDynamic => {
assert!(self.layout.device().enabled_features().robust_buffer_access);
if !buffer.inner().buffer.usage().uniform_buffer {
return Err(DescriptorSetError::MissingBufferUsage(
MissingBufferUsage::UniformBuffer,
));
}
unsafe {
DescriptorWrite::dynamic_uniform_buffer(
self.cur_binding as u32,
descriptor.array_element,
&buffer,
)
}
}
_ => return Err(DescriptorSetError::WrongDescriptorType),
});
self.resources.add_buffer(self.cur_binding as u32, buffer);
descriptor.array_element += 1;
if leave_array {
self.leave_array()
} else {
Ok(())
}
}
pub fn add_buffer_view<B>(&mut self, view: Arc<BufferView<B>>) -> Result<(), DescriptorSetError>
where
B: BufferAccess + 'static,
{
if view.device().internal_object() != self.layout.device().internal_object() {
return Err(DescriptorSetError::ResourceWrongDevice);
}
let leave_array = if !self.in_array {
self.enter_array()?;
true
} else {
false
};
let descriptor = &mut self.descriptors[self.cur_binding];
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::StorageTexelBuffer { .. } => {
// TODO: storage_texel_buffer_atomic
if !view.storage_texel_buffer() {
return Err(DescriptorSetError::MissingBufferUsage(
MissingBufferUsage::StorageTexelBuffer,
));
}
DescriptorWrite::storage_texel_buffer(
self.cur_binding as u32,
descriptor.array_element,
&view,
)
}
DescriptorDescTy::UniformTexelBuffer { .. } => {
if !view.uniform_texel_buffer() {
return Err(DescriptorSetError::MissingBufferUsage(
MissingBufferUsage::UniformTexelBuffer,
));
}
DescriptorWrite::uniform_texel_buffer(
self.cur_binding as u32,
descriptor.array_element,
&view,
)
}
_ => return Err(DescriptorSetError::WrongDescriptorType),
});
self.resources
.add_buffer_view(self.cur_binding as u32, view);
if leave_array {
self.leave_array()
} else {
Ok(())
}
}
pub fn add_image(
&mut self,
image_view: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
) -> Result<(), DescriptorSetError> {
if image_view.image().inner().image.device().internal_object()
!= self.layout.device().internal_object()
{
return Err(DescriptorSetError::ResourceWrongDevice);
}
let leave_array = if !self.in_array {
self.enter_array()?;
true
} else {
false
};
let descriptor = &mut self.descriptors[self.cur_binding];
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) => {
if !image_view.image().inner().image.usage().sampled {
return Err(DescriptorSetError::MissingImageUsage(
MissingImageUsage::Sampled,
));
}
image_match_desc(&image_view, &desc)?;
DescriptorWrite::sampled_image(
self.cur_binding as u32,
descriptor.array_element,
&image_view,
)
}
DescriptorDescTy::StorageImage(ref desc) => {
if !image_view.image().inner().image.usage().storage {
return Err(DescriptorSetError::MissingImageUsage(
MissingImageUsage::Storage,
));
}
image_match_desc(&image_view, &desc)?;
if !image_view.component_mapping().is_identity() {
return Err(DescriptorSetError::NotIdentitySwizzled);
}
DescriptorWrite::storage_image(
self.cur_binding as u32,
descriptor.array_element,
&image_view,
)
}
DescriptorDescTy::InputAttachment { multisampled } => {
if !image_view.image().inner().image.usage().input_attachment {
return Err(DescriptorSetError::MissingImageUsage(
MissingImageUsage::InputAttachment,
));
}
if !image_view.component_mapping().is_identity() {
return Err(DescriptorSetError::NotIdentitySwizzled);
}
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);
}
let image_layers = image_view.array_layers();
let num_layers = image_layers.end - image_layers.start;
if image_view.ty().is_arrayed() {
return Err(DescriptorSetError::UnexpectedArrayed);
}
DescriptorWrite::input_attachment(
self.cur_binding as u32,
descriptor.array_element,
&image_view,
)
}
_ => return Err(DescriptorSetError::WrongDescriptorType),
});
descriptor.array_element += 1;
self.resources
.add_image(self.cur_binding as u32, image_view);
if leave_array {
self.leave_array()
} else {
Ok(())
}
}
pub fn add_sampled_image(
&mut self,
image_view: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
sampler: Arc<Sampler>,
) -> Result<(), DescriptorSetError> {
if image_view.image().inner().image.device().internal_object()
!= self.layout.device().internal_object()
{
return Err(DescriptorSetError::ResourceWrongDevice);
}
if sampler.device().internal_object() != self.layout.device().internal_object() {
return Err(DescriptorSetError::ResourceWrongDevice);
}
if !image_view.image().inner().image.usage().sampled {
return Err(DescriptorSetError::MissingImageUsage(
MissingImageUsage::Sampled,
));
}
if !image_view.can_be_sampled(&sampler) {
return Err(DescriptorSetError::IncompatibleImageViewSampler);
}
let leave_array = if !self.in_array {
self.enter_array()?;
true
} else {
false
};
let descriptor = &mut self.descriptors[self.cur_binding];
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)?;
DescriptorWrite::combined_image_sampler(
self.cur_binding as u32,
descriptor.array_element,
&sampler,
&image_view,
)
}
_ => return Err(DescriptorSetError::WrongDescriptorType),
});
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);
if leave_array {
self.leave_array()
} else {
Ok(())
}
}
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);
}
let leave_array = if !self.in_array {
self.enter_array()?;
true
} else {
false
};
let descriptor = &mut self.descriptors[self.cur_binding];
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,
),
_ => return Err(DescriptorSetError::WrongDescriptorType),
});
descriptor.array_element += 1;
self.resources.add_sampler(self.cur_binding as u32, sampler);
if leave_array {
self.leave_array()
} else {
Ok(())
}
}
}
unsafe impl DeviceOwned for DescriptorSetBuilder {
fn device(&self) -> &Arc<Device> {
self.layout.device()
}
}
// Checks whether an image view matches the descriptor.
fn image_match_desc<I>(image_view: &I, desc: &DescriptorDescImage) -> Result<(), DescriptorSetError>
where
I: ?Sized + ImageViewAbstract,
{
if image_view.ty() != desc.view_type
&& match desc.view_type {
ImageViewType::Dim1dArray => image_view.ty() != ImageViewType::Dim1d,
ImageViewType::Dim2dArray => image_view.ty() != ImageViewType::Dim2d,
ImageViewType::CubeArray => image_view.ty() != ImageViewType::Cube,
_ => true,
}
{
return Err(DescriptorSetError::ImageViewTypeMismatch {
expected: desc.view_type,
obtained: image_view.ty(),
});
}
if let Some(format) = desc.format {
if image_view.format() != format {
return Err(DescriptorSetError::ImageViewFormatMismatch {
expected: format,
obtained: image_view.format(),
});
}
}
if desc.multisampled && image_view.image().samples() == SampleCount::Sample1 {
return Err(DescriptorSetError::ExpectedMultisampled);
} else if !desc.multisampled && image_view.image().samples() != SampleCount::Sample1 {
return Err(DescriptorSetError::UnexpectedMultisampled);
}
Ok(())
}

View File

@ -1,604 +0,0 @@
// Copyright (c) 2017 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.
//! Pool of descriptor sets of a specific capacity that are automatically reclaimed.
//!
//! You are encouraged to use this type when you need a different descriptor set at each frame, or
//! regularly during the execution.
//!
//! # Example
//!
//! At initialization, create a `FixedSizeDescriptorSetsPool`.
//!
//! ```rust
//! use vulkano::descriptor_set::FixedSizeDescriptorSetsPool;
//! # use vulkano::pipeline::GraphicsPipeline;
//! # use std::sync::Arc;
//! # let graphics_pipeline: Arc<GraphicsPipeline> = return;
//! // use vulkano::pipeline::GraphicsPipeline;
//! // let graphics_pipeline: Arc<GraphicsPipeline> = ...;
//!
//! let layout = graphics_pipeline.layout().descriptor_set_layouts().get(0).unwrap();
//! let pool = FixedSizeDescriptorSetsPool::new(layout.clone());
//! ```
//!
//! You would then typically store the pool in a struct for later. Then whenever you need a
//! descriptor set, call `pool.next()` to start the process of building it.
//!
//! ```rust
//! # use std::sync::Arc;
//! # use vulkano::descriptor_set::FixedSizeDescriptorSetsPool;
//! # use vulkano::pipeline::GraphicsPipeline;
//! # let mut pool: FixedSizeDescriptorSetsPool = return;
//! let descriptor_set = pool.next()
//! //.add_buffer(...)
//! //.add_sampled_image(...)
//! .build().unwrap();
//! ```
//!
//! Note that `next()` requires exclusive (`mut`) access to the pool. You can use a `Mutex` around
//! the pool if you can't provide this.
use crate::buffer::BufferAccess;
use crate::buffer::BufferViewRef;
use crate::descriptor_set::layout::DescriptorSetLayout;
use crate::descriptor_set::persistent::*;
use crate::descriptor_set::pool::DescriptorPool;
use crate::descriptor_set::pool::DescriptorPoolAlloc;
use crate::descriptor_set::pool::DescriptorPoolAllocError;
use crate::descriptor_set::pool::UnsafeDescriptorPool;
use crate::descriptor_set::DescriptorSet;
use crate::descriptor_set::UnsafeDescriptorSet;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::image::view::ImageViewAbstract;
use crate::sampler::Sampler;
use crate::OomError;
use crate::VulkanObject;
use crossbeam_queue::SegQueue;
use std::hash::Hash;
use std::hash::Hasher;
use std::sync::Arc;
/// Pool of descriptor sets of a specific capacity that are automatically reclaimed.
#[derive(Clone)]
pub struct FixedSizeDescriptorSetsPool {
layout: Arc<DescriptorSetLayout>,
// We hold a local implementation of the `DescriptorPool` trait for our own purpose. Since we
// don't want to expose this trait impl in our API, we use a separate struct.
pool: LocalPool,
}
impl FixedSizeDescriptorSetsPool {
/// Initializes a new pool. The pool is configured to allocate sets that corresponds to the
/// parameters passed to this function.
pub fn new(layout: Arc<DescriptorSetLayout>) -> FixedSizeDescriptorSetsPool {
let device = layout.device().clone();
FixedSizeDescriptorSetsPool {
layout,
pool: LocalPool {
device,
next_capacity: 3,
current_pool: None,
},
}
}
/// Starts the process of building a new descriptor set.
///
/// The set will corresponds to the set layout that was passed to `new`.
#[inline]
pub fn next(&mut self) -> FixedSizeDescriptorSetBuilder<()> {
let inner = PersistentDescriptorSet::start(self.layout.clone());
FixedSizeDescriptorSetBuilder { pool: self, inner }
}
}
/// A descriptor set created from a `FixedSizeDescriptorSetsPool`.
pub struct FixedSizeDescriptorSet<R> {
inner: PersistentDescriptorSet<R, LocalPoolAlloc>,
}
unsafe impl<R> DescriptorSet for FixedSizeDescriptorSet<R>
where
R: PersistentDescriptorSetResources,
{
#[inline]
fn inner(&self) -> &UnsafeDescriptorSet {
self.inner.inner()
}
#[inline]
fn layout(&self) -> &Arc<DescriptorSetLayout> {
self.inner.layout()
}
#[inline]
fn num_buffers(&self) -> usize {
self.inner.num_buffers()
}
#[inline]
fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> {
self.inner.buffer(index)
}
#[inline]
fn num_images(&self) -> usize {
self.inner.num_images()
}
#[inline]
fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
self.inner.image(index)
}
}
unsafe impl<R> DeviceOwned for FixedSizeDescriptorSet<R> {
#[inline]
fn device(&self) -> &Arc<Device> {
self.inner.device()
}
}
impl<R> PartialEq for FixedSizeDescriptorSet<R>
where
R: PersistentDescriptorSetResources,
{
#[inline]
fn eq(&self, other: &Self) -> bool {
self.inner().internal_object() == other.inner().internal_object()
&& self.device() == other.device()
}
}
impl<R> Eq for FixedSizeDescriptorSet<R> where R: PersistentDescriptorSetResources {}
impl<R> Hash for FixedSizeDescriptorSet<R>
where
R: PersistentDescriptorSetResources,
{
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.inner().internal_object().hash(state);
self.device().hash(state);
}
}
// The fields of this struct can be considered as fields of the `FixedSizeDescriptorSet`. They are
// in a separate struct because we don't want to expose the fact that we implement the
// `DescriptorPool` trait.
#[derive(Clone)]
struct LocalPool {
// The `LocalPoolInner` struct contains an actual Vulkan pool. Every time it is full, we create
// a new pool and replace the current one with the new one.
current_pool: Option<Arc<LocalPoolInner>>,
// Capacity to use when we create a new Vulkan pool.
next_capacity: u32,
// The Vulkan device.
device: Arc<Device>,
}
struct LocalPoolInner {
// The actual Vulkan descriptor pool. This field isn't actually used anywhere, but we need to
// keep the pool alive in order to keep the descriptor sets valid.
actual_pool: UnsafeDescriptorPool,
// List of descriptor sets. When `alloc` is called, a descriptor will be extracted from this
// list. When a `LocalPoolAlloc` is dropped, its descriptor set is put back in this list.
reserve: SegQueue<UnsafeDescriptorSet>,
}
struct LocalPoolAlloc {
// The `LocalPoolInner` we were allocated from. We need to keep a copy of it in each allocation
// so that we can put back the allocation in the list in our `Drop` impl.
pool: Arc<LocalPoolInner>,
// The actual descriptor set, wrapped inside an `Option` so that we can extract it in our
// `Drop` impl.
actual_alloc: Option<UnsafeDescriptorSet>,
}
unsafe impl DescriptorPool for LocalPool {
type Alloc = LocalPoolAlloc;
fn alloc(&mut self, layout: &DescriptorSetLayout) -> Result<Self::Alloc, OomError> {
loop {
// Try to extract a descriptor from the current pool if any exist.
// This is the most common case.
if let Some(ref mut current_pool) = self.current_pool {
if let Some(already_existing_set) = current_pool.reserve.pop() {
return Ok(LocalPoolAlloc {
actual_alloc: Some(already_existing_set),
pool: current_pool.clone(),
});
}
}
// If we failed to grab an existing set, that means the current pool is full. Create a
// new one of larger capacity.
let count = *layout.descriptors_count() * self.next_capacity;
let mut new_pool =
UnsafeDescriptorPool::new(self.device.clone(), &count, self.next_capacity, false)?;
let alloc = unsafe {
match new_pool.alloc((0..self.next_capacity).map(|_| layout)) {
Ok(iter) => {
let stack = SegQueue::new();
for elem in iter {
stack.push(elem);
}
stack
}
Err(DescriptorPoolAllocError::OutOfHostMemory) => {
return Err(OomError::OutOfHostMemory);
}
Err(DescriptorPoolAllocError::OutOfDeviceMemory) => {
return Err(OomError::OutOfDeviceMemory);
}
Err(DescriptorPoolAllocError::FragmentedPool) => {
// This can't happen as we don't free individual sets.
unreachable!()
}
Err(DescriptorPoolAllocError::OutOfPoolMemory) => unreachable!(),
}
};
self.next_capacity = self.next_capacity.saturating_mul(2);
self.current_pool = Some(Arc::new(LocalPoolInner {
actual_pool: new_pool,
reserve: alloc,
}));
}
}
}
unsafe impl DeviceOwned for LocalPool {
#[inline]
fn device(&self) -> &Arc<Device> {
&self.device
}
}
impl DescriptorPoolAlloc for LocalPoolAlloc {
#[inline]
fn inner(&self) -> &UnsafeDescriptorSet {
self.actual_alloc.as_ref().unwrap()
}
#[inline]
fn inner_mut(&mut self) -> &mut UnsafeDescriptorSet {
self.actual_alloc.as_mut().unwrap()
}
}
impl Drop for LocalPoolAlloc {
fn drop(&mut self) {
let inner = self.actual_alloc.take().unwrap();
self.pool.reserve.push(inner);
}
}
/// Prototype of a `FixedSizeDescriptorSet`.
///
/// The template parameter `R` is an unspecified type that represents the list of resources.
///
/// See the docs of `FixedSizeDescriptorSetsPool` for an example.
pub struct FixedSizeDescriptorSetBuilder<'a, R> {
pool: &'a mut FixedSizeDescriptorSetsPool,
inner: PersistentDescriptorSetBuilder<R>,
}
impl<'a, R> FixedSizeDescriptorSetBuilder<'a, R> {
/// Builds a `FixedSizeDescriptorSet` from the builder.
#[inline]
pub fn build(self) -> Result<FixedSizeDescriptorSet<R>, PersistentDescriptorSetBuildError> {
let inner = self.inner.build_with_pool(&mut self.pool.pool)?;
Ok(FixedSizeDescriptorSet { inner })
}
/// Call this function if the next element of the set is an array in order to set the value of
/// each element.
///
/// Returns an error if the descriptor is empty.
///
/// 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.
#[inline]
pub fn enter_array(
self,
) -> Result<FixedSizeDescriptorSetBuilderArray<'a, R>, PersistentDescriptorSetError> {
Ok(FixedSizeDescriptorSetBuilderArray {
pool: self.pool,
inner: self.inner.enter_array()?,
})
}
/// Skips the current descriptor if it is empty.
#[inline]
pub fn add_empty(
self,
) -> Result<FixedSizeDescriptorSetBuilder<'a, R>, PersistentDescriptorSetError> {
Ok(FixedSizeDescriptorSetBuilder {
pool: self.pool,
inner: self.inner.add_empty()?,
})
}
/// Binds a buffer as the next descriptor.
///
/// An error is returned if the buffer isn't compatible with the descriptor.
///
/// # Panic
///
/// Panics if the buffer doesn't have the same device as the descriptor set layout.
///
#[inline]
pub fn add_buffer<T>(
self,
buffer: T,
) -> Result<
FixedSizeDescriptorSetBuilder<'a, (R, PersistentDescriptorSetBuf<T>)>,
PersistentDescriptorSetError,
>
where
T: BufferAccess,
{
Ok(FixedSizeDescriptorSetBuilder {
pool: self.pool,
inner: self.inner.add_buffer(buffer)?,
})
}
/// Binds a buffer view as the next descriptor.
///
/// An error is returned if the buffer isn't compatible with the descriptor.
///
/// # Panic
///
/// Panics if the buffer view doesn't have the same device as the descriptor set layout.
///
pub fn add_buffer_view<T>(
self,
view: T,
) -> Result<
FixedSizeDescriptorSetBuilder<'a, (R, PersistentDescriptorSetBufView<T>)>,
PersistentDescriptorSetError,
>
where
T: BufferViewRef,
{
Ok(FixedSizeDescriptorSetBuilder {
pool: self.pool,
inner: self.inner.add_buffer_view(view)?,
})
}
/// Binds an image view as the next descriptor.
///
/// An error is returned if the image view isn't compatible with the descriptor.
///
/// # Panic
///
/// Panics if the image view doesn't have the same device as the descriptor set layout.
///
#[inline]
pub fn add_image<T>(
self,
image_view: T,
) -> Result<
FixedSizeDescriptorSetBuilder<'a, (R, PersistentDescriptorSetImg<T>)>,
PersistentDescriptorSetError,
>
where
T: ImageViewAbstract,
{
Ok(FixedSizeDescriptorSetBuilder {
pool: self.pool,
inner: self.inner.add_image(image_view)?,
})
}
/// Binds an image view with a sampler as the next descriptor.
///
/// An error is returned if the image view isn't compatible with the descriptor.
///
/// # Panic
///
/// Panics if the image view or the sampler doesn't have the same device as the descriptor set layout.
///
#[inline]
pub fn add_sampled_image<T>(
self,
image_view: T,
sampler: Arc<Sampler>,
) -> Result<
FixedSizeDescriptorSetBuilder<
'a,
(
(R, PersistentDescriptorSetImg<T>),
PersistentDescriptorSetSampler,
),
>,
PersistentDescriptorSetError,
>
where
T: ImageViewAbstract,
{
Ok(FixedSizeDescriptorSetBuilder {
pool: self.pool,
inner: self.inner.add_sampled_image(image_view, sampler)?,
})
}
/// Binds a sampler as the next descriptor.
///
/// An error is returned if the sampler isn't compatible with the descriptor.
///
/// # Panic
///
/// Panics if the sampler doesn't have the same device as the descriptor set layout.
///
#[inline]
pub fn add_sampler(
self,
sampler: Arc<Sampler>,
) -> Result<
FixedSizeDescriptorSetBuilder<'a, (R, PersistentDescriptorSetSampler)>,
PersistentDescriptorSetError,
> {
Ok(FixedSizeDescriptorSetBuilder {
pool: self.pool,
inner: self.inner.add_sampler(sampler)?,
})
}
}
/// Same as `FixedSizeDescriptorSetBuilder`, but we're in an array.
pub struct FixedSizeDescriptorSetBuilderArray<'a, R> {
pool: &'a mut FixedSizeDescriptorSetsPool,
inner: PersistentDescriptorSetBuilderArray<R>,
}
impl<'a, R> FixedSizeDescriptorSetBuilderArray<'a, R> {
/// Leaves the array. Call this once you added all the elements of the array.
pub fn leave_array(
self,
) -> Result<FixedSizeDescriptorSetBuilder<'a, R>, PersistentDescriptorSetError> {
Ok(FixedSizeDescriptorSetBuilder {
pool: self.pool,
inner: self.inner.leave_array()?,
})
}
/// Binds a buffer as the next element in the array.
///
/// An error is returned if the buffer isn't compatible with the descriptor.
///
/// # Panic
///
/// Panics if the buffer doesn't have the same device as the descriptor set layout.
///
pub fn add_buffer<T>(
self,
buffer: T,
) -> Result<
FixedSizeDescriptorSetBuilderArray<'a, (R, PersistentDescriptorSetBuf<T>)>,
PersistentDescriptorSetError,
>
where
T: BufferAccess,
{
Ok(FixedSizeDescriptorSetBuilderArray {
pool: self.pool,
inner: self.inner.add_buffer(buffer)?,
})
}
/// Binds a buffer view as the next element in the array.
///
/// An error is returned if the buffer isn't compatible with the descriptor.
///
/// # Panic
///
/// Panics if the buffer view doesn't have the same device as the descriptor set layout.
///
pub fn add_buffer_view<T>(
self,
view: T,
) -> Result<
FixedSizeDescriptorSetBuilderArray<'a, (R, PersistentDescriptorSetBufView<T>)>,
PersistentDescriptorSetError,
>
where
T: BufferViewRef,
{
Ok(FixedSizeDescriptorSetBuilderArray {
pool: self.pool,
inner: self.inner.add_buffer_view(view)?,
})
}
/// Binds an image view as the next element in the array.
///
/// An error is returned if the image view isn't compatible with the descriptor.
///
/// # Panic
///
/// Panics if the image view doesn't have the same device as the descriptor set layout.
///
pub fn add_image<T>(
self,
image_view: T,
) -> Result<
FixedSizeDescriptorSetBuilderArray<'a, (R, PersistentDescriptorSetImg<T>)>,
PersistentDescriptorSetError,
>
where
T: ImageViewAbstract,
{
Ok(FixedSizeDescriptorSetBuilderArray {
pool: self.pool,
inner: self.inner.add_image(image_view)?,
})
}
/// Binds an image view with a sampler as the next element in the array.
///
/// An error is returned if the image view isn't compatible with the descriptor.
///
/// # Panic
///
/// Panics if the image or the sampler doesn't have the same device as the descriptor set layout.
///
pub fn add_sampled_image<T>(
self,
image_view: T,
sampler: Arc<Sampler>,
) -> Result<
FixedSizeDescriptorSetBuilderArray<
'a,
(
(R, PersistentDescriptorSetImg<T>),
PersistentDescriptorSetSampler,
),
>,
PersistentDescriptorSetError,
>
where
T: ImageViewAbstract,
{
Ok(FixedSizeDescriptorSetBuilderArray {
pool: self.pool,
inner: self.inner.add_sampled_image(image_view, sampler)?,
})
}
/// Binds a sampler as the next element in the array.
///
/// An error is returned if the sampler isn't compatible with the descriptor.
///
/// # Panic
///
/// Panics if the sampler doesn't have the same device as the descriptor set layout.
///
pub fn add_sampler(
self,
sampler: Arc<Sampler>,
) -> Result<
FixedSizeDescriptorSetBuilderArray<'a, (R, PersistentDescriptorSetSampler)>,
PersistentDescriptorSetError,
> {
Ok(FixedSizeDescriptorSetBuilderArray {
pool: self.pool,
inner: self.inner.add_sampler(sampler)?,
})
}
}

View File

@ -187,6 +187,24 @@ impl DescriptorSetDesc {
}
}
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")
}
}
None => panic!("descriptor is empty"),
},
None => panic!("descriptor doesn't exist"),
}
}
/// Returns whether `self` is compatible with `other`.
///
/// "Compatible" in this sense is defined by the Vulkan specification under the section
@ -319,6 +337,9 @@ pub struct DescriptorDesc {
/// Which shader stages are going to access this descriptor.
pub stages: ShaderStages,
/// True if the descriptor has a variable descriptor count.
pub variable_count: bool,
/// True if the attachment can be written by the shader.
pub mutable: bool,
}
@ -332,8 +353,9 @@ impl DescriptorDesc {
#[inline]
pub fn is_compatible_with(&self, other: &DescriptorDesc) -> bool {
self.ty.ty() == other.ty.ty()
&& self.descriptor_count == other.descriptor_count
&& self.stages == other.stages
&& self.descriptor_count == other.descriptor_count
&& self.variable_count == other.variable_count
}
/// Checks whether the descriptor of a pipeline layout `self` is compatible with the descriptor
@ -363,6 +385,13 @@ impl DescriptorDesc {
});
}
if self.variable_count != other.variable_count {
return Err(DescriptorCompatibilityError::VariableCount {
first: self.variable_count,
second: other.variable_count,
});
}
if !self.mutable && other.mutable {
return Err(DescriptorCompatibilityError::Mutability {
first: self.mutable,
@ -396,6 +425,13 @@ impl DescriptorDesc {
});
}
if self.variable_count != other.variable_count {
return Err(DescriptorCompatibilityError::VariableCount {
first: self.variable_count,
second: other.variable_count,
});
}
if self.mutable && !other.mutable {
return Err(DescriptorCompatibilityError::Mutability {
first: self.mutable,
@ -426,7 +462,7 @@ impl DescriptorDesc {
/// geometry: true,
/// fragment: false,
/// compute: true
///}, mutable: true };
///}, mutable: true, variable_count: false };
///
///let desc_part2 = DescriptorDesc{ ty: Sampler, descriptor_count: 1, stages: ShaderStages{
/// vertex: true,
@ -435,7 +471,7 @@ impl DescriptorDesc {
/// geometry: false,
/// fragment: true,
/// compute: true
///}, mutable: false };
///}, mutable: false, variable_count: false };
///
///let desc_union = DescriptorDesc{ ty: Sampler, descriptor_count: 2, stages: ShaderStages{
/// vertex: true,
@ -444,7 +480,7 @@ impl DescriptorDesc {
/// geometry: true,
/// fragment: true,
/// compute: true
///}, mutable: true };
///}, mutable: true, variable_count: false };
///
///assert_eq!(DescriptorDesc::union(Some(&desc_part1), Some(&desc_part2)), Ok(Some(desc_union)));
///```
@ -463,6 +499,7 @@ impl DescriptorDesc {
descriptor_count: cmp::max(first.descriptor_count, second.descriptor_count),
stages: first.stages | second.stages,
mutable: first.mutable || second.mutable,
variable_count: first.variable_count && second.variable_count, // TODO: What is the correct behavior here?
}))
} else {
Ok(first.or(second).cloned())
@ -750,6 +787,12 @@ pub enum DescriptorCompatibilityError {
second: u32,
},
/// The variable counts of the descriptors is not compatible.
VariableCount {
first: bool,
second: bool,
},
/// The presence or absence of a descriptor in a binding is not compatible.
Empty {
first: bool,
@ -805,6 +848,9 @@ impl fmt::Display for DescriptorCompatibilityError {
DescriptorCompatibilityError::DescriptorCount { .. } => {
"the number of descriptors is not compatible"
}
DescriptorCompatibilityError::VariableCount { .. } => {
"the variable counts of the descriptors is not compatible"
}
DescriptorCompatibilityError::Empty { .. } => {
"the presence or absence of a descriptor in a binding is not compatible"
}

View File

@ -21,6 +21,7 @@ pub use self::desc::DescriptorSetCompatibilityError;
pub use self::desc::DescriptorSetDesc;
pub use self::desc::DescriptorType;
pub use self::sys::DescriptorSetLayout;
pub use self::sys::DescriptorSetLayoutError;
mod desc;
mod sys;

View File

@ -9,12 +9,14 @@
use crate::check_errors;
use crate::descriptor_set::layout::DescriptorDesc;
use crate::descriptor_set::layout::DescriptorDescTy;
use crate::descriptor_set::layout::DescriptorSetCompatibilityError;
use crate::descriptor_set::layout::DescriptorSetDesc;
use crate::descriptor_set::pool::DescriptorsCount;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::OomError;
use crate::Version;
use crate::VulkanObject;
use smallvec::SmallVec;
use std::mem::MaybeUninit;
@ -40,58 +42,151 @@ impl DescriptorSetLayout {
/// The descriptors must be passed in the order of the bindings. In order words, descriptor
/// at bind point 0 first, then descriptor at bind point 1, and so on. If a binding must remain
/// empty, you can make the iterator yield `None` for an element.
pub fn new<D>(device: Arc<Device>, desc: D) -> Result<DescriptorSetLayout, OomError>
pub fn new<D>(
device: Arc<Device>,
desc: D,
) -> Result<DescriptorSetLayout, DescriptorSetLayoutError>
where
D: Into<DescriptorSetDesc>,
{
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 bindings = desc
.bindings()
.iter()
.enumerate()
.filter_map(|(binding, desc)| {
let desc = match desc {
Some(d) => d,
None => return None,
};
for (binding, desc) in bindings.iter().enumerate() {
let desc = match desc {
Some(d) => d,
None => continue,
};
// FIXME: it is not legal to pass eg. the TESSELLATION_SHADER bit when the device
// doesn't have tess shaders enabled
// FIXME: it is not legal to pass eg. the TESSELLATION_SHADER bit when the device
// doesn't have tess shaders enabled
let ty = desc.ty.ty();
descriptors_count.add_num(ty, desc.descriptor_count);
let ty = desc.ty.ty();
descriptors_count.add_num(ty, desc.descriptor_count);
Some(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
})
})
.collect::<SmallVec<[_; 32]>>();
if desc.variable_count {
if binding != bindings.len() - 1 {
return Err(DescriptorSetLayoutError::VariableCountDescMustBeLast);
}
if desc.ty == DescriptorDescTy::UniformBufferDynamic
|| desc.ty == DescriptorDescTy::StorageBufferDynamic
{
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 {
let infos = ash::vk::DescriptorSetLayoutCreateInfo {
flags: ash::vk::DescriptorSetLayoutCreateFlags::empty(),
binding_count: bindings.len() as u32,
p_bindings: bindings.as_ptr(),
..Default::default()
};
if variable_descriptor_count {
let enabled_features = device.enabled_features();
let api_version = device.api_version();
let enabled_extensions = device.enabled_extensions();
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(),
))?;
output.assume_init()
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 {
return Err(DescriptorSetLayoutError::VariableCountIncompatibleDevice(
IncompatibleDevice::MissingFeature(MissingFeature::RuntimeDescriptorArray),
));
}
if !enabled_features.descriptor_binding_variable_descriptor_count {
return Err(DescriptorSetLayoutError::VariableCountIncompatibleDevice(
IncompatibleDevice::MissingFeature(
MissingFeature::DescriptorBindingVariableDescriptorCount,
),
));
}
if !enabled_features.descriptor_binding_partially_bound {
return Err(DescriptorSetLayoutError::VariableCountIncompatibleDevice(
IncompatibleDevice::MissingFeature(
MissingFeature::DescriptorBindingPartiallyBound,
),
));
}
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()
}
};
Ok(DescriptorSetLayout {
@ -182,6 +277,77 @@ impl Drop for DescriptorSetLayout {
}
}
/// Error related to descriptor set layout
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DescriptorSetLayoutError {
/// Out of Memory
OomError(OomError),
/// Variable count descriptor must be last binding
VariableCountDescMustBeLast,
/// Variable count descriptor must not be a dynamic buffer
VariableCountDescMustNotBeDynamic,
/// Device is not compatible with variable count descriptors
VariableCountIncompatibleDevice(IncompatibleDevice),
}
// Part of the DescriptorSetLayoutError for the case
// of missing features on a device.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IncompatibleDevice {
MissingExtension(MissingExtension),
MissingFeature(MissingFeature),
InsufficientApiVersion {
required: Version,
obtained: Version,
},
}
// Part of the IncompatibleDevice for the case
// of missing features on a device.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MissingFeature {
RuntimeDescriptorArray,
DescriptorBindingVariableDescriptorCount,
DescriptorBindingPartiallyBound,
}
// Part of the IncompatibleDevice for the case
// of missing extensions on a device.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum MissingExtension {
DescriptorIndexing,
}
impl From<OomError> for DescriptorSetLayoutError {
fn from(error: OomError) -> Self {
Self::OomError(error)
}
}
impl std::error::Error for DescriptorSetLayoutError {}
impl std::fmt::Display for DescriptorSetLayoutError {
#[inline]
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
write!(
fmt,
"{}",
match *self {
Self::OomError(_) => "out of memory",
Self::VariableCountDescMustBeLast =>
"variable count descriptor must be last binding",
Self::VariableCountDescMustNotBeDynamic =>
"variable count descriptor must not be a dynamic buffer",
Self::VariableCountIncompatibleDevice(_) =>
"device is not compatible with variable count descriptors",
}
)
}
}
#[cfg(test)]
mod tests {
use crate::descriptor_set::layout::DescriptorDesc;
@ -207,6 +373,7 @@ mod tests {
descriptor_count: 1,
stages: ShaderStages::all_graphics(),
mutable: false,
variable_count: false,
};
let sl = DescriptorSetLayout::new(

View File

@ -74,28 +74,33 @@
//! `DescriptorSet`. It is what you pass to the draw functions.
pub use self::collection::DescriptorSetsCollection;
pub use self::fixed_size_pool::FixedSizeDescriptorSetsPool;
use self::layout::DescriptorSetLayout;
pub use self::persistent::PersistentDescriptorSet;
pub use self::persistent::PersistentDescriptorSetBuildError;
pub use self::persistent::PersistentDescriptorSetError;
pub use self::single_layout_pool::SingleLayoutDescSetPool;
use self::sys::UnsafeDescriptorSet;
use crate::buffer::BufferAccess;
use crate::descriptor_set::layout::DescriptorDescTy;
use crate::device::DeviceOwned;
use crate::format::Format;
use crate::image::view::ImageViewAbstract;
use crate::image::view::ImageViewType;
use crate::OomError;
use crate::SafeDeref;
use crate::VulkanObject;
use smallvec::SmallVec;
use std::error;
use std::fmt;
use std::hash::Hash;
use std::hash::Hasher;
use std::sync::Arc;
mod builder;
mod collection;
pub mod fixed_size_pool;
pub mod layout;
pub mod persistent;
pub mod pool;
mod resources;
pub mod single_layout_pool;
pub mod sys;
/// Trait for objects that contain a collection of resources that will be accessible by shaders.
@ -286,3 +291,170 @@ where
Self::new(descriptor_set, std::iter::empty())
}
}
/// Error related to descriptor sets.
#[derive(Debug, Clone)]
pub enum DescriptorSetError {
/// Builder is already within an array.
AlreadyInArray,
/// Builder is not in an array.
NotInArray,
/// Array doesn't contain the correct amount of descriptors
ArrayLengthMismatch {
/// Expected length
expected: u32,
/// Obtained length
obtained: u32,
},
/// Runtime array contains too many descriptors
ArrayTooManyDescriptors {
/// Capacity of array
capacity: u32,
/// Obtained length
obtained: u32,
},
/// Builder doesn't expect anymore descriptors
TooManyDescriptors,
/// Not all descriptors have been added.
DescriptorsMissing {
/// Expected bindings
expected: usize,
/// Obtained bindings
obtained: usize,
},
/// 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.
expected: Format,
/// Format of the image view that was passed.
obtained: Format,
},
/// The type of an image view doesn't match what was expected.
ImageViewTypeMismatch {
/// Expected type.
expected: ImageViewType,
/// Type of the image view that was passed.
obtained: ImageViewType,
},
/// Expected a multisampled image, but got a single-sampled image.
ExpectedMultisampled,
/// Expected a single-sampled image, but got a multisampled image.
UnexpectedMultisampled,
/// 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 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,
/// Out of memory
OomError(OomError),
/// Operation can not be performed on an empty descriptor.
DescriptorIsEmpty,
/// Expected a non-arrayed image, but got an arrayed image.
UnexpectedArrayed,
}
impl From<OomError> for DescriptorSetError {
fn from(error: OomError) -> Self {
Self::OomError(error)
}
}
impl error::Error for DescriptorSetError {}
impl fmt::Display for DescriptorSetError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
fmt,
"{}",
match *self {
Self::AlreadyInArray => "builder is already within an array",
Self::NotInArray => "builder is not in an array",
Self::ArrayLengthMismatch { .. } =>
"array doesn't contain the correct amount of descriptors",
Self::TooManyDescriptors => "builder doesn't expect anymore descriptors",
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::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::OomError(_) => "out of memory",
Self::DescriptorIsEmpty => "operation can not be performed on an empty descriptor",
Self::UnexpectedArrayed => "expected a non-arrayed image, but got an arrayed image",
Self::ArrayTooManyDescriptors { .. } =>
"runtime array contains too many descriptors",
}
)
}
}
// Part of the DescriptorSetError for the case
// of missing usage on a buffer.
#[derive(Debug, Clone)]
pub enum MissingBufferUsage {
StorageBuffer,
UniformBuffer,
StorageTexelBuffer,
UniformTexelBuffer,
}
// Part of the DescriptorSetError for the case
// of missing usage on an image.
#[derive(Debug, Clone)]
pub enum MissingImageUsage {
InputAttachment,
Sampled,
Storage,
}

File diff suppressed because it is too large Load Diff

View File

@ -197,6 +197,7 @@ mod tests {
descriptor_count: 1,
stages: ShaderStages::all(),
mutable: true,
variable_count: false,
};
let layout = DescriptorSetLayout::new(
device.clone(),

View File

@ -424,6 +424,7 @@ mod tests {
descriptor_count: 1,
stages: ShaderStages::all_graphics(),
mutable: false,
variable_count: false,
};
let set_layout = DescriptorSetLayout::new(
@ -454,6 +455,7 @@ mod tests {
descriptor_count: 1,
stages: ShaderStages::all_graphics(),
mutable: false,
variable_count: false,
};
let set_layout =

View File

@ -0,0 +1,126 @@
// Copyright (c) 2017 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.
use crate::buffer::BufferInner;
use crate::buffer::BufferView;
use crate::descriptor_set::BufferAccess;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::device::Queue;
use crate::image::ImageViewAbstract;
use crate::sampler::Sampler;
use crate::sync::AccessError;
use crate::DeviceSize;
use std::sync::Arc;
pub struct DescriptorSetResources {
buffers: Vec<(Arc<dyn BufferAccess + 'static>, u32)>,
images: Vec<(Arc<dyn ImageViewAbstract + Send + Sync + 'static>, u32)>,
samplers: Vec<(Arc<Sampler>, u32)>,
}
struct BufferViewResource<B>(Arc<BufferView<B>>)
where
B: BufferAccess;
unsafe impl<B> DeviceOwned for BufferViewResource<B>
where
B: BufferAccess,
{
fn device(&self) -> &Arc<Device> {
self.0.device()
}
}
unsafe impl<B> BufferAccess for BufferViewResource<B>
where
B: BufferAccess,
{
fn inner(&self) -> BufferInner<'_> {
self.0.buffer().inner()
}
fn size(&self) -> DeviceSize {
self.0.buffer().size()
}
fn conflict_key(&self) -> (u64, u64) {
self.0.buffer().conflict_key()
}
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError> {
self.0.buffer().try_gpu_lock(exclusive_access, queue)
}
unsafe fn increase_gpu_lock(&self) {
self.0.buffer().increase_gpu_lock()
}
unsafe fn unlock(&self) {
self.0.buffer().unlock()
}
}
impl DescriptorSetResources {
pub fn new(buffer_capacity: usize, image_capacity: usize, sampler_capacity: usize) -> Self {
Self {
buffers: Vec::with_capacity(buffer_capacity),
images: Vec::with_capacity(image_capacity),
samplers: Vec::with_capacity(sampler_capacity),
}
}
pub fn num_buffers(&self) -> usize {
self.buffers.len()
}
pub fn num_images(&self) -> usize {
self.images.len()
}
pub fn num_samplers(&self) -> usize {
self.samplers.len()
}
pub fn add_buffer(&mut self, desc_index: u32, buffer: Arc<dyn BufferAccess + 'static>) {
self.buffers.push((buffer, desc_index));
}
pub fn add_buffer_view<B>(&mut self, desc_index: u32, view: Arc<BufferView<B>>)
where
B: BufferAccess + 'static,
{
self.buffers
.push((Arc::new(BufferViewResource(view)), desc_index));
}
pub fn add_image(
&mut self,
desc_index: u32,
image: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
) {
self.images.push((image, desc_index));
}
pub fn add_sampler(&mut self, desc_index: u32, sampler: Arc<Sampler>) {
self.samplers.push((sampler, desc_index))
}
pub fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> {
self.buffers
.get(index)
.map(|(buf, bind)| (&**buf as _, *bind))
}
pub fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
self.images
.get(index)
.map(|(img, bind)| (&**img as _, *bind))
}
}

View File

@ -0,0 +1,434 @@
// Copyright (c) 2017 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.
use super::builder::DescriptorSetBuilder;
use super::builder::DescriptorSetBuilderOutput;
use super::resources::DescriptorSetResources;
use super::DescriptorSetError;
use crate::buffer::BufferView;
use crate::descriptor_set::layout::DescriptorSetLayout;
use crate::descriptor_set::pool::DescriptorPoolAlloc;
use crate::descriptor_set::pool::DescriptorPoolAllocError;
use crate::descriptor_set::pool::UnsafeDescriptorPool;
use crate::descriptor_set::BufferAccess;
use crate::descriptor_set::DescriptorSet;
use crate::descriptor_set::UnsafeDescriptorSet;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::image::ImageViewAbstract;
use crate::sampler::Sampler;
use crate::OomError;
use crate::VulkanObject;
use crossbeam_queue::SegQueue;
use std::hash::Hash;
use std::hash::Hasher;
use std::sync::Arc;
/// `SingleLayoutDescSetPool` is a convenience wrapper provided by Vulkano not to be confused with
/// `VkDescriptorPool`. Its function is to provide access to pool(s) to allocate `DescriptorSet`'s
/// from and optimizes for a specific layout. For a more general purpose pool see `descriptor_set::pool::StdDescriptorPool`.
pub struct SingleLayoutDescSetPool {
// The `SingleLayoutPool` struct contains an actual Vulkan pool. Every time it is full we create
// a new pool and replace the current one with the new one.
inner: Option<Arc<SingleLayoutPool>>,
// The Vulkan device.
device: Arc<Device>,
// The amount of sets available to use when we create a new Vulkan pool.
set_count: usize,
// The descriptor layout that this pool is for.
layout: Arc<DescriptorSetLayout>,
}
impl SingleLayoutDescSetPool {
/// Initializes a new pool. The pool is configured to allocate sets that corresponds to the
/// parameters passed to this function.
pub fn new(layout: Arc<DescriptorSetLayout>) -> Self {
let device = layout.device().clone();
Self {
inner: None,
device,
set_count: 4,
layout,
}
}
/// Starts the process of building a new descriptor set.
///
/// The set will corresponds to the set layout that was passed to `new`.
pub fn next(&mut self) -> SingleLayoutDescSetBuilder {
let layout = self.layout.clone();
SingleLayoutDescSetBuilder {
pool: self,
inner: DescriptorSetBuilder::start(layout),
poisoned: false,
}
}
fn next_alloc(&mut self) -> Result<SingleLayoutPoolAlloc, OomError> {
loop {
let mut not_enough_sets = false;
if let Some(ref mut p_inner) = self.inner {
if let Some(existing) = p_inner.reserve.pop() {
return Ok(SingleLayoutPoolAlloc {
pool: p_inner.clone(),
inner: Some(existing),
});
} else {
not_enough_sets = true;
}
}
if not_enough_sets {
self.set_count *= 2;
}
let count = *self.layout.descriptors_count() * self.set_count as u32;
let mut unsafe_pool = UnsafeDescriptorPool::new(
self.device.clone(),
&count,
self.set_count as u32,
false,
)?;
let reserve = unsafe {
match unsafe_pool.alloc((0..self.set_count).map(|_| &*self.layout)) {
Ok(alloc_iter) => {
let reserve = SegQueue::new();
for alloc in alloc_iter {
reserve.push(alloc);
}
reserve
}
Err(DescriptorPoolAllocError::OutOfHostMemory) => {
return Err(OomError::OutOfHostMemory);
}
Err(DescriptorPoolAllocError::OutOfDeviceMemory) => {
return Err(OomError::OutOfDeviceMemory);
}
Err(DescriptorPoolAllocError::FragmentedPool) => {
// This can't happen as we don't free individual sets.
unreachable!()
}
Err(DescriptorPoolAllocError::OutOfPoolMemory) => unreachable!(),
}
};
self.inner = Some(Arc::new(SingleLayoutPool {
inner: unsafe_pool,
reserve,
}));
}
}
}
struct SingleLayoutPool {
// The actual Vulkan descriptor pool. This field isn't actually used anywhere, but we need to
// keep the pool alive in order to keep the descriptor sets valid.
inner: UnsafeDescriptorPool,
// List of descriptor sets. When `alloc` is called, a descriptor will be extracted from this
// list. When a `SingleLayoutPoolAlloc` is dropped, its descriptor set is put back in this list.
reserve: SegQueue<UnsafeDescriptorSet>,
}
struct SingleLayoutPoolAlloc {
// The `SingleLayoutPool` were we allocated from. We need to keep a copy of it in each allocation
// so that we can put back the allocation in the list in our `Drop` impl.
pool: Arc<SingleLayoutPool>,
// The actual descriptor set, wrapped inside an `Option` so that we can extract it in our
// `Drop` impl.
inner: Option<UnsafeDescriptorSet>,
}
impl DescriptorPoolAlloc for SingleLayoutPoolAlloc {
#[inline]
fn inner(&self) -> &UnsafeDescriptorSet {
self.inner.as_ref().unwrap()
}
#[inline]
fn inner_mut(&mut self) -> &mut UnsafeDescriptorSet {
self.inner.as_mut().unwrap()
}
}
impl Drop for SingleLayoutPoolAlloc {
fn drop(&mut self) {
let inner = self.inner.take().unwrap();
self.pool.reserve.push(inner);
}
}
/// A descriptor set created from a `SingleLayoutDescSetPool`.
pub struct SingleLayoutDescSet {
inner: SingleLayoutPoolAlloc,
resources: DescriptorSetResources,
layout: Arc<DescriptorSetLayout>,
}
unsafe impl DescriptorSet for SingleLayoutDescSet {
#[inline]
fn inner(&self) -> &UnsafeDescriptorSet {
self.inner.inner()
}
#[inline]
fn layout(&self) -> &Arc<DescriptorSetLayout> {
&self.layout
}
#[inline]
fn num_buffers(&self) -> usize {
self.resources.num_buffers()
}
#[inline]
fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> {
self.resources.buffer(index)
}
#[inline]
fn num_images(&self) -> usize {
self.resources.num_images()
}
#[inline]
fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
self.resources.image(index)
}
}
unsafe impl DeviceOwned for SingleLayoutDescSet {
#[inline]
fn device(&self) -> &Arc<Device> {
self.layout.device()
}
}
impl PartialEq for SingleLayoutDescSet {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.inner().internal_object() == other.inner().internal_object()
&& self.device() == other.device()
}
}
impl Eq for SingleLayoutDescSet {}
impl Hash for SingleLayoutDescSet {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.inner().internal_object().hash(state);
self.device().hash(state);
}
}
/// Prototype of a `SingleLayoutDescSet`.
pub struct SingleLayoutDescSetBuilder<'a> {
pool: &'a mut SingleLayoutDescSetPool,
inner: DescriptorSetBuilder,
poisoned: bool,
}
impl<'a> SingleLayoutDescSetBuilder<'a> {
/// Call this function if the next element of the set is an array in order to set the value of
/// each element.
///
/// Returns an error if the descriptor is empty, there are no remaining descriptors, or if the
/// builder is already in an error.
///
/// 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.
#[inline]
pub fn enter_array(&mut self) -> Result<&mut Self, DescriptorSetError> {
if self.poisoned {
Err(DescriptorSetError::BuilderPoisoned)
} else {
match self.inner.enter_array() {
Ok(_) => Ok(self),
Err(e) => {
self.poisoned = true;
Err(e)
}
}
}
}
/// Leaves the array. Call this once you added all the elements of the array.
///
/// Returns an error if the array is missing elements, or if the builder is not in an array.
#[inline]
pub fn leave_array(&mut self) -> Result<&mut Self, DescriptorSetError> {
if self.poisoned {
Err(DescriptorSetError::BuilderPoisoned)
} else {
match self.inner.leave_array() {
Ok(_) => Ok(self),
Err(e) => {
self.poisoned = true;
Err(e)
}
}
}
}
/// Skips the current descriptor if it is empty.
#[inline]
pub fn add_empty(&mut self) -> Result<&mut Self, DescriptorSetError> {
if self.poisoned {
Err(DescriptorSetError::BuilderPoisoned)
} else {
match self.inner.add_empty() {
Ok(_) => Ok(self),
Err(e) => {
self.poisoned = true;
Err(e)
}
}
}
}
/// Binds a buffer as the next descriptor.
///
/// An error is returned if the buffer isn't compatible with the descriptor.
#[inline]
pub fn add_buffer(
&mut self,
buffer: Arc<dyn BufferAccess + 'static>,
) -> Result<&mut Self, DescriptorSetError> {
if self.poisoned {
Err(DescriptorSetError::BuilderPoisoned)
} else {
match self.inner.add_buffer(buffer) {
Ok(_) => Ok(self),
Err(e) => {
self.poisoned = true;
Err(e)
}
}
}
}
/// Binds a buffer view as the next descriptor.
///
/// An error is returned if the buffer isn't compatible with the descriptor.
#[inline]
pub fn add_buffer_view<B>(
&mut self,
view: Arc<BufferView<B>>,
) -> Result<&mut Self, DescriptorSetError>
where
B: BufferAccess + 'static,
{
if self.poisoned {
Err(DescriptorSetError::BuilderPoisoned)
} else {
match self.inner.add_buffer_view(view) {
Ok(_) => Ok(self),
Err(e) => {
self.poisoned = true;
Err(e)
}
}
}
}
/// Binds an image view as the next descriptor.
///
/// An error is returned if the image view isn't compatible with the descriptor.
#[inline]
pub fn add_image(
&mut self,
image_view: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
) -> Result<&mut Self, DescriptorSetError> {
if self.poisoned {
Err(DescriptorSetError::BuilderPoisoned)
} else {
match self.inner.add_image(image_view) {
Ok(_) => Ok(self),
Err(e) => {
self.poisoned = true;
Err(e)
}
}
}
}
/// Binds an image view with a sampler as the next descriptor.
///
/// An error is returned if the image view isn't compatible with the descriptor.
#[inline]
pub fn add_sampled_image(
&mut self,
image_view: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
sampler: Arc<Sampler>,
) -> Result<&mut Self, DescriptorSetError> {
if self.poisoned {
Err(DescriptorSetError::BuilderPoisoned)
} else {
match self.inner.add_sampled_image(image_view, sampler) {
Ok(_) => Ok(self),
Err(e) => {
self.poisoned = true;
Err(e)
}
}
}
}
/// Binds a sampler as the next descriptor.
///
/// An error is returned if the sampler isn't compatible with the descriptor.
#[inline]
pub fn add_sampler(&mut self, sampler: Arc<Sampler>) -> Result<&mut Self, DescriptorSetError> {
if self.poisoned {
Err(DescriptorSetError::BuilderPoisoned)
} else {
match self.inner.add_sampler(sampler) {
Ok(_) => Ok(self),
Err(e) => {
self.poisoned = true;
Err(e)
}
}
}
}
/// Builds a `SingleLayoutDescSet` from the builder.
pub fn build(self) -> Result<SingleLayoutDescSet, DescriptorSetError> {
if self.poisoned {
return Err(DescriptorSetError::BuilderPoisoned);
}
let DescriptorSetBuilderOutput {
layout,
writes,
resources,
} = self.inner.output()?;
let mut alloc = self.pool.next_alloc()?;
unsafe {
alloc
.inner_mut()
.write(&self.pool.device, writes.into_iter());
}
Ok(SingleLayoutDescSet {
inner: alloc,
resources,
layout,
})
}
}

View File

@ -71,7 +71,7 @@ impl ComputePipeline {
desc.clone(),
)?))
})
.collect::<Result<Vec<_>, OomError>>()?;
.collect::<Result<Vec<_>, PipelineLayoutCreationError>>()?;
let pipeline_layout = Arc::new(PipelineLayout::new(
device.clone(),
descriptor_set_layouts,
@ -430,6 +430,7 @@ mod tests {
..ShaderStages::none()
},
mutable: false,
variable_count: false,
})])],
None,
SpecConsts::descriptors(),
@ -466,11 +467,11 @@ mod tests {
let data_buffer =
CpuAccessibleBuffer::from_data(device.clone(), BufferUsage::all(), false, 0).unwrap();
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let set = PersistentDescriptorSet::start(layout.clone())
.add_buffer(data_buffer.clone())
.unwrap()
.build()
.unwrap();
let mut builder = PersistentDescriptorSet::start(layout.clone());
builder.add_buffer(data_buffer.clone()).unwrap();
let set = builder.build().unwrap();
let mut cbb = AutoCommandBufferBuilder::primary(
device.clone(),

View File

@ -29,6 +29,7 @@ use crate::pipeline::graphics_pipeline::GraphicsPipelineCreationError;
use crate::pipeline::graphics_pipeline::Inner as GraphicsPipelineInner;
use crate::pipeline::input_assembly::PrimitiveTopology;
use crate::pipeline::layout::PipelineLayout;
use crate::pipeline::layout::PipelineLayoutCreationError;
use crate::pipeline::layout::PipelineLayoutPcRange;
use crate::pipeline::raster::CullMode;
use crate::pipeline::raster::DepthBiasControl;
@ -47,7 +48,6 @@ use crate::pipeline::viewport::Scissor;
use crate::pipeline::viewport::Viewport;
use crate::pipeline::viewport::ViewportsState;
use crate::render_pass::Subpass;
use crate::OomError;
use crate::VulkanObject;
use smallvec::SmallVec;
use std::collections::hash_map::{Entry, HashMap};
@ -214,7 +214,7 @@ where
let descriptor_set_layouts = descriptor_set_layout_descs
.into_iter()
.map(|desc| Ok(Arc::new(DescriptorSetLayout::new(device.clone(), desc)?)))
.collect::<Result<Vec<_>, OomError>>()?;
.collect::<Result<Vec<_>, PipelineLayoutCreationError>>()?;
let pipeline_layout = Arc::new(
PipelineLayout::new(device.clone(), descriptor_set_layouts, push_constant_ranges)
.unwrap(),

View File

@ -8,6 +8,7 @@
// according to those terms.
use crate::pipeline::input_assembly::PrimitiveTopology;
use crate::pipeline::layout::PipelineLayoutCreationError;
use crate::pipeline::layout::PipelineLayoutSupersetError;
use crate::pipeline::shader::ShaderInterfaceMismatchError;
use crate::pipeline::vertex::IncompatibleVertexDefinitionError;
@ -23,6 +24,9 @@ pub enum GraphicsPipelineCreationError {
/// Not enough memory.
OomError(OomError),
/// Error while creating the pipeline layout object.
PipelineLayoutCreationError(PipelineLayoutCreationError),
/// The pipeline layout is not compatible with what the shaders expect.
IncompatiblePipelineLayout(PipelineLayoutSupersetError),
@ -194,6 +198,7 @@ impl error::Error for GraphicsPipelineCreationError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match *self {
GraphicsPipelineCreationError::OomError(ref err) => Some(err),
GraphicsPipelineCreationError::PipelineLayoutCreationError(ref err) => Some(err),
GraphicsPipelineCreationError::IncompatiblePipelineLayout(ref err) => Some(err),
GraphicsPipelineCreationError::ShaderStagesMismatch(ref err) => Some(err),
GraphicsPipelineCreationError::IncompatibleVertexDefinition(ref err) => Some(err),
@ -214,6 +219,9 @@ impl fmt::Display for GraphicsPipelineCreationError {
GraphicsPipelineCreationError::ShaderStagesMismatch(_) => {
"the output interface of one shader and the input interface of the next shader does not match"
}
GraphicsPipelineCreationError::PipelineLayoutCreationError(_) => {
"error while creating the pipeline layout object"
}
GraphicsPipelineCreationError::IncompatiblePipelineLayout(_) => {
"the pipeline layout is not compatible with what the shaders expect"
}
@ -350,6 +358,13 @@ impl From<OomError> for GraphicsPipelineCreationError {
}
}
impl From<PipelineLayoutCreationError> for GraphicsPipelineCreationError {
#[inline]
fn from(err: PipelineLayoutCreationError) -> GraphicsPipelineCreationError {
GraphicsPipelineCreationError::PipelineLayoutCreationError(err)
}
}
impl From<PipelineLayoutSupersetError> for GraphicsPipelineCreationError {
#[inline]
fn from(err: PipelineLayoutSupersetError) -> GraphicsPipelineCreationError {

View File

@ -12,6 +12,7 @@ use crate::check_errors;
use crate::descriptor_set::layout::DescriptorSetCompatibilityError;
use crate::descriptor_set::layout::DescriptorSetDesc;
use crate::descriptor_set::layout::DescriptorSetLayout;
use crate::descriptor_set::layout::DescriptorSetLayoutError;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::pipeline::layout::PipelineLayoutLimitsError;
@ -283,6 +284,8 @@ pub enum PipelineLayoutCreationError {
first_range: PipelineLayoutPcRange,
second_range: PipelineLayoutPcRange,
},
/// One of the set layouts has an error.
SetLayoutError(DescriptorSetLayoutError),
}
impl error::Error for PipelineLayoutCreationError {
@ -291,6 +294,7 @@ impl error::Error for PipelineLayoutCreationError {
match *self {
PipelineLayoutCreationError::OomError(ref err) => Some(err),
PipelineLayoutCreationError::LimitsError(ref err) => Some(err),
PipelineLayoutCreationError::SetLayoutError(ref err) => Some(err),
_ => None,
}
}
@ -313,6 +317,9 @@ impl fmt::Display for PipelineLayoutCreationError {
PipelineLayoutCreationError::PushConstantsConflict { .. } => {
"conflict between different push constants ranges"
}
PipelineLayoutCreationError::SetLayoutError(_) => {
"one of the sets has an error"
}
}
)
}
@ -332,6 +339,13 @@ impl From<PipelineLayoutLimitsError> for PipelineLayoutCreationError {
}
}
impl From<DescriptorSetLayoutError> for PipelineLayoutCreationError {
#[inline]
fn from(err: DescriptorSetLayoutError) -> PipelineLayoutCreationError {
PipelineLayoutCreationError::SetLayoutError(err)
}
}
impl From<Error> for PipelineLayoutCreationError {
#[inline]
fn from(err: Error) -> PipelineLayoutCreationError {

View File

@ -13,32 +13,32 @@ use crate::buffer::BufferAccess;
pub unsafe trait VertexBuffersCollection {
/// Converts `self` into a list of buffers.
// TODO: better than a Vec
fn into_vec(self) -> Vec<Box<dyn BufferAccess + Send + Sync>>;
fn into_vec(self) -> Vec<Box<dyn BufferAccess>>;
}
unsafe impl VertexBuffersCollection for () {
#[inline]
fn into_vec(self) -> Vec<Box<dyn BufferAccess + Send + Sync>> {
fn into_vec(self) -> Vec<Box<dyn BufferAccess>> {
vec![]
}
}
unsafe impl<T> VertexBuffersCollection for T
where
T: BufferAccess + Send + Sync + 'static,
T: BufferAccess + 'static,
{
#[inline]
fn into_vec(self) -> Vec<Box<dyn BufferAccess + Send + Sync>> {
fn into_vec(self) -> Vec<Box<dyn BufferAccess>> {
vec![Box::new(self) as Box<_>]
}
}
unsafe impl<T> VertexBuffersCollection for Vec<T>
where
T: BufferAccess + Send + Sync + 'static,
T: BufferAccess + 'static,
{
#[inline]
fn into_vec(self) -> Vec<Box<dyn BufferAccess + Send + Sync>> {
fn into_vec(self) -> Vec<Box<dyn BufferAccess>> {
self.into_iter()
.map(|source| Box::new(source) as Box<_>)
.collect()
@ -48,11 +48,11 @@ where
macro_rules! impl_collection {
($first:ident $(, $others:ident)+) => (
unsafe impl<$first$(, $others)+> VertexBuffersCollection for ($first, $($others),+)
where $first: BufferAccess + Send + Sync + 'static
$(, $others: BufferAccess + Send + Sync + 'static)*
where $first: BufferAccess + 'static
$(, $others: BufferAccess + 'static)*
{
#[inline]
fn into_vec(self) -> Vec<Box<dyn BufferAccess + Send + Sync>> {
fn into_vec(self) -> Vec<Box<dyn BufferAccess>> {
#![allow(non_snake_case)]
let ($first, $($others,)*) = self;