fix egui ?

This commit is contained in:
janis 2026-04-03 03:13:51 +02:00
parent 297b79d347
commit b00b1b3151
10 changed files with 297 additions and 327 deletions

View file

@ -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"

View file

@ -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"]}

View file

@ -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<khr::swapchain::Device>,
#[allow(dead_code)]
pub(crate) mesh_shader: Option<ext::mesh_shader::Device>,
}
@ -131,7 +75,7 @@ pub enum AllocationStrategy {
}
#[derive(Debug)]
pub(crate) enum Allocation {
pub enum Allocation {
Owned(DeviceObject<GpuAllocation>),
Shared(Arc<DeviceObject<GpuAllocation>>),
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();

View file

@ -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::<TextureId, ()>::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::<crate::Result<HashMap<_, _>>>()?;
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::<u8>(),
arc.pixels.len() * size_of::<egui::Color32>(),
)
};
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::<BTreeMap<_, _>>()
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::<Vec<_>>();
let writes = updates
.iter()
.map(|update| {
(
update.graph_id,
Access {
layout: vk::ImageLayout::GENERAL,
..Access::undefined()
},
)
})
.collect::<BTreeMap<_, _>>();
.collect::<Vec<_>>();
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(())

View file

@ -154,6 +154,7 @@ impl ImageInner {
pub struct Image {
image: ImageInner,
desc: ImageDesc,
#[allow(dead_code)]
views: Mutex<WeakVec<ImageView>>,
}
@ -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<vk::ImageView>,
#[allow(dead_code)]
desc: ImageViewDesc,
image: Arc<Image>,
}
@ -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,

View file

@ -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<T> = core::result::Result<T, Error>;
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::<Vec<_>>();
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<vk::ExtensionProperties>,
/// 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};

View file

@ -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<vk::DeviceQueueCreateInfo> {
pub fn into_create_infos(&self) -> Vec<vk::DeviceQueueCreateInfo<'_>> {
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<u32, u32> {
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
}

View file

@ -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!");

View file

@ -246,7 +246,7 @@ impl Fence {
}
#[derive(Debug, Clone, Copy)]
enum SemaphoreType {
pub enum SemaphoreType {
Binary,
Timeline(u64),
}

View file

@ -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};