mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-22 14:56:42 +00:00
Memory allocation revamp (#1997)
* Add suballocators * Add tests * Retroactively abort `PoolAllocatorCreateInfo` * Use const generic for `PoolAllocator`'s block size * Move `new` and `try_into_region` to `Suballocator` * Move `allocate_unchecked` to `Suballocator` * Fix constructor visibility * Move `free_size` to `Suballocator` * Small fixes * Merge `BumpAllocator` and `SyncBumpAllocator` * Restrict `AllocParent::None` to tests * Rewording * Add dedicated allocations * Add `Suballocator::cleanup` * Make `free_size`s lock-free * Add `Suballocator::largest_free_chunk` * Add `ArrayVec` * Remove useless `unsafe` * Add `MemoryAllocator` * Add `GenericMemoryAllocator` * Small fixes * Retroactively abort `largest_free_chunk` * Small docs adjustments * Rearrange * Add `MemoryAlloc::mapped_ptr` * Fix oopsie * Add support for non-coherent mapped memory * Add `DeviceOwned` subtrait to `Suballocator` * Move granularities to suballocators, fix tests * Add cache control * Fix oopsie where alignment of 0 is possible * Store `Arc<DeviceMemory>` in suballocators * Add `MemoryAllocator::create_{buffer, image}` * Remove `MemoryPool` * Fix examples * Remove `MemoryAlloc::{memory, memory_type_index}` * Minor improvement to `AllocationCreationError` * Add some example docs * Add support for external memory * Swicheroo * Small fix * Shorten sm names, cache atom size in suballocators * Add config for allocation type to generic allocatr * Engrish * Fix a big oopsie * Spliteroo * Inglisch
This commit is contained in:
parent
f079c2bc08
commit
34b709547f
@ -25,6 +25,7 @@ use vulkano::{
|
|||||||
physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
|
physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
|
||||||
},
|
},
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
||||||
sync::{self, GpuFuture},
|
sync::{self, GpuFuture},
|
||||||
VulkanLibrary,
|
VulkanLibrary,
|
||||||
@ -144,6 +145,7 @@ fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
|
let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
|
||||||
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
||||||
|
|
||||||
@ -153,7 +155,7 @@ fn main() {
|
|||||||
let data_iter = 0..65536u32;
|
let data_iter = 0..65536u32;
|
||||||
// Builds the buffer and fills it with this iterator.
|
// Builds the buffer and fills it with this iterator.
|
||||||
CpuAccessibleBuffer::from_iter(
|
CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
storage_buffer: true,
|
storage_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -36,6 +36,7 @@ use vulkano::{
|
|||||||
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
|
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
input_assembly::InputAssemblyState,
|
input_assembly::InputAssemblyState,
|
||||||
@ -169,8 +170,10 @@ fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone()));
|
||||||
|
|
||||||
// Vertex Buffer Pool
|
// Vertex Buffer Pool
|
||||||
let buffer_pool: CpuBufferPool<Vertex> = CpuBufferPool::vertex_buffer(device.clone());
|
let buffer_pool: CpuBufferPool<Vertex> = CpuBufferPool::vertex_buffer(memory_allocator);
|
||||||
|
|
||||||
mod vs {
|
mod vs {
|
||||||
vulkano_shaders::shader! {
|
vulkano_shaders::shader! {
|
||||||
|
@ -24,6 +24,7 @@ use vulkano::{
|
|||||||
},
|
},
|
||||||
Instance, InstanceCreateInfo, InstanceExtensions,
|
Instance, InstanceCreateInfo, InstanceExtensions,
|
||||||
},
|
},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
VulkanLibrary,
|
VulkanLibrary,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -175,7 +176,7 @@ fn main() {
|
|||||||
.expect("failed to create device");
|
.expect("failed to create device");
|
||||||
let queue = queues.next().unwrap();
|
let queue = queues.next().unwrap();
|
||||||
|
|
||||||
let command_buffer_allocator = StandardCommandBufferAllocator::new(device);
|
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
||||||
let mut command_buffer_builder = AutoCommandBufferBuilder::primary(
|
let mut command_buffer_builder = AutoCommandBufferBuilder::primary(
|
||||||
&command_buffer_allocator,
|
&command_buffer_allocator,
|
||||||
queue.queue_family_index(),
|
queue.queue_family_index(),
|
||||||
@ -191,7 +192,9 @@ fn main() {
|
|||||||
array_layers: 1,
|
array_layers: 1,
|
||||||
};
|
};
|
||||||
static DATA: [[u8; 4]; 4096 * 4096] = [[0; 4]; 4096 * 4096];
|
static DATA: [[u8; 4]; 4096 * 4096] = [[0; 4]; 4096 * 4096];
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
let _ = ImmutableImage::from_iter(
|
let _ = ImmutableImage::from_iter(
|
||||||
|
&memory_allocator,
|
||||||
DATA.iter().copied(),
|
DATA.iter().copied(),
|
||||||
dimensions,
|
dimensions,
|
||||||
MipmapsCount::One,
|
MipmapsCount::One,
|
||||||
|
@ -21,6 +21,7 @@ use vulkano::{
|
|||||||
device::Queue,
|
device::Queue,
|
||||||
image::ImageViewAbstract,
|
image::ImageViewAbstract,
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
|
memory::allocator::MemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
color_blend::{AttachmentBlend, BlendFactor, BlendOp, ColorBlendState},
|
color_blend::{AttachmentBlend, BlendFactor, BlendOp, ColorBlendState},
|
||||||
@ -48,6 +49,7 @@ impl AmbientLightingSystem {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
gfx_queue: Arc<Queue>,
|
gfx_queue: Arc<Queue>,
|
||||||
subpass: Subpass,
|
subpass: Subpass,
|
||||||
|
memory_allocator: &impl MemoryAllocator,
|
||||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||||
) -> AmbientLightingSystem {
|
) -> AmbientLightingSystem {
|
||||||
@ -66,7 +68,7 @@ impl AmbientLightingSystem {
|
|||||||
];
|
];
|
||||||
let vertex_buffer = {
|
let vertex_buffer = {
|
||||||
CpuAccessibleBuffer::from_iter(
|
CpuAccessibleBuffer::from_iter(
|
||||||
gfx_queue.device().clone(),
|
memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -22,6 +22,7 @@ use vulkano::{
|
|||||||
device::Queue,
|
device::Queue,
|
||||||
image::ImageViewAbstract,
|
image::ImageViewAbstract,
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
|
memory::allocator::MemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
color_blend::{AttachmentBlend, BlendFactor, BlendOp, ColorBlendState},
|
color_blend::{AttachmentBlend, BlendFactor, BlendOp, ColorBlendState},
|
||||||
@ -49,6 +50,7 @@ impl DirectionalLightingSystem {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
gfx_queue: Arc<Queue>,
|
gfx_queue: Arc<Queue>,
|
||||||
subpass: Subpass,
|
subpass: Subpass,
|
||||||
|
memory_allocator: &impl MemoryAllocator,
|
||||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||||
) -> DirectionalLightingSystem {
|
) -> DirectionalLightingSystem {
|
||||||
@ -67,7 +69,7 @@ impl DirectionalLightingSystem {
|
|||||||
];
|
];
|
||||||
let vertex_buffer = {
|
let vertex_buffer = {
|
||||||
CpuAccessibleBuffer::from_iter(
|
CpuAccessibleBuffer::from_iter(
|
||||||
gfx_queue.device().clone(),
|
memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -22,6 +22,7 @@ use vulkano::{
|
|||||||
device::Queue,
|
device::Queue,
|
||||||
image::ImageViewAbstract,
|
image::ImageViewAbstract,
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
|
memory::allocator::MemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
color_blend::{AttachmentBlend, BlendFactor, BlendOp, ColorBlendState},
|
color_blend::{AttachmentBlend, BlendFactor, BlendOp, ColorBlendState},
|
||||||
@ -48,6 +49,7 @@ impl PointLightingSystem {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
gfx_queue: Arc<Queue>,
|
gfx_queue: Arc<Queue>,
|
||||||
subpass: Subpass,
|
subpass: Subpass,
|
||||||
|
memory_allocator: &impl MemoryAllocator,
|
||||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||||
) -> PointLightingSystem {
|
) -> PointLightingSystem {
|
||||||
@ -66,7 +68,7 @@ impl PointLightingSystem {
|
|||||||
];
|
];
|
||||||
let vertex_buffer = {
|
let vertex_buffer = {
|
||||||
CpuAccessibleBuffer::from_iter(
|
CpuAccessibleBuffer::from_iter(
|
||||||
gfx_queue.device().clone(),
|
memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -24,6 +24,7 @@ use vulkano::{
|
|||||||
device::Queue,
|
device::Queue,
|
||||||
format::Format,
|
format::Format,
|
||||||
image::{view::ImageView, AttachmentImage, ImageAccess, ImageUsage, ImageViewAbstract},
|
image::{view::ImageView, AttachmentImage, ImageAccess, ImageUsage, ImageViewAbstract},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
||||||
sync::GpuFuture,
|
sync::GpuFuture,
|
||||||
};
|
};
|
||||||
@ -38,6 +39,7 @@ pub struct FrameSystem {
|
|||||||
// in of a change in the dimensions.
|
// in of a change in the dimensions.
|
||||||
render_pass: Arc<RenderPass>,
|
render_pass: Arc<RenderPass>,
|
||||||
|
|
||||||
|
memory_allocator: Arc<StandardMemoryAllocator>,
|
||||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||||
|
|
||||||
// Intermediate render target that will contain the albedo of each pixel of the scene.
|
// Intermediate render target that will contain the albedo of each pixel of the scene.
|
||||||
@ -71,6 +73,7 @@ impl FrameSystem {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
gfx_queue: Arc<Queue>,
|
gfx_queue: Arc<Queue>,
|
||||||
final_output_format: Format,
|
final_output_format: Format,
|
||||||
|
memory_allocator: Arc<StandardMemoryAllocator>,
|
||||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||||
) -> FrameSystem {
|
) -> FrameSystem {
|
||||||
// Creating the render pass.
|
// Creating the render pass.
|
||||||
@ -152,7 +155,7 @@ impl FrameSystem {
|
|||||||
// These images will be replaced the first time we call `frame()`.
|
// These images will be replaced the first time we call `frame()`.
|
||||||
let diffuse_buffer = ImageView::new_default(
|
let diffuse_buffer = ImageView::new_default(
|
||||||
AttachmentImage::with_usage(
|
AttachmentImage::with_usage(
|
||||||
gfx_queue.device().clone(),
|
&*memory_allocator,
|
||||||
[1, 1],
|
[1, 1],
|
||||||
Format::A2B10G10R10_UNORM_PACK32,
|
Format::A2B10G10R10_UNORM_PACK32,
|
||||||
ImageUsage {
|
ImageUsage {
|
||||||
@ -166,7 +169,7 @@ impl FrameSystem {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let normals_buffer = ImageView::new_default(
|
let normals_buffer = ImageView::new_default(
|
||||||
AttachmentImage::with_usage(
|
AttachmentImage::with_usage(
|
||||||
gfx_queue.device().clone(),
|
&*memory_allocator,
|
||||||
[1, 1],
|
[1, 1],
|
||||||
Format::R16G16B16A16_SFLOAT,
|
Format::R16G16B16A16_SFLOAT,
|
||||||
ImageUsage {
|
ImageUsage {
|
||||||
@ -180,7 +183,7 @@ impl FrameSystem {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let depth_buffer = ImageView::new_default(
|
let depth_buffer = ImageView::new_default(
|
||||||
AttachmentImage::with_usage(
|
AttachmentImage::with_usage(
|
||||||
gfx_queue.device().clone(),
|
&*memory_allocator,
|
||||||
[1, 1],
|
[1, 1],
|
||||||
Format::D16_UNORM,
|
Format::D16_UNORM,
|
||||||
ImageUsage {
|
ImageUsage {
|
||||||
@ -203,18 +206,21 @@ impl FrameSystem {
|
|||||||
let ambient_lighting_system = AmbientLightingSystem::new(
|
let ambient_lighting_system = AmbientLightingSystem::new(
|
||||||
gfx_queue.clone(),
|
gfx_queue.clone(),
|
||||||
lighting_subpass.clone(),
|
lighting_subpass.clone(),
|
||||||
|
&*memory_allocator,
|
||||||
command_buffer_allocator.clone(),
|
command_buffer_allocator.clone(),
|
||||||
descriptor_set_allocator.clone(),
|
descriptor_set_allocator.clone(),
|
||||||
);
|
);
|
||||||
let directional_lighting_system = DirectionalLightingSystem::new(
|
let directional_lighting_system = DirectionalLightingSystem::new(
|
||||||
gfx_queue.clone(),
|
gfx_queue.clone(),
|
||||||
lighting_subpass.clone(),
|
lighting_subpass.clone(),
|
||||||
|
&*memory_allocator,
|
||||||
command_buffer_allocator.clone(),
|
command_buffer_allocator.clone(),
|
||||||
descriptor_set_allocator.clone(),
|
descriptor_set_allocator.clone(),
|
||||||
);
|
);
|
||||||
let point_lighting_system = PointLightingSystem::new(
|
let point_lighting_system = PointLightingSystem::new(
|
||||||
gfx_queue.clone(),
|
gfx_queue.clone(),
|
||||||
lighting_subpass,
|
lighting_subpass,
|
||||||
|
&*memory_allocator,
|
||||||
command_buffer_allocator.clone(),
|
command_buffer_allocator.clone(),
|
||||||
descriptor_set_allocator,
|
descriptor_set_allocator,
|
||||||
);
|
);
|
||||||
@ -222,6 +228,7 @@ impl FrameSystem {
|
|||||||
FrameSystem {
|
FrameSystem {
|
||||||
gfx_queue,
|
gfx_queue,
|
||||||
render_pass,
|
render_pass,
|
||||||
|
memory_allocator,
|
||||||
command_buffer_allocator,
|
command_buffer_allocator,
|
||||||
diffuse_buffer,
|
diffuse_buffer,
|
||||||
normals_buffer,
|
normals_buffer,
|
||||||
@ -270,7 +277,7 @@ impl FrameSystem {
|
|||||||
// render pass their content becomes undefined.
|
// render pass their content becomes undefined.
|
||||||
self.diffuse_buffer = ImageView::new_default(
|
self.diffuse_buffer = ImageView::new_default(
|
||||||
AttachmentImage::with_usage(
|
AttachmentImage::with_usage(
|
||||||
self.gfx_queue.device().clone(),
|
&*self.memory_allocator,
|
||||||
img_dims,
|
img_dims,
|
||||||
Format::A2B10G10R10_UNORM_PACK32,
|
Format::A2B10G10R10_UNORM_PACK32,
|
||||||
ImageUsage {
|
ImageUsage {
|
||||||
@ -284,7 +291,7 @@ impl FrameSystem {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
self.normals_buffer = ImageView::new_default(
|
self.normals_buffer = ImageView::new_default(
|
||||||
AttachmentImage::with_usage(
|
AttachmentImage::with_usage(
|
||||||
self.gfx_queue.device().clone(),
|
&*self.memory_allocator,
|
||||||
img_dims,
|
img_dims,
|
||||||
Format::R16G16B16A16_SFLOAT,
|
Format::R16G16B16A16_SFLOAT,
|
||||||
ImageUsage {
|
ImageUsage {
|
||||||
@ -298,7 +305,7 @@ impl FrameSystem {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
self.depth_buffer = ImageView::new_default(
|
self.depth_buffer = ImageView::new_default(
|
||||||
AttachmentImage::with_usage(
|
AttachmentImage::with_usage(
|
||||||
self.gfx_queue.device().clone(),
|
&*self.memory_allocator,
|
||||||
img_dims,
|
img_dims,
|
||||||
Format::D16_UNORM,
|
Format::D16_UNORM,
|
||||||
ImageUsage {
|
ImageUsage {
|
||||||
|
@ -30,7 +30,7 @@ use crate::{
|
|||||||
triangle_draw_system::TriangleDrawSystem,
|
triangle_draw_system::TriangleDrawSystem,
|
||||||
};
|
};
|
||||||
use cgmath::{Matrix4, SquareMatrix, Vector3};
|
use cgmath::{Matrix4, SquareMatrix, Vector3};
|
||||||
use std::rc::Rc;
|
use std::{rc::Rc, sync::Arc};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
command_buffer::allocator::StandardCommandBufferAllocator,
|
command_buffer::allocator::StandardCommandBufferAllocator,
|
||||||
device::{
|
device::{
|
||||||
@ -38,6 +38,7 @@ use vulkano::{
|
|||||||
},
|
},
|
||||||
image::{view::ImageView, ImageUsage},
|
image::{view::ImageView, ImageUsage},
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
swapchain::{
|
swapchain::{
|
||||||
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
|
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
|
||||||
SwapchainPresentInfo,
|
SwapchainPresentInfo,
|
||||||
@ -164,17 +165,20 @@ fn main() {
|
|||||||
(swapchain, images)
|
(swapchain, images)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone()));
|
||||||
let command_buffer_allocator = Rc::new(StandardCommandBufferAllocator::new(device.clone()));
|
let command_buffer_allocator = Rc::new(StandardCommandBufferAllocator::new(device.clone()));
|
||||||
|
|
||||||
// Here is the basic initialization for the deferred system.
|
// Here is the basic initialization for the deferred system.
|
||||||
let mut frame_system = FrameSystem::new(
|
let mut frame_system = FrameSystem::new(
|
||||||
queue.clone(),
|
queue.clone(),
|
||||||
swapchain.image_format(),
|
swapchain.image_format(),
|
||||||
|
memory_allocator.clone(),
|
||||||
command_buffer_allocator.clone(),
|
command_buffer_allocator.clone(),
|
||||||
);
|
);
|
||||||
let triangle_draw_system = TriangleDrawSystem::new(
|
let triangle_draw_system = TriangleDrawSystem::new(
|
||||||
queue.clone(),
|
queue.clone(),
|
||||||
frame_system.deferred_subpass(),
|
frame_system.deferred_subpass(),
|
||||||
|
&memory_allocator,
|
||||||
command_buffer_allocator,
|
command_buffer_allocator,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ use vulkano::{
|
|||||||
},
|
},
|
||||||
device::Queue,
|
device::Queue,
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
depth_stencil::DepthStencilState,
|
depth_stencil::DepthStencilState,
|
||||||
@ -42,6 +43,7 @@ impl TriangleDrawSystem {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
gfx_queue: Arc<Queue>,
|
gfx_queue: Arc<Queue>,
|
||||||
subpass: Subpass,
|
subpass: Subpass,
|
||||||
|
memory_allocator: &StandardMemoryAllocator,
|
||||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||||
) -> TriangleDrawSystem {
|
) -> TriangleDrawSystem {
|
||||||
let vertices = [
|
let vertices = [
|
||||||
@ -57,7 +59,7 @@ impl TriangleDrawSystem {
|
|||||||
];
|
];
|
||||||
let vertex_buffer = {
|
let vertex_buffer = {
|
||||||
CpuAccessibleBuffer::from_iter(
|
CpuAccessibleBuffer::from_iter(
|
||||||
gfx_queue.device().clone(),
|
memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -28,6 +28,7 @@ use vulkano::{
|
|||||||
physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
|
physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
|
||||||
},
|
},
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
||||||
sync::{self, GpuFuture},
|
sync::{self, GpuFuture},
|
||||||
VulkanLibrary,
|
VulkanLibrary,
|
||||||
@ -131,6 +132,7 @@ fn main() {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
|
let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
|
||||||
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
||||||
|
|
||||||
@ -164,7 +166,7 @@ fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let input_buffer = CpuAccessibleBuffer::from_iter(
|
let input_buffer = CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
uniform_buffer: true,
|
uniform_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -175,7 +177,7 @@ fn main() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let output_buffer = CpuAccessibleBuffer::from_iter(
|
let output_buffer = CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
storage_buffer: true,
|
storage_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -30,6 +30,7 @@ use vulkano::{
|
|||||||
format::Format,
|
format::Format,
|
||||||
image::{view::ImageView, ImageDimensions, StorageImage},
|
image::{view::ImageView, ImageDimensions, StorageImage},
|
||||||
instance::{Instance, InstanceCreateInfo, InstanceExtensions},
|
instance::{Instance, InstanceCreateInfo, InstanceExtensions},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
||||||
sync::{self, GpuFuture},
|
sync::{self, GpuFuture},
|
||||||
VulkanLibrary,
|
VulkanLibrary,
|
||||||
@ -198,11 +199,12 @@ fn main() {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
|
let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
|
||||||
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
||||||
|
|
||||||
let image = StorageImage::new(
|
let image = StorageImage::new(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
ImageDimensions::Dim2d {
|
ImageDimensions::Dim2d {
|
||||||
width: 1024,
|
width: 1024,
|
||||||
height: 1024,
|
height: 1024,
|
||||||
@ -223,7 +225,7 @@ fn main() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let buf = CpuAccessibleBuffer::from_iter(
|
let buf = CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_dst: true,
|
transfer_dst: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -35,6 +35,7 @@ mod linux {
|
|||||||
debug::{DebugUtilsMessenger, DebugUtilsMessengerCreateInfo},
|
debug::{DebugUtilsMessenger, DebugUtilsMessengerCreateInfo},
|
||||||
Instance, InstanceCreateInfo, InstanceExtensions,
|
Instance, InstanceCreateInfo, InstanceExtensions,
|
||||||
},
|
},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
color_blend::ColorBlendState,
|
color_blend::ColorBlendState,
|
||||||
@ -94,11 +95,12 @@ mod linux {
|
|||||||
mut framebuffers,
|
mut framebuffers,
|
||||||
sampler,
|
sampler,
|
||||||
pipeline,
|
pipeline,
|
||||||
|
memory_allocator,
|
||||||
vertex_buffer,
|
vertex_buffer,
|
||||||
) = vk_setup(display, &event_loop);
|
) = vk_setup(display, &event_loop);
|
||||||
|
|
||||||
let image = StorageImage::new_with_exportable_fd(
|
let image = StorageImage::new_with_exportable_fd(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
vulkano::image::ImageDimensions::Dim2d {
|
vulkano::image::ImageDimensions::Dim2d {
|
||||||
width: 200,
|
width: 200,
|
||||||
height: 200,
|
height: 200,
|
||||||
@ -416,6 +418,7 @@ mod linux {
|
|||||||
Vec<Arc<Framebuffer>>,
|
Vec<Arc<Framebuffer>>,
|
||||||
Arc<vulkano::sampler::Sampler>,
|
Arc<vulkano::sampler::Sampler>,
|
||||||
Arc<GraphicsPipeline>,
|
Arc<GraphicsPipeline>,
|
||||||
|
StandardMemoryAllocator,
|
||||||
Arc<CpuAccessibleBuffer<[Vertex]>>,
|
Arc<CpuAccessibleBuffer<[Vertex]>>,
|
||||||
) {
|
) {
|
||||||
let library = VulkanLibrary::new().unwrap();
|
let library = VulkanLibrary::new().unwrap();
|
||||||
@ -561,6 +564,8 @@ mod linux {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
|
|
||||||
let vertices = [
|
let vertices = [
|
||||||
Vertex {
|
Vertex {
|
||||||
position: [-0.5, -0.5],
|
position: [-0.5, -0.5],
|
||||||
@ -576,7 +581,7 @@ mod linux {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -652,6 +657,7 @@ mod linux {
|
|||||||
framebuffers,
|
framebuffers,
|
||||||
sampler,
|
sampler,
|
||||||
pipeline,
|
pipeline,
|
||||||
|
memory_allocator,
|
||||||
vertex_buffer,
|
vertex_buffer,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ use vulkano::{
|
|||||||
},
|
},
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
color_blend::ColorBlendState,
|
color_blend::ColorBlendState,
|
||||||
@ -160,6 +161,8 @@ fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
@ -182,7 +185,7 @@ fn main() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -237,7 +240,7 @@ fn main() {
|
|||||||
reader.next_frame(&mut image_data).unwrap();
|
reader.next_frame(&mut image_data).unwrap();
|
||||||
|
|
||||||
let image = StorageImage::new(
|
let image = StorageImage::new(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
dimensions,
|
dimensions,
|
||||||
Format::R8G8B8A8_UNORM,
|
Format::R8G8B8A8_UNORM,
|
||||||
[queue.queue_family_index()],
|
[queue.queue_family_index()],
|
||||||
@ -245,7 +248,7 @@ fn main() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let buffer = CpuAccessibleBuffer::from_iter(
|
let buffer = CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_src: true,
|
transfer_src: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -28,6 +28,7 @@ use vulkano::{
|
|||||||
},
|
},
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
color_blend::ColorBlendState,
|
color_blend::ColorBlendState,
|
||||||
@ -158,6 +159,8 @@ fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
@ -180,7 +183,7 @@ fn main() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -234,6 +237,7 @@ fn main() {
|
|||||||
reader.next_frame(&mut image_data).unwrap();
|
reader.next_frame(&mut image_data).unwrap();
|
||||||
|
|
||||||
let image = ImmutableImage::from_iter(
|
let image = ImmutableImage::from_iter(
|
||||||
|
&memory_allocator,
|
||||||
image_data,
|
image_data,
|
||||||
dimensions,
|
dimensions,
|
||||||
MipmapsCount::One,
|
MipmapsCount::One,
|
||||||
|
@ -37,6 +37,7 @@ use vulkano::{
|
|||||||
},
|
},
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
color_blend::ColorBlendState,
|
color_blend::ColorBlendState,
|
||||||
@ -164,6 +165,8 @@ fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
@ -186,7 +189,7 @@ fn main() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -240,6 +243,7 @@ fn main() {
|
|||||||
reader.next_frame(&mut image_data).unwrap();
|
reader.next_frame(&mut image_data).unwrap();
|
||||||
|
|
||||||
let image = ImmutableImage::from_iter(
|
let image = ImmutableImage::from_iter(
|
||||||
|
&memory_allocator,
|
||||||
image_data,
|
image_data,
|
||||||
dimensions,
|
dimensions,
|
||||||
MipmapsCount::One,
|
MipmapsCount::One,
|
||||||
|
@ -41,6 +41,7 @@ use vulkano::{
|
|||||||
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
|
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::{MemoryUsage, StandardMemoryAllocator},
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
input_assembly::InputAssemblyState,
|
input_assembly::InputAssemblyState,
|
||||||
@ -254,23 +255,27 @@ fn main() {
|
|||||||
let fs = fs::load(device.clone()).unwrap();
|
let fs = fs::load(device.clone()).unwrap();
|
||||||
let cs = cs::load(device.clone()).unwrap();
|
let cs = cs::load(device.clone()).unwrap();
|
||||||
|
|
||||||
|
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone()));
|
||||||
|
|
||||||
// Each frame we generate a new set of vertices and each frame we need a new DrawIndirectCommand struct to
|
// Each frame we generate a new set of vertices and each frame we need a new DrawIndirectCommand struct to
|
||||||
// set the number of vertices to draw
|
// set the number of vertices to draw
|
||||||
let indirect_args_pool: CpuBufferPool<DrawIndirectCommand> = CpuBufferPool::new(
|
let indirect_args_pool: CpuBufferPool<DrawIndirectCommand> = CpuBufferPool::new(
|
||||||
device.clone(),
|
memory_allocator.clone(),
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
indirect_buffer: true,
|
indirect_buffer: true,
|
||||||
storage_buffer: true,
|
storage_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
},
|
},
|
||||||
|
MemoryUsage::Upload,
|
||||||
);
|
);
|
||||||
let vertex_pool: CpuBufferPool<Vertex> = CpuBufferPool::new(
|
let vertex_pool: CpuBufferPool<Vertex> = CpuBufferPool::new(
|
||||||
device.clone(),
|
memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
storage_buffer: true,
|
storage_buffer: true,
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
},
|
},
|
||||||
|
MemoryUsage::Upload,
|
||||||
);
|
);
|
||||||
|
|
||||||
let compute_pipeline = ComputePipeline::new(
|
let compute_pipeline = ComputePipeline::new(
|
||||||
|
@ -26,6 +26,7 @@ use vulkano::{
|
|||||||
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
|
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
input_assembly::InputAssemblyState,
|
input_assembly::InputAssemblyState,
|
||||||
@ -175,6 +176,8 @@ fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
|
|
||||||
// We now create a buffer that will store the shape of our triangle.
|
// We now create a buffer that will store the shape of our triangle.
|
||||||
// This triangle is identical to the one in the `triangle.rs` example.
|
// This triangle is identical to the one in the `triangle.rs` example.
|
||||||
let vertices = [
|
let vertices = [
|
||||||
@ -190,7 +193,7 @@ fn main() {
|
|||||||
];
|
];
|
||||||
let vertex_buffer = {
|
let vertex_buffer = {
|
||||||
CpuAccessibleBuffer::from_iter(
|
CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -225,7 +228,7 @@ fn main() {
|
|||||||
data
|
data
|
||||||
};
|
};
|
||||||
let instance_buffer = CpuAccessibleBuffer::from_iter(
|
let instance_buffer = CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -15,6 +15,7 @@ use std::{rc::Rc, sync::Arc};
|
|||||||
use vulkano::command_buffer::allocator::StandardCommandBufferAllocator;
|
use vulkano::command_buffer::allocator::StandardCommandBufferAllocator;
|
||||||
use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator;
|
use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator;
|
||||||
use vulkano::device::Queue;
|
use vulkano::device::Queue;
|
||||||
|
use vulkano::memory::allocator::StandardMemoryAllocator;
|
||||||
use vulkano::sync::GpuFuture;
|
use vulkano::sync::GpuFuture;
|
||||||
use vulkano_util::renderer::{DeviceImageView, VulkanoWindowRenderer};
|
use vulkano_util::renderer::{DeviceImageView, VulkanoWindowRenderer};
|
||||||
use vulkano_util::window::WindowDescriptor;
|
use vulkano_util::window::WindowDescriptor;
|
||||||
@ -60,6 +61,9 @@ pub struct FractalApp {
|
|||||||
|
|
||||||
impl FractalApp {
|
impl FractalApp {
|
||||||
pub fn new(gfx_queue: Arc<Queue>, image_format: vulkano::format::Format) -> FractalApp {
|
pub fn new(gfx_queue: Arc<Queue>, image_format: vulkano::format::Format) -> FractalApp {
|
||||||
|
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(
|
||||||
|
gfx_queue.device().clone(),
|
||||||
|
));
|
||||||
let command_buffer_allocator = Rc::new(StandardCommandBufferAllocator::new(
|
let command_buffer_allocator = Rc::new(StandardCommandBufferAllocator::new(
|
||||||
gfx_queue.device().clone(),
|
gfx_queue.device().clone(),
|
||||||
));
|
));
|
||||||
@ -70,11 +74,13 @@ impl FractalApp {
|
|||||||
FractalApp {
|
FractalApp {
|
||||||
fractal_pipeline: FractalComputePipeline::new(
|
fractal_pipeline: FractalComputePipeline::new(
|
||||||
gfx_queue.clone(),
|
gfx_queue.clone(),
|
||||||
|
memory_allocator.clone(),
|
||||||
command_buffer_allocator.clone(),
|
command_buffer_allocator.clone(),
|
||||||
descriptor_set_allocator.clone(),
|
descriptor_set_allocator.clone(),
|
||||||
),
|
),
|
||||||
place_over_frame: RenderPassPlaceOverFrame::new(
|
place_over_frame: RenderPassPlaceOverFrame::new(
|
||||||
gfx_queue,
|
gfx_queue,
|
||||||
|
&*memory_allocator,
|
||||||
command_buffer_allocator,
|
command_buffer_allocator,
|
||||||
descriptor_set_allocator,
|
descriptor_set_allocator,
|
||||||
image_format,
|
image_format,
|
||||||
|
@ -21,6 +21,7 @@ use vulkano::{
|
|||||||
},
|
},
|
||||||
device::Queue,
|
device::Queue,
|
||||||
image::ImageAccess,
|
image::ImageAccess,
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
||||||
sync::GpuFuture,
|
sync::GpuFuture,
|
||||||
};
|
};
|
||||||
@ -29,6 +30,7 @@ use vulkano_util::renderer::DeviceImageView;
|
|||||||
pub struct FractalComputePipeline {
|
pub struct FractalComputePipeline {
|
||||||
queue: Arc<Queue>,
|
queue: Arc<Queue>,
|
||||||
pipeline: Arc<ComputePipeline>,
|
pipeline: Arc<ComputePipeline>,
|
||||||
|
memory_allocator: Arc<StandardMemoryAllocator>,
|
||||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||||
palette: Arc<CpuAccessibleBuffer<[[f32; 4]]>>,
|
palette: Arc<CpuAccessibleBuffer<[[f32; 4]]>>,
|
||||||
@ -39,6 +41,7 @@ pub struct FractalComputePipeline {
|
|||||||
impl FractalComputePipeline {
|
impl FractalComputePipeline {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
queue: Arc<Queue>,
|
queue: Arc<Queue>,
|
||||||
|
memory_allocator: Arc<StandardMemoryAllocator>,
|
||||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||||
) -> FractalComputePipeline {
|
) -> FractalComputePipeline {
|
||||||
@ -53,7 +56,7 @@ impl FractalComputePipeline {
|
|||||||
];
|
];
|
||||||
let palette_size = colors.len() as i32;
|
let palette_size = colors.len() as i32;
|
||||||
let palette = CpuAccessibleBuffer::from_iter(
|
let palette = CpuAccessibleBuffer::from_iter(
|
||||||
queue.device().clone(),
|
&*memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
storage_buffer: true,
|
storage_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -79,6 +82,7 @@ impl FractalComputePipeline {
|
|||||||
FractalComputePipeline {
|
FractalComputePipeline {
|
||||||
queue,
|
queue,
|
||||||
pipeline,
|
pipeline,
|
||||||
|
memory_allocator,
|
||||||
command_buffer_allocator,
|
command_buffer_allocator,
|
||||||
descriptor_set_allocator,
|
descriptor_set_allocator,
|
||||||
palette,
|
palette,
|
||||||
@ -98,7 +102,7 @@ impl FractalComputePipeline {
|
|||||||
colors.push([r, g, b, a]);
|
colors.push([r, g, b, a]);
|
||||||
}
|
}
|
||||||
self.palette = CpuAccessibleBuffer::from_iter(
|
self.palette = CpuAccessibleBuffer::from_iter(
|
||||||
self.queue.device().clone(),
|
&*self.memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
storage_buffer: true,
|
storage_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -21,6 +21,7 @@ use vulkano::{
|
|||||||
device::Queue,
|
device::Queue,
|
||||||
image::ImageViewAbstract,
|
image::ImageViewAbstract,
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
|
memory::allocator::MemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
input_assembly::InputAssemblyState,
|
input_assembly::InputAssemblyState,
|
||||||
@ -81,12 +82,13 @@ impl PixelsDrawPipeline {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
gfx_queue: Arc<Queue>,
|
gfx_queue: Arc<Queue>,
|
||||||
subpass: Subpass,
|
subpass: Subpass,
|
||||||
|
memory_allocator: &impl MemoryAllocator,
|
||||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||||
) -> PixelsDrawPipeline {
|
) -> PixelsDrawPipeline {
|
||||||
let (vertices, indices) = textured_quad(2.0, 2.0);
|
let (vertices, indices) = textured_quad(2.0, 2.0);
|
||||||
let vertex_buffer = CpuAccessibleBuffer::<[TexturedVertex]>::from_iter(
|
let vertex_buffer = CpuAccessibleBuffer::<[TexturedVertex]>::from_iter(
|
||||||
gfx_queue.device().clone(),
|
memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -96,7 +98,7 @@ impl PixelsDrawPipeline {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let index_buffer = CpuAccessibleBuffer::<[u32]>::from_iter(
|
let index_buffer = CpuAccessibleBuffer::<[u32]>::from_iter(
|
||||||
gfx_queue.device().clone(),
|
memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
index_buffer: true,
|
index_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -18,6 +18,7 @@ use vulkano::{
|
|||||||
device::Queue,
|
device::Queue,
|
||||||
format::Format,
|
format::Format,
|
||||||
image::ImageAccess,
|
image::ImageAccess,
|
||||||
|
memory::allocator::MemoryAllocator,
|
||||||
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
||||||
sync::GpuFuture,
|
sync::GpuFuture,
|
||||||
};
|
};
|
||||||
@ -34,6 +35,7 @@ pub struct RenderPassPlaceOverFrame {
|
|||||||
impl RenderPassPlaceOverFrame {
|
impl RenderPassPlaceOverFrame {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
gfx_queue: Arc<Queue>,
|
gfx_queue: Arc<Queue>,
|
||||||
|
memory_allocator: &impl MemoryAllocator,
|
||||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||||
output_format: Format,
|
output_format: Format,
|
||||||
@ -57,6 +59,7 @@ impl RenderPassPlaceOverFrame {
|
|||||||
let pixels_draw_pipeline = PixelsDrawPipeline::new(
|
let pixels_draw_pipeline = PixelsDrawPipeline::new(
|
||||||
gfx_queue.clone(),
|
gfx_queue.clone(),
|
||||||
subpass,
|
subpass,
|
||||||
|
memory_allocator,
|
||||||
command_buffer_allocator.clone(),
|
command_buffer_allocator.clone(),
|
||||||
descriptor_set_allocator,
|
descriptor_set_allocator,
|
||||||
);
|
);
|
||||||
|
@ -79,6 +79,7 @@ use vulkano::{
|
|||||||
image::{view::ImageView, AttachmentImage, ImageDimensions, SampleCount, StorageImage},
|
image::{view::ImageView, AttachmentImage, ImageDimensions, SampleCount, StorageImage},
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
multisample::MultisampleState,
|
multisample::MultisampleState,
|
||||||
@ -151,13 +152,15 @@ fn main() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let queue = queues.next().unwrap();
|
let queue = queues.next().unwrap();
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
|
|
||||||
// Creating our intermediate multisampled image.
|
// Creating our intermediate multisampled image.
|
||||||
//
|
//
|
||||||
// As explained in the introduction, we pass the same dimensions and format as for the final
|
// As explained in the introduction, we pass the same dimensions and format as for the final
|
||||||
// image. But we also pass the number of samples-per-pixel, which is 4 here.
|
// image. But we also pass the number of samples-per-pixel, which is 4 here.
|
||||||
let intermediary = ImageView::new_default(
|
let intermediary = ImageView::new_default(
|
||||||
AttachmentImage::transient_multisampled(
|
AttachmentImage::transient_multisampled(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
[1024, 1024],
|
[1024, 1024],
|
||||||
SampleCount::Sample4,
|
SampleCount::Sample4,
|
||||||
Format::R8G8B8A8_UNORM,
|
Format::R8G8B8A8_UNORM,
|
||||||
@ -168,7 +171,7 @@ fn main() {
|
|||||||
|
|
||||||
// This is the final image that will receive the anti-aliased triangle.
|
// This is the final image that will receive the anti-aliased triangle.
|
||||||
let image = StorageImage::new(
|
let image = StorageImage::new(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
ImageDimensions::Dim2d {
|
ImageDimensions::Dim2d {
|
||||||
width: 1024,
|
width: 1024,
|
||||||
height: 1024,
|
height: 1024,
|
||||||
@ -284,7 +287,7 @@ fn main() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -314,10 +317,10 @@ fn main() {
|
|||||||
depth_range: 0.0..1.0,
|
depth_range: 0.0..1.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
let command_buffer_allocator = StandardCommandBufferAllocator::new(device);
|
||||||
|
|
||||||
let buf = CpuAccessibleBuffer::from_iter(
|
let buf = CpuAccessibleBuffer::from_iter(
|
||||||
device,
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_dst: true,
|
transfer_dst: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -30,6 +30,7 @@ use vulkano::{
|
|||||||
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
|
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
input_assembly::InputAssemblyState,
|
input_assembly::InputAssemblyState,
|
||||||
@ -180,6 +181,8 @@ fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
@ -199,7 +202,7 @@ fn main() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -14,6 +14,7 @@ use crate::{
|
|||||||
use std::{collections::HashMap, rc::Rc, sync::Arc};
|
use std::{collections::HashMap, rc::Rc, sync::Arc};
|
||||||
use vulkano::command_buffer::allocator::StandardCommandBufferAllocator;
|
use vulkano::command_buffer::allocator::StandardCommandBufferAllocator;
|
||||||
use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator;
|
use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator;
|
||||||
|
use vulkano::memory::allocator::StandardMemoryAllocator;
|
||||||
use vulkano::{device::Queue, format::Format};
|
use vulkano::{device::Queue, format::Format};
|
||||||
use vulkano_util::context::{VulkanoConfig, VulkanoContext};
|
use vulkano_util::context::{VulkanoConfig, VulkanoContext};
|
||||||
use vulkano_util::window::{VulkanoWindows, WindowDescriptor};
|
use vulkano_util::window::{VulkanoWindows, WindowDescriptor};
|
||||||
@ -31,6 +32,7 @@ impl RenderPipeline {
|
|||||||
size: [u32; 2],
|
size: [u32; 2],
|
||||||
swapchain_format: Format,
|
swapchain_format: Format,
|
||||||
) -> RenderPipeline {
|
) -> RenderPipeline {
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(gfx_queue.device().clone());
|
||||||
let command_buffer_allocator = Rc::new(StandardCommandBufferAllocator::new(
|
let command_buffer_allocator = Rc::new(StandardCommandBufferAllocator::new(
|
||||||
gfx_queue.device().clone(),
|
gfx_queue.device().clone(),
|
||||||
));
|
));
|
||||||
@ -41,12 +43,14 @@ impl RenderPipeline {
|
|||||||
RenderPipeline {
|
RenderPipeline {
|
||||||
compute: GameOfLifeComputePipeline::new(
|
compute: GameOfLifeComputePipeline::new(
|
||||||
compute_queue,
|
compute_queue,
|
||||||
|
&memory_allocator,
|
||||||
command_buffer_allocator.clone(),
|
command_buffer_allocator.clone(),
|
||||||
descriptor_set_allocator.clone(),
|
descriptor_set_allocator.clone(),
|
||||||
size,
|
size,
|
||||||
),
|
),
|
||||||
place_over_frame: RenderPassPlaceOverFrame::new(
|
place_over_frame: RenderPassPlaceOverFrame::new(
|
||||||
gfx_queue,
|
gfx_queue,
|
||||||
|
&memory_allocator,
|
||||||
command_buffer_allocator,
|
command_buffer_allocator,
|
||||||
descriptor_set_allocator,
|
descriptor_set_allocator,
|
||||||
swapchain_format,
|
swapchain_format,
|
||||||
|
@ -13,6 +13,7 @@ use std::{rc::Rc, sync::Arc};
|
|||||||
use vulkano::command_buffer::allocator::StandardCommandBufferAllocator;
|
use vulkano::command_buffer::allocator::StandardCommandBufferAllocator;
|
||||||
use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator;
|
use vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator;
|
||||||
use vulkano::image::{ImageUsage, StorageImage};
|
use vulkano::image::{ImageUsage, StorageImage};
|
||||||
|
use vulkano::memory::allocator::MemoryAllocator;
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
buffer::{BufferUsage, CpuAccessibleBuffer},
|
buffer::{BufferUsage, CpuAccessibleBuffer},
|
||||||
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, PrimaryAutoCommandBuffer},
|
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, PrimaryAutoCommandBuffer},
|
||||||
@ -40,9 +41,12 @@ pub struct GameOfLifeComputePipeline {
|
|||||||
image: DeviceImageView,
|
image: DeviceImageView,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rand_grid(compute_queue: &Arc<Queue>, size: [u32; 2]) -> Arc<CpuAccessibleBuffer<[u32]>> {
|
fn rand_grid(
|
||||||
|
memory_allocator: &impl MemoryAllocator,
|
||||||
|
size: [u32; 2],
|
||||||
|
) -> Arc<CpuAccessibleBuffer<[u32]>> {
|
||||||
CpuAccessibleBuffer::from_iter(
|
CpuAccessibleBuffer::from_iter(
|
||||||
compute_queue.device().clone(),
|
memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
storage_buffer: true,
|
storage_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -58,12 +62,13 @@ fn rand_grid(compute_queue: &Arc<Queue>, size: [u32; 2]) -> Arc<CpuAccessibleBuf
|
|||||||
impl GameOfLifeComputePipeline {
|
impl GameOfLifeComputePipeline {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
compute_queue: Arc<Queue>,
|
compute_queue: Arc<Queue>,
|
||||||
|
memory_allocator: &impl MemoryAllocator,
|
||||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||||
size: [u32; 2],
|
size: [u32; 2],
|
||||||
) -> GameOfLifeComputePipeline {
|
) -> GameOfLifeComputePipeline {
|
||||||
let life_in = rand_grid(&compute_queue, size);
|
let life_in = rand_grid(memory_allocator, size);
|
||||||
let life_out = rand_grid(&compute_queue, size);
|
let life_out = rand_grid(memory_allocator, size);
|
||||||
|
|
||||||
let compute_life_pipeline = {
|
let compute_life_pipeline = {
|
||||||
let shader = compute_life_cs::load(compute_queue.device().clone()).unwrap();
|
let shader = compute_life_cs::load(compute_queue.device().clone()).unwrap();
|
||||||
@ -78,6 +83,7 @@ impl GameOfLifeComputePipeline {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let image = StorageImage::general_purpose_image_view(
|
let image = StorageImage::general_purpose_image_view(
|
||||||
|
memory_allocator,
|
||||||
compute_queue.clone(),
|
compute_queue.clone(),
|
||||||
size,
|
size,
|
||||||
Format::R8G8B8A8_UNORM,
|
Format::R8G8B8A8_UNORM,
|
||||||
|
@ -21,6 +21,7 @@ use vulkano::{
|
|||||||
device::Queue,
|
device::Queue,
|
||||||
image::ImageViewAbstract,
|
image::ImageViewAbstract,
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
|
memory::allocator::MemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
input_assembly::InputAssemblyState,
|
input_assembly::InputAssemblyState,
|
||||||
@ -81,12 +82,13 @@ impl PixelsDrawPipeline {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
gfx_queue: Arc<Queue>,
|
gfx_queue: Arc<Queue>,
|
||||||
subpass: Subpass,
|
subpass: Subpass,
|
||||||
|
memory_allocator: &impl MemoryAllocator,
|
||||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||||
) -> PixelsDrawPipeline {
|
) -> PixelsDrawPipeline {
|
||||||
let (vertices, indices) = textured_quad(2.0, 2.0);
|
let (vertices, indices) = textured_quad(2.0, 2.0);
|
||||||
let vertex_buffer = CpuAccessibleBuffer::<[TexturedVertex]>::from_iter(
|
let vertex_buffer = CpuAccessibleBuffer::<[TexturedVertex]>::from_iter(
|
||||||
gfx_queue.device().clone(),
|
memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -96,7 +98,7 @@ impl PixelsDrawPipeline {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let index_buffer = CpuAccessibleBuffer::<[u32]>::from_iter(
|
let index_buffer = CpuAccessibleBuffer::<[u32]>::from_iter(
|
||||||
gfx_queue.device().clone(),
|
memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
index_buffer: true,
|
index_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -18,6 +18,7 @@ use vulkano::{
|
|||||||
device::Queue,
|
device::Queue,
|
||||||
format::Format,
|
format::Format,
|
||||||
image::ImageAccess,
|
image::ImageAccess,
|
||||||
|
memory::allocator::MemoryAllocator,
|
||||||
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
||||||
sync::GpuFuture,
|
sync::GpuFuture,
|
||||||
};
|
};
|
||||||
@ -34,6 +35,7 @@ pub struct RenderPassPlaceOverFrame {
|
|||||||
impl RenderPassPlaceOverFrame {
|
impl RenderPassPlaceOverFrame {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
gfx_queue: Arc<Queue>,
|
gfx_queue: Arc<Queue>,
|
||||||
|
memory_allocator: &impl MemoryAllocator,
|
||||||
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
command_buffer_allocator: Rc<StandardCommandBufferAllocator>,
|
||||||
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
descriptor_set_allocator: Rc<StandardDescriptorSetAllocator>,
|
||||||
output_format: Format,
|
output_format: Format,
|
||||||
@ -57,6 +59,7 @@ impl RenderPassPlaceOverFrame {
|
|||||||
let pixels_draw_pipeline = PixelsDrawPipeline::new(
|
let pixels_draw_pipeline = PixelsDrawPipeline::new(
|
||||||
gfx_queue.clone(),
|
gfx_queue.clone(),
|
||||||
subpass,
|
subpass,
|
||||||
|
memory_allocator,
|
||||||
command_buffer_allocator.clone(),
|
command_buffer_allocator.clone(),
|
||||||
descriptor_set_allocator,
|
descriptor_set_allocator,
|
||||||
);
|
);
|
||||||
|
@ -32,6 +32,7 @@ use vulkano::{
|
|||||||
},
|
},
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
instance::{Instance, InstanceCreateInfo, InstanceExtensions},
|
instance::{Instance, InstanceCreateInfo, InstanceExtensions},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
input_assembly::InputAssemblyState,
|
input_assembly::InputAssemblyState,
|
||||||
@ -129,8 +130,10 @@ fn main() {
|
|||||||
|
|
||||||
let queue = queues.next().unwrap();
|
let queue = queues.next().unwrap();
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
|
|
||||||
let image = StorageImage::with_usage(
|
let image = StorageImage::with_usage(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
ImageDimensions::Dim2d {
|
ImageDimensions::Dim2d {
|
||||||
width: 512,
|
width: 512,
|
||||||
height: 512,
|
height: 512,
|
||||||
@ -168,7 +171,7 @@ fn main() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -281,7 +284,7 @@ fn main() {
|
|||||||
|
|
||||||
let create_buffer = || {
|
let create_buffer = || {
|
||||||
CpuAccessibleBuffer::from_iter(
|
CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_dst: true,
|
transfer_dst: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -351,7 +354,7 @@ fn main() {
|
|||||||
|
|
||||||
let command_buffer = builder.build().unwrap();
|
let command_buffer = builder.build().unwrap();
|
||||||
|
|
||||||
let future = sync::now(device.clone())
|
let future = sync::now(device)
|
||||||
.then_execute(queue, command_buffer)
|
.then_execute(queue, command_buffer)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.then_signal_fence_and_flush()
|
.then_signal_fence_and_flush()
|
||||||
|
@ -20,13 +20,13 @@ use vulkano::{
|
|||||||
RenderPassBeginInfo, SubpassContents,
|
RenderPassBeginInfo, SubpassContents,
|
||||||
},
|
},
|
||||||
device::{
|
device::{
|
||||||
physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, DeviceOwned,
|
physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
|
||||||
QueueCreateInfo,
|
|
||||||
},
|
},
|
||||||
format::Format,
|
format::Format,
|
||||||
image::{view::ImageView, AttachmentImage, ImageAccess, ImageUsage, SwapchainImage},
|
image::{view::ImageView, AttachmentImage, ImageAccess, ImageUsage, SwapchainImage},
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
depth_stencil::DepthStencilState,
|
depth_stencil::DepthStencilState,
|
||||||
@ -154,6 +154,8 @@ fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
@ -209,7 +211,7 @@ fn main() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -325,7 +327,12 @@ fn main() {
|
|||||||
|
|
||||||
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
||||||
|
|
||||||
let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport);
|
let mut framebuffers = window_size_dependent_setup(
|
||||||
|
&images,
|
||||||
|
render_pass.clone(),
|
||||||
|
&mut viewport,
|
||||||
|
&memory_allocator,
|
||||||
|
);
|
||||||
|
|
||||||
let mut recreate_swapchain = false;
|
let mut recreate_swapchain = false;
|
||||||
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
|
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
@ -363,8 +370,12 @@ fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
swapchain = new_swapchain;
|
swapchain = new_swapchain;
|
||||||
framebuffers =
|
framebuffers = window_size_dependent_setup(
|
||||||
window_size_dependent_setup(&new_images, render_pass.clone(), &mut viewport);
|
&new_images,
|
||||||
|
render_pass.clone(),
|
||||||
|
&mut viewport,
|
||||||
|
&memory_allocator,
|
||||||
|
);
|
||||||
recreate_swapchain = false;
|
recreate_swapchain = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -542,13 +553,14 @@ fn window_size_dependent_setup(
|
|||||||
images: &[Arc<SwapchainImage>],
|
images: &[Arc<SwapchainImage>],
|
||||||
render_pass: Arc<RenderPass>,
|
render_pass: Arc<RenderPass>,
|
||||||
viewport: &mut Viewport,
|
viewport: &mut Viewport,
|
||||||
|
memory_allocator: &StandardMemoryAllocator,
|
||||||
) -> Vec<Arc<Framebuffer>> {
|
) -> Vec<Arc<Framebuffer>> {
|
||||||
let dimensions = images[0].dimensions().width_height();
|
let dimensions = images[0].dimensions().width_height();
|
||||||
viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32];
|
viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32];
|
||||||
|
|
||||||
let depth_attachment = ImageView::new_default(
|
let depth_attachment = ImageView::new_default(
|
||||||
AttachmentImage::with_usage(
|
AttachmentImage::with_usage(
|
||||||
render_pass.device().clone(),
|
memory_allocator,
|
||||||
dimensions,
|
dimensions,
|
||||||
Format::D16_UNORM,
|
Format::D16_UNORM,
|
||||||
ImageUsage {
|
ImageUsage {
|
||||||
|
@ -24,6 +24,7 @@ use vulkano::{
|
|||||||
physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
|
physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
|
||||||
},
|
},
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
||||||
sync::{self, GpuFuture},
|
sync::{self, GpuFuture},
|
||||||
VulkanLibrary,
|
VulkanLibrary,
|
||||||
@ -129,13 +130,14 @@ fn main() {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
|
let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
|
||||||
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
||||||
|
|
||||||
let data_buffer = {
|
let data_buffer = {
|
||||||
let data_iter = 0..65536u32;
|
let data_iter = 0..65536u32;
|
||||||
CpuAccessibleBuffer::from_iter(
|
CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
storage_buffer: true,
|
storage_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -26,6 +26,7 @@ use vulkano::{
|
|||||||
},
|
},
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
color_blend::ColorBlendState,
|
color_blend::ColorBlendState,
|
||||||
@ -154,6 +155,8 @@ fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
@ -176,7 +179,7 @@ fn main() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -229,6 +232,7 @@ fn main() {
|
|||||||
reader.next_frame(&mut image_data).unwrap();
|
reader.next_frame(&mut image_data).unwrap();
|
||||||
|
|
||||||
let image = ImmutableImage::from_iter(
|
let image = ImmutableImage::from_iter(
|
||||||
|
&memory_allocator,
|
||||||
image_data,
|
image_data,
|
||||||
dimensions,
|
dimensions,
|
||||||
MipmapsCount::One,
|
MipmapsCount::One,
|
||||||
|
@ -33,6 +33,7 @@ use vulkano::{
|
|||||||
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
|
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
input_assembly::InputAssemblyState,
|
input_assembly::InputAssemblyState,
|
||||||
@ -221,6 +222,8 @@ fn main() {
|
|||||||
|
|
||||||
let mut recreate_swapchain = false;
|
let mut recreate_swapchain = false;
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
|
|
||||||
let vertices = [
|
let vertices = [
|
||||||
Vertex {
|
Vertex {
|
||||||
position: [-1.0, 1.0],
|
position: [-1.0, 1.0],
|
||||||
@ -236,7 +239,7 @@ fn main() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -33,6 +33,7 @@ use vulkano::{
|
|||||||
},
|
},
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
color_blend::ColorBlendState,
|
color_blend::ColorBlendState,
|
||||||
@ -170,6 +171,8 @@ fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
@ -242,7 +245,7 @@ fn main() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -296,6 +299,7 @@ fn main() {
|
|||||||
reader.next_frame(&mut image_data).unwrap();
|
reader.next_frame(&mut image_data).unwrap();
|
||||||
|
|
||||||
let image = ImmutableImage::from_iter(
|
let image = ImmutableImage::from_iter(
|
||||||
|
&memory_allocator,
|
||||||
image_data,
|
image_data,
|
||||||
dimensions,
|
dimensions,
|
||||||
MipmapsCount::One,
|
MipmapsCount::One,
|
||||||
@ -323,6 +327,7 @@ fn main() {
|
|||||||
reader.next_frame(&mut image_data).unwrap();
|
reader.next_frame(&mut image_data).unwrap();
|
||||||
|
|
||||||
let image = ImmutableImage::from_iter(
|
let image = ImmutableImage::from_iter(
|
||||||
|
&memory_allocator,
|
||||||
image_data,
|
image_data,
|
||||||
dimensions,
|
dimensions,
|
||||||
MipmapsCount::One,
|
MipmapsCount::One,
|
||||||
|
@ -23,6 +23,7 @@ use vulkano::{
|
|||||||
physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
|
physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
|
||||||
},
|
},
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
||||||
sync::{self, GpuFuture},
|
sync::{self, GpuFuture},
|
||||||
VulkanLibrary,
|
VulkanLibrary,
|
||||||
@ -116,6 +117,7 @@ fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
|
let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
|
||||||
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
||||||
|
|
||||||
@ -123,7 +125,7 @@ fn main() {
|
|||||||
// we intitialize half of the array and leave the other half to 0, we will use copy later to fill it
|
// 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 });
|
let data_iter = (0..65536u32).map(|n| if n < 65536 / 2 { n } else { 0 });
|
||||||
CpuAccessibleBuffer::from_iter(
|
CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
storage_buffer: true,
|
storage_buffer: true,
|
||||||
transfer_src: true,
|
transfer_src: true,
|
||||||
|
@ -23,6 +23,7 @@ use vulkano::{
|
|||||||
physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
|
physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
|
||||||
},
|
},
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
||||||
sync::{self, GpuFuture},
|
sync::{self, GpuFuture},
|
||||||
VulkanLibrary,
|
VulkanLibrary,
|
||||||
@ -124,13 +125,14 @@ fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
|
let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
|
||||||
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
||||||
|
|
||||||
let data_buffer = {
|
let data_buffer = {
|
||||||
let data_iter = 0..65536u32;
|
let data_iter = 0..65536u32;
|
||||||
CpuAccessibleBuffer::from_iter(
|
CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
storage_buffer: true,
|
storage_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -41,6 +41,7 @@ use vulkano::{
|
|||||||
QueueCreateInfo,
|
QueueCreateInfo,
|
||||||
},
|
},
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
||||||
sync::{self, GpuFuture},
|
sync::{self, GpuFuture},
|
||||||
VulkanLibrary,
|
VulkanLibrary,
|
||||||
@ -237,6 +238,7 @@ fn main() {
|
|||||||
future.wait(None).unwrap();
|
future.wait(None).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
||||||
let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
|
let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
|
||||||
|
|
||||||
@ -244,7 +246,7 @@ fn main() {
|
|||||||
let data_buffer = {
|
let data_buffer = {
|
||||||
let data_iter = 0..65536u32;
|
let data_iter = 0..65536u32;
|
||||||
CpuAccessibleBuffer::from_iter(
|
CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
storage_buffer: true,
|
storage_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -30,6 +30,7 @@ use vulkano::{
|
|||||||
image::{view::ImageView, ImageUsage},
|
image::{view::ImageView, ImageUsage},
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
input_assembly::{InputAssemblyState, PrimitiveTopology},
|
input_assembly::{InputAssemblyState, PrimitiveTopology},
|
||||||
@ -317,6 +318,7 @@ fn main() {
|
|||||||
let vs = vs::load(device.clone()).unwrap();
|
let vs = vs::load(device.clone()).unwrap();
|
||||||
let fs = fs::load(device.clone()).unwrap();
|
let fs = fs::load(device.clone()).unwrap();
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
|
let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
|
||||||
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
||||||
|
|
||||||
@ -341,7 +343,7 @@ fn main() {
|
|||||||
|
|
||||||
// Create a CPU accessible buffer initialized with the vertex data.
|
// Create a CPU accessible buffer initialized with the vertex data.
|
||||||
let temporary_accessible_buffer = CpuAccessibleBuffer::from_iter(
|
let temporary_accessible_buffer = CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_src: true,
|
transfer_src: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -353,7 +355,7 @@ fn main() {
|
|||||||
|
|
||||||
// Create a buffer array on the GPU with enough space for `PARTICLE_COUNT` number of `Vertex`.
|
// Create a buffer array on the GPU with enough space for `PARTICLE_COUNT` number of `Vertex`.
|
||||||
let device_local_buffer = DeviceLocalBuffer::<[Vertex]>::array(
|
let device_local_buffer = DeviceLocalBuffer::<[Vertex]>::array(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
PARTICLE_COUNT as vulkano::DeviceSize,
|
PARTICLE_COUNT as vulkano::DeviceSize,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
storage_buffer: true,
|
storage_buffer: true,
|
||||||
|
@ -21,6 +21,7 @@ use vulkano::{
|
|||||||
physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
|
physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
|
||||||
},
|
},
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
||||||
sync::{self, GpuFuture},
|
sync::{self, GpuFuture},
|
||||||
VulkanLibrary,
|
VulkanLibrary,
|
||||||
@ -125,13 +126,14 @@ fn main() {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
|
let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
|
||||||
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
||||||
|
|
||||||
let data_buffer = {
|
let data_buffer = {
|
||||||
let data_iter = 0..65536u32;
|
let data_iter = 0..65536u32;
|
||||||
CpuAccessibleBuffer::from_iter(
|
CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
storage_buffer: true,
|
storage_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -20,11 +20,13 @@ use vulkano::{
|
|||||||
allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet,
|
allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet,
|
||||||
},
|
},
|
||||||
device::{
|
device::{
|
||||||
physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo,
|
physical::PhysicalDeviceType, Device, DeviceCreateInfo, DeviceExtensions, DeviceOwned,
|
||||||
|
QueueCreateInfo,
|
||||||
},
|
},
|
||||||
format::Format,
|
format::Format,
|
||||||
image::{view::ImageView, AttachmentImage, ImageAccess, ImageUsage, SwapchainImage},
|
image::{view::ImageView, AttachmentImage, ImageAccess, ImageUsage, SwapchainImage},
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::{MemoryUsage, StandardMemoryAllocator},
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
depth_stencil::DepthStencilState,
|
depth_stencil::DepthStencilState,
|
||||||
@ -156,8 +158,10 @@ fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone()));
|
||||||
|
|
||||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&*memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -167,7 +171,7 @@ fn main() {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let normals_buffer = CpuAccessibleBuffer::from_iter(
|
let normals_buffer = CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&*memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -177,7 +181,7 @@ fn main() {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let index_buffer = CpuAccessibleBuffer::from_iter(
|
let index_buffer = CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&*memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
index_buffer: true,
|
index_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -188,11 +192,12 @@ fn main() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let uniform_buffer = CpuBufferPool::<vs::ty::Data>::new(
|
let uniform_buffer = CpuBufferPool::<vs::ty::Data>::new(
|
||||||
device.clone(),
|
memory_allocator.clone(),
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
uniform_buffer: true,
|
uniform_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
},
|
},
|
||||||
|
MemoryUsage::Upload,
|
||||||
);
|
);
|
||||||
|
|
||||||
let vs = vs::load(device.clone()).unwrap();
|
let vs = vs::load(device.clone()).unwrap();
|
||||||
@ -221,7 +226,7 @@ fn main() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let (mut pipeline, mut framebuffers) =
|
let (mut pipeline, mut framebuffers) =
|
||||||
window_size_dependent_setup(device.clone(), &vs, &fs, &images, render_pass.clone());
|
window_size_dependent_setup(&memory_allocator, &vs, &fs, &images, render_pass.clone());
|
||||||
let mut recreate_swapchain = false;
|
let mut recreate_swapchain = false;
|
||||||
|
|
||||||
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
|
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||||
@ -266,7 +271,7 @@ fn main() {
|
|||||||
|
|
||||||
swapchain = new_swapchain;
|
swapchain = new_swapchain;
|
||||||
let (new_pipeline, new_framebuffers) = window_size_dependent_setup(
|
let (new_pipeline, new_framebuffers) = window_size_dependent_setup(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
&vs,
|
&vs,
|
||||||
&fs,
|
&fs,
|
||||||
&new_images,
|
&new_images,
|
||||||
@ -399,7 +404,7 @@ fn main() {
|
|||||||
|
|
||||||
/// This method is called once during initialization, then again whenever the window is resized
|
/// This method is called once during initialization, then again whenever the window is resized
|
||||||
fn window_size_dependent_setup(
|
fn window_size_dependent_setup(
|
||||||
device: Arc<Device>,
|
memory_allocator: &StandardMemoryAllocator,
|
||||||
vs: &ShaderModule,
|
vs: &ShaderModule,
|
||||||
fs: &ShaderModule,
|
fs: &ShaderModule,
|
||||||
images: &[Arc<SwapchainImage>],
|
images: &[Arc<SwapchainImage>],
|
||||||
@ -408,7 +413,7 @@ fn window_size_dependent_setup(
|
|||||||
let dimensions = images[0].dimensions().width_height();
|
let dimensions = images[0].dimensions().width_height();
|
||||||
|
|
||||||
let depth_buffer = ImageView::new_default(
|
let depth_buffer = ImageView::new_default(
|
||||||
AttachmentImage::transient(device.clone(), dimensions, Format::D16_UNORM).unwrap(),
|
AttachmentImage::transient(memory_allocator, dimensions, Format::D16_UNORM).unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -449,7 +454,7 @@ fn window_size_dependent_setup(
|
|||||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||||
.depth_stencil_state(DepthStencilState::simple_depth_test())
|
.depth_stencil_state(DepthStencilState::simple_depth_test())
|
||||||
.render_pass(Subpass::from(render_pass, 0).unwrap())
|
.render_pass(Subpass::from(render_pass, 0).unwrap())
|
||||||
.build(device)
|
.build(memory_allocator.device().clone())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
(pipeline, framebuffers)
|
(pipeline, framebuffers)
|
||||||
|
@ -33,6 +33,7 @@ use vulkano::{
|
|||||||
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
|
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
input_assembly::{InputAssemblyState, PrimitiveTopology},
|
input_assembly::{InputAssemblyState, PrimitiveTopology},
|
||||||
@ -262,6 +263,8 @@ fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
@ -299,7 +302,7 @@ fn main() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -28,6 +28,7 @@ use vulkano::{
|
|||||||
},
|
},
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
color_blend::ColorBlendState,
|
color_blend::ColorBlendState,
|
||||||
@ -160,6 +161,8 @@ fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
@ -182,7 +185,7 @@ fn main() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
let vertex_buffer = CpuAccessibleBuffer::<[Vertex]>::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -244,6 +247,7 @@ fn main() {
|
|||||||
array_layers: 3,
|
array_layers: 3,
|
||||||
}; // Replace with your actual image array dimensions
|
}; // Replace with your actual image array dimensions
|
||||||
let image = ImmutableImage::from_iter(
|
let image = ImmutableImage::from_iter(
|
||||||
|
&memory_allocator,
|
||||||
image_array_data,
|
image_array_data,
|
||||||
dimensions,
|
dimensions,
|
||||||
MipmapsCount::Log2,
|
MipmapsCount::Log2,
|
||||||
|
@ -36,6 +36,7 @@ use vulkano::{
|
|||||||
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
|
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
input_assembly::InputAssemblyState,
|
input_assembly::InputAssemblyState,
|
||||||
@ -279,6 +280,8 @@ fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
|
|
||||||
// We now create a buffer that will store the shape of our triangle.
|
// We now create a buffer that will store the shape of our triangle.
|
||||||
// We use #[repr(C)] here to force rustc to not do anything funky with our data, although for this
|
// We use #[repr(C)] here to force rustc to not do anything funky with our data, although for this
|
||||||
// particular example, it doesn't actually change the in-memory representation.
|
// particular example, it doesn't actually change the in-memory representation.
|
||||||
@ -301,7 +304,7 @@ fn main() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -30,6 +30,7 @@ use vulkano::{
|
|||||||
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
|
image::{view::ImageView, ImageAccess, ImageUsage, SwapchainImage},
|
||||||
impl_vertex,
|
impl_vertex,
|
||||||
instance::{Instance, InstanceCreateInfo},
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{
|
pipeline::{
|
||||||
graphics::{
|
graphics::{
|
||||||
input_assembly::InputAssemblyState,
|
input_assembly::InputAssemblyState,
|
||||||
@ -259,6 +260,8 @@ fn main() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
|
|
||||||
// We now create a buffer that will store the shape of our triangle.
|
// We now create a buffer that will store the shape of our triangle.
|
||||||
// We use #[repr(C)] here to force rustc to not do anything funky with our data, although for this
|
// We use #[repr(C)] here to force rustc to not do anything funky with our data, although for this
|
||||||
// particular example, it doesn't actually change the in-memory representation.
|
// particular example, it doesn't actually change the in-memory representation.
|
||||||
@ -281,7 +284,7 @@ fn main() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -17,6 +17,7 @@ use vulkano::{
|
|||||||
debug::{DebugUtilsMessenger, DebugUtilsMessengerCreateInfo},
|
debug::{DebugUtilsMessenger, DebugUtilsMessengerCreateInfo},
|
||||||
Instance, InstanceCreateInfo, InstanceExtensions,
|
Instance, InstanceCreateInfo, InstanceExtensions,
|
||||||
},
|
},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
Version, VulkanLibrary,
|
Version, VulkanLibrary,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -105,6 +106,7 @@ pub struct VulkanoContext {
|
|||||||
device: Arc<Device>,
|
device: Arc<Device>,
|
||||||
graphics_queue: Arc<Queue>,
|
graphics_queue: Arc<Queue>,
|
||||||
compute_queue: Arc<Queue>,
|
compute_queue: Arc<Queue>,
|
||||||
|
memory_allocator: Arc<StandardMemoryAllocator>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for VulkanoContext {
|
impl Default for VulkanoContext {
|
||||||
@ -173,12 +175,15 @@ impl VulkanoContext {
|
|||||||
config.device_features,
|
config.device_features,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone()));
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
instance,
|
instance,
|
||||||
_debug_utils_messenger,
|
_debug_utils_messenger,
|
||||||
device,
|
device,
|
||||||
graphics_queue,
|
graphics_queue,
|
||||||
compute_queue,
|
compute_queue,
|
||||||
|
memory_allocator,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,4 +297,10 @@ impl VulkanoContext {
|
|||||||
pub fn compute_queue(&self) -> &Arc<Queue> {
|
pub fn compute_queue(&self) -> &Arc<Queue> {
|
||||||
&self.compute_queue
|
&self.compute_queue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the memory allocator.
|
||||||
|
#[inline]
|
||||||
|
pub fn memory_allocator(&self) -> &Arc<StandardMemoryAllocator> {
|
||||||
|
&self.memory_allocator
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ use vulkano::{
|
|||||||
image::{
|
image::{
|
||||||
view::ImageView, ImageAccess, ImageUsage, ImageViewAbstract, StorageImage, SwapchainImage,
|
view::ImageView, ImageAccess, ImageUsage, ImageViewAbstract, StorageImage, SwapchainImage,
|
||||||
},
|
},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
swapchain::{
|
swapchain::{
|
||||||
self, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
|
self, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
|
||||||
SwapchainPresentInfo,
|
SwapchainPresentInfo,
|
||||||
@ -46,6 +47,7 @@ pub struct VulkanoWindowRenderer {
|
|||||||
compute_queue: Arc<Queue>,
|
compute_queue: Arc<Queue>,
|
||||||
swapchain: Arc<Swapchain>,
|
swapchain: Arc<Swapchain>,
|
||||||
final_views: Vec<SwapchainImageView>,
|
final_views: Vec<SwapchainImageView>,
|
||||||
|
memory_allocator: Arc<StandardMemoryAllocator>,
|
||||||
/// Additional image views that you can add which are resized with the window.
|
/// Additional image views that you can add which are resized with the window.
|
||||||
/// Use associated functions to get access to these.
|
/// Use associated functions to get access to these.
|
||||||
additional_image_views: HashMap<usize, DeviceImageView>,
|
additional_image_views: HashMap<usize, DeviceImageView>,
|
||||||
@ -64,6 +66,7 @@ impl VulkanoWindowRenderer {
|
|||||||
window: winit::window::Window,
|
window: winit::window::Window,
|
||||||
descriptor: &WindowDescriptor,
|
descriptor: &WindowDescriptor,
|
||||||
swapchain_create_info_modify: fn(&mut SwapchainCreateInfo),
|
swapchain_create_info_modify: fn(&mut SwapchainCreateInfo),
|
||||||
|
memory_allocator: Arc<StandardMemoryAllocator>,
|
||||||
) -> VulkanoWindowRenderer {
|
) -> VulkanoWindowRenderer {
|
||||||
// Create rendering surface from window
|
// Create rendering surface from window
|
||||||
let surface =
|
let surface =
|
||||||
@ -86,6 +89,7 @@ impl VulkanoWindowRenderer {
|
|||||||
compute_queue: vulkano_context.compute_queue().clone(),
|
compute_queue: vulkano_context.compute_queue().clone(),
|
||||||
swapchain: swap_chain,
|
swapchain: swap_chain,
|
||||||
final_views,
|
final_views,
|
||||||
|
memory_allocator,
|
||||||
additional_image_views: HashMap::default(),
|
additional_image_views: HashMap::default(),
|
||||||
recreate_swapchain: false,
|
recreate_swapchain: false,
|
||||||
previous_frame_end,
|
previous_frame_end,
|
||||||
@ -239,6 +243,7 @@ impl VulkanoWindowRenderer {
|
|||||||
pub fn add_additional_image_view(&mut self, key: usize, format: Format, usage: ImageUsage) {
|
pub fn add_additional_image_view(&mut self, key: usize, format: Format, usage: ImageUsage) {
|
||||||
let size = self.swapchain_image_size();
|
let size = self.swapchain_image_size();
|
||||||
let image = StorageImage::general_purpose_image_view(
|
let image = StorageImage::general_purpose_image_view(
|
||||||
|
&*self.memory_allocator,
|
||||||
self.graphics_queue.clone(),
|
self.graphics_queue.clone(),
|
||||||
size,
|
size,
|
||||||
format,
|
format,
|
||||||
|
@ -168,6 +168,7 @@ impl VulkanoWindows {
|
|||||||
winit_window,
|
winit_window,
|
||||||
window_descriptor,
|
window_descriptor,
|
||||||
swapchain_create_info_modify,
|
swapchain_create_info_modify,
|
||||||
|
vulkano_context.memory_allocator().clone(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -17,17 +17,18 @@
|
|||||||
//! or write and write simultaneously will block.
|
//! or write and write simultaneously will block.
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
sys::UnsafeBuffer, BufferAccess, BufferAccessObject, BufferContents, BufferInner, BufferUsage,
|
sys::UnsafeBuffer, BufferAccess, BufferAccessObject, BufferContents, BufferCreationError,
|
||||||
|
BufferInner, BufferUsage,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
buffer::{sys::UnsafeBufferCreateInfo, BufferCreationError, TypedBufferAccess},
|
buffer::{sys::UnsafeBufferCreateInfo, TypedBufferAccess},
|
||||||
device::{Device, DeviceOwned},
|
device::{Device, DeviceOwned},
|
||||||
memory::{
|
memory::{
|
||||||
pool::{
|
allocator::{
|
||||||
AllocFromRequirementsFilter, AllocLayout, MappingRequirement, MemoryPoolAlloc,
|
AllocationCreateInfo, AllocationCreationError, AllocationType, MemoryAlloc,
|
||||||
PotentialDedicatedAllocation, StandardMemoryPoolAlloc,
|
MemoryAllocatePreference, MemoryAllocator, MemoryUsage,
|
||||||
},
|
},
|
||||||
DedicatedAllocation, DeviceMemoryError, MemoryPool,
|
DedicatedAllocation,
|
||||||
},
|
},
|
||||||
sync::Sharing,
|
sync::Sharing,
|
||||||
DeviceSize,
|
DeviceSize,
|
||||||
@ -51,7 +52,7 @@ use std::{
|
|||||||
/// memory caches GPU data on the CPU side. This can be more performant in cases where
|
/// memory caches GPU data on the CPU side. This can be more performant in cases where
|
||||||
/// the cpu needs to read data coming off the GPU.
|
/// the cpu needs to read data coming off the GPU.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CpuAccessibleBuffer<T, A = PotentialDedicatedAllocation<StandardMemoryPoolAlloc>>
|
pub struct CpuAccessibleBuffer<T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized,
|
T: BufferContents + ?Sized,
|
||||||
{
|
{
|
||||||
@ -59,7 +60,7 @@ where
|
|||||||
inner: Arc<UnsafeBuffer>,
|
inner: Arc<UnsafeBuffer>,
|
||||||
|
|
||||||
// The memory held by the buffer.
|
// The memory held by the buffer.
|
||||||
memory: A,
|
memory: MemoryAlloc,
|
||||||
|
|
||||||
// Queue families allowed to access this buffer.
|
// Queue families allowed to access this buffer.
|
||||||
queue_family_indices: SmallVec<[u32; 4]>,
|
queue_family_indices: SmallVec<[u32; 4]>,
|
||||||
@ -77,17 +78,15 @@ where
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// - Panics if `T` has zero size.
|
/// - Panics if `T` has zero size.
|
||||||
/// - Panics if `usage.shader_device_address` is `true`.
|
|
||||||
// TODO: ^
|
|
||||||
pub fn from_data(
|
pub fn from_data(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
usage: BufferUsage,
|
usage: BufferUsage,
|
||||||
host_cached: bool,
|
host_cached: bool,
|
||||||
data: T,
|
data: T,
|
||||||
) -> Result<Arc<CpuAccessibleBuffer<T>>, DeviceMemoryError> {
|
) -> Result<Arc<CpuAccessibleBuffer<T>>, AllocationCreationError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let uninitialized = CpuAccessibleBuffer::raw(
|
let uninitialized = CpuAccessibleBuffer::raw(
|
||||||
device,
|
allocator,
|
||||||
size_of::<T>() as DeviceSize,
|
size_of::<T>() as DeviceSize,
|
||||||
usage,
|
usage,
|
||||||
host_cached,
|
host_cached,
|
||||||
@ -113,11 +112,17 @@ where
|
|||||||
///
|
///
|
||||||
/// - Panics if `T` has zero size.
|
/// - Panics if `T` has zero size.
|
||||||
pub unsafe fn uninitialized(
|
pub unsafe fn uninitialized(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
usage: BufferUsage,
|
usage: BufferUsage,
|
||||||
host_cached: bool,
|
host_cached: bool,
|
||||||
) -> Result<Arc<CpuAccessibleBuffer<T>>, DeviceMemoryError> {
|
) -> Result<Arc<CpuAccessibleBuffer<T>>, AllocationCreationError> {
|
||||||
CpuAccessibleBuffer::raw(device, size_of::<T>() as DeviceSize, usage, host_cached, [])
|
CpuAccessibleBuffer::raw(
|
||||||
|
allocator,
|
||||||
|
size_of::<T>() as DeviceSize,
|
||||||
|
usage,
|
||||||
|
host_cached,
|
||||||
|
[],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,14 +137,12 @@ where
|
|||||||
///
|
///
|
||||||
/// - Panics if `T` has zero size.
|
/// - Panics if `T` has zero size.
|
||||||
/// - Panics if `data` is empty.
|
/// - Panics if `data` is empty.
|
||||||
/// - Panics if `usage.shader_device_address` is `true`.
|
|
||||||
// TODO: ^
|
|
||||||
pub fn from_iter<I>(
|
pub fn from_iter<I>(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
usage: BufferUsage,
|
usage: BufferUsage,
|
||||||
host_cached: bool,
|
host_cached: bool,
|
||||||
data: I,
|
data: I,
|
||||||
) -> Result<Arc<CpuAccessibleBuffer<[T]>>, DeviceMemoryError>
|
) -> Result<Arc<CpuAccessibleBuffer<[T]>>, AllocationCreationError>
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = T>,
|
I: IntoIterator<Item = T>,
|
||||||
I::IntoIter: ExactSizeIterator,
|
I::IntoIter: ExactSizeIterator,
|
||||||
@ -148,7 +151,7 @@ where
|
|||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let uninitialized = CpuAccessibleBuffer::uninitialized_array(
|
let uninitialized = CpuAccessibleBuffer::uninitialized_array(
|
||||||
device,
|
allocator,
|
||||||
data.len() as DeviceSize,
|
data.len() as DeviceSize,
|
||||||
usage,
|
usage,
|
||||||
host_cached,
|
host_cached,
|
||||||
@ -176,16 +179,14 @@ where
|
|||||||
///
|
///
|
||||||
/// - Panics if `T` has zero size.
|
/// - Panics if `T` has zero size.
|
||||||
/// - Panics if `len` is zero.
|
/// - Panics if `len` is zero.
|
||||||
/// - Panics if `usage.shader_device_address` is `true`.
|
|
||||||
// TODO: ^
|
|
||||||
pub unsafe fn uninitialized_array(
|
pub unsafe fn uninitialized_array(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
len: DeviceSize,
|
len: DeviceSize,
|
||||||
usage: BufferUsage,
|
usage: BufferUsage,
|
||||||
host_cached: bool,
|
host_cached: bool,
|
||||||
) -> Result<Arc<CpuAccessibleBuffer<[T]>>, DeviceMemoryError> {
|
) -> Result<Arc<CpuAccessibleBuffer<[T]>>, AllocationCreationError> {
|
||||||
CpuAccessibleBuffer::raw(
|
CpuAccessibleBuffer::raw(
|
||||||
device,
|
allocator,
|
||||||
len * size_of::<T>() as DeviceSize,
|
len * size_of::<T>() as DeviceSize,
|
||||||
usage,
|
usage,
|
||||||
host_cached,
|
host_cached,
|
||||||
@ -207,20 +208,17 @@ where
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// - Panics if `size` is zero.
|
/// - Panics if `size` is zero.
|
||||||
/// - Panics if `usage.shader_device_address` is `true`.
|
|
||||||
// TODO: ^
|
|
||||||
pub unsafe fn raw(
|
pub unsafe fn raw(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
size: DeviceSize,
|
size: DeviceSize,
|
||||||
usage: BufferUsage,
|
usage: BufferUsage,
|
||||||
host_cached: bool,
|
host_cached: bool,
|
||||||
queue_family_indices: impl IntoIterator<Item = u32>,
|
queue_family_indices: impl IntoIterator<Item = u32>,
|
||||||
) -> Result<Arc<CpuAccessibleBuffer<T>>, DeviceMemoryError> {
|
) -> Result<Arc<CpuAccessibleBuffer<T>>, AllocationCreationError> {
|
||||||
let queue_family_indices: SmallVec<[_; 4]> = queue_family_indices.into_iter().collect();
|
let queue_family_indices: SmallVec<[_; 4]> = queue_family_indices.into_iter().collect();
|
||||||
|
|
||||||
let buffer = {
|
let buffer = UnsafeBuffer::new(
|
||||||
match UnsafeBuffer::new(
|
allocator.device().clone(),
|
||||||
device.clone(),
|
|
||||||
UnsafeBufferCreateInfo {
|
UnsafeBufferCreateInfo {
|
||||||
sharing: if queue_family_indices.len() >= 2 {
|
sharing: if queue_family_indices.len() >= 2 {
|
||||||
Sharing::Concurrent(queue_family_indices.clone())
|
Sharing::Concurrent(queue_family_indices.clone())
|
||||||
@ -231,51 +229,49 @@ where
|
|||||||
usage,
|
usage,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
) {
|
)
|
||||||
Ok(b) => b,
|
.map_err(|err| match err {
|
||||||
Err(BufferCreationError::AllocError(err)) => return Err(err),
|
BufferCreationError::AllocError(err) => err,
|
||||||
Err(_) => unreachable!(), // We don't use sparse binding, therefore the other
|
// We don't use sparse-binding, therefore the other errors can't happen.
|
||||||
// errors can't happen
|
_ => unreachable!(),
|
||||||
}
|
})?;
|
||||||
};
|
let requirements = buffer.memory_requirements();
|
||||||
let mem_reqs = buffer.memory_requirements();
|
let create_info = AllocationCreateInfo {
|
||||||
|
requirements,
|
||||||
let memory = MemoryPool::alloc_from_requirements(
|
allocation_type: AllocationType::Linear,
|
||||||
&device.standard_memory_pool(),
|
usage: if host_cached {
|
||||||
&mem_reqs,
|
MemoryUsage::Download
|
||||||
AllocLayout::Linear,
|
|
||||||
MappingRequirement::Map,
|
|
||||||
Some(DedicatedAllocation::Buffer(&buffer)),
|
|
||||||
|m| {
|
|
||||||
if m.property_flags.host_cached {
|
|
||||||
if host_cached {
|
|
||||||
AllocFromRequirementsFilter::Preferred
|
|
||||||
} else {
|
} else {
|
||||||
AllocFromRequirementsFilter::Allowed
|
MemoryUsage::Upload
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if host_cached {
|
|
||||||
AllocFromRequirementsFilter::Allowed
|
|
||||||
} else {
|
|
||||||
AllocFromRequirementsFilter::Preferred
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
)?;
|
allocate_preference: MemoryAllocatePreference::Unknown,
|
||||||
debug_assert!((memory.offset() % mem_reqs.alignment) == 0);
|
dedicated_allocation: Some(DedicatedAllocation::Buffer(&buffer)),
|
||||||
debug_assert!(memory.mapped_memory().is_some());
|
..Default::default()
|
||||||
buffer.bind_memory(memory.memory(), memory.offset())?;
|
};
|
||||||
|
|
||||||
|
match allocator.allocate_unchecked(create_info) {
|
||||||
|
Ok(mut alloc) => {
|
||||||
|
debug_assert!(alloc.offset() % requirements.alignment == 0);
|
||||||
|
debug_assert!(alloc.size() == requirements.size);
|
||||||
|
// The implementation might require a larger size than we wanted. With this it is
|
||||||
|
// easier to invalidate and flush the whole buffer. It does not affect the
|
||||||
|
// allocation in any way.
|
||||||
|
alloc.shrink(size);
|
||||||
|
buffer.bind_memory(alloc.device_memory(), alloc.offset())?;
|
||||||
|
|
||||||
Ok(Arc::new(CpuAccessibleBuffer {
|
Ok(Arc::new(CpuAccessibleBuffer {
|
||||||
inner: buffer,
|
inner: buffer,
|
||||||
memory,
|
memory: alloc,
|
||||||
queue_family_indices,
|
queue_family_indices,
|
||||||
marker: PhantomData,
|
marker: PhantomData,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
Err(err) => Err(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> CpuAccessibleBuffer<T, A>
|
impl<T> CpuAccessibleBuffer<T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized,
|
T: BufferContents + ?Sized,
|
||||||
{
|
{
|
||||||
@ -285,10 +281,9 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> CpuAccessibleBuffer<T, A>
|
impl<T> CpuAccessibleBuffer<T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized,
|
T: BufferContents + ?Sized,
|
||||||
A: MemoryPoolAlloc,
|
|
||||||
{
|
{
|
||||||
/// Locks the buffer in order to read its content from the CPU.
|
/// Locks the buffer in order to read its content from the CPU.
|
||||||
///
|
///
|
||||||
@ -299,7 +294,7 @@ where
|
|||||||
/// After this function successfully locks the buffer, any attempt to submit a command buffer
|
/// After this function successfully locks the buffer, any attempt to submit a command buffer
|
||||||
/// that uses it in exclusive mode will fail. You can still submit this buffer for non-exclusive
|
/// that uses it in exclusive mode will fail. You can still submit this buffer for non-exclusive
|
||||||
/// accesses (ie. reads).
|
/// accesses (ie. reads).
|
||||||
pub fn read(&self) -> Result<ReadLock<'_, T, A>, ReadLockError> {
|
pub fn read(&self) -> Result<ReadLock<'_, T>, ReadLockError> {
|
||||||
let mut state = self.inner.state();
|
let mut state = self.inner.state();
|
||||||
let buffer_range = self.inner().offset..self.inner().offset + self.size();
|
let buffer_range = self.inner().offset..self.inner().offset + self.size();
|
||||||
|
|
||||||
@ -308,20 +303,14 @@ where
|
|||||||
state.cpu_read_lock(buffer_range.clone());
|
state.cpu_read_lock(buffer_range.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mapped_memory = self.memory.mapped_memory().unwrap();
|
|
||||||
let offset = self.memory.offset();
|
|
||||||
let memory_range = offset..offset + self.inner.size();
|
|
||||||
|
|
||||||
let bytes = unsafe {
|
let bytes = unsafe {
|
||||||
// If there are other read locks being held at this point, they also called
|
// If there are other read locks being held at this point, they also called
|
||||||
// `invalidate_range` when locking. The GPU can't write data while the CPU holds a read
|
// `invalidate_range` when locking. The GPU can't write data while the CPU holds a read
|
||||||
// lock, so there will no new data and this call will do nothing.
|
// lock, so there will no new data and this call will do nothing.
|
||||||
// TODO: probably still more efficient to call it only if we're the first to acquire a
|
// TODO: probably still more efficient to call it only if we're the first to acquire a
|
||||||
// read lock, but the number of CPU locks isn't currently tracked anywhere.
|
// read lock, but the number of CPU locks isn't currently tracked anywhere.
|
||||||
mapped_memory
|
self.memory.invalidate_range(0..self.size()).unwrap();
|
||||||
.invalidate_range(memory_range.clone())
|
self.memory.mapped_slice().unwrap()
|
||||||
.unwrap();
|
|
||||||
mapped_memory.read(memory_range).unwrap()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(ReadLock {
|
Ok(ReadLock {
|
||||||
@ -339,7 +328,7 @@ where
|
|||||||
///
|
///
|
||||||
/// After this function successfully locks the buffer, any attempt to submit a command buffer
|
/// After this function successfully locks the buffer, any attempt to submit a command buffer
|
||||||
/// that uses it and any attempt to call `read()` will return an error.
|
/// that uses it and any attempt to call `read()` will return an error.
|
||||||
pub fn write(&self) -> Result<WriteLock<'_, T, A>, WriteLockError> {
|
pub fn write(&self) -> Result<WriteLock<'_, T>, WriteLockError> {
|
||||||
let mut state = self.inner.state();
|
let mut state = self.inner.state();
|
||||||
let buffer_range = self.inner().offset..self.inner().offset + self.size();
|
let buffer_range = self.inner().offset..self.inner().offset + self.size();
|
||||||
|
|
||||||
@ -348,30 +337,22 @@ where
|
|||||||
state.cpu_write_lock(buffer_range.clone());
|
state.cpu_write_lock(buffer_range.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mapped_memory = self.memory.mapped_memory().unwrap();
|
|
||||||
let offset = self.memory.offset();
|
|
||||||
let memory_range = offset..offset + self.size();
|
|
||||||
|
|
||||||
let bytes = unsafe {
|
let bytes = unsafe {
|
||||||
mapped_memory
|
self.memory.invalidate_range(0..self.size()).unwrap();
|
||||||
.invalidate_range(memory_range.clone())
|
self.memory.write(0..self.size()).unwrap()
|
||||||
.unwrap();
|
|
||||||
mapped_memory.write(memory_range.clone()).unwrap()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(WriteLock {
|
Ok(WriteLock {
|
||||||
inner: self,
|
inner: self,
|
||||||
buffer_range,
|
buffer_range,
|
||||||
memory_range,
|
|
||||||
data: T::from_bytes_mut(bytes).unwrap(),
|
data: T::from_bytes_mut(bytes).unwrap(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, A> BufferAccess for CpuAccessibleBuffer<T, A>
|
unsafe impl<T> BufferAccess for CpuAccessibleBuffer<T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized,
|
T: BufferContents + ?Sized,
|
||||||
A: Send + Sync,
|
|
||||||
{
|
{
|
||||||
fn inner(&self) -> BufferInner<'_> {
|
fn inner(&self) -> BufferInner<'_> {
|
||||||
BufferInner {
|
BufferInner {
|
||||||
@ -385,25 +366,23 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> BufferAccessObject for Arc<CpuAccessibleBuffer<T, A>>
|
impl<T> BufferAccessObject for Arc<CpuAccessibleBuffer<T>>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized,
|
T: BufferContents + ?Sized,
|
||||||
A: Send + Sync + 'static,
|
|
||||||
{
|
{
|
||||||
fn as_buffer_access_object(&self) -> Arc<dyn BufferAccess> {
|
fn as_buffer_access_object(&self) -> Arc<dyn BufferAccess> {
|
||||||
self.clone()
|
self.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, A> TypedBufferAccess for CpuAccessibleBuffer<T, A>
|
unsafe impl<T> TypedBufferAccess for CpuAccessibleBuffer<T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized,
|
T: BufferContents + ?Sized,
|
||||||
A: Send + Sync,
|
|
||||||
{
|
{
|
||||||
type Content = T;
|
type Content = T;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, A> DeviceOwned for CpuAccessibleBuffer<T, A>
|
unsafe impl<T> DeviceOwned for CpuAccessibleBuffer<T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized,
|
T: BufferContents + ?Sized,
|
||||||
{
|
{
|
||||||
@ -412,27 +391,20 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> PartialEq for CpuAccessibleBuffer<T, A>
|
impl<T> PartialEq for CpuAccessibleBuffer<T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized,
|
T: BufferContents + ?Sized,
|
||||||
A: Send + Sync,
|
|
||||||
{
|
{
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.inner() == other.inner() && self.size() == other.size()
|
self.inner() == other.inner() && self.size() == other.size()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> Eq for CpuAccessibleBuffer<T, A>
|
impl<T> Eq for CpuAccessibleBuffer<T> where T: BufferContents + ?Sized {}
|
||||||
where
|
|
||||||
T: BufferContents + ?Sized,
|
|
||||||
A: Send + Sync,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, A> Hash for CpuAccessibleBuffer<T, A>
|
impl<T> Hash for CpuAccessibleBuffer<T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized,
|
T: BufferContents + ?Sized,
|
||||||
A: Send + Sync,
|
|
||||||
{
|
{
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.inner().hash(state);
|
self.inner().hash(state);
|
||||||
@ -445,20 +417,18 @@ where
|
|||||||
/// Note that this object holds a rwlock read guard on the chunk. If another thread tries to access
|
/// Note that this object holds a rwlock read guard on the chunk. If another thread tries to access
|
||||||
/// this buffer's content or tries to submit a GPU command that uses this buffer, it will block.
|
/// this buffer's content or tries to submit a GPU command that uses this buffer, it will block.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ReadLock<'a, T, A>
|
pub struct ReadLock<'a, T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized,
|
T: BufferContents + ?Sized,
|
||||||
A: MemoryPoolAlloc,
|
|
||||||
{
|
{
|
||||||
inner: &'a CpuAccessibleBuffer<T, A>,
|
inner: &'a CpuAccessibleBuffer<T>,
|
||||||
buffer_range: Range<DeviceSize>,
|
buffer_range: Range<DeviceSize>,
|
||||||
data: &'a T,
|
data: &'a T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, A> Drop for ReadLock<'a, T, A>
|
impl<'a, T> Drop for ReadLock<'a, T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized + 'a,
|
T: BufferContents + ?Sized + 'a,
|
||||||
A: MemoryPoolAlloc,
|
|
||||||
{
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -468,10 +438,9 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, A> Deref for ReadLock<'a, T, A>
|
impl<'a, T> Deref for ReadLock<'a, T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized + 'a,
|
T: BufferContents + ?Sized + 'a,
|
||||||
A: MemoryPoolAlloc,
|
|
||||||
{
|
{
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
@ -485,30 +454,22 @@ where
|
|||||||
/// Note that this object holds a rwlock write guard on the chunk. If another thread tries to access
|
/// Note that this object holds a rwlock write guard on the chunk. If another thread tries to access
|
||||||
/// this buffer's content or tries to submit a GPU command that uses this buffer, it will block.
|
/// this buffer's content or tries to submit a GPU command that uses this buffer, it will block.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct WriteLock<'a, T, A>
|
pub struct WriteLock<'a, T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized,
|
T: BufferContents + ?Sized,
|
||||||
A: MemoryPoolAlloc,
|
|
||||||
{
|
{
|
||||||
inner: &'a CpuAccessibleBuffer<T, A>,
|
inner: &'a CpuAccessibleBuffer<T>,
|
||||||
buffer_range: Range<DeviceSize>,
|
buffer_range: Range<DeviceSize>,
|
||||||
memory_range: Range<DeviceSize>,
|
|
||||||
data: &'a mut T,
|
data: &'a mut T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, A> Drop for WriteLock<'a, T, A>
|
impl<'a, T> Drop for WriteLock<'a, T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized + 'a,
|
T: BufferContents + ?Sized + 'a,
|
||||||
A: MemoryPoolAlloc,
|
|
||||||
{
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.inner
|
self.inner.memory.flush_range(0..self.inner.size()).unwrap();
|
||||||
.memory
|
|
||||||
.mapped_memory()
|
|
||||||
.unwrap()
|
|
||||||
.flush_range(self.memory_range.clone())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut state = self.inner.inner.state();
|
let mut state = self.inner.inner.state();
|
||||||
state.cpu_write_unlock(self.buffer_range.clone());
|
state.cpu_write_unlock(self.buffer_range.clone());
|
||||||
@ -516,10 +477,9 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, A> Deref for WriteLock<'a, T, A>
|
impl<'a, T> Deref for WriteLock<'a, T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized + 'a,
|
T: BufferContents + ?Sized + 'a,
|
||||||
A: MemoryPoolAlloc,
|
|
||||||
{
|
{
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
@ -528,10 +488,9 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, A> DerefMut for WriteLock<'a, T, A>
|
impl<'a, T> DerefMut for WriteLock<'a, T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized + 'a,
|
T: BufferContents + ?Sized + 'a,
|
||||||
A: MemoryPoolAlloc,
|
|
||||||
{
|
{
|
||||||
fn deref_mut(&mut self) -> &mut T {
|
fn deref_mut(&mut self) -> &mut T {
|
||||||
self.data
|
self.data
|
||||||
@ -592,17 +551,19 @@ impl Display for WriteLockError {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::buffer::{BufferUsage, CpuAccessibleBuffer};
|
use super::*;
|
||||||
|
use crate::memory::allocator::StandardMemoryAllocator;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create_empty_buffer() {
|
fn create_empty_buffer() {
|
||||||
let (device, _queue) = gfx_dev_and_queue!();
|
let (device, _queue) = gfx_dev_and_queue!();
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
|
|
||||||
const EMPTY: [i32; 0] = [];
|
const EMPTY: [i32; 0] = [];
|
||||||
|
|
||||||
assert_should_panic!({
|
assert_should_panic!({
|
||||||
CpuAccessibleBuffer::from_data(
|
CpuAccessibleBuffer::from_data(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_dst: true,
|
transfer_dst: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -612,7 +573,7 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
CpuAccessibleBuffer::from_iter(
|
CpuAccessibleBuffer::from_iter(
|
||||||
device,
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_dst: true,
|
transfer_dst: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -15,13 +15,13 @@ use super::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
device::{Device, DeviceOwned},
|
device::{Device, DeviceOwned},
|
||||||
memory::{
|
memory::{
|
||||||
pool::{
|
allocator::{
|
||||||
AllocFromRequirementsFilter, AllocLayout, MappingRequirement, MemoryPoolAlloc,
|
AllocationCreateInfo, AllocationCreationError, AllocationType, MemoryAlloc,
|
||||||
PotentialDedicatedAllocation, StandardMemoryPool,
|
MemoryAllocatePreference, MemoryAllocator, MemoryUsage, StandardMemoryAllocator,
|
||||||
},
|
},
|
||||||
DedicatedAllocation, DeviceMemoryError, MemoryPool,
|
DedicatedAllocation,
|
||||||
},
|
},
|
||||||
DeviceSize, OomError,
|
DeviceSize,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
@ -65,12 +65,12 @@ use std::{
|
|||||||
/// use vulkano::command_buffer::CommandBufferUsage;
|
/// use vulkano::command_buffer::CommandBufferUsage;
|
||||||
/// use vulkano::command_buffer::PrimaryCommandBufferAbstract;
|
/// use vulkano::command_buffer::PrimaryCommandBufferAbstract;
|
||||||
/// use vulkano::sync::GpuFuture;
|
/// use vulkano::sync::GpuFuture;
|
||||||
/// # let device: std::sync::Arc<vulkano::device::Device> = return;
|
|
||||||
/// # let queue: std::sync::Arc<vulkano::device::Queue> = return;
|
/// # let queue: std::sync::Arc<vulkano::device::Queue> = return;
|
||||||
|
/// # let memory_allocator: std::sync::Arc<vulkano::memory::allocator::StandardMemoryAllocator> = return;
|
||||||
/// # let command_buffer_allocator: vulkano::command_buffer::allocator::StandardCommandBufferAllocator = return;
|
/// # let command_buffer_allocator: vulkano::command_buffer::allocator::StandardCommandBufferAllocator = return;
|
||||||
///
|
///
|
||||||
/// // Create the ring buffer.
|
/// // Create the ring buffer.
|
||||||
/// let buffer = CpuBufferPool::upload(device.clone());
|
/// let buffer = CpuBufferPool::upload(memory_allocator);
|
||||||
///
|
///
|
||||||
/// for n in 0 .. 25u32 {
|
/// for n in 0 .. 25u32 {
|
||||||
/// // Each loop grabs a new entry from that ring buffer and stores ` data` in it.
|
/// // Each loop grabs a new entry from that ring buffer and stores ` data` in it.
|
||||||
@ -95,22 +95,21 @@ use std::{
|
|||||||
/// .unwrap();
|
/// .unwrap();
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct CpuBufferPool<T, A = Arc<StandardMemoryPool>>
|
pub struct CpuBufferPool<T, A = StandardMemoryAllocator>
|
||||||
where
|
where
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool,
|
A: MemoryAllocator + ?Sized,
|
||||||
{
|
{
|
||||||
// The device of the pool.
|
|
||||||
device: Arc<Device>,
|
|
||||||
|
|
||||||
// The memory pool to use for allocations.
|
// The memory pool to use for allocations.
|
||||||
pool: A,
|
allocator: Arc<A>,
|
||||||
|
|
||||||
// Current buffer from which elements are grabbed.
|
// Current buffer from which elements are grabbed.
|
||||||
current_buffer: Mutex<Option<Arc<ActualBuffer<A>>>>,
|
current_buffer: Mutex<Option<Arc<ActualBuffer>>>,
|
||||||
|
|
||||||
// Buffer usage.
|
// Buffer usage.
|
||||||
usage: BufferUsage,
|
buffer_usage: BufferUsage,
|
||||||
|
|
||||||
|
memory_usage: MemoryUsage,
|
||||||
|
|
||||||
// Necessary to make it compile.
|
// Necessary to make it compile.
|
||||||
marker: PhantomData<Box<T>>,
|
marker: PhantomData<Box<T>>,
|
||||||
@ -118,15 +117,12 @@ where
|
|||||||
|
|
||||||
// One buffer of the pool.
|
// One buffer of the pool.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ActualBuffer<A>
|
struct ActualBuffer {
|
||||||
where
|
|
||||||
A: MemoryPool,
|
|
||||||
{
|
|
||||||
// Inner content.
|
// Inner content.
|
||||||
inner: Arc<UnsafeBuffer>,
|
inner: Arc<UnsafeBuffer>,
|
||||||
|
|
||||||
// The memory held by the buffer.
|
// The memory held by the buffer.
|
||||||
memory: PotentialDedicatedAllocation<A::Alloc>,
|
memory: MemoryAlloc,
|
||||||
|
|
||||||
// List of the chunks that are reserved.
|
// List of the chunks that are reserved.
|
||||||
chunks_in_use: Mutex<Vec<ActualBufferChunk>>,
|
chunks_in_use: Mutex<Vec<ActualBufferChunk>>,
|
||||||
@ -154,12 +150,11 @@ struct ActualBufferChunk {
|
|||||||
/// A subbuffer allocated from a `CpuBufferPool`.
|
/// A subbuffer allocated from a `CpuBufferPool`.
|
||||||
///
|
///
|
||||||
/// When this object is destroyed, the subbuffer is automatically reclaimed by the pool.
|
/// When this object is destroyed, the subbuffer is automatically reclaimed by the pool.
|
||||||
pub struct CpuBufferPoolChunk<T, A>
|
pub struct CpuBufferPoolChunk<T>
|
||||||
where
|
where
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool,
|
|
||||||
{
|
{
|
||||||
buffer: Arc<ActualBuffer<A>>,
|
buffer: Arc<ActualBuffer>,
|
||||||
|
|
||||||
// Index of the subbuffer within `buffer`. In number of elements.
|
// Index of the subbuffer within `buffer`. In number of elements.
|
||||||
index: DeviceSize,
|
index: DeviceSize,
|
||||||
@ -179,37 +174,38 @@ where
|
|||||||
/// A subbuffer allocated from a `CpuBufferPool`.
|
/// A subbuffer allocated from a `CpuBufferPool`.
|
||||||
///
|
///
|
||||||
/// When this object is destroyed, the subbuffer is automatically reclaimed by the pool.
|
/// When this object is destroyed, the subbuffer is automatically reclaimed by the pool.
|
||||||
pub struct CpuBufferPoolSubbuffer<T, A>
|
pub struct CpuBufferPoolSubbuffer<T>
|
||||||
where
|
where
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool,
|
|
||||||
{
|
{
|
||||||
// This struct is just a wrapper around `CpuBufferPoolChunk`.
|
// This struct is just a wrapper around `CpuBufferPoolChunk`.
|
||||||
chunk: CpuBufferPoolChunk<T, A>,
|
chunk: CpuBufferPoolChunk<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> CpuBufferPool<T>
|
impl<T, A> CpuBufferPool<T, A>
|
||||||
where
|
where
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
|
A: MemoryAllocator + ?Sized,
|
||||||
{
|
{
|
||||||
/// Builds a `CpuBufferPool`.
|
/// Builds a `CpuBufferPool`.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// - Panics if `T` has zero size.
|
/// - Panics if `T` has zero size.
|
||||||
/// - Panics if `usage.shader_device_address` is `true`.
|
/// - Panics if `memory_usage` is [`MemoryUsage::GpuOnly`].
|
||||||
// TODO: ^
|
pub fn new(
|
||||||
#[inline]
|
allocator: Arc<A>,
|
||||||
pub fn new(device: Arc<Device>, usage: BufferUsage) -> CpuBufferPool<T> {
|
buffer_usage: BufferUsage,
|
||||||
|
memory_usage: MemoryUsage,
|
||||||
|
) -> CpuBufferPool<T, A> {
|
||||||
assert!(size_of::<T>() > 0);
|
assert!(size_of::<T>() > 0);
|
||||||
assert!(!usage.shader_device_address);
|
assert!(memory_usage != MemoryUsage::GpuOnly);
|
||||||
let pool = device.standard_memory_pool();
|
|
||||||
|
|
||||||
CpuBufferPool {
|
CpuBufferPool {
|
||||||
device,
|
allocator,
|
||||||
pool,
|
|
||||||
current_buffer: Mutex::new(None),
|
current_buffer: Mutex::new(None),
|
||||||
usage,
|
buffer_usage,
|
||||||
|
memory_usage,
|
||||||
marker: PhantomData,
|
marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -222,14 +218,14 @@ where
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// - Panics if `T` has zero size.
|
/// - Panics if `T` has zero size.
|
||||||
#[inline]
|
pub fn upload(allocator: Arc<A>) -> CpuBufferPool<T, A> {
|
||||||
pub fn upload(device: Arc<Device>) -> CpuBufferPool<T> {
|
|
||||||
CpuBufferPool::new(
|
CpuBufferPool::new(
|
||||||
device,
|
allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_src: true,
|
transfer_src: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
},
|
},
|
||||||
|
MemoryUsage::Upload,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,14 +237,14 @@ where
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// - Panics if `T` has zero size.
|
/// - Panics if `T` has zero size.
|
||||||
#[inline]
|
pub fn download(allocator: Arc<A>) -> CpuBufferPool<T, A> {
|
||||||
pub fn download(device: Arc<Device>) -> CpuBufferPool<T> {
|
|
||||||
CpuBufferPool::new(
|
CpuBufferPool::new(
|
||||||
device,
|
allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_dst: true,
|
transfer_dst: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
},
|
},
|
||||||
|
MemoryUsage::Download,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,14 +256,14 @@ where
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// - Panics if `T` has zero size.
|
/// - Panics if `T` has zero size.
|
||||||
#[inline]
|
pub fn uniform_buffer(allocator: Arc<A>) -> CpuBufferPool<T, A> {
|
||||||
pub fn uniform_buffer(device: Arc<Device>) -> CpuBufferPool<T> {
|
|
||||||
CpuBufferPool::new(
|
CpuBufferPool::new(
|
||||||
device,
|
allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
uniform_buffer: true,
|
uniform_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
},
|
},
|
||||||
|
MemoryUsage::Upload,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,14 +275,14 @@ where
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// - Panics if `T` has zero size.
|
/// - Panics if `T` has zero size.
|
||||||
#[inline]
|
pub fn vertex_buffer(allocator: Arc<A>) -> CpuBufferPool<T, A> {
|
||||||
pub fn vertex_buffer(device: Arc<Device>) -> CpuBufferPool<T> {
|
|
||||||
CpuBufferPool::new(
|
CpuBufferPool::new(
|
||||||
device,
|
allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
},
|
},
|
||||||
|
MemoryUsage::Upload,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,14 +294,14 @@ where
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// - Panics if `T` has zero size.
|
/// - Panics if `T` has zero size.
|
||||||
#[inline]
|
pub fn indirect_buffer(allocator: Arc<A>) -> CpuBufferPool<T, A> {
|
||||||
pub fn indirect_buffer(device: Arc<Device>) -> CpuBufferPool<T> {
|
|
||||||
CpuBufferPool::new(
|
CpuBufferPool::new(
|
||||||
device,
|
allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
indirect_buffer: true,
|
indirect_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
},
|
},
|
||||||
|
MemoryUsage::Upload,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -313,7 +309,7 @@ where
|
|||||||
impl<T, A> CpuBufferPool<T, A>
|
impl<T, A> CpuBufferPool<T, A>
|
||||||
where
|
where
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool,
|
A: MemoryAllocator + ?Sized,
|
||||||
{
|
{
|
||||||
/// Returns the current capacity of the pool, in number of elements.
|
/// Returns the current capacity of the pool, in number of elements.
|
||||||
pub fn capacity(&self) -> DeviceSize {
|
pub fn capacity(&self) -> DeviceSize {
|
||||||
@ -327,7 +323,7 @@ where
|
|||||||
/// case.
|
/// case.
|
||||||
///
|
///
|
||||||
/// Since this can involve a memory allocation, an `OomError` can happen.
|
/// Since this can involve a memory allocation, an `OomError` can happen.
|
||||||
pub fn reserve(&self, capacity: DeviceSize) -> Result<(), DeviceMemoryError> {
|
pub fn reserve(&self, capacity: DeviceSize) -> Result<(), AllocationCreationError> {
|
||||||
if capacity == 0 {
|
if capacity == 0 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -352,11 +348,10 @@ where
|
|||||||
///
|
///
|
||||||
/// > **Note**: You can think of it like a `Vec`. If you insert an element and the `Vec` is not
|
/// > **Note**: You can think of it like a `Vec`. If you insert an element and the `Vec` is not
|
||||||
/// > large enough, a new chunk of memory is automatically allocated.
|
/// > large enough, a new chunk of memory is automatically allocated.
|
||||||
#[inline]
|
|
||||||
pub fn from_data(
|
pub fn from_data(
|
||||||
&self,
|
&self,
|
||||||
data: T,
|
data: T,
|
||||||
) -> Result<Arc<CpuBufferPoolSubbuffer<T, A>>, DeviceMemoryError> {
|
) -> Result<Arc<CpuBufferPoolSubbuffer<T>>, AllocationCreationError> {
|
||||||
Ok(Arc::new(CpuBufferPoolSubbuffer {
|
Ok(Arc::new(CpuBufferPoolSubbuffer {
|
||||||
chunk: self.chunk_impl([data].into_iter())?,
|
chunk: self.chunk_impl([data].into_iter())?,
|
||||||
}))
|
}))
|
||||||
@ -373,9 +368,10 @@ where
|
|||||||
/// # Panic
|
/// # Panic
|
||||||
///
|
///
|
||||||
/// Panics if the length of the iterator didn't match the actual number of elements.
|
/// Panics if the length of the iterator didn't match the actual number of elements.
|
||||||
///
|
pub fn from_iter<I>(
|
||||||
#[inline]
|
&self,
|
||||||
pub fn from_iter<I>(&self, iter: I) -> Result<Arc<CpuBufferPoolChunk<T, A>>, DeviceMemoryError>
|
iter: I,
|
||||||
|
) -> Result<Arc<CpuBufferPoolChunk<T>>, AllocationCreationError>
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = T>,
|
I: IntoIterator<Item = T>,
|
||||||
I::IntoIter: ExactSizeIterator,
|
I::IntoIter: ExactSizeIterator,
|
||||||
@ -386,7 +382,7 @@ where
|
|||||||
fn chunk_impl(
|
fn chunk_impl(
|
||||||
&self,
|
&self,
|
||||||
data: impl ExactSizeIterator<Item = T>,
|
data: impl ExactSizeIterator<Item = T>,
|
||||||
) -> Result<CpuBufferPoolChunk<T, A>, DeviceMemoryError> {
|
) -> Result<CpuBufferPoolChunk<T>, AllocationCreationError> {
|
||||||
let mut mutex = self.current_buffer.lock().unwrap();
|
let mut mutex = self.current_buffer.lock().unwrap();
|
||||||
|
|
||||||
let data = match self.try_next_impl(&mut mutex, data) {
|
let data = match self.try_next_impl(&mut mutex, data) {
|
||||||
@ -413,8 +409,7 @@ where
|
|||||||
///
|
///
|
||||||
/// A `CpuBufferPool` is always empty the first time you use it, so you shouldn't use
|
/// A `CpuBufferPool` is always empty the first time you use it, so you shouldn't use
|
||||||
/// `try_next` the first time you use it.
|
/// `try_next` the first time you use it.
|
||||||
#[inline]
|
pub fn try_next(&self, data: T) -> Option<Arc<CpuBufferPoolSubbuffer<T>>> {
|
||||||
pub fn try_next(&self, data: T) -> Option<Arc<CpuBufferPoolSubbuffer<T, A>>> {
|
|
||||||
let mut mutex = self.current_buffer.lock().unwrap();
|
let mut mutex = self.current_buffer.lock().unwrap();
|
||||||
self.try_next_impl(&mut mutex, [data])
|
self.try_next_impl(&mut mutex, [data])
|
||||||
.map(|c| Arc::new(CpuBufferPoolSubbuffer { chunk: c }))
|
.map(|c| Arc::new(CpuBufferPoolSubbuffer { chunk: c }))
|
||||||
@ -426,44 +421,47 @@ where
|
|||||||
// `cur_buf_mutex` must be an active lock of `self.current_buffer`.
|
// `cur_buf_mutex` must be an active lock of `self.current_buffer`.
|
||||||
fn reset_buf(
|
fn reset_buf(
|
||||||
&self,
|
&self,
|
||||||
cur_buf_mutex: &mut MutexGuard<'_, Option<Arc<ActualBuffer<A>>>>,
|
cur_buf_mutex: &mut MutexGuard<'_, Option<Arc<ActualBuffer>>>,
|
||||||
capacity: DeviceSize,
|
capacity: DeviceSize,
|
||||||
) -> Result<(), DeviceMemoryError> {
|
) -> Result<(), AllocationCreationError> {
|
||||||
let size = match (size_of::<T>() as DeviceSize).checked_mul(capacity) {
|
let size = match (size_of::<T>() as DeviceSize).checked_mul(capacity) {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => return Err(DeviceMemoryError::OomError(OomError::OutOfDeviceMemory)),
|
None => return Err(AllocationCreationError::OutOfDeviceMemory),
|
||||||
};
|
};
|
||||||
let buffer = match UnsafeBuffer::new(
|
|
||||||
self.device.clone(),
|
let buffer = UnsafeBuffer::new(
|
||||||
|
self.device().clone(),
|
||||||
UnsafeBufferCreateInfo {
|
UnsafeBufferCreateInfo {
|
||||||
size,
|
size,
|
||||||
usage: self.usage,
|
usage: self.buffer_usage,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
) {
|
)
|
||||||
Ok(b) => b,
|
.map_err(|err| match err {
|
||||||
Err(BufferCreationError::AllocError(err)) => return Err(err),
|
BufferCreationError::AllocError(err) => err,
|
||||||
Err(_) => unreachable!(), // We don't use sparse binding, therefore the other
|
// We don't use sparse-binding, therefore the other errors can't happen.
|
||||||
// errors can't happen
|
_ => unreachable!(),
|
||||||
|
})?;
|
||||||
|
let requirements = buffer.memory_requirements();
|
||||||
|
let create_info = AllocationCreateInfo {
|
||||||
|
requirements,
|
||||||
|
allocation_type: AllocationType::Linear,
|
||||||
|
usage: self.memory_usage,
|
||||||
|
allocate_preference: MemoryAllocatePreference::Unknown,
|
||||||
|
dedicated_allocation: Some(DedicatedAllocation::Buffer(&buffer)),
|
||||||
|
..Default::default()
|
||||||
};
|
};
|
||||||
let mem_reqs = buffer.memory_requirements();
|
|
||||||
|
|
||||||
unsafe {
|
match unsafe { self.allocator.allocate_unchecked(create_info) } {
|
||||||
let mem = MemoryPool::alloc_from_requirements(
|
Ok(mut alloc) => {
|
||||||
&self.pool,
|
debug_assert!(alloc.offset() % requirements.alignment == 0);
|
||||||
&mem_reqs,
|
debug_assert!(alloc.size() == requirements.size);
|
||||||
AllocLayout::Linear,
|
alloc.shrink(size);
|
||||||
MappingRequirement::Map,
|
unsafe { buffer.bind_memory(alloc.device_memory(), alloc.offset()) }?;
|
||||||
Some(DedicatedAllocation::Buffer(&buffer)),
|
|
||||||
|_| AllocFromRequirementsFilter::Allowed,
|
|
||||||
)?;
|
|
||||||
debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
|
|
||||||
debug_assert!(mem.mapped_memory().is_some());
|
|
||||||
buffer.bind_memory(mem.memory(), mem.offset())?;
|
|
||||||
|
|
||||||
**cur_buf_mutex = Some(Arc::new(ActualBuffer {
|
**cur_buf_mutex = Some(Arc::new(ActualBuffer {
|
||||||
inner: buffer,
|
inner: buffer,
|
||||||
memory: mem,
|
memory: alloc,
|
||||||
chunks_in_use: Mutex::new(vec![]),
|
chunks_in_use: Mutex::new(vec![]),
|
||||||
next_index: AtomicU64::new(0),
|
next_index: AtomicU64::new(0),
|
||||||
capacity,
|
capacity,
|
||||||
@ -471,6 +469,8 @@ where
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Err(err) => Err(err),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tries to lock a subbuffer from the current buffer.
|
// Tries to lock a subbuffer from the current buffer.
|
||||||
@ -482,12 +482,11 @@ where
|
|||||||
// # Panic
|
// # Panic
|
||||||
//
|
//
|
||||||
// Panics if the length of the iterator didn't match the actual number of element.
|
// Panics if the length of the iterator didn't match the actual number of element.
|
||||||
//
|
|
||||||
fn try_next_impl<I>(
|
fn try_next_impl<I>(
|
||||||
&self,
|
&self,
|
||||||
cur_buf_mutex: &mut MutexGuard<'_, Option<Arc<ActualBuffer<A>>>>,
|
cur_buf_mutex: &mut MutexGuard<'_, Option<Arc<ActualBuffer>>>,
|
||||||
data: I,
|
data: I,
|
||||||
) -> Result<CpuBufferPoolChunk<T, A>, I::IntoIter>
|
) -> Result<CpuBufferPoolChunk<T>, I::IntoIter>
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = T>,
|
I: IntoIterator<Item = T>,
|
||||||
I::IntoIter: ExactSizeIterator,
|
I::IntoIter: ExactSizeIterator,
|
||||||
@ -533,7 +532,7 @@ where
|
|||||||
let idx = current_buffer.next_index.load(Ordering::SeqCst);
|
let idx = current_buffer.next_index.load(Ordering::SeqCst);
|
||||||
|
|
||||||
// Find the required alignment in bytes.
|
// Find the required alignment in bytes.
|
||||||
let align_uniform = if self.usage.uniform_buffer {
|
let align_uniform = if self.buffer_usage.uniform_buffer {
|
||||||
self.device()
|
self.device()
|
||||||
.physical_device()
|
.physical_device()
|
||||||
.properties()
|
.properties()
|
||||||
@ -541,7 +540,7 @@ where
|
|||||||
} else {
|
} else {
|
||||||
1
|
1
|
||||||
};
|
};
|
||||||
let align_storage = if self.usage.storage_buffer {
|
let align_storage = if self.buffer_usage.storage_buffer {
|
||||||
self.device()
|
self.device()
|
||||||
.physical_device()
|
.physical_device()
|
||||||
.properties()
|
.properties()
|
||||||
@ -586,12 +585,10 @@ where
|
|||||||
|
|
||||||
// Write `data` in the memory.
|
// Write `data` in the memory.
|
||||||
unsafe {
|
unsafe {
|
||||||
let mem_off = current_buffer.memory.offset();
|
let range = (index * size_of::<T>() as DeviceSize + align_offset)
|
||||||
let range = (index * size_of::<T>() as DeviceSize + align_offset + mem_off)
|
..((index + requested_len) * size_of::<T>() as DeviceSize + align_offset);
|
||||||
..((index + requested_len) * size_of::<T>() as DeviceSize + align_offset + mem_off);
|
|
||||||
|
|
||||||
let mapped_memory = current_buffer.memory.mapped_memory().unwrap();
|
let bytes = current_buffer.memory.write(range.clone()).unwrap();
|
||||||
let bytes = mapped_memory.write(range.clone()).unwrap();
|
|
||||||
let mapping = <[T]>::from_bytes_mut(bytes).unwrap();
|
let mapping = <[T]>::from_bytes_mut(bytes).unwrap();
|
||||||
|
|
||||||
let mut written = 0;
|
let mut written = 0;
|
||||||
@ -600,7 +597,7 @@ where
|
|||||||
written += 1;
|
written += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
mapped_memory.flush_range(range).unwrap();
|
current_buffer.memory.flush_range(range).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
written, requested_len,
|
written, requested_len,
|
||||||
@ -634,16 +631,16 @@ where
|
|||||||
impl<T, A> Clone for CpuBufferPool<T, A>
|
impl<T, A> Clone for CpuBufferPool<T, A>
|
||||||
where
|
where
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool + Clone,
|
A: MemoryAllocator + ?Sized,
|
||||||
{
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
let buf = self.current_buffer.lock().unwrap();
|
let buf = self.current_buffer.lock().unwrap();
|
||||||
|
|
||||||
CpuBufferPool {
|
CpuBufferPool {
|
||||||
device: self.device.clone(),
|
allocator: self.allocator.clone(),
|
||||||
pool: self.pool.clone(),
|
|
||||||
current_buffer: Mutex::new(buf.clone()),
|
current_buffer: Mutex::new(buf.clone()),
|
||||||
usage: self.usage,
|
buffer_usage: self.buffer_usage,
|
||||||
|
memory_usage: self.memory_usage,
|
||||||
marker: PhantomData,
|
marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -652,20 +649,18 @@ where
|
|||||||
unsafe impl<T, A> DeviceOwned for CpuBufferPool<T, A>
|
unsafe impl<T, A> DeviceOwned for CpuBufferPool<T, A>
|
||||||
where
|
where
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool,
|
A: MemoryAllocator + ?Sized,
|
||||||
{
|
{
|
||||||
#[inline]
|
|
||||||
fn device(&self) -> &Arc<Device> {
|
fn device(&self) -> &Arc<Device> {
|
||||||
&self.device
|
self.allocator.device()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> Clone for CpuBufferPoolChunk<T, A>
|
impl<T> Clone for CpuBufferPoolChunk<T>
|
||||||
where
|
where
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool,
|
|
||||||
{
|
{
|
||||||
fn clone(&self) -> CpuBufferPoolChunk<T, A> {
|
fn clone(&self) -> CpuBufferPoolChunk<T> {
|
||||||
let mut chunks_in_use_lock = self.buffer.chunks_in_use.lock().unwrap();
|
let mut chunks_in_use_lock = self.buffer.chunks_in_use.lock().unwrap();
|
||||||
let chunk = chunks_in_use_lock
|
let chunk = chunks_in_use_lock
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
@ -688,13 +683,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, A> BufferAccess for CpuBufferPoolChunk<T, A>
|
unsafe impl<T> BufferAccess for CpuBufferPoolChunk<T>
|
||||||
where
|
where
|
||||||
T: Send + Sync,
|
T: Send + Sync,
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool,
|
|
||||||
{
|
{
|
||||||
#[inline]
|
|
||||||
fn inner(&self) -> BufferInner<'_> {
|
fn inner(&self) -> BufferInner<'_> {
|
||||||
BufferInner {
|
BufferInner {
|
||||||
buffer: &self.buffer.inner,
|
buffer: &self.buffer.inner,
|
||||||
@ -702,28 +695,24 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn size(&self) -> DeviceSize {
|
fn size(&self) -> DeviceSize {
|
||||||
self.requested_len * size_of::<T>() as DeviceSize
|
self.requested_len * size_of::<T>() as DeviceSize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> BufferAccessObject for Arc<CpuBufferPoolChunk<T, A>>
|
impl<T> BufferAccessObject for Arc<CpuBufferPoolChunk<T>>
|
||||||
where
|
where
|
||||||
T: Send + Sync,
|
T: Send + Sync,
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool + 'static,
|
|
||||||
{
|
{
|
||||||
#[inline]
|
|
||||||
fn as_buffer_access_object(&self) -> Arc<dyn BufferAccess> {
|
fn as_buffer_access_object(&self) -> Arc<dyn BufferAccess> {
|
||||||
self.clone()
|
self.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> Drop for CpuBufferPoolChunk<T, A>
|
impl<T> Drop for CpuBufferPoolChunk<T>
|
||||||
where
|
where
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool,
|
|
||||||
{
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// If `requested_len` is 0, then no entry was added in the chunks.
|
// If `requested_len` is 0, then no entry was added in the chunks.
|
||||||
@ -745,147 +734,125 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, A> TypedBufferAccess for CpuBufferPoolChunk<T, A>
|
unsafe impl<T> TypedBufferAccess for CpuBufferPoolChunk<T>
|
||||||
where
|
where
|
||||||
T: Send + Sync,
|
T: Send + Sync,
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool,
|
|
||||||
{
|
{
|
||||||
type Content = [T];
|
type Content = [T];
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, A> DeviceOwned for CpuBufferPoolChunk<T, A>
|
unsafe impl<T> DeviceOwned for CpuBufferPoolChunk<T>
|
||||||
where
|
where
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool,
|
|
||||||
{
|
{
|
||||||
#[inline]
|
|
||||||
fn device(&self) -> &Arc<Device> {
|
fn device(&self) -> &Arc<Device> {
|
||||||
self.buffer.inner.device()
|
self.buffer.inner.device()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> PartialEq for CpuBufferPoolChunk<T, A>
|
impl<T> PartialEq for CpuBufferPoolChunk<T>
|
||||||
where
|
where
|
||||||
T: Send + Sync,
|
T: Send + Sync,
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool,
|
|
||||||
{
|
{
|
||||||
#[inline]
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.inner() == other.inner() && self.size() == other.size()
|
self.inner() == other.inner() && self.size() == other.size()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> Eq for CpuBufferPoolChunk<T, A>
|
impl<T> Eq for CpuBufferPoolChunk<T>
|
||||||
where
|
where
|
||||||
T: Send + Sync,
|
T: Send + Sync,
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool,
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> Hash for CpuBufferPoolChunk<T, A>
|
impl<T> Hash for CpuBufferPoolChunk<T>
|
||||||
where
|
where
|
||||||
T: Send + Sync,
|
T: Send + Sync,
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool,
|
|
||||||
{
|
{
|
||||||
#[inline]
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.inner().hash(state);
|
self.inner().hash(state);
|
||||||
self.size().hash(state);
|
self.size().hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> Clone for CpuBufferPoolSubbuffer<T, A>
|
impl<T> Clone for CpuBufferPoolSubbuffer<T>
|
||||||
where
|
where
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool,
|
|
||||||
{
|
{
|
||||||
fn clone(&self) -> CpuBufferPoolSubbuffer<T, A> {
|
fn clone(&self) -> CpuBufferPoolSubbuffer<T> {
|
||||||
CpuBufferPoolSubbuffer {
|
CpuBufferPoolSubbuffer {
|
||||||
chunk: self.chunk.clone(),
|
chunk: self.chunk.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, A> BufferAccess for CpuBufferPoolSubbuffer<T, A>
|
unsafe impl<T> BufferAccess for CpuBufferPoolSubbuffer<T>
|
||||||
where
|
where
|
||||||
T: Send + Sync,
|
T: Send + Sync,
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool,
|
|
||||||
{
|
{
|
||||||
#[inline]
|
|
||||||
fn inner(&self) -> BufferInner<'_> {
|
fn inner(&self) -> BufferInner<'_> {
|
||||||
self.chunk.inner()
|
self.chunk.inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn size(&self) -> DeviceSize {
|
fn size(&self) -> DeviceSize {
|
||||||
self.chunk.size()
|
self.chunk.size()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> BufferAccessObject for Arc<CpuBufferPoolSubbuffer<T, A>>
|
impl<T> BufferAccessObject for Arc<CpuBufferPoolSubbuffer<T>>
|
||||||
where
|
where
|
||||||
T: Send + Sync,
|
T: Send + Sync,
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool + 'static,
|
|
||||||
{
|
{
|
||||||
#[inline]
|
|
||||||
fn as_buffer_access_object(&self) -> Arc<dyn BufferAccess> {
|
fn as_buffer_access_object(&self) -> Arc<dyn BufferAccess> {
|
||||||
self.clone()
|
self.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, A> TypedBufferAccess for CpuBufferPoolSubbuffer<T, A>
|
unsafe impl<T> TypedBufferAccess for CpuBufferPoolSubbuffer<T>
|
||||||
where
|
where
|
||||||
T: BufferContents,
|
T: BufferContents,
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool,
|
|
||||||
{
|
{
|
||||||
type Content = T;
|
type Content = T;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, A> DeviceOwned for CpuBufferPoolSubbuffer<T, A>
|
unsafe impl<T> DeviceOwned for CpuBufferPoolSubbuffer<T>
|
||||||
where
|
where
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool,
|
|
||||||
{
|
{
|
||||||
#[inline]
|
|
||||||
fn device(&self) -> &Arc<Device> {
|
fn device(&self) -> &Arc<Device> {
|
||||||
self.chunk.buffer.inner.device()
|
self.chunk.buffer.inner.device()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> PartialEq for CpuBufferPoolSubbuffer<T, A>
|
impl<T> PartialEq for CpuBufferPoolSubbuffer<T>
|
||||||
where
|
where
|
||||||
T: Send + Sync,
|
T: Send + Sync,
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool,
|
|
||||||
{
|
{
|
||||||
#[inline]
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.inner() == other.inner() && self.size() == other.size()
|
self.inner() == other.inner() && self.size() == other.size()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> Eq for CpuBufferPoolSubbuffer<T, A>
|
impl<T> Eq for CpuBufferPoolSubbuffer<T>
|
||||||
where
|
where
|
||||||
T: Send + Sync,
|
T: Send + Sync,
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool,
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> Hash for CpuBufferPoolSubbuffer<T, A>
|
impl<T> Hash for CpuBufferPoolSubbuffer<T>
|
||||||
where
|
where
|
||||||
T: Send + Sync,
|
T: Send + Sync,
|
||||||
[T]: BufferContents,
|
[T]: BufferContents,
|
||||||
A: MemoryPool,
|
|
||||||
{
|
{
|
||||||
#[inline]
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.inner().hash(state);
|
self.inner().hash(state);
|
||||||
self.size().hash(state);
|
self.size().hash(state);
|
||||||
@ -894,20 +861,22 @@ where
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::buffer::CpuBufferPool;
|
use super::*;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn basic_create() {
|
fn basic_create() {
|
||||||
let (device, _) = gfx_dev_and_queue!();
|
let (device, _) = gfx_dev_and_queue!();
|
||||||
let _ = CpuBufferPool::<u8>::upload(device);
|
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device));
|
||||||
|
let _ = CpuBufferPool::<u8>::upload(memory_allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn reserve() {
|
fn reserve() {
|
||||||
let (device, _) = gfx_dev_and_queue!();
|
let (device, _) = gfx_dev_and_queue!();
|
||||||
|
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device));
|
||||||
|
|
||||||
let pool = CpuBufferPool::<u8>::upload(device);
|
let pool = CpuBufferPool::<u8>::upload(memory_allocator);
|
||||||
assert_eq!(pool.capacity(), 0);
|
assert_eq!(pool.capacity(), 0);
|
||||||
|
|
||||||
pool.reserve(83).unwrap();
|
pool.reserve(83).unwrap();
|
||||||
@ -917,8 +886,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn capacity_increase() {
|
fn capacity_increase() {
|
||||||
let (device, _) = gfx_dev_and_queue!();
|
let (device, _) = gfx_dev_and_queue!();
|
||||||
|
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device));
|
||||||
|
|
||||||
let pool = CpuBufferPool::upload(device);
|
let pool = CpuBufferPool::upload(memory_allocator);
|
||||||
assert_eq!(pool.capacity(), 0);
|
assert_eq!(pool.capacity(), 0);
|
||||||
|
|
||||||
pool.from_data(12).unwrap();
|
pool.from_data(12).unwrap();
|
||||||
@ -935,8 +905,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn reuse_subbuffers() {
|
fn reuse_subbuffers() {
|
||||||
let (device, _) = gfx_dev_and_queue!();
|
let (device, _) = gfx_dev_and_queue!();
|
||||||
|
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device));
|
||||||
|
|
||||||
let pool = CpuBufferPool::upload(device);
|
let pool = CpuBufferPool::upload(memory_allocator);
|
||||||
assert_eq!(pool.capacity(), 0);
|
assert_eq!(pool.capacity(), 0);
|
||||||
|
|
||||||
let mut capacity = None;
|
let mut capacity = None;
|
||||||
@ -955,8 +926,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn chunk_loopback() {
|
fn chunk_loopback() {
|
||||||
let (device, _) = gfx_dev_and_queue!();
|
let (device, _) = gfx_dev_and_queue!();
|
||||||
|
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device));
|
||||||
|
|
||||||
let pool = CpuBufferPool::<u8>::upload(device);
|
let pool = CpuBufferPool::<u8>::upload(memory_allocator);
|
||||||
pool.reserve(5).unwrap();
|
pool.reserve(5).unwrap();
|
||||||
|
|
||||||
let a = pool.from_iter(vec![0, 0]).unwrap();
|
let a = pool.from_iter(vec![0, 0]).unwrap();
|
||||||
@ -973,8 +945,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn chunk_0_elems_doesnt_pollute() {
|
fn chunk_0_elems_doesnt_pollute() {
|
||||||
let (device, _) = gfx_dev_and_queue!();
|
let (device, _) = gfx_dev_and_queue!();
|
||||||
|
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device));
|
||||||
|
|
||||||
let pool = CpuBufferPool::<u8>::upload(device);
|
let pool = CpuBufferPool::<u8>::upload(memory_allocator);
|
||||||
|
|
||||||
let _ = pool.from_iter(vec![]).unwrap();
|
let _ = pool.from_iter(vec![]).unwrap();
|
||||||
let _ = pool.from_iter(vec![0, 0]).unwrap();
|
let _ = pool.from_iter(vec![0, 0]).unwrap();
|
||||||
|
@ -16,31 +16,26 @@
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
sys::{UnsafeBuffer, UnsafeBufferCreateInfo},
|
sys::{UnsafeBuffer, UnsafeBufferCreateInfo},
|
||||||
BufferAccess, BufferAccessObject, BufferContents, BufferCreationError, BufferInner,
|
BufferAccess, BufferAccessObject, BufferContents, BufferInner, BufferUsage,
|
||||||
BufferUsage, CpuAccessibleBuffer, TypedBufferAccess,
|
CpuAccessibleBuffer, TypedBufferAccess,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
command_buffer::{
|
buffer::{BufferCreationError, ExternalBufferInfo},
|
||||||
allocator::CommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferBeginError,
|
command_buffer::{allocator::CommandBufferAllocator, AutoCommandBufferBuilder, CopyBufferInfo},
|
||||||
CopyBufferInfo,
|
|
||||||
},
|
|
||||||
device::{Device, DeviceOwned},
|
device::{Device, DeviceOwned},
|
||||||
memory::{
|
memory::{
|
||||||
pool::{
|
allocator::{
|
||||||
alloc_dedicated_with_exportable_fd, AllocFromRequirementsFilter, AllocLayout,
|
AllocationCreateInfo, AllocationCreationError, AllocationType, MemoryAlloc,
|
||||||
MappingRequirement, MemoryPoolAlloc, PotentialDedicatedAllocation,
|
MemoryAllocatePreference, MemoryAllocator, MemoryUsage,
|
||||||
StandardMemoryPoolAlloc,
|
|
||||||
},
|
},
|
||||||
DedicatedAllocation, DeviceMemoryError, ExternalMemoryHandleType, MemoryPool,
|
DedicatedAllocation, DeviceMemoryError, ExternalMemoryHandleType,
|
||||||
MemoryRequirements,
|
ExternalMemoryHandleTypes,
|
||||||
},
|
},
|
||||||
sync::Sharing,
|
sync::Sharing,
|
||||||
DeviceSize,
|
DeviceSize,
|
||||||
};
|
};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::{
|
use std::{
|
||||||
error::Error,
|
|
||||||
fmt::{Display, Error as FmtError, Formatter},
|
|
||||||
fs::File,
|
fs::File,
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
@ -79,6 +74,7 @@ use std::{
|
|||||||
/// use vulkano::sync::GpuFuture;
|
/// use vulkano::sync::GpuFuture;
|
||||||
/// # let device: std::sync::Arc<vulkano::device::Device> = return;
|
/// # let device: std::sync::Arc<vulkano::device::Device> = return;
|
||||||
/// # let queue: std::sync::Arc<vulkano::device::Queue> = return;
|
/// # let queue: std::sync::Arc<vulkano::device::Queue> = return;
|
||||||
|
/// # let memory_allocator: vulkano::memory::allocator::StandardMemoryAllocator = return;
|
||||||
/// # let command_buffer_allocator: vulkano::command_buffer::allocator::StandardCommandBufferAllocator = return;
|
/// # let command_buffer_allocator: vulkano::command_buffer::allocator::StandardCommandBufferAllocator = return;
|
||||||
///
|
///
|
||||||
/// // Simple iterator to construct test data.
|
/// // Simple iterator to construct test data.
|
||||||
@ -86,7 +82,7 @@ use std::{
|
|||||||
///
|
///
|
||||||
/// // Create a CPU accessible buffer initialized with the data.
|
/// // Create a CPU accessible buffer initialized with the data.
|
||||||
/// let temporary_accessible_buffer = CpuAccessibleBuffer::from_iter(
|
/// let temporary_accessible_buffer = CpuAccessibleBuffer::from_iter(
|
||||||
/// device.clone(),
|
/// &memory_allocator,
|
||||||
/// BufferUsage { transfer_src: true, ..BufferUsage::empty() }, // Specify this buffer will be used as a transfer source.
|
/// BufferUsage { transfer_src: true, ..BufferUsage::empty() }, // Specify this buffer will be used as a transfer source.
|
||||||
/// false,
|
/// false,
|
||||||
/// data,
|
/// data,
|
||||||
@ -95,7 +91,7 @@ use std::{
|
|||||||
///
|
///
|
||||||
/// // Create a buffer array on the GPU with enough space for `10_000` floats.
|
/// // Create a buffer array on the GPU with enough space for `10_000` floats.
|
||||||
/// let device_local_buffer = DeviceLocalBuffer::<[f32]>::array(
|
/// let device_local_buffer = DeviceLocalBuffer::<[f32]>::array(
|
||||||
/// device.clone(),
|
/// &memory_allocator,
|
||||||
/// 10_000 as vulkano::DeviceSize,
|
/// 10_000 as vulkano::DeviceSize,
|
||||||
/// BufferUsage {
|
/// BufferUsage {
|
||||||
/// storage_buffer: true,
|
/// storage_buffer: true,
|
||||||
@ -129,7 +125,7 @@ use std::{
|
|||||||
/// .unwrap()
|
/// .unwrap()
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DeviceLocalBuffer<T, A = PotentialDedicatedAllocation<StandardMemoryPoolAlloc>>
|
pub struct DeviceLocalBuffer<T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized,
|
T: BufferContents + ?Sized,
|
||||||
{
|
{
|
||||||
@ -137,7 +133,7 @@ where
|
|||||||
inner: Arc<UnsafeBuffer>,
|
inner: Arc<UnsafeBuffer>,
|
||||||
|
|
||||||
// The memory held by the buffer.
|
// The memory held by the buffer.
|
||||||
memory: A,
|
memory: MemoryAlloc,
|
||||||
|
|
||||||
// Queue families allowed to access this buffer.
|
// Queue families allowed to access this buffer.
|
||||||
queue_family_indices: SmallVec<[u32; 4]>,
|
queue_family_indices: SmallVec<[u32; 4]>,
|
||||||
@ -156,13 +152,13 @@ where
|
|||||||
///
|
///
|
||||||
/// - Panics if `T` has zero size.
|
/// - Panics if `T` has zero size.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
usage: BufferUsage,
|
usage: BufferUsage,
|
||||||
queue_family_indices: impl IntoIterator<Item = u32>,
|
queue_family_indices: impl IntoIterator<Item = u32>,
|
||||||
) -> Result<Arc<DeviceLocalBuffer<T>>, DeviceMemoryError> {
|
) -> Result<Arc<DeviceLocalBuffer<T>>, AllocationCreationError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
DeviceLocalBuffer::raw(
|
DeviceLocalBuffer::raw(
|
||||||
device,
|
allocator,
|
||||||
size_of::<T>() as DeviceSize,
|
size_of::<T>() as DeviceSize,
|
||||||
usage,
|
usage,
|
||||||
queue_family_indices,
|
queue_family_indices,
|
||||||
@ -183,16 +179,12 @@ where
|
|||||||
///
|
///
|
||||||
/// `command_buffer_builder` can then be used to record other commands, built, and executed as
|
/// `command_buffer_builder` can then be used to record other commands, built, and executed as
|
||||||
/// normal. If it is not executed, the buffer contents will be left undefined.
|
/// normal. If it is not executed, the buffer contents will be left undefined.
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// - Panics if `usage.shader_device_address` is `true`.
|
|
||||||
// TODO: ^
|
|
||||||
pub fn from_buffer<B, L, A>(
|
pub fn from_buffer<B, L, A>(
|
||||||
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
source: Arc<B>,
|
source: Arc<B>,
|
||||||
usage: BufferUsage,
|
usage: BufferUsage,
|
||||||
command_buffer_builder: &mut AutoCommandBufferBuilder<L, A>,
|
command_buffer_builder: &mut AutoCommandBufferBuilder<L, A>,
|
||||||
) -> Result<Arc<DeviceLocalBuffer<T>>, DeviceLocalBufferCreationError>
|
) -> Result<Arc<DeviceLocalBuffer<T>>, AllocationCreationError>
|
||||||
where
|
where
|
||||||
B: TypedBufferAccess<Content = T> + 'static,
|
B: TypedBufferAccess<Content = T> + 'static,
|
||||||
A: CommandBufferAllocator,
|
A: CommandBufferAllocator,
|
||||||
@ -205,7 +197,7 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
let buffer = DeviceLocalBuffer::raw(
|
let buffer = DeviceLocalBuffer::raw(
|
||||||
source.device().clone(),
|
allocator,
|
||||||
source.size(),
|
source.size(),
|
||||||
actual_usage,
|
actual_usage,
|
||||||
source
|
source
|
||||||
@ -237,18 +229,17 @@ where
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// - Panics if `T` has zero size.
|
/// - Panics if `T` has zero size.
|
||||||
/// - Panics if `usage.shader_device_address` is `true`.
|
|
||||||
// TODO: ^
|
|
||||||
pub fn from_data<L, A>(
|
pub fn from_data<L, A>(
|
||||||
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
data: T,
|
data: T,
|
||||||
usage: BufferUsage,
|
usage: BufferUsage,
|
||||||
command_buffer_builder: &mut AutoCommandBufferBuilder<L, A>,
|
command_buffer_builder: &mut AutoCommandBufferBuilder<L, A>,
|
||||||
) -> Result<Arc<DeviceLocalBuffer<T>>, DeviceLocalBufferCreationError>
|
) -> Result<Arc<DeviceLocalBuffer<T>>, AllocationCreationError>
|
||||||
where
|
where
|
||||||
A: CommandBufferAllocator,
|
A: CommandBufferAllocator,
|
||||||
{
|
{
|
||||||
let source = CpuAccessibleBuffer::from_data(
|
let source = CpuAccessibleBuffer::from_data(
|
||||||
command_buffer_builder.device().clone(),
|
allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_src: true,
|
transfer_src: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -256,7 +247,7 @@ where
|
|||||||
false,
|
false,
|
||||||
data,
|
data,
|
||||||
)?;
|
)?;
|
||||||
DeviceLocalBuffer::from_buffer(source, usage, command_buffer_builder)
|
DeviceLocalBuffer::from_buffer(allocator, source, usage, command_buffer_builder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,20 +265,19 @@ where
|
|||||||
///
|
///
|
||||||
/// - Panics if `T` has zero size.
|
/// - Panics if `T` has zero size.
|
||||||
/// - Panics if `data` is empty.
|
/// - Panics if `data` is empty.
|
||||||
/// - Panics if `usage.shader_device_address` is `true`.
|
|
||||||
// TODO: ^
|
|
||||||
pub fn from_iter<D, L, A>(
|
pub fn from_iter<D, L, A>(
|
||||||
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
data: D,
|
data: D,
|
||||||
usage: BufferUsage,
|
usage: BufferUsage,
|
||||||
command_buffer_builder: &mut AutoCommandBufferBuilder<L, A>,
|
command_buffer_builder: &mut AutoCommandBufferBuilder<L, A>,
|
||||||
) -> Result<Arc<DeviceLocalBuffer<[T]>>, DeviceLocalBufferCreationError>
|
) -> Result<Arc<DeviceLocalBuffer<[T]>>, AllocationCreationError>
|
||||||
where
|
where
|
||||||
D: IntoIterator<Item = T>,
|
D: IntoIterator<Item = T>,
|
||||||
D::IntoIter: ExactSizeIterator,
|
D::IntoIter: ExactSizeIterator,
|
||||||
A: CommandBufferAllocator,
|
A: CommandBufferAllocator,
|
||||||
{
|
{
|
||||||
let source = CpuAccessibleBuffer::from_iter(
|
let source = CpuAccessibleBuffer::from_iter(
|
||||||
command_buffer_builder.device().clone(),
|
allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_src: true,
|
transfer_src: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -295,7 +285,7 @@ where
|
|||||||
false,
|
false,
|
||||||
data,
|
data,
|
||||||
)?;
|
)?;
|
||||||
DeviceLocalBuffer::from_buffer(source, usage, command_buffer_builder)
|
DeviceLocalBuffer::from_buffer(allocator, source, usage, command_buffer_builder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,17 +299,15 @@ where
|
|||||||
///
|
///
|
||||||
/// - Panics if `T` has zero size.
|
/// - Panics if `T` has zero size.
|
||||||
/// - Panics if `len` is zero.
|
/// - Panics if `len` is zero.
|
||||||
/// - Panics if `usage.shader_device_address` is `true`.
|
|
||||||
// TODO: ^
|
|
||||||
pub fn array(
|
pub fn array(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
len: DeviceSize,
|
len: DeviceSize,
|
||||||
usage: BufferUsage,
|
usage: BufferUsage,
|
||||||
queue_family_indices: impl IntoIterator<Item = u32>,
|
queue_family_indices: impl IntoIterator<Item = u32>,
|
||||||
) -> Result<Arc<DeviceLocalBuffer<[T]>>, DeviceMemoryError> {
|
) -> Result<Arc<DeviceLocalBuffer<[T]>>, AllocationCreationError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
DeviceLocalBuffer::raw(
|
DeviceLocalBuffer::raw(
|
||||||
device,
|
allocator,
|
||||||
len * size_of::<T>() as DeviceSize,
|
len * size_of::<T>() as DeviceSize,
|
||||||
usage,
|
usage,
|
||||||
queue_family_indices,
|
queue_family_indices,
|
||||||
@ -341,98 +329,16 @@ where
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// - Panics if `size` is zero.
|
/// - Panics if `size` is zero.
|
||||||
/// - Panics if `usage.shader_device_address` is `true`.
|
|
||||||
// TODO: ^
|
|
||||||
pub unsafe fn raw(
|
pub unsafe fn raw(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
size: DeviceSize,
|
size: DeviceSize,
|
||||||
usage: BufferUsage,
|
usage: BufferUsage,
|
||||||
queue_family_indices: impl IntoIterator<Item = u32>,
|
queue_family_indices: impl IntoIterator<Item = u32>,
|
||||||
) -> Result<Arc<DeviceLocalBuffer<T>>, DeviceMemoryError> {
|
) -> Result<Arc<DeviceLocalBuffer<T>>, AllocationCreationError> {
|
||||||
let queue_family_indices: SmallVec<[_; 4]> = queue_family_indices.into_iter().collect();
|
let queue_family_indices: SmallVec<[_; 4]> = queue_family_indices.into_iter().collect();
|
||||||
|
|
||||||
let (buffer, mem_reqs) = Self::build_buffer(&device, size, usage, &queue_family_indices)?;
|
let buffer = UnsafeBuffer::new(
|
||||||
|
allocator.device().clone(),
|
||||||
let memory = MemoryPool::alloc_from_requirements(
|
|
||||||
&device.standard_memory_pool(),
|
|
||||||
&mem_reqs,
|
|
||||||
AllocLayout::Linear,
|
|
||||||
MappingRequirement::DoNotMap,
|
|
||||||
Some(DedicatedAllocation::Buffer(&buffer)),
|
|
||||||
|t| {
|
|
||||||
if t.property_flags.device_local {
|
|
||||||
AllocFromRequirementsFilter::Preferred
|
|
||||||
} else {
|
|
||||||
AllocFromRequirementsFilter::Allowed
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
debug_assert!((memory.offset() % mem_reqs.alignment) == 0);
|
|
||||||
buffer.bind_memory(memory.memory(), memory.offset())?;
|
|
||||||
|
|
||||||
Ok(Arc::new(DeviceLocalBuffer {
|
|
||||||
inner: buffer,
|
|
||||||
memory,
|
|
||||||
queue_family_indices,
|
|
||||||
marker: PhantomData,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Same as `raw` but with exportable fd option for the allocated memory on Linux/BSD
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// - Panics if `size` is zero.
|
|
||||||
/// - Panics if `usage.shader_device_address` is `true`.
|
|
||||||
// TODO: ^
|
|
||||||
pub unsafe fn raw_with_exportable_fd(
|
|
||||||
device: Arc<Device>,
|
|
||||||
size: DeviceSize,
|
|
||||||
usage: BufferUsage,
|
|
||||||
queue_family_indices: impl IntoIterator<Item = u32>,
|
|
||||||
) -> Result<Arc<DeviceLocalBuffer<T>>, DeviceMemoryError> {
|
|
||||||
assert!(device.enabled_extensions().khr_external_memory_fd);
|
|
||||||
assert!(device.enabled_extensions().khr_external_memory);
|
|
||||||
|
|
||||||
let queue_family_indices: SmallVec<[_; 4]> = queue_family_indices.into_iter().collect();
|
|
||||||
|
|
||||||
let (buffer, mem_reqs) = Self::build_buffer(&device, size, usage, &queue_family_indices)?;
|
|
||||||
|
|
||||||
let memory = alloc_dedicated_with_exportable_fd(
|
|
||||||
device,
|
|
||||||
&mem_reqs,
|
|
||||||
AllocLayout::Linear,
|
|
||||||
MappingRequirement::DoNotMap,
|
|
||||||
DedicatedAllocation::Buffer(&buffer),
|
|
||||||
|t| {
|
|
||||||
if t.property_flags.device_local {
|
|
||||||
AllocFromRequirementsFilter::Preferred
|
|
||||||
} else {
|
|
||||||
AllocFromRequirementsFilter::Allowed
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
let mem_offset = memory.offset();
|
|
||||||
debug_assert!((mem_offset % mem_reqs.alignment) == 0);
|
|
||||||
buffer.bind_memory(memory.memory(), mem_offset)?;
|
|
||||||
|
|
||||||
Ok(Arc::new(DeviceLocalBuffer {
|
|
||||||
inner: buffer,
|
|
||||||
memory,
|
|
||||||
queue_family_indices,
|
|
||||||
marker: PhantomData,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn build_buffer(
|
|
||||||
device: &Arc<Device>,
|
|
||||||
size: DeviceSize,
|
|
||||||
usage: BufferUsage,
|
|
||||||
queue_family_indices: &SmallVec<[u32; 4]>,
|
|
||||||
) -> Result<(Arc<UnsafeBuffer>, MemoryRequirements), DeviceMemoryError> {
|
|
||||||
let buffer = {
|
|
||||||
match UnsafeBuffer::new(
|
|
||||||
device.clone(),
|
|
||||||
UnsafeBufferCreateInfo {
|
UnsafeBufferCreateInfo {
|
||||||
sharing: if queue_family_indices.len() >= 2 {
|
sharing: if queue_family_indices.len() >= 2 {
|
||||||
Sharing::Concurrent(queue_family_indices.clone())
|
Sharing::Concurrent(queue_family_indices.clone())
|
||||||
@ -443,16 +349,124 @@ where
|
|||||||
usage,
|
usage,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
) {
|
)
|
||||||
Ok(b) => b,
|
.map_err(|err| match err {
|
||||||
Err(BufferCreationError::AllocError(err)) => return Err(err),
|
BufferCreationError::AllocError(err) => err,
|
||||||
Err(_) => unreachable!(), // We don't use sparse binding, therefore the other
|
// We don't use sparse-binding, therefore the other errors can't happen.
|
||||||
// errors can't happen
|
_ => unreachable!(),
|
||||||
}
|
})?;
|
||||||
|
let requirements = buffer.memory_requirements();
|
||||||
|
let create_info = AllocationCreateInfo {
|
||||||
|
requirements,
|
||||||
|
allocation_type: AllocationType::Linear,
|
||||||
|
usage: MemoryUsage::GpuOnly,
|
||||||
|
allocate_preference: MemoryAllocatePreference::Unknown,
|
||||||
|
dedicated_allocation: Some(DedicatedAllocation::Buffer(&buffer)),
|
||||||
|
..Default::default()
|
||||||
};
|
};
|
||||||
let mem_reqs = buffer.memory_requirements();
|
|
||||||
|
|
||||||
Ok((buffer, mem_reqs))
|
match allocator.allocate_unchecked(create_info) {
|
||||||
|
Ok(alloc) => {
|
||||||
|
debug_assert!(alloc.offset() % requirements.alignment == 0);
|
||||||
|
debug_assert!(alloc.size() == requirements.size);
|
||||||
|
buffer.bind_memory(alloc.device_memory(), alloc.offset())?;
|
||||||
|
|
||||||
|
Ok(Arc::new(DeviceLocalBuffer {
|
||||||
|
inner: buffer,
|
||||||
|
memory: alloc,
|
||||||
|
queue_family_indices,
|
||||||
|
marker: PhantomData,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
Err(err) => Err(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as `raw` but with exportable fd option for the allocated memory on Linux/BSD
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// - Panics if `size` is zero.
|
||||||
|
pub unsafe fn raw_with_exportable_fd(
|
||||||
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
|
size: DeviceSize,
|
||||||
|
usage: BufferUsage,
|
||||||
|
queue_family_indices: impl IntoIterator<Item = u32>,
|
||||||
|
) -> Result<Arc<DeviceLocalBuffer<T>>, AllocationCreationError> {
|
||||||
|
let enabled_extensions = allocator.device().enabled_extensions();
|
||||||
|
assert!(enabled_extensions.khr_external_memory_fd);
|
||||||
|
assert!(enabled_extensions.khr_external_memory);
|
||||||
|
|
||||||
|
let queue_family_indices: SmallVec<[_; 4]> = queue_family_indices.into_iter().collect();
|
||||||
|
|
||||||
|
let external_memory_properties = allocator
|
||||||
|
.device()
|
||||||
|
.physical_device()
|
||||||
|
.external_buffer_properties(ExternalBufferInfo {
|
||||||
|
usage,
|
||||||
|
..ExternalBufferInfo::handle_type(ExternalMemoryHandleType::OpaqueFd)
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
.external_memory_properties;
|
||||||
|
// VUID-VkExportMemoryAllocateInfo-handleTypes-00656
|
||||||
|
assert!(external_memory_properties.exportable);
|
||||||
|
|
||||||
|
// VUID-VkMemoryAllocateInfo-pNext-00639
|
||||||
|
// Guaranteed because we always create a dedicated allocation
|
||||||
|
|
||||||
|
let external_memory_handle_types = ExternalMemoryHandleTypes {
|
||||||
|
opaque_fd: true,
|
||||||
|
..ExternalMemoryHandleTypes::empty()
|
||||||
|
};
|
||||||
|
let buffer = UnsafeBuffer::new(
|
||||||
|
allocator.device().clone(),
|
||||||
|
UnsafeBufferCreateInfo {
|
||||||
|
sharing: if queue_family_indices.len() >= 2 {
|
||||||
|
Sharing::Concurrent(queue_family_indices.clone())
|
||||||
|
} else {
|
||||||
|
Sharing::Exclusive
|
||||||
|
},
|
||||||
|
size,
|
||||||
|
usage,
|
||||||
|
external_memory_handle_types,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.map_err(|err| match err {
|
||||||
|
BufferCreationError::AllocError(err) => err,
|
||||||
|
// We don't use sparse-binding, therefore the other errors can't happen.
|
||||||
|
_ => unreachable!(),
|
||||||
|
})?;
|
||||||
|
let requirements = buffer.memory_requirements();
|
||||||
|
let memory_type_index = allocator
|
||||||
|
.find_memory_type_index(requirements.memory_type_bits, MemoryUsage::GpuOnly.into())
|
||||||
|
.expect("failed to find a suitable memory type");
|
||||||
|
|
||||||
|
let memory_properties = allocator.device().physical_device().memory_properties();
|
||||||
|
let heap_index = memory_properties.memory_types[memory_type_index as usize].heap_index;
|
||||||
|
// VUID-vkAllocateMemory-pAllocateInfo-01713
|
||||||
|
assert!(size <= memory_properties.memory_heaps[heap_index as usize].size);
|
||||||
|
|
||||||
|
match allocator.allocate_dedicated_unchecked(
|
||||||
|
memory_type_index,
|
||||||
|
requirements.size,
|
||||||
|
Some(DedicatedAllocation::Buffer(&buffer)),
|
||||||
|
external_memory_handle_types,
|
||||||
|
) {
|
||||||
|
Ok(alloc) => {
|
||||||
|
debug_assert!(alloc.offset() % requirements.alignment == 0);
|
||||||
|
debug_assert!(alloc.size() == requirements.size);
|
||||||
|
buffer.bind_memory(alloc.device_memory(), alloc.offset())?;
|
||||||
|
|
||||||
|
Ok(Arc::new(DeviceLocalBuffer {
|
||||||
|
inner: buffer,
|
||||||
|
memory: alloc,
|
||||||
|
queue_family_indices,
|
||||||
|
marker: PhantomData,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
Err(err) => Err(err),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Exports posix file descriptor for the allocated memory
|
/// Exports posix file descriptor for the allocated memory
|
||||||
@ -460,12 +474,12 @@ where
|
|||||||
/// Only works on Linux/BSD.
|
/// Only works on Linux/BSD.
|
||||||
pub fn export_posix_fd(&self) -> Result<File, DeviceMemoryError> {
|
pub fn export_posix_fd(&self) -> Result<File, DeviceMemoryError> {
|
||||||
self.memory
|
self.memory
|
||||||
.memory()
|
.device_memory()
|
||||||
.export_fd(ExternalMemoryHandleType::OpaqueFd)
|
.export_fd(ExternalMemoryHandleType::OpaqueFd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> DeviceLocalBuffer<T, A>
|
impl<T> DeviceLocalBuffer<T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized,
|
T: BufferContents + ?Sized,
|
||||||
{
|
{
|
||||||
@ -475,7 +489,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, A> DeviceOwned for DeviceLocalBuffer<T, A>
|
unsafe impl<T> DeviceOwned for DeviceLocalBuffer<T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized,
|
T: BufferContents + ?Sized,
|
||||||
{
|
{
|
||||||
@ -484,10 +498,9 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, A> BufferAccess for DeviceLocalBuffer<T, A>
|
unsafe impl<T> BufferAccess for DeviceLocalBuffer<T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized,
|
T: BufferContents + ?Sized,
|
||||||
A: Send + Sync,
|
|
||||||
{
|
{
|
||||||
fn inner(&self) -> BufferInner<'_> {
|
fn inner(&self) -> BufferInner<'_> {
|
||||||
BufferInner {
|
BufferInner {
|
||||||
@ -501,45 +514,36 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> BufferAccessObject for Arc<DeviceLocalBuffer<T, A>>
|
impl<T> BufferAccessObject for Arc<DeviceLocalBuffer<T>>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized,
|
T: BufferContents + ?Sized,
|
||||||
A: Send + Sync + 'static,
|
|
||||||
{
|
{
|
||||||
fn as_buffer_access_object(&self) -> Arc<dyn BufferAccess> {
|
fn as_buffer_access_object(&self) -> Arc<dyn BufferAccess> {
|
||||||
self.clone()
|
self.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T, A> TypedBufferAccess for DeviceLocalBuffer<T, A>
|
unsafe impl<T> TypedBufferAccess for DeviceLocalBuffer<T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized,
|
T: BufferContents + ?Sized,
|
||||||
A: Send + Sync,
|
|
||||||
{
|
{
|
||||||
type Content = T;
|
type Content = T;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> PartialEq for DeviceLocalBuffer<T, A>
|
impl<T> PartialEq for DeviceLocalBuffer<T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized,
|
T: BufferContents + ?Sized,
|
||||||
A: Send + Sync,
|
|
||||||
{
|
{
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.inner() == other.inner() && self.size() == other.size()
|
self.inner() == other.inner() && self.size() == other.size()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> Eq for DeviceLocalBuffer<T, A>
|
impl<T> Eq for DeviceLocalBuffer<T> where T: BufferContents + ?Sized {}
|
||||||
where
|
|
||||||
T: BufferContents + ?Sized,
|
|
||||||
A: Send + Sync,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, A> Hash for DeviceLocalBuffer<T, A>
|
impl<T> Hash for DeviceLocalBuffer<T>
|
||||||
where
|
where
|
||||||
T: BufferContents + ?Sized,
|
T: BufferContents + ?Sized,
|
||||||
A: Send + Sync,
|
|
||||||
{
|
{
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.inner().hash(state);
|
self.inner().hash(state);
|
||||||
@ -547,42 +551,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum DeviceLocalBufferCreationError {
|
|
||||||
DeviceMemoryAllocationError(DeviceMemoryError),
|
|
||||||
CommandBufferBeginError(CommandBufferBeginError),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for DeviceLocalBufferCreationError {
|
|
||||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
|
||||||
match self {
|
|
||||||
Self::DeviceMemoryAllocationError(err) => Some(err),
|
|
||||||
Self::CommandBufferBeginError(err) => Some(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for DeviceLocalBufferCreationError {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
|
|
||||||
match self {
|
|
||||||
Self::DeviceMemoryAllocationError(err) => err.fmt(f),
|
|
||||||
Self::CommandBufferBeginError(err) => err.fmt(f),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<DeviceMemoryError> for DeviceLocalBufferCreationError {
|
|
||||||
fn from(e: DeviceMemoryError) -> Self {
|
|
||||||
Self::DeviceMemoryAllocationError(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<CommandBufferBeginError> for DeviceLocalBufferCreationError {
|
|
||||||
fn from(e: CommandBufferBeginError) -> Self {
|
|
||||||
Self::CommandBufferBeginError(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -591,6 +559,7 @@ mod tests {
|
|||||||
allocator::StandardCommandBufferAllocator, CommandBufferUsage,
|
allocator::StandardCommandBufferAllocator, CommandBufferUsage,
|
||||||
PrimaryCommandBufferAbstract,
|
PrimaryCommandBufferAbstract,
|
||||||
},
|
},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
sync::GpuFuture,
|
sync::GpuFuture,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -605,8 +574,10 @@ mod tests {
|
|||||||
CommandBufferUsage::OneTimeSubmit,
|
CommandBufferUsage::OneTimeSubmit,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
|
|
||||||
let buffer = DeviceLocalBuffer::from_data(
|
let buffer = DeviceLocalBuffer::from_data(
|
||||||
|
&memory_allocator,
|
||||||
12u32,
|
12u32,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_src: true,
|
transfer_src: true,
|
||||||
@ -617,7 +588,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let destination = CpuAccessibleBuffer::from_data(
|
let destination = CpuAccessibleBuffer::from_data(
|
||||||
device,
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_dst: true,
|
transfer_dst: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -653,8 +624,10 @@ mod tests {
|
|||||||
CommandBufferUsage::OneTimeSubmit,
|
CommandBufferUsage::OneTimeSubmit,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let allocator = StandardMemoryAllocator::new_default(device);
|
||||||
|
|
||||||
let buffer = DeviceLocalBuffer::from_iter(
|
let buffer = DeviceLocalBuffer::from_iter(
|
||||||
|
&allocator,
|
||||||
(0..512u32).map(|n| n * 2),
|
(0..512u32).map(|n| n * 2),
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_src: true,
|
transfer_src: true,
|
||||||
@ -665,7 +638,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let destination = CpuAccessibleBuffer::from_iter(
|
let destination = CpuAccessibleBuffer::from_iter(
|
||||||
device,
|
&allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_dst: true,
|
transfer_dst: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -697,16 +670,18 @@ mod tests {
|
|||||||
fn create_buffer_zero_size_data() {
|
fn create_buffer_zero_size_data() {
|
||||||
let (device, queue) = gfx_dev_and_queue!();
|
let (device, queue) = gfx_dev_and_queue!();
|
||||||
|
|
||||||
let command_buffer_allocator = StandardCommandBufferAllocator::new(device);
|
let command_buffer_allocator = StandardCommandBufferAllocator::new(device.clone());
|
||||||
let mut command_buffer_builder = AutoCommandBufferBuilder::primary(
|
let mut command_buffer_builder = AutoCommandBufferBuilder::primary(
|
||||||
&command_buffer_allocator,
|
&command_buffer_allocator,
|
||||||
queue.queue_family_index(),
|
queue.queue_family_index(),
|
||||||
CommandBufferUsage::OneTimeSubmit,
|
CommandBufferUsage::OneTimeSubmit,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let allocator = StandardMemoryAllocator::new_default(device);
|
||||||
|
|
||||||
assert_should_panic!({
|
assert_should_panic!({
|
||||||
DeviceLocalBuffer::from_data(
|
DeviceLocalBuffer::from_data(
|
||||||
|
&allocator,
|
||||||
(),
|
(),
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_dst: true,
|
transfer_dst: true,
|
||||||
|
@ -31,7 +31,10 @@ use super::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
device::{Device, DeviceOwned},
|
device::{Device, DeviceOwned},
|
||||||
macros::vulkan_bitflags,
|
macros::vulkan_bitflags,
|
||||||
memory::{DeviceMemory, DeviceMemoryError, ExternalMemoryHandleTypes, MemoryRequirements},
|
memory::{
|
||||||
|
allocator::AllocationCreationError, DeviceMemory, ExternalMemoryHandleTypes,
|
||||||
|
MemoryRequirements,
|
||||||
|
},
|
||||||
range_map::RangeMap,
|
range_map::RangeMap,
|
||||||
sync::{AccessError, CurrentAccess, Sharing},
|
sync::{AccessError, CurrentAccess, Sharing},
|
||||||
DeviceSize, OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
|
DeviceSize, OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
|
||||||
@ -584,7 +587,7 @@ impl Default for UnsafeBufferCreateInfo {
|
|||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum BufferCreationError {
|
pub enum BufferCreationError {
|
||||||
/// Allocating memory failed.
|
/// Allocating memory failed.
|
||||||
AllocError(DeviceMemoryError),
|
AllocError(AllocationCreationError),
|
||||||
|
|
||||||
RequirementNotMet {
|
RequirementNotMet {
|
||||||
required_for: &'static str,
|
required_for: &'static str,
|
||||||
@ -645,11 +648,11 @@ impl From<OomError> for BufferCreationError {
|
|||||||
impl From<VulkanError> for BufferCreationError {
|
impl From<VulkanError> for BufferCreationError {
|
||||||
fn from(err: VulkanError) -> BufferCreationError {
|
fn from(err: VulkanError) -> BufferCreationError {
|
||||||
match err {
|
match err {
|
||||||
err @ VulkanError::OutOfHostMemory => {
|
VulkanError::OutOfHostMemory => {
|
||||||
BufferCreationError::AllocError(DeviceMemoryError::from(err))
|
BufferCreationError::AllocError(AllocationCreationError::OutOfHostMemory)
|
||||||
}
|
}
|
||||||
err @ VulkanError::OutOfDeviceMemory => {
|
VulkanError::OutOfDeviceMemory => {
|
||||||
BufferCreationError::AllocError(DeviceMemoryError::from(err))
|
BufferCreationError::AllocError(AllocationCreationError::OutOfDeviceMemory)
|
||||||
}
|
}
|
||||||
_ => panic!("unexpected error: {:?}", err),
|
_ => panic!("unexpected error: {:?}", err),
|
||||||
}
|
}
|
||||||
|
@ -24,26 +24,28 @@
|
|||||||
//! use vulkano::buffer::view::{BufferView, BufferViewCreateInfo};
|
//! use vulkano::buffer::view::{BufferView, BufferViewCreateInfo};
|
||||||
//! use vulkano::format::Format;
|
//! use vulkano::format::Format;
|
||||||
//!
|
//!
|
||||||
//! # let device: Arc<vulkano::device::Device> = return;
|
|
||||||
//! # let queue: Arc<vulkano::device::Queue> = return;
|
//! # let queue: Arc<vulkano::device::Queue> = return;
|
||||||
|
//! # let memory_allocator: vulkano::memory::allocator::StandardMemoryAllocator = return;
|
||||||
//! let usage = BufferUsage {
|
//! let usage = BufferUsage {
|
||||||
//! storage_texel_buffer: true,
|
//! storage_texel_buffer: true,
|
||||||
//! ..BufferUsage::empty()
|
//! ..BufferUsage::empty()
|
||||||
//! };
|
//! };
|
||||||
//!
|
//!
|
||||||
//! let buffer = DeviceLocalBuffer::<[u32]>::array(
|
//! let buffer = DeviceLocalBuffer::<[u32]>::array(
|
||||||
//! device.clone(),
|
//! &memory_allocator,
|
||||||
//! 128,
|
//! 128,
|
||||||
//! usage,
|
//! usage,
|
||||||
//! [queue.queue_family_index()],
|
//! [queue.queue_family_index()],
|
||||||
//! ).unwrap();
|
//! )
|
||||||
|
//! .unwrap();
|
||||||
//! let _view = BufferView::new(
|
//! let _view = BufferView::new(
|
||||||
//! buffer,
|
//! buffer,
|
||||||
//! BufferViewCreateInfo {
|
//! BufferViewCreateInfo {
|
||||||
//! format: Some(Format::R32_UINT),
|
//! format: Some(Format::R32_UINT),
|
||||||
//! ..Default::default()
|
//! ..Default::default()
|
||||||
//! },
|
//! },
|
||||||
//! ).unwrap();
|
//! )
|
||||||
|
//! .unwrap();
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use super::{BufferAccess, BufferAccessObject, BufferInner};
|
use super::{BufferAccess, BufferAccessObject, BufferInner};
|
||||||
@ -477,26 +479,30 @@ impl Hash for dyn BufferViewAbstract {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use super::{BufferView, BufferViewCreateInfo, BufferViewCreationError};
|
||||||
use crate::{
|
use crate::{
|
||||||
buffer::{
|
buffer::{BufferUsage, DeviceLocalBuffer},
|
||||||
view::{BufferView, BufferViewCreateInfo, BufferViewCreationError},
|
|
||||||
BufferUsage, DeviceLocalBuffer,
|
|
||||||
},
|
|
||||||
format::Format,
|
format::Format,
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create_uniform() {
|
fn create_uniform() {
|
||||||
// `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
|
// `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 memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
|
|
||||||
let usage = BufferUsage {
|
let usage = BufferUsage {
|
||||||
uniform_texel_buffer: true,
|
uniform_texel_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
};
|
};
|
||||||
|
|
||||||
let buffer =
|
let buffer = DeviceLocalBuffer::<[[u8; 4]]>::array(
|
||||||
DeviceLocalBuffer::<[[u8; 4]]>::array(device, 128, usage, [queue.queue_family_index()])
|
&memory_allocator,
|
||||||
|
128,
|
||||||
|
usage,
|
||||||
|
[queue.queue_family_index()],
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
BufferView::new(
|
BufferView::new(
|
||||||
buffer,
|
buffer,
|
||||||
@ -512,14 +518,19 @@ mod tests {
|
|||||||
fn create_storage() {
|
fn create_storage() {
|
||||||
// `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
|
// `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 memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
|
|
||||||
let usage = BufferUsage {
|
let usage = BufferUsage {
|
||||||
storage_texel_buffer: true,
|
storage_texel_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
};
|
};
|
||||||
|
|
||||||
let buffer =
|
let buffer = DeviceLocalBuffer::<[[u8; 4]]>::array(
|
||||||
DeviceLocalBuffer::<[[u8; 4]]>::array(device, 128, usage, [queue.queue_family_index()])
|
&memory_allocator,
|
||||||
|
128,
|
||||||
|
usage,
|
||||||
|
[queue.queue_family_index()],
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
BufferView::new(
|
BufferView::new(
|
||||||
buffer,
|
buffer,
|
||||||
@ -535,14 +546,19 @@ mod tests {
|
|||||||
fn create_storage_atomic() {
|
fn create_storage_atomic() {
|
||||||
// `VK_FORMAT_R32_UINT` guaranteed to be a supported format for atomics
|
// `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 memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
|
|
||||||
let usage = BufferUsage {
|
let usage = BufferUsage {
|
||||||
storage_texel_buffer: true,
|
storage_texel_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
};
|
};
|
||||||
|
|
||||||
let buffer =
|
let buffer = DeviceLocalBuffer::<[u32]>::array(
|
||||||
DeviceLocalBuffer::<[u32]>::array(device, 128, usage, [queue.queue_family_index()])
|
&memory_allocator,
|
||||||
|
128,
|
||||||
|
usage,
|
||||||
|
[queue.queue_family_index()],
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
BufferView::new(
|
BufferView::new(
|
||||||
buffer,
|
buffer,
|
||||||
@ -558,9 +574,10 @@ mod tests {
|
|||||||
fn wrong_usage() {
|
fn wrong_usage() {
|
||||||
// `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
|
// `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 memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
|
|
||||||
let buffer = DeviceLocalBuffer::<[[u8; 4]]>::array(
|
let buffer = DeviceLocalBuffer::<[[u8; 4]]>::array(
|
||||||
device,
|
&memory_allocator,
|
||||||
128,
|
128,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_dst: true, // Dummy value
|
transfer_dst: true, // Dummy value
|
||||||
@ -585,6 +602,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn unsupported_format() {
|
fn unsupported_format() {
|
||||||
let (device, queue) = gfx_dev_and_queue!();
|
let (device, queue) = gfx_dev_and_queue!();
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
|
|
||||||
let usage = BufferUsage {
|
let usage = BufferUsage {
|
||||||
uniform_texel_buffer: true,
|
uniform_texel_buffer: true,
|
||||||
@ -593,7 +611,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let buffer = DeviceLocalBuffer::<[[f64; 4]]>::array(
|
let buffer = DeviceLocalBuffer::<[[f64; 4]]>::array(
|
||||||
device,
|
&memory_allocator,
|
||||||
128,
|
128,
|
||||||
usage,
|
usage,
|
||||||
[queue.queue_family_index()],
|
[queue.queue_family_index()],
|
||||||
|
@ -727,6 +727,12 @@ pub struct PrimaryAutoCommandBuffer<A = StandardCommandBufferAlloc> {
|
|||||||
state: Mutex<CommandBufferState>,
|
state: Mutex<CommandBufferState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl<A> DeviceOwned for PrimaryAutoCommandBuffer<A> {
|
||||||
|
fn device(&self) -> &Arc<Device> {
|
||||||
|
self.inner.device()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsafe impl<A> VulkanObject for PrimaryAutoCommandBuffer<A> {
|
unsafe impl<A> VulkanObject for PrimaryAutoCommandBuffer<A> {
|
||||||
type Handle = ash::vk::CommandBuffer;
|
type Handle = ash::vk::CommandBuffer;
|
||||||
|
|
||||||
@ -735,12 +741,6 @@ unsafe impl<A> VulkanObject for PrimaryAutoCommandBuffer<A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<A> DeviceOwned for PrimaryAutoCommandBuffer<A> {
|
|
||||||
fn device(&self) -> &Arc<Device> {
|
|
||||||
self.inner.device()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<A> PrimaryCommandBufferAbstract for PrimaryAutoCommandBuffer<A>
|
unsafe impl<A> PrimaryCommandBufferAbstract for PrimaryAutoCommandBuffer<A>
|
||||||
where
|
where
|
||||||
A: CommandBufferAlloc,
|
A: CommandBufferAlloc,
|
||||||
@ -918,6 +918,7 @@ mod tests {
|
|||||||
ExecuteCommandsError,
|
ExecuteCommandsError,
|
||||||
},
|
},
|
||||||
device::{DeviceCreateInfo, QueueCreateInfo},
|
device::{DeviceCreateInfo, QueueCreateInfo},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
sync::GpuFuture,
|
sync::GpuFuture,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -943,9 +944,10 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let queue = queues.next().unwrap();
|
let queue = queues.next().unwrap();
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
|
|
||||||
let source = CpuAccessibleBuffer::from_iter(
|
let source = CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_src: true,
|
transfer_src: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -956,7 +958,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let destination = CpuAccessibleBuffer::from_iter(
|
let destination = CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_dst: true,
|
transfer_dst: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -966,9 +968,9 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let allocator = StandardCommandBufferAllocator::new(device);
|
let cb_allocator = StandardCommandBufferAllocator::new(device);
|
||||||
let mut cbb = AutoCommandBufferBuilder::primary(
|
let mut cbb = AutoCommandBufferBuilder::primary(
|
||||||
&allocator,
|
&cb_allocator,
|
||||||
queue.queue_family_index(),
|
queue.queue_family_index(),
|
||||||
CommandBufferUsage::OneTimeSubmit,
|
CommandBufferUsage::OneTimeSubmit,
|
||||||
)
|
)
|
||||||
@ -1004,11 +1006,11 @@ mod tests {
|
|||||||
fn secondary_nonconcurrent_conflict() {
|
fn secondary_nonconcurrent_conflict() {
|
||||||
let (device, queue) = gfx_dev_and_queue!();
|
let (device, queue) = gfx_dev_and_queue!();
|
||||||
|
|
||||||
let allocator = StandardCommandBufferAllocator::new(device);
|
let cb_allocator = StandardCommandBufferAllocator::new(device);
|
||||||
|
|
||||||
// Make a secondary CB that doesn't support simultaneous use.
|
// Make a secondary CB that doesn't support simultaneous use.
|
||||||
let builder = AutoCommandBufferBuilder::secondary(
|
let builder = AutoCommandBufferBuilder::secondary(
|
||||||
&allocator,
|
&cb_allocator,
|
||||||
queue.queue_family_index(),
|
queue.queue_family_index(),
|
||||||
CommandBufferUsage::MultipleSubmit,
|
CommandBufferUsage::MultipleSubmit,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
@ -1018,7 +1020,7 @@ mod tests {
|
|||||||
|
|
||||||
{
|
{
|
||||||
let mut builder = AutoCommandBufferBuilder::primary(
|
let mut builder = AutoCommandBufferBuilder::primary(
|
||||||
&allocator,
|
&cb_allocator,
|
||||||
queue.queue_family_index(),
|
queue.queue_family_index(),
|
||||||
CommandBufferUsage::SimultaneousUse,
|
CommandBufferUsage::SimultaneousUse,
|
||||||
)
|
)
|
||||||
@ -1041,7 +1043,7 @@ mod tests {
|
|||||||
|
|
||||||
{
|
{
|
||||||
let mut builder = AutoCommandBufferBuilder::primary(
|
let mut builder = AutoCommandBufferBuilder::primary(
|
||||||
&allocator,
|
&cb_allocator,
|
||||||
queue.queue_family_index(),
|
queue.queue_family_index(),
|
||||||
CommandBufferUsage::SimultaneousUse,
|
CommandBufferUsage::SimultaneousUse,
|
||||||
)
|
)
|
||||||
@ -1050,7 +1052,7 @@ mod tests {
|
|||||||
let cb1 = builder.build().unwrap();
|
let cb1 = builder.build().unwrap();
|
||||||
|
|
||||||
let mut builder = AutoCommandBufferBuilder::primary(
|
let mut builder = AutoCommandBufferBuilder::primary(
|
||||||
&allocator,
|
&cb_allocator,
|
||||||
queue.queue_family_index(),
|
queue.queue_family_index(),
|
||||||
CommandBufferUsage::SimultaneousUse,
|
CommandBufferUsage::SimultaneousUse,
|
||||||
)
|
)
|
||||||
@ -1078,8 +1080,9 @@ mod tests {
|
|||||||
fn buffer_self_copy_overlapping() {
|
fn buffer_self_copy_overlapping() {
|
||||||
let (device, queue) = gfx_dev_and_queue!();
|
let (device, queue) = gfx_dev_and_queue!();
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
let source = CpuAccessibleBuffer::from_iter(
|
let source = CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_src: true,
|
transfer_src: true,
|
||||||
transfer_dst: true,
|
transfer_dst: true,
|
||||||
@ -1090,9 +1093,9 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let allocator = StandardCommandBufferAllocator::new(device);
|
let cb_allocator = StandardCommandBufferAllocator::new(device);
|
||||||
let mut builder = AutoCommandBufferBuilder::primary(
|
let mut builder = AutoCommandBufferBuilder::primary(
|
||||||
&allocator,
|
&cb_allocator,
|
||||||
queue.queue_family_index(),
|
queue.queue_family_index(),
|
||||||
CommandBufferUsage::OneTimeSubmit,
|
CommandBufferUsage::OneTimeSubmit,
|
||||||
)
|
)
|
||||||
@ -1129,8 +1132,9 @@ mod tests {
|
|||||||
fn buffer_self_copy_not_overlapping() {
|
fn buffer_self_copy_not_overlapping() {
|
||||||
let (device, queue) = gfx_dev_and_queue!();
|
let (device, queue) = gfx_dev_and_queue!();
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
let source = CpuAccessibleBuffer::from_iter(
|
let source = CpuAccessibleBuffer::from_iter(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_src: true,
|
transfer_src: true,
|
||||||
transfer_dst: true,
|
transfer_dst: true,
|
||||||
@ -1141,9 +1145,9 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let allocator = StandardCommandBufferAllocator::new(device);
|
let cb_allocator = StandardCommandBufferAllocator::new(device);
|
||||||
let mut builder = AutoCommandBufferBuilder::primary(
|
let mut builder = AutoCommandBufferBuilder::primary(
|
||||||
&allocator,
|
&cb_allocator,
|
||||||
queue.queue_family_index(),
|
queue.queue_family_index(),
|
||||||
CommandBufferUsage::OneTimeSubmit,
|
CommandBufferUsage::OneTimeSubmit,
|
||||||
)
|
)
|
||||||
|
@ -377,6 +377,7 @@ mod tests {
|
|||||||
},
|
},
|
||||||
PersistentDescriptorSet, WriteDescriptorSet,
|
PersistentDescriptorSet, WriteDescriptorSet,
|
||||||
},
|
},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{layout::PipelineLayoutCreateInfo, PipelineBindPoint, PipelineLayout},
|
pipeline::{layout::PipelineLayoutCreateInfo, PipelineBindPoint, PipelineLayout},
|
||||||
sampler::{Sampler, SamplerCreateInfo},
|
sampler::{Sampler, SamplerCreateInfo},
|
||||||
shader::ShaderStages,
|
shader::ShaderStages,
|
||||||
@ -412,27 +413,28 @@ mod tests {
|
|||||||
unsafe {
|
unsafe {
|
||||||
let (device, queue) = gfx_dev_and_queue!();
|
let (device, queue) = gfx_dev_and_queue!();
|
||||||
|
|
||||||
let command_buffer_allocator = StandardCommandBufferAllocator::new(device);
|
let cb_allocator = StandardCommandBufferAllocator::new(device.clone());
|
||||||
let mut command_buffer_builder = AutoCommandBufferBuilder::primary(
|
let mut cbb = AutoCommandBufferBuilder::primary(
|
||||||
&command_buffer_allocator,
|
&cb_allocator,
|
||||||
queue.queue_family_index(),
|
queue.queue_family_index(),
|
||||||
CommandBufferUsage::OneTimeSubmit,
|
CommandBufferUsage::OneTimeSubmit,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
// Create a tiny test buffer
|
// Create a tiny test buffer
|
||||||
let buffer = DeviceLocalBuffer::from_data(
|
let buffer = DeviceLocalBuffer::from_data(
|
||||||
|
&memory_allocator,
|
||||||
0u32,
|
0u32,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_dst: true,
|
transfer_dst: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
},
|
},
|
||||||
&mut command_buffer_builder,
|
&mut cbb,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
command_buffer_builder
|
cbb.build()
|
||||||
.build()
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.execute(queue.clone())
|
.execute(queue.clone())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -445,7 +447,7 @@ mod tests {
|
|||||||
let secondary = (0..2)
|
let secondary = (0..2)
|
||||||
.map(|_| {
|
.map(|_| {
|
||||||
let mut builder = AutoCommandBufferBuilder::secondary(
|
let mut builder = AutoCommandBufferBuilder::secondary(
|
||||||
&command_buffer_allocator,
|
&cb_allocator,
|
||||||
queue.queue_family_index(),
|
queue.queue_family_index(),
|
||||||
CommandBufferUsage::SimultaneousUse,
|
CommandBufferUsage::SimultaneousUse,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
@ -461,7 +463,7 @@ mod tests {
|
|||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let allocs = command_buffer_allocator
|
let allocs = cb_allocator
|
||||||
.allocate(queue.queue_family_index(), CommandBufferLevel::Primary, 2)
|
.allocate(queue.queue_family_index(), CommandBufferLevel::Primary, 2)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
@ -520,9 +522,8 @@ mod tests {
|
|||||||
unsafe {
|
unsafe {
|
||||||
let (device, queue) = gfx_dev_and_queue!();
|
let (device, queue) = gfx_dev_and_queue!();
|
||||||
|
|
||||||
let allocator = StandardCommandBufferAllocator::new(device.clone());
|
let cb_allocator = StandardCommandBufferAllocator::new(device.clone());
|
||||||
|
let builder_alloc = cb_allocator
|
||||||
let builder_alloc = allocator
|
|
||||||
.allocate(queue.queue_family_index(), CommandBufferLevel::Primary, 1)
|
.allocate(queue.queue_family_index(), CommandBufferLevel::Primary, 1)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.next()
|
.next()
|
||||||
@ -535,8 +536,10 @@ mod tests {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
let buf = CpuAccessibleBuffer::from_data(
|
let buf = CpuAccessibleBuffer::from_data(
|
||||||
device,
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
vertex_buffer: true,
|
vertex_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -114,9 +114,8 @@ pub use crate::{
|
|||||||
fns::DeviceFunctions,
|
fns::DeviceFunctions,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
instance::Instance,
|
instance::Instance, memory::ExternalMemoryHandleType, OomError, RequirementNotMet,
|
||||||
memory::{pool::StandardMemoryPool, ExternalMemoryHandleType},
|
RequiresOneOf, Version, VulkanError, VulkanObject,
|
||||||
OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
|
|
||||||
};
|
};
|
||||||
use ash::vk::Handle;
|
use ash::vk::Handle;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
@ -132,7 +131,7 @@ use std::{
|
|||||||
ptr,
|
ptr,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicU32, Ordering},
|
atomic::{AtomicU32, Ordering},
|
||||||
Arc, Weak,
|
Arc,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -153,7 +152,6 @@ pub struct Device {
|
|||||||
api_version: Version,
|
api_version: Version,
|
||||||
|
|
||||||
fns: DeviceFunctions,
|
fns: DeviceFunctions,
|
||||||
standard_memory_pool: Mutex<Weak<StandardMemoryPool>>,
|
|
||||||
enabled_extensions: DeviceExtensions,
|
enabled_extensions: DeviceExtensions,
|
||||||
enabled_features: Features,
|
enabled_features: Features,
|
||||||
active_queue_family_indices: SmallVec<[u32; 2]>,
|
active_queue_family_indices: SmallVec<[u32; 2]>,
|
||||||
@ -410,7 +408,6 @@ impl Device {
|
|||||||
physical_device,
|
physical_device,
|
||||||
api_version,
|
api_version,
|
||||||
fns,
|
fns,
|
||||||
standard_memory_pool: Mutex::new(Weak::new()),
|
|
||||||
enabled_extensions,
|
enabled_extensions,
|
||||||
enabled_features,
|
enabled_features,
|
||||||
active_queue_family_indices,
|
active_queue_family_indices,
|
||||||
@ -491,21 +488,6 @@ impl Device {
|
|||||||
&self.enabled_features
|
&self.enabled_features
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the standard memory pool used by default if you don't provide any other pool.
|
|
||||||
pub fn standard_memory_pool(self: &Arc<Self>) -> Arc<StandardMemoryPool> {
|
|
||||||
let mut pool = self.standard_memory_pool.lock();
|
|
||||||
|
|
||||||
if let Some(p) = pool.upgrade() {
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The weak pointer is empty, so we create the pool.
|
|
||||||
let new_pool = StandardMemoryPool::new(self.clone());
|
|
||||||
*pool = Arc::downgrade(&new_pool);
|
|
||||||
|
|
||||||
new_pool
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the current number of active [`DeviceMemory`] allocations the device has.
|
/// Returns the current number of active [`DeviceMemory`] allocations the device has.
|
||||||
///
|
///
|
||||||
/// [`DeviceMemory`]: crate::memory::DeviceMemory
|
/// [`DeviceMemory`]: crate::memory::DeviceMemory
|
||||||
|
@ -14,15 +14,14 @@ use super::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
device::{Device, DeviceOwned},
|
device::{Device, DeviceOwned},
|
||||||
format::Format,
|
format::Format,
|
||||||
image::{sys::UnsafeImageCreateInfo, ImageDimensions},
|
image::{sys::UnsafeImageCreateInfo, ImageDimensions, ImageFormatInfo},
|
||||||
memory::{
|
memory::{
|
||||||
pool::{
|
allocator::{
|
||||||
alloc_dedicated_with_exportable_fd, AllocFromRequirementsFilter, AllocLayout,
|
AllocationCreateInfo, AllocationType, MemoryAlloc, MemoryAllocatePreference,
|
||||||
MappingRequirement, MemoryPoolAlloc, PotentialDedicatedAllocation,
|
MemoryAllocator, MemoryUsage,
|
||||||
StandardMemoryPoolAlloc,
|
|
||||||
},
|
},
|
||||||
DedicatedAllocation, DeviceMemoryError, ExternalMemoryHandleType,
|
DedicatedAllocation, DeviceMemoryError, ExternalMemoryHandleType,
|
||||||
ExternalMemoryHandleTypes, MemoryPool,
|
ExternalMemoryHandleTypes,
|
||||||
},
|
},
|
||||||
DeviceSize,
|
DeviceSize,
|
||||||
};
|
};
|
||||||
@ -65,12 +64,12 @@ use std::{
|
|||||||
///
|
///
|
||||||
// TODO: forbid reading transient images outside render passes?
|
// TODO: forbid reading transient images outside render passes?
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AttachmentImage<A = PotentialDedicatedAllocation<StandardMemoryPoolAlloc>> {
|
pub struct AttachmentImage {
|
||||||
// Inner implementation.
|
// Inner implementation.
|
||||||
image: Arc<UnsafeImage>,
|
image: Arc<UnsafeImage>,
|
||||||
|
|
||||||
// Memory used to back the image.
|
// Memory used to back the image.
|
||||||
memory: A,
|
memory: MemoryAlloc,
|
||||||
|
|
||||||
// Layout to use when the image is used as a framebuffer attachment.
|
// Layout to use when the image is used as a framebuffer attachment.
|
||||||
// Must be either "depth-stencil optimal" or "color optimal".
|
// Must be either "depth-stencil optimal" or "color optimal".
|
||||||
@ -88,12 +87,12 @@ impl AttachmentImage {
|
|||||||
/// format as a framebuffer attachment.
|
/// format as a framebuffer attachment.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
dimensions: [u32; 2],
|
dimensions: [u32; 2],
|
||||||
format: Format,
|
format: Format,
|
||||||
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
||||||
AttachmentImage::new_impl(
|
AttachmentImage::new_impl(
|
||||||
device,
|
allocator,
|
||||||
dimensions,
|
dimensions,
|
||||||
1,
|
1,
|
||||||
format,
|
format,
|
||||||
@ -107,7 +106,7 @@ impl AttachmentImage {
|
|||||||
/// > **Note**: This function is just a convenient shortcut for `with_usage`.
|
/// > **Note**: This function is just a convenient shortcut for `with_usage`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn input_attachment(
|
pub fn input_attachment(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
dimensions: [u32; 2],
|
dimensions: [u32; 2],
|
||||||
format: Format,
|
format: Format,
|
||||||
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
||||||
@ -117,7 +116,7 @@ impl AttachmentImage {
|
|||||||
};
|
};
|
||||||
|
|
||||||
AttachmentImage::new_impl(
|
AttachmentImage::new_impl(
|
||||||
device,
|
allocator,
|
||||||
dimensions,
|
dimensions,
|
||||||
1,
|
1,
|
||||||
format,
|
format,
|
||||||
@ -132,12 +131,19 @@ impl AttachmentImage {
|
|||||||
/// > want a regular image.
|
/// > want a regular image.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn multisampled(
|
pub fn multisampled(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
dimensions: [u32; 2],
|
dimensions: [u32; 2],
|
||||||
samples: SampleCount,
|
samples: SampleCount,
|
||||||
format: Format,
|
format: Format,
|
||||||
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
||||||
AttachmentImage::new_impl(device, dimensions, 1, format, ImageUsage::empty(), samples)
|
AttachmentImage::new_impl(
|
||||||
|
allocator,
|
||||||
|
dimensions,
|
||||||
|
1,
|
||||||
|
format,
|
||||||
|
ImageUsage::empty(),
|
||||||
|
samples,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `multisampled`, but creates an image that can be used as an input attachment.
|
/// Same as `multisampled`, but creates an image that can be used as an input attachment.
|
||||||
@ -145,7 +151,7 @@ impl AttachmentImage {
|
|||||||
/// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
|
/// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn multisampled_input_attachment(
|
pub fn multisampled_input_attachment(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
dimensions: [u32; 2],
|
dimensions: [u32; 2],
|
||||||
samples: SampleCount,
|
samples: SampleCount,
|
||||||
format: Format,
|
format: Format,
|
||||||
@ -155,7 +161,7 @@ impl AttachmentImage {
|
|||||||
..ImageUsage::empty()
|
..ImageUsage::empty()
|
||||||
};
|
};
|
||||||
|
|
||||||
AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples)
|
AttachmentImage::new_impl(allocator, dimensions, 1, format, base_usage, samples)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `new`, but lets you specify additional usages.
|
/// Same as `new`, but lets you specify additional usages.
|
||||||
@ -165,12 +171,19 @@ impl AttachmentImage {
|
|||||||
/// addition to these two.
|
/// addition to these two.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn with_usage(
|
pub fn with_usage(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
dimensions: [u32; 2],
|
dimensions: [u32; 2],
|
||||||
format: Format,
|
format: Format,
|
||||||
usage: ImageUsage,
|
usage: ImageUsage,
|
||||||
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
||||||
AttachmentImage::new_impl(device, dimensions, 1, format, usage, SampleCount::Sample1)
|
AttachmentImage::new_impl(
|
||||||
|
allocator,
|
||||||
|
dimensions,
|
||||||
|
1,
|
||||||
|
format,
|
||||||
|
usage,
|
||||||
|
SampleCount::Sample1,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `with_usage`, but creates a multisampled image.
|
/// Same as `with_usage`, but creates a multisampled image.
|
||||||
@ -179,13 +192,13 @@ impl AttachmentImage {
|
|||||||
/// > want a regular image.
|
/// > want a regular image.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn multisampled_with_usage(
|
pub fn multisampled_with_usage(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
dimensions: [u32; 2],
|
dimensions: [u32; 2],
|
||||||
samples: SampleCount,
|
samples: SampleCount,
|
||||||
format: Format,
|
format: Format,
|
||||||
usage: ImageUsage,
|
usage: ImageUsage,
|
||||||
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
||||||
AttachmentImage::new_impl(device, dimensions, 1, format, usage, samples)
|
AttachmentImage::new_impl(allocator, dimensions, 1, format, usage, samples)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `multisampled_with_usage`, but creates an image with multiple layers.
|
/// Same as `multisampled_with_usage`, but creates an image with multiple layers.
|
||||||
@ -194,14 +207,14 @@ impl AttachmentImage {
|
|||||||
/// > want a regular image.
|
/// > want a regular image.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn multisampled_with_usage_with_layers(
|
pub fn multisampled_with_usage_with_layers(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
dimensions: [u32; 2],
|
dimensions: [u32; 2],
|
||||||
array_layers: u32,
|
array_layers: u32,
|
||||||
samples: SampleCount,
|
samples: SampleCount,
|
||||||
format: Format,
|
format: Format,
|
||||||
usage: ImageUsage,
|
usage: ImageUsage,
|
||||||
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
||||||
AttachmentImage::new_impl(device, dimensions, array_layers, format, usage, samples)
|
AttachmentImage::new_impl(allocator, dimensions, array_layers, format, usage, samples)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `new`, except that the image can later be sampled.
|
/// Same as `new`, except that the image can later be sampled.
|
||||||
@ -209,7 +222,7 @@ impl AttachmentImage {
|
|||||||
/// > **Note**: This function is just a convenient shortcut for `with_usage`.
|
/// > **Note**: This function is just a convenient shortcut for `with_usage`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn sampled(
|
pub fn sampled(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
dimensions: [u32; 2],
|
dimensions: [u32; 2],
|
||||||
format: Format,
|
format: Format,
|
||||||
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
||||||
@ -219,7 +232,7 @@ impl AttachmentImage {
|
|||||||
};
|
};
|
||||||
|
|
||||||
AttachmentImage::new_impl(
|
AttachmentImage::new_impl(
|
||||||
device,
|
allocator,
|
||||||
dimensions,
|
dimensions,
|
||||||
1,
|
1,
|
||||||
format,
|
format,
|
||||||
@ -233,7 +246,7 @@ impl AttachmentImage {
|
|||||||
/// > **Note**: This function is just a convenient shortcut for `with_usage`.
|
/// > **Note**: This function is just a convenient shortcut for `with_usage`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn sampled_input_attachment(
|
pub fn sampled_input_attachment(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
dimensions: [u32; 2],
|
dimensions: [u32; 2],
|
||||||
format: Format,
|
format: Format,
|
||||||
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
||||||
@ -244,7 +257,7 @@ impl AttachmentImage {
|
|||||||
};
|
};
|
||||||
|
|
||||||
AttachmentImage::new_impl(
|
AttachmentImage::new_impl(
|
||||||
device,
|
allocator,
|
||||||
dimensions,
|
dimensions,
|
||||||
1,
|
1,
|
||||||
format,
|
format,
|
||||||
@ -261,7 +274,7 @@ impl AttachmentImage {
|
|||||||
/// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
|
/// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn sampled_multisampled(
|
pub fn sampled_multisampled(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
dimensions: [u32; 2],
|
dimensions: [u32; 2],
|
||||||
samples: SampleCount,
|
samples: SampleCount,
|
||||||
format: Format,
|
format: Format,
|
||||||
@ -271,7 +284,7 @@ impl AttachmentImage {
|
|||||||
..ImageUsage::empty()
|
..ImageUsage::empty()
|
||||||
};
|
};
|
||||||
|
|
||||||
AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples)
|
AttachmentImage::new_impl(allocator, dimensions, 1, format, base_usage, samples)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `sampled_multisampled`, but creates an image that can be used as an input
|
/// Same as `sampled_multisampled`, but creates an image that can be used as an input
|
||||||
@ -280,7 +293,7 @@ impl AttachmentImage {
|
|||||||
/// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
|
/// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn sampled_multisampled_input_attachment(
|
pub fn sampled_multisampled_input_attachment(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
dimensions: [u32; 2],
|
dimensions: [u32; 2],
|
||||||
samples: SampleCount,
|
samples: SampleCount,
|
||||||
format: Format,
|
format: Format,
|
||||||
@ -291,7 +304,7 @@ impl AttachmentImage {
|
|||||||
..ImageUsage::empty()
|
..ImageUsage::empty()
|
||||||
};
|
};
|
||||||
|
|
||||||
AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples)
|
AttachmentImage::new_impl(allocator, dimensions, 1, format, base_usage, samples)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `new`, except that the image will be transient.
|
/// Same as `new`, except that the image will be transient.
|
||||||
@ -302,7 +315,7 @@ impl AttachmentImage {
|
|||||||
/// > **Note**: This function is just a convenient shortcut for `with_usage`.
|
/// > **Note**: This function is just a convenient shortcut for `with_usage`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn transient(
|
pub fn transient(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
dimensions: [u32; 2],
|
dimensions: [u32; 2],
|
||||||
format: Format,
|
format: Format,
|
||||||
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
||||||
@ -312,7 +325,7 @@ impl AttachmentImage {
|
|||||||
};
|
};
|
||||||
|
|
||||||
AttachmentImage::new_impl(
|
AttachmentImage::new_impl(
|
||||||
device,
|
allocator,
|
||||||
dimensions,
|
dimensions,
|
||||||
1,
|
1,
|
||||||
format,
|
format,
|
||||||
@ -326,7 +339,7 @@ impl AttachmentImage {
|
|||||||
/// > **Note**: This function is just a convenient shortcut for `with_usage`.
|
/// > **Note**: This function is just a convenient shortcut for `with_usage`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn transient_input_attachment(
|
pub fn transient_input_attachment(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
dimensions: [u32; 2],
|
dimensions: [u32; 2],
|
||||||
format: Format,
|
format: Format,
|
||||||
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
||||||
@ -337,7 +350,7 @@ impl AttachmentImage {
|
|||||||
};
|
};
|
||||||
|
|
||||||
AttachmentImage::new_impl(
|
AttachmentImage::new_impl(
|
||||||
device,
|
allocator,
|
||||||
dimensions,
|
dimensions,
|
||||||
1,
|
1,
|
||||||
format,
|
format,
|
||||||
@ -354,7 +367,7 @@ impl AttachmentImage {
|
|||||||
/// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
|
/// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn transient_multisampled(
|
pub fn transient_multisampled(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
dimensions: [u32; 2],
|
dimensions: [u32; 2],
|
||||||
samples: SampleCount,
|
samples: SampleCount,
|
||||||
format: Format,
|
format: Format,
|
||||||
@ -364,7 +377,7 @@ impl AttachmentImage {
|
|||||||
..ImageUsage::empty()
|
..ImageUsage::empty()
|
||||||
};
|
};
|
||||||
|
|
||||||
AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples)
|
AttachmentImage::new_impl(allocator, dimensions, 1, format, base_usage, samples)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `transient_multisampled`, but creates an image that can be used as an input
|
/// Same as `transient_multisampled`, but creates an image that can be used as an input
|
||||||
@ -373,7 +386,7 @@ impl AttachmentImage {
|
|||||||
/// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
|
/// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn transient_multisampled_input_attachment(
|
pub fn transient_multisampled_input_attachment(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
dimensions: [u32; 2],
|
dimensions: [u32; 2],
|
||||||
samples: SampleCount,
|
samples: SampleCount,
|
||||||
format: Format,
|
format: Format,
|
||||||
@ -384,19 +397,19 @@ impl AttachmentImage {
|
|||||||
..ImageUsage::empty()
|
..ImageUsage::empty()
|
||||||
};
|
};
|
||||||
|
|
||||||
AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples)
|
AttachmentImage::new_impl(allocator, dimensions, 1, format, base_usage, samples)
|
||||||
}
|
}
|
||||||
|
|
||||||
// All constructors dispatch to this one.
|
// All constructors dispatch to this one.
|
||||||
fn new_impl(
|
fn new_impl(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
dimensions: [u32; 2],
|
dimensions: [u32; 2],
|
||||||
array_layers: u32,
|
array_layers: u32,
|
||||||
format: Format,
|
format: Format,
|
||||||
base_usage: ImageUsage,
|
base_usage: ImageUsage,
|
||||||
samples: SampleCount,
|
samples: SampleCount,
|
||||||
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
||||||
let physical_device = device.physical_device();
|
let physical_device = allocator.device().physical_device();
|
||||||
let device_properties = physical_device.properties();
|
let device_properties = physical_device.properties();
|
||||||
|
|
||||||
if dimensions[0] > device_properties.max_framebuffer_height {
|
if dimensions[0] > device_properties.max_framebuffer_height {
|
||||||
@ -417,7 +430,7 @@ impl AttachmentImage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let image = UnsafeImage::new(
|
let image = UnsafeImage::new(
|
||||||
device.clone(),
|
allocator.device().clone(),
|
||||||
UnsafeImageCreateInfo {
|
UnsafeImageCreateInfo {
|
||||||
dimensions: ImageDimensions::Dim2d {
|
dimensions: ImageDimensions::Dim2d {
|
||||||
width: dimensions[0],
|
width: dimensions[0],
|
||||||
@ -434,30 +447,25 @@ impl AttachmentImage {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
let requirements = image.memory_requirements();
|
||||||
|
let create_info = AllocationCreateInfo {
|
||||||
|
requirements,
|
||||||
|
allocation_type: AllocationType::NonLinear,
|
||||||
|
usage: MemoryUsage::GpuOnly,
|
||||||
|
allocate_preference: MemoryAllocatePreference::Unknown,
|
||||||
|
dedicated_allocation: Some(DedicatedAllocation::Image(&image)),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
let mem_reqs = image.memory_requirements();
|
match unsafe { allocator.allocate_unchecked(create_info) } {
|
||||||
let memory = MemoryPool::alloc_from_requirements(
|
Ok(alloc) => {
|
||||||
&device.standard_memory_pool(),
|
debug_assert!(alloc.offset() % requirements.alignment == 0);
|
||||||
&mem_reqs,
|
debug_assert!(alloc.size() == requirements.size);
|
||||||
AllocLayout::Optimal,
|
unsafe { image.bind_memory(alloc.device_memory(), alloc.offset()) }?;
|
||||||
MappingRequirement::DoNotMap,
|
|
||||||
Some(DedicatedAllocation::Image(&image)),
|
|
||||||
|t| {
|
|
||||||
if t.property_flags.device_local {
|
|
||||||
AllocFromRequirementsFilter::Preferred
|
|
||||||
} else {
|
|
||||||
AllocFromRequirementsFilter::Allowed
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
debug_assert!((memory.offset() % mem_reqs.alignment) == 0);
|
|
||||||
unsafe {
|
|
||||||
image.bind_memory(memory.memory(), memory.offset())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Arc::new(AttachmentImage {
|
Ok(Arc::new(AttachmentImage {
|
||||||
image,
|
image,
|
||||||
memory,
|
memory: alloc,
|
||||||
attachment_layout: if is_depth {
|
attachment_layout: if is_depth {
|
||||||
ImageLayout::DepthStencilAttachmentOptimal
|
ImageLayout::DepthStencilAttachmentOptimal
|
||||||
} else {
|
} else {
|
||||||
@ -466,16 +474,19 @@ impl AttachmentImage {
|
|||||||
initialized: AtomicBool::new(false),
|
initialized: AtomicBool::new(false),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
Err(err) => Err(err.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new_with_exportable_fd(
|
pub fn new_with_exportable_fd(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
dimensions: [u32; 2],
|
dimensions: [u32; 2],
|
||||||
array_layers: u32,
|
array_layers: u32,
|
||||||
format: Format,
|
format: Format,
|
||||||
base_usage: ImageUsage,
|
base_usage: ImageUsage,
|
||||||
samples: SampleCount,
|
samples: SampleCount,
|
||||||
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
) -> Result<Arc<AttachmentImage>, ImageCreationError> {
|
||||||
let physical_device = device.physical_device();
|
let physical_device = allocator.device().physical_device();
|
||||||
let device_properties = physical_device.properties();
|
let device_properties = physical_device.properties();
|
||||||
|
|
||||||
if dimensions[0] > device_properties.max_framebuffer_height {
|
if dimensions[0] > device_properties.max_framebuffer_height {
|
||||||
@ -490,9 +501,37 @@ impl AttachmentImage {
|
|||||||
|
|
||||||
let aspects = format.aspects();
|
let aspects = format.aspects();
|
||||||
let is_depth = aspects.depth || aspects.stencil;
|
let is_depth = aspects.depth || aspects.stencil;
|
||||||
|
let usage = ImageUsage {
|
||||||
|
color_attachment: !is_depth,
|
||||||
|
depth_stencil_attachment: is_depth,
|
||||||
|
..base_usage
|
||||||
|
};
|
||||||
|
|
||||||
|
let external_memory_properties = allocator
|
||||||
|
.device()
|
||||||
|
.physical_device()
|
||||||
|
.image_format_properties(ImageFormatInfo {
|
||||||
|
format: Some(format),
|
||||||
|
usage,
|
||||||
|
external_memory_handle_type: Some(ExternalMemoryHandleType::OpaqueFd),
|
||||||
|
mutable_format: true,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
|
.external_memory_properties;
|
||||||
|
// VUID-VkExportMemoryAllocateInfo-handleTypes-00656
|
||||||
|
assert!(external_memory_properties.exportable);
|
||||||
|
|
||||||
|
// VUID-VkMemoryAllocateInfo-pNext-00639
|
||||||
|
// Guaranteed because we always create a dedicated allocation
|
||||||
|
|
||||||
|
let external_memory_handle_types = ExternalMemoryHandleTypes {
|
||||||
|
opaque_fd: true,
|
||||||
|
..ExternalMemoryHandleTypes::empty()
|
||||||
|
};
|
||||||
let image = UnsafeImage::new(
|
let image = UnsafeImage::new(
|
||||||
device.clone(),
|
allocator.device().clone(),
|
||||||
UnsafeImageCreateInfo {
|
UnsafeImageCreateInfo {
|
||||||
dimensions: ImageDimensions::Dim2d {
|
dimensions: ImageDimensions::Dim2d {
|
||||||
width: dimensions[0],
|
width: dimensions[0],
|
||||||
@ -501,44 +540,33 @@ impl AttachmentImage {
|
|||||||
},
|
},
|
||||||
format: Some(format),
|
format: Some(format),
|
||||||
samples,
|
samples,
|
||||||
usage: ImageUsage {
|
usage,
|
||||||
color_attachment: !is_depth,
|
external_memory_handle_types,
|
||||||
depth_stencil_attachment: is_depth,
|
|
||||||
..base_usage
|
|
||||||
},
|
|
||||||
external_memory_handle_types: ExternalMemoryHandleTypes {
|
|
||||||
opaque_fd: true,
|
|
||||||
..ExternalMemoryHandleTypes::empty()
|
|
||||||
},
|
|
||||||
mutable_format: true,
|
mutable_format: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
let requirements = image.memory_requirements();
|
||||||
|
let memory_type_index = allocator
|
||||||
|
.find_memory_type_index(requirements.memory_type_bits, MemoryUsage::GpuOnly.into())
|
||||||
|
.expect("failed to find a suitable memory type");
|
||||||
|
|
||||||
let mem_reqs = image.memory_requirements();
|
match unsafe {
|
||||||
let memory = alloc_dedicated_with_exportable_fd(
|
allocator.allocate_dedicated_unchecked(
|
||||||
device.clone(),
|
memory_type_index,
|
||||||
&mem_reqs,
|
requirements.size,
|
||||||
AllocLayout::Optimal,
|
Some(DedicatedAllocation::Image(&image)),
|
||||||
MappingRequirement::DoNotMap,
|
external_memory_handle_types,
|
||||||
DedicatedAllocation::Image(&image),
|
)
|
||||||
|t| {
|
} {
|
||||||
if t.property_flags.device_local {
|
Ok(alloc) => {
|
||||||
AllocFromRequirementsFilter::Preferred
|
debug_assert!(alloc.offset() % requirements.alignment == 0);
|
||||||
} else {
|
debug_assert!(alloc.size() == requirements.size);
|
||||||
AllocFromRequirementsFilter::Allowed
|
unsafe { image.bind_memory(alloc.device_memory(), alloc.offset()) }?;
|
||||||
}
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
debug_assert!((memory.offset() % mem_reqs.alignment) == 0);
|
|
||||||
unsafe {
|
|
||||||
image.bind_memory(memory.memory(), memory.offset())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Arc::new(AttachmentImage {
|
Ok(Arc::new(AttachmentImage {
|
||||||
image,
|
image,
|
||||||
memory,
|
memory: alloc,
|
||||||
attachment_layout: if is_depth {
|
attachment_layout: if is_depth {
|
||||||
ImageLayout::DepthStencilAttachmentOptimal
|
ImageLayout::DepthStencilAttachmentOptimal
|
||||||
} else {
|
} else {
|
||||||
@ -547,27 +575,28 @@ impl AttachmentImage {
|
|||||||
initialized: AtomicBool::new(false),
|
initialized: AtomicBool::new(false),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
Err(err) => Err(err.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Exports posix file descriptor for the allocated memory.
|
/// Exports posix file descriptor for the allocated memory.
|
||||||
/// Requires `khr_external_memory_fd` and `khr_external_memory` extensions to be loaded.
|
/// Requires `khr_external_memory_fd` and `khr_external_memory` extensions to be loaded.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn export_posix_fd(&self) -> Result<File, DeviceMemoryError> {
|
pub fn export_posix_fd(&self) -> Result<File, DeviceMemoryError> {
|
||||||
self.memory
|
self.memory
|
||||||
.memory()
|
.device_memory()
|
||||||
.export_fd(ExternalMemoryHandleType::OpaqueFd)
|
.export_fd(ExternalMemoryHandleType::OpaqueFd)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the size of the allocated memory (used e.g. with cuda).
|
/// Return the size of the allocated memory (used e.g. with cuda).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mem_size(&self) -> DeviceSize {
|
pub fn mem_size(&self) -> DeviceSize {
|
||||||
self.memory.memory().allocation_size()
|
self.memory.device_memory().allocation_size()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<A> ImageAccess for AttachmentImage<A>
|
unsafe impl ImageAccess for AttachmentImage {
|
||||||
where
|
#[inline]
|
||||||
A: MemoryPoolAlloc,
|
|
||||||
{
|
|
||||||
fn inner(&self) -> ImageInner<'_> {
|
fn inner(&self) -> ImageInner<'_> {
|
||||||
ImageInner {
|
ImageInner {
|
||||||
image: &self.image,
|
image: &self.image,
|
||||||
@ -578,14 +607,17 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn initial_layout_requirement(&self) -> ImageLayout {
|
fn initial_layout_requirement(&self) -> ImageLayout {
|
||||||
self.attachment_layout
|
self.attachment_layout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn final_layout_requirement(&self) -> ImageLayout {
|
fn final_layout_requirement(&self) -> ImageLayout {
|
||||||
self.attachment_layout
|
self.attachment_layout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
|
fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
|
||||||
Some(ImageDescriptorLayouts {
|
Some(ImageDescriptorLayouts {
|
||||||
storage_image: ImageLayout::General,
|
storage_image: ImageLayout::General,
|
||||||
@ -595,45 +627,40 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
unsafe fn layout_initialized(&self) {
|
unsafe fn layout_initialized(&self) {
|
||||||
self.initialized.store(true, Ordering::SeqCst);
|
self.initialized.store(true, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn is_layout_initialized(&self) -> bool {
|
fn is_layout_initialized(&self) -> bool {
|
||||||
self.initialized.load(Ordering::SeqCst)
|
self.initialized.load(Ordering::SeqCst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<A> DeviceOwned for AttachmentImage<A> {
|
unsafe impl DeviceOwned for AttachmentImage {
|
||||||
|
#[inline]
|
||||||
fn device(&self) -> &Arc<Device> {
|
fn device(&self) -> &Arc<Device> {
|
||||||
self.image.device()
|
self.image.device()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<P, A> ImageContent<P> for AttachmentImage<A>
|
unsafe impl<P> ImageContent<P> for AttachmentImage {
|
||||||
where
|
|
||||||
A: MemoryPoolAlloc,
|
|
||||||
{
|
|
||||||
fn matches_format(&self) -> bool {
|
fn matches_format(&self) -> bool {
|
||||||
true // FIXME:
|
true // FIXME:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A> PartialEq for AttachmentImage<A>
|
impl PartialEq for AttachmentImage {
|
||||||
where
|
#[inline]
|
||||||
A: MemoryPoolAlloc,
|
|
||||||
{
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.inner() == other.inner()
|
self.inner() == other.inner()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A> Eq for AttachmentImage<A> where A: MemoryPoolAlloc {}
|
impl Eq for AttachmentImage {}
|
||||||
|
|
||||||
impl<A> Hash for AttachmentImage<A>
|
impl Hash for AttachmentImage {
|
||||||
where
|
|
||||||
A: MemoryPoolAlloc,
|
|
||||||
{
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.inner().hash(state);
|
self.inner().hash(state);
|
||||||
}
|
}
|
||||||
@ -641,24 +668,29 @@ where
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::AttachmentImage;
|
use super::*;
|
||||||
use crate::format::Format;
|
use crate::memory::allocator::StandardMemoryAllocator;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create_regular() {
|
fn create_regular() {
|
||||||
let (device, _) = gfx_dev_and_queue!();
|
let (device, _) = gfx_dev_and_queue!();
|
||||||
let _img = AttachmentImage::new(device, [32, 32], Format::R8G8B8A8_UNORM).unwrap();
|
let memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
|
let _img =
|
||||||
|
AttachmentImage::new(&memory_allocator, [32, 32], Format::R8G8B8A8_UNORM).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create_transient() {
|
fn create_transient() {
|
||||||
let (device, _) = gfx_dev_and_queue!();
|
let (device, _) = gfx_dev_and_queue!();
|
||||||
let _img = AttachmentImage::transient(device, [32, 32], Format::R8G8B8A8_UNORM).unwrap();
|
let memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
|
let _img = AttachmentImage::transient(&memory_allocator, [32, 32], Format::R8G8B8A8_UNORM)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn d16_unorm_always_supported() {
|
fn d16_unorm_always_supported() {
|
||||||
let (device, _) = gfx_dev_and_queue!();
|
let (device, _) = gfx_dev_and_queue!();
|
||||||
let _img = AttachmentImage::new(device, [32, 32], Format::D16_UNORM).unwrap();
|
let memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
|
let _img = AttachmentImage::new(&memory_allocator, [32, 32], Format::D16_UNORM).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,11 +22,11 @@ use crate::{
|
|||||||
format::Format,
|
format::Format,
|
||||||
image::sys::UnsafeImageCreateInfo,
|
image::sys::UnsafeImageCreateInfo,
|
||||||
memory::{
|
memory::{
|
||||||
pool::{
|
allocator::{
|
||||||
AllocFromRequirementsFilter, AllocLayout, MappingRequirement, MemoryPoolAlloc,
|
AllocationCreateInfo, AllocationCreationError, AllocationType, MemoryAlloc,
|
||||||
PotentialDedicatedAllocation, StandardMemoryPoolAlloc,
|
MemoryAllocatePreference, MemoryAllocator, MemoryUsage,
|
||||||
},
|
},
|
||||||
DedicatedAllocation, DeviceMemoryError, MemoryPool,
|
DedicatedAllocation,
|
||||||
},
|
},
|
||||||
sampler::Filter,
|
sampler::Filter,
|
||||||
sync::Sharing,
|
sync::Sharing,
|
||||||
@ -44,10 +44,10 @@ use std::{
|
|||||||
/// but then you must only ever read from it.
|
/// but then you must only ever read from it.
|
||||||
// TODO: type (2D, 3D, array, etc.) as template parameter
|
// TODO: type (2D, 3D, array, etc.) as template parameter
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ImmutableImage<A = PotentialDedicatedAllocation<StandardMemoryPoolAlloc>> {
|
pub struct ImmutableImage {
|
||||||
image: Arc<UnsafeImage>,
|
image: Arc<UnsafeImage>,
|
||||||
dimensions: ImageDimensions,
|
dimensions: ImageDimensions,
|
||||||
_memory: A,
|
_memory: MemoryAlloc,
|
||||||
layout: ImageLayout,
|
layout: ImageLayout,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ impl ImmutableImage {
|
|||||||
/// Returns two things: the image, and a special access that should be used for the initial
|
/// Returns two things: the image, and a special access that should be used for the initial
|
||||||
/// upload to the image.
|
/// upload to the image.
|
||||||
pub fn uninitialized(
|
pub fn uninitialized(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
dimensions: ImageDimensions,
|
dimensions: ImageDimensions,
|
||||||
format: Format,
|
format: Format,
|
||||||
mip_levels: impl Into<MipmapsCount>,
|
mip_levels: impl Into<MipmapsCount>,
|
||||||
@ -118,7 +118,7 @@ impl ImmutableImage {
|
|||||||
let queue_family_indices: SmallVec<[_; 4]> = queue_family_indices.into_iter().collect();
|
let queue_family_indices: SmallVec<[_; 4]> = queue_family_indices.into_iter().collect();
|
||||||
|
|
||||||
let image = UnsafeImage::new(
|
let image = UnsafeImage::new(
|
||||||
device.clone(),
|
allocator.device().clone(),
|
||||||
UnsafeImageCreateInfo {
|
UnsafeImageCreateInfo {
|
||||||
dimensions,
|
dimensions,
|
||||||
format: Some(format),
|
format: Some(format),
|
||||||
@ -140,30 +140,25 @@ impl ImmutableImage {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
let requirements = image.memory_requirements();
|
||||||
|
let create_info = AllocationCreateInfo {
|
||||||
|
requirements,
|
||||||
|
allocation_type: AllocationType::NonLinear,
|
||||||
|
usage: MemoryUsage::GpuOnly,
|
||||||
|
allocate_preference: MemoryAllocatePreference::Unknown,
|
||||||
|
dedicated_allocation: Some(DedicatedAllocation::Image(&image)),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
let mem_reqs = image.memory_requirements();
|
match unsafe { allocator.allocate_unchecked(create_info) } {
|
||||||
let memory = MemoryPool::alloc_from_requirements(
|
Ok(alloc) => {
|
||||||
&device.standard_memory_pool(),
|
debug_assert!(alloc.offset() % requirements.alignment == 0);
|
||||||
&mem_reqs,
|
debug_assert!(alloc.size() == requirements.size);
|
||||||
AllocLayout::Optimal,
|
unsafe { image.bind_memory(alloc.device_memory(), alloc.offset()) }?;
|
||||||
MappingRequirement::DoNotMap,
|
|
||||||
Some(DedicatedAllocation::Image(&image)),
|
|
||||||
|t| {
|
|
||||||
if t.property_flags.device_local {
|
|
||||||
AllocFromRequirementsFilter::Preferred
|
|
||||||
} else {
|
|
||||||
AllocFromRequirementsFilter::Allowed
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
debug_assert!((memory.offset() % mem_reqs.alignment) == 0);
|
|
||||||
unsafe {
|
|
||||||
image.bind_memory(memory.memory(), memory.offset())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let image = Arc::new(ImmutableImage {
|
let image = Arc::new(ImmutableImage {
|
||||||
image,
|
image,
|
||||||
_memory: memory,
|
_memory: alloc,
|
||||||
dimensions,
|
dimensions,
|
||||||
layout,
|
layout,
|
||||||
});
|
});
|
||||||
@ -174,6 +169,9 @@ impl ImmutableImage {
|
|||||||
|
|
||||||
Ok((image, init))
|
Ok((image, init))
|
||||||
}
|
}
|
||||||
|
Err(err) => Err(err.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Construct an ImmutableImage from the contents of `iter`.
|
/// Construct an ImmutableImage from the contents of `iter`.
|
||||||
///
|
///
|
||||||
@ -181,6 +179,7 @@ impl ImmutableImage {
|
|||||||
/// `iter` to it, then calling [`from_buffer`](ImmutableImage::from_buffer) to copy the data
|
/// `iter` to it, then calling [`from_buffer`](ImmutableImage::from_buffer) to copy the data
|
||||||
/// over.
|
/// over.
|
||||||
pub fn from_iter<Px, I, L, A>(
|
pub fn from_iter<Px, I, L, A>(
|
||||||
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
iter: I,
|
iter: I,
|
||||||
dimensions: ImageDimensions,
|
dimensions: ImageDimensions,
|
||||||
mip_levels: MipmapsCount,
|
mip_levels: MipmapsCount,
|
||||||
@ -194,7 +193,7 @@ impl ImmutableImage {
|
|||||||
A: CommandBufferAllocator,
|
A: CommandBufferAllocator,
|
||||||
{
|
{
|
||||||
let source = CpuAccessibleBuffer::from_iter(
|
let source = CpuAccessibleBuffer::from_iter(
|
||||||
command_buffer_builder.device().clone(),
|
allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
transfer_src: true,
|
transfer_src: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
@ -202,7 +201,9 @@ impl ImmutableImage {
|
|||||||
false,
|
false,
|
||||||
iter,
|
iter,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
ImmutableImage::from_buffer(
|
ImmutableImage::from_buffer(
|
||||||
|
allocator,
|
||||||
source,
|
source,
|
||||||
dimensions,
|
dimensions,
|
||||||
mip_levels,
|
mip_levels,
|
||||||
@ -221,6 +222,7 @@ impl ImmutableImage {
|
|||||||
/// `command_buffer_builder` can then be used to record other commands, built, and executed as
|
/// `command_buffer_builder` can then be used to record other commands, built, and executed as
|
||||||
/// normal. If it is not executed, the image contents will be left undefined.
|
/// normal. If it is not executed, the image contents will be left undefined.
|
||||||
pub fn from_buffer<L, A>(
|
pub fn from_buffer<L, A>(
|
||||||
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
source: Arc<dyn BufferAccess>,
|
source: Arc<dyn BufferAccess>,
|
||||||
dimensions: ImageDimensions,
|
dimensions: ImageDimensions,
|
||||||
mip_levels: MipmapsCount,
|
mip_levels: MipmapsCount,
|
||||||
@ -258,7 +260,7 @@ impl ImmutableImage {
|
|||||||
let layout = ImageLayout::ShaderReadOnlyOptimal;
|
let layout = ImageLayout::ShaderReadOnlyOptimal;
|
||||||
|
|
||||||
let (image, initializer) = ImmutableImage::uninitialized(
|
let (image, initializer) = ImmutableImage::uninitialized(
|
||||||
source.device().clone(),
|
allocator,
|
||||||
dimensions,
|
dimensions,
|
||||||
format,
|
format,
|
||||||
mip_levels,
|
mip_levels,
|
||||||
@ -292,16 +294,15 @@ impl ImmutableImage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<A> DeviceOwned for ImmutableImage<A> {
|
unsafe impl DeviceOwned for ImmutableImage {
|
||||||
|
#[inline]
|
||||||
fn device(&self) -> &Arc<Device> {
|
fn device(&self) -> &Arc<Device> {
|
||||||
self.image.device()
|
self.image.device()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<A> ImageAccess for ImmutableImage<A>
|
unsafe impl ImageAccess for ImmutableImage {
|
||||||
where
|
#[inline]
|
||||||
A: MemoryPoolAlloc,
|
|
||||||
{
|
|
||||||
fn inner(&self) -> ImageInner<'_> {
|
fn inner(&self) -> ImageInner<'_> {
|
||||||
ImageInner {
|
ImageInner {
|
||||||
image: &self.image,
|
image: &self.image,
|
||||||
@ -312,18 +313,22 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn is_layout_initialized(&self) -> bool {
|
fn is_layout_initialized(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn initial_layout_requirement(&self) -> ImageLayout {
|
fn initial_layout_requirement(&self) -> ImageLayout {
|
||||||
self.layout
|
self.layout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn final_layout_requirement(&self) -> ImageLayout {
|
fn final_layout_requirement(&self) -> ImageLayout {
|
||||||
self.layout
|
self.layout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
|
fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
|
||||||
Some(ImageDescriptorLayouts {
|
Some(ImageDescriptorLayouts {
|
||||||
storage_image: ImageLayout::General,
|
storage_image: ImageLayout::General,
|
||||||
@ -334,82 +339,71 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<P, A> ImageContent<P> for ImmutableImage<A>
|
unsafe impl<P> ImageContent<P> for ImmutableImage {
|
||||||
where
|
|
||||||
A: MemoryPoolAlloc,
|
|
||||||
{
|
|
||||||
fn matches_format(&self) -> bool {
|
fn matches_format(&self) -> bool {
|
||||||
true // FIXME:
|
true // FIXME:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A> PartialEq for ImmutableImage<A>
|
impl PartialEq for ImmutableImage {
|
||||||
where
|
#[inline]
|
||||||
A: MemoryPoolAlloc,
|
|
||||||
{
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.inner() == other.inner()
|
self.inner() == other.inner()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A> Eq for ImmutableImage<A> where A: MemoryPoolAlloc {}
|
impl Eq for ImmutableImage {}
|
||||||
|
|
||||||
impl<A> Hash for ImmutableImage<A>
|
impl Hash for ImmutableImage {
|
||||||
where
|
|
||||||
A: MemoryPoolAlloc,
|
|
||||||
{
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.inner().hash(state);
|
self.inner().hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must not implement Clone, as that would lead to multiple `used` values.
|
// Must not implement Clone, as that would lead to multiple `used` values.
|
||||||
pub struct ImmutableImageInitialization<A = PotentialDedicatedAllocation<StandardMemoryPoolAlloc>> {
|
pub struct ImmutableImageInitialization {
|
||||||
image: Arc<ImmutableImage<A>>,
|
image: Arc<ImmutableImage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<A> DeviceOwned for ImmutableImageInitialization<A> {
|
unsafe impl DeviceOwned for ImmutableImageInitialization {
|
||||||
|
#[inline]
|
||||||
fn device(&self) -> &Arc<Device> {
|
fn device(&self) -> &Arc<Device> {
|
||||||
self.image.device()
|
self.image.device()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<A> ImageAccess for ImmutableImageInitialization<A>
|
unsafe impl ImageAccess for ImmutableImageInitialization {
|
||||||
where
|
#[inline]
|
||||||
A: MemoryPoolAlloc,
|
|
||||||
{
|
|
||||||
fn inner(&self) -> ImageInner<'_> {
|
fn inner(&self) -> ImageInner<'_> {
|
||||||
self.image.inner()
|
self.image.inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn initial_layout_requirement(&self) -> ImageLayout {
|
fn initial_layout_requirement(&self) -> ImageLayout {
|
||||||
ImageLayout::Undefined
|
ImageLayout::Undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn final_layout_requirement(&self) -> ImageLayout {
|
fn final_layout_requirement(&self) -> ImageLayout {
|
||||||
self.image.layout
|
self.image.layout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
|
fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A> PartialEq for ImmutableImageInitialization<A>
|
impl PartialEq for ImmutableImageInitialization {
|
||||||
where
|
#[inline]
|
||||||
A: MemoryPoolAlloc,
|
|
||||||
{
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.inner() == other.inner()
|
self.inner() == other.inner()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A> Eq for ImmutableImageInitialization<A> where A: MemoryPoolAlloc {}
|
impl Eq for ImmutableImageInitialization {}
|
||||||
|
|
||||||
impl<A> Hash for ImmutableImageInitialization<A>
|
impl Hash for ImmutableImageInitialization {
|
||||||
where
|
|
||||||
A: MemoryPoolAlloc,
|
|
||||||
{
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.inner().hash(state);
|
self.inner().hash(state);
|
||||||
}
|
}
|
||||||
@ -419,7 +413,7 @@ where
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum ImmutableImageCreationError {
|
pub enum ImmutableImageCreationError {
|
||||||
ImageCreationError(ImageCreationError),
|
ImageCreationError(ImageCreationError),
|
||||||
DeviceMemoryAllocationError(DeviceMemoryError),
|
AllocError(AllocationCreationError),
|
||||||
CommandBufferBeginError(CommandBufferBeginError),
|
CommandBufferBeginError(CommandBufferBeginError),
|
||||||
|
|
||||||
/// The size of the provided source data is less than the required size for an image with the
|
/// The size of the provided source data is less than the required size for an image with the
|
||||||
@ -434,7 +428,7 @@ impl Error for ImmutableImageCreationError {
|
|||||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||||
match self {
|
match self {
|
||||||
Self::ImageCreationError(err) => Some(err),
|
Self::ImageCreationError(err) => Some(err),
|
||||||
Self::DeviceMemoryAllocationError(err) => Some(err),
|
Self::AllocError(err) => Some(err),
|
||||||
Self::CommandBufferBeginError(err) => Some(err),
|
Self::CommandBufferBeginError(err) => Some(err),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
@ -445,15 +439,15 @@ impl Display for ImmutableImageCreationError {
|
|||||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
|
||||||
match self {
|
match self {
|
||||||
Self::ImageCreationError(err) => err.fmt(f),
|
Self::ImageCreationError(err) => err.fmt(f),
|
||||||
Self::DeviceMemoryAllocationError(err) => err.fmt(f),
|
Self::AllocError(err) => err.fmt(f),
|
||||||
Self::CommandBufferBeginError(err) => err.fmt(f),
|
Self::CommandBufferBeginError(err) => err.fmt(f),
|
||||||
|
|
||||||
Self::SourceTooSmall {
|
Self::SourceTooSmall {
|
||||||
source_size,
|
source_size,
|
||||||
required_size,
|
required_size,
|
||||||
} => write!(
|
} => write!(
|
||||||
f,
|
f,
|
||||||
"the size of the provided source data ({} bytes) is less than the required size for an image of the given format and dimensions ({} bytes)",
|
"the size of the provided source data ({} bytes) is less than the required size \
|
||||||
|
for an image of the given format and dimensions ({} bytes)",
|
||||||
source_size, required_size,
|
source_size, required_size,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
@ -466,15 +460,15 @@ impl From<ImageCreationError> for ImmutableImageCreationError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<DeviceMemoryError> for ImmutableImageCreationError {
|
impl From<AllocationCreationError> for ImmutableImageCreationError {
|
||||||
fn from(err: DeviceMemoryError) -> Self {
|
fn from(err: AllocationCreationError) -> Self {
|
||||||
Self::DeviceMemoryAllocationError(err)
|
Self::AllocError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<OomError> for ImmutableImageCreationError {
|
impl From<OomError> for ImmutableImageCreationError {
|
||||||
fn from(err: OomError) -> Self {
|
fn from(err: OomError) -> Self {
|
||||||
Self::DeviceMemoryAllocationError(err.into())
|
Self::AllocError(err.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -915,6 +915,7 @@ mod tests {
|
|||||||
},
|
},
|
||||||
format::Format,
|
format::Format,
|
||||||
image::{ImageAccess, ImageDimensions, ImmutableImage, MipmapsCount},
|
image::{ImageAccess, ImageDimensions, ImmutableImage, MipmapsCount},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1021,14 +1022,15 @@ mod tests {
|
|||||||
fn mipmap_working_immutable_image() {
|
fn mipmap_working_immutable_image() {
|
||||||
let (device, queue) = gfx_dev_and_queue!();
|
let (device, queue) = gfx_dev_and_queue!();
|
||||||
|
|
||||||
let command_buffer_allocator = StandardCommandBufferAllocator::new(device);
|
let cb_allocator = StandardCommandBufferAllocator::new(device.clone());
|
||||||
let mut command_buffer_builder = AutoCommandBufferBuilder::primary(
|
let mut cbb = AutoCommandBufferBuilder::primary(
|
||||||
&command_buffer_allocator,
|
&cb_allocator,
|
||||||
queue.queue_family_index(),
|
queue.queue_family_index(),
|
||||||
CommandBufferUsage::OneTimeSubmit,
|
CommandBufferUsage::OneTimeSubmit,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
let dimensions = ImageDimensions::Dim2d {
|
let dimensions = ImageDimensions::Dim2d {
|
||||||
width: 512,
|
width: 512,
|
||||||
height: 512,
|
height: 512,
|
||||||
@ -1040,11 +1042,12 @@ mod tests {
|
|||||||
vec.resize(512 * 512, 0u8);
|
vec.resize(512 * 512, 0u8);
|
||||||
|
|
||||||
let image = ImmutableImage::from_iter(
|
let image = ImmutableImage::from_iter(
|
||||||
|
&memory_allocator,
|
||||||
vec.into_iter(),
|
vec.into_iter(),
|
||||||
dimensions,
|
dimensions,
|
||||||
MipmapsCount::One,
|
MipmapsCount::One,
|
||||||
Format::R8_UNORM,
|
Format::R8_UNORM,
|
||||||
&mut command_buffer_builder,
|
&mut cbb,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(image.mip_levels(), 1);
|
assert_eq!(image.mip_levels(), 1);
|
||||||
@ -1055,11 +1058,12 @@ mod tests {
|
|||||||
vec.resize(512 * 512, 0u8);
|
vec.resize(512 * 512, 0u8);
|
||||||
|
|
||||||
let image = ImmutableImage::from_iter(
|
let image = ImmutableImage::from_iter(
|
||||||
|
&memory_allocator,
|
||||||
vec.into_iter(),
|
vec.into_iter(),
|
||||||
dimensions,
|
dimensions,
|
||||||
MipmapsCount::Log2,
|
MipmapsCount::Log2,
|
||||||
Format::R8_UNORM,
|
Format::R8_UNORM,
|
||||||
&mut command_buffer_builder,
|
&mut cbb,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(image.mip_levels(), 10);
|
assert_eq!(image.mip_levels(), 10);
|
||||||
|
@ -14,14 +14,14 @@ use super::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
device::{Device, DeviceOwned, Queue},
|
device::{Device, DeviceOwned, Queue},
|
||||||
format::Format,
|
format::Format,
|
||||||
image::{sys::UnsafeImageCreateInfo, view::ImageView},
|
image::{sys::UnsafeImageCreateInfo, view::ImageView, ImageFormatInfo},
|
||||||
memory::{
|
memory::{
|
||||||
pool::{
|
allocator::{
|
||||||
alloc_dedicated_with_exportable_fd, AllocFromRequirementsFilter, AllocLayout,
|
AllocationCreateInfo, AllocationType, MemoryAlloc, MemoryAllocatePreference,
|
||||||
MappingRequirement, MemoryPoolAlloc, PotentialDedicatedAllocation, StandardMemoryPool,
|
MemoryAllocator, MemoryUsage,
|
||||||
},
|
},
|
||||||
DedicatedAllocation, DeviceMemoryError, ExternalMemoryHandleType,
|
DedicatedAllocation, DeviceMemoryError, ExternalMemoryHandleType,
|
||||||
ExternalMemoryHandleTypes, MemoryPool,
|
ExternalMemoryHandleTypes,
|
||||||
},
|
},
|
||||||
sync::Sharing,
|
sync::Sharing,
|
||||||
DeviceSize,
|
DeviceSize,
|
||||||
@ -36,15 +36,12 @@ use std::{
|
|||||||
/// General-purpose image in device memory. Can be used for any usage, but will be slower than a
|
/// General-purpose image in device memory. Can be used for any usage, but will be slower than a
|
||||||
/// specialized image.
|
/// specialized image.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct StorageImage<A = Arc<StandardMemoryPool>>
|
pub struct StorageImage {
|
||||||
where
|
|
||||||
A: MemoryPool,
|
|
||||||
{
|
|
||||||
// Inner implementation.
|
// Inner implementation.
|
||||||
image: Arc<UnsafeImage>,
|
image: Arc<UnsafeImage>,
|
||||||
|
|
||||||
// Memory used to back the image.
|
// Memory used to back the image.
|
||||||
memory: PotentialDedicatedAllocation<A::Alloc>,
|
memory: MemoryAlloc,
|
||||||
|
|
||||||
// Dimensions of the image.
|
// Dimensions of the image.
|
||||||
dimensions: ImageDimensions,
|
dimensions: ImageDimensions,
|
||||||
@ -53,7 +50,7 @@ where
|
|||||||
impl StorageImage {
|
impl StorageImage {
|
||||||
/// Creates a new image with the given dimensions and format.
|
/// Creates a new image with the given dimensions and format.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
dimensions: ImageDimensions,
|
dimensions: ImageDimensions,
|
||||||
format: Format,
|
format: Format,
|
||||||
queue_family_indices: impl IntoIterator<Item = u32>,
|
queue_family_indices: impl IntoIterator<Item = u32>,
|
||||||
@ -78,7 +75,7 @@ impl StorageImage {
|
|||||||
let flags = ImageCreateFlags::empty();
|
let flags = ImageCreateFlags::empty();
|
||||||
|
|
||||||
StorageImage::with_usage(
|
StorageImage::with_usage(
|
||||||
device,
|
allocator,
|
||||||
dimensions,
|
dimensions,
|
||||||
format,
|
format,
|
||||||
usage,
|
usage,
|
||||||
@ -89,7 +86,7 @@ impl StorageImage {
|
|||||||
|
|
||||||
/// Same as `new`, but allows specifying the usage.
|
/// Same as `new`, but allows specifying the usage.
|
||||||
pub fn with_usage(
|
pub fn with_usage(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
dimensions: ImageDimensions,
|
dimensions: ImageDimensions,
|
||||||
format: Format,
|
format: Format,
|
||||||
usage: ImageUsage,
|
usage: ImageUsage,
|
||||||
@ -99,7 +96,7 @@ impl StorageImage {
|
|||||||
let queue_family_indices: SmallVec<[_; 4]> = queue_family_indices.into_iter().collect();
|
let queue_family_indices: SmallVec<[_; 4]> = queue_family_indices.into_iter().collect();
|
||||||
|
|
||||||
let image = UnsafeImage::new(
|
let image = UnsafeImage::new(
|
||||||
device.clone(),
|
allocator.device().clone(),
|
||||||
UnsafeImageCreateInfo {
|
UnsafeImageCreateInfo {
|
||||||
dimensions,
|
dimensions,
|
||||||
format: Some(format),
|
format: Some(format),
|
||||||
@ -116,36 +113,34 @@ impl StorageImage {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
let requirements = image.memory_requirements();
|
||||||
|
let create_info = AllocationCreateInfo {
|
||||||
|
requirements,
|
||||||
|
allocation_type: AllocationType::NonLinear,
|
||||||
|
usage: MemoryUsage::GpuOnly,
|
||||||
|
allocate_preference: MemoryAllocatePreference::Unknown,
|
||||||
|
dedicated_allocation: Some(DedicatedAllocation::Image(&image)),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
let mem_reqs = image.memory_requirements();
|
match unsafe { allocator.allocate_unchecked(create_info) } {
|
||||||
let memory = MemoryPool::alloc_from_requirements(
|
Ok(alloc) => {
|
||||||
&device.standard_memory_pool(),
|
debug_assert!(alloc.offset() % requirements.alignment == 0);
|
||||||
&mem_reqs,
|
debug_assert!(alloc.size() == requirements.size);
|
||||||
AllocLayout::Optimal,
|
unsafe { image.bind_memory(alloc.device_memory(), alloc.offset()) }?;
|
||||||
MappingRequirement::DoNotMap,
|
|
||||||
Some(DedicatedAllocation::Image(&image)),
|
|
||||||
|t| {
|
|
||||||
if t.property_flags.device_local {
|
|
||||||
AllocFromRequirementsFilter::Preferred
|
|
||||||
} else {
|
|
||||||
AllocFromRequirementsFilter::Allowed
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
debug_assert!((memory.offset() % mem_reqs.alignment) == 0);
|
|
||||||
unsafe {
|
|
||||||
image.bind_memory(memory.memory(), memory.offset())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Arc::new(StorageImage {
|
Ok(Arc::new(StorageImage {
|
||||||
image,
|
image,
|
||||||
memory,
|
memory: alloc,
|
||||||
dimensions,
|
dimensions,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
Err(err) => Err(err.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new_with_exportable_fd(
|
pub fn new_with_exportable_fd(
|
||||||
device: Arc<Device>,
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
dimensions: ImageDimensions,
|
dimensions: ImageDimensions,
|
||||||
format: Format,
|
format: Format,
|
||||||
usage: ImageUsage,
|
usage: ImageUsage,
|
||||||
@ -154,8 +149,35 @@ impl StorageImage {
|
|||||||
) -> Result<Arc<StorageImage>, ImageCreationError> {
|
) -> Result<Arc<StorageImage>, ImageCreationError> {
|
||||||
let queue_family_indices: SmallVec<[_; 4]> = queue_family_indices.into_iter().collect();
|
let queue_family_indices: SmallVec<[_; 4]> = queue_family_indices.into_iter().collect();
|
||||||
|
|
||||||
|
let external_memory_properties = allocator
|
||||||
|
.device()
|
||||||
|
.physical_device()
|
||||||
|
.image_format_properties(ImageFormatInfo {
|
||||||
|
format: Some(format),
|
||||||
|
image_type: dimensions.image_type(),
|
||||||
|
usage,
|
||||||
|
external_memory_handle_type: Some(ExternalMemoryHandleType::OpaqueFd),
|
||||||
|
mutable_format: flags.mutable_format,
|
||||||
|
cube_compatible: flags.cube_compatible,
|
||||||
|
array_2d_compatible: flags.array_2d_compatible,
|
||||||
|
block_texel_view_compatible: flags.block_texel_view_compatible,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
|
.external_memory_properties;
|
||||||
|
// VUID-VkExportMemoryAllocateInfo-handleTypes-00656
|
||||||
|
assert!(external_memory_properties.exportable);
|
||||||
|
|
||||||
|
// VUID-VkMemoryAllocateInfo-pNext-00639
|
||||||
|
// Guaranteed because we always create a dedicated allocation
|
||||||
|
|
||||||
|
let external_memory_handle_types = ExternalMemoryHandleTypes {
|
||||||
|
opaque_fd: true,
|
||||||
|
..ExternalMemoryHandleTypes::empty()
|
||||||
|
};
|
||||||
let image = UnsafeImage::new(
|
let image = UnsafeImage::new(
|
||||||
device.clone(),
|
allocator.device().clone(),
|
||||||
UnsafeImageCreateInfo {
|
UnsafeImageCreateInfo {
|
||||||
dimensions,
|
dimensions,
|
||||||
format: Some(format),
|
format: Some(format),
|
||||||
@ -165,10 +187,7 @@ impl StorageImage {
|
|||||||
} else {
|
} else {
|
||||||
Sharing::Exclusive
|
Sharing::Exclusive
|
||||||
},
|
},
|
||||||
external_memory_handle_types: ExternalMemoryHandleTypes {
|
external_memory_handle_types,
|
||||||
opaque_fd: true,
|
|
||||||
..ExternalMemoryHandleTypes::empty()
|
|
||||||
},
|
|
||||||
mutable_format: flags.mutable_format,
|
mutable_format: flags.mutable_format,
|
||||||
cube_compatible: flags.cube_compatible,
|
cube_compatible: flags.cube_compatible,
|
||||||
array_2d_compatible: flags.array_2d_compatible,
|
array_2d_compatible: flags.array_2d_compatible,
|
||||||
@ -176,37 +195,38 @@ impl StorageImage {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
let requirements = image.memory_requirements();
|
||||||
|
let memory_type_index = allocator
|
||||||
|
.find_memory_type_index(requirements.memory_type_bits, MemoryUsage::GpuOnly.into())
|
||||||
|
.expect("failed to find a suitable memory type");
|
||||||
|
|
||||||
let mem_reqs = image.memory_requirements();
|
match unsafe {
|
||||||
let memory = alloc_dedicated_with_exportable_fd(
|
allocator.allocate_dedicated_unchecked(
|
||||||
device,
|
memory_type_index,
|
||||||
&mem_reqs,
|
requirements.size,
|
||||||
AllocLayout::Optimal,
|
Some(DedicatedAllocation::Image(&image)),
|
||||||
MappingRequirement::DoNotMap,
|
external_memory_handle_types,
|
||||||
DedicatedAllocation::Image(&image),
|
)
|
||||||
|t| {
|
} {
|
||||||
if t.property_flags.device_local {
|
Ok(alloc) => {
|
||||||
AllocFromRequirementsFilter::Preferred
|
debug_assert!(alloc.offset() % requirements.alignment == 0);
|
||||||
} else {
|
debug_assert!(alloc.size() == requirements.size);
|
||||||
AllocFromRequirementsFilter::Allowed
|
unsafe { image.bind_memory(alloc.device_memory(), alloc.offset()) }?;
|
||||||
}
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
debug_assert!((memory.offset() % mem_reqs.alignment) == 0);
|
|
||||||
unsafe {
|
|
||||||
image.bind_memory(memory.memory(), memory.offset())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Arc::new(StorageImage {
|
Ok(Arc::new(StorageImage {
|
||||||
image,
|
image,
|
||||||
memory,
|
memory: alloc,
|
||||||
dimensions,
|
dimensions,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
Err(err) => Err(err.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Allows the creation of a simple 2D general purpose image view from `StorageImage`.
|
/// Allows the creation of a simple 2D general purpose image view from `StorageImage`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn general_purpose_image_view(
|
pub fn general_purpose_image_view(
|
||||||
|
allocator: &(impl MemoryAllocator + ?Sized),
|
||||||
queue: Arc<Queue>,
|
queue: Arc<Queue>,
|
||||||
size: [u32; 2],
|
size: [u32; 2],
|
||||||
format: Format,
|
format: Format,
|
||||||
@ -219,7 +239,7 @@ impl StorageImage {
|
|||||||
};
|
};
|
||||||
let flags = ImageCreateFlags::empty();
|
let flags = ImageCreateFlags::empty();
|
||||||
let image_result = StorageImage::with_usage(
|
let image_result = StorageImage::with_usage(
|
||||||
queue.device().clone(),
|
allocator,
|
||||||
dims,
|
dims,
|
||||||
format,
|
format,
|
||||||
usage,
|
usage,
|
||||||
@ -244,30 +264,26 @@ impl StorageImage {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn export_posix_fd(&self) -> Result<File, DeviceMemoryError> {
|
pub fn export_posix_fd(&self) -> Result<File, DeviceMemoryError> {
|
||||||
self.memory
|
self.memory
|
||||||
.memory()
|
.device_memory()
|
||||||
.export_fd(ExternalMemoryHandleType::OpaqueFd)
|
.export_fd(ExternalMemoryHandleType::OpaqueFd)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the size of the allocated memory (used e.g. with cuda).
|
/// Return the size of the allocated memory (used e.g. with cuda).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mem_size(&self) -> DeviceSize {
|
pub fn mem_size(&self) -> DeviceSize {
|
||||||
self.memory.memory().allocation_size()
|
self.memory.device_memory().allocation_size()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<A> DeviceOwned for StorageImage<A>
|
unsafe impl DeviceOwned for StorageImage {
|
||||||
where
|
#[inline]
|
||||||
A: MemoryPool,
|
|
||||||
{
|
|
||||||
fn device(&self) -> &Arc<Device> {
|
fn device(&self) -> &Arc<Device> {
|
||||||
self.image.device()
|
self.image.device()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<A> ImageAccess for StorageImage<A>
|
unsafe impl ImageAccess for StorageImage {
|
||||||
where
|
#[inline]
|
||||||
A: MemoryPool,
|
|
||||||
{
|
|
||||||
fn inner(&self) -> ImageInner<'_> {
|
fn inner(&self) -> ImageInner<'_> {
|
||||||
ImageInner {
|
ImageInner {
|
||||||
image: &self.image,
|
image: &self.image,
|
||||||
@ -278,14 +294,17 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn initial_layout_requirement(&self) -> ImageLayout {
|
fn initial_layout_requirement(&self) -> ImageLayout {
|
||||||
ImageLayout::General
|
ImageLayout::General
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn final_layout_requirement(&self) -> ImageLayout {
|
fn final_layout_requirement(&self) -> ImageLayout {
|
||||||
ImageLayout::General
|
ImageLayout::General
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
|
fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
|
||||||
Some(ImageDescriptorLayouts {
|
Some(ImageDescriptorLayouts {
|
||||||
storage_image: ImageLayout::General,
|
storage_image: ImageLayout::General,
|
||||||
@ -296,30 +315,22 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<P, A> ImageContent<P> for StorageImage<A>
|
unsafe impl<P> ImageContent<P> for StorageImage {
|
||||||
where
|
|
||||||
A: MemoryPool,
|
|
||||||
{
|
|
||||||
fn matches_format(&self) -> bool {
|
fn matches_format(&self) -> bool {
|
||||||
true // FIXME:
|
true // FIXME:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A> PartialEq for StorageImage<A>
|
impl PartialEq for StorageImage {
|
||||||
where
|
#[inline]
|
||||||
A: MemoryPool,
|
|
||||||
{
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.inner() == other.inner()
|
self.inner() == other.inner()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A> Eq for StorageImage<A> where A: MemoryPool {}
|
impl Eq for StorageImage {}
|
||||||
|
|
||||||
impl<A> Hash for StorageImage<A>
|
impl Hash for StorageImage {
|
||||||
where
|
|
||||||
A: MemoryPool,
|
|
||||||
{
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.inner().hash(state);
|
self.inner().hash(state);
|
||||||
}
|
}
|
||||||
@ -327,20 +338,15 @@ where
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::StorageImage;
|
use super::*;
|
||||||
use crate::{
|
use crate::{image::view::ImageViewCreationError, memory::allocator::StandardMemoryAllocator};
|
||||||
format::Format,
|
|
||||||
image::{
|
|
||||||
view::ImageViewCreationError, ImageAccess, ImageCreationError, ImageDimensions,
|
|
||||||
ImageUsage,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create() {
|
fn create() {
|
||||||
let (device, queue) = gfx_dev_and_queue!();
|
let (device, queue) = gfx_dev_and_queue!();
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
let _img = StorageImage::new(
|
let _img = StorageImage::new(
|
||||||
device,
|
&memory_allocator,
|
||||||
ImageDimensions::Dim2d {
|
ImageDimensions::Dim2d {
|
||||||
width: 32,
|
width: 32,
|
||||||
height: 32,
|
height: 32,
|
||||||
@ -354,7 +360,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create_general_purpose_image_view() {
|
fn create_general_purpose_image_view() {
|
||||||
let (_device, queue) = gfx_dev_and_queue!();
|
let (device, queue) = gfx_dev_and_queue!();
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
let usage = ImageUsage {
|
let usage = ImageUsage {
|
||||||
transfer_src: true,
|
transfer_src: true,
|
||||||
transfer_dst: true,
|
transfer_dst: true,
|
||||||
@ -362,6 +369,7 @@ mod tests {
|
|||||||
..ImageUsage::empty()
|
..ImageUsage::empty()
|
||||||
};
|
};
|
||||||
let img_view = StorageImage::general_purpose_image_view(
|
let img_view = StorageImage::general_purpose_image_view(
|
||||||
|
&memory_allocator,
|
||||||
queue,
|
queue,
|
||||||
[32, 32],
|
[32, 32],
|
||||||
Format::R8G8B8A8_UNORM,
|
Format::R8G8B8A8_UNORM,
|
||||||
@ -373,13 +381,15 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create_general_purpose_image_view_failed() {
|
fn create_general_purpose_image_view_failed() {
|
||||||
let (_device, queue) = gfx_dev_and_queue!();
|
let (device, queue) = gfx_dev_and_queue!();
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
// Not valid for image view...
|
// Not valid for image view...
|
||||||
let usage = ImageUsage {
|
let usage = ImageUsage {
|
||||||
transfer_src: true,
|
transfer_src: true,
|
||||||
..ImageUsage::empty()
|
..ImageUsage::empty()
|
||||||
};
|
};
|
||||||
let img_result = StorageImage::general_purpose_image_view(
|
let img_result = StorageImage::general_purpose_image_view(
|
||||||
|
&memory_allocator,
|
||||||
queue,
|
queue,
|
||||||
[32, 32],
|
[32, 32],
|
||||||
Format::R8G8B8A8_UNORM,
|
Format::R8G8B8A8_UNORM,
|
||||||
|
@ -27,8 +27,8 @@ use crate::{
|
|||||||
SparseImageFormatProperties,
|
SparseImageFormatProperties,
|
||||||
},
|
},
|
||||||
memory::{
|
memory::{
|
||||||
DeviceMemory, DeviceMemoryError, ExternalMemoryHandleType, ExternalMemoryHandleTypes,
|
allocator::AllocationCreationError, DeviceMemory, ExternalMemoryHandleType,
|
||||||
MemoryRequirements,
|
ExternalMemoryHandleTypes, MemoryRequirements,
|
||||||
},
|
},
|
||||||
range_map::RangeMap,
|
range_map::RangeMap,
|
||||||
sync::{AccessError, CurrentAccess, Sharing},
|
sync::{AccessError, CurrentAccess, Sharing},
|
||||||
@ -1917,11 +1917,11 @@ impl Default for UnsafeImageCreateInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error that can happen when creating an instance.
|
/// Error that can happen when creating an image.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum ImageCreationError {
|
pub enum ImageCreationError {
|
||||||
/// Allocating memory failed.
|
/// Allocating memory failed.
|
||||||
AllocError(DeviceMemoryError),
|
AllocError(AllocationCreationError),
|
||||||
|
|
||||||
RequirementNotMet {
|
RequirementNotMet {
|
||||||
required_for: &'static str,
|
required_for: &'static str,
|
||||||
@ -2174,12 +2174,12 @@ impl Display for ImageCreationError {
|
|||||||
|
|
||||||
impl From<OomError> for ImageCreationError {
|
impl From<OomError> for ImageCreationError {
|
||||||
fn from(err: OomError) -> Self {
|
fn from(err: OomError) -> Self {
|
||||||
Self::AllocError(DeviceMemoryError::OomError(err))
|
Self::AllocError(err.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<DeviceMemoryError> for ImageCreationError {
|
impl From<AllocationCreationError> for ImageCreationError {
|
||||||
fn from(err: DeviceMemoryError) -> Self {
|
fn from(err: AllocationCreationError) -> Self {
|
||||||
Self::AllocError(err)
|
Self::AllocError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2187,8 +2187,12 @@ impl From<DeviceMemoryError> for ImageCreationError {
|
|||||||
impl From<VulkanError> for ImageCreationError {
|
impl From<VulkanError> for ImageCreationError {
|
||||||
fn from(err: VulkanError) -> Self {
|
fn from(err: VulkanError) -> Self {
|
||||||
match err {
|
match err {
|
||||||
err @ VulkanError::OutOfHostMemory => Self::AllocError(err.into()),
|
VulkanError::OutOfHostMemory => {
|
||||||
err @ VulkanError::OutOfDeviceMemory => Self::AllocError(err.into()),
|
Self::AllocError(AllocationCreationError::OutOfHostMemory)
|
||||||
|
}
|
||||||
|
VulkanError::OutOfDeviceMemory => {
|
||||||
|
Self::AllocError(AllocationCreationError::OutOfDeviceMemory)
|
||||||
|
}
|
||||||
_ => panic!("unexpected error: {:?}", err),
|
_ => panic!("unexpected error: {:?}", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1593
vulkano/src/memory/allocator/mod.rs
Normal file
1593
vulkano/src/memory/allocator/mod.rs
Normal file
File diff suppressed because it is too large
Load Diff
3090
vulkano/src/memory/allocator/suballocator.rs
Normal file
3090
vulkano/src/memory/allocator/suballocator.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -92,13 +92,9 @@
|
|||||||
//! get memory from that pool. By default if you don't specify any pool when creating a buffer or
|
//! get memory from that pool. By default if you don't specify any pool when creating a buffer or
|
||||||
//! an image, an instance of `StandardMemoryPool` that is shared by the `Device` object is used.
|
//! an image, an instance of `StandardMemoryPool` that is shared by the `Device` object is used.
|
||||||
|
|
||||||
pub use self::{
|
pub use self::device_memory::{
|
||||||
device_memory::{
|
|
||||||
DeviceMemory, DeviceMemoryError, ExternalMemoryHandleType, ExternalMemoryHandleTypes,
|
DeviceMemory, DeviceMemoryError, ExternalMemoryHandleType, ExternalMemoryHandleTypes,
|
||||||
MappedDeviceMemory, MemoryAllocateFlags, MemoryAllocateInfo, MemoryImportInfo,
|
MappedDeviceMemory, MemoryAllocateFlags, MemoryAllocateInfo, MemoryImportInfo, MemoryMapError,
|
||||||
MemoryMapError,
|
|
||||||
},
|
|
||||||
pool::MemoryPool,
|
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
buffer::{sys::UnsafeBuffer, BufferAccess},
|
buffer::{sys::UnsafeBuffer, BufferAccess},
|
||||||
@ -109,8 +105,8 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub mod allocator;
|
||||||
mod device_memory;
|
mod device_memory;
|
||||||
pub mod pool;
|
|
||||||
|
|
||||||
/// Properties of the memory in a physical device.
|
/// Properties of the memory in a physical device.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -1,181 +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 crate::{
|
|
||||||
device::Device,
|
|
||||||
memory::{
|
|
||||||
device_memory::MemoryAllocateInfo, DeviceMemory, DeviceMemoryError, MappedDeviceMemory,
|
|
||||||
},
|
|
||||||
DeviceSize,
|
|
||||||
};
|
|
||||||
use parking_lot::Mutex;
|
|
||||||
use std::{cmp, ops::Range, sync::Arc};
|
|
||||||
|
|
||||||
/// Memory pool that operates on a given memory type.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct StandardHostVisibleMemoryTypePool {
|
|
||||||
device: Arc<Device>,
|
|
||||||
memory_type_index: u32,
|
|
||||||
// TODO: obviously very inefficient
|
|
||||||
occupied: Mutex<Vec<(Arc<MappedDeviceMemory>, Vec<Range<DeviceSize>>)>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StandardHostVisibleMemoryTypePool {
|
|
||||||
/// Creates a new pool that will operate on the given memory type.
|
|
||||||
///
|
|
||||||
/// # Panic
|
|
||||||
///
|
|
||||||
/// - Panics if `memory_type_index` is out of range.
|
|
||||||
/// - Panics if `memory_type_index` refers to a memory type that is not host-visible.
|
|
||||||
///
|
|
||||||
#[inline]
|
|
||||||
pub fn new(
|
|
||||||
device: Arc<Device>,
|
|
||||||
memory_type_index: u32,
|
|
||||||
) -> Arc<StandardHostVisibleMemoryTypePool> {
|
|
||||||
let memory_type =
|
|
||||||
&device.physical_device().memory_properties().memory_types[memory_type_index as usize];
|
|
||||||
assert!(memory_type.property_flags.host_visible);
|
|
||||||
|
|
||||||
Arc::new(StandardHostVisibleMemoryTypePool {
|
|
||||||
device,
|
|
||||||
memory_type_index,
|
|
||||||
occupied: Mutex::new(Vec::new()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Allocates memory from the pool.
|
|
||||||
///
|
|
||||||
/// # Panic
|
|
||||||
///
|
|
||||||
/// - Panics if `size` is 0.
|
|
||||||
/// - Panics if `alignment` is 0.
|
|
||||||
///
|
|
||||||
pub fn alloc(
|
|
||||||
self: &Arc<Self>,
|
|
||||||
size: DeviceSize,
|
|
||||||
alignment: DeviceSize,
|
|
||||||
) -> Result<StandardHostVisibleMemoryTypePoolAlloc, DeviceMemoryError> {
|
|
||||||
assert!(size != 0);
|
|
||||||
assert!(alignment != 0);
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn align(val: DeviceSize, al: DeviceSize) -> DeviceSize {
|
|
||||||
al * (1 + (val - 1) / al)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find a location.
|
|
||||||
let mut occupied = self.occupied.lock();
|
|
||||||
|
|
||||||
// Try finding an entry in already-allocated chunks.
|
|
||||||
for &mut (ref dev_mem, ref mut entries) in occupied.iter_mut() {
|
|
||||||
// Try find some free space in-between two entries.
|
|
||||||
for i in 0..entries.len().saturating_sub(1) {
|
|
||||||
let entry1 = entries[i].clone();
|
|
||||||
let entry1_end = align(entry1.end, alignment);
|
|
||||||
let entry2 = entries[i + 1].clone();
|
|
||||||
if entry1_end + size <= entry2.start {
|
|
||||||
entries.insert(i + 1, entry1_end..entry1_end + size);
|
|
||||||
return Ok(StandardHostVisibleMemoryTypePoolAlloc {
|
|
||||||
pool: self.clone(),
|
|
||||||
memory: dev_mem.clone(),
|
|
||||||
offset: entry1_end,
|
|
||||||
size,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try append at the end.
|
|
||||||
let last_end = entries.last().map(|e| align(e.end, alignment)).unwrap_or(0);
|
|
||||||
if last_end + size <= (**dev_mem).as_ref().allocation_size() {
|
|
||||||
entries.push(last_end..last_end + size);
|
|
||||||
return Ok(StandardHostVisibleMemoryTypePoolAlloc {
|
|
||||||
pool: self.clone(),
|
|
||||||
memory: dev_mem.clone(),
|
|
||||||
offset: last_end,
|
|
||||||
size,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to allocate a new block.
|
|
||||||
let new_block = {
|
|
||||||
const MIN_BLOCK_SIZE: DeviceSize = 8 * 1024 * 1024; // 8 MB
|
|
||||||
let allocation_size = cmp::max(MIN_BLOCK_SIZE, size.next_power_of_two());
|
|
||||||
let memory = DeviceMemory::allocate(
|
|
||||||
self.device.clone(),
|
|
||||||
MemoryAllocateInfo {
|
|
||||||
allocation_size,
|
|
||||||
memory_type_index: self.memory_type_index,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
let new_block = MappedDeviceMemory::new(memory, 0..allocation_size)?;
|
|
||||||
Arc::new(new_block)
|
|
||||||
};
|
|
||||||
|
|
||||||
occupied.push((new_block.clone(), vec![0..size]));
|
|
||||||
Ok(StandardHostVisibleMemoryTypePoolAlloc {
|
|
||||||
pool: self.clone(),
|
|
||||||
memory: new_block,
|
|
||||||
offset: 0,
|
|
||||||
size,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the device this pool operates on.
|
|
||||||
#[inline]
|
|
||||||
pub fn device(&self) -> &Arc<Device> {
|
|
||||||
&self.device
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the index of the memory type this pool operates on.
|
|
||||||
#[inline]
|
|
||||||
pub fn memory_type_index(&self) -> u32 {
|
|
||||||
self.memory_type_index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct StandardHostVisibleMemoryTypePoolAlloc {
|
|
||||||
pool: Arc<StandardHostVisibleMemoryTypePool>,
|
|
||||||
memory: Arc<MappedDeviceMemory>,
|
|
||||||
offset: DeviceSize,
|
|
||||||
size: DeviceSize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StandardHostVisibleMemoryTypePoolAlloc {
|
|
||||||
#[inline]
|
|
||||||
pub fn memory(&self) -> &MappedDeviceMemory {
|
|
||||||
&self.memory
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn offset(&self) -> DeviceSize {
|
|
||||||
self.offset
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn size(&self) -> DeviceSize {
|
|
||||||
self.size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for StandardHostVisibleMemoryTypePoolAlloc {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
let mut occupied = self.pool.occupied.lock();
|
|
||||||
|
|
||||||
let entries = occupied
|
|
||||||
.iter_mut()
|
|
||||||
.find(|e| &*e.0 as *const MappedDeviceMemory == &*self.memory)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
entries.1.retain(|e| e.start != self.offset);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,322 +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.
|
|
||||||
|
|
||||||
pub use self::{
|
|
||||||
host_visible::{StandardHostVisibleMemoryTypePool, StandardHostVisibleMemoryTypePoolAlloc},
|
|
||||||
non_host_visible::{
|
|
||||||
StandardNonHostVisibleMemoryTypePool, StandardNonHostVisibleMemoryTypePoolAlloc,
|
|
||||||
},
|
|
||||||
pool::{StandardMemoryPool, StandardMemoryPoolAlloc},
|
|
||||||
};
|
|
||||||
use super::MemoryType;
|
|
||||||
use crate::{
|
|
||||||
device::{Device, DeviceOwned},
|
|
||||||
memory::{
|
|
||||||
device_memory::MemoryAllocateInfo, DedicatedAllocation, DeviceMemory, DeviceMemoryError,
|
|
||||||
ExternalMemoryHandleTypes, MappedDeviceMemory, MemoryRequirements,
|
|
||||||
},
|
|
||||||
DeviceSize,
|
|
||||||
};
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
mod host_visible;
|
|
||||||
mod non_host_visible;
|
|
||||||
mod pool;
|
|
||||||
|
|
||||||
// If the allocation size goes beyond this, then we perform a dedicated allocation which bypasses
|
|
||||||
// the pool. This prevents the pool from overallocating a significant amount of memory.
|
|
||||||
const MAX_POOL_ALLOC: DeviceSize = 256 * 1024 * 1024;
|
|
||||||
|
|
||||||
fn choose_allocation_memory_type<F>(
|
|
||||||
device: &Arc<Device>,
|
|
||||||
requirements: &MemoryRequirements,
|
|
||||||
mut filter: F,
|
|
||||||
map: MappingRequirement,
|
|
||||||
) -> u32
|
|
||||||
where
|
|
||||||
F: FnMut(&MemoryType) -> AllocFromRequirementsFilter,
|
|
||||||
{
|
|
||||||
let mem_ty = {
|
|
||||||
let mut filter = |ty: &MemoryType| {
|
|
||||||
if map == MappingRequirement::Map && !ty.property_flags.host_visible {
|
|
||||||
return AllocFromRequirementsFilter::Forbidden;
|
|
||||||
}
|
|
||||||
filter(ty)
|
|
||||||
};
|
|
||||||
let first_loop = device
|
|
||||||
.physical_device()
|
|
||||||
.memory_properties()
|
|
||||||
.memory_types
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(i, t)| (i as u32, t, AllocFromRequirementsFilter::Preferred));
|
|
||||||
let second_loop = device
|
|
||||||
.physical_device()
|
|
||||||
.memory_properties()
|
|
||||||
.memory_types
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(i, t)| (i as u32, t, AllocFromRequirementsFilter::Allowed));
|
|
||||||
first_loop
|
|
||||||
.chain(second_loop)
|
|
||||||
.filter(|(i, _, _)| (requirements.memory_type_bits & (1 << *i)) != 0)
|
|
||||||
.find(|&(_, t, rq)| filter(t) == rq)
|
|
||||||
.expect("Couldn't find a memory type to allocate from")
|
|
||||||
.0
|
|
||||||
};
|
|
||||||
mem_ty
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Allocate dedicated memory with exportable fd.
|
|
||||||
/// Memory pool memory always exports the same fd, thus dedicated is preferred.
|
|
||||||
pub(crate) fn alloc_dedicated_with_exportable_fd<F>(
|
|
||||||
device: Arc<Device>,
|
|
||||||
requirements: &MemoryRequirements,
|
|
||||||
_layout: AllocLayout,
|
|
||||||
map: MappingRequirement,
|
|
||||||
dedicated_allocation: DedicatedAllocation<'_>,
|
|
||||||
filter: F,
|
|
||||||
) -> Result<PotentialDedicatedAllocation<StandardMemoryPoolAlloc>, DeviceMemoryError>
|
|
||||||
where
|
|
||||||
F: FnMut(&MemoryType) -> AllocFromRequirementsFilter,
|
|
||||||
{
|
|
||||||
assert!(device.enabled_extensions().khr_external_memory_fd);
|
|
||||||
assert!(device.enabled_extensions().khr_external_memory);
|
|
||||||
|
|
||||||
let memory_type_index = choose_allocation_memory_type(&device, requirements, filter, map);
|
|
||||||
let memory = DeviceMemory::allocate(
|
|
||||||
device,
|
|
||||||
MemoryAllocateInfo {
|
|
||||||
allocation_size: requirements.size,
|
|
||||||
memory_type_index,
|
|
||||||
export_handle_types: ExternalMemoryHandleTypes {
|
|
||||||
opaque_fd: true,
|
|
||||||
..ExternalMemoryHandleTypes::empty()
|
|
||||||
},
|
|
||||||
..MemoryAllocateInfo::dedicated_allocation(dedicated_allocation)
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
match map {
|
|
||||||
MappingRequirement::Map => {
|
|
||||||
let mapped_memory = MappedDeviceMemory::new(memory, 0..requirements.size)?;
|
|
||||||
Ok(PotentialDedicatedAllocation::DedicatedMapped(mapped_memory))
|
|
||||||
}
|
|
||||||
MappingRequirement::DoNotMap => Ok(PotentialDedicatedAllocation::Dedicated(memory)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pool of GPU-visible memory that can be allocated from.
|
|
||||||
pub unsafe trait MemoryPool: DeviceOwned {
|
|
||||||
/// Object that represents a single allocation. Its destructor should free the chunk.
|
|
||||||
type Alloc: MemoryPoolAlloc;
|
|
||||||
|
|
||||||
/// Allocates memory from the pool.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// Implementation safety:
|
|
||||||
///
|
|
||||||
/// - The returned object must match the requirements.
|
|
||||||
/// - When a linear object is allocated next to an optimal object, it is mandatory that
|
|
||||||
/// the boundary is aligned to the value of the `buffer_image_granularity` limit.
|
|
||||||
///
|
|
||||||
/// Note that it is not unsafe to *call* this function, but it is unsafe to bind the memory
|
|
||||||
/// returned by this function to a resource.
|
|
||||||
///
|
|
||||||
/// # Panic
|
|
||||||
///
|
|
||||||
/// - Panics if `memory_type` doesn't belong to the same physical device as the device which
|
|
||||||
/// was used to create this pool.
|
|
||||||
/// - Panics if the memory type is not host-visible and `map` is `MappingRequirement::Map`.
|
|
||||||
/// - Panics if `size` is 0.
|
|
||||||
/// - Panics if `alignment` is 0.
|
|
||||||
///
|
|
||||||
fn alloc_generic(
|
|
||||||
&self,
|
|
||||||
memory_type_index: u32,
|
|
||||||
size: DeviceSize,
|
|
||||||
alignment: DeviceSize,
|
|
||||||
layout: AllocLayout,
|
|
||||||
map: MappingRequirement,
|
|
||||||
) -> Result<Self::Alloc, DeviceMemoryError>;
|
|
||||||
|
|
||||||
/// Chooses a memory type and allocates memory from it.
|
|
||||||
///
|
|
||||||
/// Contrary to `alloc_generic`, this function may allocate a whole new block of memory
|
|
||||||
/// dedicated to a resource based on `requirements.prefer_dedicated`.
|
|
||||||
///
|
|
||||||
/// `filter` can be used to restrict the memory types and to indicate which are preferred.
|
|
||||||
/// If `map` is `MappingRequirement::Map`, then non-host-visible memory types will
|
|
||||||
/// automatically be filtered out.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// Implementation safety:
|
|
||||||
///
|
|
||||||
/// - The returned object must match the requirements.
|
|
||||||
/// - When a linear object is allocated next to an optimal object, it is mandatory that
|
|
||||||
/// the boundary is aligned to the value of the `buffer_image_granularity` limit.
|
|
||||||
/// - If `dedicated` is not `None`, the returned memory must either not be dedicated or be
|
|
||||||
/// dedicated to the resource that was passed.
|
|
||||||
///
|
|
||||||
/// Note that it is not unsafe to *call* this function, but it is unsafe to bind the memory
|
|
||||||
/// returned by this function to a resource.
|
|
||||||
///
|
|
||||||
/// # Panic
|
|
||||||
///
|
|
||||||
/// - Panics if no memory type could be found, which can happen if `filter` is too restrictive.
|
|
||||||
// TODO: ^ is this a good idea?
|
|
||||||
/// - Panics if `size` is 0.
|
|
||||||
/// - Panics if `alignment` is 0.
|
|
||||||
///
|
|
||||||
fn alloc_from_requirements<F>(
|
|
||||||
&self,
|
|
||||||
requirements: &MemoryRequirements,
|
|
||||||
layout: AllocLayout,
|
|
||||||
map: MappingRequirement,
|
|
||||||
dedicated_allocation: Option<DedicatedAllocation<'_>>,
|
|
||||||
filter: F,
|
|
||||||
) -> Result<PotentialDedicatedAllocation<Self::Alloc>, DeviceMemoryError>
|
|
||||||
where
|
|
||||||
F: FnMut(&MemoryType) -> AllocFromRequirementsFilter,
|
|
||||||
{
|
|
||||||
// Choose a suitable memory type.
|
|
||||||
let memory_type_index =
|
|
||||||
choose_allocation_memory_type(self.device(), requirements, filter, map);
|
|
||||||
|
|
||||||
// Redirect to `self.alloc_generic` if we don't perform a dedicated allocation.
|
|
||||||
if !requirements.prefer_dedicated && requirements.size <= MAX_POOL_ALLOC {
|
|
||||||
let alloc = self.alloc_generic(
|
|
||||||
memory_type_index,
|
|
||||||
requirements.size,
|
|
||||||
requirements.alignment,
|
|
||||||
layout,
|
|
||||||
map,
|
|
||||||
)?;
|
|
||||||
return Ok(alloc.into());
|
|
||||||
}
|
|
||||||
if dedicated_allocation.is_none() {
|
|
||||||
let alloc = self.alloc_generic(
|
|
||||||
memory_type_index,
|
|
||||||
requirements.size,
|
|
||||||
requirements.alignment,
|
|
||||||
layout,
|
|
||||||
map,
|
|
||||||
)?;
|
|
||||||
return Ok(alloc.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we reach here, then we perform a dedicated alloc.
|
|
||||||
let memory = DeviceMemory::allocate(
|
|
||||||
self.device().clone(),
|
|
||||||
MemoryAllocateInfo {
|
|
||||||
allocation_size: requirements.size,
|
|
||||||
memory_type_index,
|
|
||||||
dedicated_allocation,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
match map {
|
|
||||||
MappingRequirement::Map => {
|
|
||||||
let mapped_memory = MappedDeviceMemory::new(memory, 0..requirements.size)?;
|
|
||||||
Ok(PotentialDedicatedAllocation::DedicatedMapped(mapped_memory))
|
|
||||||
}
|
|
||||||
MappingRequirement::DoNotMap => Ok(PotentialDedicatedAllocation::Dedicated(memory)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
||||||
pub enum AllocFromRequirementsFilter {
|
|
||||||
Preferred,
|
|
||||||
Allowed,
|
|
||||||
Forbidden,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Object that represents a single allocation. Its destructor should free the chunk.
|
|
||||||
pub unsafe trait MemoryPoolAlloc: Send + Sync {
|
|
||||||
/// Returns the memory object from which this is allocated. Returns `None` if the memory is
|
|
||||||
/// not mapped.
|
|
||||||
fn mapped_memory(&self) -> Option<&MappedDeviceMemory>;
|
|
||||||
|
|
||||||
/// Returns the memory object from which this is allocated.
|
|
||||||
fn memory(&self) -> &DeviceMemory;
|
|
||||||
|
|
||||||
/// Returns the offset at the start of the memory where the first byte of this allocation
|
|
||||||
/// resides.
|
|
||||||
fn offset(&self) -> DeviceSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Whether an allocation should map the memory or not.
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub enum MappingRequirement {
|
|
||||||
/// Should map.
|
|
||||||
Map,
|
|
||||||
/// Shouldn't map.
|
|
||||||
DoNotMap,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Layout of the object being allocated.
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub enum AllocLayout {
|
|
||||||
/// The object has a linear layout.
|
|
||||||
Linear,
|
|
||||||
/// The object has an optimal layout.
|
|
||||||
Optimal,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Enumeration that can contain either a generic allocation coming from a pool, or a dedicated
|
|
||||||
/// allocation for one specific resource.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum PotentialDedicatedAllocation<A> {
|
|
||||||
Generic(A),
|
|
||||||
Dedicated(DeviceMemory),
|
|
||||||
DedicatedMapped(MappedDeviceMemory),
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<A> MemoryPoolAlloc for PotentialDedicatedAllocation<A>
|
|
||||||
where
|
|
||||||
A: MemoryPoolAlloc,
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn mapped_memory(&self) -> Option<&MappedDeviceMemory> {
|
|
||||||
match *self {
|
|
||||||
PotentialDedicatedAllocation::Generic(ref alloc) => alloc.mapped_memory(),
|
|
||||||
PotentialDedicatedAllocation::Dedicated(_) => None,
|
|
||||||
PotentialDedicatedAllocation::DedicatedMapped(ref mem) => Some(mem),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn memory(&self) -> &DeviceMemory {
|
|
||||||
match *self {
|
|
||||||
PotentialDedicatedAllocation::Generic(ref alloc) => alloc.memory(),
|
|
||||||
PotentialDedicatedAllocation::Dedicated(ref mem) => mem,
|
|
||||||
PotentialDedicatedAllocation::DedicatedMapped(ref mem) => mem.as_ref(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn offset(&self) -> DeviceSize {
|
|
||||||
match *self {
|
|
||||||
PotentialDedicatedAllocation::Generic(ref alloc) => alloc.offset(),
|
|
||||||
PotentialDedicatedAllocation::Dedicated(_) => 0,
|
|
||||||
PotentialDedicatedAllocation::DedicatedMapped(_) => 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A> From<A> for PotentialDedicatedAllocation<A> {
|
|
||||||
#[inline]
|
|
||||||
fn from(alloc: A) -> PotentialDedicatedAllocation<A> {
|
|
||||||
PotentialDedicatedAllocation::Generic(alloc)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,169 +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 crate::{
|
|
||||||
device::Device,
|
|
||||||
memory::{device_memory::MemoryAllocateInfo, DeviceMemory, DeviceMemoryError},
|
|
||||||
DeviceSize,
|
|
||||||
};
|
|
||||||
use parking_lot::Mutex;
|
|
||||||
use std::{cmp, ops::Range, sync::Arc};
|
|
||||||
|
|
||||||
/// Memory pool that operates on a given memory type.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct StandardNonHostVisibleMemoryTypePool {
|
|
||||||
device: Arc<Device>,
|
|
||||||
memory_type_index: u32,
|
|
||||||
// TODO: obviously very inefficient
|
|
||||||
occupied: Mutex<Vec<(Arc<DeviceMemory>, Vec<Range<DeviceSize>>)>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StandardNonHostVisibleMemoryTypePool {
|
|
||||||
/// Creates a new pool that will operate on the given memory type.
|
|
||||||
///
|
|
||||||
/// # Panic
|
|
||||||
///
|
|
||||||
/// - Panics if `memory_type_index` is out of range.
|
|
||||||
#[inline]
|
|
||||||
pub fn new(
|
|
||||||
device: Arc<Device>,
|
|
||||||
memory_type_index: u32,
|
|
||||||
) -> Arc<StandardNonHostVisibleMemoryTypePool> {
|
|
||||||
let _ =
|
|
||||||
&device.physical_device().memory_properties().memory_types[memory_type_index as usize];
|
|
||||||
|
|
||||||
Arc::new(StandardNonHostVisibleMemoryTypePool {
|
|
||||||
device,
|
|
||||||
memory_type_index,
|
|
||||||
occupied: Mutex::new(Vec::new()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Allocates memory from the pool.
|
|
||||||
///
|
|
||||||
/// # Panic
|
|
||||||
///
|
|
||||||
/// - Panics if `size` is 0.
|
|
||||||
/// - Panics if `alignment` is 0.
|
|
||||||
///
|
|
||||||
pub fn alloc(
|
|
||||||
self: &Arc<Self>,
|
|
||||||
size: DeviceSize,
|
|
||||||
alignment: DeviceSize,
|
|
||||||
) -> Result<StandardNonHostVisibleMemoryTypePoolAlloc, DeviceMemoryError> {
|
|
||||||
assert!(size != 0);
|
|
||||||
assert!(alignment != 0);
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn align(val: DeviceSize, al: DeviceSize) -> DeviceSize {
|
|
||||||
al * (1 + (val - 1) / al)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find a location.
|
|
||||||
let mut occupied = self.occupied.lock();
|
|
||||||
|
|
||||||
// Try finding an entry in already-allocated chunks.
|
|
||||||
for &mut (ref dev_mem, ref mut entries) in occupied.iter_mut() {
|
|
||||||
// Try find some free space in-between two entries.
|
|
||||||
for i in 0..entries.len().saturating_sub(1) {
|
|
||||||
let entry1 = entries[i].clone();
|
|
||||||
let entry1_end = align(entry1.end, alignment);
|
|
||||||
let entry2 = entries[i + 1].clone();
|
|
||||||
if entry1_end + size <= entry2.start {
|
|
||||||
entries.insert(i + 1, entry1_end..entry1_end + size);
|
|
||||||
return Ok(StandardNonHostVisibleMemoryTypePoolAlloc {
|
|
||||||
pool: self.clone(),
|
|
||||||
memory: dev_mem.clone(),
|
|
||||||
offset: entry1_end,
|
|
||||||
size,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try append at the end.
|
|
||||||
let last_end = entries.last().map(|e| align(e.end, alignment)).unwrap_or(0);
|
|
||||||
if last_end + size <= dev_mem.allocation_size() {
|
|
||||||
entries.push(last_end..last_end + size);
|
|
||||||
return Ok(StandardNonHostVisibleMemoryTypePoolAlloc {
|
|
||||||
pool: self.clone(),
|
|
||||||
memory: dev_mem.clone(),
|
|
||||||
offset: last_end,
|
|
||||||
size,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to allocate a new block.
|
|
||||||
let new_block = {
|
|
||||||
const MIN_BLOCK_SIZE: DeviceSize = 8 * 1024 * 1024; // 8 MB
|
|
||||||
let allocation_size = cmp::max(MIN_BLOCK_SIZE, size.next_power_of_two());
|
|
||||||
let new_block = DeviceMemory::allocate(
|
|
||||||
self.device.clone(),
|
|
||||||
MemoryAllocateInfo {
|
|
||||||
allocation_size,
|
|
||||||
memory_type_index: self.memory_type_index,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
Arc::new(new_block)
|
|
||||||
};
|
|
||||||
|
|
||||||
occupied.push((new_block.clone(), vec![0..size]));
|
|
||||||
Ok(StandardNonHostVisibleMemoryTypePoolAlloc {
|
|
||||||
pool: self.clone(),
|
|
||||||
memory: new_block,
|
|
||||||
offset: 0,
|
|
||||||
size,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the index of the memory type this pool operates on.
|
|
||||||
#[inline]
|
|
||||||
pub fn memory_type_index(&self) -> u32 {
|
|
||||||
self.memory_type_index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct StandardNonHostVisibleMemoryTypePoolAlloc {
|
|
||||||
pool: Arc<StandardNonHostVisibleMemoryTypePool>,
|
|
||||||
memory: Arc<DeviceMemory>,
|
|
||||||
offset: DeviceSize,
|
|
||||||
size: DeviceSize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StandardNonHostVisibleMemoryTypePoolAlloc {
|
|
||||||
#[inline]
|
|
||||||
pub fn memory(&self) -> &DeviceMemory {
|
|
||||||
&self.memory
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn offset(&self) -> DeviceSize {
|
|
||||||
self.offset
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn size(&self) -> DeviceSize {
|
|
||||||
self.size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for StandardNonHostVisibleMemoryTypePoolAlloc {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
let mut occupied = self.pool.occupied.lock();
|
|
||||||
|
|
||||||
let entries = occupied
|
|
||||||
.iter_mut()
|
|
||||||
.find(|e| &*e.0 as *const DeviceMemory == &*self.memory)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
entries.1.retain(|e| e.start != self.offset);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,206 +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 crate::{
|
|
||||||
device::{Device, DeviceOwned},
|
|
||||||
memory::{
|
|
||||||
pool::{
|
|
||||||
AllocLayout, MappingRequirement, MemoryPool, MemoryPoolAlloc,
|
|
||||||
StandardHostVisibleMemoryTypePool, StandardHostVisibleMemoryTypePoolAlloc,
|
|
||||||
StandardNonHostVisibleMemoryTypePool, StandardNonHostVisibleMemoryTypePoolAlloc,
|
|
||||||
},
|
|
||||||
DeviceMemory, DeviceMemoryError, MappedDeviceMemory,
|
|
||||||
},
|
|
||||||
DeviceSize,
|
|
||||||
};
|
|
||||||
use parking_lot::Mutex;
|
|
||||||
use std::{
|
|
||||||
collections::{hash_map::Entry, HashMap},
|
|
||||||
sync::Arc,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct StandardMemoryPool {
|
|
||||||
device: Arc<Device>,
|
|
||||||
|
|
||||||
// For each memory type index, stores the associated pool.
|
|
||||||
pools: Mutex<HashMap<(u32, AllocLayout, MappingRequirement), Pool>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StandardMemoryPool {
|
|
||||||
/// Creates a new pool.
|
|
||||||
#[inline]
|
|
||||||
pub fn new(device: Arc<Device>) -> Arc<StandardMemoryPool> {
|
|
||||||
let cap = device
|
|
||||||
.physical_device()
|
|
||||||
.memory_properties()
|
|
||||||
.memory_types
|
|
||||||
.len();
|
|
||||||
|
|
||||||
Arc::new(StandardMemoryPool {
|
|
||||||
device,
|
|
||||||
pools: Mutex::new(HashMap::with_capacity(cap)),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generic_allocation(
|
|
||||||
mem_pool: Arc<StandardMemoryPool>,
|
|
||||||
memory_type_index: u32,
|
|
||||||
size: DeviceSize,
|
|
||||||
alignment: DeviceSize,
|
|
||||||
layout: AllocLayout,
|
|
||||||
map: MappingRequirement,
|
|
||||||
) -> Result<StandardMemoryPoolAlloc, DeviceMemoryError> {
|
|
||||||
let mut pools = mem_pool.pools.lock();
|
|
||||||
|
|
||||||
let memory_properties = mem_pool.device().physical_device().memory_properties();
|
|
||||||
let memory_type = memory_properties
|
|
||||||
.memory_types
|
|
||||||
.get(memory_type_index as usize)
|
|
||||||
.ok_or(DeviceMemoryError::MemoryTypeIndexOutOfRange {
|
|
||||||
memory_type_index,
|
|
||||||
memory_type_count: memory_properties.memory_types.len() as u32,
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let memory_type_host_visible = memory_type.property_flags.host_visible;
|
|
||||||
assert!(memory_type_host_visible || map == MappingRequirement::DoNotMap);
|
|
||||||
|
|
||||||
match pools.entry((memory_type_index, layout, map)) {
|
|
||||||
Entry::Occupied(entry) => match *entry.get() {
|
|
||||||
Pool::HostVisible(ref pool) => {
|
|
||||||
let alloc = pool.alloc(size, alignment)?;
|
|
||||||
let inner = StandardMemoryPoolAllocInner::HostVisible(alloc);
|
|
||||||
Ok(StandardMemoryPoolAlloc {
|
|
||||||
inner,
|
|
||||||
_pool: mem_pool.clone(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Pool::NonHostVisible(ref pool) => {
|
|
||||||
let alloc = pool.alloc(size, alignment)?;
|
|
||||||
let inner = StandardMemoryPoolAllocInner::NonHostVisible(alloc);
|
|
||||||
Ok(StandardMemoryPoolAlloc {
|
|
||||||
inner,
|
|
||||||
_pool: mem_pool.clone(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
Entry::Vacant(entry) => {
|
|
||||||
if memory_type_host_visible {
|
|
||||||
let pool = StandardHostVisibleMemoryTypePool::new(
|
|
||||||
mem_pool.device.clone(),
|
|
||||||
memory_type_index,
|
|
||||||
);
|
|
||||||
entry.insert(Pool::HostVisible(pool.clone()));
|
|
||||||
let alloc = pool.alloc(size, alignment)?;
|
|
||||||
let inner = StandardMemoryPoolAllocInner::HostVisible(alloc);
|
|
||||||
Ok(StandardMemoryPoolAlloc {
|
|
||||||
inner,
|
|
||||||
_pool: mem_pool.clone(),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
let pool = StandardNonHostVisibleMemoryTypePool::new(
|
|
||||||
mem_pool.device.clone(),
|
|
||||||
memory_type_index,
|
|
||||||
);
|
|
||||||
entry.insert(Pool::NonHostVisible(pool.clone()));
|
|
||||||
let alloc = pool.alloc(size, alignment)?;
|
|
||||||
let inner = StandardMemoryPoolAllocInner::NonHostVisible(alloc);
|
|
||||||
Ok(StandardMemoryPoolAlloc {
|
|
||||||
inner,
|
|
||||||
_pool: mem_pool.clone(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl MemoryPool for Arc<StandardMemoryPool> {
|
|
||||||
type Alloc = StandardMemoryPoolAlloc;
|
|
||||||
|
|
||||||
fn alloc_generic(
|
|
||||||
&self,
|
|
||||||
memory_type_index: u32,
|
|
||||||
size: DeviceSize,
|
|
||||||
alignment: DeviceSize,
|
|
||||||
layout: AllocLayout,
|
|
||||||
map: MappingRequirement,
|
|
||||||
) -> Result<StandardMemoryPoolAlloc, DeviceMemoryError> {
|
|
||||||
generic_allocation(
|
|
||||||
self.clone(),
|
|
||||||
memory_type_index,
|
|
||||||
size,
|
|
||||||
alignment,
|
|
||||||
layout,
|
|
||||||
map,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl DeviceOwned for StandardMemoryPool {
|
|
||||||
#[inline]
|
|
||||||
fn device(&self) -> &Arc<Device> {
|
|
||||||
&self.device
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum Pool {
|
|
||||||
HostVisible(Arc<StandardHostVisibleMemoryTypePool>),
|
|
||||||
NonHostVisible(Arc<StandardNonHostVisibleMemoryTypePool>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct StandardMemoryPoolAlloc {
|
|
||||||
inner: StandardMemoryPoolAllocInner,
|
|
||||||
_pool: Arc<StandardMemoryPool>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StandardMemoryPoolAlloc {
|
|
||||||
#[inline]
|
|
||||||
pub fn size(&self) -> DeviceSize {
|
|
||||||
match self.inner {
|
|
||||||
StandardMemoryPoolAllocInner::NonHostVisible(ref mem) => mem.size(),
|
|
||||||
StandardMemoryPoolAllocInner::HostVisible(ref mem) => mem.size(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl MemoryPoolAlloc for StandardMemoryPoolAlloc {
|
|
||||||
#[inline]
|
|
||||||
fn memory(&self) -> &DeviceMemory {
|
|
||||||
match self.inner {
|
|
||||||
StandardMemoryPoolAllocInner::NonHostVisible(ref mem) => mem.memory(),
|
|
||||||
StandardMemoryPoolAllocInner::HostVisible(ref mem) => mem.memory().as_ref(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn mapped_memory(&self) -> Option<&MappedDeviceMemory> {
|
|
||||||
match self.inner {
|
|
||||||
StandardMemoryPoolAllocInner::NonHostVisible(_) => None,
|
|
||||||
StandardMemoryPoolAllocInner::HostVisible(ref mem) => Some(mem.memory()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn offset(&self) -> DeviceSize {
|
|
||||||
match self.inner {
|
|
||||||
StandardMemoryPoolAllocInner::NonHostVisible(ref mem) => mem.offset(),
|
|
||||||
StandardMemoryPoolAllocInner::HostVisible(ref mem) => mem.offset(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum StandardMemoryPoolAllocInner {
|
|
||||||
NonHostVisible(StandardNonHostVisibleMemoryTypePoolAlloc),
|
|
||||||
HostVisible(StandardHostVisibleMemoryTypePoolAlloc),
|
|
||||||
}
|
|
@ -409,6 +409,7 @@ mod tests {
|
|||||||
descriptor_set::{
|
descriptor_set::{
|
||||||
allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet,
|
allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet,
|
||||||
},
|
},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
||||||
shader::{ShaderModule, SpecializationConstants, SpecializationMapEntry},
|
shader::{ShaderModule, SpecializationConstants, SpecializationMapEntry},
|
||||||
sync::{now, GpuFuture},
|
sync::{now, GpuFuture},
|
||||||
@ -491,8 +492,9 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||||
let data_buffer = CpuAccessibleBuffer::from_data(
|
let data_buffer = CpuAccessibleBuffer::from_data(
|
||||||
device.clone(),
|
&memory_allocator,
|
||||||
BufferUsage {
|
BufferUsage {
|
||||||
storage_buffer: true,
|
storage_buffer: true,
|
||||||
..BufferUsage::empty()
|
..BufferUsage::empty()
|
||||||
|
@ -720,6 +720,7 @@ mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
format::Format,
|
format::Format,
|
||||||
image::{attachment::AttachmentImage, view::ImageView},
|
image::{attachment::AttachmentImage, view::ImageView},
|
||||||
|
memory::allocator::StandardMemoryAllocator,
|
||||||
render_pass::{Framebuffer, FramebufferCreateInfo, FramebufferCreationError, RenderPass},
|
render_pass::{Framebuffer, FramebufferCreateInfo, FramebufferCreationError, RenderPass},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -743,8 +744,9 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
let view = ImageView::new_default(
|
let view = ImageView::new_default(
|
||||||
AttachmentImage::new(device, [1024, 768], Format::R8G8B8A8_UNORM).unwrap(),
|
AttachmentImage::new(&memory_allocator, [1024, 768], Format::R8G8B8A8_UNORM).unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let _ = Framebuffer::new(
|
let _ = Framebuffer::new(
|
||||||
@ -810,8 +812,9 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
let view = ImageView::new_default(
|
let view = ImageView::new_default(
|
||||||
AttachmentImage::new(device, [1024, 768], Format::R8_UNORM).unwrap(),
|
AttachmentImage::new(&memory_allocator, [1024, 768], Format::R8_UNORM).unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -849,8 +852,9 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
let view = ImageView::new_default(
|
let view = ImageView::new_default(
|
||||||
AttachmentImage::new(device, [600, 600], Format::R8G8B8A8_UNORM).unwrap(),
|
AttachmentImage::new(&memory_allocator, [600, 600], Format::R8G8B8A8_UNORM).unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -886,8 +890,9 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
let view = ImageView::new_default(
|
let view = ImageView::new_default(
|
||||||
AttachmentImage::new(device, [512, 700], Format::R8G8B8A8_UNORM).unwrap(),
|
AttachmentImage::new(&memory_allocator, [512, 700], Format::R8G8B8A8_UNORM).unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -931,12 +936,13 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
let a = ImageView::new_default(
|
let a = ImageView::new_default(
|
||||||
AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8_UNORM).unwrap(),
|
AttachmentImage::new(&memory_allocator, [256, 512], Format::R8G8B8A8_UNORM).unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let b = ImageView::new_default(
|
let b = ImageView::new_default(
|
||||||
AttachmentImage::new(device, [512, 128], Format::R8G8B8A8_UNORM).unwrap(),
|
AttachmentImage::new(&memory_allocator, [512, 128], Format::R8G8B8A8_UNORM).unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -981,8 +987,9 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
let view = ImageView::new_default(
|
let view = ImageView::new_default(
|
||||||
AttachmentImage::new(device, [256, 512], Format::R8G8B8A8_UNORM).unwrap(),
|
AttachmentImage::new(&memory_allocator, [256, 512], Format::R8G8B8A8_UNORM).unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -1023,12 +1030,13 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let memory_allocator = StandardMemoryAllocator::new_default(device);
|
||||||
let a = ImageView::new_default(
|
let a = ImageView::new_default(
|
||||||
AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8_UNORM).unwrap(),
|
AttachmentImage::new(&memory_allocator, [256, 512], Format::R8G8B8A8_UNORM).unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let b = ImageView::new_default(
|
let b = ImageView::new_default(
|
||||||
AttachmentImage::new(device, [256, 512], Format::R8G8B8A8_UNORM).unwrap(),
|
AttachmentImage::new(&memory_allocator, [256, 512], Format::R8G8B8A8_UNORM).unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
//! # let device: std::sync::Arc<vulkano::device::Device> = return;
|
//! # let device: std::sync::Arc<vulkano::device::Device> = return;
|
||||||
//! # let image_data: Vec<u8> = return;
|
//! # let image_data: Vec<u8> = return;
|
||||||
//! # let queue: std::sync::Arc<vulkano::device::Queue> = return;
|
//! # let queue: std::sync::Arc<vulkano::device::Queue> = return;
|
||||||
|
//! # let memory_allocator: vulkano::memory::allocator::StandardMemoryAllocator = return;
|
||||||
//! # let descriptor_set_allocator: vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator = return;
|
//! # let descriptor_set_allocator: vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator = return;
|
||||||
//! # let mut command_buffer_builder: vulkano::command_buffer::AutoCommandBufferBuilder<vulkano::command_buffer::PrimaryAutoCommandBuffer> = return;
|
//! # let mut command_buffer_builder: vulkano::command_buffer::AutoCommandBufferBuilder<vulkano::command_buffer::PrimaryAutoCommandBuffer> = return;
|
||||||
//! use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
|
//! use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
|
||||||
@ -67,6 +68,7 @@
|
|||||||
//! ).unwrap();
|
//! ).unwrap();
|
||||||
//!
|
//!
|
||||||
//! let image = ImmutableImage::from_iter(
|
//! let image = ImmutableImage::from_iter(
|
||||||
|
//! &memory_allocator,
|
||||||
//! image_data,
|
//! image_data,
|
||||||
//! ImageDimensions::Dim2d { width: 1920, height: 1080, array_layers: 1 },
|
//! ImageDimensions::Dim2d { width: 1920, height: 1080, array_layers: 1 },
|
||||||
//! MipmapsCount::One,
|
//! MipmapsCount::One,
|
||||||
|
Loading…
Reference in New Issue
Block a user