Compare commits

..

No commits in common. "377b10cda28cef1f7362cdfdc93eba6dce490881" and "294ad3dbbd2988694cb911829f4067ec38238b96" have entirely different histories.

12 changed files with 228 additions and 847 deletions

View file

@ -1,11 +1,14 @@
use std::borrow::Cow; use std::{
borrow::Cow,
ops::{Deref, DerefMut},
sync::Arc,
};
use ash::vk; use ash::{prelude::VkResult, vk};
use gpu_allocator::vulkan::AllocationScheme;
use crate::{ use crate::{
Device, Device,
device::{Allocation, AllocationStrategy, DeviceObject, QueueFlags}, device::{Allocation, DeviceObject, QueueFlags},
}; };
#[derive(Clone)] #[derive(Clone)]
@ -15,9 +18,7 @@ pub struct BufferDesc {
pub size: u64, pub size: u64,
pub usage: vk::BufferUsageFlags, pub usage: vk::BufferUsageFlags,
pub queue_families: QueueFlags, pub queue_families: QueueFlags,
pub mem_location: gpu_allocator::MemoryLocation, pub mem_location: gpu_allocator::MemoryLocation,
pub alloc_scheme: AllocationStrategy,
} }
impl std::hash::Hash for BufferDesc { impl std::hash::Hash for BufferDesc {
@ -39,7 +40,6 @@ impl std::fmt::Debug for BufferDesc {
.field("usage", &self.usage) .field("usage", &self.usage)
.field("queue_families", &self.queue_families) .field("queue_families", &self.queue_families)
.field("mem_location", &self.mem_location) .field("mem_location", &self.mem_location)
.field("alloc_scheme", &self.alloc_scheme)
.finish() .finish()
} }
} }
@ -66,7 +66,6 @@ impl Default for BufferDesc {
usage: Default::default(), usage: Default::default(),
queue_families: QueueFlags::empty(), queue_families: QueueFlags::empty(),
mem_location: gpu_allocator::MemoryLocation::Unknown, mem_location: gpu_allocator::MemoryLocation::Unknown,
alloc_scheme: AllocationStrategy::default(),
} }
} }
} }
@ -98,12 +97,7 @@ impl Buffer {
requirements, requirements,
location: desc.mem_location, location: desc.mem_location,
linear: true, linear: true,
allocation_scheme: match desc.alloc_scheme { allocation_scheme: gpu_allocator::vulkan::AllocationScheme::GpuAllocatorManaged,
AllocationStrategy::AllocatorManaged => {
AllocationScheme::GpuAllocatorManaged
}
AllocationStrategy::Dedicated => AllocationScheme::DedicatedBuffer(buffer),
},
})?; })?;
Ok(Self { Ok(Self {
@ -152,7 +146,7 @@ impl Buffer {
} }
} }
pub fn raw(&self) -> vk::Buffer { pub fn buffer(&self) -> vk::Buffer {
*self.buffer *self.buffer
} }
pub fn len(&self) -> u64 { pub fn len(&self) -> u64 {

View file

@ -33,7 +33,7 @@ impl Drop for SingleUseCommandPool {
impl SingleUseCommandPool { impl SingleUseCommandPool {
pub fn new(device: Device, queue: Queue) -> VkResult<Arc<Self>> { pub fn new(device: Device, queue: Queue) -> VkResult<Arc<Self>> {
let pool_info = vk::CommandPoolCreateInfo::default() let pool_info = vk::CommandPoolCreateInfo::default()
.queue_family_index(queue.family_index()) .queue_family_index(queue.family())
.flags(vk::CommandPoolCreateFlags::TRANSIENT); .flags(vk::CommandPoolCreateFlags::TRANSIENT);
let pool = unsafe { device.dev().create_command_pool(&pool_info, None)? }; let pool = unsafe { device.dev().create_command_pool(&pool_info, None)? };
@ -110,7 +110,7 @@ impl<T: HasQueue> CommandList<T> {
self.0[0] self.0[0]
.device() .device()
.dev() .dev()
.queue_submit(queue.raw(), &[info], fence.raw()) .queue_submit(queue, &[info], fence.fence())
})?; })?;
Ok(FenceFuture::<'a>::new(fence)) Ok(FenceFuture::<'a>::new(fence))
@ -257,7 +257,7 @@ impl SingleUseCommand {
self.pool.queue().with_locked(|queue| unsafe { self.pool.queue().with_locked(|queue| unsafe {
self.device() self.device()
.dev() .dev()
.queue_submit(queue.raw(), &[submit_info], fence) .queue_submit(queue, &[submit_info], fence)
})?; })?;
self.state.set_pending(); self.state.set_pending();
@ -329,7 +329,7 @@ pub mod traits {
queue.with_locked(|queue| unsafe { queue.with_locked(|queue| unsafe {
self.device() self.device()
.dev() .dev()
.queue_submit(queue.raw(), &[submit_info], fence.raw()) .queue_submit(queue, &[submit_info], fence.fence())
})?; })?;
tracing::trace!("submitted queue {:?} and fence {:?}", queue, fence); tracing::trace!("submitted queue {:?} and fence {:?}", queue, fence);
@ -888,7 +888,7 @@ mod command_pools {
) -> Result<CommandBufferFuture, Error> { ) -> Result<CommandBufferFuture, Error> {
let this = ManuallyDrop::new(self); let this = ManuallyDrop::new(self);
if queue.family_index() != this.pool.family { if queue.1 != this.pool.family {
tracing::error!("attempted to submit commandbuffer to incompatible queue."); tracing::error!("attempted to submit commandbuffer to incompatible queue.");
return Err(Error::InvalidQueueSubmission); return Err(Error::InvalidQueueSubmission);
} }
@ -911,7 +911,7 @@ mod command_pools {
queue.with_locked(|queue| unsafe { queue.with_locked(|queue| unsafe {
this.device() this.device()
.dev() .dev()
.queue_submit(queue.raw(), &[submit_info], fence.raw()) .queue_submit(queue, &[submit_info], fence.fence())
})?; })?;
Ok(CommandBufferFuture { Ok(CommandBufferFuture {
@ -931,7 +931,7 @@ mod command_pools {
} }
impl CommandBufferFuture { impl CommandBufferFuture {
pub fn block(&self) -> crate::Result<()> { pub fn block(&self) -> VkResult<()> {
self.inner.block() self.inner.block()
} }
} }

View file

@ -118,18 +118,6 @@ impl DeviceHandle for GpuAllocation {
} }
} }
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AllocationStrategy {
#[default]
/// Let gpu_allocator manage the memory for this allocation, sub-allocating
/// from larger blocks as needed.
AllocatorManaged,
/// Allocate a dedicated block of memory for this allocation. This is
/// recommended for long-lived resources or resources with specific memory
/// requirements.
Dedicated,
}
#[derive(Debug)] #[derive(Debug)]
pub(crate) enum Allocation { pub(crate) enum Allocation {
Owned(DeviceObject<GpuAllocation>), Owned(DeviceObject<GpuAllocation>),
@ -156,6 +144,7 @@ impl Allocation {
} }
pub struct DeviceInner { pub struct DeviceInner {
pub(crate) alloc: vk_mem::Allocator,
pub(crate) alloc2: Mutex<gpu_allocator::vulkan::Allocator>, pub(crate) alloc2: Mutex<gpu_allocator::vulkan::Allocator>,
pub(crate) raw: ash::Device, pub(crate) raw: ash::Device,
pub(crate) adapter: PhysicalDeviceInfo, pub(crate) adapter: PhysicalDeviceInfo,
@ -450,6 +439,13 @@ impl PhysicalDeviceInfo {
let inner = DeviceInner { let inner = DeviceInner {
raw: device.clone(), raw: device.clone(),
alloc: unsafe {
vk_mem::Allocator::new(vk_mem::AllocatorCreateInfo::new(
&instance.inner.raw,
&device,
self.pdev,
))?
},
alloc2: Mutex::new(alloc2), alloc2: Mutex::new(alloc2),
instance: instance.clone(), instance: instance.clone(),
adapter: self, adapter: self,
@ -535,6 +531,9 @@ impl DeviceInner {
pub fn sync_threadpool(&self) -> &sync::SyncThreadpool { pub fn sync_threadpool(&self) -> &sync::SyncThreadpool {
&self.sync_threadpool &self.sync_threadpool
} }
pub fn alloc(&self) -> &vk_mem::Allocator {
&self.alloc
}
pub fn dev(&self) -> &ash::Device { pub fn dev(&self) -> &ash::Device {
&self.raw &self.raw
} }

View file

@ -1,14 +1,13 @@
use std::{collections::BTreeMap, sync::Arc}; use std::{collections::BTreeMap, sync::Arc};
use ash::vk; use ash::{prelude::VkResult, vk};
use gpu_allocator::MemoryLocation;
use indexmap::IndexMap; use indexmap::IndexMap;
use crate::{ use crate::{
EguiState, EguiState,
buffers::{Buffer, BufferDesc}, buffers::{Buffer, BufferDesc},
commands::traits::CommandBufferExt, commands::traits::CommandBufferExt,
device::{self, AllocationStrategy}, device::{self, DeviceOwned},
images::{Image, ImageDesc, ImageViewDesc}, images::{Image, ImageDesc, ImageViewDesc},
render_graph::{ render_graph::{
Access, Barrier, GraphResourceDesc, GraphResourceId, PassDesc, RecordFn, RenderContext, Access, Barrier, GraphResourceDesc, GraphResourceId, PassDesc, RecordFn, RenderContext,
@ -24,7 +23,7 @@ pub fn egui_pre_pass(
textures: &mut crate::texture::TextureManager, textures: &mut crate::texture::TextureManager,
egui_state: &mut EguiState, egui_state: &mut EguiState,
output: &egui::FullOutput, output: &egui::FullOutput,
) -> crate::Result<()> { ) -> VkResult<()> {
// allocate resource ids for textures in tessellated list (imported from texture manager) // allocate resource ids for textures in tessellated list (imported from texture manager)
// define accesses for resource ids // define accesses for resource ids
@ -51,8 +50,7 @@ pub fn egui_pre_pass(
depth: 1, depth: 1,
}, },
usage: vk::ImageUsageFlags::SAMPLED | vk::ImageUsageFlags::TRANSFER_DST, usage: vk::ImageUsageFlags::SAMPLED | vk::ImageUsageFlags::TRANSFER_DST,
mem_location: MemoryLocation::GpuOnly, mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
alloc_scheme: AllocationStrategy::Dedicated,
..Default::default() ..Default::default()
}, },
)?; )?;
@ -96,7 +94,10 @@ pub fn egui_pre_pass(
size: staging_size as u64, size: staging_size as u64,
usage: vk::BufferUsageFlags::TRANSFER_SRC, usage: vk::BufferUsageFlags::TRANSFER_SRC,
queue_families: device::QueueFlags::empty(), queue_families: device::QueueFlags::empty(),
mem_location: MemoryLocation::CpuToGpu, mem_usage: vk_mem::MemoryUsage::AutoPreferHost,
alloc_flags: vk_mem::AllocationCreateFlags::MAPPED
| vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE
| vk_mem::AllocationCreateFlags::STRATEGY_FIRST_FIT,
..Default::default() ..Default::default()
}, },
)?; )?;
@ -114,14 +115,14 @@ pub fn egui_pre_pass(
}, },
usage: vk::ImageUsageFlags::TRANSFER_SRC | vk::ImageUsageFlags::TRANSFER_DST, usage: vk::ImageUsageFlags::TRANSFER_SRC | vk::ImageUsageFlags::TRANSFER_DST,
queue_families: device::QueueFlags::empty(), queue_families: device::QueueFlags::empty(),
mem_location: MemoryLocation::GpuOnly, mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
..Default::default() ..Default::default()
}, },
)?); )?);
let aliased_images = { let aliased_images = {
tracing::trace!("mmap-ing staging buffer"); tracing::trace!("mmap-ing staging buffer");
let mut staging_map = staging_buffer.map().unwrap(); let mut staging_map = staging_buffer.map()?;
let mut offset = 0; let mut offset = 0;
output output
@ -213,7 +214,7 @@ pub fn egui_pre_pass(
let texture = textures.get(&id).and_then(|id| ctx.get_image(*id)).unwrap(); let texture = textures.get(&id).and_then(|id| ctx.get_image(*id)).unwrap();
let image: Barrier = image_barrier( let image: Barrier = image_barrier(
alias.raw(), alias.handle(),
alias.format(), alias.format(),
Access { Access {
stage: vk::PipelineStageFlags2::NONE, stage: vk::PipelineStageFlags2::NONE,
@ -236,8 +237,8 @@ pub fn egui_pre_pass(
} }
ctx.cmd.copy_buffer_to_image( ctx.cmd.copy_buffer_to_image(
staging_buffer.raw(), staging_buffer.handle(),
alias.raw(), alias.handle(),
vk::ImageLayout::TRANSFER_DST_OPTIMAL, vk::ImageLayout::TRANSFER_DST_OPTIMAL,
&[vk::BufferImageCopy { &[vk::BufferImageCopy {
buffer_offset: offset as u64, buffer_offset: offset as u64,
@ -254,7 +255,7 @@ pub fn egui_pre_pass(
); );
let from_barrier = image_barrier( let from_barrier = image_barrier(
alias.raw(), alias.handle(),
alias.format(), alias.format(),
Access { Access {
stage: vk::PipelineStageFlags2::TRANSFER, stage: vk::PipelineStageFlags2::TRANSFER,
@ -270,7 +271,7 @@ pub fn egui_pre_pass(
); );
let to_barrier = image_barrier( let to_barrier = image_barrier(
texture.raw(), texture.handle(),
texture.format(), texture.format(),
Access { Access {
stage: vk::PipelineStageFlags2::NONE, stage: vk::PipelineStageFlags2::NONE,
@ -303,9 +304,9 @@ pub fn egui_pre_pass(
); );
} }
ctx.cmd.copy_images( ctx.cmd.copy_images(
alias.raw(), alias.handle(),
vk::ImageLayout::TRANSFER_SRC_OPTIMAL, vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
texture.raw(), texture.handle(),
vk::ImageLayout::TRANSFER_DST_OPTIMAL, vk::ImageLayout::TRANSFER_DST_OPTIMAL,
&[vk::ImageCopy { &[vk::ImageCopy {
src_subresource: vk::ImageSubresourceLayers::default() src_subresource: vk::ImageSubresourceLayers::default()
@ -329,7 +330,7 @@ pub fn egui_pre_pass(
); );
let image: Barrier = image_barrier( let image: Barrier = image_barrier(
texture.raw(), texture.handle(),
texture.format(), texture.format(),
Access { Access {
stage: vk::PipelineStageFlags2::TRANSFER, stage: vk::PipelineStageFlags2::TRANSFER,
@ -396,7 +397,7 @@ pub fn egui_pass(
egui: &egui::Context, egui: &egui::Context,
output: egui::FullOutput, output: egui::FullOutput,
target: GraphResourceId, target: GraphResourceId,
) -> crate::Result<Vec<texture::TextureId>> { ) -> VkResult<Vec<texture::TextureId>> {
let draw_data = egui.tessellate(output.shapes, output.pixels_per_point); let draw_data = egui.tessellate(output.shapes, output.pixels_per_point);
#[repr(C)] #[repr(C)]
@ -460,13 +461,16 @@ pub fn egui_pass(
name: Some("egui-draw-staging".into()), name: Some("egui-draw-staging".into()),
size: staging_size as u64, size: staging_size as u64,
usage: vk::BufferUsageFlags::TRANSFER_SRC, usage: vk::BufferUsageFlags::TRANSFER_SRC,
mem_location: MemoryLocation::CpuToGpu, mem_usage: vk_mem::MemoryUsage::AutoPreferHost,
alloc_flags: vk_mem::AllocationCreateFlags::MAPPED
| vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE
| vk_mem::AllocationCreateFlags::STRATEGY_FIRST_FIT,
..Default::default() ..Default::default()
}, },
)?; )?;
{ {
let map = staging.map_mut().unwrap(); let mut map = staging.map()?;
let (st_vertices, rest) = map.split_at_mut(vertices_size); let (st_vertices, rest) = map.split_at_mut(vertices_size);
let (st_indices, st_drawcalls) = rest.split_at_mut(indices_size); let (st_indices, st_drawcalls) = rest.split_at_mut(indices_size);
@ -480,21 +484,21 @@ pub fn egui_pass(
name: Some("egui-draw-vertices".into()), name: Some("egui-draw-vertices".into()),
size: vertices_size as u64, size: vertices_size as u64,
usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::VERTEX_BUFFER, usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::VERTEX_BUFFER,
mem_location: MemoryLocation::GpuOnly, mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
..Default::default() ..Default::default()
})); }));
let indices = rg.add_resource(GraphResourceDesc::Buffer(BufferDesc { let indices = rg.add_resource(GraphResourceDesc::Buffer(BufferDesc {
name: Some("egui-draw-indices".into()), name: Some("egui-draw-indices".into()),
size: indices_size as u64, size: indices_size as u64,
usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::INDEX_BUFFER, usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::INDEX_BUFFER,
mem_location: MemoryLocation::GpuOnly, mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
..Default::default() ..Default::default()
})); }));
let draw_calls = rg.add_resource(GraphResourceDesc::Buffer(BufferDesc { let draw_calls = rg.add_resource(GraphResourceDesc::Buffer(BufferDesc {
name: Some("egui-draw-draw_calls".into()), name: Some("egui-draw-draw_calls".into()),
size: draw_calls_size as u64, size: draw_calls_size as u64,
usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::INDIRECT_BUFFER, usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::INDIRECT_BUFFER,
mem_location: MemoryLocation::GpuOnly, mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
..Default::default() ..Default::default()
})); }));
@ -504,14 +508,13 @@ pub fn egui_pass(
name: Some("egui-draw-texture_ids".into()), name: Some("egui-draw-texture_ids".into()),
size: (textures_indices.len() * size_of::<u32>()) as u64, size: (textures_indices.len() * size_of::<u32>()) as u64,
usage: vk::BufferUsageFlags::STORAGE_BUFFER, usage: vk::BufferUsageFlags::STORAGE_BUFFER,
mem_location: MemoryLocation::CpuToGpu, mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
alloc_flags: vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE,
..Default::default() ..Default::default()
}, },
)?; )?;
{ {
let map = texture_ids let mut map = texture_ids.map()?;
.map_mut()
.expect("texture id buffer should be device visible");
map.copy_from_slice(bytemuck::cast_slice(&textures_indices)); map.copy_from_slice(bytemuck::cast_slice(&textures_indices));
} }
@ -525,20 +528,22 @@ pub fn egui_pass(
vk::DescriptorImageInfo { vk::DescriptorImageInfo {
sampler: samplers.get_sampler(entry.as_sampler_desc()).unwrap(), sampler: samplers.get_sampler(entry.as_sampler_desc()).unwrap(),
image_view: texture image_view: texture
.create_view( .get_view(ImageViewDesc {
ImageViewDesc::color_2d() kind: vk::ImageViewType::TYPE_2D,
.with_mip_range(0..1) format: texture.format(),
.with_layer_range(0..1), aspect: vk::ImageAspectFlags::COLOR,
) mip_range: (0..1).into(),
.unwrap() layer_range: (0..1).into(),
.raw(), ..Default::default()
})
.unwrap(),
image_layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, image_layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
} }
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let uniform_info = vk::DescriptorBufferInfo { let uniform_info = vk::DescriptorBufferInfo {
buffer: texture_ids.raw(), buffer: texture_ids.buffer(),
offset: 0, offset: 0,
range: texture_ids.len(), range: texture_ids.len(),
}; };
@ -604,8 +609,8 @@ pub fn egui_pass(
let target = ctx.get_image(target).unwrap(); let target = ctx.get_image(target).unwrap();
cmd.copy_buffers( cmd.copy_buffers(
staging.raw(), staging.buffer(),
vertices.raw(), vertices.buffer(),
&[vk::BufferCopy { &[vk::BufferCopy {
src_offset: 0, src_offset: 0,
dst_offset: 0, dst_offset: 0,
@ -613,8 +618,8 @@ pub fn egui_pass(
}], }],
); );
cmd.copy_buffers( cmd.copy_buffers(
staging.raw(), staging.buffer(),
indices.raw(), indices.buffer(),
&[vk::BufferCopy { &[vk::BufferCopy {
src_offset: vertices_size as u64, src_offset: vertices_size as u64,
dst_offset: 0, dst_offset: 0,
@ -622,8 +627,8 @@ pub fn egui_pass(
}], }],
); );
cmd.copy_buffers( cmd.copy_buffers(
staging.raw(), staging.buffer(),
draw_calls.raw(), draw_calls.buffer(),
&[vk::BufferCopy { &[vk::BufferCopy {
src_offset: (vertices_size + indices_size) as u64, src_offset: (vertices_size + indices_size) as u64,
dst_offset: 0, dst_offset: 0,
@ -633,7 +638,7 @@ pub fn egui_pass(
let barriers = [ let barriers = [
buffer_barrier( buffer_barrier(
vertices.raw(), vertices.handle(),
0, 0,
vertices.len(), vertices.len(),
Access::transfer_write(), Access::transfer_write(),
@ -641,7 +646,7 @@ pub fn egui_pass(
None, None,
), ),
buffer_barrier( buffer_barrier(
indices.raw(), indices.handle(),
0, 0,
indices.len(), indices.len(),
Access::transfer_write(), Access::transfer_write(),
@ -649,7 +654,7 @@ pub fn egui_pass(
None, None,
), ),
buffer_barrier( buffer_barrier(
draw_calls.raw(), draw_calls.handle(),
0, 0,
draw_calls.len(), draw_calls.len(),
Access::transfer_write(), Access::transfer_write(),
@ -666,7 +671,12 @@ pub fn egui_pass(
let color_attachment = &vk::RenderingAttachmentInfo::default() let color_attachment = &vk::RenderingAttachmentInfo::default()
.image_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL) .image_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
.image_view(target.create_view(ImageViewDesc::color_2d())?.raw()) .image_view(target.get_view(ImageViewDesc {
kind: vk::ImageViewType::TYPE_2D,
format: target.format(),
aspect: vk::ImageAspectFlags::COLOR,
..Default::default()
})?)
.load_op(vk::AttachmentLoadOp::LOAD) .load_op(vk::AttachmentLoadOp::LOAD)
.store_op(vk::AttachmentStoreOp::STORE); .store_op(vk::AttachmentStoreOp::STORE);
@ -690,8 +700,8 @@ pub fn egui_pass(
.height(target.height() as f32)]); .height(target.height() as f32)]);
cmd.bind_pipeline(&pipeline); cmd.bind_pipeline(&pipeline);
cmd.bind_indices(indices.raw(), 0, vk::IndexType::UINT32); cmd.bind_indices(indices.buffer(), 0, vk::IndexType::UINT32);
cmd.bind_vertex_buffers(&[vertices.raw()], &[0]); cmd.bind_vertex_buffers(&[vertices.buffer()], &[0]);
cmd.push_constants( cmd.push_constants(
&pipeline_layout, &pipeline_layout,
vk::ShaderStageFlags::VERTEX, vk::ShaderStageFlags::VERTEX,
@ -706,7 +716,7 @@ pub fn egui_pass(
&[descriptor_set], &[descriptor_set],
); );
cmd.draw_indexed_indirect( cmd.draw_indexed_indirect(
draw_calls.raw(), draw_calls.buffer(),
0, 0,
num_draw_calls as u32, num_draw_calls as u32,
size_of::<vk::DrawIndexedIndirectCommand>() as u32, size_of::<vk::DrawIndexedIndirectCommand>() as u32,

View file

@ -1,15 +1,21 @@
use std::{borrow::Cow, sync::Arc}; use std::{
borrow::Cow,
collections::HashMap,
sync::{Arc, Weak},
};
use crate::{ use crate::{
device::{Allocation, AllocationStrategy, DeviceHandle, DeviceObject, QueueFlags}, define_device_owned_handle,
device::{Allocation, DeviceHandle, DeviceObject, DeviceOwned, QueueFlags},
swapchain::Swapchain, swapchain::Swapchain,
util::weak_vec::WeakVec, util::weak_vec::WeakVec,
}; };
use super::Device; use super::Device;
use ash::vk; use ash::{prelude::*, vk};
use gpu_allocator::vulkan::{AllocationCreateDesc, AllocationScheme}; use gpu_allocator::vulkan::{AllocationCreateDesc, AllocationScheme};
use parking_lot::Mutex; use parking_lot::Mutex;
use vk_mem::Alloc;
#[derive(Clone)] #[derive(Clone)]
pub struct ImageDesc { pub struct ImageDesc {
@ -27,7 +33,6 @@ pub struct ImageDesc {
pub layout: vk::ImageLayout, pub layout: vk::ImageLayout,
pub mem_location: gpu_allocator::MemoryLocation, pub mem_location: gpu_allocator::MemoryLocation,
pub alloc_scheme: AllocationStrategy,
} }
impl std::hash::Hash for ImageDesc { impl std::hash::Hash for ImageDesc {
@ -82,7 +87,6 @@ impl<'a> std::fmt::Debug for ImageDesc {
.field("queue_families", &self.queue_families) .field("queue_families", &self.queue_families)
.field("layout", &self.layout) .field("layout", &self.layout)
.field("mem_location", &self.mem_location) .field("mem_location", &self.mem_location)
.field("alloc_scheme", &self.alloc_scheme)
.finish() .finish()
} }
} }
@ -103,7 +107,6 @@ impl Default for ImageDesc {
queue_families: QueueFlags::empty(), queue_families: QueueFlags::empty(),
layout: vk::ImageLayout::UNDEFINED, layout: vk::ImageLayout::UNDEFINED,
mem_location: gpu_allocator::MemoryLocation::Unknown, mem_location: gpu_allocator::MemoryLocation::Unknown,
alloc_scheme: AllocationStrategy::AllocatorManaged,
} }
} }
} }
@ -165,10 +168,7 @@ impl Image {
requirements, requirements,
location: desc.mem_location, location: desc.mem_location,
linear: desc.tiling == vk::ImageTiling::LINEAR, linear: desc.tiling == vk::ImageTiling::LINEAR,
allocation_scheme: match desc.alloc_scheme { allocation_scheme: AllocationScheme::GpuAllocatorManaged,
AllocationStrategy::AllocatorManaged => AllocationScheme::GpuAllocatorManaged,
AllocationStrategy::Dedicated => AllocationScheme::DedicatedImage(image),
},
})?; })?;
Ok(Self { Ok(Self {
@ -316,10 +316,6 @@ impl Image {
Ok((image, requirements)) Ok((image, requirements))
} }
pub fn raw(&self) -> vk::Image {
self.image.image()
}
} }
impl Eq for Image {} impl Eq for Image {}
@ -363,35 +359,35 @@ impl Image {
self.image.allocation_mut() self.image.allocation_mut()
} }
// /// technically, this ImageView belongs to the image and is managed by it. /// technically, this ImageView belongs to the image and is managed by it.
// pub fn get_view(&self, desc: ImageViewDesc) -> VkResult<vk::ImageView> { pub fn get_view(&self, desc: ImageViewDesc) -> VkResult<vk::ImageView> {
// use std::collections::hash_map::Entry::*; use std::collections::hash_map::Entry::*;
// match self.views.lock().entry(desc.hash_eq_copy()) { match self.views.lock().entry(desc.hash_eq_copy()) {
// Occupied(occupied) => Ok(*occupied.get()), Occupied(occupied) => Ok(*occupied.get()),
// Vacant(vacant) => { Vacant(vacant) => {
// let view = unsafe { let view = unsafe {
// let create_info = vk::ImageViewCreateInfo::default() let create_info = vk::ImageViewCreateInfo::default()
// .flags(desc.flags) .flags(desc.flags)
// .image(self.image()) .image(self.image())
// .view_type(vk::ImageViewType::TYPE_2D) .view_type(vk::ImageViewType::TYPE_2D)
// .format(desc.format) .format(desc.format)
// .components(desc.components) .components(desc.components)
// .subresource_range( .subresource_range(
// vk::ImageSubresourceRange::default() vk::ImageSubresourceRange::default()
// .aspect_mask(desc.aspect) .aspect_mask(desc.aspect)
// .base_mip_level(desc.mip_range.0) .base_mip_level(desc.mip_range.0)
// .level_count(desc.mip_range.count()) .level_count(desc.mip_range.count())
// .base_array_layer(desc.layer_range.0) .base_array_layer(desc.layer_range.0)
// .layer_count(desc.layer_range.count()), .layer_count(desc.layer_range.count()),
// ); );
// self.device().dev().create_image_view(&create_info, None)? self.device().dev().create_image_view(&create_info, None)?
// }; };
// Ok(*vacant.insert(view)) Ok(*vacant.insert(view))
// } }
// } }
// } }
pub fn create_view(self: &Arc<Self>, mut desc: ImageViewDesc) -> crate::Result<ImageView> { pub fn create_view(&self, desc: ImageViewDesc) -> crate::Result<ImageView> {
// validate // validate
if !view_kind_compatible(self.desc.kind, desc.kind) { if !view_kind_compatible(self.desc.kind, desc.kind) {
tracing::error!( tracing::error!(
@ -411,24 +407,7 @@ impl Image {
desc.mip_range, desc.mip_range,
self.desc.mip_levels self.desc.mip_levels
); );
return Err(crate::Error::Todo( return Err(crate::Error::Unspecified);
"image view mip range exceeds image mip levels",
));
}
if desc.format == vk::Format::UNDEFINED {
desc.format = self.desc.format;
}
if !validate_image_view_format(&self.desc, desc.format) {
tracing::error!(
"image view format {:?} is not compatible with image format {:?}",
desc.format,
self.desc.format
);
return Err(crate::Error::Todo(
"image view format is not compatible with image format",
));
} }
let create_info = vk::ImageViewCreateInfo::default() let create_info = vk::ImageViewCreateInfo::default()
@ -449,22 +428,7 @@ impl Image {
let device = self.image.device(); let device = self.image.device();
let view = unsafe { device.raw.create_image_view(&create_info, None)? }; let view = unsafe { device.raw.create_image_view(&create_info, None)? };
Ok(ImageView { ImageView::construct(self.device().clone(), view, desc.name)
view: DeviceObject::new(view, device.clone(), desc.name.clone()),
desc,
image: self.clone(),
})
}
}
fn validate_image_view_format(image: &ImageDesc, view_format: vk::Format) -> bool {
let mutable = image.flags.contains(vk::ImageCreateFlags::MUTABLE_FORMAT);
if mutable {
image.format == view_format
|| FormatClass::from(image.format) == FormatClass::from(view_format)
} else {
image.format == view_format
} }
} }
@ -492,44 +456,7 @@ pub struct ImageViewDesc {
} }
impl ImageViewDesc { impl ImageViewDesc {
pub fn color_2d() -> Self { pub fn hash_eq_copy(&self) -> Self {
Self {
kind: vk::ImageViewType::TYPE_2D,
aspect: vk::ImageAspectFlags::COLOR,
..Default::default()
}
}
pub fn with_format(self, format: vk::Format) -> Self {
Self { format, ..self }
}
pub fn with_mip_range<R: core::ops::RangeBounds<u32>>(self, range: R) -> Self {
Self {
mip_range: range.into(),
..self
}
}
pub fn with_layer_range<R: core::ops::RangeBounds<u32>>(self, range: R) -> Self {
Self {
layer_range: range.into(),
..self
}
}
pub fn with_aspect(self, aspect: vk::ImageAspectFlags) -> Self {
Self { aspect, ..self }
}
pub fn with_name(self, name: impl Into<Cow<'static, str>>) -> Self {
Self {
name: Some(name.into()),
..self
}
}
pub(crate) fn hash_eq_copy(&self) -> Self {
let &Self { let &Self {
flags, flags,
kind, kind,
@ -634,15 +561,6 @@ pub struct ImageView {
image: Arc<Image>, image: Arc<Image>,
} }
impl ImageView {
pub fn raw(&self) -> vk::ImageView {
*self.view
}
pub fn image(&self) -> &Arc<Image> {
&self.image
}
}
impl DeviceHandle for vk::ImageView { impl DeviceHandle for vk::ImageView {
unsafe fn destroy(&mut self, device: &Device) { unsafe fn destroy(&mut self, device: &Device) {
unsafe { unsafe {
@ -671,487 +589,3 @@ pub const SUBRESOURCERANGE_COLOR_ALL: vk::ImageSubresourceRange = vk::ImageSubre
base_array_layer: 0, base_array_layer: 0,
layer_count: vk::REMAINING_ARRAY_LAYERS, layer_count: vk::REMAINING_ARRAY_LAYERS,
}; };
// copilot generated from spec:
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FormatClass {
Bits8,
Bits16,
Alpha8,
Bits24,
Bits32,
Bits48,
Bits64,
Bits96,
Bits128,
Bits192,
Bits256,
D16,
D24,
D32,
S8,
D16S8,
D24S8,
D32S8,
Bc1Rgb,
Bc1Rgba,
Bc2,
Bc3,
Bc4,
Bc5,
Bc6h,
Bc7,
Etc2Rgb,
Etc2Rgba,
Etc2EacRgba,
EacR,
EacRg,
Astc4x4,
Astc5x4,
Astc5x5,
Astc6x5,
Astc6x6,
Astc8x5,
Astc8x6,
Astc8x8,
Astc10x5,
Astc10x6,
Astc10x8,
Astc10x10,
Astc12x10,
Astc12x12,
YuvG8B8G8R8_422,
YuvB8G8R8G8_422,
YuvG8B8R8Triplane420,
YuvG8B8R8Biplane420,
YuvG8B8R8Triplane422,
YuvG8B8R8Biplane422,
YuvG8B8R8Triplane444,
YuvG10X6B10X6R10X6Triplane420,
YuvG10X6B10X6R10X6Biplane420,
YuvG10X6B10X6R10X6Triplane422,
YuvG10X6B10X6R10X6Biplane422,
YuvG10X6B10X6R10X6Triplane444,
YuvG12X4B12X4R12X4Triplane420,
YuvG12X4B12X4R12X4Biplane420,
YuvG12X4B12X4R12X4Triplane422,
YuvG12X4B12X4R12X4Biplane422,
YuvG12X4B12X4R12X4Triplane444,
YuvG16B16R16Triplane420,
YuvG16B16R16Biplane420,
YuvG16B16R16Triplane422,
YuvG16B16R16Biplane422,
YuvG16B16R16Triplane444,
YuvG8B8R8Biplane444,
YuvG10X6B10X6R10X6Biplane444,
YuvG12X4B12X4R12X4Biplane444,
YuvG16B16R16Biplane444,
Bits64R10G10B10A10,
Bits64G10B10G10R10_422,
Bits64B10G10R10G10_422,
Bits64R12G12B12A12,
Bits64G12B12G12R12_422,
Bits64B12G12R12G12_422,
Bits64G16B16G16R16_422,
Bits64B16G16R16G16_422,
Bits64R14G14B14A14,
Pvrtc1_2bpp,
Pvrtc1_4bpp,
Pvrtc2_2bpp,
Pvrtc2_4bpp,
Astc3x3x3,
Astc4x3x3,
Astc4x4x3,
Astc4x4x4,
Astc5x4x4,
Astc5x5x4,
Astc5x5x5,
Astc6x5x5,
Astc6x6x5,
Astc6x6x6,
YuvG14X2B14X2R14X2Biplane420,
YuvG14X2B14X2R14X2Biplane422,
}
impl From<vk::Format> for FormatClass {
fn from(format: vk::Format) -> Self {
use vk::Format as F;
match format {
// 8-bit
F::R4G4_UNORM_PACK8
| F::R8_UNORM
| F::R8_SNORM
| F::R8_USCALED
| F::R8_SSCALED
// | F::R8_BOOL_ARM
// | F::R8_SFLOAT_FPENCODING_FLOAT8E4M3_ARM
// | F::R8_SFLOAT_FPENCODING_FLOAT8E5M2_ARM
| F::R8_UINT
| F::R8_SINT
| F::R8_SRGB => FormatClass::Bits8,
// 16-bit
F::A1B5G5R5_UNORM_PACK16_KHR
| F::R10X6_UNORM_PACK16
| F::R12X4_UNORM_PACK16
| F::A4R4G4B4_UNORM_PACK16
| F::A4B4G4R4_UNORM_PACK16
// | F::R10X6_UINT_PACK16_ARM
// | F::R12X4_UINT_PACK16_ARM
// | F::R14X2_UINT_PACK16_ARM
// | F::R14X2_UNORM_PACK16_ARM
// | F::R16_SFLOAT_FPENCODING_BFLOAT16_ARM
| F::R4G4B4A4_UNORM_PACK16
| F::B4G4R4A4_UNORM_PACK16
| F::R5G6B5_UNORM_PACK16
| F::B5G6R5_UNORM_PACK16
| F::R5G5B5A1_UNORM_PACK16
| F::B5G5R5A1_UNORM_PACK16
| F::A1R5G5B5_UNORM_PACK16
| F::R8G8_UNORM
| F::R8G8_SNORM
| F::R8G8_USCALED
| F::R8G8_SSCALED
| F::R8G8_UINT
| F::R8G8_SINT
| F::R8G8_SRGB
| F::R16_UNORM
| F::R16_SNORM
| F::R16_USCALED
| F::R16_SSCALED
| F::R16_UINT
| F::R16_SINT
| F::R16_SFLOAT => FormatClass::Bits16,
// 8-bit alpha
F::A8_UNORM_KHR => FormatClass::Alpha8,
// 24-bit
F::R8G8B8_UNORM
| F::R8G8B8_SNORM
| F::R8G8B8_USCALED
| F::R8G8B8_SSCALED
| F::R8G8B8_UINT
| F::R8G8B8_SINT
| F::R8G8B8_SRGB
| F::B8G8R8_UNORM
| F::B8G8R8_SNORM
| F::B8G8R8_USCALED
| F::B8G8R8_SSCALED
| F::B8G8R8_UINT
| F::B8G8R8_SINT
| F::B8G8R8_SRGB => FormatClass::Bits24,
// 32-bit
F::R10X6G10X6_UNORM_2PACK16
| F::R12X4G12X4_UNORM_2PACK16
// | F::R16G16_SFIXED5_NV
// | F::R10X6G10X6_UINT_2PACK16_ARM
// | F::R12X4G12X4_UINT_2PACK16_ARM
// | F::R14X2G14X2_UINT_2PACK16_ARM
// | F::R14X2G14X2_UNORM_2PACK16_ARM
| F::R8G8B8A8_UNORM
| F::R8G8B8A8_SNORM
| F::R8G8B8A8_USCALED
| F::R8G8B8A8_SSCALED
| F::R8G8B8A8_UINT
| F::R8G8B8A8_SINT
| F::R8G8B8A8_SRGB
| F::B8G8R8A8_UNORM
| F::B8G8R8A8_SNORM
| F::B8G8R8A8_USCALED
| F::B8G8R8A8_SSCALED
| F::B8G8R8A8_UINT
| F::B8G8R8A8_SINT
| F::B8G8R8A8_SRGB
| F::A8B8G8R8_UNORM_PACK32
| F::A8B8G8R8_SNORM_PACK32
| F::A8B8G8R8_USCALED_PACK32
| F::A8B8G8R8_SSCALED_PACK32
| F::A8B8G8R8_UINT_PACK32
| F::A8B8G8R8_SINT_PACK32
| F::A8B8G8R8_SRGB_PACK32
| F::A2R10G10B10_UNORM_PACK32
| F::A2R10G10B10_SNORM_PACK32
| F::A2R10G10B10_USCALED_PACK32
| F::A2R10G10B10_SSCALED_PACK32
| F::A2R10G10B10_UINT_PACK32
| F::A2R10G10B10_SINT_PACK32
| F::A2B10G10R10_UNORM_PACK32
| F::A2B10G10R10_SNORM_PACK32
| F::A2B10G10R10_USCALED_PACK32
| F::A2B10G10R10_SSCALED_PACK32
| F::A2B10G10R10_UINT_PACK32
| F::A2B10G10R10_SINT_PACK32
| F::R16G16_UNORM
| F::R16G16_SNORM
| F::R16G16_USCALED
| F::R16G16_SSCALED
| F::R16G16_UINT
| F::R16G16_SINT
| F::R16G16_SFLOAT
| F::R32_UINT
| F::R32_SINT
| F::R32_SFLOAT
| F::B10G11R11_UFLOAT_PACK32
| F::E5B9G9R9_UFLOAT_PACK32 => FormatClass::Bits32,
// 48-bit
F::R16G16B16_UNORM
| F::R16G16B16_SNORM
| F::R16G16B16_USCALED
| F::R16G16B16_SSCALED
| F::R16G16B16_UINT
| F::R16G16B16_SINT
| F::R16G16B16_SFLOAT => FormatClass::Bits48,
// 64-bit
F::R16G16B16A16_UNORM
| F::R16G16B16A16_SNORM
| F::R16G16B16A16_USCALED
| F::R16G16B16A16_SSCALED
| F::R16G16B16A16_UINT
| F::R16G16B16A16_SINT
| F::R16G16B16A16_SFLOAT
| F::R32G32_UINT
| F::R32G32_SINT
| F::R32G32_SFLOAT
| F::R64_UINT
| F::R64_SINT
| F::R64_SFLOAT => FormatClass::Bits64,
// 96-bit
F::R32G32B32_UINT | F::R32G32B32_SINT | F::R32G32B32_SFLOAT => FormatClass::Bits96,
// 128-bit
F::R32G32B32A32_UINT
| F::R32G32B32A32_SINT
| F::R32G32B32A32_SFLOAT
| F::R64G64_UINT
| F::R64G64_SINT
| F::R64G64_SFLOAT => FormatClass::Bits128,
// 192-bit
F::R64G64B64_UINT | F::R64G64B64_SINT | F::R64G64B64_SFLOAT => FormatClass::Bits192,
// 256-bit
F::R64G64B64A64_UINT | F::R64G64B64A64_SINT | F::R64G64B64A64_SFLOAT => {
FormatClass::Bits256
}
// Depth / Stencil
F::D16_UNORM => FormatClass::D16,
F::X8_D24_UNORM_PACK32 => FormatClass::D24,
F::D32_SFLOAT => FormatClass::D32,
F::S8_UINT => FormatClass::S8,
F::D16_UNORM_S8_UINT => FormatClass::D16S8,
F::D24_UNORM_S8_UINT => FormatClass::D24S8,
F::D32_SFLOAT_S8_UINT => FormatClass::D32S8,
// BCn
F::BC1_RGB_UNORM_BLOCK | F::BC1_RGB_SRGB_BLOCK => FormatClass::Bc1Rgb,
F::BC1_RGBA_UNORM_BLOCK | F::BC1_RGBA_SRGB_BLOCK => FormatClass::Bc1Rgba,
F::BC2_UNORM_BLOCK | F::BC2_SRGB_BLOCK => FormatClass::Bc2,
F::BC3_UNORM_BLOCK | F::BC3_SRGB_BLOCK => FormatClass::Bc3,
F::BC4_UNORM_BLOCK | F::BC4_SNORM_BLOCK => FormatClass::Bc4,
F::BC5_UNORM_BLOCK | F::BC5_SNORM_BLOCK => FormatClass::Bc5,
F::BC6H_UFLOAT_BLOCK | F::BC6H_SFLOAT_BLOCK => FormatClass::Bc6h,
F::BC7_UNORM_BLOCK | F::BC7_SRGB_BLOCK => FormatClass::Bc7,
// ETC2 / EAC
F::ETC2_R8G8B8_UNORM_BLOCK | F::ETC2_R8G8B8_SRGB_BLOCK => FormatClass::Etc2Rgb,
F::ETC2_R8G8B8A1_UNORM_BLOCK | F::ETC2_R8G8B8A1_SRGB_BLOCK => FormatClass::Etc2Rgba,
F::ETC2_R8G8B8A8_UNORM_BLOCK | F::ETC2_R8G8B8A8_SRGB_BLOCK => FormatClass::Etc2EacRgba,
F::EAC_R11_UNORM_BLOCK | F::EAC_R11_SNORM_BLOCK => FormatClass::EacR,
F::EAC_R11G11_UNORM_BLOCK | F::EAC_R11G11_SNORM_BLOCK => FormatClass::EacRg,
// ASTC 2D
F::ASTC_4X4_SFLOAT_BLOCK | F::ASTC_4X4_UNORM_BLOCK | F::ASTC_4X4_SRGB_BLOCK => {
FormatClass::Astc4x4
}
F::ASTC_5X4_SFLOAT_BLOCK | F::ASTC_5X4_UNORM_BLOCK | F::ASTC_5X4_SRGB_BLOCK => {
FormatClass::Astc5x4
}
F::ASTC_5X5_SFLOAT_BLOCK | F::ASTC_5X5_UNORM_BLOCK | F::ASTC_5X5_SRGB_BLOCK => {
FormatClass::Astc5x5
}
F::ASTC_6X5_SFLOAT_BLOCK | F::ASTC_6X5_UNORM_BLOCK | F::ASTC_6X5_SRGB_BLOCK => {
FormatClass::Astc6x5
}
F::ASTC_6X6_SFLOAT_BLOCK | F::ASTC_6X6_UNORM_BLOCK | F::ASTC_6X6_SRGB_BLOCK => {
FormatClass::Astc6x6
}
F::ASTC_8X5_SFLOAT_BLOCK | F::ASTC_8X5_UNORM_BLOCK | F::ASTC_8X5_SRGB_BLOCK => {
FormatClass::Astc8x5
}
F::ASTC_8X6_SFLOAT_BLOCK | F::ASTC_8X6_UNORM_BLOCK | F::ASTC_8X6_SRGB_BLOCK => {
FormatClass::Astc8x6
}
F::ASTC_8X8_SFLOAT_BLOCK | F::ASTC_8X8_UNORM_BLOCK | F::ASTC_8X8_SRGB_BLOCK => {
FormatClass::Astc8x8
}
F::ASTC_10X5_SFLOAT_BLOCK | F::ASTC_10X5_UNORM_BLOCK | F::ASTC_10X5_SRGB_BLOCK => {
FormatClass::Astc10x5
}
F::ASTC_10X6_SFLOAT_BLOCK | F::ASTC_10X6_UNORM_BLOCK | F::ASTC_10X6_SRGB_BLOCK => {
FormatClass::Astc10x6
}
F::ASTC_10X8_SFLOAT_BLOCK | F::ASTC_10X8_UNORM_BLOCK | F::ASTC_10X8_SRGB_BLOCK => {
FormatClass::Astc10x8
}
F::ASTC_10X10_SFLOAT_BLOCK | F::ASTC_10X10_UNORM_BLOCK | F::ASTC_10X10_SRGB_BLOCK => {
FormatClass::Astc10x10
}
F::ASTC_12X10_SFLOAT_BLOCK | F::ASTC_12X10_UNORM_BLOCK | F::ASTC_12X10_SRGB_BLOCK => {
FormatClass::Astc12x10
}
F::ASTC_12X12_SFLOAT_BLOCK | F::ASTC_12X12_UNORM_BLOCK | F::ASTC_12X12_SRGB_BLOCK => {
FormatClass::Astc12x12
}
// Packed/YCbCr-ish (as listed)
F::G8B8G8R8_422_UNORM => FormatClass::YuvG8B8G8R8_422,
F::B8G8R8G8_422_UNORM => FormatClass::YuvB8G8R8G8_422,
F::G8_B8_R8_3PLANE_420_UNORM => FormatClass::YuvG8B8R8Triplane420,
F::G8_B8R8_2PLANE_420_UNORM => FormatClass::YuvG8B8R8Biplane420,
F::G8_B8_R8_3PLANE_422_UNORM => FormatClass::YuvG8B8R8Triplane422,
F::G8_B8R8_2PLANE_422_UNORM => FormatClass::YuvG8B8R8Biplane422,
F::G8_B8_R8_3PLANE_444_UNORM => FormatClass::YuvG8B8R8Triplane444,
F::G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 => {
FormatClass::YuvG10X6B10X6R10X6Triplane420
}
F::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 => {
FormatClass::YuvG10X6B10X6R10X6Biplane420
}
F::G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 => {
FormatClass::YuvG10X6B10X6R10X6Triplane422
}
F::G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 => {
FormatClass::YuvG10X6B10X6R10X6Biplane422
}
F::G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 => {
FormatClass::YuvG10X6B10X6R10X6Triplane444
}
F::G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 => {
FormatClass::YuvG12X4B12X4R12X4Triplane420
}
F::G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 => {
FormatClass::YuvG12X4B12X4R12X4Biplane420
}
F::G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 => {
FormatClass::YuvG12X4B12X4R12X4Triplane422
}
F::G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 => {
FormatClass::YuvG12X4B12X4R12X4Biplane422
}
F::G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 => {
FormatClass::YuvG12X4B12X4R12X4Triplane444
}
F::G16_B16_R16_3PLANE_420_UNORM => FormatClass::YuvG16B16R16Triplane420,
F::G16_B16R16_2PLANE_420_UNORM => FormatClass::YuvG16B16R16Biplane420,
F::G16_B16_R16_3PLANE_422_UNORM => FormatClass::YuvG16B16R16Triplane422,
F::G16_B16R16_2PLANE_422_UNORM => FormatClass::YuvG16B16R16Biplane422,
F::G16_B16_R16_3PLANE_444_UNORM => FormatClass::YuvG16B16R16Triplane444,
// 2-plane 444 (additional section)
F::G8_B8R8_2PLANE_444_UNORM => FormatClass::YuvG8B8R8Biplane444,
F::G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 => {
FormatClass::YuvG10X6B10X6R10X6Biplane444
}
F::G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 => {
FormatClass::YuvG12X4B12X4R12X4Biplane444
}
F::G16_B16R16_2PLANE_444_UNORM => FormatClass::YuvG16B16R16Biplane444,
// 64-bit special grouped headings from the markdown
F::R10X6G10X6B10X6A10X6_UNORM_4PACK16 /* | F::R10X6G10X6B10X6A10X6_UINT_4PACK16_ARM */
=> {
FormatClass::Bits64R10G10B10A10
}
F::G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 => FormatClass::Bits64G10B10G10R10_422,
F::B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 => FormatClass::Bits64B10G10R10G10_422,
F::R12X4G12X4B12X4A12X4_UNORM_4PACK16 /*| F::R12X4G12X4B12X4A12X4_UINT_4PACK16_ARM */
=> {
FormatClass::Bits64R12G12B12A12
}
F::G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 => FormatClass::Bits64G12B12G12R12_422,
F::B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 => FormatClass::Bits64B12G12R12G12_422,
F::G16B16G16R16_422_UNORM => FormatClass::Bits64G16B16G16R16_422,
F::B16G16R16G16_422_UNORM => FormatClass::Bits64B16G16R16G16_422,
// F::R14X2G14X2B14X2A14X2_UINT_4PACK16_ARM
// | F::R14X2G14X2B14X2A14X2_UNORM_4PACK16_ARM => FormatClass::Bits64_R14G14B14A14,
// PVRTC
F::PVRTC1_2BPP_UNORM_BLOCK_IMG | F::PVRTC1_2BPP_SRGB_BLOCK_IMG => {
FormatClass::Pvrtc1_2bpp
}
F::PVRTC1_4BPP_UNORM_BLOCK_IMG | F::PVRTC1_4BPP_SRGB_BLOCK_IMG => {
FormatClass::Pvrtc1_4bpp
}
F::PVRTC2_2BPP_UNORM_BLOCK_IMG | F::PVRTC2_2BPP_SRGB_BLOCK_IMG => {
FormatClass::Pvrtc2_2bpp
}
F::PVRTC2_4BPP_UNORM_BLOCK_IMG | F::PVRTC2_4BPP_SRGB_BLOCK_IMG => {
FormatClass::Pvrtc2_4bpp
}
// ASTC 3D (EXT)
// F::ASTC_3X3X3_UNORM_BLOCK_EXT
// | F::ASTC_3X3X3_SRGB_BLOCK_EXT
// | F::ASTC_3X3X3_SFLOAT_BLOCK_EXT => FormatClass::Astc3x3x3,
// F::ASTC_4X3X3_UNORM_BLOCK_EXT
// | F::ASTC_4X3X3_SRGB_BLOCK_EXT
// | F::ASTC_4X3X3_SFLOAT_BLOCK_EXT => FormatClass::Astc4x3x3,
// F::ASTC_4X4X3_UNORM_BLOCK_EXT
// | F::ASTC_4X4X3_SRGB_BLOCK_EXT
// | F::ASTC_4X4X3_SFLOAT_BLOCK_EXT => FormatClass::Astc4x4x3,
// F::ASTC_4X4X4_UNORM_BLOCK_EXT
// | F::ASTC_4X4X4_SRGB_BLOCK_EXT
// | F::ASTC_4X4X4_SFLOAT_BLOCK_EXT => FormatClass::Astc4x4x4,
// F::ASTC_5X4X4_UNORM_BLOCK_EXT
// | F::ASTC_5X4X4_SRGB_BLOCK_EXT
// | F::ASTC_5X4X4_SFLOAT_BLOCK_EXT => FormatClass::Astc5x4x4,
// F::ASTC_5X5X4_UNORM_BLOCK_EXT
// | F::ASTC_5X5X4_SRGB_BLOCK_EXT
// | F::ASTC_5X5X4_SFLOAT_BLOCK_EXT => FormatClass::Astc5x5x4,
// F::ASTC_5X5X5_UNORM_BLOCK_EXT
// | F::ASTC_5X5X5_SRGB_BLOCK_EXT
// | F::ASTC_5X5X5_SFLOAT_BLOCK_EXT => FormatClass::Astc5x5x5,
// F::ASTC_6X5X5_UNORM_BLOCK_EXT
// | F::ASTC_6X5X5_SRGB_BLOCK_EXT
// | F::ASTC_6X5X5_SFLOAT_BLOCK_EXT => FormatClass::Astc6x5x5,
// F::ASTC_6X6X5_UNORM_BLOCK_EXT
// | F::ASTC_6X6X5_SRGB_BLOCK_EXT
// | F::ASTC_6X6X5_SFLOAT_BLOCK_EXT => FormatClass::Astc6x6x5,
// F::ASTC_6X6X6_UNORM_BLOCK_EXT
// | F::ASTC_6X6X6_SRGB_BLOCK_EXT
// | F::ASTC_6X6X6_SFLOAT_BLOCK_EXT => FormatClass::Astc6x6x6,
// // 14-bit 2-plane
// F::G14X2_B14X2R14X2_2PLANE_420_UNORM_3PACK16_ARM => {
// FormatClass::YuvG14X2_B14X2R14X2_2Plane_420
// }
// F::G14X2_B14X2R14X2_2PLANE_422_UNORM_3PACK16_ARM => {
// FormatClass::YuvG14X2_B14X2R14X2_2Plane_422
// }
_ => todo!(),
}
}
}

View file

@ -1,4 +1,5 @@
use std::{ use std::{
cell::OnceCell,
cmp::Ordering, cmp::Ordering,
ffi::{CStr, CString}, ffi::{CStr, CString},
ops::Deref, ops::Deref,

View file

@ -118,8 +118,6 @@ pub enum Error {
}, },
#[error("Unspecified Error")] #[error("Unspecified Error")]
Unspecified, Unspecified,
#[error("BEEP BOOP create an error variant for {0} BEEP BOOP")]
Todo(&'static str),
} }
pub type Result<T> = core::result::Result<T, Error>; pub type Result<T> = core::result::Result<T, Error>;
@ -1023,13 +1021,10 @@ impl Renderer2 {
surface: &swapchain::Surface, surface: &swapchain::Surface,
cb: F, cb: F,
) -> Result<T> { ) -> Result<T> {
let Some(frame) = surface.acquire_image() else { let frame = surface.acquire_image().await?;
return Err(Error::SuboptimalSwapchain);
};
let (frame, _suboptimal) = frame.await?;
let mut rg = render_graph::RenderGraph::new(); let mut rg = render_graph::RenderGraph::new();
let _framebuffer = rg.import_framebuffer(frame.image().clone()); let _framebuffer = rg.import_framebuffer(frame.image.clone());
let out = cb(self, &mut rg); let out = cb(self, &mut rg);

View file

@ -47,15 +47,6 @@ pub struct QueueInner {
pub(crate) lock: Mutex<()>, pub(crate) lock: Mutex<()>,
} }
impl QueueInner {
pub fn raw(&self) -> vk::Queue {
self.raw
}
pub fn family_index(&self) -> u32 {
self.family.index
}
}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct QueueFamily { pub struct QueueFamily {
pub index: u32, pub index: u32,

View file

@ -10,7 +10,7 @@ use crate::{
buffers::{Buffer, BufferDesc}, buffers::{Buffer, BufferDesc},
commands::{self, traits::CommandBufferExt}, commands::{self, traits::CommandBufferExt},
def_monotonic_id, def_monotonic_id,
device::{self}, device::{self, DeviceOwned},
images::{self, Image, ImageDesc}, images::{self, Image, ImageDesc},
util::{self, Rgba, WithLifetime}, util::{self, Rgba, WithLifetime},
}; };
@ -62,11 +62,13 @@ impl GraphResource {
discr.hash(&mut state); discr.hash(&mut state);
match self { match self {
GraphResource::Framebuffer(swapchain_frame) => (swapchain_frame.raw()).hash(&mut state), GraphResource::Framebuffer(swapchain_frame) => {
GraphResource::ImportedImage(image) => image.raw().hash(&mut state), (swapchain_frame.handle()).hash(&mut state)
GraphResource::ImportedBuffer(buffer) => buffer.raw().hash(&mut state), }
GraphResource::Image(image) => image.raw().hash(&mut state), GraphResource::ImportedImage(image) => image.handle().hash(&mut state),
GraphResource::Buffer(buffer) => buffer.raw().hash(&mut state), GraphResource::ImportedBuffer(buffer) => buffer.handle().hash(&mut state),
GraphResource::Image(image) => image.handle().hash(&mut state),
GraphResource::Buffer(buffer) => buffer.handle().hash(&mut state),
GraphResource::ImageDesc(image_desc) => image_desc.hash(&mut state), GraphResource::ImageDesc(image_desc) => image_desc.hash(&mut state),
GraphResource::BufferDesc(buffer_desc) => buffer_desc.hash(&mut state), GraphResource::BufferDesc(buffer_desc) => buffer_desc.hash(&mut state),
GraphResource::Default => {} GraphResource::Default => {}
@ -484,7 +486,7 @@ impl RenderGraph {
_ => {} _ => {}
} }
} }
crate::Result::Ok(()) ash::prelude::VkResult::Ok(())
})?; })?;
let pool = let pool =
@ -559,19 +561,19 @@ impl RenderGraph {
) { ) {
let barrier: Barrier = match res { let barrier: Barrier = match res {
GraphResource::Framebuffer(arc) => { GraphResource::Framebuffer(arc) => {
image_barrier(arc.raw(), arc.format(), from, to, None).into() image_barrier(arc.handle(), arc.format(), from, to, None).into()
} }
GraphResource::ImportedImage(arc) => { GraphResource::ImportedImage(arc) => {
image_barrier(arc.raw(), arc.format(), from, to, None).into() image_barrier(arc.handle(), arc.format(), from, to, None).into()
} }
GraphResource::ImportedBuffer(arc) => { GraphResource::ImportedBuffer(arc) => {
buffer_barrier(arc.raw(), 0, arc.len(), from, to, None).into() buffer_barrier(arc.handle(), 0, arc.len(), from, to, None).into()
} }
GraphResource::Image(image) => { GraphResource::Image(image) => {
image_barrier(image.raw(), image.format(), from, to, None).into() image_barrier(image.handle(), image.format(), from, to, None).into()
} }
GraphResource::Buffer(buffer) => { GraphResource::Buffer(buffer) => {
buffer_barrier(buffer.raw(), 0, buffer.len(), from, to, None).into() buffer_barrier(buffer.handle(), 0, buffer.len(), from, to, None).into()
} }
_ => { _ => {
unreachable!() unreachable!()
@ -1295,7 +1297,7 @@ pub fn clear_pass(rg: &mut RenderGraph, color: Rgba, target: GraphResourceId) {
let cmd = &ctx.cmd; let cmd = &ctx.cmd;
cmd.clear_color_image( cmd.clear_color_image(
target.raw(), target.handle(),
target.format(), target.format(),
vk::ImageLayout::TRANSFER_DST_OPTIMAL, vk::ImageLayout::TRANSFER_DST_OPTIMAL,
color, color,

View file

@ -2,7 +2,6 @@ use std::sync::Arc;
use ash::vk; use ash::vk;
use glam::{f32::Mat4, vec3}; use glam::{f32::Mat4, vec3};
use gpu_allocator::MemoryLocation;
pub use crate::egui_pass::{egui_pass, egui_pre_pass}; pub use crate::egui_pass::{egui_pass, egui_pre_pass};
@ -10,7 +9,7 @@ use crate::{
Result, Result,
buffers::{Buffer, BufferDesc}, buffers::{Buffer, BufferDesc},
commands::{self, traits::CommandBufferExt}, commands::{self, traits::CommandBufferExt},
device::Device, device::{Device, DeviceOwned},
images::ImageViewDesc, images::ImageViewDesc,
pipeline, pipeline,
render_graph::{ render_graph::{
@ -51,15 +50,16 @@ impl Wireframe {
name: Some("wireframe-staging".into()), name: Some("wireframe-staging".into()),
size: staging_size as u64, size: staging_size as u64,
usage: vk::BufferUsageFlags::TRANSFER_SRC, usage: vk::BufferUsageFlags::TRANSFER_SRC,
mem_location: MemoryLocation::CpuToGpu, mem_usage: vk_mem::MemoryUsage::AutoPreferHost,
alloc_flags: vk_mem::AllocationCreateFlags::MAPPED
| vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE
| vk_mem::AllocationCreateFlags::STRATEGY_FIRST_FIT,
..Default::default() ..Default::default()
}, },
)?; )?;
{ {
let map = staging let mut map = staging.map()?;
.map_mut()
.expect("staging buffer should be host visible");
map[..positions_size].copy_from_slice(bytemuck::cast_slice(&positions)); map[..positions_size].copy_from_slice(bytemuck::cast_slice(&positions));
map[indices_offset..][..indices_size].copy_from_slice(bytemuck::cast_slice(&indices)); map[indices_offset..][..indices_size].copy_from_slice(bytemuck::cast_slice(&indices));
@ -72,7 +72,7 @@ impl Wireframe {
name: Some("wireframe-positions".into()), name: Some("wireframe-positions".into()),
size: positions_size as u64, size: positions_size as u64,
usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::VERTEX_BUFFER, usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::VERTEX_BUFFER,
mem_location: MemoryLocation::GpuOnly, mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
..Default::default() ..Default::default()
}, },
)?; )?;
@ -82,7 +82,7 @@ impl Wireframe {
name: Some("wireframe-indices".into()), name: Some("wireframe-indices".into()),
size: indices_size as u64, size: indices_size as u64,
usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::INDEX_BUFFER, usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::INDEX_BUFFER,
mem_location: MemoryLocation::GpuOnly, mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
..Default::default() ..Default::default()
}, },
)?; )?;
@ -92,7 +92,7 @@ impl Wireframe {
name: Some("wireframe-colors".into()), name: Some("wireframe-colors".into()),
size: colors_size as u64, size: colors_size as u64,
usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::VERTEX_BUFFER, usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::VERTEX_BUFFER,
mem_location: MemoryLocation::GpuOnly, mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
..Default::default() ..Default::default()
}, },
)?; )?;
@ -102,8 +102,8 @@ impl Wireframe {
let cmd = pool.alloc()?; let cmd = pool.alloc()?;
cmd.copy_buffers( cmd.copy_buffers(
staging.raw(), staging.handle(),
positions.raw(), positions.handle(),
&[vk::BufferCopy { &[vk::BufferCopy {
src_offset: 0, src_offset: 0,
dst_offset: 0, dst_offset: 0,
@ -111,8 +111,8 @@ impl Wireframe {
}], }],
); );
cmd.copy_buffers( cmd.copy_buffers(
staging.raw(), staging.handle(),
indices.raw(), indices.handle(),
&[vk::BufferCopy { &[vk::BufferCopy {
src_offset: indices_offset as u64, src_offset: indices_offset as u64,
dst_offset: 0, dst_offset: 0,
@ -120,8 +120,8 @@ impl Wireframe {
}], }],
); );
cmd.copy_buffers( cmd.copy_buffers(
staging.raw(), staging.handle(),
colors.raw(), colors.handle(),
&[vk::BufferCopy { &[vk::BufferCopy {
src_offset: colors_offset as u64, src_offset: colors_offset as u64,
dst_offset: 0, dst_offset: 0,
@ -131,7 +131,7 @@ impl Wireframe {
let barriers = [ let barriers = [
buffer_barrier( buffer_barrier(
positions.raw(), positions.handle(),
0, 0,
positions.len(), positions.len(),
Access::transfer_write(), Access::transfer_write(),
@ -139,7 +139,7 @@ impl Wireframe {
None, None,
), ),
buffer_barrier( buffer_barrier(
indices.raw(), indices.handle(),
0, 0,
indices.len(), indices.len(),
Access::transfer_write(), Access::transfer_write(),
@ -147,7 +147,7 @@ impl Wireframe {
None, None,
), ),
buffer_barrier( buffer_barrier(
colors.raw(), colors.handle(),
0, 0,
colors.len(), colors.len(),
Access::transfer_write(), Access::transfer_write(),
@ -334,7 +334,12 @@ impl Wireframe {
let color_attachment = &vk::RenderingAttachmentInfo::default() let color_attachment = &vk::RenderingAttachmentInfo::default()
.image_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL) .image_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
.image_view(target.create_view(ImageViewDesc::color_2d())?.raw()) .image_view(target.get_view(ImageViewDesc {
kind: vk::ImageViewType::TYPE_2D,
format: target.format(),
aspect: vk::ImageAspectFlags::COLOR,
..Default::default()
})?)
.load_op(vk::AttachmentLoadOp::LOAD) .load_op(vk::AttachmentLoadOp::LOAD)
.store_op(vk::AttachmentStoreOp::STORE); .store_op(vk::AttachmentStoreOp::STORE);
@ -358,8 +363,8 @@ impl Wireframe {
.height(target.height() as f32)]); .height(target.height() as f32)]);
cmd.bind_pipeline(&pipeline); cmd.bind_pipeline(&pipeline);
cmd.bind_indices(indices.raw(), 0, vk::IndexType::UINT32); cmd.bind_indices(indices.buffer(), 0, vk::IndexType::UINT32);
cmd.bind_vertex_buffers(&[positions.raw(), colors.raw()], &[0, 0]); cmd.bind_vertex_buffers(&[positions.handle(), colors.handle()], &[0, 0]);
cmd.push_constants( cmd.push_constants(
&layout, &layout,
vk::ShaderStageFlags::VERTEX, vk::ShaderStageFlags::VERTEX,

View file

@ -1,6 +1,6 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
ops::Deref, marker::PhantomData,
sync::{ sync::{
Arc, Arc,
atomic::{AtomicU32, AtomicU64, Ordering}, atomic::{AtomicU32, AtomicU64, Ordering},
@ -12,14 +12,16 @@ use ash::{
prelude::VkResult, prelude::VkResult,
vk::{self, Handle}, vk::{self, Handle},
}; };
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RawMutex, RwLock};
use raw_window_handle::{RawDisplayHandle, RawWindowHandle}; use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
use crate::{ use crate::{
Instance, PhysicalDeviceInfo, Result, SurfaceCapabilities, Instance, PhysicalDeviceInfo, Result, SurfaceCapabilities, define_device_owned_handle,
device::{Device, DeviceObject}, device::{Device, DeviceObject, DeviceOwned},
images::{self, ImageViewDesc}, images,
sync::Fence, instance::InstanceInner,
sync::{self, Fence},
util::RawMutexGuard,
}; };
use derive_more::Debug; use derive_more::Debug;
@ -272,18 +274,6 @@ impl Surface {
composite_alpha_mode, composite_alpha_mode,
}) })
} }
pub fn acquire_image(
&self,
) -> Option<impl std::future::Future<Output = crate::Result<(SwapchainImage, bool)>>> {
// ensure lock does not block for the entire duration of the async image acquisition.
let swapchain = self.swapchain.read().as_ref().cloned();
if let Some(swapchain) = swapchain {
Some(swapchain.acquire_image())
} else {
None
}
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -312,7 +302,7 @@ pub struct Swapchain {
// Some of the swapchain operations require external synchronisation; this mutex allows `Swapchain` to be `Sync`. // Some of the swapchain operations require external synchronisation; this mutex allows `Swapchain` to be `Sync`.
#[debug(skip)] #[debug(skip)]
pub(crate) guard: parking_lot::Mutex<()>, guard: parking_lot::RawMutex,
// for khr_present_id/khr_present_wait // for khr_present_id/khr_present_wait
#[allow(unused)] #[allow(unused)]
@ -375,7 +365,7 @@ impl Swapchain {
.expect("swapchain extension not loaded"); .expect("swapchain extension not loaded");
let (swapchain, images) = { let (swapchain, images) = {
let _lock = old_swapchain.as_ref().map(|old| old.guard.lock()); let _lock = old_swapchain.as_ref().map(|old| old.lock());
let old_swapchain = old_swapchain let old_swapchain = old_swapchain
.map(|swp| *swp.swapchain) .map(|swp| *swp.swapchain)
.unwrap_or(vk::SwapchainKHR::null()); .unwrap_or(vk::SwapchainKHR::null());
@ -477,7 +467,7 @@ impl Swapchain {
), ),
images, images,
config, config,
guard: Mutex::new(()), guard: <RawMutex as parking_lot::lock_api::RawMutex>::INIT,
min_image_count: surface_caps.capabilities.min_image_count, min_image_count: surface_caps.capabilities.min_image_count,
acquire_semaphores, acquire_semaphores,
release_semaphores, release_semaphores,
@ -495,15 +485,11 @@ impl Swapchain {
self.images.len() as u32 self.images.len() as u32
} }
pub fn raw(&self) -> vk::SwapchainKHR {
*self.swapchain
}
/// returns a future yielding the frame, and true if the swapchain is /// returns a future yielding the frame, and true if the swapchain is
/// suboptimal and should be recreated. /// suboptimal and should be recreated.
fn acquire_image( fn acquire_image(
self: Arc<Self>, self: Arc<Self>,
) -> impl std::future::Future<Output = crate::Result<(SwapchainImage, bool)>> { ) -> impl std::future::Future<Output = crate::Result<(SwapchainFrame, bool)>> {
let frame = self let frame = self
.current_frame .current_frame
.try_update(Ordering::Release, Ordering::Relaxed, |i| { .try_update(Ordering::Release, Ordering::Relaxed, |i| {
@ -521,34 +507,28 @@ impl Swapchain {
// spawn on threadpool because it might block. // spawn on threadpool because it might block.
let (idx, suboptimal) = smol::unblock({ let (idx, suboptimal) = smol::unblock({
let this = self.clone(); let this = self.clone();
let fence = fence.raw();
move || unsafe { move || unsafe {
this.with_locked(|swapchain| { this.with_locked(|swapchain| {
this.functor this.functor
.acquire_next_image(swapchain.raw(), u64::MAX, acquire, fence) .acquire_next_image(swapchain, u64::MAX, acquire, fence.raw())
}) })
} }
}) })
.await?; .await?;
let idx = idx as usize;
let image = self.images[idx].clone();
let image = Arc::new(images::Image::from_swapchain_image(image, &self));
let view = image.create_view(ImageViewDesc {
name: Some(format!("swapchain-{:x}-image-view-{idx}", self.raw().as_raw()).into()),
kind: vk::ImageViewType::TYPE_2D,
format: self.config.format,
aspect: vk::ImageAspectFlags::COLOR,
..Default::default()
})?;
// wait for image to become available. // wait for image to become available.
fence.into_future().await; fence.into_future().await;
let idx = idx as usize;
let image = self.images[idx].clone();
let view = self.image_views[idx];
Ok(( Ok((
SwapchainImage { SwapchainFrame {
index: idx as u32, index: idx as u32,
swapchain: self, swapchain: self.clone(),
format: self.config.format,
image,
view, view,
acquire, acquire,
release, release,
@ -558,36 +538,31 @@ impl Swapchain {
} }
} }
/// # Safety fn present(&self, frame: SwapchainFrame, wait: Option<vk::Semaphore>) -> Result<()> {
/// The caller must ensure that the provided index corresponds to an image let swpchain = self.lock();
/// that is currently acquired and not yet presented. let queue = self.device().present_queue().lock();
unsafe fn present(&self, index: u32, wait: Option<vk::Semaphore>) -> Result<()> {
let _lock = self.guard.lock();
let wait_semaphores = wait.as_slice(); let wait_semaphores = wait.as_slice();
// TODO: make this optional for devices with no support for present_wait/present_id
// let present_id = self
// .present_id
// .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
// let mut present_id =
// vk::PresentIdKHR::default().present_ids(core::slice::from_ref(&present_id));
let present_info = vk::PresentInfoKHR::default() let present_info = vk::PresentInfoKHR::default()
.image_indices(core::slice::from_ref(&index)) .image_indices(core::slice::from_ref(&frame.index))
.swapchains(core::slice::from_ref(&*self.swapchain)) .swapchains(core::slice::from_ref(&swpchain))
.wait_semaphores(wait_semaphores); .wait_semaphores(wait_semaphores);
//.push_next(&mut present_id)
let queue = self.swapchain.device().queues.graphics(); // call winits pre_present_notify here
queue.with_locked(|queue| -> crate::Result<()> {
// TODO: make this optional for devices with no support for present_wait/present_id
// let present_id = self
// .present_id
// .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
// let mut present_id =
// vk::PresentIdKHR::default().present_ids(core::slice::from_ref(&present_id));
//.push_next(&mut present_id) unsafe {
self.functor.queue_present(*queue, &present_info)?;
// call winits pre_present_notify here }
Ok(())
unsafe {
self.functor.queue_present(queue.raw(), &present_info)?;
}
Ok(())
})
} }
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
@ -640,41 +615,6 @@ impl Swapchain {
} }
static SWAPCHAIN_COUNT: AtomicU64 = AtomicU64::new(0); static SWAPCHAIN_COUNT: AtomicU64 = AtomicU64::new(0);
#[derive(Debug)]
#[must_use = "This struct represents an acquired image from the Swapchain and
must be presented in order to free resources on the device."]
pub struct SwapchainImage {
view: images::ImageView,
// The swapchain must be kept alive while the image is in use, because the
// image is owned by the swapchain and will be freed when the swapchain is
// dropped. Additionally, we need access to the swapchain in order to
// present the image.
swapchain: Arc<Swapchain>,
index: u32,
pub acquire: vk::Semaphore,
pub release: vk::Semaphore,
}
impl Deref for SwapchainImage {
type Target = images::ImageView;
fn deref(&self) -> &Self::Target {
&self.view
}
}
impl SwapchainImage {
pub fn index(&self) -> u32 {
self.index
}
pub fn present(self, wait: Option<vk::Semaphore>) -> crate::Result<()> {
// SAFETY: we know the index is valid because we've aquired the image,
// and we know it isn't presented yet because we still own the image.
unsafe { self.swapchain.present(self.index, wait) }
}
}
#[derive(Debug)] #[derive(Debug)]
#[must_use = "This struct represents an acquired image from the swapchain and #[must_use = "This struct represents an acquired image from the swapchain and
must be presented in order to free resources on the device."] must be presented in order to free resources on the device."]
@ -697,8 +637,7 @@ impl PartialEq for SwapchainFrame {
impl SwapchainFrame { impl SwapchainFrame {
pub fn present(self, wait: Option<vk::Semaphore>) -> crate::Result<()> { pub fn present(self, wait: Option<vk::Semaphore>) -> crate::Result<()> {
// SAFETY: we know the index is valid because we've aquired the image, and we know it isn't presented yet because we still own the image. self.swapchain.clone().present(self, wait)
unsafe { self.swapchain.present(self.index, wait) }
} }
} }
@ -739,9 +678,19 @@ pub struct SwapchainConfiguration {
} }
impl Swapchain { impl Swapchain {
pub fn with_locked<T, F: FnOnce(&Self) -> T>(&self, f: F) -> T { pub fn lock(&self) -> RawMutexGuard<'_, vk::SwapchainKHR> {
let _lock = self.guard.lock(); use parking_lot::lock_api::RawMutex;
f(self) self.guard.lock();
RawMutexGuard {
mutex: &self.guard,
value: &*self.swapchain,
_pd: PhantomData,
}
}
pub fn with_locked<T, F: FnOnce(vk::SwapchainKHR) -> T>(&self, f: F) -> T {
let lock = self.lock();
f(*lock)
} }
} }

View file

@ -3,15 +3,16 @@ use std::borrow::Cow;
use std::{ use std::{
future::Future, future::Future,
marker::PhantomData, marker::PhantomData,
mem::ManuallyDrop,
sync::{Arc, atomic::AtomicU32}, sync::{Arc, atomic::AtomicU32},
time::Duration, time::Duration,
}; };
use crate::device::{DeviceObject, Pool, PoolObject, Pooled}; use crate::device::{DeviceObject, DeviceOwned, Pool, PoolObject, Pooled};
use crate::{Result, device::DeviceInner}; use crate::{Result, device::DeviceInner};
use super::Device; use super::Device;
use ash::{prelude::VkResult, vk}; use ash::{prelude::*, vk};
use crossbeam::channel::{Receiver, Sender}; use crossbeam::channel::{Receiver, Sender};
type Message = (SyncPrimitive, std::task::Waker); type Message = (SyncPrimitive, std::task::Waker);
@ -211,7 +212,7 @@ impl Fence {
} }
} }
pub fn wait_on(&self, timeout: Option<u64>) -> VkResult<()> { pub fn wait_on(&self, timeout: Option<u64>) -> Result<()> {
unsafe { unsafe {
self.device().raw.wait_for_fences( self.device().raw.wait_for_fences(
core::slice::from_ref(&self.raw()), core::slice::from_ref(&self.raw()),