diff --git a/examples/src/bin/basic-compute-shader.rs b/examples/src/bin/basic-compute-shader.rs index 7af9fa10..23aacb23 100644 --- a/examples/src/bin/basic-compute-shader.rs +++ b/examples/src/bin/basic-compute-shader.rs @@ -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}; diff --git a/examples/src/bin/deferred/frame/ambient_lighting_system.rs b/examples/src/bin/deferred/frame/ambient_lighting_system.rs index d96a38f1..b2456e80 100644 --- a/examples/src/bin/deferred/frame/ambient_lighting_system.rs +++ b/examples/src/bin/deferred/frame/ambient_lighting_system.rs @@ -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; diff --git a/examples/src/bin/deferred/frame/directional_lighting_system.rs b/examples/src/bin/deferred/frame/directional_lighting_system.rs index de6db03c..082e70b9 100644 --- a/examples/src/bin/deferred/frame/directional_lighting_system.rs +++ b/examples/src/bin/deferred/frame/directional_lighting_system.rs @@ -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; diff --git a/examples/src/bin/deferred/frame/point_lighting_system.rs b/examples/src/bin/deferred/frame/point_lighting_system.rs index 08e227e5..f0755f38 100644 --- a/examples/src/bin/deferred/frame/point_lighting_system.rs +++ b/examples/src/bin/deferred/frame/point_lighting_system.rs @@ -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; diff --git a/examples/src/bin/dynamic-buffers.rs b/examples/src/bin/dynamic-buffers.rs index cd822402..d305ff5b 100644 --- a/examples/src/bin/dynamic-buffers.rs +++ b/examples/src/bin/dynamic-buffers.rs @@ -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}; diff --git a/examples/src/bin/dynamic-local-size.rs b/examples/src/bin/dynamic-local-size.rs index 75d813fe..4d2361f6 100644 --- a/examples/src/bin/dynamic-local-size.rs +++ b/examples/src/bin/dynamic-local-size.rs @@ -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; diff --git a/examples/src/bin/image/main.rs b/examples/src/bin/image/main.rs index b8e3527f..f5b267ab 100644 --- a/examples/src/bin/image/main.rs +++ b/examples/src/bin/image/main.rs @@ -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; diff --git a/examples/src/bin/immutable-buffer-initialization.rs b/examples/src/bin/immutable-buffer-initialization.rs index 1f0850fd..db3cf240 100644 --- a/examples/src/bin/immutable-buffer-initialization.rs +++ b/examples/src/bin/immutable-buffer-initialization.rs @@ -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}; diff --git a/examples/src/bin/indirect.rs b/examples/src/bin/indirect.rs index eb580094..bc1216af 100644 --- a/examples/src/bin/indirect.rs +++ b/examples/src/bin/indirect.rs @@ -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; diff --git a/examples/src/bin/push-constants.rs b/examples/src/bin/push-constants.rs index e1f4aea1..bb9e7cf3 100644 --- a/examples/src/bin/push-constants.rs +++ b/examples/src/bin/push-constants.rs @@ -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}; diff --git a/examples/src/bin/shader-include/main.rs b/examples/src/bin/shader-include/main.rs index dd93d0b6..ecb92832 100644 --- a/examples/src/bin/shader-include/main.rs +++ b/examples/src/bin/shader-include/main.rs @@ -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}; diff --git a/examples/src/bin/specialization-constants.rs b/examples/src/bin/specialization-constants.rs index 18730d94..a91684d0 100644 --- a/examples/src/bin/specialization-constants.rs +++ b/examples/src/bin/specialization-constants.rs @@ -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}; diff --git a/examples/src/bin/teapot/main.rs b/examples/src/bin/teapot/main.rs index 3e03ef47..20d4718b 100644 --- a/examples/src/bin/teapot/main.rs +++ b/examples/src/bin/teapot/main.rs @@ -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; diff --git a/vulkano-shaders/src/codegen.rs b/vulkano-shaders/src/codegen.rs index e87b8ab7..3b66f9db 100644 --- a/vulkano-shaders/src/codegen.rs +++ b/vulkano-shaders/src/codegen.rs @@ -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; diff --git a/vulkano/autogen/properties.rs b/vulkano/autogen/properties.rs index 99f89045..b59d33d0 100644 --- a/vulkano/autogen/properties.rs +++ b/vulkano/autogen/properties.rs @@ -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), } diff --git a/vulkano/src/command_buffer/auto.rs b/vulkano/src/command_buffer/auto.rs index 778f4111..c10b634b 100644 --- a/vulkano/src/command_buffer/auto.rs +++ b/vulkano/src/command_buffer/auto.rs @@ -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; diff --git a/vulkano/src/command_buffer/state_cacher.rs b/vulkano/src/command_buffer/state_cacher.rs index b3edf1d4..d7b62167 100644 --- a/vulkano/src/command_buffer/state_cacher.rs +++ b/vulkano/src/command_buffer/state_cacher.rs @@ -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; diff --git a/vulkano/src/command_buffer/synced/commands.rs b/vulkano/src/command_buffer/synced/commands.rs index c1ef3181..eb0ab240 100644 --- a/vulkano/src/command_buffer/synced/commands.rs +++ b/vulkano/src/command_buffer/synced/commands.rs @@ -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; diff --git a/vulkano/src/command_buffer/sys.rs b/vulkano/src/command_buffer/sys.rs index 066033cf..a210e1d8 100644 --- a/vulkano/src/command_buffer/sys.rs +++ b/vulkano/src/command_buffer/sys.rs @@ -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; diff --git a/vulkano/src/command_buffer/validity/descriptor_sets.rs b/vulkano/src/command_buffer/validity/descriptor_sets.rs index 19b85d63..cbe9f748 100644 --- a/vulkano/src/command_buffer/validity/descriptor_sets.rs +++ b/vulkano/src/command_buffer/validity/descriptor_sets.rs @@ -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. diff --git a/vulkano/src/descriptor/descriptor_set/sys.rs b/vulkano/src/descriptor/descriptor_set/sys.rs deleted file mode 100644 index 6a65e00d..00000000 --- a/vulkano/src/descriptor/descriptor_set/sys.rs +++ /dev/null @@ -1,1266 +0,0 @@ -// Copyright (c) 2016 The vulkano developers -// Licensed under the Apache License, Version 2.0 -// or the MIT -// license , -// at your option. All files in the project carrying such -// notice may not be copied, modified, or distributed except -// according to those terms. - -use crate::buffer::BufferAccess; -use crate::buffer::BufferInner; -use crate::buffer::BufferView; -use crate::check_errors; -use crate::descriptor::descriptor::DescriptorType; -use crate::descriptor::descriptor_set::UnsafeDescriptorSetLayout; -use crate::device::Device; -use crate::device::DeviceOwned; -use crate::image::view::ImageViewAbstract; -use crate::sampler::Sampler; -use crate::OomError; -use crate::VulkanObject; -use smallvec::SmallVec; -use std::cmp; -use std::error; -use std::fmt; -use std::mem::MaybeUninit; -use std::ops; -use std::ptr; -use std::sync::Arc; -use std::vec::IntoIter as VecIntoIter; - -/// 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` 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: &UnsafeDescriptorSetLayout) -> Result; -} - -/// 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::descriptor_set::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 { - 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 for DescriptorsCount { - type Output = DescriptorsCount; - - #[inline] - fn mul(self, rhs: u32) -> DescriptorsCount { - DescriptorsCount { - $( - $name: self.$name * rhs, - )+ - } - } - } - - impl ops::MulAssign 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, -} - -/// 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, -} - -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, - count: &DescriptorsCount, - max_sets: u32, - free_descriptor_set_bit: bool, - ) -> Result { - 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 - where - I: IntoIterator, - { - 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 { - 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(&mut self, descriptor_sets: I) -> Result<(), OomError> - where - I: IntoIterator, - { - let sets: SmallVec<[_; 8]> = descriptor_sets.into_iter().map(|s| s.set).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 { - &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, -} - -impl Iterator for UnsafeDescriptorPoolAllocIter { - type Item = UnsafeDescriptorSet; - - #[inline] - fn next(&mut self) -> Option { - self.sets.next().map(|s| UnsafeDescriptorSet { set: s }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.sets.size_hint() - } -} - -impl ExactSizeIterator for UnsafeDescriptorPoolAllocIter {} - -/// 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 { - 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 `UnsafeDescriptorSetLayout` object is alive before - /// updating a descriptor set. - /// - /// # Safety - /// - /// - The `Device` must be the device the pool of this set was created with. - /// - The `UnsafeDescriptorSetLayout` 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(&mut self, device: &Device, writes: I) - where - I: Iterator, - { - 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, "", 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(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) -> DescriptorWrite { - DescriptorWrite { - binding, - first_array_element: array_element, - inner: smallvec!(DescriptorWriteInner::Sampler(sampler.internal_object())), - } - } - - #[inline] - pub fn sampled_image(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( - binding: u32, - array_element: u32, - sampler: &Arc, - 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, - ) -> 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, - ) -> 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(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(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( - 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( - 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(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, - } - } -} - -#[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::UnsafeDescriptorPool; - use crate::descriptor::descriptor_set::UnsafeDescriptorSetLayout; - 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 = - UnsafeDescriptorSetLayout::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 = UnsafeDescriptorSetLayout::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); - } - } -} diff --git a/vulkano/src/descriptor/mod.rs b/vulkano/src/descriptor/mod.rs deleted file mode 100644 index ddb5abc5..00000000 --- a/vulkano/src/descriptor/mod.rs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2016 The vulkano developers -// Licensed under the Apache License, Version 2.0 -// or the MIT -// license , -// 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; diff --git a/vulkano/src/descriptor/descriptor_set/collection.rs b/vulkano/src/descriptor_set/collection.rs similarity index 96% rename from vulkano/src/descriptor/descriptor_set/collection.rs rename to vulkano/src/descriptor_set/collection.rs index 6e6304d9..33b16f75 100644 --- a/vulkano/src/descriptor/descriptor_set/collection.rs +++ b/vulkano/src/descriptor_set/collection.rs @@ -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 { diff --git a/vulkano/src/descriptor/descriptor_set/fixed_size_pool.rs b/vulkano/src/descriptor_set/fixed_size_pool.rs similarity index 88% rename from vulkano/src/descriptor/descriptor_set/fixed_size_pool.rs rename to vulkano/src/descriptor_set/fixed_size_pool.rs index 3dce305e..451b0715 100644 --- a/vulkano/src/descriptor/descriptor_set/fixed_size_pool.rs +++ b/vulkano/src/descriptor_set/fixed_size_pool.rs @@ -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 = return; +//! // use vulkano::pipeline::GraphicsPipelineAbstract; +//! // let graphics_pipeline: Arc = ...; +//! +//! 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 = return; -/// // use vulkano::pipeline::GraphicsPipelineAbstract; -/// // let graphics_pipeline: Arc = ...; -/// -/// 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, + layout: Arc, // 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) -> FixedSizeDescriptorSetsPool { + pub fn new(layout: Arc) -> 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 { + fn alloc(&mut self, layout: &DescriptorSetLayout) -> Result { loop { // Try to extract a descriptor from the current pool if any exist. // This is the most common case. diff --git a/vulkano/src/descriptor/descriptor.rs b/vulkano/src/descriptor_set/layout/desc.rs similarity index 77% rename from vulkano/src/descriptor/descriptor.rs rename to vulkano/src/descriptor_set/layout/desc.rs index 98594b04..1d943491 100644 --- a/vulkano/src/descriptor/descriptor.rs +++ b/vulkano/src/descriptor_set/layout/desc.rs @@ -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; +} + +unsafe impl 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 { + (**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 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 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 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 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", - } - ) - } -} diff --git a/vulkano/src/descriptor_set/layout/mod.rs b/vulkano/src/descriptor_set/layout/mod.rs new file mode 100644 index 00000000..66d1d089 --- /dev/null +++ b/vulkano/src/descriptor_set/layout/mod.rs @@ -0,0 +1,28 @@ +// Copyright (c) 2021 The vulkano developers +// Licensed under the Apache License, Version 2.0 +// or the MIT +// license , +// 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; diff --git a/vulkano/src/descriptor/descriptor_set/unsafe_layout.rs b/vulkano/src/descriptor_set/layout/sys.rs similarity index 77% rename from vulkano/src/descriptor/descriptor_set/unsafe_layout.rs rename to vulkano/src/descriptor_set/layout/sys.rs index 9fcc2a08..216dca3e 100644 --- a/vulkano/src/descriptor/descriptor_set/unsafe_layout.rs +++ b/vulkano/src/descriptor_set/layout/sys.rs @@ -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( - device: Arc, - descriptors: I, - ) -> Result + pub fn new(device: Arc, descriptors: I) -> Result where I: IntoIterator>, { @@ -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 { &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(), diff --git a/vulkano/src/descriptor/descriptor_set/mod.rs b/vulkano/src/descriptor_set/mod.rs similarity index 68% rename from vulkano/src/descriptor/descriptor_set/mod.rs rename to vulkano/src/descriptor_set/mod.rs index efc2f38a..515e8360 100644 --- a/vulkano/src/descriptor/descriptor_set/mod.rs +++ b/vulkano/src/descriptor_set/mod.rs @@ -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; -} - -unsafe impl 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 { - (**self).descriptor(binding) - } -} diff --git a/vulkano/src/descriptor/descriptor_set/persistent.rs b/vulkano/src/descriptor_set/persistent.rs similarity index 95% rename from vulkano/src/descriptor/descriptor_set/persistent.rs rename to vulkano/src/descriptor_set/persistent.rs index 86a555f8..c4504862 100644 --- a/vulkano/src/descriptor/descriptor_set/persistent.rs +++ b/vulkano/src/descriptor_set/persistent.rs @@ -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` +//! or a `Arc`. +//! +//! # 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` -/// or a `Arc`. -/// -/// # Example -// TODO: +/// A simple, immutable descriptor set that is expected to be long-lived. pub struct PersistentDescriptorSet { inner: P, resources: R, - layout: Arc, + layout: Arc, } impl PersistentDescriptorSet<()> { @@ -68,7 +70,7 @@ impl PersistentDescriptorSet<()> { /// /// - Panics if the set id is out of range. /// - pub fn start(layout: Arc) -> PersistentDescriptorSetBuilder<()> { + pub fn start(layout: Arc) -> PersistentDescriptorSetBuilder<()> { let cap = layout.num_bindings(); PersistentDescriptorSetBuilder { @@ -168,7 +170,7 @@ where /// See the docs of `PersistentDescriptorSet` for an example. pub struct PersistentDescriptorSetBuilder { // The descriptor set layout. - layout: Arc, + layout: Arc, // Binding currently being filled. binding_id: usize, // The writes to perform on a descriptor set in order to put the resources in it. diff --git a/vulkano/src/descriptor_set/pool/mod.rs b/vulkano/src/descriptor_set/pool/mod.rs new file mode 100644 index 00000000..e29209cf --- /dev/null +++ b/vulkano/src/descriptor_set/pool/mod.rs @@ -0,0 +1,220 @@ +// Copyright (c) 2021 The vulkano developers +// Licensed under the Apache License, Version 2.0 +// or the MIT +// license , +// 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` 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; +} + +/// 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 { + 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 for DescriptorsCount { + type Output = DescriptorsCount; + + #[inline] + fn mul(self, rhs: u32) -> DescriptorsCount { + DescriptorsCount { + $( + $name: self.$name * rhs, + )+ + } + } + } + + impl ops::MulAssign 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, +} diff --git a/vulkano/src/descriptor/descriptor_set/std_pool.rs b/vulkano/src/descriptor_set/pool/standard.rs similarity index 86% rename from vulkano/src/descriptor/descriptor_set/std_pool.rs rename to vulkano/src/descriptor_set/pool/standard.rs index 4fdd4972..866cb5e8 100644 --- a/vulkano/src/descriptor/descriptor_set/std_pool.rs +++ b/vulkano/src/descriptor_set/pool/standard.rs @@ -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 { type Alloc = StdDescriptorPoolAlloc; // TODO: eventually use a lock-free algorithm? - fn alloc( - &mut self, - layout: &UnsafeDescriptorSetLayout, - ) -> Result { + fn alloc(&mut self, layout: &DescriptorSetLayout) -> Result { 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); diff --git a/vulkano/src/descriptor_set/pool/sys.rs b/vulkano/src/descriptor_set/pool/sys.rs new file mode 100644 index 00000000..5ae243f8 --- /dev/null +++ b/vulkano/src/descriptor_set/pool/sys.rs @@ -0,0 +1,497 @@ +// Copyright (c) 2021 The vulkano developers +// Licensed under the Apache License, Version 2.0 +// or the MIT +// license , +// 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, +} + +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, + count: &DescriptorsCount, + max_sets: u32, + free_descriptor_set_bit: bool, + ) -> Result { + 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 + where + I: IntoIterator, + { + 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 { + 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(&mut self, descriptor_sets: I) -> Result<(), OomError> + where + I: IntoIterator, + { + 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 { + &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, +} + +impl Iterator for UnsafeDescriptorPoolAllocIter { + type Item = UnsafeDescriptorSet; + + #[inline] + fn next(&mut self) -> Option { + self.sets.next().map(|s| UnsafeDescriptorSet { set: s }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + 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); + } + } +} diff --git a/vulkano/src/descriptor_set/sys.rs b/vulkano/src/descriptor_set/sys.rs new file mode 100644 index 00000000..ace5edfc --- /dev/null +++ b/vulkano/src/descriptor_set/sys.rs @@ -0,0 +1,595 @@ +// Copyright (c) 2016 The vulkano developers +// Licensed under the Apache License, Version 2.0 +// or the MIT +// license , +// 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(&mut self, device: &Device, writes: I) + where + I: Iterator, + { + 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, "", 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(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) -> DescriptorWrite { + DescriptorWrite { + binding, + first_array_element: array_element, + inner: smallvec!(DescriptorWriteInner::Sampler(sampler.internal_object())), + } + } + + #[inline] + pub fn sampled_image(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( + binding: u32, + array_element: u32, + sampler: &Arc, + 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, + ) -> 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, + ) -> 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(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(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( + 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( + 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(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, + } + } +} diff --git a/vulkano/src/device/mod.rs b/vulkano/src/device/mod.rs index 2575e91a..1e520b01 100644 --- a/vulkano/src/device/mod.rs +++ b/vulkano/src/device/mod.rs @@ -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::{ diff --git a/vulkano/src/device/properties.rs b/vulkano/src/device/properties.rs index 1ab83d13..ef5c5f67 100644 --- a/vulkano/src/device/properties.rs +++ b/vulkano/src/device/properties.rs @@ -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; diff --git a/vulkano/src/lib.rs b/vulkano/src/lib.rs index c1a133eb..17523ca9 100644 --- a/vulkano/src/lib.rs +++ b/vulkano/src/lib.rs @@ -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; diff --git a/vulkano/src/pipeline/compute_pipeline.rs b/vulkano/src/pipeline/compute_pipeline.rs index e1f5b7bf..683ad5c0 100644 --- a/vulkano/src/pipeline/compute_pipeline.rs +++ b/vulkano/src/pipeline/compute_pipeline.rs @@ -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; diff --git a/vulkano/src/pipeline/layout/desc.rs b/vulkano/src/pipeline/layout/desc.rs index 0b715717..c4cd5f12 100644 --- a/vulkano/src/pipeline/layout/desc.rs +++ b/vulkano/src/pipeline/layout/desc.rs @@ -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() { diff --git a/vulkano/src/pipeline/layout/limits_check.rs b/vulkano/src/pipeline/layout/limits_check.rs index 6ee98437..d1f71ef9 100644 --- a/vulkano/src/pipeline/layout/limits_check.rs +++ b/vulkano/src/pipeline/layout/limits_check.rs @@ -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; diff --git a/vulkano/src/pipeline/layout/sys.rs b/vulkano/src/pipeline/layout/sys.rs index 73f77861..fd551bd8 100644 --- a/vulkano/src/pipeline/layout/sys.rs +++ b/vulkano/src/pipeline/layout/sys.rs @@ -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, layout: ash::vk::PipelineLayout, - descriptor_set_layouts: SmallVec<[Arc; 16]>, + descriptor_set_layouts: SmallVec<[Arc; 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> { + pub fn descriptor_set_layout(&self, index: usize) -> Option<&Arc> { 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 }; diff --git a/vulkano/src/pipeline/shader.rs b/vulkano/src/pipeline/shader.rs index 2ca0ab24..2b33bb81 100644 --- a/vulkano/src/pipeline/shader.rs +++ b/vulkano/src/pipeline/shader.rs @@ -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 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 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 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", + } + ) + } +} diff --git a/vulkano/src/swapchain/capabilities.rs b/vulkano/src/swapchain/capabilities.rs index b0850965..54154fed 100644 --- a/vulkano/src/swapchain/capabilities.rs +++ b/vulkano/src/swapchain/capabilities.rs @@ -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 . /// /// > **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