Rearrange descriptor set modules and types (#1622)

* Move descriptor_set.rs to parent, make descriptor.rs its child

* Rename UnsafeDescriptorSetLayout to DescriptorSetLayout, as there isn't actually anything unsafe about it

* Make fixed_size_pool and persistent modules public, reduce number of re-exports from there

* Split off pool.rs from sys.rs

* Move std_pool module to pool::standard

* Make sys public, remove re-exports

* Move descriptor module and DescriptorSetDesc into layout module

* Move ShaderStages to pipeline::shader

* Make descriptor_set::collection module private

* Documentation
This commit is contained in:
Rua 2021-06-28 10:28:09 +02:00 committed by GitHub
parent b12414f892
commit d5bcffa902
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 1823 additions and 1834 deletions

View File

@ -16,7 +16,7 @@
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::instance::{Instance, InstanceExtensions};

View File

@ -12,7 +12,7 @@ use vulkano::buffer::CpuAccessibleBuffer;
use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, SecondaryAutoCommandBuffer,
};
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::device::Queue;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::blend::AttachmentBlend;

View File

@ -13,7 +13,7 @@ use vulkano::buffer::CpuAccessibleBuffer;
use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, SecondaryAutoCommandBuffer,
};
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::device::Queue;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::blend::AttachmentBlend;

View File

@ -14,7 +14,7 @@ use vulkano::buffer::CpuAccessibleBuffer;
use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, SecondaryAutoCommandBuffer,
};
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::device::Queue;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::blend::AttachmentBlend;

View File

@ -18,7 +18,7 @@ use std::mem;
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::instance::{Instance, InstanceExtensions};

View File

@ -20,7 +20,7 @@ use std::path::Path;
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::format::Format;

View File

@ -14,7 +14,7 @@ use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, SubpassContents,
};
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::format::Format;

View File

@ -12,7 +12,7 @@
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, ImmutableBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::instance::{Instance, InstanceExtensions};

View File

@ -37,7 +37,7 @@ use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, DrawIndirectCommand, DynamicState,
SubpassContents,
};
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::image::view::ImageView;

View File

@ -12,7 +12,7 @@
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::instance::{Instance, InstanceExtensions};

View File

@ -14,7 +14,7 @@
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::instance::{Instance, InstanceExtensions};

View File

@ -12,7 +12,7 @@
use std::sync::Arc;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::instance::{Instance, InstanceExtensions};

View File

@ -17,7 +17,7 @@ use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, SubpassContents,
};
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::format::Format;

View File

@ -326,25 +326,21 @@ where
#[allow(unused_imports)]
use vulkano::device::Device;
#[allow(unused_imports)]
use vulkano::descriptor::descriptor::DescriptorDesc;
use vulkano::descriptor_set::layout::DescriptorDesc;
#[allow(unused_imports)]
use vulkano::descriptor::descriptor::DescriptorDescTy;
use vulkano::descriptor_set::layout::DescriptorDescTy;
#[allow(unused_imports)]
use vulkano::descriptor::descriptor::DescriptorBufferDesc;
use vulkano::descriptor_set::layout::DescriptorBufferDesc;
#[allow(unused_imports)]
use vulkano::descriptor::descriptor::DescriptorImageDesc;
use vulkano::descriptor_set::layout::DescriptorImageDesc;
#[allow(unused_imports)]
use vulkano::descriptor::descriptor::DescriptorImageDescDimensions;
use vulkano::descriptor_set::layout::DescriptorImageDescDimensions;
#[allow(unused_imports)]
use vulkano::descriptor::descriptor::DescriptorImageDescArray;
use vulkano::descriptor_set::layout::DescriptorImageDescArray;
#[allow(unused_imports)]
use vulkano::descriptor::descriptor::ShaderStages;
use vulkano::descriptor_set::layout::DescriptorSetLayout;
#[allow(unused_imports)]
use vulkano::descriptor::descriptor_set::DescriptorSet;
#[allow(unused_imports)]
use vulkano::descriptor::descriptor_set::UnsafeDescriptorSet;
#[allow(unused_imports)]
use vulkano::descriptor::descriptor_set::UnsafeDescriptorSetLayout;
use vulkano::descriptor_set::DescriptorSet;
#[allow(unused_imports)]
use vulkano::format::Format;
#[allow(unused_imports)]
@ -352,6 +348,8 @@ where
#[allow(unused_imports)]
use vulkano::pipeline::layout::PipelineLayoutDescPcRange;
#[allow(unused_imports)]
use vulkano::pipeline::shader::ShaderStages;
#[allow(unused_imports)]
use vulkano::pipeline::shader::SpecializationConstants as SpecConstsTrait;
#[allow(unused_imports)]
use vulkano::pipeline::shader::SpecializationMapEntry;

View File

@ -341,7 +341,7 @@ fn vulkano_type(ty: &str, len: Option<&str>) -> &'static str {
"VkShaderFloatControlsIndependence" => {
"crate::device::physical::ShaderFloatControlsIndependence"
}
"VkShaderStageFlags" => "crate::descriptor::descriptor::ShaderStages",
"VkShaderStageFlags" => "crate::pipeline::shader::ShaderStages",
"VkSubgroupFeatureFlags" => "crate::device::physical::SubgroupFeatures",
_ => unimplemented!("{}", ty),
}

View File

@ -37,8 +37,8 @@ use crate::command_buffer::SecondaryCommandBuffer;
use crate::command_buffer::StateCacher;
use crate::command_buffer::StateCacherOutcome;
use crate::command_buffer::SubpassContents;
use crate::descriptor::descriptor::{DescriptorBufferDesc, DescriptorDescTy};
use crate::descriptor::descriptor_set::{DescriptorSetDesc, DescriptorSetsCollection};
use crate::descriptor_set::layout::{DescriptorBufferDesc, DescriptorDescTy, DescriptorSetDesc};
use crate::descriptor_set::DescriptorSetsCollection;
use crate::device::physical::QueueFamily;
use crate::device::Device;
use crate::device::DeviceOwned;

View File

@ -9,7 +9,7 @@
use crate::buffer::BufferAccess;
use crate::command_buffer::DynamicState;
use crate::descriptor::DescriptorSet;
use crate::descriptor_set::DescriptorSet;
use crate::pipeline::input_assembly::IndexType;
use crate::pipeline::ComputePipelineAbstract;
use crate::pipeline::GraphicsPipelineAbstract;

View File

@ -25,9 +25,8 @@ use crate::command_buffer::CommandBufferExecError;
use crate::command_buffer::ImageUninitializedSafe;
use crate::command_buffer::SecondaryCommandBuffer;
use crate::command_buffer::SubpassContents;
use crate::descriptor::descriptor::DescriptorDescTy;
use crate::descriptor::descriptor::ShaderStages;
use crate::descriptor::descriptor_set::DescriptorSet;
use crate::descriptor_set::layout::DescriptorDescTy;
use crate::descriptor_set::DescriptorSet;
use crate::format::ClearValue;
use crate::image::ImageAccess;
use crate::image::ImageLayout;
@ -35,6 +34,7 @@ use crate::pipeline::depth_stencil::DynamicStencilValue;
use crate::pipeline::depth_stencil::StencilFaceFlags;
use crate::pipeline::input_assembly::IndexType;
use crate::pipeline::layout::PipelineLayout;
use crate::pipeline::shader::ShaderStages;
use crate::pipeline::viewport::Scissor;
use crate::pipeline::viewport::Viewport;
use crate::pipeline::ComputePipelineAbstract;

View File

@ -17,8 +17,7 @@ use crate::command_buffer::CommandBufferLevel;
use crate::command_buffer::CommandBufferUsage;
use crate::command_buffer::SecondaryCommandBuffer;
use crate::command_buffer::SubpassContents;
use crate::descriptor::descriptor::ShaderStages;
use crate::descriptor::descriptor_set::UnsafeDescriptorSet;
use crate::descriptor_set::sys::UnsafeDescriptorSet;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::format::ClearValue;
@ -31,6 +30,7 @@ use crate::image::SampleCount;
use crate::pipeline::depth_stencil::StencilFaceFlags;
use crate::pipeline::input_assembly::IndexType;
use crate::pipeline::layout::PipelineLayout;
use crate::pipeline::shader::ShaderStages;
use crate::pipeline::viewport::Scissor;
use crate::pipeline::viewport::Viewport;
use crate::pipeline::ComputePipelineAbstract;

View File

@ -10,8 +10,8 @@
use std::error;
use std::fmt;
use crate::descriptor::descriptor::DescriptorDescSupersetError;
use crate::descriptor::descriptor_set::DescriptorSetsCollection;
use crate::descriptor_set::layout::DescriptorDescSupersetError;
use crate::descriptor_set::DescriptorSetsCollection;
use crate::pipeline::layout::PipelineLayoutDesc;
/// Checks whether descriptor sets are compatible with the pipeline.

File diff suppressed because it is too large Load Diff

View File

@ -1,87 +0,0 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
//! Provides a way for shaders to access the content of buffers and images, or read arbitrary data.
//!
//! If you except vertex attributes, there are two ways in Vulkan to pass data to a shader:
//!
//! - You can pass a very small amount of data (only a guaranteed 128 bytes) through the *push
//! constants* mechanism. Push constants are the fastest and easiest way to pass data.
//! - You can make your shader read from a buffer or an image by binding it to a *descriptor*.
//!
//! Here is an example fragment shader in GLSL that uses both:
//!
//! ```ignore
//! #version 450
//!
//! // This is a descriptor that contains a texture.
//! layout(set = 0, binding = 0) uniform sampler2D u_texture;
//!
//! // This is a descriptor that contains a buffer.
//! layout(set = 0, binding = 1) uniform struct {
//! int data[128];
//! } u_buffer;
//!
//! layout(push_constant) uniform PushConstants {
//! // This is a push constant.
//! float opacity;
//! } push_constants;
//!
//! layout(location = 0) in vec2 v_tex_coords;
//! layout(location = 0) out vec4 f_output;
//!
//! void main() {
//! f_output.rgb = texture(u_texture, v_tex_coords).rgb;
//! if (u_buffer.data[12] == 5) { f_output.rgb *= 2.0; }
//! f_output.a = push_constants.opacity;
//! }
//! ```
//!
//! # Descriptors
//!
//! In order to read the content of a buffer or an image from a shader, that buffer or image
//! must be put in a *descriptor*. Each descriptor contains one buffer or one image alongside with
//! the way that it can be accessed. A descriptor can also be an array, in which case it contains
//! multiple buffers or images that all have the same layout.
//!
//! Descriptors are grouped in what is called *descriptor sets*. In Vulkan you don't bind
//! individual descriptors one by one, but you create then bind descriptor sets one by one. As
//! binding a descriptor set has (small but non-null) a cost, you are encouraged to put descriptors
//! that are often used together in the same set so that you can keep the same set binding through
//! multiple draws.
//!
//! # Example
//!
//! > **Note**: This section describes the simple way to bind resources. There are more optimized
//! > ways.
//!
//! There are two steps to give access to a resource in a shader: creating the descriptor set, and
//! passing the descriptor sets when drawing.
//!
//! ## Creating a descriptor set
//!
//! TODO: write example for: PersistentDescriptorSet::start(layout.clone()).add_buffer(data_buffer.clone())
//!
//! ## Passing the descriptor set when drawing
//!
//! TODO: write
//!
//! # When drawing
//!
//! When you call a function that adds a draw command to a command buffer, one of the parameters
//! corresponds to the list of descriptor sets to use, and another parameter contains the push
//! constants. Vulkano will check that what you passed is compatible with the layout of the
//! compute or graphics pipeline.
//!
//! TODO: talk about perfs of changing sets
pub use self::descriptor_set::DescriptorSet;
pub mod descriptor;
pub mod descriptor_set;

View File

@ -7,9 +7,9 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::descriptor::descriptor::DescriptorDesc;
use crate::descriptor::descriptor_set::DescriptorSet;
use crate::descriptor::descriptor_set::DescriptorSetDesc;
use crate::descriptor_set::layout::DescriptorDesc;
use crate::descriptor_set::DescriptorSet;
use crate::descriptor_set::DescriptorSetDesc;
/// A collection of descriptor set objects.
pub unsafe trait DescriptorSetsCollection {

View File

@ -7,71 +7,71 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crossbeam_queue::SegQueue;
use std::hash::Hash;
use std::hash::Hasher;
use std::sync::Arc;
//! Pool of descriptor sets of a specific capacity that are automatically reclaimed.
//!
//! You are encouraged to use this type when you need a different descriptor set at each frame, or
//! regularly during the execution.
//!
//! # Example
//!
//! At initialization, create a `FixedSizeDescriptorSetsPool`.
//!
//! ```rust
//! use vulkano::descriptor_set::FixedSizeDescriptorSetsPool;
//! # use vulkano::pipeline::GraphicsPipelineAbstract;
//! # use std::sync::Arc;
//! # let graphics_pipeline: Arc<GraphicsPipelineAbstract> = return;
//! // use vulkano::pipeline::GraphicsPipelineAbstract;
//! // let graphics_pipeline: Arc<GraphicsPipelineAbstract> = ...;
//!
//! let layout = graphics_pipeline.layout().descriptor_set_layout(0).unwrap();
//! let pool = FixedSizeDescriptorSetsPool::new(layout.clone());
//! ```
//!
//! You would then typically store the pool in a struct for later. Then whenever you need a
//! descriptor set, call `pool.next()` to start the process of building it.
//!
//! ```rust
//! # use std::sync::Arc;
//! # use vulkano::descriptor_set::FixedSizeDescriptorSetsPool;
//! # use vulkano::pipeline::GraphicsPipelineAbstract;
//! # let mut pool: FixedSizeDescriptorSetsPool = return;
//! let descriptor_set = pool.next()
//! //.add_buffer(...)
//! //.add_sampled_image(...)
//! .build().unwrap();
//! ```
//!
//! Note that `next()` requires exclusive (`mut`) access to the pool. You can use a `Mutex` around
//! the pool if you can't provide this.
use crate::buffer::BufferAccess;
use crate::buffer::BufferViewRef;
use crate::descriptor::descriptor::DescriptorDesc;
use crate::descriptor::descriptor_set::persistent::*;
use crate::descriptor::descriptor_set::DescriptorPool;
use crate::descriptor::descriptor_set::DescriptorPoolAlloc;
use crate::descriptor::descriptor_set::DescriptorPoolAllocError;
use crate::descriptor::descriptor_set::DescriptorSet;
use crate::descriptor::descriptor_set::DescriptorSetDesc;
use crate::descriptor::descriptor_set::UnsafeDescriptorPool;
use crate::descriptor::descriptor_set::UnsafeDescriptorSet;
use crate::descriptor::descriptor_set::UnsafeDescriptorSetLayout;
use crate::descriptor_set::layout::DescriptorDesc;
use crate::descriptor_set::layout::DescriptorSetLayout;
use crate::descriptor_set::persistent::*;
use crate::descriptor_set::pool::DescriptorPool;
use crate::descriptor_set::pool::DescriptorPoolAlloc;
use crate::descriptor_set::pool::DescriptorPoolAllocError;
use crate::descriptor_set::pool::UnsafeDescriptorPool;
use crate::descriptor_set::DescriptorSet;
use crate::descriptor_set::DescriptorSetDesc;
use crate::descriptor_set::UnsafeDescriptorSet;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::image::view::ImageViewAbstract;
use crate::sampler::Sampler;
use crate::OomError;
use crate::VulkanObject;
use crossbeam_queue::SegQueue;
use std::hash::Hash;
use std::hash::Hasher;
use std::sync::Arc;
/// Pool of descriptor sets of a specific capacity and that are automatically reclaimed.
///
/// You are encouraged to use this type when you need a different descriptor set at each frame, or
/// regularly during the execution.
///
/// # Example
///
/// At initialization, create a `FixedSizeDescriptorSetsPool`.
///
/// ```rust
/// use vulkano::descriptor::descriptor_set::FixedSizeDescriptorSetsPool;
/// # use vulkano::pipeline::GraphicsPipelineAbstract;
/// # use std::sync::Arc;
/// # let graphics_pipeline: Arc<GraphicsPipelineAbstract> = return;
/// // use vulkano::pipeline::GraphicsPipelineAbstract;
/// // let graphics_pipeline: Arc<GraphicsPipelineAbstract> = ...;
///
/// let layout = graphics_pipeline.layout().descriptor_set_layout(0).unwrap();
/// let pool = FixedSizeDescriptorSetsPool::new(layout.clone());
/// ```
///
/// You would then typically store the pool in a struct for later. Then whenever you need a
/// descriptor set, call `pool.next()` to start the process of building it.
///
/// ```rust
/// # use std::sync::Arc;
/// # use vulkano::descriptor::descriptor_set::FixedSizeDescriptorSetsPool;
/// # use vulkano::pipeline::GraphicsPipelineAbstract;
/// # let mut pool: FixedSizeDescriptorSetsPool = return;
/// let descriptor_set = pool.next()
/// //.add_buffer(...)
/// //.add_sampled_image(...)
/// .build().unwrap();
/// ```
///
/// Note that `next()` requires exclusive (`mut`) access to the pool. You can use a `Mutex` around
/// the pool if you can't provide this.
///
/// Pool of descriptor sets of a specific capacity that are automatically reclaimed.
#[derive(Clone)]
pub struct FixedSizeDescriptorSetsPool {
layout: Arc<UnsafeDescriptorSetLayout>,
layout: Arc<DescriptorSetLayout>,
// We hold a local implementation of the `DescriptorPool` trait for our own purpose. Since we
// don't want to expose this trait impl in our API, we use a separate struct.
pool: LocalPool,
@ -80,7 +80,7 @@ pub struct FixedSizeDescriptorSetsPool {
impl FixedSizeDescriptorSetsPool {
/// Initializes a new pool. The pool is configured to allocate sets that corresponds to the
/// parameters passed to this function.
pub fn new(layout: Arc<UnsafeDescriptorSetLayout>) -> FixedSizeDescriptorSetsPool {
pub fn new(layout: Arc<DescriptorSetLayout>) -> FixedSizeDescriptorSetsPool {
let device = layout.device().clone();
FixedSizeDescriptorSetsPool {
@ -219,7 +219,7 @@ struct LocalPoolAlloc {
unsafe impl DescriptorPool for LocalPool {
type Alloc = LocalPoolAlloc;
fn alloc(&mut self, layout: &UnsafeDescriptorSetLayout) -> Result<Self::Alloc, OomError> {
fn alloc(&mut self, layout: &DescriptorSetLayout) -> Result<Self::Alloc, OomError> {
loop {
// Try to extract a descriptor from the current pool if any exist.
// This is the most common case.

View File

@ -43,12 +43,39 @@
use crate::format::Format;
use crate::image::view::ImageViewType;
use crate::pipeline::shader::ShaderStages;
use crate::pipeline::shader::ShaderStagesSupersetError;
use crate::sync::AccessFlags;
use crate::sync::PipelineStages;
use crate::SafeDeref;
use std::cmp;
use std::error;
use std::fmt;
use std::ops::BitOr;
/// Trait for objects that describe the layout of the descriptors of a set.
pub unsafe trait DescriptorSetDesc {
/// Returns the number of binding slots in the set.
fn num_bindings(&self) -> usize;
/// Returns a description of a descriptor, or `None` if out of range.
fn descriptor(&self, binding: usize) -> Option<DescriptorDesc>;
}
unsafe impl<T> DescriptorSetDesc for T
where
T: SafeDeref,
T::Target: DescriptorSetDesc,
{
#[inline]
fn num_bindings(&self) -> usize {
(**self).num_bindings()
}
#[inline]
fn descriptor(&self, binding: usize) -> Option<DescriptorDesc> {
(**self).descriptor(binding)
}
}
/// Contains the exact description of a single descriptor.
///
@ -80,9 +107,9 @@ impl DescriptorDesc {
///
///# Example
///```
///use vulkano::descriptor::descriptor::DescriptorDesc;
///use vulkano::descriptor::descriptor::DescriptorDescTy::*;
///use vulkano::descriptor::descriptor::ShaderStages;
///use vulkano::descriptor_set::layout::DescriptorDesc;
///use vulkano::descriptor_set::layout::DescriptorDescTy::*;
///use vulkano::pipeline::shader::ShaderStages;
///
///let desc_super = DescriptorDesc{ ty: Sampler, array_count: 2, stages: ShaderStages{
/// vertex: true,
@ -132,9 +159,9 @@ impl DescriptorDesc {
///
///# Example
///```
///use vulkano::descriptor::descriptor::DescriptorDesc;
///use vulkano::descriptor::descriptor::DescriptorDescTy::*;
///use vulkano::descriptor::descriptor::ShaderStages;
///use vulkano::descriptor_set::layout::DescriptorDesc;
///use vulkano::descriptor_set::layout::DescriptorDescTy::*;
///use vulkano::pipeline::shader::ShaderStages;
///
///let desc_part1 = DescriptorDesc{ ty: Sampler, array_count: 2, stages: ShaderStages{
/// vertex: true,
@ -643,204 +670,3 @@ impl From<ShaderStagesSupersetError> for DescriptorDescSupersetError {
}
}
}
/// Describes which shader stages have access to a descriptor.
// TODO: add example with BitOr
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct ShaderStages {
/// `True` means that the descriptor will be used by the vertex shader.
pub vertex: bool,
/// `True` means that the descriptor will be used by the tessellation control shader.
pub tessellation_control: bool,
/// `True` means that the descriptor will be used by the tessellation evaluation shader.
pub tessellation_evaluation: bool,
/// `True` means that the descriptor will be used by the geometry shader.
pub geometry: bool,
/// `True` means that the descriptor will be used by the fragment shader.
pub fragment: bool,
/// `True` means that the descriptor will be used by the compute shader.
pub compute: bool,
}
impl ShaderStages {
/// Creates a `ShaderStages` struct will all stages set to `true`.
// TODO: add example
#[inline]
pub const fn all() -> ShaderStages {
ShaderStages {
vertex: true,
tessellation_control: true,
tessellation_evaluation: true,
geometry: true,
fragment: true,
compute: true,
}
}
/// Creates a `ShaderStages` struct will all stages set to `false`.
// TODO: add example
#[inline]
pub const fn none() -> ShaderStages {
ShaderStages {
vertex: false,
tessellation_control: false,
tessellation_evaluation: false,
geometry: false,
fragment: false,
compute: false,
}
}
/// Creates a `ShaderStages` struct with all graphics stages set to `true`.
// TODO: add example
#[inline]
pub const fn all_graphics() -> ShaderStages {
ShaderStages {
vertex: true,
tessellation_control: true,
tessellation_evaluation: true,
geometry: true,
fragment: true,
compute: false,
}
}
/// Creates a `ShaderStages` struct with the compute stage set to `true`.
// TODO: add example
#[inline]
pub const fn compute() -> ShaderStages {
ShaderStages {
vertex: false,
tessellation_control: false,
tessellation_evaluation: false,
geometry: false,
fragment: false,
compute: true,
}
}
/// Checks whether we have more stages enabled than `other`.
// TODO: add example
#[inline]
pub const fn is_superset_of(
&self,
other: &ShaderStages,
) -> Result<(), ShaderStagesSupersetError> {
if (self.vertex || !other.vertex)
&& (self.tessellation_control || !other.tessellation_control)
&& (self.tessellation_evaluation || !other.tessellation_evaluation)
&& (self.geometry || !other.geometry)
&& (self.fragment || !other.fragment)
&& (self.compute || !other.compute)
{
Ok(())
} else {
Err(ShaderStagesSupersetError::NotSuperset)
}
}
/// Checks whether any of the stages in `self` are also present in `other`.
// TODO: add example
#[inline]
pub const fn intersects(&self, other: &ShaderStages) -> bool {
(self.vertex && other.vertex)
|| (self.tessellation_control && other.tessellation_control)
|| (self.tessellation_evaluation && other.tessellation_evaluation)
|| (self.geometry && other.geometry)
|| (self.fragment && other.fragment)
|| (self.compute && other.compute)
}
}
impl From<ShaderStages> for ash::vk::ShaderStageFlags {
#[inline]
fn from(val: ShaderStages) -> Self {
let mut result = ash::vk::ShaderStageFlags::empty();
if val.vertex {
result |= ash::vk::ShaderStageFlags::VERTEX;
}
if val.tessellation_control {
result |= ash::vk::ShaderStageFlags::TESSELLATION_CONTROL;
}
if val.tessellation_evaluation {
result |= ash::vk::ShaderStageFlags::TESSELLATION_EVALUATION;
}
if val.geometry {
result |= ash::vk::ShaderStageFlags::GEOMETRY;
}
if val.fragment {
result |= ash::vk::ShaderStageFlags::FRAGMENT;
}
if val.compute {
result |= ash::vk::ShaderStageFlags::COMPUTE;
}
result
}
}
impl From<ash::vk::ShaderStageFlags> for ShaderStages {
#[inline]
fn from(val: ash::vk::ShaderStageFlags) -> Self {
Self {
vertex: val.intersects(ash::vk::ShaderStageFlags::VERTEX),
tessellation_control: val.intersects(ash::vk::ShaderStageFlags::TESSELLATION_CONTROL),
tessellation_evaluation: val
.intersects(ash::vk::ShaderStageFlags::TESSELLATION_EVALUATION),
geometry: val.intersects(ash::vk::ShaderStageFlags::GEOMETRY),
fragment: val.intersects(ash::vk::ShaderStageFlags::FRAGMENT),
compute: val.intersects(ash::vk::ShaderStageFlags::COMPUTE),
}
}
}
impl BitOr for ShaderStages {
type Output = ShaderStages;
#[inline]
fn bitor(self, other: ShaderStages) -> ShaderStages {
ShaderStages {
vertex: self.vertex || other.vertex,
tessellation_control: self.tessellation_control || other.tessellation_control,
tessellation_evaluation: self.tessellation_evaluation || other.tessellation_evaluation,
geometry: self.geometry || other.geometry,
fragment: self.fragment || other.fragment,
compute: self.compute || other.compute,
}
}
}
impl From<ShaderStages> for PipelineStages {
#[inline]
fn from(stages: ShaderStages) -> PipelineStages {
PipelineStages {
vertex_shader: stages.vertex,
tessellation_control_shader: stages.tessellation_control,
tessellation_evaluation_shader: stages.tessellation_evaluation,
geometry_shader: stages.geometry,
fragment_shader: stages.fragment,
compute_shader: stages.compute,
..PipelineStages::none()
}
}
}
/// Error when checking whether some shader stages are superset of others.
#[derive(Debug, Clone)]
pub enum ShaderStagesSupersetError {
NotSuperset,
}
impl error::Error for ShaderStagesSupersetError {}
impl fmt::Display for ShaderStagesSupersetError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
fmt,
"{}",
match *self {
ShaderStagesSupersetError::NotSuperset => "shader stages not a superset",
}
)
}
}

View File

@ -0,0 +1,28 @@
// Copyright (c) 2021 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.
//! Describes the layout of all descriptors within a descriptor set.
//!
//! When creating a new descriptor set, you must provide a *layout* object to create it from. You
//! can create a descriptor set layout manually, but it is normally created automatically by each
//! pipeline layout.
pub use self::desc::DescriptorBufferDesc;
pub use self::desc::DescriptorDesc;
pub use self::desc::DescriptorDescSupersetError;
pub use self::desc::DescriptorDescTy;
pub use self::desc::DescriptorImageDesc;
pub use self::desc::DescriptorImageDescArray;
pub use self::desc::DescriptorImageDescDimensions;
pub use self::desc::DescriptorSetDesc;
pub use self::desc::DescriptorType;
pub use self::sys::DescriptorSetLayout;
mod desc;
mod sys;

View File

@ -8,9 +8,9 @@
// according to those terms.
use crate::check_errors;
use crate::descriptor::descriptor::DescriptorDesc;
use crate::descriptor::descriptor_set::DescriptorSetDesc;
use crate::descriptor::descriptor_set::DescriptorsCount;
use crate::descriptor_set::layout::DescriptorDesc;
use crate::descriptor_set::pool::DescriptorsCount;
use crate::descriptor_set::DescriptorSetDesc;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::OomError;
@ -22,11 +22,7 @@ use std::ptr;
use std::sync::Arc;
/// Describes to the Vulkan implementation the layout of all descriptors within a descriptor set.
///
/// Despite its name, this type is technically not unsafe. However it serves the same purpose
/// in the API as other types whose names start with `Unsafe`. Using the same naming scheme avoids
/// confusions.
pub struct UnsafeDescriptorSetLayout {
pub struct DescriptorSetLayout {
// The layout.
layout: ash::vk::DescriptorSetLayout,
// The device this layout belongs to.
@ -37,16 +33,13 @@ pub struct UnsafeDescriptorSetLayout {
descriptors_count: DescriptorsCount,
}
impl UnsafeDescriptorSetLayout {
/// Builds a new `UnsafeDescriptorSetLayout` with the given descriptors.
impl DescriptorSetLayout {
/// Builds a new `DescriptorSetLayout` with the given descriptors.
///
/// The descriptors must be passed in the order of the bindings. In order words, descriptor
/// at bind point 0 first, then descriptor at bind point 1, and so on. If a binding must remain
/// empty, you can make the iterator yield `None` for an element.
pub fn new<I>(
device: Arc<Device>,
descriptors: I,
) -> Result<UnsafeDescriptorSetLayout, OomError>
pub fn new<I>(device: Arc<Device>, descriptors: I) -> Result<DescriptorSetLayout, OomError>
where
I: IntoIterator<Item = Option<DescriptorDesc>>,
{
@ -99,7 +92,7 @@ impl UnsafeDescriptorSetLayout {
output.assume_init()
};
Ok(UnsafeDescriptorSetLayout {
Ok(DescriptorSetLayout {
layout: layout,
device: device,
descriptors: descriptors,
@ -114,7 +107,7 @@ impl UnsafeDescriptorSetLayout {
}
}
unsafe impl DescriptorSetDesc for UnsafeDescriptorSetLayout {
unsafe impl DescriptorSetDesc for DescriptorSetLayout {
#[inline]
fn num_bindings(&self) -> usize {
self.descriptors.len()
@ -125,23 +118,23 @@ unsafe impl DescriptorSetDesc for UnsafeDescriptorSetLayout {
}
}
unsafe impl DeviceOwned for UnsafeDescriptorSetLayout {
unsafe impl DeviceOwned for DescriptorSetLayout {
#[inline]
fn device(&self) -> &Arc<Device> {
&self.device
}
}
impl fmt::Debug for UnsafeDescriptorSetLayout {
impl fmt::Debug for DescriptorSetLayout {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fmt.debug_struct("UnsafeDescriptorSetLayout")
fmt.debug_struct("DescriptorSetLayout")
.field("raw", &self.layout)
.field("device", &self.device)
.finish()
}
}
unsafe impl VulkanObject for UnsafeDescriptorSetLayout {
unsafe impl VulkanObject for DescriptorSetLayout {
type Object = ash::vk::DescriptorSetLayout;
#[inline]
@ -150,7 +143,7 @@ unsafe impl VulkanObject for UnsafeDescriptorSetLayout {
}
}
impl Drop for UnsafeDescriptorSetLayout {
impl Drop for DescriptorSetLayout {
#[inline]
fn drop(&mut self) {
unsafe {
@ -166,18 +159,18 @@ impl Drop for UnsafeDescriptorSetLayout {
#[cfg(test)]
mod tests {
use crate::descriptor::descriptor::DescriptorBufferDesc;
use crate::descriptor::descriptor::DescriptorDesc;
use crate::descriptor::descriptor::DescriptorDescTy;
use crate::descriptor::descriptor::ShaderStages;
use crate::descriptor::descriptor_set::DescriptorsCount;
use crate::descriptor::descriptor_set::UnsafeDescriptorSetLayout;
use crate::descriptor_set::layout::DescriptorBufferDesc;
use crate::descriptor_set::layout::DescriptorDesc;
use crate::descriptor_set::layout::DescriptorDescTy;
use crate::descriptor_set::layout::DescriptorSetLayout;
use crate::descriptor_set::pool::DescriptorsCount;
use crate::pipeline::shader::ShaderStages;
use std::iter;
#[test]
fn empty() {
let (device, _) = gfx_dev_and_queue!();
let _layout = UnsafeDescriptorSetLayout::new(device, iter::empty());
let _layout = DescriptorSetLayout::new(device, iter::empty());
}
#[test]
@ -194,7 +187,7 @@ mod tests {
readonly: true,
};
let sl = UnsafeDescriptorSetLayout::new(device.clone(), iter::once(Some(layout))).unwrap();
let sl = DescriptorSetLayout::new(device.clone(), iter::once(Some(layout))).unwrap();
assert_eq!(
sl.descriptors_count(),

View File

@ -7,14 +7,52 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
//! Descriptor sets creation and management
//! Bindings between shaders and the resources they access.
//!
//! This module is dedicated to managing descriptor sets. There are three concepts in Vulkan
//! related to descriptor sets:
//! # Overview
//!
//! In order to access a buffer or an image from a shader, that buffer or image must be put in a
//! *descriptor*. Each descriptor contains one buffer or one image alongside with the way that it
//! can be accessed. A descriptor can also be an array, in which case it contains multiple buffers
//! or images that all have the same layout.
//!
//! Descriptors are grouped in what is called *descriptor sets*. In Vulkan you don't bind
//! individual descriptors one by one, but you create then bind descriptor sets one by one. As
//! binding a descriptor set has (small but non-null) a cost, you are encouraged to put descriptors
//! that are often used together in the same set so that you can keep the same set binding through
//! multiple draws.
//!
//! # Example
//!
//! > **Note**: This section describes the simple way to bind resources. There are more optimized
//! > ways.
//!
//! There are two steps to give access to a resource in a shader: creating the descriptor set, and
//! passing the descriptor sets when drawing.
//!
//! ## Creating a descriptor set
//!
//! TODO: write example for: PersistentDescriptorSet::start(layout.clone()).add_buffer(data_buffer.clone())
//!
//! ## Passing the descriptor set when drawing
//!
//! TODO: write
//!
//! # When drawing
//!
//! When you call a function that adds a draw command to a command buffer, one of the parameters
//! corresponds to the list of descriptor sets to use. Vulkano will check that what you passed is
//! compatible with the layout of the pipeline.
//!
//! TODO: talk about perfs of changing sets
//!
//! # Descriptor sets creation and management
//!
//! There are three concepts in Vulkan related to descriptor sets:
//!
//! - A `DescriptorSetLayout` is a Vulkan object that describes to the Vulkan implementation the
//! layout of a future descriptor set. When you allocate a descriptor set, you have to pass an
//! instance of this object. This is represented with the `UnsafeDescriptorSetLayout` type in
//! instance of this object. This is represented with the `DescriptorSetLayout` type in
//! vulkano.
//! - A `DescriptorPool` is a Vulkan object that holds the memory of descriptor sets and that can
//! be used to allocate and free individual descriptor sets. This is represented with the
@ -35,49 +73,27 @@
//! - The `DescriptorSetsCollection` trait is implemented on collections of types that implement
//! `DescriptorSet`. It is what you pass to the draw functions.
use std::hash::Hash;
use std::hash::Hasher;
pub use self::collection::DescriptorSetsCollection;
pub use self::fixed_size_pool::FixedSizeDescriptorSetsPool;
use self::layout::DescriptorSetDesc;
pub use self::persistent::PersistentDescriptorSet;
pub use self::persistent::PersistentDescriptorSetBuildError;
pub use self::persistent::PersistentDescriptorSetError;
use self::sys::UnsafeDescriptorSet;
use crate::buffer::BufferAccess;
use crate::descriptor::descriptor::DescriptorDesc;
use crate::device::DeviceOwned;
use crate::image::view::ImageViewAbstract;
use crate::SafeDeref;
use crate::VulkanObject;
use std::hash::Hash;
use std::hash::Hasher;
pub use self::collection::DescriptorSetsCollection;
pub use self::fixed_size_pool::FixedSizeDescriptorSet;
pub use self::fixed_size_pool::FixedSizeDescriptorSetBuilder;
pub use self::fixed_size_pool::FixedSizeDescriptorSetBuilderArray;
pub use self::fixed_size_pool::FixedSizeDescriptorSetsPool;
pub use self::persistent::PersistentDescriptorSet;
pub use self::persistent::PersistentDescriptorSetBuf;
pub use self::persistent::PersistentDescriptorSetBufView;
pub use self::persistent::PersistentDescriptorSetBuildError;
pub use self::persistent::PersistentDescriptorSetBuilder;
pub use self::persistent::PersistentDescriptorSetBuilderArray;
pub use self::persistent::PersistentDescriptorSetError;
pub use self::persistent::PersistentDescriptorSetImg;
pub use self::persistent::PersistentDescriptorSetSampler;
pub use self::std_pool::StdDescriptorPool;
pub use self::std_pool::StdDescriptorPoolAlloc;
pub use self::sys::DescriptorPool;
pub use self::sys::DescriptorPoolAlloc;
pub use self::sys::DescriptorPoolAllocError;
pub use self::sys::DescriptorWrite;
pub use self::sys::DescriptorsCount;
pub use self::sys::UnsafeDescriptorPool;
pub use self::sys::UnsafeDescriptorPoolAllocIter;
pub use self::sys::UnsafeDescriptorSet;
pub use self::unsafe_layout::UnsafeDescriptorSetLayout;
pub mod collection;
mod fixed_size_pool;
mod persistent;
mod std_pool;
mod sys;
mod unsafe_layout;
mod collection;
pub mod fixed_size_pool;
pub mod layout;
pub mod persistent;
pub mod pool;
pub mod sys;
/// Trait for objects that contain a collection of resources that will be accessible by shaders.
///
@ -153,28 +169,3 @@ impl Hash for dyn DescriptorSet + Send + Sync {
self.device().hash(state);
}
}
/// Trait for objects that describe the layout of the descriptors of a set.
pub unsafe trait DescriptorSetDesc {
/// Returns the number of binding slots in the set.
fn num_bindings(&self) -> usize;
/// Returns a description of a descriptor, or `None` if out of range.
fn descriptor(&self, binding: usize) -> Option<DescriptorDesc>;
}
unsafe impl<T> DescriptorSetDesc for T
where
T: SafeDeref,
T::Target: DescriptorSetDesc,
{
#[inline]
fn num_bindings(&self) -> usize {
(**self).num_bindings()
}
#[inline]
fn descriptor(&self, binding: usize) -> Option<DescriptorDesc> {
(**self).descriptor(binding)
}
}

View File

@ -7,22 +7,41 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
//! A simple, immutable descriptor set that is expected to be long-lived.
//!
//! Creating a persistent descriptor set allocates from a pool, and can't be modified once created.
//! You are therefore encouraged to create them at initialization and not the during
//! performance-critical paths.
//!
//! > **Note**: You can control of the pool that is used to create the descriptor set, if you wish
//! > so. By creating a implementation of the `DescriptorPool` trait that doesn't perform any
//! > actual allocation, you can skip this allocation and make it acceptable to use a persistent
//! > descriptor set in performance-critical paths..
//!
//! The template parameter of the `PersistentDescriptorSet` is complex, and you shouldn't try to
//! express it explicitly. If you want to store your descriptor set in a struct or in a `Vec` for
//! example, you are encouraged to turn the `PersistentDescriptorSet` into a `Box<DescriptorSet>`
//! or a `Arc<DescriptorSet>`.
//!
//! # Example
//! TODO:
use crate::buffer::BufferAccess;
use crate::buffer::BufferViewRef;
use crate::descriptor::descriptor::DescriptorDesc;
use crate::descriptor::descriptor::DescriptorDescTy;
use crate::descriptor::descriptor::DescriptorImageDesc;
use crate::descriptor::descriptor::DescriptorImageDescArray;
use crate::descriptor::descriptor::DescriptorImageDescDimensions;
use crate::descriptor::descriptor::DescriptorType;
use crate::descriptor::descriptor_set::DescriptorPool;
use crate::descriptor::descriptor_set::DescriptorPoolAlloc;
use crate::descriptor::descriptor_set::DescriptorSet;
use crate::descriptor::descriptor_set::DescriptorSetDesc;
use crate::descriptor::descriptor_set::DescriptorWrite;
use crate::descriptor::descriptor_set::StdDescriptorPoolAlloc;
use crate::descriptor::descriptor_set::UnsafeDescriptorSet;
use crate::descriptor::descriptor_set::UnsafeDescriptorSetLayout;
use crate::descriptor_set::layout::DescriptorDesc;
use crate::descriptor_set::layout::DescriptorDescTy;
use crate::descriptor_set::layout::DescriptorImageDesc;
use crate::descriptor_set::layout::DescriptorImageDescArray;
use crate::descriptor_set::layout::DescriptorImageDescDimensions;
use crate::descriptor_set::layout::DescriptorSetLayout;
use crate::descriptor_set::layout::DescriptorType;
use crate::descriptor_set::pool::standard::StdDescriptorPoolAlloc;
use crate::descriptor_set::pool::DescriptorPool;
use crate::descriptor_set::pool::DescriptorPoolAlloc;
use crate::descriptor_set::sys::DescriptorWrite;
use crate::descriptor_set::DescriptorSet;
use crate::descriptor_set::DescriptorSetDesc;
use crate::descriptor_set::UnsafeDescriptorSet;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::format::Format;
@ -37,28 +56,11 @@ use std::hash::Hash;
use std::hash::Hasher;
use std::sync::Arc;
/// An immutable descriptor set that is expected to be long-lived.
///
/// Creating a persistent descriptor set allocates from a pool, and can't be modified once created.
/// You are therefore encouraged to create them at initialization and not the during
/// performance-critical paths.
///
/// > **Note**: You can control of the pool that is used to create the descriptor set, if you wish
/// > so. By creating a implementation of the `DescriptorPool` trait that doesn't perform any
/// > actual allocation, you can skip this allocation and make it acceptable to use a persistent
/// > descriptor set in performance-critical paths..
///
/// The template parameter of the `PersistentDescriptorSet` is complex, and you shouldn't try to
/// express it explicitly. If you want to store your descriptor set in a struct or in a `Vec` for
/// example, you are encouraged to turn the `PersistentDescriptorSet` into a `Box<DescriptorSet>`
/// or a `Arc<DescriptorSet>`.
///
/// # Example
// TODO:
/// A simple, immutable descriptor set that is expected to be long-lived.
pub struct PersistentDescriptorSet<R, P = StdDescriptorPoolAlloc> {
inner: P,
resources: R,
layout: Arc<UnsafeDescriptorSetLayout>,
layout: Arc<DescriptorSetLayout>,
}
impl PersistentDescriptorSet<()> {
@ -68,7 +70,7 @@ impl PersistentDescriptorSet<()> {
///
/// - Panics if the set id is out of range.
///
pub fn start(layout: Arc<UnsafeDescriptorSetLayout>) -> PersistentDescriptorSetBuilder<()> {
pub fn start(layout: Arc<DescriptorSetLayout>) -> PersistentDescriptorSetBuilder<()> {
let cap = layout.num_bindings();
PersistentDescriptorSetBuilder {
@ -168,7 +170,7 @@ where
/// See the docs of `PersistentDescriptorSet` for an example.
pub struct PersistentDescriptorSetBuilder<R> {
// The descriptor set layout.
layout: Arc<UnsafeDescriptorSetLayout>,
layout: Arc<DescriptorSetLayout>,
// Binding currently being filled.
binding_id: usize,
// The writes to perform on a descriptor set in order to put the resources in it.

View File

@ -0,0 +1,220 @@
// Copyright (c) 2021 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.
//! A pool from which descriptor sets can be allocated.
pub use self::standard::StdDescriptorPool;
pub use self::sys::DescriptorPoolAllocError;
pub use self::sys::UnsafeDescriptorPool;
pub use self::sys::UnsafeDescriptorPoolAllocIter;
use crate::descriptor_set::layout::DescriptorSetLayout;
use crate::descriptor_set::layout::DescriptorType;
use crate::descriptor_set::UnsafeDescriptorSet;
use crate::device::DeviceOwned;
use crate::OomError;
use std::cmp;
use std::ops;
pub mod standard;
mod sys;
/// A pool from which descriptor sets can be allocated.
///
/// Since the destructor of `Alloc` must free the descriptor set, this trait is usually implemented
/// on `Arc<T>` or `&'a T` and not `T` directly, so that the `Alloc` object can hold the pool.
pub unsafe trait DescriptorPool: DeviceOwned {
/// Object that represented an allocated descriptor set.
///
/// The destructor of this object should free the descriptor set.
type Alloc: DescriptorPoolAlloc;
/// Allocates a descriptor set.
fn alloc(&mut self, layout: &DescriptorSetLayout) -> Result<Self::Alloc, OomError>;
}
/// An allocated descriptor set.
pub trait DescriptorPoolAlloc {
/// Returns the inner unsafe descriptor set object.
fn inner(&self) -> &UnsafeDescriptorSet;
/// Returns the inner unsafe descriptor set object.
fn inner_mut(&mut self) -> &mut UnsafeDescriptorSet;
}
macro_rules! descriptors_count {
($($name:ident,)+) => (
/// Number of available descriptors slots in a pool.
///
/// # Example
///
/// ```
/// use vulkano::descriptor_set::pool::DescriptorsCount;
///
/// let _descriptors = DescriptorsCount {
/// uniform_buffer: 10,
/// input_attachment: 5,
/// .. DescriptorsCount::zero()
/// };
/// ```
///
#[derive(Debug, Copy, Clone)]
pub struct DescriptorsCount {
$(
pub $name: u32,
)+
}
impl DescriptorsCount {
/// Returns a `DescriptorsCount` object with all fields set to 0.
#[inline]
pub fn zero() -> DescriptorsCount {
DescriptorsCount {
$(
$name: 0,
)+
}
}
/// Adds one descriptor of the given type to the count.
#[inline]
pub fn add_one(&mut self, ty: DescriptorType) {
self.add_num(ty, 1);
}
/// Adds `num` descriptors of the given type to the count.
#[inline]
pub fn add_num(&mut self, ty: DescriptorType, num: u32) {
match ty {
DescriptorType::Sampler => self.sampler += num,
DescriptorType::CombinedImageSampler => self.combined_image_sampler += num,
DescriptorType::SampledImage => self.sampled_image += num,
DescriptorType::StorageImage => self.storage_image += num,
DescriptorType::UniformTexelBuffer => self.uniform_texel_buffer += num,
DescriptorType::StorageTexelBuffer => self.storage_texel_buffer += num,
DescriptorType::UniformBuffer => self.uniform_buffer += num,
DescriptorType::StorageBuffer => self.storage_buffer += num,
DescriptorType::UniformBufferDynamic => self.uniform_buffer_dynamic += num,
DescriptorType::StorageBufferDynamic => self.storage_buffer_dynamic += num,
DescriptorType::InputAttachment => self.input_attachment += num,
};
}
}
impl cmp::PartialEq for DescriptorsCount {
#[inline]
fn eq(&self, other: &DescriptorsCount) -> bool {
self.partial_cmp(other) == Some(cmp::Ordering::Equal)
}
}
impl cmp::Eq for DescriptorsCount {
}
impl cmp::PartialOrd for DescriptorsCount {
fn partial_cmp(&self, other: &DescriptorsCount) -> Option<cmp::Ordering> {
if $(self.$name > other.$name)&&+ {
Some(cmp::Ordering::Greater)
} else if $(self.$name < other.$name)&&+ {
Some(cmp::Ordering::Less)
} else if $(self.$name == other.$name)&&+ {
Some(cmp::Ordering::Equal)
} else {
None
}
}
fn le(&self, other: &DescriptorsCount) -> bool {
$(self.$name <= other.$name)&&+
}
fn ge(&self, other: &DescriptorsCount) -> bool {
$(self.$name >= other.$name)&&+
}
}
impl ops::Sub for DescriptorsCount {
type Output = DescriptorsCount;
#[inline]
fn sub(self, rhs: DescriptorsCount) -> DescriptorsCount {
DescriptorsCount {
$(
$name: self.$name - rhs.$name,
)+
}
}
}
impl ops::SubAssign for DescriptorsCount {
#[inline]
fn sub_assign(&mut self, rhs: DescriptorsCount) {
$(
self.$name -= rhs.$name;
)+
}
}
impl ops::Add for DescriptorsCount {
type Output = DescriptorsCount;
#[inline]
fn add(self, rhs: DescriptorsCount) -> DescriptorsCount {
DescriptorsCount {
$(
$name: self.$name + rhs.$name,
)+
}
}
}
impl ops::AddAssign for DescriptorsCount {
#[inline]
fn add_assign(&mut self, rhs: DescriptorsCount) {
$(
self.$name += rhs.$name;
)+
}
}
impl ops::Mul<u32> for DescriptorsCount {
type Output = DescriptorsCount;
#[inline]
fn mul(self, rhs: u32) -> DescriptorsCount {
DescriptorsCount {
$(
$name: self.$name * rhs,
)+
}
}
}
impl ops::MulAssign<u32> for DescriptorsCount {
#[inline]
fn mul_assign(&mut self, rhs: u32) {
$(
self.$name *= rhs;
)+
}
}
);
}
descriptors_count! {
uniform_buffer,
storage_buffer,
uniform_buffer_dynamic,
storage_buffer_dynamic,
uniform_texel_buffer,
storage_texel_buffer,
sampled_image,
storage_image,
sampler,
combined_image_sampler,
input_attachment,
}

View File

@ -7,19 +7,18 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::sync::Arc;
use std::sync::Mutex;
use crate::descriptor::descriptor_set::DescriptorPool;
use crate::descriptor::descriptor_set::DescriptorPoolAlloc;
use crate::descriptor::descriptor_set::DescriptorPoolAllocError;
use crate::descriptor::descriptor_set::DescriptorsCount;
use crate::descriptor::descriptor_set::UnsafeDescriptorPool;
use crate::descriptor::descriptor_set::UnsafeDescriptorSet;
use crate::descriptor::descriptor_set::UnsafeDescriptorSetLayout;
use crate::descriptor_set::layout::DescriptorSetLayout;
use crate::descriptor_set::pool::DescriptorPool;
use crate::descriptor_set::pool::DescriptorPoolAlloc;
use crate::descriptor_set::pool::DescriptorPoolAllocError;
use crate::descriptor_set::pool::DescriptorsCount;
use crate::descriptor_set::pool::UnsafeDescriptorPool;
use crate::descriptor_set::UnsafeDescriptorSet;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::OomError;
use std::sync::Arc;
use std::sync::Mutex;
/// Standard implementation of a descriptor pool.
///
@ -65,10 +64,7 @@ unsafe impl DescriptorPool for Arc<StdDescriptorPool> {
type Alloc = StdDescriptorPoolAlloc;
// TODO: eventually use a lock-free algorithm?
fn alloc(
&mut self,
layout: &UnsafeDescriptorSetLayout,
) -> Result<StdDescriptorPoolAlloc, OomError> {
fn alloc(&mut self, layout: &DescriptorSetLayout) -> Result<StdDescriptorPoolAlloc, OomError> {
let mut pools = self.pools.lock().unwrap();
// Try find an existing pool with some free space.
@ -181,12 +177,12 @@ impl Drop for StdDescriptorPoolAlloc {
#[cfg(test)]
mod tests {
use crate::descriptor::descriptor::DescriptorDesc;
use crate::descriptor::descriptor::DescriptorDescTy;
use crate::descriptor::descriptor::ShaderStages;
use crate::descriptor::descriptor_set::DescriptorPool;
use crate::descriptor::descriptor_set::StdDescriptorPool;
use crate::descriptor::descriptor_set::UnsafeDescriptorSetLayout;
use crate::descriptor_set::layout::DescriptorDesc;
use crate::descriptor_set::layout::DescriptorDescTy;
use crate::descriptor_set::layout::DescriptorSetLayout;
use crate::descriptor_set::pool::DescriptorPool;
use crate::descriptor_set::pool::StdDescriptorPool;
use crate::pipeline::shader::ShaderStages;
use std::iter;
use std::sync::Arc;
@ -201,8 +197,7 @@ mod tests {
stages: ShaderStages::all(),
readonly: false,
};
let layout =
UnsafeDescriptorSetLayout::new(device.clone(), iter::once(Some(desc))).unwrap();
let layout = DescriptorSetLayout::new(device.clone(), iter::once(Some(desc))).unwrap();
let mut pool = Arc::new(StdDescriptorPool::new(device));
let pool_weak = Arc::downgrade(&pool);

View File

@ -0,0 +1,497 @@
// Copyright (c) 2021 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::check_errors;
use crate::descriptor_set::layout::DescriptorSetLayout;
use crate::descriptor_set::pool::DescriptorsCount;
use crate::descriptor_set::UnsafeDescriptorSet;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::OomError;
use crate::VulkanObject;
use smallvec::SmallVec;
use std::error;
use std::fmt;
use std::mem::MaybeUninit;
use std::ptr;
use std::sync::Arc;
use std::vec::IntoIter as VecIntoIter;
/// Pool from which descriptor sets are allocated from.
///
/// A pool has a maximum number of descriptor sets and a maximum number of descriptors (one value
/// per descriptor type) it can allocate.
pub struct UnsafeDescriptorPool {
pool: ash::vk::DescriptorPool,
device: Arc<Device>,
}
impl UnsafeDescriptorPool {
/// Initializes a new pool.
///
/// Initializes a pool whose capacity is given by `count` and `max_sets`. At most `count`
/// descriptors or `max_sets` descriptor sets can be allocated at once with this pool.
///
/// If `free_descriptor_set_bit` is `true`, then individual descriptor sets can be free'd from
/// the pool. Otherwise you must reset or destroy the whole pool at once.
///
/// # Panic
///
/// - Panics if all the descriptors count are 0.
/// - Panics if `max_sets` is 0.
///
pub fn new(
device: Arc<Device>,
count: &DescriptorsCount,
max_sets: u32,
free_descriptor_set_bit: bool,
) -> Result<UnsafeDescriptorPool, OomError> {
let fns = device.fns();
assert_ne!(max_sets, 0, "The maximum number of sets can't be 0");
let mut pool_sizes: SmallVec<[_; 10]> = SmallVec::new();
macro_rules! elem {
($field:ident, $ty:expr) => {
if count.$field >= 1 {
pool_sizes.push(ash::vk::DescriptorPoolSize {
ty: $ty,
descriptor_count: count.$field,
});
}
};
}
elem!(uniform_buffer, ash::vk::DescriptorType::UNIFORM_BUFFER);
elem!(storage_buffer, ash::vk::DescriptorType::STORAGE_BUFFER);
elem!(
uniform_buffer_dynamic,
ash::vk::DescriptorType::UNIFORM_BUFFER_DYNAMIC
);
elem!(
storage_buffer_dynamic,
ash::vk::DescriptorType::STORAGE_BUFFER_DYNAMIC
);
elem!(
uniform_texel_buffer,
ash::vk::DescriptorType::UNIFORM_TEXEL_BUFFER
);
elem!(
storage_texel_buffer,
ash::vk::DescriptorType::STORAGE_TEXEL_BUFFER
);
elem!(sampled_image, ash::vk::DescriptorType::SAMPLED_IMAGE);
elem!(storage_image, ash::vk::DescriptorType::STORAGE_IMAGE);
elem!(sampler, ash::vk::DescriptorType::SAMPLER);
elem!(
combined_image_sampler,
ash::vk::DescriptorType::COMBINED_IMAGE_SAMPLER
);
elem!(input_attachment, ash::vk::DescriptorType::INPUT_ATTACHMENT);
assert!(
!pool_sizes.is_empty(),
"All the descriptors count of a pool are 0"
);
let pool = unsafe {
let infos = ash::vk::DescriptorPoolCreateInfo {
flags: if free_descriptor_set_bit {
ash::vk::DescriptorPoolCreateFlags::FREE_DESCRIPTOR_SET
} else {
ash::vk::DescriptorPoolCreateFlags::empty()
},
max_sets: max_sets,
pool_size_count: pool_sizes.len() as u32,
p_pool_sizes: pool_sizes.as_ptr(),
..Default::default()
};
let mut output = MaybeUninit::uninit();
check_errors(fns.v1_0.create_descriptor_pool(
device.internal_object(),
&infos,
ptr::null(),
output.as_mut_ptr(),
))?;
output.assume_init()
};
Ok(UnsafeDescriptorPool {
pool,
device: device.clone(),
})
}
/// Allocates descriptor sets from the pool, one for each layout.
/// Returns an iterator to the allocated sets, or an error.
///
/// The `FragmentedPool` errors often can't be prevented. If the function returns this error,
/// you should just create a new pool.
///
/// # Panic
///
/// - Panics if one of the layouts wasn't created with the same device as the pool.
///
/// # Safety
///
/// See also the `new` function.
///
/// - The total descriptors of the layouts must fit in the pool.
/// - The total number of descriptor sets allocated from the pool must not overflow the pool.
/// - You must ensure that the allocated descriptor sets are no longer in use when the pool
/// is destroyed, as destroying the pool is equivalent to freeing all the sets.
///
#[inline]
pub unsafe fn alloc<'l, I>(
&mut self,
layouts: I,
) -> Result<UnsafeDescriptorPoolAllocIter, DescriptorPoolAllocError>
where
I: IntoIterator<Item = &'l DescriptorSetLayout>,
{
let layouts: SmallVec<[_; 8]> = layouts
.into_iter()
.map(|l| {
assert_eq!(
self.device.internal_object(),
l.device().internal_object(),
"Tried to allocate from a pool with a set layout of a different \
device"
);
l.internal_object()
})
.collect();
self.alloc_impl(&layouts)
}
// Actual implementation of `alloc`. Separated so that it is not inlined.
unsafe fn alloc_impl(
&mut self,
layouts: &SmallVec<[ash::vk::DescriptorSetLayout; 8]>,
) -> Result<UnsafeDescriptorPoolAllocIter, DescriptorPoolAllocError> {
let num = layouts.len();
if num == 0 {
return Ok(UnsafeDescriptorPoolAllocIter {
sets: vec![].into_iter(),
});
}
let infos = ash::vk::DescriptorSetAllocateInfo {
descriptor_pool: self.pool,
descriptor_set_count: layouts.len() as u32,
p_set_layouts: layouts.as_ptr(),
..Default::default()
};
let mut output = Vec::with_capacity(num);
let fns = self.device.fns();
let ret = fns.v1_0.allocate_descriptor_sets(
self.device.internal_object(),
&infos,
output.as_mut_ptr(),
);
// According to the specs, because `VK_ERROR_FRAGMENTED_POOL` was added after version
// 1.0 of Vulkan, any negative return value except out-of-memory errors must be
// considered as a fragmented pool error.
match ret {
ash::vk::Result::ERROR_OUT_OF_HOST_MEMORY => {
return Err(DescriptorPoolAllocError::OutOfHostMemory);
}
ash::vk::Result::ERROR_OUT_OF_DEVICE_MEMORY => {
return Err(DescriptorPoolAllocError::OutOfDeviceMemory);
}
ash::vk::Result::ERROR_OUT_OF_POOL_MEMORY_KHR => {
return Err(DescriptorPoolAllocError::OutOfPoolMemory);
}
c if c.as_raw() < 0 => {
return Err(DescriptorPoolAllocError::FragmentedPool);
}
_ => (),
};
output.set_len(num);
Ok(UnsafeDescriptorPoolAllocIter {
sets: output.into_iter(),
})
}
/// Frees some descriptor sets.
///
/// Note that it is not mandatory to free sets. Destroying or resetting the pool destroys all
/// the descriptor sets.
///
/// # Safety
///
/// - The pool must have been created with `free_descriptor_set_bit` set to `true`.
/// - The descriptor sets must have been allocated from the pool.
/// - The descriptor sets must not be free'd twice.
/// - The descriptor sets must not be in use by the GPU.
///
#[inline]
pub unsafe fn free<I>(&mut self, descriptor_sets: I) -> Result<(), OomError>
where
I: IntoIterator<Item = UnsafeDescriptorSet>,
{
let sets: SmallVec<[_; 8]> = descriptor_sets
.into_iter()
.map(|s| s.internal_object())
.collect();
if !sets.is_empty() {
self.free_impl(&sets)
} else {
Ok(())
}
}
// Actual implementation of `free`. Separated so that it is not inlined.
unsafe fn free_impl(
&mut self,
sets: &SmallVec<[ash::vk::DescriptorSet; 8]>,
) -> Result<(), OomError> {
let fns = self.device.fns();
check_errors(fns.v1_0.free_descriptor_sets(
self.device.internal_object(),
self.pool,
sets.len() as u32,
sets.as_ptr(),
))?;
Ok(())
}
/// Resets the pool.
///
/// This destroys all descriptor sets and empties the pool.
pub unsafe fn reset(&mut self) -> Result<(), OomError> {
let fns = self.device.fns();
check_errors(fns.v1_0.reset_descriptor_pool(
self.device.internal_object(),
self.pool,
ash::vk::DescriptorPoolResetFlags::empty(),
))?;
Ok(())
}
}
unsafe impl DeviceOwned for UnsafeDescriptorPool {
#[inline]
fn device(&self) -> &Arc<Device> {
&self.device
}
}
impl fmt::Debug for UnsafeDescriptorPool {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fmt.debug_struct("UnsafeDescriptorPool")
.field("raw", &self.pool)
.field("device", &self.device)
.finish()
}
}
impl Drop for UnsafeDescriptorPool {
#[inline]
fn drop(&mut self) {
unsafe {
let fns = self.device.fns();
fns.v1_0
.destroy_descriptor_pool(self.device.internal_object(), self.pool, ptr::null());
}
}
}
/// Error that can be returned when creating a device.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum DescriptorPoolAllocError {
/// There is no memory available on the host (ie. the CPU, RAM, etc.).
OutOfHostMemory,
/// There is no memory available on the device (ie. video memory).
OutOfDeviceMemory,
/// Allocation has failed because the pool is too fragmented.
FragmentedPool,
/// There is no more space available in the descriptor pool.
OutOfPoolMemory,
}
impl error::Error for DescriptorPoolAllocError {}
impl fmt::Display for DescriptorPoolAllocError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
fmt,
"{}",
match *self {
DescriptorPoolAllocError::OutOfHostMemory => "no memory available on the host",
DescriptorPoolAllocError::OutOfDeviceMemory => {
"no memory available on the graphical device"
}
DescriptorPoolAllocError::FragmentedPool => {
"allocation has failed because the pool is too fragmented"
}
DescriptorPoolAllocError::OutOfPoolMemory => {
"there is no more space available in the descriptor pool"
}
}
)
}
}
/// Iterator to the descriptor sets allocated from an unsafe descriptor pool.
#[derive(Debug)]
pub struct UnsafeDescriptorPoolAllocIter {
sets: VecIntoIter<ash::vk::DescriptorSet>,
}
impl Iterator for UnsafeDescriptorPoolAllocIter {
type Item = UnsafeDescriptorSet;
#[inline]
fn next(&mut self) -> Option<UnsafeDescriptorSet> {
self.sets.next().map(|s| UnsafeDescriptorSet { set: s })
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.sets.size_hint()
}
}
impl ExactSizeIterator for UnsafeDescriptorPoolAllocIter {}
#[cfg(test)]
mod tests {
use crate::descriptor_set::layout::DescriptorBufferDesc;
use crate::descriptor_set::layout::DescriptorDesc;
use crate::descriptor_set::layout::DescriptorDescTy;
use crate::descriptor_set::layout::DescriptorSetLayout;
use crate::descriptor_set::pool::DescriptorsCount;
use crate::descriptor_set::pool::UnsafeDescriptorPool;
use crate::pipeline::shader::ShaderStages;
use std::iter;
#[test]
fn pool_create() {
let (device, _) = gfx_dev_and_queue!();
let desc = DescriptorsCount {
uniform_buffer: 1,
..DescriptorsCount::zero()
};
let _ = UnsafeDescriptorPool::new(device, &desc, 10, false).unwrap();
}
#[test]
fn zero_max_set() {
let (device, _) = gfx_dev_and_queue!();
let desc = DescriptorsCount {
uniform_buffer: 1,
..DescriptorsCount::zero()
};
assert_should_panic!("The maximum number of sets can't be 0", {
let _ = UnsafeDescriptorPool::new(device, &desc, 0, false);
});
}
#[test]
fn zero_descriptors() {
let (device, _) = gfx_dev_and_queue!();
assert_should_panic!("All the descriptors count of a pool are 0", {
let _ = UnsafeDescriptorPool::new(device, &DescriptorsCount::zero(), 10, false);
});
}
#[test]
fn basic_alloc() {
let (device, _) = gfx_dev_and_queue!();
let layout = DescriptorDesc {
ty: DescriptorDescTy::Buffer(DescriptorBufferDesc {
dynamic: Some(false),
storage: false,
}),
array_count: 1,
stages: ShaderStages::all_graphics(),
readonly: true,
};
let set_layout =
DescriptorSetLayout::new(device.clone(), iter::once(Some(layout))).unwrap();
let desc = DescriptorsCount {
uniform_buffer: 10,
..DescriptorsCount::zero()
};
let mut pool = UnsafeDescriptorPool::new(device, &desc, 10, false).unwrap();
unsafe {
let sets = pool.alloc(iter::once(&set_layout)).unwrap();
assert_eq!(sets.count(), 1);
}
}
#[test]
fn alloc_diff_device() {
let (device1, _) = gfx_dev_and_queue!();
let (device2, _) = gfx_dev_and_queue!();
let layout = DescriptorDesc {
ty: DescriptorDescTy::Buffer(DescriptorBufferDesc {
dynamic: Some(false),
storage: false,
}),
array_count: 1,
stages: ShaderStages::all_graphics(),
readonly: true,
};
let set_layout = DescriptorSetLayout::new(device1, iter::once(Some(layout))).unwrap();
let desc = DescriptorsCount {
uniform_buffer: 10,
..DescriptorsCount::zero()
};
assert_should_panic!(
"Tried to allocate from a pool with a set layout \
of a different device",
{
let mut pool = UnsafeDescriptorPool::new(device2, &desc, 10, false).unwrap();
unsafe {
let _ = pool.alloc(iter::once(&set_layout));
}
}
);
}
#[test]
fn alloc_zero() {
let (device, _) = gfx_dev_and_queue!();
let desc = DescriptorsCount {
uniform_buffer: 1,
..DescriptorsCount::zero()
};
let mut pool = UnsafeDescriptorPool::new(device, &desc, 1, false).unwrap();
unsafe {
let sets = pool.alloc(iter::empty()).unwrap();
assert_eq!(sets.count(), 0);
}
}
}

View File

@ -0,0 +1,595 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
//! Low-level descriptor set.
use crate::buffer::BufferAccess;
use crate::buffer::BufferInner;
use crate::buffer::BufferView;
use crate::descriptor_set::layout::DescriptorType;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::image::view::ImageViewAbstract;
use crate::sampler::Sampler;
use crate::VulkanObject;
use smallvec::SmallVec;
use std::fmt;
use std::ptr;
use std::sync::Arc;
/// Low-level descriptor set.
///
/// Contrary to most other objects in this library, this one doesn't free itself automatically and
/// doesn't hold the pool or the device it is associated to.
/// Instead it is an object meant to be used with the `UnsafeDescriptorPool`.
pub struct UnsafeDescriptorSet {
pub(super) set: ash::vk::DescriptorSet,
}
impl UnsafeDescriptorSet {
// TODO: add copying from other descriptor sets
// add a `copy` method that just takes a copy, and an `update` method that takes both
// writes and copies and that actually performs the operation
/// Modifies a descriptor set. Doesn't check that the writes or copies are correct, and
/// doesn't check whether the descriptor set is in use.
///
/// **Important**: You must ensure that the `DescriptorSetLayout` object is alive before
/// updating a descriptor set.
///
/// # Safety
///
/// - The `Device` must be the device the pool of this set was created with.
/// - The `DescriptorSetLayout` object this set was created with must be alive.
/// - Doesn't verify that the things you write in the descriptor set match its layout.
/// - Doesn't keep the resources alive. You have to do that yourself.
/// - Updating a descriptor set obeys synchronization rules that aren't checked here. Once a
/// command buffer contains a pointer/reference to a descriptor set, it is illegal to write
/// to it.
///
pub unsafe fn write<I>(&mut self, device: &Device, writes: I)
where
I: Iterator<Item = DescriptorWrite>,
{
let fns = device.fns();
// In this function, we build 4 arrays: one array of image descriptors (image_descriptors),
// one for buffer descriptors (buffer_descriptors), one for buffer view descriptors
// (buffer_views_descriptors), and one for the final list of writes (raw_writes).
// Only the final list is passed to Vulkan, but it will contain pointers to the first three
// lists in `pImageInfo`, `pBufferInfo` and `pTexelBufferView`.
//
// In order to handle that, we start by writing null pointers as placeholders in the final
// writes, and we store in `raw_writes_img_infos`, `raw_writes_buf_infos` and
// `raw_writes_buf_view_infos` the offsets of the pointers compared to the start of the
// list.
// Once we have finished iterating all the writes requested by the user, we modify
// `raw_writes` to point to the correct locations.
let mut buffer_descriptors: SmallVec<[_; 64]> = SmallVec::new();
let mut image_descriptors: SmallVec<[_; 64]> = SmallVec::new();
let mut buffer_views_descriptors: SmallVec<[_; 64]> = SmallVec::new();
let mut raw_writes: SmallVec<[_; 64]> = SmallVec::new();
let mut raw_writes_img_infos: SmallVec<[_; 64]> = SmallVec::new();
let mut raw_writes_buf_infos: SmallVec<[_; 64]> = SmallVec::new();
let mut raw_writes_buf_view_infos: SmallVec<[_; 64]> = SmallVec::new();
for indiv_write in writes {
// Since the `DescriptorWrite` objects are built only through functions, we know for
// sure that it's impossible to have an empty descriptor write.
debug_assert!(!indiv_write.inner.is_empty());
// The whole struct thats written here is valid, except for pImageInfo, pBufferInfo
// and pTexelBufferView which are placeholder values.
raw_writes.push(ash::vk::WriteDescriptorSet {
dst_set: self.set,
dst_binding: indiv_write.binding,
dst_array_element: indiv_write.first_array_element,
descriptor_count: indiv_write.inner.len() as u32,
descriptor_type: indiv_write.ty().into(),
p_image_info: ptr::null(),
p_buffer_info: ptr::null(),
p_texel_buffer_view: ptr::null(),
..Default::default()
});
match indiv_write.inner[0] {
DescriptorWriteInner::Sampler(_)
| DescriptorWriteInner::CombinedImageSampler(_, _, _)
| DescriptorWriteInner::SampledImage(_, _)
| DescriptorWriteInner::StorageImage(_, _)
| DescriptorWriteInner::InputAttachment(_, _) => {
raw_writes_img_infos.push(Some(image_descriptors.len()));
raw_writes_buf_infos.push(None);
raw_writes_buf_view_infos.push(None);
}
DescriptorWriteInner::UniformBuffer(_, _, _)
| DescriptorWriteInner::StorageBuffer(_, _, _)
| DescriptorWriteInner::DynamicUniformBuffer(_, _, _)
| DescriptorWriteInner::DynamicStorageBuffer(_, _, _) => {
raw_writes_img_infos.push(None);
raw_writes_buf_infos.push(Some(buffer_descriptors.len()));
raw_writes_buf_view_infos.push(None);
}
DescriptorWriteInner::UniformTexelBuffer(_)
| DescriptorWriteInner::StorageTexelBuffer(_) => {
raw_writes_img_infos.push(None);
raw_writes_buf_infos.push(None);
raw_writes_buf_view_infos.push(Some(buffer_views_descriptors.len()));
}
}
for elem in indiv_write.inner.iter() {
match *elem {
DescriptorWriteInner::UniformBuffer(buffer, offset, size)
| DescriptorWriteInner::DynamicUniformBuffer(buffer, offset, size) => {
buffer_descriptors.push(ash::vk::DescriptorBufferInfo {
buffer,
offset: offset as u64,
range: size as u64,
});
}
DescriptorWriteInner::StorageBuffer(buffer, offset, size)
| DescriptorWriteInner::DynamicStorageBuffer(buffer, offset, size) => {
buffer_descriptors.push(ash::vk::DescriptorBufferInfo {
buffer,
offset: offset as u64,
range: size as u64,
});
}
DescriptorWriteInner::Sampler(sampler) => {
image_descriptors.push(ash::vk::DescriptorImageInfo {
sampler,
image_view: ash::vk::ImageView::null(),
image_layout: ash::vk::ImageLayout::UNDEFINED,
});
}
DescriptorWriteInner::CombinedImageSampler(sampler, view, layout) => {
image_descriptors.push(ash::vk::DescriptorImageInfo {
sampler,
image_view: view,
image_layout: layout,
});
}
DescriptorWriteInner::StorageImage(view, layout) => {
image_descriptors.push(ash::vk::DescriptorImageInfo {
sampler: ash::vk::Sampler::null(),
image_view: view,
image_layout: layout,
});
}
DescriptorWriteInner::SampledImage(view, layout) => {
image_descriptors.push(ash::vk::DescriptorImageInfo {
sampler: ash::vk::Sampler::null(),
image_view: view,
image_layout: layout,
});
}
DescriptorWriteInner::InputAttachment(view, layout) => {
image_descriptors.push(ash::vk::DescriptorImageInfo {
sampler: ash::vk::Sampler::null(),
image_view: view,
image_layout: layout,
});
}
DescriptorWriteInner::UniformTexelBuffer(view)
| DescriptorWriteInner::StorageTexelBuffer(view) => {
buffer_views_descriptors.push(view);
}
}
}
}
// Now that `image_descriptors`, `buffer_descriptors` and `buffer_views_descriptors` are
// entirely filled and will never move again, we can fill the pointers in `raw_writes`.
for (i, write) in raw_writes.iter_mut().enumerate() {
write.p_image_info = match raw_writes_img_infos[i] {
Some(off) => image_descriptors.as_ptr().offset(off as isize),
None => ptr::null(),
};
write.p_buffer_info = match raw_writes_buf_infos[i] {
Some(off) => buffer_descriptors.as_ptr().offset(off as isize),
None => ptr::null(),
};
write.p_texel_buffer_view = match raw_writes_buf_view_infos[i] {
Some(off) => buffer_views_descriptors.as_ptr().offset(off as isize),
None => ptr::null(),
};
}
// It is forbidden to call `vkUpdateDescriptorSets` with 0 writes, so we need to perform
// this emptiness check.
if !raw_writes.is_empty() {
fns.v1_0.update_descriptor_sets(
device.internal_object(),
raw_writes.len() as u32,
raw_writes.as_ptr(),
0,
ptr::null(),
);
}
}
}
unsafe impl VulkanObject for UnsafeDescriptorSet {
type Object = ash::vk::DescriptorSet;
#[inline]
fn internal_object(&self) -> ash::vk::DescriptorSet {
self.set
}
}
impl fmt::Debug for UnsafeDescriptorSet {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "<Vulkan descriptor set {:?}>", self.set)
}
}
/// 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.
// TODO: allow binding whole arrays at once
pub struct DescriptorWrite {
binding: u32,
first_array_element: u32,
inner: SmallVec<[DescriptorWriteInner; 1]>,
}
#[derive(Debug, Clone)]
enum DescriptorWriteInner {
Sampler(ash::vk::Sampler),
StorageImage(ash::vk::ImageView, ash::vk::ImageLayout),
SampledImage(ash::vk::ImageView, ash::vk::ImageLayout),
CombinedImageSampler(ash::vk::Sampler, ash::vk::ImageView, ash::vk::ImageLayout),
UniformTexelBuffer(ash::vk::BufferView),
StorageTexelBuffer(ash::vk::BufferView),
UniformBuffer(ash::vk::Buffer, usize, usize),
StorageBuffer(ash::vk::Buffer, usize, usize),
DynamicUniformBuffer(ash::vk::Buffer, usize, usize),
DynamicStorageBuffer(ash::vk::Buffer, usize, usize),
InputAttachment(ash::vk::ImageView, ash::vk::ImageLayout),
}
macro_rules! smallvec {
($elem:expr) => {{
let mut s = SmallVec::new();
s.push($elem);
s
}};
}
impl DescriptorWrite {
#[inline]
pub fn storage_image<I>(binding: u32, array_element: u32, image_view: &I) -> DescriptorWrite
where
I: ImageViewAbstract,
{
let layouts = image_view
.image()
.descriptor_layouts()
.expect("descriptor_layouts must return Some when used in an image view");
DescriptorWrite {
binding,
first_array_element: array_element,
inner: smallvec!({
DescriptorWriteInner::StorageImage(
image_view.inner().internal_object(),
layouts.storage_image.into(),
)
}),
}
}
#[inline]
pub fn sampler(binding: u32, array_element: u32, sampler: &Arc<Sampler>) -> DescriptorWrite {
DescriptorWrite {
binding,
first_array_element: array_element,
inner: smallvec!(DescriptorWriteInner::Sampler(sampler.internal_object())),
}
}
#[inline]
pub fn sampled_image<I>(binding: u32, array_element: u32, image_view: &I) -> DescriptorWrite
where
I: ImageViewAbstract,
{
let layouts = image_view
.image()
.descriptor_layouts()
.expect("descriptor_layouts must return Some when used in an image view");
DescriptorWrite {
binding,
first_array_element: array_element,
inner: smallvec!({
DescriptorWriteInner::SampledImage(
image_view.inner().internal_object(),
layouts.sampled_image.into(),
)
}),
}
}
#[inline]
pub fn combined_image_sampler<I>(
binding: u32,
array_element: u32,
sampler: &Arc<Sampler>,
image_view: &I,
) -> DescriptorWrite
where
I: ImageViewAbstract,
{
let layouts = image_view
.image()
.descriptor_layouts()
.expect("descriptor_layouts must return Some when used in an image view");
DescriptorWrite {
binding,
first_array_element: array_element,
inner: smallvec!({
DescriptorWriteInner::CombinedImageSampler(
sampler.internal_object(),
image_view.inner().internal_object(),
layouts.combined_image_sampler.into(),
)
}),
}
}
#[inline]
pub fn uniform_texel_buffer<'a, B>(
binding: u32,
array_element: u32,
view: &BufferView<B>,
) -> DescriptorWrite
where
B: BufferAccess,
{
assert!(view.uniform_texel_buffer());
DescriptorWrite {
binding,
first_array_element: array_element,
inner: smallvec!(DescriptorWriteInner::UniformTexelBuffer(
view.internal_object()
)),
}
}
#[inline]
pub fn storage_texel_buffer<'a, B>(
binding: u32,
array_element: u32,
view: &BufferView<B>,
) -> DescriptorWrite
where
B: BufferAccess,
{
assert!(view.storage_texel_buffer());
DescriptorWrite {
binding,
first_array_element: array_element,
inner: smallvec!(DescriptorWriteInner::StorageTexelBuffer(
view.internal_object()
)),
}
}
#[inline]
pub unsafe fn uniform_buffer<B>(binding: u32, array_element: u32, buffer: &B) -> DescriptorWrite
where
B: BufferAccess,
{
let size = buffer.size();
let BufferInner { buffer, offset } = buffer.inner();
debug_assert_eq!(
offset
% buffer
.device()
.physical_device()
.properties()
.min_uniform_buffer_offset_alignment
.unwrap() as usize,
0
);
debug_assert!(
size <= buffer
.device()
.physical_device()
.properties()
.max_uniform_buffer_range
.unwrap() as usize
);
DescriptorWrite {
binding,
first_array_element: array_element,
inner: smallvec!({
DescriptorWriteInner::UniformBuffer(buffer.internal_object(), offset, size)
}),
}
}
#[inline]
pub unsafe fn storage_buffer<B>(binding: u32, array_element: u32, buffer: &B) -> DescriptorWrite
where
B: BufferAccess,
{
let size = buffer.size();
let BufferInner { buffer, offset } = buffer.inner();
debug_assert_eq!(
offset
% buffer
.device()
.physical_device()
.properties()
.min_storage_buffer_offset_alignment
.unwrap() as usize,
0
);
debug_assert!(
size <= buffer
.device()
.physical_device()
.properties()
.max_storage_buffer_range
.unwrap() as usize
);
DescriptorWrite {
binding,
first_array_element: array_element,
inner: smallvec!({
DescriptorWriteInner::StorageBuffer(buffer.internal_object(), offset, size)
}),
}
}
#[inline]
pub unsafe fn dynamic_uniform_buffer<B>(
binding: u32,
array_element: u32,
buffer: &B,
) -> DescriptorWrite
where
B: BufferAccess,
{
let size = buffer.size();
let BufferInner { buffer, offset } = buffer.inner();
debug_assert_eq!(
offset
% buffer
.device()
.physical_device()
.properties()
.min_uniform_buffer_offset_alignment
.unwrap() as usize,
0
);
debug_assert!(
size <= buffer
.device()
.physical_device()
.properties()
.max_uniform_buffer_range
.unwrap() as usize
);
DescriptorWrite {
binding,
first_array_element: array_element,
inner: smallvec!(DescriptorWriteInner::DynamicUniformBuffer(
buffer.internal_object(),
offset,
size
)),
}
}
#[inline]
pub unsafe fn dynamic_storage_buffer<B>(
binding: u32,
array_element: u32,
buffer: &B,
) -> DescriptorWrite
where
B: BufferAccess,
{
let size = buffer.size();
let BufferInner { buffer, offset } = buffer.inner();
debug_assert_eq!(
offset
% buffer
.device()
.physical_device()
.properties()
.min_storage_buffer_offset_alignment
.unwrap() as usize,
0
);
debug_assert!(
size <= buffer
.device()
.physical_device()
.properties()
.max_storage_buffer_range
.unwrap() as usize
);
DescriptorWrite {
binding,
first_array_element: array_element,
inner: smallvec!(DescriptorWriteInner::DynamicStorageBuffer(
buffer.internal_object(),
offset,
size
)),
}
}
#[inline]
pub fn input_attachment<I>(binding: u32, array_element: u32, image_view: &I) -> DescriptorWrite
where
I: ImageViewAbstract,
{
let layouts = image_view
.image()
.descriptor_layouts()
.expect("descriptor_layouts must return Some when used in an image view");
DescriptorWrite {
binding,
first_array_element: array_element,
inner: smallvec!({
DescriptorWriteInner::InputAttachment(
image_view.inner().internal_object(),
layouts.input_attachment.into(),
)
}),
}
}
/// Returns the type corresponding to this write.
#[inline]
pub fn ty(&self) -> DescriptorType {
match self.inner[0] {
DescriptorWriteInner::Sampler(_) => DescriptorType::Sampler,
DescriptorWriteInner::CombinedImageSampler(_, _, _) => {
DescriptorType::CombinedImageSampler
}
DescriptorWriteInner::SampledImage(_, _) => DescriptorType::SampledImage,
DescriptorWriteInner::StorageImage(_, _) => DescriptorType::StorageImage,
DescriptorWriteInner::UniformTexelBuffer(_) => DescriptorType::UniformTexelBuffer,
DescriptorWriteInner::StorageTexelBuffer(_) => DescriptorType::StorageTexelBuffer,
DescriptorWriteInner::UniformBuffer(_, _, _) => DescriptorType::UniformBuffer,
DescriptorWriteInner::StorageBuffer(_, _, _) => DescriptorType::StorageBuffer,
DescriptorWriteInner::DynamicUniformBuffer(_, _, _) => {
DescriptorType::UniformBufferDynamic
}
DescriptorWriteInner::DynamicStorageBuffer(_, _, _) => {
DescriptorType::StorageBufferDynamic
}
DescriptorWriteInner::InputAttachment(_, _) => DescriptorType::InputAttachment,
}
}
}

View File

@ -97,7 +97,7 @@ pub(crate) use self::properties::PropertiesFfi;
pub use crate::autogen::DeviceExtensions;
use crate::check_errors;
use crate::command_buffer::pool::StandardCommandPool;
use crate::descriptor::descriptor_set::StdDescriptorPool;
use crate::descriptor_set::pool::StdDescriptorPool;
use crate::device::physical::PhysicalDevice;
use crate::device::physical::QueueFamily;
pub use crate::extensions::{

View File

@ -1,9 +1,9 @@
use crate::descriptor::descriptor::ShaderStages;
use crate::device::physical::{
ConformanceVersion, DriverId, PhysicalDeviceType, PointClippingBehavior, ShaderCoreProperties,
ShaderFloatControlsIndependence, SubgroupFeatures,
};
use crate::image::{SampleCount, SampleCounts};
use crate::pipeline::shader::ShaderStages;
use crate::render_pass::ResolveModes;
use crate::Version;
use std::convert::TryInto;

View File

@ -77,7 +77,7 @@ mod tests;
mod extensions;
pub mod buffer;
pub mod command_buffer;
pub mod descriptor;
pub mod descriptor_set;
pub mod device;
pub mod format;
mod version;

View File

@ -364,13 +364,13 @@ mod tests {
use crate::buffer::CpuAccessibleBuffer;
use crate::command_buffer::AutoCommandBufferBuilder;
use crate::command_buffer::CommandBufferUsage;
use crate::descriptor::descriptor::DescriptorBufferDesc;
use crate::descriptor::descriptor::DescriptorDesc;
use crate::descriptor::descriptor::DescriptorDescTy;
use crate::descriptor::descriptor::ShaderStages;
use crate::descriptor::descriptor_set::PersistentDescriptorSet;
use crate::descriptor_set::layout::DescriptorBufferDesc;
use crate::descriptor_set::layout::DescriptorDesc;
use crate::descriptor_set::layout::DescriptorDescTy;
use crate::descriptor_set::PersistentDescriptorSet;
use crate::pipeline::layout::PipelineLayoutDesc;
use crate::pipeline::shader::ShaderModule;
use crate::pipeline::shader::ShaderStages;
use crate::pipeline::shader::SpecializationConstants;
use crate::pipeline::shader::SpecializationMapEntry;
use crate::pipeline::ComputePipeline;

View File

@ -7,14 +7,14 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::descriptor::descriptor::DescriptorBufferDesc;
use crate::descriptor::descriptor::DescriptorDesc;
use crate::descriptor::descriptor::DescriptorDescSupersetError;
use crate::descriptor::descriptor::DescriptorDescTy;
use crate::descriptor::descriptor::ShaderStages;
use crate::descriptor::descriptor_set::DescriptorSetsCollection;
use crate::descriptor_set::layout::DescriptorBufferDesc;
use crate::descriptor_set::layout::DescriptorDesc;
use crate::descriptor_set::layout::DescriptorDescSupersetError;
use crate::descriptor_set::layout::DescriptorDescTy;
use crate::descriptor_set::DescriptorSetsCollection;
use crate::device::Device;
use crate::pipeline::layout::limits_check;
use crate::pipeline::shader::ShaderStages;
use fnv::FnvHashSet;
use std::cmp;
use std::error;
@ -418,10 +418,10 @@ impl fmt::Display for PipelineLayoutNotSupersetError {
#[cfg(test)]
mod tests {
use crate::descriptor::descriptor::ShaderStages;
use crate::pipeline::layout::PipelineLayoutDesc;
use crate::pipeline::layout::PipelineLayoutDescError;
use crate::pipeline::layout::PipelineLayoutDescPcRange;
use crate::pipeline::shader::ShaderStages;
#[test]
fn pc_conflict() {

View File

@ -9,11 +9,11 @@
//! Contains the `check_desc_against_limits` function and the `PipelineLayoutLimitsError` error.
use crate::descriptor::descriptor::DescriptorType;
use crate::descriptor::descriptor::ShaderStages;
use crate::descriptor_set::layout::DescriptorType;
use crate::device::Properties;
use crate::pipeline::layout::PipelineLayoutDesc;
use crate::pipeline::layout::PipelineLayoutDescPcRange;
use crate::pipeline::shader::ShaderStages;
use std::error;
use std::fmt;

View File

@ -8,13 +8,13 @@
// according to those terms.
use crate::check_errors;
use crate::descriptor::descriptor::ShaderStages;
use crate::descriptor::descriptor_set::UnsafeDescriptorSetLayout;
use crate::descriptor_set::layout::DescriptorSetLayout;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::pipeline::layout::PipelineLayoutDesc;
use crate::pipeline::layout::PipelineLayoutDescPcRange;
use crate::pipeline::layout::PipelineLayoutLimitsError;
use crate::pipeline::shader::ShaderStages;
use crate::Error;
use crate::OomError;
use crate::VulkanObject;
@ -30,7 +30,7 @@ use std::sync::Arc;
pub struct PipelineLayout {
device: Arc<Device>,
layout: ash::vk::PipelineLayout,
descriptor_set_layouts: SmallVec<[Arc<UnsafeDescriptorSetLayout>; 16]>,
descriptor_set_layouts: SmallVec<[Arc<DescriptorSetLayout>; 16]>,
desc: PipelineLayoutDesc,
}
@ -45,12 +45,12 @@ impl PipelineLayout {
desc.check_against_limits(&device)?;
// Building the list of `UnsafeDescriptorSetLayout` objects.
// Building the list of `DescriptorSetLayout` objects.
let descriptor_set_layouts = {
let mut layouts: SmallVec<[_; 16]> = SmallVec::new();
for set in desc.descriptor_sets() {
layouts.push({
Arc::new(UnsafeDescriptorSetLayout::new(
Arc::new(DescriptorSetLayout::new(
device.clone(),
set.iter().map(|s| s.clone()),
)?)
@ -145,11 +145,11 @@ impl PipelineLayout {
&self.desc
}
/// Returns the `UnsafeDescriptorSetLayout` object of the specified set index.
/// Returns the `DescriptorSetLayout` object of the specified set index.
///
/// Returns `None` if out of range or if the set is empty for this index.
#[inline]
pub fn descriptor_set_layout(&self, index: usize) -> Option<&Arc<UnsafeDescriptorSetLayout>> {
pub fn descriptor_set_layout(&self, index: usize) -> Option<&Arc<DescriptorSetLayout>> {
self.descriptor_set_layouts.get(index)
}
}
@ -270,7 +270,7 @@ mod tests {
use std::iter;
use std::sync::Arc;
use descriptor::descriptor::ShaderStages;
use descriptor::descriptor_set::UnsafeDescriptorSetLayout;
use descriptor::descriptor_set::DescriptorSetLayout;
use descriptor::pipeline_layout::sys::PipelineLayout;
use descriptor::pipeline_layout::sys::PipelineLayoutCreationError;
@ -285,7 +285,7 @@ mod tests {
let (device1, _) = gfx_dev_and_queue!();
let (device2, _) = gfx_dev_and_queue!();
let set = match UnsafeDescriptorSetLayout::raw(device1, iter::empty()) {
let set = match DescriptorSetLayout::raw(device1, iter::empty()) {
Ok(s) => Arc::new(s),
Err(_) => return
};

View File

@ -22,6 +22,7 @@ use crate::device::Device;
use crate::format::Format;
use crate::pipeline::input_assembly::PrimitiveTopology;
use crate::pipeline::layout::PipelineLayoutDesc;
use crate::sync::PipelineStages;
use crate::OomError;
use crate::VulkanObject;
use std::borrow::Cow;
@ -30,6 +31,7 @@ use std::ffi::CStr;
use std::fmt;
use std::mem;
use std::mem::MaybeUninit;
use std::ops::BitOr;
use std::ops::Range;
use std::ptr;
use std::sync::Arc;
@ -580,3 +582,198 @@ pub struct SpecializationMapEntry {
/// Size of the data in bytes. Must match the size of the constant (`4` for booleans).
pub size: usize,
}
/// Describes a set of shader stages.
// TODO: add example with BitOr
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct ShaderStages {
pub vertex: bool,
pub tessellation_control: bool,
pub tessellation_evaluation: bool,
pub geometry: bool,
pub fragment: bool,
pub compute: bool,
}
impl ShaderStages {
/// Creates a `ShaderStages` struct will all stages set to `true`.
// TODO: add example
#[inline]
pub const fn all() -> ShaderStages {
ShaderStages {
vertex: true,
tessellation_control: true,
tessellation_evaluation: true,
geometry: true,
fragment: true,
compute: true,
}
}
/// Creates a `ShaderStages` struct will all stages set to `false`.
// TODO: add example
#[inline]
pub const fn none() -> ShaderStages {
ShaderStages {
vertex: false,
tessellation_control: false,
tessellation_evaluation: false,
geometry: false,
fragment: false,
compute: false,
}
}
/// Creates a `ShaderStages` struct with all graphics stages set to `true`.
// TODO: add example
#[inline]
pub const fn all_graphics() -> ShaderStages {
ShaderStages {
vertex: true,
tessellation_control: true,
tessellation_evaluation: true,
geometry: true,
fragment: true,
compute: false,
}
}
/// Creates a `ShaderStages` struct with the compute stage set to `true`.
// TODO: add example
#[inline]
pub const fn compute() -> ShaderStages {
ShaderStages {
vertex: false,
tessellation_control: false,
tessellation_evaluation: false,
geometry: false,
fragment: false,
compute: true,
}
}
/// Checks whether we have more stages enabled than `other`.
// TODO: add example
#[inline]
pub const fn is_superset_of(
&self,
other: &ShaderStages,
) -> Result<(), ShaderStagesSupersetError> {
if (self.vertex || !other.vertex)
&& (self.tessellation_control || !other.tessellation_control)
&& (self.tessellation_evaluation || !other.tessellation_evaluation)
&& (self.geometry || !other.geometry)
&& (self.fragment || !other.fragment)
&& (self.compute || !other.compute)
{
Ok(())
} else {
Err(ShaderStagesSupersetError::NotSuperset)
}
}
/// Checks whether any of the stages in `self` are also present in `other`.
// TODO: add example
#[inline]
pub const fn intersects(&self, other: &ShaderStages) -> bool {
(self.vertex && other.vertex)
|| (self.tessellation_control && other.tessellation_control)
|| (self.tessellation_evaluation && other.tessellation_evaluation)
|| (self.geometry && other.geometry)
|| (self.fragment && other.fragment)
|| (self.compute && other.compute)
}
}
impl From<ShaderStages> for ash::vk::ShaderStageFlags {
#[inline]
fn from(val: ShaderStages) -> Self {
let mut result = ash::vk::ShaderStageFlags::empty();
if val.vertex {
result |= ash::vk::ShaderStageFlags::VERTEX;
}
if val.tessellation_control {
result |= ash::vk::ShaderStageFlags::TESSELLATION_CONTROL;
}
if val.tessellation_evaluation {
result |= ash::vk::ShaderStageFlags::TESSELLATION_EVALUATION;
}
if val.geometry {
result |= ash::vk::ShaderStageFlags::GEOMETRY;
}
if val.fragment {
result |= ash::vk::ShaderStageFlags::FRAGMENT;
}
if val.compute {
result |= ash::vk::ShaderStageFlags::COMPUTE;
}
result
}
}
impl From<ash::vk::ShaderStageFlags> for ShaderStages {
#[inline]
fn from(val: ash::vk::ShaderStageFlags) -> Self {
Self {
vertex: val.intersects(ash::vk::ShaderStageFlags::VERTEX),
tessellation_control: val.intersects(ash::vk::ShaderStageFlags::TESSELLATION_CONTROL),
tessellation_evaluation: val
.intersects(ash::vk::ShaderStageFlags::TESSELLATION_EVALUATION),
geometry: val.intersects(ash::vk::ShaderStageFlags::GEOMETRY),
fragment: val.intersects(ash::vk::ShaderStageFlags::FRAGMENT),
compute: val.intersects(ash::vk::ShaderStageFlags::COMPUTE),
}
}
}
impl BitOr for ShaderStages {
type Output = ShaderStages;
#[inline]
fn bitor(self, other: ShaderStages) -> ShaderStages {
ShaderStages {
vertex: self.vertex || other.vertex,
tessellation_control: self.tessellation_control || other.tessellation_control,
tessellation_evaluation: self.tessellation_evaluation || other.tessellation_evaluation,
geometry: self.geometry || other.geometry,
fragment: self.fragment || other.fragment,
compute: self.compute || other.compute,
}
}
}
impl From<ShaderStages> for PipelineStages {
#[inline]
fn from(stages: ShaderStages) -> PipelineStages {
PipelineStages {
vertex_shader: stages.vertex,
tessellation_control_shader: stages.tessellation_control,
tessellation_evaluation_shader: stages.tessellation_evaluation,
geometry_shader: stages.geometry,
fragment_shader: stages.fragment,
compute_shader: stages.compute,
..PipelineStages::none()
}
}
}
/// Error when checking that a `ShaderStages` object is a superset of another.
#[derive(Debug, Clone)]
pub enum ShaderStagesSupersetError {
NotSuperset,
}
impl error::Error for ShaderStagesSupersetError {}
impl fmt::Display for ShaderStagesSupersetError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
fmt,
"{}",
match *self {
ShaderStagesSupersetError::NotSuperset => "shader stages not a superset",
}
)
}
}

View File

@ -597,7 +597,7 @@ impl Default for SurfaceTransform {
/// - Swapchain images should have a format with the `Srgb` suffix.
///
/// > **Note**: It is unclear whether the `SrgbNonLinear` color space is always supported by the
/// > the implementation or not. See https://github.com/KhronosGroup/Vulkan-Docs/issues/442.
/// > the implementation or not. See <https://github.com/KhronosGroup/Vulkan-Docs/issues/442>.
///
/// > **Note**: Lots of developers are confused by color spaces. You can sometimes find articles
/// > talking about gamma correction and suggestion to put your colors to the power 2.2 for