Remove DescriptorSetBuilder, use descriptor writes directly (#1774)

* Remove DescriptorSetBuilder, use descriptor writes directly

* Merge two error types
This commit is contained in:
Rua 2021-12-18 11:32:38 +01:00 committed by GitHub
parent 974087c0f4
commit 2151697af0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 1462 additions and 1708 deletions

View File

@ -15,7 +15,7 @@
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::{WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::instance::{Instance, InstanceExtensions};
@ -148,11 +148,11 @@ fn main() {
// If you want to run the pipeline on multiple different buffers, you need to create multiple
// descriptor sets that each contain the buffer you want to run the shader on.
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
set_builder.add_buffer(data_buffer.clone()).unwrap();
let set = set_builder.build().unwrap();
let set = PersistentDescriptorSet::new(
layout.clone(),
[WriteDescriptorSet::buffer(0, data_buffer.clone())],
)
.unwrap();
// In order to execute our operation, we have to build a command buffer.
let mut builder = AutoCommandBufferBuilder::primary(

View File

@ -12,7 +12,7 @@ use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer,
};
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::{WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::device::Queue;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::graphics::color_blend::{
@ -118,11 +118,11 @@ impl AmbientLightingSystem {
.descriptor_set_layouts()
.get(0)
.unwrap();
let mut descriptor_set_builder = PersistentDescriptorSet::start(layout.clone());
descriptor_set_builder.add_image(color_input).unwrap();
let descriptor_set = descriptor_set_builder.build().unwrap();
let descriptor_set = PersistentDescriptorSet::new(
layout.clone(),
[WriteDescriptorSet::image_view(0, color_input)],
)
.unwrap();
let viewport = Viewport {
origin: [0.0, 0.0],

View File

@ -13,7 +13,7 @@ use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer,
};
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::{WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::device::Queue;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::graphics::color_blend::{
@ -129,15 +129,14 @@ impl DirectionalLightingSystem {
.descriptor_set_layouts()
.get(0)
.unwrap();
let mut descriptor_set_builder = PersistentDescriptorSet::start(layout.clone());
descriptor_set_builder
.add_image(color_input)
.unwrap()
.add_image(normals_input)
.unwrap();
let descriptor_set = descriptor_set_builder.build().unwrap();
let descriptor_set = PersistentDescriptorSet::new(
layout.clone(),
[
WriteDescriptorSet::image_view(0, color_input),
WriteDescriptorSet::image_view(1, normals_input),
],
)
.unwrap();
let viewport = Viewport {
origin: [0.0, 0.0],

View File

@ -13,7 +13,7 @@ use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer,
};
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::{WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::device::Queue;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::graphics::color_blend::{
@ -140,17 +140,15 @@ impl PointLightingSystem {
.descriptor_set_layouts()
.get(0)
.unwrap();
let mut descriptor_set_builder = PersistentDescriptorSet::start(layout.clone());
descriptor_set_builder
.add_image(color_input)
.unwrap()
.add_image(normals_input)
.unwrap()
.add_image(depth_input)
.unwrap();
let descriptor_set = descriptor_set_builder.build().unwrap();
let descriptor_set = PersistentDescriptorSet::new(
layout.clone(),
[
WriteDescriptorSet::image_view(0, color_input),
WriteDescriptorSet::image_view(1, normals_input),
WriteDescriptorSet::image_view(2, depth_input),
],
)
.unwrap();
let viewport = Viewport {
origin: [0.0, 0.0],

View File

@ -17,7 +17,7 @@
use std::mem;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::{DescriptorSet, PersistentDescriptorSet};
use vulkano::descriptor_set::{DescriptorSet, WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::instance::{Instance, InstanceExtensions};
@ -155,15 +155,14 @@ fn main() {
.unwrap();
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
set_builder
.add_buffer(input_buffer.clone())
.unwrap()
.add_buffer(output_buffer.clone())
.unwrap();
let set = set_builder.build().unwrap();
let set = PersistentDescriptorSet::new(
layout.clone(),
[
WriteDescriptorSet::buffer(0, input_buffer.clone()),
WriteDescriptorSet::buffer(1, output_buffer.clone()),
],
)
.unwrap();
// Build the command buffer, using different offsets for each call.
let mut builder = AutoCommandBufferBuilder::primary(

View File

@ -19,7 +19,7 @@ use std::io::BufWriter;
use std::path::Path;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::{WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::format::Format;
@ -196,11 +196,11 @@ fn main() {
let view = ImageView::new(image.clone()).unwrap();
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
set_builder.add_image(view.clone()).unwrap();
let set = set_builder.build().unwrap();
let set = PersistentDescriptorSet::new(
layout.clone(),
[WriteDescriptorSet::image_view(0, view.clone())],
)
.unwrap();
let buf = CpuAccessibleBuffer::from_iter(
device.clone(),

View File

@ -18,7 +18,7 @@ use vulkano::{
submit::SubmitCommandBufferBuilder, AutoCommandBufferBuilder, CommandBufferUsage,
SubpassContents,
},
descriptor_set::PersistentDescriptorSet,
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
device::{
physical::{PhysicalDevice, PhysicalDeviceType},
Device, DeviceExtensions, Queue,
@ -173,13 +173,15 @@ fn main() {
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
set_builder
.add_sampled_image(image_view, sampler.clone())
.unwrap();
let set = set_builder.build().unwrap();
let set = PersistentDescriptorSet::new(
layout.clone(),
[WriteDescriptorSet::image_view_sampler(
0,
image_view,
sampler.clone(),
)],
)
.unwrap();
let mut recreate_swapchain = false;
let mut previous_frame_end: Option<Box<dyn GpuFuture>> = Some(Box::new(now(device.clone())));

View File

@ -12,7 +12,7 @@ use std::io::Cursor;
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::format::Format;
@ -205,13 +205,15 @@ fn main() {
.unwrap();
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
set_builder
.add_sampled_image(texture.clone(), sampler.clone())
.unwrap();
let set = set_builder.build().unwrap();
let set = PersistentDescriptorSet::new(
layout.clone(),
[WriteDescriptorSet::image_view_sampler(
0,
texture.clone(),
sampler.clone(),
)],
)
.unwrap();
let mut viewport = Viewport {
origin: [0.0, 0.0],

View File

@ -11,7 +11,7 @@
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, ImmutableBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::instance::{Instance, InstanceExtensions};
@ -145,16 +145,15 @@ void main() {
};
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
set_builder
.add_buffer(data_buffer.clone())
.unwrap()
// Now you can just add immutable buffer like other buffers.
.add_buffer(immutable_data_buffer.clone())
.unwrap();
let set = set_builder.build().unwrap();
let set = PersistentDescriptorSet::new(
layout.clone(),
[
WriteDescriptorSet::buffer(0, data_buffer.clone()),
// Now you can just add immutable buffer like other buffers.
WriteDescriptorSet::buffer(1, immutable_data_buffer.clone()),
],
)
.unwrap();
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),

View File

@ -21,7 +21,7 @@ use std::io::Cursor;
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::{WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::format::Format;
@ -215,12 +215,13 @@ fn main() {
.unwrap();
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
// Use `add_image` instead of `add_sampled_image`, since the sampler is already in the layout.
set_builder.add_image(texture.clone()).unwrap();
let set = set_builder.build().unwrap();
// Use `image_view` instead of `image_view_sampler`, since the sampler is already in the layout.
let set = PersistentDescriptorSet::new(
layout.clone(),
[WriteDescriptorSet::image_view(0, texture.clone())],
)
.unwrap();
let mut viewport = Viewport {
origin: [0.0, 0.0],

View File

@ -36,7 +36,7 @@ use vulkano::buffer::{BufferUsage, CpuBufferPool};
use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, DrawIndirectCommand, SubpassContents,
};
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::image::view::ImageView;
@ -330,15 +330,14 @@ fn main() {
.descriptor_set_layouts()
.get(0)
.unwrap();
let mut cs_desciptor_set_builder = PersistentDescriptorSet::start(layout.clone());
cs_desciptor_set_builder
.add_buffer(vertices.clone())
.unwrap()
.add_buffer(indirect_args.clone())
.unwrap();
let cs_desciptor_set = cs_desciptor_set_builder.build().unwrap();
let cs_desciptor_set = PersistentDescriptorSet::new(
layout.clone(),
[
WriteDescriptorSet::buffer(0, vertices.clone()),
WriteDescriptorSet::buffer(1, indirect_args.clone()),
],
)
.unwrap();
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),

View File

@ -14,7 +14,7 @@ use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::PrimaryCommandBuffer;
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::{WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::device::Queue;
use vulkano::image::ImageAccess;
use vulkano::pipeline::{ComputePipeline, Pipeline, PipelineBindPoint};
@ -98,13 +98,14 @@ impl FractalComputePipeline {
let img_dims = image.image().dimensions().width_height();
let pipeline_layout = self.pipeline.layout();
let desc_layout = pipeline_layout.descriptor_set_layouts().get(0).unwrap();
let mut desc_set_builder = PersistentDescriptorSet::start(desc_layout.clone());
desc_set_builder
.add_image(image.clone())
.unwrap()
.add_buffer(self.palette.clone())
.unwrap();
let set = desc_set_builder.build().unwrap();
let set = PersistentDescriptorSet::new(
desc_layout.clone(),
[
WriteDescriptorSet::image_view(0, image.clone()),
WriteDescriptorSet::buffer(1, self.palette.clone()),
],
)
.unwrap();
let mut builder = AutoCommandBufferBuilder::primary(
self.gfx_queue.device().clone(),
self.gfx_queue.family(),

View File

@ -12,7 +12,7 @@ use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer,
};
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::{WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::device::Queue;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
@ -126,11 +126,15 @@ impl PixelsDrawPipeline {
0.0,
)
.unwrap();
let mut desc_set_builder = PersistentDescriptorSet::start(layout.clone());
desc_set_builder
.add_sampled_image(image.clone(), sampler)
.unwrap();
desc_set_builder.build().unwrap()
PersistentDescriptorSet::new(
layout.clone(),
[WriteDescriptorSet::image_view_sampler(
0,
image.clone(),
sampler,
)],
)
.unwrap()
}
/// Draw input `image` over a quad of size -1.0 to 1.0

View File

@ -11,7 +11,7 @@
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::instance::{Instance, InstanceExtensions};
@ -106,11 +106,11 @@ fn main() {
};
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
set_builder.add_buffer(data_buffer.clone()).unwrap();
let set = set_builder.build().unwrap();
let set = PersistentDescriptorSet::new(
layout.clone(),
[WriteDescriptorSet::buffer(0, data_buffer.clone())],
)
.unwrap();
// The `vulkano_shaders::shaders!` macro generates a struct with the correct representation of the push constants struct specified in the shader.
// Here we create an instance of the generated struct.

View File

@ -12,7 +12,7 @@ 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::descriptor_set::WriteDescriptorSet;
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::format::Format;
@ -276,12 +276,12 @@ fn main() {
.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()
})
.push_descriptor_set(
PipelineBindPoint::Graphics,
pipeline.layout().clone(),
0,
[WriteDescriptorSet::image_view(0, texture.clone())],
)
.bind_vertex_buffers(0, vertex_buffer.clone())
.draw(vertex_buffer.len() as u32, 1, 0, 0)
.unwrap()

View File

@ -15,7 +15,7 @@ use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, Subp
use vulkano::descriptor_set::layout::{
DescriptorSetDesc, DescriptorSetLayout, DescriptorSetLayoutError,
};
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::format::Format;
@ -318,19 +318,19 @@ fn main() {
.unwrap();
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
set_builder
.enter_array()
.unwrap()
.add_sampled_image(mascot_texture.clone(), sampler.clone())
.unwrap()
.add_sampled_image(vulkano_texture.clone(), sampler.clone())
.unwrap()
.leave_array()
.unwrap();
let set = set_builder.build().unwrap();
let set = PersistentDescriptorSet::new_variable(
layout.clone(),
2,
[WriteDescriptorSet::image_view_sampler_array(
0,
0,
[
(mascot_texture.clone() as _, sampler.clone()),
(vulkano_texture.clone() as _, sampler.clone()),
],
)],
)
.unwrap();
let mut viewport = Viewport {
origin: [0.0, 0.0],

View File

@ -13,7 +13,7 @@
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::instance::{Instance, InstanceExtensions};
@ -108,11 +108,11 @@ fn main() {
};
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
set_builder.add_buffer(data_buffer.clone()).unwrap();
let set = set_builder.build().unwrap();
let set = PersistentDescriptorSet::new(
layout.clone(),
[WriteDescriptorSet::buffer(0, data_buffer.clone())],
)
.unwrap();
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),

View File

@ -30,7 +30,7 @@
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features, Queue};
use vulkano::instance::{Instance, InstanceExtensions};
@ -172,11 +172,11 @@ fn main() {
parameters: shaders::ty::Parameters,
) {
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
set_builder.add_buffer(data_buffer.clone()).unwrap();
let set = set_builder.build().unwrap();
let set = PersistentDescriptorSet::new(
layout.clone(),
[WriteDescriptorSet::buffer(0, data_buffer.clone())],
)
.unwrap();
let mut builder = AutoCommandBufferBuilder::primary(
queue.device().clone(),

View File

@ -11,7 +11,7 @@
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::{WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::instance::{Instance, InstanceExtensions};
@ -110,11 +110,11 @@ fn main() {
};
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
set_builder.add_buffer(data_buffer.clone()).unwrap();
let set = set_builder.build().unwrap();
let set = PersistentDescriptorSet::new(
layout.clone(),
[WriteDescriptorSet::buffer(0, data_buffer.clone())],
)
.unwrap();
let mut builder = AutoCommandBufferBuilder::primary(
device.clone(),

View File

@ -14,7 +14,7 @@ use std::time::Instant;
use vulkano::buffer::cpu_pool::CpuBufferPool;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::{WriteDescriptorSet, PersistentDescriptorSet};
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::format::Format;
@ -223,11 +223,11 @@ fn main() {
};
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
set_builder.add_buffer(uniform_buffer_subbuffer).unwrap();
let set = set_builder.build().unwrap();
let set = PersistentDescriptorSet::new(
layout.clone(),
[WriteDescriptorSet::buffer(0, uniform_buffer_subbuffer)],
)
.unwrap();
let (image_num, suboptimal, acquire_future) =
match swapchain::acquire_next_image(swapchain.clone(), None) {

View File

@ -238,7 +238,7 @@ where
}
}
pub unsafe trait BufferViewAbstract: Send + Sync {
pub unsafe trait BufferViewAbstract: DeviceOwned + Send + Sync {
/// Returns the inner handle used by this buffer view.
fn inner(&self) -> ash::vk::BufferView;

View File

@ -37,8 +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::descriptor_set::{check_descriptor_write, DescriptorSetsCollection, WriteDescriptorSet};
use crate::device::physical::QueueFamily;
use crate::device::Device;
use crate::device::DeviceOwned;
@ -1758,12 +1757,13 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
/// [`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`.
/// - Panics if an element of `descriptor_writes` is not compatible with `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
descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
) -> &mut Self {
match pipeline_bind_point {
PipelineBindPoint::Compute => assert!(
@ -1785,12 +1785,12 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
"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,
);
let descriptor_writes: SmallVec<[_; 8]> = descriptor_writes.into_iter().collect();
let descriptor_set_layout = &pipeline_layout.descriptor_set_layouts()[set_num as usize];
for write in &descriptor_writes {
check_descriptor_write(write, descriptor_set_layout, 0).unwrap();
}
unsafe {
self.inner.push_descriptor_set(

View File

@ -25,10 +25,10 @@ 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::DescriptorType;
use crate::descriptor_set::DescriptorBindingResources;
use crate::descriptor_set::DescriptorSetWithOffsets;
use crate::descriptor_set::WriteDescriptorSet;
use crate::format::ClearValue;
use crate::image::ImageAccess;
use crate::image::ImageLayout;
@ -1531,13 +1531,13 @@ impl SyncCommandBufferBuilder {
pipeline_bind_point: PipelineBindPoint,
pipeline_layout: Arc<PipelineLayout>,
set_num: u32,
descriptor_writes: DescriptorSetBuilderOutput,
descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
) {
struct Cmd {
pipeline_bind_point: PipelineBindPoint,
pipeline_layout: Arc<PipelineLayout>,
set_num: u32,
descriptor_writes: DescriptorSetBuilderOutput,
descriptor_writes: SmallVec<[WriteDescriptorSet; 8]>,
}
impl Command for Cmd {
@ -1550,11 +1550,14 @@ impl SyncCommandBufferBuilder {
self.pipeline_bind_point,
&self.pipeline_layout,
self.set_num,
self.descriptor_writes.writes(),
&self.descriptor_writes,
);
}
}
let descriptor_writes: SmallVec<[WriteDescriptorSet; 8]> =
descriptor_writes.into_iter().collect();
let state = self.current_state.invalidate_descriptor_sets(
pipeline_bind_point,
pipeline_layout.clone(),
@ -1572,7 +1575,10 @@ impl SyncCommandBufferBuilder {
SetOrPush::Push(set_resources) => set_resources,
_ => unreachable!(),
};
set_resources.update(descriptor_writes.writes());
for write in &descriptor_writes {
set_resources.update(write);
}
self.append_command(
Cmd {
@ -2632,7 +2638,7 @@ impl SyncCommandBufferBuilder {
.binding(binding)
.unwrap()
{
DescriptorBindingResources::None => continue,
DescriptorBindingResources::None(_) => continue,
DescriptorBindingResources::Buffer(elements) => {
resources.extend(elements.iter().flatten().cloned().map(buffer_resource));
}

View File

@ -492,6 +492,7 @@ mod tests {
use crate::descriptor_set::layout::DescriptorSetLayout;
use crate::descriptor_set::layout::DescriptorType;
use crate::descriptor_set::PersistentDescriptorSet;
use crate::descriptor_set::WriteDescriptorSet;
use crate::device::Device;
use crate::pipeline::layout::PipelineLayout;
use crate::pipeline::PipelineBindPoint;
@ -682,13 +683,14 @@ mod tests {
PipelineLayout::new(device.clone(), [set_layout.clone(), set_layout.clone()], [])
.unwrap();
let set = {
let mut builder = PersistentDescriptorSet::start(set_layout.clone());
builder
.add_sampler(Sampler::simple_repeat_linear(device.clone()))
.unwrap();
builder.build().unwrap()
};
let set = PersistentDescriptorSet::new(
set_layout.clone(),
[WriteDescriptorSet::sampler(
0,
Sampler::simple_repeat_linear(device.clone()),
)],
)
.unwrap();
let mut set_builder = sync.bind_descriptor_sets();
set_builder.add(set.clone());
@ -734,13 +736,14 @@ mod tests {
)
.unwrap();
let set = {
let mut builder = PersistentDescriptorSet::start(set_layout.clone());
builder
.add_sampler(Sampler::simple_repeat_linear(device.clone()))
.unwrap();
builder.build().unwrap()
};
let set = PersistentDescriptorSet::new(
set_layout.clone(),
[WriteDescriptorSet::sampler(
0,
Sampler::simple_repeat_linear(device.clone()),
)],
)
.unwrap();
let mut set_builder = sync.bind_descriptor_sets();
set_builder.add(set);

View File

@ -17,9 +17,8 @@ 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::DescriptorWriteInfo;
use crate::descriptor_set::sys::UnsafeDescriptorSet;
use crate::descriptor_set::{DescriptorWriteInfo, WriteDescriptorSet};
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::format::ClearValue;
@ -1356,24 +1355,20 @@ impl UnsafeCommandBufferBuilder {
///
/// If the list is empty then the command is automatically ignored.
#[inline]
pub unsafe fn push_descriptor_set(
pub unsafe fn push_descriptor_set<'a>(
&mut self,
pipeline_bind_point: PipelineBindPoint,
pipeline_layout: &PipelineLayout,
set_num: u32,
descriptor_writes: &[DescriptorWrite],
descriptor_writes: impl IntoIterator<Item = &'a WriteDescriptorSet>,
) {
debug_assert!(self.device().enabled_extensions().khr_push_descriptor);
if descriptor_writes.is_empty() {
return;
}
let (infos, mut writes): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = descriptor_writes
.into_iter()
.map(|write| {
let descriptor = pipeline_layout.descriptor_set_layouts()[set_num as usize]
.descriptor(write.binding_num)
.descriptor(write.binding())
.unwrap();
(
@ -1383,6 +1378,10 @@ impl UnsafeCommandBufferBuilder {
})
.unzip();
if writes.is_empty() {
return;
}
// Set the info pointers separately.
for (info, write) in infos.iter().zip(writes.iter_mut()) {
match info {

View File

@ -80,7 +80,7 @@ pub(in super::super) fn check_descriptor_sets_validity<'a, P: Pipeline>(
let binding_resources = set_resources.binding(binding_num).unwrap();
match binding_resources {
DescriptorBindingResources::None => (),
DescriptorBindingResources::None(_) => (),
DescriptorBindingResources::Buffer(elements) => {
check_resources(set_num, binding_num, reqs, elements, |_| Ok(()))?;
}

View File

@ -1,610 +0,0 @@
// Copyright (c) 2017 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::buffer::{BufferAccess, BufferView};
use crate::descriptor_set::layout::{DescriptorDesc, DescriptorType};
use crate::descriptor_set::sys::DescriptorWrite;
use crate::descriptor_set::{
DescriptorSetError, DescriptorSetLayout, MissingBufferUsage, MissingImageUsage,
};
use crate::device::{Device, DeviceOwned};
use crate::image::ImageViewAbstract;
use crate::sampler::Sampler;
use crate::VulkanObject;
use std::sync::Arc;
struct BuilderDescriptor {
desc: Option<DescriptorDesc>,
array_element: u32,
}
/// A builder for constructing a new descriptor set.
pub struct DescriptorSetBuilder {
layout: Arc<DescriptorSetLayout>,
variable_descriptor_count: u32,
writes: Vec<DescriptorWrite>,
cur_binding: u32,
descriptors: Vec<BuilderDescriptor>,
in_array: bool,
poisoned: bool,
}
impl DescriptorSetBuilder {
/// Starts the process of building a descriptor set. Returns a builder.
///
/// # Panic
///
/// - Panics if the set id is out of range.
pub fn start(layout: Arc<DescriptorSetLayout>) -> Self {
let mut descriptors = Vec::with_capacity(layout.num_bindings() as usize);
let mut desc_writes_capacity = 0;
for binding_i in 0..layout.num_bindings() {
if let Some(desc) = layout.descriptor(binding_i) {
desc_writes_capacity += desc.descriptor_count as usize;
descriptors.push(BuilderDescriptor {
desc: Some(desc),
array_element: 0,
});
} else {
descriptors.push(BuilderDescriptor {
desc: None,
array_element: 0,
});
}
}
Self {
layout,
variable_descriptor_count: 0,
writes: Vec::with_capacity(desc_writes_capacity),
cur_binding: 0,
descriptors,
in_array: false,
poisoned: false,
}
}
/// Finalizes the building process and returns the generated output.
pub fn build(self) -> Result<DescriptorSetBuilderOutput, DescriptorSetError> {
if self.poisoned {
return Err(DescriptorSetError::BuilderPoisoned);
}
if self.in_array {
return Err(DescriptorSetError::InArray);
}
if self.cur_binding != self.descriptors.len() as u32 {
return Err(DescriptorSetError::DescriptorsMissing {
expected: self.descriptors.len() as u32,
obtained: self.cur_binding,
});
} else {
Ok(DescriptorSetBuilderOutput {
layout: self.layout,
writes: self.writes,
variable_descriptor_count: self.variable_descriptor_count,
})
}
}
fn poison_on_err(
&mut self,
func: impl FnOnce(&mut Self) -> Result<(), DescriptorSetError>,
) -> Result<&mut Self, DescriptorSetError> {
if self.poisoned {
return Err(DescriptorSetError::BuilderPoisoned);
}
match func(self) {
Ok(()) => Ok(self),
Err(err) => {
self.poisoned = true;
Err(err)
}
}
}
/// Call this function if the next element of the set is an array in order to set the value of
/// each element.
///
/// This function can be called even if the descriptor isn't an array, and it is valid to enter
/// the "array", add one element, then leave.
pub fn enter_array(&mut self) -> Result<&mut Self, DescriptorSetError> {
self.poison_on_err(|builder| {
if builder.in_array {
Err(DescriptorSetError::InArray)
} else if builder.cur_binding >= builder.descriptors.len() as u32 {
Err(DescriptorSetError::TooManyDescriptors)
} else if builder.descriptors[builder.cur_binding as usize]
.desc
.is_none()
{
Err(DescriptorSetError::DescriptorIsEmpty)
} else {
builder.in_array = true;
Ok(())
}
})
}
/// Leaves the array. Call this once you added all the elements of the array.
pub fn leave_array(&mut self) -> Result<&mut Self, DescriptorSetError> {
self.poison_on_err(|builder| {
if !builder.in_array {
Err(DescriptorSetError::NotInArray)
} else {
let descriptor = &builder.descriptors[builder.cur_binding as usize];
let inner_desc = match descriptor.desc.as_ref() {
Some(some) => some,
None => unreachable!(),
};
if inner_desc.variable_count {
if descriptor.array_element > inner_desc.descriptor_count {
return Err(DescriptorSetError::ArrayTooManyDescriptors {
capacity: inner_desc.descriptor_count,
obtained: descriptor.array_element,
});
}
debug_assert!(builder.cur_binding as usize == builder.descriptors.len() - 1);
debug_assert!(builder.variable_descriptor_count == 0);
builder.variable_descriptor_count = descriptor.array_element;
} else if descriptor.array_element != inner_desc.descriptor_count {
return Err(DescriptorSetError::ArrayLengthMismatch {
expected: inner_desc.descriptor_count,
obtained: descriptor.array_element,
});
}
builder.in_array = false;
builder.cur_binding += 1;
Ok(())
}
})
}
/// Skips the current descriptor if it is empty.
pub fn add_empty(&mut self) -> Result<&mut Self, DescriptorSetError> {
self.poison_on_err(|builder| {
// Should be unreachable as enter_array prevents entering an array for empty descriptors.
debug_assert!(!builder.in_array);
if builder.descriptors[builder.cur_binding as usize]
.desc
.is_some()
{
return Err(DescriptorSetError::WrongDescriptorType);
}
builder.cur_binding += 1;
Ok(())
})
}
/// Binds a buffer as the next descriptor or array element.
pub fn add_buffer(
&mut self,
buffer: Arc<dyn BufferAccess>,
) -> Result<&mut Self, DescriptorSetError> {
self.poison_on_err(|builder| {
if buffer.inner().buffer.device().internal_object()
!= builder.layout.device().internal_object()
{
return Err(DescriptorSetError::ResourceWrongDevice);
}
let leave_array = if !builder.in_array {
builder.enter_array()?;
true
} else {
false
};
let descriptor = &mut builder.descriptors[builder.cur_binding as usize];
let inner_desc = match descriptor.desc.as_ref() {
Some(some) => some,
None => return Err(DescriptorSetError::WrongDescriptorType),
};
// Note that the buffer content is not checked. This is technically not unsafe as
// long as the data in the buffer has no invalid memory representation (ie. no
// bool, no enum, no pointer, no str) and as long as the robust buffer access
// feature is enabled.
// TODO: this is not checked ^
// TODO: eventually shouldn't be an assert ; for now robust_buffer_access is always
// enabled so this assert should never fail in practice, but we put it anyway
// in case we forget to adjust this code
match inner_desc.ty {
DescriptorType::StorageBuffer | DescriptorType::StorageBufferDynamic => {
assert!(
builder
.layout
.device()
.enabled_features()
.robust_buffer_access
);
if !buffer.inner().buffer.usage().storage_buffer {
return Err(DescriptorSetError::MissingBufferUsage(
MissingBufferUsage::StorageBuffer,
));
}
}
DescriptorType::UniformBuffer => {
assert!(
builder
.layout
.device()
.enabled_features()
.robust_buffer_access
);
if !buffer.inner().buffer.usage().uniform_buffer {
return Err(DescriptorSetError::MissingBufferUsage(
MissingBufferUsage::UniformBuffer,
));
}
}
DescriptorType::UniformBufferDynamic => {
assert!(
builder
.layout
.device()
.enabled_features()
.robust_buffer_access
);
if !buffer.inner().buffer.usage().uniform_buffer {
return Err(DescriptorSetError::MissingBufferUsage(
MissingBufferUsage::UniformBuffer,
));
}
}
_ => return Err(DescriptorSetError::WrongDescriptorType),
}
unsafe {
builder.writes.push(DescriptorWrite::buffer(
builder.cur_binding,
descriptor.array_element,
[buffer],
));
}
descriptor.array_element += 1;
if leave_array {
builder.leave_array()?;
}
Ok(())
})
}
/// Binds a buffer view as the next descriptor or array element.
pub fn add_buffer_view<B>(
&mut self,
view: Arc<BufferView<B>>,
) -> Result<&mut Self, DescriptorSetError>
where
B: BufferAccess + 'static,
{
self.poison_on_err(|builder| {
if view.device().internal_object() != builder.layout.device().internal_object() {
return Err(DescriptorSetError::ResourceWrongDevice);
}
let leave_array = if !builder.in_array {
builder.enter_array()?;
true
} else {
false
};
let descriptor = &mut builder.descriptors[builder.cur_binding as usize];
let inner_desc = match descriptor.desc.as_ref() {
Some(some) => some,
None => return Err(DescriptorSetError::WrongDescriptorType),
};
match inner_desc.ty {
DescriptorType::StorageTexelBuffer => {
// TODO: storage_texel_buffer_atomic
if !view.storage_texel_buffer() {
return Err(DescriptorSetError::MissingBufferUsage(
MissingBufferUsage::StorageTexelBuffer,
));
}
}
DescriptorType::UniformTexelBuffer => {
if !view.uniform_texel_buffer() {
return Err(DescriptorSetError::MissingBufferUsage(
MissingBufferUsage::UniformTexelBuffer,
));
}
}
_ => return Err(DescriptorSetError::WrongDescriptorType),
}
unsafe {
builder.writes.push(DescriptorWrite::buffer_view(
builder.cur_binding,
descriptor.array_element,
[view as Arc<_>],
));
}
descriptor.array_element += 1;
if leave_array {
builder.leave_array()?;
}
Ok(())
})
}
/// Binds an image view as the next descriptor or array element.
pub fn add_image(
&mut self,
image_view: Arc<dyn ImageViewAbstract>,
) -> Result<&mut Self, DescriptorSetError> {
self.poison_on_err(|builder| {
if image_view.image().inner().image.device().internal_object()
!= builder.layout.device().internal_object()
{
return Err(DescriptorSetError::ResourceWrongDevice);
}
let leave_array = if !builder.in_array {
builder.enter_array()?;
true
} else {
false
};
let descriptor = &mut builder.descriptors[builder.cur_binding as usize];
let inner_desc = match descriptor.desc.as_ref() {
Some(some) => some,
None => return Err(DescriptorSetError::WrongDescriptorType),
};
match &inner_desc.ty {
DescriptorType::CombinedImageSampler
if !inner_desc.immutable_samplers.is_empty() =>
{
if !image_view.image().inner().image.usage().sampled {
return Err(DescriptorSetError::MissingImageUsage(
MissingImageUsage::Sampled,
));
}
if !image_view.can_be_sampled(
&inner_desc.immutable_samplers[descriptor.array_element as usize],
) {
return Err(DescriptorSetError::IncompatibleImageViewSampler);
}
}
DescriptorType::SampledImage => {
if !image_view.image().inner().image.usage().sampled {
return Err(DescriptorSetError::MissingImageUsage(
MissingImageUsage::Sampled,
));
}
}
DescriptorType::StorageImage => {
if !image_view.image().inner().image.usage().storage {
return Err(DescriptorSetError::MissingImageUsage(
MissingImageUsage::Storage,
));
}
if !image_view.component_mapping().is_identity() {
return Err(DescriptorSetError::NotIdentitySwizzled);
}
}
DescriptorType::InputAttachment => {
if !image_view.image().inner().image.usage().input_attachment {
return Err(DescriptorSetError::MissingImageUsage(
MissingImageUsage::InputAttachment,
));
}
if !image_view.component_mapping().is_identity() {
return Err(DescriptorSetError::NotIdentitySwizzled);
}
let image_layers = image_view.array_layers();
let num_layers = image_layers.end - image_layers.start;
if image_view.ty().is_arrayed() {
return Err(DescriptorSetError::UnexpectedArrayed);
}
}
_ => return Err(DescriptorSetError::WrongDescriptorType),
}
unsafe {
builder.writes.push(DescriptorWrite::image_view(
builder.cur_binding,
descriptor.array_element,
[image_view],
));
}
descriptor.array_element += 1;
if leave_array {
builder.leave_array()?;
}
Ok(())
})
}
/// Binds an image view with a sampler as the next descriptor or array element.
///
/// If the descriptor set layout contains immutable samplers for this descriptor, use
/// `add_image` instead.
pub fn add_sampled_image(
&mut self,
image_view: Arc<dyn ImageViewAbstract>,
sampler: Arc<Sampler>,
) -> Result<&mut Self, DescriptorSetError> {
self.poison_on_err(|builder| {
if image_view.image().inner().image.device().internal_object()
!= builder.layout.device().internal_object()
{
return Err(DescriptorSetError::ResourceWrongDevice);
}
if sampler.device().internal_object() != builder.layout.device().internal_object() {
return Err(DescriptorSetError::ResourceWrongDevice);
}
if !image_view.image().inner().image.usage().sampled {
return Err(DescriptorSetError::MissingImageUsage(
MissingImageUsage::Sampled,
));
}
if !image_view.can_be_sampled(&sampler) {
return Err(DescriptorSetError::IncompatibleImageViewSampler);
}
let leave_array = if !builder.in_array {
builder.enter_array()?;
true
} else {
false
};
let descriptor = &mut builder.descriptors[builder.cur_binding as usize];
let inner_desc = match descriptor.desc.as_ref() {
Some(some) => some,
None => return Err(DescriptorSetError::WrongDescriptorType),
};
match &inner_desc.ty {
DescriptorType::CombinedImageSampler => {
if !inner_desc.immutable_samplers.is_empty() {
return Err(DescriptorSetError::SamplerIsImmutable);
}
}
_ => return Err(DescriptorSetError::WrongDescriptorType),
}
unsafe {
builder.writes.push(DescriptorWrite::image_view_sampler(
builder.cur_binding,
descriptor.array_element,
[(image_view, sampler)],
));
}
descriptor.array_element += 1;
if leave_array {
builder.leave_array()?;
}
Ok(())
})
}
/// Binds a sampler as the next descriptor or array element.
pub fn add_sampler(&mut self, sampler: Arc<Sampler>) -> Result<&mut Self, DescriptorSetError> {
self.poison_on_err(|builder| {
if sampler.device().internal_object() != builder.layout.device().internal_object() {
return Err(DescriptorSetError::ResourceWrongDevice);
}
let leave_array = if !builder.in_array {
builder.enter_array()?;
true
} else {
false
};
let descriptor = &mut builder.descriptors[builder.cur_binding as usize];
let inner_desc = match descriptor.desc.as_ref() {
Some(some) => some,
None => return Err(DescriptorSetError::WrongDescriptorType),
};
match &inner_desc.ty {
DescriptorType::Sampler => {
if !inner_desc.immutable_samplers.is_empty() {
return Err(DescriptorSetError::SamplerIsImmutable);
}
}
_ => return Err(DescriptorSetError::WrongDescriptorType),
}
unsafe {
builder.writes.push(DescriptorWrite::sampler(
builder.cur_binding,
descriptor.array_element,
[sampler],
));
}
descriptor.array_element += 1;
if leave_array {
builder.leave_array()?;
}
Ok(())
})
}
}
unsafe impl DeviceOwned for DescriptorSetBuilder {
fn device(&self) -> &Arc<Device> {
self.layout.device()
}
}
/// The output of the descriptor set builder.
///
/// This is not a descriptor set yet, but can be used to write the descriptors to one.
pub struct DescriptorSetBuilderOutput {
layout: Arc<DescriptorSetLayout>,
variable_descriptor_count: u32,
writes: Vec<DescriptorWrite>,
}
impl DescriptorSetBuilderOutput {
/// Returns the descriptor set layout.
#[inline]
pub fn layout(&self) -> &Arc<DescriptorSetLayout> {
&self.layout
}
/// Returns the number of variable descriptors.
#[inline]
pub fn variable_descriptor_count(&self) -> u32 {
self.variable_descriptor_count
}
/// Returns the descriptor writes.
#[inline]
pub fn writes(&self) -> &[DescriptorWrite] {
&self.writes
}
}

View File

@ -73,33 +73,35 @@
//! - 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;
pub use self::resources::{DescriptorBindingResources, DescriptorSetResources};
pub use self::single_layout_pool::SingleLayoutDescSetPool;
use self::sys::UnsafeDescriptorSet;
pub(crate) use self::update::{check_descriptor_write, DescriptorWriteInfo};
pub use self::update::{DescriptorSetUpdateError, WriteDescriptorSet, WriteDescriptorSetElements};
use crate::buffer::BufferAccess;
use crate::buffer::BufferViewAbstract;
use crate::descriptor_set::layout::DescriptorType;
use crate::device::DeviceOwned;
use crate::image::ImageViewAbstract;
use crate::sampler::Sampler;
use crate::OomError;
use crate::VulkanObject;
use smallvec::SmallVec;
use std::error;
use std::fmt;
use fnv::FnvHashMap;
use smallvec::{smallvec, SmallVec};
use std::hash::Hash;
use std::hash::Hasher;
use std::ptr;
use std::sync::Arc;
pub mod builder;
mod collection;
pub mod layout;
pub mod persistent;
pub mod pool;
mod resources;
pub mod single_layout_pool;
pub mod sys;
mod update;
/// Trait for objects that contain a collection of resources that will be accessible by shaders.
///
@ -142,6 +144,269 @@ impl Hash for dyn DescriptorSet {
}
}
pub(crate) struct DescriptorSetInner {
handle: ash::vk::DescriptorSet,
layout: Arc<DescriptorSetLayout>,
variable_descriptor_count: u32,
resources: DescriptorSetResources,
}
impl DescriptorSetInner {
pub(crate) fn new(
handle: ash::vk::DescriptorSet,
layout: Arc<DescriptorSetLayout>,
variable_descriptor_count: u32,
descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
) -> Result<Self, DescriptorSetUpdateError> {
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"
);
let max_count = layout.variable_descriptor_count();
assert!(
variable_descriptor_count <= max_count,
"the provided variable_descriptor_count ({}) is greater than the maximum number of variable count descriptors in the layout ({})",
variable_descriptor_count,
max_count,
);
let mut resources = DescriptorSetResources::new(&layout, variable_descriptor_count);
let descriptor_writes = descriptor_writes.into_iter();
let (lower_size_bound, _) = descriptor_writes.size_hint();
let mut descriptor_write_info: SmallVec<[_; 8]> = SmallVec::with_capacity(lower_size_bound);
let mut write_descriptor_set: SmallVec<[_; 8]> = SmallVec::with_capacity(lower_size_bound);
for write in descriptor_writes {
let layout_binding =
check_descriptor_write(&write, &layout, variable_descriptor_count)?;
resources.update(&write);
descriptor_write_info.push(write.to_vulkan_info(layout_binding.ty));
write_descriptor_set.push(write.to_vulkan(handle, layout_binding.ty));
}
if !write_descriptor_set.is_empty() {
for (info, write) in descriptor_write_info
.iter()
.zip(write_descriptor_set.iter_mut())
{
match info {
DescriptorWriteInfo::Image(info) => {
write.descriptor_count = info.len() as u32;
write.p_image_info = info.as_ptr();
}
DescriptorWriteInfo::Buffer(info) => {
write.descriptor_count = info.len() as u32;
write.p_buffer_info = info.as_ptr();
}
DescriptorWriteInfo::BufferView(info) => {
write.descriptor_count = info.len() as u32;
write.p_texel_buffer_view = info.as_ptr();
}
}
}
}
unsafe {
let fns = layout.device().fns();
fns.v1_0.update_descriptor_sets(
layout.device().internal_object(),
write_descriptor_set.len() as u32,
write_descriptor_set.as_ptr(),
0,
ptr::null(),
);
}
Ok(DescriptorSetInner {
handle,
layout,
variable_descriptor_count,
resources,
})
}
pub(crate) fn layout(&self) -> &Arc<DescriptorSetLayout> {
&self.layout
}
pub(crate) fn variable_descriptor_count(&self) -> u32 {
self.variable_descriptor_count
}
pub(crate) fn resources(&self) -> &DescriptorSetResources {
&self.resources
}
}
/// The resources that are bound to a descriptor set.
#[derive(Clone)]
pub struct DescriptorSetResources {
binding_resources: FnvHashMap<u32, DescriptorBindingResources>,
}
impl DescriptorSetResources {
/// Creates a new `DescriptorSetResources` matching the provided descriptor set layout, and
/// all descriptors set to `None`.
pub fn new(layout: &DescriptorSetLayout, variable_descriptor_count: u32) -> Self {
assert!(variable_descriptor_count <= layout.variable_descriptor_count());
let binding_resources = layout
.desc()
.bindings()
.iter()
.enumerate()
.filter_map(|(b, d)| d.as_ref().map(|d| (b as u32, d)))
.map(|(binding_num, binding_desc)| {
let count = if binding_desc.variable_count {
variable_descriptor_count
} else {
binding_desc.descriptor_count
} as usize;
let binding_resources = match binding_desc.ty {
DescriptorType::UniformBuffer
| DescriptorType::StorageBuffer
| DescriptorType::UniformBufferDynamic
| DescriptorType::StorageBufferDynamic => {
DescriptorBindingResources::Buffer(smallvec![None; count])
}
DescriptorType::UniformTexelBuffer | DescriptorType::StorageTexelBuffer => {
DescriptorBindingResources::BufferView(smallvec![None; count])
}
DescriptorType::SampledImage
| DescriptorType::StorageImage
| DescriptorType::InputAttachment => {
DescriptorBindingResources::ImageView(smallvec![None; count])
}
DescriptorType::CombinedImageSampler => {
if binding_desc.immutable_samplers.is_empty() {
DescriptorBindingResources::ImageViewSampler(smallvec![None; count])
} else {
DescriptorBindingResources::ImageView(smallvec![None; count])
}
}
DescriptorType::Sampler => {
if binding_desc.immutable_samplers.is_empty() {
DescriptorBindingResources::Sampler(smallvec![None; count])
} else if layout.desc().is_push_descriptor() {
// For push descriptors, no resource is written by default, this needs
// to be done explicitly via a dummy write.
DescriptorBindingResources::None(smallvec![None; count])
} else {
// For regular descriptor sets, all descriptors are considered valid
// from the start.
DescriptorBindingResources::None(smallvec![Some(()); count])
}
}
};
(binding_num, binding_resources)
})
.collect();
Self { binding_resources }
}
/// Applies a descriptor write to the resources.
///
/// # Panics
///
/// - Panics if the binding number of a write does not exist in the resources.
/// - See also [`DescriptorBindingResources::update`].
pub fn update<'a>(&mut self, write: &WriteDescriptorSet) {
self.binding_resources
.get_mut(&write.binding())
.expect("descriptor write has invalid binding number")
.update(write)
}
/// Returns a reference to the bound resources for `binding`. Returns `None` if the binding
/// doesn't exist.
#[inline]
pub fn binding(&self, binding: u32) -> Option<&DescriptorBindingResources> {
self.binding_resources.get(&binding)
}
}
/// The resources that are bound to a single descriptor set binding.
#[derive(Clone)]
pub enum DescriptorBindingResources {
None(Elements<()>),
Buffer(Elements<Arc<dyn BufferAccess>>),
BufferView(Elements<Arc<dyn BufferViewAbstract>>),
ImageView(Elements<Arc<dyn ImageViewAbstract>>),
ImageViewSampler(Elements<(Arc<dyn ImageViewAbstract>, Arc<Sampler>)>),
Sampler(Elements<Arc<Sampler>>),
}
type Elements<T> = SmallVec<[Option<T>; 1]>;
impl DescriptorBindingResources {
/// Applies a descriptor write to the resources.
///
/// # Panics
///
/// - Panics if the resource types do not match.
/// - Panics if the write goes out of bounds.
pub fn update(&mut self, write: &WriteDescriptorSet) {
fn write_resources<T: Clone>(first: usize, resources: &mut [Option<T>], elements: &[T]) {
resources
.get_mut(first..first + elements.len())
.expect("descriptor write for binding out of bounds")
.iter_mut()
.zip(elements)
.for_each(|(resource, element)| {
*resource = Some(element.clone());
});
}
let first = write.first_array_element() as usize;
match (self, write.elements()) {
(
DescriptorBindingResources::None(resources),
WriteDescriptorSetElements::None(num_elements),
) => {
resources
.get_mut(first..first + *num_elements as usize)
.expect("descriptor write for binding out of bounds")
.iter_mut()
.for_each(|resource| {
*resource = Some(());
});
}
(
DescriptorBindingResources::Buffer(resources),
WriteDescriptorSetElements::Buffer(elements),
) => write_resources(first, resources, elements),
(
DescriptorBindingResources::BufferView(resources),
WriteDescriptorSetElements::BufferView(elements),
) => write_resources(first, resources, elements),
(
DescriptorBindingResources::ImageView(resources),
WriteDescriptorSetElements::ImageView(elements),
) => write_resources(first, resources, elements),
(
DescriptorBindingResources::ImageViewSampler(resources),
WriteDescriptorSetElements::ImageViewSampler(elements),
) => write_resources(first, resources, elements),
(
DescriptorBindingResources::Sampler(resources),
WriteDescriptorSetElements::Sampler(elements),
) => write_resources(first, resources, elements),
_ => panic!(
"descriptor write for binding {} has wrong resource type",
write.binding(),
),
}
}
}
#[derive(Clone)]
pub struct DescriptorSetWithOffsets {
descriptor_set: Arc<dyn DescriptorSet>,
@ -234,143 +499,44 @@ where
}
}
/// Error related to descriptor sets.
#[derive(Debug, Clone)]
pub enum DescriptorSetError {
/// The number of array layers of an image doesn't match what was expected.
ArrayLayersMismatch {
/// Number of expected array layers for the image.
expected: u32,
/// Number of array layers of the image that was added.
obtained: u32,
},
/// Array doesn't contain the correct amount of descriptors
ArrayLengthMismatch {
/// Expected length
expected: u32,
/// Obtained length
obtained: u32,
},
/// Runtime array contains too many descriptors
ArrayTooManyDescriptors {
/// Capacity of array
capacity: u32,
/// Obtained length
obtained: u32,
},
/// The builder has previously return an error and is an unknown state.
BuilderPoisoned,
/// Operation can not be performed on an empty descriptor.
DescriptorIsEmpty,
/// Not all descriptors have been added.
DescriptorsMissing {
/// Expected bindings
expected: u32,
/// Obtained bindings
obtained: u32,
},
/// The builder is within an array, but the operation requires it not to be.
InArray,
/// The image view isn't compatible with the sampler.
IncompatibleImageViewSampler,
/// The buffer is missing the correct usage.
MissingBufferUsage(MissingBufferUsage),
/// The image is missing the correct usage.
MissingImageUsage(MissingImageUsage),
/// The image view has a component swizzle that is different from identity.
NotIdentitySwizzled,
/// The builder is not in an array, but the operation requires it to be.
NotInArray,
/// Out of memory
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DescriptorSetCreationError {
DescriptorSetUpdateError(DescriptorSetUpdateError),
OomError(OomError),
/// Resource belongs to another device.
ResourceWrongDevice,
/// Provided a dynamically assigned sampler, but the descriptor has an immutable sampler.
SamplerIsImmutable,
/// Builder doesn't expect anymore descriptors
TooManyDescriptors,
/// Expected a non-arrayed image, but got an arrayed image.
UnexpectedArrayed,
/// Expected one type of resource but got another.
WrongDescriptorType,
}
impl From<OomError> for DescriptorSetError {
fn from(error: OomError) -> Self {
Self::OomError(error)
}
}
impl error::Error for DescriptorSetError {}
impl fmt::Display for DescriptorSetError {
impl std::error::Error for DescriptorSetCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
fmt,
"{}",
match *self {
Self::ArrayLayersMismatch { .. } =>
"the number of array layers of an image doesn't match what was expected",
Self::ArrayLengthMismatch { .. } =>
"array doesn't contain the correct amount of descriptors",
Self::ArrayTooManyDescriptors { .. } =>
"runtime array contains too many descriptors",
Self::BuilderPoisoned =>
"the builder has previously return an error and is an unknown state",
Self::DescriptorIsEmpty => "operation can not be performed on an empty descriptor",
Self::DescriptorsMissing { .. } => "not all descriptors have been added",
Self::InArray => "the builder is within an array, but the operation requires it not to be",
Self::IncompatibleImageViewSampler =>
"the image view isn't compatible with the sampler",
Self::MissingBufferUsage(_) => "the buffer is missing the correct usage",
Self::MissingImageUsage(_) => "the image is missing the correct usage",
Self::NotIdentitySwizzled =>
"the image view has a component swizzle that is different from identity",
Self::NotInArray => "the builder is not in an array, but the operation requires it to be",
Self::OomError(_) => "out of memory",
Self::ResourceWrongDevice => "resource belongs to another device",
Self::SamplerIsImmutable => "provided a dynamically assigned sampler, but the descriptor has an immutable sampler",
Self::TooManyDescriptors => "builder doesn't expect anymore descriptors",
Self::UnexpectedArrayed => "expected a non-arrayed image, but got an arrayed image",
Self::WrongDescriptorType => "expected one type of resource but got another",
}
)
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::DescriptorSetUpdateError(err) => Some(err),
Self::OomError(err) => Some(err),
}
}
}
// Part of the DescriptorSetError for the case
// of missing usage on a buffer.
#[derive(Debug, Clone)]
pub enum MissingBufferUsage {
StorageBuffer,
UniformBuffer,
StorageTexelBuffer,
UniformTexelBuffer,
impl std::fmt::Display for DescriptorSetCreationError {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::DescriptorSetUpdateError(err) => {
write!(f, "an error occurred while updating the descriptor set")
}
Self::OomError(err) => write!(f, "out of memory"),
}
}
}
// Part of the DescriptorSetError for the case
// of missing usage on an image.
#[derive(Debug, Clone)]
pub enum MissingImageUsage {
InputAttachment,
Sampled,
Storage,
impl From<DescriptorSetUpdateError> for DescriptorSetCreationError {
#[inline]
fn from(err: DescriptorSetUpdateError) -> Self {
Self::DescriptorSetUpdateError(err)
}
}
impl From<OomError> for DescriptorSetCreationError {
#[inline]
fn from(err: OomError) -> Self {
Self::OomError(err)
}
}

View File

@ -21,17 +21,14 @@
//! # Example
//! TODO:
use crate::buffer::BufferView;
use crate::descriptor_set::builder::DescriptorSetBuilder;
use crate::descriptor_set::pool::standard::StdDescriptorPoolAlloc;
use crate::descriptor_set::pool::{DescriptorPool, DescriptorPoolAlloc};
use crate::descriptor_set::resources::DescriptorSetResources;
use crate::descriptor_set::update::WriteDescriptorSet;
use crate::descriptor_set::{
BufferAccess, DescriptorSet, DescriptorSetError, DescriptorSetLayout, UnsafeDescriptorSet,
DescriptorSet, DescriptorSetCreationError, DescriptorSetInner, DescriptorSetLayout,
DescriptorSetResources, UnsafeDescriptorSet,
};
use crate::device::{Device, DeviceOwned};
use crate::image::ImageViewAbstract;
use crate::sampler::Sampler;
use crate::VulkanObject;
use std::hash::{Hash, Hasher};
use std::sync::Arc;
@ -39,21 +36,79 @@ use std::sync::Arc;
/// A simple, immutable descriptor set that is expected to be long-lived.
pub struct PersistentDescriptorSet<P = StdDescriptorPoolAlloc> {
alloc: P,
resources: DescriptorSetResources,
layout: Arc<DescriptorSetLayout>,
inner: DescriptorSetInner,
}
impl PersistentDescriptorSet {
/// Starts the process of building a `PersistentDescriptorSet`. Returns a builder.
pub fn start(layout: Arc<DescriptorSetLayout>) -> PersistentDescriptorSetBuilder {
/// Creates and returns a new descriptor set with a variable descriptor count of 0.
///
/// See `new_with_pool` for more.
#[inline]
pub fn new(
layout: Arc<DescriptorSetLayout>,
descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
) -> Result<Arc<PersistentDescriptorSet>, DescriptorSetCreationError> {
let mut pool = Device::standard_descriptor_pool(layout.device());
Self::new_with_pool(layout, 0, &mut pool, descriptor_writes)
}
/// Creates and returns a new descriptor set with the requested variable descriptor count.
///
/// See `new_with_pool` for more.
#[inline]
pub fn new_variable(
layout: Arc<DescriptorSetLayout>,
variable_descriptor_count: u32,
descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
) -> Result<Arc<PersistentDescriptorSet>, DescriptorSetCreationError> {
let mut pool = Device::standard_descriptor_pool(layout.device());
Self::new_with_pool(
layout,
variable_descriptor_count,
&mut pool,
descriptor_writes,
)
}
/// Creates and returns a new descriptor set with the requested variable descriptor count,
/// allocating it from the provided pool.
///
/// # Panics
///
/// - Panics if `layout` was created for push descriptors rather than descriptor sets.
/// - Panics if `variable_descriptor_count` is too large for the given `layout`.
pub fn new_with_pool<P>(
layout: Arc<DescriptorSetLayout>,
variable_descriptor_count: u32,
pool: &mut P,
descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
) -> Result<Arc<PersistentDescriptorSet<P::Alloc>>, DescriptorSetCreationError>
where
P: ?Sized + DescriptorPool,
{
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),
}
let max_count = layout.variable_descriptor_count();
assert!(
variable_descriptor_count <= max_count,
"the provided variable_descriptor_count ({}) is greater than the maximum number of variable count descriptors in the set ({})",
variable_descriptor_count,
max_count,
);
let alloc = pool.alloc(&layout, variable_descriptor_count)?;
let inner = DescriptorSetInner::new(
alloc.inner().internal_object(),
layout,
variable_descriptor_count,
descriptor_writes,
)?;
Ok(Arc::new(PersistentDescriptorSet { alloc, inner }))
}
}
@ -68,12 +123,12 @@ where
#[inline]
fn layout(&self) -> &Arc<DescriptorSetLayout> {
&self.layout
self.inner.layout()
}
#[inline]
fn resources(&self) -> &DescriptorSetResources {
&self.resources
self.inner.resources()
}
}
@ -83,7 +138,7 @@ where
{
#[inline]
fn device(&self) -> &Arc<Device> {
self.layout.device()
self.inner.layout().device()
}
}
@ -110,138 +165,3 @@ where
self.device().hash(state);
}
}
/// Prototype of a `PersistentDescriptorSet`.
pub struct PersistentDescriptorSetBuilder {
inner: DescriptorSetBuilder,
}
impl PersistentDescriptorSetBuilder {
/// Call this function if the next element of the set is an array in order to set the value of
/// each element.
///
/// Returns an error if the descriptor is empty, there are no remaining descriptors, or if the
/// builder is already in an error.
///
/// This function can be called even if the descriptor isn't an array, and it is valid to enter
/// the "array", add one element, then leave.
#[inline]
pub fn enter_array(&mut self) -> Result<&mut Self, DescriptorSetError> {
self.inner.enter_array()?;
Ok(self)
}
/// Leaves the array. Call this once you added all the elements of the array.
///
/// Returns an error if the array is missing elements, or if the builder is not in an array.
#[inline]
pub fn leave_array(&mut self) -> Result<&mut Self, DescriptorSetError> {
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> {
self.inner.add_empty()?;
Ok(self)
}
/// Binds a buffer as the next descriptor.
///
/// An error is returned if the buffer isn't compatible with the descriptor.
#[inline]
pub fn add_buffer(
&mut self,
buffer: Arc<dyn BufferAccess>,
) -> Result<&mut Self, DescriptorSetError> {
self.inner.add_buffer(buffer)?;
Ok(self)
}
/// Binds a buffer view as the next descriptor.
///
/// An error is returned if the buffer isn't compatible with the descriptor.
#[inline]
pub fn add_buffer_view<B>(
&mut self,
view: Arc<BufferView<B>>,
) -> Result<&mut Self, DescriptorSetError>
where
B: BufferAccess + 'static,
{
self.inner.add_buffer_view(view)?;
Ok(self)
}
/// Binds an image view as the next descriptor.
///
/// An error is returned if the image view isn't compatible with the descriptor.
#[inline]
pub fn add_image(
&mut self,
image_view: Arc<dyn ImageViewAbstract>,
) -> Result<&mut Self, DescriptorSetError> {
self.inner.add_image(image_view)?;
Ok(self)
}
/// Binds an image view with a sampler as the next descriptor.
///
/// If the descriptor set layout contains immutable samplers for this descriptor, use
/// `add_image` instead.
///
/// An error is returned if the image view isn't compatible with the descriptor.
#[inline]
pub fn add_sampled_image(
&mut self,
image_view: Arc<dyn ImageViewAbstract>,
sampler: Arc<Sampler>,
) -> Result<&mut Self, DescriptorSetError> {
self.inner.add_sampled_image(image_view, sampler)?;
Ok(self)
}
/// Binds a sampler as the next descriptor.
///
/// An error is returned if the sampler isn't compatible with the descriptor.
#[inline]
pub fn add_sampler(&mut self, sampler: Arc<Sampler>) -> Result<&mut Self, DescriptorSetError> {
self.inner.add_sampler(sampler)?;
Ok(self)
}
/// Builds a `PersistentDescriptorSet` from the builder.
#[inline]
pub fn build(
self,
) -> Result<Arc<PersistentDescriptorSet<StdDescriptorPoolAlloc>>, DescriptorSetError> {
let mut pool = Device::standard_descriptor_pool(self.inner.device());
self.build_with_pool(&mut pool)
}
/// Builds a `PersistentDescriptorSet` from the builder.
pub fn build_with_pool<P>(
self,
pool: &mut P,
) -> Result<Arc<PersistentDescriptorSet<P::Alloc>>, DescriptorSetError>
where
P: ?Sized + DescriptorPool,
{
let writes = self.inner.build()?;
let mut alloc = pool.alloc(writes.layout(), writes.variable_descriptor_count())?;
let mut resources =
DescriptorSetResources::new(writes.layout(), writes.variable_descriptor_count());
unsafe {
alloc.inner_mut().write(writes.layout(), writes.writes());
resources.update(writes.writes());
}
Ok(Arc::new(PersistentDescriptorSet {
alloc,
resources,
layout: writes.layout().clone(),
}))
}
}

View File

@ -1,166 +0,0 @@
// Copyright (c) 2017 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::buffer::BufferViewAbstract;
use crate::descriptor_set::layout::{DescriptorSetLayout, DescriptorType};
use crate::descriptor_set::sys::{DescriptorWrite, DescriptorWriteElements};
use crate::descriptor_set::BufferAccess;
use crate::image::ImageViewAbstract;
use crate::sampler::Sampler;
use fnv::FnvHashMap;
use smallvec::{smallvec, SmallVec};
use std::sync::Arc;
/// The resources that are bound to a descriptor set.
#[derive(Clone)]
pub struct DescriptorSetResources {
descriptors: FnvHashMap<u32, DescriptorBindingResources>,
}
impl DescriptorSetResources {
/// Creates a new `DescriptorSetResources` matching the provided descriptor set layout, and
/// all descriptors set to `None`.
pub fn new(layout: &DescriptorSetLayout, variable_descriptor_count: u32) -> Self {
assert!(variable_descriptor_count <= layout.variable_descriptor_count());
let descriptors = layout
.desc()
.bindings()
.iter()
.enumerate()
.filter_map(|(b, d)| d.as_ref().map(|d| (b as u32, d)))
.map(|(binding_num, binding_desc)| {
let count = if binding_desc.variable_count {
variable_descriptor_count
} else {
binding_desc.descriptor_count
} as usize;
let binding_resources = match binding_desc.ty {
DescriptorType::UniformBuffer
| DescriptorType::StorageBuffer
| DescriptorType::UniformBufferDynamic
| DescriptorType::StorageBufferDynamic => {
DescriptorBindingResources::Buffer(smallvec![None; count])
}
DescriptorType::UniformTexelBuffer | DescriptorType::StorageTexelBuffer => {
DescriptorBindingResources::BufferView(smallvec![None; count])
}
DescriptorType::SampledImage
| DescriptorType::StorageImage
| DescriptorType::InputAttachment => {
DescriptorBindingResources::ImageView(smallvec![None; count])
}
DescriptorType::CombinedImageSampler => {
if binding_desc.immutable_samplers.is_empty() {
DescriptorBindingResources::ImageViewSampler(smallvec![None; count])
} else {
DescriptorBindingResources::ImageView(smallvec![None; count])
}
}
DescriptorType::Sampler => {
if binding_desc.immutable_samplers.is_empty() {
DescriptorBindingResources::Sampler(smallvec![None; count])
} else {
DescriptorBindingResources::None
}
}
};
(binding_num, binding_resources)
})
.collect();
Self { descriptors }
}
/// Applies descriptor writes to the resources.
///
/// # Panics
///
/// - Panics if the binding number of a write does not exist in the resources.
/// - See also [`DescriptorBindingResources::update`].
pub fn update<'a>(&mut self, writes: impl IntoIterator<Item = &'a DescriptorWrite>) {
for write in writes {
self.descriptors
.get_mut(&write.binding_num)
.expect("descriptor write has invalid binding number")
.update(write)
}
}
/// Returns a reference to the bound resources for `binding`. Returns `None` if the binding
/// doesn't exist.
#[inline]
pub fn binding(&self, binding: u32) -> Option<&DescriptorBindingResources> {
self.descriptors.get(&binding)
}
}
/// The resources that are bound to a single descriptor set binding.
#[derive(Clone)]
pub enum DescriptorBindingResources {
None,
Buffer(Elements<Arc<dyn BufferAccess>>),
BufferView(Elements<Arc<dyn BufferViewAbstract>>),
ImageView(Elements<Arc<dyn ImageViewAbstract>>),
ImageViewSampler(Elements<(Arc<dyn ImageViewAbstract>, Arc<Sampler>)>),
Sampler(Elements<Arc<Sampler>>),
}
type Elements<T> = SmallVec<[Option<T>; 1]>;
impl DescriptorBindingResources {
/// Applies a descriptor write to the resources.
///
/// # Panics
///
/// - Panics if the resource types do not match.
/// - Panics if the write goes out of bounds.
pub fn update(&mut self, write: &DescriptorWrite) {
fn write_resources<T: Clone>(first: usize, resources: &mut [Option<T>], elements: &[T]) {
resources
.get_mut(first..first + elements.len())
.expect("descriptor write for binding out of bounds")
.iter_mut()
.zip(elements)
.for_each(|(resource, element)| {
*resource = Some(element.clone());
});
}
let first = write.first_array_element() as usize;
match (self, write.elements()) {
(
DescriptorBindingResources::Buffer(resources),
DescriptorWriteElements::Buffer(elements),
) => write_resources(first, resources, elements),
(
DescriptorBindingResources::BufferView(resources),
DescriptorWriteElements::BufferView(elements),
) => write_resources(first, resources, elements),
(
DescriptorBindingResources::ImageView(resources),
DescriptorWriteElements::ImageView(elements),
) => write_resources(first, resources, elements),
(
DescriptorBindingResources::ImageViewSampler(resources),
DescriptorWriteElements::ImageViewSampler(elements),
) => write_resources(first, resources, elements),
(
DescriptorBindingResources::Sampler(resources),
DescriptorWriteElements::Sampler(elements),
) => write_resources(first, resources, elements),
_ => panic!(
"descriptor write for binding {} has wrong resource type",
write.binding_num,
),
}
}
}

View File

@ -7,17 +7,16 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use super::resources::DescriptorSetResources;
use crate::buffer::BufferView;
use crate::descriptor_set::builder::DescriptorSetBuilder;
use crate::descriptor_set::layout::DescriptorSetLayout;
use crate::descriptor_set::pool::{
DescriptorPoolAlloc, DescriptorPoolAllocError, DescriptorSetAllocateInfo, UnsafeDescriptorPool,
};
use crate::descriptor_set::{BufferAccess, DescriptorSet, DescriptorSetError, UnsafeDescriptorSet};
use crate::descriptor_set::update::WriteDescriptorSet;
use crate::descriptor_set::{
DescriptorSet, DescriptorSetCreationError, DescriptorSetInner, DescriptorSetResources,
UnsafeDescriptorSet,
};
use crate::device::{Device, DeviceOwned};
use crate::image::ImageViewAbstract;
use crate::sampler::Sampler;
use crate::OomError;
use crate::VulkanObject;
use crossbeam_queue::SegQueue;
@ -66,16 +65,22 @@ impl SingleLayoutDescSetPool {
}
}
/// Starts the process of building a new descriptor set.
///
/// The set will corresponds to the set layout that was passed to `new`.
pub fn next(&mut self) -> SingleLayoutDescSetBuilder {
let layout = self.layout.clone();
/// Returns a new descriptor set, either by creating a new one or returning an existing one
/// from the internal reserve.
#[inline]
pub fn next(
&mut self,
descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
) -> Result<Arc<SingleLayoutDescSet>, DescriptorSetCreationError> {
let alloc = self.next_alloc()?;
let inner = DescriptorSetInner::new(
alloc.inner().internal_object(),
self.layout.clone(),
0,
descriptor_writes,
)?;
SingleLayoutDescSetBuilder {
pool: self,
inner: DescriptorSetBuilder::start(layout),
}
Ok(Arc::new(SingleLayoutDescSet { alloc, inner }))
}
fn next_alloc(&mut self) -> Result<SingleLayoutPoolAlloc, OomError> {
@ -183,8 +188,7 @@ impl Drop for SingleLayoutPoolAlloc {
/// A descriptor set created from a `SingleLayoutDescSetPool`.
pub struct SingleLayoutDescSet {
alloc: SingleLayoutPoolAlloc,
resources: DescriptorSetResources,
layout: Arc<DescriptorSetLayout>,
inner: DescriptorSetInner,
}
unsafe impl DescriptorSet for SingleLayoutDescSet {
@ -195,19 +199,19 @@ unsafe impl DescriptorSet for SingleLayoutDescSet {
#[inline]
fn layout(&self) -> &Arc<DescriptorSetLayout> {
&self.layout
self.inner.layout()
}
#[inline]
fn resources(&self) -> &DescriptorSetResources {
&self.resources
self.inner.resources()
}
}
unsafe impl DeviceOwned for SingleLayoutDescSet {
#[inline]
fn device(&self) -> &Arc<Device> {
self.layout.device()
self.inner.layout().device()
}
}
@ -228,124 +232,3 @@ impl Hash for SingleLayoutDescSet {
self.device().hash(state);
}
}
/// Prototype of a `SingleLayoutDescSet`.
pub struct SingleLayoutDescSetBuilder<'a> {
pool: &'a mut SingleLayoutDescSetPool,
inner: DescriptorSetBuilder,
}
impl<'a> SingleLayoutDescSetBuilder<'a> {
/// Call this function if the next element of the set is an array in order to set the value of
/// each element.
///
/// Returns an error if the descriptor is empty, there are no remaining descriptors, or if the
/// builder is already in an error.
///
/// This function can be called even if the descriptor isn't an array, and it is valid to enter
/// the "array", add one element, then leave.
#[inline]
pub fn enter_array(&mut self) -> Result<&mut Self, DescriptorSetError> {
self.inner.enter_array()?;
Ok(self)
}
/// Leaves the array. Call this once you added all the elements of the array.
///
/// Returns an error if the array is missing elements, or if the builder is not in an array.
#[inline]
pub fn leave_array(&mut self) -> Result<&mut Self, DescriptorSetError> {
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> {
self.inner.add_empty()?;
Ok(self)
}
/// Binds a buffer as the next descriptor.
///
/// An error is returned if the buffer isn't compatible with the descriptor.
#[inline]
pub fn add_buffer(
&mut self,
buffer: Arc<dyn BufferAccess>,
) -> Result<&mut Self, DescriptorSetError> {
self.inner.add_buffer(buffer)?;
Ok(self)
}
/// Binds a buffer view as the next descriptor.
///
/// An error is returned if the buffer isn't compatible with the descriptor.
#[inline]
pub fn add_buffer_view<B>(
&mut self,
view: Arc<BufferView<B>>,
) -> Result<&mut Self, DescriptorSetError>
where
B: BufferAccess + 'static,
{
self.inner.add_buffer_view(view)?;
Ok(self)
}
/// Binds an image view as the next descriptor.
///
/// An error is returned if the image view isn't compatible with the descriptor.
#[inline]
pub fn add_image(
&mut self,
image_view: Arc<dyn ImageViewAbstract + 'static>,
) -> Result<&mut Self, DescriptorSetError> {
self.inner.add_image(image_view)?;
Ok(self)
}
/// Binds an image view with a sampler as the next descriptor.
///
/// If the descriptor set layout contains immutable samplers for this descriptor, use
/// `add_image` instead.
///
/// An error is returned if the image view isn't compatible with the descriptor.
#[inline]
pub fn add_sampled_image(
&mut self,
image_view: Arc<dyn ImageViewAbstract + 'static>,
sampler: Arc<Sampler>,
) -> Result<&mut Self, DescriptorSetError> {
self.inner.add_sampled_image(image_view, sampler)?;
Ok(self)
}
/// Binds a sampler as the next descriptor.
///
/// An error is returned if the sampler isn't compatible with the descriptor.
#[inline]
pub fn add_sampler(&mut self, sampler: Arc<Sampler>) -> Result<&mut Self, DescriptorSetError> {
self.inner.add_sampler(sampler)?;
Ok(self)
}
/// Builds a `SingleLayoutDescSet` from the builder.
pub fn build(self) -> Result<Arc<SingleLayoutDescSet>, DescriptorSetError> {
let writes = self.inner.build()?;
debug_assert!(writes.variable_descriptor_count() == 0);
let mut alloc = self.pool.next_alloc()?;
let mut resources = DescriptorSetResources::new(writes.layout(), 0);
unsafe {
alloc.inner_mut().write(writes.layout(), writes.writes());
resources.update(writes.writes());
}
Ok(Arc::new(SingleLayoutDescSet {
alloc,
resources,
layout: writes.layout().clone(),
}))
}
}

View File

@ -9,17 +9,13 @@
//! Low-level descriptor set.
use crate::buffer::{BufferAccess, BufferInner, BufferViewAbstract};
use crate::descriptor_set::layout::{DescriptorSetLayout, DescriptorType};
use crate::descriptor_set::layout::DescriptorSetLayout;
use crate::descriptor_set::update::{DescriptorWriteInfo, WriteDescriptorSet};
use crate::device::DeviceOwned;
use crate::image::view::ImageViewAbstract;
use crate::sampler::Sampler;
use crate::DeviceSize;
use crate::VulkanObject;
use smallvec::SmallVec;
use std::fmt;
use std::ptr;
use std::sync::Arc;
/// Low-level descriptor set.
///
@ -50,12 +46,12 @@ impl UnsafeDescriptorSet {
pub unsafe fn write<'a>(
&mut self,
layout: &DescriptorSetLayout,
writes: impl IntoIterator<Item = &'a DescriptorWrite>,
writes: impl IntoIterator<Item = &'a WriteDescriptorSet>,
) {
let (infos, mut writes): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = writes
.into_iter()
.map(|write| {
let descriptor_type = layout.descriptor(write.binding_num).unwrap().ty;
let descriptor_type = layout.descriptor(write.binding()).unwrap().ty;
(
write.to_vulkan_info(descriptor_type),
@ -120,294 +116,3 @@ impl fmt::Debug for UnsafeDescriptorSet {
write!(fmt, "<Vulkan descriptor set {:?}>", self.handle)
}
}
/// Represents a single write entry to a descriptor set.
///
/// 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.
pub struct DescriptorWrite {
pub(crate) binding_num: u32,
first_array_element: u32,
elements: DescriptorWriteElements,
}
impl DescriptorWrite {
#[inline]
pub unsafe fn buffer(
binding_num: u32,
first_array_element: u32,
elements: impl IntoIterator<Item = Arc<dyn BufferAccess>>,
) -> Self {
let elements: SmallVec<_> = elements.into_iter().collect();
assert!(!elements.is_empty());
Self {
binding_num,
first_array_element,
elements: DescriptorWriteElements::Buffer(elements),
}
}
#[inline]
pub unsafe fn buffer_view(
binding_num: u32,
first_array_element: u32,
elements: impl IntoIterator<Item = Arc<dyn BufferViewAbstract>>,
) -> Self {
let elements: SmallVec<_> = elements.into_iter().collect();
assert!(!elements.is_empty());
Self {
binding_num,
first_array_element,
elements: DescriptorWriteElements::BufferView(elements),
}
}
#[inline]
pub unsafe fn image_view(
binding_num: u32,
first_array_element: u32,
elements: impl IntoIterator<Item = Arc<dyn ImageViewAbstract>>,
) -> Self {
let elements: SmallVec<_> = elements.into_iter().collect();
assert!(!elements.is_empty());
Self {
binding_num,
first_array_element,
elements: DescriptorWriteElements::ImageView(elements),
}
}
#[inline]
pub unsafe fn image_view_sampler(
binding_num: u32,
first_array_element: u32,
elements: impl IntoIterator<Item = (Arc<dyn ImageViewAbstract>, Arc<Sampler>)>,
) -> Self {
let elements: SmallVec<_> = elements.into_iter().collect();
assert!(!elements.is_empty());
Self {
binding_num,
first_array_element,
elements: DescriptorWriteElements::ImageViewSampler(elements),
}
}
#[inline]
pub unsafe fn sampler(
binding_num: u32,
first_array_element: u32,
elements: impl IntoIterator<Item = Arc<Sampler>>,
) -> Self {
let elements: SmallVec<_> = elements.into_iter().collect();
assert!(!elements.is_empty());
Self {
binding_num,
first_array_element,
elements: DescriptorWriteElements::Sampler(elements),
}
}
/// Returns the binding number that is updated by this descriptor write.
#[inline]
pub fn binding_num(&self) -> u32 {
self.binding_num
}
/// Returns the first array element in the binding that is updated by this descriptor write.
#[inline]
pub fn first_array_element(&self) -> u32 {
self.first_array_element
}
/// Returns a reference to the elements held by this descriptor write.
#[inline]
pub fn elements(&self) -> &DescriptorWriteElements {
&self.elements
}
pub(crate) fn to_vulkan_info(&self, descriptor_type: DescriptorType) -> DescriptorWriteInfo {
match &self.elements {
DescriptorWriteElements::Buffer(elements) => {
debug_assert!(matches!(
descriptor_type,
DescriptorType::UniformBuffer
| DescriptorType::StorageBuffer
| DescriptorType::UniformBufferDynamic
| DescriptorType::StorageBufferDynamic
));
DescriptorWriteInfo::Buffer(
elements
.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(),
)
}
DescriptorWriteElements::BufferView(elements) => {
debug_assert!(matches!(
descriptor_type,
DescriptorType::UniformTexelBuffer | DescriptorType::StorageTexelBuffer
));
DescriptorWriteInfo::BufferView(
elements
.iter()
.map(|buffer_view| buffer_view.inner())
.collect(),
)
}
DescriptorWriteElements::ImageView(elements) => {
// Note: combined image sampler can occur with immutable samplers
debug_assert!(matches!(
descriptor_type,
DescriptorType::CombinedImageSampler
| DescriptorType::SampledImage
| DescriptorType::StorageImage
| DescriptorType::InputAttachment
));
DescriptorWriteInfo::Image(
elements
.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.layout_for(descriptor_type).into(),
}
})
.collect(),
)
}
DescriptorWriteElements::ImageViewSampler(elements) => {
debug_assert!(matches!(
descriptor_type,
DescriptorType::CombinedImageSampler
));
DescriptorWriteInfo::Image(
elements
.iter()
.map(|(image_view, sampler)| {
let layouts = image_view.image().descriptor_layouts().expect(
"descriptor_layouts must return Some when used in an image view",
);
ash::vk::DescriptorImageInfo {
sampler: sampler.internal_object(),
image_view: image_view.inner().internal_object(),
image_layout: layouts.layout_for(descriptor_type).into(),
}
})
.collect(),
)
}
DescriptorWriteElements::Sampler(elements) => {
debug_assert!(matches!(descriptor_type, DescriptorType::Sampler));
DescriptorWriteInfo::Image(
elements
.iter()
.map(|sampler| ash::vk::DescriptorImageInfo {
sampler: sampler.internal_object(),
image_view: ash::vk::ImageView::null(),
image_layout: ash::vk::ImageLayout::UNDEFINED,
})
.collect(),
)
}
}
}
pub(crate) fn to_vulkan(
&self,
dst_set: ash::vk::DescriptorSet,
descriptor_type: DescriptorType,
) -> ash::vk::WriteDescriptorSet {
ash::vk::WriteDescriptorSet {
dst_set,
dst_binding: self.binding_num,
dst_array_element: self.first_array_element,
descriptor_count: 0,
descriptor_type: descriptor_type.into(),
p_image_info: ptr::null(),
p_buffer_info: ptr::null(),
p_texel_buffer_view: ptr::null(),
..Default::default()
}
}
}
/// The elements held by a descriptor write.
pub enum DescriptorWriteElements {
Buffer(SmallVec<[Arc<dyn BufferAccess>; 1]>),
BufferView(SmallVec<[Arc<dyn BufferViewAbstract>; 1]>),
ImageView(SmallVec<[Arc<dyn ImageViewAbstract>; 1]>),
ImageViewSampler(SmallVec<[(Arc<dyn ImageViewAbstract>, Arc<Sampler>); 1]>),
Sampler(SmallVec<[Arc<Sampler>; 1]>),
}
impl DescriptorWriteElements {
/// Returns the number of elements.
#[inline]
pub fn len(&self) -> u32 {
match self {
DescriptorWriteElements::Buffer(elements) => elements.len() as u32,
DescriptorWriteElements::BufferView(elements) => elements.len() as u32,
DescriptorWriteElements::ImageView(elements) => elements.len() as u32,
DescriptorWriteElements::ImageViewSampler(elements) => elements.len() as u32,
DescriptorWriteElements::Sampler(elements) => elements.len() as u32,
}
}
}
#[derive(Clone, Debug)]
pub(crate) enum DescriptorWriteInfo {
Image(SmallVec<[ash::vk::DescriptorImageInfo; 1]>),
Buffer(SmallVec<[ash::vk::DescriptorBufferInfo; 1]>),
BufferView(SmallVec<[ash::vk::BufferView; 1]>),
}
impl DescriptorWriteInfo {
fn set_info(&self, write: &mut ash::vk::WriteDescriptorSet) {
match self {
DescriptorWriteInfo::Image(info) => {
write.descriptor_count = info.len() as u32;
write.p_image_info = info.as_ptr();
}
DescriptorWriteInfo::Buffer(info) => {
write.descriptor_count = info.len() as u32;
write.p_buffer_info = info.as_ptr();
}
DescriptorWriteInfo::BufferView(info) => {
write.descriptor_count = info.len() as u32;
write.p_texel_buffer_view = info.as_ptr();
}
}
debug_assert!(write.descriptor_count != 0);
}
}

View File

@ -0,0 +1,822 @@
// Copyright (c) 2017 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::buffer::{BufferAccess, BufferInner, BufferViewAbstract};
use crate::descriptor_set::layout::{DescriptorDesc, DescriptorType};
use crate::descriptor_set::DescriptorSetLayout;
use crate::device::DeviceOwned;
use crate::image::ImageViewAbstract;
use crate::sampler::Sampler;
use crate::DeviceSize;
use crate::VulkanObject;
use smallvec::SmallVec;
use std::ptr;
use std::sync::Arc;
/// Represents a single write operation to the binding of a descriptor set.
///
/// `WriteDescriptorSet` specifies the binding number and target array index, and includes one or
/// more resources of a given type that need to be written to that location. Two constructors are
/// provided for each resource type:
/// - The basic constructor variant writes a single element to array index 0. It is intended for
/// non-arrayed bindings, where `descriptor_count` in the descriptor set layout is 1.
/// - The `_array` variant writes several elements and allows specifying the target array index.
/// At least one element must be provided; a panic results if the provided iterator is empty.
pub struct WriteDescriptorSet {
binding: u32,
first_array_element: u32,
elements: WriteDescriptorSetElements,
}
impl WriteDescriptorSet {
/// Write an empty element to array element 0.
///
/// See `none_array` for more information.
#[inline]
pub fn none(binding: u32) -> Self {
Self::none_array(binding, 0, 1)
}
/// Write a number of consecutive empty elements.
///
/// This is used for push descriptors in combination with `Sampler` descriptors that have
/// immutable samplers in the layout. The Vulkan spec requires these elements to be explicitly
/// written, but since there is no data to write, a dummy write is provided instead.
///
/// For regular descriptor sets, the data for such descriptors is automatically valid, and dummy
/// writes are not allowed.
#[inline]
pub fn none_array(binding: u32, first_array_element: u32, num_elements: u32) -> Self {
assert!(num_elements != 0);
Self {
binding,
first_array_element,
elements: WriteDescriptorSetElements::None(num_elements),
}
}
/// Write a single buffer to array element 0.
#[inline]
pub fn buffer(binding: u32, buffer: Arc<dyn BufferAccess>) -> Self {
Self::buffer_array(binding, 0, [buffer])
}
/// Write a number of consecutive buffer elements.
#[inline]
pub fn buffer_array(
binding: u32,
first_array_element: u32,
elements: impl IntoIterator<Item = Arc<dyn BufferAccess>>,
) -> Self {
let elements: SmallVec<_> = elements.into_iter().collect();
assert!(!elements.is_empty());
Self {
binding,
first_array_element,
elements: WriteDescriptorSetElements::Buffer(elements),
}
}
/// Write a single buffer view to array element 0.
#[inline]
pub fn buffer_view(binding: u32, buffer_view: Arc<dyn BufferViewAbstract>) -> Self {
Self::buffer_view_array(binding, 0, [buffer_view])
}
/// Write a number of consecutive buffer view elements.
#[inline]
pub fn buffer_view_array(
binding: u32,
first_array_element: u32,
elements: impl IntoIterator<Item = Arc<dyn BufferViewAbstract>>,
) -> Self {
let elements: SmallVec<_> = elements.into_iter().collect();
assert!(!elements.is_empty());
Self {
binding,
first_array_element,
elements: WriteDescriptorSetElements::BufferView(elements),
}
}
/// Write a single image view to array element 0.
#[inline]
pub fn image_view(binding: u32, image_view: Arc<dyn ImageViewAbstract>) -> Self {
Self::image_view_array(binding, 0, [image_view])
}
/// Write a number of consecutive image view elements.
#[inline]
pub fn image_view_array(
binding: u32,
first_array_element: u32,
elements: impl IntoIterator<Item = Arc<dyn ImageViewAbstract>>,
) -> Self {
let elements: SmallVec<_> = elements.into_iter().collect();
assert!(!elements.is_empty());
Self {
binding,
first_array_element,
elements: WriteDescriptorSetElements::ImageView(elements),
}
}
/// Write a single image view and sampler to array element 0.
#[inline]
pub fn image_view_sampler(
binding: u32,
image_view: Arc<dyn ImageViewAbstract>,
sampler: Arc<Sampler>,
) -> Self {
Self::image_view_sampler_array(binding, 0, [(image_view, sampler)])
}
/// Write a number of consecutive image view and sampler elements.
#[inline]
pub fn image_view_sampler_array(
binding: u32,
first_array_element: u32,
elements: impl IntoIterator<Item = (Arc<dyn ImageViewAbstract>, Arc<Sampler>)>,
) -> Self {
let elements: SmallVec<_> = elements.into_iter().collect();
assert!(!elements.is_empty());
Self {
binding,
first_array_element,
elements: WriteDescriptorSetElements::ImageViewSampler(elements),
}
}
/// Write a single sampler to array element 0.
#[inline]
pub fn sampler(binding: u32, sampler: Arc<Sampler>) -> Self {
Self::sampler_array(binding, 0, [sampler])
}
/// Write a number of consecutive sampler elements.
#[inline]
pub fn sampler_array(
binding: u32,
first_array_element: u32,
elements: impl IntoIterator<Item = Arc<Sampler>>,
) -> Self {
let elements: SmallVec<_> = elements.into_iter().collect();
assert!(!elements.is_empty());
Self {
binding,
first_array_element,
elements: WriteDescriptorSetElements::Sampler(elements),
}
}
/// Returns the binding number that is updated by this descriptor write.
#[inline]
pub fn binding(&self) -> u32 {
self.binding
}
/// Returns the first array element in the binding that is updated by this descriptor write.
#[inline]
pub fn first_array_element(&self) -> u32 {
self.first_array_element
}
/// Returns a reference to the elements held by this descriptor write.
#[inline]
pub fn elements(&self) -> &WriteDescriptorSetElements {
&self.elements
}
pub(crate) fn to_vulkan_info(&self, descriptor_type: DescriptorType) -> DescriptorWriteInfo {
match &self.elements {
WriteDescriptorSetElements::None(num_elements) => {
debug_assert!(matches!(descriptor_type, DescriptorType::Sampler));
DescriptorWriteInfo::Image(
std::iter::repeat_with(|| ash::vk::DescriptorImageInfo {
sampler: ash::vk::Sampler::null(),
image_view: ash::vk::ImageView::null(),
image_layout: ash::vk::ImageLayout::UNDEFINED,
})
.take(*num_elements as usize)
.collect(),
)
}
WriteDescriptorSetElements::Buffer(elements) => {
debug_assert!(matches!(
descriptor_type,
DescriptorType::UniformBuffer
| DescriptorType::StorageBuffer
| DescriptorType::UniformBufferDynamic
| DescriptorType::StorageBufferDynamic
));
DescriptorWriteInfo::Buffer(
elements
.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(),
)
}
WriteDescriptorSetElements::BufferView(elements) => {
debug_assert!(matches!(
descriptor_type,
DescriptorType::UniformTexelBuffer | DescriptorType::StorageTexelBuffer
));
DescriptorWriteInfo::BufferView(
elements
.iter()
.map(|buffer_view| buffer_view.inner())
.collect(),
)
}
WriteDescriptorSetElements::ImageView(elements) => {
// Note: combined image sampler can occur with immutable samplers
debug_assert!(matches!(
descriptor_type,
DescriptorType::CombinedImageSampler
| DescriptorType::SampledImage
| DescriptorType::StorageImage
| DescriptorType::InputAttachment
));
DescriptorWriteInfo::Image(
elements
.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.layout_for(descriptor_type).into(),
}
})
.collect(),
)
}
WriteDescriptorSetElements::ImageViewSampler(elements) => {
debug_assert!(matches!(
descriptor_type,
DescriptorType::CombinedImageSampler
));
DescriptorWriteInfo::Image(
elements
.iter()
.map(|(image_view, sampler)| {
let layouts = image_view.image().descriptor_layouts().expect(
"descriptor_layouts must return Some when used in an image view",
);
ash::vk::DescriptorImageInfo {
sampler: sampler.internal_object(),
image_view: image_view.inner().internal_object(),
image_layout: layouts.layout_for(descriptor_type).into(),
}
})
.collect(),
)
}
WriteDescriptorSetElements::Sampler(elements) => {
debug_assert!(matches!(descriptor_type, DescriptorType::Sampler));
DescriptorWriteInfo::Image(
elements
.iter()
.map(|sampler| ash::vk::DescriptorImageInfo {
sampler: sampler.internal_object(),
image_view: ash::vk::ImageView::null(),
image_layout: ash::vk::ImageLayout::UNDEFINED,
})
.collect(),
)
}
}
}
pub(crate) fn to_vulkan(
&self,
dst_set: ash::vk::DescriptorSet,
descriptor_type: DescriptorType,
) -> ash::vk::WriteDescriptorSet {
ash::vk::WriteDescriptorSet {
dst_set,
dst_binding: self.binding,
dst_array_element: self.first_array_element,
descriptor_count: 0,
descriptor_type: descriptor_type.into(),
p_image_info: ptr::null(),
p_buffer_info: ptr::null(),
p_texel_buffer_view: ptr::null(),
..Default::default()
}
}
}
/// The elements held by a `WriteDescriptorSet`.
pub enum WriteDescriptorSetElements {
None(u32),
Buffer(SmallVec<[Arc<dyn BufferAccess>; 1]>),
BufferView(SmallVec<[Arc<dyn BufferViewAbstract>; 1]>),
ImageView(SmallVec<[Arc<dyn ImageViewAbstract>; 1]>),
ImageViewSampler(SmallVec<[(Arc<dyn ImageViewAbstract>, Arc<Sampler>); 1]>),
Sampler(SmallVec<[Arc<Sampler>; 1]>),
}
impl WriteDescriptorSetElements {
/// Returns the number of elements.
#[inline]
pub fn len(&self) -> u32 {
match self {
Self::None(num_elements) => *num_elements,
Self::Buffer(elements) => elements.len() as u32,
Self::BufferView(elements) => elements.len() as u32,
Self::ImageView(elements) => elements.len() as u32,
Self::ImageViewSampler(elements) => elements.len() as u32,
Self::Sampler(elements) => elements.len() as u32,
}
}
}
#[derive(Clone, Debug)]
pub(crate) enum DescriptorWriteInfo {
Image(SmallVec<[ash::vk::DescriptorImageInfo; 1]>),
Buffer(SmallVec<[ash::vk::DescriptorBufferInfo; 1]>),
BufferView(SmallVec<[ash::vk::BufferView; 1]>),
}
impl DescriptorWriteInfo {
fn set_info(&self, write: &mut ash::vk::WriteDescriptorSet) {
match self {
DescriptorWriteInfo::Image(info) => {
write.descriptor_count = info.len() as u32;
write.p_image_info = info.as_ptr();
}
DescriptorWriteInfo::Buffer(info) => {
write.descriptor_count = info.len() as u32;
write.p_buffer_info = info.as_ptr();
}
DescriptorWriteInfo::BufferView(info) => {
write.descriptor_count = info.len() as u32;
write.p_texel_buffer_view = info.as_ptr();
}
}
debug_assert!(write.descriptor_count != 0);
}
}
pub(crate) fn check_descriptor_write<'a>(
write: &WriteDescriptorSet,
layout: &'a DescriptorSetLayout,
variable_descriptor_count: u32,
) -> Result<&'a DescriptorDesc, DescriptorSetUpdateError> {
let layout_binding = match layout.desc().descriptor(write.binding()) {
Some(binding) => binding,
None => {
return Err(DescriptorSetUpdateError::InvalidBinding {
binding: write.binding(),
})
}
};
let max_descriptor_count = if layout_binding.variable_count {
variable_descriptor_count
} else {
layout_binding.descriptor_count
};
let elements = write.elements();
let num_elements = elements.len();
debug_assert!(num_elements != 0);
let descriptor_range_start = write.first_array_element();
let descriptor_range_end = descriptor_range_start + num_elements;
if descriptor_range_end > max_descriptor_count {
return Err(DescriptorSetUpdateError::ArrayIndexOutOfBounds {
binding: write.binding(),
available_count: max_descriptor_count,
written_count: descriptor_range_end,
});
}
match elements {
WriteDescriptorSetElements::None(num_elements) => match layout_binding.ty {
DescriptorType::Sampler
if layout.desc().is_push_descriptor()
&& !layout_binding.immutable_samplers.is_empty() => {}
_ => {
return Err(DescriptorSetUpdateError::IncompatibleDescriptorType {
binding: write.binding(),
})
}
},
WriteDescriptorSetElements::Buffer(elements) => {
match layout_binding.ty {
DescriptorType::StorageBuffer | DescriptorType::StorageBufferDynamic => {
for (index, buffer) in elements.iter().enumerate() {
assert_eq!(
buffer.device().internal_object(),
layout.device().internal_object(),
);
if !buffer.inner().buffer.usage().storage_buffer {
return Err(DescriptorSetUpdateError::MissingUsage {
binding: write.binding(),
index: descriptor_range_start + index as u32,
usage: "storage_buffer",
});
}
}
}
DescriptorType::UniformBuffer | DescriptorType::UniformBufferDynamic => {
for (index, buffer) in elements.iter().enumerate() {
assert_eq!(
buffer.device().internal_object(),
layout.device().internal_object(),
);
if !buffer.inner().buffer.usage().uniform_buffer {
return Err(DescriptorSetUpdateError::MissingUsage {
binding: write.binding(),
index: descriptor_range_start + index as u32,
usage: "uniform_buffer",
});
}
}
}
_ => {
return Err(DescriptorSetUpdateError::IncompatibleDescriptorType {
binding: write.binding(),
})
}
}
// Note that the buffer content is not checked. This is technically not unsafe as
// long as the data in the buffer has no invalid memory representation (ie. no
// bool, no enum, no pointer, no str) and as long as the robust buffer access
// feature is enabled.
// TODO: this is not checked ^
// TODO: eventually shouldn't be an assert ; for now robust_buffer_access is always
// enabled so this assert should never fail in practice, but we put it anyway
// in case we forget to adjust this code
assert!(layout.device().enabled_features().robust_buffer_access);
}
WriteDescriptorSetElements::BufferView(elements) => {
match layout_binding.ty {
DescriptorType::StorageTexelBuffer => {
for (index, buffer_view) in elements.iter().enumerate() {
assert_eq!(
buffer_view.device().internal_object(),
layout.device().internal_object(),
);
// TODO: storage_texel_buffer_atomic
if !buffer_view
.buffer()
.inner()
.buffer
.usage()
.storage_texel_buffer
{
return Err(DescriptorSetUpdateError::MissingUsage {
binding: write.binding(),
index: descriptor_range_start + index as u32,
usage: "storage_texel_buffer",
});
}
}
}
DescriptorType::UniformTexelBuffer => {
for (index, buffer_view) in elements.iter().enumerate() {
assert_eq!(
buffer_view.device().internal_object(),
layout.device().internal_object(),
);
if !buffer_view
.buffer()
.inner()
.buffer
.usage()
.uniform_texel_buffer
{
return Err(DescriptorSetUpdateError::MissingUsage {
binding: write.binding(),
index: descriptor_range_start + index as u32,
usage: "uniform_texel_buffer",
});
}
}
}
_ => {
return Err(DescriptorSetUpdateError::IncompatibleDescriptorType {
binding: write.binding(),
})
}
}
}
WriteDescriptorSetElements::ImageView(elements) => match layout_binding.ty {
DescriptorType::CombinedImageSampler
if !layout_binding.immutable_samplers.is_empty() =>
{
let immutable_samplers = &layout_binding.immutable_samplers
[descriptor_range_start as usize..descriptor_range_end as usize];
for (index, (image_view, sampler)) in
elements.iter().zip(immutable_samplers).enumerate()
{
assert_eq!(
image_view.device().internal_object(),
layout.device().internal_object(),
);
if !image_view.image().inner().image.usage().sampled {
return Err(DescriptorSetUpdateError::MissingUsage {
binding: write.binding(),
index: descriptor_range_start + index as u32,
usage: "sampled",
});
}
if !image_view.can_be_sampled(sampler) {
return Err(DescriptorSetUpdateError::ImageViewIncompatibleSampler {
binding: write.binding(),
index: descriptor_range_start + index as u32,
});
}
}
}
DescriptorType::SampledImage => {
for (index, image_view) in elements.iter().enumerate() {
assert_eq!(
image_view.device().internal_object(),
layout.device().internal_object(),
);
if !image_view.image().inner().image.usage().sampled {
return Err(DescriptorSetUpdateError::MissingUsage {
binding: write.binding(),
index: descriptor_range_start + index as u32,
usage: "sampled",
});
}
}
}
DescriptorType::StorageImage => {
for (index, image_view) in elements.iter().enumerate() {
assert_eq!(
image_view.device().internal_object(),
layout.device().internal_object(),
);
if !image_view.image().inner().image.usage().storage {
return Err(DescriptorSetUpdateError::MissingUsage {
binding: write.binding(),
index: descriptor_range_start + index as u32,
usage: "storage",
});
}
if !image_view.component_mapping().is_identity() {
return Err(DescriptorSetUpdateError::ImageViewNotIdentitySwizzled {
binding: write.binding(),
index: descriptor_range_start + index as u32,
});
}
}
}
DescriptorType::InputAttachment => {
for (index, image_view) in elements.iter().enumerate() {
assert_eq!(
image_view.device().internal_object(),
layout.device().internal_object(),
);
if !image_view.image().inner().image.usage().input_attachment {
return Err(DescriptorSetUpdateError::MissingUsage {
binding: write.binding(),
index: descriptor_range_start + index as u32,
usage: "input_attachment",
});
}
if !image_view.component_mapping().is_identity() {
return Err(DescriptorSetUpdateError::ImageViewNotIdentitySwizzled {
binding: write.binding(),
index: descriptor_range_start + index as u32,
});
}
let image_layers = image_view.array_layers();
let num_layers = image_layers.end - image_layers.start;
if image_view.ty().is_arrayed() {
return Err(DescriptorSetUpdateError::ImageViewIsArrayed {
binding: write.binding(),
index: descriptor_range_start + index as u32,
});
}
}
}
_ => {
return Err(DescriptorSetUpdateError::IncompatibleDescriptorType {
binding: write.binding(),
})
}
},
WriteDescriptorSetElements::ImageViewSampler(elements) => match layout_binding.ty {
DescriptorType::CombinedImageSampler => {
if !layout_binding.immutable_samplers.is_empty() {
return Err(DescriptorSetUpdateError::SamplerIsImmutable {
binding: write.binding(),
});
}
for (index, (image_view, sampler)) in elements.iter().enumerate() {
assert_eq!(
image_view.device().internal_object(),
layout.device().internal_object(),
);
assert_eq!(
sampler.device().internal_object(),
layout.device().internal_object(),
);
if !image_view.image().inner().image.usage().sampled {
return Err(DescriptorSetUpdateError::MissingUsage {
binding: write.binding(),
index: descriptor_range_start + index as u32,
usage: "sampled",
});
}
if !image_view.can_be_sampled(&sampler) {
return Err(DescriptorSetUpdateError::ImageViewIncompatibleSampler {
binding: write.binding(),
index: descriptor_range_start + index as u32,
});
}
}
}
_ => {
return Err(DescriptorSetUpdateError::IncompatibleDescriptorType {
binding: write.binding(),
})
}
},
WriteDescriptorSetElements::Sampler(elements) => match layout_binding.ty {
DescriptorType::Sampler => {
if !layout_binding.immutable_samplers.is_empty() {
return Err(DescriptorSetUpdateError::SamplerIsImmutable {
binding: write.binding(),
});
}
for sampler in elements {
assert_eq!(
sampler.device().internal_object(),
layout.device().internal_object(),
);
}
}
_ => {
return Err(DescriptorSetUpdateError::IncompatibleDescriptorType {
binding: write.binding(),
})
}
},
}
Ok(layout_binding)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DescriptorSetUpdateError {
/// Tried to write more elements than were available in a binding.
ArrayIndexOutOfBounds {
/// Binding that is affected.
binding: u32,
/// Number of available descriptors in the binding.
available_count: u32,
/// The number of descriptors that were in the update.
written_count: u32,
},
/// Tried to write an image view of an arrayed type to a descriptor type that does not support
/// it.
ImageViewIsArrayed { binding: u32, index: u32 },
/// Tried to write an image view that was not compatible with the sampler that was provided as
/// part of the update or immutably in the layout.
ImageViewIncompatibleSampler { binding: u32, index: u32 },
/// Tried to write an image view to a descriptor type that requires it to be identity swizzled,
/// but it was not.
ImageViewNotIdentitySwizzled { binding: u32, index: u32 },
/// Tried to write an element type that was not compatible with the descriptor type in the
/// layout.
IncompatibleDescriptorType { binding: u32 },
/// Tried to write to a nonexistent binding.
InvalidBinding { binding: u32 },
/// A resource was missing a usage flag that was required.
MissingUsage {
binding: u32,
index: u32,
usage: &'static str,
},
/// Tried to write a sampler to a binding with immutable samplers.
SamplerIsImmutable { binding: u32 },
}
impl std::error::Error for DescriptorSetUpdateError {}
impl std::fmt::Display for DescriptorSetUpdateError {
#[inline]
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
match self {
Self::ArrayIndexOutOfBounds {
binding,
available_count,
written_count,
} => write!(
fmt,
"tried to write up to element {} to binding {}, but only {} descriptors are available",
written_count, binding, available_count,
),
Self::ImageViewIsArrayed { binding, index } => write!(
fmt,
"tried to write an image view of an arrayed type to binding {} index {}, but this binding has a descriptor type that does not support arrayed image views",
binding, index,
),
Self::ImageViewIncompatibleSampler { binding, index } => write!(
fmt,
"tried to write an image view to binding {} index {}, that was not compatible with the sampler that was provided as part of the update or immutably in the layout",
binding, index,
),
Self::ImageViewNotIdentitySwizzled { binding, index } => write!(
fmt,
"tried to write an image view with non-identity swizzling to binding {} index {}, but this binding has a descriptor type that requires it to be identity swizzled",
binding, index,
),
Self::IncompatibleDescriptorType { binding } => write!(
fmt,
"tried to write a resource to binding {} whose type was not compatible with the descriptor type",
binding,
),
Self::InvalidBinding { binding } => write!(
fmt,
"tried to write to a nonexistent binding {}",
binding,
),
Self::MissingUsage {
binding,
index,
usage,
} => write!(
fmt,
"tried to write a resource to binding {} index {} that did not have the required usage {} enabled",
binding, index, usage,
),
Self::SamplerIsImmutable { binding } => write!(
fmt,
"tried to write a sampler to binding {}, which already contains immutable samplers in the descriptor set layout",
binding,
),
}
}
}

View File

@ -15,6 +15,7 @@
use crate::check_errors;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::format::Format;
use crate::image::sys::UnsafeImage;
use crate::image::ImageAccess;
@ -89,6 +90,15 @@ where
}
}
unsafe impl<I> DeviceOwned for ImageView<I>
where
I: ImageAccess,
{
fn device(&self) -> &Arc<Device> {
self.inner.device()
}
}
#[derive(Debug)]
pub struct ImageViewBuilder<I> {
array_layers: Range<u32>,
@ -436,6 +446,12 @@ unsafe impl VulkanObject for UnsafeImageView {
}
}
unsafe impl DeviceOwned for UnsafeImageView {
fn device(&self) -> &Arc<Device> {
&self.device
}
}
impl fmt::Debug for UnsafeImageView {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
@ -581,7 +597,7 @@ impl Default for ComponentSwizzle {
}
/// Trait for types that represent the GPU can access an image view.
pub unsafe trait ImageViewAbstract: Send + Sync {
pub unsafe trait ImageViewAbstract: DeviceOwned + Send + Sync {
/// Returns the wrapped image that this image view was created from.
fn image(&self) -> Arc<dyn ImageAccess>;

View File

@ -393,6 +393,7 @@ mod tests {
use crate::command_buffer::AutoCommandBufferBuilder;
use crate::command_buffer::CommandBufferUsage;
use crate::descriptor_set::PersistentDescriptorSet;
use crate::descriptor_set::WriteDescriptorSet;
use crate::pipeline::ComputePipeline;
use crate::pipeline::Pipeline;
use crate::pipeline::PipelineBindPoint;
@ -481,12 +482,17 @@ mod tests {
let data_buffer =
CpuAccessibleBuffer::from_data(device.clone(), BufferUsage::all(), false, 0).unwrap();
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
let mut builder = PersistentDescriptorSet::start(layout.clone());
builder.add_buffer(data_buffer.clone()).unwrap();
let set = builder.build().unwrap();
let set = PersistentDescriptorSet::new(
pipeline
.layout()
.descriptor_set_layouts()
.get(0)
.unwrap()
.clone(),
[WriteDescriptorSet::buffer(0, data_buffer.clone())],
)
.unwrap();
let mut cbb = AutoCommandBufferBuilder::primary(
device.clone(),