stuff?
This commit is contained in:
parent
99c86c0c85
commit
29258aed7b
|
@ -20,6 +20,7 @@ vk-sync = "0.1.6"
|
|||
winit = "0.30.5"
|
||||
tinyvec = "1.8"
|
||||
rand = "0.8.5"
|
||||
tokio = "1.42.0"
|
||||
|
||||
futures = "0.3"
|
||||
smol = "2.0"
|
||||
|
|
|
@ -6,6 +6,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
tinyvec = {workspace = true}
|
||||
rand = {workspace = true}
|
||||
tokio = {workspace = true, features = ["rt", "sync"]}
|
||||
dyn-clone = "1"
|
||||
anyhow = "1.0.89"
|
||||
ash = "0.38.0"
|
||||
|
|
205
crates/renderer/src/commands.rs
Normal file
205
crates/renderer/src/commands.rs
Normal file
|
@ -0,0 +1,205 @@
|
|||
use std::{future::Future, marker::PhantomData};
|
||||
|
||||
use super::{Device2 as Device, Queue};
|
||||
use ash::{prelude::*, vk};
|
||||
|
||||
pub struct FenceFuture<'a> {
|
||||
device: Device,
|
||||
fence: vk::Fence,
|
||||
_pd: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl Drop for FenceFuture<'_> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { self.device.dev().destroy_fence(self.fence, None) };
|
||||
}
|
||||
}
|
||||
|
||||
impl FenceFuture<'_> {
|
||||
/// Unsafe because `fence` must not be destroyed while this future is live.
|
||||
pub unsafe fn from_fence(device: Device, fence: vk::Fence) -> Self {
|
||||
Self {
|
||||
device,
|
||||
fence,
|
||||
_pd: PhantomData,
|
||||
}
|
||||
}
|
||||
pub fn block_until(&self) -> VkResult<()> {
|
||||
unsafe {
|
||||
self.device
|
||||
.dev()
|
||||
.wait_for_fences(&[self.fence], true, u64::MAX)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Future for FenceFuture<'_> {
|
||||
type Output = ();
|
||||
|
||||
fn poll(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
) -> std::task::Poll<Self::Output> {
|
||||
let signaled = unsafe {
|
||||
self.device
|
||||
.dev()
|
||||
.get_fence_status(self.fence)
|
||||
.unwrap_or(false)
|
||||
};
|
||||
|
||||
if signaled {
|
||||
std::task::Poll::Ready(())
|
||||
} else {
|
||||
tokio::task::spawn_blocking(move || {});
|
||||
std::task::Poll::Pending
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SingleUseCommandPool {
|
||||
device: Device,
|
||||
pool: vk::CommandPool,
|
||||
}
|
||||
|
||||
impl Drop for SingleUseCommandPool {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.device.dev().destroy_command_pool(self.pool, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SingleUseCommandPool {
|
||||
pub fn new(device: Device, family_index: u32) -> VkResult<Self> {
|
||||
let pool_info = vk::CommandPoolCreateInfo::default()
|
||||
.queue_family_index(family_index)
|
||||
.flags(vk::CommandPoolCreateFlags::TRANSIENT);
|
||||
|
||||
let pool =
|
||||
unsafe { device.dev().create_command_pool(&pool_info, None)? };
|
||||
|
||||
Ok(Self { device, pool })
|
||||
}
|
||||
|
||||
pub fn pool(&self) -> vk::CommandPool {
|
||||
self.pool
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SingleUseCommand {
|
||||
device: Device,
|
||||
pool: vk::CommandPool,
|
||||
buffer: vk::CommandBuffer,
|
||||
}
|
||||
|
||||
impl Drop for SingleUseCommand {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.device
|
||||
.dev()
|
||||
.free_command_buffers(self.pool, &[self.buffer])
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl SingleUseCommand {
|
||||
pub fn new(device: Device, pool: vk::CommandPool) -> VkResult<Self> {
|
||||
let buffer = unsafe {
|
||||
let alloc_info = vk::CommandBufferAllocateInfo::default()
|
||||
.command_buffer_count(1)
|
||||
.command_pool(pool)
|
||||
.level(vk::CommandBufferLevel::PRIMARY);
|
||||
let buffer = device.dev().allocate_command_buffers(&alloc_info)?[0];
|
||||
|
||||
let begin_info = vk::CommandBufferBeginInfo::default()
|
||||
.flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT);
|
||||
device.dev().begin_command_buffer(buffer, &begin_info)?;
|
||||
|
||||
buffer
|
||||
};
|
||||
Ok(Self {
|
||||
device,
|
||||
pool,
|
||||
buffer,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn command_buffer(&self) -> vk::CommandBuffer {
|
||||
self.buffer
|
||||
}
|
||||
|
||||
fn submit_fence(
|
||||
&self,
|
||||
queue: Queue,
|
||||
wait: Option<(vk::Semaphore, vk::PipelineStageFlags)>,
|
||||
signal: Option<vk::Semaphore>,
|
||||
) -> VkResult<vk::Fence> {
|
||||
unsafe { self.device.dev().end_command_buffer(self.buffer)? };
|
||||
|
||||
let buffers = [self.buffer];
|
||||
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,
|
||||
)
|
||||
});
|
||||
}
|
||||
if let Some((semaphore, stage)) = wait.as_ref() {
|
||||
submit_info = submit_info
|
||||
.wait_semaphores(core::slice::from_ref(semaphore))
|
||||
.wait_dst_stage_mask(core::slice::from_ref(stage));
|
||||
}
|
||||
|
||||
let fence = {
|
||||
let create_info = vk::FenceCreateInfo::default();
|
||||
unsafe { self.device.dev().create_fence(&create_info, None)? }
|
||||
};
|
||||
|
||||
queue.with_locked(|queue| unsafe {
|
||||
self.device.dev().queue_submit(queue, &[submit_info], fence)
|
||||
})?;
|
||||
|
||||
Ok(fence)
|
||||
}
|
||||
|
||||
pub fn submit_async<'a>(
|
||||
&'a self,
|
||||
queue: Queue,
|
||||
wait: Option<(vk::Semaphore, vk::PipelineStageFlags)>,
|
||||
signal: Option<vk::Semaphore>,
|
||||
) -> VkResult<FenceFuture<'a>> {
|
||||
let device = self.device.clone();
|
||||
let fence = self.submit_fence(queue, wait, signal)?;
|
||||
|
||||
Ok(unsafe { FenceFuture::from_fence(device, fence) })
|
||||
}
|
||||
|
||||
pub fn submit_blocking(
|
||||
self,
|
||||
queue: Queue,
|
||||
wait: Option<(vk::Semaphore, vk::PipelineStageFlags)>,
|
||||
signal: Option<vk::Semaphore>,
|
||||
) -> VkResult<()> {
|
||||
let device = self.device.clone();
|
||||
let fence = self.submit_fence(queue, wait, signal)?;
|
||||
|
||||
unsafe {
|
||||
device.dev().wait_for_fences(&[fence], true, u64::MAX)?;
|
||||
device.dev().destroy_fence(fence, None);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
async fn async_submit(cmd: SingleUseCommand, queue: Queue) {
|
||||
cmd.submit_async(queue, None, None).unwrap().await;
|
||||
}
|
||||
}
|
137
crates/renderer/src/images.rs
Normal file
137
crates/renderer/src/images.rs
Normal file
|
@ -0,0 +1,137 @@
|
|||
use super::{Device2 as Device, Queue, VkAllocator};
|
||||
use ash::{prelude::*, vk};
|
||||
use vk_mem::Alloc;
|
||||
|
||||
pub struct Image2D {
|
||||
alloc: VkAllocator,
|
||||
image: vk::Image,
|
||||
size: vk::Extent2D,
|
||||
mip_levels: u32,
|
||||
format: vk::Format,
|
||||
allocation: vk_mem::Allocation,
|
||||
}
|
||||
|
||||
impl Image2D {
|
||||
pub fn new_exclusive(
|
||||
alloc: VkAllocator,
|
||||
extent: vk::Extent2D,
|
||||
mip_levels: u32,
|
||||
array_layers: u32,
|
||||
format: vk::Format,
|
||||
tiling: vk::ImageTiling,
|
||||
usage: vk::ImageUsageFlags,
|
||||
memory_usage: vk_mem::MemoryUsage,
|
||||
alloc_flags: vk_mem::AllocationCreateFlags,
|
||||
) -> VkResult<Image2D> {
|
||||
let create_info = vk::ImageCreateInfo::default()
|
||||
.array_layers(array_layers)
|
||||
.mip_levels(mip_levels)
|
||||
.extent(vk::Extent3D {
|
||||
width: extent.width,
|
||||
height: extent.height,
|
||||
depth: 1,
|
||||
})
|
||||
.image_type(vk::ImageType::TYPE_2D)
|
||||
.format(format)
|
||||
.tiling(tiling)
|
||||
.initial_layout(vk::ImageLayout::UNDEFINED)
|
||||
.usage(usage)
|
||||
.sharing_mode(vk::SharingMode::EXCLUSIVE)
|
||||
.samples(vk::SampleCountFlags::TYPE_1);
|
||||
|
||||
let alloc_info = vk_mem::AllocationCreateInfo {
|
||||
usage: memory_usage,
|
||||
flags: alloc_flags,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let (image, allocation) =
|
||||
unsafe { alloc.create_image(&create_info, &alloc_info)? };
|
||||
|
||||
Ok(Self {
|
||||
alloc,
|
||||
image,
|
||||
size: extent,
|
||||
mip_levels,
|
||||
format,
|
||||
allocation,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn view(
|
||||
&self,
|
||||
device: &Device,
|
||||
aspect: vk::ImageAspectFlags,
|
||||
) -> VkResult<vk::ImageView> {
|
||||
let create_info = vk::ImageViewCreateInfo::default()
|
||||
.image(self.image)
|
||||
.view_type(vk::ImageViewType::TYPE_2D)
|
||||
.format(self.format)
|
||||
.components(vk::ComponentMapping::default())
|
||||
.subresource_range(
|
||||
vk::ImageSubresourceRange::default()
|
||||
.aspect_mask(aspect)
|
||||
.base_mip_level(0)
|
||||
.level_count(self.mip_levels)
|
||||
.base_array_layer(0)
|
||||
.layer_count(1),
|
||||
);
|
||||
|
||||
let view =
|
||||
unsafe { device.dev().create_image_view(&create_info, None)? };
|
||||
|
||||
Ok(view)
|
||||
}
|
||||
|
||||
pub fn image(&self) -> vk::Image {
|
||||
self.image
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Image2D {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.alloc.destroy_image(self.image, &mut self.allocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct QueueOwnership {
|
||||
src: u32,
|
||||
dst: u32,
|
||||
}
|
||||
|
||||
pub fn image_barrier<'a>(
|
||||
image: vk::Image,
|
||||
aspects: vk::ImageAspectFlags,
|
||||
src_stage: vk::PipelineStageFlags2,
|
||||
src_access: vk::AccessFlags2,
|
||||
dst_stage: vk::PipelineStageFlags2,
|
||||
dst_access: vk::AccessFlags2,
|
||||
old_layout: vk::ImageLayout,
|
||||
new_layout: vk::ImageLayout,
|
||||
queue_ownership_op: Option<QueueOwnership>,
|
||||
) -> vk::ImageMemoryBarrier2<'a> {
|
||||
let (src_family, dst_family) = queue_ownership_op
|
||||
.map(|t| (t.src, t.dst))
|
||||
.unwrap_or((vk::QUEUE_FAMILY_IGNORED, vk::QUEUE_FAMILY_IGNORED));
|
||||
|
||||
vk::ImageMemoryBarrier2::default()
|
||||
.image(image)
|
||||
.subresource_range(
|
||||
vk::ImageSubresourceRange::default()
|
||||
.aspect_mask(aspects)
|
||||
.base_mip_level(0)
|
||||
.base_array_layer(0)
|
||||
.level_count(vk::REMAINING_MIP_LEVELS)
|
||||
.layer_count(vk::REMAINING_ARRAY_LAYERS),
|
||||
)
|
||||
.src_stage_mask(src_stage)
|
||||
.src_access_mask(src_access)
|
||||
.dst_stage_mask(dst_stage)
|
||||
.dst_access_mask(dst_access)
|
||||
.dst_queue_family_index(dst_family)
|
||||
.src_queue_family_index(src_family)
|
||||
.old_layout(old_layout)
|
||||
.new_layout(new_layout)
|
||||
}
|
|
@ -5,7 +5,7 @@ use std::{
|
|||
ffi::{CStr, CString},
|
||||
fmt::Debug,
|
||||
marker::PhantomData,
|
||||
sync::{Arc, Mutex},
|
||||
sync::{atomic::AtomicU64, Arc, Mutex},
|
||||
};
|
||||
|
||||
use ash::{
|
||||
|
@ -967,6 +967,22 @@ impl Vulkan {
|
|||
.mesh_shader(true)
|
||||
.task_shader(true),
|
||||
)
|
||||
.with_extension(
|
||||
make_extention_properties(
|
||||
ash::khr::present_id::NAME,
|
||||
ash::khr::present_id::SPEC_VERSION,
|
||||
),
|
||||
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),
|
||||
)
|
||||
.with_extension(
|
||||
make_extention_properties(
|
||||
ash::ext::index_type_uint8::NAME,
|
||||
|
@ -1649,16 +1665,31 @@ impl Renderer {
|
|||
let wait_semaphores = [signal_semaphore.semaphore()];
|
||||
let swapchains = [ctx.current_swapchain.swapchain];
|
||||
let indices = [swapchain_index];
|
||||
static PRESENT_ID: AtomicU64 = AtomicU64::new(1);
|
||||
let mut present_ids = [PRESENT_ID
|
||||
.fetch_add(1, std::sync::atomic::Ordering::Release)];
|
||||
let mut present_id =
|
||||
vk::PresentIdKHR::default().present_ids(&present_ids);
|
||||
let present_info = vk::PresentInfoKHR::default()
|
||||
.image_indices(&indices)
|
||||
.swapchains(&swapchains)
|
||||
.wait_semaphores(&wait_semaphores);
|
||||
.wait_semaphores(&wait_semaphores)
|
||||
.push_next(&mut present_id);
|
||||
dev.present_queue().with_locked(|queue| {
|
||||
dev.swapchain().queue_present(queue, &present_info)
|
||||
})?;
|
||||
|
||||
future.block_until()?;
|
||||
dev.dev().device_wait_idle();
|
||||
khr::present_wait::Device::new(
|
||||
&self.vulkan.instance.instance,
|
||||
&self.vulkan.device.device,
|
||||
)
|
||||
.wait_for_present(
|
||||
ctx.current_swapchain.swapchain,
|
||||
present_ids[0],
|
||||
u64::MAX,
|
||||
)?;
|
||||
// dev.dev().device_wait_idle();
|
||||
drop(ready_semaphore);
|
||||
drop(signal_semaphore);
|
||||
}
|
||||
|
|
42
crates/renderer/src/sync.rs
Normal file
42
crates/renderer/src/sync.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use super::Device2 as Device;
|
||||
use ash::{prelude::*, vk};
|
||||
|
||||
pub struct Semaphore {
|
||||
device: Device,
|
||||
inner: vk::Semaphore,
|
||||
}
|
||||
|
||||
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)? };
|
||||
|
||||
Ok(Self { device, inner })
|
||||
}
|
||||
pub fn new_timeline(device: Device, value: u64) -> VkResult<Self> {
|
||||
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)? };
|
||||
|
||||
Ok(Self { device, inner })
|
||||
}
|
||||
pub fn semaphore(&self) -> vk::Semaphore {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Semaphore {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.device.dev().destroy_semaphore(self.inner, None);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue