mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-25 00:04:15 +00:00
Add support for immutable samplers, some small changes (#1688)
This commit is contained in:
parent
8a9c617a19
commit
ebf3ace481
@ -113,7 +113,14 @@ fn main() {
|
||||
}
|
||||
}
|
||||
let shader = cs::Shader::load(device.clone()).unwrap();
|
||||
ComputePipeline::new(device.clone(), &shader.main_entry_point(), &(), None).unwrap()
|
||||
ComputePipeline::new(
|
||||
device.clone(),
|
||||
&shader.main_entry_point(),
|
||||
&(),
|
||||
None,
|
||||
|_| {},
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
// We start by creating the buffer that will store the data.
|
||||
@ -144,15 +151,9 @@ fn main() {
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
|
||||
|
||||
set_builder
|
||||
.add_buffer(data_buffer.clone())
|
||||
.unwrap();
|
||||
set_builder.add_buffer(data_buffer.clone()).unwrap();
|
||||
|
||||
let set = Arc::new(
|
||||
set_builder
|
||||
.build()
|
||||
.unwrap()
|
||||
);
|
||||
let set = Arc::new(set_builder.build().unwrap());
|
||||
|
||||
// In order to execute our operation, we have to build a command buffer.
|
||||
let mut builder = AutoCommandBufferBuilder::primary(
|
||||
|
@ -18,17 +18,13 @@ use std::mem;
|
||||
use std::sync::Arc;
|
||||
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
|
||||
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage};
|
||||
use vulkano::descriptor_set::layout::{DescriptorSetDesc, DescriptorSetLayout};
|
||||
use vulkano::descriptor_set::{DescriptorSet, PersistentDescriptorSet};
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
use vulkano::device::{Device, DeviceExtensions, Features};
|
||||
use vulkano::instance::{Instance, InstanceExtensions};
|
||||
use vulkano::pipeline::layout::PipelineLayout;
|
||||
use vulkano::pipeline::shader::EntryPointAbstract;
|
||||
use vulkano::pipeline::{ComputePipeline, PipelineBindPoint};
|
||||
use vulkano::sync;
|
||||
use vulkano::sync::GpuFuture;
|
||||
use vulkano::descriptor_set::layout::DescriptorSetLayoutError;
|
||||
use vulkano::Version;
|
||||
|
||||
fn main() {
|
||||
@ -101,52 +97,15 @@ fn main() {
|
||||
}
|
||||
|
||||
let shader = shader::Shader::load(device.clone()).unwrap();
|
||||
|
||||
// For Graphics pipelines, use the `with_auto_layout` method
|
||||
// instead of the `build` method to specify dynamic buffers.
|
||||
// `with_auto_layout` will automatically handle tweaking the
|
||||
// pipeline.
|
||||
let pipeline = Arc::new(
|
||||
ComputePipeline::with_pipeline_layout(
|
||||
ComputePipeline::new(
|
||||
device.clone(),
|
||||
&shader.main_entry_point(),
|
||||
&(),
|
||||
{
|
||||
let mut descriptor_set_layout_descs: Vec<_> = shader
|
||||
.main_entry_point()
|
||||
.descriptor_set_layout_descs()
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
DescriptorSetDesc::tweak_multiple(
|
||||
&mut descriptor_set_layout_descs,
|
||||
[(0, 0)], // The dynamic uniform buffer is at set 0, descriptor 0
|
||||
);
|
||||
let descriptor_set_layouts = descriptor_set_layout_descs
|
||||
.into_iter()
|
||||
.map(|desc| {
|
||||
Ok(Arc::new(DescriptorSetLayout::new(
|
||||
device.clone(),
|
||||
desc.clone(),
|
||||
)?))
|
||||
})
|
||||
.collect::<Result<Vec<_>, DescriptorSetLayoutError>>()
|
||||
.unwrap();
|
||||
|
||||
Arc::new(
|
||||
PipelineLayout::new(
|
||||
device.clone(),
|
||||
descriptor_set_layouts,
|
||||
shader
|
||||
.main_entry_point()
|
||||
.push_constant_range()
|
||||
.iter()
|
||||
.cloned(),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
},
|
||||
None,
|
||||
|set_descs| {
|
||||
set_descs[0].set_buffer_dynamic(0);
|
||||
},
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
@ -207,11 +166,7 @@ fn main() {
|
||||
.add_buffer(output_buffer.clone())
|
||||
.unwrap();
|
||||
|
||||
let set = Arc::new(
|
||||
set_builder
|
||||
.build()
|
||||
.unwrap()
|
||||
);
|
||||
let set = Arc::new(set_builder.build().unwrap());
|
||||
|
||||
// Build the command buffer, using different offsets for each call.
|
||||
let mut builder = AutoCommandBufferBuilder::primary(
|
||||
|
@ -180,6 +180,7 @@ fn main() {
|
||||
&shader.main_entry_point(),
|
||||
&spec_consts,
|
||||
None,
|
||||
|_| {},
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
@ -200,15 +201,9 @@ fn main() {
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
|
||||
|
||||
set_builder
|
||||
.add_image(view.clone())
|
||||
.unwrap();
|
||||
set_builder.add_image(view.clone()).unwrap();
|
||||
|
||||
let set = Arc::new(
|
||||
set_builder
|
||||
.build()
|
||||
.unwrap()
|
||||
);
|
||||
let set = Arc::new(set_builder.build().unwrap());
|
||||
|
||||
let buf = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
|
@ -90,7 +90,14 @@ void main() {
|
||||
}
|
||||
}
|
||||
let shader = cs::Shader::load(device.clone()).unwrap();
|
||||
ComputePipeline::new(device.clone(), &shader.main_entry_point(), &(), None).unwrap()
|
||||
ComputePipeline::new(
|
||||
device.clone(),
|
||||
&shader.main_entry_point(),
|
||||
&(),
|
||||
None,
|
||||
|_| {},
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
let data_buffer = {
|
||||
@ -148,11 +155,7 @@ void main() {
|
||||
.add_buffer(immutable_data_buffer.clone())
|
||||
.unwrap();
|
||||
|
||||
let set = Arc::new(
|
||||
set_builder
|
||||
.build()
|
||||
.unwrap()
|
||||
);
|
||||
let set = Arc::new(set_builder.build().unwrap());
|
||||
|
||||
let mut builder = AutoCommandBufferBuilder::primary(
|
||||
device.clone(),
|
||||
|
BIN
examples/src/bin/immutable-sampler/image_img.png
Normal file
BIN
examples/src/bin/immutable-sampler/image_img.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
390
examples/src/bin/immutable-sampler/main.rs
Normal file
390
examples/src/bin/immutable-sampler/main.rs
Normal file
@ -0,0 +1,390 @@
|
||||
// Copyright (c) 2016 The vulkano developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
|
||||
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
|
||||
// at your option. All files in the project carrying such
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
// An immutable sampler is a sampler that is integrated into the descriptor set layout
|
||||
// (and thus pipeline layout), instead of being written to an individual descriptor set.
|
||||
// Consequently, all descriptor sets with this layout will share the same sampler.
|
||||
//
|
||||
// This example is almost identical to the image example, but with two differences, which have
|
||||
// been commented:
|
||||
// - The sampler is added to the descriptor set layout at pipeline creation.
|
||||
// - No sampler is included when building a descriptor set.
|
||||
|
||||
use png;
|
||||
use std::io::Cursor;
|
||||
use std::sync::Arc;
|
||||
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
|
||||
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
|
||||
use vulkano::descriptor_set::PersistentDescriptorSet;
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
use vulkano::device::{Device, DeviceExtensions, Features};
|
||||
use vulkano::format::Format;
|
||||
use vulkano::image::{
|
||||
view::ImageView, ImageDimensions, ImageUsage, ImmutableImage, MipmapsCount, SwapchainImage,
|
||||
};
|
||||
use vulkano::instance::Instance;
|
||||
use vulkano::pipeline::viewport::Viewport;
|
||||
use vulkano::pipeline::{GraphicsPipeline, PipelineBindPoint};
|
||||
use vulkano::render_pass::{Framebuffer, FramebufferAbstract, RenderPass, Subpass};
|
||||
use vulkano::sampler::{Filter, MipmapMode, Sampler, SamplerAddressMode};
|
||||
use vulkano::swapchain;
|
||||
use vulkano::swapchain::{AcquireError, Swapchain, SwapchainCreationError};
|
||||
use vulkano::sync;
|
||||
use vulkano::sync::{FlushError, GpuFuture};
|
||||
use vulkano::Version;
|
||||
use vulkano_win::VkSurfaceBuild;
|
||||
use winit::event::{Event, WindowEvent};
|
||||
use winit::event_loop::{ControlFlow, EventLoop};
|
||||
use winit::window::{Window, WindowBuilder};
|
||||
|
||||
fn main() {
|
||||
let required_extensions = vulkano_win::required_extensions();
|
||||
let instance = Instance::new(None, Version::V1_1, &required_extensions, None).unwrap();
|
||||
|
||||
let event_loop = EventLoop::new();
|
||||
let surface = WindowBuilder::new()
|
||||
.build_vk_surface(&event_loop, instance.clone())
|
||||
.unwrap();
|
||||
|
||||
let device_extensions = DeviceExtensions {
|
||||
khr_swapchain: true,
|
||||
..DeviceExtensions::none()
|
||||
};
|
||||
let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance)
|
||||
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||
.filter_map(|p| {
|
||||
p.queue_families()
|
||||
.find(|&q| q.supports_graphics() && surface.is_supported(q).unwrap_or(false))
|
||||
.map(|q| (p, q))
|
||||
})
|
||||
.min_by_key(|(p, _)| match p.properties().device_type {
|
||||
PhysicalDeviceType::DiscreteGpu => 0,
|
||||
PhysicalDeviceType::IntegratedGpu => 1,
|
||||
PhysicalDeviceType::VirtualGpu => 2,
|
||||
PhysicalDeviceType::Cpu => 3,
|
||||
PhysicalDeviceType::Other => 4,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
println!(
|
||||
"Using device: {} (type: {:?})",
|
||||
physical_device.properties().device_name,
|
||||
physical_device.properties().device_type,
|
||||
);
|
||||
|
||||
let (device, mut queues) = Device::new(
|
||||
physical_device,
|
||||
&Features::none(),
|
||||
&physical_device
|
||||
.required_extensions()
|
||||
.union(&device_extensions),
|
||||
[(queue_family, 0.5)].iter().cloned(),
|
||||
)
|
||||
.unwrap();
|
||||
let queue = queues.next().unwrap();
|
||||
|
||||
let (mut swapchain, images) = {
|
||||
let caps = surface.capabilities(physical_device).unwrap();
|
||||
let composite_alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
||||
let format = caps.supported_formats[0].0;
|
||||
let dimensions: [u32; 2] = surface.window().inner_size().into();
|
||||
|
||||
Swapchain::start(device.clone(), surface.clone())
|
||||
.num_images(caps.min_image_count)
|
||||
.format(format)
|
||||
.dimensions(dimensions)
|
||||
.usage(ImageUsage::color_attachment())
|
||||
.sharing_mode(&queue)
|
||||
.composite_alpha(composite_alpha)
|
||||
.build()
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
struct Vertex {
|
||||
position: [f32; 2],
|
||||
}
|
||||
vulkano::impl_vertex!(Vertex, position);
|
||||
|
||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
false,
|
||||
[
|
||||
Vertex {
|
||||
position: [-0.5, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.5, 0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, -0.5],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.5, 0.5],
|
||||
},
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::Shader::load(device.clone()).unwrap();
|
||||
let fs = fs::Shader::load(device.clone()).unwrap();
|
||||
|
||||
let render_pass = Arc::new(
|
||||
vulkano::single_pass_renderpass!(device.clone(),
|
||||
attachments: {
|
||||
color: {
|
||||
load: Clear,
|
||||
store: Store,
|
||||
format: swapchain.format(),
|
||||
samples: 1,
|
||||
}
|
||||
},
|
||||
pass: {
|
||||
color: [color],
|
||||
depth_stencil: {}
|
||||
}
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let (texture, tex_future) = {
|
||||
let png_bytes = include_bytes!("image_img.png").to_vec();
|
||||
let cursor = Cursor::new(png_bytes);
|
||||
let decoder = png::Decoder::new(cursor);
|
||||
let (info, mut reader) = decoder.read_info().unwrap();
|
||||
let dimensions = ImageDimensions::Dim2d {
|
||||
width: info.width,
|
||||
height: info.height,
|
||||
array_layers: 1,
|
||||
};
|
||||
let mut image_data = Vec::new();
|
||||
image_data.resize((info.width * info.height * 4) as usize, 0);
|
||||
reader.next_frame(&mut image_data).unwrap();
|
||||
|
||||
let (image, future) = ImmutableImage::from_iter(
|
||||
image_data.iter().cloned(),
|
||||
dimensions,
|
||||
MipmapsCount::One,
|
||||
Format::R8G8B8A8_SRGB,
|
||||
queue.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
(ImageView::new(image).unwrap(), future)
|
||||
};
|
||||
|
||||
let sampler = Sampler::new(
|
||||
device.clone(),
|
||||
Filter::Linear,
|
||||
Filter::Linear,
|
||||
MipmapMode::Nearest,
|
||||
SamplerAddressMode::Repeat,
|
||||
SamplerAddressMode::Repeat,
|
||||
SamplerAddressMode::Repeat,
|
||||
0.0,
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let pipeline = Arc::new(
|
||||
GraphicsPipeline::start()
|
||||
.vertex_input_single_buffer::<Vertex>()
|
||||
.vertex_shader(vs.main_entry_point(), ())
|
||||
.triangle_strip()
|
||||
.viewports_dynamic_scissors_irrelevant(1)
|
||||
.fragment_shader(fs.main_entry_point(), ())
|
||||
.blend_alpha_blending()
|
||||
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
|
||||
.with_auto_layout(device.clone(), |set_descs| {
|
||||
// Modify the auto-generated layout by setting an immutable sampler to
|
||||
// set 0 binding 0.
|
||||
set_descs[0].set_immutable_samplers(0, [sampler]);
|
||||
})
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
|
||||
|
||||
// Use `add_image` instead of `add_sampled_image`, since the sampler is already in the layout.
|
||||
set_builder.add_image(texture.clone()).unwrap();
|
||||
|
||||
let set = Arc::new(set_builder.build().unwrap());
|
||||
|
||||
let mut viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [0.0, 0.0],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport);
|
||||
|
||||
let mut recreate_swapchain = false;
|
||||
let mut previous_frame_end = Some(tex_future.boxed());
|
||||
|
||||
event_loop.run(move |event, _, control_flow| match event {
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::CloseRequested,
|
||||
..
|
||||
} => {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
}
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::Resized(_),
|
||||
..
|
||||
} => {
|
||||
recreate_swapchain = true;
|
||||
}
|
||||
Event::RedrawEventsCleared => {
|
||||
previous_frame_end.as_mut().unwrap().cleanup_finished();
|
||||
|
||||
if recreate_swapchain {
|
||||
let dimensions: [u32; 2] = surface.window().inner_size().into();
|
||||
let (new_swapchain, new_images) =
|
||||
match swapchain.recreate().dimensions(dimensions).build() {
|
||||
Ok(r) => r,
|
||||
Err(SwapchainCreationError::UnsupportedDimensions) => return,
|
||||
Err(e) => panic!("Failed to recreate swapchain: {:?}", e),
|
||||
};
|
||||
|
||||
swapchain = new_swapchain;
|
||||
framebuffers =
|
||||
window_size_dependent_setup(&new_images, render_pass.clone(), &mut viewport);
|
||||
recreate_swapchain = false;
|
||||
}
|
||||
|
||||
let (image_num, suboptimal, acquire_future) =
|
||||
match swapchain::acquire_next_image(swapchain.clone(), None) {
|
||||
Ok(r) => r,
|
||||
Err(AcquireError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
return;
|
||||
}
|
||||
Err(e) => panic!("Failed to acquire next image: {:?}", e),
|
||||
};
|
||||
|
||||
if suboptimal {
|
||||
recreate_swapchain = true;
|
||||
}
|
||||
|
||||
let clear_values = vec![[0.0, 0.0, 1.0, 1.0].into()];
|
||||
let mut builder = AutoCommandBufferBuilder::primary(
|
||||
device.clone(),
|
||||
queue.family(),
|
||||
CommandBufferUsage::OneTimeSubmit,
|
||||
)
|
||||
.unwrap();
|
||||
builder
|
||||
.begin_render_pass(
|
||||
framebuffers[image_num].clone(),
|
||||
SubpassContents::Inline,
|
||||
clear_values,
|
||||
)
|
||||
.unwrap()
|
||||
.set_viewport(0, [viewport.clone()])
|
||||
.bind_pipeline_graphics(pipeline.clone())
|
||||
.bind_descriptor_sets(
|
||||
PipelineBindPoint::Graphics,
|
||||
pipeline.layout().clone(),
|
||||
0,
|
||||
set.clone(),
|
||||
)
|
||||
.bind_vertex_buffers(0, vertex_buffer.clone())
|
||||
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
||||
.unwrap()
|
||||
.end_render_pass()
|
||||
.unwrap();
|
||||
let command_buffer = builder.build().unwrap();
|
||||
|
||||
let future = previous_frame_end
|
||||
.take()
|
||||
.unwrap()
|
||||
.join(acquire_future)
|
||||
.then_execute(queue.clone(), command_buffer)
|
||||
.unwrap()
|
||||
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
|
||||
.then_signal_fence_and_flush();
|
||||
|
||||
match future {
|
||||
Ok(future) => {
|
||||
previous_frame_end = Some(future.boxed());
|
||||
}
|
||||
Err(FlushError::OutOfDate) => {
|
||||
recreate_swapchain = true;
|
||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Failed to flush future: {:?}", e);
|
||||
previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
});
|
||||
}
|
||||
|
||||
/// This method is called once during initialization, then again whenever the window is resized
|
||||
fn window_size_dependent_setup(
|
||||
images: &[Arc<SwapchainImage<Window>>],
|
||||
render_pass: Arc<RenderPass>,
|
||||
viewport: &mut Viewport,
|
||||
) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
|
||||
let dimensions = images[0].dimensions();
|
||||
viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32];
|
||||
|
||||
images
|
||||
.iter()
|
||||
.map(|image| {
|
||||
let view = ImageView::new(image.clone()).unwrap();
|
||||
Arc::new(
|
||||
Framebuffer::start(render_pass.clone())
|
||||
.add(view)
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap(),
|
||||
) as Arc<dyn FramebufferAbstract + Send + Sync>
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
mod vs {
|
||||
vulkano_shaders::shader! {
|
||||
ty: "vertex",
|
||||
src: "
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 position;
|
||||
layout(location = 0) out vec2 tex_coords;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(position, 0.0, 1.0);
|
||||
tex_coords = position + vec2(0.5);
|
||||
}"
|
||||
}
|
||||
}
|
||||
|
||||
mod fs {
|
||||
vulkano_shaders::shader! {
|
||||
ty: "fragment",
|
||||
src: "
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 tex_coords;
|
||||
layout(location = 0) out vec4 f_color;
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D tex;
|
||||
|
||||
void main() {
|
||||
f_color = texture(tex, tex_coords);
|
||||
}"
|
||||
}
|
||||
}
|
@ -210,8 +210,9 @@ fn main() {
|
||||
CpuBufferPool::new(device.clone(), BufferUsage::all());
|
||||
let vertex_pool: CpuBufferPool<Vertex> = CpuBufferPool::new(device.clone(), BufferUsage::all());
|
||||
|
||||
let compute_pipeline =
|
||||
Arc::new(ComputePipeline::new(device.clone(), &cs.main_entry_point(), &(), None).unwrap());
|
||||
let compute_pipeline = Arc::new(
|
||||
ComputePipeline::new(device.clone(), &cs.main_entry_point(), &(), None, |_| {}).unwrap(),
|
||||
);
|
||||
|
||||
let render_pass = Arc::new(
|
||||
single_pass_renderpass!(
|
||||
@ -306,20 +307,24 @@ fn main() {
|
||||
|
||||
// Allocate a GPU buffer to hold the arguments for this frames draw call. The compute
|
||||
// shader will only update vertex_count, so set the other parameters correctly here.
|
||||
let indirect_args = Arc::new(indirect_args_pool
|
||||
.chunk(iter::once(DrawIndirectCommand {
|
||||
vertex_count: 0,
|
||||
instance_count: 1,
|
||||
first_vertex: 0,
|
||||
first_instance: 0,
|
||||
}))
|
||||
.unwrap());
|
||||
let indirect_args = Arc::new(
|
||||
indirect_args_pool
|
||||
.chunk(iter::once(DrawIndirectCommand {
|
||||
vertex_count: 0,
|
||||
instance_count: 1,
|
||||
first_vertex: 0,
|
||||
first_instance: 0,
|
||||
}))
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
// Allocate a GPU buffer to hold this frames vertices. This needs to be large enough to hold
|
||||
// the worst case number of vertices generated by the compute shader
|
||||
let vertices = Arc::new(vertex_pool
|
||||
.chunk((0..(6 * 16)).map(|_| Vertex { position: [0.0; 2] }))
|
||||
.unwrap());
|
||||
let vertices = Arc::new(
|
||||
vertex_pool
|
||||
.chunk((0..(6 * 16)).map(|_| Vertex { position: [0.0; 2] }))
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
// Pass the two buffers to the compute shader
|
||||
let layout = compute_pipeline
|
||||
@ -335,11 +340,7 @@ fn main() {
|
||||
.add_buffer(indirect_args.clone())
|
||||
.unwrap();
|
||||
|
||||
let cs_desciptor_set = Arc::new(
|
||||
cs_desciptor_set_builder
|
||||
.build()
|
||||
.unwrap()
|
||||
);
|
||||
let cs_desciptor_set = Arc::new(cs_desciptor_set_builder.build().unwrap());
|
||||
|
||||
let mut builder = AutoCommandBufferBuilder::primary(
|
||||
device.clone(),
|
||||
|
@ -119,6 +119,7 @@ fn main() {
|
||||
&shader.main_entry_point(),
|
||||
&(),
|
||||
Some(pipeline_cache.clone()),
|
||||
|_| {},
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
|
@ -92,7 +92,14 @@ fn main() {
|
||||
|
||||
let shader = cs::Shader::load(device.clone()).unwrap();
|
||||
let pipeline = Arc::new(
|
||||
ComputePipeline::new(device.clone(), &shader.main_entry_point(), &(), None).unwrap(),
|
||||
ComputePipeline::new(
|
||||
device.clone(),
|
||||
&shader.main_entry_point(),
|
||||
&(),
|
||||
None,
|
||||
|_| {},
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let data_buffer = {
|
||||
@ -104,15 +111,9 @@ fn main() {
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
|
||||
|
||||
set_builder
|
||||
.add_buffer(data_buffer.clone())
|
||||
.unwrap();
|
||||
set_builder.add_buffer(data_buffer.clone()).unwrap();
|
||||
|
||||
let set = Arc::new(
|
||||
set_builder
|
||||
.build()
|
||||
.unwrap()
|
||||
);
|
||||
let set = Arc::new(set_builder.build().unwrap());
|
||||
|
||||
// The `vulkano_shaders::shaders!` macro generates a struct with the correct representation of the push constants struct specified in the shader.
|
||||
// Here we create an instance of the generated struct.
|
||||
|
@ -92,7 +92,14 @@ fn main() {
|
||||
}
|
||||
}
|
||||
let shader = cs::Shader::load(device.clone()).unwrap();
|
||||
ComputePipeline::new(device.clone(), &shader.main_entry_point(), &(), None).unwrap()
|
||||
ComputePipeline::new(
|
||||
device.clone(),
|
||||
&shader.main_entry_point(),
|
||||
&(),
|
||||
None,
|
||||
|_| {},
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
let data_buffer = {
|
||||
@ -104,15 +111,9 @@ fn main() {
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
|
||||
|
||||
set_builder
|
||||
.add_buffer(data_buffer.clone())
|
||||
.unwrap();
|
||||
set_builder.add_buffer(data_buffer.clone()).unwrap();
|
||||
|
||||
let set = Arc::new(
|
||||
set_builder
|
||||
.build()
|
||||
.unwrap()
|
||||
);
|
||||
let set = Arc::new(set_builder.build().unwrap());
|
||||
|
||||
let mut builder = AutoCommandBufferBuilder::primary(
|
||||
device.clone(),
|
||||
|
@ -101,6 +101,7 @@ fn main() {
|
||||
&shader.main_entry_point(),
|
||||
&spec_consts,
|
||||
None,
|
||||
|_| {},
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
@ -114,15 +115,9 @@ fn main() {
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
|
||||
|
||||
set_builder
|
||||
.add_buffer(data_buffer.clone())
|
||||
.unwrap();
|
||||
set_builder.add_buffer(data_buffer.clone()).unwrap();
|
||||
|
||||
let set = Arc::new(
|
||||
set_builder
|
||||
.build()
|
||||
.unwrap()
|
||||
);
|
||||
let set = Arc::new(set_builder.build().unwrap());
|
||||
|
||||
let mut builder = AutoCommandBufferBuilder::primary(
|
||||
device.clone(),
|
||||
|
@ -466,20 +466,6 @@ fn descriptor_infos(
|
||||
Some((desc, mutable, 1, false))
|
||||
}
|
||||
_ => {
|
||||
let (ty, mutable) = if force_combined_image_sampled {
|
||||
// VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
|
||||
// Never writable.
|
||||
assert!(sampled, "A combined image sampler must not reference a storage image");
|
||||
(quote! { DescriptorDescTy::CombinedImageSampler }, false) // Sampled images are never mutable.
|
||||
} else {
|
||||
if sampled {
|
||||
// VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE
|
||||
(quote! { DescriptorDescTy::SampledImage }, false) // Sampled images are never mutable.
|
||||
} else {
|
||||
// VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
|
||||
(quote! { DescriptorDescTy::StorageImage }, true)
|
||||
}
|
||||
};
|
||||
let view_type = match (dim, arrayed) {
|
||||
(Dim::Dim1D, false) => quote! { ImageViewType::Dim1d },
|
||||
(Dim::Dim1D, true) => quote! { ImageViewType::Dim1dArray },
|
||||
@ -493,12 +479,45 @@ fn descriptor_infos(
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let desc = quote! {
|
||||
#ty(DescriptorDescImage {
|
||||
let image_desc = quote! {
|
||||
DescriptorDescImage {
|
||||
format: #vulkan_format,
|
||||
multisampled: #ms,
|
||||
view_type: #view_type,
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let (desc, mutable) = if force_combined_image_sampled {
|
||||
// VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
|
||||
// Never writable.
|
||||
assert!(sampled, "A combined image sampler must not reference a storage image");
|
||||
|
||||
(
|
||||
quote! {
|
||||
DescriptorDescTy::CombinedImageSampler {
|
||||
image_desc: #image_desc,
|
||||
immutable_samplers: Vec::new(),
|
||||
}
|
||||
},
|
||||
false, // Sampled images are never mutable.
|
||||
)
|
||||
} else {
|
||||
let (ty, mutable) = if sampled {
|
||||
// VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE
|
||||
(quote! { DescriptorDescTy::SampledImage }, false) // Sampled images are never mutable.
|
||||
} else {
|
||||
// VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
|
||||
(quote! { DescriptorDescTy::StorageImage }, true)
|
||||
};
|
||||
|
||||
(
|
||||
quote! {
|
||||
#ty {
|
||||
image_desc: #image_desc,
|
||||
}
|
||||
},
|
||||
mutable,
|
||||
)
|
||||
};
|
||||
|
||||
Some((desc, mutable, 1, false))
|
||||
@ -514,7 +533,7 @@ fn descriptor_infos(
|
||||
}
|
||||
|
||||
&Instruction::TypeSampler { result_id } if result_id == pointed_ty => {
|
||||
let desc = quote! { DescriptorDescTy::Sampler };
|
||||
let desc = quote! { DescriptorDescTy::Sampler { immutable_samplers: Vec::new() } };
|
||||
Some((desc, false, 1, false))
|
||||
}
|
||||
&Instruction::TypeArray {
|
||||
|
@ -2859,9 +2859,9 @@ impl SyncCommandBufferBuilder {
|
||||
.descriptor_layouts()
|
||||
.expect("descriptor_layouts must return Some when used in an image view");
|
||||
let layout = match desc.ty {
|
||||
DescriptorDescTy::CombinedImageSampler(_) => layouts.combined_image_sampler,
|
||||
DescriptorDescTy::SampledImage(_) => layouts.sampled_image,
|
||||
DescriptorDescTy::StorageImage(_) => layouts.storage_image,
|
||||
DescriptorDescTy::CombinedImageSampler { .. } => layouts.combined_image_sampler,
|
||||
DescriptorDescTy::SampledImage { .. } => layouts.sampled_image,
|
||||
DescriptorDescTy::StorageImage { .. } => layouts.storage_image,
|
||||
DescriptorDescTy::InputAttachment { .. } => {
|
||||
// FIXME: This is tricky. Since we read from the input attachment
|
||||
// and this input attachment is being written in an earlier pass,
|
||||
|
@ -712,7 +712,9 @@ mod tests {
|
||||
DescriptorSetLayout::new(
|
||||
device.clone(),
|
||||
[Some(DescriptorDesc {
|
||||
ty: DescriptorDescTy::Sampler,
|
||||
ty: DescriptorDescTy::Sampler {
|
||||
immutable_samplers: vec![],
|
||||
},
|
||||
descriptor_count: 1,
|
||||
stages: ShaderStages::all(),
|
||||
mutable: false,
|
||||
|
@ -33,15 +33,19 @@ struct BuilderDescriptor {
|
||||
array_element: u32,
|
||||
}
|
||||
|
||||
/// A builder for constructing a new descriptor set.
|
||||
pub struct DescriptorSetBuilder {
|
||||
layout: Arc<DescriptorSetLayout>,
|
||||
in_array: bool,
|
||||
descriptors: Vec<BuilderDescriptor>,
|
||||
cur_binding: usize,
|
||||
cur_binding: u32,
|
||||
resources: DescriptorSetResources,
|
||||
desc_writes: Vec<DescriptorWrite>,
|
||||
}
|
||||
|
||||
/// The output of the descriptor set builder.
|
||||
///
|
||||
/// This is not a descriptor set yet, but can be used to write the descriptors to one.
|
||||
pub struct DescriptorSetBuilderOutput {
|
||||
pub layout: Arc<DescriptorSetLayout>,
|
||||
pub writes: Vec<DescriptorWrite>,
|
||||
@ -49,6 +53,11 @@ pub struct DescriptorSetBuilderOutput {
|
||||
}
|
||||
|
||||
impl DescriptorSetBuilder {
|
||||
/// Starts the process of building a descriptor set. Returns a builder.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// - Panics if the set id is out of range.
|
||||
pub fn start(layout: Arc<DescriptorSetLayout>) -> Self {
|
||||
let mut descriptors = Vec::with_capacity(layout.num_bindings() as usize);
|
||||
let mut desc_writes_capacity = 0;
|
||||
@ -60,11 +69,11 @@ impl DescriptorSetBuilder {
|
||||
if let Some(desc) = layout.descriptor(binding_i) {
|
||||
let descriptor_count = desc.descriptor_count as usize;
|
||||
let (num_bufs, num_imgs, num_samplers) = match desc.ty {
|
||||
DescriptorDescTy::Sampler => (0, 0, 1),
|
||||
DescriptorDescTy::CombinedImageSampler(_) => (0, 1, 1),
|
||||
DescriptorDescTy::SampledImage(_) => (0, 1, 0),
|
||||
DescriptorDescTy::Sampler { .. } => (0, 0, 1),
|
||||
DescriptorDescTy::CombinedImageSampler { .. } => (0, 1, 1),
|
||||
DescriptorDescTy::SampledImage { .. } => (0, 1, 0),
|
||||
DescriptorDescTy::InputAttachment { .. } => (0, 1, 0),
|
||||
DescriptorDescTy::StorageImage(_) => (0, 1, 0),
|
||||
DescriptorDescTy::StorageImage { .. } => (0, 1, 0),
|
||||
DescriptorDescTy::UniformTexelBuffer { .. } => (1, 0, 0),
|
||||
DescriptorDescTy::StorageTexelBuffer { .. } => (1, 0, 0),
|
||||
DescriptorDescTy::UniformBuffer => (1, 0, 0),
|
||||
@ -100,10 +109,11 @@ impl DescriptorSetBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/// Finalizes the building process and returns the generated output.
|
||||
pub fn output(self) -> Result<DescriptorSetBuilderOutput, DescriptorSetError> {
|
||||
if self.cur_binding != self.descriptors.len() {
|
||||
if self.cur_binding != self.descriptors.len() as u32 {
|
||||
Err(DescriptorSetError::DescriptorsMissing {
|
||||
expected: self.descriptors.len(),
|
||||
expected: self.descriptors.len() as u32,
|
||||
obtained: self.cur_binding,
|
||||
})
|
||||
} else {
|
||||
@ -115,12 +125,17 @@ impl DescriptorSetBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/// Call this function if the next element of the set is an array in order to set the value of
|
||||
/// each element.
|
||||
///
|
||||
/// This function can be called even if the descriptor isn't an array, and it is valid to enter
|
||||
/// the "array", add one element, then leave.
|
||||
pub fn enter_array(&mut self) -> Result<(), DescriptorSetError> {
|
||||
if self.in_array {
|
||||
Err(DescriptorSetError::AlreadyInArray)
|
||||
} else if self.cur_binding >= self.descriptors.len() {
|
||||
} else if self.cur_binding >= self.descriptors.len() as u32 {
|
||||
Err(DescriptorSetError::TooManyDescriptors)
|
||||
} else if self.descriptors[self.cur_binding].desc.is_none() {
|
||||
} else if self.descriptors[self.cur_binding as usize].desc.is_none() {
|
||||
Err(DescriptorSetError::DescriptorIsEmpty)
|
||||
} else {
|
||||
self.in_array = true;
|
||||
@ -128,11 +143,12 @@ impl DescriptorSetBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/// Leaves the array. Call this once you added all the elements of the array.
|
||||
pub fn leave_array(&mut self) -> Result<(), DescriptorSetError> {
|
||||
if !self.in_array {
|
||||
Err(DescriptorSetError::NotInArray)
|
||||
} else {
|
||||
let descriptor = &self.descriptors[self.cur_binding];
|
||||
let descriptor = &self.descriptors[self.cur_binding as usize];
|
||||
let inner_desc = match descriptor.desc.as_ref() {
|
||||
Some(some) => some,
|
||||
None => unreachable!(),
|
||||
@ -158,11 +174,12 @@ impl DescriptorSetBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/// Skips the current descriptor if it is empty.
|
||||
pub fn add_empty(&mut self) -> Result<(), DescriptorSetError> {
|
||||
// Should be unreahable as enter_array prevents entering an array for empty descriptors.
|
||||
assert!(!self.in_array);
|
||||
|
||||
if self.descriptors[self.cur_binding].desc.is_some() {
|
||||
if self.descriptors[self.cur_binding as usize].desc.is_some() {
|
||||
return Err(DescriptorSetError::WrongDescriptorType);
|
||||
}
|
||||
|
||||
@ -170,6 +187,7 @@ impl DescriptorSetBuilder {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Binds a buffer as the next descriptor or array element.
|
||||
pub fn add_buffer(
|
||||
&mut self,
|
||||
buffer: Arc<dyn BufferAccess + 'static>,
|
||||
@ -187,7 +205,7 @@ impl DescriptorSetBuilder {
|
||||
false
|
||||
};
|
||||
|
||||
let descriptor = &mut self.descriptors[self.cur_binding];
|
||||
let descriptor = &mut self.descriptors[self.cur_binding as usize];
|
||||
let inner_desc = match descriptor.desc.as_ref() {
|
||||
Some(some) => some,
|
||||
None => return Err(DescriptorSetError::WrongDescriptorType),
|
||||
@ -215,7 +233,7 @@ impl DescriptorSetBuilder {
|
||||
|
||||
unsafe {
|
||||
DescriptorWrite::storage_buffer(
|
||||
self.cur_binding as u32,
|
||||
self.cur_binding,
|
||||
descriptor.array_element,
|
||||
&buffer,
|
||||
)
|
||||
@ -232,7 +250,7 @@ impl DescriptorSetBuilder {
|
||||
|
||||
unsafe {
|
||||
DescriptorWrite::uniform_buffer(
|
||||
self.cur_binding as u32,
|
||||
self.cur_binding,
|
||||
descriptor.array_element,
|
||||
&buffer,
|
||||
)
|
||||
@ -249,7 +267,7 @@ impl DescriptorSetBuilder {
|
||||
|
||||
unsafe {
|
||||
DescriptorWrite::dynamic_uniform_buffer(
|
||||
self.cur_binding as u32,
|
||||
self.cur_binding,
|
||||
descriptor.array_element,
|
||||
&buffer,
|
||||
)
|
||||
@ -258,7 +276,7 @@ impl DescriptorSetBuilder {
|
||||
_ => return Err(DescriptorSetError::WrongDescriptorType),
|
||||
});
|
||||
|
||||
self.resources.add_buffer(self.cur_binding as u32, buffer);
|
||||
self.resources.add_buffer(self.cur_binding, buffer);
|
||||
descriptor.array_element += 1;
|
||||
|
||||
if leave_array {
|
||||
@ -268,6 +286,7 @@ impl DescriptorSetBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/// Binds a buffer view as the next descriptor or array element.
|
||||
pub fn add_buffer_view<B>(&mut self, view: Arc<BufferView<B>>) -> Result<(), DescriptorSetError>
|
||||
where
|
||||
B: BufferAccess + 'static,
|
||||
@ -283,7 +302,7 @@ impl DescriptorSetBuilder {
|
||||
false
|
||||
};
|
||||
|
||||
let descriptor = &mut self.descriptors[self.cur_binding];
|
||||
let descriptor = &mut self.descriptors[self.cur_binding as usize];
|
||||
let inner_desc = match descriptor.desc.as_ref() {
|
||||
Some(some) => some,
|
||||
None => return Err(DescriptorSetError::WrongDescriptorType),
|
||||
@ -300,7 +319,7 @@ impl DescriptorSetBuilder {
|
||||
}
|
||||
|
||||
DescriptorWrite::storage_texel_buffer(
|
||||
self.cur_binding as u32,
|
||||
self.cur_binding,
|
||||
descriptor.array_element,
|
||||
&view,
|
||||
)
|
||||
@ -313,7 +332,7 @@ impl DescriptorSetBuilder {
|
||||
}
|
||||
|
||||
DescriptorWrite::uniform_texel_buffer(
|
||||
self.cur_binding as u32,
|
||||
self.cur_binding,
|
||||
descriptor.array_element,
|
||||
&view,
|
||||
)
|
||||
@ -321,8 +340,7 @@ impl DescriptorSetBuilder {
|
||||
_ => return Err(DescriptorSetError::WrongDescriptorType),
|
||||
});
|
||||
|
||||
self.resources
|
||||
.add_buffer_view(self.cur_binding as u32, view);
|
||||
self.resources.add_buffer_view(self.cur_binding, view);
|
||||
|
||||
if leave_array {
|
||||
self.leave_array()
|
||||
@ -331,6 +349,7 @@ impl DescriptorSetBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/// Binds an image view as the next descriptor or array element.
|
||||
pub fn add_image(
|
||||
&mut self,
|
||||
image_view: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
|
||||
@ -348,43 +367,66 @@ impl DescriptorSetBuilder {
|
||||
false
|
||||
};
|
||||
|
||||
let descriptor = &mut self.descriptors[self.cur_binding];
|
||||
let descriptor = &mut self.descriptors[self.cur_binding as usize];
|
||||
let inner_desc = match descriptor.desc.as_ref() {
|
||||
Some(some) => some,
|
||||
None => return Err(DescriptorSetError::WrongDescriptorType),
|
||||
};
|
||||
|
||||
self.desc_writes.push(match inner_desc.ty {
|
||||
DescriptorDescTy::SampledImage(ref desc) => {
|
||||
self.desc_writes.push(match &inner_desc.ty {
|
||||
DescriptorDescTy::CombinedImageSampler {
|
||||
image_desc,
|
||||
immutable_samplers,
|
||||
} if !immutable_samplers.is_empty() => {
|
||||
if !image_view.image().inner().image.usage().sampled {
|
||||
return Err(DescriptorSetError::MissingImageUsage(
|
||||
MissingImageUsage::Sampled,
|
||||
));
|
||||
}
|
||||
|
||||
image_match_desc(&image_view, &desc)?;
|
||||
if !image_view.can_be_sampled(&immutable_samplers[self.cur_binding as usize]) {
|
||||
return Err(DescriptorSetError::IncompatibleImageViewSampler);
|
||||
}
|
||||
|
||||
image_match_desc(&image_view, image_desc)?;
|
||||
|
||||
DescriptorWrite::combined_image_sampler(
|
||||
self.cur_binding,
|
||||
descriptor.array_element,
|
||||
None,
|
||||
&image_view,
|
||||
)
|
||||
}
|
||||
DescriptorDescTy::SampledImage { ref image_desc, .. } => {
|
||||
if !image_view.image().inner().image.usage().sampled {
|
||||
return Err(DescriptorSetError::MissingImageUsage(
|
||||
MissingImageUsage::Sampled,
|
||||
));
|
||||
}
|
||||
|
||||
image_match_desc(&image_view, image_desc)?;
|
||||
|
||||
DescriptorWrite::sampled_image(
|
||||
self.cur_binding as u32,
|
||||
self.cur_binding,
|
||||
descriptor.array_element,
|
||||
&image_view,
|
||||
)
|
||||
}
|
||||
DescriptorDescTy::StorageImage(ref desc) => {
|
||||
DescriptorDescTy::StorageImage { ref image_desc, .. } => {
|
||||
if !image_view.image().inner().image.usage().storage {
|
||||
return Err(DescriptorSetError::MissingImageUsage(
|
||||
MissingImageUsage::Storage,
|
||||
));
|
||||
}
|
||||
|
||||
image_match_desc(&image_view, &desc)?;
|
||||
image_match_desc(&image_view, image_desc)?;
|
||||
|
||||
if !image_view.component_mapping().is_identity() {
|
||||
return Err(DescriptorSetError::NotIdentitySwizzled);
|
||||
}
|
||||
|
||||
DescriptorWrite::storage_image(
|
||||
self.cur_binding as u32,
|
||||
self.cur_binding,
|
||||
descriptor.array_element,
|
||||
&image_view,
|
||||
)
|
||||
@ -400,7 +442,7 @@ impl DescriptorSetBuilder {
|
||||
return Err(DescriptorSetError::NotIdentitySwizzled);
|
||||
}
|
||||
|
||||
if multisampled && image_view.image().samples() == SampleCount::Sample1 {
|
||||
if *multisampled && image_view.image().samples() == SampleCount::Sample1 {
|
||||
return Err(DescriptorSetError::ExpectedMultisampled);
|
||||
} else if !multisampled && image_view.image().samples() != SampleCount::Sample1 {
|
||||
return Err(DescriptorSetError::UnexpectedMultisampled);
|
||||
@ -414,7 +456,7 @@ impl DescriptorSetBuilder {
|
||||
}
|
||||
|
||||
DescriptorWrite::input_attachment(
|
||||
self.cur_binding as u32,
|
||||
self.cur_binding,
|
||||
descriptor.array_element,
|
||||
&image_view,
|
||||
)
|
||||
@ -423,8 +465,7 @@ impl DescriptorSetBuilder {
|
||||
});
|
||||
|
||||
descriptor.array_element += 1;
|
||||
self.resources
|
||||
.add_image(self.cur_binding as u32, image_view);
|
||||
self.resources.add_image(self.cur_binding, image_view);
|
||||
|
||||
if leave_array {
|
||||
self.leave_array()
|
||||
@ -433,6 +474,10 @@ impl DescriptorSetBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/// Binds an image view with a sampler as the next descriptor or array element.
|
||||
///
|
||||
/// If the descriptor set layout contains immutable samplers for this descriptor, use
|
||||
/// `add_image` instead.
|
||||
pub fn add_sampled_image(
|
||||
&mut self,
|
||||
image_view: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
|
||||
@ -465,20 +510,27 @@ impl DescriptorSetBuilder {
|
||||
false
|
||||
};
|
||||
|
||||
let descriptor = &mut self.descriptors[self.cur_binding];
|
||||
let descriptor = &mut self.descriptors[self.cur_binding as usize];
|
||||
let inner_desc = match descriptor.desc.as_ref() {
|
||||
Some(some) => some,
|
||||
None => return Err(DescriptorSetError::WrongDescriptorType),
|
||||
};
|
||||
|
||||
self.desc_writes.push(match inner_desc.ty {
|
||||
DescriptorDescTy::CombinedImageSampler(ref desc) => {
|
||||
image_match_desc(&image_view, &desc)?;
|
||||
self.desc_writes.push(match &inner_desc.ty {
|
||||
DescriptorDescTy::CombinedImageSampler {
|
||||
image_desc,
|
||||
immutable_samplers,
|
||||
} => {
|
||||
if !immutable_samplers.is_empty() {
|
||||
return Err(DescriptorSetError::SamplerIsImmutable);
|
||||
}
|
||||
|
||||
image_match_desc(&image_view, image_desc)?;
|
||||
|
||||
DescriptorWrite::combined_image_sampler(
|
||||
self.cur_binding as u32,
|
||||
self.cur_binding,
|
||||
descriptor.array_element,
|
||||
&sampler,
|
||||
Some(&sampler),
|
||||
&image_view,
|
||||
)
|
||||
}
|
||||
@ -486,9 +538,8 @@ impl DescriptorSetBuilder {
|
||||
});
|
||||
|
||||
descriptor.array_element += 1;
|
||||
self.resources
|
||||
.add_image(self.cur_binding as u32, image_view);
|
||||
self.resources.add_sampler(self.cur_binding as u32, sampler);
|
||||
self.resources.add_image(self.cur_binding, image_view);
|
||||
self.resources.add_sampler(self.cur_binding, sampler);
|
||||
|
||||
if leave_array {
|
||||
self.leave_array()
|
||||
@ -497,6 +548,7 @@ impl DescriptorSetBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/// Binds a sampler as the next descriptor or array element.
|
||||
pub fn add_sampler(&mut self, sampler: Arc<Sampler>) -> Result<(), DescriptorSetError> {
|
||||
if sampler.device().internal_object() != self.layout.device().internal_object() {
|
||||
return Err(DescriptorSetError::ResourceWrongDevice);
|
||||
@ -509,23 +561,25 @@ impl DescriptorSetBuilder {
|
||||
false
|
||||
};
|
||||
|
||||
let descriptor = &mut self.descriptors[self.cur_binding];
|
||||
let descriptor = &mut self.descriptors[self.cur_binding as usize];
|
||||
let inner_desc = match descriptor.desc.as_ref() {
|
||||
Some(some) => some,
|
||||
None => return Err(DescriptorSetError::WrongDescriptorType),
|
||||
};
|
||||
|
||||
self.desc_writes.push(match inner_desc.ty {
|
||||
DescriptorDescTy::Sampler => DescriptorWrite::sampler(
|
||||
self.cur_binding as u32,
|
||||
descriptor.array_element,
|
||||
&sampler,
|
||||
),
|
||||
self.desc_writes.push(match &inner_desc.ty {
|
||||
DescriptorDescTy::Sampler { immutable_samplers } => {
|
||||
if !immutable_samplers.is_empty() {
|
||||
return Err(DescriptorSetError::SamplerIsImmutable);
|
||||
}
|
||||
|
||||
DescriptorWrite::sampler(self.cur_binding, descriptor.array_element, &sampler)
|
||||
}
|
||||
_ => return Err(DescriptorSetError::WrongDescriptorType),
|
||||
});
|
||||
|
||||
descriptor.array_element += 1;
|
||||
self.resources.add_sampler(self.cur_binding as u32, sampler);
|
||||
self.resources.add_sampler(self.cur_binding, sampler);
|
||||
|
||||
if leave_array {
|
||||
self.leave_array()
|
||||
|
@ -44,12 +44,14 @@
|
||||
use crate::format::Format;
|
||||
use crate::image::view::ImageViewType;
|
||||
use crate::pipeline::shader::ShaderStages;
|
||||
use crate::sampler::Sampler;
|
||||
use crate::sync::AccessFlags;
|
||||
use crate::sync::PipelineStages;
|
||||
use smallvec::SmallVec;
|
||||
use std::cmp;
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct DescriptorSetDesc {
|
||||
@ -87,8 +89,8 @@ impl DescriptorSetDesc {
|
||||
|
||||
/// Returns the descriptor with the given binding number, or `None` if the binding is empty.
|
||||
#[inline]
|
||||
pub fn descriptor(&self, num: usize) -> Option<&DescriptorDesc> {
|
||||
self.descriptors.get(num).and_then(|b| b.as_ref())
|
||||
pub fn descriptor(&self, num: u32) -> Option<&DescriptorDesc> {
|
||||
self.descriptors.get(num as usize).and_then(|b| b.as_ref())
|
||||
}
|
||||
|
||||
/// Builds the union of this layout description and another.
|
||||
@ -136,72 +138,82 @@ impl DescriptorSetDesc {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Transforms a `DescriptorSetDesc`.
|
||||
/// Changes a buffer descriptor's type to dynamic.
|
||||
pub fn set_buffer_dynamic(&mut self, binding_num: u32) {
|
||||
assert!(
|
||||
self.descriptor(binding_num).map_or(false, |desc| matches!(
|
||||
desc.ty,
|
||||
DescriptorDescTy::StorageBuffer | DescriptorDescTy::UniformBuffer
|
||||
)),
|
||||
"tried to make the non-buffer descriptor at binding {} a dynamic buffer",
|
||||
binding_num
|
||||
);
|
||||
|
||||
let binding = self
|
||||
.descriptors
|
||||
.get_mut(binding_num as usize)
|
||||
.and_then(|b| b.as_mut());
|
||||
|
||||
if let Some(desc) = binding {
|
||||
match &desc.ty {
|
||||
DescriptorDescTy::StorageBuffer => {
|
||||
desc.ty = DescriptorDescTy::StorageBufferDynamic;
|
||||
}
|
||||
DescriptorDescTy::UniformBuffer => {
|
||||
desc.ty = DescriptorDescTy::UniformBufferDynamic;
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the immutable samplers for a sampler or combined image sampler descriptor.
|
||||
///
|
||||
/// Used to adjust automatically inferred `DescriptorSetDesc`s with information that cannot be inferred.
|
||||
pub fn tweak<I>(&mut self, dynamic_buffers: I)
|
||||
where
|
||||
I: IntoIterator<Item = usize>,
|
||||
{
|
||||
for binding_num in dynamic_buffers {
|
||||
debug_assert!(
|
||||
self.descriptor(binding_num).map_or(false, |desc| matches!(
|
||||
desc.ty,
|
||||
DescriptorDescTy::StorageBuffer | DescriptorDescTy::UniformBuffer
|
||||
)),
|
||||
"tried to make the non-buffer descriptor at binding {} a dynamic buffer",
|
||||
binding_num
|
||||
);
|
||||
/// # Panics
|
||||
///
|
||||
/// - Panics if the binding number does not refer to a sampler or combined image sampler
|
||||
/// descriptor.
|
||||
pub fn set_immutable_samplers(
|
||||
&mut self,
|
||||
binding_num: u32,
|
||||
samplers: impl IntoIterator<Item = Arc<Sampler>>,
|
||||
) {
|
||||
let immutable_samplers = self
|
||||
.descriptors
|
||||
.get_mut(binding_num as usize)
|
||||
.and_then(|b| b.as_mut())
|
||||
.and_then(|desc| match &mut desc.ty {
|
||||
DescriptorDescTy::Sampler {
|
||||
immutable_samplers, ..
|
||||
}
|
||||
| DescriptorDescTy::CombinedImageSampler {
|
||||
immutable_samplers, ..
|
||||
} => Some(immutable_samplers),
|
||||
_ => None,
|
||||
})
|
||||
.expect("binding_num does not refer to a sampler or combined image sampler descriptor");
|
||||
|
||||
let binding = self
|
||||
.descriptors
|
||||
.get_mut(binding_num)
|
||||
.and_then(|b| b.as_mut());
|
||||
|
||||
if let Some(desc) = binding {
|
||||
match &desc.ty {
|
||||
DescriptorDescTy::StorageBuffer => {
|
||||
desc.ty = DescriptorDescTy::StorageBufferDynamic;
|
||||
}
|
||||
DescriptorDescTy::UniformBuffer => {
|
||||
desc.ty = DescriptorDescTy::UniformBufferDynamic;
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tweak_multiple<I>(sets: &mut [DescriptorSetDesc], dynamic_buffers: I)
|
||||
where
|
||||
I: IntoIterator<Item = (usize, usize)>,
|
||||
{
|
||||
for (set_num, binding_num) in dynamic_buffers {
|
||||
debug_assert!(
|
||||
set_num < sets.len(),
|
||||
"tried to make a dynamic buffer in the nonexistent set {}",
|
||||
set_num,
|
||||
);
|
||||
|
||||
sets.get_mut(set_num).map(|set| set.tweak([binding_num]));
|
||||
}
|
||||
immutable_samplers.clear();
|
||||
immutable_samplers.extend(samplers.into_iter());
|
||||
}
|
||||
|
||||
/// Sets the descriptor count for a descriptor that has a variable count.
|
||||
pub fn set_variable_descriptor_count(&mut self, binding_num: u32, descriptor_count: u32) {
|
||||
// TODO: Errors instead of panic
|
||||
|
||||
match self.descriptors.get_mut(binding_num as usize) {
|
||||
Some(desc_op) => match desc_op.as_mut() {
|
||||
Some(desc) => {
|
||||
if desc.variable_count {
|
||||
desc.descriptor_count = descriptor_count;
|
||||
} else {
|
||||
panic!("descriptor isn't variable count")
|
||||
}
|
||||
match self
|
||||
.descriptors
|
||||
.get_mut(binding_num as usize)
|
||||
.and_then(|b| b.as_mut())
|
||||
{
|
||||
Some(desc) => {
|
||||
if desc.variable_count {
|
||||
desc.descriptor_count = descriptor_count;
|
||||
} else {
|
||||
panic!("descriptor isn't variable count")
|
||||
}
|
||||
None => panic!("descriptor is empty"),
|
||||
},
|
||||
None => panic!("descriptor doesn't exist"),
|
||||
}
|
||||
None => panic!("descriptor is empty"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,7 +224,7 @@ impl DescriptorSetDesc {
|
||||
/// meaning that all descriptors are compatible.
|
||||
#[inline]
|
||||
pub fn is_compatible_with(&self, other: &DescriptorSetDesc) -> bool {
|
||||
let num_bindings = cmp::max(self.descriptors.len(), other.descriptors.len());
|
||||
let num_bindings = cmp::max(self.descriptors.len(), other.descriptors.len()) as u32;
|
||||
(0..num_bindings).all(|binding_num| {
|
||||
match (self.descriptor(binding_num), other.descriptor(binding_num)) {
|
||||
(None, None) => true,
|
||||
@ -235,7 +247,7 @@ impl DescriptorSetDesc {
|
||||
});
|
||||
}
|
||||
|
||||
for binding_num in 0..other.descriptors.len() {
|
||||
for binding_num in 0..other.descriptors.len() as u32 {
|
||||
let self_desc = self.descriptor(binding_num);
|
||||
let other_desc = self.descriptor(binding_num);
|
||||
|
||||
@ -277,7 +289,7 @@ impl DescriptorSetDesc {
|
||||
});
|
||||
}
|
||||
|
||||
for binding_num in 0..other.descriptors.len() {
|
||||
for binding_num in 0..other.descriptors.len() as u32 {
|
||||
let self_desc = self.descriptor(binding_num);
|
||||
let other_desc = self.descriptor(binding_num);
|
||||
|
||||
@ -353,6 +365,7 @@ impl DescriptorDesc {
|
||||
#[inline]
|
||||
pub fn is_compatible_with(&self, other: &DescriptorDesc) -> bool {
|
||||
self.ty.ty() == other.ty.ty()
|
||||
&& self.ty.immutable_samplers() == other.ty.immutable_samplers()
|
||||
&& self.stages == other.stages
|
||||
&& self.descriptor_count == other.descriptor_count
|
||||
&& self.variable_count == other.variable_count
|
||||
@ -455,7 +468,7 @@ impl DescriptorDesc {
|
||||
///use vulkano::descriptor_set::layout::DescriptorDescTy::*;
|
||||
///use vulkano::pipeline::shader::ShaderStages;
|
||||
///
|
||||
///let desc_part1 = DescriptorDesc{ ty: Sampler, descriptor_count: 2, stages: ShaderStages{
|
||||
///let desc_part1 = DescriptorDesc{ ty: Sampler { immutable_samplers: vec![] }, descriptor_count: 2, stages: ShaderStages{
|
||||
/// vertex: true,
|
||||
/// tessellation_control: true,
|
||||
/// tessellation_evaluation: false,
|
||||
@ -464,7 +477,7 @@ impl DescriptorDesc {
|
||||
/// compute: true
|
||||
///}, mutable: true, variable_count: false };
|
||||
///
|
||||
///let desc_part2 = DescriptorDesc{ ty: Sampler, descriptor_count: 1, stages: ShaderStages{
|
||||
///let desc_part2 = DescriptorDesc{ ty: Sampler { immutable_samplers: vec![] }, descriptor_count: 1, stages: ShaderStages{
|
||||
/// vertex: true,
|
||||
/// tessellation_control: false,
|
||||
/// tessellation_evaluation: true,
|
||||
@ -473,7 +486,7 @@ impl DescriptorDesc {
|
||||
/// compute: true
|
||||
///}, mutable: false, variable_count: false };
|
||||
///
|
||||
///let desc_union = DescriptorDesc{ ty: Sampler, descriptor_count: 2, stages: ShaderStages{
|
||||
///let desc_union = DescriptorDesc{ ty: Sampler { immutable_samplers: vec![] }, descriptor_count: 2, stages: ShaderStages{
|
||||
/// vertex: true,
|
||||
/// tessellation_control: true,
|
||||
/// tessellation_evaluation: true,
|
||||
@ -579,10 +592,28 @@ impl From<DescriptorType> for ash::vk::DescriptorType {
|
||||
/// Describes the content and layout of each array element of a descriptor.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum DescriptorDescTy {
|
||||
Sampler, // TODO: the sampler has some restrictions as well
|
||||
CombinedImageSampler(DescriptorDescImage), // TODO: the sampler has some restrictions as well
|
||||
SampledImage(DescriptorDescImage),
|
||||
StorageImage(DescriptorDescImage),
|
||||
Sampler {
|
||||
/// Samplers that are included as a fixed part of the descriptor set layout. Once bound, they
|
||||
/// do not need to be provided when creating a descriptor set.
|
||||
///
|
||||
/// The list must be either empty, or contain exactly `descriptor_count` samplers.
|
||||
immutable_samplers: Vec<Arc<Sampler>>,
|
||||
},
|
||||
CombinedImageSampler {
|
||||
image_desc: DescriptorDescImage,
|
||||
|
||||
/// Samplers that are included as a fixed part of the descriptor set layout. Once bound, they
|
||||
/// do not need to be provided when creating a descriptor set.
|
||||
///
|
||||
/// The list must be either empty, or contain exactly `descriptor_count` samplers.
|
||||
immutable_samplers: Vec<Arc<Sampler>>,
|
||||
},
|
||||
SampledImage {
|
||||
image_desc: DescriptorDescImage,
|
||||
},
|
||||
StorageImage {
|
||||
image_desc: DescriptorDescImage,
|
||||
},
|
||||
UniformTexelBuffer {
|
||||
/// The format of the content, or `None` if the format is unknown. Depending on the
|
||||
/// context, it may be invalid to have a `None` value here. If the format is `Some`, only
|
||||
@ -612,27 +643,63 @@ impl DescriptorDescTy {
|
||||
#[inline]
|
||||
pub fn ty(&self) -> DescriptorType {
|
||||
match *self {
|
||||
DescriptorDescTy::Sampler => DescriptorType::Sampler,
|
||||
DescriptorDescTy::CombinedImageSampler(_) => DescriptorType::CombinedImageSampler,
|
||||
DescriptorDescTy::SampledImage(_) => DescriptorType::SampledImage,
|
||||
DescriptorDescTy::StorageImage(_) => DescriptorType::StorageImage,
|
||||
DescriptorDescTy::UniformTexelBuffer { .. } => DescriptorType::UniformTexelBuffer,
|
||||
DescriptorDescTy::StorageTexelBuffer { .. } => DescriptorType::StorageTexelBuffer,
|
||||
DescriptorDescTy::UniformBuffer => DescriptorType::UniformBuffer,
|
||||
DescriptorDescTy::StorageBuffer => DescriptorType::StorageBuffer,
|
||||
DescriptorDescTy::UniformBufferDynamic => DescriptorType::UniformBufferDynamic,
|
||||
DescriptorDescTy::StorageBufferDynamic => DescriptorType::StorageBufferDynamic,
|
||||
DescriptorDescTy::InputAttachment { .. } => DescriptorType::InputAttachment,
|
||||
Self::Sampler { .. } => DescriptorType::Sampler,
|
||||
Self::CombinedImageSampler { .. } => DescriptorType::CombinedImageSampler,
|
||||
Self::SampledImage { .. } => DescriptorType::SampledImage,
|
||||
Self::StorageImage { .. } => DescriptorType::StorageImage,
|
||||
Self::UniformTexelBuffer { .. } => DescriptorType::UniformTexelBuffer,
|
||||
Self::StorageTexelBuffer { .. } => DescriptorType::StorageTexelBuffer,
|
||||
Self::UniformBuffer => DescriptorType::UniformBuffer,
|
||||
Self::StorageBuffer => DescriptorType::StorageBuffer,
|
||||
Self::UniformBufferDynamic => DescriptorType::UniformBufferDynamic,
|
||||
Self::StorageBufferDynamic => DescriptorType::StorageBufferDynamic,
|
||||
Self::InputAttachment { .. } => DescriptorType::InputAttachment,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn format(&self) -> Option<Format> {
|
||||
match self {
|
||||
Self::UniformTexelBuffer { format } | Self::StorageTexelBuffer { format } => *format,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn image_desc(&self) -> Option<&DescriptorDescImage> {
|
||||
match self {
|
||||
Self::CombinedImageSampler { image_desc, .. }
|
||||
| Self::SampledImage { image_desc, .. }
|
||||
| Self::StorageImage { image_desc, .. } => Some(image_desc),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn immutable_samplers(&self) -> &[Arc<Sampler>] {
|
||||
match self {
|
||||
Self::Sampler {
|
||||
immutable_samplers, ..
|
||||
} => immutable_samplers,
|
||||
Self::CombinedImageSampler {
|
||||
immutable_samplers, ..
|
||||
} => immutable_samplers,
|
||||
_ => &[],
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn multisampled(&self) -> bool {
|
||||
match self {
|
||||
DescriptorDescTy::InputAttachment { multisampled } => *multisampled,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether we are a superset of another descriptor type.
|
||||
// TODO: add example
|
||||
#[inline]
|
||||
pub fn ensure_superset_of(
|
||||
&self,
|
||||
other: &DescriptorDescTy,
|
||||
) -> Result<(), DescriptorCompatibilityError> {
|
||||
pub fn ensure_superset_of(&self, other: &Self) -> Result<(), DescriptorCompatibilityError> {
|
||||
if self.ty() != other.ty() {
|
||||
return Err(DescriptorCompatibilityError::Type {
|
||||
first: self.ty(),
|
||||
@ -640,51 +707,28 @@ impl DescriptorDescTy {
|
||||
});
|
||||
}
|
||||
|
||||
match (self, other) {
|
||||
(
|
||||
DescriptorDescTy::CombinedImageSampler(ref me)
|
||||
| DescriptorDescTy::SampledImage(ref me)
|
||||
| DescriptorDescTy::StorageImage(ref me),
|
||||
DescriptorDescTy::CombinedImageSampler(ref other)
|
||||
| DescriptorDescTy::SampledImage(ref other)
|
||||
| DescriptorDescTy::StorageImage(ref other),
|
||||
) => me.ensure_superset_of(other)?,
|
||||
if self.immutable_samplers() != other.immutable_samplers() {
|
||||
return Err(DescriptorCompatibilityError::ImmutableSamplers);
|
||||
}
|
||||
|
||||
(
|
||||
DescriptorDescTy::UniformTexelBuffer { format: me_format }
|
||||
| DescriptorDescTy::StorageTexelBuffer { format: me_format },
|
||||
DescriptorDescTy::UniformTexelBuffer {
|
||||
format: other_format,
|
||||
}
|
||||
| DescriptorDescTy::StorageTexelBuffer {
|
||||
format: other_format,
|
||||
},
|
||||
) => {
|
||||
if other_format.is_some() && me_format != other_format {
|
||||
return Err(DescriptorCompatibilityError::Format {
|
||||
first: *me_format,
|
||||
second: other_format.unwrap(),
|
||||
});
|
||||
}
|
||||
if let (Some(me), Some(other)) = (self.image_desc(), other.image_desc()) {
|
||||
me.ensure_superset_of(other)?;
|
||||
}
|
||||
|
||||
if let (me, other @ Some(_)) = (self.format(), other.format()) {
|
||||
if me != other {
|
||||
return Err(DescriptorCompatibilityError::Format {
|
||||
first: me,
|
||||
second: other.unwrap(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
(
|
||||
DescriptorDescTy::InputAttachment {
|
||||
multisampled: me_multisampled,
|
||||
},
|
||||
DescriptorDescTy::InputAttachment {
|
||||
multisampled: other_multisampled,
|
||||
},
|
||||
) => {
|
||||
if me_multisampled != other_multisampled {
|
||||
return Err(DescriptorCompatibilityError::Multisampling {
|
||||
first: *me_multisampled,
|
||||
second: *other_multisampled,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_ => (),
|
||||
if self.multisampled() != other.multisampled() {
|
||||
return Err(DescriptorCompatibilityError::Multisampling {
|
||||
first: self.multisampled(),
|
||||
second: other.multisampled(),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -782,46 +826,34 @@ impl fmt::Display for DescriptorSetCompatibilityError {
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum DescriptorCompatibilityError {
|
||||
/// The number of descriptors is not compatible.
|
||||
DescriptorCount {
|
||||
first: u32,
|
||||
second: u32,
|
||||
},
|
||||
DescriptorCount { first: u32, second: u32 },
|
||||
|
||||
/// The variable counts of the descriptors is not compatible.
|
||||
VariableCount {
|
||||
first: bool,
|
||||
second: bool,
|
||||
},
|
||||
VariableCount { first: bool, second: bool },
|
||||
|
||||
/// The presence or absence of a descriptor in a binding is not compatible.
|
||||
Empty {
|
||||
first: bool,
|
||||
second: bool,
|
||||
},
|
||||
Empty { first: bool, second: bool },
|
||||
|
||||
// The formats of an image descriptor are not compatible.
|
||||
/// The formats of an image descriptor are not compatible.
|
||||
Format {
|
||||
first: Option<Format>,
|
||||
second: Format,
|
||||
},
|
||||
|
||||
// The image view types of an image descriptor are not compatible.
|
||||
/// The image view types of an image descriptor are not compatible.
|
||||
ImageViewType {
|
||||
first: ImageViewType,
|
||||
second: ImageViewType,
|
||||
},
|
||||
|
||||
// The multisampling of an image descriptor is not compatible.
|
||||
Multisampling {
|
||||
first: bool,
|
||||
second: bool,
|
||||
},
|
||||
/// The immutable samplers of the descriptors are not compatible.
|
||||
ImmutableSamplers,
|
||||
|
||||
/// The multisampling of an image descriptor is not compatible.
|
||||
Multisampling { first: bool, second: bool },
|
||||
|
||||
/// The mutability of the descriptors is not compatible.
|
||||
Mutability {
|
||||
first: bool,
|
||||
second: bool,
|
||||
},
|
||||
Mutability { first: bool, second: bool },
|
||||
|
||||
/// The shader stages of the descriptors are not compatible.
|
||||
ShaderStages {
|
||||
@ -860,6 +892,9 @@ impl fmt::Display for DescriptorCompatibilityError {
|
||||
DescriptorCompatibilityError::ImageViewType { .. } => {
|
||||
"the image view types of an image descriptor are not compatible"
|
||||
}
|
||||
DescriptorCompatibilityError::ImmutableSamplers { .. } => {
|
||||
"the immutable samplers of the descriptors are not compatible"
|
||||
}
|
||||
DescriptorCompatibilityError::Multisampling { .. } => {
|
||||
"the multisampling of an image descriptor is not compatible"
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ use crate::device::DeviceOwned;
|
||||
use crate::OomError;
|
||||
use crate::Version;
|
||||
use crate::VulkanObject;
|
||||
use smallvec::SmallVec;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
@ -51,9 +50,10 @@ impl DescriptorSetLayout {
|
||||
{
|
||||
let desc = desc.into();
|
||||
let mut descriptors_count = DescriptorsCount::zero();
|
||||
let mut variable_descriptor_count = false;
|
||||
let bindings = desc.bindings();
|
||||
let mut bindings_vk: SmallVec<[_; 32]> = SmallVec::new();
|
||||
let mut bindings_vk = Vec::with_capacity(bindings.len());
|
||||
let mut binding_flags_vk = Vec::with_capacity(bindings.len());
|
||||
let mut immutable_samplers_vk: Vec<Box<[ash::vk::Sampler]>> = Vec::new(); // only to keep the arrays of handles alive
|
||||
|
||||
for (binding, desc) in bindings.iter().enumerate() {
|
||||
let desc = match desc {
|
||||
@ -66,6 +66,33 @@ impl DescriptorSetLayout {
|
||||
|
||||
let ty = desc.ty.ty();
|
||||
descriptors_count.add_num(ty, desc.descriptor_count);
|
||||
let mut binding_flags = ash::vk::DescriptorBindingFlags::empty();
|
||||
let immutable_samplers = desc.ty.immutable_samplers();
|
||||
|
||||
let p_immutable_samplers = if !immutable_samplers.is_empty() {
|
||||
if desc.descriptor_count != immutable_samplers.len() as u32 {
|
||||
return Err(DescriptorSetLayoutError::ImmutableSamplersCountMismatch {
|
||||
descriptor_count: desc.descriptor_count,
|
||||
sampler_count: immutable_samplers.len() as u32,
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: VUID-VkDescriptorSetLayoutBinding-pImmutableSamplers-04009
|
||||
// The sampler objects indicated by pImmutableSamplers must not have a borderColor
|
||||
// with one of the values VK_BORDER_COLOR_FLOAT_CUSTOM_EXT or
|
||||
// VK_BORDER_COLOR_INT_CUSTOM_EXT
|
||||
|
||||
let sampler_handles = immutable_samplers
|
||||
.iter()
|
||||
.map(|s| s.internal_object())
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice();
|
||||
let p_immutable_samplers = sampler_handles.as_ptr();
|
||||
immutable_samplers_vk.push(sampler_handles);
|
||||
p_immutable_samplers
|
||||
} else {
|
||||
ptr::null()
|
||||
};
|
||||
|
||||
if desc.variable_count {
|
||||
if binding != bindings.len() - 1 {
|
||||
@ -78,48 +105,16 @@ impl DescriptorSetLayout {
|
||||
return Err(DescriptorSetLayoutError::VariableCountDescMustNotBeDynamic);
|
||||
}
|
||||
|
||||
variable_descriptor_count = true;
|
||||
}
|
||||
|
||||
bindings_vk.push(ash::vk::DescriptorSetLayoutBinding {
|
||||
binding: binding as u32,
|
||||
descriptor_type: ty.into(),
|
||||
descriptor_count: desc.descriptor_count,
|
||||
stage_flags: desc.stages.into(),
|
||||
p_immutable_samplers: ptr::null(), // FIXME: not yet implemented
|
||||
});
|
||||
}
|
||||
|
||||
// Note that it seems legal to have no descriptor at all in the set.
|
||||
|
||||
let handle = unsafe {
|
||||
if variable_descriptor_count {
|
||||
let enabled_features = device.enabled_features();
|
||||
let api_version = device.api_version();
|
||||
let enabled_extensions = device.enabled_extensions();
|
||||
|
||||
if api_version.major < 1 {
|
||||
return Err(DescriptorSetLayoutError::VariableCountIncompatibleDevice(
|
||||
IncompatibleDevice::InsufficientApiVersion {
|
||||
required: Version::major_minor(1, 1),
|
||||
obtained: api_version,
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
if api_version.minor < 2 && !enabled_extensions.ext_descriptor_indexing {
|
||||
return Err(DescriptorSetLayoutError::VariableCountIncompatibleDevice(
|
||||
IncompatibleDevice::MissingExtension(MissingExtension::DescriptorIndexing),
|
||||
));
|
||||
}
|
||||
|
||||
if !enabled_features.runtime_descriptor_array {
|
||||
if !device.enabled_features().runtime_descriptor_array {
|
||||
return Err(DescriptorSetLayoutError::VariableCountIncompatibleDevice(
|
||||
IncompatibleDevice::MissingFeature(MissingFeature::RuntimeDescriptorArray),
|
||||
));
|
||||
}
|
||||
|
||||
if !enabled_features.descriptor_binding_variable_descriptor_count {
|
||||
if !device
|
||||
.enabled_features()
|
||||
.descriptor_binding_variable_descriptor_count
|
||||
{
|
||||
return Err(DescriptorSetLayoutError::VariableCountIncompatibleDevice(
|
||||
IncompatibleDevice::MissingFeature(
|
||||
MissingFeature::DescriptorBindingVariableDescriptorCount,
|
||||
@ -127,7 +122,7 @@ impl DescriptorSetLayout {
|
||||
));
|
||||
}
|
||||
|
||||
if !enabled_features.descriptor_binding_partially_bound {
|
||||
if !device.enabled_features().descriptor_binding_partially_bound {
|
||||
return Err(DescriptorSetLayoutError::VariableCountIncompatibleDevice(
|
||||
IncompatibleDevice::MissingFeature(
|
||||
MissingFeature::DescriptorBindingPartiallyBound,
|
||||
@ -135,58 +130,60 @@ impl DescriptorSetLayout {
|
||||
));
|
||||
}
|
||||
|
||||
let mut flags = vec![ash::vk::DescriptorBindingFlags::empty(); bindings_vk.len()];
|
||||
*flags.last_mut().unwrap() =
|
||||
ash::vk::DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT
|
||||
| ash::vk::DescriptorBindingFlags::PARTIALLY_BOUND;
|
||||
|
||||
let binding_flags = ash::vk::DescriptorSetLayoutBindingFlagsCreateInfo {
|
||||
binding_count: bindings_vk.len() as u32,
|
||||
p_binding_flags: flags.as_ptr(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let infos = ash::vk::DescriptorSetLayoutCreateInfo {
|
||||
flags: ash::vk::DescriptorSetLayoutCreateFlags::empty(),
|
||||
binding_count: bindings_vk.len() as u32,
|
||||
p_bindings: bindings_vk.as_ptr(),
|
||||
p_next: &binding_flags as *const _ as *const _,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut output = MaybeUninit::uninit();
|
||||
let fns = device.fns();
|
||||
|
||||
check_errors(fns.v1_0.create_descriptor_set_layout(
|
||||
device.internal_object(),
|
||||
&infos,
|
||||
ptr::null(),
|
||||
output.as_mut_ptr(),
|
||||
))
|
||||
.map_err(|e| OomError::from(e))?;
|
||||
|
||||
output.assume_init()
|
||||
} else {
|
||||
let infos = ash::vk::DescriptorSetLayoutCreateInfo {
|
||||
flags: ash::vk::DescriptorSetLayoutCreateFlags::empty(),
|
||||
binding_count: bindings_vk.len() as u32,
|
||||
p_bindings: bindings_vk.as_ptr(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut output = MaybeUninit::uninit();
|
||||
let fns = device.fns();
|
||||
|
||||
check_errors(fns.v1_0.create_descriptor_set_layout(
|
||||
device.internal_object(),
|
||||
&infos,
|
||||
ptr::null(),
|
||||
output.as_mut_ptr(),
|
||||
))
|
||||
.map_err(|e| OomError::from(e))?;
|
||||
|
||||
output.assume_init()
|
||||
// TODO: should these be settable separately by the user?
|
||||
binding_flags |= ash::vk::DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT;
|
||||
binding_flags |= ash::vk::DescriptorBindingFlags::PARTIALLY_BOUND;
|
||||
}
|
||||
|
||||
bindings_vk.push(ash::vk::DescriptorSetLayoutBinding {
|
||||
binding: binding as u32,
|
||||
descriptor_type: ty.into(),
|
||||
descriptor_count: desc.descriptor_count,
|
||||
stage_flags: desc.stages.into(),
|
||||
p_immutable_samplers,
|
||||
});
|
||||
binding_flags_vk.push(binding_flags);
|
||||
}
|
||||
|
||||
// Note that it seems legal to have no descriptor at all in the set.
|
||||
|
||||
let handle = unsafe {
|
||||
let binding_flags_infos = if device.api_version() >= Version::V1_2
|
||||
|| device.enabled_extensions().ext_descriptor_indexing
|
||||
{
|
||||
Some(ash::vk::DescriptorSetLayoutBindingFlagsCreateInfo {
|
||||
binding_count: binding_flags_vk.len() as u32,
|
||||
p_binding_flags: binding_flags_vk.as_ptr(),
|
||||
..Default::default()
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let infos = ash::vk::DescriptorSetLayoutCreateInfo {
|
||||
flags: ash::vk::DescriptorSetLayoutCreateFlags::empty(),
|
||||
binding_count: bindings_vk.len() as u32,
|
||||
p_bindings: bindings_vk.as_ptr(),
|
||||
p_next: if let Some(next) = binding_flags_infos.as_ref() {
|
||||
next as *const _ as *const _
|
||||
} else {
|
||||
ptr::null()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut output = MaybeUninit::uninit();
|
||||
let fns = device.fns();
|
||||
|
||||
check_errors(fns.v1_0.create_descriptor_set_layout(
|
||||
device.internal_object(),
|
||||
&infos,
|
||||
ptr::null(),
|
||||
output.as_mut_ptr(),
|
||||
))
|
||||
.map_err(|e| OomError::from(e))?;
|
||||
|
||||
output.assume_init()
|
||||
};
|
||||
|
||||
Ok(DescriptorSetLayout {
|
||||
@ -283,6 +280,12 @@ pub enum DescriptorSetLayoutError {
|
||||
/// Out of Memory
|
||||
OomError(OomError),
|
||||
|
||||
/// The number of immutable samplers does not match the descriptor count.
|
||||
ImmutableSamplersCountMismatch {
|
||||
descriptor_count: u32,
|
||||
sampler_count: u32,
|
||||
},
|
||||
|
||||
/// Variable count descriptor must be last binding
|
||||
VariableCountDescMustBeLast,
|
||||
|
||||
@ -337,6 +340,8 @@ impl std::fmt::Display for DescriptorSetLayoutError {
|
||||
"{}",
|
||||
match *self {
|
||||
Self::OomError(_) => "out of memory",
|
||||
Self::ImmutableSamplersCountMismatch { .. } =>
|
||||
"the number of immutable samplers does not match the descriptor count",
|
||||
Self::VariableCountDescMustBeLast =>
|
||||
"variable count descriptor must be last binding",
|
||||
Self::VariableCountDescMustNotBeDynamic =>
|
||||
|
@ -298,8 +298,16 @@ pub enum DescriptorSetError {
|
||||
/// Builder is already within an array.
|
||||
AlreadyInArray,
|
||||
|
||||
/// Builder is not in an array.
|
||||
NotInArray,
|
||||
/// The builder has previously return an error and is an unknown state.
|
||||
BuilderPoisoned,
|
||||
|
||||
/// The number of array layers of an image doesn't match what was expected.
|
||||
ArrayLayersMismatch {
|
||||
/// Number of expected array layers for the image.
|
||||
expected: u32,
|
||||
/// Number of array layers of the image that was added.
|
||||
obtained: u32,
|
||||
},
|
||||
|
||||
/// Array doesn't contain the correct amount of descriptors
|
||||
ArrayLengthMismatch {
|
||||
@ -317,29 +325,20 @@ pub enum DescriptorSetError {
|
||||
obtained: u32,
|
||||
},
|
||||
|
||||
/// Builder doesn't expect anymore descriptors
|
||||
TooManyDescriptors,
|
||||
/// Expected a multisampled image, but got a single-sampled image.
|
||||
ExpectedMultisampled,
|
||||
|
||||
/// Operation can not be performed on an empty descriptor.
|
||||
DescriptorIsEmpty,
|
||||
|
||||
/// Not all descriptors have been added.
|
||||
DescriptorsMissing {
|
||||
/// Expected bindings
|
||||
expected: usize,
|
||||
expected: u32,
|
||||
/// Obtained bindings
|
||||
obtained: usize,
|
||||
obtained: u32,
|
||||
},
|
||||
|
||||
/// The buffer is missing the correct usage.
|
||||
MissingBufferUsage(MissingBufferUsage),
|
||||
|
||||
/// The image is missing the correct usage.
|
||||
MissingImageUsage(MissingImageUsage),
|
||||
|
||||
/// Expected one type of resource but got another.
|
||||
WrongDescriptorType,
|
||||
|
||||
/// Resource belongs to another device.
|
||||
ResourceWrongDevice,
|
||||
|
||||
/// The format of an image view doesn't match what was expected.
|
||||
ImageViewFormatMismatch {
|
||||
/// Expected format.
|
||||
@ -356,37 +355,41 @@ pub enum DescriptorSetError {
|
||||
obtained: ImageViewType,
|
||||
},
|
||||
|
||||
/// Expected a multisampled image, but got a single-sampled image.
|
||||
ExpectedMultisampled,
|
||||
/// The image view isn't compatible with the sampler.
|
||||
IncompatibleImageViewSampler,
|
||||
|
||||
/// Expected a single-sampled image, but got a multisampled image.
|
||||
UnexpectedMultisampled,
|
||||
/// The buffer is missing the correct usage.
|
||||
MissingBufferUsage(MissingBufferUsage),
|
||||
|
||||
/// The number of array layers of an image doesn't match what was expected.
|
||||
ArrayLayersMismatch {
|
||||
/// Number of expected array layers for the image.
|
||||
expected: u32,
|
||||
/// Number of array layers of the image that was added.
|
||||
obtained: u32,
|
||||
},
|
||||
/// The image is missing the correct usage.
|
||||
MissingImageUsage(MissingImageUsage),
|
||||
|
||||
/// The image view has a component swizzle that is different from identity.
|
||||
NotIdentitySwizzled,
|
||||
|
||||
/// The image view isn't compatible with the sampler.
|
||||
IncompatibleImageViewSampler,
|
||||
|
||||
/// The builder has previously return an error and is an unknown state.
|
||||
BuilderPoisoned,
|
||||
/// Builder is not in an array.
|
||||
NotInArray,
|
||||
|
||||
/// Out of memory
|
||||
OomError(OomError),
|
||||
|
||||
/// Operation can not be performed on an empty descriptor.
|
||||
DescriptorIsEmpty,
|
||||
/// Resource belongs to another device.
|
||||
ResourceWrongDevice,
|
||||
|
||||
/// Provided a dynamically assigned sampler, but the descriptor has an immutable sampler.
|
||||
SamplerIsImmutable,
|
||||
|
||||
/// Builder doesn't expect anymore descriptors
|
||||
TooManyDescriptors,
|
||||
|
||||
/// Expected a non-arrayed image, but got an arrayed image.
|
||||
UnexpectedArrayed,
|
||||
|
||||
/// Expected a single-sampled image, but got a multisampled image.
|
||||
UnexpectedMultisampled,
|
||||
|
||||
/// Expected one type of resource but got another.
|
||||
WrongDescriptorType,
|
||||
}
|
||||
|
||||
impl From<OomError> for DescriptorSetError {
|
||||
@ -405,36 +408,37 @@ impl fmt::Display for DescriptorSetError {
|
||||
"{}",
|
||||
match *self {
|
||||
Self::AlreadyInArray => "builder is already within an array",
|
||||
Self::NotInArray => "builder is not in an array",
|
||||
Self::ArrayLayersMismatch { .. } =>
|
||||
"the number of array layers of an image doesn't match what was expected",
|
||||
Self::ArrayLengthMismatch { .. } =>
|
||||
"array doesn't contain the correct amount of descriptors",
|
||||
Self::TooManyDescriptors => "builder doesn't expect anymore descriptors",
|
||||
Self::ArrayTooManyDescriptors { .. } =>
|
||||
"runtime array contains too many descriptors",
|
||||
Self::BuilderPoisoned =>
|
||||
"the builder has previously return an error and is an unknown state",
|
||||
Self::DescriptorIsEmpty => "operation can not be performed on an empty descriptor",
|
||||
Self::DescriptorsMissing { .. } => "not all descriptors have been added",
|
||||
Self::MissingBufferUsage(_) => "the buffer is missing the correct usage",
|
||||
Self::MissingImageUsage(_) => "the image is missing the correct usage",
|
||||
Self::WrongDescriptorType => "expected one type of resource but got another",
|
||||
Self::ResourceWrongDevice => "resource belongs to another device",
|
||||
Self::ExpectedMultisampled =>
|
||||
"expected a multisampled image, but got a single-sampled image",
|
||||
Self::ImageViewFormatMismatch { .. } =>
|
||||
"the format of an image view doesn't match what was expected",
|
||||
Self::ImageViewTypeMismatch { .. } =>
|
||||
"the type of an image view doesn't match what was expected",
|
||||
Self::ExpectedMultisampled =>
|
||||
"expected a multisampled image, but got a single-sampled image",
|
||||
Self::UnexpectedMultisampled =>
|
||||
"expected a single-sampled image, but got a multisampled image",
|
||||
Self::ArrayLayersMismatch { .. } =>
|
||||
"the number of array layers of an image doesn't match what was expected",
|
||||
Self::NotIdentitySwizzled =>
|
||||
"the image view has a component swizzle that is different from identity",
|
||||
Self::IncompatibleImageViewSampler =>
|
||||
"the image view isn't compatible with the sampler",
|
||||
Self::BuilderPoisoned =>
|
||||
"the builder has previously return an error and is an unknown state",
|
||||
Self::MissingBufferUsage(_) => "the buffer is missing the correct usage",
|
||||
Self::MissingImageUsage(_) => "the image is missing the correct usage",
|
||||
Self::NotIdentitySwizzled =>
|
||||
"the image view has a component swizzle that is different from identity",
|
||||
Self::NotInArray => "builder is not in an array",
|
||||
Self::OomError(_) => "out of memory",
|
||||
Self::DescriptorIsEmpty => "operation can not be performed on an empty descriptor",
|
||||
Self::ResourceWrongDevice => "resource belongs to another device",
|
||||
Self::SamplerIsImmutable => "provided a dynamically assigned sampler, but the descriptor has an immutable sampler",
|
||||
Self::TooManyDescriptors => "builder doesn't expect anymore descriptors",
|
||||
Self::UnexpectedArrayed => "expected a non-arrayed image, but got an arrayed image",
|
||||
Self::ArrayTooManyDescriptors { .. } =>
|
||||
"runtime array contains too many descriptors",
|
||||
Self::UnexpectedMultisampled =>
|
||||
"expected a single-sampled image, but got a multisampled image",
|
||||
Self::WrongDescriptorType => "expected one type of resource but got another",
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -257,6 +257,9 @@ impl PersistentDescriptorSetBuilder {
|
||||
|
||||
/// Binds an image view with a sampler as the next descriptor.
|
||||
///
|
||||
/// If the descriptor set layout contains immutable samplers for this descriptor, use
|
||||
/// `add_image` instead.
|
||||
///
|
||||
/// An error is returned if the image view isn't compatible with the descriptor.
|
||||
#[inline]
|
||||
pub fn add_sampled_image(
|
||||
|
@ -193,7 +193,9 @@ mod tests {
|
||||
let (device, _) = gfx_dev_and_queue!();
|
||||
|
||||
let desc = DescriptorDesc {
|
||||
ty: DescriptorDescTy::Sampler,
|
||||
ty: DescriptorDescTy::Sampler {
|
||||
immutable_samplers: vec![],
|
||||
},
|
||||
descriptor_count: 1,
|
||||
stages: ShaderStages::all(),
|
||||
mutable: true,
|
||||
|
@ -368,6 +368,9 @@ impl<'a> SingleLayoutDescSetBuilder<'a> {
|
||||
|
||||
/// Binds an image view with a sampler as the next descriptor.
|
||||
///
|
||||
/// If the descriptor set layout contains immutable samplers for this descriptor, use
|
||||
/// `add_image` instead.
|
||||
///
|
||||
/// An error is returned if the image view isn't compatible with the descriptor.
|
||||
#[inline]
|
||||
pub fn add_sampled_image(
|
||||
|
@ -328,7 +328,7 @@ impl DescriptorWrite {
|
||||
pub fn combined_image_sampler<I>(
|
||||
binding: u32,
|
||||
array_element: u32,
|
||||
sampler: &Arc<Sampler>,
|
||||
sampler: Option<&Arc<Sampler>>, // Some for dynamic sampler, None for immutable
|
||||
image_view: &I,
|
||||
) -> DescriptorWrite
|
||||
where
|
||||
@ -344,7 +344,7 @@ impl DescriptorWrite {
|
||||
first_array_element: array_element,
|
||||
inner: smallvec!({
|
||||
DescriptorWriteInner::CombinedImageSampler(
|
||||
sampler.internal_object(),
|
||||
sampler.map(|s| s.internal_object()).unwrap_or_default(),
|
||||
image_view.inner().internal_object(),
|
||||
layouts.combined_image_sampler.into(),
|
||||
)
|
||||
|
@ -296,7 +296,8 @@ mod tests {
|
||||
};
|
||||
|
||||
let pipeline = Arc::new(
|
||||
ComputePipeline::new(device.clone(), &shader, &(), Some(cache.clone())).unwrap(),
|
||||
ComputePipeline::new(device.clone(), &shader, &(), Some(cache.clone()), |_| {})
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let cache_data = cache.get_data().unwrap();
|
||||
@ -382,13 +383,27 @@ mod tests {
|
||||
};
|
||||
|
||||
let pipeline = Arc::new(
|
||||
ComputePipeline::new(device.clone(), &first_shader, &(), Some(cache.clone())).unwrap(),
|
||||
ComputePipeline::new(
|
||||
device.clone(),
|
||||
&first_shader,
|
||||
&(),
|
||||
Some(cache.clone()),
|
||||
|_| {},
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let cache_data = cache.get_data().unwrap();
|
||||
|
||||
let second_pipeline = Arc::new(
|
||||
ComputePipeline::new(device.clone(), &second_shader, &(), Some(cache.clone())).unwrap(),
|
||||
ComputePipeline::new(
|
||||
device.clone(),
|
||||
&second_shader,
|
||||
&(),
|
||||
Some(cache.clone()),
|
||||
|_| {},
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let second_data = cache.get_data().unwrap();
|
||||
@ -436,13 +451,15 @@ mod tests {
|
||||
};
|
||||
|
||||
let pipeline = Arc::new(
|
||||
ComputePipeline::new(device.clone(), &shader, &(), Some(cache.clone())).unwrap(),
|
||||
ComputePipeline::new(device.clone(), &shader, &(), Some(cache.clone()), |_| {})
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let cache_data = cache.get_data().unwrap();
|
||||
|
||||
let second_pipeline = Arc::new(
|
||||
ComputePipeline::new(device.clone(), &shader, &(), Some(cache.clone())).unwrap(),
|
||||
ComputePipeline::new(device.clone(), &shader, &(), Some(cache.clone()), |_| {})
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let second_data = cache.get_data().unwrap();
|
||||
|
@ -8,6 +8,7 @@
|
||||
// according to those terms.
|
||||
|
||||
use crate::check_errors;
|
||||
use crate::descriptor_set::layout::DescriptorSetDesc;
|
||||
use crate::descriptor_set::layout::DescriptorSetLayout;
|
||||
use crate::device::Device;
|
||||
use crate::device::DeviceOwned;
|
||||
@ -51,32 +52,41 @@ struct Inner {
|
||||
|
||||
impl ComputePipeline {
|
||||
/// Builds a new `ComputePipeline`.
|
||||
pub fn new<Cs, Css>(
|
||||
///
|
||||
/// `func` is a closure that is given a mutable reference to the inferred descriptor set
|
||||
/// definitions. This can be used to make changes to the layout before it's created, for example
|
||||
/// to add dynamic buffers or immutable samplers.
|
||||
pub fn new<Cs, Css, F>(
|
||||
device: Arc<Device>,
|
||||
shader: &Cs,
|
||||
spec_constants: &Css,
|
||||
cache: Option<Arc<PipelineCache>>,
|
||||
func: F,
|
||||
) -> Result<ComputePipeline, ComputePipelineCreationError>
|
||||
where
|
||||
Cs: EntryPointAbstract,
|
||||
Css: SpecializationConstants,
|
||||
F: FnOnce(&mut [DescriptorSetDesc]),
|
||||
{
|
||||
let mut descriptor_set_layout_descs = shader.descriptor_set_layout_descs().to_owned();
|
||||
func(&mut descriptor_set_layout_descs);
|
||||
|
||||
let descriptor_set_layouts = descriptor_set_layout_descs
|
||||
.iter()
|
||||
.map(|desc| {
|
||||
Ok(Arc::new(DescriptorSetLayout::new(
|
||||
device.clone(),
|
||||
desc.clone(),
|
||||
)?))
|
||||
})
|
||||
.collect::<Result<Vec<_>, PipelineLayoutCreationError>>()?;
|
||||
let pipeline_layout = Arc::new(PipelineLayout::new(
|
||||
device.clone(),
|
||||
descriptor_set_layouts,
|
||||
shader.push_constant_range().iter().cloned(),
|
||||
)?);
|
||||
|
||||
unsafe {
|
||||
let descriptor_set_layouts = shader
|
||||
.descriptor_set_layout_descs()
|
||||
.iter()
|
||||
.map(|desc| {
|
||||
Ok(Arc::new(DescriptorSetLayout::new(
|
||||
device.clone(),
|
||||
desc.clone(),
|
||||
)?))
|
||||
})
|
||||
.collect::<Result<Vec<_>, PipelineLayoutCreationError>>()?;
|
||||
let pipeline_layout = Arc::new(PipelineLayout::new(
|
||||
device.clone(),
|
||||
descriptor_set_layouts,
|
||||
shader.push_constant_range().iter().cloned(),
|
||||
)?);
|
||||
ComputePipeline::with_unchecked_pipeline_layout(
|
||||
device,
|
||||
shader,
|
||||
@ -460,6 +470,7 @@ mod tests {
|
||||
&shader,
|
||||
&SpecConsts { VALUE: 0x12345678 },
|
||||
None,
|
||||
|_| {},
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
@ -139,18 +139,20 @@ where
|
||||
self,
|
||||
device: Arc<Device>,
|
||||
) -> Result<GraphicsPipeline, GraphicsPipelineCreationError> {
|
||||
self.with_auto_layout(device, &[])
|
||||
self.with_auto_layout(device, |_| {})
|
||||
}
|
||||
|
||||
/// Builds the graphics pipeline, using an inferred pipeline layout with some dynamic buffers.
|
||||
///
|
||||
/// Configures the inferred layout for each descriptor `(set, binding)` in `dynamic_buffers` to accept dynamic
|
||||
/// buffers.
|
||||
pub fn with_auto_layout(
|
||||
/// The same as `new`, but allows you to provide a closure that is given a mutable reference to
|
||||
/// the inferred descriptor set definitions. This can be used to make changes to the layout
|
||||
/// before it's created, for example to add dynamic buffers or immutable samplers.
|
||||
pub fn with_auto_layout<F>(
|
||||
self,
|
||||
device: Arc<Device>,
|
||||
dynamic_buffers: &[(usize, usize)],
|
||||
) -> Result<GraphicsPipeline, GraphicsPipelineCreationError> {
|
||||
func: F,
|
||||
) -> Result<GraphicsPipeline, GraphicsPipelineCreationError>
|
||||
where
|
||||
F: FnOnce(&mut [DescriptorSetDesc]),
|
||||
{
|
||||
let (descriptor_set_layout_descs, push_constant_ranges) = {
|
||||
let stages: SmallVec<[&GraphicsEntryPoint; 5]> = std::array::IntoIter::new([
|
||||
self.vertex_shader.as_ref().map(|s| &s.0),
|
||||
@ -178,10 +180,7 @@ where
|
||||
DescriptorSetDesc::union_multiple(&total, shader.descriptor_set_layout_descs())
|
||||
})
|
||||
.expect("Can't be union'd");
|
||||
DescriptorSetDesc::tweak_multiple(
|
||||
&mut descriptor_set_layout_descs,
|
||||
dynamic_buffers.into_iter().cloned(),
|
||||
);
|
||||
func(&mut descriptor_set_layout_descs);
|
||||
|
||||
// We want to union each push constant range into a set of ranges that do not have intersecting stage flags.
|
||||
// e.g. The range [0, 16) is either made available to Vertex | Fragment or we only make [0, 16) available to
|
||||
|
@ -77,7 +77,7 @@ use std::sync::Arc;
|
||||
|
||||
/// Describes how to retrieve data from an image within a shader.
|
||||
pub struct Sampler {
|
||||
sampler: ash::vk::Sampler,
|
||||
handle: ash::vk::Sampler,
|
||||
device: Arc<Device>,
|
||||
compare_mode: bool,
|
||||
unnormalized: bool,
|
||||
@ -266,10 +266,7 @@ impl Sampler {
|
||||
return Err(SamplerCreationError::SamplerAnisotropyFeatureNotEnabled);
|
||||
}
|
||||
|
||||
let limit = device
|
||||
.physical_device()
|
||||
.properties()
|
||||
.max_sampler_anisotropy;
|
||||
let limit = device.physical_device().properties().max_sampler_anisotropy;
|
||||
if max_anisotropy > limit {
|
||||
return Err(SamplerCreationError::AnisotropyLimitExceeded {
|
||||
requested: max_anisotropy,
|
||||
@ -280,10 +277,7 @@ impl Sampler {
|
||||
|
||||
// Check mip_lod_bias value.
|
||||
{
|
||||
let limit = device
|
||||
.physical_device()
|
||||
.properties()
|
||||
.max_sampler_lod_bias;
|
||||
let limit = device.physical_device().properties().max_sampler_lod_bias;
|
||||
if mip_lod_bias > limit {
|
||||
return Err(SamplerCreationError::MipLodBiasLimitExceeded {
|
||||
requested: mip_lod_bias,
|
||||
@ -322,7 +316,7 @@ impl Sampler {
|
||||
};
|
||||
|
||||
let fns = device.fns();
|
||||
let sampler = unsafe {
|
||||
let handle = unsafe {
|
||||
let infos = ash::vk::SamplerCreateInfo {
|
||||
flags: ash::vk::SamplerCreateFlags::empty(),
|
||||
mag_filter: mag_filter.into(),
|
||||
@ -366,7 +360,7 @@ impl Sampler {
|
||||
};
|
||||
|
||||
Ok(Arc::new(Sampler {
|
||||
sampler: sampler,
|
||||
handle,
|
||||
device: device.clone(),
|
||||
compare_mode: compare.is_some(),
|
||||
unnormalized: false,
|
||||
@ -424,7 +418,7 @@ impl Sampler {
|
||||
(b, None) => b,
|
||||
};
|
||||
|
||||
let sampler = unsafe {
|
||||
let handle = unsafe {
|
||||
let infos = ash::vk::SamplerCreateInfo {
|
||||
flags: ash::vk::SamplerCreateFlags::empty(),
|
||||
mag_filter: filter.into(),
|
||||
@ -458,7 +452,7 @@ impl Sampler {
|
||||
};
|
||||
|
||||
Ok(Arc::new(Sampler {
|
||||
sampler: sampler,
|
||||
handle,
|
||||
device: device.clone(),
|
||||
compare_mode: false,
|
||||
unnormalized: true,
|
||||
@ -530,24 +524,33 @@ unsafe impl VulkanObject for Sampler {
|
||||
|
||||
#[inline]
|
||||
fn internal_object(&self) -> ash::vk::Sampler {
|
||||
self.sampler
|
||||
self.handle
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Sampler {
|
||||
#[inline]
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
write!(fmt, "<Vulkan sampler {:?}>", self.sampler)
|
||||
write!(fmt, "<Vulkan sampler {:?}>", self.handle)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Sampler {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.handle == other.handle
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Sampler {}
|
||||
|
||||
impl Drop for Sampler {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let fns = self.device.fns();
|
||||
fns.v1_0
|
||||
.destroy_sampler(self.device.internal_object(), self.sampler, ptr::null());
|
||||
.destroy_sampler(self.device.internal_object(), self.handle, ptr::null());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user