mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-21 22:34:43 +00:00
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:
parent
b12414f892
commit
d5bcffa902
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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};
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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),
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
@ -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;
|
@ -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 {
|
@ -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.
|
@ -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",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
28
vulkano/src/descriptor_set/layout/mod.rs
Normal file
28
vulkano/src/descriptor_set/layout/mod.rs
Normal 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;
|
@ -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(),
|
@ -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)
|
||||
}
|
||||
}
|
@ -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.
|
220
vulkano/src/descriptor_set/pool/mod.rs
Normal file
220
vulkano/src/descriptor_set/pool/mod.rs
Normal 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,
|
||||
}
|
@ -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);
|
497
vulkano/src/descriptor_set/pool/sys.rs
Normal file
497
vulkano/src/descriptor_set/pool/sys.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
595
vulkano/src/descriptor_set/sys.rs
Normal file
595
vulkano/src/descriptor_set/sys.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
@ -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::{
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user