diff --git a/crates/game/src/main.rs b/crates/game/src/main.rs index daf04e7..57e0c69 100644 --- a/crates/game/src/main.rs +++ b/crates/game/src/main.rs @@ -50,6 +50,7 @@ impl WindowState { fn handle_draw_request(&mut self, window_id: WindowId) { _ = window_id; info!("TODO: implement draw request"); + self.renderer.debug_draw().expect("drawing"); } } @@ -71,7 +72,7 @@ impl ApplicationHandler for WindowState { height: size.height, }; - self.renderer.new_window_context( + let _ = self.renderer.new_window_context( extent, window_id, self.window diff --git a/crates/renderer/src/lib.rs b/crates/renderer/src/lib.rs index 0beeeeb..0365461 100644 --- a/crates/renderer/src/lib.rs +++ b/crates/renderer/src/lib.rs @@ -13,6 +13,12 @@ use dyn_clone::DynClone; use tinyvec::{array_vec, ArrayVec}; use winit::raw_window_handle::DisplayHandle; +mod commands; +mod images; +mod sync; + +type VkAllocator = Arc; + #[derive(Debug, thiserror::Error)] pub enum Error { #[error(transparent)] @@ -90,6 +96,15 @@ impl Queue { device.get_device_queue(family, index) }))) } + + pub fn with_locked T>(&self, map: F) -> T { + let lock = self.0.lock().expect("mutex lock poison"); + map(*lock) + } + + pub fn lock(&self) -> std::sync::MutexGuard<'_, vk::Queue> { + self.0.lock().unwrap() + } } trait ExtendsDeviceFeatures2Debug: @@ -198,6 +213,21 @@ impl PhysicalDeviceFeatures { } } + fn with_extension2(mut self, ext: vk::ExtensionProperties) -> Self { + self.device_extensions.push(ext); + + self + } + + fn with_extensions2>( + mut self, + exts: I, + ) -> Self { + self.device_extensions.extend(exts); + + self + } + fn with_extension( mut self, ext: vk::ExtensionProperties, @@ -409,31 +439,45 @@ struct Device { physical: PhysicalDevice, device: ash::Device, swapchain: khr::swapchain::Device, + main_queue: Queue, + compute_queue: Queue, + transfer_queue: Queue, + present_queue: Queue, } -impl Device { - fn new( - device: ash::Device, - physical: PhysicalDevice, - swapchain: khr::swapchain::Device, - ) -> Self { - Self { - device, - physical, - swapchain, - } +#[derive(Clone)] +struct Device2(Arc); + +impl Device2 { + fn dev(&self) -> &ash::Device { + &self.0.device + } + fn swapchain(&self) -> &khr::swapchain::Device { + &self.0.swapchain + } + 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 } } -impl AsRef for Device { +impl AsRef for Device2 { fn as_ref(&self) -> &khr::swapchain::Device { - &self.swapchain + &self.0.swapchain } } -impl AsRef for Device { +impl AsRef for Device2 { fn as_ref(&self) -> &ash::Device { - &self.device + &self.0.device } } @@ -560,8 +604,14 @@ impl Swapchain { .cloned() .expect("no surface format available!"); - let image_count = - 3u32.clamp(caps.min_image_count, caps.max_image_count); + let image_count = 3u32.clamp( + caps.min_image_count, + if caps.max_image_count == 0 { + u32::MAX + } else { + caps.max_image_count + }, + ); let extent = current_extent_or_clamped(&caps, requested_extent); @@ -767,8 +817,8 @@ impl Drop for Surface { pub struct Vulkan { instance: Arc, - device: DeviceAndQueues, - alloc: Arc, + device: Arc, + alloc: VkAllocator, } impl Vulkan { @@ -907,13 +957,13 @@ impl Vulkan { ) .with_extension( make_extention_properties( - ash::khr::index_type_uint8::NAME, - ash::khr::index_type_uint8::SPEC_VERSION, + ash::ext::index_type_uint8::NAME, + ash::ext::index_type_uint8::SPEC_VERSION, ), - vk::PhysicalDeviceIndexTypeUint8FeaturesKHR::default() + vk::PhysicalDeviceIndexTypeUint8FeaturesEXT::default() .index_type_uint8(true), ) - .device_extensions(vec![ + .with_extensions2([ make_extention_properties( khr::swapchain::NAME, khr::swapchain::SPEC_VERSION, @@ -938,19 +988,20 @@ impl Vulkan { )?; tracing::debug!("pdev: {pdev:?}"); - let dev = Self::create_device(&instance, pdev, &mut features)?; + let device = + Arc::new(Self::create_device(&instance, pdev, &mut features)?); let alloc_info = vk_mem::AllocatorCreateInfo::new( &instance.instance, - dev.as_ref(), - dev.device.physical.pdev, + &device.device, + device.physical.pdev, ); let alloc = Arc::new(unsafe { vk_mem::Allocator::new(alloc_info)? }); Ok(Self { instance, - device: dev, + device, alloc, }) } @@ -1145,13 +1196,16 @@ impl Vulkan { instance: &Instance, pdev: PhysicalDevice, features: &mut PhysicalDeviceFeatures, - ) -> Result { + ) -> Result { let mut unique_families = BTreeMap::::new(); let mut helper = |family: u32| { use std::collections::btree_map::Entry; let index = match unique_families.entry(family) { - Entry::Vacant(vacant_entry) => *vacant_entry.insert(0), + Entry::Vacant(vacant_entry) => { + vacant_entry.insert(1); + 0 + } Entry::Occupied(mut occupied_entry) => { let idx = occupied_entry.get_mut(); *idx += 1; @@ -1162,6 +1216,8 @@ impl Vulkan { (family, index) }; + eprintln!("queue families: {:?}", pdev.queue_families); + let graphics_family_and_index = helper(pdev.queue_families.graphics); let compute_family_and_index = pdev.queue_families.async_compute.map(|f| helper(f)); @@ -1176,8 +1232,11 @@ impl Vulkan { as usize ]; + eprintln!("unique_families: {unique_families:?}"); + let queue_infos = unique_families .into_iter() + .filter(|&(_, count)| count > 0) .map(|(family, queues)| { vk::DeviceQueueCreateInfo::default() .queue_family_index(family) @@ -1185,6 +1244,8 @@ impl Vulkan { }) .collect::>(); + eprintln!("infos: {queue_infos:#?}"); + let extensions = features .device_extensions .iter() @@ -1197,7 +1258,7 @@ impl Vulkan { .enabled_extension_names(&extensions) .push_next(&mut features2); - let device_and_queues = unsafe { + let device = unsafe { let device = instance.instance.create_device( pdev.pdev, &device_info, @@ -1222,15 +1283,13 @@ impl Vulkan { .map(|(f, i)| Queue::new(&device, f, i)) .unwrap_or(compute_queue.clone()); - DeviceAndQueues { - device: Arc::new(Device { - device: device.clone(), - physical: pdev, - swapchain: khr::swapchain::Device::new( - &instance.instance, - &device, - ), - }), + Device { + device: device.clone(), + physical: pdev, + swapchain: khr::swapchain::Device::new( + &instance.instance, + &device, + ), main_queue, present_queue, compute_queue, @@ -1238,7 +1297,7 @@ impl Vulkan { } }; - Ok(device_and_queues) + Ok(device) } fn choose_physical_device( @@ -1417,7 +1476,7 @@ pub struct WindowContext { } impl WindowContext { - pub fn new( + fn new( instance: Arc, device: Arc, extent: vk::Extent2D, @@ -1468,11 +1527,133 @@ impl Renderer { } pub fn debug_draw(&mut self) -> Result<()> { - let dev = self.vulkan.device.device.clone(); + let dev = Device2(self.vulkan.device.clone()); - unsafe { dev.device.device_wait_idle()? }; + unsafe { dev.dev().device_wait_idle()? }; - todo!() + let pool = commands::SingleUseCommandPool::new( + dev.clone(), + dev.queue_families().graphics, + )?; + + for ctx in self.window_contexts.values() { + let cmd = + commands::SingleUseCommand::new(dev.clone(), pool.pool())?; + let buffer = cmd.command_buffer(); + + let extent = ctx.current_swapchain.extent; + + let ready_semaphore = sync::Semaphore::new(dev.clone())?; + let (swapchain_index, suboptimal) = unsafe { + dev.swapchain().acquire_next_image( + ctx.current_swapchain.swapchain, + u64::MAX, + ready_semaphore.semaphore(), + vk::Fence::null(), + )? + }; + if suboptimal { + continue; + } + + let image = ctx.current_swapchain.images.first().cloned().unwrap(); + + // let image = images::Image2D::new_exclusive( + // self.vulkan.alloc.clone(), + // extent, + // 1, + // 1, + // vk::Format::R8G8B8A8_UNORM, + // vk::ImageTiling::OPTIMAL, + // vk::ImageUsageFlags::TRANSFER_SRC, + // vk_mem::MemoryUsage::AutoPreferDevice, + // vk_mem::AllocationCreateFlags::empty(), + // )?; + + // let view = image.view(&dev, vk::ImageAspectFlags::COLOR)?; + + let clear_values = vk::ClearColorValue { + float32: [0.275, 0.769, 0.941, 1.0], + }; + + unsafe { + let barriers = [images::image_barrier( + 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, + )]; + + let dependency_info = vk::DependencyInfo::default() + .dependency_flags(vk::DependencyFlags::BY_REGION) + .image_memory_barriers(&barriers); + + dev.dev().cmd_pipeline_barrier2(buffer, &dependency_info); + dev.dev().cmd_clear_color_image( + buffer, + image, + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + &clear_values, + &[vk::ImageSubresourceRange::default() + .aspect_mask(vk::ImageAspectFlags::COLOR) + .base_mip_level(0) + .base_array_layer(0) + .level_count(vk::REMAINING_MIP_LEVELS) + .layer_count(vk::REMAINING_ARRAY_LAYERS)], + ); + + let barriers = [images::image_barrier( + image, + vk::ImageAspectFlags::COLOR, + vk::PipelineStageFlags2::TRANSFER, + vk::AccessFlags2::TRANSFER_WRITE, + vk::PipelineStageFlags2::BOTTOM_OF_PIPE, + vk::AccessFlags2::empty(), + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + vk::ImageLayout::PRESENT_SRC_KHR, + None, + )]; + + let dependency_info = vk::DependencyInfo::default() + .dependency_flags(vk::DependencyFlags::BY_REGION) + .image_memory_barriers(&barriers); + + dev.dev().cmd_pipeline_barrier2(buffer, &dependency_info); + + let signal_semaphore = sync::Semaphore::new(dev.clone())?; + + let future = cmd.submit_async( + dev.graphics_queue().clone(), + Some(( + ready_semaphore.semaphore(), + vk::PipelineStageFlags::TOP_OF_PIPE, + )), + Some(signal_semaphore.semaphore()), + )?; + + let wait_semaphores = [signal_semaphore.semaphore()]; + let swapchains = [ctx.current_swapchain.swapchain]; + let indices = [swapchain_index]; + let present_info = vk::PresentInfoKHR::default() + .image_indices(&indices) + .swapchains(&swapchains) + .wait_semaphores(&wait_semaphores); + dev.present_queue().with_locked(|queue| { + dev.swapchain().queue_present(queue, &present_info) + })?; + + future.block_until()?; + } + } + + //unsafe {dev.dev().} + + Ok(()) } pub fn new_window_context( @@ -1486,7 +1667,7 @@ impl Renderer { Entry::Vacant(entry) => { let ctx = WindowContext::new( self.vulkan.instance.clone(), - self.vulkan.device.device.clone(), + self.vulkan.device.clone(), extent, window.as_raw(), self.display,