Add DescriptorSetWithOffsets type (#1641)

* Add DescriptorSetWithOffsets, remove the dynamic_offsets parameters on AutoCommandBufferBuilder

* Modify StateCacher, add checking to DescriptorSetWithOffsets constructor

* Add DescriptorSetWithOffsets to SyncCommandBufferBuilder
This commit is contained in:
Rua 2021-07-20 19:06:22 +02:00 committed by GitHub
parent 2ef4e57ee5
commit 0ad56aaeda
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 276 additions and 416 deletions

View File

@ -166,7 +166,7 @@ fn main() {
// `Arc`, this only clones the `Arc` and not the whole pipeline or set (which aren't
// cloneable anyway). In this example we would avoid cloning them since this is the last
// time we use them, but in a real code you would probably need to clone them.
.dispatch([1024, 1, 1], pipeline.clone(), set.clone(), (), vec![])
.dispatch([1024, 1, 1], pipeline.clone(), set.clone(), ())
.unwrap();
// Finish building the command buffer by calling `build`.
let command_buffer = builder.build().unwrap();

View File

@ -291,7 +291,7 @@ fn main() {
)
.unwrap()
// Draw our buffer
.draw(pipeline.clone(), &dynamic_state, buffer, (), (), vec![])
.draw(pipeline.clone(), &dynamic_state, buffer, (), ())
.unwrap()
.end_render_pass()
.unwrap();

View File

@ -158,7 +158,6 @@ impl AmbientLightingSystem {
vec![self.vertex_buffer.clone()],
descriptor_set,
push_constants,
vec![],
)
.unwrap();
builder.build().unwrap()

View File

@ -172,7 +172,6 @@ impl DirectionalLightingSystem {
vec![self.vertex_buffer.clone()],
descriptor_set,
push_constants,
vec![],
)
.unwrap();
builder.build().unwrap()

View File

@ -187,7 +187,6 @@ impl PointLightingSystem {
vec![self.vertex_buffer.clone()],
descriptor_set,
push_constants,
vec![],
)
.unwrap();
builder.build().unwrap()

View File

@ -101,7 +101,6 @@ impl TriangleDrawSystem {
vec![self.vertex_buffer.clone()],
(),
(),
vec![],
)
.unwrap();
builder.build().unwrap()

View File

@ -19,7 +19,7 @@ use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::layout::{DescriptorSetDesc, DescriptorSetLayout};
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::{DescriptorSet, PersistentDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::instance::{Instance, InstanceExtensions};
@ -222,25 +222,22 @@ fn main() {
.dispatch(
[12, 1, 1],
pipeline.clone(),
set.clone(),
set.clone().offsets([0 * align as u32]),
(),
vec![0 * align as u32],
)
.unwrap()
.dispatch(
[12, 1, 1],
pipeline.clone(),
set.clone(),
set.clone().offsets([1 * align as u32]),
(),
vec![1 * align as u32],
)
.unwrap()
.dispatch(
[12, 1, 1],
pipeline.clone(),
set.clone(),
set.clone().offsets([2 * align as u32]),
(),
vec![2 * align as u32],
)
.unwrap();
let command_buffer = builder.build().unwrap();

View File

@ -231,7 +231,6 @@ fn main() {
pipeline.clone(),
set.clone(),
(),
vec![],
)
.unwrap()
.copy_image_to_buffer(image.clone(), buf.clone())

View File

@ -297,7 +297,6 @@ fn main() {
vertex_buffer.clone(),
set.clone(),
(),
vec![],
)
.unwrap()
.end_render_pass()

View File

@ -159,7 +159,7 @@ void main() {
.unwrap();
builder
.dispatch([1024, 1, 1], pipeline.clone(), set.clone(), (), vec![])
.dispatch([1024, 1, 1], pipeline.clone(), set.clone(), ())
.unwrap();
let command_buffer = builder.build().unwrap();

View File

@ -357,7 +357,6 @@ fn main() {
compute_pipeline.clone(),
cs_desciptor_set.clone(),
(),
vec![],
)
.unwrap()
.begin_render_pass(
@ -375,7 +374,6 @@ fn main() {
indirect_args.clone(),
(),
(),
vec![],
)
.unwrap()
.end_render_pass()

View File

@ -340,7 +340,6 @@ fn main() {
(triangle_vertex_buffer.clone(), instance_data_buffer.clone()),
(),
(),
vec![],
)
.unwrap()
.end_render_pass()

View File

@ -317,7 +317,6 @@ fn main() {
vertex_buffer.clone(),
(),
(),
vec![],
)
.unwrap()
.end_render_pass()

View File

@ -386,7 +386,6 @@ fn main() {
vertex_buffer.clone(),
(),
(),
vec![],
)
.unwrap()
.end_render_pass()

View File

@ -294,7 +294,6 @@ fn main() {
vertex_buffer.clone(),
(),
(),
vec![],
)
.unwrap()
.end_render_pass()

View File

@ -345,14 +345,7 @@ fn main() {
// the `occlusion_query_precise` feature to be enabled on the device.
.begin_query(query_pool.clone(), 0, QueryControlFlags { precise: false })
.unwrap()
.draw(
pipeline.clone(),
&dynamic_state,
triangle1.clone(),
(),
(),
vec![],
)
.draw(pipeline.clone(), &dynamic_state, triangle1.clone(), (), ())
.unwrap()
// End query 0.
.end_query(query_pool.clone(), 0)
@ -360,28 +353,14 @@ fn main() {
// Begin query 1 for the cyan triangle.
.begin_query(query_pool.clone(), 1, QueryControlFlags { precise: false })
.unwrap()
.draw(
pipeline.clone(),
&dynamic_state,
triangle2.clone(),
(),
(),
vec![],
)
.draw(pipeline.clone(), &dynamic_state, triangle2.clone(), (), ())
.unwrap()
.end_query(query_pool.clone(), 1)
.unwrap()
// Finally, query 2 for the green triangle.
.begin_query(query_pool.clone(), 2, QueryControlFlags { precise: false })
.unwrap()
.draw(
pipeline.clone(),
&dynamic_state,
triangle3.clone(),
(),
(),
vec![],
)
.draw(pipeline.clone(), &dynamic_state, triangle3.clone(), (), ())
.unwrap()
.end_query(query_pool.clone(), 2)
.unwrap()

View File

@ -129,13 +129,7 @@ fn main() {
)
.unwrap();
builder
.dispatch(
[1024, 1, 1],
pipeline.clone(),
set.clone(),
push_constants,
vec![],
)
.dispatch([1024, 1, 1], pipeline.clone(), set.clone(), push_constants)
.unwrap();
let command_buffer = builder.build().unwrap();

View File

@ -365,7 +365,6 @@ fn main() {
vertex_buffer.clone(),
(),
(),
vec![],
)
.unwrap()
.end_render_pass()

View File

@ -115,7 +115,7 @@ fn main() {
)
.unwrap();
builder
.dispatch([1024, 1, 1], pipeline.clone(), set.clone(), (), vec![])
.dispatch([1024, 1, 1], pipeline.clone(), set.clone(), ())
.unwrap();
let command_buffer = builder.build().unwrap();
let future = sync::now(device.clone())

View File

@ -127,7 +127,7 @@ fn main() {
)
.unwrap();
builder
.dispatch([1024, 1, 1], pipeline.clone(), set.clone(), (), vec![])
.dispatch([1024, 1, 1], pipeline.clone(), set.clone(), ())
.unwrap();
let command_buffer = builder.build().unwrap();

View File

@ -269,7 +269,6 @@ fn main() {
index_buffer.clone(),
set.clone(),
(),
vec![],
)
.unwrap()
.end_render_pass()

View File

@ -372,7 +372,6 @@ fn main() {
vertex_buffer.clone(),
(),
(),
vec![],
)
.unwrap()
.end_render_pass()

View File

@ -495,7 +495,6 @@ fn main() {
vertex_buffer.clone(),
(),
(),
vec![],
)
.unwrap()
// We leave the render pass by calling `draw_end`. Note that if we had multiple

View File

@ -37,7 +37,7 @@ use crate::command_buffer::SecondaryCommandBuffer;
use crate::command_buffer::StateCacher;
use crate::command_buffer::StateCacherOutcome;
use crate::command_buffer::SubpassContents;
use crate::descriptor_set::layout::{DescriptorBufferDesc, DescriptorDescTy};
use crate::descriptor_set::DescriptorSetWithOffsets;
use crate::descriptor_set::DescriptorSetsCollection;
use crate::device::physical::QueueFamily;
use crate::device::Device;
@ -77,7 +77,6 @@ use crate::sync::PipelineStages;
use crate::VulkanObject;
use crate::{OomError, SafeDeref};
use fnv::FnvHashMap;
use smallvec::SmallVec;
use std::error;
use std::ffi::CStr;
use std::fmt;
@ -1051,28 +1050,27 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
/// Perform a single compute operation using a compute pipeline.
#[inline]
pub fn dispatch<Cp, S, Pc, Do, Doi>(
pub fn dispatch<Cp, S, Pc>(
&mut self,
group_counts: [u32; 3],
pipeline: Cp,
sets: S,
constants: Pc,
dynamic_offsets: Do,
descriptor_sets: S,
push_constants: Pc,
) -> Result<&mut Self, DispatchError>
where
Cp: ComputePipelineAbstract + Send + Sync + 'static + Clone, // TODO: meh for Clone
S: DescriptorSetsCollection,
Do: IntoIterator<Item = u32, IntoIter = Doi>,
Doi: Iterator<Item = u32> + Send + Sync + 'static,
{
let descriptor_sets = descriptor_sets.into_vec();
unsafe {
if !self.queue_family().supports_compute() {
return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
}
self.ensure_outside_render_pass()?;
check_push_constants_validity(pipeline.layout(), &constants)?;
check_descriptor_sets_validity(pipeline.layout(), &sets)?;
check_push_constants_validity(pipeline.layout(), &push_constants)?;
check_descriptor_sets_validity(pipeline.layout(), &descriptor_sets)?;
check_dispatch(pipeline.device(), group_counts)?;
if let StateCacherOutcome::NeedChange =
@ -1081,14 +1079,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
self.inner.bind_pipeline_compute(pipeline.clone());
}
push_constants(&mut self.inner, pipeline.layout(), constants);
descriptor_sets(
set_push_constants(&mut self.inner, pipeline.layout(), push_constants);
bind_descriptor_sets(
&mut self.inner,
&mut self.state_cacher,
PipelineBindPoint::Compute,
pipeline.layout(),
sets,
dynamic_offsets,
descriptor_sets,
)?;
self.inner.dispatch(group_counts);
@ -1099,13 +1096,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
/// Perform multiple compute operations using a compute pipeline. One dispatch is performed for
/// each `vulkano::command_buffer::DispatchIndirectCommand` struct in `indirect_buffer`.
#[inline]
pub fn dispatch_indirect<Inb, Cp, S, Pc, Do, Doi>(
pub fn dispatch_indirect<Inb, Cp, S, Pc>(
&mut self,
indirect_buffer: Inb,
pipeline: Cp,
sets: S,
constants: Pc,
dynamic_offsets: Do,
descriptor_sets: S,
push_constants: Pc,
) -> Result<&mut Self, DispatchIndirectError>
where
Inb: BufferAccess
@ -1115,9 +1111,9 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
+ 'static,
Cp: ComputePipelineAbstract + Send + Sync + 'static + Clone, // TODO: meh for Clone
S: DescriptorSetsCollection,
Do: IntoIterator<Item = u32, IntoIter = Doi>,
Doi: Iterator<Item = u32> + Send + Sync + 'static,
{
let descriptor_sets = descriptor_sets.into_vec();
unsafe {
if !self.queue_family().supports_compute() {
return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
@ -1125,8 +1121,8 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
self.ensure_outside_render_pass()?;
check_indirect_buffer(self.device(), &indirect_buffer)?;
check_push_constants_validity(pipeline.layout(), &constants)?;
check_descriptor_sets_validity(pipeline.layout(), &sets)?;
check_push_constants_validity(pipeline.layout(), &push_constants)?;
check_descriptor_sets_validity(pipeline.layout(), &descriptor_sets)?;
if let StateCacherOutcome::NeedChange =
self.state_cacher.bind_compute_pipeline(&pipeline)
@ -1134,14 +1130,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
self.inner.bind_pipeline_compute(pipeline.clone());
}
push_constants(&mut self.inner, pipeline.layout(), constants);
descriptor_sets(
set_push_constants(&mut self.inner, pipeline.layout(), push_constants);
bind_descriptor_sets(
&mut self.inner,
&mut self.state_cacher,
PipelineBindPoint::Compute,
pipeline.layout(),
sets,
dynamic_offsets,
descriptor_sets,
)?;
self.inner.dispatch_indirect(indirect_buffer)?;
@ -1156,29 +1151,28 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
/// All data in `vertex_buffer` is used for the draw operation. To use only some data in the
/// buffer, wrap it in a `vulkano::buffer::BufferSlice`.
#[inline]
pub fn draw<V, Gp, S, Pc, Do, Doi>(
pub fn draw<V, Gp, S, Pc>(
&mut self,
pipeline: Gp,
dynamic: &DynamicState,
vertex_buffer: V,
sets: S,
constants: Pc,
dynamic_offsets: Do,
vertex_buffers: V,
descriptor_sets: S,
push_constants: Pc,
) -> Result<&mut Self, DrawError>
where
Gp: GraphicsPipelineAbstract + VertexSource<V> + Send + Sync + 'static + Clone, // TODO: meh for Clone
S: DescriptorSetsCollection,
Do: IntoIterator<Item = u32, IntoIter = Doi>,
Doi: Iterator<Item = u32> + Send + Sync + 'static,
{
let descriptor_sets = descriptor_sets.into_vec();
unsafe {
// TODO: must check that pipeline is compatible with render pass
self.ensure_inside_render_pass_inline(&pipeline)?;
check_dynamic_state_validity(&pipeline, dynamic)?;
check_push_constants_validity(pipeline.layout(), &constants)?;
check_descriptor_sets_validity(pipeline.layout(), &sets)?;
let vb_infos = check_vertex_buffers(&pipeline, vertex_buffer)?;
check_push_constants_validity(pipeline.layout(), &push_constants)?;
check_descriptor_sets_validity(pipeline.layout(), &descriptor_sets)?;
let vb_infos = check_vertex_buffers(&pipeline, vertex_buffers)?;
if let StateCacherOutcome::NeedChange =
self.state_cacher.bind_graphics_pipeline(&pipeline)
@ -1188,17 +1182,16 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
let dynamic = self.state_cacher.dynamic_state(dynamic);
push_constants(&mut self.inner, pipeline.layout(), constants);
set_push_constants(&mut self.inner, pipeline.layout(), push_constants);
set_state(&mut self.inner, &dynamic);
descriptor_sets(
bind_descriptor_sets(
&mut self.inner,
&mut self.state_cacher,
PipelineBindPoint::Graphics,
pipeline.layout(),
sets,
dynamic_offsets,
descriptor_sets,
)?;
vertex_buffers(
bind_vertex_buffers(
&mut self.inner,
&mut self.state_cacher,
vb_infos.vertex_buffers,
@ -1231,15 +1224,14 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
/// All data in `vertex_buffer` is used for every draw operation. To use only some data in the
/// buffer, wrap it in a `vulkano::buffer::BufferSlice`.
#[inline]
pub fn draw_indirect<V, Gp, S, Pc, Inb, Do, Doi>(
pub fn draw_indirect<V, Gp, S, Pc, Inb>(
&mut self,
pipeline: Gp,
dynamic: &DynamicState,
vertex_buffer: V,
vertex_buffers: V,
indirect_buffer: Inb,
sets: S,
constants: Pc,
dynamic_offsets: Do,
descriptor_sets: S,
push_constants: Pc,
) -> Result<&mut Self, DrawIndirectError>
where
Gp: GraphicsPipelineAbstract + VertexSource<V> + Send + Sync + 'static + Clone, // TODO: meh for Clone
@ -1249,18 +1241,18 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
+ Send
+ Sync
+ 'static,
Do: IntoIterator<Item = u32, IntoIter = Doi>,
Doi: Iterator<Item = u32> + Send + Sync + 'static,
{
let descriptor_sets = descriptor_sets.into_vec();
unsafe {
// TODO: must check that pipeline is compatible with render pass
self.ensure_inside_render_pass_inline(&pipeline)?;
check_indirect_buffer(self.device(), &indirect_buffer)?;
check_dynamic_state_validity(&pipeline, dynamic)?;
check_push_constants_validity(pipeline.layout(), &constants)?;
check_descriptor_sets_validity(pipeline.layout(), &sets)?;
let vb_infos = check_vertex_buffers(&pipeline, vertex_buffer)?;
check_push_constants_validity(pipeline.layout(), &push_constants)?;
check_descriptor_sets_validity(pipeline.layout(), &descriptor_sets)?;
let vb_infos = check_vertex_buffers(&pipeline, vertex_buffers)?;
let requested = indirect_buffer.len() as u32;
let limit = self
@ -1288,17 +1280,16 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
let dynamic = self.state_cacher.dynamic_state(dynamic);
push_constants(&mut self.inner, pipeline.layout(), constants);
set_push_constants(&mut self.inner, pipeline.layout(), push_constants);
set_state(&mut self.inner, &dynamic);
descriptor_sets(
bind_descriptor_sets(
&mut self.inner,
&mut self.state_cacher,
PipelineBindPoint::Graphics,
pipeline.layout(),
sets,
dynamic_offsets,
descriptor_sets,
)?;
vertex_buffers(
bind_vertex_buffers(
&mut self.inner,
&mut self.state_cacher,
vb_infos.vertex_buffers,
@ -1324,33 +1315,32 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
/// All data in `vertex_buffer` and `index_buffer` is used for the draw operation. To use
/// only some data in the buffer, wrap it in a `vulkano::buffer::BufferSlice`.
#[inline]
pub fn draw_indexed<V, Gp, S, Pc, Ib, I, Do, Doi>(
pub fn draw_indexed<V, Gp, S, Pc, Ib, I>(
&mut self,
pipeline: Gp,
dynamic: &DynamicState,
vertex_buffer: V,
vertex_buffers: V,
index_buffer: Ib,
sets: S,
constants: Pc,
dynamic_offsets: Do,
descriptor_sets: S,
push_constants: Pc,
) -> Result<&mut Self, DrawIndexedError>
where
Gp: GraphicsPipelineAbstract + VertexSource<V> + Send + Sync + 'static + Clone, // TODO: meh for Clone
S: DescriptorSetsCollection,
Ib: BufferAccess + TypedBufferAccess<Content = [I]> + Send + Sync + 'static,
I: Index + 'static,
Do: IntoIterator<Item = u32, IntoIter = Doi>,
Doi: Iterator<Item = u32> + Send + Sync + 'static,
{
let descriptor_sets = descriptor_sets.into_vec();
unsafe {
// TODO: must check that pipeline is compatible with render pass
self.ensure_inside_render_pass_inline(&pipeline)?;
let ib_infos = check_index_buffer(self.device(), &index_buffer)?;
check_dynamic_state_validity(&pipeline, dynamic)?;
check_push_constants_validity(pipeline.layout(), &constants)?;
check_descriptor_sets_validity(pipeline.layout(), &sets)?;
let vb_infos = check_vertex_buffers(&pipeline, vertex_buffer)?;
check_push_constants_validity(pipeline.layout(), &push_constants)?;
check_descriptor_sets_validity(pipeline.layout(), &descriptor_sets)?;
let vb_infos = check_vertex_buffers(&pipeline, vertex_buffers)?;
if let StateCacherOutcome::NeedChange =
self.state_cacher.bind_graphics_pipeline(&pipeline)
@ -1366,17 +1356,16 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
let dynamic = self.state_cacher.dynamic_state(dynamic);
push_constants(&mut self.inner, pipeline.layout(), constants);
set_push_constants(&mut self.inner, pipeline.layout(), push_constants);
set_state(&mut self.inner, &dynamic);
descriptor_sets(
bind_descriptor_sets(
&mut self.inner,
&mut self.state_cacher,
PipelineBindPoint::Graphics,
pipeline.layout(),
sets,
dynamic_offsets,
descriptor_sets,
)?;
vertex_buffers(
bind_vertex_buffers(
&mut self.inner,
&mut self.state_cacher,
vb_infos.vertex_buffers,
@ -1412,16 +1401,15 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
/// All data in `vertex_buffer` and `index_buffer` is used for every draw operation. To use
/// only some data in the buffer, wrap it in a `vulkano::buffer::BufferSlice`.
#[inline]
pub fn draw_indexed_indirect<V, Gp, S, Pc, Ib, Inb, I, Do, Doi>(
pub fn draw_indexed_indirect<V, Gp, S, Pc, Ib, Inb, I>(
&mut self,
pipeline: Gp,
dynamic: &DynamicState,
vertex_buffer: V,
vertex_buffers: V,
index_buffer: Ib,
indirect_buffer: Inb,
sets: S,
constants: Pc,
dynamic_offsets: Do,
descriptor_sets: S,
push_constants: Pc,
) -> Result<&mut Self, DrawIndexedIndirectError>
where
Gp: GraphicsPipelineAbstract + VertexSource<V> + Send + Sync + 'static + Clone, // TODO: meh for Clone
@ -1433,9 +1421,9 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
+ Sync
+ 'static,
I: Index + 'static,
Do: IntoIterator<Item = u32, IntoIter = Doi>,
Doi: Iterator<Item = u32> + Send + Sync + 'static,
{
let descriptor_sets = descriptor_sets.into_vec();
unsafe {
// TODO: must check that pipeline is compatible with render pass
@ -1443,9 +1431,9 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
let ib_infos = check_index_buffer(self.device(), &index_buffer)?;
check_indirect_buffer(self.device(), &indirect_buffer)?;
check_dynamic_state_validity(&pipeline, dynamic)?;
check_push_constants_validity(pipeline.layout(), &constants)?;
check_descriptor_sets_validity(pipeline.layout(), &sets)?;
let vb_infos = check_vertex_buffers(&pipeline, vertex_buffer)?;
check_push_constants_validity(pipeline.layout(), &push_constants)?;
check_descriptor_sets_validity(pipeline.layout(), &descriptor_sets)?;
let vb_infos = check_vertex_buffers(&pipeline, vertex_buffers)?;
let requested = indirect_buffer.len() as u32;
let limit = self
@ -1479,17 +1467,16 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
let dynamic = self.state_cacher.dynamic_state(dynamic);
push_constants(&mut self.inner, pipeline.layout(), constants);
set_push_constants(&mut self.inner, pipeline.layout(), push_constants);
set_state(&mut self.inner, &dynamic);
descriptor_sets(
bind_descriptor_sets(
&mut self.inner,
&mut self.state_cacher,
PipelineBindPoint::Graphics,
pipeline.layout(),
sets,
dynamic_offsets,
descriptor_sets,
)?;
vertex_buffers(
bind_vertex_buffers(
&mut self.inner,
&mut self.state_cacher,
vb_infos.vertex_buffers,
@ -2097,7 +2084,7 @@ unsafe impl<L, P> DeviceOwned for AutoCommandBufferBuilder<L, P> {
}
// Shortcut function to set the push constants.
unsafe fn push_constants<Pc>(
unsafe fn set_push_constants<Pc>(
destination: &mut SyncCommandBufferBuilder,
pipeline_layout: &Arc<PipelineLayout>,
push_constants: Pc,
@ -2151,7 +2138,7 @@ unsafe fn set_state(destination: &mut SyncCommandBufferBuilder, dynamic: &Dynami
}
// Shortcut function to bind vertex buffers.
unsafe fn vertex_buffers(
unsafe fn bind_vertex_buffers(
destination: &mut SyncCommandBufferBuilder,
state_cacher: &mut StateCacher,
vertex_buffers: Vec<Box<dyn BufferAccess + Send + Sync>>,
@ -2182,76 +2169,17 @@ unsafe fn vertex_buffers(
Ok(())
}
unsafe fn descriptor_sets<S, Do, Doi>(
unsafe fn bind_descriptor_sets(
destination: &mut SyncCommandBufferBuilder,
state_cacher: &mut StateCacher,
pipeline_bind_point: PipelineBindPoint,
pipeline_layout: &Arc<PipelineLayout>,
sets: S,
dynamic_offsets: Do,
) -> Result<(), SyncCommandBufferBuilderError>
where
S: DescriptorSetsCollection,
Do: IntoIterator<Item = u32, IntoIter = Doi>,
Doi: Iterator<Item = u32> + Send + Sync + 'static,
{
let sets = sets.into_vec();
let dynamic_offsets: SmallVec<[u32; 32]> = dynamic_offsets.into_iter().collect();
// Ensure that the number of dynamic_offsets is correct and that each
// dynamic offset is a multiple of the minimum offset alignment specified
// by the physical device.
let properties = pipeline_layout.device().physical_device().properties();
let min_uniform_off_align = properties.min_uniform_buffer_offset_alignment.unwrap() as u32;
let min_storage_off_align = properties.min_storage_buffer_offset_alignment.unwrap() as u32;
let mut dynamic_offset_index = 0;
for set in &sets {
for desc_index in 0..set.layout().num_bindings() {
let desc = set.layout().descriptor(desc_index).unwrap();
if let DescriptorDescTy::Buffer(DescriptorBufferDesc {
dynamic: Some(true),
storage,
}) = desc.ty
{
// Don't check alignment if there are not enough offsets anyway
if dynamic_offsets.len() > dynamic_offset_index {
if storage {
assert!(
dynamic_offsets[dynamic_offset_index] % min_storage_off_align == 0,
"Dynamic storage buffer offset must be a multiple of min_storage_buffer_offset_alignment: got {}, expected a multiple of {}",
dynamic_offsets[dynamic_offset_index],
min_storage_off_align
);
} else {
assert!(
dynamic_offsets[dynamic_offset_index] % min_uniform_off_align == 0,
"Dynamic uniform buffer offset must be a multiple of min_uniform_buffer_offset_alignment: got {}, expected a multiple of {}",
dynamic_offsets[dynamic_offset_index],
min_uniform_off_align
);
}
}
dynamic_offset_index += 1;
}
}
}
assert!(
!(dynamic_offsets.len() < dynamic_offset_index),
"Too few dynamic offsets: got {}, expected {}",
dynamic_offsets.len(),
dynamic_offset_index
);
assert!(
!(dynamic_offsets.len() > dynamic_offset_index),
"Too many dynamic offsets: got {}, expected {}",
dynamic_offsets.len(),
dynamic_offset_index
);
descriptor_sets: Vec<DescriptorSetWithOffsets>,
) -> Result<(), SyncCommandBufferBuilderError> {
let first_binding = {
let mut compare = state_cacher.bind_descriptor_sets(pipeline_bind_point);
for set in sets.iter() {
compare.add(set, &dynamic_offsets);
for descriptor_set in descriptor_sets.iter() {
compare.add(descriptor_set);
}
compare.compare()
};
@ -2262,15 +2190,10 @@ where
};
let mut sets_binder = destination.bind_descriptor_sets();
for set in sets.into_iter().skip(first_binding as usize) {
for set in descriptor_sets.into_iter().skip(first_binding as usize) {
sets_binder.add(set);
}
sets_binder.submit(
pipeline_bind_point,
pipeline_layout.clone(),
first_binding,
dynamic_offsets.into_iter(),
)?;
sets_binder.submit(pipeline_bind_point, pipeline_layout.clone(), first_binding)?;
Ok(())
}

View File

@ -9,7 +9,7 @@
use crate::buffer::BufferAccess;
use crate::command_buffer::DynamicState;
use crate::descriptor_set::DescriptorSet;
use crate::descriptor_set::DescriptorSetWithOffsets;
use crate::pipeline::input_assembly::IndexType;
use crate::pipeline::ComputePipelineAbstract;
use crate::pipeline::GraphicsPipelineAbstract;
@ -253,21 +253,20 @@ pub struct StateCacherDescriptorSets<'s> {
impl<'s> StateCacherDescriptorSets<'s> {
/// Adds a descriptor set to the list to compare.
#[inline]
pub fn add<S>(&mut self, set: &S, dynamic_offsets: &SmallVec<[u32; 32]>)
where
S: ?Sized + DescriptorSet,
{
let raw = set.inner().internal_object();
pub fn add(&mut self, descriptor_set: &DescriptorSetWithOffsets) {
let (descriptor_set, dynamic_offsets) = descriptor_set.as_ref();
let raw = descriptor_set.inner().internal_object();
let dynamic_offsets = dynamic_offsets.iter().copied().collect();
if self.offset < self.state.len() {
if (&self.state[self.offset].0, &self.state[self.offset].1) == (&raw, dynamic_offsets) {
if let Some(state) = self.state.get_mut(self.offset) {
if (&state.0, &state.1) == (&raw, &dynamic_offsets) {
self.offset += 1;
return;
}
self.state[self.offset] = (raw, dynamic_offsets.clone());
*state = (raw, dynamic_offsets);
} else {
self.state.push((raw, dynamic_offsets.clone()));
self.state.push((raw, dynamic_offsets));
}
if self.found_diff.is_none() {

View File

@ -27,6 +27,7 @@ use crate::command_buffer::SecondaryCommandBuffer;
use crate::command_buffer::SubpassContents;
use crate::descriptor_set::layout::DescriptorDescTy;
use crate::descriptor_set::DescriptorSet;
use crate::descriptor_set::DescriptorSetWithOffsets;
use crate::format::ClearValue;
use crate::image::ImageAccess;
use crate::image::ImageLayout;
@ -393,7 +394,7 @@ impl SyncCommandBufferBuilder {
pub fn bind_descriptor_sets(&mut self) -> SyncCommandBufferBuilderBindDescriptorSets {
SyncCommandBufferBuilderBindDescriptorSets {
builder: self,
inner: SmallVec::new(),
descriptor_sets: SmallVec::new(),
}
}
@ -2613,57 +2614,56 @@ impl SyncCommandBufferBuilder {
pub struct SyncCommandBufferBuilderBindDescriptorSets<'b> {
builder: &'b mut SyncCommandBufferBuilder,
inner: SmallVec<[Box<dyn DescriptorSet + Send + Sync>; 12]>,
descriptor_sets: SmallVec<[DescriptorSetWithOffsets; 12]>,
}
impl<'b> SyncCommandBufferBuilderBindDescriptorSets<'b> {
/// Adds a descriptor set to the list.
#[inline]
pub fn add<S>(&mut self, set: S)
pub fn add<S>(&mut self, descriptor_set: S)
where
S: DescriptorSet + Send + Sync + 'static,
S: Into<DescriptorSetWithOffsets>,
{
self.inner.push(Box::new(set));
self.descriptor_sets.push(descriptor_set.into());
}
#[inline]
pub unsafe fn submit<I>(
pub unsafe fn submit(
self,
pipeline_bind_point: PipelineBindPoint,
pipeline_layout: Arc<PipelineLayout>,
first_binding: u32,
dynamic_offsets: I,
) -> Result<(), SyncCommandBufferBuilderError>
where
I: Iterator<Item = u32> + Send + Sync + 'static,
{
if self.inner.is_empty() {
) -> Result<(), SyncCommandBufferBuilderError> {
if self.descriptor_sets.is_empty() {
return Ok(());
}
struct Cmd<I> {
inner: SmallVec<[Box<dyn DescriptorSet + Send + Sync>; 12]>,
struct Cmd {
descriptor_sets: SmallVec<[DescriptorSetWithOffsets; 12]>,
pipeline_bind_point: PipelineBindPoint,
pipeline_layout: Arc<PipelineLayout>,
first_binding: u32,
dynamic_offsets: Option<I>,
}
impl<I> Command for Cmd<I>
where
I: Iterator<Item = u32>,
{
impl Command for Cmd {
fn name(&self) -> &'static str {
"vkCmdBindDescriptorSets"
}
unsafe fn send(&mut self, out: &mut UnsafeCommandBufferBuilder) {
let descriptor_sets = self.descriptor_sets.iter().map(|x| x.as_ref().0.inner());
let dynamic_offsets = self
.descriptor_sets
.iter()
.map(|x| x.as_ref().1.iter().copied())
.flatten();
out.bind_descriptor_sets(
self.pipeline_bind_point,
&self.pipeline_layout,
self.first_binding,
self.inner.iter().map(|s| s.inner()),
self.dynamic_offsets.take().unwrap(),
descriptor_sets,
dynamic_offsets,
);
}
@ -2718,11 +2718,16 @@ impl<'b> SyncCommandBufferBuilderBindDescriptorSets<'b> {
panic!()
}
}
Box::new(Fin(self.inner))
Box::new(Fin(self
.descriptor_sets
.into_iter()
.map(|x| x.into_tuple().0)
.collect()))
}
fn buffer(&self, mut num: usize) -> &dyn BufferAccess {
for set in self.inner.iter() {
for set in self.descriptor_sets.iter().map(|so| so.as_ref().0) {
if let Some(buf) = set.buffer(num) {
return buf.0;
}
@ -2732,7 +2737,12 @@ impl<'b> SyncCommandBufferBuilderBindDescriptorSets<'b> {
}
fn buffer_name(&self, mut num: usize) -> Cow<'static, str> {
for (set_num, set) in self.inner.iter().enumerate() {
for (set_num, set) in self
.descriptor_sets
.iter()
.map(|so| so.as_ref().0)
.enumerate()
{
if let Some(buf) = set.buffer(num) {
return format!("Buffer bound to descriptor {} of set {}", buf.1, set_num)
.into();
@ -2743,7 +2753,7 @@ impl<'b> SyncCommandBufferBuilderBindDescriptorSets<'b> {
}
fn image(&self, mut num: usize) -> &dyn ImageAccess {
for set in self.inner.iter() {
for set in self.descriptor_sets.iter().map(|so| so.as_ref().0) {
if let Some(img) = set.image(num) {
return img.0.image();
}
@ -2753,7 +2763,12 @@ impl<'b> SyncCommandBufferBuilderBindDescriptorSets<'b> {
}
fn image_name(&self, mut num: usize) -> Cow<'static, str> {
for (set_num, set) in self.inner.iter().enumerate() {
for (set_num, set) in self
.descriptor_sets
.iter()
.map(|so| so.as_ref().0)
.enumerate()
{
if let Some(img) = set.image(num) {
return format!("Image bound to descriptor {} of set {}", img.1, set_num)
.into();
@ -2766,7 +2781,7 @@ impl<'b> SyncCommandBufferBuilderBindDescriptorSets<'b> {
let resources = {
let mut resources = Vec::new();
for ds in self.inner.iter() {
for ds in self.descriptor_sets.iter().map(|so| so.as_ref().0) {
for buf_num in 0..ds.num_buffers() {
let desc = ds
.layout()
@ -2842,11 +2857,10 @@ impl<'b> SyncCommandBufferBuilderBindDescriptorSets<'b> {
self.builder.append_command(
Cmd {
inner: self.inner,
descriptor_sets: self.descriptor_sets,
pipeline_bind_point,
pipeline_layout,
first_binding,
dynamic_offsets: Some(dynamic_offsets),
},
&resources,
)?;

View File

@ -11,17 +11,14 @@ use std::error;
use std::fmt;
use crate::descriptor_set::layout::DescriptorDescSupersetError;
use crate::descriptor_set::DescriptorSetsCollection;
use crate::descriptor_set::DescriptorSetWithOffsets;
use crate::pipeline::layout::PipelineLayout;
/// Checks whether descriptor sets are compatible with the pipeline.
pub fn check_descriptor_sets_validity<D>(
pub fn check_descriptor_sets_validity(
pipeline_layout: &PipelineLayout,
descriptor_sets: &D,
) -> Result<(), CheckDescriptorSetsValidityError>
where
D: ?Sized + DescriptorSetsCollection,
{
descriptor_sets: &[DescriptorSetWithOffsets],
) -> Result<(), CheckDescriptorSetsValidityError> {
// What's important is not that the pipeline layout and the descriptor sets *match*. Instead
// what's important is that the descriptor sets are a superset of the pipeline layout. It's not
// a problem if the descriptor sets provide more elements than expected.
@ -30,7 +27,9 @@ where
for (binding_num, pipeline_desc) in
(0..set.num_bindings()).filter_map(|i| set.descriptor(i).map(|d| (i, d)))
{
let set_desc = descriptor_sets.descriptor(set_num, binding_num);
let set_desc = descriptor_sets
.get(set_num)
.and_then(|so| so.as_ref().0.layout().descriptor(binding_num));
let set_desc = match set_desc {
Some(s) => s,

View File

@ -7,194 +7,59 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::descriptor_set::layout::DescriptorDesc;
use crate::descriptor_set::DescriptorSet;
use crate::descriptor_set::DescriptorSetWithOffsets;
/// A collection of descriptor set objects.
pub unsafe trait DescriptorSetsCollection {
fn into_vec(self) -> Vec<Box<dyn DescriptorSet + Send + Sync>>;
fn set(&self, num: usize) -> Option<&(dyn DescriptorSet + Send + Sync)>;
/// Returns the number of descriptors in the set. Includes possibly empty descriptors.
///
/// Returns `None` if the set is out of range.
// TODO: remove ; user should just use `into_vec` instead
fn num_bindings_in_set(&self, set: usize) -> Option<usize>;
/// Returns the descriptor for the given binding of the given set.
///
/// Returns `None` if out of range.
// TODO: remove ; user should just use `into_vec` instead
fn descriptor(&self, set: usize, binding: usize) -> Option<DescriptorDesc>;
fn into_vec(self) -> Vec<DescriptorSetWithOffsets>;
}
unsafe impl DescriptorSetsCollection for () {
#[inline]
fn into_vec(self) -> Vec<Box<dyn DescriptorSet + Send + Sync>> {
fn into_vec(self) -> Vec<DescriptorSetWithOffsets> {
vec![]
}
#[inline]
fn set(&self, num: usize) -> Option<&(dyn DescriptorSet + Send + Sync)> {
None
}
#[inline]
fn num_bindings_in_set(&self, _: usize) -> Option<usize> {
None
}
#[inline]
fn descriptor(&self, _: usize, _: usize) -> Option<DescriptorDesc> {
None
}
}
unsafe impl<T> DescriptorSetsCollection for T
where
T: DescriptorSet + Send + Sync + 'static,
T: Into<DescriptorSetWithOffsets>,
{
#[inline]
fn into_vec(self) -> Vec<Box<dyn DescriptorSet + Send + Sync>> {
vec![Box::new(self) as Box<_>]
}
#[inline]
fn set(&self, num: usize) -> Option<&(dyn DescriptorSet + Send + Sync)> {
match num {
0 => Some(self),
_ => None,
}
}
#[inline]
fn num_bindings_in_set(&self, set: usize) -> Option<usize> {
match set {
0 => Some(self.layout().num_bindings()),
_ => None,
}
}
#[inline]
fn descriptor(&self, set: usize, binding: usize) -> Option<DescriptorDesc> {
match set {
0 => self.layout().descriptor(binding),
_ => None,
}
fn into_vec(self) -> Vec<DescriptorSetWithOffsets> {
vec![self.into()]
}
}
unsafe impl<T> DescriptorSetsCollection for Vec<T>
where
T: DescriptorSet + Send + Sync + 'static,
T: Into<DescriptorSetWithOffsets>,
{
#[inline]
fn into_vec(self) -> Vec<Box<dyn DescriptorSet + Send + Sync>> {
let mut v = Vec::new();
for o in self {
v.push(Box::new(o) as Box<_>);
}
return v;
}
#[inline]
fn set(&self, num: usize) -> Option<&(dyn DescriptorSet + Send + Sync)> {
self.get(num).map(|x| x as _)
}
#[inline]
fn num_bindings_in_set(&self, set: usize) -> Option<usize> {
self.get(set).map(|x| x.layout().num_bindings())
}
#[inline]
fn descriptor(&self, set: usize, binding: usize) -> Option<DescriptorDesc> {
self.get(set).and_then(|x| x.layout().descriptor(binding))
fn into_vec(self) -> Vec<DescriptorSetWithOffsets> {
self.into_iter().map(|x| x.into()).collect()
}
}
macro_rules! impl_collection {
($first:ident $(, $others:ident)+) => (
unsafe impl<$first$(, $others)+> DescriptorSetsCollection for ($first, $($others),+)
where $first: DescriptorSet + Send + Sync + 'static
$(, $others: DescriptorSet + Send + Sync + 'static)*
where $first: Into<DescriptorSetWithOffsets>
$(, $others: Into<DescriptorSetWithOffsets>)*
{
#[inline]
fn into_vec(self) -> Vec<Box<dyn DescriptorSet + Send + Sync>> {
fn into_vec(self) -> Vec<DescriptorSetWithOffsets> {
#![allow(non_snake_case)]
let ($first, $($others,)*) = self;
let mut list = Vec::new();
list.push(Box::new($first) as Box<_>);
list.push($first.into());
$(
list.push(Box::new($others) as Box<_>);
list.push($others.into());
)+
list
}
#[inline]
fn set(&self, mut num: usize) -> Option<&(dyn DescriptorSet + Send + Sync)> {
#![allow(non_snake_case)]
#![allow(unused_mut)] // For the `num` parameter.
if num == 0 {
return Some(&self.0);
}
let &(_, $(ref $others,)*) = self;
$(
num -= 1;
if num == 0 {
return Some($others);
}
)*
None
}
#[inline]
fn num_bindings_in_set(&self, mut set: usize) -> Option<usize> {
#![allow(non_snake_case)]
#![allow(unused_mut)] // For the `set` parameter.
if set == 0 {
return Some(self.0.layout().num_bindings());
}
let &(_, $(ref $others,)*) = self;
$(
set -= 1;
if set == 0 {
return Some($others.layout().num_bindings());
}
)*
None
}
#[inline]
fn descriptor(&self, mut set: usize, binding: usize) -> Option<DescriptorDesc> {
#![allow(non_snake_case)]
#![allow(unused_mut)] // For the `set` parameter.
if set == 0 {
return self.0.layout().descriptor(binding);
}
let &(_, $(ref $others,)*) = self;
$(
set -= 1;
if set == 0 {
return $others.layout().descriptor(binding);
}
)*
None
}
}
impl_collection!($($others),+);

View File

@ -81,10 +81,12 @@ pub use self::persistent::PersistentDescriptorSetBuildError;
pub use self::persistent::PersistentDescriptorSetError;
use self::sys::UnsafeDescriptorSet;
use crate::buffer::BufferAccess;
use crate::descriptor_set::layout::{DescriptorBufferDesc, DescriptorDescTy};
use crate::device::DeviceOwned;
use crate::image::view::ImageViewAbstract;
use crate::SafeDeref;
use crate::VulkanObject;
use smallvec::SmallVec;
use std::hash::Hash;
use std::hash::Hasher;
use std::sync::Arc;
@ -106,6 +108,15 @@ pub unsafe trait DescriptorSet: DeviceOwned {
/// Returns the layout of this descriptor set.
fn layout(&self) -> &Arc<DescriptorSetLayout>;
/// Creates a [`DescriptorSetWithOffsets`] with the given dynamic offsets.
fn offsets<I>(self, dynamic_offsets: I) -> DescriptorSetWithOffsets
where
Self: Sized + Send + Sync + 'static,
I: IntoIterator<Item = u32>,
{
DescriptorSetWithOffsets::new(self, dynamic_offsets)
}
/// Returns the number of buffers within this descriptor set.
fn num_buffers(&self) -> usize;
@ -178,3 +189,99 @@ impl Hash for dyn DescriptorSet + Send + Sync {
self.device().hash(state);
}
}
pub struct DescriptorSetWithOffsets {
descriptor_set: Box<dyn DescriptorSet + Send + Sync>,
dynamic_offsets: SmallVec<[u32; 4]>,
}
impl DescriptorSetWithOffsets {
#[inline]
pub fn new<S, O>(descriptor_set: S, dynamic_offsets: O) -> Self
where
S: DescriptorSet + Send + Sync + 'static,
O: IntoIterator<Item = u32>,
{
let dynamic_offsets: SmallVec<_> = dynamic_offsets.into_iter().collect();
let layout = descriptor_set.layout();
let properties = layout.device().physical_device().properties();
let min_uniform_off_align = properties.min_uniform_buffer_offset_alignment.unwrap() as u32;
let min_storage_off_align = properties.min_storage_buffer_offset_alignment.unwrap() as u32;
let mut dynamic_offset_index = 0;
// Ensure that the number of dynamic_offsets is correct and that each
// dynamic offset is a multiple of the minimum offset alignment specified
// by the physical device.
for desc in layout.desc().bindings() {
let desc = desc.as_ref().unwrap();
if let DescriptorDescTy::Buffer(DescriptorBufferDesc {
dynamic: Some(true),
storage,
}) = desc.ty
{
// Don't check alignment if there are not enough offsets anyway
if dynamic_offsets.len() > dynamic_offset_index {
if storage {
assert!(
dynamic_offsets[dynamic_offset_index] % min_storage_off_align == 0,
"Dynamic storage buffer offset must be a multiple of min_storage_buffer_offset_alignment: got {}, expected a multiple of {}",
dynamic_offsets[dynamic_offset_index],
min_storage_off_align
);
} else {
assert!(
dynamic_offsets[dynamic_offset_index] % min_uniform_off_align == 0,
"Dynamic uniform buffer offset must be a multiple of min_uniform_buffer_offset_alignment: got {}, expected a multiple of {}",
dynamic_offsets[dynamic_offset_index],
min_uniform_off_align
);
}
}
dynamic_offset_index += 1;
}
}
assert!(
!(dynamic_offsets.len() < dynamic_offset_index),
"Too few dynamic offsets: got {}, expected {}",
dynamic_offsets.len(),
dynamic_offset_index
);
assert!(
!(dynamic_offsets.len() > dynamic_offset_index),
"Too many dynamic offsets: got {}, expected {}",
dynamic_offsets.len(),
dynamic_offset_index
);
DescriptorSetWithOffsets {
descriptor_set: Box::new(descriptor_set),
dynamic_offsets,
}
}
#[inline]
pub fn as_ref(&self) -> (&dyn DescriptorSet, &[u32]) {
(&self.descriptor_set, &self.dynamic_offsets)
}
#[inline]
pub fn into_tuple(
self,
) -> (
Box<dyn DescriptorSet + Send + Sync>,
impl ExactSizeIterator<Item = u32>,
) {
(self.descriptor_set, self.dynamic_offsets.into_iter())
}
}
impl<S> From<S> for DescriptorSetWithOffsets
where
S: DescriptorSet + Send + Sync + 'static,
{
#[inline]
fn from(descriptor_set: S) -> Self {
Self::new(descriptor_set, std::iter::empty())
}
}

View File

@ -507,8 +507,7 @@ mod tests {
CommandBufferUsage::OneTimeSubmit,
)
.unwrap();
cbb.dispatch([1, 1, 1], pipeline.clone(), set, (), vec![])
.unwrap();
cbb.dispatch([1, 1, 1], pipeline.clone(), set, ()).unwrap();
let cb = cbb.build().unwrap();
let future = now(device.clone())