fix egui ?
This commit is contained in:
parent
297b79d347
commit
b00b1b3151
|
|
@ -42,6 +42,7 @@ ash = "0.38.0"
|
||||||
ash-window = "0.13.0"
|
ash-window = "0.13.0"
|
||||||
vk-mem = "0.5.0"
|
vk-mem = "0.5.0"
|
||||||
gpu-allocator = { git = "https://github.com/janis-bhm/gpu-allocator", branch = "main" }
|
gpu-allocator = { git = "https://github.com/janis-bhm/gpu-allocator", branch = "main" }
|
||||||
|
rectangle-pack = "0.4.2"
|
||||||
vk-sync = "0.1.6"
|
vk-sync = "0.1.6"
|
||||||
|
|
||||||
arrayvec = "0.7.6"
|
arrayvec = "0.7.6"
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ ash = { workspace = true }
|
||||||
ash-window = { workspace = true }
|
ash-window = { workspace = true }
|
||||||
vk-mem = { workspace = true }
|
vk-mem = { workspace = true }
|
||||||
gpu-allocator = { workspace = true }
|
gpu-allocator = { workspace = true }
|
||||||
|
rectangle-pack = { workspace = true }
|
||||||
|
|
||||||
raw-window-handle = { workspace = true }
|
raw-window-handle = { workspace = true }
|
||||||
egui = { workspace = true , features = ["bytemuck"]}
|
egui = { workspace = true , features = ["bytemuck"]}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ use ash::{
|
||||||
};
|
};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use raw_window_handle::RawDisplayHandle;
|
use raw_window_handle::RawDisplayHandle;
|
||||||
use tinyvec::{ArrayVec, array_vec};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Instance, PhysicalDeviceFeatures, PhysicalDeviceInfo, Result,
|
Instance, PhysicalDeviceFeatures, PhysicalDeviceInfo, Result,
|
||||||
|
|
@ -22,62 +21,6 @@ use crate::{
|
||||||
sync::{self, BinarySemaphore, TimelineSemaphore},
|
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! {
|
bitflags::bitflags! {
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[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) debug_utils: ext::debug_utils::Device,
|
||||||
pub(crate) swapchain: Option<khr::swapchain::Device>,
|
pub(crate) swapchain: Option<khr::swapchain::Device>,
|
||||||
|
#[allow(dead_code)]
|
||||||
pub(crate) mesh_shader: Option<ext::mesh_shader::Device>,
|
pub(crate) mesh_shader: Option<ext::mesh_shader::Device>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,7 +75,7 @@ pub enum AllocationStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum Allocation {
|
pub enum Allocation {
|
||||||
Owned(DeviceObject<GpuAllocation>),
|
Owned(DeviceObject<GpuAllocation>),
|
||||||
Shared(Arc<DeviceObject<GpuAllocation>>),
|
Shared(Arc<DeviceObject<GpuAllocation>>),
|
||||||
Unmanaged,
|
Unmanaged,
|
||||||
|
|
@ -163,6 +107,7 @@ pub struct DeviceInner {
|
||||||
pub(crate) queues: DeviceQueues,
|
pub(crate) queues: DeviceQueues,
|
||||||
pub(crate) sync_threadpool: sync::SyncThreadpool,
|
pub(crate) sync_threadpool: sync::SyncThreadpool,
|
||||||
pub(crate) device_extensions: DeviceExtensions,
|
pub(crate) device_extensions: DeviceExtensions,
|
||||||
|
#[allow(dead_code)]
|
||||||
pub(crate) enabled_extensions: Vec<&'static CStr>,
|
pub(crate) enabled_extensions: Vec<&'static CStr>,
|
||||||
_drop: DeviceDrop,
|
_drop: DeviceDrop,
|
||||||
}
|
}
|
||||||
|
|
@ -550,7 +495,7 @@ impl DeviceInner {
|
||||||
pub fn features(&self) -> &crate::PhysicalDeviceFeatures {
|
pub fn features(&self) -> &crate::PhysicalDeviceFeatures {
|
||||||
&self.adapter.features
|
&self.adapter.features
|
||||||
}
|
}
|
||||||
pub fn properties(&self) -> &crate::PhysicalDeviceProperties {
|
pub(crate) fn properties(&self) -> &crate::PhysicalDeviceProperties {
|
||||||
&self.adapter.properties
|
&self.adapter.properties
|
||||||
}
|
}
|
||||||
pub fn physical_device(&self) -> &PhysicalDeviceInfo {
|
pub fn physical_device(&self) -> &PhysicalDeviceInfo {
|
||||||
|
|
@ -566,12 +511,18 @@ impl DeviceInner {
|
||||||
self.queues.transfer()
|
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) {
|
pub unsafe fn lock_queues(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.queues.lock();
|
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) {
|
pub unsafe fn unlock_queues(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.queues.unlock();
|
self.queues.unlock();
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
use std::{collections::BTreeMap, sync::Arc};
|
use std::{
|
||||||
|
collections::{BTreeMap, HashMap},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
use ash::vk;
|
use ash::vk;
|
||||||
use gpu_allocator::MemoryLocation;
|
use gpu_allocator::MemoryLocation;
|
||||||
|
|
@ -14,8 +17,7 @@ use crate::{
|
||||||
Access, Barrier, GraphResourceDesc, GraphResourceId, PassDesc, RecordFn, RenderContext,
|
Access, Barrier, GraphResourceDesc, GraphResourceId, PassDesc, RecordFn, RenderContext,
|
||||||
RenderGraph, buffer_barrier, image_barrier,
|
RenderGraph, buffer_barrier, image_barrier,
|
||||||
},
|
},
|
||||||
texture,
|
texture::{self, TextureId},
|
||||||
util::Rect2D,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn egui_pre_pass(
|
pub fn egui_pre_pass(
|
||||||
|
|
@ -32,15 +34,32 @@ pub fn egui_pre_pass(
|
||||||
return Ok(());
|
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
|
// 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
|
.textures_delta
|
||||||
.set
|
.set
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, image)| image.is_whole())
|
.map(|(egui_id, delta)| {
|
||||||
{
|
max_width = max_width.max(delta.image.width() as u32);
|
||||||
|
max_height = max_height.max(delta.image.height() as u32);
|
||||||
|
|
||||||
|
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:?}");
|
tracing::trace!("creating texture image for egui image {egui_id:?}");
|
||||||
let image = Image::new(
|
|
||||||
|
let Ok(image) = Image::new(
|
||||||
dev.clone(),
|
dev.clone(),
|
||||||
ImageDesc {
|
ImageDesc {
|
||||||
name: Some(format!("egui-texture-{egui_id:?}").into()),
|
name: Some(format!("egui-texture-{egui_id:?}").into()),
|
||||||
|
|
@ -55,45 +74,66 @@ pub fn egui_pre_pass(
|
||||||
alloc_scheme: AllocationStrategy::Dedicated,
|
alloc_scheme: AllocationStrategy::Dedicated,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
)?;
|
) else {
|
||||||
|
return Err(crate::Error::Todo(
|
||||||
let tid = textures.insert_image(Arc::new(image));
|
"handle image creation failure in egui pre-pass",
|
||||||
if let Some(old) = egui_state.textures.insert(
|
|
||||||
*egui_id,
|
|
||||||
crate::EguiTextureInfo {
|
|
||||||
id: tid,
|
|
||||||
options: delta.options,
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
textures.remove_texture(old.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 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,
|
||||||
|
) {
|
||||||
|
Ok(placements) => break placements,
|
||||||
|
Err(_) => {
|
||||||
|
max_width *= 2;
|
||||||
|
max_height *= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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!(
|
tracing::trace!(
|
||||||
staging_size,
|
"creating staging buffer {}x{} for uploading egui textures",
|
||||||
"creating staging buffer for uploading egui textures"
|
extent.0,
|
||||||
|
extent.1,
|
||||||
);
|
);
|
||||||
let mut staging_buffer = Buffer::new(
|
let mut staging_buffer = Buffer::new(
|
||||||
dev.clone(),
|
dev.clone(),
|
||||||
BufferDesc {
|
BufferDesc {
|
||||||
name: Some("egui-prepass-staging-buffer".into()),
|
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,
|
usage: vk::BufferUsageFlags::TRANSFER_SRC,
|
||||||
queue_families: device::QueueFlags::empty(),
|
queue_families: device::QueueFlags::empty(),
|
||||||
mem_location: MemoryLocation::CpuToGpu,
|
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 = Image::new(
|
||||||
let staging_image = Arc::new(Image::new(
|
|
||||||
dev.clone(),
|
dev.clone(),
|
||||||
ImageDesc {
|
ImageDesc {
|
||||||
name: Some("egui-prepass-staging-buffer".into()),
|
name: Some("egui-prepass-staging-buffer".into()),
|
||||||
format: vk::Format::R8G8B8A8_UNORM,
|
format: vk::Format::R8G8B8A8_UNORM,
|
||||||
extent: vk::Extent3D {
|
extent: vk::Extent3D {
|
||||||
width: image_size.x,
|
width: extent.0,
|
||||||
height: image_size.y,
|
height: extent.1,
|
||||||
depth: 1,
|
depth: 1,
|
||||||
},
|
},
|
||||||
usage: vk::ImageUsageFlags::TRANSFER_SRC | vk::ImageUsageFlags::TRANSFER_DST,
|
usage: vk::ImageUsageFlags::TRANSFER_SRC | vk::ImageUsageFlags::TRANSFER_DST,
|
||||||
|
|
@ -117,104 +156,90 @@ pub fn egui_pre_pass(
|
||||||
mem_location: MemoryLocation::GpuOnly,
|
mem_location: MemoryLocation::GpuOnly,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
)?);
|
)?;
|
||||||
|
|
||||||
let aliased_images = {
|
let staging_map = staging_buffer.map_mut().unwrap();
|
||||||
tracing::trace!("mmap-ing staging buffer");
|
|
||||||
let mut staging_map = staging_buffer.map().unwrap();
|
|
||||||
let mut offset = 0;
|
|
||||||
|
|
||||||
output
|
struct ImageUpdate {
|
||||||
.textures_delta
|
#[allow(dead_code)]
|
||||||
.set
|
id: TextureId,
|
||||||
.iter()
|
graph_id: GraphResourceId,
|
||||||
.map(|(id, delta)| {
|
dest_offset: (u32, u32),
|
||||||
let bytes =
|
src_offset: (u32, u32),
|
||||||
delta.image.height() * delta.image.width() * delta.image.bytes_per_pixel();
|
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 old_offset = offset;
|
let updates = updates
|
||||||
offset += bytes;
|
.into_iter()
|
||||||
|
.filter_map(|(id, (pos, image))| {
|
||||||
|
let (_, loc) = rect_placements.packed_locations().get(&id)?;
|
||||||
|
|
||||||
let pos = delta.pos.unwrap_or_default();
|
// copy scanlines from image data into staging buffer
|
||||||
let rect = Rect2D::new_from_size(
|
let rect_width = loc.width() as usize;
|
||||||
glam::ivec2(pos[0] as i32, pos[1] as i32),
|
let rect_height = loc.height() as usize;
|
||||||
glam::ivec2(delta.image.width() as i32, delta.image.height() as i32),
|
let rect_x = loc.x() as usize;
|
||||||
);
|
let rect_y = loc.y() as usize;
|
||||||
(*id, (old_offset, bytes, rect))
|
|
||||||
})
|
|
||||||
.collect::<BTreeMap<_, _>>()
|
|
||||||
|
|
||||||
// let tessellated = egui.tessellate(output.shapes, output.pixels_per_point);
|
let pixel_size = 4usize; // RGBA8
|
||||||
|
let atlas_width = extent.0 as usize;
|
||||||
|
|
||||||
|
let image_data = match image {
|
||||||
|
egui::ImageData::Color(color_image) => color_image.as_raw(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let textures = output
|
for (atlas_y, image_y) in (rect_y..rect_y + rect_height).enumerate() {
|
||||||
.textures_delta
|
let atlas_start = (image_y * atlas_width + rect_x) * pixel_size;
|
||||||
.set
|
let atlas_end = atlas_start + rect_width * pixel_size;
|
||||||
.iter()
|
|
||||||
.filter_map(|(egui_id, _)| {
|
let image_start = (atlas_y * rect_width) * pixel_size;
|
||||||
egui_state
|
let image_end = image_start + rect_width * pixel_size;
|
||||||
.lookup_texture(*egui_id)
|
staging_map[atlas_start..atlas_end]
|
||||||
.and_then(|tid| textures.get_texture(tid))
|
.copy_from_slice(&image_data[image_start..image_end]);
|
||||||
.map(|img| (*egui_id, img))
|
}
|
||||||
})
|
|
||||||
.map(|(id, img)| {
|
let graph_id = rg.import_image(
|
||||||
(
|
textures.get_texture(id)?,
|
||||||
id,
|
Access {
|
||||||
rg.import_image(
|
layout: vk::ImageLayout::GENERAL,
|
||||||
img,
|
..Access::undefined()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
Some(ImageUpdate {
|
||||||
|
id,
|
||||||
|
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 {
|
Access {
|
||||||
layout: vk::ImageLayout::GENERAL,
|
layout: vk::ImageLayout::GENERAL,
|
||||||
..Access::undefined()
|
..Access::undefined()
|
||||||
},
|
},
|
||||||
),
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<BTreeMap<_, _>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let staging_buffer = rg.import_buffer(Arc::new(staging_buffer), Access::undefined());
|
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 record = Box::new({
|
||||||
let textures = textures.clone();
|
// let textures = textures.clone();
|
||||||
move |ctx: &RenderContext| -> crate::Result<()> {
|
move |ctx: &RenderContext| -> crate::Result<()> {
|
||||||
let staging_image = ctx.get_image(staging_image).unwrap().clone();
|
let staging_image = ctx.get_image(staging_image).unwrap().clone();
|
||||||
let staging_buffer = ctx.get_buffer(staging_buffer).unwrap();
|
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 texture = textures.get(&id).and_then(|id| ctx.get_image(*id)).unwrap();
|
|
||||||
|
|
||||||
let image: Barrier = image_barrier(
|
let image: Barrier = image_barrier(
|
||||||
alias.raw(),
|
staging_image.raw(),
|
||||||
alias.format(),
|
staging_image.format(),
|
||||||
Access {
|
Access {
|
||||||
stage: vk::PipelineStageFlags2::NONE,
|
stage: vk::PipelineStageFlags2::NONE,
|
||||||
mask: vk::AccessFlags2::empty(),
|
mask: vk::AccessFlags2::empty(),
|
||||||
|
|
@ -237,25 +262,25 @@ pub fn egui_pre_pass(
|
||||||
|
|
||||||
ctx.cmd.copy_buffer_to_image(
|
ctx.cmd.copy_buffer_to_image(
|
||||||
staging_buffer.raw(),
|
staging_buffer.raw(),
|
||||||
alias.raw(),
|
staging_image.raw(),
|
||||||
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||||
&[vk::BufferImageCopy {
|
&[vk::BufferImageCopy {
|
||||||
buffer_offset: offset as u64,
|
buffer_offset: 0,
|
||||||
buffer_row_length: alias.width(),
|
buffer_row_length: staging_image.width(),
|
||||||
buffer_image_height: alias.height(),
|
buffer_image_height: staging_image.height(),
|
||||||
image_subresource: vk::ImageSubresourceLayers::default()
|
image_subresource: vk::ImageSubresourceLayers::default()
|
||||||
.aspect_mask(vk::ImageAspectFlags::COLOR)
|
.aspect_mask(vk::ImageAspectFlags::COLOR)
|
||||||
.base_array_layer(0)
|
.base_array_layer(0)
|
||||||
.mip_level(0)
|
.mip_level(0)
|
||||||
.layer_count(1),
|
.layer_count(1),
|
||||||
image_offset: vk::Offset3D { x: 0, y: 0, z: 0 },
|
image_offset: vk::Offset3D { x: 0, y: 0, z: 0 },
|
||||||
image_extent: alias.size(),
|
image_extent: staging_image.size(),
|
||||||
}],
|
}],
|
||||||
);
|
);
|
||||||
|
|
||||||
let from_barrier = image_barrier(
|
let from_barrier: Barrier = image_barrier(
|
||||||
alias.raw(),
|
staging_image.raw(),
|
||||||
alias.format(),
|
staging_image.format(),
|
||||||
Access {
|
Access {
|
||||||
stage: vk::PipelineStageFlags2::TRANSFER,
|
stage: vk::PipelineStageFlags2::TRANSFER,
|
||||||
mask: vk::AccessFlags2::TRANSFER_WRITE,
|
mask: vk::AccessFlags2::TRANSFER_WRITE,
|
||||||
|
|
@ -267,9 +292,26 @@ pub fn egui_pre_pass(
|
||||||
layout: vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
|
layout: vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
);
|
)
|
||||||
|
.into();
|
||||||
|
|
||||||
let to_barrier = image_barrier(
|
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.raw(),
|
||||||
texture.format(),
|
texture.format(),
|
||||||
Access {
|
Access {
|
||||||
|
|
@ -281,7 +323,7 @@ pub fn egui_pre_pass(
|
||||||
// overwritten, so the layout doesn't matter, and else
|
// overwritten, so the layout doesn't matter, and else
|
||||||
// the layout will be `GENERAL` because the texture was
|
// the layout will be `GENERAL` because the texture was
|
||||||
// previously written to.
|
// previously written to.
|
||||||
layout: if alias.size() == texture.size() {
|
layout: if staging_image.size() == texture.size() {
|
||||||
vk::ImageLayout::UNDEFINED
|
vk::ImageLayout::UNDEFINED
|
||||||
} else {
|
} else {
|
||||||
vk::ImageLayout::GENERAL
|
vk::ImageLayout::GENERAL
|
||||||
|
|
@ -293,17 +335,17 @@ pub fn egui_pre_pass(
|
||||||
layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
);
|
)
|
||||||
|
.into();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
ctx.device.dev().cmd_pipeline_barrier2(
|
ctx.device
|
||||||
ctx.cmd.buffer(),
|
.dev()
|
||||||
&vk::DependencyInfo::default()
|
.cmd_pipeline_barrier2(ctx.cmd.buffer(), &((&to_barrier).into()));
|
||||||
.image_memory_barriers(&[from_barrier, to_barrier]),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.cmd.copy_images(
|
ctx.cmd.copy_images(
|
||||||
alias.raw(),
|
staging_image.raw(),
|
||||||
vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
|
vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
|
||||||
texture.raw(),
|
texture.raw(),
|
||||||
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||||
|
|
@ -313,18 +355,26 @@ pub fn egui_pre_pass(
|
||||||
.base_array_layer(0)
|
.base_array_layer(0)
|
||||||
.mip_level(0)
|
.mip_level(0)
|
||||||
.layer_count(1),
|
.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()
|
dst_subresource: vk::ImageSubresourceLayers::default()
|
||||||
.aspect_mask(vk::ImageAspectFlags::COLOR)
|
.aspect_mask(vk::ImageAspectFlags::COLOR)
|
||||||
.base_array_layer(0)
|
.base_array_layer(0)
|
||||||
.mip_level(0)
|
.mip_level(0)
|
||||||
.layer_count(1),
|
.layer_count(1),
|
||||||
dst_offset: vk::Offset3D {
|
dst_offset: vk::Offset3D {
|
||||||
x: rect.top_left().x,
|
x: dest_offset.0 as i32,
|
||||||
y: rect.top_left().y,
|
y: dest_offset.1 as i32,
|
||||||
z: 0,
|
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()),
|
(staging_image, Access::undefined()),
|
||||||
]
|
]
|
||||||
.to_vec(),
|
.to_vec(),
|
||||||
writes: textures
|
writes,
|
||||||
.values()
|
|
||||||
.map(|id| {
|
|
||||||
(
|
|
||||||
*id,
|
|
||||||
Access {
|
|
||||||
layout: vk::ImageLayout::GENERAL,
|
|
||||||
..Access::undefined()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
record: Some(record),
|
record: Some(record),
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,7 @@ impl ImageInner {
|
||||||
pub struct Image {
|
pub struct Image {
|
||||||
image: ImageInner,
|
image: ImageInner,
|
||||||
desc: ImageDesc,
|
desc: ImageDesc,
|
||||||
|
#[allow(dead_code)]
|
||||||
views: Mutex<WeakVec<ImageView>>,
|
views: Mutex<WeakVec<ImageView>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -529,6 +530,7 @@ impl ImageViewDesc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub(crate) fn hash_eq_copy(&self) -> Self {
|
pub(crate) fn hash_eq_copy(&self) -> Self {
|
||||||
let &Self {
|
let &Self {
|
||||||
flags,
|
flags,
|
||||||
|
|
@ -630,6 +632,7 @@ impl PartialEq for ImageViewDesc {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ImageView {
|
pub struct ImageView {
|
||||||
view: DeviceObject<vk::ImageView>,
|
view: DeviceObject<vk::ImageView>,
|
||||||
|
#[allow(dead_code)]
|
||||||
desc: ImageViewDesc,
|
desc: ImageViewDesc,
|
||||||
image: Arc<Image>,
|
image: Arc<Image>,
|
||||||
}
|
}
|
||||||
|
|
@ -673,6 +676,7 @@ pub const SUBRESOURCERANGE_COLOR_ALL: vk::ImageSubresourceRange = vk::ImageSubre
|
||||||
};
|
};
|
||||||
|
|
||||||
// copilot generated from spec:
|
// copilot generated from spec:
|
||||||
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub enum FormatClass {
|
pub enum FormatClass {
|
||||||
Bits8,
|
Bits8,
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
#![feature(
|
#![feature(
|
||||||
closure_lifetime_binder,
|
|
||||||
negative_impls,
|
negative_impls,
|
||||||
map_try_insert,
|
map_try_insert,
|
||||||
debug_closure_helpers,
|
debug_closure_helpers,
|
||||||
slice_partition_dedup
|
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};
|
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
|
||||||
|
|
||||||
|
|
@ -35,7 +34,7 @@ pub mod sync;
|
||||||
mod text;
|
mod text;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
use device::{Device, DeviceOwned, DeviceQueueFamilies};
|
use device::{Device, DeviceOwned};
|
||||||
|
|
||||||
mod texture {
|
mod texture {
|
||||||
use std::{collections::BTreeMap, sync::Arc};
|
use std::{collections::BTreeMap, sync::Arc};
|
||||||
|
|
@ -124,22 +123,6 @@ pub enum Error {
|
||||||
|
|
||||||
pub type Result<T> = core::result::Result<T, 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)]
|
#[derive(Debug, Clone)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
struct DeviceExtension<'a> {
|
struct DeviceExtension<'a> {
|
||||||
|
|
@ -147,13 +130,6 @@ struct DeviceExtension<'a> {
|
||||||
version: u32,
|
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
|
/// returns true if lhs and rhs have the same name and lhs spec_version is less
|
||||||
/// than or equal to rhs spec_version
|
/// than or equal to rhs spec_version
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
@ -548,7 +524,7 @@ impl PhysicalDeviceFeatures {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub(crate) struct PhysicalDeviceProperties {
|
pub struct PhysicalDeviceProperties {
|
||||||
/// Extensions supported by the device, as reported by `enumerate_device_extension_properties`.
|
/// Extensions supported by the device, as reported by `enumerate_device_extension_properties`.
|
||||||
supported_extensions: Vec<vk::ExtensionProperties>,
|
supported_extensions: Vec<vk::ExtensionProperties>,
|
||||||
/// Vulkan 1.0 properties.
|
/// 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(crate) use instance::DebugUtils;
|
||||||
pub use instance::{DebugUtilsCreateInfo, Instance};
|
pub use instance::{DebugUtilsCreateInfo, Instance};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -164,6 +164,9 @@ impl DeviceQueues {
|
||||||
core::slice::from_ref(&self.graphics.family.index)
|
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) {
|
pub unsafe fn lock(&self) {
|
||||||
core::mem::forget((
|
core::mem::forget((
|
||||||
self.graphics.inner.lock.lock(),
|
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) {
|
pub unsafe fn unlock(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.graphics.inner.lock.force_unlock();
|
self.graphics.inner.lock.force_unlock();
|
||||||
|
|
@ -190,31 +196,29 @@ pub struct DeviceQueueInfos {
|
||||||
|
|
||||||
impl DeviceQueueInfos {
|
impl DeviceQueueInfos {
|
||||||
const PRIORITIES: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
|
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 families = self.queue_family_indices();
|
||||||
|
|
||||||
let create_infos = families
|
families
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(index, count)| {
|
.map(|(index, count)| {
|
||||||
vk::DeviceQueueCreateInfo::default()
|
vk::DeviceQueueCreateInfo::default()
|
||||||
.queue_family_index(index)
|
.queue_family_index(index)
|
||||||
.queue_priorities(&Self::PRIORITIES[..count as usize])
|
.queue_priorities(&Self::PRIORITIES[..count as usize])
|
||||||
})
|
})
|
||||||
.collect();
|
.collect()
|
||||||
|
|
||||||
create_infos
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn queue_family_indices(&self) -> HashMap<u32, u32> {
|
fn queue_family_indices(&self) -> HashMap<u32, u32> {
|
||||||
let mut families = HashMap::new();
|
let mut families = HashMap::new();
|
||||||
|
|
||||||
families.insert(self.graphics.index, 1);
|
families.insert(self.graphics.index, 1);
|
||||||
self.compute.map(|compute| {
|
if let Some(compute) = self.compute {
|
||||||
*families.entry(compute.index).or_insert(0) += 1;
|
*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.entry(transfer.index).or_insert(0) += 1;
|
||||||
});
|
}
|
||||||
|
|
||||||
families
|
families
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -209,6 +209,7 @@ impl Surface {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
fn get_fallback_swapchain_configuration(
|
fn get_fallback_swapchain_configuration(
|
||||||
&self,
|
&self,
|
||||||
instance: &Instance,
|
instance: &Instance,
|
||||||
|
|
@ -366,7 +367,7 @@ impl Swapchain {
|
||||||
surface.validate_swapchain_configuration(&device.instance, &device.adapter, &mut config)?;
|
surface.validate_swapchain_configuration(&device.instance, &device.adapter, &mut config)?;
|
||||||
let surface_caps = device
|
let surface_caps = device
|
||||||
.instance
|
.instance
|
||||||
.get_adapter_surface_capabilities(device.adapter.pdev, &surface)?;
|
.get_adapter_surface_capabilities(device.adapter.pdev, surface)?;
|
||||||
|
|
||||||
let functor = device
|
let functor = device
|
||||||
.device_extensions
|
.device_extensions
|
||||||
|
|
@ -532,7 +533,7 @@ impl Swapchain {
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let idx = idx as usize;
|
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 image = Arc::new(images::Image::from_swapchain_image(image, &self));
|
||||||
let view = image.create_view(ImageViewDesc {
|
let view = image.create_view(ImageViewDesc {
|
||||||
name: Some(format!("swapchain-{:x}-image-view-{idx}", self.raw().as_raw()).into()),
|
name: Some(format!("swapchain-{:x}-image-view-{idx}", self.raw().as_raw()).into()),
|
||||||
|
|
@ -638,7 +639,6 @@ impl Swapchain {
|
||||||
Ok((swapchain, images))
|
Ok((swapchain, images))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static SWAPCHAIN_COUNT: AtomicU64 = AtomicU64::new(0);
|
|
||||||
|
|
||||||
#[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
|
||||||
|
|
@ -702,6 +702,7 @@ impl SwapchainFrame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
fn current_extent_or_clamped(
|
fn current_extent_or_clamped(
|
||||||
caps: &vk::SurfaceCapabilitiesKHR,
|
caps: &vk::SurfaceCapabilitiesKHR,
|
||||||
fallback: vk::Extent2D,
|
fallback: vk::Extent2D,
|
||||||
|
|
@ -867,7 +868,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn async_swapchain_acquiring() {
|
fn async_swapchain_acquiring() {
|
||||||
let (_dev, surface) = create_headless_vk().expect("init");
|
let (_dev, surface) = create_headless_vk().expect("init");
|
||||||
let ctx = Arc::new(surface);
|
let _ctx = Arc::new(surface);
|
||||||
// let (rx, handle) = ctx.clone().images();
|
// let (rx, handle) = ctx.clone().images();
|
||||||
|
|
||||||
// eprintln!("hello world!");
|
// eprintln!("hello world!");
|
||||||
|
|
|
||||||
|
|
@ -246,7 +246,7 @@ impl Fence {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum SemaphoreType {
|
pub enum SemaphoreType {
|
||||||
Binary,
|
Binary,
|
||||||
Timeline(u64),
|
Timeline(u64),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ use ash::vk;
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
|
|
||||||
pub(crate) mod weak_vec {
|
pub(crate) mod weak_vec {
|
||||||
|
#![allow(dead_code)]
|
||||||
//! Module containing the [`WeakVec`] API.
|
//! Module containing the [`WeakVec`] API.
|
||||||
|
|
||||||
use std::{sync::Weak, vec::Vec};
|
use std::{sync::Weak, vec::Vec};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue