From f0fff72bce736c3b672f1c0e3761c1f562cdcd05 Mon Sep 17 00:00:00 2001 From: Janis Date: Sun, 29 Dec 2024 15:48:55 +0100 Subject: [PATCH] idek so much when i thought i was only doing egui integration egui cant draw yet, but textures are loaded/updated --- Cargo.toml | 6 +- crates/game/Cargo.toml | 1 + crates/game/src/main.rs | 58 +- crates/renderer/Cargo.toml | 2 +- crates/renderer/src/buffers.rs | 37 +- crates/renderer/src/commands.rs | 69 +- crates/renderer/src/device.rs | 314 ++++++++ crates/renderer/src/images.rs | 51 +- crates/renderer/src/lib.rs | 1099 +++++++++++---------------- crates/renderer/src/render_graph.rs | 5 +- crates/renderer/src/sync.rs | 53 +- crates/renderer/src/util.rs | 61 +- 12 files changed, 985 insertions(+), 771 deletions(-) create mode 100644 crates/renderer/src/device.rs diff --git a/Cargo.toml b/Cargo.toml index 22c0d38..8e02c17 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ anyhow = "1.0.89" ash = "0.38.0" ash-window = "0.13.0" glam = "0.29.0" -thiserror = "1.0.64" +thiserror = "2.0" tracing = "0.1.40" tracing-subscriber = "0.3.18" vk-mem = "0.4.0" @@ -28,5 +28,5 @@ rayon = "1.10" winit = {version = "0.30.5", features = ["rwh_06"]} raw-window-handle = "0.6" -egui = "0.30.0" -egui_winit_platform = "0.24.0" \ No newline at end of file +egui = "0.30" +egui_winit_platform = "0.25" \ No newline at end of file diff --git a/crates/game/Cargo.toml b/crates/game/Cargo.toml index b132a68..1b5c411 100644 --- a/crates/game/Cargo.toml +++ b/crates/game/Cargo.toml @@ -11,3 +11,4 @@ renderer = { path = "../renderer" } egui = { workspace = true } egui_winit_platform = { workspace = true } +egui_demo_lib = "0.30.0" diff --git a/crates/game/src/main.rs b/crates/game/src/main.rs index 9c14519..657730a 100644 --- a/crates/game/src/main.rs +++ b/crates/game/src/main.rs @@ -2,6 +2,7 @@ use std::collections::BTreeMap; use renderer::Renderer; use tracing::info; +use tracing_subscriber::EnvFilter; use winit::{ application::ApplicationHandler, dpi::{LogicalSize, PhysicalSize}, @@ -14,10 +15,7 @@ use winit::{ struct WindowState { window: Window, egui_platform: egui_winit_platform::Platform, -} - -struct EguiRenderState { - textures: BTreeMap, + demo_app: egui_demo_lib::DemoWindows, } struct WinitState { @@ -37,20 +35,13 @@ impl WinitState { window_attrs: WindowAttributes::default() .with_title(window_title) .with_resizable(true) - .with_inner_size(LogicalSize::new( - Self::BASE_WIDTH, - Self::BASE_HEIGHT, - )), + .with_inner_size(LogicalSize::new(Self::BASE_WIDTH, Self::BASE_HEIGHT)), // TODO: pass down this error and add some kind of error handling UI or dump renderer: Renderer::new(display.as_raw()).expect("renderer"), } } - fn handle_final_resize( - &mut self, - window_id: WindowId, - new_size: PhysicalSize, - ) { + fn handle_final_resize(&mut self, window_id: WindowId, new_size: PhysicalSize) { _ = (window_id, new_size); info!("TODO: implement resize events"); if let Some(ctx) = self.renderer.window_contexts.get_mut(&window_id) { @@ -71,21 +62,17 @@ impl WinitState { if let Some(window) = self.windows2.get_mut(&window_id) { // egui - window.egui_platform.begin_frame(); - let output = window.egui_platform.end_frame(Some(&window.window)); + window.egui_platform.begin_pass(); + window.demo_app.ui(&window.egui_platform.context()); + let output = window.egui_platform.end_pass(Some(&window.window)); - let _draw_data = window - .egui_platform - .context() - .tessellate(output.shapes, output.pixels_per_point); + self.renderer + .draw_egui(&window.egui_platform.context(), output); // rendering self.renderer - .debug_draw( - &window_id, - || { // window.window.pre_present_notify() - }, - ) + .debug_draw(&window_id, || { // window.window.pre_present_notify() + }) .expect("drawing"); window.window.request_redraw(); } @@ -98,10 +85,7 @@ impl WinitState { self.renderer.window_contexts.remove(&window_id); } - fn create_window( - &mut self, - event_loop: &winit::event_loop::ActiveEventLoop, - ) { + fn create_window(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) { let window = event_loop .create_window( self.window_attrs @@ -132,6 +116,7 @@ impl WinitState { window_id, WindowState { window, + demo_app: egui_demo_lib::DemoWindows::default(), egui_platform: egui_winit_platform::Platform::new( egui_winit_platform::PlatformDescriptor { physical_width: size.width, @@ -152,10 +137,7 @@ impl ApplicationHandler for WinitState { self.create_window(event_loop); } - fn about_to_wait( - &mut self, - event_loop: &winit::event_loop::ActiveEventLoop, - ) { + fn about_to_wait(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) { tracing::info!("winit::about_to_wait"); for (&window, &resize) in self.last_resize_events.clone().iter() { self.handle_final_resize(window, resize); @@ -192,9 +174,7 @@ impl ApplicationHandler for WinitState { event: winit::event::KeyEvent { physical_key: - winit::keyboard::PhysicalKey::Code( - winit::keyboard::KeyCode::KeyQ, - ), + winit::keyboard::PhysicalKey::Code(winit::keyboard::KeyCode::KeyQ), state: ElementState::Pressed, repeat: false, .. @@ -207,9 +187,7 @@ impl ApplicationHandler for WinitState { event: winit::event::KeyEvent { physical_key: - winit::keyboard::PhysicalKey::Code( - winit::keyboard::KeyCode::Space, - ), + winit::keyboard::PhysicalKey::Code(winit::keyboard::KeyCode::Space), state: ElementState::Pressed, repeat: false, .. @@ -247,7 +225,9 @@ impl ApplicationHandler for WinitState { } fn main() { - tracing_subscriber::fmt().init(); + let _ = tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env()) + .init(); let ev = EventLoop::new().unwrap(); ev.set_control_flow(winit::event_loop::ControlFlow::Poll); diff --git a/crates/renderer/Cargo.toml b/crates/renderer/Cargo.toml index 6d5da6d..a058c47 100644 --- a/crates/renderer/Cargo.toml +++ b/crates/renderer/Cargo.toml @@ -12,7 +12,7 @@ anyhow = "1.0.89" ash = "0.38.0" ash-window = "0.13.0" glam = "0.29.0" -thiserror = "1.0.64" +thiserror = {workspace = true} tracing = "0.1.40" tracing-subscriber = "0.3.18" vk-mem = "0.4.0" diff --git a/crates/renderer/src/buffers.rs b/crates/renderer/src/buffers.rs index 0e3e977..3f7e0cf 100644 --- a/crates/renderer/src/buffers.rs +++ b/crates/renderer/src/buffers.rs @@ -1,4 +1,7 @@ -use std::{ops::Deref, sync::Arc}; +use std::{ + ops::{Deref, DerefMut}, + sync::Arc, +}; use ash::{prelude::VkResult, vk}; use vk_mem::Alloc; @@ -33,14 +36,15 @@ impl Buffer { alloc_flags: vk_mem::AllocationCreateFlags, ) -> VkResult> { let sharing_mode = if queue_families.len() > 1 { - vk::SharingMode::EXCLUSIVE - } else { vk::SharingMode::CONCURRENT + } else { + vk::SharingMode::EXCLUSIVE }; let (buffer, allocation) = unsafe { device.alloc().create_buffer( &vk::BufferCreateInfo::default() + .size(size as u64) .usage(usage) .queue_family_indices(queue_families) .sharing_mode(sharing_mode), @@ -66,17 +70,32 @@ impl Buffer { pub fn map(&mut self) -> VkResult> { let bytes = unsafe { let data = self.device.alloc().map_memory(&mut self.allocation)?; - let slice = core::slice::from_raw_parts(data, self.size as usize); + let slice = core::slice::from_raw_parts_mut(data, self.size as usize); slice }; - Ok(MappedBuffer { bytes }) + Ok(MappedBuffer { inner: self, bytes }) + } + pub fn buffer(&self) -> vk::Buffer { + self.buffer } } pub struct MappedBuffer<'a> { - bytes: &'a [u8], + bytes: &'a mut [u8], + inner: &'a mut Buffer, +} + +impl Drop for MappedBuffer<'_> { + fn drop(&mut self) { + unsafe { + self.inner + .device + .alloc() + .unmap_memory(&mut self.inner.allocation); + } + } } impl Deref for MappedBuffer<'_> { @@ -86,3 +105,9 @@ impl Deref for MappedBuffer<'_> { self.bytes } } + +impl DerefMut for MappedBuffer<'_> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.bytes + } +} diff --git a/crates/renderer/src/commands.rs b/crates/renderer/src/commands.rs index 819a271..cf9f6e7 100644 --- a/crates/renderer/src/commands.rs +++ b/crates/renderer/src/commands.rs @@ -4,7 +4,7 @@ use crate::{ buffers::Buffer, images::{Image2D, QueueOwnership}, sync::{self, FenceFuture}, - util::{FormatExt, MutexExt}, + util::{self, FormatExt, MutexExt}, }; use super::{Device, Queue}; @@ -33,8 +33,7 @@ impl SingleUseCommandPool { .queue_family_index(queue.family()) .flags(vk::CommandPoolCreateFlags::TRANSIENT); - let pool = - unsafe { device.dev().create_command_pool(&pool_info, None)? }; + let pool = unsafe { device.dev().create_command_pool(&pool_info, None)? }; Ok(Arc::new(Self { device, @@ -68,18 +67,15 @@ impl !Sync for SingleUseCommand {} impl Drop for SingleUseCommand { fn drop(&mut self) { unsafe { - self.pool.pool.with_locked(|&pool| { - self.device.dev().free_command_buffers(pool, &[self.buffer]) - }) + self.pool + .pool + .with_locked(|&pool| self.device.dev().free_command_buffers(pool, &[self.buffer])) }; } } impl SingleUseCommand { - pub fn new( - device: Device, - pool: Arc, - ) -> VkResult { + pub fn new(device: Device, pool: Arc) -> VkResult { let buffer = unsafe { let alloc_info = vk::CommandBufferAllocateInfo::default() .command_buffer_count(1) @@ -154,6 +150,52 @@ impl SingleUseCommand { } } + pub fn blit_images( + &self, + src: &Image2D, + src_region: util::Rect2D, + dst: &Image2D, + dst_region: util::Rect2D, + ) { + unsafe { + self.device.dev().cmd_blit_image( + self.buffer, + src.image(), + vk::ImageLayout::TRANSFER_SRC_OPTIMAL, + dst.image(), + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + &[vk::ImageBlit::default() + .src_subresource( + vk::ImageSubresourceLayers::default() + .aspect_mask(vk::ImageAspectFlags::COLOR) + .layer_count(1), + ) + .dst_subresource( + vk::ImageSubresourceLayers::default() + .aspect_mask(vk::ImageAspectFlags::COLOR) + .layer_count(1), + ) + .src_offsets(src_region.into_offsets_3d()) + .dst_offsets(dst_region.into_offsets_3d())], + vk::Filter::LINEAR, + ); + } + } + + pub fn copy_buffer_to_image( + &self, + buffer: vk::Buffer, + image: vk::Image, + layout: vk::ImageLayout, + regions: &[vk::BufferImageCopy], + ) { + unsafe { + self.device + .dev() + .cmd_copy_buffer_to_image(self.buffer, buffer, image, layout, regions); + } + } + pub fn clear_color_image( &self, image: vk::Image, @@ -194,15 +236,12 @@ impl SingleUseCommand { unsafe { self.device.dev().end_command_buffer(self.buffer)? }; let buffers = [self.buffer]; - let mut submit_info = - vk::SubmitInfo::default().command_buffers(&buffers); + let mut submit_info = vk::SubmitInfo::default().command_buffers(&buffers); if let Some(semaphore) = signal.as_ref() { // SAFETY: T and [T;1] have the same layout submit_info = submit_info.signal_semaphores(unsafe { - core::mem::transmute::<&vk::Semaphore, &[vk::Semaphore; 1]>( - semaphore, - ) + core::mem::transmute::<&vk::Semaphore, &[vk::Semaphore; 1]>(semaphore) }); } if let Some((semaphore, stage)) = wait.as_ref() { diff --git a/crates/renderer/src/device.rs b/crates/renderer/src/device.rs new file mode 100644 index 0000000..85b7d91 --- /dev/null +++ b/crates/renderer/src/device.rs @@ -0,0 +1,314 @@ +use std::{borrow::Cow, collections::BTreeMap, ops::Deref, sync::Arc}; + +use ash::{khr, prelude::VkResult, vk}; +use parking_lot::Mutex; +use tinyvec::{array_vec, ArrayVec}; + +use crate::{sync, Instance, PhysicalDevice, Queue}; + +#[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), +} + +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 + } +} + +#[repr(transparent)] +struct DeviceWrapper(ash::Device); + +impl Deref for DeviceWrapper { + type Target = ash::Device; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Drop for DeviceWrapper { + fn drop(&mut self) { + unsafe { + _ = self.0.device_wait_idle(); + self.0.destroy_device(None); + } + } +} + +pub struct DeviceInner { + alloc: vk_mem::Allocator, + device: DeviceWrapper, + physical: PhysicalDevice, + instance: Arc, + swapchain: khr::swapchain::Device, + debug_utils: ash::ext::debug_utils::Device, + allocated_queues: BTreeMap<(u32, u32), Queue>, + // these are resident in allocated_queues, and may in fact be clones of each + // other, for ease of access + main_queue: Queue, + compute_queue: Queue, + transfer_queue: Queue, + present_queue: Queue, + sync_threadpool: sync::SyncThreadpool, +} + +impl core::fmt::Debug for DeviceInner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("DeviceInner") + .field("device", &self.device.handle()) + .finish() + } +} + +#[derive(Clone, Debug)] +pub struct Device(Arc); +pub type WeakDevice = std::sync::Weak; + +impl Device { + pub fn new( + instance: Arc, + physical: PhysicalDevice, + mut features: crate::PhysicalDeviceFeatures, + ) -> VkResult { + // we have 4 queues at most: graphics, compute, transfer, present + let priorities = [1.0f32; 4]; + + let queue_infos = physical + .queue_families + .families + .iter() + .map(|&(family, queues)| { + vk::DeviceQueueCreateInfo::default() + .queue_family_index(family) + .queue_priorities(&priorities[..queues as usize]) + }) + .collect::>(); + + let extensions = features + .device_extensions + .iter() + .map(|ext| ext.extension_name.as_ptr()) + .collect::>(); + + let mut features2 = features.features2(); + let device_info = vk::DeviceCreateInfo::default() + .queue_create_infos(&queue_infos) + .enabled_extension_names(&extensions) + .push_next(&mut features2); + + let device = unsafe { + let device = instance + .instance + .create_device(physical.pdev, &device_info, None)?; + + let allocated_queues = queue_infos + .iter() + .flat_map(|info| { + (0..info.queue_count).map(|i| { + ( + (info.queue_family_index, i), + Queue::new(&device, info.queue_family_index, i), + ) + }) + }) + .collect::>(); + + let get_queue = + |(family, index)| allocated_queues.get(&(family, index)).cloned().unwrap(); + + let main_queue = get_queue(physical.queue_families.graphics); + let present_queue = get_queue(physical.queue_families.present); + let compute_queue = get_queue(physical.queue_families.async_compute); + let transfer_queue = get_queue(physical.queue_families.transfer); + + let alloc_info = + vk_mem::AllocatorCreateInfo::new(&instance.instance, &device, physical.pdev); + + let alloc = unsafe { vk_mem::Allocator::new(alloc_info)? }; + + DeviceInner { + device: DeviceWrapper(device.clone()), + physical, + swapchain: khr::swapchain::Device::new(&instance.instance, &device), + debug_utils: ash::ext::debug_utils::Device::new(&instance.instance, &device), + instance, + alloc, + allocated_queues, + main_queue, + present_queue, + compute_queue, + transfer_queue, + sync_threadpool: sync::SyncThreadpool::new(), + } + }; + + Ok(Self(Arc::new(device))) + } + pub fn sync_threadpool(&self) -> &sync::SyncThreadpool { + &self.0.sync_threadpool + } + pub fn weak(&self) -> WeakDevice { + Arc::downgrade(&self.0) + } + pub fn alloc(&self) -> &vk_mem::Allocator { + &self.0.alloc + } + pub fn dev(&self) -> &ash::Device { + &self.0.device + } + pub fn swapchain(&self) -> &khr::swapchain::Device { + &self.0.swapchain + } + pub fn debug_utils(&self) -> &ash::ext::debug_utils::Device { + &self.0.debug_utils + } + pub fn queue_families(&self) -> &DeviceQueueFamilies { + &self.0.physical.queue_families + } + pub fn phy(&self) -> vk::PhysicalDevice { + self.0.physical.pdev + } + pub fn graphics_queue(&self) -> &Queue { + &self.0.main_queue + } + pub fn present_queue(&self) -> &Queue { + &self.0.present_queue + } + + pub unsafe fn lock_queues(&self) { + // this is obviously awful, allocating for this + self.0 + .allocated_queues + .values() + .for_each(|q| core::mem::forget(q.lock())); + } + + pub unsafe fn unlock_queues(&self) { + self.0 + .allocated_queues + .values() + .for_each(|q| unsafe { q.0.force_unlock() }); + } + + pub fn wait_queue_idle(&self, queue: &Queue) -> VkResult<()> { + tracing::warn!("locking queue {queue:?} and waiting for idle"); + + queue.with_locked(|q| unsafe { self.dev().queue_wait_idle(q) })?; + + tracing::warn!("finished waiting: unlocking queue {queue:?}."); + Ok(()) + } + + pub fn wait_idle(&self) -> VkResult<()> { + tracing::warn!("locking all queues and waiting for device to idle"); + unsafe { + self.lock_queues(); + self.dev().device_wait_idle()?; + self.unlock_queues(); + } + tracing::warn!("finished waiting: unlocking all queues."); + Ok(()) + } +} + +impl AsRef for Device { + fn as_ref(&self) -> &khr::swapchain::Device { + &self.0.swapchain + } +} + +impl AsRef for Device { + fn as_ref(&self) -> &ash::Device { + &self.0.device + } +} + +pub struct DeviceAndQueues { + pub(crate) device: Device, + pub(crate) main_queue: Queue, + pub(crate) compute_queue: Queue, + pub(crate) transfer_queue: Queue, + pub(crate) present_queue: Queue, +} + +impl AsRef for DeviceAndQueues { + fn as_ref(&self) -> &ash::Device { + &self.device.as_ref() + } +} +impl AsRef for DeviceAndQueues { + fn as_ref(&self) -> &ash::khr::swapchain::Device { + &self.device.as_ref() + } +} + +#[derive(Clone)] +pub struct DeviceOwnedDebugObject { + device: Device, + object: T, + name: Option>, +} + +impl DeviceOwnedDebugObject { + fn new>>( + device: crate::Device, + object: T, + name: Option, + ) -> ash::prelude::VkResult + where + T: vk::Handle + Copy, + { + let name = name.map(Into::>::into); + if let Some(name) = name.as_ref() { + let name = + std::ffi::CString::new(name.as_bytes()).unwrap_or(c"invalid name".to_owned()); + unsafe { + device.debug_utils().set_debug_utils_object_name( + &vk::DebugUtilsObjectNameInfoEXT::default() + .object_handle(object) + .object_name(&name), + )?; + } + } + + Ok(Self { + device, + object, + name, + }) + } + + pub fn dev(&self) -> &crate::Device { + &self.device + } + pub fn handle(&self) -> T + where + T: Copy, + { + self.object + } +} diff --git a/crates/renderer/src/images.rs b/crates/renderer/src/images.rs index d50c37d..0bc643d 100644 --- a/crates/renderer/src/images.rs +++ b/crates/renderer/src/images.rs @@ -6,6 +6,7 @@ use super::{Device, Queue}; use ash::{prelude::*, vk}; use vk_mem::Alloc; +#[derive(Debug)] pub struct Image2D { device: Device, size: vk::Extent2D, @@ -13,10 +14,12 @@ pub struct Image2D { format: vk::Format, image: vk::Image, allocation: vk_mem::Allocation, + name: Option, } impl Drop for Image2D { fn drop(&mut self) { + tracing::debug!("destroying image {:?}", self); unsafe { self.device .alloc() @@ -36,6 +39,7 @@ impl Image2D { usage: vk::ImageUsageFlags, memory_usage: vk_mem::MemoryUsage, alloc_flags: vk_mem::AllocationCreateFlags, + name: Option<&str>, ) -> VkResult> { let create_info = vk::ImageCreateInfo::default() .array_layers(array_layers) @@ -62,6 +66,19 @@ impl Image2D { let (image, allocation) = unsafe { device.alloc().create_image(&create_info, &alloc_info)? }; + if let Some(name) = name { + let info = device.alloc().get_allocation_info(&allocation); + + let name = std::ffi::CString::new(name).unwrap_or(c"invalid name".to_owned()); + unsafe { + device.debug_utils().set_debug_utils_object_name( + &vk::DebugUtilsObjectNameInfoEXT::default() + .object_handle(info.device_memory) + .object_name(&name), + )?; + } + } + Ok(Arc::new(Self { size: extent, mip_levels, @@ -69,6 +86,7 @@ impl Image2D { device: device.clone(), image, allocation, + name: name.map(|s| s.to_owned()), })) } @@ -76,12 +94,6 @@ impl Image2D { self.format } - pub fn copy_from_buffer(&self, buffer: &Buffer) { - unsafe { - // self.device.dev().cmd_copy_buffer_to_image(command_buffer, src_buffer, dst_image, dst_image_layout, regions); - } - } - pub fn view( self: &Arc, device: &Device, @@ -101,8 +113,7 @@ impl Image2D { .layer_count(1), ); - let view = - unsafe { device.dev().create_image_view(&create_info, None)? }; + let view = unsafe { device.dev().create_image_view(&create_info, None)? }; Ok(Arc::new(ImageView2D { view, @@ -114,6 +125,15 @@ impl Image2D { pub fn image(&self) -> vk::Image { self.image } + pub fn size(&self) -> vk::Extent2D { + self.size + } + pub fn width(&self) -> u32 { + self.size.width + } + pub fn height(&self) -> u32 { + self.size.height + } } pub struct ImageView2D { @@ -172,11 +192,10 @@ pub fn image_barrier<'a>( .new_layout(new_layout) } -pub const SUBRESOURCERANGE_COLOR_ALL: vk::ImageSubresourceRange = - vk::ImageSubresourceRange { - aspect_mask: vk::ImageAspectFlags::COLOR, - base_mip_level: 0, - level_count: vk::REMAINING_MIP_LEVELS, - base_array_layer: 0, - layer_count: vk::REMAINING_ARRAY_LAYERS, - }; +pub const SUBRESOURCERANGE_COLOR_ALL: vk::ImageSubresourceRange = vk::ImageSubresourceRange { + aspect_mask: vk::ImageAspectFlags::COLOR, + base_mip_level: 0, + level_count: vk::REMAINING_MIP_LEVELS, + base_array_layer: 0, + layer_count: vk::REMAINING_ARRAY_LAYERS, +}; diff --git a/crates/renderer/src/lib.rs b/crates/renderer/src/lib.rs index 186171b..79b9503 100644 --- a/crates/renderer/src/lib.rs +++ b/crates/renderer/src/lib.rs @@ -19,6 +19,7 @@ use std::{ }, }; +use egui::Color32; use parking_lot::{Mutex, MutexGuard, RwLock}; use ash::{ @@ -35,11 +36,36 @@ use tracing::info; mod buffers; mod commands; +mod device; mod images; mod render_graph; mod sync; mod util; +use device::{Device, DeviceAndQueues, DeviceQueueFamilies, WeakDevice}; + +mod texture { + use std::{collections::BTreeMap, sync::Arc}; + + use crate::{def_monotonic_id, images::Image2D, Device}; + + def_monotonic_id!(TextureId); + + pub struct TextureManager { + pub textures: BTreeMap>, + dev: Device, + } + + impl TextureManager { + pub fn new(dev: Device) -> Self { + Self { + dev, + textures: BTreeMap::new(), + } + } + } +} + use render_graph::Rgba; #[derive(Debug, thiserror::Error)] @@ -82,10 +108,7 @@ struct DeviceExtension<'a> { version: u32, } -fn make_extention_properties( - name: &CStr, - version: u32, -) -> vk::ExtensionProperties { +fn make_extention_properties(name: &CStr, version: u32) -> vk::ExtensionProperties { vk::ExtensionProperties::default() .spec_version(version) .extension_name(name) @@ -139,22 +162,15 @@ impl Queue { } } -trait ExtendsDeviceFeatures2Debug: - vk::ExtendsPhysicalDeviceFeatures2 + Debug -{ -} +trait ExtendsDeviceFeatures2Debug: vk::ExtendsPhysicalDeviceFeatures2 + Debug {} trait ExtendsDeviceProperties2Debug: vk::ExtendsPhysicalDeviceProperties2 + Debug + DynClone + Send + Sync { } -impl ExtendsDeviceFeatures2Debug - for T -{ -} -impl< - T: vk::ExtendsPhysicalDeviceProperties2 + Debug + DynClone + Send + Sync, - > ExtendsDeviceProperties2Debug for T +impl ExtendsDeviceFeatures2Debug for T {} +impl + ExtendsDeviceProperties2Debug for T { } @@ -180,10 +196,7 @@ impl PhysicalDeviceFeatures { .features13(Default::default()) } - fn query( - instance: &ash::Instance, - pdev: vk::PhysicalDevice, - ) -> Result { + fn query(instance: &ash::Instance, pdev: vk::PhysicalDevice) -> Result { let mut this = Self::all_default(); let mut features2 = this.features2(); let features = unsafe { @@ -193,53 +206,37 @@ impl PhysicalDeviceFeatures { }; this = this.features10(features); - let extensions = - unsafe { instance.enumerate_device_extension_properties(pdev)? }; + let extensions = unsafe { instance.enumerate_device_extension_properties(pdev)? }; this = this.device_extensions(extensions); Ok(this) } - fn features10( - self, - physical_features_10: vk::PhysicalDeviceFeatures, - ) -> Self { + fn features10(self, physical_features_10: vk::PhysicalDeviceFeatures) -> Self { Self { physical_features_10, ..self } } - fn features11( - self, - physical_features_11: vk::PhysicalDeviceVulkan11Features<'static>, - ) -> Self { + fn features11(self, physical_features_11: vk::PhysicalDeviceVulkan11Features<'static>) -> Self { Self { physical_features_11: Some(physical_features_11), ..self } } - fn features12( - self, - physical_features_12: vk::PhysicalDeviceVulkan12Features<'static>, - ) -> Self { + fn features12(self, physical_features_12: vk::PhysicalDeviceVulkan12Features<'static>) -> Self { Self { physical_features_12: Some(physical_features_12), ..self } } - fn features13( - self, - physical_features_13: vk::PhysicalDeviceVulkan13Features<'static>, - ) -> Self { + fn features13(self, physical_features_13: vk::PhysicalDeviceVulkan13Features<'static>) -> Self { Self { physical_features_13: Some(physical_features_13), ..self } } - fn device_extensions( - self, - device_extensions: Vec, - ) -> Self { + fn device_extensions(self, device_extensions: Vec) -> Self { Self { device_extensions, ..self @@ -261,11 +258,7 @@ impl PhysicalDeviceFeatures { self } - fn with_extension( - mut self, - ext: vk::ExtensionProperties, - features: F, - ) -> Self + fn with_extension(mut self, ext: vk::ExtensionProperties, features: F) -> Self where F: ExtendsDeviceFeatures2Debug + 'static, { @@ -276,8 +269,8 @@ impl PhysicalDeviceFeatures { } fn features2(&mut self) -> vk::PhysicalDeviceFeatures2<'_> { - let mut features2 = vk::PhysicalDeviceFeatures2::default() - .features(self.physical_features_10); + let mut features2 = + vk::PhysicalDeviceFeatures2::default().features(self.physical_features_10); if let Some(ref mut features11) = self.physical_features_11 { features2 = features2.push_next(features11); @@ -297,8 +290,7 @@ impl PhysicalDeviceFeatures { } fn compatible_with(&self, device: &Self) -> bool { - let sort_exts = |a: &vk::ExtensionProperties, - b: &vk::ExtensionProperties| { + let sort_exts = |a: &vk::ExtensionProperties, b: &vk::ExtensionProperties| { (a.extension_name_as_c_str().unwrap(), a.spec_version) .cmp(&(b.extension_name_as_c_str().unwrap(), b.spec_version)) }; @@ -330,30 +322,21 @@ impl PhysicalDeviceFeatures { .physical_features_11 .zip(device.physical_features_11) .map(|(a, b)| { - utils::eq_device_features11( - &utils::bitand_device_features11(&a, &b), - &a, - ) + utils::eq_device_features11(&utils::bitand_device_features11(&a, &b), &a) }) .unwrap_or(true) && self .physical_features_12 .zip(device.physical_features_12) .map(|(a, b)| { - utils::eq_device_features12( - &utils::bitand_device_features12(&a, &b), - &a, - ) + utils::eq_device_features12(&utils::bitand_device_features12(&a, &b), &a) }) .unwrap_or(true) && self .physical_features_13 .zip(device.physical_features_13) .map(|(a, b)| { - utils::eq_device_features13( - &utils::bitand_device_features13(&a, &b), - &a, - ) + utils::eq_device_features13(&utils::bitand_device_features13(&a, &b), &a) }) .unwrap_or(true) } @@ -427,10 +410,8 @@ struct Instance { impl Drop for Instance { fn drop(&mut self) { unsafe { - self.debug_utils.destroy_debug_utils_messenger( - self.debug_utils_messenger, - None, - ); + self.debug_utils + .destroy_debug_utils_messenger(self.debug_utils_messenger, None); } } } @@ -446,169 +427,6 @@ impl AsRef for Instance { } } -#[derive(Debug, Default)] -struct DeviceQueueFamilies { - families: Vec<(u32, u32)>, - graphics: (u32, u32), - present: Option<(u32, u32)>, - async_compute: Option<(u32, u32)>, - transfer: Option<(u32, u32)>, -} - -impl DeviceQueueFamilies { - fn swapchain_family_indices(&self) -> ArrayVec<[u32; 2]> { - let mut indices = array_vec!([u32; 2] => self.graphics.0); - - if let Some(present) = self.present - && present.0 != self.graphics.0 - { - indices.push(present.0); - } - - indices - } -} - -struct DeviceInner { - instance: Arc, - physical: PhysicalDevice, - alloc: vk_mem::Allocator, - device: ash::Device, - swapchain: khr::swapchain::Device, - debug_utils: ash::ext::debug_utils::Device, - allocated_queues: BTreeMap<(u32, u32), Queue>, - // these are resident in allocated_queues, and may in fact be clones of each - // other, for ease of access - main_queue: Queue, - compute_queue: Queue, - transfer_queue: Queue, - present_queue: Queue, - sync_threadpool: sync::SyncThreadpool, -} - -impl core::fmt::Debug for DeviceInner { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("DeviceInner") - .field("device", &self.device.handle()) - .finish() - } -} - -#[derive(Clone, Debug)] -pub struct Device(Arc); -pub type WeakDevice = std::sync::Weak; - -impl Device { - fn new(inner: DeviceInner) -> Self { - Self(Arc::new(inner)) - } - fn sync_threadpool(&self) -> &sync::SyncThreadpool { - &self.0.sync_threadpool - } - fn weak(&self) -> WeakDevice { - Arc::downgrade(&self.0) - } - fn alloc(&self) -> &vk_mem::Allocator { - &self.0.alloc - } - fn dev(&self) -> &ash::Device { - &self.0.device - } - fn swapchain(&self) -> &khr::swapchain::Device { - &self.0.swapchain - } - fn debug_utils(&self) -> &ash::ext::debug_utils::Device { - &self.0.debug_utils - } - fn queue_families(&self) -> &DeviceQueueFamilies { - &self.0.physical.queue_families - } - fn phy(&self) -> vk::PhysicalDevice { - self.0.physical.pdev - } - fn graphics_queue(&self) -> &Queue { - &self.0.main_queue - } - fn present_queue(&self) -> &Queue { - &self.0.present_queue - } - - unsafe fn lock_queues(&self) { - // this is obviously awful, allocating for this - self.0 - .allocated_queues - .values() - .for_each(|q| core::mem::forget(q.lock())); - } - - unsafe fn unlock_queues(&self) { - self.0 - .allocated_queues - .values() - .for_each(|q| unsafe { q.0.force_unlock() }); - } - - fn wait_queue_idle(&self, queue: &Queue) -> VkResult<()> { - tracing::warn!("locking queue {queue:?} and waiting for idle"); - - queue.with_locked(|q| unsafe { self.dev().queue_wait_idle(q) })?; - - tracing::warn!("finished waiting: unlocking queue {queue:?}."); - Ok(()) - } - - fn wait_idle(&self) -> VkResult<()> { - tracing::warn!("locking all queues and waiting for device to idle"); - unsafe { - self.lock_queues(); - self.dev().device_wait_idle()?; - self.unlock_queues(); - } - tracing::warn!("finished waiting: unlocking all queues."); - Ok(()) - } -} - -impl AsRef for Device { - fn as_ref(&self) -> &khr::swapchain::Device { - &self.0.swapchain - } -} - -impl AsRef for Device { - fn as_ref(&self) -> &ash::Device { - &self.0.device - } -} - -impl Drop for DeviceInner { - fn drop(&mut self) { - unsafe { - _ = self.device.device_wait_idle(); - self.device.destroy_device(None); - } - } -} - -struct DeviceAndQueues { - device: Device, - main_queue: Queue, - compute_queue: Queue, - transfer_queue: Queue, - present_queue: Queue, -} - -impl AsRef for DeviceAndQueues { - fn as_ref(&self) -> &ash::Device { - &self.device.as_ref() - } -} -impl AsRef for DeviceAndQueues { - fn as_ref(&self) -> &ash::khr::swapchain::Device { - &self.device.as_ref() - } -} - struct RawSwapchain(vk::SwapchainKHR); impl !Sync for RawSwapchain {} @@ -692,14 +510,12 @@ fn current_extent_or_clamped( ) -> vk::Extent2D { if caps.current_extent.width == u32::MAX { vk::Extent2D { - width: fallback.width.clamp( - caps.min_image_extent.width, - caps.max_image_extent.width, - ), - height: fallback.height.clamp( - caps.min_image_extent.height, - caps.max_image_extent.height, - ), + width: fallback + .width + .clamp(caps.min_image_extent.width, caps.max_image_extent.width), + height: fallback + .height + .clamp(caps.min_image_extent.height, caps.max_image_extent.height), } } else { caps.current_extent @@ -771,8 +587,7 @@ impl Swapchain { .max_by_key(|&&format| { let is_rgba_unorm = format.format == vk::Format::R8G8B8A8_UNORM || format.format == vk::Format::B8G8R8A8_UNORM; - let is_srgb = - format.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR; + let is_srgb = format.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR; is_rgba_unorm as u8 * 10 + is_srgb as u8 }) .or(formats.first()) @@ -785,14 +600,12 @@ impl Swapchain { .unwrap_or(u32::MAX); // we want PREFERRED_IMAGES_IN_FLIGHT images acquired at the same time, - let image_count = (caps.min_image_count - + Self::PREFERRED_IMAGES_IN_FLIGHT) - .min(max_image_count); + let image_count = + (caps.min_image_count + Self::PREFERRED_IMAGES_IN_FLIGHT).min(max_image_count); let extent = current_extent_or_clamped( &caps, - requested_extent - .unwrap_or(vk::Extent2D::default().width(1).height(1)), + requested_extent.unwrap_or(vk::Extent2D::default().width(1).height(1)), ); Ok(SwapchainParams { @@ -830,12 +643,7 @@ impl Swapchain { image_count, min_image_count, extent, - } = Self::get_swapchain_params_from_surface( - &instance, - surface.surface, - pdev, - extent, - )?; + } = Self::get_swapchain_params_from_surface(&instance, surface.surface, pdev, extent)?; let (swapchain, images) = { let lock = old_swapchain.as_ref().map(|handle| handle.lock()); @@ -880,26 +688,26 @@ impl Swapchain { let acquire_semaphores = { (0..inflight_frames) .map(|i| unsafe { - device.dev().create_semaphore( - &vk::SemaphoreCreateInfo::default(), - None, - ).inspect(|r| { - #[cfg(debug_assertions)] - - { - let name = CString::new(format!( - "semaphore-{:x}_{i}-acquire", - swapchain.0.lock().as_raw() - )) + device + .dev() + .create_semaphore(&vk::SemaphoreCreateInfo::default(), None) + .inspect(|r| { + #[cfg(debug_assertions)] + { + let name = CString::new(format!( + "semaphore-{:x}_{i}-acquire", + swapchain.0.lock().as_raw() + )) .unwrap(); - unsafe { - device.debug_utils().set_debug_utils_object_name( - &vk::DebugUtilsObjectNameInfoEXT::default() - .object_handle(*r) - .object_name(&name), - );} - } - }) + unsafe { + device.debug_utils().set_debug_utils_object_name( + &vk::DebugUtilsObjectNameInfoEXT::default() + .object_handle(*r) + .object_name(&name), + ); + } + } + }) }) .collect::>>()? }; @@ -907,51 +715,53 @@ impl Swapchain { let release_semaphores = { (0..inflight_frames) .map(|i| unsafe { - device.dev().create_semaphore( - &vk::SemaphoreCreateInfo::default(), - None, - ).inspect(|r| { - #[cfg(debug_assertions)] - - { - let name = CString::new(format!( - "semaphore-{:x}_{i}-release", - swapchain.0.lock().as_raw() - )) + device + .dev() + .create_semaphore(&vk::SemaphoreCreateInfo::default(), None) + .inspect(|r| { + #[cfg(debug_assertions)] + { + let name = CString::new(format!( + "semaphore-{:x}_{i}-release", + swapchain.0.lock().as_raw() + )) .unwrap(); - unsafe { - device.debug_utils().set_debug_utils_object_name( - &vk::DebugUtilsObjectNameInfoEXT::default() - .object_handle(*r) - .object_name(&name), - );} - } - }) + unsafe { + device.debug_utils().set_debug_utils_object_name( + &vk::DebugUtilsObjectNameInfoEXT::default() + .object_handle(*r) + .object_name(&name), + ); + } + } + }) }) .collect::>>()? }; let fences = { (0..inflight_frames) - .map(|i| Ok(Arc::new(sync::Fence::create(device.clone()) - .inspect(|r| { - #[cfg(debug_assertions)] - - { - let name = CString::new(format!( - "fence-{:x}_{i}", - swapchain.0.lock().as_raw() - )) + .map(|i| { + Ok(Arc::new(sync::Fence::create(device.clone()).inspect( + |r| { + #[cfg(debug_assertions)] + { + let name = CString::new(format!( + "fence-{:x}_{i}", + swapchain.0.lock().as_raw() + )) .unwrap(); - unsafe { - device.debug_utils().set_debug_utils_object_name( - &vk::DebugUtilsObjectNameInfoEXT::default() - .object_handle(r.fence()) - .object_name(&name), - );} - } - }) -?))) + unsafe { + device.debug_utils().set_debug_utils_object_name( + &vk::DebugUtilsObjectNameInfoEXT::default() + .object_handle(r.fence()) + .object_name(&name), + ); + } + } + }, + )?)) + }) .collect::>>()? }; @@ -1000,8 +810,7 @@ impl Swapchain { /// suboptimal and should be recreated. fn acquire_image( self: Arc, - ) -> impl std::future::Future> - { + ) -> impl std::future::Future> { let frame = self .current_frame .fetch_update( @@ -1067,8 +876,8 @@ impl Swapchain { let present_id = self .present_id .fetch_add(1, std::sync::atomic::Ordering::Relaxed); - let mut present_id = vk::PresentIdKHR::default() - .present_ids(core::slice::from_ref(&present_id)); + let mut present_id = + vk::PresentIdKHR::default().present_ids(core::slice::from_ref(&present_id)); let present_info = vk::PresentInfoKHR::default() .image_indices(core::slice::from_ref(&frame.index)) @@ -1103,10 +912,7 @@ impl Swapchain { .image_color_space(image_color_space) .image_format(image_format) .min_image_count(image_count) - .image_usage( - vk::ImageUsageFlags::TRANSFER_DST - | vk::ImageUsageFlags::COLOR_ATTACHMENT, - ) + .image_usage(vk::ImageUsageFlags::TRANSFER_DST | vk::ImageUsageFlags::COLOR_ATTACHMENT) .image_array_layers(1) .image_extent(image_extent) .image_sharing_mode(if queue_families.len() <= 1 { @@ -1121,16 +927,14 @@ impl Swapchain { .clipped(true); let (swapchain, images) = unsafe { - let swapchain = - device.swapchain().create_swapchain(&create_info, None)?; + let swapchain = device.swapchain().create_swapchain(&create_info, None)?; #[cfg(debug_assertions)] { let name = CString::new(format!( "swapchain-{}_{}", surface.as_raw(), - SWAPCHAIN_COUNT - .fetch_add(1, std::sync::atomic::Ordering::Relaxed) + SWAPCHAIN_COUNT.fetch_add(1, std::sync::atomic::Ordering::Relaxed) )) .unwrap(); device.debug_utils().set_debug_utils_object_name( @@ -1158,15 +962,11 @@ struct Surface { impl Surface { fn headless(instance: Arc) -> Result { unsafe { - let headless_instance = ash::ext::headless_surface::Instance::new( - &instance.entry, - &instance.instance, - ); + let headless_instance = + ash::ext::headless_surface::Instance::new(&instance.entry, &instance.instance); - let surface = headless_instance.create_headless_surface( - &vk::HeadlessSurfaceCreateInfoEXT::default(), - None, - )?; + let surface = headless_instance + .create_headless_surface(&vk::HeadlessSurfaceCreateInfoEXT::default(), None)?; Ok(Self { instance, surface }) } @@ -1213,11 +1013,9 @@ impl Drop for Vulkan { } impl Vulkan { - const VALIDATION_LAYER_NAME: &'static core::ffi::CStr = - c"VK_LAYER_KHRONOS_validation"; + const VALIDATION_LAYER_NAME: &'static core::ffi::CStr = c"VK_LAYER_KHRONOS_validation"; #[allow(unused)] - const RENDERDOC_LAYER_NAME: &'static core::ffi::CStr = - c"VK_LAYER_RENDERDOC_Capture"; + const RENDERDOC_LAYER_NAME: &'static core::ffi::CStr = c"VK_LAYER_RENDERDOC_Capture"; #[allow(unused)] const NSIGHT_TRACE_LAYER_NAME: &'static core::ffi::CStr = c"VK_LAYER_NV_GPU_Trace_release_public_2021_4_2"; @@ -1251,9 +1049,7 @@ impl Vulkan { .values(&[1]), vk::LayerSettingEXT::default() .layer_name(Self::VALIDATION_LAYER_NAME) - .setting_name( - c"VK_KHRONOS_VALIDATION_VALIDATE_BEST_PRACTICES_AMD", - ) + .setting_name(c"VK_KHRONOS_VALIDATION_VALIDATE_BEST_PRACTICES_AMD") .ty(vk::LayerSettingTypeEXT::BOOL32) .values(&[1]), vk::LayerSettingEXT::default() @@ -1262,11 +1058,10 @@ impl Vulkan { .ty(vk::LayerSettingTypeEXT::BOOL32) .values(&[1]), ]; - let mut validation_info = vk::LayerSettingsCreateInfoEXT::default() - .settings(&validation_settings); + let mut validation_info = + vk::LayerSettingsCreateInfoEXT::default().settings(&validation_settings); - let layers = - Self::get_layers(&entry, &[Self::VALIDATION_LAYER_NAME]).unwrap(); + let layers = Self::get_layers(&entry, &[Self::VALIDATION_LAYER_NAME]).unwrap(); // optional display handle let extensions = Self::get_extensions( @@ -1300,14 +1095,10 @@ impl Vulkan { ) .pfn_user_callback(Some(debug::debug_callback)); - let debug_utils_instance = - ash::ext::debug_utils::Instance::new(&entry, &instance); - let debug_utils_messenger = unsafe { - debug_utils_instance - .create_debug_utils_messenger(&debug_info, None)? - }; - let surface_instance = - ash::khr::surface::Instance::new(&entry, &instance); + let debug_utils_instance = ash::ext::debug_utils::Instance::new(&entry, &instance); + let debug_utils_messenger = + unsafe { debug_utils_instance.create_debug_utils_messenger(&debug_info, None)? }; + let surface_instance = ash::khr::surface::Instance::new(&entry, &instance); let instance = Arc::new(Instance { instance, @@ -1324,10 +1115,7 @@ impl Vulkan { .sampler_anisotropy(true) .multi_draw_indirect(true), ) - .features11( - vk::PhysicalDeviceVulkan11Features::default() - .shader_draw_parameters(true), - ) + .features11(vk::PhysicalDeviceVulkan11Features::default().shader_draw_parameters(true)) .features12( vk::PhysicalDeviceVulkan12Features::default() .shader_int8(true) @@ -1353,34 +1141,25 @@ impl Vulkan { ash::khr::present_id::NAME, ash::khr::present_id::SPEC_VERSION, ), - vk::PhysicalDevicePresentIdFeaturesKHR::default() - .present_id(true), + vk::PhysicalDevicePresentIdFeaturesKHR::default().present_id(true), ) .with_extension( make_extention_properties( ash::khr::present_wait::NAME, ash::khr::present_wait::SPEC_VERSION, ), - vk::PhysicalDevicePresentWaitFeaturesKHR::default() - .present_wait(true), + vk::PhysicalDevicePresentWaitFeaturesKHR::default().present_wait(true), ) .with_extension( make_extention_properties( ash::ext::index_type_uint8::NAME, ash::ext::index_type_uint8::SPEC_VERSION, ), - vk::PhysicalDeviceIndexTypeUint8FeaturesEXT::default() - .index_type_uint8(true), + vk::PhysicalDeviceIndexTypeUint8FeaturesEXT::default().index_type_uint8(true), ) .with_extensions2([ - make_extention_properties( - khr::swapchain::NAME, - khr::swapchain::SPEC_VERSION, - ), - make_extention_properties( - khr::spirv_1_4::NAME, - khr::spirv_1_4::SPEC_VERSION, - ), + make_extention_properties(khr::swapchain::NAME, khr::swapchain::SPEC_VERSION), + make_extention_properties(khr::spirv_1_4::NAME, khr::spirv_1_4::SPEC_VERSION), ]); // Consider this: switching physical device in game? @@ -1397,8 +1176,7 @@ impl Vulkan { )?; tracing::debug!("pdev: {pdev:?}"); - let device = - Self::create_device(instance.clone(), pdev, &mut features)?; + let device = Device::new(instance.clone(), pdev, features)?; Ok(Self { instance, device }) } @@ -1416,28 +1194,19 @@ impl Vulkan { } RawDisplayHandle::Xcb(_xcb_display_handle) => todo!(), RawDisplayHandle::Wayland(wayland_display_handle) => { - ash::khr::wayland_surface::Instance::new( - &instance.entry, - &instance.instance, - ) - .get_physical_device_wayland_presentation_support( - pdev, - queue_family, - wayland_display_handle.display.cast().as_mut(), - ) + ash::khr::wayland_surface::Instance::new(&instance.entry, &instance.instance) + .get_physical_device_wayland_presentation_support( + pdev, + queue_family, + wayland_display_handle.display.cast().as_mut(), + ) } RawDisplayHandle::Drm(_) => { todo!() } RawDisplayHandle::Windows(_) => { - ash::khr::win32_surface::Instance::new( - &instance.entry, - &instance.instance, - ) - .get_physical_device_win32_presentation_support( - pdev, - queue_family, - ) + ash::khr::win32_surface::Instance::new(&instance.entry, &instance.instance) + .get_physical_device_win32_presentation_support(pdev, queue_family) } _ => panic!("unsupported platform"), } @@ -1515,14 +1284,11 @@ impl Vulkan { .enumerate() .map(|(i, family)| { let q = i as u32; - let is_graphics = - family.queue_flags.contains(vk::QueueFlags::GRAPHICS); - let is_compute = - family.queue_flags.contains(vk::QueueFlags::COMPUTE); - let is_transfer = - family.queue_flags.contains(vk::QueueFlags::TRANSFER) - || is_compute - || is_graphics; + let is_graphics = family.queue_flags.contains(vk::QueueFlags::GRAPHICS); + let is_compute = family.queue_flags.contains(vk::QueueFlags::COMPUTE); + let is_transfer = family.queue_flags.contains(vk::QueueFlags::TRANSFER) + || is_compute + || is_graphics; let is_present = display_handle .map(|display_handle| { Self::queue_family_supports_presentation( @@ -1570,8 +1336,7 @@ impl Vulkan { None} }); - let async_compute = - queue_families.find_first(|family| family.is_compute); + let async_compute = queue_families.find_first(|family| family.is_compute); let transfer = queue_families.find_first(|family| family.is_transfer); let mut unique_families = BTreeMap::::new(); @@ -1594,9 +1359,9 @@ impl Vulkan { }; let graphics = helper(graphics); - let async_compute = async_compute.map(|f| helper(f)); - let transfer = transfer.map(|f| helper(f)); - let present = present.map(|f| helper(f)); + let async_compute = async_compute.map(|f| helper(f)).unwrap_or(graphics); + let transfer = transfer.map(|f| helper(f)).unwrap_or(async_compute); + let present = present.map(|f| helper(f)).unwrap_or(graphics); let families = unique_families .into_iter() @@ -1617,110 +1382,6 @@ impl Vulkan { queues } - fn create_device( - instance: Arc, - pdev: PhysicalDevice, - features: &mut PhysicalDeviceFeatures, - ) -> Result { - // we have 4 queues at most: graphics, compute, transfer, present - let priorities = [1.0f32; 4]; - - let queue_infos = pdev - .queue_families - .families - .iter() - .map(|&(family, queues)| { - vk::DeviceQueueCreateInfo::default() - .queue_family_index(family) - .queue_priorities(&priorities[..queues as usize]) - }) - .collect::>(); - - let extensions = features - .device_extensions - .iter() - .map(|ext| ext.extension_name.as_ptr()) - .collect::>(); - - let mut features2 = features.features2(); - let device_info = vk::DeviceCreateInfo::default() - .queue_create_infos(&queue_infos) - .enabled_extension_names(&extensions) - .push_next(&mut features2); - - let device = unsafe { - let device = instance.instance.create_device( - pdev.pdev, - &device_info, - None, - )?; - - let allocated_queues = queue_infos - .iter() - .flat_map(|info| { - (0..info.queue_count).map(|i| { - ( - (info.queue_family_index, i), - Queue::new(&device, info.queue_family_index, i), - ) - }) - }) - .collect::>(); - - let get_queue = |(family, index)| { - allocated_queues.get(&(family, index)).cloned().unwrap() - }; - - let main_queue = get_queue(pdev.queue_families.graphics); - let present_queue = pdev - .queue_families - .present - .map(get_queue) - .unwrap_or(main_queue.clone()); - let compute_queue = pdev - .queue_families - .async_compute - .map(get_queue) - .unwrap_or(main_queue.clone()); - let transfer_queue = pdev - .queue_families - .transfer - .map(get_queue) - .unwrap_or(compute_queue.clone()); - - let alloc_info = vk_mem::AllocatorCreateInfo::new( - &instance.instance, - &device, - pdev.pdev, - ); - - let alloc = unsafe { vk_mem::Allocator::new(alloc_info)? }; - - Device::new(DeviceInner { - device: device.clone(), - physical: pdev, - swapchain: khr::swapchain::Device::new( - &instance.instance, - &device, - ), - debug_utils: ash::ext::debug_utils::Device::new( - &instance.instance, - &device, - ), - instance, - alloc, - allocated_queues, - main_queue, - present_queue, - compute_queue, - transfer_queue, - sync_threadpool: sync::SyncThreadpool::new(), - }) - }; - - Ok(device) - } - fn choose_physical_device( instance: &Instance, display_handle: Option, @@ -1732,13 +1393,12 @@ impl Vulkan { let (pdev, properties) = pdevs .into_iter() .map(|pdev| { - let mut props = PhysicalDeviceProperties::default() - .extra_properties( - extra_properties - .iter() - .map(|b| dyn_clone::clone_box(&**b)) - .collect::>(), - ); + let mut props = PhysicalDeviceProperties::default().extra_properties( + extra_properties + .iter() + .map(|b| dyn_clone::clone_box(&**b)) + .collect::>(), + ); props.query(&instance.instance, pdev); (pdev, props) @@ -1751,8 +1411,7 @@ impl Vulkan { // device which doesn't support all of the extensions. .filter(|(pdev, _)| { let query_features = - PhysicalDeviceFeatures::query(&instance.instance, *pdev) - .unwrap(); + PhysicalDeviceFeatures::query(&instance.instance, *pdev).unwrap(); requirements.compatible_with(&query_features) }) @@ -1773,11 +1432,7 @@ impl Vulkan { .ok_or(Error::NoPhysicalDevice)?; Ok(PhysicalDevice { - queue_families: Self::select_pdev_queue_families( - instance, - display_handle, - pdev, - ), + queue_families: Self::select_pdev_queue_families(instance, display_handle, pdev), pdev, properties, }) @@ -1788,15 +1443,15 @@ impl Vulkan { layers: &[&CStr], ) -> Result> { unsafe { - let extensions = core::iter::once( - entry.enumerate_instance_extension_properties(None), - ) - .chain(layers.iter().map(|&layer| { - entry.enumerate_instance_extension_properties(Some(layer)) - })) - .filter_map(|result| result.ok()) - .flatten() - .collect::>(); + let extensions = core::iter::once(entry.enumerate_instance_extension_properties(None)) + .chain( + layers + .iter() + .map(|&layer| entry.enumerate_instance_extension_properties(Some(layer))), + ) + .filter_map(|result| result.ok()) + .flatten() + .collect::>(); Ok(extensions) } @@ -1807,13 +1462,10 @@ impl Vulkan { layers: &[&'a CStr], extensions: &[&'a CStr], display_handle: Option, - ) -> core::result::Result, (Vec<&'a CStr>, Vec<&'a CStr>)> - { + ) -> core::result::Result, (Vec<&'a CStr>, Vec<&'a CStr>)> { unsafe { - let available_extensions = Self::get_available_extensions( - entry, layers, - ) - .map_err(|_| (Vec::<&'a CStr>::new(), extensions.to_vec()))?; + let available_extensions = Self::get_available_extensions(entry, layers) + .map_err(|_| (Vec::<&'a CStr>::new(), extensions.to_vec()))?; let available_extension_names = available_extensions .iter() @@ -1822,8 +1474,7 @@ impl Vulkan { .map_err(|_| (Vec::<&'a CStr>::new(), extensions.to_vec()))?; let mut out_extensions = Vec::with_capacity(extensions.len()); - let mut unsupported_extensions = - Vec::with_capacity(extensions.len()); + let mut unsupported_extensions = Vec::with_capacity(extensions.len()); for &extension in extensions { if available_extension_names.contains(&extension) { out_extensions.push(extension); @@ -1833,9 +1484,7 @@ impl Vulkan { } let Ok(required_extension_names) = display_handle - .map(|display_handle| { - ash_window::enumerate_required_extensions(display_handle) - }) + .map(|display_handle| ash_window::enumerate_required_extensions(display_handle)) .unwrap_or(Ok(&[])) else { return Err((out_extensions, unsupported_extensions)); @@ -1861,8 +1510,7 @@ impl Vulkan { fn get_layers<'a>( entry: &ash::Entry, wants_layers: &[&'a CStr], - ) -> core::result::Result, (Vec<&'a CStr>, Vec<&'a CStr>)> - { + ) -> core::result::Result, (Vec<&'a CStr>, Vec<&'a CStr>)> { unsafe { let available_layers = entry .enumerate_instance_layer_properties() @@ -1943,11 +1591,7 @@ impl WindowContext { window_handle: raw_window_handle::RawWindowHandle, display: RawDisplayHandle, ) -> Result { - let surface = Arc::new(Surface::create( - instance.clone(), - display, - window_handle, - )?); + let surface = Arc::new(Surface::create(instance.clone(), display, window_handle)?); let swapchain = Arc::new(Swapchain::new( instance, @@ -2010,10 +1654,18 @@ impl WindowContext { } } +#[derive(Debug, Default)] +pub struct EguiState { + pub textures: HashMap, +} + pub struct Renderer { - vulkan: Vulkan, + pub texture_handler: texture::TextureManager, + pub egui_state: EguiState, + // thinkw: want renderer linked with display? then no (real) headless display: RawDisplayHandle, pub window_contexts: HashMap, + vulkan: Vulkan, } pub use vk::Extent2D; @@ -2022,17 +1674,220 @@ impl Renderer { pub fn new(display: RawDisplayHandle) -> Result { let vulkan = Vulkan::new("Vidya", &[], &[], Some(display))?; Ok(Self { + texture_handler: texture::TextureManager::new(vulkan.device.clone()), vulkan, + egui_state: Default::default(), display, window_contexts: HashMap::new(), }) } - pub fn debug_draw( - &mut self, - window: &K, - pre_present_cb: F, - ) -> Result<()> + pub fn draw_egui(&mut self, ctx: &egui::Context, output: egui::FullOutput) { + let pool = commands::SingleUseCommandPool::new( + self.vulkan.device.clone(), + self.vulkan.device.graphics_queue().clone(), + ) + .unwrap(); + let cmd = pool.alloc().unwrap(); + + let cmd_objects = output + .textures_delta + .set + .iter() + .map(|(egui_id, delta)| { + let size = delta.image.size(); + let byte_size = size[0] * size[1] * 4; + let mut staging = buffers::Buffer::new( + self.vulkan.device.clone(), + byte_size, + vk::BufferUsageFlags::TRANSFER_SRC, + &[], + vk_mem::MemoryUsage::AutoPreferHost, + vk_mem::AllocationCreateFlags::MAPPED + | vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE + | vk_mem::AllocationCreateFlags::STRATEGY_FIRST_FIT, + ) + .expect("staging buffer"); + { + let mut mem = Arc::get_mut(&mut staging) + .unwrap() + .map() + .expect("mapping staging buffer"); + 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); + } + egui::ImageData::Font(font_image) => { + for (i, c) in font_image.srgba_pixels(None).enumerate() { + let bytes = c.to_array(); + mem[i * 4..(i + 1) * 4].copy_from_slice(&bytes); + } + } + } + } + + let sampled = if delta.is_whole() { + vk::ImageUsageFlags::SAMPLED + } else { + vk::ImageUsageFlags::TRANSFER_SRC + }; + let extent = vk::Extent2D { + width: delta.image.width() as u32, + height: delta.image.height() as u32, + }; + let texture = images::Image2D::new_exclusive( + &self.vulkan.device, + extent, + 1, + 1, + vk::Format::R8G8B8A8_UNORM, + vk::ImageTiling::OPTIMAL, + sampled | vk::ImageUsageFlags::TRANSFER_DST, + vk_mem::MemoryUsage::AutoPreferDevice, + vk_mem::AllocationCreateFlags::empty(), + Some(&format!("egui-texture-{egui_id:?}")), + ) + .expect("image creation"); + + cmd.image_barrier( + texture.image(), + vk::ImageAspectFlags::COLOR, + vk::PipelineStageFlags2::TRANSFER, + vk::AccessFlags2::empty(), + vk::PipelineStageFlags2::TRANSFER, + vk::AccessFlags2::TRANSFER_WRITE, + vk::ImageLayout::UNDEFINED, + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + None, + ); + cmd.copy_buffer_to_image( + staging.buffer(), + texture.image(), + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + &[vk::BufferImageCopy { + buffer_offset: 0, + buffer_row_length: delta.image.width() as u32, + buffer_image_height: delta.image.height() as u32, + 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: vk::Extent3D { + width: texture.size().width, + height: texture.size().height, + depth: 1, + }, + }], + ); + + let id = self + .egui_state + .textures + .get(egui_id) + .cloned() + .unwrap_or_else(|| { + let id = texture::TextureId::new(); + self.egui_state.textures.insert(*egui_id, id); + + id + }); + + if let Some(pos) = delta.pos { + // SAFETY: must exist because image is not whole. + let existing_texture = self.texture_handler.textures.get(&id).cloned().unwrap(); + + cmd.image_barrier( + texture.image(), + vk::ImageAspectFlags::COLOR, + vk::PipelineStageFlags2::TRANSFER, + vk::AccessFlags2::TRANSFER_WRITE, + vk::PipelineStageFlags2::TRANSFER, + vk::AccessFlags2::TRANSFER_READ, + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + vk::ImageLayout::TRANSFER_SRC_OPTIMAL, + None, + ); + cmd.image_barrier( + existing_texture.image(), + vk::ImageAspectFlags::COLOR, + vk::PipelineStageFlags2::empty(), + vk::AccessFlags2::empty(), + vk::PipelineStageFlags2::TRANSFER, + vk::AccessFlags2::TRANSFER_WRITE, + vk::ImageLayout::UNDEFINED, + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + None, + ); + cmd.blit_images( + &texture, + util::Rect2D::new(0, 0, texture.width() as i32, texture.height() as i32), + &existing_texture, + util::Rect2D::new_from_size( + glam::ivec2(pos[0] as i32, pos[1] as i32), + glam::ivec2(texture.width() as i32, texture.height() as i32), + ), + ); + cmd.image_barrier( + existing_texture.image(), + vk::ImageAspectFlags::COLOR, + vk::PipelineStageFlags2::TRANSFER, + vk::AccessFlags2::TRANSFER_WRITE, + vk::PipelineStageFlags2::FRAGMENT_SHADER, + vk::AccessFlags2::SHADER_SAMPLED_READ, + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, + None, + ); + } else { + cmd.image_barrier( + texture.image(), + vk::ImageAspectFlags::COLOR, + vk::PipelineStageFlags2::TRANSFER, + vk::AccessFlags2::TRANSFER_WRITE, + vk::PipelineStageFlags2::FRAGMENT_SHADER, + vk::AccessFlags2::SHADER_SAMPLED_READ, + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, + None, + ); + self.texture_handler.textures.insert(id, texture.clone()); + info!("new texture for egui: {egui_id:?} -> {id:?}"); + } + + (staging, texture) + }) + .collect::>(); + + let fence = Arc::new(sync::Fence::create(self.vulkan.device.clone()).unwrap()); + let future = cmd.submit_async(None, None, fence).unwrap(); + + future.block(); + + let draw_data = ctx.tessellate(output.shapes, output.pixels_per_point); + + // do drawing stuff + let cmd = pool.alloc().unwrap(); + + // free after drawing + let texture_deltas = &output.textures_delta; + texture_deltas + .free + .iter() + .filter_map(|id| self.egui_state.textures.get(id).cloned()) + .for_each(|id| { + self.texture_handler.textures.remove(&id); + }); + } + + pub fn debug_draw(&mut self, window: &K, pre_present_cb: F) -> Result<()> where K: core::hash::Hash + Eq, W: core::hash::Hash + Eq + Borrow, @@ -2041,17 +1896,13 @@ impl Renderer { unsafe { dev.dev().device_wait_idle()? }; - let pool = commands::SingleUseCommandPool::new( - dev.clone(), - dev.graphics_queue().clone(), - )?; + let pool = commands::SingleUseCommandPool::new(dev.clone(), dev.graphics_queue().clone())?; if let Some(ctx) = self.window_contexts.get(window) { let cmd = pool.alloc()?; - let (frame, suboptimal) = smol::block_on( - ctx.current_swapchain.read().clone().acquire_image(), - )?; + let (frame, suboptimal) = + smol::block_on(ctx.current_swapchain.read().clone().acquire_image())?; if suboptimal { tracing::warn!( @@ -2074,10 +1925,8 @@ impl Renderer { // let view = image.view(&dev, vk::ImageAspectFlags::COLOR)?; - let [r, g, b] = rand::prelude::StdRng::seed_from_u64( - ctx.surface.surface.as_raw(), - ) - .gen::<[f32; 3]>(); + let [r, g, b] = rand::prelude::StdRng::seed_from_u64(ctx.surface.surface.as_raw()) + .gen::<[f32; 3]>(); let clear_color = Rgba([r, g, b, 1.0]); let clear_values = vk::ClearColorValue { float32: [r, g, b, 1.0], @@ -2183,9 +2032,7 @@ mod debug { use ash::vk; use tracing::{event, Level}; - unsafe fn str_from_raw_parts<'a>( - str: *const i8, - ) -> std::borrow::Cow<'a, str> { + unsafe fn str_from_raw_parts<'a>(str: *const i8) -> std::borrow::Cow<'a, str> { use std::{borrow::Cow, ffi}; if str.is_null() { Cow::from("") @@ -2204,8 +2051,7 @@ mod debug { let callback_data = *callback_data; let message_id_number = callback_data.message_id_number; - let message_id_name = - str_from_raw_parts(callback_data.p_message_id_name); + let message_id_name = str_from_raw_parts(callback_data.p_message_id_name); let message = str_from_raw_parts(callback_data.p_message); match message_severity { @@ -2267,8 +2113,7 @@ pub mod utils { && lhs.dual_src_blend == rhs.dual_src_blend && lhs.logic_op == rhs.logic_op && lhs.multi_draw_indirect == rhs.multi_draw_indirect - && lhs.draw_indirect_first_instance - == rhs.draw_indirect_first_instance + && lhs.draw_indirect_first_instance == rhs.draw_indirect_first_instance && lhs.depth_clamp == rhs.depth_clamp && lhs.depth_bias_clamp == rhs.depth_bias_clamp && lhs.fill_mode_non_solid == rhs.fill_mode_non_solid @@ -2279,23 +2124,18 @@ pub mod utils { && lhs.multi_viewport == rhs.multi_viewport && lhs.sampler_anisotropy == rhs.sampler_anisotropy && lhs.texture_compression_etc2 == rhs.texture_compression_etc2 - && lhs.texture_compression_astc_ldr - == rhs.texture_compression_astc_ldr + && lhs.texture_compression_astc_ldr == rhs.texture_compression_astc_ldr && lhs.texture_compression_bc == rhs.texture_compression_bc && lhs.occlusion_query_precise == rhs.occlusion_query_precise && lhs.pipeline_statistics_query == rhs.pipeline_statistics_query - && lhs.vertex_pipeline_stores_and_atomics - == rhs.vertex_pipeline_stores_and_atomics - && lhs.fragment_stores_and_atomics - == rhs.fragment_stores_and_atomics + && lhs.vertex_pipeline_stores_and_atomics == rhs.vertex_pipeline_stores_and_atomics + && lhs.fragment_stores_and_atomics == rhs.fragment_stores_and_atomics && lhs.shader_tessellation_and_geometry_point_size == rhs.shader_tessellation_and_geometry_point_size - && lhs.shader_image_gather_extended - == rhs.shader_image_gather_extended + && lhs.shader_image_gather_extended == rhs.shader_image_gather_extended && lhs.shader_storage_image_extended_formats == rhs.shader_storage_image_extended_formats - && lhs.shader_storage_image_multisample - == rhs.shader_storage_image_multisample + && lhs.shader_storage_image_multisample == rhs.shader_storage_image_multisample && lhs.shader_storage_image_read_without_format == rhs.shader_storage_image_read_without_format && lhs.shader_storage_image_write_without_format @@ -2339,10 +2179,8 @@ pub mod utils { && lhs.storage_input_output16 == rhs.storage_input_output16 && lhs.multiview == rhs.multiview && lhs.multiview_geometry_shader == rhs.multiview_geometry_shader - && lhs.multiview_tessellation_shader - == rhs.multiview_tessellation_shader - && lhs.variable_pointers_storage_buffer - == rhs.variable_pointers_storage_buffer + && lhs.multiview_tessellation_shader == rhs.multiview_tessellation_shader + && lhs.variable_pointers_storage_buffer == rhs.variable_pointers_storage_buffer && lhs.variable_pointers == rhs.variable_pointers && lhs.protected_memory == rhs.protected_memory && lhs.sampler_ycbcr_conversion == rhs.sampler_ycbcr_conversion @@ -2359,10 +2197,8 @@ pub mod utils { && lhs.uniform_and_storage_buffer8_bit_access == rhs.uniform_and_storage_buffer8_bit_access && lhs.storage_push_constant8 == rhs.storage_push_constant8 - && lhs.shader_buffer_int64_atomics - == rhs.shader_buffer_int64_atomics - && lhs.shader_shared_int64_atomics - == rhs.shader_shared_int64_atomics + && lhs.shader_buffer_int64_atomics == rhs.shader_buffer_int64_atomics + && lhs.shader_shared_int64_atomics == rhs.shader_shared_int64_atomics && lhs.shader_float16 == rhs.shader_float16 && lhs.shader_int8 == rhs.shader_int8 && lhs.descriptor_indexing == rhs.descriptor_indexing @@ -2400,37 +2236,28 @@ pub mod utils { == rhs.descriptor_binding_storage_texel_buffer_update_after_bind && lhs.descriptor_binding_update_unused_while_pending == rhs.descriptor_binding_update_unused_while_pending - && lhs.descriptor_binding_partially_bound - == rhs.descriptor_binding_partially_bound + && lhs.descriptor_binding_partially_bound == rhs.descriptor_binding_partially_bound && lhs.descriptor_binding_variable_descriptor_count == rhs.descriptor_binding_variable_descriptor_count && lhs.runtime_descriptor_array == rhs.runtime_descriptor_array && lhs.sampler_filter_minmax == rhs.sampler_filter_minmax && lhs.scalar_block_layout == rhs.scalar_block_layout && lhs.imageless_framebuffer == rhs.imageless_framebuffer - && lhs.uniform_buffer_standard_layout - == rhs.uniform_buffer_standard_layout - && lhs.shader_subgroup_extended_types - == rhs.shader_subgroup_extended_types - && lhs.separate_depth_stencil_layouts - == rhs.separate_depth_stencil_layouts + && lhs.uniform_buffer_standard_layout == rhs.uniform_buffer_standard_layout + && lhs.shader_subgroup_extended_types == rhs.shader_subgroup_extended_types + && lhs.separate_depth_stencil_layouts == rhs.separate_depth_stencil_layouts && lhs.host_query_reset == rhs.host_query_reset && lhs.timeline_semaphore == rhs.timeline_semaphore && lhs.buffer_device_address == rhs.buffer_device_address - && lhs.buffer_device_address_capture_replay - == rhs.buffer_device_address_capture_replay - && lhs.buffer_device_address_multi_device - == rhs.buffer_device_address_multi_device + && lhs.buffer_device_address_capture_replay == rhs.buffer_device_address_capture_replay + && lhs.buffer_device_address_multi_device == rhs.buffer_device_address_multi_device && lhs.vulkan_memory_model == rhs.vulkan_memory_model - && lhs.vulkan_memory_model_device_scope - == rhs.vulkan_memory_model_device_scope + && lhs.vulkan_memory_model_device_scope == rhs.vulkan_memory_model_device_scope && lhs.vulkan_memory_model_availability_visibility_chains == rhs.vulkan_memory_model_availability_visibility_chains - && lhs.shader_output_viewport_index - == rhs.shader_output_viewport_index + && lhs.shader_output_viewport_index == rhs.shader_output_viewport_index && lhs.shader_output_layer == rhs.shader_output_layer - && lhs.subgroup_broadcast_dynamic_id - == rhs.subgroup_broadcast_dynamic_id + && lhs.subgroup_broadcast_dynamic_id == rhs.subgroup_broadcast_dynamic_id } pub fn eq_device_features13( @@ -2441,18 +2268,14 @@ pub mod utils { && lhs.inline_uniform_block == rhs.inline_uniform_block && lhs.descriptor_binding_inline_uniform_block_update_after_bind == rhs.descriptor_binding_inline_uniform_block_update_after_bind - && lhs.pipeline_creation_cache_control - == rhs.pipeline_creation_cache_control + && lhs.pipeline_creation_cache_control == rhs.pipeline_creation_cache_control && lhs.private_data == rhs.private_data - && lhs.shader_demote_to_helper_invocation - == rhs.shader_demote_to_helper_invocation - && lhs.shader_terminate_invocation - == rhs.shader_terminate_invocation + && lhs.shader_demote_to_helper_invocation == rhs.shader_demote_to_helper_invocation + && lhs.shader_terminate_invocation == rhs.shader_terminate_invocation && lhs.subgroup_size_control == rhs.subgroup_size_control && lhs.compute_full_subgroups == rhs.compute_full_subgroups && lhs.synchronization2 == rhs.synchronization2 - && lhs.texture_compression_astc_hdr - == rhs.texture_compression_astc_hdr + && lhs.texture_compression_astc_hdr == rhs.texture_compression_astc_hdr && lhs.shader_zero_initialize_workgroup_memory == rhs.shader_zero_initialize_workgroup_memory && lhs.dynamic_rendering == rhs.dynamic_rendering @@ -2466,48 +2289,30 @@ pub mod utils { ) -> vk::PhysicalDeviceFeatures { use core::ops::BitAnd; vk::PhysicalDeviceFeatures { - robust_buffer_access: lhs - .robust_buffer_access - .bitand(&rhs.robust_buffer_access), + robust_buffer_access: lhs.robust_buffer_access.bitand(&rhs.robust_buffer_access), full_draw_index_uint32: lhs .full_draw_index_uint32 .bitand(&rhs.full_draw_index_uint32), - image_cube_array: lhs - .image_cube_array - .bitand(&rhs.image_cube_array), - independent_blend: lhs - .independent_blend - .bitand(&rhs.independent_blend), + image_cube_array: lhs.image_cube_array.bitand(&rhs.image_cube_array), + independent_blend: lhs.independent_blend.bitand(&rhs.independent_blend), geometry_shader: lhs.geometry_shader.bitand(&rhs.geometry_shader), - tessellation_shader: lhs - .tessellation_shader - .bitand(&rhs.tessellation_shader), - sample_rate_shading: lhs - .sample_rate_shading - .bitand(&rhs.sample_rate_shading), + tessellation_shader: lhs.tessellation_shader.bitand(&rhs.tessellation_shader), + sample_rate_shading: lhs.sample_rate_shading.bitand(&rhs.sample_rate_shading), dual_src_blend: lhs.dual_src_blend.bitand(&rhs.dual_src_blend), logic_op: lhs.logic_op.bitand(&rhs.logic_op), - multi_draw_indirect: lhs - .multi_draw_indirect - .bitand(&rhs.multi_draw_indirect), + multi_draw_indirect: lhs.multi_draw_indirect.bitand(&rhs.multi_draw_indirect), draw_indirect_first_instance: lhs .draw_indirect_first_instance .bitand(&rhs.draw_indirect_first_instance), depth_clamp: lhs.depth_clamp.bitand(&rhs.depth_clamp), - depth_bias_clamp: lhs - .depth_bias_clamp - .bitand(&rhs.depth_bias_clamp), - fill_mode_non_solid: lhs - .fill_mode_non_solid - .bitand(&rhs.fill_mode_non_solid), + depth_bias_clamp: lhs.depth_bias_clamp.bitand(&rhs.depth_bias_clamp), + fill_mode_non_solid: lhs.fill_mode_non_solid.bitand(&rhs.fill_mode_non_solid), depth_bounds: lhs.depth_bounds.bitand(&rhs.depth_bounds), wide_lines: lhs.wide_lines.bitand(&rhs.wide_lines), large_points: lhs.large_points.bitand(&rhs.large_points), alpha_to_one: lhs.alpha_to_one.bitand(&rhs.alpha_to_one), multi_viewport: lhs.multi_viewport.bitand(&rhs.multi_viewport), - sampler_anisotropy: lhs - .sampler_anisotropy - .bitand(&rhs.sampler_anisotropy), + sampler_anisotropy: lhs.sampler_anisotropy.bitand(&rhs.sampler_anisotropy), texture_compression_etc2: lhs .texture_compression_etc2 .bitand(&rhs.texture_compression_etc2), @@ -2559,12 +2364,8 @@ pub mod utils { shader_storage_image_array_dynamic_indexing: lhs .shader_storage_image_array_dynamic_indexing .bitand(&rhs.shader_storage_image_array_dynamic_indexing), - shader_clip_distance: lhs - .shader_clip_distance - .bitand(&rhs.shader_clip_distance), - shader_cull_distance: lhs - .shader_cull_distance - .bitand(&rhs.shader_cull_distance), + shader_clip_distance: lhs.shader_clip_distance.bitand(&rhs.shader_clip_distance), + shader_cull_distance: lhs.shader_cull_distance.bitand(&rhs.shader_cull_distance), shader_float64: lhs.shader_float64.bitand(&rhs.shader_float64), shader_int64: lhs.shader_int64.bitand(&rhs.shader_int64), shader_int16: lhs.shader_int16.bitand(&rhs.shader_int16), @@ -2602,9 +2403,7 @@ pub mod utils { variable_multisample_rate: lhs .variable_multisample_rate .bitand(&rhs.variable_multisample_rate), - inherited_queries: lhs - .inherited_queries - .bitand(&rhs.inherited_queries), + inherited_queries: lhs.inherited_queries.bitand(&rhs.inherited_queries), } } @@ -2636,12 +2435,8 @@ pub mod utils { variable_pointers_storage_buffer: lhs .variable_pointers_storage_buffer .bitand(&rhs.variable_pointers_storage_buffer), - variable_pointers: lhs - .variable_pointers - .bitand(&rhs.variable_pointers), - protected_memory: lhs - .protected_memory - .bitand(&rhs.protected_memory), + variable_pointers: lhs.variable_pointers.bitand(&rhs.variable_pointers), + protected_memory: lhs.protected_memory.bitand(&rhs.protected_memory), sampler_ycbcr_conversion: lhs .sampler_ycbcr_conversion .bitand(&rhs.sampler_ycbcr_conversion), @@ -2843,9 +2638,7 @@ mod test_swapchain { )?); let window_ctx = WindowContext { - window_handle: RawWindowHandle::Web( - raw_window_handle::WebWindowHandle::new(0), - ), + window_handle: RawWindowHandle::Web(raw_window_handle::WebWindowHandle::new(0)), surface, current_swapchain: RwLock::new(swapchain), }; diff --git a/crates/renderer/src/render_graph.rs b/crates/renderer/src/render_graph.rs index b70db29..d068c27 100644 --- a/crates/renderer/src/render_graph.rs +++ b/crates/renderer/src/render_graph.rs @@ -14,8 +14,9 @@ impl std::hash::Hash for Rgba { std::num::FpCategory::Infinite | std::num::FpCategory::Zero => { (classify as u8, f.signum() as i8).hash(state) } - std::num::FpCategory::Subnormal - | std::num::FpCategory::Normal => f.to_bits().hash(state), + std::num::FpCategory::Subnormal | std::num::FpCategory::Normal => { + f.to_bits().hash(state) + } } } self.0.map(|f| hash_f32(state, f)); diff --git a/crates/renderer/src/sync.rs b/crates/renderer/src/sync.rs index 89d65e2..e81521d 100644 --- a/crates/renderer/src/sync.rs +++ b/crates/renderer/src/sync.rs @@ -45,17 +45,15 @@ impl SyncThreadpool { fn try_spawn_thread(&self) -> Option<()> { use std::sync::atomic::Ordering; - match self.num_threads.fetch_update( - Ordering::Release, - Ordering::Acquire, - |i| { + match self + .num_threads + .fetch_update(Ordering::Release, Ordering::Acquire, |i| { if i < self.max_threads { Some(i + 1) } else { None } - }, - ) { + }) { Ok(tid) => { struct SyncThread { timeout: u64, @@ -68,22 +66,14 @@ impl SyncThreadpool { fn run(self, barrier: Arc) { tracing::info!("spawned new sync thread"); barrier.wait(); - while let Ok((sync, waker)) = - self.rx.recv_timeout(self.thread_dies_after) - { - tracing::info!( - "received ({:?}, {:?})", - sync, - waker - ); + while let Ok((sync, waker)) = self.rx.recv_timeout(self.thread_dies_after) { + tracing::info!("received ({:?}, {:?})", sync, waker); loop { let wait_result = match &sync { SyncPrimitive::Fence(fence) => { fence.wait_on(Some(self.timeout)) } - SyncPrimitive::DeviceIdle(device) => { - device.wait_idle() - } + SyncPrimitive::DeviceIdle(device) => device.wait_idle(), }; match wait_result { @@ -95,7 +85,7 @@ impl SyncThreadpool { Err(err) => { tracing::error!( "failed to wait on {sync:?} in waiter thread: {err}" - ); + ); break; } } @@ -197,8 +187,7 @@ impl Fence { Ok(Self::new( dev.clone(), dev.dev().create_fence( - &vk::FenceCreateInfo::default() - .flags(vk::FenceCreateFlags::SIGNALED), + &vk::FenceCreateInfo::default().flags(vk::FenceCreateFlags::SIGNALED), None, )?, )) @@ -207,11 +196,9 @@ impl Fence { pub fn wait_on(&self, timeout: Option) -> Result<(), vk::Result> { use core::slice::from_ref; unsafe { - self.dev.dev().wait_for_fences( - from_ref(&self.fence), - true, - timeout.unwrap_or(u64::MAX), - ) + self.dev + .dev() + .wait_for_fences(from_ref(&self.fence), true, timeout.unwrap_or(u64::MAX)) } } pub fn fence(&self) -> vk::Fence { @@ -236,12 +223,10 @@ impl AsRef for Fence { impl Semaphore { pub fn new(device: Device) -> VkResult { - let mut type_info = vk::SemaphoreTypeCreateInfo::default() - .semaphore_type(vk::SemaphoreType::BINARY); - let create_info = - vk::SemaphoreCreateInfo::default().push_next(&mut type_info); - let inner = - unsafe { device.dev().create_semaphore(&create_info, None)? }; + let mut type_info = + vk::SemaphoreTypeCreateInfo::default().semaphore_type(vk::SemaphoreType::BINARY); + let create_info = vk::SemaphoreCreateInfo::default().push_next(&mut type_info); + let inner = unsafe { device.dev().create_semaphore(&create_info, None)? }; Ok(Self { device, inner }) } @@ -249,10 +234,8 @@ impl Semaphore { let mut type_info = vk::SemaphoreTypeCreateInfo::default() .semaphore_type(vk::SemaphoreType::TIMELINE) .initial_value(value); - let create_info = - vk::SemaphoreCreateInfo::default().push_next(&mut type_info); - let inner = - unsafe { device.dev().create_semaphore(&create_info, None)? }; + let create_info = vk::SemaphoreCreateInfo::default().push_next(&mut type_info); + let inner = unsafe { device.dev().create_semaphore(&create_info, None)? }; Ok(Self { device, inner }) } diff --git a/crates/renderer/src/util.rs b/crates/renderer/src/util.rs index 82400ef..166669b 100644 --- a/crates/renderer/src/util.rs +++ b/crates/renderer/src/util.rs @@ -1,7 +1,28 @@ -use std::ops::Deref; +use std::{borrow::Cow, ops::Deref}; use ash::vk; +#[macro_export] +macro_rules! def_monotonic_id { + ($ty:ident) => { + #[derive(Copy, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, Debug)] + pub struct $ty(::core::num::NonZero); + + impl $ty { + pub fn new() -> Self { + use ::core::sync::atomic::{AtomicU32, Ordering}; + static COUNTER: AtomicU32 = AtomicU32::new(1); + + let inner = COUNTER.fetch_add(1, Ordering::Relaxed); + Self( + ::core::num::NonZero::::new(inner) + .expect(&format!("integer overwarp for {}", stringify!($ty))), + ) + } + } + }; +} + pub trait MutexExt<'a, T: 'a> { type Guard: Deref + 'a; fn lock(&'a self) -> Self::Guard; @@ -239,3 +260,41 @@ impl FormatExt for vk::Format { format_to_primitive(*self) == FormatComponentKind::SInt } } + +#[derive(Debug, Default, PartialEq, Eq, Hash, Clone, Copy)] +pub struct Rect2D { + top_left: glam::IVec2, + bottom_right: glam::IVec2, +} + +impl Rect2D { + pub fn new(left: i32, top: i32, right: i32, bottom: i32) -> Self { + use glam::ivec2; + Self { + top_left: ivec2(left, top), + bottom_right: ivec2(right, bottom), + } + } + pub fn new_from_size(pos: glam::IVec2, size: glam::IVec2) -> Self { + use glam::ivec2; + Self { + top_left: pos, + bottom_right: pos + size, + } + } + + pub fn into_offsets_3d(&self) -> [vk::Offset3D; 2] { + [ + vk::Offset3D { + x: self.top_left.x, + y: self.top_left.y, + z: 0, + }, + vk::Offset3D { + x: self.bottom_right.x, + y: self.bottom_right.y, + z: 1, + }, + ] + } +}