mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-25 00:04:15 +00:00
Descriptor sets are working
This commit is contained in:
parent
0fe6c0f23d
commit
3ebaaca45d
@ -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();
|
||||
|
@ -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<_>>();
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
layout(location = 0) in vec2 position;
|
||||
|
||||
uniform Data {
|
||||
layout(set = 0, binding = 0) uniform Data {
|
||||
mat4 worldview;
|
||||
} uniforms;
|
||||
|
||||
|
@ -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<_>>();
|
||||
|
@ -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>>)
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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>),
|
||||
}
|
||||
|
@ -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> {
|
||||
|
Loading…
Reference in New Issue
Block a user