Compare commits
5 commits
0529ce0a3c
...
7c3f7120b0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c3f7120b0 | ||
|
|
260a61fb11 | ||
|
|
446a50bbc1 | ||
|
|
10b4d8a929 | ||
|
|
1f4a0abf21 |
|
|
@ -52,6 +52,9 @@ petgraph = "0.7"
|
||||||
itertools = "0.14.0"
|
itertools = "0.14.0"
|
||||||
ahash = "0.8"
|
ahash = "0.8"
|
||||||
|
|
||||||
|
# for non-cryptographic hashing of resources like pipelines, e.g. for caching
|
||||||
|
md-5 = "0.11.0"
|
||||||
|
|
||||||
parking_lot = "0.12.3"
|
parking_lot = "0.12.3"
|
||||||
|
|
||||||
tokio = "1.42"
|
tokio = "1.42"
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ vk-mem = { workspace = true }
|
||||||
gpu-allocator = { workspace = true }
|
gpu-allocator = { workspace = true }
|
||||||
rectangle-pack = { workspace = true }
|
rectangle-pack = { workspace = true }
|
||||||
|
|
||||||
|
md-5 = { workspace = true }
|
||||||
|
|
||||||
raw-window-handle = { workspace = true }
|
raw-window-handle = { workspace = true }
|
||||||
egui = { workspace = true , features = ["bytemuck"]}
|
egui = { workspace = true , features = ["bytemuck"]}
|
||||||
egui_winit_platform = { workspace = true }
|
egui_winit_platform = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -547,7 +547,7 @@ pub mod traits {
|
||||||
self.device().dev().cmd_bind_pipeline(
|
self.device().dev().cmd_bind_pipeline(
|
||||||
self.handle(),
|
self.handle(),
|
||||||
pipeline.bind_point(),
|
pipeline.bind_point(),
|
||||||
pipeline.handle(),
|
pipeline.raw(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
collections::{BTreeSet, HashMap, HashSet},
|
collections::{BTreeSet, HashMap, HashSet},
|
||||||
ffi::CStr,
|
ffi::CStr,
|
||||||
mem::ManuallyDrop,
|
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
@ -17,6 +16,7 @@ use raw_window_handle::RawDisplayHandle;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Instance, PhysicalDeviceFeatures, PhysicalDeviceInfo, Result,
|
Instance, PhysicalDeviceFeatures, PhysicalDeviceInfo, Result,
|
||||||
|
pipeline::pipeline_cache::PipelineCache,
|
||||||
queue::{DeviceQueueInfos, DeviceQueues, Queue},
|
queue::{DeviceQueueInfos, DeviceQueues, Queue},
|
||||||
sync::{self, BinarySemaphore, TimelineSemaphore},
|
sync::{self, BinarySemaphore, TimelineSemaphore},
|
||||||
};
|
};
|
||||||
|
|
@ -109,9 +109,16 @@ pub struct DeviceInner {
|
||||||
pub(crate) device_extensions: DeviceExtensions,
|
pub(crate) device_extensions: DeviceExtensions,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) enabled_extensions: Vec<&'static CStr>,
|
pub(crate) enabled_extensions: Vec<&'static CStr>,
|
||||||
|
|
||||||
_drop: DeviceDrop,
|
_drop: DeviceDrop,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AsRef<DeviceInner> for DeviceInner {
|
||||||
|
fn as_ref(&self) -> &DeviceInner {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl core::fmt::Debug for DeviceInner {
|
impl core::fmt::Debug for DeviceInner {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_struct("DeviceInner")
|
f.debug_struct("DeviceInner")
|
||||||
|
|
@ -437,19 +444,30 @@ impl PhysicalDeviceInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct DevicePools {
|
pub(crate) struct DevicePools {
|
||||||
pub(crate) fences: Pool<vk::Fence>,
|
pub(crate) fences: Arc<Pool<vk::Fence>>,
|
||||||
pub(crate) binary_semaphores: Pool<BinarySemaphore>,
|
pub(crate) binary_semaphores: Pool<BinarySemaphore>,
|
||||||
pub(crate) timeline_semaphores: Pool<TimelineSemaphore>,
|
pub(crate) timeline_semaphores: Pool<TimelineSemaphore>,
|
||||||
|
pub(crate) pipeline_cache: asdf::DeviceObject<PipelineCache, Arc<DeviceInner>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<DevicePools> for DevicePools {
|
||||||
|
fn as_ref(&self) -> &DevicePools {
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DevicePools {
|
impl DevicePools {
|
||||||
pub fn new(device: Arc<DeviceInner>) -> Self {
|
pub fn new(device: Arc<DeviceInner>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
fences: Pool::new(device.clone()),
|
fences: Arc::new(Pool::new(device.clone())),
|
||||||
binary_semaphores: Pool::new(device.clone()),
|
binary_semaphores: Pool::new(device.clone()),
|
||||||
timeline_semaphores: Pool::new(device),
|
timeline_semaphores: Pool::new(device.clone()),
|
||||||
|
pipeline_cache: asdf::DeviceObject::new(
|
||||||
|
device.clone(),
|
||||||
|
PipelineCache::new(&device.raw, &device.adapter).unwrap(),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -476,6 +494,16 @@ impl core::ops::Deref for Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> AsRef<T> for Device
|
||||||
|
where
|
||||||
|
T: ?Sized,
|
||||||
|
<Self as Deref>::Target: AsRef<T>,
|
||||||
|
{
|
||||||
|
fn as_ref(&self) -> &T {
|
||||||
|
self.deref().as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl DeviceInner {
|
impl DeviceInner {
|
||||||
pub fn sync_threadpool(&self) -> &sync::SyncThreadpool {
|
pub fn sync_threadpool(&self) -> &sync::SyncThreadpool {
|
||||||
&self.sync_threadpool
|
&self.sync_threadpool
|
||||||
|
|
@ -701,7 +729,7 @@ impl<T: DeviceHandle> DeviceObject<T> {
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
if let Some(name) = name.as_ref() {
|
if let Some(name) = name.as_ref() {
|
||||||
device.debug_name_object(inner.clone(), &name);
|
device.debug_name_object(inner.clone(), name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -726,7 +754,7 @@ impl<T: DeviceHandle> DeviceObject<T> {
|
||||||
pub fn name(&self) -> Option<&str> {
|
pub fn name(&self) -> Option<&str> {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
self.name.as_deref().map(|cow| cow.as_ref())
|
self.name.as_deref()
|
||||||
}
|
}
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
{
|
{
|
||||||
|
|
@ -744,6 +772,8 @@ impl<T: DeviceHandle> Drop for DeviceObject<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait DeviceHandle {
|
pub trait DeviceHandle {
|
||||||
|
/// # Safety
|
||||||
|
/// The caller must ensure this function is only called once for a given object.
|
||||||
unsafe fn destroy(&mut self, device: &Device);
|
unsafe fn destroy(&mut self, device: &Device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -774,11 +804,9 @@ impl DeviceHandle for vk::Buffer {
|
||||||
impl DeviceHandle for vk::SwapchainKHR {
|
impl DeviceHandle for vk::SwapchainKHR {
|
||||||
unsafe fn destroy(&mut self, device: &Device) {
|
unsafe fn destroy(&mut self, device: &Device) {
|
||||||
unsafe {
|
unsafe {
|
||||||
device
|
if let Some(swapchain) = device.device_extensions.swapchain.as_ref() {
|
||||||
.device_extensions
|
swapchain.destroy_swapchain(*self, None)
|
||||||
.swapchain
|
}
|
||||||
.as_ref()
|
|
||||||
.map(|swapchain| swapchain.destroy_swapchain(*self, None));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -792,52 +820,9 @@ pub trait Pooled: Sized {
|
||||||
fn create_from_pool(pool: &Pool<Self>) -> Result<Self>;
|
fn create_from_pool(pool: &Pool<Self>) -> Result<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PoolObject<T: Pooled + vk::Handle + Clone> {
|
#[derive(Debug)]
|
||||||
pub(crate) inner: ManuallyDrop<T>,
|
|
||||||
pub(crate) pool: Pool<T>,
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
pub(crate) name: Option<Cow<'static, str>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Pooled + vk::Handle + Clone> PoolObject<T> {
|
|
||||||
pub fn name_object(&mut self, name: impl Into<Cow<'static, str>>) {
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
unsafe {
|
|
||||||
self.name = Some(name.into());
|
|
||||||
self.pool
|
|
||||||
.device
|
|
||||||
.debug_name_object(T::clone(&self.inner), self.name.as_ref().unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn device(&self) -> &Arc<DeviceInner> {
|
|
||||||
&self.pool.device
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Pooled + vk::Handle + Clone> Drop for PoolObject<T> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
let handle = unsafe { ManuallyDrop::take(&mut self.inner) };
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
if self.name.is_some() {
|
|
||||||
unsafe { self.pool.device.debug_name_object(handle.clone(), "") };
|
|
||||||
}
|
|
||||||
|
|
||||||
self.pool.push(handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Pooled + vk::Handle + Clone> Deref for PoolObject<T> {
|
|
||||||
type Target = T;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.inner
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Pool<T> {
|
pub struct Pool<T> {
|
||||||
pub(crate) pool: Arc<Mutex<Vec<T>>>,
|
pub(crate) pool: Mutex<Vec<T>>,
|
||||||
pub(crate) device: Arc<DeviceInner>,
|
pub(crate) device: Arc<DeviceInner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -847,7 +832,7 @@ impl<T> Pool<T> {
|
||||||
}
|
}
|
||||||
pub fn new(device: Arc<DeviceInner>) -> Self {
|
pub fn new(device: Arc<DeviceInner>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pool: Arc::new(Mutex::new(Vec::new())),
|
pool: Mutex::new(Vec::new()),
|
||||||
device,
|
device,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -856,27 +841,37 @@ impl<T> Pool<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Pooled + vk::Handle + Clone> Pool<T> {
|
impl<T> AsRef<Pool<T>> for Pool<T> {
|
||||||
pub fn get(&self) -> Result<PoolObject<T>> {
|
fn as_ref(&self) -> &Pool<T> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type PoolObject<T, U = Arc<Pool<T>>> = asdf::ExternallyManagedObject<T, U>;
|
||||||
|
|
||||||
|
impl<T: Pooled> Pool<T> {
|
||||||
|
pub fn get(&self) -> Result<T> {
|
||||||
let item = if let Some(item) = self.pool.lock().pop() {
|
let item = if let Some(item) = self.pool.lock().pop() {
|
||||||
item
|
item
|
||||||
} else {
|
} else {
|
||||||
T::create_from_pool(self)?
|
T::create_from_pool(self)?
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(PoolObject {
|
Ok(item)
|
||||||
inner: ManuallyDrop::new(item),
|
|
||||||
pool: self.clone(),
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
name: None,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_named(&self, name: Option<impl Into<Cow<'static, str>>>) -> Result<PoolObject<T>> {
|
pub fn get_debug_named(&self, name: Option<impl Into<Cow<'static, str>>>) -> Result<T>
|
||||||
let mut obj = self.get()?;
|
where
|
||||||
if let Some(name) = name {
|
T: asdf::traits::DebugNameable,
|
||||||
obj.name_object(name);
|
{
|
||||||
|
let obj = self.get()?;
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
let name = name.map(Into::into).unwrap_or_default();
|
||||||
|
<T as asdf::traits::DebugNameable>::debug_name(&obj, &self.device, &name);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(obj)
|
Ok(obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -937,3 +932,233 @@ macro_rules! define_device_owned_handle {
|
||||||
)?
|
)?
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This module is an experiment in a more generic way to manage device-owned resources.
|
||||||
|
// #[cfg(false)]
|
||||||
|
pub(crate) mod asdf {
|
||||||
|
use std::{
|
||||||
|
mem::{ManuallyDrop, MaybeUninit},
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
use ash::vk;
|
||||||
|
|
||||||
|
use crate::{device::DeviceInner, util::DebugName};
|
||||||
|
|
||||||
|
pub mod traits {
|
||||||
|
/// A trait describing an object owned by some manager-type, which is
|
||||||
|
/// responsible for destroying it.
|
||||||
|
pub trait ExternallyManagedObject<T> {
|
||||||
|
/// # Safety
|
||||||
|
/// The caller must ensure this function is only called once for a given object.
|
||||||
|
unsafe fn destroy(self, owner: &T);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A trait describing an object which can have a debug name assigned to it.
|
||||||
|
pub trait DebugNameable {
|
||||||
|
fn debug_name(&self, device: &super::DeviceInner, name: &str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper for types which are owned by another type `O`, which is responsible for destruction.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ExternallyManagedObject<T: traits::ExternallyManagedObject<O>, O> {
|
||||||
|
inner: ManuallyDrop<T>,
|
||||||
|
owner: O,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: traits::ExternallyManagedObject<O>, O> Deref for ExternallyManagedObject<T, O> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: traits::ExternallyManagedObject<O>, O> DerefMut for ExternallyManagedObject<T, O> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: traits::ExternallyManagedObject<O>, O> ExternallyManagedObject<T, O> {
|
||||||
|
pub fn new(inner: T, owner: O) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: ManuallyDrop::new(inner),
|
||||||
|
owner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn owner(&self) -> &O {
|
||||||
|
&self.owner
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map_inner<U>(self, f: impl FnOnce(T) -> U) -> ExternallyManagedObject<U, O>
|
||||||
|
where
|
||||||
|
U: traits::ExternallyManagedObject<O>,
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
let mut this = MaybeUninit::new(self);
|
||||||
|
let inner = ManuallyDrop::take(&mut this.assume_init_mut().inner);
|
||||||
|
let owner = core::ptr::read(&raw const this.assume_init_mut().owner);
|
||||||
|
|
||||||
|
let new_inner = f(inner);
|
||||||
|
|
||||||
|
ExternallyManagedObject {
|
||||||
|
inner: ManuallyDrop::new(new_inner),
|
||||||
|
owner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn map_owner<U>(self, f: impl FnOnce(O) -> U) -> ExternallyManagedObject<T, U>
|
||||||
|
where
|
||||||
|
T: traits::ExternallyManagedObject<U>,
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
let mut this = MaybeUninit::new(self);
|
||||||
|
let inner = ManuallyDrop::take(&mut this.assume_init_mut().inner);
|
||||||
|
|
||||||
|
// get the old owner without calling `Self::drop`
|
||||||
|
let owner = core::ptr::read(&raw const this.assume_init_mut().owner);
|
||||||
|
|
||||||
|
ExternallyManagedObject {
|
||||||
|
inner: ManuallyDrop::new(inner),
|
||||||
|
owner: f(owner),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, O> Drop for ExternallyManagedObject<T, O>
|
||||||
|
where
|
||||||
|
T: traits::ExternallyManagedObject<O>,
|
||||||
|
{
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
let inner = ManuallyDrop::take(&mut self.inner);
|
||||||
|
inner.destroy(&self.owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A wrapper for vulkan types which are owned by the device, taking care of destruction.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DeviceObject<
|
||||||
|
T: traits::ExternallyManagedObject<O>,
|
||||||
|
O: AsRef<super::DeviceInner> = Arc<super::DeviceInner>,
|
||||||
|
> {
|
||||||
|
inner: ExternallyManagedObject<T, O>,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
name: Option<DebugName>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<
|
||||||
|
T: traits::ExternallyManagedObject<O> + traits::DebugNameable,
|
||||||
|
O: AsRef<super::DeviceInner>,
|
||||||
|
> DeviceObject<T, O>
|
||||||
|
{
|
||||||
|
pub fn new_debug_named(owner: O, inner: T, name: Option<impl Into<DebugName>>) -> Self {
|
||||||
|
let name = name.map(Into::into);
|
||||||
|
if let Some(ref name) = name {
|
||||||
|
traits::DebugNameable::debug_name(&inner, owner.as_ref(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
let obj = ExternallyManagedObject::new(inner, owner);
|
||||||
|
|
||||||
|
Self { inner: obj, name }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: traits::ExternallyManagedObject<O>, O: AsRef<super::DeviceInner>> DeviceObject<T, O> {
|
||||||
|
pub fn new(owner: O, inner: T) -> Self {
|
||||||
|
let inner = ExternallyManagedObject::new(inner, owner);
|
||||||
|
|
||||||
|
Self { inner, name: None }
|
||||||
|
}
|
||||||
|
pub fn device(&self) -> &O {
|
||||||
|
self.inner.owner()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, O> Deref for DeviceObject<T, O>
|
||||||
|
where
|
||||||
|
T: traits::ExternallyManagedObject<O>,
|
||||||
|
O: AsRef<super::DeviceInner>,
|
||||||
|
{
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod impls {
|
||||||
|
use crate::device::{DeviceInner, DevicePools, GpuAllocation};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl<T: AsRef<DeviceInner>> traits::ExternallyManagedObject<T> for ash::vk::Semaphore {
|
||||||
|
unsafe fn destroy(self, device: &T) {
|
||||||
|
unsafe {
|
||||||
|
device.as_ref().raw.destroy_semaphore(self, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: AsRef<DeviceInner>> traits::ExternallyManagedObject<T> for GpuAllocation {
|
||||||
|
unsafe fn destroy(self, device: &T) {
|
||||||
|
_ = device.as_ref().alloc2.lock().free(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl traits::ExternallyManagedObject<DevicePools> for vk::Semaphore {
|
||||||
|
unsafe fn destroy(self, owner: &DevicePools) {
|
||||||
|
owner
|
||||||
|
.binary_semaphores
|
||||||
|
.push(crate::sync::BinarySemaphore(self));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> traits::DebugNameable for T
|
||||||
|
where
|
||||||
|
T: vk::Handle + Copy,
|
||||||
|
{
|
||||||
|
fn debug_name(&self, device: &super::DeviceInner, name: &str) {
|
||||||
|
unsafe {
|
||||||
|
device.debug_name_object(*self, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[cfg(test)]
|
||||||
|
fn asdf() {
|
||||||
|
use crate::device::{DevicePools, GpuAllocation};
|
||||||
|
fn summon<T>() -> T {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
let _inner_ref: DeviceObject<vk::Semaphore, &DeviceInner> = DeviceObject::new_debug_named(
|
||||||
|
summon::<&DeviceInner>(),
|
||||||
|
summon::<vk::Semaphore>(),
|
||||||
|
Some("my semaphore"),
|
||||||
|
);
|
||||||
|
|
||||||
|
let _device_owned: DeviceObject<vk::Semaphore, super::Device> =
|
||||||
|
DeviceObject::new_debug_named(
|
||||||
|
summon::<super::Device>(),
|
||||||
|
summon::<vk::Semaphore>(),
|
||||||
|
Some("my other semaphore"),
|
||||||
|
);
|
||||||
|
|
||||||
|
let _allocation: DeviceObject<GpuAllocation, Arc<super::DeviceInner>> = DeviceObject::new(
|
||||||
|
summon::<Arc<super::DeviceInner>>(),
|
||||||
|
summon::<GpuAllocation>(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let _pool_owned: ExternallyManagedObject<vk::Semaphore, DevicePools> =
|
||||||
|
ExternallyManagedObject::new(summon::<vk::Semaphore>(), summon::<DevicePools>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -809,9 +809,9 @@ impl EguiState {
|
||||||
"crates/renderer/shaders/egui_vert.spv",
|
"crates/renderer/shaders/egui_vert.spv",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let pipeline = pipeline::Pipeline::new(
|
let pipeline = pipeline::Pipeline::new_graphics(
|
||||||
device.clone(),
|
device.clone(),
|
||||||
pipeline::PipelineDesc::Graphics(pipeline::GraphicsPipelineDesc {
|
pipeline::GraphicsPipelineDesc {
|
||||||
flags: Default::default(),
|
flags: Default::default(),
|
||||||
name: Some("egui-pipeline".into()),
|
name: Some("egui-pipeline".into()),
|
||||||
shader_stages: &[
|
shader_stages: &[
|
||||||
|
|
@ -904,7 +904,7 @@ impl EguiState {
|
||||||
dynamic_states: &[vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR],
|
dynamic_states: &[vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
}),
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use ash::{ext, prelude::*, vk};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
define_device_owned_handle,
|
define_device_owned_handle,
|
||||||
device::{Device, DeviceOwnedDebugObject},
|
device::{Device, DeviceHandle, DeviceObject},
|
||||||
make_extension,
|
make_extension,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -40,12 +40,6 @@ pub struct PipelineLayoutDesc<'a> {
|
||||||
pub name: Option<Cow<'static, str>>,
|
pub name: Option<Cow<'static, str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum PipelineDesc<'a> {
|
|
||||||
Compute(ComputePipelineDesc<'a>),
|
|
||||||
Graphics(GraphicsPipelineDesc<'a>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ComputePipelineDesc<'a> {
|
pub struct ComputePipelineDesc<'a> {
|
||||||
pub flags: vk::PipelineCreateFlags,
|
pub flags: vk::PipelineCreateFlags,
|
||||||
|
|
@ -251,18 +245,17 @@ impl DescriptorPool {
|
||||||
let info = &vk::DescriptorSetAllocateInfo::default()
|
let info = &vk::DescriptorSetAllocateInfo::default()
|
||||||
.descriptor_pool(self.handle())
|
.descriptor_pool(self.handle())
|
||||||
.set_layouts(&layouts);
|
.set_layouts(&layouts);
|
||||||
let sets = unsafe { self.device().dev().allocate_descriptor_sets(&info)? };
|
let sets = unsafe { self.device().dev().allocate_descriptor_sets(info)? };
|
||||||
|
|
||||||
for (&set, desc) in sets.iter().zip(descs) {
|
for (&set, desc) in sets.iter().zip(descs) {
|
||||||
if let Some(name) = desc.name.as_ref() {
|
if let Some(name) = desc.name.as_ref() {
|
||||||
unsafe { self.device().debug_name_object(set, &name) };
|
unsafe { self.device().debug_name_object(set, name) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(sets)
|
Ok(sets)
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn free(&self) {}
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn reset(&self) -> VkResult<()> {
|
pub fn reset(&self) -> VkResult<()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
@ -474,18 +467,13 @@ impl ShaderModule {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Pipeline {
|
pub struct Pipeline {
|
||||||
pipeline: DeviceOwnedDebugObject<vk::Pipeline>,
|
pipeline: DeviceObject<vk::Pipeline>,
|
||||||
bind_point: vk::PipelineBindPoint,
|
bind_point: vk::PipelineBindPoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Pipeline {
|
impl DeviceHandle for vk::Pipeline {
|
||||||
fn drop(&mut self) {
|
unsafe fn destroy(&mut self, device: &Device) {
|
||||||
unsafe {
|
unsafe { device.raw.destroy_pipeline(*self, None) };
|
||||||
self.pipeline
|
|
||||||
.dev()
|
|
||||||
.dev()
|
|
||||||
.destroy_pipeline(self.pipeline.handle(), None);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -500,224 +488,322 @@ impl ShaderStageDesc<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pipeline {
|
impl Pipeline {
|
||||||
pub fn new(device: Device, desc: PipelineDesc) -> VkResult<Self> {
|
pub fn new_compute(device: Device, desc: ComputePipelineDesc) -> crate::Result<Self> {
|
||||||
let name: Option<Cow<'static, str>>;
|
let info = &vk::ComputePipelineCreateInfo::default()
|
||||||
let bind_point: vk::PipelineBindPoint;
|
.flags(desc.flags)
|
||||||
let result = match desc {
|
.layout(desc.layout.handle())
|
||||||
PipelineDesc::Compute(desc) => {
|
.base_pipeline_handle(
|
||||||
name = desc.name;
|
desc.base_pipeline
|
||||||
bind_point = vk::PipelineBindPoint::COMPUTE;
|
.map(|p| p.raw())
|
||||||
let info = &vk::ComputePipelineCreateInfo::default()
|
.unwrap_or(vk::Pipeline::null()),
|
||||||
.flags(desc.flags)
|
)
|
||||||
.layout(desc.layout.handle())
|
.stage(desc.shader_stage.as_create_info());
|
||||||
.base_pipeline_handle(
|
|
||||||
desc.base_pipeline
|
|
||||||
.map(|p| p.handle())
|
|
||||||
.unwrap_or(vk::Pipeline::null()),
|
|
||||||
)
|
|
||||||
.stage(desc.shader_stage.as_create_info());
|
|
||||||
|
|
||||||
unsafe {
|
let pipeline = unsafe {
|
||||||
device.dev().create_compute_pipelines(
|
device
|
||||||
vk::PipelineCache::null(),
|
.dev()
|
||||||
core::slice::from_ref(info),
|
.create_compute_pipelines(
|
||||||
None,
|
device.pools.pipeline_cache.raw,
|
||||||
)
|
core::slice::from_ref(info),
|
||||||
}
|
None,
|
||||||
}
|
)
|
||||||
PipelineDesc::Graphics(desc) => {
|
// It's cool to just take the first one and ignore any
|
||||||
name = desc.name;
|
// potentially created pipelines since we know there wont be any
|
||||||
bind_point = vk::PipelineBindPoint::GRAPHICS;
|
// others.
|
||||||
|
.map_err(|(_, err)| err)?[0]
|
||||||
let stages = desc
|
|
||||||
.shader_stages
|
|
||||||
.iter()
|
|
||||||
.map(|stage| stage.as_create_info())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let vertex_input = desc.vertex_input.map(|vertex| {
|
|
||||||
vk::PipelineVertexInputStateCreateInfo::default()
|
|
||||||
.vertex_attribute_descriptions(vertex.attributes)
|
|
||||||
.vertex_binding_descriptions(vertex.bindings)
|
|
||||||
});
|
|
||||||
let input_assembly = desc.input_assembly.map(|state| {
|
|
||||||
vk::PipelineInputAssemblyStateCreateInfo::default()
|
|
||||||
.primitive_restart_enable(state.primitive_restart)
|
|
||||||
.topology(state.topology)
|
|
||||||
});
|
|
||||||
let tessellation = desc.tessellation.map(|state| {
|
|
||||||
vk::PipelineTessellationStateCreateInfo::default()
|
|
||||||
.flags(state.flags)
|
|
||||||
.patch_control_points(state.patch_control_points)
|
|
||||||
});
|
|
||||||
let viewport = desc.viewport.map(|state| {
|
|
||||||
let mut info = vk::PipelineViewportStateCreateInfo::default()
|
|
||||||
.scissor_count(state.num_scissors)
|
|
||||||
.viewport_count(state.num_viewports);
|
|
||||||
if let Some(viewports) = state.viewports {
|
|
||||||
info = info.viewports(viewports);
|
|
||||||
}
|
|
||||||
if let Some(scissors) = state.scissors {
|
|
||||||
info = info.scissors(scissors);
|
|
||||||
}
|
|
||||||
|
|
||||||
info
|
|
||||||
});
|
|
||||||
|
|
||||||
let rasterization = desc.rasterization.map(|state| {
|
|
||||||
let mut info = vk::PipelineRasterizationStateCreateInfo::default()
|
|
||||||
.line_width(state.line_width)
|
|
||||||
.cull_mode(state.cull_mode)
|
|
||||||
.polygon_mode(state.polygon_mode)
|
|
||||||
.rasterizer_discard_enable(state.discard_enable)
|
|
||||||
.depth_clamp_enable(state.depth_clamp_enable);
|
|
||||||
|
|
||||||
if let Some(depth_bias) = state.depth_bias {
|
|
||||||
info = info
|
|
||||||
.depth_bias_enable(true)
|
|
||||||
.depth_bias_clamp(depth_bias.clamp)
|
|
||||||
.depth_bias_constant_factor(depth_bias.constant_factor)
|
|
||||||
.depth_bias_slope_factor(depth_bias.slope_factor);
|
|
||||||
}
|
|
||||||
|
|
||||||
info
|
|
||||||
});
|
|
||||||
|
|
||||||
let multisample = desc.multisample.map(|state| {
|
|
||||||
let info = vk::PipelineMultisampleStateCreateInfo::default()
|
|
||||||
.flags(state.flags)
|
|
||||||
.min_sample_shading(state.min_sample_shading)
|
|
||||||
.rasterization_samples(state.rasterization_samples)
|
|
||||||
.sample_mask(state.sample_mask)
|
|
||||||
.sample_shading_enable(state.sample_shading_enable)
|
|
||||||
.alpha_to_coverage_enable(state.alpha_to_coverage_enable)
|
|
||||||
.alpha_to_one_enable(state.alpha_to_one_enable);
|
|
||||||
|
|
||||||
info
|
|
||||||
});
|
|
||||||
|
|
||||||
let color_blend = desc.color_blend.map(|state| {
|
|
||||||
let info = vk::PipelineColorBlendStateCreateInfo::default()
|
|
||||||
.flags(state.flags)
|
|
||||||
.attachments(state.attachments)
|
|
||||||
.blend_constants(state.blend_constants)
|
|
||||||
.logic_op(state.logic_op.unwrap_or(Default::default()))
|
|
||||||
.logic_op_enable(state.logic_op.is_some());
|
|
||||||
|
|
||||||
info
|
|
||||||
});
|
|
||||||
|
|
||||||
let depth_stencil = desc.depth_stencil.map(|state| {
|
|
||||||
let mut info =
|
|
||||||
vk::PipelineDepthStencilStateCreateInfo::default().flags(state.flags);
|
|
||||||
|
|
||||||
if let Some(depth) = state.depth {
|
|
||||||
info = info
|
|
||||||
.depth_compare_op(depth.compare_op.unwrap_or(vk::CompareOp::default()))
|
|
||||||
.depth_test_enable(depth.compare_op.is_some())
|
|
||||||
.depth_write_enable(depth.write_enable)
|
|
||||||
.depth_bounds_test_enable(depth.bounds.is_some());
|
|
||||||
if let Some(bounds) = depth.bounds {
|
|
||||||
info = info
|
|
||||||
.max_depth_bounds(bounds.max)
|
|
||||||
.min_depth_bounds(bounds.min);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(stencil) = state.stencil {
|
|
||||||
info = info
|
|
||||||
.stencil_test_enable(true)
|
|
||||||
.front(stencil.front)
|
|
||||||
.back(stencil.back);
|
|
||||||
}
|
|
||||||
|
|
||||||
info
|
|
||||||
});
|
|
||||||
|
|
||||||
let dynamic = desc.dynamic.map(|state| {
|
|
||||||
let info = vk::PipelineDynamicStateCreateInfo::default()
|
|
||||||
.flags(state.flags)
|
|
||||||
.dynamic_states(state.dynamic_states);
|
|
||||||
|
|
||||||
info
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut rendering = desc.rendering.map(|state| {
|
|
||||||
let info = vk::PipelineRenderingCreateInfo::default()
|
|
||||||
.color_attachment_formats(state.color_formats)
|
|
||||||
.depth_attachment_format(state.depth_format.unwrap_or_default())
|
|
||||||
.stencil_attachment_format(state.stencil_format.unwrap_or_default());
|
|
||||||
|
|
||||||
info
|
|
||||||
});
|
|
||||||
|
|
||||||
fn option_to_ptr<T>(option: &Option<T>) -> *const T {
|
|
||||||
option
|
|
||||||
.as_ref()
|
|
||||||
.map(|t| t as *const T)
|
|
||||||
.unwrap_or(core::ptr::null())
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut info = vk::GraphicsPipelineCreateInfo {
|
|
||||||
flags: desc.flags,
|
|
||||||
stage_count: stages.len() as u32,
|
|
||||||
p_stages: stages.as_ptr(),
|
|
||||||
p_vertex_input_state: option_to_ptr(&vertex_input),
|
|
||||||
p_input_assembly_state: option_to_ptr(&input_assembly),
|
|
||||||
p_tessellation_state: option_to_ptr(&tessellation),
|
|
||||||
p_viewport_state: option_to_ptr(&viewport),
|
|
||||||
p_rasterization_state: option_to_ptr(&rasterization),
|
|
||||||
p_multisample_state: option_to_ptr(&multisample),
|
|
||||||
p_depth_stencil_state: option_to_ptr(&depth_stencil),
|
|
||||||
p_color_blend_state: option_to_ptr(&color_blend),
|
|
||||||
p_dynamic_state: option_to_ptr(&dynamic),
|
|
||||||
layout: desc.layout.handle(),
|
|
||||||
render_pass: desc.render_pass.unwrap_or(vk::RenderPass::null()),
|
|
||||||
subpass: desc.subpass.unwrap_or(0),
|
|
||||||
base_pipeline_handle: desc
|
|
||||||
.base_pipeline
|
|
||||||
.map(|piepline| piepline.pipeline.handle())
|
|
||||||
.unwrap_or(vk::Pipeline::null()),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(rendering) = rendering.as_mut() {
|
|
||||||
info = info.push_next(rendering)
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
device.dev().create_graphics_pipelines(
|
|
||||||
vk::PipelineCache::null(),
|
|
||||||
core::slice::from_ref(&info),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let pipeline = match result {
|
|
||||||
Ok(pipelines) => pipelines[0],
|
|
||||||
Err((pipelines, error)) => {
|
|
||||||
tracing::error!("failed to create pipelines with :{error}");
|
|
||||||
for pipeline in pipelines {
|
|
||||||
unsafe {
|
|
||||||
device.dev().destroy_pipeline(pipeline, None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Err(error.into());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
pipeline: DeviceOwnedDebugObject::new(device, pipeline, name)?,
|
pipeline: DeviceObject::new(pipeline, device, desc.name),
|
||||||
bind_point,
|
bind_point: vk::PipelineBindPoint::COMPUTE,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle(&self) -> vk::Pipeline {
|
pub fn new_graphics(device: Device, desc: GraphicsPipelineDesc) -> crate::Result<Self> {
|
||||||
self.pipeline.handle()
|
let stages = desc
|
||||||
|
.shader_stages
|
||||||
|
.iter()
|
||||||
|
.map(|stage| stage.as_create_info())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let vertex_input = desc.vertex_input.map(|vertex| {
|
||||||
|
vk::PipelineVertexInputStateCreateInfo::default()
|
||||||
|
.vertex_attribute_descriptions(vertex.attributes)
|
||||||
|
.vertex_binding_descriptions(vertex.bindings)
|
||||||
|
});
|
||||||
|
let input_assembly = desc.input_assembly.map(|state| {
|
||||||
|
vk::PipelineInputAssemblyStateCreateInfo::default()
|
||||||
|
.primitive_restart_enable(state.primitive_restart)
|
||||||
|
.topology(state.topology)
|
||||||
|
});
|
||||||
|
let tessellation = desc.tessellation.map(|state| {
|
||||||
|
vk::PipelineTessellationStateCreateInfo::default()
|
||||||
|
.flags(state.flags)
|
||||||
|
.patch_control_points(state.patch_control_points)
|
||||||
|
});
|
||||||
|
let viewport = desc.viewport.map(|state| {
|
||||||
|
let mut info = vk::PipelineViewportStateCreateInfo::default()
|
||||||
|
.scissor_count(state.num_scissors)
|
||||||
|
.viewport_count(state.num_viewports);
|
||||||
|
if let Some(viewports) = state.viewports {
|
||||||
|
info = info.viewports(viewports);
|
||||||
|
}
|
||||||
|
if let Some(scissors) = state.scissors {
|
||||||
|
info = info.scissors(scissors);
|
||||||
|
}
|
||||||
|
|
||||||
|
info
|
||||||
|
});
|
||||||
|
|
||||||
|
let rasterization = desc.rasterization.map(|state| {
|
||||||
|
let mut info = vk::PipelineRasterizationStateCreateInfo::default()
|
||||||
|
.line_width(state.line_width)
|
||||||
|
.cull_mode(state.cull_mode)
|
||||||
|
.polygon_mode(state.polygon_mode)
|
||||||
|
.rasterizer_discard_enable(state.discard_enable)
|
||||||
|
.depth_clamp_enable(state.depth_clamp_enable);
|
||||||
|
|
||||||
|
if let Some(depth_bias) = state.depth_bias {
|
||||||
|
info = info
|
||||||
|
.depth_bias_enable(true)
|
||||||
|
.depth_bias_clamp(depth_bias.clamp)
|
||||||
|
.depth_bias_constant_factor(depth_bias.constant_factor)
|
||||||
|
.depth_bias_slope_factor(depth_bias.slope_factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
info
|
||||||
|
});
|
||||||
|
|
||||||
|
let multisample = desc.multisample.map(|state| {
|
||||||
|
vk::PipelineMultisampleStateCreateInfo::default()
|
||||||
|
.flags(state.flags)
|
||||||
|
.min_sample_shading(state.min_sample_shading)
|
||||||
|
.rasterization_samples(state.rasterization_samples)
|
||||||
|
.sample_mask(state.sample_mask)
|
||||||
|
.sample_shading_enable(state.sample_shading_enable)
|
||||||
|
.alpha_to_coverage_enable(state.alpha_to_coverage_enable)
|
||||||
|
.alpha_to_one_enable(state.alpha_to_one_enable)
|
||||||
|
});
|
||||||
|
|
||||||
|
let color_blend = desc.color_blend.map(|state| {
|
||||||
|
vk::PipelineColorBlendStateCreateInfo::default()
|
||||||
|
.flags(state.flags)
|
||||||
|
.attachments(state.attachments)
|
||||||
|
.blend_constants(state.blend_constants)
|
||||||
|
.logic_op(state.logic_op.unwrap_or(Default::default()))
|
||||||
|
.logic_op_enable(state.logic_op.is_some())
|
||||||
|
});
|
||||||
|
|
||||||
|
let depth_stencil = desc.depth_stencil.map(|state| {
|
||||||
|
let mut info = vk::PipelineDepthStencilStateCreateInfo::default().flags(state.flags);
|
||||||
|
|
||||||
|
if let Some(depth) = state.depth {
|
||||||
|
info = info
|
||||||
|
.depth_compare_op(depth.compare_op.unwrap_or(vk::CompareOp::default()))
|
||||||
|
.depth_test_enable(depth.compare_op.is_some())
|
||||||
|
.depth_write_enable(depth.write_enable)
|
||||||
|
.depth_bounds_test_enable(depth.bounds.is_some());
|
||||||
|
if let Some(bounds) = depth.bounds {
|
||||||
|
info = info
|
||||||
|
.max_depth_bounds(bounds.max)
|
||||||
|
.min_depth_bounds(bounds.min);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(stencil) = state.stencil {
|
||||||
|
info = info
|
||||||
|
.stencil_test_enable(true)
|
||||||
|
.front(stencil.front)
|
||||||
|
.back(stencil.back);
|
||||||
|
}
|
||||||
|
|
||||||
|
info
|
||||||
|
});
|
||||||
|
|
||||||
|
let dynamic = desc.dynamic.map(|state| {
|
||||||
|
vk::PipelineDynamicStateCreateInfo::default()
|
||||||
|
.flags(state.flags)
|
||||||
|
.dynamic_states(state.dynamic_states)
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut rendering = desc.rendering.map(|state| {
|
||||||
|
vk::PipelineRenderingCreateInfo::default()
|
||||||
|
.color_attachment_formats(state.color_formats)
|
||||||
|
.depth_attachment_format(state.depth_format.unwrap_or_default())
|
||||||
|
.stencil_attachment_format(state.stencil_format.unwrap_or_default())
|
||||||
|
});
|
||||||
|
|
||||||
|
fn option_to_ptr<T>(option: &Option<T>) -> *const T {
|
||||||
|
option
|
||||||
|
.as_ref()
|
||||||
|
.map(|t| t as *const T)
|
||||||
|
.unwrap_or(core::ptr::null())
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut info = vk::GraphicsPipelineCreateInfo {
|
||||||
|
flags: desc.flags,
|
||||||
|
stage_count: stages.len() as u32,
|
||||||
|
p_stages: stages.as_ptr(),
|
||||||
|
p_vertex_input_state: option_to_ptr(&vertex_input),
|
||||||
|
p_input_assembly_state: option_to_ptr(&input_assembly),
|
||||||
|
p_tessellation_state: option_to_ptr(&tessellation),
|
||||||
|
p_viewport_state: option_to_ptr(&viewport),
|
||||||
|
p_rasterization_state: option_to_ptr(&rasterization),
|
||||||
|
p_multisample_state: option_to_ptr(&multisample),
|
||||||
|
p_depth_stencil_state: option_to_ptr(&depth_stencil),
|
||||||
|
p_color_blend_state: option_to_ptr(&color_blend),
|
||||||
|
p_dynamic_state: option_to_ptr(&dynamic),
|
||||||
|
layout: desc.layout.handle(),
|
||||||
|
render_pass: desc.render_pass.unwrap_or(vk::RenderPass::null()),
|
||||||
|
subpass: desc.subpass.unwrap_or(0),
|
||||||
|
base_pipeline_handle: desc
|
||||||
|
.base_pipeline
|
||||||
|
.map(|piepline| *piepline.pipeline)
|
||||||
|
.unwrap_or(vk::Pipeline::null()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(rendering) = rendering.as_mut() {
|
||||||
|
info = info.push_next(rendering)
|
||||||
|
}
|
||||||
|
|
||||||
|
let pipeline = unsafe {
|
||||||
|
device
|
||||||
|
.dev()
|
||||||
|
.create_graphics_pipelines(
|
||||||
|
device.pools.pipeline_cache.raw,
|
||||||
|
core::slice::from_ref(&info),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
// It's cool to just take the first one and ignore any
|
||||||
|
// potentially created pipelines since we know there wont be any
|
||||||
|
// others.
|
||||||
|
.map_err(|(_, err)| err)?[0]
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
pipeline: DeviceObject::new(pipeline, device, desc.name),
|
||||||
|
bind_point: vk::PipelineBindPoint::GRAPHICS,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn raw(&self) -> vk::Pipeline {
|
||||||
|
*self.pipeline
|
||||||
}
|
}
|
||||||
pub fn bind_point(&self) -> vk::PipelineBindPoint {
|
pub fn bind_point(&self) -> vk::PipelineBindPoint {
|
||||||
self.bind_point
|
self.bind_point
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) mod pipeline_cache {
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use ash::vk;
|
||||||
|
|
||||||
|
use ash::Device;
|
||||||
|
|
||||||
|
use crate::PhysicalDeviceInfo;
|
||||||
|
use crate::device::DeviceInner;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PipelineCache {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
key: u128,
|
||||||
|
pub(crate) raw: vk::PipelineCache,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::device::asdf::traits::ExternallyManagedObject<Arc<DeviceInner>> for PipelineCache {
|
||||||
|
unsafe fn destroy(self, owner: &Arc<DeviceInner>) {
|
||||||
|
if let Ok(data) = self.export(&owner.raw) {
|
||||||
|
_ = Self::write_to_disk(self.key, &data).inspect_err(|err| {
|
||||||
|
tracing::error!("failed to write pipeline cache to disk: {err}");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
unsafe { owner.raw.destroy_pipeline_cache(self.raw, None) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PipelineCache {
|
||||||
|
const MAGIC: [u8; 4] = *b"VYPC";
|
||||||
|
const KEY_VERSION: u32 = 1;
|
||||||
|
const PATH: &'static str = "pipeline_cache.bin";
|
||||||
|
fn calculate_key(adapter: &PhysicalDeviceInfo) -> u128 {
|
||||||
|
use md5::Digest;
|
||||||
|
let mut hasher = md5::Md5::new();
|
||||||
|
let props = &adapter.properties;
|
||||||
|
hasher.update(bytemuck::bytes_of(&[
|
||||||
|
props.core.vendor_id,
|
||||||
|
props.core.api_version,
|
||||||
|
props.core.device_id,
|
||||||
|
props.core.driver_version,
|
||||||
|
]));
|
||||||
|
u128::from_le_bytes(hasher.finalize().into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_from_disk(key: u128) -> Option<(u128, Vec<u8>)> {
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
let file = std::fs::File::open(Self::PATH).ok()?;
|
||||||
|
let mut reader = std::io::BufReader::new(file);
|
||||||
|
let mut magic = [0; 4];
|
||||||
|
reader.read_exact(&mut magic).ok()?;
|
||||||
|
if magic != Self::MAGIC {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut version = 0;
|
||||||
|
reader
|
||||||
|
.read_exact(bytemuck::bytes_of_mut(&mut version))
|
||||||
|
.ok()?;
|
||||||
|
if version != Self::KEY_VERSION {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut disk_key = 0;
|
||||||
|
reader
|
||||||
|
.read_exact(bytemuck::bytes_of_mut(&mut disk_key))
|
||||||
|
.ok()?;
|
||||||
|
if disk_key != key {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut data = Vec::new();
|
||||||
|
reader.read_to_end(&mut data).ok()?;
|
||||||
|
|
||||||
|
Some((key, data))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_to_disk(key: u128, data: &[u8]) -> std::io::Result<()> {
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
let file = std::fs::File::create(Self::PATH)?;
|
||||||
|
let mut writer = std::io::BufWriter::new(file);
|
||||||
|
writer.write_all(&Self::MAGIC)?;
|
||||||
|
writer.write_all(bytemuck::bytes_of(&Self::KEY_VERSION))?;
|
||||||
|
writer.write_all(bytemuck::bytes_of(&key))?;
|
||||||
|
writer.write_all(data)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(device: &Device, adapter: &PhysicalDeviceInfo) -> crate::Result<Self> {
|
||||||
|
let key = Self::calculate_key(adapter);
|
||||||
|
let data = Self::load_from_disk(key).map(|(key, data)| {
|
||||||
|
tracing::info!("loaded pipeline cache from disk with key {key:x}");
|
||||||
|
data
|
||||||
|
});
|
||||||
|
|
||||||
|
let info = vk::PipelineCacheCreateInfo::default()
|
||||||
|
// .flags(vk::PipelineCacheCreateFlags::EXTERNALLY_SYNCHRONIZED)
|
||||||
|
.initial_data(data.as_deref().unwrap_or_default());
|
||||||
|
|
||||||
|
let cache = unsafe { device.create_pipeline_cache(&info, None)? };
|
||||||
|
|
||||||
|
Ok(Self { key, raw: cache })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn export(&self, device: &ash::Device) -> crate::Result<Vec<u8>> {
|
||||||
|
let data = unsafe { device.get_pipeline_cache_data(self.raw)? };
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -201,9 +201,9 @@ impl Wireframe {
|
||||||
"crates/renderer/shaders/wireframe.spv",
|
"crates/renderer/shaders/wireframe.spv",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let pipeline = pipeline::Pipeline::new(
|
let pipeline = pipeline::Pipeline::new_graphics(
|
||||||
device.clone(),
|
device.clone(),
|
||||||
pipeline::PipelineDesc::Graphics(pipeline::GraphicsPipelineDesc {
|
pipeline::GraphicsPipelineDesc {
|
||||||
flags: Default::default(),
|
flags: Default::default(),
|
||||||
name: Some("wireframe-pipeline".into()),
|
name: Some("wireframe-pipeline".into()),
|
||||||
shader_stages: &[
|
shader_stages: &[
|
||||||
|
|
@ -298,7 +298,7 @@ impl Wireframe {
|
||||||
dynamic_states: &[vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR],
|
dynamic_states: &[vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
}),
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok((pipeline, pipeline_layout))
|
Ok((pipeline, pipeline_layout))
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::{
|
use std::{
|
||||||
future::Future,
|
future::Future,
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
|
|
@ -7,7 +5,10 @@ use std::{
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::device::{DeviceObject, Pool, PoolObject, Pooled};
|
use crate::device::{
|
||||||
|
DevicePools, Pool, PoolObject, Pooled,
|
||||||
|
asdf::{DeviceObject, traits::ExternallyManagedObject as ExternallyManagedObjectTrait},
|
||||||
|
};
|
||||||
use crate::{Result, device::DeviceInner};
|
use crate::{Result, device::DeviceInner};
|
||||||
|
|
||||||
use super::Device;
|
use super::Device;
|
||||||
|
|
@ -155,8 +156,12 @@ impl SyncThreadpool {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Fence {
|
pub enum Fence {
|
||||||
Dedicated { fence: DeviceObject<vk::Fence> },
|
Dedicated {
|
||||||
Pooled { fence: PoolObject<vk::Fence> },
|
fence: DeviceObject<vk::Fence>,
|
||||||
|
},
|
||||||
|
Pooled {
|
||||||
|
fence: PoolObject<vk::Fence, Arc<Pool<vk::Fence>>>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pooled for vk::Fence {
|
impl Pooled for vk::Fence {
|
||||||
|
|
@ -171,6 +176,20 @@ impl Pooled for vk::Fence {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ExternallyManagedObjectTrait<Arc<Pool<vk::Fence>>> for vk::Fence {
|
||||||
|
unsafe fn destroy(self, pool: &Arc<Pool<vk::Fence>>) {
|
||||||
|
pool.push(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExternallyManagedObjectTrait<Arc<DeviceInner>> for vk::Fence {
|
||||||
|
unsafe fn destroy(self, device: &Arc<DeviceInner>) {
|
||||||
|
unsafe {
|
||||||
|
device.raw.destroy_fence(self, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for Fence {
|
impl std::fmt::Debug for Fence {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_struct("Fence").field("fence", &self.raw()).finish()
|
f.debug_struct("Fence").field("fence", &self.raw()).finish()
|
||||||
|
|
@ -185,16 +204,15 @@ impl Fence {
|
||||||
.create_fence(&vk::FenceCreateInfo::default(), None)?
|
.create_fence(&vk::FenceCreateInfo::default(), None)?
|
||||||
};
|
};
|
||||||
Ok(Self::Dedicated {
|
Ok(Self::Dedicated {
|
||||||
fence: DeviceObject::new(fence, device, name.map(Into::into)),
|
fence: DeviceObject::new_debug_named(device.shared, fence, name),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn from_pool(pool: &Pool<vk::Fence>, name: Option<&'static str>) -> Result<Fence> {
|
pub fn from_pool(pool: &Arc<Pool<vk::Fence>>, name: Option<&'static str>) -> Result<Fence> {
|
||||||
let mut fence = pool.get()?;
|
let fence = pool.get_debug_named(name)?;
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
if let Some(name) = name {
|
Ok(Self::Pooled {
|
||||||
fence.name_object(name);
|
fence: PoolObject::new(fence, pool.clone()),
|
||||||
}
|
})
|
||||||
Ok(Self::Pooled { fence })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raw(&self) -> vk::Fence {
|
pub fn raw(&self) -> vk::Fence {
|
||||||
|
|
@ -206,8 +224,8 @@ impl Fence {
|
||||||
|
|
||||||
fn device(&self) -> &Arc<DeviceInner> {
|
fn device(&self) -> &Arc<DeviceInner> {
|
||||||
match self {
|
match self {
|
||||||
Fence::Dedicated { fence } => &fence.device().shared,
|
Fence::Dedicated { fence } => &fence.device(),
|
||||||
Fence::Pooled { fence } => fence.device(),
|
Fence::Pooled { fence } => &fence.owner().device,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -251,24 +269,82 @@ pub enum SemaphoreType {
|
||||||
Timeline(u64),
|
Timeline(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum SemaphoreInner {
|
||||||
|
Binary(vk::Semaphore),
|
||||||
|
Timeline(vk::Semaphore),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExternallyManagedObjectTrait<Arc<DevicePools>> for SemaphoreInner {
|
||||||
|
unsafe fn destroy(self, owner: &Arc<DevicePools>) {
|
||||||
|
match self {
|
||||||
|
SemaphoreInner::Binary(semaphore) => {
|
||||||
|
owner.binary_semaphores.push(BinarySemaphore(semaphore))
|
||||||
|
}
|
||||||
|
SemaphoreInner::Timeline(semaphore) => {
|
||||||
|
owner.timeline_semaphores.push(TimelineSemaphore(semaphore))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExternallyManagedObjectTrait<Arc<DeviceInner>> for SemaphoreInner {
|
||||||
|
unsafe fn destroy(self, owner: &Arc<DeviceInner>) {
|
||||||
|
match self {
|
||||||
|
SemaphoreInner::Binary(semaphore) | SemaphoreInner::Timeline(semaphore) => {
|
||||||
|
unsafe { owner.raw.destroy_semaphore(semaphore, None) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::device::asdf::traits::DebugNameable for SemaphoreInner {
|
||||||
|
fn debug_name(&self, device: &DeviceInner, name: &str) {
|
||||||
|
unsafe {
|
||||||
|
device.debug_name_object(self.raw(), name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SemaphoreInner {
|
||||||
|
pub fn raw(&self) -> vk::Semaphore {
|
||||||
|
match self {
|
||||||
|
SemaphoreInner::Binary(semaphore) | SemaphoreInner::Timeline(semaphore) => *semaphore,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn semaphore_type(&self) -> SemaphoreType {
|
||||||
|
match self {
|
||||||
|
SemaphoreInner::Binary(_) => SemaphoreType::Binary,
|
||||||
|
SemaphoreInner::Timeline(_) => SemaphoreType::Timeline(!0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BinarySemaphore> for SemaphoreInner {
|
||||||
|
fn from(value: BinarySemaphore) -> Self {
|
||||||
|
SemaphoreInner::Binary(value.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<TimelineSemaphore> for SemaphoreInner {
|
||||||
|
fn from(value: TimelineSemaphore) -> Self {
|
||||||
|
SemaphoreInner::Timeline(value.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub enum Semaphore {
|
pub enum Semaphore {
|
||||||
Dedicated {
|
Dedicated {
|
||||||
semaphore_type: SemaphoreType,
|
semaphore: DeviceObject<SemaphoreInner>,
|
||||||
semaphore: DeviceObject<vk::Semaphore>,
|
|
||||||
},
|
},
|
||||||
Pooled {
|
Pooled {
|
||||||
semaphore_type: SemaphoreType,
|
#[allow(private_interfaces)]
|
||||||
semaphore: vk::Semaphore,
|
semaphore: PoolObject<SemaphoreInner, Arc<DevicePools>>,
|
||||||
device: Device,
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
name: Option<Cow<'static, str>>,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub(crate) struct BinarySemaphore(vk::Semaphore);
|
pub(crate) struct BinarySemaphore(pub(crate) vk::Semaphore);
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub(crate) struct TimelineSemaphore(vk::Semaphore);
|
pub(crate) struct TimelineSemaphore(pub(crate) vk::Semaphore);
|
||||||
|
|
||||||
// This is just so that ash can name these semaphore newtypes
|
// This is just so that ash can name these semaphore newtypes
|
||||||
impl vk::Handle for BinarySemaphore {
|
impl vk::Handle for BinarySemaphore {
|
||||||
|
|
@ -316,36 +392,6 @@ impl Pooled for TimelineSemaphore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Semaphore {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
if let Semaphore::Pooled {
|
|
||||||
device,
|
|
||||||
semaphore_type,
|
|
||||||
semaphore,
|
|
||||||
name,
|
|
||||||
} = self
|
|
||||||
{
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
if name.is_some() {
|
|
||||||
// reset the name to avoid confusion in case this semaphore is re-used
|
|
||||||
unsafe { device.debug_name_object(*semaphore, "") };
|
|
||||||
}
|
|
||||||
match semaphore_type {
|
|
||||||
SemaphoreType::Binary => device
|
|
||||||
.pools
|
|
||||||
.binary_semaphores
|
|
||||||
.push(BinarySemaphore(*semaphore)),
|
|
||||||
SemaphoreType::Timeline(_) => {
|
|
||||||
device
|
|
||||||
.pools
|
|
||||||
.timeline_semaphores
|
|
||||||
.push(TimelineSemaphore(*semaphore));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Semaphore {
|
impl Semaphore {
|
||||||
pub fn new_dedicated(
|
pub fn new_dedicated(
|
||||||
device: Device,
|
device: Device,
|
||||||
|
|
@ -366,9 +412,13 @@ impl Semaphore {
|
||||||
let create_info = vk::SemaphoreCreateInfo::default().push_next(&mut type_info);
|
let create_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)? };
|
||||||
|
|
||||||
|
let inner = match semaphore_type {
|
||||||
|
SemaphoreType::Binary => SemaphoreInner::Binary(inner),
|
||||||
|
SemaphoreType::Timeline(_) => SemaphoreInner::Timeline(inner),
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Self::Dedicated {
|
Ok(Self::Dedicated {
|
||||||
semaphore_type,
|
semaphore: DeviceObject::new_debug_named(device.shared, inner, name),
|
||||||
semaphore: DeviceObject::new(inner, device, name.map(Into::into)),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -379,48 +429,35 @@ impl Semaphore {
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let semaphore = match semaphore_type {
|
let semaphore = match semaphore_type {
|
||||||
SemaphoreType::Binary => {
|
SemaphoreType::Binary => {
|
||||||
if let Some(semaphore) = device.pools.binary_semaphores.pop() {
|
let semaphore: SemaphoreInner =
|
||||||
semaphore.0
|
device.pools.binary_semaphores.get_debug_named(name)?.into();
|
||||||
} else {
|
PoolObject::new(semaphore, device.pools)
|
||||||
let mut type_info = vk::SemaphoreTypeCreateInfo::default()
|
|
||||||
.semaphore_type(vk::SemaphoreType::BINARY);
|
|
||||||
let create_info = vk::SemaphoreCreateInfo::default().push_next(&mut type_info);
|
|
||||||
unsafe { device.raw.create_semaphore(&create_info, None)? }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
SemaphoreType::Timeline(value) => {
|
SemaphoreType::Timeline(value) => {
|
||||||
if let Some(semaphore) = device.pools.binary_semaphores.pop() {
|
let semaphore: SemaphoreInner = device
|
||||||
semaphore.0
|
.pools
|
||||||
} else {
|
.timeline_semaphores
|
||||||
let mut type_info = vk::SemaphoreTypeCreateInfo::default()
|
.get_debug_named(name)?
|
||||||
.semaphore_type(vk::SemaphoreType::TIMELINE)
|
.into();
|
||||||
.initial_value(value);
|
|
||||||
let create_info = vk::SemaphoreCreateInfo::default().push_next(&mut type_info);
|
let info = vk::SemaphoreSignalInfo::default()
|
||||||
unsafe { device.raw.create_semaphore(&create_info, None)? }
|
.semaphore(semaphore.raw())
|
||||||
|
.value(value);
|
||||||
|
unsafe {
|
||||||
|
device.raw.signal_semaphore(&info)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PoolObject::new(semaphore, device.pools)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
Ok(Self::Pooled { semaphore })
|
||||||
if let Some(name) = name {
|
|
||||||
unsafe {
|
|
||||||
device.debug_name_object(semaphore, name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Self::Pooled {
|
|
||||||
semaphore_type,
|
|
||||||
semaphore,
|
|
||||||
device,
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
name: name.map(Into::into),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn semaphore(&self) -> vk::Semaphore {
|
pub fn semaphore(&self) -> vk::Semaphore {
|
||||||
match self {
|
match self {
|
||||||
Semaphore::Dedicated { semaphore, .. } => **semaphore,
|
Semaphore::Dedicated { semaphore, .. } => semaphore.raw(),
|
||||||
Semaphore::Pooled { semaphore, .. } => *semaphore,
|
Semaphore::Pooled { semaphore, .. } => semaphore.raw(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue