From 9ef4dcaab5b5214c3a31acb0aa0bfe67e223e55c Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Sat, 20 Feb 2016 15:10:49 +0100 Subject: [PATCH] Better docs for descriptor sets --- vulkano-shaders/src/lib.rs | 2 +- vulkano/src/descriptor_set.rs | 159 ++++++++++++++++++++++++---------- 2 files changed, 112 insertions(+), 49 deletions(-) diff --git a/vulkano-shaders/src/lib.rs b/vulkano-shaders/src/lib.rs index 17031f34..1804df10 100644 --- a/vulkano-shaders/src/lib.rs +++ b/vulkano-shaders/src/lib.rs @@ -251,7 +251,7 @@ unsafe impl ::vulkano::descriptor_set::DescriptorSetDesc for Set1 { ::vulkano::descriptor_set::DescriptorDesc { binding: 0, ty: ::vulkano::descriptor_set::DescriptorType::UniformBuffer, - count: 1, + array_count: 1, stages: ::vulkano::descriptor_set::ShaderStages::all_graphics(), } ] diff --git a/vulkano/src/descriptor_set.rs b/vulkano/src/descriptor_set.rs index cd122d2c..3b882a03 100644 --- a/vulkano/src/descriptor_set.rs +++ b/vulkano/src/descriptor_set.rs @@ -1,20 +1,37 @@ +//! Collection of resources accessed by the pipeline. +//! +//! The resources accessed by the pipeline must be accessed through what is called a *descriptor*. +//! Descriptors are grouped in what is called *descriptor sets*. Descriptor sets are also grouped +//! in what is called a *pipeline layout*. +//! +//! # Pipeline initialization +//! +//! In order to build a pipeline object (a `GraphicsPipeline` or a `ComputePipeline`), you have to +//! pass a pointer to a `PipelineLayout` struct. This struct is a wrapper around a Vulkan struct +//! that contains all the data about the descriptor sets and descriptors that will be available +//! in the pipeline. The `T` parameter must implement the `PipelineLayoutDesc` trait and describes +//! the descriptor sets and descriptors on vulkano's side. +//! +//! To build a `PipelineLayout`, you need to pass a collection of `DescriptorSetLayout` structs. +//! A `DescriptorSetLayout` if the equivalent of `PipelineLayout` but for a single descriptor +//! set. The `T` parameter must implement the `DescriptorSetDesc` trait. +//! +//! # Binding resources //! +//! In parallel of the pipeline initialization, you have to create a `DescriptorSet`. This +//! struct contains the list of actual resources that will be binded when the pipeline is executed. +//! To build a `DescriptorSet`, you need to pass a `DescriptorSetLayout`. The `T` parameter +//! must implement `DescriptorSetDesc` as if the same for both the descriptor set and its layout. +//! +//! TODO: describe descriptor set writes +//! +//! # Shader analyser //! -//! How does that work? -//! -//! The shader analyser determines which descriptors are used by each shader and outputs a struct -//! that describes this stuff. This struct implements `PipelineLayoutDesc`. -//! -//! When shaders are grouped together in the pipeline, they are passed through `CompatiblePipeline` -//! to be merged into a single pipeline layout struct. If the descriptors of the various shaders -//! are incompatible, it is detected at that moment. -//! -//! The single struct that represents the layout is stored as a template parameter of the pipeline. -//! It is also stored in the `PipelineLayout` object (which wraps around vulkan's pipeline layout). -//! When you draw, you have to pass a collection of descriptor sets that are compatible with the -//! pipeline layout desc of the pipeline. -//! -//! +//! While you can manually implement the `PipelineLayoutDesc` and `DescriptorSetDesc` traits on +//! your own types, it is encouraged to use the `vulkano-shaders` crate instead. This crate will +//! automatically parse your SPIR-V code and generate structs that implement these traits and +//! describe the pipeline layout to vulkano. + // FIXME: all destructors are missing @@ -34,18 +51,32 @@ use vk; /// Types that describe the layout of a pipeline (descriptor sets and push constants). pub unsafe trait PipelineLayoutDesc { - type DescriptorSets; // example: (Arc>, Arc>) where Layout1 and Layout2 implement DescriptorSetDesc - type DescriptorSetLayouts; // example: (Arc>, Arc>) where Layout1 and Layout2 implement DescriptorSetDesc + /// Represents a collection of `DescriptorSet` structs. A parameter of this type must be + /// passed when you add a draw command to a command buffer that uses this layout. + type DescriptorSets; + + /// Represents a collection of `DescriptorSetLayout` structs. A parameter of this type must + /// be passed when creating a `PipelineLayout` struct. + type DescriptorSetLayouts; + + /// Not yet implemented. Useless for now. type PushConstants; - fn decode_descriptor_set_layouts(&self, Self::DescriptorSetLayouts) -> Vec>; - + /// Turns the `DescriptorSets` associated type into something vulkano can understand. fn decode_descriptor_sets(&self, Self::DescriptorSets) -> Vec>; + /// Turns the `DescriptorSetLayouts` associated type into something vulkano can understand. + fn decode_descriptor_set_layouts(&self, Self::DescriptorSetLayouts) + -> Vec>; + // FIXME: implement this correctly fn is_compatible_with

(&self, _: &P) -> bool where P: PipelineLayoutDesc { true } } +/// Dummy implementation of `PipelineLayoutDesc` that describes an empty pipeline. +/// +/// The descriptors, descriptor sets and push constants are all `()`. You have to pass `()` when +/// drawing when you use a `EmptyPipelineDesc`. #[derive(Debug, Copy, Clone, Default)] pub struct EmptyPipelineDesc; unsafe impl PipelineLayoutDesc for EmptyPipelineDesc { @@ -53,33 +84,65 @@ unsafe impl PipelineLayoutDesc for EmptyPipelineDesc { type DescriptorSetLayouts = (); type PushConstants = (); - fn decode_descriptor_set_layouts(&self, _: Self::DescriptorSetLayouts) -> Vec> { vec![] } - fn decode_descriptor_sets(&self, _: Self::DescriptorSets) -> Vec> { vec![] } + #[inline] + fn decode_descriptor_set_layouts(&self, _: Self::DescriptorSetLayouts) + -> Vec> { vec![] } + #[inline] + fn decode_descriptor_sets(&self, _: Self::DescriptorSets) + -> Vec> { vec![] } } /// Types that describe a single descriptor set. pub unsafe trait DescriptorSetDesc { + /// Represents a modification of a descriptor set. A parameter of this type must be passed + /// when you modify a descriptor set. type Write; + /// type Init; + /// Returns the list of descriptors contained in this set. fn descriptors(&self) -> Vec; // TODO: Cow for better perfs + /// Turns the `Write` associated type into something vulkano can understand. + fn decode_write(&self, Self::Write) -> Vec; + + /// Turns the `Init` associated type into something vulkano can understand. + fn decode_init(&self, Self::Init) -> Vec; + // FIXME: implement this correctly fn is_compatible_with(&self, _: &S) -> bool where S: DescriptorSetDesc { true } - - fn decode_write(&self, Self::Write) -> Vec; - - fn decode_init(&self, Self::Init) -> Vec; } -pub struct DescriptorDesc { +// FIXME: shoud allow multiple array binds at once +pub struct DescriptorWrite { pub binding: u32, + pub array_element: u32, + pub content: DescriptorBind, +} + +// FIXME: incomplete +#[derive(Clone)] // TODO: Debug +pub enum DescriptorBind { + UniformBuffer(Arc), +} + +/// Describes a single descriptor. +pub struct DescriptorDesc { + /// Offset of the binding within the descriptor. + pub binding: u32, + + /// What kind of resource can later be bind to this descriptor. pub ty: DescriptorType, - pub count: u32, + + /// How many array elements this descriptor is made of. + pub array_count: u32, + + /// Which shader stages are going to access this descriptor. pub stages: ShaderStages, } +/// Describes what kind of resource may later be bind to a descriptor. // FIXME: add immutable sampler when relevant #[derive(Debug, Copy, Clone)] #[repr(u32)] @@ -106,6 +169,7 @@ impl DescriptorType { } } +/// Describes which shader stages have access to a descriptor. pub struct ShaderStages { pub vertex: bool, pub tessellation_control: bool, @@ -143,6 +207,7 @@ impl ShaderStages { } } +#[doc(hidden)] impl Into for ShaderStages { #[inline] fn into(self) -> vk::ShaderStageFlags { @@ -207,6 +272,7 @@ impl CompatibleDescriptor for T where T: Descriptor { type Out = T; } pub unsafe trait Descriptor {}*/ +/// An actual descriptor set with the resources that are binded to it. pub struct DescriptorSet { set: vk::DescriptorSet, pool: Arc, @@ -248,9 +314,20 @@ impl DescriptorSet where S: DescriptorSetDesc { })) } + /// Modifies a descriptor set. + /// + /// The parameter depends on your implementation of `DescriptorSetDesc`. + /// + /// This function trusts the implementation of `DescriptorSetDesc` when it comes to making sure + /// that the correct resource type is written to the correct descriptor. pub fn write(&self, write: S::Write) { - let vk = self.pool.device.pointers(); let write = self.layout.description().decode_write(write); + unsafe { self.unchecked_write(write); } + } + + /// Modifies a descriptor set without checking that the writes are correct. + pub unsafe fn unchecked_write(&self, write: Vec) { + let vk = self.pool.device.pointers(); // FIXME: store resources in the descriptor set so that they aren't destroyed @@ -299,10 +376,11 @@ impl VulkanObject for DescriptorSet { } } -/// Trait that is implemented on all `DescriptorSet` objects. +/// Implemented on all `DescriptorSet` objects. Hides the template parameters. pub unsafe trait AbstractDescriptorSet: ::VulkanObjectU64 {} unsafe impl AbstractDescriptorSet for DescriptorSet {} +/// Describes the layout of all descriptors within a descriptor set. pub struct DescriptorSetLayout { layout: vk::DescriptorSetLayout, device: Arc, @@ -319,7 +397,7 @@ impl DescriptorSetLayout where S: DescriptorSetDesc { vk::DescriptorSetLayoutBinding { binding: desc.binding, descriptorType: desc.ty.vk_enum(), - descriptorCount: desc.count, + descriptorCount: desc.array_count, stageFlags: desc.stages.into(), pImmutableSamplers: ptr::null(), // FIXME: not yet implemented } @@ -362,14 +440,11 @@ impl VulkanObject for DescriptorSetLayout { } } -/// Trait that is implemented on all `DescriptorSetLayout` objects. +/// Implemented on all `DescriptorSetLayout` objects. Hides the template parameters. pub unsafe trait AbstractDescriptorSetLayout: ::VulkanObjectU64 {} unsafe impl AbstractDescriptorSetLayout for DescriptorSetLayout {} -/// Represents the layout of all the resources and data that can be binded before drawing and -/// that will be accessible from the shaders. -/// -/// The template parameter represents the descriptor sets. +/// A collection of `DescriptorSetLayout` structs. // TODO: push constants. pub struct PipelineLayout

{ device: Arc, @@ -431,6 +506,7 @@ impl

VulkanObject for PipelineLayout

{ } } +/// Pool from which descriptor sets are allocated from. pub struct DescriptorPool { pool: vk::DescriptorPool, device: Arc, @@ -470,16 +546,3 @@ impl DescriptorPool { })) } } - -// FIXME: shoud allow multiple array binds at once -pub struct DescriptorWrite { - pub binding: u32, - pub array_element: u32, - pub content: DescriptorBind, -} - -// FIXME: incomplete -#[derive(Clone)] // TODO: Debug -pub enum DescriptorBind { - UniformBuffer(Arc), -}