From b00b1b315134b6bdbf54ecb3ff3f78f20e528cd6 Mon Sep 17 00:00:00 2001 From: janis Date: Fri, 3 Apr 2026 03:13:51 +0200 Subject: [PATCH] fix egui ? --- Cargo.toml | 1 + crates/renderer/Cargo.toml | 1 + crates/renderer/src/device.rs | 71 +---- crates/renderer/src/egui.rs | 475 +++++++++++++++++-------------- crates/renderer/src/images.rs | 4 + crates/renderer/src/lib.rs | 38 +-- crates/renderer/src/queue.rs | 22 +- crates/renderer/src/swapchain.rs | 9 +- crates/renderer/src/sync.rs | 2 +- crates/renderer/src/util.rs | 1 + 10 files changed, 297 insertions(+), 327 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b49a858..a28b274 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ ash = "0.38.0" ash-window = "0.13.0" vk-mem = "0.5.0" gpu-allocator = { git = "https://github.com/janis-bhm/gpu-allocator", branch = "main" } +rectangle-pack = "0.4.2" vk-sync = "0.1.6" arrayvec = "0.7.6" diff --git a/crates/renderer/Cargo.toml b/crates/renderer/Cargo.toml index cb95eee..bba6729 100644 --- a/crates/renderer/Cargo.toml +++ b/crates/renderer/Cargo.toml @@ -24,6 +24,7 @@ ash = { workspace = true } ash-window = { workspace = true } vk-mem = { workspace = true } gpu-allocator = { workspace = true } +rectangle-pack = { workspace = true } raw-window-handle = { workspace = true } egui = { workspace = true , features = ["bytemuck"]} diff --git a/crates/renderer/src/device.rs b/crates/renderer/src/device.rs index e7420e1..1836a9e 100644 --- a/crates/renderer/src/device.rs +++ b/crates/renderer/src/device.rs @@ -14,7 +14,6 @@ use ash::{ }; use parking_lot::Mutex; use raw_window_handle::RawDisplayHandle; -use tinyvec::{ArrayVec, array_vec}; use crate::{ Instance, PhysicalDeviceFeatures, PhysicalDeviceInfo, Result, @@ -22,62 +21,6 @@ use crate::{ sync::{self, BinarySemaphore, TimelineSemaphore}, }; -#[derive(Debug, Default)] -pub struct DeviceQueueFamilies { - pub(crate) families: Vec<(u32, u32)>, - pub(crate) graphics: (u32, u32), - pub(crate) present: (u32, u32), - pub(crate) async_compute: (u32, u32), - pub(crate) transfer: (u32, u32), - #[expect(dead_code)] - pub(crate) properties: Box<[vk::QueueFamilyProperties]>, -} - -impl DeviceQueueFamilies { - pub fn swapchain_family_indices(&self) -> ArrayVec<[u32; 2]> { - let mut indices = array_vec!([u32; 2] => self.graphics.0); - - if self.present.0 != self.graphics.0 { - indices.push(self.present.0); - } - - indices - } - pub fn graphics_familty(&self) -> u32 { - self.graphics.0 - } - pub fn present_familty(&self) -> u32 { - self.present.0 - } - pub fn async_compute_familty(&self) -> u32 { - self.async_compute.0 - } - pub fn transfer_familty(&self) -> u32 { - self.transfer.0 - } - - pub fn family_indices(&self, flags: QueueFlags) -> ArrayVec<[u32; 4]> { - let mut indices = array_vec!([u32; 4]); - if flags.contains(QueueFlags::GRAPHICS) { - indices.push(self.graphics_familty()); - } - if flags.contains(QueueFlags::PRESENT) { - indices.push(self.present_familty()); - } - if flags.contains(QueueFlags::ASYNC_COMPUTE) { - indices.push(self.async_compute_familty()); - } - if flags.contains(QueueFlags::TRANSFER) { - indices.push(self.transfer_familty()); - } - - let unique_len = indices.partition_dedup().0.len(); - indices.drain(unique_len..); - - indices - } -} - bitflags::bitflags! { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -102,9 +45,10 @@ impl Drop for DeviceDrop { } } -struct DeviceExtensions { +pub(crate) struct DeviceExtensions { pub(crate) debug_utils: ext::debug_utils::Device, pub(crate) swapchain: Option, + #[allow(dead_code)] pub(crate) mesh_shader: Option, } @@ -131,7 +75,7 @@ pub enum AllocationStrategy { } #[derive(Debug)] -pub(crate) enum Allocation { +pub enum Allocation { Owned(DeviceObject), Shared(Arc>), Unmanaged, @@ -163,6 +107,7 @@ pub struct DeviceInner { pub(crate) queues: DeviceQueues, pub(crate) sync_threadpool: sync::SyncThreadpool, pub(crate) device_extensions: DeviceExtensions, + #[allow(dead_code)] pub(crate) enabled_extensions: Vec<&'static CStr>, _drop: DeviceDrop, } @@ -550,7 +495,7 @@ impl DeviceInner { pub fn features(&self) -> &crate::PhysicalDeviceFeatures { &self.adapter.features } - pub fn properties(&self) -> &crate::PhysicalDeviceProperties { + pub(crate) fn properties(&self) -> &crate::PhysicalDeviceProperties { &self.adapter.properties } pub fn physical_device(&self) -> &PhysicalDeviceInfo { @@ -566,12 +511,18 @@ impl DeviceInner { self.queues.transfer() } + /// # Safety + /// + /// The caller must ensure that the queues aren't already locked when calling this function. pub unsafe fn lock_queues(&self) { unsafe { self.queues.lock(); } } + /// # Safety + /// + /// The caller must have acquired and have logical ownership of the lock on the queues. pub unsafe fn unlock_queues(&self) { unsafe { self.queues.unlock(); diff --git a/crates/renderer/src/egui.rs b/crates/renderer/src/egui.rs index 8bb3653..02caf87 100644 --- a/crates/renderer/src/egui.rs +++ b/crates/renderer/src/egui.rs @@ -1,4 +1,7 @@ -use std::{collections::BTreeMap, sync::Arc}; +use std::{ + collections::{BTreeMap, HashMap}, + sync::Arc, +}; use ash::vk; use gpu_allocator::MemoryLocation; @@ -14,8 +17,7 @@ use crate::{ Access, Barrier, GraphResourceDesc, GraphResourceId, PassDesc, RecordFn, RenderContext, RenderGraph, buffer_barrier, image_barrier, }, - texture, - util::Rect2D, + texture::{self, TextureId}, }; pub fn egui_pre_pass( @@ -32,68 +34,106 @@ pub fn egui_pre_pass( return Ok(()); } + use rectangle_pack::{ + GroupedRectsToPlace, RectToInsert, TargetBin, contains_smallest_box, pack_rects, + volume_heuristic, + }; + let mut rects_to_place = GroupedRectsToPlace::::new(); + + let mut max_width = 0; + let mut max_height = 0; + // create textures for new egui textures - for (egui_id, delta) in output + // these are real images that will be sampled from in the shader. + let updates = output .textures_delta .set .iter() - .filter(|(_, image)| image.is_whole()) - { - tracing::trace!("creating texture image for egui image {egui_id:?}"); - let image = Image::new( - dev.clone(), - ImageDesc { - name: Some(format!("egui-texture-{egui_id:?}").into()), - format: vk::Format::R8G8B8A8_UNORM, - extent: vk::Extent3D { - width: delta.image.width() as u32, - height: delta.image.height() as u32, - depth: 1, - }, - usage: vk::ImageUsageFlags::SAMPLED | vk::ImageUsageFlags::TRANSFER_DST, - mem_location: MemoryLocation::GpuOnly, - alloc_scheme: AllocationStrategy::Dedicated, - ..Default::default() - }, - )?; + .map(|(egui_id, delta)| { + max_width = max_width.max(delta.image.width() as u32); + max_height = max_height.max(delta.image.height() as u32); - let tid = textures.insert_image(Arc::new(image)); - if let Some(old) = egui_state.textures.insert( - *egui_id, - crate::EguiTextureInfo { - id: tid, - options: delta.options, - }, + use std::collections::hash_map::Entry; + let id = match egui_state.textures.entry(*egui_id) { + Entry::Occupied(entry) => entry.get().id, + Entry::Vacant(entry) => { + tracing::trace!("creating texture image for egui image {egui_id:?}"); + + let Ok(image) = Image::new( + dev.clone(), + ImageDesc { + name: Some(format!("egui-texture-{egui_id:?}").into()), + format: vk::Format::R8G8B8A8_UNORM, + extent: vk::Extent3D { + width: delta.image.width() as u32, + height: delta.image.height() as u32, + depth: 1, + }, + usage: vk::ImageUsageFlags::SAMPLED | vk::ImageUsageFlags::TRANSFER_DST, + mem_location: MemoryLocation::GpuOnly, + alloc_scheme: AllocationStrategy::Dedicated, + ..Default::default() + }, + ) else { + return Err(crate::Error::Todo( + "handle image creation failure in egui pre-pass", + )); + }; + + let id = textures.insert_image(Arc::new(image)); + entry.insert(crate::EguiTextureInfo { + id, + options: delta.options, + }); + id + } + }; + + rects_to_place.push_rect( + id, + None, + RectToInsert::new(delta.image.width() as u32, delta.image.height() as u32, 1), + ); + + Ok((id, (delta.pos, &delta.image))) + }) + .collect::>>()?; + + let rect_placements = loop { + let mut target_bins = BTreeMap::new(); + target_bins.insert(0, TargetBin::new(max_width, max_height, 1)); + + match pack_rects( + &rects_to_place, + &mut target_bins, + &volume_heuristic, + &contains_smallest_box, ) { - textures.remove_texture(old.id); + Ok(placements) => break placements, + Err(_) => { + max_width *= 2; + max_height *= 2; + } } - } + }; - // calculate size for staging buffer. - // calculate size for staging image. - let (staging_size, image_size) = output.textures_delta.set.iter().fold( - (0usize, glam::UVec2::ZERO), - |(mut buffer, mut image), (_id, delta)| { - let bytes = delta.image.height() * delta.image.width() * delta.image.bytes_per_pixel(); - image = image.max(glam::uvec2( - delta.image.width() as u32, - delta.image.height() as u32, - )); - buffer += bytes; - - (buffer, image) - }, - ); + let extent = rect_placements + .packed_locations() + .iter() + .fold((0u32, 0u32), |(w, h), (_id, (_bin, loc))| { + (w.max(loc.x() + loc.width()), h.max(loc.y() + loc.height())) + }); tracing::trace!( - staging_size, - "creating staging buffer for uploading egui textures" + "creating staging buffer {}x{} for uploading egui textures", + extent.0, + extent.1, ); let mut staging_buffer = Buffer::new( dev.clone(), BufferDesc { name: Some("egui-prepass-staging-buffer".into()), - size: staging_size as u64, + size: (extent.0 * extent.1 * 4) as u64, // RGBA8 usage: vk::BufferUsageFlags::TRANSFER_SRC, queue_families: device::QueueFlags::empty(), mem_location: MemoryLocation::CpuToGpu, @@ -101,15 +141,14 @@ pub fn egui_pre_pass( }, )?; - tracing::trace!("creating staging image for uploading egui textures with dims={image_size:?}"); - let staging_image = Arc::new(Image::new( + let staging_image = Image::new( dev.clone(), ImageDesc { name: Some("egui-prepass-staging-buffer".into()), format: vk::Format::R8G8B8A8_UNORM, extent: vk::Extent3D { - width: image_size.x, - height: image_size.y, + width: extent.0, + height: extent.1, depth: 1, }, usage: vk::ImageUsageFlags::TRANSFER_SRC | vk::ImageUsageFlags::TRANSFER_DST, @@ -117,108 +156,178 @@ pub fn egui_pre_pass( mem_location: MemoryLocation::GpuOnly, ..Default::default() }, - )?); + )?; - let aliased_images = { - tracing::trace!("mmap-ing staging buffer"); - let mut staging_map = staging_buffer.map().unwrap(); - let mut offset = 0; + let staging_map = staging_buffer.map_mut().unwrap(); - output - .textures_delta - .set - .iter() - .map(|(id, delta)| { - let bytes = - delta.image.height() * delta.image.width() * delta.image.bytes_per_pixel(); + struct ImageUpdate { + #[allow(dead_code)] + id: TextureId, + graph_id: GraphResourceId, + dest_offset: (u32, u32), + src_offset: (u32, u32), + size: (u32, u32), + } - let mem = &mut staging_map[offset..offset + bytes]; - match &delta.image { - egui::ImageData::Color(arc) => { - let slice = unsafe { - core::slice::from_raw_parts( - arc.pixels.as_ptr().cast::(), - arc.pixels.len() * size_of::(), - ) - }; - mem[..slice.len()].copy_from_slice(slice); - } - } + let updates = updates + .into_iter() + .filter_map(|(id, (pos, image))| { + let (_, loc) = rect_placements.packed_locations().get(&id)?; - let old_offset = offset; - offset += bytes; + // copy scanlines from image data into staging buffer + let rect_width = loc.width() as usize; + let rect_height = loc.height() as usize; + let rect_x = loc.x() as usize; + let rect_y = loc.y() as usize; - let pos = delta.pos.unwrap_or_default(); - let rect = Rect2D::new_from_size( - glam::ivec2(pos[0] as i32, pos[1] as i32), - glam::ivec2(delta.image.width() as i32, delta.image.height() as i32), - ); - (*id, (old_offset, bytes, rect)) - }) - .collect::>() + let pixel_size = 4usize; // RGBA8 + let atlas_width = extent.0 as usize; - // let tessellated = egui.tessellate(output.shapes, output.pixels_per_point); - }; + let image_data = match image { + egui::ImageData::Color(color_image) => color_image.as_raw(), + }; - let textures = output - .textures_delta - .set - .iter() - .filter_map(|(egui_id, _)| { - egui_state - .lookup_texture(*egui_id) - .and_then(|tid| textures.get_texture(tid)) - .map(|img| (*egui_id, img)) - }) - .map(|(id, img)| { - ( + for (atlas_y, image_y) in (rect_y..rect_y + rect_height).enumerate() { + let atlas_start = (image_y * atlas_width + rect_x) * pixel_size; + let atlas_end = atlas_start + rect_width * pixel_size; + + let image_start = (atlas_y * rect_width) * pixel_size; + let image_end = image_start + rect_width * pixel_size; + staging_map[atlas_start..atlas_end] + .copy_from_slice(&image_data[image_start..image_end]); + } + + let graph_id = rg.import_image( + textures.get_texture(id)?, + Access { + layout: vk::ImageLayout::GENERAL, + ..Access::undefined() + }, + ); + + Some(ImageUpdate { id, - rg.import_image( - img, - Access { - layout: vk::ImageLayout::GENERAL, - ..Access::undefined() - }, - ), + graph_id, + dest_offset: pos.map(|p| (p[0] as u32, p[1] as u32)).unwrap_or_default(), + src_offset: (rect_x as u32, rect_y as u32), + size: (rect_width as u32, rect_height as u32), + }) + }) + .collect::>(); + + let writes = updates + .iter() + .map(|update| { + ( + update.graph_id, + Access { + layout: vk::ImageLayout::GENERAL, + ..Access::undefined() + }, ) }) - .collect::>(); + .collect::>(); let staging_buffer = rg.import_buffer(Arc::new(staging_buffer), Access::undefined()); - let staging_image = rg.import_image(staging_image, Access::undefined()); + let staging_image = rg.import_image(Arc::new(staging_image), Access::undefined()); let record = Box::new({ - let textures = textures.clone(); + // let textures = textures.clone(); move |ctx: &RenderContext| -> crate::Result<()> { let staging_image = ctx.get_image(staging_image).unwrap().clone(); let staging_buffer = ctx.get_buffer(staging_buffer).unwrap(); - for (id, (offset, _, rect)) in aliased_images { - tracing::trace!( - "record-prepass: fetching alias of prepass staging image id={id:?}" - ); - let alias = staging_image.get_alias(ImageDesc { - name: Some(format!("egui-prepass-staging-aliased-{id:?}v").into()), - format: vk::Format::R8G8B8A8_UNORM, - extent: vk::Extent3D { - width: rect.width() as u32, - height: rect.height() as u32, - depth: 1, - }, - usage: vk::ImageUsageFlags::TRANSFER_SRC | vk::ImageUsageFlags::TRANSFER_DST, - queue_families: device::QueueFlags::empty(), - ..Default::default() - })?; + let image: Barrier = image_barrier( + staging_image.raw(), + staging_image.format(), + Access { + stage: vk::PipelineStageFlags2::NONE, + mask: vk::AccessFlags2::empty(), + layout: vk::ImageLayout::UNDEFINED, + }, + Access { + stage: vk::PipelineStageFlags2::TRANSFER, + mask: vk::AccessFlags2::TRANSFER_WRITE, + layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL, + }, + None, + ) + .into(); - let texture = textures.get(&id).and_then(|id| ctx.get_image(*id)).unwrap(); + unsafe { + ctx.device + .dev() + .cmd_pipeline_barrier2(ctx.cmd.buffer(), &((&image).into())); + } - let image: Barrier = image_barrier( - alias.raw(), - alias.format(), + ctx.cmd.copy_buffer_to_image( + staging_buffer.raw(), + staging_image.raw(), + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + &[vk::BufferImageCopy { + buffer_offset: 0, + buffer_row_length: staging_image.width(), + buffer_image_height: staging_image.height(), + image_subresource: vk::ImageSubresourceLayers::default() + .aspect_mask(vk::ImageAspectFlags::COLOR) + .base_array_layer(0) + .mip_level(0) + .layer_count(1), + image_offset: vk::Offset3D { x: 0, y: 0, z: 0 }, + image_extent: staging_image.size(), + }], + ); + + let from_barrier: Barrier = image_barrier( + staging_image.raw(), + staging_image.format(), + Access { + stage: vk::PipelineStageFlags2::TRANSFER, + mask: vk::AccessFlags2::TRANSFER_WRITE, + layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL, + }, + Access { + stage: vk::PipelineStageFlags2::TRANSFER, + mask: vk::AccessFlags2::TRANSFER_READ, + layout: vk::ImageLayout::TRANSFER_SRC_OPTIMAL, + }, + None, + ) + .into(); + + unsafe { + ctx.device + .dev() + .cmd_pipeline_barrier2(ctx.cmd.buffer(), &((&from_barrier).into())); + } + + for ImageUpdate { + graph_id, + dest_offset, + src_offset, + size, + .. + } in &updates + { + let texture = ctx.get_image(*graph_id).unwrap(); + + let to_barrier: Barrier = image_barrier( + texture.raw(), + texture.format(), Access { stage: vk::PipelineStageFlags2::NONE, mask: vk::AccessFlags2::empty(), - layout: vk::ImageLayout::UNDEFINED, + // TODO: this is somewhat sub-optimal, but I think + // perfectly legal to not-care about the layout of a + // texture? In this case, the entire texture is + // overwritten, so the layout doesn't matter, and else + // the layout will be `GENERAL` because the texture was + // previously written to. + layout: if staging_image.size() == texture.size() { + vk::ImageLayout::UNDEFINED + } else { + vk::ImageLayout::GENERAL + }, }, Access { stage: vk::PipelineStageFlags2::TRANSFER, @@ -232,78 +341,11 @@ pub fn egui_pre_pass( unsafe { ctx.device .dev() - .cmd_pipeline_barrier2(ctx.cmd.buffer(), &((&image).into())); + .cmd_pipeline_barrier2(ctx.cmd.buffer(), &((&to_barrier).into())); } - ctx.cmd.copy_buffer_to_image( - staging_buffer.raw(), - alias.raw(), - vk::ImageLayout::TRANSFER_DST_OPTIMAL, - &[vk::BufferImageCopy { - buffer_offset: offset as u64, - buffer_row_length: alias.width(), - buffer_image_height: alias.height(), - image_subresource: vk::ImageSubresourceLayers::default() - .aspect_mask(vk::ImageAspectFlags::COLOR) - .base_array_layer(0) - .mip_level(0) - .layer_count(1), - image_offset: vk::Offset3D { x: 0, y: 0, z: 0 }, - image_extent: alias.size(), - }], - ); - - let from_barrier = image_barrier( - alias.raw(), - alias.format(), - Access { - stage: vk::PipelineStageFlags2::TRANSFER, - mask: vk::AccessFlags2::TRANSFER_WRITE, - layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL, - }, - Access { - stage: vk::PipelineStageFlags2::TRANSFER, - mask: vk::AccessFlags2::TRANSFER_READ, - layout: vk::ImageLayout::TRANSFER_SRC_OPTIMAL, - }, - None, - ); - - let to_barrier = image_barrier( - texture.raw(), - texture.format(), - Access { - stage: vk::PipelineStageFlags2::NONE, - mask: vk::AccessFlags2::empty(), - // TODO: this is somewhat sub-optimal, but I think - // perfectly legal to not-care about the layout of a - // texture? In this case, the entire texture is - // overwritten, so the layout doesn't matter, and else - // the layout will be `GENERAL` because the texture was - // previously written to. - layout: if alias.size() == texture.size() { - vk::ImageLayout::UNDEFINED - } else { - vk::ImageLayout::GENERAL - }, - }, - Access { - stage: vk::PipelineStageFlags2::TRANSFER, - mask: vk::AccessFlags2::TRANSFER_WRITE, - layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL, - }, - None, - ); - - unsafe { - ctx.device.dev().cmd_pipeline_barrier2( - ctx.cmd.buffer(), - &vk::DependencyInfo::default() - .image_memory_barriers(&[from_barrier, to_barrier]), - ); - } ctx.cmd.copy_images( - alias.raw(), + staging_image.raw(), vk::ImageLayout::TRANSFER_SRC_OPTIMAL, texture.raw(), vk::ImageLayout::TRANSFER_DST_OPTIMAL, @@ -313,18 +355,26 @@ pub fn egui_pre_pass( .base_array_layer(0) .mip_level(0) .layer_count(1), - src_offset: vk::Offset3D { x: 0, y: 0, z: 0 }, + src_offset: vk::Offset3D { + x: src_offset.0 as i32, + y: src_offset.1 as i32, + z: 0, + }, dst_subresource: vk::ImageSubresourceLayers::default() .aspect_mask(vk::ImageAspectFlags::COLOR) .base_array_layer(0) .mip_level(0) .layer_count(1), dst_offset: vk::Offset3D { - x: rect.top_left().x, - y: rect.top_left().y, + x: dest_offset.0 as i32, + y: dest_offset.1 as i32, z: 0, }, - extent: alias.size(), + extent: vk::Extent3D { + width: size.0, + height: size.1, + depth: 0, + }, }], ); @@ -368,18 +418,7 @@ pub fn egui_pre_pass( (staging_image, Access::undefined()), ] .to_vec(), - writes: textures - .values() - .map(|id| { - ( - *id, - Access { - layout: vk::ImageLayout::GENERAL, - ..Access::undefined() - }, - ) - }) - .collect(), + writes, record: Some(record), }); Ok(()) diff --git a/crates/renderer/src/images.rs b/crates/renderer/src/images.rs index 6e6291e..65f85d5 100644 --- a/crates/renderer/src/images.rs +++ b/crates/renderer/src/images.rs @@ -154,6 +154,7 @@ impl ImageInner { pub struct Image { image: ImageInner, desc: ImageDesc, + #[allow(dead_code)] views: Mutex>, } @@ -529,6 +530,7 @@ impl ImageViewDesc { } } + #[allow(dead_code)] pub(crate) fn hash_eq_copy(&self) -> Self { let &Self { flags, @@ -630,6 +632,7 @@ impl PartialEq for ImageViewDesc { #[derive(Debug)] pub struct ImageView { view: DeviceObject, + #[allow(dead_code)] desc: ImageViewDesc, image: Arc, } @@ -673,6 +676,7 @@ pub const SUBRESOURCERANGE_COLOR_ALL: vk::ImageSubresourceRange = vk::ImageSubre }; // copilot generated from spec: +#[allow(dead_code)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum FormatClass { Bits8, diff --git a/crates/renderer/src/lib.rs b/crates/renderer/src/lib.rs index 91f905f..4a957e2 100644 --- a/crates/renderer/src/lib.rs +++ b/crates/renderer/src/lib.rs @@ -1,12 +1,11 @@ #![feature( - closure_lifetime_binder, negative_impls, map_try_insert, debug_closure_helpers, slice_partition_dedup )] -use std::{collections::HashMap, ffi::CStr, fmt::Debug, marker::PhantomData, sync::Arc}; +use std::{collections::HashMap, fmt::Debug, sync::Arc}; use raw_window_handle::{RawDisplayHandle, RawWindowHandle}; @@ -35,7 +34,7 @@ pub mod sync; mod text; pub mod util; -use device::{Device, DeviceOwned, DeviceQueueFamilies}; +use device::{Device, DeviceOwned}; mod texture { use std::{collections::BTreeMap, sync::Arc}; @@ -124,22 +123,6 @@ pub enum Error { pub type Result = core::result::Result; -struct VkNameList<'a> { - names: Vec<*const i8>, - _pd: PhantomData<&'a ()>, -} - -impl<'a> VkNameList<'a> { - fn from_strs(strs: &[&'a CStr]) -> Self { - let names = strs.iter().map(|str| str.as_ptr()).collect::>(); - - Self { - names, - _pd: PhantomData, - } - } -} - #[derive(Debug, Clone)] #[allow(dead_code)] struct DeviceExtension<'a> { @@ -147,13 +130,6 @@ struct DeviceExtension<'a> { version: u32, } -fn make_extention_properties(name: &CStr, version: u32) -> vk::ExtensionProperties { - vk::ExtensionProperties::default() - .spec_version(version) - .extension_name(name) - .unwrap() -} - /// returns true if lhs and rhs have the same name and lhs spec_version is less /// than or equal to rhs spec_version #[allow(dead_code)] @@ -548,7 +524,7 @@ impl PhysicalDeviceFeatures { } #[derive(Debug, Default)] -pub(crate) struct PhysicalDeviceProperties { +pub struct PhysicalDeviceProperties { /// Extensions supported by the device, as reported by `enumerate_device_extension_properties`. supported_extensions: Vec, /// Vulkan 1.0 properties. @@ -661,14 +637,6 @@ impl PhysicalDeviceProperties { } } -#[derive(Debug)] -pub struct PhysicalDevice { - pdev: vk::PhysicalDevice, - queue_families: DeviceQueueFamilies, - #[allow(dead_code)] - properties: PhysicalDeviceProperties, -} - pub(crate) use instance::DebugUtils; pub use instance::{DebugUtilsCreateInfo, Instance}; diff --git a/crates/renderer/src/queue.rs b/crates/renderer/src/queue.rs index 291f3c5..5afd33c 100644 --- a/crates/renderer/src/queue.rs +++ b/crates/renderer/src/queue.rs @@ -164,6 +164,9 @@ impl DeviceQueues { core::slice::from_ref(&self.graphics.family.index) } + /// # Safety + /// + /// The caller must ensure that the queues aren't already locked when calling this function. pub unsafe fn lock(&self) { core::mem::forget(( self.graphics.inner.lock.lock(), @@ -172,6 +175,9 @@ impl DeviceQueues { )); } + /// # Safety + /// + /// The caller must have acquired and have logical ownership of the lock on the queues. pub unsafe fn unlock(&self) { unsafe { self.graphics.inner.lock.force_unlock(); @@ -190,31 +196,29 @@ pub struct DeviceQueueInfos { impl DeviceQueueInfos { const PRIORITIES: [f32; 4] = [1.0, 1.0, 1.0, 1.0]; - pub fn into_create_infos(&self) -> Vec { + pub fn into_create_infos(&self) -> Vec> { let families = self.queue_family_indices(); - let create_infos = families + families .into_iter() .map(|(index, count)| { vk::DeviceQueueCreateInfo::default() .queue_family_index(index) .queue_priorities(&Self::PRIORITIES[..count as usize]) }) - .collect(); - - create_infos + .collect() } fn queue_family_indices(&self) -> HashMap { let mut families = HashMap::new(); families.insert(self.graphics.index, 1); - self.compute.map(|compute| { + if let Some(compute) = self.compute { *families.entry(compute.index).or_insert(0) += 1; - }); - self.transfer.map(|transfer| { + } + if let Some(transfer) = self.transfer { *families.entry(transfer.index).or_insert(0) += 1; - }); + } families } diff --git a/crates/renderer/src/swapchain.rs b/crates/renderer/src/swapchain.rs index f1030c9..387afec 100644 --- a/crates/renderer/src/swapchain.rs +++ b/crates/renderer/src/swapchain.rs @@ -209,6 +209,7 @@ impl Surface { Ok(()) } + #[allow(dead_code)] fn get_fallback_swapchain_configuration( &self, instance: &Instance, @@ -366,7 +367,7 @@ impl Swapchain { surface.validate_swapchain_configuration(&device.instance, &device.adapter, &mut config)?; let surface_caps = device .instance - .get_adapter_surface_capabilities(device.adapter.pdev, &surface)?; + .get_adapter_surface_capabilities(device.adapter.pdev, surface)?; let functor = device .device_extensions @@ -532,7 +533,7 @@ impl Swapchain { .await?; let idx = idx as usize; - let image = self.images[idx].clone(); + let image = self.images[idx]; 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()), @@ -638,7 +639,6 @@ impl Swapchain { Ok((swapchain, images)) } } -static SWAPCHAIN_COUNT: AtomicU64 = AtomicU64::new(0); #[derive(Debug)] #[must_use = "This struct represents an acquired image from the Swapchain and @@ -702,6 +702,7 @@ impl SwapchainFrame { } } +#[allow(dead_code)] fn current_extent_or_clamped( caps: &vk::SurfaceCapabilitiesKHR, fallback: vk::Extent2D, @@ -867,7 +868,7 @@ mod tests { #[test] fn async_swapchain_acquiring() { let (_dev, surface) = create_headless_vk().expect("init"); - let ctx = Arc::new(surface); + let _ctx = Arc::new(surface); // let (rx, handle) = ctx.clone().images(); // eprintln!("hello world!"); diff --git a/crates/renderer/src/sync.rs b/crates/renderer/src/sync.rs index 47fb841..6509384 100644 --- a/crates/renderer/src/sync.rs +++ b/crates/renderer/src/sync.rs @@ -246,7 +246,7 @@ impl Fence { } #[derive(Debug, Clone, Copy)] -enum SemaphoreType { +pub enum SemaphoreType { Binary, Timeline(u64), } diff --git a/crates/renderer/src/util.rs b/crates/renderer/src/util.rs index 9c34d0b..64e77ca 100644 --- a/crates/renderer/src/util.rs +++ b/crates/renderer/src/util.rs @@ -7,6 +7,7 @@ use ash::vk; use bytemuck::{Pod, Zeroable}; pub(crate) mod weak_vec { + #![allow(dead_code)] //! Module containing the [`WeakVec`] API. use std::{sync::Weak, vec::Vec};