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:
parent
f7e6a92018
commit
f0fff72bce
|
@ -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"
|
||||
egui = "0.30"
|
||||
egui_winit_platform = "0.25"
|
|
@ -11,3 +11,4 @@ renderer = { path = "../renderer" }
|
|||
|
||||
egui = { workspace = true }
|
||||
egui_winit_platform = { workspace = true }
|
||||
egui_demo_lib = "0.30.0"
|
||||
|
|
|
@ -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<u64, ()>,
|
||||
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<u32>,
|
||||
) {
|
||||
fn handle_final_resize(&mut self, window_id: WindowId, new_size: PhysicalSize<u32>) {
|
||||
_ = (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);
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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<Arc<Self>> {
|
||||
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<MappedBuffer<'_>> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<SingleUseCommandPool>,
|
||||
) -> VkResult<Self> {
|
||||
pub fn new(device: Device, pool: Arc<SingleUseCommandPool>) -> VkResult<Self> {
|
||||
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() {
|
||||
|
|
314
crates/renderer/src/device.rs
Normal file
314
crates/renderer/src/device.rs
Normal 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
|
||||
}
|
||||
}
|
|
@ -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<String>,
|
||||
}
|
||||
|
||||
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<Arc<Self>> {
|
||||
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<Self>,
|
||||
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 {
|
||||
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,
|
||||
};
|
||||
};
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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));
|
||||
|
|
|
@ -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<std::sync::Barrier>) {
|
||||
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 {
|
||||
|
@ -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<u64>) -> 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<vk::Fence> for Fence {
|
|||
|
||||
impl Semaphore {
|
||||
pub fn new(device: Device) -> VkResult<Self> {
|
||||
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 })
|
||||
}
|
||||
|
|
|
@ -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<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> {
|
||||
type Guard: Deref<Target = T> + '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,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue