mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-22 06:45:23 +00:00
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>
This commit is contained in:
parent
f70f43340f
commit
ef65c98ad1
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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();
|
||||
|
@ -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<CpuAccessibleBuffer<[Vertex]>>,
|
||||
subpass: Subpass,
|
||||
pipeline: Arc<GraphicsPipeline>,
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||
}
|
||||
|
||||
impl AmbientLightingSystem {
|
||||
/// Initializes the ambient lighting system.
|
||||
pub fn new(gfx_queue: Arc<Queue>, subpass: Subpass) -> AmbientLightingSystem {
|
||||
pub fn new(
|
||||
gfx_queue: Arc<Queue>,
|
||||
subpass: Subpass,
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||
) -> 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 {
|
||||
|
@ -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<CpuAccessibleBuffer<[Vertex]>>,
|
||||
subpass: Subpass,
|
||||
pipeline: Arc<GraphicsPipeline>,
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||
}
|
||||
|
||||
impl DirectionalLightingSystem {
|
||||
/// Initializes the directional lighting system.
|
||||
pub fn new(gfx_queue: Arc<Queue>, subpass: Subpass) -> DirectionalLightingSystem {
|
||||
pub fn new(
|
||||
gfx_queue: Arc<Queue>,
|
||||
subpass: Subpass,
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||
) -> 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 {
|
||||
|
@ -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<CpuAccessibleBuffer<[Vertex]>>,
|
||||
subpass: Subpass,
|
||||
pipeline: Arc<GraphicsPipeline>,
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||
}
|
||||
|
||||
impl PointLightingSystem {
|
||||
/// Initializes the point lighting system.
|
||||
pub fn new(gfx_queue: Arc<Queue>, subpass: Subpass) -> PointLightingSystem {
|
||||
pub fn new(
|
||||
gfx_queue: Arc<Queue>,
|
||||
subpass: Subpass,
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||
) -> 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 {
|
||||
|
@ -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<RenderPass>,
|
||||
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
|
||||
// Intermediate render target that will contain the albedo of each pixel of the scene.
|
||||
diffuse_buffer: Arc<ImageView<AttachmentImage>>,
|
||||
// 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<Queue>, final_output_format: Format) -> FrameSystem {
|
||||
pub fn new(
|
||||
gfx_queue: Arc<Queue>,
|
||||
final_output_format: Format,
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
) -> 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,
|
||||
)
|
||||
|
@ -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());
|
||||
|
@ -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<CpuAccessibleBuffer<[Vertex]>>,
|
||||
subpass: Subpass,
|
||||
pipeline: Arc<GraphicsPipeline>,
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
}
|
||||
|
||||
impl TriangleDrawSystem {
|
||||
/// Initializes a triangle drawing system.
|
||||
pub fn new(gfx_queue: Arc<Queue>, subpass: Subpass) -> TriangleDrawSystem {
|
||||
pub fn new(
|
||||
gfx_queue: Arc<Queue>,
|
||||
subpass: Subpass,
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
) -> 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 {
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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<Queue>, 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),
|
||||
|
@ -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<Queue>,
|
||||
pipeline: Arc<ComputePipeline>,
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||
palette: Arc<CpuAccessibleBuffer<[[f32; 4]]>>,
|
||||
palette_size: i32,
|
||||
end_color: [f32; 4],
|
||||
}
|
||||
|
||||
impl FractalComputePipeline {
|
||||
pub fn new(queue: Arc<Queue>) -> FractalComputePipeline {
|
||||
pub fn new(
|
||||
queue: Arc<Queue>,
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||
) -> 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<f32>,
|
||||
scale: Vector2<f32>,
|
||||
@ -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,
|
||||
)
|
||||
|
@ -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<Queue>,
|
||||
subpass: Subpass,
|
||||
pipeline: Arc<GraphicsPipeline>,
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||
vertices: Arc<CpuAccessibleBuffer<[TexturedVertex]>>,
|
||||
indices: Arc<CpuAccessibleBuffer<[u32]>>,
|
||||
}
|
||||
|
||||
impl PixelsDrawPipeline {
|
||||
pub fn new(gfx_queue: Arc<Queue>, subpass: Subpass) -> PixelsDrawPipeline {
|
||||
pub fn new(
|
||||
gfx_queue: Arc<Queue>,
|
||||
subpass: Subpass,
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||
) -> 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<dyn ImageViewAbstract>,
|
||||
) -> SecondaryAutoCommandBuffer {
|
||||
let mut builder = AutoCommandBufferBuilder::secondary(
|
||||
self.gfx_queue.device().clone(),
|
||||
&*self.command_buffer_allocator,
|
||||
self.gfx_queue.queue_family_index(),
|
||||
CommandBufferUsage::MultipleSubmit,
|
||||
CommandBufferInheritanceInfo {
|
||||
|
@ -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<Queue>,
|
||||
render_pass: Arc<RenderPass>,
|
||||
pixels_draw_pipeline: PixelsDrawPipeline,
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
}
|
||||
|
||||
impl RenderPassPlaceOverFrame {
|
||||
pub fn new(gfx_queue: Arc<Queue>, output_format: Format) -> RenderPassPlaceOverFrame {
|
||||
pub fn new(
|
||||
gfx_queue: Arc<Queue>,
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||
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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<Queue>,
|
||||
compute_life_pipeline: Arc<ComputePipeline>,
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||
life_in: Arc<CpuAccessibleBuffer<[u32]>>,
|
||||
life_out: Arc<CpuAccessibleBuffer<[u32]>>,
|
||||
image: DeviceImageView,
|
||||
@ -52,7 +56,12 @@ fn rand_grid(compute_queue: &Arc<Queue>, size: [u32; 2]) -> Arc<CpuAccessibleBuf
|
||||
}
|
||||
|
||||
impl GameOfLifeComputePipeline {
|
||||
pub fn new(compute_queue: Arc<Queue>, size: [u32; 2]) -> GameOfLifeComputePipeline {
|
||||
pub fn new(
|
||||
compute_queue: Arc<Queue>,
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||
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<i32>) {
|
||||
pub fn draw_life(&self, pos: Vector2<i32>) {
|
||||
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<dyn GpuFuture> {
|
||||
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<PrimaryAutoCommandBuffer>,
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
@ -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<Queue>,
|
||||
subpass: Subpass,
|
||||
pipeline: Arc<GraphicsPipeline>,
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||
vertices: Arc<CpuAccessibleBuffer<[TexturedVertex]>>,
|
||||
indices: Arc<CpuAccessibleBuffer<[u32]>>,
|
||||
}
|
||||
|
||||
impl PixelsDrawPipeline {
|
||||
pub fn new(gfx_queue: Arc<Queue>, subpass: Subpass) -> PixelsDrawPipeline {
|
||||
pub fn new(
|
||||
gfx_queue: Arc<Queue>,
|
||||
subpass: Subpass,
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||
) -> 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<dyn ImageViewAbstract>,
|
||||
) -> SecondaryAutoCommandBuffer {
|
||||
let mut builder = AutoCommandBufferBuilder::secondary(
|
||||
self.gfx_queue.device().clone(),
|
||||
&*self.command_buffer_allocator,
|
||||
self.gfx_queue.queue_family_index(),
|
||||
CommandBufferUsage::MultipleSubmit,
|
||||
CommandBufferInheritanceInfo {
|
||||
|
@ -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<Queue>,
|
||||
render_pass: Arc<RenderPass>,
|
||||
pixels_draw_pipeline: PixelsDrawPipeline,
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
}
|
||||
|
||||
impl RenderPassPlaceOverFrame {
|
||||
pub fn new(gfx_queue: Arc<Queue>, output_format: Format) -> RenderPassPlaceOverFrame {
|
||||
pub fn new(
|
||||
gfx_queue: Arc<Queue>,
|
||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||
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<F>(
|
||||
&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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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<Queue>,
|
||||
data_buffer: Arc<CpuAccessibleBuffer<[u32]>>,
|
||||
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();
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -67,6 +67,7 @@ use std::{
|
||||
/// use vulkano::sync::GpuFuture;
|
||||
/// # let device: std::sync::Arc<vulkano::device::Device> = return;
|
||||
/// # let queue: std::sync::Arc<vulkano::device::Queue> = 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<T, A = Arc<StandardMemoryPool>>
|
||||
where
|
||||
[T]: BufferContents,
|
||||
|
@ -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<vulkano::device::Device> = return;
|
||||
/// # let queue: std::sync::Arc<vulkano::device::Queue> = 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<NowFuture>;
|
||||
|
||||
impl<T> DeviceLocalBuffer<T>
|
||||
where
|
||||
T: BufferContents + ?Sized,
|
||||
@ -186,9 +184,13 @@ where
|
||||
pub fn from_buffer<B>(
|
||||
source: Arc<B>,
|
||||
usage: BufferUsage,
|
||||
command_buffer_allocator: &impl CommandBufferAllocator,
|
||||
queue: Arc<Queue>,
|
||||
) -> Result<
|
||||
(Arc<DeviceLocalBuffer<T>>, DeviceLocalBufferFromBufferFuture),
|
||||
(
|
||||
Arc<DeviceLocalBuffer<T>>,
|
||||
CommandBufferExecFuture<NowFuture>,
|
||||
),
|
||||
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<Queue>,
|
||||
) -> Result<
|
||||
(Arc<DeviceLocalBuffer<T>>, DeviceLocalBufferFromBufferFuture),
|
||||
(
|
||||
Arc<DeviceLocalBuffer<T>>,
|
||||
CommandBufferExecFuture<NowFuture>,
|
||||
),
|
||||
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<D>(
|
||||
data: D,
|
||||
usage: BufferUsage,
|
||||
command_buffer_allocator: &impl CommandBufferAllocator,
|
||||
queue: Arc<Queue>,
|
||||
) -> Result<
|
||||
(
|
||||
Arc<DeviceLocalBuffer<[T]>>,
|
||||
DeviceLocalBufferFromBufferFuture,
|
||||
CommandBufferExecFuture<NowFuture>,
|
||||
),
|
||||
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<CommandBufferBeginError> 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();
|
||||
|
@ -26,13 +26,18 @@
|
||||
//!
|
||||
//! # let device: Arc<vulkano::device::Device> = return;
|
||||
//! # let queue: Arc<vulkano::device::Queue> = 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(
|
||||
|
369
vulkano/src/command_buffer/allocator.rs
Normal file
369
vulkano/src/command_buffer/allocator.rs
Normal file
@ -0,0 +1,369 @@
|
||||
// Copyright (c) 2016 The vulkano developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
|
||||
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
|
||||
// at your option. All files in the project carrying such
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
//! 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<Item = Self::Builder>;
|
||||
|
||||
/// Represents a command buffer that has been allocated and that is currently being built.
|
||||
type Builder: CommandBufferBuilderAlloc<Alloc = Self::Alloc>;
|
||||
|
||||
/// 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<Self::Iter, OomError>;
|
||||
}
|
||||
|
||||
/// 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<Device>,
|
||||
/// Each queue family index points directly to its pool.
|
||||
pools: SmallVec<[UnsafeCell<Option<Arc<Pool>>>; 8]>,
|
||||
}
|
||||
|
||||
impl StandardCommandBufferAllocator {
|
||||
/// Creates a new `StandardCommandBufferAllocator`.
|
||||
#[inline]
|
||||
pub fn new(device: Arc<Device>) -> 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<StandardCommandBufferBuilderAlloc>;
|
||||
|
||||
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<Self::Iter, OomError> {
|
||||
// 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<Device> {
|
||||
&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<CommandPoolAlloc>,
|
||||
// List of existing secondary command buffers that are available for reuse.
|
||||
secondary_pool: SegQueue<CommandPoolAlloc>,
|
||||
}
|
||||
|
||||
impl Pool {
|
||||
fn new(device: Arc<Device>, queue_family_index: u32) -> Result<Arc<Self>, 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<Self>,
|
||||
level: CommandBufferLevel,
|
||||
mut command_buffer_count: u32,
|
||||
) -> Result<IntoIter<StandardCommandBufferBuilderAlloc>, 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<Device> {
|
||||
self.inner.device()
|
||||
}
|
||||
}
|
||||
|
||||
/// Command buffer allocated from a [`StandardCommandBufferAllocator`].
|
||||
pub struct StandardCommandBufferAlloc {
|
||||
// The actual command buffer. Extracted in the `Drop` implementation.
|
||||
cmd: ManuallyDrop<CommandPoolAlloc>,
|
||||
// We hold a reference to the command pool for our destructor.
|
||||
pool: Arc<Pool>,
|
||||
}
|
||||
|
||||
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<Device> {
|
||||
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());
|
||||
}
|
||||
}
|
@ -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<StandardCommandPool>`)
|
||||
/// 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<L, P = StandardCommandPoolBuilder> {
|
||||
/// 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<L, A = StandardCommandBufferAllocator>
|
||||
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<PrimaryAutoCommandBuffer, StandardCommandPoolBuilder> {
|
||||
impl<A> AutoCommandBufferBuilder<PrimaryAutoCommandBuffer, A>
|
||||
where
|
||||
A: CommandBufferAllocator,
|
||||
{
|
||||
/// Starts recording a primary command buffer.
|
||||
#[inline]
|
||||
pub fn primary(
|
||||
device: Arc<Device>,
|
||||
allocator: &A,
|
||||
queue_family_index: u32,
|
||||
usage: CommandBufferUsage,
|
||||
) -> Result<
|
||||
AutoCommandBufferBuilder<PrimaryAutoCommandBuffer, StandardCommandPoolBuilder>,
|
||||
AutoCommandBufferBuilder<PrimaryAutoCommandBuffer<A::Alloc>, A>,
|
||||
CommandBufferBeginError,
|
||||
> {
|
||||
unsafe {
|
||||
AutoCommandBufferBuilder::begin(
|
||||
device,
|
||||
allocator,
|
||||
queue_family_index,
|
||||
CommandBufferLevel::Primary,
|
||||
CommandBufferBeginInfo {
|
||||
@ -148,21 +154,24 @@ impl AutoCommandBufferBuilder<PrimaryAutoCommandBuffer, StandardCommandPoolBuild
|
||||
}
|
||||
}
|
||||
|
||||
impl AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder> {
|
||||
impl<A> AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, A>
|
||||
where
|
||||
A: CommandBufferAllocator,
|
||||
{
|
||||
/// Starts recording a secondary command buffer.
|
||||
#[inline]
|
||||
pub fn secondary(
|
||||
device: Arc<Device>,
|
||||
allocator: &A,
|
||||
queue_family_index: u32,
|
||||
usage: CommandBufferUsage,
|
||||
inheritance_info: CommandBufferInheritanceInfo,
|
||||
) -> Result<
|
||||
AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder>,
|
||||
AutoCommandBufferBuilder<SecondaryAutoCommandBuffer<A::Alloc>, A>,
|
||||
CommandBufferBeginError,
|
||||
> {
|
||||
unsafe {
|
||||
AutoCommandBufferBuilder::begin(
|
||||
device,
|
||||
allocator,
|
||||
queue_family_index,
|
||||
CommandBufferLevel::Secondary,
|
||||
CommandBufferBeginInfo {
|
||||
@ -175,18 +184,20 @@ impl AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBui
|
||||
}
|
||||
}
|
||||
|
||||
impl<L> AutoCommandBufferBuilder<L, StandardCommandPoolBuilder> {
|
||||
impl<L, A> AutoCommandBufferBuilder<L, A>
|
||||
where
|
||||
A: CommandBufferAllocator,
|
||||
{
|
||||
// Actual constructor. Private.
|
||||
//
|
||||
// `begin_info.inheritance_info` must match `level`.
|
||||
unsafe fn begin(
|
||||
device: Arc<Device>,
|
||||
allocator: &A,
|
||||
queue_family_index: u32,
|
||||
level: CommandBufferLevel,
|
||||
begin_info: CommandBufferBeginInfo,
|
||||
) -> Result<AutoCommandBufferBuilder<L, StandardCommandPoolBuilder>, CommandBufferBeginError>
|
||||
{
|
||||
Self::validate_begin(&device, queue_family_index, level, &begin_info)?;
|
||||
) -> Result<AutoCommandBufferBuilder<L, A>, CommandBufferBeginError> {
|
||||
Self::validate_begin(allocator.device(), queue_family_index, level, &begin_info)?;
|
||||
|
||||
let &CommandBufferBeginInfo {
|
||||
usage,
|
||||
@ -250,25 +261,23 @@ impl<L> AutoCommandBufferBuilder<L, StandardCommandPoolBuilder> {
|
||||
}
|
||||
}
|
||||
|
||||
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<RequirementNotMet> for CommandBufferBeginError {
|
||||
}
|
||||
}
|
||||
|
||||
impl<P> AutoCommandBufferBuilder<PrimaryAutoCommandBuffer<P::Alloc>, P>
|
||||
impl<A> AutoCommandBufferBuilder<PrimaryAutoCommandBuffer<A::Alloc>, A>
|
||||
where
|
||||
P: CommandPoolBuilderAlloc,
|
||||
A: CommandBufferAllocator,
|
||||
{
|
||||
/// Builds the command buffer.
|
||||
pub fn build(self) -> Result<PrimaryAutoCommandBuffer<P::Alloc>, BuildError> {
|
||||
pub fn build(self) -> Result<PrimaryAutoCommandBuffer<A::Alloc>, 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<P> AutoCommandBufferBuilder<SecondaryAutoCommandBuffer<P::Alloc>, P>
|
||||
impl<A> AutoCommandBufferBuilder<SecondaryAutoCommandBuffer<A::Alloc>, A>
|
||||
where
|
||||
P: CommandPoolBuilderAlloc,
|
||||
A: CommandBufferAllocator,
|
||||
{
|
||||
/// Builds the command buffer.
|
||||
pub fn build(self) -> Result<SecondaryAutoCommandBuffer<P::Alloc>, BuildError> {
|
||||
pub fn build(self) -> Result<SecondaryAutoCommandBuffer<A::Alloc>, 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<OomError> for BuildError {
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
impl<L, A> AutoCommandBufferBuilder<L, A>
|
||||
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<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<L, P> DeviceOwned for AutoCommandBufferBuilder<L, P> {
|
||||
unsafe impl<L, A> DeviceOwned for AutoCommandBufferBuilder<L, A>
|
||||
where
|
||||
A: CommandBufferAllocator,
|
||||
{
|
||||
fn device(&self) -> &Arc<Device> {
|
||||
self.inner.device()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PrimaryAutoCommandBuffer<P = StandardCommandPoolAlloc> {
|
||||
pub struct PrimaryAutoCommandBuffer<A = StandardCommandBufferAlloc> {
|
||||
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<P> DeviceOwned for PrimaryAutoCommandBuffer<P> {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<P> PrimaryCommandBuffer for PrimaryAutoCommandBuffer<P>
|
||||
unsafe impl<A> PrimaryCommandBuffer for PrimaryAutoCommandBuffer<A>
|
||||
where
|
||||
P: CommandPoolAlloc,
|
||||
A: CommandBufferAlloc,
|
||||
{
|
||||
fn inner(&self) -> &UnsafeCommandBuffer {
|
||||
self.inner.as_ref()
|
||||
@ -817,24 +832,24 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SecondaryAutoCommandBuffer<P = StandardCommandPoolAlloc> {
|
||||
pub struct SecondaryAutoCommandBuffer<A = StandardCommandBufferAlloc> {
|
||||
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<P> DeviceOwned for SecondaryAutoCommandBuffer<P> {
|
||||
unsafe impl<A> DeviceOwned for SecondaryAutoCommandBuffer<A> {
|
||||
fn device(&self) -> &Arc<Device> {
|
||||
self.inner.device()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<P> SecondaryCommandBuffer for SecondaryAutoCommandBuffer<P>
|
||||
unsafe impl<A> SecondaryCommandBuffer for SecondaryAutoCommandBuffer<A>
|
||||
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,
|
||||
)
|
||||
|
@ -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<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
impl<L, A> AutoCommandBufferBuilder<L, A>
|
||||
where
|
||||
A: CommandBufferAllocator,
|
||||
{
|
||||
/// Binds descriptor sets for future dispatch or draw calls.
|
||||
///
|
||||
/// # Panics
|
||||
|
@ -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<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
impl<L, A> AutoCommandBufferBuilder<L, A>
|
||||
where
|
||||
A: CommandBufferAllocator,
|
||||
{
|
||||
/// Opens a command buffer debug label region.
|
||||
pub fn begin_debug_utils_label(
|
||||
&mut self,
|
||||
|
@ -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<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
impl<L, A> AutoCommandBufferBuilder<L, A>
|
||||
where
|
||||
A: CommandBufferAllocator,
|
||||
{
|
||||
// Helper function for dynamic state setting.
|
||||
fn validate_pipeline_fixed_state(
|
||||
&self,
|
||||
|
@ -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<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
impl<L, A> AutoCommandBufferBuilder<L, A>
|
||||
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
|
||||
|
@ -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<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
impl<L, A> AutoCommandBufferBuilder<L, A>
|
||||
where
|
||||
A: CommandBufferAllocator,
|
||||
{
|
||||
/// Perform a single compute operation using a compute pipeline.
|
||||
///
|
||||
/// A compute pipeline must have been bound using
|
||||
|
@ -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<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
impl<L, A> AutoCommandBufferBuilder<L, A>
|
||||
where
|
||||
A: CommandBufferAllocator,
|
||||
{
|
||||
/// Begins a query.
|
||||
///
|
||||
/// The query will be active until [`end_query`](Self::end_query) is called for the same query.
|
||||
|
@ -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<P> AutoCommandBufferBuilder<PrimaryAutoCommandBuffer<P::Alloc>, P>
|
||||
impl<L, A> AutoCommandBufferBuilder<L, A>
|
||||
where
|
||||
P: CommandPoolBuilderAlloc,
|
||||
A: CommandBufferAllocator,
|
||||
{
|
||||
/// Begins a render pass using a render pass object and framebuffer.
|
||||
///
|
||||
@ -526,7 +526,10 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
impl<L, A> AutoCommandBufferBuilder<L, A>
|
||||
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.
|
||||
|
@ -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<P> AutoCommandBufferBuilder<PrimaryAutoCommandBuffer<P::Alloc>, P>
|
||||
impl<L, A> AutoCommandBufferBuilder<L, A>
|
||||
where
|
||||
P: CommandPoolBuilderAlloc,
|
||||
A: CommandBufferAllocator,
|
||||
{
|
||||
/// Executes a secondary command buffer.
|
||||
///
|
||||
|
@ -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<L, P> AutoCommandBufferBuilder<L, P> {
|
||||
impl<L, A> AutoCommandBufferBuilder<L, A>
|
||||
where
|
||||
A: CommandBufferAllocator,
|
||||
{
|
||||
/// Copies data from a buffer to another buffer.
|
||||
///
|
||||
/// # Panics
|
||||
|
@ -61,8 +61,9 @@
|
||||
//! # let vertex_buffer: std::sync::Arc<vulkano::buffer::CpuAccessibleBuffer<[Vertex]>> = return;
|
||||
//! # let render_pass_begin_info: vulkano::command_buffer::RenderPassBeginInfo = return;
|
||||
//! # let graphics_pipeline: std::sync::Arc<vulkano::pipeline::graphics::GraphicsPipeline> = 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;
|
||||
|
@ -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<Device>,
|
||||
// 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<Cell<ash::vk::CommandPool>>,
|
||||
}
|
||||
|
||||
unsafe impl Send for UnsafeCommandPool {}
|
||||
|
||||
impl UnsafeCommandPool {
|
||||
/// Creates a new `UnsafeCommandPool`.
|
||||
impl CommandPool {
|
||||
/// Creates a new `CommandPool`.
|
||||
pub fn new(
|
||||
device: Arc<Device>,
|
||||
mut create_info: UnsafeCommandPoolCreateInfo,
|
||||
) -> Result<UnsafeCommandPool, UnsafeCommandPoolCreationError> {
|
||||
mut create_info: CommandPoolCreateInfo,
|
||||
) -> Result<CommandPool, CommandPoolCreationError> {
|
||||
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<Device>,
|
||||
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<ash::vk::CommandPool, UnsafeCommandPoolCreationError> {
|
||||
let &UnsafeCommandPoolCreateInfo {
|
||||
create_info: &CommandPoolCreateInfo,
|
||||
) -> Result<ash::vk::CommandPool, CommandPoolCreationError> {
|
||||
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<impl ExactSizeIterator<Item = UnsafeCommandPoolAlloc>, OomError> {
|
||||
) -> Result<impl ExactSizeIterator<Item = CommandPoolAlloc>, 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<Item = UnsafeCommandPoolAlloc>,
|
||||
command_buffers: impl IntoIterator<Item = CommandPoolAlloc>,
|
||||
) {
|
||||
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<Device> {
|
||||
&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<H: Hasher>(&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<VulkanError> for UnsafeCommandPoolCreationError {
|
||||
impl From<VulkanError> for CommandPoolCreationError {
|
||||
fn from(err: VulkanError) -> Self {
|
||||
match err {
|
||||
err @ VulkanError::OutOfHostMemory => Self::OomError(OomError::from(err)),
|
||||
@ -411,9 +405,9 @@ impl From<VulkanError> 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<Device>,
|
||||
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<Device> {
|
||||
&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<H: Hasher>(&self, state: &mut H) {
|
||||
self.handle.hash(state);
|
||||
self.device().hash(state);
|
||||
@ -556,20 +550,19 @@ impl From<VulkanError> 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()
|
||||
},
|
@ -1,105 +0,0 @@
|
||||
// Copyright (c) 2016 The vulkano developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
|
||||
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
|
||||
// at your option. All files in the project carrying such
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
//! 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<Item = Self::Builder>;
|
||||
|
||||
/// Represents a command buffer that has been allocated and that is currently being built.
|
||||
type Builder: CommandPoolBuilderAlloc<Alloc = Self::Alloc>;
|
||||
|
||||
/// 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<Self::Iter, OomError>;
|
||||
|
||||
/// 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;
|
||||
}
|
@ -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
|
||||
// <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
|
||||
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
|
||||
// at your option. All files in the project carrying such
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
/// Standard implementation of a command pool.
|
||||
///
|
||||
/// A thread can have as many `Arc<StandardCommandPool>`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<UnsafeCommandPoolAlloc>,
|
||||
// List of existing secondary command buffers that are available for reuse.
|
||||
available_secondary_command_buffers: SegQueue<UnsafeCommandPoolAlloc>,
|
||||
}
|
||||
|
||||
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<Device>,
|
||||
queue_family_index: u32,
|
||||
) -> Result<StandardCommandPool, OomError> {
|
||||
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<StandardCommandPool> {
|
||||
type Iter = VecIntoIter<StandardCommandPoolBuilder>;
|
||||
type Builder = StandardCommandPoolBuilder;
|
||||
type Alloc = StandardCommandPoolAlloc;
|
||||
|
||||
#[inline]
|
||||
fn allocate(
|
||||
&self,
|
||||
level: CommandBufferLevel,
|
||||
mut command_buffer_count: u32,
|
||||
) -> Result<Self::Iter, 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.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<Device> {
|
||||
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<Device> {
|
||||
self.inner.device()
|
||||
}
|
||||
}
|
||||
|
||||
/// Command buffer allocated from a `StandardCommandPool`.
|
||||
pub struct StandardCommandPoolAlloc {
|
||||
// The actual command buffer. Extracted in the `Drop` implementation.
|
||||
cmd: ManuallyDrop<UnsafeCommandPoolAlloc>,
|
||||
// We hold a reference to the command pool for our destructor.
|
||||
pool: Arc<StandardCommandPool>,
|
||||
}
|
||||
|
||||
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<Device> {
|
||||
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());
|
||||
}
|
||||
}
|
@ -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<SyncCommandBufferBuilder, OomError> {
|
||||
let level = pool_alloc.level();
|
||||
|
@ -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::<Vec<_>>();
|
||||
|
||||
let allocs = device
|
||||
.with_standard_command_pool(queue.queue_family_index(), |pool| {
|
||||
pool.allocate(CommandBufferLevel::Primary, 2)
|
||||
.unwrap()
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.unwrap();
|
||||
let allocs = allocator
|
||||
.allocate(queue.queue_family_index(), CommandBufferLevel::Primary, 2)
|
||||
.unwrap()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
{
|
||||
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,
|
||||
|
@ -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<UnsafeCommandBufferBuilder, OomError> {
|
||||
let CommandBufferBeginInfo {
|
||||
|
183
vulkano/src/descriptor_set/allocator.rs
Normal file
183
vulkano/src/descriptor_set/allocator.rs
Normal file
@ -0,0 +1,183 @@
|
||||
// Copyright (c) 2021 The vulkano developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
|
||||
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
|
||||
// at your option. All files in the project carrying such
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
//! 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<DescriptorSetLayout>,
|
||||
variable_descriptor_count: u32,
|
||||
) -> Result<Self::Alloc, OomError>;
|
||||
}
|
||||
|
||||
/// 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<Device>,
|
||||
pools: UnsafeCell<HashMap<Arc<DescriptorSetLayout>, Pool>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Pool {
|
||||
Fixed(SingleLayoutDescriptorSetPool),
|
||||
Variable(SingleLayoutVariableDescriptorSetPool),
|
||||
}
|
||||
|
||||
impl StandardDescriptorSetAllocator {
|
||||
/// Creates a new `StandardDescriptorSetAllocator`.
|
||||
#[inline]
|
||||
pub fn new(device: Arc<Device>) -> StandardDescriptorSetAllocator {
|
||||
StandardDescriptorSetAllocator {
|
||||
device,
|
||||
pools: UnsafeCell::new(HashMap::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl DescriptorSetAllocator for StandardDescriptorSetAllocator {
|
||||
type Alloc = StandardDescriptorSetAlloc;
|
||||
|
||||
#[inline]
|
||||
fn allocate(
|
||||
&self,
|
||||
layout: &Arc<DescriptorSetLayout>,
|
||||
variable_descriptor_count: u32,
|
||||
) -> Result<StandardDescriptorSetAlloc, OomError> {
|
||||
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<Device> {
|
||||
&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(),
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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<P = StandardDescriptorPoolAlloc> {
|
||||
pub struct PersistentDescriptorSet<P = StandardDescriptorSetAlloc> {
|
||||
alloc: P,
|
||||
inner: DescriptorSetInner,
|
||||
}
|
||||
@ -47,33 +47,15 @@ impl PersistentDescriptorSet {
|
||||
///
|
||||
/// See `new_with_pool` for more.
|
||||
#[inline]
|
||||
pub fn new(
|
||||
pub fn new<A>(
|
||||
allocator: &A,
|
||||
layout: Arc<DescriptorSetLayout>,
|
||||
descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
|
||||
) -> Result<Arc<PersistentDescriptorSet>, 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<DescriptorSetLayout>,
|
||||
variable_descriptor_count: u32,
|
||||
descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
|
||||
) -> Result<Arc<PersistentDescriptorSet>, DescriptorSetCreationError> {
|
||||
layout
|
||||
.device()
|
||||
.clone()
|
||||
.with_standard_descriptor_pool(|pool| {
|
||||
Self::new_with_pool(layout, variable_descriptor_count, pool, descriptor_writes)
|
||||
})
|
||||
) -> Result<Arc<PersistentDescriptorSet<A::Alloc>>, 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<P>(
|
||||
pub fn new_variable<A>(
|
||||
allocator: &A,
|
||||
layout: Arc<DescriptorSetLayout>,
|
||||
variable_descriptor_count: u32,
|
||||
pool: &mut P,
|
||||
descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
|
||||
) -> Result<Arc<PersistentDescriptorSet<P::Alloc>>, DescriptorSetCreationError>
|
||||
) -> Result<Arc<PersistentDescriptorSet<A::Alloc>>, 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<P> DescriptorSet for PersistentDescriptorSet<P>
|
||||
where
|
||||
P: DescriptorPoolAlloc,
|
||||
P: DescriptorSetAlloc,
|
||||
{
|
||||
fn inner(&self) -> &UnsafeDescriptorSet {
|
||||
self.alloc.inner()
|
||||
@ -139,7 +121,7 @@ where
|
||||
|
||||
unsafe impl<P> DeviceOwned for PersistentDescriptorSet<P>
|
||||
where
|
||||
P: DescriptorPoolAlloc,
|
||||
P: DescriptorSetAlloc,
|
||||
{
|
||||
fn device(&self) -> &Arc<Device> {
|
||||
self.inner.layout().device()
|
||||
@ -148,7 +130,7 @@ where
|
||||
|
||||
impl<P> PartialEq for PersistentDescriptorSet<P>
|
||||
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<P> Eq for PersistentDescriptorSet<P> where P: DescriptorPoolAlloc {}
|
||||
impl<P> Eq for PersistentDescriptorSet<P> where P: DescriptorSetAlloc {}
|
||||
|
||||
impl<P> Hash for PersistentDescriptorSet<P>
|
||||
where
|
||||
P: DescriptorPoolAlloc,
|
||||
P: DescriptorSetAlloc,
|
||||
{
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.inner().internal_object().hash(state);
|
||||
|
@ -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<Device>,
|
||||
|
||||
max_sets: u32,
|
||||
pool_sizes: HashMap<DescriptorType, u32>,
|
||||
can_free_descriptor_sets: bool,
|
||||
// Unimplement `Sync`, as Vulkan descriptor pools are not thread safe.
|
||||
_marker: PhantomData<Cell<ash::vk::DescriptorPool>>,
|
||||
}
|
||||
|
||||
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<Device>,
|
||||
create_info: UnsafeDescriptorPoolCreateInfo,
|
||||
) -> Result<UnsafeDescriptorPool, OomError> {
|
||||
let UnsafeDescriptorPoolCreateInfo {
|
||||
create_info: DescriptorPoolCreateInfo,
|
||||
) -> Result<DescriptorPool, OomError> {
|
||||
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<Device>,
|
||||
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<Item = DescriptorSetAllocateInfo<'a>>,
|
||||
) -> Result<impl ExactSizeIterator<Item = UnsafeDescriptorSet>, 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<Item = UnsafeDescriptorSet>,
|
||||
) -> 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<Device> {
|
||||
&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<H: Hasher>(&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()
|
@ -1,48 +0,0 @@
|
||||
// Copyright (c) 2021 The vulkano developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
|
||||
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
|
||||
// at your option. All files in the project carrying such
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
//! 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<DescriptorSetLayout>,
|
||||
variable_descriptor_count: u32,
|
||||
) -> Result<Self::Alloc, OomError>;
|
||||
}
|
||||
|
||||
/// 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;
|
||||
}
|
@ -1,139 +0,0 @@
|
||||
// Copyright (c) 2016 The vulkano developers
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
|
||||
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
|
||||
// at your option. All files in the project carrying such
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use 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<Device>,
|
||||
pools: HashMap<Arc<DescriptorSetLayout>, Pool>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Pool {
|
||||
Fixed(SingleLayoutDescSetPool),
|
||||
Variable(SingleLayoutVariableDescSetPool),
|
||||
}
|
||||
|
||||
impl StandardDescriptorPool {
|
||||
/// Builds a new `StandardDescriptorPool`.
|
||||
#[inline]
|
||||
pub fn new(device: Arc<Device>) -> StandardDescriptorPool {
|
||||
StandardDescriptorPool {
|
||||
device,
|
||||
pools: HashMap::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl DescriptorPool for StandardDescriptorPool {
|
||||
type Alloc = StandardDescriptorPoolAlloc;
|
||||
|
||||
#[inline]
|
||||
fn allocate(
|
||||
&mut self,
|
||||
layout: &Arc<DescriptorSetLayout>,
|
||||
variable_descriptor_count: u32,
|
||||
) -> Result<StandardDescriptorPoolAlloc, OomError> {
|
||||
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<Device> {
|
||||
&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(),
|
||||
}
|
||||
}
|
||||
}
|
@ -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<SingleLayoutPool>,
|
||||
inner: UnsafeCell<Arc<SingleLayoutPool>>,
|
||||
// The amount of sets available to use when we create a new Vulkan pool.
|
||||
set_count: usize,
|
||||
set_count: Cell<usize>,
|
||||
// The descriptor set layout that this pool is for.
|
||||
layout: Arc<DescriptorSetLayout>,
|
||||
}
|
||||
|
||||
impl SingleLayoutDescSetPool {
|
||||
// This is needed because of the blanket impl on `Arc<T>`, 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<Item = WriteDescriptorSet>,
|
||||
) -> Result<Arc<SingleLayoutDescSet>, 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<SingleLayoutPoolAlloc, OomError> {
|
||||
pub(crate) fn next_alloc(&self) -> Result<SingleLayoutPoolAlloc, OomError> {
|
||||
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<UnsafeDescriptorSet>,
|
||||
@ -125,9 +131,9 @@ struct SingleLayoutPool {
|
||||
|
||||
impl SingleLayoutPool {
|
||||
fn new(layout: &Arc<DescriptorSetLayout>, set_count: usize) -> Result<Arc<Self>, 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<SingleLayoutPool>,
|
||||
}
|
||||
|
||||
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<SingleLayoutVariablePool>,
|
||||
inner: UnsafeCell<Arc<SingleLayoutVariablePool>>,
|
||||
// When a `SingleLayoutVariablePool` is dropped, it returns its Vulkan pool here for reuse.
|
||||
reserve: Arc<ArrayQueue<UnsafeDescriptorPool>>,
|
||||
reserve: Arc<ArrayQueue<DescriptorPool>>,
|
||||
// The descriptor set layout that this pool is for.
|
||||
layout: Arc<DescriptorSetLayout>,
|
||||
// The number of sets currently allocated from the Vulkan pool.
|
||||
allocated_sets: usize,
|
||||
allocated_sets: Cell<usize>,
|
||||
}
|
||||
|
||||
impl SingleLayoutVariableDescSetPool {
|
||||
// This is needed because of the blanket impl on `Arc<T>`, 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<Item = WriteDescriptorSet>,
|
||||
) -> Result<SingleLayoutVariableDescSet, DescriptorSetCreationError> {
|
||||
@ -326,73 +341,68 @@ impl SingleLayoutVariableDescSetPool {
|
||||
}
|
||||
|
||||
pub(crate) fn next_alloc(
|
||||
&mut self,
|
||||
&self,
|
||||
variable_descriptor_count: u32,
|
||||
) -> Result<SingleLayoutVariablePoolAlloc, OomError> {
|
||||
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<ManuallyDrop<UnsafeDescriptorPool>>,
|
||||
inner: ManuallyDrop<DescriptorPool>,
|
||||
// Where we return the Vulkan descriptor pool in our `Drop` impl.
|
||||
reserve: Arc<ArrayQueue<UnsafeDescriptorPool>>,
|
||||
reserve: Arc<ArrayQueue<DescriptorPool>>,
|
||||
}
|
||||
|
||||
impl SingleLayoutVariablePool {
|
||||
fn new(
|
||||
layout: &Arc<DescriptorSetLayout>,
|
||||
reserve: Arc<ArrayQueue<UnsafeDescriptorPool>>,
|
||||
reserve: Arc<ArrayQueue<DescriptorPool>>,
|
||||
) -> Result<Arc<Self>, 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<SingleLayoutVariablePool>,
|
||||
}
|
||||
|
||||
// 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,
|
||||
|
@ -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<T>(
|
||||
self: &Arc<Self>,
|
||||
f: impl FnOnce(&mut StandardDescriptorPool) -> T,
|
||||
) -> T {
|
||||
thread_local! {
|
||||
static TLS: RefCell<HashMap<ash::vk::Device, StandardDescriptorPool>> =
|
||||
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<T>(
|
||||
self: &Arc<Self>,
|
||||
queue_family_index: u32,
|
||||
f: impl FnOnce(&Arc<StandardCommandPool>) -> T,
|
||||
) -> Result<T, OomError> {
|
||||
thread_local! {
|
||||
static TLS: RefCell<HashMap<(ash::vk::Device, u32), Arc<StandardCommandPool>>> =
|
||||
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
|
||||
|
@ -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,
|
||||
|
@ -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<L>(
|
||||
cbb: &mut AutoCommandBufferBuilder<L>,
|
||||
fn generate_mipmaps<L, Cba>(
|
||||
cbb: &mut AutoCommandBufferBuilder<L, Cba>,
|
||||
image: Arc<dyn ImageAccess>,
|
||||
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<L>(
|
||||
}
|
||||
|
||||
impl ImmutableImage {
|
||||
#[deprecated(note = "use ImmutableImage::uninitialized instead")]
|
||||
pub fn new(
|
||||
device: Arc<Device>,
|
||||
dimensions: ImageDimensions,
|
||||
format: Format,
|
||||
queue_family_indices: impl IntoIterator<Item = u32>,
|
||||
) -> Result<Arc<ImmutableImage>, 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<Device>,
|
||||
dimensions: ImageDimensions,
|
||||
format: Format,
|
||||
mip_levels: impl Into<MipmapsCount>,
|
||||
queue_family_indices: impl IntoIterator<Item = u32>,
|
||||
) -> Result<Arc<ImmutableImage>, 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<Queue>,
|
||||
) -> Result<(Arc<Self>, CommandBufferExecFuture<NowFuture>), 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<Queue>,
|
||||
) -> Result<(Arc<Self>, CommandBufferExecFuture<NowFuture>), 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,
|
||||
)?;
|
||||
|
@ -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();
|
||||
|
@ -403,8 +403,12 @@ impl From<VulkanError> 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,
|
||||
)
|
||||
|
@ -26,6 +26,8 @@
|
||||
//! # let device: std::sync::Arc<vulkano::device::Device> = return;
|
||||
//! # let image_data: Vec<u8> = return;
|
||||
//! # let queue: std::sync::Arc<vulkano::device::Queue> = 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();
|
||||
|
Loading…
Reference in New Issue
Block a user