Descriptor sets are working

This commit is contained in:
Pierre Krieger 2016-02-20 14:40:50 +01:00
parent 0fe6c0f23d
commit 3ebaaca45d
9 changed files with 200 additions and 37 deletions

View File

@ -242,6 +242,10 @@ fn write_descriptor_sets(doc: &parse::Spirv) -> String {
pub struct Set1;
unsafe impl ::vulkano::descriptor_set::DescriptorSetDesc for Set1 {
type Write = ::std::sync::Arc<::vulkano::buffer::BufferResource>;
type Init = ::std::sync::Arc<::vulkano::buffer::BufferResource>;
fn descriptors(&self) -> Vec<::vulkano::descriptor_set::DescriptorDesc> {
vec![
::vulkano::descriptor_set::DescriptorDesc {
@ -252,6 +256,21 @@ unsafe impl ::vulkano::descriptor_set::DescriptorSetDesc for Set1 {
}
]
}
fn decode_write(&self, write: Self::Write) -> Vec<::vulkano::descriptor_set::DescriptorWrite> {
vec![
::vulkano::descriptor_set::DescriptorWrite {
binding: 0,
array_element: 0,
content: ::vulkano::descriptor_set::DescriptorBind::UniformBuffer(write),
}
]
}
#[inline]
fn decode_init(&self, write: Self::Init) -> Vec<::vulkano::descriptor_set::DescriptorWrite> {
self.decode_write(write)
}
}
#[derive(Default)]
@ -269,6 +288,14 @@ unsafe impl ::vulkano::descriptor_set::PipelineLayoutDesc for Layout {
layouts
]
}
fn decode_descriptor_sets(&self, sets: Self::DescriptorSets)
-> Vec<::std::sync::Arc<::vulkano::descriptor_set::AbstractDescriptorSet>>
{
vec![
sets
]
}
}
"#.to_owned();

View File

@ -18,7 +18,7 @@ fn main() {
// TODO: for the moment the AMD driver crashes if you don't pass an ApplicationInfo, but in theory it's optional
let app = vulkano::instance::ApplicationInfo { application_name: "test", application_version: 1, engine_name: "test", engine_version: 1 };
let instance = vulkano::instance::Instance::new(Some(&app), &["VK_LAYER_LUNARG_draw_state"]).expect("failed to create instance");
let instance = vulkano::instance::Instance::new(Some(&app), &[]).expect("failed to create instance");
let physical = vulkano::instance::PhysicalDevice::enumerate(&instance)
.next().expect("no device available");
@ -33,7 +33,7 @@ fn main() {
let (device, queues) = vulkano::device::Device::new(&physical, physical.supported_features(),
[(queue, 0.5)].iter().cloned(),
&["VK_LAYER_LUNARG_draw_state"])
&[])
.expect("failed to create device");
let queue = queues.into_iter().next().unwrap();
@ -66,6 +66,20 @@ fn main() {
mapping[2].position = [0.25, -0.1];
}
let uniform_buffer = vulkano::buffer::Buffer::<[[f32; 4]; 4], _>
::new(&device, &vulkano::buffer::Usage::all(),
vulkano::memory::HostVisible, &queue)
.expect("failed to create buffer");
{
let mut mapping = uniform_buffer.try_write().unwrap();
*mapping = [
[1.0, 0.0, 0.0, 0.0],
[0.0, 2.0, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0]
];
}
mod vs { include!{concat!(env!("OUT_DIR"), "/examples-teapot_vs.rs")} }
let vs = vs::TeapotShader::load(&device).expect("failed to create shader module");
mod fs { include!{concat!(env!("OUT_DIR"), "/examples-teapot_fs.rs")} }
@ -137,11 +151,12 @@ fn main() {
}).collect::<Vec<_>>();
set.write(uniform_buffer.clone());
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])
.draw(&pipeline, vertex_buffer.clone(), &vulkano::command_buffer::DynamicState::none())
.draw(&pipeline, vertex_buffer.clone(), &vulkano::command_buffer::DynamicState::none(), set.clone())
.draw_end()
.build().unwrap()
}).collect::<Vec<_>>();

View File

@ -5,7 +5,7 @@
layout(location = 0) in vec2 position;
uniform Data {
layout(set = 0, binding = 0) uniform Data {
mat4 worldview;
} uniforms;

View File

@ -162,7 +162,7 @@ fn main() {
}
}.unwrap();
let pipeline: Arc<vulkano::pipeline::GraphicsPipeline<Arc<vulkano::buffer::Buffer<[Vertex; 3], _>>>> = {
let pipeline: Arc<vulkano::pipeline::GraphicsPipeline<Arc<vulkano::buffer::Buffer<[Vertex; 3], _>>, _>> = {
let ia = vulkano::pipeline::input_assembly::InputAssembly {
topology: vulkano::pipeline::input_assembly::PrimitiveTopology::TriangleList,
primitive_restart_enable: false,
@ -190,7 +190,7 @@ fn main() {
};
vulkano::pipeline::GraphicsPipeline::new(&device, &vs.main_entry_point(), &ia, &viewports,
&raster, &ms, &blend, &fs.main_entry_point(),
&raster, &ms, &blend, &fs.main_entry_point(), &vulkano::descriptor_set::PipelineLayout::new(&device, Default::default(), ()).unwrap(),
&renderpass.subpass(0).unwrap()).unwrap()
};
@ -215,7 +215,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])
.draw(&pipeline, vertex_buffer.clone(), &vulkano::command_buffer::DynamicState::none())
.draw(&pipeline, vertex_buffer.clone(), &vulkano::command_buffer::DynamicState::none(), ())
.draw_end()
.build().unwrap()
}).collect::<Vec<_>>();

View File

@ -40,7 +40,10 @@ use VulkanPointers;
use check_errors;
use vk;
pub unsafe trait BufferResource: Resource {
pub unsafe trait BufferResource: Resource + ::VulkanObjectU64 {
/// Returns the size of the buffer in bytes.
fn size(&self) -> usize;
/// Instructs the resource that it is going to be used by the GPU soon in the future. The
/// function should block if the memory is currently being accessed by the CPU.
///
@ -302,6 +305,11 @@ unsafe impl<T: ?Sized, M> Resource for Buffer<T, M> where M: MemorySourceChunk {
}
unsafe impl<T: ?Sized, M> BufferResource for Buffer<T, M> where M: MemorySourceChunk {
#[inline]
fn size(&self) -> usize {
self.inner.size
}
#[inline]
fn gpu_access(&self, write: bool, offset: usize, size: usize, queue: &mut Queue,
fence: Option<Arc<Fence>>, semaphore: Option<Arc<Semaphore>>)

View File

@ -7,6 +7,7 @@ use buffer::BufferSlice;
use buffer::BufferResource;
use command_buffer::CommandBufferPool;
use command_buffer::DynamicState;
use descriptor_set::PipelineLayoutDesc;
use device::Queue;
use framebuffer::ClearValue;
use framebuffer::Framebuffer;
@ -263,14 +264,15 @@ impl InnerCommandBufferBuilder {
/// Calls `vkCmdDraw`.
// FIXME: push constants
pub unsafe fn draw<V: 'static, L: 'static>(mut self, pipeline: &Arc<GraphicsPipeline<V, L>>,
vertices: V, dynamic: &DynamicState) -> InnerCommandBufferBuilder
where V: MultiVertex
vertices: V, dynamic: &DynamicState,
sets: L::DescriptorSets) -> InnerCommandBufferBuilder
where V: MultiVertex, L: PipelineLayoutDesc
{
// FIXME: add buffers to the resources
{
self.bind_gfx_pipeline_state(pipeline, dynamic);
self.bind_gfx_pipeline_state(pipeline, dynamic, sets);
let vk = self.device.pointers();
@ -285,28 +287,40 @@ impl InnerCommandBufferBuilder {
}
fn bind_gfx_pipeline_state<V: 'static, L: 'static>(&mut self, pipeline: &Arc<GraphicsPipeline<V, L>>,
dynamic: &DynamicState)
dynamic: &DynamicState, sets: L::DescriptorSets)
where V: MultiVertex, L: PipelineLayoutDesc
{
let vk = self.device.pointers();
unsafe {
let vk = self.device.pointers();
if self.graphics_pipeline != Some(pipeline.internal_object()) {
unsafe {
if self.graphics_pipeline != Some(pipeline.internal_object()) {
vk.CmdBindPipeline(self.cmd.unwrap(), vk::PIPELINE_BIND_POINT_GRAPHICS,
pipeline.internal_object());
self.pipelines.push(pipeline.clone());
self.graphics_pipeline = Some(pipeline.internal_object());
}
self.pipelines.push(pipeline.clone());
self.graphics_pipeline = Some(pipeline.internal_object());
}
if let Some(line_width) = dynamic.line_width {
assert!(pipeline.has_dynamic_line_width());
// TODO: check limits
if self.dynamic_state.line_width != Some(line_width) {
unsafe { vk.CmdSetLineWidth(self.cmd.unwrap(), line_width) };
self.dynamic_state.line_width = Some(line_width);
if let Some(line_width) = dynamic.line_width {
assert!(pipeline.has_dynamic_line_width());
// TODO: check limits
if self.dynamic_state.line_width != Some(line_width) {
vk.CmdSetLineWidth(self.cmd.unwrap(), line_width);
self.dynamic_state.line_width = Some(line_width);
}
} else {
assert!(!pipeline.has_dynamic_line_width());
}
// FIXME: keep these alive
let descriptor_sets = pipeline.layout().description().decode_descriptor_sets(sets);
let descriptor_sets = descriptor_sets.into_iter().map(|set| set.internal_object()).collect::<Vec<_>>();
// TODO: shouldn't rebind everything every time
if !descriptor_sets.is_empty() {
vk.CmdBindDescriptorSets(self.cmd.unwrap(), vk::PIPELINE_BIND_POINT_GRAPHICS,
pipeline.layout().internal_object(), 0, descriptor_sets.len() as u32,
descriptor_sets.as_ptr(), 0, ptr::null()); // FIXME: dynamic offsets
}
} else {
assert!(!pipeline.has_dynamic_line_width());
}
}

View File

@ -5,6 +5,7 @@ use buffer::BufferSlice;
use command_buffer::CommandBufferPool;
use command_buffer::inner::InnerCommandBufferBuilder;
use command_buffer::inner::InnerCommandBuffer;
use descriptor_set::PipelineLayoutDesc;
use device::Queue;
use framebuffer::Framebuffer;
use framebuffer::RenderPass;
@ -198,12 +199,13 @@ impl PrimaryCommandBufferBuilderInlineDraw {
/// Calls `vkCmdDraw`.
// FIXME: push constants
pub fn draw<V, L>(self, pipeline: &Arc<GraphicsPipeline<V, L>>,
vertices: V, dynamic: &DynamicState) -> PrimaryCommandBufferBuilderInlineDraw
where V: MultiVertex + 'static, L: 'static
vertices: V, dynamic: &DynamicState, sets: L::DescriptorSets)
-> PrimaryCommandBufferBuilderInlineDraw
where V: MultiVertex + 'static, L: PipelineLayoutDesc + 'static
{
unsafe {
PrimaryCommandBufferBuilderInlineDraw {
inner: self.inner.draw(pipeline, vertices, dynamic),
inner: self.inner.draw(pipeline, vertices, dynamic, sets),
num_subpasses: self.num_subpasses,
current_subpass: self.current_subpass,
}

View File

@ -23,6 +23,7 @@ use std::mem;
use std::ptr;
use std::sync::Arc;
use buffer::BufferResource;
use device::Device;
use OomError;
@ -31,7 +32,7 @@ use VulkanPointers;
use check_errors;
use vk;
/// Types that describe the layout of a pipeline (descriptor sets and push constants).
pub unsafe trait PipelineLayoutDesc {
type DescriptorSets; // example: (Arc<DescriptorSet<Layout1>>, Arc<DescriptorSet<Layout2>>) where Layout1 and Layout2 implement DescriptorSetDesc
type DescriptorSetLayouts; // example: (Arc<DescriptorSetLayout<Layout1>>, Arc<DescriptorSetLayout<Layout2>>) where Layout1 and Layout2 implement DescriptorSetDesc
@ -39,19 +40,37 @@ pub unsafe trait PipelineLayoutDesc {
fn decode_descriptor_set_layouts(&self, Self::DescriptorSetLayouts) -> Vec<Arc<AbstractDescriptorSetLayout>>;
fn decode_descriptor_sets(&self, Self::DescriptorSets) -> Vec<Arc<AbstractDescriptorSet>>;
// FIXME: implement this correctly
fn is_compatible_with<P>(&self, _: &P) -> bool where P: PipelineLayoutDesc { true }
}
/// Description of a descriptor.
///
/// A descriptor is a single entry in the list of resources accessible by a shader. This struct
/// describes it the resource that can be binded to it.
#[derive(Debug, Copy, Clone, Default)]
pub struct EmptyPipelineDesc;
unsafe impl PipelineLayoutDesc for EmptyPipelineDesc {
type DescriptorSets = ();
type DescriptorSetLayouts = ();
type PushConstants = ();
fn decode_descriptor_set_layouts(&self, _: Self::DescriptorSetLayouts) -> Vec<Arc<AbstractDescriptorSetLayout>> { vec![] }
fn decode_descriptor_sets(&self, _: Self::DescriptorSets) -> Vec<Arc<AbstractDescriptorSet>> { vec![] }
}
/// Types that describe a single descriptor set.
pub unsafe trait DescriptorSetDesc {
type Write;
type Init;
fn descriptors(&self) -> Vec<DescriptorDesc>; // TODO: Cow for better perfs
// FIXME: implement this correctly
fn is_compatible_with<S>(&self, _: &S) -> bool where S: DescriptorSetDesc { true }
fn decode_write(&self, Self::Write) -> Vec<DescriptorWrite>;
fn decode_init(&self, Self::Init) -> Vec<DescriptorWrite>;
}
pub struct DescriptorDesc {
@ -194,7 +213,7 @@ pub struct DescriptorSet<S> {
layout: Arc<DescriptorSetLayout<S>>,
}
impl<S> DescriptorSet<S> {
impl<S> DescriptorSet<S> where S: DescriptorSetDesc {
///
/// # Panic
///
@ -228,8 +247,62 @@ impl<S> DescriptorSet<S> {
layout: layout.clone(),
}))
}
pub fn write(&self, write: S::Write) {
let vk = self.pool.device.pointers();
let write = self.layout.description().decode_write(write);
// FIXME: store resources in the descriptor set so that they aren't destroyed
// TODO: the architecture of this function is going to be tricky
let buffer_descriptors = write.iter().enumerate().map(|(num, write)| {
match write.content {
DescriptorBind::UniformBuffer(ref buffer) => {
Some(vk::DescriptorBufferInfo {
buffer: buffer.internal_object(),
offset: 0, // FIXME: allow buffer slices
range: buffer.size() as u64, // FIXME: allow buffer slices
})
},
}
}).collect::<Vec<_>>();
let vk_writes = write.iter().enumerate().map(|(num, write)| {
vk::WriteDescriptorSet {
sType: vk::STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
pNext: ptr::null(),
dstSet: self.set,
dstBinding: write.binding,
dstArrayElement: write.array_element,
descriptorCount: 1,
descriptorType: vk::DESCRIPTOR_TYPE_UNIFORM_BUFFER, // FIXME:
pImageInfo: ptr::null(), // FIXME:
pBufferInfo: if let Some(ref b) = buffer_descriptors[num] { b } else { ptr::null() },
pTexelBufferView: ptr::null(), // FIXME:
}
}).collect::<Vec<_>>();
unsafe {
vk.UpdateDescriptorSets(self.pool.device.internal_object(), vk_writes.len() as u32,
vk_writes.as_ptr(), 0, ptr::null());
}
}
}
impl<S> VulkanObject for DescriptorSet<S> {
type Object = vk::DescriptorSet;
#[inline]
fn internal_object(&self) -> vk::DescriptorSet {
self.set
}
}
/// Trait that is implemented on all `DescriptorSet` objects.
pub unsafe trait AbstractDescriptorSet: ::VulkanObjectU64 {}
unsafe impl<S> AbstractDescriptorSet for DescriptorSet<S> {}
pub struct DescriptorSetLayout<S> {
layout: vk::DescriptorSetLayout,
device: Arc<Device>,
@ -313,9 +386,9 @@ impl<P> PipelineLayout<P> where P: PipelineLayoutDesc {
let vk = device.pointers();
let layouts = description.decode_descriptor_set_layouts(layouts);
let layouts_ids = layouts.clone().into_iter().map(|l| {
let layouts_ids = layouts.iter().map(|l| {
// FIXME: check that they belong to the same device
::VulkanObjectU64::internal_object(&*l)
::VulkanObjectU64::internal_object(&**l)
}).collect::<Vec<_>>();
let layout = unsafe {
@ -342,6 +415,11 @@ impl<P> PipelineLayout<P> where P: PipelineLayoutDesc {
layouts: layouts,
}))
}
#[inline]
pub fn description(&self) -> &P {
&self.description
}
}
impl<P> VulkanObject for PipelineLayout<P> {
@ -392,3 +470,16 @@ 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<BufferResource>),
}

View File

@ -296,6 +296,12 @@ impl<MV, L> GraphicsPipeline<MV, L>
marker: PhantomData,
}))
}
/// Returns the pipeline layout used in the constructor.
#[inline]
pub fn layout(&self) -> &Arc<PipelineLayout<L>> {
&self.layout
}
}
impl<MultiVertex, Layout> GraphicsPipeline<MultiVertex, Layout> {