mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-25 16:25:31 +00:00
Add basic support for khr_push_descriptor
(#1727)
* Add basic support for khr_push_descriptor * Add basic support for khr_push_descriptor * Support arrays in `DescriptorWrite` * Use assert when creating the builder
This commit is contained in:
parent
9aba801319
commit
35fed6b577
BIN
examples/src/bin/push-descriptors/image_img.png
Normal file
BIN
examples/src/bin/push-descriptors/image_img.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
377
examples/src/bin/push-descriptors/main.rs
Normal file
377
examples/src/bin/push-descriptors/main.rs
Normal file
@ -0,0 +1,377 @@
|
||||
// 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::DescriptorSetBuilder;
|
||||
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::color_blend::ColorBlendState;
|
||||
use vulkano::pipeline::input_assembly::{InputAssemblyState, PrimitiveTopology};
|
||||
use vulkano::pipeline::viewport::{Viewport, ViewportState};
|
||||
use vulkano::pipeline::{GraphicsPipeline, PipelineBindPoint};
|
||||
use vulkano::render_pass::{Framebuffer, FramebufferAbstract, RenderPass, Subpass};
|
||||
use vulkano::sampler::{Filter, MipmapMode, Sampler, SamplerAddressMode};
|
||||
use vulkano::swapchain::{self, AcquireError, Swapchain, SwapchainCreationError};
|
||||
use vulkano::sync::{self, FlushError, GpuFuture};
|
||||
use vulkano::Version;
|
||||
use vulkano_win::VkSurfaceBuild;
|
||||
use winit::event::{Event, WindowEvent};
|
||||
use winit::event_loop::{ControlFlow, EventLoop};
|
||||
use winit::window::{Window, WindowBuilder};
|
||||
|
||||
fn main() {
|
||||
let required_extensions = vulkano_win::required_extensions();
|
||||
let instance = Instance::new(None, Version::V1_1, &required_extensions, None).unwrap();
|
||||
|
||||
let event_loop = EventLoop::new();
|
||||
let surface = WindowBuilder::new()
|
||||
.build_vk_surface(&event_loop, instance.clone())
|
||||
.unwrap();
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
khr_push_descriptor: 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,
|
||||
})
|
||||
.expect("No suitable physical device found");
|
||||
|
||||
println!(
|
||||
"Using device: {} (type: {:?})",
|
||||
physical_device.properties().device_name,
|
||||
physical_device.properties().device_type,
|
||||
);
|
||||
|
||||
let (device, mut queues) = Device::new(
|
||||
physical_device,
|
||||
&Features::none(),
|
||||
&physical_device
|
||||
.required_extensions()
|
||||
.union(&device_extensions),
|
||||
[(queue_family, 0.5)].iter().cloned(),
|
||||
)
|
||||
.unwrap();
|
||||
let queue = queues.next().unwrap();
|
||||
|
||||
let (mut swapchain, images) = {
|
||||
let caps = surface.capabilities(physical_device).unwrap();
|
||||
let composite_alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
||||
let format = caps.supported_formats[0].0;
|
||||
let dimensions: [u32; 2] = surface.window().inner_size().into();
|
||||
|
||||
Swapchain::start(device.clone(), surface.clone())
|
||||
.num_images(caps.min_image_count)
|
||||
.format(format)
|
||||
.dimensions(dimensions)
|
||||
.usage(ImageUsage::color_attachment())
|
||||
.sharing_mode(&queue)
|
||||
.composite_alpha(composite_alpha)
|
||||
.build()
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
struct Vertex {
|
||||
position: [f32; 2],
|
||||
}
|
||||
vulkano::impl_vertex!(Vertex, position);
|
||||
|
||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
false,
|
||||
[
|
||||
Vertex {
|
||||
position: [-0.5, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, 0.5],
|
||||
},
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::Shader::load(device.clone()).unwrap();
|
||||
let fs = fs::Shader::load(device.clone()).unwrap();
|
||||
|
||||
let render_pass = Arc::new(
|
||||
vulkano::single_pass_renderpass!(device.clone(),
|
||||
attachments: {
|
||||
color: {
|
||||
load: Clear,
|
||||
store: Store,
|
||||
format: swapchain.format(),
|
||||
samples: 1,
|
||||
}
|
||||
},
|
||||
pass: {
|
||||
color: [color],
|
||||
depth_stencil: {}
|
||||
}
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let (texture, tex_future) = {
|
||||
let png_bytes = include_bytes!("image_img.png").to_vec();
|
||||
let cursor = Cursor::new(png_bytes);
|
||||
let decoder = png::Decoder::new(cursor);
|
||||
let mut reader = decoder.read_info().unwrap();
|
||||
let info = reader.info();
|
||||
let dimensions = ImageDimensions::Dim2d {
|
||||
width: info.width,
|
||||
height: info.height,
|
||||
array_layers: 1,
|
||||
};
|
||||
let mut image_data = Vec::new();
|
||||
image_data.resize((info.width * info.height * 4) as usize, 0);
|
||||
reader.next_frame(&mut image_data).unwrap();
|
||||
|
||||
let (image, future) = ImmutableImage::from_iter(
|
||||
image_data.iter().cloned(),
|
||||
dimensions,
|
||||
MipmapsCount::One,
|
||||
Format::R8G8B8A8_SRGB,
|
||||
queue.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
(ImageView::new(image).unwrap(), future)
|
||||
};
|
||||
|
||||
let sampler = Sampler::new(
|
||||
device.clone(),
|
||||
Filter::Linear,
|
||||
Filter::Linear,
|
||||
MipmapMode::Nearest,
|
||||
SamplerAddressMode::Repeat,
|
||||
SamplerAddressMode::Repeat,
|
||||
SamplerAddressMode::Repeat,
|
||||
0.0,
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
|
||||
let pipeline = Arc::new(
|
||||
GraphicsPipeline::start()
|
||||
.vertex_input_single_buffer::<Vertex>()
|
||||
.vertex_shader(vs.main_entry_point(), ())
|
||||
.input_assembly_state(
|
||||
InputAssemblyState::new().topology(PrimitiveTopology::TriangleStrip),
|
||||
)
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
.fragment_shader(fs.main_entry_point(), ())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()).blend_alpha())
|
||||
.render_pass(subpass)
|
||||
.with_auto_layout(device.clone(), |set_descs| {
|
||||
set_descs[0].set_push_descriptor(true);
|
||||
set_descs[0].set_immutable_samplers(0, [sampler]);
|
||||
})
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let mut viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [0.0, 0.0],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport);
|
||||
|
||||
let mut recreate_swapchain = false;
|
||||
let mut previous_frame_end = Some(tex_future.boxed());
|
||||
|
||||
event_loop.run(move |event, _, control_flow| match event {
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::CloseRequested,
|
||||
..
|
||||
} => {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
}
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::Resized(_),
|
||||
..
|
||||
} => {
|
||||
recreate_swapchain = true;
|
||||
}
|
||||
Event::RedrawEventsCleared => {
|
||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||
|
||||
if recreate_swapchain {
|
||||
let dimensions: [u32; 2] = surface.window().inner_size().into();
|
||||
let (new_swapchain, new_images) =
|
||||
match swapchain.recreate().dimensions(dimensions).build() {
|
||||
Ok(r) => r,
|
||||
Err(SwapchainCreationError::UnsupportedDimensions) => return,
|
||||
Err(e) => panic!("Failed to recreate swapchain: {:?}", e),
|
||||
};
|
||||
|
||||
swapchain = new_swapchain;
|
||||
framebuffers =
|
||||
window_size_dependent_setup(&new_images, render_pass.clone(), &mut viewport);
|
||||
recreate_swapchain = false;
|
||||
}
|
||||
|
||||
let (image_num, suboptimal, acquire_future) =
|
||||
match swapchain::acquire_next_image(swapchain.clone(), None) {
|
||||
Ok(r) => r,
|
||||
Err(AcquireError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
return;
|
||||
}
|
||||
Err(e) => panic!("Failed to acquire next image: {:?}", e),
|
||||
};
|
||||
|
||||
if suboptimal {
|
||||
recreate_swapchain = true;
|
||||
}
|
||||
|
||||
let clear_values = vec![[0.0, 0.0, 1.0, 1.0].into()];
|
||||
let mut builder = AutoCommandBufferBuilder::primary(
|
||||
device.clone(),
|
||||
queue.family(),
|
||||
CommandBufferUsage::OneTimeSubmit,
|
||||
)
|
||||
.unwrap();
|
||||
builder
|
||||
.begin_render_pass(
|
||||
framebuffers[image_num].clone(),
|
||||
SubpassContents::Inline,
|
||||
clear_values,
|
||||
)
|
||||
.unwrap()
|
||||
.set_viewport(0, [viewport.clone()])
|
||||
.bind_pipeline_graphics(pipeline.clone())
|
||||
.push_descriptor_set(PipelineBindPoint::Graphics, pipeline.layout().clone(), 0, {
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let mut set_builder = DescriptorSetBuilder::start(layout.clone());
|
||||
set_builder.add_image(texture.clone()).unwrap();
|
||||
set_builder.build().unwrap()
|
||||
})
|
||||
.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>> {
|
||||
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>
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
mod vs {
|
||||
vulkano_shaders::shader! {
|
||||
ty: "vertex",
|
||||
src: "
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 position;
|
||||
layout(location = 0) out vec2 tex_coords;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(position, 0.0, 1.0);
|
||||
tex_coords = position + vec2(0.5);
|
||||
}"
|
||||
}
|
||||
}
|
||||
|
||||
mod fs {
|
||||
vulkano_shaders::shader! {
|
||||
ty: "fragment",
|
||||
src: "
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 tex_coords;
|
||||
layout(location = 0) out vec4 f_color;
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D tex;
|
||||
|
||||
void main() {
|
||||
f_color = texture(tex, tex_coords);
|
||||
}"
|
||||
}
|
||||
}
|
@ -37,6 +37,7 @@ use crate::command_buffer::ImageUninitializedSafe;
|
||||
use crate::command_buffer::PrimaryCommandBuffer;
|
||||
use crate::command_buffer::SecondaryCommandBuffer;
|
||||
use crate::command_buffer::SubpassContents;
|
||||
use crate::descriptor_set::builder::DescriptorSetBuilderOutput;
|
||||
use crate::descriptor_set::DescriptorSetsCollection;
|
||||
use crate::device::physical::QueueFamily;
|
||||
use crate::device::Device;
|
||||
@ -1778,6 +1779,61 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Pushes descriptor data directly into the command buffer for future dispatch or draw calls.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// - Panics if the queue family of the command buffer does not support `pipeline_bind_point`.
|
||||
/// - Panics if the
|
||||
/// [`khr_push_descriptor`](crate::device::DeviceExtensions::khr_push_descriptor)
|
||||
/// extension is not enabled on the device.
|
||||
/// - Panics if `set_num` is not less than the number of sets in `pipeline_layout`.
|
||||
pub fn push_descriptor_set(
|
||||
&mut self,
|
||||
pipeline_bind_point: PipelineBindPoint,
|
||||
pipeline_layout: Arc<PipelineLayout>,
|
||||
set_num: u32,
|
||||
descriptor_writes: DescriptorSetBuilderOutput, // TODO: make partial writes possible
|
||||
) -> &mut Self {
|
||||
match pipeline_bind_point {
|
||||
PipelineBindPoint::Compute => assert!(
|
||||
self.queue_family().supports_compute(),
|
||||
"the queue family of the command buffer must support compute operations"
|
||||
),
|
||||
PipelineBindPoint::Graphics => assert!(
|
||||
self.queue_family().supports_graphics(),
|
||||
"the queue family of the command buffer must support graphics operations"
|
||||
),
|
||||
}
|
||||
|
||||
assert!(
|
||||
self.device().enabled_extensions().khr_push_descriptor,
|
||||
"the khr_push_descriptor extension must be enabled on the device"
|
||||
);
|
||||
assert!(
|
||||
set_num as usize <= pipeline_layout.descriptor_set_layouts().len(),
|
||||
"the descriptor set slot being bound must be less than the number of sets in pipeline_layout"
|
||||
);
|
||||
|
||||
let pipeline_set = &pipeline_layout.descriptor_set_layouts()[set_num as usize];
|
||||
assert!(
|
||||
pipeline_set.is_compatible_with(descriptor_writes.layout()),
|
||||
"descriptor_writes is not compatible with slot {} in pipeline_layout",
|
||||
set_num as usize,
|
||||
);
|
||||
|
||||
unsafe {
|
||||
self.inner.push_descriptor_set(
|
||||
pipeline_bind_point,
|
||||
pipeline_layout,
|
||||
set_num,
|
||||
descriptor_writes,
|
||||
);
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
// Helper function for dynamic state setting.
|
||||
fn has_fixed_state(&self, state: DynamicState) -> bool {
|
||||
self.state()
|
||||
|
@ -23,10 +23,13 @@ use crate::command_buffer::CommandBufferExecError;
|
||||
use crate::command_buffer::CommandBufferLevel;
|
||||
use crate::command_buffer::CommandBufferUsage;
|
||||
use crate::command_buffer::ImageUninitializedSafe;
|
||||
use crate::descriptor_set::builder::DescriptorSetBuilderOutput;
|
||||
use crate::descriptor_set::layout::DescriptorSetLayout;
|
||||
use crate::descriptor_set::DescriptorSet;
|
||||
use crate::device::Device;
|
||||
use crate::device::DeviceOwned;
|
||||
use crate::image::ImageLayout;
|
||||
use crate::image::ImageViewAbstract;
|
||||
use crate::pipeline::color_blend::LogicOp;
|
||||
use crate::pipeline::depth_stencil::CompareOp;
|
||||
use crate::pipeline::depth_stencil::StencilOp;
|
||||
@ -50,6 +53,7 @@ use crate::sync::AccessFlags;
|
||||
use crate::sync::PipelineMemoryAccess;
|
||||
use crate::sync::PipelineStages;
|
||||
use crate::OomError;
|
||||
use crate::VulkanObject;
|
||||
use fnv::FnvHashMap;
|
||||
use smallvec::SmallVec;
|
||||
use std::borrow::Cow;
|
||||
@ -808,6 +812,69 @@ impl CurrentState {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn invalidate_descriptor_sets(
|
||||
&mut self,
|
||||
pipeline_bind_point: PipelineBindPoint,
|
||||
pipeline_layout: Arc<PipelineLayout>,
|
||||
first_set: u32,
|
||||
num_descriptor_sets: u32,
|
||||
cmd: &Arc<dyn Command>,
|
||||
) {
|
||||
let state = match self.descriptor_sets.entry(pipeline_bind_point) {
|
||||
Entry::Vacant(entry) => entry.insert(DescriptorSetState {
|
||||
descriptor_sets: Default::default(),
|
||||
pipeline_layout,
|
||||
}),
|
||||
Entry::Occupied(entry) => {
|
||||
let state = entry.into_mut();
|
||||
|
||||
let invalidate_from = if state.pipeline_layout.internal_object()
|
||||
== pipeline_layout.internal_object()
|
||||
{
|
||||
// If we're still using the exact same layout, then of course it's compatible.
|
||||
None
|
||||
} else if state.pipeline_layout.push_constant_ranges()
|
||||
!= pipeline_layout.push_constant_ranges()
|
||||
{
|
||||
// If the push constant ranges don't match,
|
||||
// all bound descriptor sets are disturbed.
|
||||
Some(0)
|
||||
} else {
|
||||
// Find the first descriptor set layout in the current pipeline layout that
|
||||
// isn't compatible with the corresponding set in the new pipeline layout.
|
||||
// If an incompatible set was found, all bound sets from that slot onwards will
|
||||
// be disturbed.
|
||||
let current_layouts = state.pipeline_layout.descriptor_set_layouts();
|
||||
let new_layouts = pipeline_layout.descriptor_set_layouts();
|
||||
let max = (current_layouts.len() as u32).min(first_set + num_descriptor_sets);
|
||||
(0..max).find(|&num| {
|
||||
let num = num as usize;
|
||||
!current_layouts[num].is_compatible_with(&new_layouts[num])
|
||||
})
|
||||
};
|
||||
|
||||
if let Some(invalidate_from) = invalidate_from {
|
||||
// Remove disturbed sets and set new pipeline layout.
|
||||
state
|
||||
.descriptor_sets
|
||||
.retain(|&num, _| num < invalidate_from);
|
||||
state.pipeline_layout = pipeline_layout;
|
||||
} else if (first_set + num_descriptor_sets) as usize
|
||||
>= state.pipeline_layout.descriptor_set_layouts().len()
|
||||
{
|
||||
// New layout is a superset of the old one.
|
||||
state.pipeline_layout = pipeline_layout;
|
||||
}
|
||||
|
||||
state
|
||||
}
|
||||
};
|
||||
|
||||
for i in 0..num_descriptor_sets {
|
||||
state.descriptor_sets.insert(first_set + i, cmd.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -830,16 +897,18 @@ impl<'a> CommandBufferState<'a> {
|
||||
&self,
|
||||
pipeline_bind_point: PipelineBindPoint,
|
||||
set_num: u32,
|
||||
) -> Option<(&'a dyn DescriptorSet, &'a [u32])> {
|
||||
self.current_state
|
||||
.descriptor_sets
|
||||
.get(&pipeline_bind_point)
|
||||
.and_then(|state| {
|
||||
) -> Option<SetOrPush<'a>> {
|
||||
let state =
|
||||
if let Some(state) = self.current_state.descriptor_sets.get(&pipeline_bind_point) {
|
||||
state
|
||||
.descriptor_sets
|
||||
.get(&set_num)
|
||||
.map(|cmd| cmd.bound_descriptor_set(set_num))
|
||||
})
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
state
|
||||
.descriptor_sets
|
||||
.get(&set_num)
|
||||
.map(|cmd| cmd.bound_descriptor_set(set_num))
|
||||
}
|
||||
|
||||
/// Returns the pipeline layout that describes all currently bound descriptor sets.
|
||||
@ -1086,6 +1155,53 @@ impl<'a> CommandBufferState<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum SetOrPush<'a> {
|
||||
Set(&'a dyn DescriptorSet, &'a [u32]),
|
||||
Push(&'a DescriptorSetBuilderOutput),
|
||||
}
|
||||
|
||||
impl<'a> SetOrPush<'a> {
|
||||
pub fn layout(&self) -> &'a Arc<DescriptorSetLayout> {
|
||||
match *self {
|
||||
Self::Set(set, offsets) => set.layout(),
|
||||
Self::Push(writes) => writes.layout(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn num_buffers(&self) -> usize {
|
||||
match self {
|
||||
Self::Set(set, offsets) => set.num_buffers(),
|
||||
Self::Push(writes) => writes.resources().num_buffers(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn buffer(&self, num: usize) -> Option<(&'a dyn BufferAccess, u32)> {
|
||||
match *self {
|
||||
Self::Set(set, offsets) => set.buffer(num),
|
||||
Self::Push(writes) => writes.resources().buffer(num),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn num_images(&self) -> usize {
|
||||
match self {
|
||||
Self::Set(set, offsets) => set.num_images(),
|
||||
Self::Push(writes) => writes.resources().num_images(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn image(&self, num: usize) -> Option<(&'a dyn ImageViewAbstract, u32)> {
|
||||
match *self {
|
||||
Self::Set(set, offsets) => set.image(num),
|
||||
Self::Push(writes) => writes.resources().image(num),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Holds the current stencil state of a command buffer builder.
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct StencilStateDynamic {
|
||||
|
@ -25,8 +25,8 @@ use crate::command_buffer::CommandBufferExecError;
|
||||
use crate::command_buffer::ImageUninitializedSafe;
|
||||
use crate::command_buffer::SecondaryCommandBuffer;
|
||||
use crate::command_buffer::SubpassContents;
|
||||
use crate::descriptor_set::builder::DescriptorSetBuilderOutput;
|
||||
use crate::descriptor_set::layout::DescriptorDescTy;
|
||||
use crate::descriptor_set::DescriptorSet;
|
||||
use crate::descriptor_set::DescriptorSetWithOffsets;
|
||||
use crate::format::ClearValue;
|
||||
use crate::image::ImageAccess;
|
||||
@ -58,7 +58,6 @@ use crate::SafeDeref;
|
||||
use crate::VulkanObject;
|
||||
use smallvec::SmallVec;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
use std::ops::Range;
|
||||
@ -1247,7 +1246,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32))
|
||||
{
|
||||
if let Some(buf) = set.buffer(num) {
|
||||
return buf.0;
|
||||
@ -1262,7 +1261,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32)))
|
||||
{
|
||||
if let Some(buf) = set.buffer(num) {
|
||||
return format!("Buffer bound to set {} descriptor {}", set_num, buf.1)
|
||||
@ -1278,7 +1277,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32))
|
||||
{
|
||||
if let Some(img) = set.image(num) {
|
||||
return img.0.image();
|
||||
@ -1293,7 +1292,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32)))
|
||||
{
|
||||
if let Some(img) = set.image(num) {
|
||||
return format!("Image bound to set {} descriptor {}", set_num, img.1)
|
||||
@ -1360,7 +1359,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32))
|
||||
{
|
||||
if let Some(buf) = set.buffer(num) {
|
||||
return buf.0;
|
||||
@ -1378,7 +1377,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32)))
|
||||
{
|
||||
if let Some(buf) = set.buffer(num) {
|
||||
return format!("Buffer bound to set {} descriptor {}", set_num, buf.1)
|
||||
@ -1397,7 +1396,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32))
|
||||
{
|
||||
if let Some(img) = set.image(num) {
|
||||
return img.0.image();
|
||||
@ -1412,7 +1411,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32)))
|
||||
{
|
||||
if let Some(img) = set.image(num) {
|
||||
return format!("Image bound to set {} descriptor {}", set_num, img.1)
|
||||
@ -1487,7 +1486,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32))
|
||||
{
|
||||
if let Some(buf) = set.buffer(num) {
|
||||
return buf.0;
|
||||
@ -1514,7 +1513,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32)))
|
||||
{
|
||||
if let Some(buf) = set.buffer(num) {
|
||||
return format!("Buffer bound to set {} descriptor {}", set_num, buf.1)
|
||||
@ -1542,7 +1541,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32))
|
||||
{
|
||||
if let Some(img) = set.image(num) {
|
||||
return img.0.image();
|
||||
@ -1557,7 +1556,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32)))
|
||||
{
|
||||
if let Some(img) = set.image(num) {
|
||||
return format!("Image bound to set {} descriptor {}", set_num, img.1)
|
||||
@ -1640,7 +1639,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32))
|
||||
{
|
||||
if let Some(buf) = set.buffer(num) {
|
||||
return buf.0;
|
||||
@ -1671,7 +1670,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32)))
|
||||
{
|
||||
if let Some(buf) = set.buffer(num) {
|
||||
return format!("Buffer bound to set {} descriptor {}", set_num, buf.1)
|
||||
@ -1703,7 +1702,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32))
|
||||
{
|
||||
if let Some(img) = set.image(num) {
|
||||
return img.0.image();
|
||||
@ -1718,7 +1717,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32)))
|
||||
{
|
||||
if let Some(img) = set.image(num) {
|
||||
return format!("Image bound to set {} descriptor {}", set_num, img.1)
|
||||
@ -1799,7 +1798,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32))
|
||||
{
|
||||
if let Some(buf) = set.buffer(num) {
|
||||
return buf.0;
|
||||
@ -1830,7 +1829,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32)))
|
||||
{
|
||||
if let Some(buf) = set.buffer(num) {
|
||||
return format!("Buffer bound to set {} descriptor {}", set_num, buf.1)
|
||||
@ -1862,7 +1861,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32))
|
||||
{
|
||||
if let Some(img) = set.image(num) {
|
||||
return img.0.image();
|
||||
@ -1877,7 +1876,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32)))
|
||||
{
|
||||
if let Some(img) = set.image(num) {
|
||||
return format!("Image bound to set {} descriptor {}", set_num, img.1)
|
||||
@ -1957,7 +1956,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32))
|
||||
{
|
||||
if let Some(buf) = set.buffer(num) {
|
||||
return buf.0;
|
||||
@ -1990,7 +1989,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32)))
|
||||
{
|
||||
if let Some(buf) = set.buffer(num) {
|
||||
return format!("Buffer bound to set {} descriptor {}", set_num, buf.1)
|
||||
@ -2024,7 +2023,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32))
|
||||
{
|
||||
if let Some(img) = set.image(num) {
|
||||
return img.0.image();
|
||||
@ -2039,7 +2038,7 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
|
||||
.map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32)))
|
||||
{
|
||||
if let Some(img) = set.image(num) {
|
||||
return format!("Image bound to set {} descriptor {}", set_num, img.1)
|
||||
@ -2282,6 +2281,61 @@ impl SyncCommandBufferBuilder {
|
||||
self.current_state.push_constants_pipeline_layout = Some(pipeline_layout);
|
||||
}
|
||||
|
||||
/// Calls `vkCmdPushDescriptorSetKHR` on the builder.
|
||||
pub unsafe fn push_descriptor_set(
|
||||
&mut self,
|
||||
pipeline_bind_point: PipelineBindPoint,
|
||||
pipeline_layout: Arc<PipelineLayout>,
|
||||
set_num: u32,
|
||||
descriptor_writes: DescriptorSetBuilderOutput,
|
||||
) {
|
||||
struct Cmd {
|
||||
pipeline_bind_point: PipelineBindPoint,
|
||||
pipeline_layout: Arc<PipelineLayout>,
|
||||
set_num: u32,
|
||||
descriptor_writes: DescriptorSetBuilderOutput,
|
||||
}
|
||||
|
||||
impl Command for Cmd {
|
||||
fn name(&self) -> &'static str {
|
||||
"vkCmdPushDescriptorSetKHR"
|
||||
}
|
||||
|
||||
unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
|
||||
out.push_descriptor_set(
|
||||
self.pipeline_bind_point,
|
||||
&self.pipeline_layout,
|
||||
self.set_num,
|
||||
self.descriptor_writes.writes(),
|
||||
);
|
||||
}
|
||||
|
||||
fn bound_descriptor_set(&self, num: u32) -> SetOrPush {
|
||||
debug_assert!(num == self.set_num);
|
||||
SetOrPush::Push(&self.descriptor_writes)
|
||||
}
|
||||
}
|
||||
|
||||
self.append_command(
|
||||
Cmd {
|
||||
pipeline_bind_point,
|
||||
pipeline_layout: pipeline_layout.clone(),
|
||||
set_num,
|
||||
descriptor_writes,
|
||||
},
|
||||
&[],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
self.current_state.invalidate_descriptor_sets(
|
||||
pipeline_bind_point,
|
||||
pipeline_layout,
|
||||
set_num,
|
||||
1,
|
||||
self.commands.last().unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Calls `vkCmdResetEvent` on the builder.
|
||||
#[inline]
|
||||
pub unsafe fn reset_event(&mut self, event: Arc<Event>, stages: PipelineStages) {
|
||||
@ -3266,7 +3320,7 @@ impl SyncCommandBufferBuilder {
|
||||
for ds in descriptor_sets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
|
||||
.map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32))
|
||||
{
|
||||
for buf_num in 0..ds.num_buffers() {
|
||||
let desc = ds
|
||||
@ -3511,9 +3565,10 @@ impl<'b> SyncCommandBufferBuilderBindDescriptorSets<'b> {
|
||||
);
|
||||
}
|
||||
|
||||
fn bound_descriptor_set(&self, set_num: u32) -> (&dyn DescriptorSet, &[u32]) {
|
||||
fn bound_descriptor_set(&self, set_num: u32) -> SetOrPush {
|
||||
let index = set_num.checked_sub(self.first_set).unwrap() as usize;
|
||||
self.descriptor_sets[index].as_ref()
|
||||
let (set, offset) = self.descriptor_sets[index].as_ref();
|
||||
SetOrPush::Set(set, offset)
|
||||
}
|
||||
}
|
||||
|
||||
@ -3530,65 +3585,13 @@ impl<'b> SyncCommandBufferBuilderBindDescriptorSets<'b> {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let cmd = self.builder.commands.last().unwrap();
|
||||
let state = match self
|
||||
.builder
|
||||
.current_state
|
||||
.descriptor_sets
|
||||
.entry(pipeline_bind_point)
|
||||
{
|
||||
Entry::Vacant(entry) => entry.insert(DescriptorSetState {
|
||||
descriptor_sets: Default::default(),
|
||||
pipeline_layout,
|
||||
}),
|
||||
Entry::Occupied(entry) => {
|
||||
let state = entry.into_mut();
|
||||
|
||||
let invalidate_from = if state.pipeline_layout.internal_object()
|
||||
== pipeline_layout.internal_object()
|
||||
{
|
||||
// If we're still using the exact same layout, then of course it's compatible.
|
||||
None
|
||||
} else if state.pipeline_layout.push_constant_ranges()
|
||||
!= pipeline_layout.push_constant_ranges()
|
||||
{
|
||||
// If the push constant ranges don't match,
|
||||
// all bound descriptor sets are disturbed.
|
||||
Some(0)
|
||||
} else {
|
||||
// Find the first descriptor set layout in the current pipeline layout that
|
||||
// isn't compatible with the corresponding set in the new pipeline layout.
|
||||
// If an incompatible set was found, all bound sets from that slot onwards will
|
||||
// be disturbed.
|
||||
let current_layouts = state.pipeline_layout.descriptor_set_layouts();
|
||||
let new_layouts = pipeline_layout.descriptor_set_layouts();
|
||||
let max = (current_layouts.len() as u32).min(first_set + num_descriptor_sets);
|
||||
(0..max).find(|&num| {
|
||||
let num = num as usize;
|
||||
!current_layouts[num].is_compatible_with(&new_layouts[num])
|
||||
})
|
||||
};
|
||||
|
||||
if let Some(invalidate_from) = invalidate_from {
|
||||
// Remove disturbed sets and set new pipeline layout.
|
||||
state
|
||||
.descriptor_sets
|
||||
.retain(|&num, _| num < invalidate_from);
|
||||
state.pipeline_layout = pipeline_layout;
|
||||
} else if (first_set + num_descriptor_sets) as usize
|
||||
>= state.pipeline_layout.descriptor_set_layouts().len()
|
||||
{
|
||||
// New layout is a superset of the old one.
|
||||
state.pipeline_layout = pipeline_layout;
|
||||
}
|
||||
|
||||
state
|
||||
}
|
||||
};
|
||||
|
||||
for i in 0..num_descriptor_sets {
|
||||
state.descriptor_sets.insert(first_set + i, cmd.clone());
|
||||
}
|
||||
self.builder.current_state.invalidate_descriptor_sets(
|
||||
pipeline_bind_point,
|
||||
pipeline_layout,
|
||||
first_set,
|
||||
num_descriptor_sets,
|
||||
self.builder.commands.last().unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,6 +65,7 @@
|
||||
//! queue with a fresh new barrier prototype.
|
||||
|
||||
pub use self::builder::CommandBufferState;
|
||||
pub use self::builder::SetOrPush;
|
||||
pub use self::builder::StencilOpStateDynamic;
|
||||
pub use self::builder::StencilStateDynamic;
|
||||
pub use self::builder::SyncCommandBufferBuilder;
|
||||
@ -77,7 +78,6 @@ use crate::command_buffer::sys::UnsafeCommandBuffer;
|
||||
use crate::command_buffer::sys::UnsafeCommandBufferBuilder;
|
||||
use crate::command_buffer::CommandBufferExecError;
|
||||
use crate::command_buffer::ImageUninitializedSafe;
|
||||
use crate::descriptor_set::DescriptorSet;
|
||||
use crate::device::Device;
|
||||
use crate::device::DeviceOwned;
|
||||
use crate::device::Queue;
|
||||
@ -492,7 +492,7 @@ trait Command: Send + Sync {
|
||||
panic!()
|
||||
}
|
||||
|
||||
fn bound_descriptor_set(&self, set_num: u32) -> (&dyn DescriptorSet, &[u32]) {
|
||||
fn bound_descriptor_set(&self, set_num: u32) -> SetOrPush {
|
||||
panic!()
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ use crate::command_buffer::CommandBufferLevel;
|
||||
use crate::command_buffer::CommandBufferUsage;
|
||||
use crate::command_buffer::SecondaryCommandBuffer;
|
||||
use crate::command_buffer::SubpassContents;
|
||||
use crate::descriptor_set::sys::DescriptorWrite;
|
||||
use crate::descriptor_set::sys::UnsafeDescriptorSet;
|
||||
use crate::device::Device;
|
||||
use crate::device::DeviceOwned;
|
||||
@ -1354,6 +1355,41 @@ impl UnsafeCommandBufferBuilder {
|
||||
);
|
||||
}
|
||||
|
||||
/// Calls `vkCmdPushDescriptorSetKHR` on the builder.
|
||||
///
|
||||
/// If the list is empty then the command is automatically ignored.
|
||||
#[inline]
|
||||
pub unsafe fn push_descriptor_set(
|
||||
&mut self,
|
||||
pipeline_bind_point: PipelineBindPoint,
|
||||
pipeline_layout: &PipelineLayout,
|
||||
set_num: u32,
|
||||
descriptor_writes: &[DescriptorWrite],
|
||||
) {
|
||||
debug_assert!(self.device().enabled_extensions().khr_push_descriptor);
|
||||
|
||||
if descriptor_writes.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let fns = self.device().fns();
|
||||
let cmd = self.internal_object();
|
||||
|
||||
let raw_writes: SmallVec<[_; 8]> = descriptor_writes
|
||||
.iter()
|
||||
.map(|write| write.to_vulkan(ash::vk::DescriptorSet::null()))
|
||||
.collect();
|
||||
|
||||
fns.khr_push_descriptor.cmd_push_descriptor_set_khr(
|
||||
cmd,
|
||||
pipeline_bind_point.into(),
|
||||
pipeline_layout.internal_object(),
|
||||
set_num,
|
||||
raw_writes.len() as u32,
|
||||
raw_writes.as_ptr(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Calls `vkCmdResetEvent` on the builder.
|
||||
#[inline]
|
||||
pub unsafe fn reset_event(&mut self, event: &Event, stages: PipelineStages) {
|
||||
|
@ -8,6 +8,7 @@
|
||||
// according to those terms.
|
||||
|
||||
use crate::command_buffer::synced::CommandBufferState;
|
||||
use crate::command_buffer::synced::SetOrPush;
|
||||
use crate::descriptor_set::layout::DescriptorSetCompatibilityError;
|
||||
use crate::pipeline::layout::PipelineLayout;
|
||||
use crate::pipeline::PipelineBindPoint;
|
||||
@ -46,7 +47,12 @@ pub(in super::super) fn check_descriptor_sets_validity(
|
||||
None => return Err(CheckDescriptorSetsValidityError::MissingDescriptorSet { set_num }),
|
||||
};
|
||||
|
||||
match pipeline_set.ensure_compatible_with_bind(descriptor_set.0.layout()) {
|
||||
let descriptor_set_layout = match descriptor_set {
|
||||
SetOrPush::Set(descriptor_set, _dynamic_offsets) => descriptor_set.layout(),
|
||||
SetOrPush::Push(descriptor_writes) => descriptor_writes.layout(),
|
||||
};
|
||||
|
||||
match pipeline_set.ensure_compatible_with_bind(descriptor_set_layout) {
|
||||
Ok(_) => (),
|
||||
Err(error) => {
|
||||
return Err(
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -55,7 +55,8 @@ use std::sync::Arc;
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct DescriptorSetDesc {
|
||||
descriptors: SmallVec<[Option<DescriptorDesc>; 32]>,
|
||||
descriptors: SmallVec<[Option<DescriptorDesc>; 4]>,
|
||||
push_descriptor: bool,
|
||||
}
|
||||
|
||||
impl DescriptorSetDesc {
|
||||
@ -71,6 +72,7 @@ impl DescriptorSetDesc {
|
||||
{
|
||||
DescriptorSetDesc {
|
||||
descriptors: descriptors.into_iter().collect(),
|
||||
push_descriptor: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,10 +81,12 @@ impl DescriptorSetDesc {
|
||||
pub fn empty() -> DescriptorSetDesc {
|
||||
DescriptorSetDesc {
|
||||
descriptors: SmallVec::new(),
|
||||
push_descriptor: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the descriptors in the set.
|
||||
#[inline]
|
||||
pub fn bindings(&self) -> &[Option<DescriptorDesc>] {
|
||||
&self.descriptors
|
||||
}
|
||||
@ -93,6 +97,12 @@ impl DescriptorSetDesc {
|
||||
self.descriptors.get(num as usize).and_then(|b| b.as_ref())
|
||||
}
|
||||
|
||||
/// Returns whether the description is set to be a push descriptor.
|
||||
#[inline]
|
||||
pub fn is_push_descriptor(&self) -> bool {
|
||||
self.push_descriptor
|
||||
}
|
||||
|
||||
/// Builds the union of this layout description and another.
|
||||
#[inline]
|
||||
pub fn union(
|
||||
@ -116,7 +126,10 @@ impl DescriptorSetDesc {
|
||||
)
|
||||
})
|
||||
.collect::<Result<_, ()>>()?;
|
||||
Ok(DescriptorSetDesc { descriptors })
|
||||
Ok(DescriptorSetDesc {
|
||||
descriptors,
|
||||
push_descriptor: false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Builds the union of multiple descriptor sets.
|
||||
@ -139,7 +152,16 @@ impl DescriptorSetDesc {
|
||||
}
|
||||
|
||||
/// Changes a buffer descriptor's type to dynamic.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// - Panics if the description is set to be a push descriptor.
|
||||
/// - Panics if `binding_num` does not refer to a `StorageBuffer` or `UniformBuffer` descriptor.
|
||||
pub fn set_buffer_dynamic(&mut self, binding_num: u32) {
|
||||
assert!(
|
||||
!self.push_descriptor,
|
||||
"push descriptor is enabled, which does not allow dynamic buffer descriptors"
|
||||
);
|
||||
assert!(
|
||||
self.descriptor(binding_num).map_or(false, |desc| matches!(
|
||||
desc.ty,
|
||||
@ -197,6 +219,30 @@ impl DescriptorSetDesc {
|
||||
immutable_samplers.extend(samplers.into_iter());
|
||||
}
|
||||
|
||||
/// Sets the descriptor set layout to use push descriptors instead of descriptor sets.
|
||||
///
|
||||
/// If set to enabled, the
|
||||
/// [`khr_push_descriptor`](crate::device::DeviceExtensions::khr_push_descriptor) extension must
|
||||
/// be enabled on the device.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// - If enabled, panics if the description contains a dynamic buffer descriptor.
|
||||
pub fn set_push_descriptor(&mut self, enabled: bool) {
|
||||
if enabled {
|
||||
assert!(
|
||||
!self.descriptors.iter().flatten().any(|desc| {
|
||||
matches!(
|
||||
desc.ty.ty(),
|
||||
DescriptorType::UniformBufferDynamic | DescriptorType::StorageBufferDynamic
|
||||
)
|
||||
}),
|
||||
"descriptor set contains a dynamic buffer descriptor"
|
||||
);
|
||||
}
|
||||
self.push_descriptor = enabled;
|
||||
}
|
||||
|
||||
/// Sets the descriptor count for a descriptor that has a variable count.
|
||||
pub fn set_variable_descriptor_count(&mut self, binding_num: u32, descriptor_count: u32) {
|
||||
// TODO: Errors instead of panic
|
||||
@ -221,9 +267,13 @@ impl DescriptorSetDesc {
|
||||
///
|
||||
/// "Compatible" in this sense is defined by the Vulkan specification under the section
|
||||
/// "Pipeline layout compatibility": the two must be identically defined to the Vulkan API,
|
||||
/// meaning that all descriptors are compatible.
|
||||
/// meaning that all descriptors are compatible and flags are identical.
|
||||
#[inline]
|
||||
pub fn is_compatible_with(&self, other: &DescriptorSetDesc) -> bool {
|
||||
if self.push_descriptor != other.push_descriptor {
|
||||
return false;
|
||||
}
|
||||
|
||||
let num_bindings = cmp::max(self.descriptors.len(), other.descriptors.len()) as u32;
|
||||
(0..num_bindings).all(|binding_num| {
|
||||
match (self.descriptor(binding_num), other.descriptor(binding_num)) {
|
||||
@ -240,6 +290,8 @@ impl DescriptorSetDesc {
|
||||
&self,
|
||||
other: &DescriptorSetDesc,
|
||||
) -> Result<(), DescriptorSetCompatibilityError> {
|
||||
// Don't care about push descriptors.
|
||||
|
||||
if self.descriptors.len() < other.descriptors.len() {
|
||||
return Err(DescriptorSetCompatibilityError::DescriptorsCountMismatch {
|
||||
self_num: self.descriptors.len() as u32,
|
||||
@ -276,12 +328,22 @@ impl DescriptorSetDesc {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Checks whether the descriptor of a pipeline layout `self` is compatible with the descriptor
|
||||
/// of a descriptor set being bound `other`.
|
||||
/// Checks whether the descriptor set of a pipeline layout `self` is compatible with the
|
||||
/// descriptor set being bound `other`.
|
||||
///
|
||||
/// This performs the same check as `is_compatible_with`, but additionally ensures that the
|
||||
/// shader can accept the binding.
|
||||
pub fn ensure_compatible_with_bind(
|
||||
&self,
|
||||
other: &DescriptorSetDesc,
|
||||
) -> Result<(), DescriptorSetCompatibilityError> {
|
||||
if self.push_descriptor != other.push_descriptor {
|
||||
return Err(DescriptorSetCompatibilityError::PushDescriptorMismatch {
|
||||
self_enabled: self.push_descriptor,
|
||||
other_enabled: other.push_descriptor,
|
||||
});
|
||||
}
|
||||
|
||||
if self.descriptors.len() != other.descriptors.len() {
|
||||
return Err(DescriptorSetCompatibilityError::DescriptorsCountMismatch {
|
||||
self_num: self.descriptors.len() as u32,
|
||||
@ -327,6 +389,7 @@ where
|
||||
fn from(val: I) -> Self {
|
||||
DescriptorSetDesc {
|
||||
descriptors: val.into_iter().collect(),
|
||||
push_descriptor: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -790,6 +853,12 @@ pub enum DescriptorSetCompatibilityError {
|
||||
error: DescriptorCompatibilityError,
|
||||
binding_num: u32,
|
||||
},
|
||||
|
||||
/// The push descriptor settings of the two sets are not compatible.
|
||||
PushDescriptorMismatch {
|
||||
self_enabled: bool,
|
||||
other_enabled: bool,
|
||||
},
|
||||
}
|
||||
|
||||
impl error::Error for DescriptorSetCompatibilityError {
|
||||
@ -807,18 +876,23 @@ impl error::Error for DescriptorSetCompatibilityError {
|
||||
impl fmt::Display for DescriptorSetCompatibilityError {
|
||||
#[inline]
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
write!(
|
||||
fmt,
|
||||
"{}",
|
||||
match *self {
|
||||
DescriptorSetCompatibilityError::DescriptorsCountMismatch { .. } => {
|
||||
"the number of descriptors in the two sets is not compatible."
|
||||
}
|
||||
DescriptorSetCompatibilityError::IncompatibleDescriptors { .. } => {
|
||||
"two descriptors are incompatible"
|
||||
}
|
||||
match *self {
|
||||
DescriptorSetCompatibilityError::DescriptorsCountMismatch { .. } => {
|
||||
write!(
|
||||
fmt,
|
||||
"the number of descriptors in the two sets is not compatible"
|
||||
)
|
||||
}
|
||||
)
|
||||
DescriptorSetCompatibilityError::IncompatibleDescriptors { .. } => {
|
||||
write!(fmt, "two descriptors are incompatible")
|
||||
}
|
||||
DescriptorSetCompatibilityError::PushDescriptorMismatch { .. } => {
|
||||
write!(
|
||||
fmt,
|
||||
"the push descriptor settings of the two sets are not compatible"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -828,9 +902,6 @@ pub enum DescriptorCompatibilityError {
|
||||
/// The number of descriptors is not compatible.
|
||||
DescriptorCount { first: u32, 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, second: bool },
|
||||
|
||||
@ -866,6 +937,9 @@ pub enum DescriptorCompatibilityError {
|
||||
first: DescriptorType,
|
||||
second: DescriptorType,
|
||||
},
|
||||
|
||||
/// The variable counts of the descriptors is not compatible.
|
||||
VariableCount { first: bool, second: bool },
|
||||
}
|
||||
|
||||
impl error::Error for DescriptorCompatibilityError {}
|
||||
|
@ -12,6 +12,7 @@ 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::layout::DescriptorType;
|
||||
use crate::descriptor_set::pool::DescriptorsCount;
|
||||
use crate::device::Device;
|
||||
use crate::device::DeviceOwned;
|
||||
@ -31,7 +32,7 @@ pub struct DescriptorSetLayout {
|
||||
device: Arc<Device>,
|
||||
// Descriptors.
|
||||
desc: DescriptorSetDesc,
|
||||
// Number of descriptors.
|
||||
// Number of descriptors of each type.
|
||||
descriptors_count: DescriptorsCount,
|
||||
// Number of descriptors in a variable count descriptor. Will be zero if no variable count descriptors are present.
|
||||
variable_descriptor_count: u32,
|
||||
@ -45,21 +46,38 @@ impl DescriptorSetLayout {
|
||||
/// empty, you can make the iterator yield `None` for an element.
|
||||
pub fn new<D>(
|
||||
device: Arc<Device>,
|
||||
desc: D,
|
||||
set_desc: D,
|
||||
) -> Result<DescriptorSetLayout, DescriptorSetLayoutError>
|
||||
where
|
||||
D: Into<DescriptorSetDesc>,
|
||||
{
|
||||
let desc = desc.into();
|
||||
let set_desc = set_desc.into();
|
||||
let mut descriptors_count = DescriptorsCount::zero();
|
||||
let mut variable_descriptor_count = 0;
|
||||
let bindings = desc.bindings();
|
||||
let bindings = set_desc.bindings();
|
||||
let mut bindings_vk = Vec::with_capacity(bindings.len());
|
||||
let mut binding_flags_vk = Vec::with_capacity(bindings.len());
|
||||
let mut immutable_samplers_vk: Vec<Box<[ash::vk::Sampler]>> = Vec::new(); // only to keep the arrays of handles alive
|
||||
|
||||
for (binding, desc) in bindings.iter().enumerate() {
|
||||
let desc = match desc {
|
||||
let mut flags = ash::vk::DescriptorSetLayoutCreateFlags::empty();
|
||||
|
||||
if set_desc.is_push_descriptor() {
|
||||
if !device.enabled_extensions().khr_push_descriptor {
|
||||
return Err(DescriptorSetLayoutError::ExtensionNotEnabled {
|
||||
extension: "khr_push_descriptor",
|
||||
reason: "description was set to be a push descriptor",
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: VUID-VkDescriptorSetLayoutCreateInfo-flags-04590
|
||||
// If flags contains VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR, flags must
|
||||
// not contain VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE
|
||||
|
||||
flags |= ash::vk::DescriptorSetLayoutCreateFlags::PUSH_DESCRIPTOR_KHR;
|
||||
}
|
||||
|
||||
for (binding, binding_desc) in bindings.iter().enumerate() {
|
||||
let binding_desc = match binding_desc {
|
||||
Some(d) => d,
|
||||
None => continue,
|
||||
};
|
||||
@ -67,15 +85,34 @@ impl DescriptorSetLayout {
|
||||
// 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 = binding_desc.ty.ty();
|
||||
|
||||
if set_desc.is_push_descriptor() {
|
||||
if matches!(
|
||||
ty,
|
||||
DescriptorType::StorageBufferDynamic | DescriptorType::UniformBufferDynamic
|
||||
) {
|
||||
return Err(DescriptorSetLayoutError::PushDescriptorDynamicBuffer);
|
||||
}
|
||||
|
||||
// TODO: VUID-VkDescriptorSetLayoutCreateInfo-flags-02208
|
||||
// If flags contains VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR, then all
|
||||
// elements of pBindings must not have a descriptorType of
|
||||
// VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT
|
||||
|
||||
// TODO: VUID-VkDescriptorSetLayoutCreateInfo-flags-04591
|
||||
// If flags contains VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR,
|
||||
// pBindings must not have a descriptorType of VK_DESCRIPTOR_TYPE_MUTABLE_VALVE
|
||||
}
|
||||
|
||||
descriptors_count.add_num(ty, binding_desc.descriptor_count);
|
||||
let mut binding_flags = ash::vk::DescriptorBindingFlags::empty();
|
||||
let immutable_samplers = desc.ty.immutable_samplers();
|
||||
let immutable_samplers = binding_desc.ty.immutable_samplers();
|
||||
|
||||
let p_immutable_samplers = if !immutable_samplers.is_empty() {
|
||||
if desc.descriptor_count != immutable_samplers.len() as u32 {
|
||||
if binding_desc.descriptor_count != immutable_samplers.len() as u32 {
|
||||
return Err(DescriptorSetLayoutError::ImmutableSamplersCountMismatch {
|
||||
descriptor_count: desc.descriptor_count,
|
||||
descriptor_count: binding_desc.descriptor_count,
|
||||
sampler_count: immutable_samplers.len() as u32,
|
||||
});
|
||||
}
|
||||
@ -97,43 +134,42 @@ impl DescriptorSetLayout {
|
||||
ptr::null()
|
||||
};
|
||||
|
||||
if desc.variable_count {
|
||||
if binding_desc.variable_count {
|
||||
if binding != bindings.len() - 1 {
|
||||
return Err(DescriptorSetLayoutError::VariableCountDescMustBeLast);
|
||||
}
|
||||
|
||||
if desc.ty == DescriptorDescTy::UniformBufferDynamic
|
||||
|| desc.ty == DescriptorDescTy::StorageBufferDynamic
|
||||
if binding_desc.ty == DescriptorDescTy::UniformBufferDynamic
|
||||
|| binding_desc.ty == DescriptorDescTy::StorageBufferDynamic
|
||||
{
|
||||
return Err(DescriptorSetLayoutError::VariableCountDescMustNotBeDynamic);
|
||||
}
|
||||
|
||||
if !device.enabled_features().runtime_descriptor_array {
|
||||
return Err(DescriptorSetLayoutError::VariableCountIncompatibleDevice(
|
||||
IncompatibleDevice::MissingFeature(MissingFeature::RuntimeDescriptorArray),
|
||||
));
|
||||
return Err(DescriptorSetLayoutError::FeatureNotEnabled {
|
||||
feature: "runtime_descriptor_array",
|
||||
reason: "binding has a variable count",
|
||||
});
|
||||
}
|
||||
|
||||
if !device
|
||||
.enabled_features()
|
||||
.descriptor_binding_variable_descriptor_count
|
||||
{
|
||||
return Err(DescriptorSetLayoutError::VariableCountIncompatibleDevice(
|
||||
IncompatibleDevice::MissingFeature(
|
||||
MissingFeature::DescriptorBindingVariableDescriptorCount,
|
||||
),
|
||||
));
|
||||
return Err(DescriptorSetLayoutError::FeatureNotEnabled {
|
||||
feature: "descriptor_binding_variable_descriptor_count",
|
||||
reason: "binding has a variable count",
|
||||
});
|
||||
}
|
||||
|
||||
if !device.enabled_features().descriptor_binding_partially_bound {
|
||||
return Err(DescriptorSetLayoutError::VariableCountIncompatibleDevice(
|
||||
IncompatibleDevice::MissingFeature(
|
||||
MissingFeature::DescriptorBindingPartiallyBound,
|
||||
),
|
||||
));
|
||||
return Err(DescriptorSetLayoutError::FeatureNotEnabled {
|
||||
feature: "descriptor_binding_partially_bound",
|
||||
reason: "binding has a variable count",
|
||||
});
|
||||
}
|
||||
|
||||
variable_descriptor_count = desc.descriptor_count;
|
||||
variable_descriptor_count = binding_desc.descriptor_count;
|
||||
// TODO: should these be settable separately by the user?
|
||||
binding_flags |= ash::vk::DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT;
|
||||
binding_flags |= ash::vk::DescriptorBindingFlags::PARTIALLY_BOUND;
|
||||
@ -142,20 +178,37 @@ impl DescriptorSetLayout {
|
||||
bindings_vk.push(ash::vk::DescriptorSetLayoutBinding {
|
||||
binding: binding as u32,
|
||||
descriptor_type: ty.into(),
|
||||
descriptor_count: desc.descriptor_count,
|
||||
stage_flags: desc.stages.into(),
|
||||
descriptor_count: binding_desc.descriptor_count,
|
||||
stage_flags: binding_desc.stages.into(),
|
||||
p_immutable_samplers,
|
||||
});
|
||||
binding_flags_vk.push(binding_flags);
|
||||
}
|
||||
|
||||
// Note that it seems legal to have no descriptor at all in the set.
|
||||
if set_desc.is_push_descriptor()
|
||||
&& descriptors_count.total()
|
||||
> device
|
||||
.physical_device()
|
||||
.properties()
|
||||
.max_push_descriptors
|
||||
.unwrap_or(0)
|
||||
{
|
||||
return Err(DescriptorSetLayoutError::MaxPushDescriptorsExceeded {
|
||||
max: device
|
||||
.physical_device()
|
||||
.properties()
|
||||
.max_push_descriptors
|
||||
.unwrap_or(0),
|
||||
obtained: descriptors_count.total(),
|
||||
});
|
||||
}
|
||||
|
||||
let handle = unsafe {
|
||||
let binding_flags_infos = if device.api_version() >= Version::V1_2
|
||||
|| device.enabled_extensions().ext_descriptor_indexing
|
||||
{
|
||||
Some(ash::vk::DescriptorSetLayoutBindingFlagsCreateInfo {
|
||||
// Note that it seems legal to have no descriptor at all in the set.
|
||||
binding_count: binding_flags_vk.len() as u32,
|
||||
p_binding_flags: binding_flags_vk.as_ptr(),
|
||||
..Default::default()
|
||||
@ -165,7 +218,7 @@ impl DescriptorSetLayout {
|
||||
};
|
||||
|
||||
let infos = ash::vk::DescriptorSetLayoutCreateInfo {
|
||||
flags: ash::vk::DescriptorSetLayoutCreateFlags::empty(),
|
||||
flags,
|
||||
binding_count: bindings_vk.len() as u32,
|
||||
p_bindings: bindings_vk.as_ptr(),
|
||||
p_next: if let Some(next) = binding_flags_infos.as_ref() {
|
||||
@ -193,7 +246,7 @@ impl DescriptorSetLayout {
|
||||
Ok(DescriptorSetLayout {
|
||||
handle,
|
||||
device,
|
||||
desc,
|
||||
desc: set_desc,
|
||||
descriptors_count,
|
||||
variable_descriptor_count,
|
||||
})
|
||||
@ -285,11 +338,17 @@ impl Drop for DescriptorSetLayout {
|
||||
}
|
||||
}
|
||||
|
||||
/// Error related to descriptor set layout
|
||||
/// Error related to descriptor set layout.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum DescriptorSetLayoutError {
|
||||
/// Out of Memory
|
||||
OomError(OomError),
|
||||
ExtensionNotEnabled {
|
||||
extension: &'static str,
|
||||
reason: &'static str,
|
||||
},
|
||||
FeatureNotEnabled {
|
||||
feature: &'static str,
|
||||
reason: &'static str,
|
||||
},
|
||||
|
||||
/// The number of immutable samplers does not match the descriptor count.
|
||||
ImmutableSamplersCountMismatch {
|
||||
@ -297,42 +356,25 @@ pub enum DescriptorSetLayoutError {
|
||||
sampler_count: u32,
|
||||
},
|
||||
|
||||
/// Variable count descriptor must be last binding
|
||||
/// The maximum number of push descriptors has been exceeded.
|
||||
MaxPushDescriptorsExceeded {
|
||||
/// Maximum allowed value.
|
||||
max: u32,
|
||||
/// Value that was passed.
|
||||
obtained: u32,
|
||||
},
|
||||
|
||||
/// Out of Memory.
|
||||
OomError(OomError),
|
||||
|
||||
/// The layout was being created for push descriptors, but included a dynamic buffer descriptor.
|
||||
PushDescriptorDynamicBuffer,
|
||||
|
||||
/// Variable count descriptor must be last binding.
|
||||
VariableCountDescMustBeLast,
|
||||
|
||||
/// Variable count descriptor must not be a dynamic buffer
|
||||
/// 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 {
|
||||
@ -346,21 +388,45 @@ 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::ImmutableSamplersCountMismatch { .. } =>
|
||||
"the number of immutable samplers does not match the descriptor count",
|
||||
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",
|
||||
match *self {
|
||||
Self::ExtensionNotEnabled { extension, reason } => {
|
||||
write!(
|
||||
fmt,
|
||||
"the extension {} must be enabled: {}",
|
||||
extension, reason
|
||||
)
|
||||
}
|
||||
)
|
||||
Self::FeatureNotEnabled { feature, reason } => {
|
||||
write!(fmt, "the feature {} must be enabled: {}", feature, reason)
|
||||
}
|
||||
Self::ImmutableSamplersCountMismatch { .. } => {
|
||||
write!(
|
||||
fmt,
|
||||
"the number of immutable samplers does not match the descriptor count"
|
||||
)
|
||||
}
|
||||
Self::MaxPushDescriptorsExceeded { .. } => {
|
||||
write!(
|
||||
fmt,
|
||||
"the maximum number of push descriptors has been exceeded"
|
||||
)
|
||||
}
|
||||
Self::PushDescriptorDynamicBuffer => {
|
||||
write!(fmt, "the layout was being created for push descriptors, but included a dynamic buffer descriptor")
|
||||
}
|
||||
Self::OomError(_) => {
|
||||
write!(fmt, "out of memory")
|
||||
}
|
||||
Self::VariableCountDescMustBeLast => {
|
||||
write!(fmt, "variable count descriptor must be last binding")
|
||||
}
|
||||
Self::VariableCountDescMustNotBeDynamic => {
|
||||
write!(
|
||||
fmt,
|
||||
"variable count descriptor must not be a dynamic buffer"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,6 +73,7 @@
|
||||
//! - The `DescriptorSetsCollection` trait is implemented on collections of types that implement
|
||||
//! `DescriptorSet`. It is what you pass to the draw functions.
|
||||
|
||||
pub use self::builder::DescriptorSetBuilder;
|
||||
pub use self::collection::DescriptorSetsCollection;
|
||||
use self::layout::DescriptorSetLayout;
|
||||
pub use self::persistent::PersistentDescriptorSet;
|
||||
@ -94,7 +95,7 @@ use std::hash::Hash;
|
||||
use std::hash::Hasher;
|
||||
use std::sync::Arc;
|
||||
|
||||
mod builder;
|
||||
pub mod builder;
|
||||
mod collection;
|
||||
pub mod layout;
|
||||
pub mod persistent;
|
||||
@ -293,9 +294,6 @@ pub enum DescriptorSetError {
|
||||
/// Builder is already within an array.
|
||||
AlreadyInArray,
|
||||
|
||||
/// The builder has previously return an error and is an unknown state.
|
||||
BuilderPoisoned,
|
||||
|
||||
/// The number of array layers of an image doesn't match what was expected.
|
||||
ArrayLayersMismatch {
|
||||
/// Number of expected array layers for the image.
|
||||
@ -320,8 +318,8 @@ pub enum DescriptorSetError {
|
||||
obtained: u32,
|
||||
},
|
||||
|
||||
/// Expected a multisampled image, but got a single-sampled image.
|
||||
ExpectedMultisampled,
|
||||
/// The builder has previously return an error and is an unknown state.
|
||||
BuilderPoisoned,
|
||||
|
||||
/// Operation can not be performed on an empty descriptor.
|
||||
DescriptorIsEmpty,
|
||||
@ -334,6 +332,9 @@ pub enum DescriptorSetError {
|
||||
obtained: u32,
|
||||
},
|
||||
|
||||
/// Expected a multisampled image, but got a single-sampled image.
|
||||
ExpectedMultisampled,
|
||||
|
||||
/// The format of an image view doesn't match what was expected.
|
||||
ImageViewFormatMismatch {
|
||||
/// Expected format.
|
||||
|
@ -22,7 +22,6 @@
|
||||
//! TODO:
|
||||
|
||||
use super::builder::DescriptorSetBuilder;
|
||||
use super::builder::DescriptorSetBuilderOutput;
|
||||
use super::resources::DescriptorSetResources;
|
||||
use super::DescriptorSetError;
|
||||
use crate::buffer::BufferView;
|
||||
@ -52,9 +51,13 @@ pub struct PersistentDescriptorSet<P = StdDescriptorPoolAlloc> {
|
||||
impl PersistentDescriptorSet {
|
||||
/// Starts the process of building a `PersistentDescriptorSet`. Returns a builder.
|
||||
pub fn start(layout: Arc<DescriptorSetLayout>) -> PersistentDescriptorSetBuilder {
|
||||
assert!(
|
||||
!layout.desc().is_push_descriptor(),
|
||||
"the provided descriptor set layout is for push descriptors, and cannot be used to build a descriptor set object"
|
||||
);
|
||||
|
||||
PersistentDescriptorSetBuilder {
|
||||
inner: DescriptorSetBuilder::start(layout),
|
||||
poisoned: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -128,7 +131,6 @@ where
|
||||
/// Prototype of a `PersistentDescriptorSet`.
|
||||
pub struct PersistentDescriptorSetBuilder {
|
||||
inner: DescriptorSetBuilder,
|
||||
poisoned: bool,
|
||||
}
|
||||
|
||||
impl PersistentDescriptorSetBuilder {
|
||||
@ -142,17 +144,8 @@ impl PersistentDescriptorSetBuilder {
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.inner.enter_array()?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Leaves the array. Call this once you added all the elements of the array.
|
||||
@ -160,33 +153,15 @@ impl PersistentDescriptorSetBuilder {
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.inner.leave_array()?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.inner.add_empty()?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Binds a buffer as the next descriptor.
|
||||
@ -197,17 +172,8 @@ impl PersistentDescriptorSetBuilder {
|
||||
&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)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.inner.add_buffer(buffer)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Binds a buffer view as the next descriptor.
|
||||
@ -221,17 +187,8 @@ impl PersistentDescriptorSetBuilder {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.inner.add_buffer_view(view)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Binds an image view as the next descriptor.
|
||||
@ -242,17 +199,8 @@ impl PersistentDescriptorSetBuilder {
|
||||
&mut self,
|
||||
image_view: Arc<dyn ImageViewAbstract + '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)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.inner.add_image(image_view)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Binds an image view with a sampler as the next descriptor.
|
||||
@ -267,17 +215,8 @@ impl PersistentDescriptorSetBuilder {
|
||||
image_view: Arc<dyn ImageViewAbstract + '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)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.inner.add_sampled_image(image_view, sampler)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Binds a sampler as the next descriptor.
|
||||
@ -285,17 +224,8 @@ impl PersistentDescriptorSetBuilder {
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.inner.add_sampler(sampler)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Builds a `PersistentDescriptorSet` from the builder.
|
||||
@ -315,19 +245,10 @@ impl PersistentDescriptorSetBuilder {
|
||||
where
|
||||
P: ?Sized + DescriptorPool,
|
||||
{
|
||||
if self.poisoned {
|
||||
return Err(DescriptorSetError::BuilderPoisoned);
|
||||
}
|
||||
|
||||
let DescriptorSetBuilderOutput {
|
||||
layout,
|
||||
writes,
|
||||
resources,
|
||||
} = self.inner.output()?;
|
||||
|
||||
let (layout, writes, resources) = self.inner.build()?.into();
|
||||
let set = unsafe {
|
||||
let mut set = pool.alloc(&layout)?;
|
||||
set.inner_mut().write(pool.device(), writes.into_iter());
|
||||
set.inner_mut().write(pool.device(), &writes);
|
||||
set
|
||||
};
|
||||
|
||||
|
@ -79,6 +79,13 @@ macro_rules! descriptors_count {
|
||||
)+
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the total number of descriptors.
|
||||
#[inline]
|
||||
pub fn total(&self) -> u32 {
|
||||
std::array::IntoIter::new([$(self.$name,)+]).sum()
|
||||
}
|
||||
|
||||
/// Adds one descriptor of the given type to the count.
|
||||
#[inline]
|
||||
pub fn add_one(&mut self, ty: DescriptorType) {
|
||||
|
@ -160,16 +160,16 @@ impl UnsafeDescriptorPool {
|
||||
|
||||
let layouts: SmallVec<[_; 8]> = layouts
|
||||
.into_iter()
|
||||
.map(|l| {
|
||||
.map(|layout| {
|
||||
assert_eq!(
|
||||
self.device.internal_object(),
|
||||
l.device().internal_object(),
|
||||
"Tried to allocate from a pool with a set layout of a different \
|
||||
device"
|
||||
layout.device().internal_object(),
|
||||
"Tried to allocate from a pool with a set layout of a different device"
|
||||
);
|
||||
debug_assert!(!layout.desc().is_push_descriptor());
|
||||
|
||||
variable_descriptor_counts.push(l.variable_descriptor_count());
|
||||
l.internal_object()
|
||||
variable_descriptor_counts.push(layout.variable_descriptor_count());
|
||||
layout.internal_object()
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -8,7 +8,6 @@
|
||||
// according to those terms.
|
||||
|
||||
use super::builder::DescriptorSetBuilder;
|
||||
use super::builder::DescriptorSetBuilderOutput;
|
||||
use super::resources::DescriptorSetResources;
|
||||
use super::DescriptorSetError;
|
||||
use crate::buffer::BufferView;
|
||||
@ -49,11 +48,14 @@ 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();
|
||||
assert!(
|
||||
!layout.desc().is_push_descriptor(),
|
||||
"the provided descriptor set layout is for push descriptors, and cannot be used to build a descriptor set object"
|
||||
);
|
||||
|
||||
Self {
|
||||
inner: None,
|
||||
device,
|
||||
device: layout.device().clone(),
|
||||
set_count: 4,
|
||||
layout,
|
||||
}
|
||||
@ -68,7 +70,6 @@ impl SingleLayoutDescSetPool {
|
||||
SingleLayoutDescSetBuilder {
|
||||
pool: self,
|
||||
inner: DescriptorSetBuilder::start(layout),
|
||||
poisoned: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,7 +240,6 @@ impl Hash for SingleLayoutDescSet {
|
||||
pub struct SingleLayoutDescSetBuilder<'a> {
|
||||
pool: &'a mut SingleLayoutDescSetPool,
|
||||
inner: DescriptorSetBuilder,
|
||||
poisoned: bool,
|
||||
}
|
||||
|
||||
impl<'a> SingleLayoutDescSetBuilder<'a> {
|
||||
@ -253,17 +253,8 @@ impl<'a> SingleLayoutDescSetBuilder<'a> {
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.inner.enter_array()?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Leaves the array. Call this once you added all the elements of the array.
|
||||
@ -271,33 +262,15 @@ impl<'a> SingleLayoutDescSetBuilder<'a> {
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.inner.leave_array()?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.inner.add_empty()?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Binds a buffer as the next descriptor.
|
||||
@ -308,17 +281,8 @@ impl<'a> SingleLayoutDescSetBuilder<'a> {
|
||||
&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)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.inner.add_buffer(buffer)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Binds a buffer view as the next descriptor.
|
||||
@ -332,17 +296,8 @@ impl<'a> SingleLayoutDescSetBuilder<'a> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.inner.add_buffer_view(view)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Binds an image view as the next descriptor.
|
||||
@ -353,17 +308,8 @@ impl<'a> SingleLayoutDescSetBuilder<'a> {
|
||||
&mut self,
|
||||
image_view: Arc<dyn ImageViewAbstract + '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)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.inner.add_image(image_view)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Binds an image view with a sampler as the next descriptor.
|
||||
@ -378,17 +324,8 @@ impl<'a> SingleLayoutDescSetBuilder<'a> {
|
||||
image_view: Arc<dyn ImageViewAbstract + '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)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.inner.add_sampled_image(image_view, sampler)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Binds a sampler as the next descriptor.
|
||||
@ -396,36 +333,16 @@ impl<'a> SingleLayoutDescSetBuilder<'a> {
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.inner.add_sampler(sampler)?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// 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 (layout, writes, resources) = self.inner.build()?.into();
|
||||
let mut alloc = self.pool.next_alloc()?;
|
||||
unsafe {
|
||||
alloc
|
||||
.inner_mut()
|
||||
.write(&self.pool.device, writes.into_iter());
|
||||
alloc.inner_mut().write(&self.pool.device, &writes);
|
||||
}
|
||||
|
||||
Ok(SingleLayoutDescSet {
|
||||
|
@ -54,170 +54,27 @@ impl UnsafeDescriptorSet {
|
||||
/// command buffer contains a pointer/reference to a descriptor set, it is illegal to write
|
||||
/// to it.
|
||||
///
|
||||
pub unsafe fn write<I>(&mut self, device: &Device, writes: I)
|
||||
where
|
||||
I: IntoIterator<Item = DescriptorWrite>,
|
||||
{
|
||||
pub unsafe fn write(&mut self, device: &Device, writes: &[DescriptorWrite]) {
|
||||
let fns = device.fns();
|
||||
|
||||
// In this function, we build 4 arrays: one array of image descriptors (image_descriptors),
|
||||
// one for buffer descriptors (buffer_descriptors), one for buffer view descriptors
|
||||
// (buffer_views_descriptors), and one for the final list of writes (raw_writes).
|
||||
// Only the final list is passed to Vulkan, but it will contain pointers to the first three
|
||||
// lists in `pImageInfo`, `pBufferInfo` and `pTexelBufferView`.
|
||||
//
|
||||
// In order to handle that, we start by writing null pointers as placeholders in the final
|
||||
// writes, and we store in `raw_writes_img_infos`, `raw_writes_buf_infos` and
|
||||
// `raw_writes_buf_view_infos` the offsets of the pointers compared to the start of the
|
||||
// list.
|
||||
// Once we have finished iterating all the writes requested by the user, we modify
|
||||
// `raw_writes` to point to the correct locations.
|
||||
|
||||
let mut buffer_descriptors: SmallVec<[_; 64]> = SmallVec::new();
|
||||
let mut image_descriptors: SmallVec<[_; 64]> = SmallVec::new();
|
||||
let mut buffer_views_descriptors: SmallVec<[_; 64]> = SmallVec::new();
|
||||
|
||||
let mut raw_writes: SmallVec<[_; 64]> = SmallVec::new();
|
||||
let mut raw_writes_img_infos: SmallVec<[_; 64]> = SmallVec::new();
|
||||
let mut raw_writes_buf_infos: SmallVec<[_; 64]> = SmallVec::new();
|
||||
let mut raw_writes_buf_view_infos: SmallVec<[_; 64]> = SmallVec::new();
|
||||
|
||||
for indiv_write in writes {
|
||||
// Since the `DescriptorWrite` objects are built only through functions, we know for
|
||||
// sure that it's impossible to have an empty descriptor write.
|
||||
debug_assert!(!indiv_write.inner.is_empty());
|
||||
|
||||
// The whole struct thats written here is valid, except for pImageInfo, pBufferInfo
|
||||
// and pTexelBufferView which are placeholder values.
|
||||
raw_writes.push(ash::vk::WriteDescriptorSet {
|
||||
dst_set: self.set,
|
||||
dst_binding: indiv_write.binding,
|
||||
dst_array_element: indiv_write.first_array_element,
|
||||
descriptor_count: indiv_write.inner.len() as u32,
|
||||
descriptor_type: indiv_write.ty().into(),
|
||||
p_image_info: ptr::null(),
|
||||
p_buffer_info: ptr::null(),
|
||||
p_texel_buffer_view: ptr::null(),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
match indiv_write.inner[0] {
|
||||
DescriptorWriteInner::Sampler(_)
|
||||
| DescriptorWriteInner::CombinedImageSampler(_, _, _)
|
||||
| DescriptorWriteInner::SampledImage(_, _)
|
||||
| DescriptorWriteInner::StorageImage(_, _)
|
||||
| DescriptorWriteInner::InputAttachment(_, _) => {
|
||||
raw_writes_img_infos.push(Some(image_descriptors.len()));
|
||||
raw_writes_buf_infos.push(None);
|
||||
raw_writes_buf_view_infos.push(None);
|
||||
}
|
||||
DescriptorWriteInner::UniformBuffer(_, _, _)
|
||||
| DescriptorWriteInner::StorageBuffer(_, _, _)
|
||||
| DescriptorWriteInner::DynamicUniformBuffer(_, _, _)
|
||||
| DescriptorWriteInner::DynamicStorageBuffer(_, _, _) => {
|
||||
raw_writes_img_infos.push(None);
|
||||
raw_writes_buf_infos.push(Some(buffer_descriptors.len()));
|
||||
raw_writes_buf_view_infos.push(None);
|
||||
}
|
||||
DescriptorWriteInner::UniformTexelBuffer(_)
|
||||
| DescriptorWriteInner::StorageTexelBuffer(_) => {
|
||||
raw_writes_img_infos.push(None);
|
||||
raw_writes_buf_infos.push(None);
|
||||
raw_writes_buf_view_infos.push(Some(buffer_views_descriptors.len()));
|
||||
}
|
||||
}
|
||||
|
||||
for elem in indiv_write.inner.iter() {
|
||||
match *elem {
|
||||
DescriptorWriteInner::UniformBuffer(buffer, offset, size)
|
||||
| DescriptorWriteInner::DynamicUniformBuffer(buffer, offset, size) => {
|
||||
buffer_descriptors.push(ash::vk::DescriptorBufferInfo {
|
||||
buffer,
|
||||
offset,
|
||||
range: size,
|
||||
});
|
||||
}
|
||||
DescriptorWriteInner::StorageBuffer(buffer, offset, size)
|
||||
| DescriptorWriteInner::DynamicStorageBuffer(buffer, offset, size) => {
|
||||
buffer_descriptors.push(ash::vk::DescriptorBufferInfo {
|
||||
buffer,
|
||||
offset,
|
||||
range: size,
|
||||
});
|
||||
}
|
||||
DescriptorWriteInner::Sampler(sampler) => {
|
||||
image_descriptors.push(ash::vk::DescriptorImageInfo {
|
||||
sampler,
|
||||
image_view: ash::vk::ImageView::null(),
|
||||
image_layout: ash::vk::ImageLayout::UNDEFINED,
|
||||
});
|
||||
}
|
||||
DescriptorWriteInner::CombinedImageSampler(sampler, view, layout) => {
|
||||
image_descriptors.push(ash::vk::DescriptorImageInfo {
|
||||
sampler,
|
||||
image_view: view,
|
||||
image_layout: layout,
|
||||
});
|
||||
}
|
||||
DescriptorWriteInner::StorageImage(view, layout) => {
|
||||
image_descriptors.push(ash::vk::DescriptorImageInfo {
|
||||
sampler: ash::vk::Sampler::null(),
|
||||
image_view: view,
|
||||
image_layout: layout,
|
||||
});
|
||||
}
|
||||
DescriptorWriteInner::SampledImage(view, layout) => {
|
||||
image_descriptors.push(ash::vk::DescriptorImageInfo {
|
||||
sampler: ash::vk::Sampler::null(),
|
||||
image_view: view,
|
||||
image_layout: layout,
|
||||
});
|
||||
}
|
||||
DescriptorWriteInner::InputAttachment(view, layout) => {
|
||||
image_descriptors.push(ash::vk::DescriptorImageInfo {
|
||||
sampler: ash::vk::Sampler::null(),
|
||||
image_view: view,
|
||||
image_layout: layout,
|
||||
});
|
||||
}
|
||||
DescriptorWriteInner::UniformTexelBuffer(view)
|
||||
| DescriptorWriteInner::StorageTexelBuffer(view) => {
|
||||
buffer_views_descriptors.push(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now that `image_descriptors`, `buffer_descriptors` and `buffer_views_descriptors` are
|
||||
// entirely filled and will never move again, we can fill the pointers in `raw_writes`.
|
||||
for (i, write) in raw_writes.iter_mut().enumerate() {
|
||||
write.p_image_info = match raw_writes_img_infos[i] {
|
||||
Some(off) => image_descriptors.as_ptr().offset(off as isize),
|
||||
None => ptr::null(),
|
||||
};
|
||||
|
||||
write.p_buffer_info = match raw_writes_buf_infos[i] {
|
||||
Some(off) => buffer_descriptors.as_ptr().offset(off as isize),
|
||||
None => ptr::null(),
|
||||
};
|
||||
|
||||
write.p_texel_buffer_view = match raw_writes_buf_view_infos[i] {
|
||||
Some(off) => buffer_views_descriptors.as_ptr().offset(off as isize),
|
||||
None => ptr::null(),
|
||||
};
|
||||
}
|
||||
let raw_writes: SmallVec<[_; 8]> = writes
|
||||
.iter()
|
||||
.map(|write| write.to_vulkan(self.set))
|
||||
.collect();
|
||||
|
||||
// It is forbidden to call `vkUpdateDescriptorSets` with 0 writes, so we need to perform
|
||||
// this emptiness check.
|
||||
if !raw_writes.is_empty() {
|
||||
fns.v1_0.update_descriptor_sets(
|
||||
device.internal_object(),
|
||||
raw_writes.len() as u32,
|
||||
raw_writes.as_ptr(),
|
||||
0,
|
||||
ptr::null(),
|
||||
);
|
||||
if raw_writes.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
fns.v1_0.update_descriptor_sets(
|
||||
device.internal_object(),
|
||||
raw_writes.len() as u32,
|
||||
raw_writes.as_ptr(),
|
||||
0,
|
||||
ptr::null(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -240,349 +97,443 @@ impl fmt::Debug for UnsafeDescriptorSet {
|
||||
///
|
||||
/// Use the various constructors to build a `DescriptorWrite`. While it is safe to build a
|
||||
/// `DescriptorWrite`, it is unsafe to actually use it to write to a descriptor set.
|
||||
// TODO: allow binding whole arrays at once
|
||||
pub struct DescriptorWrite {
|
||||
binding: u32,
|
||||
first_array_element: u32,
|
||||
inner: SmallVec<[DescriptorWriteInner; 1]>,
|
||||
descriptor_type: DescriptorType,
|
||||
info: DescriptorWriteInfo,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum DescriptorWriteInner {
|
||||
Sampler(ash::vk::Sampler),
|
||||
StorageImage(ash::vk::ImageView, ash::vk::ImageLayout),
|
||||
SampledImage(ash::vk::ImageView, ash::vk::ImageLayout),
|
||||
CombinedImageSampler(ash::vk::Sampler, ash::vk::ImageView, ash::vk::ImageLayout),
|
||||
UniformTexelBuffer(ash::vk::BufferView),
|
||||
StorageTexelBuffer(ash::vk::BufferView),
|
||||
UniformBuffer(ash::vk::Buffer, DeviceSize, DeviceSize),
|
||||
StorageBuffer(ash::vk::Buffer, DeviceSize, DeviceSize),
|
||||
DynamicUniformBuffer(ash::vk::Buffer, DeviceSize, DeviceSize),
|
||||
DynamicStorageBuffer(ash::vk::Buffer, DeviceSize, DeviceSize),
|
||||
InputAttachment(ash::vk::ImageView, ash::vk::ImageLayout),
|
||||
}
|
||||
|
||||
macro_rules! smallvec {
|
||||
($elem:expr) => {{
|
||||
let mut s = SmallVec::new();
|
||||
s.push($elem);
|
||||
s
|
||||
}};
|
||||
#[derive(Clone, Debug)]
|
||||
enum DescriptorWriteInfo {
|
||||
Image(SmallVec<[ash::vk::DescriptorImageInfo; 1]>),
|
||||
Buffer(SmallVec<[ash::vk::DescriptorBufferInfo; 1]>),
|
||||
BufferView(SmallVec<[ash::vk::BufferView; 1]>),
|
||||
}
|
||||
|
||||
impl DescriptorWrite {
|
||||
#[inline]
|
||||
pub fn storage_image<I>(binding: u32, array_element: u32, image_view: &I) -> DescriptorWrite
|
||||
where
|
||||
I: ImageViewAbstract,
|
||||
{
|
||||
let layouts = image_view
|
||||
.image()
|
||||
.descriptor_layouts()
|
||||
.expect("descriptor_layouts must return Some when used in an image view");
|
||||
|
||||
DescriptorWrite {
|
||||
binding,
|
||||
first_array_element: array_element,
|
||||
inner: smallvec!({
|
||||
DescriptorWriteInner::StorageImage(
|
||||
image_view.inner().internal_object(),
|
||||
layouts.storage_image.into(),
|
||||
)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn sampler(binding: u32, array_element: u32, sampler: &Arc<Sampler>) -> DescriptorWrite {
|
||||
DescriptorWrite {
|
||||
binding,
|
||||
first_array_element: array_element,
|
||||
inner: smallvec!(DescriptorWriteInner::Sampler(sampler.internal_object())),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn sampled_image<I>(binding: u32, array_element: u32, image_view: &I) -> DescriptorWrite
|
||||
where
|
||||
I: ImageViewAbstract,
|
||||
{
|
||||
let layouts = image_view
|
||||
.image()
|
||||
.descriptor_layouts()
|
||||
.expect("descriptor_layouts must return Some when used in an image view");
|
||||
|
||||
DescriptorWrite {
|
||||
binding,
|
||||
first_array_element: array_element,
|
||||
inner: smallvec!({
|
||||
DescriptorWriteInner::SampledImage(
|
||||
image_view.inner().internal_object(),
|
||||
layouts.sampled_image.into(),
|
||||
)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn combined_image_sampler<I>(
|
||||
pub fn storage_image<'a, I>(
|
||||
binding: u32,
|
||||
array_element: u32,
|
||||
sampler: Option<&Arc<Sampler>>, // Some for dynamic sampler, None for immutable
|
||||
image_view: &I,
|
||||
first_array_element: u32,
|
||||
image_views: impl IntoIterator<Item = &'a I>,
|
||||
) -> DescriptorWrite
|
||||
where
|
||||
I: ImageViewAbstract,
|
||||
I: ImageViewAbstract + 'a,
|
||||
{
|
||||
let layouts = image_view
|
||||
.image()
|
||||
.descriptor_layouts()
|
||||
.expect("descriptor_layouts must return Some when used in an image view");
|
||||
|
||||
DescriptorWrite {
|
||||
binding,
|
||||
first_array_element: array_element,
|
||||
inner: smallvec!({
|
||||
DescriptorWriteInner::CombinedImageSampler(
|
||||
sampler.map(|s| s.internal_object()).unwrap_or_default(),
|
||||
image_view.inner().internal_object(),
|
||||
layouts.combined_image_sampler.into(),
|
||||
)
|
||||
}),
|
||||
first_array_element,
|
||||
descriptor_type: DescriptorType::StorageImage,
|
||||
info: DescriptorWriteInfo::Image(
|
||||
image_views
|
||||
.into_iter()
|
||||
.map(|image_view| {
|
||||
let layouts = image_view.image().descriptor_layouts().expect(
|
||||
"descriptor_layouts must return Some when used in an image view",
|
||||
);
|
||||
ash::vk::DescriptorImageInfo {
|
||||
sampler: ash::vk::Sampler::null(),
|
||||
image_view: image_view.inner().internal_object(),
|
||||
image_layout: layouts.storage_image.into(),
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn sampler<'a>(
|
||||
binding: u32,
|
||||
first_array_element: u32,
|
||||
samplers: impl IntoIterator<Item = &'a Arc<Sampler>>,
|
||||
) -> DescriptorWrite {
|
||||
DescriptorWrite {
|
||||
binding,
|
||||
first_array_element,
|
||||
descriptor_type: DescriptorType::Sampler,
|
||||
info: DescriptorWriteInfo::Image(
|
||||
samplers
|
||||
.into_iter()
|
||||
.map(|sampler| ash::vk::DescriptorImageInfo {
|
||||
sampler: sampler.internal_object(),
|
||||
image_view: ash::vk::ImageView::null(),
|
||||
image_layout: ash::vk::ImageLayout::UNDEFINED,
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn sampled_image<'a, I>(
|
||||
binding: u32,
|
||||
first_array_element: u32,
|
||||
image_views: impl IntoIterator<Item = &'a I>,
|
||||
) -> DescriptorWrite
|
||||
where
|
||||
I: ImageViewAbstract + 'a,
|
||||
{
|
||||
DescriptorWrite {
|
||||
binding,
|
||||
first_array_element,
|
||||
descriptor_type: DescriptorType::SampledImage,
|
||||
info: DescriptorWriteInfo::Image(
|
||||
image_views
|
||||
.into_iter()
|
||||
.map(|image_view| {
|
||||
let layouts = image_view.image().descriptor_layouts().expect(
|
||||
"descriptor_layouts must return Some when used in an image view",
|
||||
);
|
||||
ash::vk::DescriptorImageInfo {
|
||||
sampler: ash::vk::Sampler::null(),
|
||||
image_view: image_view.inner().internal_object(),
|
||||
image_layout: layouts.sampled_image.into(),
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn combined_image_sampler<'a, I>(
|
||||
binding: u32,
|
||||
first_array_element: u32,
|
||||
image_views_samplers: impl IntoIterator<Item = (Option<&'a Arc<Sampler>>, &'a I)>, // Some for dynamic sampler, None for immutable
|
||||
) -> DescriptorWrite
|
||||
where
|
||||
I: ImageViewAbstract + 'a,
|
||||
{
|
||||
DescriptorWrite {
|
||||
binding,
|
||||
first_array_element,
|
||||
descriptor_type: DescriptorType::CombinedImageSampler,
|
||||
info: DescriptorWriteInfo::Image(
|
||||
image_views_samplers
|
||||
.into_iter()
|
||||
.map(|(sampler, image_view)| {
|
||||
let layouts = image_view.image().descriptor_layouts().expect(
|
||||
"descriptor_layouts must return Some when used in an image view",
|
||||
);
|
||||
ash::vk::DescriptorImageInfo {
|
||||
sampler: sampler.map(|s| s.internal_object()).unwrap_or_default(),
|
||||
image_view: image_view.inner().internal_object(),
|
||||
image_layout: layouts.combined_image_sampler.into(),
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn uniform_texel_buffer<'a, B>(
|
||||
binding: u32,
|
||||
array_element: u32,
|
||||
view: &BufferView<B>,
|
||||
first_array_element: u32,
|
||||
buffer_views: impl IntoIterator<Item = &'a BufferView<B>>,
|
||||
) -> DescriptorWrite
|
||||
where
|
||||
B: BufferAccess,
|
||||
B: BufferAccess + 'a,
|
||||
{
|
||||
assert!(view.uniform_texel_buffer());
|
||||
|
||||
DescriptorWrite {
|
||||
binding,
|
||||
first_array_element: array_element,
|
||||
inner: smallvec!(DescriptorWriteInner::UniformTexelBuffer(
|
||||
view.internal_object()
|
||||
)),
|
||||
first_array_element,
|
||||
descriptor_type: DescriptorType::UniformTexelBuffer,
|
||||
info: DescriptorWriteInfo::BufferView(
|
||||
buffer_views
|
||||
.into_iter()
|
||||
.map(|buffer_view| {
|
||||
assert!(buffer_view.uniform_texel_buffer());
|
||||
buffer_view.internal_object()
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn storage_texel_buffer<'a, B>(
|
||||
binding: u32,
|
||||
array_element: u32,
|
||||
view: &BufferView<B>,
|
||||
first_array_element: u32,
|
||||
buffer_view: impl IntoIterator<Item = &'a BufferView<B>>,
|
||||
) -> DescriptorWrite
|
||||
where
|
||||
B: BufferAccess,
|
||||
B: BufferAccess + 'a,
|
||||
{
|
||||
assert!(view.storage_texel_buffer());
|
||||
|
||||
DescriptorWrite {
|
||||
binding,
|
||||
first_array_element: array_element,
|
||||
inner: smallvec!(DescriptorWriteInner::StorageTexelBuffer(
|
||||
view.internal_object()
|
||||
)),
|
||||
first_array_element,
|
||||
descriptor_type: DescriptorType::StorageTexelBuffer,
|
||||
info: DescriptorWriteInfo::BufferView(
|
||||
buffer_view
|
||||
.into_iter()
|
||||
.map(|buffer_view| {
|
||||
assert!(buffer_view.storage_texel_buffer());
|
||||
buffer_view.internal_object()
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn uniform_buffer<B>(binding: u32, array_element: u32, buffer: &B) -> DescriptorWrite
|
||||
where
|
||||
B: BufferAccess,
|
||||
{
|
||||
let size = buffer.size();
|
||||
let BufferInner { buffer, offset } = buffer.inner();
|
||||
|
||||
debug_assert_eq!(
|
||||
offset
|
||||
% buffer
|
||||
.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.min_uniform_buffer_offset_alignment,
|
||||
0
|
||||
);
|
||||
debug_assert!(
|
||||
size <= buffer
|
||||
.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.max_uniform_buffer_range as DeviceSize
|
||||
);
|
||||
|
||||
DescriptorWrite {
|
||||
binding,
|
||||
first_array_element: array_element,
|
||||
inner: smallvec!({
|
||||
DescriptorWriteInner::UniformBuffer(buffer.internal_object(), offset, size)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn storage_buffer<B>(binding: u32, array_element: u32, buffer: &B) -> DescriptorWrite
|
||||
where
|
||||
B: BufferAccess,
|
||||
{
|
||||
let size = buffer.size();
|
||||
let BufferInner { buffer, offset } = buffer.inner();
|
||||
|
||||
debug_assert_eq!(
|
||||
offset
|
||||
% buffer
|
||||
.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.min_storage_buffer_offset_alignment,
|
||||
0
|
||||
);
|
||||
debug_assert!(
|
||||
size <= buffer
|
||||
.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.max_storage_buffer_range as DeviceSize
|
||||
);
|
||||
|
||||
DescriptorWrite {
|
||||
binding,
|
||||
first_array_element: array_element,
|
||||
inner: smallvec!({
|
||||
DescriptorWriteInner::StorageBuffer(buffer.internal_object(), offset, size)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn dynamic_uniform_buffer<B>(
|
||||
pub unsafe fn uniform_buffer<'a, B>(
|
||||
binding: u32,
|
||||
array_element: u32,
|
||||
buffer: &B,
|
||||
first_array_element: u32,
|
||||
buffers: impl IntoIterator<Item = &'a B>,
|
||||
) -> DescriptorWrite
|
||||
where
|
||||
B: BufferAccess,
|
||||
B: BufferAccess + 'a,
|
||||
{
|
||||
let size = buffer.size();
|
||||
let BufferInner { buffer, offset } = buffer.inner();
|
||||
|
||||
debug_assert_eq!(
|
||||
offset
|
||||
% buffer
|
||||
.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.min_uniform_buffer_offset_alignment,
|
||||
0
|
||||
);
|
||||
debug_assert!(
|
||||
size <= buffer
|
||||
.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.max_uniform_buffer_range as DeviceSize
|
||||
);
|
||||
|
||||
DescriptorWrite {
|
||||
binding,
|
||||
first_array_element: array_element,
|
||||
inner: smallvec!(DescriptorWriteInner::DynamicUniformBuffer(
|
||||
buffer.internal_object(),
|
||||
offset,
|
||||
size
|
||||
)),
|
||||
first_array_element,
|
||||
descriptor_type: DescriptorType::UniformBuffer,
|
||||
info: DescriptorWriteInfo::Buffer(
|
||||
buffers
|
||||
.into_iter()
|
||||
.map(|buffer| {
|
||||
let size = buffer.size();
|
||||
let BufferInner { buffer, offset } = buffer.inner();
|
||||
|
||||
debug_assert_eq!(
|
||||
offset
|
||||
% buffer
|
||||
.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.min_uniform_buffer_offset_alignment,
|
||||
0
|
||||
);
|
||||
debug_assert!(
|
||||
size <= buffer
|
||||
.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.max_uniform_buffer_range
|
||||
as DeviceSize
|
||||
);
|
||||
ash::vk::DescriptorBufferInfo {
|
||||
buffer: buffer.internal_object(),
|
||||
offset,
|
||||
range: size,
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn dynamic_storage_buffer<B>(
|
||||
pub unsafe fn storage_buffer<'a, B>(
|
||||
binding: u32,
|
||||
array_element: u32,
|
||||
buffer: &B,
|
||||
first_array_element: u32,
|
||||
buffers: impl IntoIterator<Item = &'a B>,
|
||||
) -> DescriptorWrite
|
||||
where
|
||||
B: BufferAccess,
|
||||
B: BufferAccess + 'a,
|
||||
{
|
||||
let size = buffer.size();
|
||||
let BufferInner { buffer, offset } = buffer.inner();
|
||||
|
||||
debug_assert_eq!(
|
||||
offset
|
||||
% buffer
|
||||
.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.min_storage_buffer_offset_alignment,
|
||||
0
|
||||
);
|
||||
debug_assert!(
|
||||
size <= buffer
|
||||
.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.max_storage_buffer_range as DeviceSize
|
||||
);
|
||||
|
||||
DescriptorWrite {
|
||||
binding,
|
||||
first_array_element: array_element,
|
||||
inner: smallvec!(DescriptorWriteInner::DynamicStorageBuffer(
|
||||
buffer.internal_object(),
|
||||
offset,
|
||||
size
|
||||
)),
|
||||
first_array_element,
|
||||
descriptor_type: DescriptorType::StorageBuffer,
|
||||
info: DescriptorWriteInfo::Buffer(
|
||||
buffers
|
||||
.into_iter()
|
||||
.map(|buffer| {
|
||||
let size = buffer.size();
|
||||
let BufferInner { buffer, offset } = buffer.inner();
|
||||
|
||||
debug_assert_eq!(
|
||||
offset
|
||||
% buffer
|
||||
.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.min_storage_buffer_offset_alignment,
|
||||
0
|
||||
);
|
||||
debug_assert!(
|
||||
size <= buffer
|
||||
.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.max_storage_buffer_range
|
||||
as DeviceSize
|
||||
);
|
||||
ash::vk::DescriptorBufferInfo {
|
||||
buffer: buffer.internal_object(),
|
||||
offset,
|
||||
range: size,
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn input_attachment<I>(binding: u32, array_element: u32, image_view: &I) -> DescriptorWrite
|
||||
pub unsafe fn dynamic_uniform_buffer<'a, B>(
|
||||
binding: u32,
|
||||
first_array_element: u32,
|
||||
buffers: impl IntoIterator<Item = &'a B>,
|
||||
) -> DescriptorWrite
|
||||
where
|
||||
I: ImageViewAbstract,
|
||||
B: BufferAccess + 'a,
|
||||
{
|
||||
let layouts = image_view
|
||||
.image()
|
||||
.descriptor_layouts()
|
||||
.expect("descriptor_layouts must return Some when used in an image view");
|
||||
|
||||
DescriptorWrite {
|
||||
binding,
|
||||
first_array_element: array_element,
|
||||
inner: smallvec!({
|
||||
DescriptorWriteInner::InputAttachment(
|
||||
image_view.inner().internal_object(),
|
||||
layouts.input_attachment.into(),
|
||||
)
|
||||
}),
|
||||
first_array_element,
|
||||
descriptor_type: DescriptorType::UniformBufferDynamic,
|
||||
info: DescriptorWriteInfo::Buffer(
|
||||
buffers
|
||||
.into_iter()
|
||||
.map(|buffer| {
|
||||
let size = buffer.size();
|
||||
let BufferInner { buffer, offset } = buffer.inner();
|
||||
|
||||
debug_assert_eq!(
|
||||
offset
|
||||
% buffer
|
||||
.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.min_uniform_buffer_offset_alignment,
|
||||
0
|
||||
);
|
||||
debug_assert!(
|
||||
size <= buffer
|
||||
.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.max_uniform_buffer_range
|
||||
as DeviceSize
|
||||
);
|
||||
ash::vk::DescriptorBufferInfo {
|
||||
buffer: buffer.internal_object(),
|
||||
offset,
|
||||
range: size,
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the type corresponding to this write.
|
||||
#[inline]
|
||||
pub fn ty(&self) -> DescriptorType {
|
||||
match self.inner[0] {
|
||||
DescriptorWriteInner::Sampler(_) => DescriptorType::Sampler,
|
||||
DescriptorWriteInner::CombinedImageSampler(_, _, _) => {
|
||||
DescriptorType::CombinedImageSampler
|
||||
}
|
||||
DescriptorWriteInner::SampledImage(_, _) => DescriptorType::SampledImage,
|
||||
DescriptorWriteInner::StorageImage(_, _) => DescriptorType::StorageImage,
|
||||
DescriptorWriteInner::UniformTexelBuffer(_) => DescriptorType::UniformTexelBuffer,
|
||||
DescriptorWriteInner::StorageTexelBuffer(_) => DescriptorType::StorageTexelBuffer,
|
||||
DescriptorWriteInner::UniformBuffer(_, _, _) => DescriptorType::UniformBuffer,
|
||||
DescriptorWriteInner::StorageBuffer(_, _, _) => DescriptorType::StorageBuffer,
|
||||
DescriptorWriteInner::DynamicUniformBuffer(_, _, _) => {
|
||||
DescriptorType::UniformBufferDynamic
|
||||
}
|
||||
DescriptorWriteInner::DynamicStorageBuffer(_, _, _) => {
|
||||
DescriptorType::StorageBufferDynamic
|
||||
}
|
||||
DescriptorWriteInner::InputAttachment(_, _) => DescriptorType::InputAttachment,
|
||||
pub unsafe fn dynamic_storage_buffer<'a, B>(
|
||||
binding: u32,
|
||||
first_array_element: u32,
|
||||
buffers: impl IntoIterator<Item = &'a B>,
|
||||
) -> DescriptorWrite
|
||||
where
|
||||
B: BufferAccess + 'a,
|
||||
{
|
||||
DescriptorWrite {
|
||||
binding,
|
||||
first_array_element,
|
||||
descriptor_type: DescriptorType::StorageBufferDynamic,
|
||||
info: DescriptorWriteInfo::Buffer(
|
||||
buffers
|
||||
.into_iter()
|
||||
.map(|buffer| {
|
||||
let size = buffer.size();
|
||||
let BufferInner { buffer, offset } = buffer.inner();
|
||||
|
||||
debug_assert_eq!(
|
||||
offset
|
||||
% buffer
|
||||
.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.min_storage_buffer_offset_alignment,
|
||||
0
|
||||
);
|
||||
debug_assert!(
|
||||
size <= buffer
|
||||
.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.max_storage_buffer_range
|
||||
as DeviceSize
|
||||
);
|
||||
ash::vk::DescriptorBufferInfo {
|
||||
buffer: buffer.internal_object(),
|
||||
offset,
|
||||
range: size,
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn input_attachment<'a, I>(
|
||||
binding: u32,
|
||||
first_array_element: u32,
|
||||
image_views: impl IntoIterator<Item = &'a I>,
|
||||
) -> DescriptorWrite
|
||||
where
|
||||
I: ImageViewAbstract + 'a,
|
||||
{
|
||||
DescriptorWrite {
|
||||
binding,
|
||||
first_array_element,
|
||||
descriptor_type: DescriptorType::InputAttachment,
|
||||
info: DescriptorWriteInfo::Image(
|
||||
image_views
|
||||
.into_iter()
|
||||
.map(|image_view| {
|
||||
let layouts = image_view.image().descriptor_layouts().expect(
|
||||
"descriptor_layouts must return Some when used in an image view",
|
||||
);
|
||||
ash::vk::DescriptorImageInfo {
|
||||
sampler: ash::vk::Sampler::null(),
|
||||
image_view: image_view.inner().internal_object(),
|
||||
image_layout: layouts.input_attachment.into(),
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn to_vulkan(&self, dst_set: ash::vk::DescriptorSet) -> ash::vk::WriteDescriptorSet {
|
||||
let mut result = ash::vk::WriteDescriptorSet {
|
||||
dst_set,
|
||||
dst_binding: self.binding,
|
||||
dst_array_element: self.first_array_element,
|
||||
descriptor_count: 0,
|
||||
descriptor_type: self.descriptor_type.into(),
|
||||
p_image_info: ptr::null(),
|
||||
p_buffer_info: ptr::null(),
|
||||
p_texel_buffer_view: ptr::null(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// Set the pointers separately.
|
||||
// You must keep `*self` alive and unmoved until the function call is done.
|
||||
match &self.info {
|
||||
DescriptorWriteInfo::Image(info) => {
|
||||
result.descriptor_count = info.len() as u32;
|
||||
result.p_image_info = info.as_ptr();
|
||||
}
|
||||
DescriptorWriteInfo::Buffer(info) => {
|
||||
result.descriptor_count = info.len() as u32;
|
||||
result.p_buffer_info = info.as_ptr();
|
||||
}
|
||||
DescriptorWriteInfo::BufferView(info) => {
|
||||
result.descriptor_count = info.len() as u32;
|
||||
result.p_texel_buffer_view = info.as_ptr();
|
||||
}
|
||||
}
|
||||
|
||||
// Since the `DescriptorWrite` objects are built only through functions, we know for
|
||||
// sure that it's impossible to have an empty descriptor write.
|
||||
debug_assert!(result.descriptor_count != 0);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
@ -33,8 +33,8 @@ use std::sync::Arc;
|
||||
pub struct PipelineLayout {
|
||||
handle: ash::vk::PipelineLayout,
|
||||
device: Arc<Device>,
|
||||
descriptor_set_layouts: SmallVec<[Arc<DescriptorSetLayout>; 16]>,
|
||||
push_constant_ranges: SmallVec<[PipelineLayoutPcRange; 8]>,
|
||||
descriptor_set_layouts: SmallVec<[Arc<DescriptorSetLayout>; 4]>,
|
||||
push_constant_ranges: SmallVec<[PipelineLayoutPcRange; 4]>,
|
||||
}
|
||||
|
||||
impl PipelineLayout {
|
||||
@ -50,9 +50,19 @@ impl PipelineLayout {
|
||||
P: IntoIterator<Item = PipelineLayoutPcRange>,
|
||||
{
|
||||
let fns = device.fns();
|
||||
let descriptor_set_layouts: SmallVec<[Arc<DescriptorSetLayout>; 16]> =
|
||||
let descriptor_set_layouts: SmallVec<[Arc<DescriptorSetLayout>; 4]> =
|
||||
descriptor_set_layouts.into_iter().collect();
|
||||
let mut push_constant_ranges: SmallVec<[PipelineLayoutPcRange; 8]> =
|
||||
|
||||
if descriptor_set_layouts
|
||||
.iter()
|
||||
.filter(|layout| layout.desc().is_push_descriptor())
|
||||
.count()
|
||||
> 1
|
||||
{
|
||||
return Err(PipelineLayoutCreationError::MultiplePushDescriptor);
|
||||
}
|
||||
|
||||
let mut push_constant_ranges: SmallVec<[PipelineLayoutPcRange; 4]> =
|
||||
push_constant_ranges.into_iter().collect();
|
||||
|
||||
// Check for overlapping stages
|
||||
@ -89,11 +99,11 @@ impl PipelineLayout {
|
||||
let layouts_ids = descriptor_set_layouts
|
||||
.iter()
|
||||
.map(|l| l.internal_object())
|
||||
.collect::<SmallVec<[_; 16]>>();
|
||||
.collect::<SmallVec<[_; 4]>>();
|
||||
|
||||
// Builds a list of `vkPushConstantRange` that describe the push constants.
|
||||
let push_constants = {
|
||||
let mut out: SmallVec<[_; 8]> = SmallVec::new();
|
||||
let mut out: SmallVec<[_; 4]> = SmallVec::new();
|
||||
|
||||
for &PipelineLayoutPcRange {
|
||||
offset,
|
||||
@ -279,6 +289,8 @@ pub enum PipelineLayoutCreationError {
|
||||
/// One of the push constants range didn't obey the rules. The list of stages must not be
|
||||
/// empty, the size must not be 0, and the size must be a multiple or 4.
|
||||
InvalidPushConstant,
|
||||
/// More than one descriptor set layout was set for push descriptors.
|
||||
MultiplePushDescriptor,
|
||||
/// Conflict between different push constants ranges.
|
||||
PushConstantsConflict {
|
||||
first_range: PipelineLayoutPcRange,
|
||||
@ -292,9 +304,9 @@ impl error::Error for PipelineLayoutCreationError {
|
||||
#[inline]
|
||||
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
||||
match *self {
|
||||
PipelineLayoutCreationError::OomError(ref err) => Some(err),
|
||||
PipelineLayoutCreationError::LimitsError(ref err) => Some(err),
|
||||
PipelineLayoutCreationError::SetLayoutError(ref err) => Some(err),
|
||||
Self::OomError(ref err) => Some(err),
|
||||
Self::LimitsError(ref err) => Some(err),
|
||||
Self::SetLayoutError(ref err) => Some(err),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -303,25 +315,28 @@ impl error::Error for PipelineLayoutCreationError {
|
||||
impl fmt::Display for PipelineLayoutCreationError {
|
||||
#[inline]
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
write!(
|
||||
fmt,
|
||||
"{}",
|
||||
match *self {
|
||||
PipelineLayoutCreationError::OomError(_) => "not enough memory available",
|
||||
PipelineLayoutCreationError::LimitsError(_) => {
|
||||
match *self {
|
||||
Self::OomError(_) => write!(fmt, "not enough memory available"),
|
||||
Self::LimitsError(_) => {
|
||||
write!(
|
||||
fmt,
|
||||
"the pipeline layout description doesn't fulfill the limit requirements"
|
||||
}
|
||||
PipelineLayoutCreationError::InvalidPushConstant => {
|
||||
"one of the push constants range didn't obey the rules"
|
||||
}
|
||||
PipelineLayoutCreationError::PushConstantsConflict { .. } => {
|
||||
"conflict between different push constants ranges"
|
||||
}
|
||||
PipelineLayoutCreationError::SetLayoutError(_) => {
|
||||
"one of the sets has an error"
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
Self::InvalidPushConstant => {
|
||||
write!(fmt, "one of the push constants range didn't obey the rules")
|
||||
}
|
||||
Self::MultiplePushDescriptor => {
|
||||
write!(
|
||||
fmt,
|
||||
"more than one descriptor set layout was set for push descriptors"
|
||||
)
|
||||
}
|
||||
Self::PushConstantsConflict { .. } => {
|
||||
write!(fmt, "conflict between different push constants ranges")
|
||||
}
|
||||
Self::SetLayoutError(_) => write!(fmt, "one of the sets has an error"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user