Better descriptor sets design

This commit is contained in:
Pierre Krieger 2016-02-22 15:09:55 +01:00
parent b155b5bae4
commit 5106b6aa0f
5 changed files with 242 additions and 96 deletions

View File

@ -140,14 +140,26 @@ fn main() {
let descriptor_pool = vulkano::descriptor_set::DescriptorPool::new(&device).unwrap();
let descriptor_set_layout = {
let desc = vulkano::descriptor_set::RuntimeDescriptorSetDesc {
descriptors: vec![
vulkano::descriptor_set::DescriptorDesc {
binding: 0,
ty: vulkano::descriptor_set::DescriptorType::UniformBuffer,
array_count: 1,
stages: vulkano::descriptor_set::ShaderStages::all_graphics(),
}
]
};
let (pipeline_layout, set) = {
let layout1 = vulkano::descriptor_set::DescriptorSetLayout::new(&device, Default::default()).unwrap();
let pipeline_layout = vulkano::descriptor_set::PipelineLayout::new(&device, Default::default(), (layout1.clone(), ())).unwrap();
let set1 = vulkano::descriptor_set::DescriptorSet::new(&descriptor_pool, &layout1, uniform_buffer.clone() as std::sync::Arc<_>).unwrap();
(pipeline_layout, set1)
vulkano::descriptor_set::DescriptorSetLayout::new(&device, desc).unwrap()
};
let pipeline_layout = vulkano::descriptor_set::PipelineLayout::new(&device, vulkano::descriptor_set::RuntimeDesc, vec![descriptor_set_layout.clone()]).unwrap();
let set = vulkano::descriptor_set::DescriptorSet::new(&descriptor_pool, &descriptor_set_layout,
vec![(0, vulkano::descriptor_set::DescriptorBind::UniformBuffer(uniform_buffer.clone()))]).unwrap();
let pipeline = {
let ia = vulkano::pipeline::input_assembly::InputAssembly {
topology: vulkano::pipeline::input_assembly::PrimitiveTopology::TriangleList,
@ -189,7 +201,7 @@ fn main() {
let command_buffers = framebuffers.iter().map(|framebuffer| {
vulkano::command_buffer::PrimaryCommandBufferBuilder::new(&cb_pool).unwrap()
.draw_inline(&renderpass, &framebuffer, ([0.0, 0.0, 1.0, 1.0], 1.0))
.draw_indexed(&pipeline, (vertex_buffer.clone(), normals_buffer.clone()), &index_buffer, &vulkano::command_buffer::DynamicState::none(), (set.clone(), ()))
.draw_indexed(&pipeline, (vertex_buffer.clone(), normals_buffer.clone()), &index_buffer, &vulkano::command_buffer::DynamicState::none(), set.clone())
.draw_end()
.build().unwrap()
}).collect::<Vec<_>>();

View File

@ -8,6 +8,7 @@ use buffer::BufferResource;
use command_buffer::CommandBufferPool;
use command_buffer::DynamicState;
use descriptor_set::PipelineLayoutDesc;
use descriptor_set::DescriptorSetsCollection;
use device::Queue;
use framebuffer::ClearValue;
use framebuffer::Framebuffer;
@ -265,10 +266,11 @@ impl InnerCommandBufferBuilder {
/// Calls `vkCmdDraw`.
// FIXME: push constants
pub unsafe fn draw<V, L>(mut self, pipeline: &Arc<GraphicsPipeline<V, L>>,
pub unsafe fn draw<V, Pl, L>(mut self, pipeline: &Arc<GraphicsPipeline<V, Pl>>,
vertices: V, dynamic: &DynamicState,
sets: L::DescriptorSets) -> InnerCommandBufferBuilder
where V: 'static + MultiVertex, L: 'static + PipelineLayoutDesc
sets: L) -> InnerCommandBufferBuilder
where V: 'static + MultiVertex, L: 'static + DescriptorSetsCollection,
Pl: 'static + PipelineLayoutDesc
{
// FIXME: add buffers to the resources
@ -292,10 +294,11 @@ impl InnerCommandBufferBuilder {
/// Calls `vkCmdDrawIndexed`.
// FIXME: push constants
pub unsafe fn draw_indexed<'a, V, L, I, Ib, IbM>(mut self, pipeline: &Arc<GraphicsPipeline<V, L>>,
pub unsafe fn draw_indexed<'a, V, Pl, L, I, Ib, IbM>(mut self, pipeline: &Arc<GraphicsPipeline<V, Pl>>,
vertices: V, indices: Ib, dynamic: &DynamicState,
sets: L::DescriptorSets) -> InnerCommandBufferBuilder
where V: 'static + MultiVertex, L: 'static + PipelineLayoutDesc,
sets: L) -> InnerCommandBufferBuilder
where V: 'static + MultiVertex, L: 'static + DescriptorSetsCollection,
Pl: 'static + PipelineLayoutDesc,
Ib: Into<BufferSlice<'a, [I], IbM>>, I: 'static + Index, IbM: 'static
{
@ -323,13 +326,16 @@ impl InnerCommandBufferBuilder {
self
}
fn bind_gfx_pipeline_state<V: 'static, L: 'static>(&mut self, pipeline: &Arc<GraphicsPipeline<V, L>>,
dynamic: &DynamicState, sets: L::DescriptorSets)
where V: MultiVertex, L: PipelineLayoutDesc
fn bind_gfx_pipeline_state<V, Pl, L>(&mut self, pipeline: &Arc<GraphicsPipeline<V, Pl>>,
dynamic: &DynamicState, sets: L)
where V: 'static + MultiVertex, L: 'static + DescriptorSetsCollection,
Pl: 'static + PipelineLayoutDesc
{
unsafe {
let vk = self.device.pointers();
assert!(sets.is_compatible_with(pipeline.layout()));
if self.graphics_pipeline != Some(pipeline.internal_object()) {
vk.CmdBindPipeline(self.cmd.unwrap(), vk::PIPELINE_BIND_POINT_GRAPHICS,
pipeline.internal_object());
@ -349,7 +355,8 @@ impl InnerCommandBufferBuilder {
}
// FIXME: keep these alive
let descriptor_sets = pipeline.layout().description().decode_descriptor_sets(sets);
// TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
let descriptor_sets = sets.list().collect::<Vec<_>>();
// TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
let descriptor_sets = descriptor_sets.into_iter().map(|set| set.internal_object()).collect::<Vec<_>>();

View File

@ -6,6 +6,7 @@ use command_buffer::CommandBufferPool;
use command_buffer::inner::InnerCommandBufferBuilder;
use command_buffer::inner::InnerCommandBuffer;
use descriptor_set::PipelineLayoutDesc;
use descriptor_set::DescriptorSetsCollection;
use device::Queue;
use framebuffer::Framebuffer;
use framebuffer::RenderPass;
@ -203,10 +204,11 @@ pub struct PrimaryCommandBufferBuilderInlineDraw {
impl PrimaryCommandBufferBuilderInlineDraw {
/// Calls `vkCmdDraw`.
// FIXME: push constants
pub fn draw<V, L>(self, pipeline: &Arc<GraphicsPipeline<V, L>>,
vertices: V, dynamic: &DynamicState, sets: L::DescriptorSets)
-> PrimaryCommandBufferBuilderInlineDraw
where V: MultiVertex + 'static, L: PipelineLayoutDesc + 'static
pub fn draw<V, L, Pl>(self, pipeline: &Arc<GraphicsPipeline<V, Pl>>,
vertices: V, dynamic: &DynamicState, sets: L)
-> PrimaryCommandBufferBuilderInlineDraw
where V: MultiVertex + 'static, Pl: PipelineLayoutDesc + 'static,
L: DescriptorSetsCollection + 'static
{
unsafe {
PrimaryCommandBufferBuilderInlineDraw {
@ -218,11 +220,12 @@ impl PrimaryCommandBufferBuilderInlineDraw {
}
/// Calls `vkCmdDrawIndexed`.
pub fn draw_indexed<'a, V, L, I, Ib, IbM>(mut self, pipeline: &Arc<GraphicsPipeline<V, L>>,
pub fn draw_indexed<'a, V, L, Pl, I, Ib, IbM>(mut self, pipeline: &Arc<GraphicsPipeline<V, Pl>>,
vertices: V, indices: Ib, dynamic: &DynamicState,
sets: L::DescriptorSets) -> PrimaryCommandBufferBuilderInlineDraw
where V: 'static + MultiVertex, L: 'static + PipelineLayoutDesc,
Ib: Into<BufferSlice<'a, [I], IbM>>, I: 'static + Index, IbM: 'static
sets: L) -> PrimaryCommandBufferBuilderInlineDraw
where V: 'static + MultiVertex, Pl: 'static + PipelineLayoutDesc,
Ib: Into<BufferSlice<'a, [I], IbM>>, I: 'static + Index, IbM: 'static,
L: DescriptorSetsCollection + 'static
{
unsafe {
PrimaryCommandBufferBuilderInlineDraw {

View File

@ -19,7 +19,7 @@
//! # Binding resources
//!
//! In parallel of the pipeline initialization, you have to create a `DescriptorSet<T>`. This
//! struct contains the list of actual resources that will be binded when the pipeline is executed.
//! struct contains the list of actual resources that will be bound when the pipeline is executed.
//! To build a `DescriptorSet<T>`, you need to pass a `DescriptorSetLayout<T>`. The `T` parameter
//! must implement `DescriptorSetDesc` as if the same for both the descriptor set and its layout.
//!
@ -37,6 +37,7 @@
use std::mem;
use std::option::IntoIter as OptionIntoIter;
use std::ptr;
use std::sync::Arc;
@ -63,43 +64,135 @@ pub unsafe trait PipelineLayoutDesc {
type PushConstants;
/// Turns the `DescriptorSets` associated type into something vulkano can understand.
fn decode_descriptor_sets(&self, Self::DescriptorSets) -> Vec<Arc<AbstractDescriptorSet>>;
fn decode_descriptor_sets(&self, Self::DescriptorSets) -> Vec<Arc<AbstractDescriptorSet>>; // TODO: vec is slow
/// Turns the `DescriptorSetLayouts` associated type into something vulkano can understand.
fn decode_descriptor_set_layouts(&self, Self::DescriptorSetLayouts)
-> Vec<Arc<AbstractDescriptorSetLayout>>;
-> Vec<Arc<AbstractDescriptorSetLayout>>; // TODO: vec is slow
// FIXME: implement this correctly
fn is_compatible_with<P>(&self, _: &P) -> bool where P: PipelineLayoutDesc { true }
}
// FIXME: should merge the two and check for collisions instead of making them cohabit
unsafe impl<A, B> PipelineLayoutDesc for (A, B)
where A: PipelineLayoutDesc, B: PipelineLayoutDesc
{
type DescriptorSets = (A::DescriptorSets, B::DescriptorSets);
type DescriptorSetLayouts = (A::DescriptorSetLayouts, B::DescriptorSetLayouts);
type PushConstants = (A::PushConstants, B::PushConstants);
/// FIXME: it should be unsafe to create this struct
pub struct RuntimeDesc;
unsafe impl PipelineLayoutDesc for RuntimeDesc {
type DescriptorSets = Vec<Arc<AbstractDescriptorSet>>;
type DescriptorSetLayouts = Vec<Arc<AbstractDescriptorSetLayout>>;
type PushConstants = ();
#[inline]
fn decode_descriptor_sets(&self, s: Self::DescriptorSets) -> Vec<Arc<AbstractDescriptorSet>> {
let mut a = self.0.decode_descriptor_sets(s.0);
let b = self.1.decode_descriptor_sets(s.1);
a.extend_from_slice(&b);
a
fn decode_descriptor_sets(&self, sets: Self::DescriptorSets) -> Vec<Arc<AbstractDescriptorSet>> {
sets
}
#[inline]
fn decode_descriptor_set_layouts(&self, s: Self::DescriptorSetLayouts)
fn decode_descriptor_set_layouts(&self, layouts: Self::DescriptorSetLayouts)
-> Vec<Arc<AbstractDescriptorSetLayout>>
{
let mut a = self.0.decode_descriptor_set_layouts(s.0);
let b = self.1.decode_descriptor_set_layouts(s.1);
a.extend_from_slice(&b);
a
layouts
}
}
/*
#[macro_export]
macro_rules! pipeline_layout {
(sets: {$($set_name:ident: { $($name:ident : ),* }),*}) => {
mod layout {
use std::sync::Arc;
use $crate::descriptor_set::DescriptorType;
use $crate::descriptor_set::DescriptorDesc;
use $crate::descriptor_set::DescriptorSetDesc;
use $crate::descriptor_set::DescriptorWrite;
use $crate::descriptor_set::DescriptorBind;
use $crate::descriptor_set::PipelineLayout;
use $crate::descriptor_set::PipelineLayoutDesc;
use $crate::descriptor_set::ShaderStages;
use $crate::buffer::BufferResource;
$(
pub struct $set_name;
unsafe impl DescriptorSetDesc for $set_name {
type Write = ( // FIXME: variable number of elems
Arc<BufferResource> // FIXME: strong typing
);
type Init = Self::Write;
#[inline]
fn descriptors(&self) -> Vec<DescriptorDesc> {
let mut binding = 0;
let mut result = Vec::new(); // TODO: with_capacity
//$(
result.push(DescriptorDesc {
binding: binding,
ty: DescriptorType::UniformBuffer, // FIXME:
array_count: 1, // FIXME:
stages: ShaderStages::all_graphics(), // FIXME:
});
binding += 1;
//)* // FIXME: variable number of elems
let _ = binding; // removes a warning
result
}
fn decode_write(&self, data: Self::Write) -> Vec<DescriptorWrite> {
let mut binding = 0;
let mut result = Vec::new(); // TODO: with_capacity
let $($name),* = data;
$(
result.push(DescriptorWrite {
binding: binding,
array_element: 0, // FIXME:
content: DescriptorBind::UniformBuffer($name),
});
binding += 1;
)*
result
}
#[inline]
fn decode_init(&self, data: Self::Init) -> Vec<DescriptorWrite> {
self.decode_write(data)
}
}
)*
pub struct Layout;
unsafe impl PipelineLayoutDesc for Layout {
type DescriptorSets = ($(Arc<DescriptorSet<$set_name>>),*);
type DescriptorSetLayouts = ($(Arc<DescriptorSetLayout<$set_name>>),*);
type PushConstants = ();
#[inline]
fn decode_descriptor_sets(&self, sets: Self::DescriptorSets)
-> Vec<Arc<AbstractDescriptorSet>>
{
let $($set_name),* = sets;
vec![$($set_name as Arc<_>),*]
}
#[inline]
fn decode_descriptor_set_layouts(&self, layouts: Self::DescriptorSetLayouts)
-> Vec<Arc<AbstractDescriptorSetLayout>>
{
let $($set_name),* = layouts;
vec![$($set_name as Arc<_>),*]
}
}
}
}
}*/
/// Dummy implementation of `PipelineLayoutDesc` that describes an empty pipeline.
///
/// The descriptors, descriptor sets and push constants are all `()`. You have to pass `()` when
@ -119,6 +212,26 @@ unsafe impl PipelineLayoutDesc for EmptyPipelineDesc {
-> Vec<Arc<AbstractDescriptorSet>> { vec![] }
}
unsafe impl<A, B> PipelineLayoutDesc for (Arc<DescriptorSet<A>>, Arc<DescriptorSet<B>>)
where A: 'static + DescriptorSetDesc, B: 'static + DescriptorSetDesc
{
type DescriptorSets = (Arc<DescriptorSet<A>>, Arc<DescriptorSet<B>>);
type DescriptorSetLayouts = (Arc<DescriptorSetLayout<A>>, Arc<DescriptorSetLayout<B>>);
type PushConstants = ();
#[inline]
fn decode_descriptor_sets(&self, sets: Self::DescriptorSets) -> Vec<Arc<AbstractDescriptorSet>> {
vec![sets.0, sets.1]
}
#[inline]
fn decode_descriptor_set_layouts(&self, layouts: Self::DescriptorSetLayouts)
-> Vec<Arc<AbstractDescriptorSetLayout>>
{
vec![layouts.0, layouts.1]
}
}
/// 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
@ -129,13 +242,13 @@ pub unsafe trait DescriptorSetDesc {
type Init;
/// Returns the list of descriptors contained in this set.
fn descriptors(&self) -> Vec<DescriptorDesc>; // TODO: Cow for better perfs
fn descriptors(&self) -> Vec<DescriptorDesc>; // TODO: better perfs
/// Turns the `Write` associated type into something vulkano can understand.
fn decode_write(&self, Self::Write) -> Vec<DescriptorWrite>;
fn decode_write(&self, Self::Write) -> Vec<DescriptorWrite>; // TODO: better perfs
/// Turns the `Init` associated type into something vulkano can understand.
fn decode_init(&self, Self::Init) -> Vec<DescriptorWrite>;
fn decode_init(&self, Self::Init) -> Vec<DescriptorWrite>; // TODO: better perfs
// FIXME: implement this correctly
fn is_compatible_with<S>(&self, _: &S) -> bool where S: DescriptorSetDesc { true }
@ -155,6 +268,7 @@ pub enum DescriptorBind {
}
/// Describes a single descriptor.
#[derive(Debug, Copy, Clone)]
pub struct DescriptorDesc {
/// Offset of the binding within the descriptor.
pub binding: u32,
@ -169,7 +283,7 @@ pub struct DescriptorDesc {
pub stages: ShaderStages,
}
/// Describes what kind of resource may later be bind to a descriptor.
/// Describes what kind of resource may later be bound to a descriptor.
// FIXME: add immutable sampler when relevant
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
@ -197,6 +311,7 @@ impl DescriptorType {
}
/// Describes which shader stages have access to a descriptor.
#[derive(Debug, Copy, Clone)]
pub struct ShaderStages {
pub vertex: bool,
pub tessellation_control: bool,
@ -249,55 +364,37 @@ impl Into<vk::ShaderStageFlags> for ShaderStages {
}
}
/*
pub unsafe trait CompatiblePipeline<T> { type Out: PipelineLayoutDesc; }
pub unsafe trait CompatibleSet<T> { type Out: DescriptorSetDesc; }
macro_rules! impl_tuple {
(($in_first:ident $out_first:ident) $(, ($in_rest:ident $out_rest:ident))*) => {
unsafe impl<$in_first, $out_first $(, $in_rest, $out_rest)*>
CompatibleSet<($out_first, $($out_rest,)*)> for ($in_first, $($in_rest,)*)
where $in_first: CompatibleDescriptor<$out_first> $(, $in_rest: CompatibleDescriptor<$out_rest>)*
{
type Out = (
<$in_first as CompatibleDescriptor<$out_first>>::Out,
$(
<$in_rest as CompatibleDescriptor<$out_rest>>::Out,
)*
);
}
unsafe impl<$in_first, $out_first $(, $in_rest, $out_rest)*>
CompatiblePipeline<($out_first, $($out_rest,)*)> for ($in_first, $($in_rest,)*)
where $in_first: CompatibleSet<$out_first> $(, $in_rest: CompatibleSet<$out_rest>)*
{
type Out = (
<$in_first as CompatibleSet<$out_first>>::Out,
$(
<$in_rest as CompatibleSet<$out_rest>>::Out,
)*
);
}
impl_tuple!{$(($in_rest $out_rest)),*}
};
() => ();
/// FIXME: should be unsafe to create this struct
pub struct RuntimeDescriptorSetDesc {
pub descriptors: Vec<DescriptorDesc>,
}
impl_tuple!( (A N), (B O), (C P), (D Q), (E R), (F S), (G T),
(H U), (I V), (J W), (K X), (L Y), (M Z) );
unsafe impl DescriptorSetDesc for RuntimeDescriptorSetDesc {
type Write = Vec<(u32, DescriptorBind)>;
/// If a type `A` can be interpreted as a `T`, then `A` will implement `CompatibleDescriptor<T>`.
trait CompatibleDescriptor<T> { type Out; }
type Init = Vec<(u32, DescriptorBind)>;
impl CompatibleDescriptor<()> for () { type Out = (); }
impl<T> CompatibleDescriptor<()> for T where T: Descriptor { type Out = T; }
impl<T> CompatibleDescriptor<T> for () where T: Descriptor { type Out = T; }
impl<T> CompatibleDescriptor<T> for T where T: Descriptor { type Out = T; }
fn descriptors(&self) -> Vec<DescriptorDesc> {
self.descriptors.clone()
}
fn decode_write(&self, data: Self::Write) -> Vec<DescriptorWrite> {
data.into_iter().map(|(binding, bind)| {
// TODO: check correctness?
DescriptorWrite {
binding: binding,
array_element: 0, // FIXME:
content: bind,
}
}).collect()
}
fn decode_init(&self, data: Self::Init) -> Vec<DescriptorWrite> {
self.decode_write(data)
}
}
pub unsafe trait Descriptor {}*/
/// An actual descriptor set with the resources that are binded to it.
pub struct DescriptorSet<S> {
@ -595,3 +692,28 @@ impl DescriptorPool {
}))
}
}
pub unsafe trait DescriptorSetsCollection {
type Iter: ExactSizeIterator<Item = Arc<AbstractDescriptorSet>>;
fn list(&self) -> Self::Iter;
fn is_compatible_with<P>(&self, pipeline_layout: &Arc<PipelineLayout<P>>) -> bool;
}
unsafe impl<T> DescriptorSetsCollection for Arc<DescriptorSet<T>>
where T: 'static + DescriptorSetDesc
{
type Iter = OptionIntoIter<Arc<AbstractDescriptorSet>>;
#[inline]
fn list(&self) -> Self::Iter {
Some(self.clone() as Arc<_>).into_iter()
}
#[inline]
fn is_compatible_with<P>(&self, pipeline_layout: &Arc<PipelineLayout<P>>) -> bool {
// FIXME:
true
}
}

View File

@ -42,8 +42,8 @@ pub struct GraphicsPipeline<MultiVertex, Layout> {
marker: PhantomData<(MultiVertex,)>
}
impl<MV, Vl, Fl> GraphicsPipeline<MV, (Vl, Fl)>
where MV: MultiVertex
impl<MV, L> GraphicsPipeline<MV, L>
where MV: MultiVertex, L: PipelineLayoutDesc
{
/// Builds a new graphics pipeline object.
///
@ -54,16 +54,18 @@ impl<MV, Vl, Fl> GraphicsPipeline<MV, (Vl, Fl)>
/// - Panicks if the `sample_shading` parameter of `multisample` is not between 0.0 and 1.0.
///
// TODO: check all the device's limits
pub fn new<Vi, Fo, R>
pub fn new<Vi, Fo, R, Vl, Fl>
(device: &Arc<Device>, vertex_shader: &VertexShaderEntryPoint<Vi, Vl>,
input_assembly: &InputAssembly, viewport: &ViewportsState,
raster: &Rasterization, multisample: &Multisample, blend: &Blend,
fragment_shader: &FragmentShaderEntryPoint<Fo, Fl>,
layout: &Arc<PipelineLayout<(Vl, Fl)>>, render_pass: &Subpass<R>)
-> Result<Arc<GraphicsPipeline<MV, (Vl, Fl)>>, OomError>
layout: &Arc<PipelineLayout<L>>, render_pass: &Subpass<R>)
-> Result<Arc<GraphicsPipeline<MV, L>>, OomError>
{
let vk = device.pointers();
// FIXME: check layout compatibility
let pipeline = unsafe {
// TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
let mut dynamic_states: Vec<vk::DynamicState> = Vec::new();