fix egui ?
This commit is contained in:
parent
297b79d347
commit
b00b1b3151
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"]}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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!");
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ impl Fence {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum SemaphoreType {
|
||||
pub enum SemaphoreType {
|
||||
Binary,
|
||||
Timeline(u64),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
Loading…
Reference in a new issue