mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-25 08:14:20 +00:00
Support for Runtime Descriptor Arrays (#1674)
This commit is contained in:
parent
f79814c2f2
commit
0a3791c303
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,5 +5,6 @@ examples/**/triangle.png
|
||||
examples/**/mandelbrot.png
|
||||
examples/**/multiview1.png
|
||||
examples/**/multiview2.png
|
||||
examples/**/pipeline_cache.bin
|
||||
.idea
|
||||
*.swp
|
||||
|
@ -142,12 +142,16 @@ fn main() {
|
||||
// If you want to run the pipeline on multiple different buffers, you need to create multiple
|
||||
// descriptor sets that each contain the buffer you want to run the shader on.
|
||||
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();
|
||||
|
||||
let set = Arc::new(
|
||||
PersistentDescriptorSet::start(layout.clone())
|
||||
.add_buffer(data_buffer.clone())
|
||||
.unwrap()
|
||||
set_builder
|
||||
.build()
|
||||
.unwrap(),
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
// In order to execute our operation, we have to build a command buffer.
|
||||
|
@ -110,15 +110,12 @@ impl AmbientLightingSystem {
|
||||
/// result of the deferred pass.
|
||||
/// - `ambient_color` is the color to apply.
|
||||
///
|
||||
pub fn draw<C>(
|
||||
pub fn draw(
|
||||
&self,
|
||||
viewport_dimensions: [u32; 2],
|
||||
color_input: C,
|
||||
color_input: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
|
||||
ambient_color: [f32; 3],
|
||||
) -> SecondaryAutoCommandBuffer
|
||||
where
|
||||
C: ImageViewAbstract + Send + Sync + 'static,
|
||||
{
|
||||
) -> SecondaryAutoCommandBuffer {
|
||||
let push_constants = fs::ty::PushConstants {
|
||||
color: [ambient_color[0], ambient_color[1], ambient_color[2], 1.0],
|
||||
};
|
||||
@ -129,9 +126,13 @@ impl AmbientLightingSystem {
|
||||
.descriptor_set_layouts()
|
||||
.get(0)
|
||||
.unwrap();
|
||||
let descriptor_set = PersistentDescriptorSet::start(layout.clone())
|
||||
let mut descriptor_set_builder = PersistentDescriptorSet::start(layout.clone());
|
||||
|
||||
descriptor_set_builder
|
||||
.add_image(color_input)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let descriptor_set = descriptor_set_builder
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
|
@ -118,18 +118,14 @@ impl DirectionalLightingSystem {
|
||||
/// - `direction` is the direction of the light in world coordinates.
|
||||
/// - `color` is the color to apply.
|
||||
///
|
||||
pub fn draw<C, N>(
|
||||
pub fn draw(
|
||||
&self,
|
||||
viewport_dimensions: [u32; 2],
|
||||
color_input: C,
|
||||
normals_input: N,
|
||||
color_input: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
|
||||
normals_input: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
|
||||
direction: Vector3<f32>,
|
||||
color: [f32; 3],
|
||||
) -> SecondaryAutoCommandBuffer
|
||||
where
|
||||
C: ImageViewAbstract + Send + Sync + 'static,
|
||||
N: ImageViewAbstract + Send + Sync + 'static,
|
||||
{
|
||||
) -> SecondaryAutoCommandBuffer {
|
||||
let push_constants = fs::ty::PushConstants {
|
||||
color: [color[0], color[1], color[2], 1.0],
|
||||
direction: direction.extend(0.0).into(),
|
||||
@ -141,11 +137,15 @@ impl DirectionalLightingSystem {
|
||||
.descriptor_set_layouts()
|
||||
.get(0)
|
||||
.unwrap();
|
||||
let descriptor_set = PersistentDescriptorSet::start(layout.clone())
|
||||
let mut descriptor_set_builder = PersistentDescriptorSet::start(layout.clone());
|
||||
|
||||
descriptor_set_builder
|
||||
.add_image(color_input)
|
||||
.unwrap()
|
||||
.add_image(normals_input)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let descriptor_set = descriptor_set_builder
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
|
@ -127,21 +127,16 @@ impl PointLightingSystem {
|
||||
/// - `position` is the position of the spot light in world coordinates.
|
||||
/// - `color` is the color of the light.
|
||||
///
|
||||
pub fn draw<C, N, D>(
|
||||
pub fn draw(
|
||||
&self,
|
||||
viewport_dimensions: [u32; 2],
|
||||
color_input: C,
|
||||
normals_input: N,
|
||||
depth_input: D,
|
||||
color_input: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
|
||||
normals_input: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
|
||||
depth_input: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
|
||||
screen_to_world: Matrix4<f32>,
|
||||
position: Vector3<f32>,
|
||||
color: [f32; 3],
|
||||
) -> SecondaryAutoCommandBuffer
|
||||
where
|
||||
C: ImageViewAbstract + Send + Sync + 'static,
|
||||
N: ImageViewAbstract + Send + Sync + 'static,
|
||||
D: ImageViewAbstract + Send + Sync + 'static,
|
||||
{
|
||||
) -> SecondaryAutoCommandBuffer {
|
||||
let push_constants = fs::ty::PushConstants {
|
||||
screen_to_world: screen_to_world.into(),
|
||||
color: [color[0], color[1], color[2], 1.0],
|
||||
@ -154,13 +149,17 @@ impl PointLightingSystem {
|
||||
.descriptor_set_layouts()
|
||||
.get(0)
|
||||
.unwrap();
|
||||
let descriptor_set = PersistentDescriptorSet::start(layout.clone())
|
||||
let mut descriptor_set_builder = PersistentDescriptorSet::start(layout.clone());
|
||||
|
||||
descriptor_set_builder
|
||||
.add_image(color_input)
|
||||
.unwrap()
|
||||
.add_image(normals_input)
|
||||
.unwrap()
|
||||
.add_image(depth_input)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let descriptor_set = descriptor_set_builder
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
|
@ -225,15 +225,14 @@ impl FrameSystem {
|
||||
/// - `world_to_framebuffer` is the matrix that will be used to convert from 3D coordinates in
|
||||
/// the world into 2D coordinates on the framebuffer.
|
||||
///
|
||||
pub fn frame<F, I>(
|
||||
pub fn frame<F>(
|
||||
&mut self,
|
||||
before_future: F,
|
||||
final_image: I,
|
||||
final_image: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
|
||||
world_to_framebuffer: Matrix4<f32>,
|
||||
) -> Frame
|
||||
where
|
||||
F: GpuFuture + 'static,
|
||||
I: ImageViewAbstract + Clone + Send + Sync + 'static,
|
||||
{
|
||||
// First of all we recreate `self.diffuse_buffer`, `self.normals_buffer` and
|
||||
// `self.depth_buffer` if their dimensions doesn't match the dimensions of the final image.
|
||||
|
@ -28,7 +28,7 @@ use vulkano::pipeline::shader::EntryPointAbstract;
|
||||
use vulkano::pipeline::{ComputePipeline, PipelineBindPoint};
|
||||
use vulkano::sync;
|
||||
use vulkano::sync::GpuFuture;
|
||||
use vulkano::OomError;
|
||||
use vulkano::descriptor_set::layout::DescriptorSetLayoutError;
|
||||
use vulkano::Version;
|
||||
|
||||
fn main() {
|
||||
@ -130,7 +130,7 @@ fn main() {
|
||||
desc.clone(),
|
||||
)?))
|
||||
})
|
||||
.collect::<Result<Vec<_>, OomError>>()
|
||||
.collect::<Result<Vec<_>, DescriptorSetLayoutError>>()
|
||||
.unwrap();
|
||||
|
||||
Arc::new(
|
||||
@ -199,14 +199,18 @@ fn main() {
|
||||
.unwrap();
|
||||
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
|
||||
|
||||
set_builder
|
||||
.add_buffer(input_buffer.clone())
|
||||
.unwrap()
|
||||
.add_buffer(output_buffer.clone())
|
||||
.unwrap();
|
||||
|
||||
let set = Arc::new(
|
||||
PersistentDescriptorSet::start(layout.clone())
|
||||
.add_buffer(input_buffer.clone())
|
||||
.unwrap()
|
||||
.add_buffer(output_buffer.clone())
|
||||
.unwrap()
|
||||
set_builder
|
||||
.build()
|
||||
.unwrap(),
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
// Build the command buffer, using different offsets for each call.
|
||||
|
@ -198,12 +198,16 @@ fn main() {
|
||||
let view = ImageView::new(image.clone()).unwrap();
|
||||
|
||||
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();
|
||||
|
||||
let set = Arc::new(
|
||||
PersistentDescriptorSet::start(layout.clone())
|
||||
.add_image(view.clone())
|
||||
.unwrap()
|
||||
set_builder
|
||||
.build()
|
||||
.unwrap(),
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
let buf = CpuAccessibleBuffer::from_iter(
|
||||
|
@ -204,12 +204,16 @@ fn main() {
|
||||
);
|
||||
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
|
||||
|
||||
set_builder
|
||||
.add_sampled_image(texture.clone(), sampler.clone())
|
||||
.unwrap();
|
||||
|
||||
let set = Arc::new(
|
||||
PersistentDescriptorSet::start(layout.clone())
|
||||
.add_sampled_image(texture.clone(), sampler.clone())
|
||||
.unwrap()
|
||||
set_builder
|
||||
.build()
|
||||
.unwrap(),
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
let mut viewport = Viewport {
|
||||
|
@ -139,15 +139,19 @@ void 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()
|
||||
// Now you can just add immutable buffer like other buffers.
|
||||
.add_buffer(immutable_data_buffer.clone())
|
||||
.unwrap();
|
||||
|
||||
let set = Arc::new(
|
||||
PersistentDescriptorSet::start(layout.clone())
|
||||
.add_buffer(data_buffer.clone())
|
||||
.unwrap()
|
||||
// Now you can just add immutable buffer like other buffers.
|
||||
.add_buffer(immutable_data_buffer.clone())
|
||||
.unwrap()
|
||||
set_builder
|
||||
.build()
|
||||
.unwrap(),
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
let mut builder = AutoCommandBufferBuilder::primary(
|
||||
|
@ -30,6 +30,7 @@ extern crate vulkano_shaders;
|
||||
extern crate vulkano_win;
|
||||
extern crate winit;
|
||||
|
||||
use std::iter;
|
||||
use std::sync::Arc;
|
||||
use vulkano::buffer::{BufferUsage, CpuBufferPool};
|
||||
use vulkano::command_buffer::{
|
||||
@ -305,20 +306,20 @@ 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 = indirect_args_pool
|
||||
.chunk([DrawIndirectCommand {
|
||||
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();
|
||||
}))
|
||||
.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 = vertex_pool
|
||||
let vertices = Arc::new(vertex_pool
|
||||
.chunk((0..(6 * 16)).map(|_| Vertex { position: [0.0; 2] }))
|
||||
.unwrap();
|
||||
.unwrap());
|
||||
|
||||
// Pass the two buffers to the compute shader
|
||||
let layout = compute_pipeline
|
||||
@ -326,14 +327,18 @@ fn main() {
|
||||
.descriptor_set_layouts()
|
||||
.get(0)
|
||||
.unwrap();
|
||||
let mut cs_desciptor_set_builder = PersistentDescriptorSet::start(layout.clone());
|
||||
|
||||
cs_desciptor_set_builder
|
||||
.add_buffer(vertices.clone())
|
||||
.unwrap()
|
||||
.add_buffer(indirect_args.clone())
|
||||
.unwrap();
|
||||
|
||||
let cs_desciptor_set = Arc::new(
|
||||
PersistentDescriptorSet::start(layout.clone())
|
||||
.add_buffer(vertices.clone())
|
||||
.unwrap()
|
||||
.add_buffer(indirect_args.clone())
|
||||
.unwrap()
|
||||
cs_desciptor_set_builder
|
||||
.build()
|
||||
.unwrap(),
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
let mut builder = AutoCommandBufferBuilder::primary(
|
||||
|
@ -102,12 +102,16 @@ 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();
|
||||
|
||||
let set = Arc::new(
|
||||
PersistentDescriptorSet::start(layout.clone())
|
||||
.add_buffer(data_buffer.clone())
|
||||
.unwrap()
|
||||
set_builder
|
||||
.build()
|
||||
.unwrap(),
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
// The `vulkano_shaders::shaders!` macro generates a struct with the correct representation of the push constants struct specified in the shader.
|
||||
|
525
examples/src/bin/runtime_array/main.rs
Normal file
525
examples/src/bin/runtime_array/main.rs
Normal file
@ -0,0 +1,525 @@
|
||||
// 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.
|
||||
|
||||
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};
|
||||
use vulkano::pipeline::shader::EntryPointAbstract;
|
||||
use vulkano::pipeline::layout::PipelineLayout;
|
||||
use vulkano::descriptor_set::layout::DescriptorSetLayoutError;
|
||||
use vulkano::descriptor_set::layout::DescriptorSetLayout;
|
||||
|
||||
fn main() {
|
||||
// The start of this example is exactly the same as `triangle`. You should read the
|
||||
// `triangle` example if you haven't done so yet.
|
||||
|
||||
let required_extensions = vulkano_win::required_extensions();
|
||||
let instance = Instance::new(None, Version::V1_2, &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 {
|
||||
descriptor_indexing: true,
|
||||
shader_uniform_buffer_array_non_uniform_indexing: true,
|
||||
runtime_descriptor_array: true,
|
||||
descriptor_binding_variable_descriptor_count: true,
|
||||
descriptor_binding_partially_bound: true,
|
||||
..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],
|
||||
tex_i: u32,
|
||||
coords: [f32; 2],
|
||||
}
|
||||
vulkano::impl_vertex!(Vertex, position, tex_i, coords);
|
||||
|
||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::all(),
|
||||
false,
|
||||
[
|
||||
Vertex {
|
||||
position: [-0.1, -0.9],
|
||||
tex_i: 0,
|
||||
coords: [1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.9, -0.9],
|
||||
tex_i: 0,
|
||||
coords: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.9, -0.1],
|
||||
tex_i: 0,
|
||||
coords: [0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.1, -0.9],
|
||||
tex_i: 0,
|
||||
coords: [1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.9, -0.1],
|
||||
tex_i: 0,
|
||||
coords: [0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [-0.1, -0.1],
|
||||
tex_i: 0,
|
||||
coords: [1.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.9, -0.9],
|
||||
tex_i: 1,
|
||||
coords: [1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.1, -0.9],
|
||||
tex_i: 1,
|
||||
coords: [0.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.1, -0.1],
|
||||
tex_i: 1,
|
||||
coords: [0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.9, -0.9],
|
||||
tex_i: 1,
|
||||
coords: [1.0, 0.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.1, -0.1],
|
||||
tex_i: 1,
|
||||
coords: [0.0, 1.0],
|
||||
},
|
||||
Vertex {
|
||||
position: [0.9, -0.1],
|
||||
tex_i: 1,
|
||||
coords: [1.0, 1.0],
|
||||
},
|
||||
]
|
||||
.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 mascot_texture = {
|
||||
let png_bytes = include_bytes!("rust_mascot.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 = ImmutableImage::from_iter(
|
||||
image_data.iter().cloned(),
|
||||
dimensions,
|
||||
MipmapsCount::One,
|
||||
Format::R8G8B8A8Srgb,
|
||||
queue.clone(),
|
||||
)
|
||||
.unwrap()
|
||||
.0;
|
||||
|
||||
ImageView::new(image).unwrap()
|
||||
};
|
||||
|
||||
let vulkano_texture = {
|
||||
let png_bytes = include_bytes!("vulkano_logo.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 = ImmutableImage::from_iter(
|
||||
image_data.iter().cloned(),
|
||||
dimensions,
|
||||
MipmapsCount::One,
|
||||
Format::R8G8B8A8Srgb,
|
||||
queue.clone(),
|
||||
)
|
||||
.unwrap()
|
||||
.0;
|
||||
|
||||
ImageView::new(image).unwrap()
|
||||
};
|
||||
|
||||
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_layout = {
|
||||
let mut descriptor_set_descs: Vec<_> =
|
||||
(&fs.main_entry_point() as &dyn EntryPointAbstract)
|
||||
.descriptor_set_layout_descs()
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
// Set 0, Binding 0
|
||||
descriptor_set_descs[0].set_variable_descriptor_count(0, 2);
|
||||
|
||||
let descriptor_set_layouts = descriptor_set_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,
|
||||
(&fs.main_entry_point() as &dyn EntryPointAbstract)
|
||||
.push_constant_range()
|
||||
.iter()
|
||||
.cloned(),
|
||||
)
|
||||
.unwrap()
|
||||
)
|
||||
};
|
||||
|
||||
let pipeline = Arc::new(
|
||||
GraphicsPipeline::start()
|
||||
.vertex_input_single_buffer::<Vertex>()
|
||||
.vertex_shader(vs.main_entry_point(), ())
|
||||
.viewports_dynamic_scissors_irrelevant(1)
|
||||
.fragment_shader(fs.main_entry_point(), ())
|
||||
.blend_alpha_blending()
|
||||
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
|
||||
.with_pipeline_layout(device.clone(), pipeline_layout)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
|
||||
|
||||
set_builder
|
||||
.enter_array()
|
||||
.unwrap()
|
||||
.add_sampled_image(mascot_texture.clone(), sampler.clone())
|
||||
.unwrap()
|
||||
.add_sampled_image(vulkano_texture.clone(), sampler.clone())
|
||||
.unwrap()
|
||||
.leave_array()
|
||||
.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: Option<Box<dyn GpuFuture>> =
|
||||
Some(Box::new(vulkano::sync::now(device.clone())));
|
||||
|
||||
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",
|
||||
vulkan_version: "1.2",
|
||||
spirv_version: "1.5",
|
||||
src: "
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 position;
|
||||
layout(location = 1) in uint tex_i;
|
||||
layout(location = 2) in vec2 coords;
|
||||
|
||||
layout(location = 0) out flat uint out_tex_i;
|
||||
layout(location = 1) out vec2 out_coords;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(position, 0.0, 1.0);
|
||||
out_tex_i = tex_i;
|
||||
out_coords = coords;
|
||||
}"
|
||||
}
|
||||
}
|
||||
|
||||
mod fs {
|
||||
vulkano_shaders::shader! {
|
||||
ty: "fragment",
|
||||
vulkan_version: "1.2",
|
||||
spirv_version: "1.5",
|
||||
src: "
|
||||
#version 450
|
||||
|
||||
#extension GL_EXT_nonuniform_qualifier : enable
|
||||
|
||||
layout(location = 0) in flat uint tex_i;
|
||||
layout(location = 1) in vec2 coords;
|
||||
|
||||
layout(location = 0) out vec4 f_color;
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D tex[];
|
||||
|
||||
void main() {
|
||||
f_color = texture(tex[tex_i], coords);
|
||||
}"
|
||||
}
|
||||
}
|
BIN
examples/src/bin/runtime_array/rust_mascot.png
Normal file
BIN
examples/src/bin/runtime_array/rust_mascot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
BIN
examples/src/bin/runtime_array/vulkano_logo.png
Normal file
BIN
examples/src/bin/runtime_array/vulkano_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
@ -100,14 +100,20 @@ fn main() {
|
||||
CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, data_iter)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
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();
|
||||
|
||||
let set = Arc::new(
|
||||
PersistentDescriptorSet::start(layout.clone())
|
||||
.add_buffer(data_buffer.clone())
|
||||
.unwrap()
|
||||
set_builder
|
||||
.build()
|
||||
.unwrap(),
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
let mut builder = AutoCommandBufferBuilder::primary(
|
||||
device.clone(),
|
||||
queue.family(),
|
||||
|
@ -112,12 +112,16 @@ 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();
|
||||
|
||||
let set = Arc::new(
|
||||
PersistentDescriptorSet::start(layout.clone())
|
||||
.add_buffer(data_buffer.clone())
|
||||
.unwrap()
|
||||
set_builder
|
||||
.build()
|
||||
.unwrap(),
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
let mut builder = AutoCommandBufferBuilder::primary(
|
||||
|
@ -221,16 +221,20 @@ fn main() {
|
||||
proj: proj.into(),
|
||||
};
|
||||
|
||||
uniform_buffer.next(uniform_data).unwrap()
|
||||
Arc::new(uniform_buffer.next(uniform_data).unwrap())
|
||||
};
|
||||
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let mut set_builder = PersistentDescriptorSet::start(layout.clone());
|
||||
|
||||
set_builder
|
||||
.add_buffer(uniform_buffer_subbuffer)
|
||||
.unwrap();
|
||||
|
||||
let set = Arc::new(
|
||||
PersistentDescriptorSet::start(layout.clone())
|
||||
.add_buffer(uniform_buffer_subbuffer)
|
||||
.unwrap()
|
||||
set_builder
|
||||
.build()
|
||||
.unwrap(),
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
let (image_num, suboptimal, acquire_future) =
|
||||
|
@ -20,6 +20,7 @@ struct Descriptor {
|
||||
binding: u32,
|
||||
desc_ty: TokenStream,
|
||||
descriptor_count: u64,
|
||||
variable_count: bool,
|
||||
mutable: bool,
|
||||
}
|
||||
|
||||
@ -53,11 +54,13 @@ pub(super) fn write_descriptor_set_layout_descs(
|
||||
let desc_ty = &d.desc_ty;
|
||||
let descriptor_count = d.descriptor_count as u32;
|
||||
let mutable = d.mutable;
|
||||
let variable_count = d.variable_count;
|
||||
quote! {
|
||||
Some(DescriptorDesc {
|
||||
ty: #desc_ty,
|
||||
descriptor_count: #descriptor_count,
|
||||
stages: #stages,
|
||||
variable_count: #variable_count,
|
||||
mutable: #mutable,
|
||||
}),
|
||||
}
|
||||
@ -177,7 +180,7 @@ fn find_descriptors(
|
||||
.is_some();
|
||||
|
||||
// Find information about the kind of binding for this descriptor.
|
||||
let (desc_ty, mutable, descriptor_count) =
|
||||
let (desc_ty, mutable, descriptor_count, variable_count) =
|
||||
descriptor_infos(doc, pointed_ty, storage_class, false).expect(&format!(
|
||||
"Couldn't find relevant type for uniform `{}` (type {}, maybe unimplemented)",
|
||||
name, pointed_ty
|
||||
@ -188,6 +191,7 @@ fn find_descriptors(
|
||||
binding,
|
||||
descriptor_count,
|
||||
mutable: !nonwritable && mutable,
|
||||
variable_count: variable_count,
|
||||
});
|
||||
}
|
||||
|
||||
@ -372,7 +376,7 @@ fn descriptor_infos(
|
||||
pointed_ty: u32,
|
||||
pointer_storage: StorageClass,
|
||||
force_combined_image_sampled: bool,
|
||||
) -> Option<(TokenStream, bool, u64)> {
|
||||
) -> Option<(TokenStream, bool, u64, bool)> {
|
||||
doc.instructions
|
||||
.iter()
|
||||
.filter_map(|i| {
|
||||
@ -402,7 +406,7 @@ fn descriptor_infos(
|
||||
(quote! { DescriptorDescTy::UniformBuffer }, false) // Uniforms are never mutable.
|
||||
};
|
||||
|
||||
Some((ty, mutable, 1))
|
||||
Some((ty, mutable, 1, false))
|
||||
}
|
||||
&Instruction::TypeImage {
|
||||
result_id,
|
||||
@ -442,7 +446,7 @@ fn descriptor_infos(
|
||||
}
|
||||
};
|
||||
|
||||
Some((desc, true, 1)) // Never writable.
|
||||
Some((desc, true, 1, false)) // Never writable.
|
||||
}
|
||||
Dim::DimBuffer => {
|
||||
let (ty, mutable) = if sampled {
|
||||
@ -459,8 +463,7 @@ fn descriptor_infos(
|
||||
}
|
||||
};
|
||||
|
||||
Some((desc, mutable, 1))
|
||||
|
||||
Some((desc, mutable, 1, false))
|
||||
}
|
||||
_ => {
|
||||
let (ty, mutable) = if force_combined_image_sampled {
|
||||
@ -498,7 +501,7 @@ fn descriptor_infos(
|
||||
})
|
||||
};
|
||||
|
||||
Some((desc, mutable, 1))
|
||||
Some((desc, mutable, 1, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -512,19 +515,20 @@ fn descriptor_infos(
|
||||
|
||||
&Instruction::TypeSampler { result_id } if result_id == pointed_ty => {
|
||||
let desc = quote! { DescriptorDescTy::Sampler };
|
||||
Some((desc, false, 1))
|
||||
Some((desc, false, 1, false))
|
||||
}
|
||||
&Instruction::TypeArray {
|
||||
result_id,
|
||||
type_id,
|
||||
length_id,
|
||||
} if result_id == pointed_ty => {
|
||||
let (desc, mutable, arr) =
|
||||
let (desc, mutable, arr, variable_count) =
|
||||
match descriptor_infos(doc, type_id, pointer_storage.clone(), false) {
|
||||
None => return None,
|
||||
Some(v) => v,
|
||||
};
|
||||
assert_eq!(arr, 1); // TODO: implement?
|
||||
assert!(!variable_count); // TODO: Is this even a thing?
|
||||
let len = doc
|
||||
.instructions
|
||||
.iter()
|
||||
@ -539,8 +543,25 @@ fn descriptor_infos(
|
||||
.next()
|
||||
.expect("failed to find array length");
|
||||
let len = len.iter().rev().fold(0, |a, &b| (a << 32) | b as u64);
|
||||
Some((desc, mutable, len))
|
||||
|
||||
Some((desc, mutable, len, false))
|
||||
}
|
||||
|
||||
&Instruction::TypeRuntimeArray {
|
||||
result_id,
|
||||
type_id,
|
||||
} if result_id == pointed_ty => {
|
||||
let (desc, mutable, arr, variable_count) =
|
||||
match descriptor_infos(doc, type_id, pointer_storage.clone(), false) {
|
||||
None => return None,
|
||||
Some(v) => v,
|
||||
};
|
||||
assert_eq!(arr, 1); // TODO: implement?
|
||||
assert!(!variable_count); // TODO: Don't think this is possible?
|
||||
|
||||
Some((desc, mutable, 1, true))
|
||||
}
|
||||
|
||||
_ => None, // TODO: other types
|
||||
}
|
||||
})
|
||||
|
@ -368,6 +368,7 @@ where
|
||||
unsafe impl<T: ?Sized, A> BufferAccess for CpuAccessibleBuffer<T, A>
|
||||
where
|
||||
T: 'static + Send + Sync,
|
||||
A: Send + Sync,
|
||||
{
|
||||
#[inline]
|
||||
fn inner(&self) -> BufferInner {
|
||||
@ -484,6 +485,7 @@ where
|
||||
unsafe impl<T: ?Sized, A> TypedBufferAccess for CpuAccessibleBuffer<T, A>
|
||||
where
|
||||
T: 'static + Send + Sync,
|
||||
A: Send + Sync,
|
||||
{
|
||||
type Content = T;
|
||||
}
|
||||
@ -498,6 +500,7 @@ unsafe impl<T: ?Sized, A> DeviceOwned for CpuAccessibleBuffer<T, A> {
|
||||
impl<T: ?Sized, A> PartialEq for CpuAccessibleBuffer<T, A>
|
||||
where
|
||||
T: 'static + Send + Sync,
|
||||
A: Send + Sync,
|
||||
{
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
@ -505,11 +508,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized, A> Eq for CpuAccessibleBuffer<T, A> where T: 'static + Send + Sync {}
|
||||
impl<T: ?Sized, A> Eq for CpuAccessibleBuffer<T, A>
|
||||
where
|
||||
T: 'static + Send + Sync,
|
||||
A: Send + Sync,
|
||||
{
|
||||
}
|
||||
|
||||
impl<T: ?Sized, A> Hash for CpuAccessibleBuffer<T, A>
|
||||
where
|
||||
T: 'static + Send + Sync,
|
||||
A: Send + Sync,
|
||||
{
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
|
@ -620,7 +620,9 @@ where
|
||||
|
||||
unsafe impl<T, A> BufferAccess for CpuBufferPoolChunk<T, A>
|
||||
where
|
||||
T: Send + Sync,
|
||||
A: MemoryPool,
|
||||
<A as MemoryPool>::Alloc: Send + Sync,
|
||||
{
|
||||
#[inline]
|
||||
fn inner(&self) -> BufferInner {
|
||||
@ -731,7 +733,9 @@ where
|
||||
|
||||
unsafe impl<T, A> TypedBufferAccess for CpuBufferPoolChunk<T, A>
|
||||
where
|
||||
T: Send + Sync,
|
||||
A: MemoryPool,
|
||||
<A as MemoryPool>::Alloc: Send + Sync,
|
||||
{
|
||||
type Content = [T];
|
||||
}
|
||||
@ -748,7 +752,9 @@ where
|
||||
|
||||
impl<T, A> PartialEq for CpuBufferPoolChunk<T, A>
|
||||
where
|
||||
T: Send + Sync,
|
||||
A: MemoryPool,
|
||||
<A as MemoryPool>::Alloc: Send + Sync,
|
||||
{
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
@ -756,11 +762,19 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A> Eq for CpuBufferPoolChunk<T, A> where A: MemoryPool {}
|
||||
impl<T, A> Eq for CpuBufferPoolChunk<T, A>
|
||||
where
|
||||
T: Send + Sync,
|
||||
A: MemoryPool,
|
||||
<A as MemoryPool>::Alloc: Send + Sync,
|
||||
{
|
||||
}
|
||||
|
||||
impl<T, A> Hash for CpuBufferPoolChunk<T, A>
|
||||
where
|
||||
T: Send + Sync,
|
||||
A: MemoryPool,
|
||||
<A as MemoryPool>::Alloc: Send + Sync,
|
||||
{
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
@ -782,7 +796,9 @@ where
|
||||
|
||||
unsafe impl<T, A> BufferAccess for CpuBufferPoolSubbuffer<T, A>
|
||||
where
|
||||
T: Send + Sync,
|
||||
A: MemoryPool,
|
||||
<A as MemoryPool>::Alloc: Send + Sync,
|
||||
{
|
||||
#[inline]
|
||||
fn inner(&self) -> BufferInner {
|
||||
@ -817,7 +833,9 @@ where
|
||||
|
||||
unsafe impl<T, A> TypedBufferAccess for CpuBufferPoolSubbuffer<T, A>
|
||||
where
|
||||
T: Send + Sync,
|
||||
A: MemoryPool,
|
||||
<A as MemoryPool>::Alloc: Send + Sync,
|
||||
{
|
||||
type Content = T;
|
||||
}
|
||||
@ -834,7 +852,9 @@ where
|
||||
|
||||
impl<T, A> PartialEq for CpuBufferPoolSubbuffer<T, A>
|
||||
where
|
||||
T: Send + Sync,
|
||||
A: MemoryPool,
|
||||
<A as MemoryPool>::Alloc: Send + Sync,
|
||||
{
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
@ -842,11 +862,19 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A> Eq for CpuBufferPoolSubbuffer<T, A> where A: MemoryPool {}
|
||||
impl<T, A> Eq for CpuBufferPoolSubbuffer<T, A>
|
||||
where
|
||||
T: Send + Sync,
|
||||
A: MemoryPool,
|
||||
<A as MemoryPool>::Alloc: Send + Sync,
|
||||
{
|
||||
}
|
||||
|
||||
impl<T, A> Hash for CpuBufferPoolSubbuffer<T, A>
|
||||
where
|
||||
T: Send + Sync,
|
||||
A: MemoryPool,
|
||||
<A as MemoryPool>::Alloc: Send + Sync,
|
||||
{
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
|
@ -293,6 +293,7 @@ unsafe impl<T: ?Sized, A> DeviceOwned for DeviceLocalBuffer<T, A> {
|
||||
unsafe impl<T: ?Sized, A> BufferAccess for DeviceLocalBuffer<T, A>
|
||||
where
|
||||
T: 'static + Send + Sync,
|
||||
A: Send + Sync,
|
||||
{
|
||||
#[inline]
|
||||
fn inner(&self) -> BufferInner {
|
||||
@ -382,6 +383,7 @@ where
|
||||
unsafe impl<T: ?Sized, A> TypedBufferAccess for DeviceLocalBuffer<T, A>
|
||||
where
|
||||
T: 'static + Send + Sync,
|
||||
A: Send + Sync,
|
||||
{
|
||||
type Content = T;
|
||||
}
|
||||
@ -389,6 +391,7 @@ where
|
||||
impl<T: ?Sized, A> PartialEq for DeviceLocalBuffer<T, A>
|
||||
where
|
||||
T: 'static + Send + Sync,
|
||||
A: Send + Sync,
|
||||
{
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
@ -396,11 +399,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized, A> Eq for DeviceLocalBuffer<T, A> where T: 'static + Send + Sync {}
|
||||
impl<T: ?Sized, A> Eq for DeviceLocalBuffer<T, A>
|
||||
where
|
||||
T: 'static + Send + Sync,
|
||||
A: Send + Sync,
|
||||
{
|
||||
}
|
||||
|
||||
impl<T: ?Sized, A> Hash for DeviceLocalBuffer<T, A>
|
||||
where
|
||||
T: 'static + Send + Sync,
|
||||
A: Send + Sync,
|
||||
{
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
|
@ -353,7 +353,11 @@ impl<T: ?Sized, A> ImmutableBuffer<T, A> {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: ?Sized, A> BufferAccess for ImmutableBuffer<T, A> {
|
||||
unsafe impl<T, A> BufferAccess for ImmutableBuffer<T, A>
|
||||
where
|
||||
T: Send + Sync + ?Sized,
|
||||
A: Send + Sync,
|
||||
{
|
||||
#[inline]
|
||||
fn inner(&self) -> BufferInner {
|
||||
BufferInner {
|
||||
@ -392,7 +396,11 @@ unsafe impl<T: ?Sized, A> BufferAccess for ImmutableBuffer<T, A> {
|
||||
unsafe fn unlock(&self) {}
|
||||
}
|
||||
|
||||
unsafe impl<T: ?Sized, A> TypedBufferAccess for ImmutableBuffer<T, A> {
|
||||
unsafe impl<T, A> TypedBufferAccess for ImmutableBuffer<T, A>
|
||||
where
|
||||
T: Send + Sync + ?Sized,
|
||||
A: Send + Sync,
|
||||
{
|
||||
type Content = T;
|
||||
}
|
||||
|
||||
@ -403,16 +411,29 @@ unsafe impl<T: ?Sized, A> DeviceOwned for ImmutableBuffer<T, A> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized, A> PartialEq for ImmutableBuffer<T, A> {
|
||||
impl<T: ?Sized, A> PartialEq for ImmutableBuffer<T, A>
|
||||
where
|
||||
T: Send + Sync,
|
||||
A: Send + Sync,
|
||||
{
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.inner() == other.inner() && self.size() == other.size()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized, A> Eq for ImmutableBuffer<T, A> {}
|
||||
impl<T: ?Sized, A> Eq for ImmutableBuffer<T, A>
|
||||
where
|
||||
T: Send + Sync,
|
||||
A: Send + Sync,
|
||||
{
|
||||
}
|
||||
|
||||
impl<T: ?Sized, A> Hash for ImmutableBuffer<T, A> {
|
||||
impl<T: ?Sized, A> Hash for ImmutableBuffer<T, A>
|
||||
where
|
||||
T: Send + Sync,
|
||||
A: Send + Sync,
|
||||
{
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.inner().hash(state);
|
||||
@ -430,7 +451,11 @@ pub struct ImmutableBufferInitialization<
|
||||
used: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
unsafe impl<T: ?Sized, A> BufferAccess for ImmutableBufferInitialization<T, A> {
|
||||
unsafe impl<T, A> BufferAccess for ImmutableBufferInitialization<T, A>
|
||||
where
|
||||
T: Send + Sync + ?Sized,
|
||||
A: Send + Sync,
|
||||
{
|
||||
#[inline]
|
||||
fn inner(&self) -> BufferInner {
|
||||
self.buffer.inner()
|
||||
@ -474,7 +499,11 @@ unsafe impl<T: ?Sized, A> BufferAccess for ImmutableBufferInitialization<T, A> {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: ?Sized, A> TypedBufferAccess for ImmutableBufferInitialization<T, A> {
|
||||
unsafe impl<T, A> TypedBufferAccess for ImmutableBufferInitialization<T, A>
|
||||
where
|
||||
T: Send + Sync + ?Sized,
|
||||
A: Send + Sync,
|
||||
{
|
||||
type Content = T;
|
||||
}
|
||||
|
||||
@ -495,16 +524,29 @@ impl<T: ?Sized, A> Clone for ImmutableBufferInitialization<T, A> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized, A> PartialEq for ImmutableBufferInitialization<T, A> {
|
||||
impl<T: ?Sized, A> PartialEq for ImmutableBufferInitialization<T, A>
|
||||
where
|
||||
T: Send + Sync,
|
||||
A: Send + Sync,
|
||||
{
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.inner() == other.inner() && self.size() == other.size()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized, A> Eq for ImmutableBufferInitialization<T, A> {}
|
||||
impl<T: ?Sized, A> Eq for ImmutableBufferInitialization<T, A>
|
||||
where
|
||||
T: Send + Sync,
|
||||
A: Send + Sync,
|
||||
{
|
||||
}
|
||||
|
||||
impl<T: ?Sized, A> Hash for ImmutableBufferInitialization<T, A> {
|
||||
impl<T: ?Sized, A> Hash for ImmutableBufferInitialization<T, A>
|
||||
where
|
||||
T: Send + Sync,
|
||||
A: Send + Sync,
|
||||
{
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.inner().hash(state);
|
||||
|
@ -213,9 +213,10 @@ impl<T, B> BufferSlice<[T], B> {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: ?Sized, B> BufferAccess for BufferSlice<T, B>
|
||||
unsafe impl<T, B> BufferAccess for BufferSlice<T, B>
|
||||
where
|
||||
B: BufferAccess,
|
||||
T: Send + Sync + ?Sized,
|
||||
{
|
||||
#[inline]
|
||||
fn inner(&self) -> BufferInner {
|
||||
@ -252,8 +253,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: ?Sized, B> TypedBufferAccess for BufferSlice<T, B>
|
||||
unsafe impl<T, B> TypedBufferAccess for BufferSlice<T, B>
|
||||
where
|
||||
T: ?Sized + Send + Sync,
|
||||
B: BufferAccess,
|
||||
{
|
||||
type Content = T;
|
||||
@ -283,6 +285,7 @@ impl<T, B> From<BufferSlice<T, B>> for BufferSlice<[T], B> {
|
||||
|
||||
impl<T: ?Sized, B> PartialEq for BufferSlice<T, B>
|
||||
where
|
||||
T: Send + Sync,
|
||||
B: BufferAccess,
|
||||
{
|
||||
#[inline]
|
||||
@ -291,10 +294,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized, B> Eq for BufferSlice<T, B> where B: BufferAccess {}
|
||||
impl<T: ?Sized, B> Eq for BufferSlice<T, B>
|
||||
where
|
||||
B: BufferAccess,
|
||||
T: Send + Sync,
|
||||
{
|
||||
}
|
||||
|
||||
impl<T: ?Sized, B> Hash for BufferSlice<T, B>
|
||||
where
|
||||
T: Send + Sync,
|
||||
B: BufferAccess,
|
||||
{
|
||||
#[inline]
|
||||
|
@ -24,7 +24,7 @@ use std::ops::Range;
|
||||
/// buffer.
|
||||
///
|
||||
/// See also `TypedBufferAccess`.
|
||||
pub unsafe trait BufferAccess: DeviceOwned {
|
||||
pub unsafe trait BufferAccess: DeviceOwned + Send + Sync {
|
||||
/// Returns the inner information about this buffer.
|
||||
fn inner(&self) -> BufferInner;
|
||||
|
||||
@ -166,7 +166,7 @@ pub struct BufferInner<'a> {
|
||||
|
||||
unsafe impl<T> BufferAccess for T
|
||||
where
|
||||
T: SafeDeref,
|
||||
T: SafeDeref + Send + Sync,
|
||||
T::Target: BufferAccess,
|
||||
{
|
||||
#[inline]
|
||||
@ -219,31 +219,22 @@ pub unsafe trait TypedBufferAccess: BufferAccess {
|
||||
|
||||
unsafe impl<T> TypedBufferAccess for T
|
||||
where
|
||||
T: SafeDeref,
|
||||
T: SafeDeref + Send + Sync,
|
||||
T::Target: TypedBufferAccess,
|
||||
{
|
||||
type Content = <T::Target as TypedBufferAccess>::Content;
|
||||
}
|
||||
|
||||
impl PartialEq for &dyn BufferAccess {
|
||||
impl PartialEq for dyn BufferAccess {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.inner() == other.inner() && self.size() == other.size()
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for &dyn BufferAccess {}
|
||||
impl Eq for dyn BufferAccess {}
|
||||
|
||||
impl PartialEq for dyn BufferAccess + Send + Sync {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.inner() == other.inner() && self.size() == other.size()
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for dyn BufferAccess + Send + Sync {}
|
||||
|
||||
impl Hash for dyn BufferAccess + Send + Sync {
|
||||
impl Hash for dyn BufferAccess {
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.inner().hash(state);
|
||||
|
@ -58,10 +58,10 @@ use std::sync::Arc;
|
||||
/// `view` module.
|
||||
pub struct BufferView<B>
|
||||
where
|
||||
B: BufferAccess,
|
||||
B: BufferAccess + ?Sized,
|
||||
{
|
||||
view: ash::vk::BufferView,
|
||||
buffer: B,
|
||||
buffer: Box<B>,
|
||||
atomic_accesses: bool,
|
||||
}
|
||||
|
||||
@ -167,7 +167,7 @@ where
|
||||
|
||||
Ok(BufferView {
|
||||
view,
|
||||
buffer: org_buffer,
|
||||
buffer: Box::new(org_buffer),
|
||||
atomic_accesses: !(format_props
|
||||
& ash::vk::FormatFeatureFlags::STORAGE_TEXEL_BUFFER_ATOMIC)
|
||||
.is_empty(),
|
||||
@ -235,7 +235,7 @@ where
|
||||
|
||||
impl<B> Drop for BufferView<B>
|
||||
where
|
||||
B: BufferAccess,
|
||||
B: BufferAccess + ?Sized,
|
||||
{
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
|
@ -1606,7 +1606,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
#[inline]
|
||||
pub fn fill_buffer<B>(&mut self, buffer: B, data: u32) -> Result<&mut Self, FillBufferError>
|
||||
where
|
||||
B: BufferAccess + Send + Sync + 'static,
|
||||
B: BufferAccess + 'static,
|
||||
{
|
||||
unsafe {
|
||||
self.ensure_outside_render_pass()?;
|
||||
|
@ -285,7 +285,7 @@ impl SyncCommandBufferBuilder {
|
||||
#[inline]
|
||||
pub unsafe fn bind_index_buffer<B>(&mut self, buffer: B, index_ty: IndexType)
|
||||
where
|
||||
B: BufferAccess + Send + Sync + 'static,
|
||||
B: BufferAccess + 'static,
|
||||
{
|
||||
struct Cmd<B> {
|
||||
buffer: B,
|
||||
@ -294,7 +294,7 @@ impl SyncCommandBufferBuilder {
|
||||
|
||||
impl<B> Command for Cmd<B>
|
||||
where
|
||||
B: BufferAccess + Send + Sync + 'static,
|
||||
B: BufferAccess + 'static,
|
||||
{
|
||||
fn name(&self) -> &'static str {
|
||||
"vkCmdBindIndexBuffer"
|
||||
@ -748,8 +748,8 @@ impl SyncCommandBufferBuilder {
|
||||
regions: R,
|
||||
) -> Result<(), SyncCommandBufferBuilderError>
|
||||
where
|
||||
S: BufferAccess + Send + Sync + 'static,
|
||||
D: BufferAccess + Send + Sync + 'static,
|
||||
S: BufferAccess + 'static,
|
||||
D: BufferAccess + 'static,
|
||||
R: IntoIterator<Item = (DeviceSize, DeviceSize, DeviceSize)> + Send + Sync + 'static,
|
||||
{
|
||||
struct Cmd<S, D, R> {
|
||||
@ -760,8 +760,8 @@ impl SyncCommandBufferBuilder {
|
||||
|
||||
impl<S, D, R> Command for Cmd<S, D, R>
|
||||
where
|
||||
S: BufferAccess + Send + Sync + 'static,
|
||||
D: BufferAccess + Send + Sync + 'static,
|
||||
S: BufferAccess + 'static,
|
||||
D: BufferAccess + 'static,
|
||||
R: IntoIterator<Item = (DeviceSize, DeviceSize, DeviceSize)>,
|
||||
{
|
||||
fn name(&self) -> &'static str {
|
||||
@ -857,7 +857,7 @@ impl SyncCommandBufferBuilder {
|
||||
regions: R,
|
||||
) -> Result<(), SyncCommandBufferBuilderError>
|
||||
where
|
||||
S: BufferAccess + Send + Sync + 'static,
|
||||
S: BufferAccess + 'static,
|
||||
D: ImageAccess + Send + Sync + 'static,
|
||||
R: IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy> + Send + Sync + 'static,
|
||||
{
|
||||
@ -870,7 +870,7 @@ impl SyncCommandBufferBuilder {
|
||||
|
||||
impl<S, D, R> Command for Cmd<S, D, R>
|
||||
where
|
||||
S: BufferAccess + Send + Sync + 'static,
|
||||
S: BufferAccess + 'static,
|
||||
D: ImageAccess + Send + Sync + 'static,
|
||||
R: IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy>,
|
||||
{
|
||||
@ -974,7 +974,7 @@ impl SyncCommandBufferBuilder {
|
||||
) -> Result<(), SyncCommandBufferBuilderError>
|
||||
where
|
||||
S: ImageAccess + Send + Sync + 'static,
|
||||
D: BufferAccess + Send + Sync + 'static,
|
||||
D: BufferAccess + 'static,
|
||||
R: IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy> + Send + Sync + 'static,
|
||||
{
|
||||
struct Cmd<S, D, R> {
|
||||
@ -987,7 +987,7 @@ impl SyncCommandBufferBuilder {
|
||||
impl<S, D, R> Command for Cmd<S, D, R>
|
||||
where
|
||||
S: ImageAccess + Send + Sync + 'static,
|
||||
D: BufferAccess + Send + Sync + 'static,
|
||||
D: BufferAccess + 'static,
|
||||
R: IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy>,
|
||||
{
|
||||
fn name(&self) -> &'static str {
|
||||
@ -1346,7 +1346,7 @@ impl SyncCommandBufferBuilder {
|
||||
indirect_buffer: B,
|
||||
) -> Result<(), SyncCommandBufferBuilderError>
|
||||
where
|
||||
B: BufferAccess + Send + Sync + 'static,
|
||||
B: BufferAccess + 'static,
|
||||
{
|
||||
struct Cmd<B> {
|
||||
descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]>,
|
||||
@ -1355,7 +1355,7 @@ impl SyncCommandBufferBuilder {
|
||||
|
||||
impl<B> Command for Cmd<B>
|
||||
where
|
||||
B: BufferAccess + Send + Sync + 'static,
|
||||
B: BufferAccess + 'static,
|
||||
{
|
||||
fn name(&self) -> &'static str {
|
||||
"vkCmdDispatchIndirect"
|
||||
@ -1782,7 +1782,7 @@ impl SyncCommandBufferBuilder {
|
||||
stride: u32,
|
||||
) -> Result<(), SyncCommandBufferBuilderError>
|
||||
where
|
||||
B: BufferAccess + Send + Sync + 'static,
|
||||
B: BufferAccess + 'static,
|
||||
{
|
||||
struct Cmd<B> {
|
||||
descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]>,
|
||||
@ -1794,7 +1794,7 @@ impl SyncCommandBufferBuilder {
|
||||
|
||||
impl<B> Command for Cmd<B>
|
||||
where
|
||||
B: BufferAccess + Send + Sync + 'static,
|
||||
B: BufferAccess + 'static,
|
||||
{
|
||||
fn name(&self) -> &'static str {
|
||||
"vkCmdDrawIndirect"
|
||||
@ -1939,7 +1939,7 @@ impl SyncCommandBufferBuilder {
|
||||
stride: u32,
|
||||
) -> Result<(), SyncCommandBufferBuilderError>
|
||||
where
|
||||
B: BufferAccess + Send + Sync + 'static,
|
||||
B: BufferAccess + 'static,
|
||||
{
|
||||
struct Cmd<B> {
|
||||
descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]>,
|
||||
@ -1952,7 +1952,7 @@ impl SyncCommandBufferBuilder {
|
||||
|
||||
impl<B> Command for Cmd<B>
|
||||
where
|
||||
B: BufferAccess + Send + Sync + 'static,
|
||||
B: BufferAccess + 'static,
|
||||
{
|
||||
fn name(&self) -> &'static str {
|
||||
"vkCmdDrawIndexedIndirect"
|
||||
@ -2149,7 +2149,7 @@ impl SyncCommandBufferBuilder {
|
||||
#[inline]
|
||||
pub unsafe fn fill_buffer<B>(&mut self, buffer: B, data: u32)
|
||||
where
|
||||
B: BufferAccess + Send + Sync + 'static,
|
||||
B: BufferAccess + 'static,
|
||||
{
|
||||
struct Cmd<B> {
|
||||
buffer: B,
|
||||
@ -2158,7 +2158,7 @@ impl SyncCommandBufferBuilder {
|
||||
|
||||
impl<B> Command for Cmd<B>
|
||||
where
|
||||
B: BufferAccess + Send + Sync + 'static,
|
||||
B: BufferAccess + 'static,
|
||||
{
|
||||
fn name(&self) -> &'static str {
|
||||
"vkCmdFillBuffer"
|
||||
@ -2706,7 +2706,7 @@ impl SyncCommandBufferBuilder {
|
||||
#[inline]
|
||||
pub unsafe fn update_buffer<B, D, Dd>(&mut self, buffer: B, data: Dd)
|
||||
where
|
||||
B: BufferAccess + Send + Sync + 'static,
|
||||
B: BufferAccess + 'static,
|
||||
D: ?Sized,
|
||||
Dd: SafeDeref<Target = D> + Send + Sync + 'static,
|
||||
{
|
||||
@ -2717,7 +2717,7 @@ impl SyncCommandBufferBuilder {
|
||||
|
||||
impl<B, D, Dd> Command for Cmd<B, Dd>
|
||||
where
|
||||
B: BufferAccess + Send + Sync + 'static,
|
||||
B: BufferAccess + 'static,
|
||||
D: ?Sized,
|
||||
Dd: SafeDeref<Target = D> + Send + Sync + 'static,
|
||||
{
|
||||
@ -3149,7 +3149,7 @@ impl<'b> SyncCommandBufferBuilderBindDescriptorSets<'b> {
|
||||
pub struct SyncCommandBufferBuilderBindVertexBuffer<'a> {
|
||||
builder: &'a mut SyncCommandBufferBuilder,
|
||||
inner: UnsafeCommandBufferBuilderBindVertexBuffer,
|
||||
buffers: SmallVec<[Box<dyn BufferAccess + Send + Sync>; 4]>,
|
||||
buffers: SmallVec<[Box<dyn BufferAccess>; 4]>,
|
||||
}
|
||||
|
||||
impl<'a> SyncCommandBufferBuilderBindVertexBuffer<'a> {
|
||||
@ -3157,7 +3157,7 @@ impl<'a> SyncCommandBufferBuilderBindVertexBuffer<'a> {
|
||||
#[inline]
|
||||
pub fn add<B>(&mut self, buffer: B)
|
||||
where
|
||||
B: BufferAccess + Send + Sync + 'static,
|
||||
B: BufferAccess + 'static,
|
||||
{
|
||||
self.inner.add(&buffer);
|
||||
self.buffers.push(Box::new(buffer));
|
||||
@ -3168,7 +3168,7 @@ impl<'a> SyncCommandBufferBuilderBindVertexBuffer<'a> {
|
||||
struct Cmd {
|
||||
first_set: u32,
|
||||
inner: Mutex<Option<UnsafeCommandBufferBuilderBindVertexBuffer>>,
|
||||
buffers: SmallVec<[Box<dyn BufferAccess + Send + Sync>; 4]>,
|
||||
buffers: SmallVec<[Box<dyn BufferAccess>; 4]>,
|
||||
}
|
||||
|
||||
impl Command for Cmd {
|
||||
|
@ -716,6 +716,7 @@ mod tests {
|
||||
descriptor_count: 1,
|
||||
stages: ShaderStages::all(),
|
||||
mutable: false,
|
||||
variable_count: false,
|
||||
})],
|
||||
)
|
||||
.unwrap(),
|
||||
@ -724,13 +725,14 @@ mod tests {
|
||||
PipelineLayout::new(device.clone(), [set_layout.clone(), set_layout.clone()], [])
|
||||
.unwrap(),
|
||||
);
|
||||
let set = Arc::new(
|
||||
PersistentDescriptorSet::start(set_layout.clone())
|
||||
|
||||
let set = {
|
||||
let mut builder = PersistentDescriptorSet::start(set_layout.clone());
|
||||
builder
|
||||
.add_sampler(Sampler::simple_repeat_linear(device.clone()))
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap(),
|
||||
);
|
||||
.unwrap();
|
||||
Arc::new(builder.build().unwrap())
|
||||
};
|
||||
|
||||
let mut set_builder = sync.bind_descriptor_sets();
|
||||
set_builder.add(set.clone());
|
||||
@ -771,13 +773,14 @@ mod tests {
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
let set = Arc::new(
|
||||
PersistentDescriptorSet::start(set_layout.clone())
|
||||
|
||||
let set = {
|
||||
let mut builder = PersistentDescriptorSet::start(set_layout.clone());
|
||||
builder
|
||||
.add_sampler(Sampler::simple_repeat_linear(device.clone()))
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap(),
|
||||
);
|
||||
.unwrap();
|
||||
Arc::new(builder.build().unwrap())
|
||||
};
|
||||
|
||||
let mut set_builder = sync.bind_descriptor_sets();
|
||||
set_builder.add(set);
|
||||
|
@ -20,7 +20,7 @@ pub fn check_indirect_buffer<Inb>(
|
||||
buffer: &Inb,
|
||||
) -> Result<(), CheckIndirectBufferError>
|
||||
where
|
||||
Inb: BufferAccess + Send + Sync + 'static,
|
||||
Inb: BufferAccess + 'static,
|
||||
{
|
||||
assert_eq!(
|
||||
buffer.inner().buffer.device().internal_object(),
|
||||
|
579
vulkano/src/descriptor_set/builder.rs
Normal file
579
vulkano/src/descriptor_set/builder.rs
Normal file
@ -0,0 +1,579 @@
|
||||
// Copyright (c) 2017 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.
|
||||
|
||||
use super::resources::DescriptorSetResources;
|
||||
use super::DescriptorSetError;
|
||||
use super::MissingBufferUsage;
|
||||
use super::MissingImageUsage;
|
||||
use crate::buffer::BufferView;
|
||||
use crate::descriptor_set::layout::DescriptorDesc;
|
||||
use crate::descriptor_set::layout::DescriptorDescImage;
|
||||
use crate::descriptor_set::layout::DescriptorDescTy;
|
||||
use crate::descriptor_set::sys::DescriptorWrite;
|
||||
use crate::descriptor_set::BufferAccess;
|
||||
use crate::descriptor_set::DescriptorSetLayout;
|
||||
use crate::device::Device;
|
||||
use crate::device::DeviceOwned;
|
||||
use crate::image::view::ImageViewType;
|
||||
use crate::image::ImageViewAbstract;
|
||||
use crate::image::SampleCount;
|
||||
use crate::sampler::Sampler;
|
||||
use crate::VulkanObject;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
struct BuilderDescriptor {
|
||||
desc: Option<DescriptorDesc>,
|
||||
array_element: u32,
|
||||
}
|
||||
|
||||
pub struct DescriptorSetBuilder {
|
||||
layout: Arc<DescriptorSetLayout>,
|
||||
in_array: bool,
|
||||
descriptors: Vec<BuilderDescriptor>,
|
||||
cur_binding: usize,
|
||||
resources: DescriptorSetResources,
|
||||
desc_writes: Vec<DescriptorWrite>,
|
||||
}
|
||||
|
||||
pub struct DescriptorSetBuilderOutput {
|
||||
pub layout: Arc<DescriptorSetLayout>,
|
||||
pub writes: Vec<DescriptorWrite>,
|
||||
pub resources: DescriptorSetResources,
|
||||
}
|
||||
|
||||
impl DescriptorSetBuilder {
|
||||
pub fn start(layout: Arc<DescriptorSetLayout>) -> Self {
|
||||
let mut descriptors = Vec::with_capacity(layout.num_bindings() as usize);
|
||||
let mut desc_writes_capacity = 0;
|
||||
let mut t_num_bufs = 0;
|
||||
let mut t_num_imgs = 0;
|
||||
let mut t_num_samplers = 0;
|
||||
|
||||
for binding_i in 0..layout.num_bindings() {
|
||||
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::InputAttachment { .. } => (0, 1, 0),
|
||||
DescriptorDescTy::StorageImage(_) => (0, 1, 0),
|
||||
DescriptorDescTy::UniformTexelBuffer { .. } => (1, 0, 0),
|
||||
DescriptorDescTy::StorageTexelBuffer { .. } => (1, 0, 0),
|
||||
DescriptorDescTy::UniformBuffer => (1, 0, 0),
|
||||
DescriptorDescTy::StorageBuffer => (1, 0, 0),
|
||||
DescriptorDescTy::UniformBufferDynamic => (1, 0, 0),
|
||||
DescriptorDescTy::StorageBufferDynamic => (1, 0, 0),
|
||||
};
|
||||
|
||||
t_num_bufs += num_bufs * descriptor_count;
|
||||
t_num_imgs += num_imgs * descriptor_count;
|
||||
t_num_samplers += num_samplers * descriptor_count;
|
||||
desc_writes_capacity += descriptor_count;
|
||||
|
||||
descriptors.push(BuilderDescriptor {
|
||||
desc: Some(desc),
|
||||
array_element: 0,
|
||||
});
|
||||
} else {
|
||||
descriptors.push(BuilderDescriptor {
|
||||
desc: None,
|
||||
array_element: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Self {
|
||||
layout,
|
||||
in_array: false,
|
||||
cur_binding: 0,
|
||||
descriptors,
|
||||
resources: DescriptorSetResources::new(t_num_bufs, t_num_imgs, t_num_samplers),
|
||||
desc_writes: Vec::with_capacity(desc_writes_capacity),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn output(self) -> Result<DescriptorSetBuilderOutput, DescriptorSetError> {
|
||||
if self.cur_binding != self.descriptors.len() {
|
||||
Err(DescriptorSetError::DescriptorsMissing {
|
||||
expected: self.descriptors.len(),
|
||||
obtained: self.cur_binding,
|
||||
})
|
||||
} else {
|
||||
Ok(DescriptorSetBuilderOutput {
|
||||
layout: self.layout,
|
||||
writes: self.desc_writes,
|
||||
resources: self.resources,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enter_array(&mut self) -> Result<(), DescriptorSetError> {
|
||||
if self.in_array {
|
||||
Err(DescriptorSetError::AlreadyInArray)
|
||||
} else if self.cur_binding >= self.descriptors.len() {
|
||||
Err(DescriptorSetError::TooManyDescriptors)
|
||||
} else if self.descriptors[self.cur_binding].desc.is_none() {
|
||||
Err(DescriptorSetError::DescriptorIsEmpty)
|
||||
} else {
|
||||
self.in_array = true;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn leave_array(&mut self) -> Result<(), DescriptorSetError> {
|
||||
if !self.in_array {
|
||||
Err(DescriptorSetError::NotInArray)
|
||||
} else {
|
||||
let descriptor = &self.descriptors[self.cur_binding];
|
||||
let inner_desc = match descriptor.desc.as_ref() {
|
||||
Some(some) => some,
|
||||
None => unreachable!(),
|
||||
};
|
||||
|
||||
if inner_desc.variable_count {
|
||||
if descriptor.array_element > inner_desc.descriptor_count {
|
||||
return Err(DescriptorSetError::ArrayTooManyDescriptors {
|
||||
capacity: inner_desc.descriptor_count,
|
||||
obtained: descriptor.array_element,
|
||||
});
|
||||
}
|
||||
} else if descriptor.array_element != inner_desc.descriptor_count {
|
||||
return Err(DescriptorSetError::ArrayLengthMismatch {
|
||||
expected: inner_desc.descriptor_count,
|
||||
obtained: descriptor.array_element,
|
||||
});
|
||||
}
|
||||
|
||||
self.in_array = false;
|
||||
self.cur_binding += 1;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
return Err(DescriptorSetError::WrongDescriptorType);
|
||||
}
|
||||
|
||||
self.cur_binding += 1;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_buffer(
|
||||
&mut self,
|
||||
buffer: Arc<dyn BufferAccess + 'static>,
|
||||
) -> Result<(), DescriptorSetError> {
|
||||
if buffer.inner().buffer.device().internal_object()
|
||||
!= self.layout.device().internal_object()
|
||||
{
|
||||
return Err(DescriptorSetError::ResourceWrongDevice);
|
||||
}
|
||||
|
||||
let leave_array = if !self.in_array {
|
||||
self.enter_array()?;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let descriptor = &mut self.descriptors[self.cur_binding];
|
||||
let inner_desc = match descriptor.desc.as_ref() {
|
||||
Some(some) => some,
|
||||
None => return Err(DescriptorSetError::WrongDescriptorType),
|
||||
};
|
||||
|
||||
// Note that the buffer content is not checked. This is technically not unsafe as
|
||||
// long as the data in the buffer has no invalid memory representation (ie. no
|
||||
// bool, no enum, no pointer, no str) and as long as the robust buffer access
|
||||
// feature is enabled.
|
||||
// TODO: this is not checked ^
|
||||
|
||||
// TODO: eventually shouldn't be an assert ; for now robust_buffer_access is always
|
||||
// enabled so this assert should never fail in practice, but we put it anyway
|
||||
// in case we forget to adjust this code
|
||||
|
||||
self.desc_writes.push(match inner_desc.ty {
|
||||
DescriptorDescTy::StorageBuffer | DescriptorDescTy::StorageBufferDynamic => {
|
||||
assert!(self.layout.device().enabled_features().robust_buffer_access);
|
||||
|
||||
if !buffer.inner().buffer.usage().storage_buffer {
|
||||
return Err(DescriptorSetError::MissingBufferUsage(
|
||||
MissingBufferUsage::StorageBuffer,
|
||||
));
|
||||
}
|
||||
|
||||
unsafe {
|
||||
DescriptorWrite::storage_buffer(
|
||||
self.cur_binding as u32,
|
||||
descriptor.array_element,
|
||||
&buffer,
|
||||
)
|
||||
}
|
||||
}
|
||||
DescriptorDescTy::UniformBuffer => {
|
||||
assert!(self.layout.device().enabled_features().robust_buffer_access);
|
||||
|
||||
if !buffer.inner().buffer.usage().uniform_buffer {
|
||||
return Err(DescriptorSetError::MissingBufferUsage(
|
||||
MissingBufferUsage::UniformBuffer,
|
||||
));
|
||||
}
|
||||
|
||||
unsafe {
|
||||
DescriptorWrite::uniform_buffer(
|
||||
self.cur_binding as u32,
|
||||
descriptor.array_element,
|
||||
&buffer,
|
||||
)
|
||||
}
|
||||
}
|
||||
DescriptorDescTy::UniformBufferDynamic => {
|
||||
assert!(self.layout.device().enabled_features().robust_buffer_access);
|
||||
|
||||
if !buffer.inner().buffer.usage().uniform_buffer {
|
||||
return Err(DescriptorSetError::MissingBufferUsage(
|
||||
MissingBufferUsage::UniformBuffer,
|
||||
));
|
||||
}
|
||||
|
||||
unsafe {
|
||||
DescriptorWrite::dynamic_uniform_buffer(
|
||||
self.cur_binding as u32,
|
||||
descriptor.array_element,
|
||||
&buffer,
|
||||
)
|
||||
}
|
||||
}
|
||||
_ => return Err(DescriptorSetError::WrongDescriptorType),
|
||||
});
|
||||
|
||||
self.resources.add_buffer(self.cur_binding as u32, buffer);
|
||||
descriptor.array_element += 1;
|
||||
|
||||
if leave_array {
|
||||
self.leave_array()
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_buffer_view<B>(&mut self, view: Arc<BufferView<B>>) -> Result<(), DescriptorSetError>
|
||||
where
|
||||
B: BufferAccess + 'static,
|
||||
{
|
||||
if view.device().internal_object() != self.layout.device().internal_object() {
|
||||
return Err(DescriptorSetError::ResourceWrongDevice);
|
||||
}
|
||||
|
||||
let leave_array = if !self.in_array {
|
||||
self.enter_array()?;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let descriptor = &mut self.descriptors[self.cur_binding];
|
||||
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::StorageTexelBuffer { .. } => {
|
||||
// TODO: storage_texel_buffer_atomic
|
||||
|
||||
if !view.storage_texel_buffer() {
|
||||
return Err(DescriptorSetError::MissingBufferUsage(
|
||||
MissingBufferUsage::StorageTexelBuffer,
|
||||
));
|
||||
}
|
||||
|
||||
DescriptorWrite::storage_texel_buffer(
|
||||
self.cur_binding as u32,
|
||||
descriptor.array_element,
|
||||
&view,
|
||||
)
|
||||
}
|
||||
DescriptorDescTy::UniformTexelBuffer { .. } => {
|
||||
if !view.uniform_texel_buffer() {
|
||||
return Err(DescriptorSetError::MissingBufferUsage(
|
||||
MissingBufferUsage::UniformTexelBuffer,
|
||||
));
|
||||
}
|
||||
|
||||
DescriptorWrite::uniform_texel_buffer(
|
||||
self.cur_binding as u32,
|
||||
descriptor.array_element,
|
||||
&view,
|
||||
)
|
||||
}
|
||||
_ => return Err(DescriptorSetError::WrongDescriptorType),
|
||||
});
|
||||
|
||||
self.resources
|
||||
.add_buffer_view(self.cur_binding as u32, view);
|
||||
|
||||
if leave_array {
|
||||
self.leave_array()
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_image(
|
||||
&mut self,
|
||||
image_view: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
|
||||
) -> Result<(), DescriptorSetError> {
|
||||
if image_view.image().inner().image.device().internal_object()
|
||||
!= self.layout.device().internal_object()
|
||||
{
|
||||
return Err(DescriptorSetError::ResourceWrongDevice);
|
||||
}
|
||||
|
||||
let leave_array = if !self.in_array {
|
||||
self.enter_array()?;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let descriptor = &mut self.descriptors[self.cur_binding];
|
||||
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) => {
|
||||
if !image_view.image().inner().image.usage().sampled {
|
||||
return Err(DescriptorSetError::MissingImageUsage(
|
||||
MissingImageUsage::Sampled,
|
||||
));
|
||||
}
|
||||
|
||||
image_match_desc(&image_view, &desc)?;
|
||||
|
||||
DescriptorWrite::sampled_image(
|
||||
self.cur_binding as u32,
|
||||
descriptor.array_element,
|
||||
&image_view,
|
||||
)
|
||||
}
|
||||
DescriptorDescTy::StorageImage(ref desc) => {
|
||||
if !image_view.image().inner().image.usage().storage {
|
||||
return Err(DescriptorSetError::MissingImageUsage(
|
||||
MissingImageUsage::Storage,
|
||||
));
|
||||
}
|
||||
|
||||
image_match_desc(&image_view, &desc)?;
|
||||
|
||||
if !image_view.component_mapping().is_identity() {
|
||||
return Err(DescriptorSetError::NotIdentitySwizzled);
|
||||
}
|
||||
|
||||
DescriptorWrite::storage_image(
|
||||
self.cur_binding as u32,
|
||||
descriptor.array_element,
|
||||
&image_view,
|
||||
)
|
||||
}
|
||||
DescriptorDescTy::InputAttachment { multisampled } => {
|
||||
if !image_view.image().inner().image.usage().input_attachment {
|
||||
return Err(DescriptorSetError::MissingImageUsage(
|
||||
MissingImageUsage::InputAttachment,
|
||||
));
|
||||
}
|
||||
|
||||
if !image_view.component_mapping().is_identity() {
|
||||
return Err(DescriptorSetError::NotIdentitySwizzled);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
let image_layers = image_view.array_layers();
|
||||
let num_layers = image_layers.end - image_layers.start;
|
||||
|
||||
if image_view.ty().is_arrayed() {
|
||||
return Err(DescriptorSetError::UnexpectedArrayed);
|
||||
}
|
||||
|
||||
DescriptorWrite::input_attachment(
|
||||
self.cur_binding as u32,
|
||||
descriptor.array_element,
|
||||
&image_view,
|
||||
)
|
||||
}
|
||||
_ => return Err(DescriptorSetError::WrongDescriptorType),
|
||||
});
|
||||
|
||||
descriptor.array_element += 1;
|
||||
self.resources
|
||||
.add_image(self.cur_binding as u32, image_view);
|
||||
|
||||
if leave_array {
|
||||
self.leave_array()
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_sampled_image(
|
||||
&mut self,
|
||||
image_view: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
|
||||
sampler: Arc<Sampler>,
|
||||
) -> Result<(), DescriptorSetError> {
|
||||
if image_view.image().inner().image.device().internal_object()
|
||||
!= self.layout.device().internal_object()
|
||||
{
|
||||
return Err(DescriptorSetError::ResourceWrongDevice);
|
||||
}
|
||||
|
||||
if sampler.device().internal_object() != self.layout.device().internal_object() {
|
||||
return Err(DescriptorSetError::ResourceWrongDevice);
|
||||
}
|
||||
|
||||
if !image_view.image().inner().image.usage().sampled {
|
||||
return Err(DescriptorSetError::MissingImageUsage(
|
||||
MissingImageUsage::Sampled,
|
||||
));
|
||||
}
|
||||
|
||||
if !image_view.can_be_sampled(&sampler) {
|
||||
return Err(DescriptorSetError::IncompatibleImageViewSampler);
|
||||
}
|
||||
|
||||
let leave_array = if !self.in_array {
|
||||
self.enter_array()?;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let descriptor = &mut self.descriptors[self.cur_binding];
|
||||
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)?;
|
||||
|
||||
DescriptorWrite::combined_image_sampler(
|
||||
self.cur_binding as u32,
|
||||
descriptor.array_element,
|
||||
&sampler,
|
||||
&image_view,
|
||||
)
|
||||
}
|
||||
_ => return Err(DescriptorSetError::WrongDescriptorType),
|
||||
});
|
||||
|
||||
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);
|
||||
|
||||
if leave_array {
|
||||
self.leave_array()
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
let leave_array = if !self.in_array {
|
||||
self.enter_array()?;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let descriptor = &mut self.descriptors[self.cur_binding];
|
||||
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,
|
||||
),
|
||||
_ => return Err(DescriptorSetError::WrongDescriptorType),
|
||||
});
|
||||
|
||||
descriptor.array_element += 1;
|
||||
self.resources.add_sampler(self.cur_binding as u32, sampler);
|
||||
|
||||
if leave_array {
|
||||
self.leave_array()
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl DeviceOwned for DescriptorSetBuilder {
|
||||
fn device(&self) -> &Arc<Device> {
|
||||
self.layout.device()
|
||||
}
|
||||
}
|
||||
|
||||
// Checks whether an image view matches the descriptor.
|
||||
fn image_match_desc<I>(image_view: &I, desc: &DescriptorDescImage) -> Result<(), DescriptorSetError>
|
||||
where
|
||||
I: ?Sized + ImageViewAbstract,
|
||||
{
|
||||
if image_view.ty() != desc.view_type
|
||||
&& match desc.view_type {
|
||||
ImageViewType::Dim1dArray => image_view.ty() != ImageViewType::Dim1d,
|
||||
ImageViewType::Dim2dArray => image_view.ty() != ImageViewType::Dim2d,
|
||||
ImageViewType::CubeArray => image_view.ty() != ImageViewType::Cube,
|
||||
_ => true,
|
||||
}
|
||||
{
|
||||
return Err(DescriptorSetError::ImageViewTypeMismatch {
|
||||
expected: desc.view_type,
|
||||
obtained: image_view.ty(),
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(format) = desc.format {
|
||||
if image_view.format() != format {
|
||||
return Err(DescriptorSetError::ImageViewFormatMismatch {
|
||||
expected: format,
|
||||
obtained: image_view.format(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if desc.multisampled && image_view.image().samples() == SampleCount::Sample1 {
|
||||
return Err(DescriptorSetError::ExpectedMultisampled);
|
||||
} else if !desc.multisampled && image_view.image().samples() != SampleCount::Sample1 {
|
||||
return Err(DescriptorSetError::UnexpectedMultisampled);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
@ -1,604 +0,0 @@
|
||||
// Copyright (c) 2017 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.
|
||||
|
||||
//! Pool of descriptor sets of a specific capacity that are automatically reclaimed.
|
||||
//!
|
||||
//! You are encouraged to use this type when you need a different descriptor set at each frame, or
|
||||
//! regularly during the execution.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! At initialization, create a `FixedSizeDescriptorSetsPool`.
|
||||
//!
|
||||
//! ```rust
|
||||
//! use vulkano::descriptor_set::FixedSizeDescriptorSetsPool;
|
||||
//! # use vulkano::pipeline::GraphicsPipeline;
|
||||
//! # use std::sync::Arc;
|
||||
//! # let graphics_pipeline: Arc<GraphicsPipeline> = return;
|
||||
//! // use vulkano::pipeline::GraphicsPipeline;
|
||||
//! // let graphics_pipeline: Arc<GraphicsPipeline> = ...;
|
||||
//!
|
||||
//! let layout = graphics_pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
//! let pool = FixedSizeDescriptorSetsPool::new(layout.clone());
|
||||
//! ```
|
||||
//!
|
||||
//! You would then typically store the pool in a struct for later. Then whenever you need a
|
||||
//! descriptor set, call `pool.next()` to start the process of building it.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use std::sync::Arc;
|
||||
//! # use vulkano::descriptor_set::FixedSizeDescriptorSetsPool;
|
||||
//! # use vulkano::pipeline::GraphicsPipeline;
|
||||
//! # let mut pool: FixedSizeDescriptorSetsPool = return;
|
||||
//! let descriptor_set = pool.next()
|
||||
//! //.add_buffer(...)
|
||||
//! //.add_sampled_image(...)
|
||||
//! .build().unwrap();
|
||||
//! ```
|
||||
//!
|
||||
//! Note that `next()` requires exclusive (`mut`) access to the pool. You can use a `Mutex` around
|
||||
//! the pool if you can't provide this.
|
||||
|
||||
use crate::buffer::BufferAccess;
|
||||
use crate::buffer::BufferViewRef;
|
||||
use crate::descriptor_set::layout::DescriptorSetLayout;
|
||||
use crate::descriptor_set::persistent::*;
|
||||
use crate::descriptor_set::pool::DescriptorPool;
|
||||
use crate::descriptor_set::pool::DescriptorPoolAlloc;
|
||||
use crate::descriptor_set::pool::DescriptorPoolAllocError;
|
||||
use crate::descriptor_set::pool::UnsafeDescriptorPool;
|
||||
use crate::descriptor_set::DescriptorSet;
|
||||
use crate::descriptor_set::UnsafeDescriptorSet;
|
||||
use crate::device::Device;
|
||||
use crate::device::DeviceOwned;
|
||||
use crate::image::view::ImageViewAbstract;
|
||||
use crate::sampler::Sampler;
|
||||
use crate::OomError;
|
||||
use crate::VulkanObject;
|
||||
use crossbeam_queue::SegQueue;
|
||||
use std::hash::Hash;
|
||||
use std::hash::Hasher;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Pool of descriptor sets of a specific capacity that are automatically reclaimed.
|
||||
#[derive(Clone)]
|
||||
pub struct FixedSizeDescriptorSetsPool {
|
||||
layout: Arc<DescriptorSetLayout>,
|
||||
// We hold a local implementation of the `DescriptorPool` trait for our own purpose. Since we
|
||||
// don't want to expose this trait impl in our API, we use a separate struct.
|
||||
pool: LocalPool,
|
||||
}
|
||||
|
||||
impl FixedSizeDescriptorSetsPool {
|
||||
/// Initializes a new pool. The pool is configured to allocate sets that corresponds to the
|
||||
/// parameters passed to this function.
|
||||
pub fn new(layout: Arc<DescriptorSetLayout>) -> FixedSizeDescriptorSetsPool {
|
||||
let device = layout.device().clone();
|
||||
|
||||
FixedSizeDescriptorSetsPool {
|
||||
layout,
|
||||
pool: LocalPool {
|
||||
device,
|
||||
next_capacity: 3,
|
||||
current_pool: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Starts the process of building a new descriptor set.
|
||||
///
|
||||
/// The set will corresponds to the set layout that was passed to `new`.
|
||||
#[inline]
|
||||
pub fn next(&mut self) -> FixedSizeDescriptorSetBuilder<()> {
|
||||
let inner = PersistentDescriptorSet::start(self.layout.clone());
|
||||
|
||||
FixedSizeDescriptorSetBuilder { pool: self, inner }
|
||||
}
|
||||
}
|
||||
|
||||
/// A descriptor set created from a `FixedSizeDescriptorSetsPool`.
|
||||
pub struct FixedSizeDescriptorSet<R> {
|
||||
inner: PersistentDescriptorSet<R, LocalPoolAlloc>,
|
||||
}
|
||||
|
||||
unsafe impl<R> DescriptorSet for FixedSizeDescriptorSet<R>
|
||||
where
|
||||
R: PersistentDescriptorSetResources,
|
||||
{
|
||||
#[inline]
|
||||
fn inner(&self) -> &UnsafeDescriptorSet {
|
||||
self.inner.inner()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn layout(&self) -> &Arc<DescriptorSetLayout> {
|
||||
self.inner.layout()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn num_buffers(&self) -> usize {
|
||||
self.inner.num_buffers()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> {
|
||||
self.inner.buffer(index)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn num_images(&self) -> usize {
|
||||
self.inner.num_images()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
|
||||
self.inner.image(index)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<R> DeviceOwned for FixedSizeDescriptorSet<R> {
|
||||
#[inline]
|
||||
fn device(&self) -> &Arc<Device> {
|
||||
self.inner.device()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> PartialEq for FixedSizeDescriptorSet<R>
|
||||
where
|
||||
R: PersistentDescriptorSetResources,
|
||||
{
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.inner().internal_object() == other.inner().internal_object()
|
||||
&& self.device() == other.device()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Eq for FixedSizeDescriptorSet<R> where R: PersistentDescriptorSetResources {}
|
||||
|
||||
impl<R> Hash for FixedSizeDescriptorSet<R>
|
||||
where
|
||||
R: PersistentDescriptorSetResources,
|
||||
{
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.inner().internal_object().hash(state);
|
||||
self.device().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
// The fields of this struct can be considered as fields of the `FixedSizeDescriptorSet`. They are
|
||||
// in a separate struct because we don't want to expose the fact that we implement the
|
||||
// `DescriptorPool` trait.
|
||||
#[derive(Clone)]
|
||||
struct LocalPool {
|
||||
// The `LocalPoolInner` struct contains an actual Vulkan pool. Every time it is full, we create
|
||||
// a new pool and replace the current one with the new one.
|
||||
current_pool: Option<Arc<LocalPoolInner>>,
|
||||
// Capacity to use when we create a new Vulkan pool.
|
||||
next_capacity: u32,
|
||||
// The Vulkan device.
|
||||
device: Arc<Device>,
|
||||
}
|
||||
|
||||
struct LocalPoolInner {
|
||||
// The actual Vulkan descriptor pool. This field isn't actually used anywhere, but we need to
|
||||
// keep the pool alive in order to keep the descriptor sets valid.
|
||||
actual_pool: UnsafeDescriptorPool,
|
||||
|
||||
// List of descriptor sets. When `alloc` is called, a descriptor will be extracted from this
|
||||
// list. When a `LocalPoolAlloc` is dropped, its descriptor set is put back in this list.
|
||||
reserve: SegQueue<UnsafeDescriptorSet>,
|
||||
}
|
||||
|
||||
struct LocalPoolAlloc {
|
||||
// The `LocalPoolInner` we were allocated from. We need to keep a copy of it in each allocation
|
||||
// so that we can put back the allocation in the list in our `Drop` impl.
|
||||
pool: Arc<LocalPoolInner>,
|
||||
|
||||
// The actual descriptor set, wrapped inside an `Option` so that we can extract it in our
|
||||
// `Drop` impl.
|
||||
actual_alloc: Option<UnsafeDescriptorSet>,
|
||||
}
|
||||
|
||||
unsafe impl DescriptorPool for LocalPool {
|
||||
type Alloc = LocalPoolAlloc;
|
||||
|
||||
fn alloc(&mut self, layout: &DescriptorSetLayout) -> Result<Self::Alloc, OomError> {
|
||||
loop {
|
||||
// Try to extract a descriptor from the current pool if any exist.
|
||||
// This is the most common case.
|
||||
if let Some(ref mut current_pool) = self.current_pool {
|
||||
if let Some(already_existing_set) = current_pool.reserve.pop() {
|
||||
return Ok(LocalPoolAlloc {
|
||||
actual_alloc: Some(already_existing_set),
|
||||
pool: current_pool.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// If we failed to grab an existing set, that means the current pool is full. Create a
|
||||
// new one of larger capacity.
|
||||
let count = *layout.descriptors_count() * self.next_capacity;
|
||||
let mut new_pool =
|
||||
UnsafeDescriptorPool::new(self.device.clone(), &count, self.next_capacity, false)?;
|
||||
let alloc = unsafe {
|
||||
match new_pool.alloc((0..self.next_capacity).map(|_| layout)) {
|
||||
Ok(iter) => {
|
||||
let stack = SegQueue::new();
|
||||
for elem in iter {
|
||||
stack.push(elem);
|
||||
}
|
||||
stack
|
||||
}
|
||||
Err(DescriptorPoolAllocError::OutOfHostMemory) => {
|
||||
return Err(OomError::OutOfHostMemory);
|
||||
}
|
||||
Err(DescriptorPoolAllocError::OutOfDeviceMemory) => {
|
||||
return Err(OomError::OutOfDeviceMemory);
|
||||
}
|
||||
Err(DescriptorPoolAllocError::FragmentedPool) => {
|
||||
// This can't happen as we don't free individual sets.
|
||||
unreachable!()
|
||||
}
|
||||
Err(DescriptorPoolAllocError::OutOfPoolMemory) => unreachable!(),
|
||||
}
|
||||
};
|
||||
|
||||
self.next_capacity = self.next_capacity.saturating_mul(2);
|
||||
self.current_pool = Some(Arc::new(LocalPoolInner {
|
||||
actual_pool: new_pool,
|
||||
reserve: alloc,
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl DeviceOwned for LocalPool {
|
||||
#[inline]
|
||||
fn device(&self) -> &Arc<Device> {
|
||||
&self.device
|
||||
}
|
||||
}
|
||||
|
||||
impl DescriptorPoolAlloc for LocalPoolAlloc {
|
||||
#[inline]
|
||||
fn inner(&self) -> &UnsafeDescriptorSet {
|
||||
self.actual_alloc.as_ref().unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn inner_mut(&mut self) -> &mut UnsafeDescriptorSet {
|
||||
self.actual_alloc.as_mut().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for LocalPoolAlloc {
|
||||
fn drop(&mut self) {
|
||||
let inner = self.actual_alloc.take().unwrap();
|
||||
self.pool.reserve.push(inner);
|
||||
}
|
||||
}
|
||||
|
||||
/// Prototype of a `FixedSizeDescriptorSet`.
|
||||
///
|
||||
/// The template parameter `R` is an unspecified type that represents the list of resources.
|
||||
///
|
||||
/// See the docs of `FixedSizeDescriptorSetsPool` for an example.
|
||||
pub struct FixedSizeDescriptorSetBuilder<'a, R> {
|
||||
pool: &'a mut FixedSizeDescriptorSetsPool,
|
||||
inner: PersistentDescriptorSetBuilder<R>,
|
||||
}
|
||||
|
||||
impl<'a, R> FixedSizeDescriptorSetBuilder<'a, R> {
|
||||
/// Builds a `FixedSizeDescriptorSet` from the builder.
|
||||
#[inline]
|
||||
pub fn build(self) -> Result<FixedSizeDescriptorSet<R>, PersistentDescriptorSetBuildError> {
|
||||
let inner = self.inner.build_with_pool(&mut self.pool.pool)?;
|
||||
Ok(FixedSizeDescriptorSet { inner })
|
||||
}
|
||||
|
||||
/// Call this function if the next element of the set is an array in order to set the value of
|
||||
/// each element.
|
||||
///
|
||||
/// Returns an error if the descriptor is empty.
|
||||
///
|
||||
/// 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.
|
||||
#[inline]
|
||||
pub fn enter_array(
|
||||
self,
|
||||
) -> Result<FixedSizeDescriptorSetBuilderArray<'a, R>, PersistentDescriptorSetError> {
|
||||
Ok(FixedSizeDescriptorSetBuilderArray {
|
||||
pool: self.pool,
|
||||
inner: self.inner.enter_array()?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Skips the current descriptor if it is empty.
|
||||
#[inline]
|
||||
pub fn add_empty(
|
||||
self,
|
||||
) -> Result<FixedSizeDescriptorSetBuilder<'a, R>, PersistentDescriptorSetError> {
|
||||
Ok(FixedSizeDescriptorSetBuilder {
|
||||
pool: self.pool,
|
||||
inner: self.inner.add_empty()?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Binds a buffer as the next descriptor.
|
||||
///
|
||||
/// An error is returned if the buffer isn't compatible with the descriptor.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// Panics if the buffer doesn't have the same device as the descriptor set layout.
|
||||
///
|
||||
#[inline]
|
||||
pub fn add_buffer<T>(
|
||||
self,
|
||||
buffer: T,
|
||||
) -> Result<
|
||||
FixedSizeDescriptorSetBuilder<'a, (R, PersistentDescriptorSetBuf<T>)>,
|
||||
PersistentDescriptorSetError,
|
||||
>
|
||||
where
|
||||
T: BufferAccess,
|
||||
{
|
||||
Ok(FixedSizeDescriptorSetBuilder {
|
||||
pool: self.pool,
|
||||
inner: self.inner.add_buffer(buffer)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Binds a buffer view as the next descriptor.
|
||||
///
|
||||
/// An error is returned if the buffer isn't compatible with the descriptor.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// Panics if the buffer view doesn't have the same device as the descriptor set layout.
|
||||
///
|
||||
pub fn add_buffer_view<T>(
|
||||
self,
|
||||
view: T,
|
||||
) -> Result<
|
||||
FixedSizeDescriptorSetBuilder<'a, (R, PersistentDescriptorSetBufView<T>)>,
|
||||
PersistentDescriptorSetError,
|
||||
>
|
||||
where
|
||||
T: BufferViewRef,
|
||||
{
|
||||
Ok(FixedSizeDescriptorSetBuilder {
|
||||
pool: self.pool,
|
||||
inner: self.inner.add_buffer_view(view)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Binds an image view as the next descriptor.
|
||||
///
|
||||
/// An error is returned if the image view isn't compatible with the descriptor.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// Panics if the image view doesn't have the same device as the descriptor set layout.
|
||||
///
|
||||
#[inline]
|
||||
pub fn add_image<T>(
|
||||
self,
|
||||
image_view: T,
|
||||
) -> Result<
|
||||
FixedSizeDescriptorSetBuilder<'a, (R, PersistentDescriptorSetImg<T>)>,
|
||||
PersistentDescriptorSetError,
|
||||
>
|
||||
where
|
||||
T: ImageViewAbstract,
|
||||
{
|
||||
Ok(FixedSizeDescriptorSetBuilder {
|
||||
pool: self.pool,
|
||||
inner: self.inner.add_image(image_view)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Binds an image view with a sampler as the next descriptor.
|
||||
///
|
||||
/// An error is returned if the image view isn't compatible with the descriptor.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// Panics if the image view or the sampler doesn't have the same device as the descriptor set layout.
|
||||
///
|
||||
#[inline]
|
||||
pub fn add_sampled_image<T>(
|
||||
self,
|
||||
image_view: T,
|
||||
sampler: Arc<Sampler>,
|
||||
) -> Result<
|
||||
FixedSizeDescriptorSetBuilder<
|
||||
'a,
|
||||
(
|
||||
(R, PersistentDescriptorSetImg<T>),
|
||||
PersistentDescriptorSetSampler,
|
||||
),
|
||||
>,
|
||||
PersistentDescriptorSetError,
|
||||
>
|
||||
where
|
||||
T: ImageViewAbstract,
|
||||
{
|
||||
Ok(FixedSizeDescriptorSetBuilder {
|
||||
pool: self.pool,
|
||||
inner: self.inner.add_sampled_image(image_view, sampler)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Binds a sampler as the next descriptor.
|
||||
///
|
||||
/// An error is returned if the sampler isn't compatible with the descriptor.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// Panics if the sampler doesn't have the same device as the descriptor set layout.
|
||||
///
|
||||
#[inline]
|
||||
pub fn add_sampler(
|
||||
self,
|
||||
sampler: Arc<Sampler>,
|
||||
) -> Result<
|
||||
FixedSizeDescriptorSetBuilder<'a, (R, PersistentDescriptorSetSampler)>,
|
||||
PersistentDescriptorSetError,
|
||||
> {
|
||||
Ok(FixedSizeDescriptorSetBuilder {
|
||||
pool: self.pool,
|
||||
inner: self.inner.add_sampler(sampler)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Same as `FixedSizeDescriptorSetBuilder`, but we're in an array.
|
||||
pub struct FixedSizeDescriptorSetBuilderArray<'a, R> {
|
||||
pool: &'a mut FixedSizeDescriptorSetsPool,
|
||||
inner: PersistentDescriptorSetBuilderArray<R>,
|
||||
}
|
||||
|
||||
impl<'a, R> FixedSizeDescriptorSetBuilderArray<'a, R> {
|
||||
/// Leaves the array. Call this once you added all the elements of the array.
|
||||
pub fn leave_array(
|
||||
self,
|
||||
) -> Result<FixedSizeDescriptorSetBuilder<'a, R>, PersistentDescriptorSetError> {
|
||||
Ok(FixedSizeDescriptorSetBuilder {
|
||||
pool: self.pool,
|
||||
inner: self.inner.leave_array()?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Binds a buffer as the next element in the array.
|
||||
///
|
||||
/// An error is returned if the buffer isn't compatible with the descriptor.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// Panics if the buffer doesn't have the same device as the descriptor set layout.
|
||||
///
|
||||
pub fn add_buffer<T>(
|
||||
self,
|
||||
buffer: T,
|
||||
) -> Result<
|
||||
FixedSizeDescriptorSetBuilderArray<'a, (R, PersistentDescriptorSetBuf<T>)>,
|
||||
PersistentDescriptorSetError,
|
||||
>
|
||||
where
|
||||
T: BufferAccess,
|
||||
{
|
||||
Ok(FixedSizeDescriptorSetBuilderArray {
|
||||
pool: self.pool,
|
||||
inner: self.inner.add_buffer(buffer)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Binds a buffer view as the next element in the array.
|
||||
///
|
||||
/// An error is returned if the buffer isn't compatible with the descriptor.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// Panics if the buffer view doesn't have the same device as the descriptor set layout.
|
||||
///
|
||||
pub fn add_buffer_view<T>(
|
||||
self,
|
||||
view: T,
|
||||
) -> Result<
|
||||
FixedSizeDescriptorSetBuilderArray<'a, (R, PersistentDescriptorSetBufView<T>)>,
|
||||
PersistentDescriptorSetError,
|
||||
>
|
||||
where
|
||||
T: BufferViewRef,
|
||||
{
|
||||
Ok(FixedSizeDescriptorSetBuilderArray {
|
||||
pool: self.pool,
|
||||
inner: self.inner.add_buffer_view(view)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Binds an image view as the next element in the array.
|
||||
///
|
||||
/// An error is returned if the image view isn't compatible with the descriptor.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// Panics if the image view doesn't have the same device as the descriptor set layout.
|
||||
///
|
||||
pub fn add_image<T>(
|
||||
self,
|
||||
image_view: T,
|
||||
) -> Result<
|
||||
FixedSizeDescriptorSetBuilderArray<'a, (R, PersistentDescriptorSetImg<T>)>,
|
||||
PersistentDescriptorSetError,
|
||||
>
|
||||
where
|
||||
T: ImageViewAbstract,
|
||||
{
|
||||
Ok(FixedSizeDescriptorSetBuilderArray {
|
||||
pool: self.pool,
|
||||
inner: self.inner.add_image(image_view)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Binds an image view with a sampler as the next element in the array.
|
||||
///
|
||||
/// An error is returned if the image view isn't compatible with the descriptor.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// Panics if the image or the sampler doesn't have the same device as the descriptor set layout.
|
||||
///
|
||||
pub fn add_sampled_image<T>(
|
||||
self,
|
||||
image_view: T,
|
||||
sampler: Arc<Sampler>,
|
||||
) -> Result<
|
||||
FixedSizeDescriptorSetBuilderArray<
|
||||
'a,
|
||||
(
|
||||
(R, PersistentDescriptorSetImg<T>),
|
||||
PersistentDescriptorSetSampler,
|
||||
),
|
||||
>,
|
||||
PersistentDescriptorSetError,
|
||||
>
|
||||
where
|
||||
T: ImageViewAbstract,
|
||||
{
|
||||
Ok(FixedSizeDescriptorSetBuilderArray {
|
||||
pool: self.pool,
|
||||
inner: self.inner.add_sampled_image(image_view, sampler)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Binds a sampler as the next element in the array.
|
||||
///
|
||||
/// An error is returned if the sampler isn't compatible with the descriptor.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// Panics if the sampler doesn't have the same device as the descriptor set layout.
|
||||
///
|
||||
pub fn add_sampler(
|
||||
self,
|
||||
sampler: Arc<Sampler>,
|
||||
) -> Result<
|
||||
FixedSizeDescriptorSetBuilderArray<'a, (R, PersistentDescriptorSetSampler)>,
|
||||
PersistentDescriptorSetError,
|
||||
> {
|
||||
Ok(FixedSizeDescriptorSetBuilderArray {
|
||||
pool: self.pool,
|
||||
inner: self.inner.add_sampler(sampler)?,
|
||||
})
|
||||
}
|
||||
}
|
@ -187,6 +187,24 @@ impl DescriptorSetDesc {
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
None => panic!("descriptor is empty"),
|
||||
},
|
||||
None => panic!("descriptor doesn't exist"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether `self` is compatible with `other`.
|
||||
///
|
||||
/// "Compatible" in this sense is defined by the Vulkan specification under the section
|
||||
@ -319,6 +337,9 @@ pub struct DescriptorDesc {
|
||||
/// Which shader stages are going to access this descriptor.
|
||||
pub stages: ShaderStages,
|
||||
|
||||
/// True if the descriptor has a variable descriptor count.
|
||||
pub variable_count: bool,
|
||||
|
||||
/// True if the attachment can be written by the shader.
|
||||
pub mutable: bool,
|
||||
}
|
||||
@ -332,8 +353,9 @@ impl DescriptorDesc {
|
||||
#[inline]
|
||||
pub fn is_compatible_with(&self, other: &DescriptorDesc) -> bool {
|
||||
self.ty.ty() == other.ty.ty()
|
||||
&& self.descriptor_count == other.descriptor_count
|
||||
&& self.stages == other.stages
|
||||
&& self.descriptor_count == other.descriptor_count
|
||||
&& self.variable_count == other.variable_count
|
||||
}
|
||||
|
||||
/// Checks whether the descriptor of a pipeline layout `self` is compatible with the descriptor
|
||||
@ -363,6 +385,13 @@ impl DescriptorDesc {
|
||||
});
|
||||
}
|
||||
|
||||
if self.variable_count != other.variable_count {
|
||||
return Err(DescriptorCompatibilityError::VariableCount {
|
||||
first: self.variable_count,
|
||||
second: other.variable_count,
|
||||
});
|
||||
}
|
||||
|
||||
if !self.mutable && other.mutable {
|
||||
return Err(DescriptorCompatibilityError::Mutability {
|
||||
first: self.mutable,
|
||||
@ -396,6 +425,13 @@ impl DescriptorDesc {
|
||||
});
|
||||
}
|
||||
|
||||
if self.variable_count != other.variable_count {
|
||||
return Err(DescriptorCompatibilityError::VariableCount {
|
||||
first: self.variable_count,
|
||||
second: other.variable_count,
|
||||
});
|
||||
}
|
||||
|
||||
if self.mutable && !other.mutable {
|
||||
return Err(DescriptorCompatibilityError::Mutability {
|
||||
first: self.mutable,
|
||||
@ -426,7 +462,7 @@ impl DescriptorDesc {
|
||||
/// geometry: true,
|
||||
/// fragment: false,
|
||||
/// compute: true
|
||||
///}, mutable: true };
|
||||
///}, mutable: true, variable_count: false };
|
||||
///
|
||||
///let desc_part2 = DescriptorDesc{ ty: Sampler, descriptor_count: 1, stages: ShaderStages{
|
||||
/// vertex: true,
|
||||
@ -435,7 +471,7 @@ impl DescriptorDesc {
|
||||
/// geometry: false,
|
||||
/// fragment: true,
|
||||
/// compute: true
|
||||
///}, mutable: false };
|
||||
///}, mutable: false, variable_count: false };
|
||||
///
|
||||
///let desc_union = DescriptorDesc{ ty: Sampler, descriptor_count: 2, stages: ShaderStages{
|
||||
/// vertex: true,
|
||||
@ -444,7 +480,7 @@ impl DescriptorDesc {
|
||||
/// geometry: true,
|
||||
/// fragment: true,
|
||||
/// compute: true
|
||||
///}, mutable: true };
|
||||
///}, mutable: true, variable_count: false };
|
||||
///
|
||||
///assert_eq!(DescriptorDesc::union(Some(&desc_part1), Some(&desc_part2)), Ok(Some(desc_union)));
|
||||
///```
|
||||
@ -463,6 +499,7 @@ impl DescriptorDesc {
|
||||
descriptor_count: cmp::max(first.descriptor_count, second.descriptor_count),
|
||||
stages: first.stages | second.stages,
|
||||
mutable: first.mutable || second.mutable,
|
||||
variable_count: first.variable_count && second.variable_count, // TODO: What is the correct behavior here?
|
||||
}))
|
||||
} else {
|
||||
Ok(first.or(second).cloned())
|
||||
@ -750,6 +787,12 @@ pub enum DescriptorCompatibilityError {
|
||||
second: u32,
|
||||
},
|
||||
|
||||
/// The variable counts of the descriptors is not compatible.
|
||||
VariableCount {
|
||||
first: bool,
|
||||
second: bool,
|
||||
},
|
||||
|
||||
/// The presence or absence of a descriptor in a binding is not compatible.
|
||||
Empty {
|
||||
first: bool,
|
||||
@ -805,6 +848,9 @@ impl fmt::Display for DescriptorCompatibilityError {
|
||||
DescriptorCompatibilityError::DescriptorCount { .. } => {
|
||||
"the number of descriptors is not compatible"
|
||||
}
|
||||
DescriptorCompatibilityError::VariableCount { .. } => {
|
||||
"the variable counts of the descriptors is not compatible"
|
||||
}
|
||||
DescriptorCompatibilityError::Empty { .. } => {
|
||||
"the presence or absence of a descriptor in a binding is not compatible"
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ pub use self::desc::DescriptorSetCompatibilityError;
|
||||
pub use self::desc::DescriptorSetDesc;
|
||||
pub use self::desc::DescriptorType;
|
||||
pub use self::sys::DescriptorSetLayout;
|
||||
pub use self::sys::DescriptorSetLayoutError;
|
||||
|
||||
mod desc;
|
||||
mod sys;
|
||||
|
@ -9,12 +9,14 @@
|
||||
|
||||
use crate::check_errors;
|
||||
use crate::descriptor_set::layout::DescriptorDesc;
|
||||
use crate::descriptor_set::layout::DescriptorDescTy;
|
||||
use crate::descriptor_set::layout::DescriptorSetCompatibilityError;
|
||||
use crate::descriptor_set::layout::DescriptorSetDesc;
|
||||
use crate::descriptor_set::pool::DescriptorsCount;
|
||||
use crate::device::Device;
|
||||
use crate::device::DeviceOwned;
|
||||
use crate::OomError;
|
||||
use crate::Version;
|
||||
use crate::VulkanObject;
|
||||
use smallvec::SmallVec;
|
||||
use std::mem::MaybeUninit;
|
||||
@ -40,58 +42,151 @@ impl DescriptorSetLayout {
|
||||
/// The descriptors must be passed in the order of the bindings. In order words, descriptor
|
||||
/// at bind point 0 first, then descriptor at bind point 1, and so on. If a binding must remain
|
||||
/// empty, you can make the iterator yield `None` for an element.
|
||||
pub fn new<D>(device: Arc<Device>, desc: D) -> Result<DescriptorSetLayout, OomError>
|
||||
pub fn new<D>(
|
||||
device: Arc<Device>,
|
||||
desc: D,
|
||||
) -> Result<DescriptorSetLayout, DescriptorSetLayoutError>
|
||||
where
|
||||
D: Into<DescriptorSetDesc>,
|
||||
{
|
||||
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 bindings = desc
|
||||
.bindings()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(binding, desc)| {
|
||||
let desc = match desc {
|
||||
Some(d) => d,
|
||||
None => return None,
|
||||
};
|
||||
for (binding, desc) in bindings.iter().enumerate() {
|
||||
let desc = match desc {
|
||||
Some(d) => d,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
// FIXME: it is not legal to pass eg. the TESSELLATION_SHADER bit when the device
|
||||
// doesn't have tess shaders enabled
|
||||
// FIXME: it is not legal to pass eg. the TESSELLATION_SHADER bit when the device
|
||||
// doesn't have tess shaders enabled
|
||||
|
||||
let ty = desc.ty.ty();
|
||||
descriptors_count.add_num(ty, desc.descriptor_count);
|
||||
let ty = desc.ty.ty();
|
||||
descriptors_count.add_num(ty, desc.descriptor_count);
|
||||
|
||||
Some(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
|
||||
})
|
||||
})
|
||||
.collect::<SmallVec<[_; 32]>>();
|
||||
if desc.variable_count {
|
||||
if binding != bindings.len() - 1 {
|
||||
return Err(DescriptorSetLayoutError::VariableCountDescMustBeLast);
|
||||
}
|
||||
|
||||
if desc.ty == DescriptorDescTy::UniformBufferDynamic
|
||||
|| desc.ty == DescriptorDescTy::StorageBufferDynamic
|
||||
{
|
||||
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 {
|
||||
let infos = ash::vk::DescriptorSetLayoutCreateInfo {
|
||||
flags: ash::vk::DescriptorSetLayoutCreateFlags::empty(),
|
||||
binding_count: bindings.len() as u32,
|
||||
p_bindings: bindings.as_ptr(),
|
||||
..Default::default()
|
||||
};
|
||||
if variable_descriptor_count {
|
||||
let enabled_features = device.enabled_features();
|
||||
let api_version = device.api_version();
|
||||
let enabled_extensions = device.enabled_extensions();
|
||||
|
||||
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(),
|
||||
))?;
|
||||
output.assume_init()
|
||||
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 {
|
||||
return Err(DescriptorSetLayoutError::VariableCountIncompatibleDevice(
|
||||
IncompatibleDevice::MissingFeature(MissingFeature::RuntimeDescriptorArray),
|
||||
));
|
||||
}
|
||||
|
||||
if !enabled_features.descriptor_binding_variable_descriptor_count {
|
||||
return Err(DescriptorSetLayoutError::VariableCountIncompatibleDevice(
|
||||
IncompatibleDevice::MissingFeature(
|
||||
MissingFeature::DescriptorBindingVariableDescriptorCount,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
if !enabled_features.descriptor_binding_partially_bound {
|
||||
return Err(DescriptorSetLayoutError::VariableCountIncompatibleDevice(
|
||||
IncompatibleDevice::MissingFeature(
|
||||
MissingFeature::DescriptorBindingPartiallyBound,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
};
|
||||
|
||||
Ok(DescriptorSetLayout {
|
||||
@ -182,6 +277,77 @@ impl Drop for DescriptorSetLayout {
|
||||
}
|
||||
}
|
||||
|
||||
/// Error related to descriptor set layout
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum DescriptorSetLayoutError {
|
||||
/// Out of Memory
|
||||
OomError(OomError),
|
||||
|
||||
/// Variable count descriptor must be last binding
|
||||
VariableCountDescMustBeLast,
|
||||
|
||||
/// Variable count descriptor must not be a dynamic buffer
|
||||
VariableCountDescMustNotBeDynamic,
|
||||
|
||||
/// Device is not compatible with variable count descriptors
|
||||
VariableCountIncompatibleDevice(IncompatibleDevice),
|
||||
}
|
||||
|
||||
// Part of the DescriptorSetLayoutError for the case
|
||||
// of missing features on a device.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum IncompatibleDevice {
|
||||
MissingExtension(MissingExtension),
|
||||
MissingFeature(MissingFeature),
|
||||
InsufficientApiVersion {
|
||||
required: Version,
|
||||
obtained: Version,
|
||||
},
|
||||
}
|
||||
|
||||
// Part of the IncompatibleDevice for the case
|
||||
// of missing features on a device.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum MissingFeature {
|
||||
RuntimeDescriptorArray,
|
||||
DescriptorBindingVariableDescriptorCount,
|
||||
DescriptorBindingPartiallyBound,
|
||||
}
|
||||
|
||||
// Part of the IncompatibleDevice for the case
|
||||
// of missing extensions on a device.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum MissingExtension {
|
||||
DescriptorIndexing,
|
||||
}
|
||||
|
||||
impl From<OomError> for DescriptorSetLayoutError {
|
||||
fn from(error: OomError) -> Self {
|
||||
Self::OomError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for DescriptorSetLayoutError {}
|
||||
|
||||
impl std::fmt::Display for DescriptorSetLayoutError {
|
||||
#[inline]
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
write!(
|
||||
fmt,
|
||||
"{}",
|
||||
match *self {
|
||||
Self::OomError(_) => "out of memory",
|
||||
Self::VariableCountDescMustBeLast =>
|
||||
"variable count descriptor must be last binding",
|
||||
Self::VariableCountDescMustNotBeDynamic =>
|
||||
"variable count descriptor must not be a dynamic buffer",
|
||||
Self::VariableCountIncompatibleDevice(_) =>
|
||||
"device is not compatible with variable count descriptors",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::descriptor_set::layout::DescriptorDesc;
|
||||
@ -207,6 +373,7 @@ mod tests {
|
||||
descriptor_count: 1,
|
||||
stages: ShaderStages::all_graphics(),
|
||||
mutable: false,
|
||||
variable_count: false,
|
||||
};
|
||||
|
||||
let sl = DescriptorSetLayout::new(
|
||||
|
@ -74,28 +74,33 @@
|
||||
//! `DescriptorSet`. It is what you pass to the draw functions.
|
||||
|
||||
pub use self::collection::DescriptorSetsCollection;
|
||||
pub use self::fixed_size_pool::FixedSizeDescriptorSetsPool;
|
||||
use self::layout::DescriptorSetLayout;
|
||||
pub use self::persistent::PersistentDescriptorSet;
|
||||
pub use self::persistent::PersistentDescriptorSetBuildError;
|
||||
pub use self::persistent::PersistentDescriptorSetError;
|
||||
pub use self::single_layout_pool::SingleLayoutDescSetPool;
|
||||
use self::sys::UnsafeDescriptorSet;
|
||||
use crate::buffer::BufferAccess;
|
||||
use crate::descriptor_set::layout::DescriptorDescTy;
|
||||
use crate::device::DeviceOwned;
|
||||
use crate::format::Format;
|
||||
use crate::image::view::ImageViewAbstract;
|
||||
use crate::image::view::ImageViewType;
|
||||
use crate::OomError;
|
||||
use crate::SafeDeref;
|
||||
use crate::VulkanObject;
|
||||
use smallvec::SmallVec;
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
use std::hash::Hasher;
|
||||
use std::sync::Arc;
|
||||
|
||||
mod builder;
|
||||
mod collection;
|
||||
pub mod fixed_size_pool;
|
||||
pub mod layout;
|
||||
pub mod persistent;
|
||||
pub mod pool;
|
||||
mod resources;
|
||||
pub mod single_layout_pool;
|
||||
pub mod sys;
|
||||
|
||||
/// Trait for objects that contain a collection of resources that will be accessible by shaders.
|
||||
@ -286,3 +291,170 @@ where
|
||||
Self::new(descriptor_set, std::iter::empty())
|
||||
}
|
||||
}
|
||||
|
||||
/// Error related to descriptor sets.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum DescriptorSetError {
|
||||
/// Builder is already within an array.
|
||||
AlreadyInArray,
|
||||
|
||||
/// Builder is not in an array.
|
||||
NotInArray,
|
||||
|
||||
/// Array doesn't contain the correct amount of descriptors
|
||||
ArrayLengthMismatch {
|
||||
/// Expected length
|
||||
expected: u32,
|
||||
/// Obtained length
|
||||
obtained: u32,
|
||||
},
|
||||
|
||||
/// Runtime array contains too many descriptors
|
||||
ArrayTooManyDescriptors {
|
||||
/// Capacity of array
|
||||
capacity: u32,
|
||||
/// Obtained length
|
||||
obtained: u32,
|
||||
},
|
||||
|
||||
/// Builder doesn't expect anymore descriptors
|
||||
TooManyDescriptors,
|
||||
|
||||
/// Not all descriptors have been added.
|
||||
DescriptorsMissing {
|
||||
/// Expected bindings
|
||||
expected: usize,
|
||||
/// Obtained bindings
|
||||
obtained: usize,
|
||||
},
|
||||
|
||||
/// 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.
|
||||
expected: Format,
|
||||
/// Format of the image view that was passed.
|
||||
obtained: Format,
|
||||
},
|
||||
|
||||
/// The type of an image view doesn't match what was expected.
|
||||
ImageViewTypeMismatch {
|
||||
/// Expected type.
|
||||
expected: ImageViewType,
|
||||
/// Type of the image view that was passed.
|
||||
obtained: ImageViewType,
|
||||
},
|
||||
|
||||
/// Expected a multisampled image, but got a single-sampled image.
|
||||
ExpectedMultisampled,
|
||||
|
||||
/// Expected a single-sampled image, but got a multisampled image.
|
||||
UnexpectedMultisampled,
|
||||
|
||||
/// 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 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,
|
||||
|
||||
/// Out of memory
|
||||
OomError(OomError),
|
||||
|
||||
/// Operation can not be performed on an empty descriptor.
|
||||
DescriptorIsEmpty,
|
||||
|
||||
/// Expected a non-arrayed image, but got an arrayed image.
|
||||
UnexpectedArrayed,
|
||||
}
|
||||
|
||||
impl From<OomError> for DescriptorSetError {
|
||||
fn from(error: OomError) -> Self {
|
||||
Self::OomError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for DescriptorSetError {}
|
||||
|
||||
impl fmt::Display for DescriptorSetError {
|
||||
#[inline]
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
write!(
|
||||
fmt,
|
||||
"{}",
|
||||
match *self {
|
||||
Self::AlreadyInArray => "builder is already within an array",
|
||||
Self::NotInArray => "builder is not in an array",
|
||||
Self::ArrayLengthMismatch { .. } =>
|
||||
"array doesn't contain the correct amount of descriptors",
|
||||
Self::TooManyDescriptors => "builder doesn't expect anymore descriptors",
|
||||
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::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::OomError(_) => "out of memory",
|
||||
Self::DescriptorIsEmpty => "operation can not be performed on an empty descriptor",
|
||||
Self::UnexpectedArrayed => "expected a non-arrayed image, but got an arrayed image",
|
||||
Self::ArrayTooManyDescriptors { .. } =>
|
||||
"runtime array contains too many descriptors",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Part of the DescriptorSetError for the case
|
||||
// of missing usage on a buffer.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum MissingBufferUsage {
|
||||
StorageBuffer,
|
||||
UniformBuffer,
|
||||
StorageTexelBuffer,
|
||||
UniformTexelBuffer,
|
||||
}
|
||||
|
||||
// Part of the DescriptorSetError for the case
|
||||
// of missing usage on an image.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum MissingImageUsage {
|
||||
InputAttachment,
|
||||
Sampled,
|
||||
Storage,
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -197,6 +197,7 @@ mod tests {
|
||||
descriptor_count: 1,
|
||||
stages: ShaderStages::all(),
|
||||
mutable: true,
|
||||
variable_count: false,
|
||||
};
|
||||
let layout = DescriptorSetLayout::new(
|
||||
device.clone(),
|
||||
|
@ -424,6 +424,7 @@ mod tests {
|
||||
descriptor_count: 1,
|
||||
stages: ShaderStages::all_graphics(),
|
||||
mutable: false,
|
||||
variable_count: false,
|
||||
};
|
||||
|
||||
let set_layout = DescriptorSetLayout::new(
|
||||
@ -454,6 +455,7 @@ mod tests {
|
||||
descriptor_count: 1,
|
||||
stages: ShaderStages::all_graphics(),
|
||||
mutable: false,
|
||||
variable_count: false,
|
||||
};
|
||||
|
||||
let set_layout =
|
||||
|
126
vulkano/src/descriptor_set/resources.rs
Normal file
126
vulkano/src/descriptor_set/resources.rs
Normal file
@ -0,0 +1,126 @@
|
||||
// Copyright (c) 2017 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.
|
||||
|
||||
use crate::buffer::BufferInner;
|
||||
use crate::buffer::BufferView;
|
||||
use crate::descriptor_set::BufferAccess;
|
||||
use crate::device::Device;
|
||||
use crate::device::DeviceOwned;
|
||||
use crate::device::Queue;
|
||||
use crate::image::ImageViewAbstract;
|
||||
use crate::sampler::Sampler;
|
||||
use crate::sync::AccessError;
|
||||
use crate::DeviceSize;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct DescriptorSetResources {
|
||||
buffers: Vec<(Arc<dyn BufferAccess + 'static>, u32)>,
|
||||
images: Vec<(Arc<dyn ImageViewAbstract + Send + Sync + 'static>, u32)>,
|
||||
samplers: Vec<(Arc<Sampler>, u32)>,
|
||||
}
|
||||
|
||||
struct BufferViewResource<B>(Arc<BufferView<B>>)
|
||||
where
|
||||
B: BufferAccess;
|
||||
|
||||
unsafe impl<B> DeviceOwned for BufferViewResource<B>
|
||||
where
|
||||
B: BufferAccess,
|
||||
{
|
||||
fn device(&self) -> &Arc<Device> {
|
||||
self.0.device()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<B> BufferAccess for BufferViewResource<B>
|
||||
where
|
||||
B: BufferAccess,
|
||||
{
|
||||
fn inner(&self) -> BufferInner<'_> {
|
||||
self.0.buffer().inner()
|
||||
}
|
||||
|
||||
fn size(&self) -> DeviceSize {
|
||||
self.0.buffer().size()
|
||||
}
|
||||
|
||||
fn conflict_key(&self) -> (u64, u64) {
|
||||
self.0.buffer().conflict_key()
|
||||
}
|
||||
|
||||
fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError> {
|
||||
self.0.buffer().try_gpu_lock(exclusive_access, queue)
|
||||
}
|
||||
|
||||
unsafe fn increase_gpu_lock(&self) {
|
||||
self.0.buffer().increase_gpu_lock()
|
||||
}
|
||||
|
||||
unsafe fn unlock(&self) {
|
||||
self.0.buffer().unlock()
|
||||
}
|
||||
}
|
||||
|
||||
impl DescriptorSetResources {
|
||||
pub fn new(buffer_capacity: usize, image_capacity: usize, sampler_capacity: usize) -> Self {
|
||||
Self {
|
||||
buffers: Vec::with_capacity(buffer_capacity),
|
||||
images: Vec::with_capacity(image_capacity),
|
||||
samplers: Vec::with_capacity(sampler_capacity),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn num_buffers(&self) -> usize {
|
||||
self.buffers.len()
|
||||
}
|
||||
|
||||
pub fn num_images(&self) -> usize {
|
||||
self.images.len()
|
||||
}
|
||||
|
||||
pub fn num_samplers(&self) -> usize {
|
||||
self.samplers.len()
|
||||
}
|
||||
|
||||
pub fn add_buffer(&mut self, desc_index: u32, buffer: Arc<dyn BufferAccess + 'static>) {
|
||||
self.buffers.push((buffer, desc_index));
|
||||
}
|
||||
|
||||
pub fn add_buffer_view<B>(&mut self, desc_index: u32, view: Arc<BufferView<B>>)
|
||||
where
|
||||
B: BufferAccess + 'static,
|
||||
{
|
||||
self.buffers
|
||||
.push((Arc::new(BufferViewResource(view)), desc_index));
|
||||
}
|
||||
|
||||
pub fn add_image(
|
||||
&mut self,
|
||||
desc_index: u32,
|
||||
image: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
|
||||
) {
|
||||
self.images.push((image, desc_index));
|
||||
}
|
||||
|
||||
pub fn add_sampler(&mut self, desc_index: u32, sampler: Arc<Sampler>) {
|
||||
self.samplers.push((sampler, desc_index))
|
||||
}
|
||||
|
||||
pub fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> {
|
||||
self.buffers
|
||||
.get(index)
|
||||
.map(|(buf, bind)| (&**buf as _, *bind))
|
||||
}
|
||||
|
||||
pub fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
|
||||
self.images
|
||||
.get(index)
|
||||
.map(|(img, bind)| (&**img as _, *bind))
|
||||
}
|
||||
}
|
434
vulkano/src/descriptor_set/single_layout_pool.rs
Normal file
434
vulkano/src/descriptor_set/single_layout_pool.rs
Normal file
@ -0,0 +1,434 @@
|
||||
// Copyright (c) 2017 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.
|
||||
|
||||
use super::builder::DescriptorSetBuilder;
|
||||
use super::builder::DescriptorSetBuilderOutput;
|
||||
use super::resources::DescriptorSetResources;
|
||||
use super::DescriptorSetError;
|
||||
use crate::buffer::BufferView;
|
||||
use crate::descriptor_set::layout::DescriptorSetLayout;
|
||||
use crate::descriptor_set::pool::DescriptorPoolAlloc;
|
||||
use crate::descriptor_set::pool::DescriptorPoolAllocError;
|
||||
use crate::descriptor_set::pool::UnsafeDescriptorPool;
|
||||
use crate::descriptor_set::BufferAccess;
|
||||
use crate::descriptor_set::DescriptorSet;
|
||||
use crate::descriptor_set::UnsafeDescriptorSet;
|
||||
use crate::device::Device;
|
||||
use crate::device::DeviceOwned;
|
||||
use crate::image::ImageViewAbstract;
|
||||
use crate::sampler::Sampler;
|
||||
use crate::OomError;
|
||||
use crate::VulkanObject;
|
||||
use crossbeam_queue::SegQueue;
|
||||
use std::hash::Hash;
|
||||
use std::hash::Hasher;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// `SingleLayoutDescSetPool` is a convenience wrapper provided by Vulkano not to be confused with
|
||||
/// `VkDescriptorPool`. Its function is to provide access to pool(s) to allocate `DescriptorSet`'s
|
||||
/// from and optimizes for a specific layout. For a more general purpose pool see `descriptor_set::pool::StdDescriptorPool`.
|
||||
pub struct SingleLayoutDescSetPool {
|
||||
// The `SingleLayoutPool` struct contains an actual Vulkan pool. Every time it is full we create
|
||||
// a new pool and replace the current one with the new one.
|
||||
inner: Option<Arc<SingleLayoutPool>>,
|
||||
// The Vulkan device.
|
||||
device: Arc<Device>,
|
||||
// The amount of sets available to use when we create a new Vulkan pool.
|
||||
set_count: usize,
|
||||
// The descriptor layout that this pool is for.
|
||||
layout: Arc<DescriptorSetLayout>,
|
||||
}
|
||||
|
||||
impl SingleLayoutDescSetPool {
|
||||
/// Initializes a new pool. The pool is configured to allocate sets that corresponds to the
|
||||
/// parameters passed to this function.
|
||||
pub fn new(layout: Arc<DescriptorSetLayout>) -> Self {
|
||||
let device = layout.device().clone();
|
||||
|
||||
Self {
|
||||
inner: None,
|
||||
device,
|
||||
set_count: 4,
|
||||
layout,
|
||||
}
|
||||
}
|
||||
|
||||
/// Starts the process of building a new descriptor set.
|
||||
///
|
||||
/// The set will corresponds to the set layout that was passed to `new`.
|
||||
pub fn next(&mut self) -> SingleLayoutDescSetBuilder {
|
||||
let layout = self.layout.clone();
|
||||
|
||||
SingleLayoutDescSetBuilder {
|
||||
pool: self,
|
||||
inner: DescriptorSetBuilder::start(layout),
|
||||
poisoned: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn next_alloc(&mut self) -> Result<SingleLayoutPoolAlloc, OomError> {
|
||||
loop {
|
||||
let mut not_enough_sets = false;
|
||||
|
||||
if let Some(ref mut p_inner) = self.inner {
|
||||
if let Some(existing) = p_inner.reserve.pop() {
|
||||
return Ok(SingleLayoutPoolAlloc {
|
||||
pool: p_inner.clone(),
|
||||
inner: Some(existing),
|
||||
});
|
||||
} else {
|
||||
not_enough_sets = true;
|
||||
}
|
||||
}
|
||||
|
||||
if not_enough_sets {
|
||||
self.set_count *= 2;
|
||||
}
|
||||
|
||||
let count = *self.layout.descriptors_count() * self.set_count as u32;
|
||||
let mut unsafe_pool = UnsafeDescriptorPool::new(
|
||||
self.device.clone(),
|
||||
&count,
|
||||
self.set_count as u32,
|
||||
false,
|
||||
)?;
|
||||
|
||||
let reserve = unsafe {
|
||||
match unsafe_pool.alloc((0..self.set_count).map(|_| &*self.layout)) {
|
||||
Ok(alloc_iter) => {
|
||||
let reserve = SegQueue::new();
|
||||
|
||||
for alloc in alloc_iter {
|
||||
reserve.push(alloc);
|
||||
}
|
||||
|
||||
reserve
|
||||
}
|
||||
Err(DescriptorPoolAllocError::OutOfHostMemory) => {
|
||||
return Err(OomError::OutOfHostMemory);
|
||||
}
|
||||
Err(DescriptorPoolAllocError::OutOfDeviceMemory) => {
|
||||
return Err(OomError::OutOfDeviceMemory);
|
||||
}
|
||||
Err(DescriptorPoolAllocError::FragmentedPool) => {
|
||||
// This can't happen as we don't free individual sets.
|
||||
unreachable!()
|
||||
}
|
||||
Err(DescriptorPoolAllocError::OutOfPoolMemory) => unreachable!(),
|
||||
}
|
||||
};
|
||||
|
||||
self.inner = Some(Arc::new(SingleLayoutPool {
|
||||
inner: unsafe_pool,
|
||||
reserve,
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SingleLayoutPool {
|
||||
// The actual Vulkan descriptor pool. This field isn't actually used anywhere, but we need to
|
||||
// keep the pool alive in order to keep the descriptor sets valid.
|
||||
inner: UnsafeDescriptorPool,
|
||||
|
||||
// List of descriptor sets. When `alloc` is called, a descriptor will be extracted from this
|
||||
// list. When a `SingleLayoutPoolAlloc` is dropped, its descriptor set is put back in this list.
|
||||
reserve: SegQueue<UnsafeDescriptorSet>,
|
||||
}
|
||||
|
||||
struct SingleLayoutPoolAlloc {
|
||||
// The `SingleLayoutPool` were we allocated from. We need to keep a copy of it in each allocation
|
||||
// so that we can put back the allocation in the list in our `Drop` impl.
|
||||
pool: Arc<SingleLayoutPool>,
|
||||
|
||||
// The actual descriptor set, wrapped inside an `Option` so that we can extract it in our
|
||||
// `Drop` impl.
|
||||
inner: Option<UnsafeDescriptorSet>,
|
||||
}
|
||||
|
||||
impl DescriptorPoolAlloc for SingleLayoutPoolAlloc {
|
||||
#[inline]
|
||||
fn inner(&self) -> &UnsafeDescriptorSet {
|
||||
self.inner.as_ref().unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn inner_mut(&mut self) -> &mut UnsafeDescriptorSet {
|
||||
self.inner.as_mut().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SingleLayoutPoolAlloc {
|
||||
fn drop(&mut self) {
|
||||
let inner = self.inner.take().unwrap();
|
||||
self.pool.reserve.push(inner);
|
||||
}
|
||||
}
|
||||
|
||||
/// A descriptor set created from a `SingleLayoutDescSetPool`.
|
||||
pub struct SingleLayoutDescSet {
|
||||
inner: SingleLayoutPoolAlloc,
|
||||
resources: DescriptorSetResources,
|
||||
layout: Arc<DescriptorSetLayout>,
|
||||
}
|
||||
|
||||
unsafe impl DescriptorSet for SingleLayoutDescSet {
|
||||
#[inline]
|
||||
fn inner(&self) -> &UnsafeDescriptorSet {
|
||||
self.inner.inner()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn layout(&self) -> &Arc<DescriptorSetLayout> {
|
||||
&self.layout
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn num_buffers(&self) -> usize {
|
||||
self.resources.num_buffers()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> {
|
||||
self.resources.buffer(index)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn num_images(&self) -> usize {
|
||||
self.resources.num_images()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
|
||||
self.resources.image(index)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl DeviceOwned for SingleLayoutDescSet {
|
||||
#[inline]
|
||||
fn device(&self) -> &Arc<Device> {
|
||||
self.layout.device()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for SingleLayoutDescSet {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.inner().internal_object() == other.inner().internal_object()
|
||||
&& self.device() == other.device()
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for SingleLayoutDescSet {}
|
||||
|
||||
impl Hash for SingleLayoutDescSet {
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.inner().internal_object().hash(state);
|
||||
self.device().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
/// Prototype of a `SingleLayoutDescSet`.
|
||||
pub struct SingleLayoutDescSetBuilder<'a> {
|
||||
pool: &'a mut SingleLayoutDescSetPool,
|
||||
inner: DescriptorSetBuilder,
|
||||
poisoned: bool,
|
||||
}
|
||||
|
||||
impl<'a> SingleLayoutDescSetBuilder<'a> {
|
||||
/// Call this function if the next element of the set is an array in order to set the value of
|
||||
/// each element.
|
||||
///
|
||||
/// Returns an error if the descriptor is empty, there are no remaining descriptors, or if the
|
||||
/// builder is already in an error.
|
||||
///
|
||||
/// 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.
|
||||
#[inline]
|
||||
pub fn enter_array(&mut self) -> Result<&mut Self, DescriptorSetError> {
|
||||
if self.poisoned {
|
||||
Err(DescriptorSetError::BuilderPoisoned)
|
||||
} else {
|
||||
match self.inner.enter_array() {
|
||||
Ok(_) => Ok(self),
|
||||
Err(e) => {
|
||||
self.poisoned = true;
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Leaves the array. Call this once you added all the elements of the array.
|
||||
///
|
||||
/// Returns an error if the array is missing elements, or if the builder is not in an array.
|
||||
#[inline]
|
||||
pub fn leave_array(&mut self) -> Result<&mut Self, DescriptorSetError> {
|
||||
if self.poisoned {
|
||||
Err(DescriptorSetError::BuilderPoisoned)
|
||||
} else {
|
||||
match self.inner.leave_array() {
|
||||
Ok(_) => Ok(self),
|
||||
Err(e) => {
|
||||
self.poisoned = true;
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Skips the current descriptor if it is empty.
|
||||
#[inline]
|
||||
pub fn add_empty(&mut self) -> Result<&mut Self, DescriptorSetError> {
|
||||
if self.poisoned {
|
||||
Err(DescriptorSetError::BuilderPoisoned)
|
||||
} else {
|
||||
match self.inner.add_empty() {
|
||||
Ok(_) => Ok(self),
|
||||
Err(e) => {
|
||||
self.poisoned = true;
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Binds a buffer as the next descriptor.
|
||||
///
|
||||
/// An error is returned if the buffer isn't compatible with the descriptor.
|
||||
#[inline]
|
||||
pub fn add_buffer(
|
||||
&mut self,
|
||||
buffer: Arc<dyn BufferAccess + 'static>,
|
||||
) -> Result<&mut Self, DescriptorSetError> {
|
||||
if self.poisoned {
|
||||
Err(DescriptorSetError::BuilderPoisoned)
|
||||
} else {
|
||||
match self.inner.add_buffer(buffer) {
|
||||
Ok(_) => Ok(self),
|
||||
Err(e) => {
|
||||
self.poisoned = true;
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Binds a buffer view as the next descriptor.
|
||||
///
|
||||
/// An error is returned if the buffer isn't compatible with the descriptor.
|
||||
#[inline]
|
||||
pub fn add_buffer_view<B>(
|
||||
&mut self,
|
||||
view: Arc<BufferView<B>>,
|
||||
) -> Result<&mut Self, DescriptorSetError>
|
||||
where
|
||||
B: BufferAccess + 'static,
|
||||
{
|
||||
if self.poisoned {
|
||||
Err(DescriptorSetError::BuilderPoisoned)
|
||||
} else {
|
||||
match self.inner.add_buffer_view(view) {
|
||||
Ok(_) => Ok(self),
|
||||
Err(e) => {
|
||||
self.poisoned = true;
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Binds an image view as the next descriptor.
|
||||
///
|
||||
/// An error is returned if the image view isn't compatible with the descriptor.
|
||||
#[inline]
|
||||
pub fn add_image(
|
||||
&mut self,
|
||||
image_view: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
|
||||
) -> Result<&mut Self, DescriptorSetError> {
|
||||
if self.poisoned {
|
||||
Err(DescriptorSetError::BuilderPoisoned)
|
||||
} else {
|
||||
match self.inner.add_image(image_view) {
|
||||
Ok(_) => Ok(self),
|
||||
Err(e) => {
|
||||
self.poisoned = true;
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Binds an image view with a sampler as the next descriptor.
|
||||
///
|
||||
/// An error is returned if the image view isn't compatible with the descriptor.
|
||||
#[inline]
|
||||
pub fn add_sampled_image(
|
||||
&mut self,
|
||||
image_view: Arc<dyn ImageViewAbstract + Send + Sync + 'static>,
|
||||
sampler: Arc<Sampler>,
|
||||
) -> Result<&mut Self, DescriptorSetError> {
|
||||
if self.poisoned {
|
||||
Err(DescriptorSetError::BuilderPoisoned)
|
||||
} else {
|
||||
match self.inner.add_sampled_image(image_view, sampler) {
|
||||
Ok(_) => Ok(self),
|
||||
Err(e) => {
|
||||
self.poisoned = true;
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Binds a sampler as the next descriptor.
|
||||
///
|
||||
/// An error is returned if the sampler isn't compatible with the descriptor.
|
||||
#[inline]
|
||||
pub fn add_sampler(&mut self, sampler: Arc<Sampler>) -> Result<&mut Self, DescriptorSetError> {
|
||||
if self.poisoned {
|
||||
Err(DescriptorSetError::BuilderPoisoned)
|
||||
} else {
|
||||
match self.inner.add_sampler(sampler) {
|
||||
Ok(_) => Ok(self),
|
||||
Err(e) => {
|
||||
self.poisoned = true;
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a `SingleLayoutDescSet` from the builder.
|
||||
pub fn build(self) -> Result<SingleLayoutDescSet, DescriptorSetError> {
|
||||
if self.poisoned {
|
||||
return Err(DescriptorSetError::BuilderPoisoned);
|
||||
}
|
||||
|
||||
let DescriptorSetBuilderOutput {
|
||||
layout,
|
||||
writes,
|
||||
resources,
|
||||
} = self.inner.output()?;
|
||||
|
||||
let mut alloc = self.pool.next_alloc()?;
|
||||
unsafe {
|
||||
alloc
|
||||
.inner_mut()
|
||||
.write(&self.pool.device, writes.into_iter());
|
||||
}
|
||||
|
||||
Ok(SingleLayoutDescSet {
|
||||
inner: alloc,
|
||||
resources,
|
||||
layout,
|
||||
})
|
||||
}
|
||||
}
|
@ -71,7 +71,7 @@ impl ComputePipeline {
|
||||
desc.clone(),
|
||||
)?))
|
||||
})
|
||||
.collect::<Result<Vec<_>, OomError>>()?;
|
||||
.collect::<Result<Vec<_>, PipelineLayoutCreationError>>()?;
|
||||
let pipeline_layout = Arc::new(PipelineLayout::new(
|
||||
device.clone(),
|
||||
descriptor_set_layouts,
|
||||
@ -430,6 +430,7 @@ mod tests {
|
||||
..ShaderStages::none()
|
||||
},
|
||||
mutable: false,
|
||||
variable_count: false,
|
||||
})])],
|
||||
None,
|
||||
SpecConsts::descriptors(),
|
||||
@ -466,11 +467,11 @@ mod tests {
|
||||
let data_buffer =
|
||||
CpuAccessibleBuffer::from_data(device.clone(), BufferUsage::all(), false, 0).unwrap();
|
||||
let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
|
||||
let set = PersistentDescriptorSet::start(layout.clone())
|
||||
.add_buffer(data_buffer.clone())
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap();
|
||||
let mut builder = PersistentDescriptorSet::start(layout.clone());
|
||||
|
||||
builder.add_buffer(data_buffer.clone()).unwrap();
|
||||
|
||||
let set = builder.build().unwrap();
|
||||
|
||||
let mut cbb = AutoCommandBufferBuilder::primary(
|
||||
device.clone(),
|
||||
|
@ -29,6 +29,7 @@ use crate::pipeline::graphics_pipeline::GraphicsPipelineCreationError;
|
||||
use crate::pipeline::graphics_pipeline::Inner as GraphicsPipelineInner;
|
||||
use crate::pipeline::input_assembly::PrimitiveTopology;
|
||||
use crate::pipeline::layout::PipelineLayout;
|
||||
use crate::pipeline::layout::PipelineLayoutCreationError;
|
||||
use crate::pipeline::layout::PipelineLayoutPcRange;
|
||||
use crate::pipeline::raster::CullMode;
|
||||
use crate::pipeline::raster::DepthBiasControl;
|
||||
@ -47,7 +48,6 @@ use crate::pipeline::viewport::Scissor;
|
||||
use crate::pipeline::viewport::Viewport;
|
||||
use crate::pipeline::viewport::ViewportsState;
|
||||
use crate::render_pass::Subpass;
|
||||
use crate::OomError;
|
||||
use crate::VulkanObject;
|
||||
use smallvec::SmallVec;
|
||||
use std::collections::hash_map::{Entry, HashMap};
|
||||
@ -214,7 +214,7 @@ where
|
||||
let descriptor_set_layouts = descriptor_set_layout_descs
|
||||
.into_iter()
|
||||
.map(|desc| Ok(Arc::new(DescriptorSetLayout::new(device.clone(), desc)?)))
|
||||
.collect::<Result<Vec<_>, OomError>>()?;
|
||||
.collect::<Result<Vec<_>, PipelineLayoutCreationError>>()?;
|
||||
let pipeline_layout = Arc::new(
|
||||
PipelineLayout::new(device.clone(), descriptor_set_layouts, push_constant_ranges)
|
||||
.unwrap(),
|
||||
|
@ -8,6 +8,7 @@
|
||||
// according to those terms.
|
||||
|
||||
use crate::pipeline::input_assembly::PrimitiveTopology;
|
||||
use crate::pipeline::layout::PipelineLayoutCreationError;
|
||||
use crate::pipeline::layout::PipelineLayoutSupersetError;
|
||||
use crate::pipeline::shader::ShaderInterfaceMismatchError;
|
||||
use crate::pipeline::vertex::IncompatibleVertexDefinitionError;
|
||||
@ -23,6 +24,9 @@ pub enum GraphicsPipelineCreationError {
|
||||
/// Not enough memory.
|
||||
OomError(OomError),
|
||||
|
||||
/// Error while creating the pipeline layout object.
|
||||
PipelineLayoutCreationError(PipelineLayoutCreationError),
|
||||
|
||||
/// The pipeline layout is not compatible with what the shaders expect.
|
||||
IncompatiblePipelineLayout(PipelineLayoutSupersetError),
|
||||
|
||||
@ -194,6 +198,7 @@ impl error::Error for GraphicsPipelineCreationError {
|
||||
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
||||
match *self {
|
||||
GraphicsPipelineCreationError::OomError(ref err) => Some(err),
|
||||
GraphicsPipelineCreationError::PipelineLayoutCreationError(ref err) => Some(err),
|
||||
GraphicsPipelineCreationError::IncompatiblePipelineLayout(ref err) => Some(err),
|
||||
GraphicsPipelineCreationError::ShaderStagesMismatch(ref err) => Some(err),
|
||||
GraphicsPipelineCreationError::IncompatibleVertexDefinition(ref err) => Some(err),
|
||||
@ -214,6 +219,9 @@ impl fmt::Display for GraphicsPipelineCreationError {
|
||||
GraphicsPipelineCreationError::ShaderStagesMismatch(_) => {
|
||||
"the output interface of one shader and the input interface of the next shader does not match"
|
||||
}
|
||||
GraphicsPipelineCreationError::PipelineLayoutCreationError(_) => {
|
||||
"error while creating the pipeline layout object"
|
||||
}
|
||||
GraphicsPipelineCreationError::IncompatiblePipelineLayout(_) => {
|
||||
"the pipeline layout is not compatible with what the shaders expect"
|
||||
}
|
||||
@ -350,6 +358,13 @@ impl From<OomError> for GraphicsPipelineCreationError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PipelineLayoutCreationError> for GraphicsPipelineCreationError {
|
||||
#[inline]
|
||||
fn from(err: PipelineLayoutCreationError) -> GraphicsPipelineCreationError {
|
||||
GraphicsPipelineCreationError::PipelineLayoutCreationError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PipelineLayoutSupersetError> for GraphicsPipelineCreationError {
|
||||
#[inline]
|
||||
fn from(err: PipelineLayoutSupersetError) -> GraphicsPipelineCreationError {
|
||||
|
@ -12,6 +12,7 @@ use crate::check_errors;
|
||||
use crate::descriptor_set::layout::DescriptorSetCompatibilityError;
|
||||
use crate::descriptor_set::layout::DescriptorSetDesc;
|
||||
use crate::descriptor_set::layout::DescriptorSetLayout;
|
||||
use crate::descriptor_set::layout::DescriptorSetLayoutError;
|
||||
use crate::device::Device;
|
||||
use crate::device::DeviceOwned;
|
||||
use crate::pipeline::layout::PipelineLayoutLimitsError;
|
||||
@ -283,6 +284,8 @@ pub enum PipelineLayoutCreationError {
|
||||
first_range: PipelineLayoutPcRange,
|
||||
second_range: PipelineLayoutPcRange,
|
||||
},
|
||||
/// One of the set layouts has an error.
|
||||
SetLayoutError(DescriptorSetLayoutError),
|
||||
}
|
||||
|
||||
impl error::Error for PipelineLayoutCreationError {
|
||||
@ -291,6 +294,7 @@ impl error::Error for PipelineLayoutCreationError {
|
||||
match *self {
|
||||
PipelineLayoutCreationError::OomError(ref err) => Some(err),
|
||||
PipelineLayoutCreationError::LimitsError(ref err) => Some(err),
|
||||
PipelineLayoutCreationError::SetLayoutError(ref err) => Some(err),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -313,6 +317,9 @@ impl fmt::Display for PipelineLayoutCreationError {
|
||||
PipelineLayoutCreationError::PushConstantsConflict { .. } => {
|
||||
"conflict between different push constants ranges"
|
||||
}
|
||||
PipelineLayoutCreationError::SetLayoutError(_) => {
|
||||
"one of the sets has an error"
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -332,6 +339,13 @@ impl From<PipelineLayoutLimitsError> for PipelineLayoutCreationError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DescriptorSetLayoutError> for PipelineLayoutCreationError {
|
||||
#[inline]
|
||||
fn from(err: DescriptorSetLayoutError) -> PipelineLayoutCreationError {
|
||||
PipelineLayoutCreationError::SetLayoutError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for PipelineLayoutCreationError {
|
||||
#[inline]
|
||||
fn from(err: Error) -> PipelineLayoutCreationError {
|
||||
|
@ -13,32 +13,32 @@ use crate::buffer::BufferAccess;
|
||||
pub unsafe trait VertexBuffersCollection {
|
||||
/// Converts `self` into a list of buffers.
|
||||
// TODO: better than a Vec
|
||||
fn into_vec(self) -> Vec<Box<dyn BufferAccess + Send + Sync>>;
|
||||
fn into_vec(self) -> Vec<Box<dyn BufferAccess>>;
|
||||
}
|
||||
|
||||
unsafe impl VertexBuffersCollection for () {
|
||||
#[inline]
|
||||
fn into_vec(self) -> Vec<Box<dyn BufferAccess + Send + Sync>> {
|
||||
fn into_vec(self) -> Vec<Box<dyn BufferAccess>> {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T> VertexBuffersCollection for T
|
||||
where
|
||||
T: BufferAccess + Send + Sync + 'static,
|
||||
T: BufferAccess + 'static,
|
||||
{
|
||||
#[inline]
|
||||
fn into_vec(self) -> Vec<Box<dyn BufferAccess + Send + Sync>> {
|
||||
fn into_vec(self) -> Vec<Box<dyn BufferAccess>> {
|
||||
vec![Box::new(self) as Box<_>]
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T> VertexBuffersCollection for Vec<T>
|
||||
where
|
||||
T: BufferAccess + Send + Sync + 'static,
|
||||
T: BufferAccess + 'static,
|
||||
{
|
||||
#[inline]
|
||||
fn into_vec(self) -> Vec<Box<dyn BufferAccess + Send + Sync>> {
|
||||
fn into_vec(self) -> Vec<Box<dyn BufferAccess>> {
|
||||
self.into_iter()
|
||||
.map(|source| Box::new(source) as Box<_>)
|
||||
.collect()
|
||||
@ -48,11 +48,11 @@ where
|
||||
macro_rules! impl_collection {
|
||||
($first:ident $(, $others:ident)+) => (
|
||||
unsafe impl<$first$(, $others)+> VertexBuffersCollection for ($first, $($others),+)
|
||||
where $first: BufferAccess + Send + Sync + 'static
|
||||
$(, $others: BufferAccess + Send + Sync + 'static)*
|
||||
where $first: BufferAccess + 'static
|
||||
$(, $others: BufferAccess + 'static)*
|
||||
{
|
||||
#[inline]
|
||||
fn into_vec(self) -> Vec<Box<dyn BufferAccess + Send + Sync>> {
|
||||
fn into_vec(self) -> Vec<Box<dyn BufferAccess>> {
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
let ($first, $($others,)*) = self;
|
||||
|
Loading…
Reference in New Issue
Block a user