idek so much when i thought i was only doing egui integration

egui cant draw yet, but textures are loaded/updated
This commit is contained in:
Janis 2024-12-29 15:48:55 +01:00
parent f7e6a92018
commit f0fff72bce
12 changed files with 985 additions and 771 deletions

View file

@ -12,7 +12,7 @@ anyhow = "1.0.89"
ash = "0.38.0" ash = "0.38.0"
ash-window = "0.13.0" ash-window = "0.13.0"
glam = "0.29.0" glam = "0.29.0"
thiserror = "1.0.64" thiserror = "2.0"
tracing = "0.1.40" tracing = "0.1.40"
tracing-subscriber = "0.3.18" tracing-subscriber = "0.3.18"
vk-mem = "0.4.0" vk-mem = "0.4.0"
@ -28,5 +28,5 @@ rayon = "1.10"
winit = {version = "0.30.5", features = ["rwh_06"]} winit = {version = "0.30.5", features = ["rwh_06"]}
raw-window-handle = "0.6" raw-window-handle = "0.6"
egui = "0.30.0" egui = "0.30"
egui_winit_platform = "0.24.0" egui_winit_platform = "0.25"

View file

@ -11,3 +11,4 @@ renderer = { path = "../renderer" }
egui = { workspace = true } egui = { workspace = true }
egui_winit_platform = { workspace = true } egui_winit_platform = { workspace = true }
egui_demo_lib = "0.30.0"

View file

@ -2,6 +2,7 @@ use std::collections::BTreeMap;
use renderer::Renderer; use renderer::Renderer;
use tracing::info; use tracing::info;
use tracing_subscriber::EnvFilter;
use winit::{ use winit::{
application::ApplicationHandler, application::ApplicationHandler,
dpi::{LogicalSize, PhysicalSize}, dpi::{LogicalSize, PhysicalSize},
@ -14,10 +15,7 @@ use winit::{
struct WindowState { struct WindowState {
window: Window, window: Window,
egui_platform: egui_winit_platform::Platform, egui_platform: egui_winit_platform::Platform,
} demo_app: egui_demo_lib::DemoWindows,
struct EguiRenderState {
textures: BTreeMap<u64, ()>,
} }
struct WinitState { struct WinitState {
@ -37,20 +35,13 @@ impl WinitState {
window_attrs: WindowAttributes::default() window_attrs: WindowAttributes::default()
.with_title(window_title) .with_title(window_title)
.with_resizable(true) .with_resizable(true)
.with_inner_size(LogicalSize::new( .with_inner_size(LogicalSize::new(Self::BASE_WIDTH, Self::BASE_HEIGHT)),
Self::BASE_WIDTH,
Self::BASE_HEIGHT,
)),
// TODO: pass down this error and add some kind of error handling UI or dump // TODO: pass down this error and add some kind of error handling UI or dump
renderer: Renderer::new(display.as_raw()).expect("renderer"), renderer: Renderer::new(display.as_raw()).expect("renderer"),
} }
} }
fn handle_final_resize( fn handle_final_resize(&mut self, window_id: WindowId, new_size: PhysicalSize<u32>) {
&mut self,
window_id: WindowId,
new_size: PhysicalSize<u32>,
) {
_ = (window_id, new_size); _ = (window_id, new_size);
info!("TODO: implement resize events"); info!("TODO: implement resize events");
if let Some(ctx) = self.renderer.window_contexts.get_mut(&window_id) { 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) { if let Some(window) = self.windows2.get_mut(&window_id) {
// egui // egui
window.egui_platform.begin_frame(); window.egui_platform.begin_pass();
let output = window.egui_platform.end_frame(Some(&window.window)); window.demo_app.ui(&window.egui_platform.context());
let output = window.egui_platform.end_pass(Some(&window.window));
let _draw_data = window self.renderer
.egui_platform .draw_egui(&window.egui_platform.context(), output);
.context()
.tessellate(output.shapes, output.pixels_per_point);
// rendering // rendering
self.renderer self.renderer
.debug_draw( .debug_draw(&window_id, || { // window.window.pre_present_notify()
&window_id, })
|| { // window.window.pre_present_notify()
},
)
.expect("drawing"); .expect("drawing");
window.window.request_redraw(); window.window.request_redraw();
} }
@ -98,10 +85,7 @@ impl WinitState {
self.renderer.window_contexts.remove(&window_id); self.renderer.window_contexts.remove(&window_id);
} }
fn create_window( fn create_window(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
&mut self,
event_loop: &winit::event_loop::ActiveEventLoop,
) {
let window = event_loop let window = event_loop
.create_window( .create_window(
self.window_attrs self.window_attrs
@ -132,6 +116,7 @@ impl WinitState {
window_id, window_id,
WindowState { WindowState {
window, window,
demo_app: egui_demo_lib::DemoWindows::default(),
egui_platform: egui_winit_platform::Platform::new( egui_platform: egui_winit_platform::Platform::new(
egui_winit_platform::PlatformDescriptor { egui_winit_platform::PlatformDescriptor {
physical_width: size.width, physical_width: size.width,
@ -152,10 +137,7 @@ impl ApplicationHandler for WinitState {
self.create_window(event_loop); self.create_window(event_loop);
} }
fn about_to_wait( fn about_to_wait(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
&mut self,
event_loop: &winit::event_loop::ActiveEventLoop,
) {
tracing::info!("winit::about_to_wait"); tracing::info!("winit::about_to_wait");
for (&window, &resize) in self.last_resize_events.clone().iter() { for (&window, &resize) in self.last_resize_events.clone().iter() {
self.handle_final_resize(window, resize); self.handle_final_resize(window, resize);
@ -192,9 +174,7 @@ impl ApplicationHandler for WinitState {
event: event:
winit::event::KeyEvent { winit::event::KeyEvent {
physical_key: physical_key:
winit::keyboard::PhysicalKey::Code( winit::keyboard::PhysicalKey::Code(winit::keyboard::KeyCode::KeyQ),
winit::keyboard::KeyCode::KeyQ,
),
state: ElementState::Pressed, state: ElementState::Pressed,
repeat: false, repeat: false,
.. ..
@ -207,9 +187,7 @@ impl ApplicationHandler for WinitState {
event: event:
winit::event::KeyEvent { winit::event::KeyEvent {
physical_key: physical_key:
winit::keyboard::PhysicalKey::Code( winit::keyboard::PhysicalKey::Code(winit::keyboard::KeyCode::Space),
winit::keyboard::KeyCode::Space,
),
state: ElementState::Pressed, state: ElementState::Pressed,
repeat: false, repeat: false,
.. ..
@ -247,7 +225,9 @@ impl ApplicationHandler for WinitState {
} }
fn main() { fn main() {
tracing_subscriber::fmt().init(); let _ = tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_default_env())
.init();
let ev = EventLoop::new().unwrap(); let ev = EventLoop::new().unwrap();
ev.set_control_flow(winit::event_loop::ControlFlow::Poll); ev.set_control_flow(winit::event_loop::ControlFlow::Poll);

View file

@ -12,7 +12,7 @@ anyhow = "1.0.89"
ash = "0.38.0" ash = "0.38.0"
ash-window = "0.13.0" ash-window = "0.13.0"
glam = "0.29.0" glam = "0.29.0"
thiserror = "1.0.64" thiserror = {workspace = true}
tracing = "0.1.40" tracing = "0.1.40"
tracing-subscriber = "0.3.18" tracing-subscriber = "0.3.18"
vk-mem = "0.4.0" vk-mem = "0.4.0"

View file

@ -1,4 +1,7 @@
use std::{ops::Deref, sync::Arc}; use std::{
ops::{Deref, DerefMut},
sync::Arc,
};
use ash::{prelude::VkResult, vk}; use ash::{prelude::VkResult, vk};
use vk_mem::Alloc; use vk_mem::Alloc;
@ -33,14 +36,15 @@ impl Buffer {
alloc_flags: vk_mem::AllocationCreateFlags, alloc_flags: vk_mem::AllocationCreateFlags,
) -> VkResult<Arc<Self>> { ) -> VkResult<Arc<Self>> {
let sharing_mode = if queue_families.len() > 1 { let sharing_mode = if queue_families.len() > 1 {
vk::SharingMode::EXCLUSIVE
} else {
vk::SharingMode::CONCURRENT vk::SharingMode::CONCURRENT
} else {
vk::SharingMode::EXCLUSIVE
}; };
let (buffer, allocation) = unsafe { let (buffer, allocation) = unsafe {
device.alloc().create_buffer( device.alloc().create_buffer(
&vk::BufferCreateInfo::default() &vk::BufferCreateInfo::default()
.size(size as u64)
.usage(usage) .usage(usage)
.queue_family_indices(queue_families) .queue_family_indices(queue_families)
.sharing_mode(sharing_mode), .sharing_mode(sharing_mode),
@ -66,17 +70,32 @@ impl Buffer {
pub fn map(&mut self) -> VkResult<MappedBuffer<'_>> { pub fn map(&mut self) -> VkResult<MappedBuffer<'_>> {
let bytes = unsafe { let bytes = unsafe {
let data = self.device.alloc().map_memory(&mut self.allocation)?; 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 slice
}; };
Ok(MappedBuffer { bytes }) Ok(MappedBuffer { inner: self, bytes })
}
pub fn buffer(&self) -> vk::Buffer {
self.buffer
} }
} }
pub struct MappedBuffer<'a> { 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<'_> { impl Deref for MappedBuffer<'_> {
@ -86,3 +105,9 @@ impl Deref for MappedBuffer<'_> {
self.bytes self.bytes
} }
} }
impl DerefMut for MappedBuffer<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.bytes
}
}

View file

@ -4,7 +4,7 @@ use crate::{
buffers::Buffer, buffers::Buffer,
images::{Image2D, QueueOwnership}, images::{Image2D, QueueOwnership},
sync::{self, FenceFuture}, sync::{self, FenceFuture},
util::{FormatExt, MutexExt}, util::{self, FormatExt, MutexExt},
}; };
use super::{Device, Queue}; use super::{Device, Queue};
@ -33,8 +33,7 @@ impl SingleUseCommandPool {
.queue_family_index(queue.family()) .queue_family_index(queue.family())
.flags(vk::CommandPoolCreateFlags::TRANSIENT); .flags(vk::CommandPoolCreateFlags::TRANSIENT);
let pool = let pool = unsafe { device.dev().create_command_pool(&pool_info, None)? };
unsafe { device.dev().create_command_pool(&pool_info, None)? };
Ok(Arc::new(Self { Ok(Arc::new(Self {
device, device,
@ -68,18 +67,15 @@ impl !Sync for SingleUseCommand {}
impl Drop for SingleUseCommand { impl Drop for SingleUseCommand {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
self.pool.pool.with_locked(|&pool| { self.pool
self.device.dev().free_command_buffers(pool, &[self.buffer]) .pool
}) .with_locked(|&pool| self.device.dev().free_command_buffers(pool, &[self.buffer]))
}; };
} }
} }
impl SingleUseCommand { impl SingleUseCommand {
pub fn new( pub fn new(device: Device, pool: Arc<SingleUseCommandPool>) -> VkResult<Self> {
device: Device,
pool: Arc<SingleUseCommandPool>,
) -> VkResult<Self> {
let buffer = unsafe { let buffer = unsafe {
let alloc_info = vk::CommandBufferAllocateInfo::default() let alloc_info = vk::CommandBufferAllocateInfo::default()
.command_buffer_count(1) .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( pub fn clear_color_image(
&self, &self,
image: vk::Image, image: vk::Image,
@ -194,15 +236,12 @@ impl SingleUseCommand {
unsafe { self.device.dev().end_command_buffer(self.buffer)? }; unsafe { self.device.dev().end_command_buffer(self.buffer)? };
let buffers = [self.buffer]; let buffers = [self.buffer];
let mut submit_info = let mut submit_info = vk::SubmitInfo::default().command_buffers(&buffers);
vk::SubmitInfo::default().command_buffers(&buffers);
if let Some(semaphore) = signal.as_ref() { if let Some(semaphore) = signal.as_ref() {
// SAFETY: T and [T;1] have the same layout // SAFETY: T and [T;1] have the same layout
submit_info = submit_info.signal_semaphores(unsafe { submit_info = submit_info.signal_semaphores(unsafe {
core::mem::transmute::<&vk::Semaphore, &[vk::Semaphore; 1]>( core::mem::transmute::<&vk::Semaphore, &[vk::Semaphore; 1]>(semaphore)
semaphore,
)
}); });
} }
if let Some((semaphore, stage)) = wait.as_ref() { if let Some((semaphore, stage)) = wait.as_ref() {

View file

@ -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<Instance>,
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<DeviceInner>);
pub type WeakDevice = std::sync::Weak<DeviceInner>;
impl Device {
pub fn new(
instance: Arc<Instance>,
physical: PhysicalDevice,
mut features: crate::PhysicalDeviceFeatures,
) -> VkResult<Self> {
// 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::<Vec<_>>();
let extensions = features
.device_extensions
.iter()
.map(|ext| ext.extension_name.as_ptr())
.collect::<Vec<_>>();
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::<BTreeMap<_, _>>();
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<khr::swapchain::Device> for Device {
fn as_ref(&self) -> &khr::swapchain::Device {
&self.0.swapchain
}
}
impl AsRef<ash::Device> 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<ash::Device> for DeviceAndQueues {
fn as_ref(&self) -> &ash::Device {
&self.device.as_ref()
}
}
impl AsRef<ash::khr::swapchain::Device> for DeviceAndQueues {
fn as_ref(&self) -> &ash::khr::swapchain::Device {
&self.device.as_ref()
}
}
#[derive(Clone)]
pub struct DeviceOwnedDebugObject<T> {
device: Device,
object: T,
name: Option<Cow<'static, str>>,
}
impl<T> DeviceOwnedDebugObject<T> {
fn new<S: Into<Cow<'static, str>>>(
device: crate::Device,
object: T,
name: Option<S>,
) -> ash::prelude::VkResult<Self>
where
T: vk::Handle + Copy,
{
let name = name.map(Into::<Cow<_>>::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
}
}

View file

@ -6,6 +6,7 @@ use super::{Device, Queue};
use ash::{prelude::*, vk}; use ash::{prelude::*, vk};
use vk_mem::Alloc; use vk_mem::Alloc;
#[derive(Debug)]
pub struct Image2D { pub struct Image2D {
device: Device, device: Device,
size: vk::Extent2D, size: vk::Extent2D,
@ -13,10 +14,12 @@ pub struct Image2D {
format: vk::Format, format: vk::Format,
image: vk::Image, image: vk::Image,
allocation: vk_mem::Allocation, allocation: vk_mem::Allocation,
name: Option<String>,
} }
impl Drop for Image2D { impl Drop for Image2D {
fn drop(&mut self) { fn drop(&mut self) {
tracing::debug!("destroying image {:?}", self);
unsafe { unsafe {
self.device self.device
.alloc() .alloc()
@ -36,6 +39,7 @@ impl Image2D {
usage: vk::ImageUsageFlags, usage: vk::ImageUsageFlags,
memory_usage: vk_mem::MemoryUsage, memory_usage: vk_mem::MemoryUsage,
alloc_flags: vk_mem::AllocationCreateFlags, alloc_flags: vk_mem::AllocationCreateFlags,
name: Option<&str>,
) -> VkResult<Arc<Self>> { ) -> VkResult<Arc<Self>> {
let create_info = vk::ImageCreateInfo::default() let create_info = vk::ImageCreateInfo::default()
.array_layers(array_layers) .array_layers(array_layers)
@ -62,6 +66,19 @@ impl Image2D {
let (image, allocation) = let (image, allocation) =
unsafe { device.alloc().create_image(&create_info, &alloc_info)? }; 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 { Ok(Arc::new(Self {
size: extent, size: extent,
mip_levels, mip_levels,
@ -69,6 +86,7 @@ impl Image2D {
device: device.clone(), device: device.clone(),
image, image,
allocation, allocation,
name: name.map(|s| s.to_owned()),
})) }))
} }
@ -76,12 +94,6 @@ impl Image2D {
self.format 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( pub fn view(
self: &Arc<Self>, self: &Arc<Self>,
device: &Device, device: &Device,
@ -101,8 +113,7 @@ impl Image2D {
.layer_count(1), .layer_count(1),
); );
let view = let view = unsafe { device.dev().create_image_view(&create_info, None)? };
unsafe { device.dev().create_image_view(&create_info, None)? };
Ok(Arc::new(ImageView2D { Ok(Arc::new(ImageView2D {
view, view,
@ -114,6 +125,15 @@ impl Image2D {
pub fn image(&self) -> vk::Image { pub fn image(&self) -> vk::Image {
self.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 { pub struct ImageView2D {
@ -172,11 +192,10 @@ pub fn image_barrier<'a>(
.new_layout(new_layout) .new_layout(new_layout)
} }
pub const SUBRESOURCERANGE_COLOR_ALL: vk::ImageSubresourceRange = pub const SUBRESOURCERANGE_COLOR_ALL: vk::ImageSubresourceRange = vk::ImageSubresourceRange {
vk::ImageSubresourceRange { aspect_mask: vk::ImageAspectFlags::COLOR,
aspect_mask: vk::ImageAspectFlags::COLOR, base_mip_level: 0,
base_mip_level: 0, level_count: vk::REMAINING_MIP_LEVELS,
level_count: vk::REMAINING_MIP_LEVELS, base_array_layer: 0,
base_array_layer: 0, layer_count: vk::REMAINING_ARRAY_LAYERS,
layer_count: vk::REMAINING_ARRAY_LAYERS, };
};

File diff suppressed because it is too large Load diff

View file

@ -14,8 +14,9 @@ impl std::hash::Hash for Rgba {
std::num::FpCategory::Infinite | std::num::FpCategory::Zero => { std::num::FpCategory::Infinite | std::num::FpCategory::Zero => {
(classify as u8, f.signum() as i8).hash(state) (classify as u8, f.signum() as i8).hash(state)
} }
std::num::FpCategory::Subnormal std::num::FpCategory::Subnormal | std::num::FpCategory::Normal => {
| std::num::FpCategory::Normal => f.to_bits().hash(state), f.to_bits().hash(state)
}
} }
} }
self.0.map(|f| hash_f32(state, f)); self.0.map(|f| hash_f32(state, f));

View file

@ -45,17 +45,15 @@ impl SyncThreadpool {
fn try_spawn_thread(&self) -> Option<()> { fn try_spawn_thread(&self) -> Option<()> {
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
match self.num_threads.fetch_update( match self
Ordering::Release, .num_threads
Ordering::Acquire, .fetch_update(Ordering::Release, Ordering::Acquire, |i| {
|i| {
if i < self.max_threads { if i < self.max_threads {
Some(i + 1) Some(i + 1)
} else { } else {
None None
} }
}, }) {
) {
Ok(tid) => { Ok(tid) => {
struct SyncThread { struct SyncThread {
timeout: u64, timeout: u64,
@ -68,22 +66,14 @@ impl SyncThreadpool {
fn run(self, barrier: Arc<std::sync::Barrier>) { fn run(self, barrier: Arc<std::sync::Barrier>) {
tracing::info!("spawned new sync thread"); tracing::info!("spawned new sync thread");
barrier.wait(); barrier.wait();
while let Ok((sync, waker)) = while let Ok((sync, waker)) = self.rx.recv_timeout(self.thread_dies_after) {
self.rx.recv_timeout(self.thread_dies_after) tracing::info!("received ({:?}, {:?})", sync, waker);
{
tracing::info!(
"received ({:?}, {:?})",
sync,
waker
);
loop { loop {
let wait_result = match &sync { let wait_result = match &sync {
SyncPrimitive::Fence(fence) => { SyncPrimitive::Fence(fence) => {
fence.wait_on(Some(self.timeout)) fence.wait_on(Some(self.timeout))
} }
SyncPrimitive::DeviceIdle(device) => { SyncPrimitive::DeviceIdle(device) => device.wait_idle(),
device.wait_idle()
}
}; };
match wait_result { match wait_result {
@ -95,7 +85,7 @@ impl SyncThreadpool {
Err(err) => { Err(err) => {
tracing::error!( tracing::error!(
"failed to wait on {sync:?} in waiter thread: {err}" "failed to wait on {sync:?} in waiter thread: {err}"
); );
break; break;
} }
} }
@ -197,8 +187,7 @@ impl Fence {
Ok(Self::new( Ok(Self::new(
dev.clone(), dev.clone(),
dev.dev().create_fence( dev.dev().create_fence(
&vk::FenceCreateInfo::default() &vk::FenceCreateInfo::default().flags(vk::FenceCreateFlags::SIGNALED),
.flags(vk::FenceCreateFlags::SIGNALED),
None, None,
)?, )?,
)) ))
@ -207,11 +196,9 @@ impl Fence {
pub fn wait_on(&self, timeout: Option<u64>) -> Result<(), vk::Result> { pub fn wait_on(&self, timeout: Option<u64>) -> Result<(), vk::Result> {
use core::slice::from_ref; use core::slice::from_ref;
unsafe { unsafe {
self.dev.dev().wait_for_fences( self.dev
from_ref(&self.fence), .dev()
true, .wait_for_fences(from_ref(&self.fence), true, timeout.unwrap_or(u64::MAX))
timeout.unwrap_or(u64::MAX),
)
} }
} }
pub fn fence(&self) -> vk::Fence { pub fn fence(&self) -> vk::Fence {
@ -236,12 +223,10 @@ impl AsRef<vk::Fence> for Fence {
impl Semaphore { impl Semaphore {
pub fn new(device: Device) -> VkResult<Self> { pub fn new(device: Device) -> VkResult<Self> {
let mut type_info = vk::SemaphoreTypeCreateInfo::default() let mut type_info =
.semaphore_type(vk::SemaphoreType::BINARY); vk::SemaphoreTypeCreateInfo::default().semaphore_type(vk::SemaphoreType::BINARY);
let create_info = let create_info = vk::SemaphoreCreateInfo::default().push_next(&mut type_info);
vk::SemaphoreCreateInfo::default().push_next(&mut type_info); let inner = unsafe { device.dev().create_semaphore(&create_info, None)? };
let inner =
unsafe { device.dev().create_semaphore(&create_info, None)? };
Ok(Self { device, inner }) Ok(Self { device, inner })
} }
@ -249,10 +234,8 @@ impl Semaphore {
let mut type_info = vk::SemaphoreTypeCreateInfo::default() let mut type_info = vk::SemaphoreTypeCreateInfo::default()
.semaphore_type(vk::SemaphoreType::TIMELINE) .semaphore_type(vk::SemaphoreType::TIMELINE)
.initial_value(value); .initial_value(value);
let create_info = let create_info = vk::SemaphoreCreateInfo::default().push_next(&mut type_info);
vk::SemaphoreCreateInfo::default().push_next(&mut type_info); let inner = unsafe { device.dev().create_semaphore(&create_info, None)? };
let inner =
unsafe { device.dev().create_semaphore(&create_info, None)? };
Ok(Self { device, inner }) Ok(Self { device, inner })
} }

View file

@ -1,7 +1,28 @@
use std::ops::Deref; use std::{borrow::Cow, ops::Deref};
use ash::vk; 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<u32>);
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::<u32>::new(inner)
.expect(&format!("integer overwarp for {}", stringify!($ty))),
)
}
}
};
}
pub trait MutexExt<'a, T: 'a> { pub trait MutexExt<'a, T: 'a> {
type Guard: Deref<Target = T> + 'a; type Guard: Deref<Target = T> + 'a;
fn lock(&'a self) -> Self::Guard; fn lock(&'a self) -> Self::Guard;
@ -239,3 +260,41 @@ impl FormatExt for vk::Format {
format_to_primitive(*self) == FormatComponentKind::SInt 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,
},
]
}
}