From ef65c98ad15976c05e61566e747a1f9da76b6358 Mon Sep 17 00:00:00 2001 From: marc0246 <40955683+marc0246@users.noreply.github.com> Date: Wed, 5 Oct 2022 11:09:26 +0200 Subject: [PATCH] Move to manual management of descriptor set and command buffer allocators (#1957) * Rename `Pool` -> `Allocator` * Fix module names * Rename actual pool types * Remove internally managed allocators * Fix doc tests * Update docs * Update examples * Fix merging oopsie * Fix cb allocators only working for one q family * Make `DescriptorPool` `!Sync`, remove `&mut` * Combine lean files * Consistency * Rename single layout pools * Re-export variable descriptor set pool Co-authored-by: comrademarc <40955683+comrademarc@users.noreply.github.com> --- examples/src/bin/basic-compute-shader.rs | 14 +- examples/src/bin/buffer-pool.rs | 7 +- examples/src/bin/clear_attachments.rs | 8 +- examples/src/bin/debug.rs | 6 +- .../deferred/frame/ambient_lighting_system.rs | 24 +- .../frame/directional_lighting_system.rs | 24 +- .../deferred/frame/point_lighting_system.rs | 24 +- examples/src/bin/deferred/frame/system.rs | 45 ++- examples/src/bin/deferred/main.rs | 17 +- .../src/bin/deferred/triangle_draw_system.rs | 16 +- examples/src/bin/dynamic-buffers.rs | 13 +- examples/src/bin/dynamic-local-size.rs | 23 +- examples/src/bin/gl-interop.rs | 15 +- examples/src/bin/image-self-copy-blit/main.rs | 19 +- examples/src/bin/image/main.rs | 14 +- examples/src/bin/immutable-sampler/main.rs | 22 +- examples/src/bin/indirect.rs | 14 +- examples/src/bin/instancing.rs | 7 +- examples/src/bin/interactive_fractal/app.rs | 24 +- .../fractal_compute_pipeline.rs | 27 +- .../pixels_draw_pipeline.rs | 25 +- .../interactive_fractal/place_over_frame.rs | 25 +- examples/src/bin/msaa-renderpass.rs | 10 +- examples/src/bin/multi-window.rs | 7 +- .../src/bin/multi_window_game_of_life/app.rs | 25 +- .../multi_window_game_of_life/game_of_life.rs | 27 +- .../multi_window_game_of_life/pixels_draw.rs | 27 +- .../multi_window_game_of_life/render_pass.rs | 27 +- examples/src/bin/multiview.rs | 8 +- examples/src/bin/occlusion-query.rs | 7 +- examples/src/bin/push-constants.rs | 14 +- examples/src/bin/push-descriptors/main.rs | 8 +- examples/src/bin/runtime-shader/main.rs | 7 +- examples/src/bin/runtime_array/main.rs | 12 +- examples/src/bin/self-copy-buffer.rs | 13 +- examples/src/bin/shader-include/main.rs | 14 +- examples/src/bin/shader-types-sharing.rs | 22 +- examples/src/bin/simple-particles.rs | 24 +- examples/src/bin/specialization-constants.rs | 14 +- examples/src/bin/teapot/main.rs | 13 +- examples/src/bin/tessellation.rs | 7 +- examples/src/bin/texture_array/main.rs | 14 +- examples/src/bin/triangle-v1_3.rs | 13 +- examples/src/bin/triangle.rs | 13 +- vulkano/src/buffer/cpu_pool.rs | 28 +- vulkano/src/buffer/device_local.rs | 50 ++- vulkano/src/buffer/view.rs | 66 +++- vulkano/src/command_buffer/allocator.rs | 369 ++++++++++++++++++ vulkano/src/command_buffer/auto.rs | 150 ++++--- .../src/command_buffer/commands/bind_push.rs | 6 +- vulkano/src/command_buffer/commands/debug.rs | 6 +- .../command_buffer/commands/dynamic_state.rs | 6 +- vulkano/src/command_buffer/commands/image.rs | 6 +- .../src/command_buffer/commands/pipeline.rs | 6 +- vulkano/src/command_buffer/commands/query.rs | 6 +- .../command_buffer/commands/render_pass.rs | 13 +- .../src/command_buffer/commands/secondary.rs | 8 +- .../src/command_buffer/commands/transfer.rs | 6 +- vulkano/src/command_buffer/mod.rs | 4 +- .../command_buffer/{pool/sys.rs => pool.rs} | 139 ++++--- vulkano/src/command_buffer/pool/mod.rs | 105 ----- vulkano/src/command_buffer/pool/standard.rs | 291 -------------- vulkano/src/command_buffer/synced/builder.rs | 4 +- vulkano/src/command_buffer/synced/mod.rs | 69 ++-- vulkano/src/command_buffer/sys.rs | 5 +- vulkano/src/descriptor_set/allocator.rs | 183 +++++++++ vulkano/src/descriptor_set/mod.rs | 30 +- vulkano/src/descriptor_set/persistent.rs | 56 +-- .../descriptor_set/{pool/sys.rs => pool.rs} | 76 ++-- vulkano/src/descriptor_set/pool/mod.rs | 48 --- vulkano/src/descriptor_set/pool/standard.rs | 139 ------- .../src/descriptor_set/single_layout_pool.rs | 174 +++++---- vulkano/src/device/mod.rs | 82 +--- vulkano/src/device/physical.rs | 2 +- vulkano/src/image/immutable.rs | 73 +--- vulkano/src/image/mod.rs | 7 +- vulkano/src/pipeline/compute.rs | 13 +- vulkano/src/sampler/ycbcr.rs | 4 + 78 files changed, 1669 insertions(+), 1300 deletions(-) create mode 100644 vulkano/src/command_buffer/allocator.rs rename vulkano/src/command_buffer/{pool/sys.rs => pool.rs} (83%) delete mode 100644 vulkano/src/command_buffer/pool/mod.rs delete mode 100644 vulkano/src/command_buffer/pool/standard.rs create mode 100644 vulkano/src/descriptor_set/allocator.rs rename vulkano/src/descriptor_set/{pool/sys.rs => pool.rs} (92%) delete mode 100644 vulkano/src/descriptor_set/pool/mod.rs delete mode 100644 vulkano/src/descriptor_set/pool/standard.rs diff --git a/examples/src/bin/basic-compute-shader.rs b/examples/src/bin/basic-compute-shader.rs index fdde4ba1..39ed94d4 100644 --- a/examples/src/bin/basic-compute-shader.rs +++ b/examples/src/bin/basic-compute-shader.rs @@ -15,8 +15,12 @@ use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer}, - command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage}, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, + command_buffer::{ + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, + }, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, }, @@ -140,6 +144,9 @@ fn main() { .unwrap() }; + let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone()); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + // We start by creating the buffer that will store the data. let data_buffer = { // Iterator that produces the data. @@ -167,6 +174,7 @@ fn main() { // descriptor sets that each contain the buffer you want to run the shader on. let layout = pipeline.layout().set_layouts().get(0).unwrap(); let set = PersistentDescriptorSet::new( + &descriptor_set_allocator, layout.clone(), [WriteDescriptorSet::buffer(0, data_buffer.clone())], ) @@ -174,7 +182,7 @@ fn main() { // In order to execute our operation, we have to build a command buffer. let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/buffer-pool.rs b/examples/src/bin/buffer-pool.rs index 952a9974..04b7f7a4 100644 --- a/examples/src/bin/buffer-pool.rs +++ b/examples/src/bin/buffer-pool.rs @@ -27,7 +27,8 @@ use std::{ use vulkano::{ buffer::CpuBufferPool, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + RenderPassBeginInfo, SubpassContents, }, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, @@ -239,6 +240,8 @@ fn main() { let mut recreate_swapchain = false; let mut previous_frame_end = Some(sync::now(device.clone()).boxed()); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + event_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { @@ -330,7 +333,7 @@ fn main() { // Allocate a new chunk from buffer_pool let buffer = buffer_pool.from_iter(data.to_vec()).unwrap(); let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/clear_attachments.rs b/examples/src/bin/clear_attachments.rs index 000959a3..1e535ec0 100644 --- a/examples/src/bin/clear_attachments.rs +++ b/examples/src/bin/clear_attachments.rs @@ -10,8 +10,8 @@ use std::sync::Arc; use vulkano::{ command_buffer::{ - AutoCommandBufferBuilder, ClearAttachment, ClearRect, CommandBufferUsage, - RenderPassBeginInfo, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, ClearAttachment, + ClearRect, CommandBufferUsage, RenderPassBeginInfo, SubpassContents, }, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, @@ -153,6 +153,8 @@ fn main() { ) .unwrap(); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + let mut width = swapchain.image_extent()[0]; let mut height = swapchain.image_extent()[1]; let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone()); @@ -213,7 +215,7 @@ fn main() { } let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/debug.rs b/examples/src/bin/debug.rs index 724fddab..6446cb9f 100644 --- a/examples/src/bin/debug.rs +++ b/examples/src/bin/debug.rs @@ -9,6 +9,7 @@ use std::sync::Arc; use vulkano::{ + command_buffer::allocator::StandardCommandBufferAllocator, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, }, @@ -158,7 +159,7 @@ fn main() { }) .expect("no device available"); - let (_, mut queues) = Device::new( + let (device, mut queues) = Device::new( physical_device, DeviceCreateInfo { enabled_extensions: device_extensions, @@ -172,6 +173,8 @@ fn main() { .expect("failed to create device"); let queue = queues.next().unwrap(); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device); + // Create an image in order to generate some additional logging: let pixel_format = Format::R8G8B8A8_UINT; let dimensions = ImageDimensions::Dim2d { @@ -185,6 +188,7 @@ fn main() { dimensions, MipmapsCount::One, pixel_format, + &command_buffer_allocator, queue, ) .unwrap(); diff --git a/examples/src/bin/deferred/frame/ambient_lighting_system.rs b/examples/src/bin/deferred/frame/ambient_lighting_system.rs index 56d3e09d..1c86a470 100644 --- a/examples/src/bin/deferred/frame/ambient_lighting_system.rs +++ b/examples/src/bin/deferred/frame/ambient_lighting_system.rs @@ -8,14 +8,16 @@ // according to those terms. use bytemuck::{Pod, Zeroable}; -use std::sync::Arc; +use std::{rc::Rc, sync::Arc}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferInheritanceInfo, CommandBufferUsage, - SecondaryAutoCommandBuffer, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, + CommandBufferInheritanceInfo, CommandBufferUsage, SecondaryAutoCommandBuffer, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, }, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, device::Queue, image::ImageViewAbstract, impl_vertex, @@ -37,11 +39,18 @@ pub struct AmbientLightingSystem { vertex_buffer: Arc>, subpass: Subpass, pipeline: Arc, + command_buffer_allocator: Rc, + descriptor_set_allocator: Rc, } impl AmbientLightingSystem { /// Initializes the ambient lighting system. - pub fn new(gfx_queue: Arc, subpass: Subpass) -> AmbientLightingSystem { + pub fn new( + gfx_queue: Arc, + subpass: Subpass, + command_buffer_allocator: Rc, + descriptor_set_allocator: Rc, + ) -> AmbientLightingSystem { // TODO: vulkano doesn't allow us to draw without a vertex buffer, otherwise we could // hard-code these values in the shader let vertices = [ @@ -98,6 +107,8 @@ impl AmbientLightingSystem { vertex_buffer, subpass, pipeline, + command_buffer_allocator, + descriptor_set_allocator, } } @@ -125,6 +136,7 @@ impl AmbientLightingSystem { let layout = self.pipeline.layout().set_layouts().get(0).unwrap(); let descriptor_set = PersistentDescriptorSet::new( + &*self.descriptor_set_allocator, layout.clone(), [WriteDescriptorSet::image_view(0, color_input)], ) @@ -137,7 +149,7 @@ impl AmbientLightingSystem { }; let mut builder = AutoCommandBufferBuilder::secondary( - self.gfx_queue.device().clone(), + &*self.command_buffer_allocator, self.gfx_queue.queue_family_index(), CommandBufferUsage::MultipleSubmit, CommandBufferInheritanceInfo { diff --git a/examples/src/bin/deferred/frame/directional_lighting_system.rs b/examples/src/bin/deferred/frame/directional_lighting_system.rs index 8512d350..eba9c046 100644 --- a/examples/src/bin/deferred/frame/directional_lighting_system.rs +++ b/examples/src/bin/deferred/frame/directional_lighting_system.rs @@ -9,14 +9,16 @@ use bytemuck::{Pod, Zeroable}; use cgmath::Vector3; -use std::sync::Arc; +use std::{rc::Rc, sync::Arc}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferInheritanceInfo, CommandBufferUsage, - SecondaryAutoCommandBuffer, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, + CommandBufferInheritanceInfo, CommandBufferUsage, SecondaryAutoCommandBuffer, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, }, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, device::Queue, image::ImageViewAbstract, impl_vertex, @@ -38,11 +40,18 @@ pub struct DirectionalLightingSystem { vertex_buffer: Arc>, subpass: Subpass, pipeline: Arc, + command_buffer_allocator: Rc, + descriptor_set_allocator: Rc, } impl DirectionalLightingSystem { /// Initializes the directional lighting system. - pub fn new(gfx_queue: Arc, subpass: Subpass) -> DirectionalLightingSystem { + pub fn new( + gfx_queue: Arc, + subpass: Subpass, + command_buffer_allocator: Rc, + descriptor_set_allocator: Rc, + ) -> DirectionalLightingSystem { // TODO: vulkano doesn't allow us to draw without a vertex buffer, otherwise we could // hard-code these values in the shader let vertices = [ @@ -99,6 +108,8 @@ impl DirectionalLightingSystem { vertex_buffer, subpass, pipeline, + command_buffer_allocator, + descriptor_set_allocator, } } @@ -136,6 +147,7 @@ impl DirectionalLightingSystem { let layout = self.pipeline.layout().set_layouts().get(0).unwrap(); let descriptor_set = PersistentDescriptorSet::new( + &*self.descriptor_set_allocator, layout.clone(), [ WriteDescriptorSet::image_view(0, color_input), @@ -151,7 +163,7 @@ impl DirectionalLightingSystem { }; let mut builder = AutoCommandBufferBuilder::secondary( - self.gfx_queue.device().clone(), + &*self.command_buffer_allocator, self.gfx_queue.queue_family_index(), CommandBufferUsage::MultipleSubmit, CommandBufferInheritanceInfo { diff --git a/examples/src/bin/deferred/frame/point_lighting_system.rs b/examples/src/bin/deferred/frame/point_lighting_system.rs index 11232324..b2f5062f 100644 --- a/examples/src/bin/deferred/frame/point_lighting_system.rs +++ b/examples/src/bin/deferred/frame/point_lighting_system.rs @@ -9,14 +9,16 @@ use bytemuck::{Pod, Zeroable}; use cgmath::{Matrix4, Vector3}; -use std::sync::Arc; +use std::{rc::Rc, sync::Arc}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferInheritanceInfo, CommandBufferUsage, - SecondaryAutoCommandBuffer, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, + CommandBufferInheritanceInfo, CommandBufferUsage, SecondaryAutoCommandBuffer, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, }, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, device::Queue, image::ImageViewAbstract, impl_vertex, @@ -37,11 +39,18 @@ pub struct PointLightingSystem { vertex_buffer: Arc>, subpass: Subpass, pipeline: Arc, + command_buffer_allocator: Rc, + descriptor_set_allocator: Rc, } impl PointLightingSystem { /// Initializes the point lighting system. - pub fn new(gfx_queue: Arc, subpass: Subpass) -> PointLightingSystem { + pub fn new( + gfx_queue: Arc, + subpass: Subpass, + command_buffer_allocator: Rc, + descriptor_set_allocator: Rc, + ) -> PointLightingSystem { // TODO: vulkano doesn't allow us to draw without a vertex buffer, otherwise we could // hard-code these values in the shader let vertices = [ @@ -98,6 +107,8 @@ impl PointLightingSystem { vertex_buffer, subpass, pipeline, + command_buffer_allocator, + descriptor_set_allocator, } } @@ -148,6 +159,7 @@ impl PointLightingSystem { let layout = self.pipeline.layout().set_layouts().get(0).unwrap(); let descriptor_set = PersistentDescriptorSet::new( + &*self.descriptor_set_allocator, layout.clone(), [ WriteDescriptorSet::image_view(0, color_input), @@ -164,7 +176,7 @@ impl PointLightingSystem { }; let mut builder = AutoCommandBufferBuilder::secondary( - self.gfx_queue.device().clone(), + &*self.command_buffer_allocator, self.gfx_queue.queue_family_index(), CommandBufferUsage::MultipleSubmit, CommandBufferInheritanceInfo { diff --git a/examples/src/bin/deferred/frame/system.rs b/examples/src/bin/deferred/frame/system.rs index 0f017322..568aedb9 100644 --- a/examples/src/bin/deferred/frame/system.rs +++ b/examples/src/bin/deferred/frame/system.rs @@ -13,12 +13,13 @@ use super::{ point_lighting_system::PointLightingSystem, }; use cgmath::{Matrix4, SquareMatrix, Vector3}; -use std::sync::Arc; +use std::{rc::Rc, sync::Arc}; use vulkano::{ command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, PrimaryAutoCommandBuffer, - RenderPassBeginInfo, SecondaryCommandBuffer, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + PrimaryAutoCommandBuffer, RenderPassBeginInfo, SecondaryCommandBuffer, SubpassContents, }, + descriptor_set::allocator::StandardDescriptorSetAllocator, device::Queue, format::Format, image::{view::ImageView, AttachmentImage, ImageAccess, ImageUsage, ImageViewAbstract}, @@ -36,6 +37,8 @@ pub struct FrameSystem { // in of a change in the dimensions. render_pass: Arc, + command_buffer_allocator: Rc, + // Intermediate render target that will contain the albedo of each pixel of the scene. diffuse_buffer: Arc>, // Intermediate render target that will contain the normal vector in world coordinates of each @@ -64,7 +67,11 @@ impl FrameSystem { /// `frame()` method. We need to know that in advance. If that format ever changes, we have /// to create a new `FrameSystem`. /// - pub fn new(gfx_queue: Arc, final_output_format: Format) -> FrameSystem { + pub fn new( + gfx_queue: Arc, + final_output_format: Format, + command_buffer_allocator: Rc, + ) -> FrameSystem { // Creating the render pass. // // The render pass has two subpasses. In the first subpass, we draw all the objects of the @@ -185,18 +192,36 @@ impl FrameSystem { ) .unwrap(); + let descriptor_set_allocator = Rc::new(StandardDescriptorSetAllocator::new( + gfx_queue.device().clone(), + )); + // Initialize the three lighting systems. // Note that we need to pass to them the subpass where they will be executed. let lighting_subpass = Subpass::from(render_pass.clone(), 1).unwrap(); - let ambient_lighting_system = - AmbientLightingSystem::new(gfx_queue.clone(), lighting_subpass.clone()); - let directional_lighting_system = - DirectionalLightingSystem::new(gfx_queue.clone(), lighting_subpass.clone()); - let point_lighting_system = PointLightingSystem::new(gfx_queue.clone(), lighting_subpass); + let ambient_lighting_system = AmbientLightingSystem::new( + gfx_queue.clone(), + lighting_subpass.clone(), + command_buffer_allocator.clone(), + descriptor_set_allocator.clone(), + ); + let directional_lighting_system = DirectionalLightingSystem::new( + gfx_queue.clone(), + lighting_subpass.clone(), + command_buffer_allocator.clone(), + descriptor_set_allocator.clone(), + ); + let point_lighting_system = PointLightingSystem::new( + gfx_queue.clone(), + lighting_subpass, + command_buffer_allocator.clone(), + descriptor_set_allocator, + ); FrameSystem { gfx_queue, render_pass, + command_buffer_allocator, diffuse_buffer, normals_buffer, depth_buffer, @@ -304,7 +329,7 @@ impl FrameSystem { // Start the command buffer builder that will be filled throughout the frame handling. let mut command_buffer_builder = AutoCommandBufferBuilder::primary( - self.gfx_queue.device().clone(), + &*self.command_buffer_allocator, self.gfx_queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/deferred/main.rs b/examples/src/bin/deferred/main.rs index bf193251..b0fa1804 100644 --- a/examples/src/bin/deferred/main.rs +++ b/examples/src/bin/deferred/main.rs @@ -30,7 +30,9 @@ use crate::{ triangle_draw_system::TriangleDrawSystem, }; use cgmath::{Matrix4, SquareMatrix, Vector3}; +use std::rc::Rc; use vulkano::{ + command_buffer::allocator::StandardCommandBufferAllocator, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, }, @@ -161,10 +163,19 @@ fn main() { (swapchain, images) }; + let command_buffer_allocator = Rc::new(StandardCommandBufferAllocator::new(device.clone())); + // Here is the basic initialization for the deferred system. - let mut frame_system = FrameSystem::new(queue.clone(), swapchain.image_format()); - let triangle_draw_system = - TriangleDrawSystem::new(queue.clone(), frame_system.deferred_subpass()); + let mut frame_system = FrameSystem::new( + queue.clone(), + swapchain.image_format(), + command_buffer_allocator.clone(), + ); + let triangle_draw_system = TriangleDrawSystem::new( + queue.clone(), + frame_system.deferred_subpass(), + command_buffer_allocator, + ); let mut recreate_swapchain = false; let mut previous_frame_end = Some(sync::now(device.clone()).boxed()); diff --git a/examples/src/bin/deferred/triangle_draw_system.rs b/examples/src/bin/deferred/triangle_draw_system.rs index dd446d5a..37467576 100644 --- a/examples/src/bin/deferred/triangle_draw_system.rs +++ b/examples/src/bin/deferred/triangle_draw_system.rs @@ -8,12 +8,12 @@ // according to those terms. use bytemuck::{Pod, Zeroable}; -use std::sync::Arc; +use std::{rc::Rc, sync::Arc}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferInheritanceInfo, CommandBufferUsage, - SecondaryAutoCommandBuffer, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, + CommandBufferInheritanceInfo, CommandBufferUsage, SecondaryAutoCommandBuffer, }, device::Queue, impl_vertex, @@ -34,11 +34,16 @@ pub struct TriangleDrawSystem { vertex_buffer: Arc>, subpass: Subpass, pipeline: Arc, + command_buffer_allocator: Rc, } impl TriangleDrawSystem { /// Initializes a triangle drawing system. - pub fn new(gfx_queue: Arc, subpass: Subpass) -> TriangleDrawSystem { + pub fn new( + gfx_queue: Arc, + subpass: Subpass, + command_buffer_allocator: Rc, + ) -> TriangleDrawSystem { let vertices = [ Vertex { position: [-0.5, -0.25], @@ -84,13 +89,14 @@ impl TriangleDrawSystem { vertex_buffer, subpass, pipeline, + command_buffer_allocator, } } /// Builds a secondary command buffer that draws the triangle on the current subpass. pub fn draw(&self, viewport_dimensions: [u32; 2]) -> SecondaryAutoCommandBuffer { let mut builder = AutoCommandBufferBuilder::secondary( - self.gfx_queue.device().clone(), + &*self.command_buffer_allocator, self.gfx_queue.queue_family_index(), CommandBufferUsage::MultipleSubmit, CommandBufferInheritanceInfo { diff --git a/examples/src/bin/dynamic-buffers.rs b/examples/src/bin/dynamic-buffers.rs index 9a288dfc..a2b25525 100644 --- a/examples/src/bin/dynamic-buffers.rs +++ b/examples/src/bin/dynamic-buffers.rs @@ -17,9 +17,12 @@ use std::{iter::repeat, mem::size_of}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer}, - command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage}, + command_buffer::{ + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + }, descriptor_set::{ - layout::DescriptorType, DescriptorSet, PersistentDescriptorSet, WriteDescriptorSet, + allocator::StandardDescriptorSetAllocator, layout::DescriptorType, DescriptorSet, + PersistentDescriptorSet, WriteDescriptorSet, }, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, @@ -128,6 +131,9 @@ fn main() { ) .unwrap(); + let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone()); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + // Declare input buffer. // Data in a dynamic buffer **MUST** be aligned to min_uniform_buffer_offset_align // or min_storage_buffer_offset_align, depending on the type of buffer. @@ -181,6 +187,7 @@ fn main() { let layout = pipeline.layout().set_layouts().get(0).unwrap(); let set = PersistentDescriptorSet::new( + &descriptor_set_allocator, layout.clone(), [ WriteDescriptorSet::buffer(0, input_buffer), @@ -191,7 +198,7 @@ fn main() { // Build the command buffer, using different offsets for each call. let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/dynamic-local-size.rs b/examples/src/bin/dynamic-local-size.rs index 97797abb..b1bf2a37 100644 --- a/examples/src/bin/dynamic-local-size.rs +++ b/examples/src/bin/dynamic-local-size.rs @@ -17,8 +17,13 @@ use std::{fs::File, io::BufWriter, path::Path}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer}, - command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, CopyImageToBufferInfo}, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, + command_buffer::{ + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + CopyImageToBufferInfo, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, + }, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, }, @@ -193,6 +198,9 @@ fn main() { ) .unwrap(); + let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone()); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + let image = StorageImage::new( device.clone(), ImageDimensions::Dim2d { @@ -207,9 +215,12 @@ fn main() { let view = ImageView::new_default(image.clone()).unwrap(); let layout = pipeline.layout().set_layouts().get(0).unwrap(); - let set = - PersistentDescriptorSet::new(layout.clone(), [WriteDescriptorSet::image_view(0, view)]) - .unwrap(); + let set = PersistentDescriptorSet::new( + &descriptor_set_allocator, + layout.clone(), + [WriteDescriptorSet::image_view(0, view)], + ) + .unwrap(); let buf = CpuAccessibleBuffer::from_iter( device.clone(), @@ -223,7 +234,7 @@ fn main() { .unwrap(); let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/gl-interop.rs b/examples/src/bin/gl-interop.rs index c1d983f0..93a81359 100644 --- a/examples/src/bin/gl-interop.rs +++ b/examples/src/bin/gl-interop.rs @@ -17,10 +17,13 @@ mod linux { use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SemaphoreSubmitInfo, - SubmitInfo, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, + CommandBufferUsage, RenderPassBeginInfo, SemaphoreSubmitInfo, SubmitInfo, + SubpassContents, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, }, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, Queue, QueueCreateInfo, @@ -225,9 +228,13 @@ mod linux { } }); + let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone()); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + let layout = pipeline.layout().set_layouts().get(0).unwrap(); let set = PersistentDescriptorSet::new( + &descriptor_set_allocator, layout.clone(), [WriteDescriptorSet::image_view_sampler( 0, image_view, sampler, @@ -324,7 +331,7 @@ mod linux { } let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/image-self-copy-blit/main.rs b/examples/src/bin/image-self-copy-blit/main.rs index c565dc4a..8b7d91c0 100644 --- a/examples/src/bin/image-self-copy-blit/main.rs +++ b/examples/src/bin/image-self-copy-blit/main.rs @@ -12,11 +12,14 @@ use std::{io::Cursor, sync::Arc}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, BlitImageInfo, BufferImageCopy, ClearColorImageInfo, - CommandBufferUsage, CopyBufferToImageInfo, CopyImageInfo, ImageBlit, ImageCopy, - PrimaryCommandBuffer, RenderPassBeginInfo, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, BlitImageInfo, + BufferImageCopy, ClearColorImageInfo, CommandBufferUsage, CopyBufferToImageInfo, + CopyImageInfo, ImageBlit, ImageCopy, PrimaryCommandBuffer, RenderPassBeginInfo, + SubpassContents, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, }, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, }, @@ -207,6 +210,9 @@ fn main() { ) .unwrap(); + let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone()); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + let (texture, tex_future) = { let png_bytes = include_bytes!("image_img.png").to_vec(); let cursor = Cursor::new(png_bytes); @@ -243,7 +249,7 @@ fn main() { .unwrap(); let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) @@ -339,6 +345,7 @@ fn main() { let layout = pipeline.layout().set_layouts().get(0).unwrap(); let set = PersistentDescriptorSet::new( + &descriptor_set_allocator, layout.clone(), [WriteDescriptorSet::image_view_sampler(0, texture, sampler)], ) @@ -406,7 +413,7 @@ fn main() { } let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/image/main.rs b/examples/src/bin/image/main.rs index cb2cb635..9e37c684 100644 --- a/examples/src/bin/image/main.rs +++ b/examples/src/bin/image/main.rs @@ -12,9 +12,12 @@ use std::{io::Cursor, sync::Arc}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + RenderPassBeginInfo, SubpassContents, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, }, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, }, @@ -205,6 +208,9 @@ fn main() { ) .unwrap(); + let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone()); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + let (texture, tex_future) = { let png_bytes = include_bytes!("image_img.png").to_vec(); let cursor = Cursor::new(png_bytes); @@ -225,6 +231,7 @@ fn main() { dimensions, MipmapsCount::One, Format::R8G8B8A8_SRGB, + &command_buffer_allocator, queue.clone(), ) .unwrap(); @@ -256,6 +263,7 @@ fn main() { let layout = pipeline.layout().set_layouts().get(0).unwrap(); let set = PersistentDescriptorSet::new( + &descriptor_set_allocator, layout.clone(), [WriteDescriptorSet::image_view_sampler(0, texture, sampler)], ) @@ -323,7 +331,7 @@ fn main() { } let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/immutable-sampler/main.rs b/examples/src/bin/immutable-sampler/main.rs index ee09981d..c4e77dee 100644 --- a/examples/src/bin/immutable-sampler/main.rs +++ b/examples/src/bin/immutable-sampler/main.rs @@ -21,9 +21,12 @@ use std::{io::Cursor, sync::Arc}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + RenderPassBeginInfo, SubpassContents, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, }, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, }, @@ -211,6 +214,9 @@ fn main() { ) .unwrap(); + let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone()); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + let (texture, tex_future) = { let png_bytes = include_bytes!("image_img.png").to_vec(); let cursor = Cursor::new(png_bytes); @@ -231,6 +237,7 @@ fn main() { dimensions, MipmapsCount::One, Format::R8G8B8A8_SRGB, + &command_buffer_allocator, queue.clone(), ) .unwrap(); @@ -268,9 +275,12 @@ fn main() { let layout = pipeline.layout().set_layouts().get(0).unwrap(); // Use `image_view` instead of `image_view_sampler`, since the sampler is already in the layout. - let set = - PersistentDescriptorSet::new(layout.clone(), [WriteDescriptorSet::image_view(0, texture)]) - .unwrap(); + let set = PersistentDescriptorSet::new( + &descriptor_set_allocator, + layout.clone(), + [WriteDescriptorSet::image_view(0, texture)], + ) + .unwrap(); let mut viewport = Viewport { origin: [0.0, 0.0], @@ -334,7 +344,7 @@ fn main() { } let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/indirect.rs b/examples/src/bin/indirect.rs index 019f0aaf..c70f8ee6 100644 --- a/examples/src/bin/indirect.rs +++ b/examples/src/bin/indirect.rs @@ -29,10 +29,12 @@ use std::sync::Arc; use vulkano::{ buffer::{BufferUsage, CpuBufferPool}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, DrawIndirectCommand, RenderPassBeginInfo, - SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + DrawIndirectCommand, RenderPassBeginInfo, SubpassContents, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, }, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, }, @@ -315,6 +317,9 @@ fn main() { let mut recreate_swapchain = false; let mut previous_frame_end = Some(sync::now(device.clone()).boxed()); + let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone()); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + event_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { @@ -390,6 +395,7 @@ fn main() { // Pass the two buffers to the compute shader let layout = compute_pipeline.layout().set_layouts().get(0).unwrap(); let cs_desciptor_set = PersistentDescriptorSet::new( + &descriptor_set_allocator, layout.clone(), [ WriteDescriptorSet::buffer(0, vertices.clone()), @@ -399,7 +405,7 @@ fn main() { .unwrap(); let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/instancing.rs b/examples/src/bin/instancing.rs index fc1469cd..ae507abf 100644 --- a/examples/src/bin/instancing.rs +++ b/examples/src/bin/instancing.rs @@ -17,7 +17,8 @@ use std::sync::Arc; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + RenderPassBeginInfo, SubpassContents, }, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, @@ -314,6 +315,8 @@ fn main() { let mut recreate_swapchain = false; let mut previous_frame_end = Some(sync::now(device.clone()).boxed()); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + event_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { @@ -371,7 +374,7 @@ fn main() { } let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/interactive_fractal/app.rs b/examples/src/bin/interactive_fractal/app.rs index f591381c..cdeb48fe 100644 --- a/examples/src/bin/interactive_fractal/app.rs +++ b/examples/src/bin/interactive_fractal/app.rs @@ -10,8 +10,10 @@ use crate::fractal_compute_pipeline::FractalComputePipeline; use crate::place_over_frame::RenderPassPlaceOverFrame; use cgmath::Vector2; -use std::sync::Arc; use std::time::Instant; +use std::{rc::Rc, sync::Arc}; +use vulkano::command_buffer::allocator::StandardCommandBufferAllocator; +use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator; use vulkano::device::Queue; use vulkano::sync::GpuFuture; use vulkano_util::renderer::{DeviceImageView, VulkanoWindowRenderer}; @@ -58,9 +60,25 @@ pub struct FractalApp { impl FractalApp { pub fn new(gfx_queue: Arc, image_format: vulkano::format::Format) -> FractalApp { + let command_buffer_allocator = Rc::new(StandardCommandBufferAllocator::new( + gfx_queue.device().clone(), + )); + let descriptor_set_allocator = Rc::new(StandardDescriptorSetAllocator::new( + gfx_queue.device().clone(), + )); + FractalApp { - fractal_pipeline: FractalComputePipeline::new(gfx_queue.clone()), - place_over_frame: RenderPassPlaceOverFrame::new(gfx_queue, image_format), + fractal_pipeline: FractalComputePipeline::new( + gfx_queue.clone(), + command_buffer_allocator.clone(), + descriptor_set_allocator.clone(), + ), + place_over_frame: RenderPassPlaceOverFrame::new( + gfx_queue, + command_buffer_allocator, + descriptor_set_allocator, + image_format, + ), is_julia: false, is_c_paused: false, c: Vector2::new(0.0, 0.0), diff --git a/examples/src/bin/interactive_fractal/fractal_compute_pipeline.rs b/examples/src/bin/interactive_fractal/fractal_compute_pipeline.rs index d6e43f31..c5554ab6 100644 --- a/examples/src/bin/interactive_fractal/fractal_compute_pipeline.rs +++ b/examples/src/bin/interactive_fractal/fractal_compute_pipeline.rs @@ -9,11 +9,16 @@ use cgmath::Vector2; use rand::Rng; -use std::sync::Arc; +use std::{rc::Rc, sync::Arc}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer}, - command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBuffer}, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, + command_buffer::{ + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + PrimaryCommandBuffer, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, + }, device::Queue, image::ImageAccess, pipeline::{ComputePipeline, Pipeline, PipelineBindPoint}, @@ -24,13 +29,19 @@ use vulkano_util::renderer::DeviceImageView; pub struct FractalComputePipeline { queue: Arc, pipeline: Arc, + command_buffer_allocator: Rc, + descriptor_set_allocator: Rc, palette: Arc>, palette_size: i32, end_color: [f32; 4], } impl FractalComputePipeline { - pub fn new(queue: Arc) -> FractalComputePipeline { + pub fn new( + queue: Arc, + command_buffer_allocator: Rc, + descriptor_set_allocator: Rc, + ) -> FractalComputePipeline { // Initial colors let colors = vec![ [1.0, 0.0, 0.0, 1.0], @@ -64,9 +75,12 @@ impl FractalComputePipeline { ) .unwrap() }; + FractalComputePipeline { queue, pipeline, + command_buffer_allocator, + descriptor_set_allocator, palette, palette_size, end_color, @@ -96,7 +110,7 @@ impl FractalComputePipeline { } pub fn compute( - &mut self, + &self, image: DeviceImageView, c: Vector2, scale: Vector2, @@ -109,6 +123,7 @@ impl FractalComputePipeline { let pipeline_layout = self.pipeline.layout(); let desc_layout = pipeline_layout.set_layouts().get(0).unwrap(); let set = PersistentDescriptorSet::new( + &*self.descriptor_set_allocator, desc_layout.clone(), [ WriteDescriptorSet::image_view(0, image), @@ -117,7 +132,7 @@ impl FractalComputePipeline { ) .unwrap(); let mut builder = AutoCommandBufferBuilder::primary( - self.queue.device().clone(), + &*self.command_buffer_allocator, self.queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/interactive_fractal/pixels_draw_pipeline.rs b/examples/src/bin/interactive_fractal/pixels_draw_pipeline.rs index 7e8f11bd..878deaec 100644 --- a/examples/src/bin/interactive_fractal/pixels_draw_pipeline.rs +++ b/examples/src/bin/interactive_fractal/pixels_draw_pipeline.rs @@ -8,14 +8,16 @@ // according to those terms. use bytemuck::{Pod, Zeroable}; -use std::sync::Arc; +use std::{rc::Rc, sync::Arc}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferInheritanceInfo, CommandBufferUsage, - SecondaryAutoCommandBuffer, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, + CommandBufferInheritanceInfo, CommandBufferUsage, SecondaryAutoCommandBuffer, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, }, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, device::Queue, image::ImageViewAbstract, impl_vertex, @@ -69,12 +71,19 @@ pub struct PixelsDrawPipeline { gfx_queue: Arc, subpass: Subpass, pipeline: Arc, + command_buffer_allocator: Rc, + descriptor_set_allocator: Rc, vertices: Arc>, indices: Arc>, } impl PixelsDrawPipeline { - pub fn new(gfx_queue: Arc, subpass: Subpass) -> PixelsDrawPipeline { + pub fn new( + gfx_queue: Arc, + subpass: Subpass, + command_buffer_allocator: Rc, + descriptor_set_allocator: Rc, + ) -> PixelsDrawPipeline { let (vertices, indices) = textured_quad(2.0, 2.0); let vertex_buffer = CpuAccessibleBuffer::<[TexturedVertex]>::from_iter( gfx_queue.device().clone(), @@ -110,10 +119,13 @@ impl PixelsDrawPipeline { .build(gfx_queue.device().clone()) .unwrap() }; + PixelsDrawPipeline { gfx_queue, subpass, pipeline, + command_buffer_allocator, + descriptor_set_allocator, vertices: vertex_buffer, indices: index_buffer, } @@ -137,6 +149,7 @@ impl PixelsDrawPipeline { .unwrap(); PersistentDescriptorSet::new( + &*self.descriptor_set_allocator, layout.clone(), [WriteDescriptorSet::image_view_sampler( 0, @@ -154,7 +167,7 @@ impl PixelsDrawPipeline { image: Arc, ) -> SecondaryAutoCommandBuffer { let mut builder = AutoCommandBufferBuilder::secondary( - self.gfx_queue.device().clone(), + &*self.command_buffer_allocator, self.gfx_queue.queue_family_index(), CommandBufferUsage::MultipleSubmit, CommandBufferInheritanceInfo { diff --git a/examples/src/bin/interactive_fractal/place_over_frame.rs b/examples/src/bin/interactive_fractal/place_over_frame.rs index d51a7d17..d11c5387 100644 --- a/examples/src/bin/interactive_fractal/place_over_frame.rs +++ b/examples/src/bin/interactive_fractal/place_over_frame.rs @@ -8,11 +8,13 @@ // according to those terms. use crate::pixels_draw_pipeline::PixelsDrawPipeline; -use std::sync::Arc; +use std::{rc::Rc, sync::Arc}; use vulkano::{ command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + RenderPassBeginInfo, SubpassContents, }, + descriptor_set::allocator::StandardDescriptorSetAllocator, device::Queue, format::Format, image::ImageAccess, @@ -26,10 +28,16 @@ pub struct RenderPassPlaceOverFrame { gfx_queue: Arc, render_pass: Arc, pixels_draw_pipeline: PixelsDrawPipeline, + command_buffer_allocator: Rc, } impl RenderPassPlaceOverFrame { - pub fn new(gfx_queue: Arc, output_format: Format) -> RenderPassPlaceOverFrame { + pub fn new( + gfx_queue: Arc, + command_buffer_allocator: Rc, + descriptor_set_allocator: Rc, + output_format: Format, + ) -> RenderPassPlaceOverFrame { let render_pass = vulkano::single_pass_renderpass!(gfx_queue.device().clone(), attachments: { color: { @@ -46,11 +54,18 @@ impl RenderPassPlaceOverFrame { ) .unwrap(); let subpass = Subpass::from(render_pass.clone(), 0).unwrap(); - let pixels_draw_pipeline = PixelsDrawPipeline::new(gfx_queue.clone(), subpass); + let pixels_draw_pipeline = PixelsDrawPipeline::new( + gfx_queue.clone(), + subpass, + command_buffer_allocator.clone(), + descriptor_set_allocator, + ); + RenderPassPlaceOverFrame { gfx_queue, render_pass, pixels_draw_pipeline, + command_buffer_allocator, } } @@ -78,7 +93,7 @@ impl RenderPassPlaceOverFrame { .unwrap(); // Create primary command buffer builder let mut command_buffer_builder = AutoCommandBufferBuilder::primary( - self.gfx_queue.device().clone(), + &*self.command_buffer_allocator, self.gfx_queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/msaa-renderpass.rs b/examples/src/bin/msaa-renderpass.rs index c429aa9f..ae33a319 100644 --- a/examples/src/bin/msaa-renderpass.rs +++ b/examples/src/bin/msaa-renderpass.rs @@ -69,8 +69,8 @@ use std::{fs::File, io::BufWriter, path::Path}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, CopyImageToBufferInfo, PrimaryCommandBuffer, - RenderPassBeginInfo, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + CopyImageToBufferInfo, PrimaryCommandBuffer, RenderPassBeginInfo, SubpassContents, }, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, @@ -314,8 +314,10 @@ fn main() { depth_range: 0.0..1.0, }; + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + let buf = CpuAccessibleBuffer::from_iter( - device.clone(), + device, BufferUsage { transfer_dst: true, ..BufferUsage::empty() @@ -326,7 +328,7 @@ fn main() { .unwrap(); let mut builder = AutoCommandBufferBuilder::primary( - device, + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/multi-window.rs b/examples/src/bin/multi-window.rs index 44695397..3be759a0 100644 --- a/examples/src/bin/multi-window.rs +++ b/examples/src/bin/multi-window.rs @@ -21,7 +21,8 @@ use std::{collections::HashMap, sync::Arc}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + RenderPassBeginInfo, SubpassContents, }, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, @@ -272,6 +273,8 @@ fn main() { depth_range: 0.0..1.0, }; + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + window_surfaces.insert( window_id, WindowSurface { @@ -415,7 +418,7 @@ fn main() { } let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/multi_window_game_of_life/app.rs b/examples/src/bin/multi_window_game_of_life/app.rs index 7eb5fa34..5fd3a6d9 100644 --- a/examples/src/bin/multi_window_game_of_life/app.rs +++ b/examples/src/bin/multi_window_game_of_life/app.rs @@ -11,7 +11,9 @@ use crate::{ game_of_life::GameOfLifeComputePipeline, render_pass::RenderPassPlaceOverFrame, SCALING, WINDOW2_HEIGHT, WINDOW2_WIDTH, WINDOW_HEIGHT, WINDOW_WIDTH, }; -use std::{collections::HashMap, sync::Arc}; +use std::{collections::HashMap, rc::Rc, sync::Arc}; +use vulkano::command_buffer::allocator::StandardCommandBufferAllocator; +use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator; use vulkano::{device::Queue, format::Format}; use vulkano_util::context::{VulkanoConfig, VulkanoContext}; use vulkano_util::window::{VulkanoWindows, WindowDescriptor}; @@ -29,9 +31,26 @@ impl RenderPipeline { size: [u32; 2], swapchain_format: Format, ) -> RenderPipeline { + let command_buffer_allocator = Rc::new(StandardCommandBufferAllocator::new( + gfx_queue.device().clone(), + )); + let descriptor_set_allocator = Rc::new(StandardDescriptorSetAllocator::new( + gfx_queue.device().clone(), + )); + RenderPipeline { - compute: GameOfLifeComputePipeline::new(compute_queue, size), - place_over_frame: RenderPassPlaceOverFrame::new(gfx_queue, swapchain_format), + compute: GameOfLifeComputePipeline::new( + compute_queue, + command_buffer_allocator.clone(), + descriptor_set_allocator.clone(), + size, + ), + place_over_frame: RenderPassPlaceOverFrame::new( + gfx_queue, + command_buffer_allocator, + descriptor_set_allocator, + swapchain_format, + ), } } } diff --git a/examples/src/bin/multi_window_game_of_life/game_of_life.rs b/examples/src/bin/multi_window_game_of_life/game_of_life.rs index af9601d2..dd0b2346 100644 --- a/examples/src/bin/multi_window_game_of_life/game_of_life.rs +++ b/examples/src/bin/multi_window_game_of_life/game_of_life.rs @@ -9,7 +9,9 @@ use cgmath::Vector2; use rand::Rng; -use std::sync::Arc; +use std::{rc::Rc, sync::Arc}; +use vulkano::command_buffer::allocator::StandardCommandBufferAllocator; +use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator; use vulkano::image::{ImageUsage, StorageImage}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer}, @@ -31,6 +33,8 @@ use vulkano_util::renderer::DeviceImageView; pub struct GameOfLifeComputePipeline { compute_queue: Arc, compute_life_pipeline: Arc, + command_buffer_allocator: Rc, + descriptor_set_allocator: Rc, life_in: Arc>, life_out: Arc>, image: DeviceImageView, @@ -52,7 +56,12 @@ fn rand_grid(compute_queue: &Arc, size: [u32; 2]) -> Arc, size: [u32; 2]) -> GameOfLifeComputePipeline { + pub fn new( + compute_queue: Arc, + command_buffer_allocator: Rc, + descriptor_set_allocator: Rc, + size: [u32; 2], + ) -> GameOfLifeComputePipeline { let life_in = rand_grid(&compute_queue, size); let life_out = rand_grid(&compute_queue, size); @@ -81,9 +90,12 @@ impl GameOfLifeComputePipeline { }, ) .unwrap(); + GameOfLifeComputePipeline { compute_queue, compute_life_pipeline, + command_buffer_allocator, + descriptor_set_allocator, life_in, life_out, image, @@ -94,7 +106,7 @@ impl GameOfLifeComputePipeline { self.image.clone() } - pub fn draw_life(&mut self, pos: Vector2) { + pub fn draw_life(&self, pos: Vector2) { let mut life_in = self.life_in.write().unwrap(); let size = self.image.image().dimensions().width_height(); if pos.y < 0 || pos.y >= size[1] as i32 || pos.x < 0 || pos.x >= size[0] as i32 { @@ -111,7 +123,7 @@ impl GameOfLifeComputePipeline { dead_color: [f32; 4], ) -> Box { let mut builder = AutoCommandBufferBuilder::primary( - self.compute_queue.device().clone(), + &*self.command_buffer_allocator, self.compute_queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) @@ -140,7 +152,7 @@ impl GameOfLifeComputePipeline { /// Build the command for a dispatch. fn dispatch( - &mut self, + &self, builder: &mut AutoCommandBufferBuilder, life_color: [f32; 4], dead_color: [f32; 4], @@ -152,6 +164,7 @@ impl GameOfLifeComputePipeline { let pipeline_layout = self.compute_life_pipeline.layout(); let desc_layout = pipeline_layout.set_layouts().get(0).unwrap(); let set = PersistentDescriptorSet::new( + &*self.descriptor_set_allocator, desc_layout.clone(), [ WriteDescriptorSet::image_view(0, self.image.clone()), @@ -202,7 +215,7 @@ int get_index(ivec2 pos) { void compute_life() { ivec2 pos = ivec2(gl_GlobalInvocationID.xy); int index = get_index(pos); - + ivec2 up_left = pos + ivec2(-1, 1); ivec2 up = pos + ivec2(0, 1); ivec2 up_right = pos + ivec2(1, 1); @@ -230,7 +243,7 @@ void compute_life() { life_out[index] = 0; } // Else Do nothing else { - + life_out[index] = life_in[index]; } } diff --git a/examples/src/bin/multi_window_game_of_life/pixels_draw.rs b/examples/src/bin/multi_window_game_of_life/pixels_draw.rs index 0eaa2a26..6540f8ea 100644 --- a/examples/src/bin/multi_window_game_of_life/pixels_draw.rs +++ b/examples/src/bin/multi_window_game_of_life/pixels_draw.rs @@ -8,14 +8,16 @@ // according to those terms. use bytemuck::{Pod, Zeroable}; -use std::sync::Arc; +use std::{rc::Rc, sync::Arc}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferInheritanceInfo, CommandBufferUsage, - SecondaryAutoCommandBuffer, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, + CommandBufferInheritanceInfo, CommandBufferUsage, SecondaryAutoCommandBuffer, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, }, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, device::Queue, image::ImageViewAbstract, impl_vertex, @@ -69,12 +71,19 @@ pub struct PixelsDrawPipeline { gfx_queue: Arc, subpass: Subpass, pipeline: Arc, + command_buffer_allocator: Rc, + descriptor_set_allocator: Rc, vertices: Arc>, indices: Arc>, } impl PixelsDrawPipeline { - pub fn new(gfx_queue: Arc, subpass: Subpass) -> PixelsDrawPipeline { + pub fn new( + gfx_queue: Arc, + subpass: Subpass, + command_buffer_allocator: Rc, + descriptor_set_allocator: Rc, + ) -> PixelsDrawPipeline { let (vertices, indices) = textured_quad(2.0, 2.0); let vertex_buffer = CpuAccessibleBuffer::<[TexturedVertex]>::from_iter( gfx_queue.device().clone(), @@ -110,10 +119,13 @@ impl PixelsDrawPipeline { .build(gfx_queue.device().clone()) .unwrap() }; + PixelsDrawPipeline { gfx_queue, subpass, pipeline, + command_buffer_allocator, + descriptor_set_allocator, vertices: vertex_buffer, indices: index_buffer, } @@ -137,6 +149,7 @@ impl PixelsDrawPipeline { .unwrap(); PersistentDescriptorSet::new( + &*self.descriptor_set_allocator, layout.clone(), [WriteDescriptorSet::image_view_sampler( 0, @@ -149,12 +162,12 @@ impl PixelsDrawPipeline { /// Draw input `image` over a quad of size -1.0 to 1.0 pub fn draw( - &mut self, + &self, viewport_dimensions: [u32; 2], image: Arc, ) -> SecondaryAutoCommandBuffer { let mut builder = AutoCommandBufferBuilder::secondary( - self.gfx_queue.device().clone(), + &*self.command_buffer_allocator, self.gfx_queue.queue_family_index(), CommandBufferUsage::MultipleSubmit, CommandBufferInheritanceInfo { diff --git a/examples/src/bin/multi_window_game_of_life/render_pass.rs b/examples/src/bin/multi_window_game_of_life/render_pass.rs index 17c9d71c..31666c97 100644 --- a/examples/src/bin/multi_window_game_of_life/render_pass.rs +++ b/examples/src/bin/multi_window_game_of_life/render_pass.rs @@ -8,11 +8,13 @@ // according to those terms. use crate::pixels_draw::PixelsDrawPipeline; -use std::sync::Arc; +use std::{rc::Rc, sync::Arc}; use vulkano::{ command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + RenderPassBeginInfo, SubpassContents, }, + descriptor_set::allocator::StandardDescriptorSetAllocator, device::Queue, format::Format, image::ImageAccess, @@ -26,10 +28,16 @@ pub struct RenderPassPlaceOverFrame { gfx_queue: Arc, render_pass: Arc, pixels_draw_pipeline: PixelsDrawPipeline, + command_buffer_allocator: Rc, } impl RenderPassPlaceOverFrame { - pub fn new(gfx_queue: Arc, output_format: Format) -> RenderPassPlaceOverFrame { + pub fn new( + gfx_queue: Arc, + command_buffer_allocator: Rc, + descriptor_set_allocator: Rc, + output_format: Format, + ) -> RenderPassPlaceOverFrame { let render_pass = vulkano::single_pass_renderpass!(gfx_queue.device().clone(), attachments: { color: { @@ -46,18 +54,25 @@ impl RenderPassPlaceOverFrame { ) .unwrap(); let subpass = Subpass::from(render_pass.clone(), 0).unwrap(); - let pixels_draw_pipeline = PixelsDrawPipeline::new(gfx_queue.clone(), subpass); + let pixels_draw_pipeline = PixelsDrawPipeline::new( + gfx_queue.clone(), + subpass, + command_buffer_allocator.clone(), + descriptor_set_allocator, + ); + RenderPassPlaceOverFrame { gfx_queue, render_pass, pixels_draw_pipeline, + command_buffer_allocator, } } /// Place view exactly over swapchain image target. /// Texture draw pipeline uses a quad onto which it places the view. pub fn render( - &mut self, + &self, before_future: F, view: DeviceImageView, target: SwapchainImageView, @@ -78,7 +93,7 @@ impl RenderPassPlaceOverFrame { .unwrap(); // Create primary command buffer builder let mut command_buffer_builder = AutoCommandBufferBuilder::primary( - self.gfx_queue.device().clone(), + &*self.command_buffer_allocator, self.gfx_queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/multiview.rs b/examples/src/bin/multiview.rs index 67ca89d8..7d971e0b 100644 --- a/examples/src/bin/multiview.rs +++ b/examples/src/bin/multiview.rs @@ -18,8 +18,8 @@ use std::{fs::File, io::BufWriter, path::Path, sync::Arc}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, BufferImageCopy, CommandBufferUsage, CopyImageToBufferInfo, - RenderPassBeginInfo, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, BufferImageCopy, + CommandBufferUsage, CopyImageToBufferInfo, RenderPassBeginInfo, SubpassContents, }, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, Features, @@ -277,6 +277,8 @@ fn main() { .build(device.clone()) .unwrap(); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + let create_buffer = || { CpuAccessibleBuffer::from_iter( device.clone(), @@ -294,7 +296,7 @@ fn main() { let buffer2 = create_buffer(); let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/occlusion-query.rs b/examples/src/bin/occlusion-query.rs index 8b80ef29..8f699856 100644 --- a/examples/src/bin/occlusion-query.rs +++ b/examples/src/bin/occlusion-query.rs @@ -16,7 +16,8 @@ use std::sync::Arc; use vulkano::{ buffer::{BufferAccess, BufferUsage, CpuAccessibleBuffer}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + RenderPassBeginInfo, SubpassContents, }, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, DeviceOwned, @@ -321,6 +322,8 @@ fn main() { depth_range: 0.0..1.0, }; + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport); let mut recreate_swapchain = false; @@ -378,7 +381,7 @@ fn main() { } let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/push-constants.rs b/examples/src/bin/push-constants.rs index ed8a4fb4..9d2582da 100644 --- a/examples/src/bin/push-constants.rs +++ b/examples/src/bin/push-constants.rs @@ -14,8 +14,12 @@ use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer}, - command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage}, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, + command_buffer::{ + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, + }, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, }, @@ -125,6 +129,9 @@ fn main() { ) .unwrap(); + let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone()); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + let data_buffer = { let data_iter = 0..65536u32; CpuAccessibleBuffer::from_iter( @@ -141,6 +148,7 @@ fn main() { let layout = pipeline.layout().set_layouts().get(0).unwrap(); let set = PersistentDescriptorSet::new( + &descriptor_set_allocator, layout.clone(), [WriteDescriptorSet::buffer(0, data_buffer.clone())], ) @@ -159,7 +167,7 @@ fn main() { // Note that there is no type safety for the push constants argument. // So be careful to only pass an instance of the struct generated by the `vulkano_shaders::shaders!` macro. let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/push-descriptors/main.rs b/examples/src/bin/push-descriptors/main.rs index 7fe8823f..3cdbd73e 100644 --- a/examples/src/bin/push-descriptors/main.rs +++ b/examples/src/bin/push-descriptors/main.rs @@ -12,7 +12,8 @@ use std::{io::Cursor, sync::Arc}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + RenderPassBeginInfo, SubpassContents, }, descriptor_set::WriteDescriptorSet, device::{ @@ -203,6 +204,8 @@ fn main() { ) .unwrap(); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + let (texture, tex_future) = { let png_bytes = include_bytes!("image_img.png").to_vec(); let cursor = Cursor::new(png_bytes); @@ -223,6 +226,7 @@ fn main() { dimensions, MipmapsCount::One, Format::R8G8B8A8_SRGB, + &command_buffer_allocator, queue.clone(), ) .unwrap(); @@ -319,7 +323,7 @@ fn main() { } let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/runtime-shader/main.rs b/examples/src/bin/runtime-shader/main.rs index 4eeaf2f8..0e94c466 100644 --- a/examples/src/bin/runtime-shader/main.rs +++ b/examples/src/bin/runtime-shader/main.rs @@ -24,7 +24,8 @@ use std::{fs::File, io::Read, sync::Arc}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + RenderPassBeginInfo, SubpassContents, }, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, @@ -256,6 +257,8 @@ fn main() { let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport); let mut previous_frame_end = Some(sync::now(device.clone()).boxed()); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + event_loop.run(move |event, _, control_flow| match event { Event::WindowEvent { event: WindowEvent::CloseRequested, @@ -308,7 +311,7 @@ fn main() { } let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::MultipleSubmit, ) diff --git a/examples/src/bin/runtime_array/main.rs b/examples/src/bin/runtime_array/main.rs index d5855b34..155789e5 100644 --- a/examples/src/bin/runtime_array/main.rs +++ b/examples/src/bin/runtime_array/main.rs @@ -12,9 +12,11 @@ use std::{io::Cursor, sync::Arc}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + RenderPassBeginInfo, SubpassContents, }, descriptor_set::{ + allocator::StandardDescriptorSetAllocator, layout::{ DescriptorSetLayout, DescriptorSetLayoutCreateInfo, DescriptorSetLayoutCreationError, }, @@ -268,6 +270,9 @@ fn main() { ) .unwrap(); + let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone()); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + let mascot_texture = { let png_bytes = include_bytes!("rust_mascot.png").to_vec(); let cursor = Cursor::new(png_bytes); @@ -288,6 +293,7 @@ fn main() { dimensions, MipmapsCount::One, Format::R8G8B8A8_SRGB, + &command_buffer_allocator, queue.clone(), ) .unwrap() @@ -316,6 +322,7 @@ fn main() { dimensions, MipmapsCount::One, Format::R8G8B8A8_SRGB, + &command_buffer_allocator, queue.clone(), ) .unwrap() @@ -381,6 +388,7 @@ fn main() { let layout = pipeline.layout().set_layouts().get(0).unwrap(); let set = PersistentDescriptorSet::new_variable( + &descriptor_set_allocator, layout.clone(), 2, [WriteDescriptorSet::image_view_sampler_array( @@ -457,7 +465,7 @@ fn main() { } let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/self-copy-buffer.rs b/examples/src/bin/self-copy-buffer.rs index 19b1599f..61d12422 100644 --- a/examples/src/bin/self-copy-buffer.rs +++ b/examples/src/bin/self-copy-buffer.rs @@ -13,9 +13,12 @@ use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer}, command_buffer::{ - AutoCommandBufferBuilder, BufferCopy, CommandBufferUsage, CopyBufferInfoTyped, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, BufferCopy, + CommandBufferUsage, CopyBufferInfoTyped, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, }, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, }, @@ -113,6 +116,9 @@ fn main() { .unwrap() }; + let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone()); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + let data_buffer = { // we intitialize half of the array and leave the other half to 0, we will use copy later to fill it let data_iter = (0..65536u32).map(|n| if n < 65536 / 2 { n } else { 0 }); @@ -132,13 +138,14 @@ fn main() { let layout = pipeline.layout().set_layouts().get(0).unwrap(); let set = PersistentDescriptorSet::new( + &descriptor_set_allocator, layout.clone(), [WriteDescriptorSet::buffer(0, data_buffer.clone())], ) .unwrap(); let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/shader-include/main.rs b/examples/src/bin/shader-include/main.rs index eb10014d..3f2197df 100644 --- a/examples/src/bin/shader-include/main.rs +++ b/examples/src/bin/shader-include/main.rs @@ -13,8 +13,12 @@ use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer}, - command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage}, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, + command_buffer::{ + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, + }, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, }, @@ -120,6 +124,9 @@ fn main() { .unwrap() }; + let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone()); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + let data_buffer = { let data_iter = 0..65536u32; CpuAccessibleBuffer::from_iter( @@ -136,13 +143,14 @@ fn main() { let layout = pipeline.layout().set_layouts().get(0).unwrap(); let set = PersistentDescriptorSet::new( + &descriptor_set_allocator, layout.clone(), [WriteDescriptorSet::buffer(0, data_buffer.clone())], ) .unwrap(); let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/shader-types-sharing.rs b/examples/src/bin/shader-types-sharing.rs index b38e6cd1..d178945b 100644 --- a/examples/src/bin/shader-types-sharing.rs +++ b/examples/src/bin/shader-types-sharing.rs @@ -30,8 +30,12 @@ use std::sync::Arc; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer}, - command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage}, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, + command_buffer::{ + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, + }, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, Queue, QueueCreateInfo, @@ -194,16 +198,19 @@ fn main() { queue: Arc, data_buffer: Arc>, parameters: shaders::ty::Parameters, + command_buffer_allocator: &StandardCommandBufferAllocator, + descriptor_set_allocator: &mut StandardDescriptorSetAllocator, ) { let layout = pipeline.layout().set_layouts().get(0).unwrap(); let set = PersistentDescriptorSet::new( + descriptor_set_allocator, layout.clone(), [WriteDescriptorSet::buffer(0, data_buffer)], ) .unwrap(); let mut builder = AutoCommandBufferBuilder::primary( - queue.device().clone(), + command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) @@ -230,6 +237,9 @@ fn main() { future.wait(None).unwrap(); } + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + let mut descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone()); + // Preparing test data array `[0, 1, 2, 3....]` let data_buffer = { let data_iter = 0..65536u32; @@ -277,6 +287,8 @@ fn main() { queue.clone(), data_buffer.clone(), shaders::ty::Parameters { value: 2 }, + &command_buffer_allocator, + &mut descriptor_set_allocator, ); // Then add 1 to each value @@ -285,6 +297,8 @@ fn main() { queue.clone(), data_buffer.clone(), shaders::ty::Parameters { value: 1 }, + &command_buffer_allocator, + &mut descriptor_set_allocator, ); // Then multiply each value by 3 @@ -293,6 +307,8 @@ fn main() { queue, data_buffer.clone(), shaders::ty::Parameters { value: 3 }, + &command_buffer_allocator, + &mut descriptor_set_allocator, ); let data_buffer_content = data_buffer.read().unwrap(); diff --git a/examples/src/bin/simple-particles.rs b/examples/src/bin/simple-particles.rs index 11372922..129252a7 100644 --- a/examples/src/bin/simple-particles.rs +++ b/examples/src/bin/simple-particles.rs @@ -18,10 +18,12 @@ use std::{sync::Arc, time::SystemTime}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, DeviceLocalBuffer}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, CopyBufferInfo, PrimaryCommandBuffer, - RenderPassBeginInfo, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + CopyBufferInfo, PrimaryCommandBuffer, RenderPassBeginInfo, SubpassContents, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, }, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, }, @@ -202,12 +204,12 @@ fn main() { #version 450 layout(local_size_x = 128, local_size_y = 1, local_size_z = 1) in; - + struct VertexData { vec2 pos; vec2 vel; }; - + // Storage buffer binding, which we optimize by using a DeviceLocalBuffer. layout (binding = 0) buffer VertexBuffer { VertexData verticies[]; @@ -303,9 +305,9 @@ fn main() { #version 450 layout(location = 0) in vec4 outColor; - + layout(location = 0) out vec4 fragColor; - + void main() { fragColor = outColor; } @@ -317,6 +319,9 @@ fn main() { let vs = vs::load(device.clone()).unwrap(); let fs = fs::load(device.clone()).unwrap(); + let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone()); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + #[repr(C)] #[derive(Clone, Copy, Debug, Default, Zeroable, Pod)] struct Vertex { @@ -366,7 +371,7 @@ fn main() { // Create one-time command to copy between the buffers. let mut cbb = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) @@ -402,6 +407,7 @@ fn main() { // Create a new descriptor set for binding vertices as a Storage Buffer. use vulkano::pipeline::Pipeline; // Required to access layout() method of pipeline. let descriptor_set = PersistentDescriptorSet::new( + &descriptor_set_allocator, compute_pipeline .layout() .set_layouts() @@ -497,7 +503,7 @@ fn main() { }; let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/specialization-constants.rs b/examples/src/bin/specialization-constants.rs index 5ca03f24..fd5f90b3 100644 --- a/examples/src/bin/specialization-constants.rs +++ b/examples/src/bin/specialization-constants.rs @@ -11,8 +11,12 @@ use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer}, - command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage}, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, + command_buffer::{ + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, + }, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, }, @@ -121,6 +125,9 @@ fn main() { ) .unwrap(); + let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone()); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + let data_buffer = { let data_iter = 0..65536u32; CpuAccessibleBuffer::from_iter( @@ -137,13 +144,14 @@ fn main() { let layout = pipeline.layout().set_layouts().get(0).unwrap(); let set = PersistentDescriptorSet::new( + &descriptor_set_allocator, layout.clone(), [WriteDescriptorSet::buffer(0, data_buffer.clone())], ) .unwrap(); let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/teapot/main.rs b/examples/src/bin/teapot/main.rs index f7573186..cf6d876b 100644 --- a/examples/src/bin/teapot/main.rs +++ b/examples/src/bin/teapot/main.rs @@ -13,9 +13,12 @@ use std::{sync::Arc, time::Instant}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, CpuBufferPool, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + RenderPassBeginInfo, SubpassContents, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, }, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, }, @@ -223,6 +226,9 @@ fn main() { let mut previous_frame_end = Some(sync::now(device.clone()).boxed()); let rotation_start = Instant::now(); + let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone()); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + event_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { @@ -303,6 +309,7 @@ fn main() { let layout = pipeline.layout().set_layouts().get(0).unwrap(); let set = PersistentDescriptorSet::new( + &descriptor_set_allocator, layout.clone(), [WriteDescriptorSet::buffer(0, uniform_buffer_subbuffer)], ) @@ -323,7 +330,7 @@ fn main() { } let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/tessellation.rs b/examples/src/bin/tessellation.rs index 38cae730..16f5286e 100644 --- a/examples/src/bin/tessellation.rs +++ b/examples/src/bin/tessellation.rs @@ -23,7 +23,8 @@ use std::sync::Arc; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + RenderPassBeginInfo, SubpassContents, }, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, Features, @@ -363,6 +364,8 @@ fn main() { }; let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + event_loop.run(move |event, _, control_flow| match event { Event::WindowEvent { event: WindowEvent::CloseRequested, @@ -415,7 +418,7 @@ fn main() { } let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/texture_array/main.rs b/examples/src/bin/texture_array/main.rs index 29dd5567..53547fba 100644 --- a/examples/src/bin/texture_array/main.rs +++ b/examples/src/bin/texture_array/main.rs @@ -12,9 +12,12 @@ use std::{io::Cursor, sync::Arc}; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + RenderPassBeginInfo, SubpassContents, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, }, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, }, @@ -207,6 +210,9 @@ fn main() { ) .unwrap(); + let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone()); + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + let (texture, tex_future) = { let image_array_data: Vec<_> = vec![ include_bytes!("square.png").to_vec(), @@ -235,6 +241,7 @@ fn main() { dimensions, MipmapsCount::Log2, Format::R8G8B8A8_SRGB, + &command_buffer_allocator, queue.clone(), ) .unwrap(); @@ -257,6 +264,7 @@ fn main() { let layout = pipeline.layout().set_layouts().get(0).unwrap(); let set = PersistentDescriptorSet::new( + &descriptor_set_allocator, layout.clone(), [WriteDescriptorSet::image_view_sampler(0, texture, sampler)], ) @@ -324,7 +332,7 @@ fn main() { } let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/triangle-v1_3.rs b/examples/src/bin/triangle-v1_3.rs index 0d0eebcc..5b18b266 100644 --- a/examples/src/bin/triangle-v1_3.rs +++ b/examples/src/bin/triangle-v1_3.rs @@ -26,7 +26,8 @@ use std::sync::Arc; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, RenderingAttachmentInfo, RenderingInfo, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + RenderingAttachmentInfo, RenderingInfo, }, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, Features, @@ -405,6 +406,14 @@ fn main() { // each image. let mut attachment_image_views = window_size_dependent_setup(&images, &mut viewport); + // Before we can start creating and recording command buffers, we need a way of allocating + // them. Vulkano provides a command buffer allocator, which manages raw Vulkan command pools + // underneath and provides a safe interface for them. + // + // A Vulkan command pool only works for one queue family, and vulkano's command buffer allocator + // reflects that, therefore we need to pass the queue family during creation. + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + // Initialization is finally finished! // In some situations, the swapchain will become invalid by itself. This includes for example @@ -506,7 +515,7 @@ fn main() { // Note that we have to pass a queue family when we create the command buffer. The command // buffer will only be executable on that given queue family. let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/examples/src/bin/triangle.rs b/examples/src/bin/triangle.rs index be1be46a..bf2e7b9e 100644 --- a/examples/src/bin/triangle.rs +++ b/examples/src/bin/triangle.rs @@ -21,7 +21,8 @@ use std::sync::Arc; use vulkano::{ buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}, command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, RenderPassBeginInfo, SubpassContents, + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + RenderPassBeginInfo, SubpassContents, }, device::{ physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, @@ -412,6 +413,14 @@ fn main() { // each image. let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport); + // Before we can start creating and recording command buffers, we need a way of allocating + // them. Vulkano provides a command buffer allocator, which manages raw Vulkan command pools + // underneath and provides a safe interface for them. + // + // A Vulkan command pool only works for one queue family, and vulkano's command buffer allocator + // reflects that, therefore we need to pass the queue family during creation. + let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone()); + // Initialization is finally finished! // In some situations, the swapchain will become invalid by itself. This includes for example @@ -523,7 +532,7 @@ fn main() { // Note that we have to pass a queue family when we create the command buffer. The command // buffer will only be executable on that given queue family. let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/vulkano/src/buffer/cpu_pool.rs b/vulkano/src/buffer/cpu_pool.rs index 4b7dbcb1..9245433e 100644 --- a/vulkano/src/buffer/cpu_pool.rs +++ b/vulkano/src/buffer/cpu_pool.rs @@ -67,6 +67,7 @@ use std::{ /// use vulkano::sync::GpuFuture; /// # let device: std::sync::Arc = return; /// # let queue: std::sync::Arc = return; +/// # let command_buffer_allocator: vulkano::command_buffer::allocator::StandardCommandBufferAllocator = return; /// /// // Create the ring buffer. /// let buffer = CpuBufferPool::upload(device.clone()); @@ -77,20 +78,23 @@ use std::{ /// let sub_buffer = buffer.from_data(data).unwrap(); /// /// // You can then use `sub_buffer` as if it was an entirely separate buffer. -/// AutoCommandBufferBuilder::primary(device.clone(), queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit) -/// .unwrap() -/// // For the sake of the example we just call `update_buffer` on the buffer, even though -/// // it is pointless to do that. -/// .update_buffer(&[0.2, 0.3, 0.4, 0.5], sub_buffer.clone(), 0) -/// .unwrap() -/// .build().unwrap() -/// .execute(queue.clone()) -/// .unwrap() -/// .then_signal_fence_and_flush() -/// .unwrap(); +/// AutoCommandBufferBuilder::primary( +/// &command_buffer_allocator, +/// queue.queue_family_index(), +/// CommandBufferUsage::OneTimeSubmit, +/// ) +/// .unwrap() +/// // For the sake of the example we just call `update_buffer` on the buffer, even though +/// // it is pointless to do that. +/// .update_buffer(&[0.2, 0.3, 0.4, 0.5], sub_buffer.clone(), 0) +/// .unwrap() +/// .build().unwrap() +/// .execute(queue.clone()) +/// .unwrap() +/// .then_signal_fence_and_flush() +/// .unwrap(); /// } /// ``` -/// pub struct CpuBufferPool> where [T]: BufferContents, diff --git a/vulkano/src/buffer/device_local.rs b/vulkano/src/buffer/device_local.rs index 246f8d01..e09af131 100644 --- a/vulkano/src/buffer/device_local.rs +++ b/vulkano/src/buffer/device_local.rs @@ -21,8 +21,8 @@ use super::{ }; use crate::{ command_buffer::{ - AutoCommandBufferBuilder, CommandBufferBeginError, CommandBufferExecFuture, - CommandBufferUsage, CopyBufferInfo, PrimaryCommandBuffer, + allocator::CommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferBeginError, + CommandBufferExecFuture, CommandBufferUsage, CopyBufferInfo, PrimaryCommandBuffer, }, device::{Device, DeviceOwned, Queue}, memory::{ @@ -79,6 +79,7 @@ use std::{ /// use vulkano::sync::GpuFuture; /// # let device: std::sync::Arc = return; /// # let queue: std::sync::Arc = return; +/// # let command_buffer_allocator: vulkano::command_buffer::allocator::StandardCommandBufferAllocator = return; /// /// // Simple iterator to construct test data. /// let data = (0..10_000).map(|i| i as f32); @@ -107,7 +108,7 @@ use std::{ /// /// // Create a one-time command to copy between the buffers. /// let mut cbb = AutoCommandBufferBuilder::primary( -/// device.clone(), +/// &command_buffer_allocator, /// queue.queue_family_index(), /// CommandBufferUsage::OneTimeSubmit, /// ) @@ -170,9 +171,6 @@ where } } -// TODO: make this prettier -type DeviceLocalBufferFromBufferFuture = CommandBufferExecFuture; - impl DeviceLocalBuffer where T: BufferContents + ?Sized, @@ -186,9 +184,13 @@ where pub fn from_buffer( source: Arc, usage: BufferUsage, + command_buffer_allocator: &impl CommandBufferAllocator, queue: Arc, ) -> Result< - (Arc>, DeviceLocalBufferFromBufferFuture), + ( + Arc>, + CommandBufferExecFuture, + ), DeviceLocalBufferCreationError, > where @@ -213,7 +215,7 @@ where )?; let mut cbb = AutoCommandBufferBuilder::primary( - source.device().clone(), + command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::MultipleSubmit, )?; @@ -252,9 +254,13 @@ where pub fn from_data( data: T, usage: BufferUsage, + command_buffer_allocator: &impl CommandBufferAllocator, queue: Arc, ) -> Result< - (Arc>, DeviceLocalBufferFromBufferFuture), + ( + Arc>, + CommandBufferExecFuture, + ), DeviceLocalBufferCreationError, > { let source = CpuAccessibleBuffer::from_data( @@ -266,7 +272,7 @@ where false, data, )?; - DeviceLocalBuffer::from_buffer(source, usage, queue) + DeviceLocalBuffer::from_buffer(source, usage, command_buffer_allocator, queue) } } @@ -281,11 +287,12 @@ where pub fn from_iter( data: D, usage: BufferUsage, + command_buffer_allocator: &impl CommandBufferAllocator, queue: Arc, ) -> Result< ( Arc>, - DeviceLocalBufferFromBufferFuture, + CommandBufferExecFuture, ), DeviceLocalBufferCreationError, > @@ -302,7 +309,7 @@ where false, data, )?; - DeviceLocalBuffer::from_buffer(source, usage, queue) + DeviceLocalBuffer::from_buffer(source, usage, command_buffer_allocator, queue) } } @@ -587,24 +594,27 @@ impl From for DeviceLocalBufferCreationError { #[cfg(test)] mod tests { use super::*; - use crate::sync::GpuFuture; + use crate::{command_buffer::allocator::StandardCommandBufferAllocator, sync::GpuFuture}; #[test] fn from_data_working() { let (device, queue) = gfx_dev_and_queue!(); + let cb_allocator = StandardCommandBufferAllocator::new(device.clone()); + let (buffer, _) = DeviceLocalBuffer::from_data( 12u32, BufferUsage { transfer_src: true, ..BufferUsage::empty() }, + &cb_allocator, queue.clone(), ) .unwrap(); let destination = CpuAccessibleBuffer::from_data( - device.clone(), + device, BufferUsage { transfer_dst: true, ..BufferUsage::empty() @@ -615,7 +625,7 @@ mod tests { .unwrap(); let mut cbb = AutoCommandBufferBuilder::primary( - device, + &cb_allocator, queue.queue_family_index(), CommandBufferUsage::MultipleSubmit, ) @@ -638,18 +648,21 @@ mod tests { fn from_iter_working() { let (device, queue) = gfx_dev_and_queue!(); + let cb_allocator = StandardCommandBufferAllocator::new(device.clone()); + let (buffer, _) = DeviceLocalBuffer::from_iter( (0..512u32).map(|n| n * 2), BufferUsage { transfer_src: true, ..BufferUsage::empty() }, + &cb_allocator, queue.clone(), ) .unwrap(); let destination = CpuAccessibleBuffer::from_iter( - device.clone(), + device, BufferUsage { transfer_dst: true, ..BufferUsage::empty() @@ -660,7 +673,7 @@ mod tests { .unwrap(); let mut cbb = AutoCommandBufferBuilder::primary( - device, + &cb_allocator, queue.queue_family_index(), CommandBufferUsage::MultipleSubmit, ) @@ -686,6 +699,8 @@ mod tests { fn create_buffer_zero_size_data() { let (device, queue) = gfx_dev_and_queue!(); + let cb_allocator = StandardCommandBufferAllocator::new(device); + assert_should_panic!({ DeviceLocalBuffer::from_data( (), @@ -693,6 +708,7 @@ mod tests { transfer_dst: true, ..BufferUsage::empty() }, + &cb_allocator, queue.clone(), ) .unwrap(); diff --git a/vulkano/src/buffer/view.rs b/vulkano/src/buffer/view.rs index 2b075ac7..044e4ce1 100644 --- a/vulkano/src/buffer/view.rs +++ b/vulkano/src/buffer/view.rs @@ -26,13 +26,18 @@ //! //! # let device: Arc = return; //! # let queue: Arc = return; +//! # let command_buffer_allocator: vulkano::command_buffer::allocator::StandardCommandBufferAllocator = return; //! let usage = BufferUsage { //! storage_texel_buffer: true, -//! .. BufferUsage::empty() +//! ..BufferUsage::empty() //! }; //! -//! let (buffer, _future) = DeviceLocalBuffer::<[u32]>::from_iter((0..128).map(|n| n), usage, -//! queue.clone()).unwrap(); +//! let (buffer, _future) = DeviceLocalBuffer::<[u32]>::from_iter( +//! (0..128).map(|n| n), +//! usage, +//! &command_buffer_allocator, +//! queue.clone() +//! ).unwrap(); //! let _view = BufferView::new( //! buffer, //! BufferViewCreateInfo { @@ -478,22 +483,29 @@ mod tests { view::{BufferView, BufferViewCreateInfo, BufferViewCreationError}, BufferUsage, DeviceLocalBuffer, }, + command_buffer::allocator::StandardCommandBufferAllocator, format::Format, }; #[test] fn create_uniform() { // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format - let (_device, queue) = gfx_dev_and_queue!(); + let (device, queue) = gfx_dev_and_queue!(); let usage = BufferUsage { uniform_texel_buffer: true, ..BufferUsage::empty() }; - let (buffer, _) = - DeviceLocalBuffer::<[[u8; 4]]>::from_iter((0..128).map(|_| [0; 4]), usage, queue) - .unwrap(); + let cb_allocator = StandardCommandBufferAllocator::new(device); + + let (buffer, _) = DeviceLocalBuffer::<[[u8; 4]]>::from_iter( + (0..128).map(|_| [0; 4]), + usage, + &cb_allocator, + queue, + ) + .unwrap(); BufferView::new( buffer, BufferViewCreateInfo { @@ -507,16 +519,22 @@ mod tests { #[test] fn create_storage() { // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format - let (_device, queue) = gfx_dev_and_queue!(); + let (device, queue) = gfx_dev_and_queue!(); let usage = BufferUsage { storage_texel_buffer: true, ..BufferUsage::empty() }; - let (buffer, _) = - DeviceLocalBuffer::<[[u8; 4]]>::from_iter((0..128).map(|_| [0; 4]), usage, queue) - .unwrap(); + let cb_allocator = StandardCommandBufferAllocator::new(device); + + let (buffer, _) = DeviceLocalBuffer::<[[u8; 4]]>::from_iter( + (0..128).map(|_| [0; 4]), + usage, + &cb_allocator, + queue, + ) + .unwrap(); BufferView::new( buffer, BufferViewCreateInfo { @@ -530,15 +548,18 @@ mod tests { #[test] fn create_storage_atomic() { // `VK_FORMAT_R32_UINT` guaranteed to be a supported format for atomics - let (_device, queue) = gfx_dev_and_queue!(); + let (device, queue) = gfx_dev_and_queue!(); let usage = BufferUsage { storage_texel_buffer: true, ..BufferUsage::empty() }; + let cb_allocator = StandardCommandBufferAllocator::new(device); + let (buffer, _) = - DeviceLocalBuffer::<[u32]>::from_iter((0..128).map(|_| 0), usage, queue).unwrap(); + DeviceLocalBuffer::<[u32]>::from_iter((0..128).map(|_| 0), usage, &cb_allocator, queue) + .unwrap(); BufferView::new( buffer, BufferViewCreateInfo { @@ -552,11 +573,14 @@ mod tests { #[test] fn wrong_usage() { // `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format - let (_device, queue) = gfx_dev_and_queue!(); + let (device, queue) = gfx_dev_and_queue!(); + + let cb_allocator = StandardCommandBufferAllocator::new(device); let (buffer, _) = DeviceLocalBuffer::<[[u8; 4]]>::from_iter( (0..128).map(|_| [0; 4]), BufferUsage::empty(), + &cb_allocator, queue, ) .unwrap(); @@ -575,7 +599,7 @@ mod tests { #[test] fn unsupported_format() { - let (_device, queue) = gfx_dev_and_queue!(); + let (device, queue) = gfx_dev_and_queue!(); let usage = BufferUsage { uniform_texel_buffer: true, @@ -583,9 +607,15 @@ mod tests { ..BufferUsage::empty() }; - let (buffer, _) = - DeviceLocalBuffer::<[[f64; 4]]>::from_iter((0..128).map(|_| [0.0; 4]), usage, queue) - .unwrap(); + let cb_allocator = StandardCommandBufferAllocator::new(device); + + let (buffer, _) = DeviceLocalBuffer::<[[f64; 4]]>::from_iter( + (0..128).map(|_| [0.0; 4]), + usage, + &cb_allocator, + queue, + ) + .unwrap(); // TODO: what if R64G64B64A64_SFLOAT is supported? match BufferView::new( diff --git a/vulkano/src/command_buffer/allocator.rs b/vulkano/src/command_buffer/allocator.rs new file mode 100644 index 00000000..f0393506 --- /dev/null +++ b/vulkano/src/command_buffer/allocator.rs @@ -0,0 +1,369 @@ +// Copyright (c) 2016 The vulkano developers +// Licensed under the Apache License, Version 2.0 +// or the MIT +// license , +// at your option. All files in the project carrying such +// notice may not be copied, modified, or distributed except +// according to those terms. + +//! In the Vulkan API, command buffers must be allocated from *command pools*. +//! +//! A command pool holds and manages the memory of one or more command buffers. If you destroy a +//! command pool, all of its command buffers are automatically destroyed. +//! +//! In vulkano, creating a command buffer requires passing an implementation of the +//! [`CommandBufferAllocator`] trait, which you can implement yourself or use the vulkano-provided +//! [`StandardCommandBufferAllocator`]. + +use super::{ + pool::{ + CommandBufferAllocateInfo, CommandPool, CommandPoolAlloc, CommandPoolCreateInfo, + CommandPoolCreationError, + }, + CommandBufferLevel, +}; +use crate::{ + device::{Device, DeviceOwned}, + OomError, +}; +use crossbeam_queue::SegQueue; +use smallvec::SmallVec; +use std::{cell::UnsafeCell, marker::PhantomData, mem::ManuallyDrop, sync::Arc, vec::IntoIter}; + +/// Types that manage the memory of command buffers. +/// +/// # Safety +/// +/// A Vulkan command pool must be externally synchronized as if it owned the command buffers that +/// were allocated from it. This includes allocating from the pool, freeing from the pool, resetting +/// the pool or individual command buffers, and most importantly recording commands to command +/// buffers. The implementation of `CommandBufferAllocator` is expected to manage this. +/// +/// The destructors of the [`CommandBufferBuilderAlloc`] and the [`CommandBufferAlloc`] are expected +/// to free the command buffer, reset the command buffer, or add it to a pool so that it gets +/// reused. If the implementation frees or resets the command buffer, it must not forget that this +/// operation must be externally synchronized. +pub unsafe trait CommandBufferAllocator: DeviceOwned { + /// See [`allocate`](Self::allocate). + type Iter: Iterator; + + /// Represents a command buffer that has been allocated and that is currently being built. + type Builder: CommandBufferBuilderAlloc; + + /// Represents a command buffer that has been allocated and that is pending execution or is + /// being executed. + type Alloc: CommandBufferAlloc; + + /// Allocates command buffers. + /// + /// Returns an iterator that contains the requested amount of allocated command buffers. + fn allocate( + &self, + queue_family_index: u32, + level: CommandBufferLevel, + command_buffer_count: u32, + ) -> Result; +} + +/// A command buffer allocated from a pool and that can be recorded. +/// +/// # Safety +/// +/// See [`CommandBufferAllocator`] for information about safety. +pub unsafe trait CommandBufferBuilderAlloc: DeviceOwned { + /// Return type of `into_alloc`. + type Alloc: CommandBufferAlloc; + + /// Returns the internal object that contains the command buffer. + fn inner(&self) -> &CommandPoolAlloc; + + /// Turns this builder into a command buffer that is pending execution. + fn into_alloc(self) -> Self::Alloc; + + /// Returns the index of the queue family that the pool targets. + fn queue_family_index(&self) -> u32; +} + +/// A command buffer allocated from a pool that has finished being recorded. +/// +/// # Safety +/// +/// See [`CommandBufferAllocator`] for information about safety. +pub unsafe trait CommandBufferAlloc: DeviceOwned + Send + Sync + 'static { + /// Returns the internal object that contains the command buffer. + fn inner(&self) -> &CommandPoolAlloc; + + /// Returns the index of the queue family that the pool targets. + fn queue_family_index(&self) -> u32; +} + +/// Standard implementation of a command buffer allocator. +/// +/// A thread can have as many `StandardCommandBufferAllocator`s as needed, but they can't be shared +/// between threads. This is done so that there are no locks involved when creating command +/// buffers. You are encouraged to create one allocator per frame in flight per thread. +/// +/// Command buffers can't be moved between threads during the building process, but finished command +/// buffers can. When a command buffer is dropped, it is returned back to the pool for reuse. +#[derive(Debug)] +pub struct StandardCommandBufferAllocator { + device: Arc, + /// Each queue family index points directly to its pool. + pools: SmallVec<[UnsafeCell>>; 8]>, +} + +impl StandardCommandBufferAllocator { + /// Creates a new `StandardCommandBufferAllocator`. + #[inline] + pub fn new(device: Arc) -> Self { + let pools = device + .physical_device() + .queue_family_properties() + .iter() + .map(|_| UnsafeCell::new(None)) + .collect(); + + StandardCommandBufferAllocator { device, pools } + } +} + +unsafe impl CommandBufferAllocator for StandardCommandBufferAllocator { + type Iter = IntoIter; + + type Builder = StandardCommandBufferBuilderAlloc; + + type Alloc = StandardCommandBufferAlloc; + + /// # Panics + /// + /// - Panics if the queue family index is not active on the device. + #[inline] + fn allocate( + &self, + queue_family_index: u32, + level: CommandBufferLevel, + command_buffer_count: u32, + ) -> Result { + // VUID-vkCreateCommandPool-queueFamilyIndex-01937 + assert!(self + .device + .active_queue_family_indices() + .contains(&queue_family_index)); + + let pool = unsafe { &mut *self.pools[queue_family_index as usize].get() }; + if pool.is_none() { + *pool = Some(Pool::new(self.device.clone(), queue_family_index)?); + } + + pool.as_ref().unwrap().allocate(level, command_buffer_count) + } +} + +unsafe impl DeviceOwned for StandardCommandBufferAllocator { + #[inline] + fn device(&self) -> &Arc { + &self.device + } +} + +#[derive(Debug)] +struct Pool { + // The Vulkan pool specific to a device's queue family. + inner: CommandPool, + // List of existing primary command buffers that are available for reuse. + primary_pool: SegQueue, + // List of existing secondary command buffers that are available for reuse. + secondary_pool: SegQueue, +} + +impl Pool { + fn new(device: Arc, queue_family_index: u32) -> Result, OomError> { + CommandPool::new( + device, + CommandPoolCreateInfo { + queue_family_index, + reset_command_buffer: true, + ..Default::default() + }, + ) + .map(|inner| { + Arc::new(Pool { + inner, + primary_pool: Default::default(), + secondary_pool: Default::default(), + }) + }) + .map_err(|err| match err { + CommandPoolCreationError::OomError(err) => err, + // We check that the provided queue family index is active on the device, so it can't + // be out of range. + CommandPoolCreationError::QueueFamilyIndexOutOfRange { .. } => unreachable!(), + }) + } + + fn allocate( + self: &Arc, + level: CommandBufferLevel, + mut command_buffer_count: u32, + ) -> Result, OomError> { + // The final output. + let mut output = Vec::with_capacity(command_buffer_count as usize); + + // First, pick from already-existing command buffers. + { + let existing = match level { + CommandBufferLevel::Primary => &self.primary_pool, + CommandBufferLevel::Secondary => &self.secondary_pool, + }; + + for _ in 0..command_buffer_count as usize { + if let Some(cmd) = existing.pop() { + output.push(StandardCommandBufferBuilderAlloc { + inner: StandardCommandBufferAlloc { + cmd: ManuallyDrop::new(cmd), + pool: self.clone(), + }, + dummy_avoid_send_sync: PhantomData, + }); + } else { + break; + } + } + } + + // Then allocate the rest. + if output.len() < command_buffer_count as usize { + command_buffer_count -= output.len() as u32; + + for cmd in self + .inner + .allocate_command_buffers(CommandBufferAllocateInfo { + level, + command_buffer_count, + ..Default::default() + })? + { + output.push(StandardCommandBufferBuilderAlloc { + inner: StandardCommandBufferAlloc { + cmd: ManuallyDrop::new(cmd), + pool: self.clone(), + }, + dummy_avoid_send_sync: PhantomData, + }); + } + } + + // Final output. + Ok(output.into_iter()) + } +} + +/// Command buffer allocated from a [`StandardCommandBufferAllocator`] that is currently being +/// built. +pub struct StandardCommandBufferBuilderAlloc { + // The only difference between a `StandardCommandBufferBuilder` and a + // `StandardCommandBufferAlloc` is that the former must not implement `Send` and `Sync`. + // Therefore we just share the structs. + inner: StandardCommandBufferAlloc, + // Unimplemented `Send` and `Sync` from the builder. + dummy_avoid_send_sync: PhantomData<*const u8>, +} + +unsafe impl CommandBufferBuilderAlloc for StandardCommandBufferBuilderAlloc { + type Alloc = StandardCommandBufferAlloc; + + #[inline] + fn inner(&self) -> &CommandPoolAlloc { + self.inner.inner() + } + + #[inline] + fn into_alloc(self) -> Self::Alloc { + self.inner + } + + #[inline] + fn queue_family_index(&self) -> u32 { + self.inner.queue_family_index() + } +} + +unsafe impl DeviceOwned for StandardCommandBufferBuilderAlloc { + #[inline] + fn device(&self) -> &Arc { + self.inner.device() + } +} + +/// Command buffer allocated from a [`StandardCommandBufferAllocator`]. +pub struct StandardCommandBufferAlloc { + // The actual command buffer. Extracted in the `Drop` implementation. + cmd: ManuallyDrop, + // We hold a reference to the command pool for our destructor. + pool: Arc, +} + +unsafe impl Send for StandardCommandBufferAlloc {} +unsafe impl Sync for StandardCommandBufferAlloc {} + +unsafe impl CommandBufferAlloc for StandardCommandBufferAlloc { + #[inline] + fn inner(&self) -> &CommandPoolAlloc { + &self.cmd + } + + #[inline] + fn queue_family_index(&self) -> u32 { + self.pool.inner.queue_family_index() + } +} + +unsafe impl DeviceOwned for StandardCommandBufferAlloc { + #[inline] + fn device(&self) -> &Arc { + self.pool.inner.device() + } +} + +impl Drop for StandardCommandBufferAlloc { + #[inline] + fn drop(&mut self) { + let cmd = unsafe { ManuallyDrop::take(&mut self.cmd) }; + + match cmd.level() { + CommandBufferLevel::Primary => self.pool.primary_pool.push(cmd), + CommandBufferLevel::Secondary => self.pool.secondary_pool.push(cmd), + } + } +} + +#[cfg(test)] +mod tests { + use super::{ + CommandBufferAllocator, CommandBufferBuilderAlloc, StandardCommandBufferAllocator, + }; + use crate::{command_buffer::CommandBufferLevel, VulkanObject}; + + #[test] + fn reuse_command_buffers() { + let (device, queue) = gfx_dev_and_queue!(); + + let allocator = StandardCommandBufferAllocator::new(device); + + let cb = allocator + .allocate(queue.queue_family_index(), CommandBufferLevel::Primary, 1) + .unwrap() + .next() + .unwrap(); + let raw = cb.inner().internal_object(); + drop(cb); + + let cb2 = allocator + .allocate(queue.queue_family_index(), CommandBufferLevel::Primary, 1) + .unwrap() + .next() + .unwrap(); + assert_eq!(raw, cb2.inner().internal_object()); + } +} diff --git a/vulkano/src/command_buffer/auto.rs b/vulkano/src/command_buffer/auto.rs index 2fd001c9..1f8bdb7c 100644 --- a/vulkano/src/command_buffer/auto.rs +++ b/vulkano/src/command_buffer/auto.rs @@ -8,9 +8,9 @@ // according to those terms. use super::{ - pool::{ - standard::{StandardCommandPoolAlloc, StandardCommandPoolBuilder}, - CommandPool, CommandPoolAlloc, CommandPoolBuilderAlloc, + allocator::{ + CommandBufferAlloc, CommandBufferAllocator, CommandBufferBuilderAlloc, + StandardCommandBufferAlloc, StandardCommandBufferAllocator, }, synced::{CommandBufferState, SyncCommandBuffer, SyncCommandBufferBuilder}, sys::{CommandBufferBeginInfo, UnsafeCommandBuffer}, @@ -41,13 +41,16 @@ use std::{ }, }; -/// Note that command buffers allocated from the default command pool (`Arc`) -/// don't implement the `Send` and `Sync` traits. If you use this pool, then the -/// `AutoCommandBufferBuilder` will not implement `Send` and `Sync` either. Once a command buffer -/// is built, however, it *does* implement `Send` and `Sync`. -pub struct AutoCommandBufferBuilder { +/// Note that command buffers allocated from `StandardCommandBufferAllocator` don't implement +/// the `Send` and `Sync` traits. If you use this allocator, then the `AutoCommandBufferBuilder` +/// will not implement `Send` and `Sync` either. Once a command buffer is built, however, it *does* +/// implement `Send` and `Sync`. +pub struct AutoCommandBufferBuilder +where + A: CommandBufferAllocator, +{ pub(super) inner: SyncCommandBufferBuilder, - pool_builder_alloc: P, // Safety: must be dropped after `inner` + builder_alloc: A::Builder, // Safety: must be dropped after `inner` // The index of the queue family that this command buffer is being created for. queue_family_index: u32, @@ -122,20 +125,23 @@ pub(super) struct QueryState { pub(super) in_subpass: bool, } -impl AutoCommandBufferBuilder { +impl AutoCommandBufferBuilder +where + A: CommandBufferAllocator, +{ /// Starts recording a primary command buffer. #[inline] pub fn primary( - device: Arc, + allocator: &A, queue_family_index: u32, usage: CommandBufferUsage, ) -> Result< - AutoCommandBufferBuilder, + AutoCommandBufferBuilder, A>, CommandBufferBeginError, > { unsafe { AutoCommandBufferBuilder::begin( - device, + allocator, queue_family_index, CommandBufferLevel::Primary, CommandBufferBeginInfo { @@ -148,21 +154,24 @@ impl AutoCommandBufferBuilder { +impl AutoCommandBufferBuilder +where + A: CommandBufferAllocator, +{ /// Starts recording a secondary command buffer. #[inline] pub fn secondary( - device: Arc, + allocator: &A, queue_family_index: u32, usage: CommandBufferUsage, inheritance_info: CommandBufferInheritanceInfo, ) -> Result< - AutoCommandBufferBuilder, + AutoCommandBufferBuilder, A>, CommandBufferBeginError, > { unsafe { AutoCommandBufferBuilder::begin( - device, + allocator, queue_family_index, CommandBufferLevel::Secondary, CommandBufferBeginInfo { @@ -175,18 +184,20 @@ impl AutoCommandBufferBuilder AutoCommandBufferBuilder { +impl AutoCommandBufferBuilder +where + A: CommandBufferAllocator, +{ // Actual constructor. Private. // // `begin_info.inheritance_info` must match `level`. unsafe fn begin( - device: Arc, + allocator: &A, queue_family_index: u32, level: CommandBufferLevel, begin_info: CommandBufferBeginInfo, - ) -> Result, CommandBufferBeginError> - { - Self::validate_begin(&device, queue_family_index, level, &begin_info)?; + ) -> Result, CommandBufferBeginError> { + Self::validate_begin(allocator.device(), queue_family_index, level, &begin_info)?; let &CommandBufferBeginInfo { usage, @@ -250,25 +261,23 @@ impl AutoCommandBufferBuilder { } } - device.with_standard_command_pool(queue_family_index, |pool| { - let pool_builder_alloc = pool - .allocate(level, 1)? - .next() - .expect("Requested one command buffer from the command pool, but got zero."); + let builder_alloc = allocator + .allocate(queue_family_index, level, 1)? + .next() + .expect("requested one command buffer from the command pool, but got zero"); - let inner = SyncCommandBufferBuilder::new(pool_builder_alloc.inner(), begin_info)?; + let inner = SyncCommandBufferBuilder::new(builder_alloc.inner(), begin_info)?; - Ok(AutoCommandBufferBuilder { - inner, - pool_builder_alloc, - queue_family_index, - render_pass_state, - query_state: HashMap::default(), - inheritance_info, - usage, - _data: PhantomData, - }) - })? + Ok(AutoCommandBufferBuilder { + inner, + builder_alloc, + queue_family_index, + render_pass_state, + query_state: HashMap::default(), + inheritance_info, + usage, + _data: PhantomData, + }) } fn validate_begin( @@ -592,12 +601,12 @@ impl From for CommandBufferBeginError { } } -impl

AutoCommandBufferBuilder, P> +impl AutoCommandBufferBuilder, A> where - P: CommandPoolBuilderAlloc, + A: CommandBufferAllocator, { /// Builds the command buffer. - pub fn build(self) -> Result, BuildError> { + pub fn build(self) -> Result, BuildError> { if self.render_pass_state.is_some() { return Err(BuildError::RenderPassActive); } @@ -618,18 +627,18 @@ where Ok(PrimaryAutoCommandBuffer { inner: self.inner.build()?, - _pool_alloc: self.pool_builder_alloc.into_alloc(), + _alloc: self.builder_alloc.into_alloc(), submit_state, }) } } -impl

AutoCommandBufferBuilder, P> +impl AutoCommandBufferBuilder, A> where - P: CommandPoolBuilderAlloc, + A: CommandBufferAllocator, { /// Builds the command buffer. - pub fn build(self) -> Result, BuildError> { + pub fn build(self) -> Result, BuildError> { if !self.query_state.is_empty() { return Err(BuildError::QueryActive); } @@ -646,7 +655,7 @@ where Ok(SecondaryAutoCommandBuffer { inner: self.inner.build()?, - _pool_alloc: self.pool_builder_alloc.into_alloc(), + _alloc: self.builder_alloc.into_alloc(), inheritance_info: self.inheritance_info.unwrap(), submit_state, }) @@ -692,7 +701,10 @@ impl From for BuildError { } } -impl AutoCommandBufferBuilder { +impl AutoCommandBufferBuilder +where + A: CommandBufferAllocator, +{ pub(super) fn queue_family_properties(&self) -> &QueueFamilyProperties { &self.device().physical_device().queue_family_properties()[self.queue_family_index as usize] } @@ -703,15 +715,18 @@ impl AutoCommandBufferBuilder { } } -unsafe impl DeviceOwned for AutoCommandBufferBuilder { +unsafe impl DeviceOwned for AutoCommandBufferBuilder +where + A: CommandBufferAllocator, +{ fn device(&self) -> &Arc { self.inner.device() } } -pub struct PrimaryAutoCommandBuffer

{ +pub struct PrimaryAutoCommandBuffer { inner: SyncCommandBuffer, - _pool_alloc: P, // Safety: must be dropped after `inner` + _alloc: A, // Safety: must be dropped after `inner` // Tracks usage of the command buffer on the GPU. submit_state: SubmitState, @@ -723,9 +738,9 @@ unsafe impl

DeviceOwned for PrimaryAutoCommandBuffer

{ } } -unsafe impl

PrimaryCommandBuffer for PrimaryAutoCommandBuffer

+unsafe impl PrimaryCommandBuffer for PrimaryAutoCommandBuffer where - P: CommandPoolAlloc, + A: CommandBufferAlloc, { fn inner(&self) -> &UnsafeCommandBuffer { self.inner.as_ref() @@ -817,24 +832,24 @@ where } } -pub struct SecondaryAutoCommandBuffer

{ +pub struct SecondaryAutoCommandBuffer { inner: SyncCommandBuffer, - _pool_alloc: P, // Safety: must be dropped after `inner` + _alloc: A, // Safety: must be dropped after `inner` inheritance_info: CommandBufferInheritanceInfo, // Tracks usage of the command buffer on the GPU. submit_state: SubmitState, } -unsafe impl

DeviceOwned for SecondaryAutoCommandBuffer

{ +unsafe impl DeviceOwned for SecondaryAutoCommandBuffer { fn device(&self) -> &Arc { self.inner.device() } } -unsafe impl

SecondaryCommandBuffer for SecondaryAutoCommandBuffer

+unsafe impl SecondaryCommandBuffer for SecondaryAutoCommandBuffer where - P: CommandPoolAlloc, + A: CommandBufferAlloc, { fn inner(&self) -> &UnsafeCommandBuffer { self.inner.as_ref() @@ -992,8 +1007,9 @@ mod tests { ) .unwrap(); + let allocator = StandardCommandBufferAllocator::new(device); let mut cbb = AutoCommandBufferBuilder::primary( - device, + &allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) @@ -1029,9 +1045,11 @@ mod tests { fn secondary_nonconcurrent_conflict() { let (device, queue) = gfx_dev_and_queue!(); + let allocator = StandardCommandBufferAllocator::new(device); + // Make a secondary CB that doesn't support simultaneous use. let builder = AutoCommandBufferBuilder::secondary( - device.clone(), + &allocator, queue.queue_family_index(), CommandBufferUsage::MultipleSubmit, Default::default(), @@ -1041,7 +1059,7 @@ mod tests { { let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &allocator, queue.queue_family_index(), CommandBufferUsage::SimultaneousUse, ) @@ -1064,7 +1082,7 @@ mod tests { { let mut builder = AutoCommandBufferBuilder::primary( - device.clone(), + &allocator, queue.queue_family_index(), CommandBufferUsage::SimultaneousUse, ) @@ -1073,7 +1091,7 @@ mod tests { let cb1 = builder.build().unwrap(); let mut builder = AutoCommandBufferBuilder::primary( - device, + &allocator, queue.queue_family_index(), CommandBufferUsage::SimultaneousUse, ) @@ -1113,8 +1131,9 @@ mod tests { ) .unwrap(); + let allocator = StandardCommandBufferAllocator::new(device); let mut builder = AutoCommandBufferBuilder::primary( - device, + &allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) @@ -1163,8 +1182,9 @@ mod tests { ) .unwrap(); + let allocator = StandardCommandBufferAllocator::new(device); let mut builder = AutoCommandBufferBuilder::primary( - device, + &allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/vulkano/src/command_buffer/commands/bind_push.rs b/vulkano/src/command_buffer/commands/bind_push.rs index 29f39e12..3ae5a7c7 100644 --- a/vulkano/src/command_buffer/commands/bind_push.rs +++ b/vulkano/src/command_buffer/commands/bind_push.rs @@ -10,6 +10,7 @@ use crate::{ buffer::{BufferAccess, BufferContents, TypedBufferAccess}, command_buffer::{ + allocator::CommandBufferAllocator, auto::RenderPassStateType, synced::{Command, SetOrPush, SyncCommandBufferBuilder}, sys::UnsafeCommandBufferBuilder, @@ -45,7 +46,10 @@ use std::{ /// # Commands to bind or push state for pipeline execution commands. /// /// These commands require a queue with a pipeline type that uses the given state. -impl AutoCommandBufferBuilder { +impl AutoCommandBufferBuilder +where + A: CommandBufferAllocator, +{ /// Binds descriptor sets for future dispatch or draw calls. /// /// # Panics diff --git a/vulkano/src/command_buffer/commands/debug.rs b/vulkano/src/command_buffer/commands/debug.rs index a98923dc..f48e588f 100644 --- a/vulkano/src/command_buffer/commands/debug.rs +++ b/vulkano/src/command_buffer/commands/debug.rs @@ -9,6 +9,7 @@ use crate::{ command_buffer::{ + allocator::CommandBufferAllocator, synced::{Command, SyncCommandBufferBuilder}, sys::UnsafeCommandBufferBuilder, AutoCommandBufferBuilder, @@ -28,7 +29,10 @@ use std::{ /// These commands all require the /// [`ext_debug_utils`](crate::instance::InstanceExtensions::ext_debug_utils) to be enabled on the /// instance. -impl AutoCommandBufferBuilder { +impl AutoCommandBufferBuilder +where + A: CommandBufferAllocator, +{ /// Opens a command buffer debug label region. pub fn begin_debug_utils_label( &mut self, diff --git a/vulkano/src/command_buffer/commands/dynamic_state.rs b/vulkano/src/command_buffer/commands/dynamic_state.rs index 7d440431..e2bf2787 100644 --- a/vulkano/src/command_buffer/commands/dynamic_state.rs +++ b/vulkano/src/command_buffer/commands/dynamic_state.rs @@ -9,6 +9,7 @@ use crate::{ command_buffer::{ + allocator::CommandBufferAllocator, synced::{Command, SyncCommandBufferBuilder}, sys::UnsafeCommandBufferBuilder, AutoCommandBufferBuilder, @@ -37,7 +38,10 @@ use std::{ /// # Commands to set dynamic state for pipelines. /// /// These commands require a queue with a pipeline type that uses the given state. -impl AutoCommandBufferBuilder { +impl AutoCommandBufferBuilder +where + A: CommandBufferAllocator, +{ // Helper function for dynamic state setting. fn validate_pipeline_fixed_state( &self, diff --git a/vulkano/src/command_buffer/commands/image.rs b/vulkano/src/command_buffer/commands/image.rs index b60e88e1..f3ee25e5 100644 --- a/vulkano/src/command_buffer/commands/image.rs +++ b/vulkano/src/command_buffer/commands/image.rs @@ -9,6 +9,7 @@ use crate::{ command_buffer::{ + allocator::CommandBufferAllocator, synced::{Command, Resource, SyncCommandBufferBuilder, SyncCommandBufferBuilderError}, sys::UnsafeCommandBufferBuilder, AutoCommandBufferBuilder, CopyError, CopyErrorResource, @@ -33,7 +34,10 @@ use std::{ /// /// Unlike transfer commands, these require a graphics queue, except for `clear_color_image`, which /// can also be called on a compute queue. -impl AutoCommandBufferBuilder { +impl AutoCommandBufferBuilder +where + A: CommandBufferAllocator, +{ /// Blits an image to another. /// /// A *blit* is similar to an image copy operation, except that the portion of the image that diff --git a/vulkano/src/command_buffer/commands/pipeline.rs b/vulkano/src/command_buffer/commands/pipeline.rs index b20def36..79ff67a0 100644 --- a/vulkano/src/command_buffer/commands/pipeline.rs +++ b/vulkano/src/command_buffer/commands/pipeline.rs @@ -10,6 +10,7 @@ use crate::{ buffer::{view::BufferViewAbstract, BufferAccess, TypedBufferAccess}, command_buffer::{ + allocator::CommandBufferAllocator, auto::{RenderPassState, RenderPassStateType}, synced::{Command, Resource, SyncCommandBufferBuilder, SyncCommandBufferBuilderError}, sys::UnsafeCommandBufferBuilder, @@ -49,7 +50,10 @@ use std::{ /// # Commands to execute a bound pipeline. /// /// Dispatch commands require a compute queue, draw commands require a graphics queue. -impl AutoCommandBufferBuilder { +impl AutoCommandBufferBuilder +where + A: CommandBufferAllocator, +{ /// Perform a single compute operation using a compute pipeline. /// /// A compute pipeline must have been bound using diff --git a/vulkano/src/command_buffer/commands/query.rs b/vulkano/src/command_buffer/commands/query.rs index 5046e42c..80b9422a 100644 --- a/vulkano/src/command_buffer/commands/query.rs +++ b/vulkano/src/command_buffer/commands/query.rs @@ -10,6 +10,7 @@ use crate::{ buffer::TypedBufferAccess, command_buffer::{ + allocator::CommandBufferAllocator, auto::QueryState, synced::{Command, Resource, SyncCommandBufferBuilder, SyncCommandBufferBuilderError}, sys::UnsafeCommandBufferBuilder, @@ -32,7 +33,10 @@ use std::{ }; /// # Commands related to queries. -impl AutoCommandBufferBuilder { +impl AutoCommandBufferBuilder +where + A: CommandBufferAllocator, +{ /// Begins a query. /// /// The query will be active until [`end_query`](Self::end_query) is called for the same query. diff --git a/vulkano/src/command_buffer/commands/render_pass.rs b/vulkano/src/command_buffer/commands/render_pass.rs index 4eebba50..cce7dd48 100644 --- a/vulkano/src/command_buffer/commands/render_pass.rs +++ b/vulkano/src/command_buffer/commands/render_pass.rs @@ -9,14 +9,14 @@ use crate::{ command_buffer::{ + allocator::CommandBufferAllocator, auto::{ BeginRenderPassState, BeginRenderingAttachments, BeginRenderingState, RenderPassState, RenderPassStateType, }, - pool::CommandPoolBuilderAlloc, synced::{Command, Resource, SyncCommandBufferBuilder, SyncCommandBufferBuilderError}, sys::UnsafeCommandBufferBuilder, - AutoCommandBufferBuilder, PrimaryAutoCommandBuffer, SubpassContents, + AutoCommandBufferBuilder, SubpassContents, }, device::DeviceOwned, format::{ClearColorValue, ClearValue, Format, NumericType}, @@ -40,9 +40,9 @@ use std::{ /// # Commands for render passes. /// /// These commands require a graphics queue. -impl

AutoCommandBufferBuilder, P> +impl AutoCommandBufferBuilder where - P: CommandPoolBuilderAlloc, + A: CommandBufferAllocator, { /// Begins a render pass using a render pass object and framebuffer. /// @@ -526,7 +526,10 @@ where } } -impl AutoCommandBufferBuilder { +impl AutoCommandBufferBuilder +where + A: CommandBufferAllocator, +{ /// Begins a render pass without a render pass object or framebuffer. /// /// You must call this or `begin_render_pass` before you can record draw commands. diff --git a/vulkano/src/command_buffer/commands/secondary.rs b/vulkano/src/command_buffer/commands/secondary.rs index 17f569a8..82f8f614 100644 --- a/vulkano/src/command_buffer/commands/secondary.rs +++ b/vulkano/src/command_buffer/commands/secondary.rs @@ -9,12 +9,12 @@ use crate::{ command_buffer::{ + allocator::CommandBufferAllocator, auto::RenderPassStateType, - pool::CommandPoolBuilderAlloc, synced::{Command, Resource, SyncCommandBufferBuilder, SyncCommandBufferBuilderError}, sys::UnsafeCommandBufferBuilder, AutoCommandBufferBuilder, CommandBufferExecError, CommandBufferInheritanceRenderPassType, - CommandBufferUsage, PrimaryAutoCommandBuffer, SecondaryCommandBuffer, SubpassContents, + CommandBufferUsage, SecondaryCommandBuffer, SubpassContents, }, device::DeviceOwned, format::Format, @@ -32,9 +32,9 @@ use std::{ /// /// These commands can be called on any queue that can execute the commands recorded in the /// secondary command buffer. -impl

AutoCommandBufferBuilder, P> +impl AutoCommandBufferBuilder where - P: CommandPoolBuilderAlloc, + A: CommandBufferAllocator, { /// Executes a secondary command buffer. /// diff --git a/vulkano/src/command_buffer/commands/transfer.rs b/vulkano/src/command_buffer/commands/transfer.rs index 57254f02..31e9463a 100644 --- a/vulkano/src/command_buffer/commands/transfer.rs +++ b/vulkano/src/command_buffer/commands/transfer.rs @@ -10,6 +10,7 @@ use crate::{ buffer::{BufferAccess, BufferContents, TypedBufferAccess}, command_buffer::{ + allocator::CommandBufferAllocator, synced::{Command, Resource, SyncCommandBufferBuilder, SyncCommandBufferBuilderError}, sys::UnsafeCommandBufferBuilder, AutoCommandBufferBuilder, CopyError, CopyErrorResource, @@ -33,7 +34,10 @@ use std::{ /// # Commands to transfer data to a resource, either from the host or from another resource. /// /// These commands can be called on a transfer queue, in addition to a compute or graphics queue. -impl AutoCommandBufferBuilder { +impl AutoCommandBufferBuilder +where + A: CommandBufferAllocator, +{ /// Copies data from a buffer to another buffer. /// /// # Panics diff --git a/vulkano/src/command_buffer/mod.rs b/vulkano/src/command_buffer/mod.rs index d04f7d25..61a9133a 100644 --- a/vulkano/src/command_buffer/mod.rs +++ b/vulkano/src/command_buffer/mod.rs @@ -61,8 +61,9 @@ //! # let vertex_buffer: std::sync::Arc> = return; //! # let render_pass_begin_info: vulkano::command_buffer::RenderPassBeginInfo = return; //! # let graphics_pipeline: std::sync::Arc = return; +//! # let command_buffer_allocator: vulkano::command_buffer::allocator::StandardCommandBufferAllocator = return; //! let cb = AutoCommandBufferBuilder::primary( -//! device.clone(), +//! &command_buffer_allocator, //! queue.queue_family_index(), //! CommandBufferUsage::MultipleSubmit //! ).unwrap() @@ -129,6 +130,7 @@ use crate::{ use bytemuck::{Pod, Zeroable}; use std::sync::Arc; +pub mod allocator; mod auto; mod commands; pub mod pool; diff --git a/vulkano/src/command_buffer/pool/sys.rs b/vulkano/src/command_buffer/pool.rs similarity index 83% rename from vulkano/src/command_buffer/pool/sys.rs rename to vulkano/src/command_buffer/pool.rs index 7a0f1ded..76cca70d 100644 --- a/vulkano/src/command_buffer/pool/sys.rs +++ b/vulkano/src/command_buffer/pool.rs @@ -14,6 +14,7 @@ use crate::{ }; use smallvec::SmallVec; use std::{ + cell::Cell, error::Error, fmt::{Display, Error as FmtError, Formatter}, hash::{Hash, Hasher}, @@ -23,7 +24,7 @@ use std::{ sync::Arc, }; -/// Low-level implementation of a command pool. +/// Represents a Vulkan command pool. /// /// A command pool is always tied to a specific queue family. Command buffers allocated from a pool /// can only be executed on the corresponding queue family. @@ -31,44 +32,40 @@ use std::{ /// This struct doesn't implement the `Sync` trait because Vulkan command pools are not thread /// safe. In other words, you can only use a pool from one thread at a time. #[derive(Debug)] -pub struct UnsafeCommandPool { +pub struct CommandPool { handle: ash::vk::CommandPool, device: Arc, - // We don't want `UnsafeCommandPool` to implement Sync. - // This marker unimplements both Send and Sync, but we reimplement Send manually right under. - dummy_avoid_sync: PhantomData<*const u8>, queue_family_index: u32, _transient: bool, _reset_command_buffer: bool, + // Unimplement `Sync`, as Vulkan command pools are not thread-safe. + _marker: PhantomData>, } -unsafe impl Send for UnsafeCommandPool {} - -impl UnsafeCommandPool { - /// Creates a new `UnsafeCommandPool`. +impl CommandPool { + /// Creates a new `CommandPool`. pub fn new( device: Arc, - mut create_info: UnsafeCommandPoolCreateInfo, - ) -> Result { + mut create_info: CommandPoolCreateInfo, + ) -> Result { Self::validate(&device, &mut create_info)?; let handle = unsafe { Self::create(&device, &create_info)? }; - let UnsafeCommandPoolCreateInfo { + let CommandPoolCreateInfo { queue_family_index, transient, reset_command_buffer, _ne: _, } = create_info; - Ok(UnsafeCommandPool { + Ok(CommandPool { handle, device, - dummy_avoid_sync: PhantomData, - queue_family_index, _transient: transient, _reset_command_buffer: reset_command_buffer, + _marker: PhantomData, }) } @@ -82,31 +79,30 @@ impl UnsafeCommandPool { pub unsafe fn from_handle( device: Arc, handle: ash::vk::CommandPool, - create_info: UnsafeCommandPoolCreateInfo, - ) -> UnsafeCommandPool { - let UnsafeCommandPoolCreateInfo { + create_info: CommandPoolCreateInfo, + ) -> CommandPool { + let CommandPoolCreateInfo { queue_family_index, transient, reset_command_buffer, _ne: _, } = create_info; - UnsafeCommandPool { + CommandPool { handle, device, - dummy_avoid_sync: PhantomData, - queue_family_index, _transient: transient, _reset_command_buffer: reset_command_buffer, + _marker: PhantomData, } } fn validate( device: &Device, - create_info: &mut UnsafeCommandPoolCreateInfo, - ) -> Result<(), UnsafeCommandPoolCreationError> { - let &mut UnsafeCommandPoolCreateInfo { + create_info: &mut CommandPoolCreateInfo, + ) -> Result<(), CommandPoolCreationError> { + let &mut CommandPoolCreateInfo { queue_family_index, transient: _, reset_command_buffer: _, @@ -115,7 +111,7 @@ impl UnsafeCommandPool { // VUID-vkCreateCommandPool-queueFamilyIndex-01937 if queue_family_index >= device.physical_device().queue_family_properties().len() as u32 { - return Err(UnsafeCommandPoolCreationError::QueueFamilyIndexOutOfRange { + return Err(CommandPoolCreationError::QueueFamilyIndexOutOfRange { queue_family_index, queue_family_count: device.physical_device().queue_family_properties().len() as u32, }); @@ -126,9 +122,9 @@ impl UnsafeCommandPool { unsafe fn create( device: &Device, - create_info: &UnsafeCommandPoolCreateInfo, - ) -> Result { - let &UnsafeCommandPoolCreateInfo { + create_info: &CommandPoolCreateInfo, + ) -> Result { + let &CommandPoolCreateInfo { queue_family_index, transient, reset_command_buffer, @@ -197,7 +193,7 @@ impl UnsafeCommandPool { pub fn allocate_command_buffers( &self, allocate_info: CommandBufferAllocateInfo, - ) -> Result, OomError> { + ) -> Result, OomError> { let CommandBufferAllocateInfo { level, command_buffer_count, @@ -232,14 +228,12 @@ impl UnsafeCommandPool { let device = self.device.clone(); - Ok(out - .into_iter() - .map(move |command_buffer| UnsafeCommandPoolAlloc { - handle: command_buffer, - device: device.clone(), + Ok(out.into_iter().map(move |command_buffer| CommandPoolAlloc { + handle: command_buffer, + device: device.clone(), - level, - })) + level, + })) } /// Frees individual command buffers. @@ -250,7 +244,7 @@ impl UnsafeCommandPool { /// - The `command_buffers` must not be in the pending state. pub unsafe fn free_command_buffers( &self, - command_buffers: impl IntoIterator, + command_buffers: impl IntoIterator, ) { let command_buffers: SmallVec<[_; 4]> = command_buffers.into_iter().map(|cb| cb.handle).collect(); @@ -316,7 +310,7 @@ impl UnsafeCommandPool { } } -impl Drop for UnsafeCommandPool { +impl Drop for CommandPool { #[inline] fn drop(&mut self) { unsafe { @@ -330,7 +324,7 @@ impl Drop for UnsafeCommandPool { } } -unsafe impl VulkanObject for UnsafeCommandPool { +unsafe impl VulkanObject for CommandPool { type Object = ash::vk::CommandPool; #[inline] @@ -339,32 +333,32 @@ unsafe impl VulkanObject for UnsafeCommandPool { } } -unsafe impl DeviceOwned for UnsafeCommandPool { +unsafe impl DeviceOwned for CommandPool { #[inline] fn device(&self) -> &Arc { &self.device } } -impl PartialEq for UnsafeCommandPool { +impl PartialEq for CommandPool { #[inline] fn eq(&self, other: &Self) -> bool { self.handle == other.handle && self.device() == other.device() } } -impl Eq for UnsafeCommandPool {} +impl Eq for CommandPool {} -impl Hash for UnsafeCommandPool { +impl Hash for CommandPool { fn hash(&self, state: &mut H) { self.handle.hash(state); self.device().hash(state); } } -/// Error that can happen when creating an `UnsafeCommandPool`. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum UnsafeCommandPoolCreationError { +/// Error that can happen when creating a `CommandPool`. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum CommandPoolCreationError { /// Not enough memory. OomError(OomError), @@ -376,7 +370,7 @@ pub enum UnsafeCommandPoolCreationError { }, } -impl Error for UnsafeCommandPoolCreationError { +impl Error for CommandPoolCreationError { fn source(&self) -> Option<&(dyn Error + 'static)> { match self { Self::OomError(err) => Some(err), @@ -385,7 +379,7 @@ impl Error for UnsafeCommandPoolCreationError { } } -impl Display for UnsafeCommandPoolCreationError { +impl Display for CommandPoolCreationError { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { match self { Self::OomError(_) => write!(f, "not enough memory",), @@ -402,7 +396,7 @@ impl Display for UnsafeCommandPoolCreationError { } } -impl From for UnsafeCommandPoolCreationError { +impl From for CommandPoolCreationError { fn from(err: VulkanError) -> Self { match err { err @ VulkanError::OutOfHostMemory => Self::OomError(OomError::from(err)), @@ -411,9 +405,9 @@ impl From for UnsafeCommandPoolCreationError { } } -/// Parameters to create an `UnsafeCommandPool`. +/// Parameters to create an `CommandPool`. #[derive(Clone, Debug)] -pub struct UnsafeCommandPoolCreateInfo { +pub struct CommandPoolCreateInfo { /// The index of the queue family that this pool is created for. All command buffers allocated /// from this pool must be submitted on a queue belonging to that family. /// @@ -434,7 +428,7 @@ pub struct UnsafeCommandPoolCreateInfo { pub _ne: crate::NonExhaustive, } -impl Default for UnsafeCommandPoolCreateInfo { +impl Default for CommandPoolCreateInfo { #[inline] fn default() -> Self { Self { @@ -475,13 +469,13 @@ impl Default for CommandBufferAllocateInfo { /// Opaque type that represents a command buffer allocated from a pool. #[derive(Debug)] -pub struct UnsafeCommandPoolAlloc { +pub struct CommandPoolAlloc { handle: ash::vk::CommandBuffer, device: Arc, level: CommandBufferLevel, } -impl UnsafeCommandPoolAlloc { +impl CommandPoolAlloc { /// Returns the level of the command buffer. #[inline] pub fn level(&self) -> CommandBufferLevel { @@ -489,7 +483,7 @@ impl UnsafeCommandPoolAlloc { } } -unsafe impl VulkanObject for UnsafeCommandPoolAlloc { +unsafe impl VulkanObject for CommandPoolAlloc { type Object = ash::vk::CommandBuffer; #[inline] @@ -498,23 +492,23 @@ unsafe impl VulkanObject for UnsafeCommandPoolAlloc { } } -unsafe impl DeviceOwned for UnsafeCommandPoolAlloc { +unsafe impl DeviceOwned for CommandPoolAlloc { #[inline] fn device(&self) -> &Arc { &self.device } } -impl PartialEq for UnsafeCommandPoolAlloc { +impl PartialEq for CommandPoolAlloc { #[inline] fn eq(&self, other: &Self) -> bool { self.handle == other.handle && self.device() == other.device() } } -impl Eq for UnsafeCommandPoolAlloc {} +impl Eq for CommandPoolAlloc {} -impl Hash for UnsafeCommandPoolAlloc { +impl Hash for CommandPoolAlloc { fn hash(&self, state: &mut H) { self.handle.hash(state); self.device().hash(state); @@ -556,20 +550,19 @@ impl From for CommandPoolTrimError { #[cfg(test)] mod tests { use super::{ - CommandPoolTrimError, UnsafeCommandPool, UnsafeCommandPoolCreateInfo, - UnsafeCommandPoolCreationError, + CommandPool, CommandPoolCreateInfo, CommandPoolCreationError, CommandPoolTrimError, }; use crate::{ - command_buffer::{pool::sys::CommandBufferAllocateInfo, CommandBufferLevel}, + command_buffer::{pool::CommandBufferAllocateInfo, CommandBufferLevel}, RequiresOneOf, Version, }; #[test] fn basic_create() { let (device, queue) = gfx_dev_and_queue!(); - let _ = UnsafeCommandPool::new( + let _ = CommandPool::new( device, - UnsafeCommandPoolCreateInfo { + CommandPoolCreateInfo { queue_family_index: queue.queue_family_index(), ..Default::default() }, @@ -580,9 +573,9 @@ mod tests { #[test] fn queue_family_getter() { let (device, queue) = gfx_dev_and_queue!(); - let pool = UnsafeCommandPool::new( + let pool = CommandPool::new( device, - UnsafeCommandPoolCreateInfo { + CommandPoolCreateInfo { queue_family_index: queue.queue_family_index(), ..Default::default() }, @@ -595,13 +588,13 @@ mod tests { fn check_queue_family_too_high() { let (device, _) = gfx_dev_and_queue!(); - match UnsafeCommandPool::new( + match CommandPool::new( device, - UnsafeCommandPoolCreateInfo { + CommandPoolCreateInfo { ..Default::default() }, ) { - Err(UnsafeCommandPoolCreationError::QueueFamilyIndexOutOfRange { .. }) => (), + Err(CommandPoolCreationError::QueueFamilyIndexOutOfRange { .. }) => (), _ => panic!(), } } @@ -609,9 +602,9 @@ mod tests { #[test] fn check_maintenance_when_trim() { let (device, queue) = gfx_dev_and_queue!(); - let pool = UnsafeCommandPool::new( + let pool = CommandPool::new( device.clone(), - UnsafeCommandPoolCreateInfo { + CommandPoolCreateInfo { queue_family_index: queue.queue_family_index(), ..Default::default() }, @@ -651,9 +644,9 @@ mod tests { #[test] fn basic_alloc() { let (device, queue) = gfx_dev_and_queue!(); - let pool = UnsafeCommandPool::new( + let pool = CommandPool::new( device, - UnsafeCommandPoolCreateInfo { + CommandPoolCreateInfo { queue_family_index: queue.queue_family_index(), ..Default::default() }, diff --git a/vulkano/src/command_buffer/pool/mod.rs b/vulkano/src/command_buffer/pool/mod.rs deleted file mode 100644 index 750df905..00000000 --- a/vulkano/src/command_buffer/pool/mod.rs +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) 2016 The vulkano developers -// Licensed under the Apache License, Version 2.0 -// or the MIT -// license , -// at your option. All files in the project carrying such -// notice may not be copied, modified, or distributed except -// according to those terms. - -//! In the Vulkan API, command buffers must be allocated from *command pools*. -//! -//! A command pool holds and manages the memory of one or more command buffers. If you destroy a -//! command pool, all of its command buffers are automatically destroyed. -//! -//! In vulkano, creating a command buffer requires passing an implementation of the `CommandPool` -//! trait. By default vulkano will use the `StandardCommandPool` struct, but you can implement -//! this trait yourself by wrapping around the `UnsafeCommandPool` type. - -pub use self::{ - standard::StandardCommandPool, - sys::{ - CommandPoolTrimError, UnsafeCommandPool, UnsafeCommandPoolAlloc, - UnsafeCommandPoolCreateInfo, UnsafeCommandPoolCreationError, - }, -}; -use super::CommandBufferLevel; -use crate::{device::DeviceOwned, OomError}; - -pub mod standard; -mod sys; - -/// Types that manage the memory of command buffers. -/// -/// # Safety -/// -/// A Vulkan command pool must be externally synchronized as if it owned the command buffers that -/// were allocated from it. This includes allocating from the pool, freeing from the pool, -/// resetting the pool or individual command buffers, and most importantly recording commands to -/// command buffers. -/// -/// The implementation of `CommandPool` is expected to manage this. For as long as a `Builder` -/// is alive, the trait implementation is expected to lock the pool that allocated the `Builder` -/// for the current thread. -/// -/// > **Note**: This may be modified in the future to allow different implementation strategies. -/// -/// The destructors of the `CommandPoolBuilderAlloc` and the `CommandPoolAlloc` are expected to -/// free the command buffer, reset the command buffer, or add it to a pool so that it gets reused. -/// If the implementation frees or resets the command buffer, it must not forget that this -/// operation must lock the pool. -pub unsafe trait CommandPool: DeviceOwned { - /// See `alloc()`. - type Iter: Iterator; - - /// Represents a command buffer that has been allocated and that is currently being built. - type Builder: CommandPoolBuilderAlloc; - - /// Represents a command buffer that has been allocated and that is pending execution or is - /// being executed. - type Alloc: CommandPoolAlloc; - - /// Allocates command buffers from this pool. - /// - /// Returns an iterator that contains an bunch of allocated command buffers. - fn allocate( - &self, - level: CommandBufferLevel, - command_buffer_count: u32, - ) -> Result; - - /// Returns the index of the queue family that this pool targets. - fn queue_family_index(&self) -> u32; -} - -/// A command buffer allocated from a pool and that can be recorded. -/// -/// # Safety -/// -/// See `CommandPool` for information about safety. -pub unsafe trait CommandPoolBuilderAlloc: DeviceOwned { - /// Return type of `into_alloc`. - type Alloc: CommandPoolAlloc; - - /// Returns the internal object that contains the command buffer. - fn inner(&self) -> &UnsafeCommandPoolAlloc; - - /// Turns this builder into a command buffer that is pending execution. - fn into_alloc(self) -> Self::Alloc; - - /// Returns the index of the queue family that the pool targets. - fn queue_family_index(&self) -> u32; -} - -/// A command buffer allocated from a pool that has finished being recorded. -/// -/// # Safety -/// -/// See `CommandPool` for information about safety. -pub unsafe trait CommandPoolAlloc: DeviceOwned + Send + Sync { - /// Returns the internal object that contains the command buffer. - fn inner(&self) -> &UnsafeCommandPoolAlloc; - - /// Returns the index of the queue family that the pool targets. - fn queue_family_index(&self) -> u32; -} diff --git a/vulkano/src/command_buffer/pool/standard.rs b/vulkano/src/command_buffer/pool/standard.rs deleted file mode 100644 index 0f6d4c49..00000000 --- a/vulkano/src/command_buffer/pool/standard.rs +++ /dev/null @@ -1,291 +0,0 @@ -use super::{ - sys::{CommandBufferAllocateInfo, UnsafeCommandPoolCreateInfo, UnsafeCommandPoolCreationError}, - CommandPool, CommandPoolAlloc, CommandPoolBuilderAlloc, UnsafeCommandPool, - UnsafeCommandPoolAlloc, -}; -use crate::{ - command_buffer::CommandBufferLevel, - device::{Device, DeviceOwned}, - OomError, -}; -use crossbeam_queue::SegQueue; -use std::{marker::PhantomData, mem::ManuallyDrop, ptr, sync::Arc, vec::IntoIter as VecIntoIter}; - -// Copyright (c) 2016 The vulkano developers -// Licensed under the Apache License, Version 2.0 -// or the MIT -// license , -// at your option. All files in the project carrying such -// notice may not be copied, modified, or distributed except -// according to those terms. - -/// Standard implementation of a command pool. -/// -/// A thread can have as many `Arc`s as needed, but none of them can escape the -/// thread they were created on. This is done so that there are no locks involved when creating -/// command buffers. Command buffers can't be moved between threads during the building process, but -/// finished command buffers can. When a command buffer is dropped, it is returned back to the pool -/// for reuse. -#[derive(Debug)] -pub struct StandardCommandPool { - // The Vulkan pool specific to a device's queue family. - inner: UnsafeCommandPool, - // List of existing primary command buffers that are available for reuse. - available_primary_command_buffers: SegQueue, - // List of existing secondary command buffers that are available for reuse. - available_secondary_command_buffers: SegQueue, -} - -impl StandardCommandPool { - /// Builds a new pool. - /// - /// # Panics - /// - /// - Panics if the device and the queue family don't belong to the same physical device. - pub fn new( - device: Arc, - queue_family_index: u32, - ) -> Result { - assert!( - queue_family_index < device.physical_device().queue_family_properties().len() as u32 - ); - - let inner = UnsafeCommandPool::new( - device, - UnsafeCommandPoolCreateInfo { - queue_family_index, - reset_command_buffer: true, - ..Default::default() - }, - ) - .map_err(|err| match err { - UnsafeCommandPoolCreationError::OomError(err) => err, - _ => panic!("Unexpected error: {}", err), - })?; - - Ok(StandardCommandPool { - inner, - available_primary_command_buffers: Default::default(), - available_secondary_command_buffers: Default::default(), - }) - } -} - -unsafe impl CommandPool for Arc { - type Iter = VecIntoIter; - type Builder = StandardCommandPoolBuilder; - type Alloc = StandardCommandPoolAlloc; - - #[inline] - fn allocate( - &self, - level: CommandBufferLevel, - mut command_buffer_count: u32, - ) -> Result { - // The final output. - let mut output = Vec::with_capacity(command_buffer_count as usize); - - // First, pick from already-existing command buffers. - { - let existing = match level { - CommandBufferLevel::Primary => &self.available_primary_command_buffers, - CommandBufferLevel::Secondary => &self.available_secondary_command_buffers, - }; - - for _ in 0..command_buffer_count as usize { - if let Some(cmd) = existing.pop() { - output.push(StandardCommandPoolBuilder { - inner: StandardCommandPoolAlloc { - cmd: ManuallyDrop::new(cmd), - pool: self.clone(), - }, - dummy_avoid_send_sync: PhantomData, - }); - } else { - break; - } - } - } - - // Then allocate the rest. - if output.len() < command_buffer_count as usize { - command_buffer_count -= output.len() as u32; - - for cmd in self - .inner - .allocate_command_buffers(CommandBufferAllocateInfo { - level, - command_buffer_count, - ..Default::default() - })? - { - output.push(StandardCommandPoolBuilder { - inner: StandardCommandPoolAlloc { - cmd: ManuallyDrop::new(cmd), - pool: self.clone(), - }, - dummy_avoid_send_sync: PhantomData, - }); - } - } - - // Final output. - Ok(output.into_iter()) - } - - #[inline] - fn queue_family_index(&self) -> u32 { - self.inner.queue_family_index() - } -} - -unsafe impl DeviceOwned for StandardCommandPool { - #[inline] - fn device(&self) -> &Arc { - self.inner.device() - } -} - -/// Command buffer allocated from a `StandardCommandPool` that is currently being built. -pub struct StandardCommandPoolBuilder { - // The only difference between a `StandardCommandPoolBuilder` and a `StandardCommandPoolAlloc` - // is that the former must not implement `Send` and `Sync`. Therefore we just share the structs. - inner: StandardCommandPoolAlloc, - // Unimplemented `Send` and `Sync` from the builder. - dummy_avoid_send_sync: PhantomData<*const u8>, -} - -unsafe impl CommandPoolBuilderAlloc for StandardCommandPoolBuilder { - type Alloc = StandardCommandPoolAlloc; - - #[inline] - fn inner(&self) -> &UnsafeCommandPoolAlloc { - self.inner.inner() - } - - #[inline] - fn into_alloc(self) -> Self::Alloc { - self.inner - } - - #[inline] - fn queue_family_index(&self) -> u32 { - self.inner.queue_family_index() - } -} - -unsafe impl DeviceOwned for StandardCommandPoolBuilder { - #[inline] - fn device(&self) -> &Arc { - self.inner.device() - } -} - -/// Command buffer allocated from a `StandardCommandPool`. -pub struct StandardCommandPoolAlloc { - // The actual command buffer. Extracted in the `Drop` implementation. - cmd: ManuallyDrop, - // We hold a reference to the command pool for our destructor. - pool: Arc, -} - -unsafe impl Send for StandardCommandPoolAlloc {} -unsafe impl Sync for StandardCommandPoolAlloc {} - -unsafe impl CommandPoolAlloc for StandardCommandPoolAlloc { - #[inline] - fn inner(&self) -> &UnsafeCommandPoolAlloc { - &self.cmd - } - - #[inline] - fn queue_family_index(&self) -> u32 { - self.pool.queue_family_index() - } -} - -unsafe impl DeviceOwned for StandardCommandPoolAlloc { - #[inline] - fn device(&self) -> &Arc { - self.pool.device() - } -} - -impl Drop for StandardCommandPoolAlloc { - #[inline] - fn drop(&mut self) { - // Safe because `self.cmd` is wrapped in a `ManuallyDrop`. - let cmd: UnsafeCommandPoolAlloc = unsafe { ptr::read(&*self.cmd) }; - - match cmd.level() { - CommandBufferLevel::Primary => self.pool.available_primary_command_buffers.push(cmd), - CommandBufferLevel::Secondary => { - self.pool.available_secondary_command_buffers.push(cmd) - } - } - } -} - -#[cfg(test)] -mod tests { - use crate::{ - command_buffer::{ - pool::{CommandPool, CommandPoolBuilderAlloc}, - CommandBufferLevel, - }, - VulkanObject, - }; - use std::{sync::Arc, thread}; - - #[test] - fn reuse_command_buffers() { - let (device, queue) = gfx_dev_and_queue!(); - - device - .with_standard_command_pool(queue.queue_family_index(), |pool| { - let cb = pool - .allocate(CommandBufferLevel::Primary, 1) - .unwrap() - .next() - .unwrap(); - let raw = cb.inner().internal_object(); - drop(cb); - - let cb2 = pool - .allocate(CommandBufferLevel::Primary, 1) - .unwrap() - .next() - .unwrap(); - assert_eq!(raw, cb2.inner().internal_object()); - }) - .unwrap(); - } - - #[test] - fn pool_kept_alive_by_thread() { - let (device, queue) = gfx_dev_and_queue!(); - - let thread = thread::spawn({ - let (device, queue) = (device, queue); - move || { - device - .with_standard_command_pool(queue.queue_family_index(), |pool| { - pool.allocate(CommandBufferLevel::Primary, 1) - .unwrap() - .next() - .unwrap() - .inner - }) - .unwrap() - } - }); - - // The thread-local storage should drop its reference to the pool here - let cb = thread.join().unwrap(); - - let pool_weak = Arc::downgrade(&cb.pool); - drop(cb); - assert!(pool_weak.upgrade().is_none()); - } -} diff --git a/vulkano/src/command_buffer/synced/builder.rs b/vulkano/src/command_buffer/synced/builder.rs index 8111c868..f44e6291 100644 --- a/vulkano/src/command_buffer/synced/builder.rs +++ b/vulkano/src/command_buffer/synced/builder.rs @@ -17,7 +17,7 @@ pub use crate::command_buffer::commands::{ use crate::{ buffer::{sys::UnsafeBuffer, BufferAccess}, command_buffer::{ - pool::UnsafeCommandPoolAlloc, + pool::CommandPoolAlloc, synced::{BufferFinalState, BufferUse, ImageFinalState, ImageUse}, sys::{CommandBufferBeginInfo, UnsafeCommandBufferBuilder}, CommandBufferExecError, CommandBufferLevel, @@ -121,7 +121,7 @@ impl SyncCommandBufferBuilder { /// See `UnsafeCommandBufferBuilder::new()`. #[inline] pub unsafe fn new( - pool_alloc: &UnsafeCommandPoolAlloc, + pool_alloc: &CommandPoolAlloc, begin_info: CommandBufferBeginInfo, ) -> Result { let level = pool_alloc.level(); diff --git a/vulkano/src/command_buffer/synced/mod.rs b/vulkano/src/command_buffer/synced/mod.rs index 25598083..527ef3d4 100644 --- a/vulkano/src/command_buffer/synced/mod.rs +++ b/vulkano/src/command_buffer/synced/mod.rs @@ -532,11 +532,14 @@ mod tests { use crate::{ buffer::{BufferUsage, CpuAccessibleBuffer, DeviceLocalBuffer}, command_buffer::{ - pool::{CommandPool, CommandPoolBuilderAlloc}, + allocator::{ + CommandBufferAllocator, CommandBufferBuilderAlloc, StandardCommandBufferAllocator, + }, sys::CommandBufferBeginInfo, AutoCommandBufferBuilder, CommandBufferLevel, CommandBufferUsage, FillBufferInfo, }, descriptor_set::{ + allocator::StandardDescriptorSetAllocator, layout::{ DescriptorSetLayout, DescriptorSetLayoutBinding, DescriptorSetLayoutCreateInfo, DescriptorType, @@ -553,17 +556,16 @@ mod tests { unsafe { let (device, queue) = gfx_dev_and_queue!(); - let pool_builder_alloc = device - .with_standard_command_pool(queue.queue_family_index(), |pool| { - pool.allocate(CommandBufferLevel::Primary, 1) - .unwrap() - .next() - .unwrap() - }) + let allocator = StandardCommandBufferAllocator::new(device); + + let builder_alloc = allocator + .allocate(queue.queue_family_index(), CommandBufferLevel::Primary, 1) + .unwrap() + .next() .unwrap(); SyncCommandBufferBuilder::new( - pool_builder_alloc.inner(), + builder_alloc.inner(), CommandBufferBeginInfo { usage: CommandBufferUsage::MultipleSubmit, ..Default::default() @@ -578,6 +580,8 @@ mod tests { unsafe { let (device, queue) = gfx_dev_and_queue!(); + let allocator = StandardCommandBufferAllocator::new(device); + // Create a tiny test buffer let (buf, future) = DeviceLocalBuffer::from_data( 0u32, @@ -585,6 +589,7 @@ mod tests { transfer_dst: true, ..BufferUsage::empty() }, + &allocator, queue.clone(), ) .unwrap(); @@ -598,7 +603,7 @@ mod tests { let secondary = (0..2) .map(|_| { let mut builder = AutoCommandBufferBuilder::secondary( - device.clone(), + &allocator, queue.queue_family_index(), CommandBufferUsage::SimultaneousUse, Default::default(), @@ -614,13 +619,10 @@ mod tests { }) .collect::>(); - let allocs = device - .with_standard_command_pool(queue.queue_family_index(), |pool| { - pool.allocate(CommandBufferLevel::Primary, 2) - .unwrap() - .collect::>() - }) - .unwrap(); + let allocs = allocator + .allocate(queue.queue_family_index(), CommandBufferLevel::Primary, 2) + .unwrap() + .collect::>(); { let mut builder = SyncCommandBufferBuilder::new( @@ -676,16 +678,15 @@ mod tests { unsafe { let (device, queue) = gfx_dev_and_queue!(); - let pool_builder_alloc = device - .with_standard_command_pool(queue.queue_family_index(), |pool| { - pool.allocate(CommandBufferLevel::Primary, 1) - .unwrap() - .next() - .unwrap() - }) + let allocator = StandardCommandBufferAllocator::new(device.clone()); + + let builder_alloc = allocator + .allocate(queue.queue_family_index(), CommandBufferLevel::Primary, 1) + .unwrap() + .next() .unwrap(); let mut sync = SyncCommandBufferBuilder::new( - pool_builder_alloc.inner(), + builder_alloc.inner(), CommandBufferBeginInfo { usage: CommandBufferUsage::MultipleSubmit, ..Default::default() @@ -717,16 +718,14 @@ mod tests { unsafe { let (device, queue) = gfx_dev_and_queue!(); - let pool_builder_alloc = device - .with_standard_command_pool(queue.queue_family_index(), |pool| { - pool.allocate(CommandBufferLevel::Primary, 1) - .unwrap() - .next() - .unwrap() - }) + let cb_allocator = StandardCommandBufferAllocator::new(device.clone()); + let builder_alloc = cb_allocator + .allocate(queue.queue_family_index(), CommandBufferLevel::Primary, 1) + .unwrap() + .next() .unwrap(); let mut sync = SyncCommandBufferBuilder::new( - pool_builder_alloc.inner(), + builder_alloc.inner(), CommandBufferBeginInfo { usage: CommandBufferUsage::MultipleSubmit, ..Default::default() @@ -757,7 +756,10 @@ mod tests { ) .unwrap(); + let ds_allocator = StandardDescriptorSetAllocator::new(device.clone()); + let set = PersistentDescriptorSet::new( + &ds_allocator, set_layout.clone(), [WriteDescriptorSet::sampler( 0, @@ -815,6 +817,7 @@ mod tests { .unwrap(); let set = PersistentDescriptorSet::new( + &ds_allocator, set_layout, [WriteDescriptorSet::sampler( 0, diff --git a/vulkano/src/command_buffer/sys.rs b/vulkano/src/command_buffer/sys.rs index 4d4d46d9..a3d0724f 100644 --- a/vulkano/src/command_buffer/sys.rs +++ b/vulkano/src/command_buffer/sys.rs @@ -12,8 +12,7 @@ pub use super::commands::{ secondary::UnsafeCommandBufferBuilderExecuteCommands, }; use super::{ - pool::UnsafeCommandPoolAlloc, CommandBufferInheritanceInfo, CommandBufferLevel, - CommandBufferUsage, + pool::CommandPoolAlloc, CommandBufferInheritanceInfo, CommandBufferLevel, CommandBufferUsage, }; use crate::{ command_buffer::{ @@ -52,7 +51,7 @@ impl UnsafeCommandBufferBuilder { /// - `kind` must match how `pool_alloc` was created. #[inline] pub unsafe fn new( - pool_alloc: &UnsafeCommandPoolAlloc, + pool_alloc: &CommandPoolAlloc, begin_info: CommandBufferBeginInfo, ) -> Result { let CommandBufferBeginInfo { diff --git a/vulkano/src/descriptor_set/allocator.rs b/vulkano/src/descriptor_set/allocator.rs new file mode 100644 index 00000000..4039d23a --- /dev/null +++ b/vulkano/src/descriptor_set/allocator.rs @@ -0,0 +1,183 @@ +// Copyright (c) 2021 The vulkano developers +// Licensed under the Apache License, Version 2.0 +// or the MIT +// license , +// at your option. All files in the project carrying such +// notice may not be copied, modified, or distributed except +// according to those terms. + +//! In the Vulkan API, descriptor sets must be allocated from *descriptor pools*. +//! +//! A descriptor pool holds and manages the memory of one or more descriptor sets. If you destroy a +//! descriptor pool, all of its descriptor sets are automatically destroyed. +//! +//! In vulkano, creating a descriptor set requires passing an implementation of the +//! [`DescriptorSetAllocator`] trait, which you can implement yourself or use the vulkano-provided +//! [`StandardDescriptorSetAllocator`]. + +use super::{ + layout::DescriptorSetLayout, + single_layout_pool::{ + SingleLayoutDescriptorSetPool, SingleLayoutPoolAlloc, + SingleLayoutVariableDescriptorSetPool, SingleLayoutVariablePoolAlloc, + }, + sys::UnsafeDescriptorSet, +}; +use crate::{ + device::{Device, DeviceOwned}, + OomError, +}; +use ahash::HashMap; +use std::{cell::UnsafeCell, sync::Arc}; + +/// Types that manage the memory of descriptor sets. +/// +/// # Safety +/// +/// A Vulkan descriptor pool must be externally synchronized as if it owned the descriptor sets that +/// were allocated from it. This includes allocating from the pool, freeing from the pool and +/// resetting the pool or individual descriptor sets. The implementation of `DescriptorSetAllocator` +/// is expected to manage this. +/// +/// The destructor of the [`DescriptorSetAlloc`] is expected to free the descriptor set, reset the +/// descriptor set, or add it to a pool so that it gets reused. If the implementation frees or +/// resets the descriptor set, it must not forget that this operation must be externally +/// synchronized. +pub unsafe trait DescriptorSetAllocator: DeviceOwned { + /// Object that represented an allocated descriptor set. + /// + /// The destructor of this object should free the descriptor set. + type Alloc: DescriptorSetAlloc; + + /// Allocates a descriptor set. + fn allocate( + &self, + layout: &Arc, + variable_descriptor_count: u32, + ) -> Result; +} + +/// An allocated descriptor set. +pub trait DescriptorSetAlloc: Send + Sync { + /// Returns the inner unsafe descriptor set object. + fn inner(&self) -> &UnsafeDescriptorSet; + + /// Returns the inner unsafe descriptor set object. + fn inner_mut(&mut self) -> &mut UnsafeDescriptorSet; +} + +/// Standard implementation of a descriptor set allocator. +/// +/// Internally, this implementation uses one [`SingleLayoutDescriptorSetPool`] / +/// [`SingleLayoutVariableDescriptorSetPool`] per descriptor set layout. +#[derive(Debug)] +pub struct StandardDescriptorSetAllocator { + device: Arc, + pools: UnsafeCell, Pool>>, +} + +#[derive(Debug)] +enum Pool { + Fixed(SingleLayoutDescriptorSetPool), + Variable(SingleLayoutVariableDescriptorSetPool), +} + +impl StandardDescriptorSetAllocator { + /// Creates a new `StandardDescriptorSetAllocator`. + #[inline] + pub fn new(device: Arc) -> StandardDescriptorSetAllocator { + StandardDescriptorSetAllocator { + device, + pools: UnsafeCell::new(HashMap::default()), + } + } +} + +unsafe impl DescriptorSetAllocator for StandardDescriptorSetAllocator { + type Alloc = StandardDescriptorSetAlloc; + + #[inline] + fn allocate( + &self, + layout: &Arc, + variable_descriptor_count: u32, + ) -> Result { + assert!( + !layout.push_descriptor(), + "the provided descriptor set layout is for push descriptors, and cannot be used to \ + build a descriptor set object", + ); + + let max_count = layout.variable_descriptor_count(); + + assert!( + variable_descriptor_count <= max_count, + "the provided variable_descriptor_count ({}) is greater than the maximum number of \ + variable count descriptors in the set ({})", + variable_descriptor_count, + max_count, + ); + + let pools = unsafe { &mut *self.pools.get() }; + + // We do this instead of using `HashMap::entry` directly because that would involve cloning + // an `Arc` every time. `hash_raw_entry` is still not stabilized >:( + let pool = if let Some(pool) = pools.get_mut(layout) { + pool + } else { + pools.entry(layout.clone()).or_insert(if max_count == 0 { + Pool::Fixed(SingleLayoutDescriptorSetPool::new(layout.clone())?) + } else { + Pool::Variable(SingleLayoutVariableDescriptorSetPool::new(layout.clone())?) + }) + }; + + let inner = match pool { + Pool::Fixed(pool) => PoolAlloc::Fixed(pool.next_alloc()?), + Pool::Variable(pool) => { + PoolAlloc::Variable(pool.next_alloc(variable_descriptor_count)?) + } + }; + + Ok(StandardDescriptorSetAlloc { inner }) + } +} + +unsafe impl DeviceOwned for StandardDescriptorSetAllocator { + #[inline] + fn device(&self) -> &Arc { + &self.device + } +} + +/// A descriptor set allocated from a [`StandardDescriptorSetAllocator`]. +#[derive(Debug)] +pub struct StandardDescriptorSetAlloc { + // The actual descriptor alloc. + inner: PoolAlloc, +} + +#[derive(Debug)] +enum PoolAlloc { + Fixed(SingleLayoutPoolAlloc), + Variable(SingleLayoutVariablePoolAlloc), +} + +impl DescriptorSetAlloc for StandardDescriptorSetAlloc { + #[inline] + fn inner(&self) -> &UnsafeDescriptorSet { + match &self.inner { + PoolAlloc::Fixed(alloc) => alloc.inner(), + PoolAlloc::Variable(alloc) => alloc.inner(), + } + } + + #[inline] + fn inner_mut(&mut self) -> &mut UnsafeDescriptorSet { + match &mut self.inner { + PoolAlloc::Fixed(alloc) => alloc.inner_mut(), + PoolAlloc::Variable(alloc) => alloc.inner_mut(), + } + } +} diff --git a/vulkano/src/descriptor_set/mod.rs b/vulkano/src/descriptor_set/mod.rs index d4396521..194d0b50 100644 --- a/vulkano/src/descriptor_set/mod.rs +++ b/vulkano/src/descriptor_set/mod.rs @@ -52,32 +52,37 @@ //! //! - A `DescriptorSetLayout` is a Vulkan object that describes to the Vulkan implementation the //! layout of a future descriptor set. When you allocate a descriptor set, you have to pass an -//! instance of this object. This is represented with the `DescriptorSetLayout` type in +//! instance of this object. This is represented with the [`DescriptorSetLayout`] type in //! vulkano. //! - A `DescriptorPool` is a Vulkan object that holds the memory of descriptor sets and that can //! be used to allocate and free individual descriptor sets. This is represented with the -//! `UnsafeDescriptorPool` type in vulkano. +//! [`DescriptorPool`] type in vulkano. //! - A `DescriptorSet` contains the bindings to resources and is allocated from a pool. This is -//! represented with the `UnsafeDescriptorSet` type in vulkano. +//! represented with the [`UnsafeDescriptorSet`] type in vulkano. //! //! In addition to this, vulkano defines the following: //! -//! - The `DescriptorPool` trait can be implemented on types from which you can allocate and free -//! descriptor sets. However it is different from Vulkan descriptor pools in the sense that an -//! implementation of the `DescriptorPool` trait can manage multiple Vulkan descriptor pools. -//! - The `StandardDescriptorPool` type is a default implementation of the `DescriptorPool` trait. -//! - The `DescriptorSet` trait is implemented on types that wrap around Vulkan descriptor sets in +//! - The [`DescriptorSetAllocator`] trait can be implemented on types from which you can allocate +//! and free descriptor sets. However it is different from Vulkan descriptor pools in the sense +//! that an implementation of the [`DescriptorSetAllocator`] trait can manage multiple Vulkan +//! descriptor pools. +//! - The [`StandardDescriptorSetAllocator`] type is a default implementation of the +//! [`DescriptorSetAllocator`] trait. +//! - The [`DescriptorSet`] trait is implemented on types that wrap around Vulkan descriptor sets in //! a safe way. A Vulkan descriptor set is inherently unsafe, so we need safe wrappers around //! them. -//! - The `SimpleDescriptorSet` type is a default implementation of the `DescriptorSet` trait. -//! - The `DescriptorSetsCollection` trait is implemented on collections of types that implement -//! `DescriptorSet`. It is what you pass to the draw functions. +//! - The [`DescriptorSetsCollection`] trait is implemented on collections of types that implement +//! [`DescriptorSet`]. It is what you pass to the draw functions. +//! +//! [`DescriptorPool`]: pool::DescriptorPool +//! [`DescriptorSetAllocator`]: allocator::DescriptorSetAllocator +//! [`StandardDescriptorSetAllocator`]: allocator::StandardDescriptorSetAllocator pub(crate) use self::update::{check_descriptor_write, DescriptorWriteInfo}; pub use self::{ collection::DescriptorSetsCollection, persistent::PersistentDescriptorSet, - single_layout_pool::SingleLayoutDescSetPool, + single_layout_pool::{SingleLayoutDescriptorSetPool, SingleLayoutVariableDescriptorSetPool}, update::{DescriptorSetUpdateError, WriteDescriptorSet, WriteDescriptorSetElements}, }; use self::{layout::DescriptorSetLayout, sys::UnsafeDescriptorSet}; @@ -99,6 +104,7 @@ use std::{ sync::Arc, }; +pub mod allocator; mod collection; pub mod layout; pub mod persistent; diff --git a/vulkano/src/descriptor_set/persistent.rs b/vulkano/src/descriptor_set/persistent.rs index 5d7a46d5..9e580d87 100644 --- a/vulkano/src/descriptor_set/persistent.rs +++ b/vulkano/src/descriptor_set/persistent.rs @@ -23,7 +23,7 @@ use crate::{ descriptor_set::{ - pool::{standard::StandardDescriptorPoolAlloc, DescriptorPool, DescriptorPoolAlloc}, + allocator::{DescriptorSetAlloc, DescriptorSetAllocator, StandardDescriptorSetAlloc}, update::WriteDescriptorSet, DescriptorSet, DescriptorSetCreationError, DescriptorSetInner, DescriptorSetLayout, DescriptorSetResources, UnsafeDescriptorSet, @@ -37,7 +37,7 @@ use std::{ }; /// A simple, immutable descriptor set that is expected to be long-lived. -pub struct PersistentDescriptorSet

{ +pub struct PersistentDescriptorSet

{ alloc: P, inner: DescriptorSetInner, } @@ -47,33 +47,15 @@ impl PersistentDescriptorSet { /// /// See `new_with_pool` for more. #[inline] - pub fn new( + pub fn new( + allocator: &A, layout: Arc, descriptor_writes: impl IntoIterator, - ) -> Result, DescriptorSetCreationError> { - layout - .device() - .clone() - .with_standard_descriptor_pool(|pool| { - Self::new_with_pool(layout, 0, pool, descriptor_writes) - }) - } - - /// Creates and returns a new descriptor set with the requested variable descriptor count. - /// - /// See `new_with_pool` for more. - #[inline] - pub fn new_variable( - layout: Arc, - variable_descriptor_count: u32, - descriptor_writes: impl IntoIterator, - ) -> Result, DescriptorSetCreationError> { - layout - .device() - .clone() - .with_standard_descriptor_pool(|pool| { - Self::new_with_pool(layout, variable_descriptor_count, pool, descriptor_writes) - }) + ) -> Result>, DescriptorSetCreationError> + where + A: DescriptorSetAllocator + ?Sized, + { + Self::new_variable(allocator, layout, 0, descriptor_writes) } /// Creates and returns a new descriptor set with the requested variable descriptor count, @@ -83,14 +65,14 @@ impl PersistentDescriptorSet { /// /// - Panics if `layout` was created for push descriptors rather than descriptor sets. /// - Panics if `variable_descriptor_count` is too large for the given `layout`. - pub fn new_with_pool

( + pub fn new_variable( + allocator: &A, layout: Arc, variable_descriptor_count: u32, - pool: &mut P, descriptor_writes: impl IntoIterator, - ) -> Result>, DescriptorSetCreationError> + ) -> Result>, DescriptorSetCreationError> where - P: ?Sized + DescriptorPool, + A: DescriptorSetAllocator + ?Sized, { assert!( !layout.push_descriptor(), @@ -108,7 +90,7 @@ impl PersistentDescriptorSet { max_count, ); - let alloc = pool.allocate(&layout, variable_descriptor_count)?; + let alloc = allocator.allocate(&layout, variable_descriptor_count)?; let inner = DescriptorSetInner::new( alloc.inner().internal_object(), layout, @@ -122,7 +104,7 @@ impl PersistentDescriptorSet { unsafe impl

DescriptorSet for PersistentDescriptorSet

where - P: DescriptorPoolAlloc, + P: DescriptorSetAlloc, { fn inner(&self) -> &UnsafeDescriptorSet { self.alloc.inner() @@ -139,7 +121,7 @@ where unsafe impl

DeviceOwned for PersistentDescriptorSet

where - P: DescriptorPoolAlloc, + P: DescriptorSetAlloc, { fn device(&self) -> &Arc { self.inner.layout().device() @@ -148,7 +130,7 @@ where impl

PartialEq for PersistentDescriptorSet

where - P: DescriptorPoolAlloc, + P: DescriptorSetAlloc, { fn eq(&self, other: &Self) -> bool { self.inner().internal_object() == other.inner().internal_object() @@ -156,11 +138,11 @@ where } } -impl

Eq for PersistentDescriptorSet

where P: DescriptorPoolAlloc {} +impl

Eq for PersistentDescriptorSet

where P: DescriptorSetAlloc {} impl

Hash for PersistentDescriptorSet

where - P: DescriptorPoolAlloc, + P: DescriptorSetAlloc, { fn hash(&self, state: &mut H) { self.inner().internal_object().hash(state); diff --git a/vulkano/src/descriptor_set/pool/sys.rs b/vulkano/src/descriptor_set/pool.rs similarity index 92% rename from vulkano/src/descriptor_set/pool/sys.rs rename to vulkano/src/descriptor_set/pool.rs index b9f631d8..8b4e969d 100644 --- a/vulkano/src/descriptor_set/pool/sys.rs +++ b/vulkano/src/descriptor_set/pool.rs @@ -18,9 +18,11 @@ use crate::{ use ahash::HashMap; use smallvec::SmallVec; use std::{ + cell::Cell, error::Error, fmt::{Display, Error as FmtError, Formatter}, hash::{Hash, Hasher}, + marker::PhantomData, mem::MaybeUninit, ptr, sync::Arc, @@ -31,16 +33,18 @@ use std::{ /// A pool has a maximum number of descriptor sets and a maximum number of descriptors (one value /// per descriptor type) it can allocate. #[derive(Debug)] -pub struct UnsafeDescriptorPool { +pub struct DescriptorPool { handle: ash::vk::DescriptorPool, device: Arc, max_sets: u32, pool_sizes: HashMap, can_free_descriptor_sets: bool, + // Unimplement `Sync`, as Vulkan descriptor pools are not thread safe. + _marker: PhantomData>, } -impl UnsafeDescriptorPool { +impl DescriptorPool { /// Creates a new `UnsafeDescriptorPool`. /// /// # Panics @@ -50,9 +54,9 @@ impl UnsafeDescriptorPool { /// - Panics if `create_info.pool_sizes` contains a descriptor type with a count of `0`. pub fn new( device: Arc, - create_info: UnsafeDescriptorPoolCreateInfo, - ) -> Result { - let UnsafeDescriptorPoolCreateInfo { + create_info: DescriptorPoolCreateInfo, + ) -> Result { + let DescriptorPoolCreateInfo { max_sets, pool_sizes, can_free_descriptor_sets, @@ -108,13 +112,13 @@ impl UnsafeDescriptorPool { } }; - Ok(UnsafeDescriptorPool { + Ok(DescriptorPool { handle, device, - max_sets, pool_sizes, can_free_descriptor_sets, + _marker: PhantomData, }) } @@ -128,22 +132,22 @@ impl UnsafeDescriptorPool { pub unsafe fn from_handle( device: Arc, handle: ash::vk::DescriptorPool, - create_info: UnsafeDescriptorPoolCreateInfo, - ) -> UnsafeDescriptorPool { - let UnsafeDescriptorPoolCreateInfo { + create_info: DescriptorPoolCreateInfo, + ) -> DescriptorPool { + let DescriptorPoolCreateInfo { max_sets, pool_sizes, can_free_descriptor_sets, _ne: _, } = create_info; - UnsafeDescriptorPool { + DescriptorPool { handle, device, - max_sets, pool_sizes, can_free_descriptor_sets, + _marker: PhantomData, } } @@ -184,7 +188,7 @@ impl UnsafeDescriptorPool { /// - You must ensure that the allocated descriptor sets are no longer in use when the pool /// is destroyed, as destroying the pool is equivalent to freeing all the sets. pub unsafe fn allocate_descriptor_sets<'a>( - &mut self, + &self, allocate_info: impl IntoIterator>, ) -> Result, DescriptorPoolAllocError> { let (layouts, variable_descriptor_counts): (SmallVec<[_; 1]>, SmallVec<[_; 1]>) = @@ -282,7 +286,7 @@ impl UnsafeDescriptorPool { /// - The descriptor sets must not be free'd twice. /// - The descriptor sets must not be in use by the GPU. pub unsafe fn free_descriptor_sets( - &mut self, + &self, descriptor_sets: impl IntoIterator, ) -> Result<(), OomError> { let sets: SmallVec<[_; 8]> = descriptor_sets @@ -308,7 +312,7 @@ impl UnsafeDescriptorPool { /// /// This destroys all descriptor sets and empties the pool. #[inline] - pub unsafe fn reset(&mut self) -> Result<(), OomError> { + pub unsafe fn reset(&self) -> Result<(), OomError> { let fns = self.device.fns(); (fns.v1_0.reset_descriptor_pool)( self.device.internal_object(), @@ -322,7 +326,7 @@ impl UnsafeDescriptorPool { } } -impl Drop for UnsafeDescriptorPool { +impl Drop for DescriptorPool { #[inline] fn drop(&mut self) { unsafe { @@ -336,7 +340,7 @@ impl Drop for UnsafeDescriptorPool { } } -unsafe impl VulkanObject for UnsafeDescriptorPool { +unsafe impl VulkanObject for DescriptorPool { type Object = ash::vk::DescriptorPool; #[inline] @@ -345,23 +349,23 @@ unsafe impl VulkanObject for UnsafeDescriptorPool { } } -unsafe impl DeviceOwned for UnsafeDescriptorPool { +unsafe impl DeviceOwned for DescriptorPool { #[inline] fn device(&self) -> &Arc { &self.device } } -impl PartialEq for UnsafeDescriptorPool { +impl PartialEq for DescriptorPool { #[inline] fn eq(&self, other: &Self) -> bool { self.handle == other.handle && self.device() == other.device() } } -impl Eq for UnsafeDescriptorPool {} +impl Eq for DescriptorPool {} -impl Hash for UnsafeDescriptorPool { +impl Hash for DescriptorPool { fn hash(&self, state: &mut H) { self.handle.hash(state); self.device().hash(state); @@ -370,7 +374,7 @@ impl Hash for UnsafeDescriptorPool { /// Parameters to create a new `UnsafeDescriptorPool`. #[derive(Clone, Debug)] -pub struct UnsafeDescriptorPoolCreateInfo { +pub struct DescriptorPoolCreateInfo { /// The maximum number of descriptor sets that can be allocated from the pool. /// /// The default value is `0`, which must be overridden. @@ -390,7 +394,7 @@ pub struct UnsafeDescriptorPoolCreateInfo { pub _ne: crate::NonExhaustive, } -impl Default for UnsafeDescriptorPoolCreateInfo { +impl Default for DescriptorPoolCreateInfo { #[inline] fn default() -> Self { Self { @@ -451,7 +455,7 @@ impl Display for DescriptorPoolAllocError { #[cfg(test)] mod tests { - use super::{UnsafeDescriptorPool, UnsafeDescriptorPoolCreateInfo}; + use super::{DescriptorPool, DescriptorPoolCreateInfo}; use crate::{ descriptor_set::{ layout::{ @@ -467,9 +471,9 @@ mod tests { fn pool_create() { let (device, _) = gfx_dev_and_queue!(); - let _ = UnsafeDescriptorPool::new( + let _ = DescriptorPool::new( device, - UnsafeDescriptorPoolCreateInfo { + DescriptorPoolCreateInfo { max_sets: 10, pool_sizes: [(DescriptorType::UniformBuffer, 1)].into_iter().collect(), ..Default::default() @@ -483,9 +487,9 @@ mod tests { let (device, _) = gfx_dev_and_queue!(); assert_should_panic!({ - let _ = UnsafeDescriptorPool::new( + let _ = DescriptorPool::new( device, - UnsafeDescriptorPoolCreateInfo { + DescriptorPoolCreateInfo { max_sets: 0, pool_sizes: [(DescriptorType::UniformBuffer, 1)].into_iter().collect(), ..Default::default() @@ -499,9 +503,9 @@ mod tests { let (device, _) = gfx_dev_and_queue!(); assert_should_panic!({ - let _ = UnsafeDescriptorPool::new( + let _ = DescriptorPool::new( device, - UnsafeDescriptorPoolCreateInfo { + DescriptorPoolCreateInfo { max_sets: 10, ..Default::default() }, @@ -529,9 +533,9 @@ mod tests { ) .unwrap(); - let mut pool = UnsafeDescriptorPool::new( + let pool = DescriptorPool::new( device, - UnsafeDescriptorPoolCreateInfo { + DescriptorPoolCreateInfo { max_sets: 10, pool_sizes: [(DescriptorType::UniformBuffer, 10)].into_iter().collect(), ..Default::default() @@ -571,9 +575,9 @@ mod tests { .unwrap(); assert_should_panic!({ - let mut pool = UnsafeDescriptorPool::new( + let pool = DescriptorPool::new( device2, - UnsafeDescriptorPoolCreateInfo { + DescriptorPoolCreateInfo { max_sets: 10, pool_sizes: [(DescriptorType::UniformBuffer, 10)].into_iter().collect(), ..Default::default() @@ -594,9 +598,9 @@ mod tests { fn alloc_zero() { let (device, _) = gfx_dev_and_queue!(); - let mut pool = UnsafeDescriptorPool::new( + let pool = DescriptorPool::new( device, - UnsafeDescriptorPoolCreateInfo { + DescriptorPoolCreateInfo { max_sets: 1, pool_sizes: [(DescriptorType::UniformBuffer, 1)].into_iter().collect(), ..Default::default() diff --git a/vulkano/src/descriptor_set/pool/mod.rs b/vulkano/src/descriptor_set/pool/mod.rs deleted file mode 100644 index cda4cce8..00000000 --- a/vulkano/src/descriptor_set/pool/mod.rs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2021 The vulkano developers -// Licensed under the Apache License, Version 2.0 -// or the MIT -// license , -// at your option. All files in the project carrying such -// notice may not be copied, modified, or distributed except -// according to those terms. - -//! A pool from which descriptor sets can be allocated. - -pub use self::{ - standard::StandardDescriptorPool, - sys::{ - DescriptorPoolAllocError, DescriptorSetAllocateInfo, UnsafeDescriptorPool, - UnsafeDescriptorPoolCreateInfo, - }, -}; -use super::{layout::DescriptorSetLayout, sys::UnsafeDescriptorSet}; -use crate::{device::DeviceOwned, OomError}; -use std::sync::Arc; - -pub mod standard; -mod sys; - -/// A pool from which descriptor sets can be allocated. -pub unsafe trait DescriptorPool: DeviceOwned { - /// Object that represented an allocated descriptor set. - /// - /// The destructor of this object should free the descriptor set. - type Alloc: DescriptorPoolAlloc; - - /// Allocates a descriptor set. - fn allocate( - &mut self, - layout: &Arc, - variable_descriptor_count: u32, - ) -> Result; -} - -/// An allocated descriptor set. -pub trait DescriptorPoolAlloc: Send + Sync { - /// Returns the inner unsafe descriptor set object. - fn inner(&self) -> &UnsafeDescriptorSet; - - /// Returns the inner unsafe descriptor set object. - fn inner_mut(&mut self) -> &mut UnsafeDescriptorSet; -} diff --git a/vulkano/src/descriptor_set/pool/standard.rs b/vulkano/src/descriptor_set/pool/standard.rs deleted file mode 100644 index 33e54a72..00000000 --- a/vulkano/src/descriptor_set/pool/standard.rs +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) 2016 The vulkano developers -// Licensed under the Apache License, Version 2.0 -// or the MIT -// license , -// 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::{DescriptorPool, DescriptorPoolAlloc}; -use crate::{ - descriptor_set::{ - layout::DescriptorSetLayout, - single_layout_pool::{ - SingleLayoutPoolAlloc, SingleLayoutVariableDescSetPool, SingleLayoutVariablePoolAlloc, - }, - sys::UnsafeDescriptorSet, - SingleLayoutDescSetPool, - }, - device::{Device, DeviceOwned}, - OomError, -}; -use ahash::HashMap; -use std::sync::Arc; - -/// Standard implementation of a descriptor pool. -/// -/// Interally, this implementation uses one [`SingleLayoutDescSetPool`] / -/// [`SingleLayoutVariableDescSetPool`] per descriptor set layout. -#[derive(Debug)] -pub struct StandardDescriptorPool { - device: Arc, - pools: HashMap, Pool>, -} - -#[derive(Debug)] -enum Pool { - Fixed(SingleLayoutDescSetPool), - Variable(SingleLayoutVariableDescSetPool), -} - -impl StandardDescriptorPool { - /// Builds a new `StandardDescriptorPool`. - #[inline] - pub fn new(device: Arc) -> StandardDescriptorPool { - StandardDescriptorPool { - device, - pools: HashMap::default(), - } - } -} - -unsafe impl DescriptorPool for StandardDescriptorPool { - type Alloc = StandardDescriptorPoolAlloc; - - #[inline] - fn allocate( - &mut self, - layout: &Arc, - variable_descriptor_count: u32, - ) -> Result { - assert!( - !layout.push_descriptor(), - "the provided descriptor set layout is for push descriptors, and cannot be used to \ - build a descriptor set object", - ); - - let max_count = layout.variable_descriptor_count(); - - assert!( - variable_descriptor_count <= max_count, - "the provided variable_descriptor_count ({}) is greater than the maximum number of \ - variable count descriptors in the set ({})", - variable_descriptor_count, - max_count, - ); - - // We do this instead of using `HashMap::entry` directly because that would involve cloning - // an `Arc` every time. `hash_raw_entry` is still not stabilized >:( - let pool = if let Some(pool) = self.pools.get_mut(layout) { - pool - } else { - self.pools - .entry(layout.clone()) - .or_insert(if max_count == 0 { - Pool::Fixed(SingleLayoutDescSetPool::new(layout.clone())?) - } else { - Pool::Variable(SingleLayoutVariableDescSetPool::new(layout.clone())?) - }) - }; - - let inner = match pool { - Pool::Fixed(pool) => PoolAlloc::Fixed(pool.next_alloc()?), - Pool::Variable(pool) => { - PoolAlloc::Variable(pool.next_alloc(variable_descriptor_count)?) - } - }; - - Ok(StandardDescriptorPoolAlloc { inner }) - } -} - -unsafe impl DeviceOwned for StandardDescriptorPool { - #[inline] - fn device(&self) -> &Arc { - &self.device - } -} - -/// A descriptor set allocated from a `StandardDescriptorPool`. -#[derive(Debug)] -pub struct StandardDescriptorPoolAlloc { - // The actual descriptor alloc. - inner: PoolAlloc, -} - -#[derive(Debug)] -enum PoolAlloc { - Fixed(SingleLayoutPoolAlloc), - Variable(SingleLayoutVariablePoolAlloc), -} - -impl DescriptorPoolAlloc for StandardDescriptorPoolAlloc { - #[inline] - fn inner(&self) -> &UnsafeDescriptorSet { - match &self.inner { - PoolAlloc::Fixed(alloc) => alloc.inner(), - PoolAlloc::Variable(alloc) => alloc.inner(), - } - } - - #[inline] - fn inner_mut(&mut self) -> &mut UnsafeDescriptorSet { - match &mut self.inner { - PoolAlloc::Fixed(alloc) => alloc.inner_mut(), - PoolAlloc::Variable(alloc) => alloc.inner_mut(), - } - } -} diff --git a/vulkano/src/descriptor_set/single_layout_pool.rs b/vulkano/src/descriptor_set/single_layout_pool.rs index 7f3fb3a5..ccaaebf8 100644 --- a/vulkano/src/descriptor_set/single_layout_pool.rs +++ b/vulkano/src/descriptor_set/single_layout_pool.rs @@ -8,10 +8,11 @@ // according to those terms. use super::{ + allocator::DescriptorSetAlloc, layout::DescriptorSetLayout, pool::{ - DescriptorPoolAlloc, DescriptorPoolAllocError, DescriptorSetAllocateInfo, - UnsafeDescriptorPool, UnsafeDescriptorPoolCreateInfo, + DescriptorPool, DescriptorPoolAllocError, DescriptorPoolCreateInfo, + DescriptorSetAllocateInfo, }, sys::UnsafeDescriptorSet, DescriptorSet, DescriptorSetCreationError, DescriptorSetInner, DescriptorSetResources, @@ -23,7 +24,7 @@ use crate::{ }; use crossbeam_queue::ArrayQueue; use std::{ - cell::UnsafeCell, + cell::{Cell, UnsafeCell}, hash::{Hash, Hasher}, mem::ManuallyDrop, sync::Arc, @@ -33,25 +34,29 @@ const MAX_SETS: usize = 32; const MAX_POOLS: usize = 32; -/// `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 descriptor sets -/// from and optimizes for a specific layout which must not have a variable descriptor count. If -/// you need a variable descriptor count see [`SingleLayoutVariableDescSetPool`]. For a more general -/// purpose pool see [`StandardDescriptorPool`]. +/// `SingleLayoutDescriptorSetPool` is a convenience wrapper provided by Vulkano not to be confused +/// with `VkDescriptorPool`. Its function is to provide access to pool(s) to allocate descriptor +/// sets from and optimizes for a specific layout which must not have a variable descriptor count. +/// If you need a variable descriptor count see [`SingleLayoutVariableDescriptorSetPool`]. For a +/// general-purpose descriptor set allocator see [`StandardDescriptorSetAllocator`]. /// -/// [`StandardDescriptorPool`]: super::pool::standard::StandardDescriptorPool +/// [`StandardDescriptorSetAllocator`]: super::allocator::standard::StandardDescriptorSetAllocator #[derive(Debug)] -pub struct SingleLayoutDescSetPool { +pub struct SingleLayoutDescriptorSetPool { // 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: Arc, + inner: UnsafeCell>, // The amount of sets available to use when we create a new Vulkan pool. - set_count: usize, + set_count: Cell, // The descriptor set layout that this pool is for. layout: Arc, } -impl SingleLayoutDescSetPool { +// This is needed because of the blanket impl on `Arc`, which requires that `T` is `Send + Sync`. +// `SingleLayoutPool` is `Send + !Sync`. +unsafe impl Send for SingleLayoutDescriptorSetPool {} + +impl SingleLayoutDescriptorSetPool { /// Initializes a new pool. The pool is configured to allocate sets that corresponds to the /// parameters passed to this function. /// @@ -70,12 +75,12 @@ impl SingleLayoutDescSetPool { assert!( layout.variable_descriptor_count() == 0, "the provided descriptor set layout has a binding with a variable descriptor count, \ - which cannot be used with SingleLayoutDescSetPool", + which cannot be used with SingleLayoutDescriptorSetPool", ); Ok(Self { - inner: SingleLayoutPool::new(&layout, MAX_SETS)?, - set_count: MAX_SETS, + inner: UnsafeCell::new(SingleLayoutPool::new(&layout, MAX_SETS)?), + set_count: Cell::new(MAX_SETS), layout, }) } @@ -83,7 +88,7 @@ impl SingleLayoutDescSetPool { /// Returns a new descriptor set, either by creating a new one or returning an existing one /// from the internal reserve. pub fn next( - &mut self, + &self, descriptor_writes: impl IntoIterator, ) -> Result, DescriptorSetCreationError> { let alloc = self.next_alloc()?; @@ -97,18 +102,19 @@ impl SingleLayoutDescSetPool { Ok(Arc::new(SingleLayoutDescSet { alloc, inner })) } - pub(crate) fn next_alloc(&mut self) -> Result { + pub(crate) fn next_alloc(&self) -> Result { + let inner = unsafe { &mut *self.inner.get() }; loop { - if let Some(existing) = self.inner.reserve.pop() { + if let Some(existing) = inner.reserve.pop() { return Ok(SingleLayoutPoolAlloc { - pool: self.inner.clone(), + pool: inner.clone(), inner: ManuallyDrop::new(existing), }); } - self.set_count *= 2; + self.set_count.set(self.set_count.get() * 2); - self.inner = SingleLayoutPool::new(&self.layout, self.set_count)?; + *inner = SingleLayoutPool::new(&self.layout, self.set_count.get())?; } } } @@ -117,7 +123,7 @@ impl SingleLayoutDescSetPool { 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, + _inner: DescriptorPool, // 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: ArrayQueue, @@ -125,9 +131,9 @@ struct SingleLayoutPool { impl SingleLayoutPool { fn new(layout: &Arc, set_count: usize) -> Result, OomError> { - let mut inner = UnsafeDescriptorPool::new( + let inner = DescriptorPool::new( layout.device().clone(), - UnsafeDescriptorPoolCreateInfo { + DescriptorPoolCreateInfo { max_sets: set_count as u32, pool_sizes: layout .descriptor_counts() @@ -185,7 +191,12 @@ pub(crate) struct SingleLayoutPoolAlloc { pool: Arc, } -impl DescriptorPoolAlloc for SingleLayoutPoolAlloc { +// This is required for the same reason as for `SingleLayoutDescriptorSetPool`. +unsafe impl Send for SingleLayoutPoolAlloc {} +// `DescriptorPool` is `!Sync`, but we never access it, only keep it alive. +unsafe impl Sync for SingleLayoutPoolAlloc {} + +impl DescriptorSetAlloc for SingleLayoutPoolAlloc { fn inner(&self) -> &UnsafeDescriptorSet { &self.inner } @@ -202,7 +213,7 @@ impl Drop for SingleLayoutPoolAlloc { } } -/// A descriptor set created from a [`SingleLayoutDescSetPool`]. +/// A descriptor set created from a [`SingleLayoutDescriptorSetPool`]. pub struct SingleLayoutDescSet { alloc: SingleLayoutPoolAlloc, inner: DescriptorSetInner, @@ -249,26 +260,30 @@ impl Hash for SingleLayoutDescSet { } } -/// Much like [`SingleLayoutDescSetPool`], except that it allows you to allocate descriptor sets -/// with a variable descriptor count. As this has more overhead, you should only use this pool if -/// you need the functionality and prefer [`SingleLayoutDescSetPool`] otherwise. For a more general -/// purpose pool see [`StandardDescriptorPool`]. +/// Much like [`SingleLayoutDescriptorSetPool`], except that it allows you to allocate descriptor +/// sets with a variable descriptor count. As this has more overhead, you should only use this pool +/// if you need the functionality and prefer [`SingleLayoutDescriptorSetPool`] otherwise. For a +/// more general purpose descriptor set allocator see [`StandardDescriptorSetAllocator`]. /// -/// [`StandardDescriptorPool`]: super::pool::standard::StandardDescriptorPool +/// [`StandardDescriptorSetAllocator`]: super::allocator::standard::StandardDescriptorSetAllocator #[derive(Debug)] -pub struct SingleLayoutVariableDescSetPool { +pub struct SingleLayoutVariableDescriptorSetPool { // The `SingleLayoutVariablePool` struct contains an actual Vulkan pool. Every time it is full // we grab one from the reserve, or create a new pool if there are none. - inner: Arc, + inner: UnsafeCell>, // When a `SingleLayoutVariablePool` is dropped, it returns its Vulkan pool here for reuse. - reserve: Arc>, + reserve: Arc>, // The descriptor set layout that this pool is for. layout: Arc, // The number of sets currently allocated from the Vulkan pool. - allocated_sets: usize, + allocated_sets: Cell, } -impl SingleLayoutVariableDescSetPool { +// This is needed because of the blanket impl on `Arc`, which requires that `T` is `Send + Sync`. +// `SingleLayoutVariablePool` is `Send + !Sync`. +unsafe impl Send for SingleLayoutVariableDescriptorSetPool {} + +impl SingleLayoutVariableDescriptorSetPool { /// Initializes a new pool. The pool is configured to allocate sets that corresponds to the /// parameters passed to this function. /// @@ -287,10 +302,10 @@ impl SingleLayoutVariableDescSetPool { let reserve = Arc::new(ArrayQueue::new(MAX_POOLS)); Ok(Self { - inner: SingleLayoutVariablePool::new(&layout, reserve.clone())?, + inner: UnsafeCell::new(SingleLayoutVariablePool::new(&layout, reserve.clone())?), reserve, layout, - allocated_sets: 0, + allocated_sets: Cell::new(0), }) } @@ -300,7 +315,7 @@ impl SingleLayoutVariableDescSetPool { /// /// - Panics if the provided `variable_descriptor_count` exceeds the maximum for the layout. pub fn next( - &mut self, + &self, variable_descriptor_count: u32, descriptor_writes: impl IntoIterator, ) -> Result { @@ -326,73 +341,68 @@ impl SingleLayoutVariableDescSetPool { } pub(crate) fn next_alloc( - &mut self, + &self, variable_descriptor_count: u32, ) -> Result { - if self.allocated_sets >= MAX_SETS { - self.inner = if let Some(unsafe_pool) = self.reserve.pop() { + if self.allocated_sets.get() >= MAX_SETS { + *unsafe { &mut *self.inner.get() } = if let Some(unsafe_pool) = self.reserve.pop() { Arc::new(SingleLayoutVariablePool { - inner: UnsafeCell::new(ManuallyDrop::new(unsafe_pool)), + inner: ManuallyDrop::new(unsafe_pool), reserve: self.reserve.clone(), }) } else { SingleLayoutVariablePool::new(&self.layout, self.reserve.clone())? }; - self.allocated_sets = 0; + self.allocated_sets.set(0); } - let inner = { - let unsafe_pool = unsafe { &mut *self.inner.inner.get() }; + let allocate_info = DescriptorSetAllocateInfo { + layout: &self.layout, + variable_descriptor_count, + }; - let allocate_info = DescriptorSetAllocateInfo { - layout: &self.layout, - variable_descriptor_count, - }; + let pool = unsafe { &*self.inner.get() }.clone(); - match unsafe { unsafe_pool.allocate_descriptor_sets([allocate_info]) } { - Ok(mut sets) => sets.next().unwrap(), - 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) => { - // We created the pool to fit the maximum variable descriptor count. - unreachable!(); - } + let inner = match unsafe { pool.inner.allocate_descriptor_sets([allocate_info]) } { + Ok(mut sets) => sets.next().unwrap(), + 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) => { + // We created the pool to fit the maximum variable descriptor count. + unreachable!(); } }; - self.allocated_sets += 1; + self.allocated_sets.set(self.allocated_sets.get() + 1); - Ok(SingleLayoutVariablePoolAlloc { - inner, - _pool: self.inner.clone(), - }) + Ok(SingleLayoutVariablePoolAlloc { inner, _pool: pool }) } } #[derive(Debug)] struct SingleLayoutVariablePool { // The actual Vulkan descriptor pool. - inner: UnsafeCell>, + inner: ManuallyDrop, // Where we return the Vulkan descriptor pool in our `Drop` impl. - reserve: Arc>, + reserve: Arc>, } impl SingleLayoutVariablePool { fn new( layout: &Arc, - reserve: Arc>, + reserve: Arc>, ) -> Result, OomError> { - let unsafe_pool = UnsafeDescriptorPool::new( + let unsafe_pool = DescriptorPool::new( layout.device().clone(), - UnsafeDescriptorPoolCreateInfo { + DescriptorPoolCreateInfo { max_sets: MAX_SETS as u32, pool_sizes: layout .descriptor_counts() @@ -404,7 +414,7 @@ impl SingleLayoutVariablePool { )?; Ok(Arc::new(Self { - inner: UnsafeCell::new(ManuallyDrop::new(unsafe_pool)), + inner: ManuallyDrop::new(unsafe_pool), reserve, })) } @@ -412,7 +422,7 @@ impl SingleLayoutVariablePool { impl Drop for SingleLayoutVariablePool { fn drop(&mut self) { - let mut inner = unsafe { ManuallyDrop::take(&mut *self.inner.get()) }; + let inner = unsafe { ManuallyDrop::take(&mut self.inner) }; // TODO: This should not return `Result`, resetting a pool can't fail. unsafe { inner.reset() }.unwrap(); @@ -433,10 +443,12 @@ pub(crate) struct SingleLayoutVariablePoolAlloc { _pool: Arc, } +// This is required for the same reason as for `SingleLayoutVariableDescriptorSetPool`. unsafe impl Send for SingleLayoutVariablePoolAlloc {} +// `DescriptorPool` is `!Sync`, but we never access it, only keep it alive. unsafe impl Sync for SingleLayoutVariablePoolAlloc {} -impl DescriptorPoolAlloc for SingleLayoutVariablePoolAlloc { +impl DescriptorSetAlloc for SingleLayoutVariablePoolAlloc { fn inner(&self) -> &UnsafeDescriptorSet { &self.inner } @@ -446,7 +458,7 @@ impl DescriptorPoolAlloc for SingleLayoutVariablePoolAlloc { } } -/// A descriptor set created from a [`SingleLayoutVariableDescSetPool`]. +/// A descriptor set created from a [`SingleLayoutVariableDescriptorSetPool`]. pub struct SingleLayoutVariableDescSet { alloc: SingleLayoutVariablePoolAlloc, inner: DescriptorSetInner, diff --git a/vulkano/src/device/mod.rs b/vulkano/src/device/mod.rs index 584a32c9..c54c790d 100644 --- a/vulkano/src/device/mod.rs +++ b/vulkano/src/device/mod.rs @@ -105,28 +105,22 @@ use self::physical::PhysicalDevice; pub(crate) use self::{features::FeaturesFfi, properties::PropertiesFfi}; pub use self::{ features::{FeatureRestriction, FeatureRestrictionError, Features}, - properties::Properties, queue::{Queue, QueueError, QueueFamilyProperties, QueueFlags, QueueGuard}, }; -use crate::{ - command_buffer::pool::StandardCommandPool, - descriptor_set::pool::StandardDescriptorPool, - instance::Instance, - memory::{pool::StandardMemoryPool, ExternalMemoryHandleType}, - OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject, -}; pub use crate::{ device::extensions::DeviceExtensions, extensions::{ExtensionRestriction, ExtensionRestrictionError}, fns::DeviceFunctions, }; -use ahash::HashMap; +use crate::{ + instance::Instance, + memory::{pool::StandardMemoryPool, ExternalMemoryHandleType}, + OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject, +}; use ash::vk::Handle; use parking_lot::Mutex; use smallvec::SmallVec; use std::{ - cell::RefCell, - collections::hash_map::Entry, error::Error, ffi::CString, fmt::{Display, Error as FmtError, Formatter}, @@ -511,72 +505,6 @@ impl Device { new_pool } - /// Gives you access to the standard descriptor pool that is used by default if you don't - /// provide any other pool. - /// - /// Pools are stored in thread-local storage to avoid locks, which means that a pool is only - /// dropped once both the thread exits and all descriptor sets allocated from it are dropped. - /// A pool is created lazily for each thread. - /// - /// # Panics - /// - /// - Panics if called again from within the callback. - pub fn with_standard_descriptor_pool( - self: &Arc, - f: impl FnOnce(&mut StandardDescriptorPool) -> T, - ) -> T { - thread_local! { - static TLS: RefCell> = - RefCell::new(HashMap::default()); - } - - TLS.with(|tls| { - let mut tls = tls.borrow_mut(); - let pool = match tls.entry(self.internal_object()) { - Entry::Occupied(entry) => entry.into_mut(), - Entry::Vacant(entry) => entry.insert(StandardDescriptorPool::new(self.clone())), - }; - - f(pool) - }) - } - - /// Gives you access to the standard command buffer pool used by default if you don't provide - /// any other pool. - /// - /// Pools are stored in thread-local storage to avoid locks, which means that a pool is only - /// dropped once both the thread exits and all command buffers allocated from it are dropped. - /// A pool is created lazily for each thread, device and queue family combination as needed, - /// which is why this function might return an `OomError`. - /// - /// # Panics - /// - /// - Panics if the device and the queue family don't belong to the same physical device. - /// - Panics if called again from within the callback. - pub fn with_standard_command_pool( - self: &Arc, - queue_family_index: u32, - f: impl FnOnce(&Arc) -> T, - ) -> Result { - thread_local! { - static TLS: RefCell>> = - RefCell::new(Default::default()); - } - - TLS.with(|tls| { - let mut tls = tls.borrow_mut(); - let pool = match tls.entry((self.internal_object(), queue_family_index)) { - Entry::Occupied(entry) => entry.into_mut(), - Entry::Vacant(entry) => entry.insert(Arc::new(StandardCommandPool::new( - self.clone(), - queue_family_index, - )?)), - }; - - Ok(f(pool)) - }) - } - /// Used to track the number of allocations on this device. /// /// To ensure valid usage of the Vulkan API, we cannot call `vkAllocateMemory` when diff --git a/vulkano/src/device/physical.rs b/vulkano/src/device/physical.rs index bfd29167..81c543b5 100644 --- a/vulkano/src/device/physical.rs +++ b/vulkano/src/device/physical.rs @@ -11,7 +11,7 @@ use super::QueueFamilyProperties; use crate::{ buffer::{ExternalBufferInfo, ExternalBufferProperties}, cache::OnceCache, - device::{DeviceExtensions, Features, FeaturesFfi, Properties, PropertiesFfi}, + device::{properties::Properties, DeviceExtensions, Features, FeaturesFfi, PropertiesFfi}, format::{Format, FormatProperties}, image::{ ImageCreateFlags, ImageFormatInfo, ImageFormatProperties, ImageUsage, diff --git a/vulkano/src/image/immutable.rs b/vulkano/src/image/immutable.rs index 9665b396..59e6039c 100644 --- a/vulkano/src/image/immutable.rs +++ b/vulkano/src/image/immutable.rs @@ -15,8 +15,9 @@ use super::{ use crate::{ buffer::{BufferAccess, BufferContents, BufferUsage, CpuAccessibleBuffer}, command_buffer::{ - AutoCommandBufferBuilder, BlitImageInfo, CommandBufferBeginError, CommandBufferExecFuture, - CommandBufferUsage, CopyBufferToImageInfo, ImageBlit, PrimaryCommandBuffer, + allocator::CommandBufferAllocator, AutoCommandBufferBuilder, BlitImageInfo, + CommandBufferBeginError, CommandBufferExecFuture, CommandBufferUsage, + CopyBufferToImageInfo, ImageBlit, PrimaryCommandBuffer, }, device::{Device, DeviceOwned, Queue}, format::Format, @@ -59,12 +60,14 @@ fn has_mipmaps(mipmaps: MipmapsCount) -> bool { } } -fn generate_mipmaps( - cbb: &mut AutoCommandBufferBuilder, +fn generate_mipmaps( + cbb: &mut AutoCommandBufferBuilder, image: Arc, dimensions: ImageDimensions, _layout: ImageLayout, -) { +) where + Cba: CommandBufferAllocator, +{ for level in 1..image.mip_levels() { let src_size = dimensions .mip_level_dimensions(level - 1) @@ -98,53 +101,6 @@ fn generate_mipmaps( } impl ImmutableImage { - #[deprecated(note = "use ImmutableImage::uninitialized instead")] - pub fn new( - device: Arc, - dimensions: ImageDimensions, - format: Format, - queue_family_indices: impl IntoIterator, - ) -> Result, ImmutableImageCreationError> { - #[allow(deprecated)] - ImmutableImage::with_mipmaps( - device, - dimensions, - format, - MipmapsCount::One, - queue_family_indices, - ) - } - - #[deprecated(note = "use ImmutableImage::uninitialized instead")] - pub fn with_mipmaps( - device: Arc, - dimensions: ImageDimensions, - format: Format, - mip_levels: impl Into, - queue_family_indices: impl IntoIterator, - ) -> Result, ImmutableImageCreationError> { - let usage = ImageUsage { - transfer_src: true, // for blits - transfer_dst: true, - sampled: true, - ..ImageUsage::empty() - }; - - let flags = ImageCreateFlags::empty(); - - let (image, _) = ImmutableImage::uninitialized( - device, - dimensions, - format, - mip_levels, - usage, - flags, - ImageLayout::ShaderReadOnlyOptimal, - queue_family_indices, - )?; - Ok(image) - } - /// Builds an uninitialized immutable image. /// /// Returns two things: the image, and a special access that should be used for the initial @@ -226,6 +182,7 @@ impl ImmutableImage { dimensions: ImageDimensions, mip_levels: MipmapsCount, format: Format, + command_buffer_allocator: &impl CommandBufferAllocator, queue: Arc, ) -> Result<(Arc, CommandBufferExecFuture), ImmutableImageCreationError> where @@ -242,7 +199,14 @@ impl ImmutableImage { false, iter, )?; - ImmutableImage::from_buffer(source, dimensions, mip_levels, format, queue) + ImmutableImage::from_buffer( + source, + dimensions, + mip_levels, + format, + command_buffer_allocator, + queue, + ) } /// Construct an ImmutableImage containing a copy of the data in `source`. @@ -251,6 +215,7 @@ impl ImmutableImage { dimensions: ImageDimensions, mip_levels: MipmapsCount, format: Format, + command_buffer_allocator: &impl CommandBufferAllocator, queue: Arc, ) -> Result<(Arc, CommandBufferExecFuture), ImmutableImageCreationError> { let need_to_generate_mipmaps = has_mipmaps(mip_levels); @@ -279,7 +244,7 @@ impl ImmutableImage { )?; let mut cbb = AutoCommandBufferBuilder::primary( - source.device().clone(), + command_buffer_allocator, queue.queue_family_index(), CommandBufferUsage::MultipleSubmit, )?; diff --git a/vulkano/src/image/mod.rs b/vulkano/src/image/mod.rs index ad6c1896..66ce8e87 100644 --- a/vulkano/src/image/mod.rs +++ b/vulkano/src/image/mod.rs @@ -867,6 +867,7 @@ pub struct SparseImageMemoryRequirements { #[cfg(test)] mod tests { use crate::{ + command_buffer::allocator::StandardCommandBufferAllocator, format::Format, image::{ImageAccess, ImageDimensions, ImmutableImage, MipmapsCount}, }; @@ -973,7 +974,9 @@ mod tests { #[test] fn mipmap_working_immutable_image() { - let (_device, queue) = gfx_dev_and_queue!(); + let (device, queue) = gfx_dev_and_queue!(); + + let cb_allocator = StandardCommandBufferAllocator::new(device); let dimensions = ImageDimensions::Dim2d { width: 512, @@ -990,6 +993,7 @@ mod tests { dimensions, MipmapsCount::One, Format::R8_UNORM, + &cb_allocator, queue.clone(), ) .unwrap(); @@ -1005,6 +1009,7 @@ mod tests { dimensions, MipmapsCount::Log2, Format::R8_UNORM, + &cb_allocator, queue, ) .unwrap(); diff --git a/vulkano/src/pipeline/compute.rs b/vulkano/src/pipeline/compute.rs index 5dd2befe..a9fbe0db 100644 --- a/vulkano/src/pipeline/compute.rs +++ b/vulkano/src/pipeline/compute.rs @@ -403,8 +403,12 @@ impl From for ComputePipelineCreationError { mod tests { use crate::{ buffer::{BufferUsage, CpuAccessibleBuffer}, - command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage}, - descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}, + command_buffer::{ + allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage, + }, + descriptor_set::{ + allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet, + }, pipeline::{ComputePipeline, Pipeline, PipelineBindPoint}, shader::{ShaderModule, SpecializationConstants, SpecializationMapEntry}, sync::{now, GpuFuture}, @@ -498,14 +502,17 @@ mod tests { ) .unwrap(); + let ds_allocator = StandardDescriptorSetAllocator::new(device.clone()); let set = PersistentDescriptorSet::new( + &ds_allocator, pipeline.layout().set_layouts().get(0).unwrap().clone(), [WriteDescriptorSet::buffer(0, data_buffer.clone())], ) .unwrap(); + let cb_allocator = StandardCommandBufferAllocator::new(device.clone()); let mut cbb = AutoCommandBufferBuilder::primary( - device.clone(), + &cb_allocator, queue.queue_family_index(), CommandBufferUsage::OneTimeSubmit, ) diff --git a/vulkano/src/sampler/ycbcr.rs b/vulkano/src/sampler/ycbcr.rs index 2059b02c..7eaaab08 100644 --- a/vulkano/src/sampler/ycbcr.rs +++ b/vulkano/src/sampler/ycbcr.rs @@ -26,6 +26,8 @@ //! # let device: std::sync::Arc = return; //! # let image_data: Vec = return; //! # let queue: std::sync::Arc = return; +//! # let command_buffer_allocator: vulkano::command_buffer::allocator::StandardCommandBufferAllocator = return; +//! # let descriptor_set_allocator: vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator = return; //! use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet}; //! use vulkano::descriptor_set::layout::{DescriptorSetLayout, DescriptorSetLayoutBinding, DescriptorSetLayoutCreateInfo, DescriptorType}; //! use vulkano::format::Format; @@ -69,6 +71,7 @@ //! ImageDimensions::Dim2d { width: 1920, height: 1080, array_layers: 1 }, //! MipmapsCount::One, //! Format::G8_B8_R8_3PLANE_420_UNORM, +//! &command_buffer_allocator, //! queue.clone(), //! ).unwrap(); //! @@ -79,6 +82,7 @@ //! let image_view = ImageView::new(image, create_info).unwrap(); //! //! let descriptor_set = PersistentDescriptorSet::new( +//! &descriptor_set_allocator, //! descriptor_set_layout.clone(), //! [WriteDescriptorSet::image_view(0, image_view)], //! ).unwrap();