vulkan: use sync objects if possible
This commit is contained in:
parent
2ac3519f2d
commit
3d3132fe39
23 changed files with 535 additions and 86 deletions
|
|
@ -2,6 +2,7 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
allocator::{Allocator, AllocatorError, BufferUsage, MappedBuffer},
|
allocator::{Allocator, AllocatorError, BufferUsage, MappedBuffer},
|
||||||
cli::{GlobalArgs, ScreenshotArgs, ScreenshotFormat},
|
cli::{GlobalArgs, ScreenshotArgs, ScreenshotFormat},
|
||||||
|
eventfd_cache::EventfdCache,
|
||||||
format::XRGB8888,
|
format::XRGB8888,
|
||||||
gfx_apis,
|
gfx_apis,
|
||||||
tools::tool_client::{Handle, ToolClient, with_tool_client},
|
tools::tool_client::{Handle, ToolClient, with_tool_client},
|
||||||
|
|
@ -109,7 +110,8 @@ async fn run(screenshot: Rc<Screenshot>) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let format = screenshot.args.format;
|
let format = screenshot.args.format;
|
||||||
let data = match buf_to_bytes(drm_dev.as_ref(), &buf, format) {
|
let eventfd_cache = EventfdCache::new(&tc.ring, &tc.eng);
|
||||||
|
let data = match buf_to_bytes(&eventfd_cache, drm_dev.as_ref(), &buf, format) {
|
||||||
Ok(d) => d,
|
Ok(d) => d,
|
||||||
Err(e) => fatal!("{}", ErrorFmt(e)),
|
Err(e) => fatal!("{}", ErrorFmt(e)),
|
||||||
};
|
};
|
||||||
|
|
@ -159,6 +161,7 @@ fn map(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn buf_to_bytes(
|
pub fn buf_to_bytes(
|
||||||
|
eventfd_cache: &Rc<EventfdCache>,
|
||||||
drm_dev: Option<&Rc<OwnedFd>>,
|
drm_dev: Option<&Rc<OwnedFd>>,
|
||||||
buf: &DmaBuf,
|
buf: &DmaBuf,
|
||||||
format: ScreenshotFormat,
|
format: ScreenshotFormat,
|
||||||
|
|
@ -174,7 +177,7 @@ pub fn buf_to_bytes(
|
||||||
.map_err(ScreenshotError::CreateGbmDevice)
|
.map_err(ScreenshotError::CreateGbmDevice)
|
||||||
});
|
});
|
||||||
let vulkan = Box::new(move || {
|
let vulkan = Box::new(move || {
|
||||||
gfx_apis::create_vulkan_allocator(&drm()?)
|
gfx_apis::create_vulkan_allocator(&drm()?, eventfd_cache)
|
||||||
.map_err(ScreenshotError::CreateVulkanAllocator)
|
.map_err(ScreenshotError::CreateVulkanAllocator)
|
||||||
});
|
});
|
||||||
allocators.push(vulkan);
|
allocators.push(vulkan);
|
||||||
|
|
|
||||||
|
|
@ -214,6 +214,7 @@ fn start_compositor2(
|
||||||
let cpu_worker = Rc::new(CpuWorker::new(&ring, &engine)?);
|
let cpu_worker = Rc::new(CpuWorker::new(&ring, &engine)?);
|
||||||
let color_manager = ColorManager::new();
|
let color_manager = ColorManager::new();
|
||||||
let crit_ids = Rc::new(CritMatcherIds::default());
|
let crit_ids = Rc::new(CritMatcherIds::default());
|
||||||
|
let eventfd_cache = EventfdCache::new(&ring, &engine);
|
||||||
let state = Rc::new(State {
|
let state = Rc::new(State {
|
||||||
kb_ctx,
|
kb_ctx,
|
||||||
backend: CloneCell::new(Rc::new(DummyBackend)),
|
backend: CloneCell::new(Rc::new(DummyBackend)),
|
||||||
|
|
@ -373,9 +374,9 @@ fn start_compositor2(
|
||||||
outputs_without_hc: Default::default(),
|
outputs_without_hc: Default::default(),
|
||||||
udmabuf: Default::default(),
|
udmabuf: Default::default(),
|
||||||
gfx_ctx_changed: Default::default(),
|
gfx_ctx_changed: Default::default(),
|
||||||
copy_device_registry: Rc::new(CopyDeviceRegistry::new(&ring, &engine)),
|
copy_device_registry: Rc::new(CopyDeviceRegistry::new(&ring, &engine, &eventfd_cache)),
|
||||||
supports_presentation_feedback: Default::default(),
|
supports_presentation_feedback: Default::default(),
|
||||||
eventfd_cache: EventfdCache::new(&ring, &engine),
|
eventfd_cache,
|
||||||
});
|
});
|
||||||
state.tracker.register(ClientId::from_raw(0));
|
state.tracker.register(ClientId::from_raw(0));
|
||||||
create_dummy_output(&state);
|
create_dummy_output(&state);
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,24 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::{AsyncEngine, SpawnedFuture},
|
async_engine::{AsyncEngine, SpawnedFuture},
|
||||||
|
eventfd_cache::EventfdCache,
|
||||||
format::{FORMATS, Format},
|
format::{FORMATS, Format},
|
||||||
gfx_api::FdSync,
|
gfx_api::FdSync,
|
||||||
io_uring::IoUring,
|
io_uring::IoUring,
|
||||||
rect::{Rect, Region},
|
rect::{Rect, Region},
|
||||||
utils::{
|
utils::{
|
||||||
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell,
|
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell,
|
||||||
queue::AsyncQueue, stack::Stack,
|
oserror::OsError, queue::AsyncQueue, stack::Stack,
|
||||||
},
|
},
|
||||||
video::{
|
video::{
|
||||||
LINEAR_MODIFIER, LINEAR_STRIDE_ALIGN, Modifier,
|
LINEAR_MODIFIER, LINEAR_STRIDE_ALIGN, Modifier,
|
||||||
dmabuf::{DmaBuf, DmaBufIds, DmaBufPlane, PlaneVec},
|
dmabuf::{DmaBuf, DmaBufIds, DmaBufPlane, PlaneVec},
|
||||||
|
drm::{NodeType, get_drm_nodes_from_dev, syncobj::SyncobjCtx},
|
||||||
},
|
},
|
||||||
vulkan_core::{
|
vulkan_core::{
|
||||||
self, VULKAN_API_VERSION, VulkanCoreError, VulkanCoreInstance, device::VulkanDeviceInf,
|
self, VULKAN_API_VERSION, VulkanCoreError, VulkanCoreInstance, device::VulkanDeviceInf,
|
||||||
map_extension_properties, sync::VulkanDeviceSyncExt,
|
map_extension_properties, sync::VulkanDeviceSyncExt,
|
||||||
|
timeline_semaphore::VulkanDeviceTimelineSemaphoreExt,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ahash::{AHashMap, AHashSet},
|
ahash::{AHashMap, AHashSet},
|
||||||
|
|
@ -54,9 +57,10 @@ use {
|
||||||
PhysicalDeviceExternalImageFormatInfoKHR, PhysicalDeviceExternalSemaphoreInfo,
|
PhysicalDeviceExternalImageFormatInfoKHR, PhysicalDeviceExternalSemaphoreInfo,
|
||||||
PhysicalDeviceFeatures2, PhysicalDeviceImageDrmFormatModifierInfoEXT,
|
PhysicalDeviceFeatures2, PhysicalDeviceImageDrmFormatModifierInfoEXT,
|
||||||
PhysicalDeviceImageFormatInfo2, PhysicalDeviceProperties2,
|
PhysicalDeviceImageFormatInfo2, PhysicalDeviceProperties2,
|
||||||
PhysicalDeviceSynchronization2Features, PipelineStageFlags2, QUEUE_FAMILY_FOREIGN_EXT,
|
PhysicalDeviceSynchronization2Features, PhysicalDeviceTimelineSemaphoreFeatures,
|
||||||
Queue, QueueFlags, SampleCountFlags, SemaphoreCreateInfo, SemaphoreImportFlags,
|
PipelineStageFlags2, QUEUE_FAMILY_FOREIGN_EXT, Queue, QueueFlags, SampleCountFlags,
|
||||||
SemaphoreSubmitInfo, SharingMode, SubmitInfo2, SubresourceLayout, WHOLE_SIZE,
|
SemaphoreCreateInfo, SemaphoreImportFlags, SemaphoreSubmitInfo, SharingMode,
|
||||||
|
SubmitInfo2, SubresourceLayout, WHOLE_SIZE,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
bstr::ByteSlice,
|
bstr::ByteSlice,
|
||||||
|
|
@ -162,6 +166,12 @@ pub enum CopyDeviceError {
|
||||||
BothOffDevice,
|
BothOffDevice,
|
||||||
#[error("Cannot blit between these formats")]
|
#[error("Cannot blit between these formats")]
|
||||||
BlitNotSupported,
|
BlitNotSupported,
|
||||||
|
#[error("Could not get DRM nodes")]
|
||||||
|
GetDrmNodes(#[source] OsError),
|
||||||
|
#[error("Device has no device nodes")]
|
||||||
|
NoDeviceNodes,
|
||||||
|
#[error("Could not open device node")]
|
||||||
|
OpenDeviceNode(#[source] OsError),
|
||||||
}
|
}
|
||||||
|
|
||||||
type Keyed<T> = StaticMap<TransferType, T>;
|
type Keyed<T> = StaticMap<TransferType, T>;
|
||||||
|
|
@ -170,12 +180,15 @@ type KeyedCopy<T> = StaticCopyMap<TransferType, T>;
|
||||||
pub struct PhysicalCopyDevice {
|
pub struct PhysicalCopyDevice {
|
||||||
ring: Rc<IoUring>,
|
ring: Rc<IoUring>,
|
||||||
eng: Rc<AsyncEngine>,
|
eng: Rc<AsyncEngine>,
|
||||||
|
eventfd_cache: Rc<EventfdCache>,
|
||||||
|
sync_ctx: Rc<SyncobjCtx>,
|
||||||
instance: VulkanCoreInstance,
|
instance: VulkanCoreInstance,
|
||||||
physical_device: PhysicalDevice,
|
physical_device: PhysicalDevice,
|
||||||
support: AHashMap<u32, StaticMap<Dir, Vec<CopyDeviceSupport>>>,
|
support: AHashMap<u32, StaticMap<Dir, Vec<CopyDeviceSupport>>>,
|
||||||
queues_to_allocate: Vec<QueueToAllocate>,
|
queues_to_allocate: Vec<QueueToAllocate>,
|
||||||
queues: KeyedCopy<QueueIndex>,
|
queues: KeyedCopy<QueueIndex>,
|
||||||
supports_dmabuf_export: bool,
|
supports_dmabuf_export: bool,
|
||||||
|
supports_timeline_opaque_export: bool,
|
||||||
memory_types: Vec<MemoryType>,
|
memory_types: Vec<MemoryType>,
|
||||||
rects: RefCell<Vec<(i32, i32, u32, u32)>>,
|
rects: RefCell<Vec<(i32, i32, u32, u32)>>,
|
||||||
buffer_copy_2: RefCell<Vec<BufferCopy2<'static>>>,
|
buffer_copy_2: RefCell<Vec<BufferCopy2<'static>>>,
|
||||||
|
|
@ -201,6 +214,7 @@ struct QueueIndex {
|
||||||
pub struct CopyDevice {
|
pub struct CopyDevice {
|
||||||
_tasks: Vec<SpawnedFuture<()>>,
|
_tasks: Vec<SpawnedFuture<()>>,
|
||||||
dev: Rc<CopyDeviceInner>,
|
dev: Rc<CopyDeviceInner>,
|
||||||
|
timeline_semaphore: Option<Rc<VulkanTimelineSemaphore>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CopyDeviceInner {
|
struct CopyDeviceInner {
|
||||||
|
|
@ -225,7 +239,7 @@ struct PendingSubmissions {
|
||||||
|
|
||||||
pub struct CopyDeviceCopy {
|
pub struct CopyDeviceCopy {
|
||||||
inner: Rc<CopyDeviceCopyInner>,
|
inner: Rc<CopyDeviceCopyInner>,
|
||||||
_dev: Rc<CopyDevice>,
|
dev: Rc<CopyDevice>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CopyDeviceCopyInner {
|
struct CopyDeviceCopyInner {
|
||||||
|
|
@ -283,6 +297,8 @@ struct VulkanSemaphore {
|
||||||
}
|
}
|
||||||
|
|
||||||
type VulkanFence = vulkan_core::fence::VulkanFence<CopyDeviceInner>;
|
type VulkanFence = vulkan_core::fence::VulkanFence<CopyDeviceInner>;
|
||||||
|
type VulkanTimelineSemaphore =
|
||||||
|
vulkan_core::timeline_semaphore::VulkanTimelineSemaphore<CopyDeviceInner>;
|
||||||
type VulkanSync = vulkan_core::sync::VulkanSync<CopyDeviceInner>;
|
type VulkanSync = vulkan_core::sync::VulkanSync<CopyDeviceInner>;
|
||||||
|
|
||||||
struct VulkanBuffer {
|
struct VulkanBuffer {
|
||||||
|
|
@ -336,6 +352,7 @@ struct ClassifiedDmabuf<'a> {
|
||||||
pub struct CopyDeviceRegistry {
|
pub struct CopyDeviceRegistry {
|
||||||
ring: Rc<IoUring>,
|
ring: Rc<IoUring>,
|
||||||
eng: Rc<AsyncEngine>,
|
eng: Rc<AsyncEngine>,
|
||||||
|
eventfd_cache: Rc<EventfdCache>,
|
||||||
devs: CopyHashMap<c::dev_t, Option<Rc<PhysicalCopyDevice>>>,
|
devs: CopyHashMap<c::dev_t, Option<Rc<PhysicalCopyDevice>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -352,6 +369,7 @@ impl PhysicalCopyDevice {
|
||||||
fn new(
|
fn new(
|
||||||
ring: &Rc<IoUring>,
|
ring: &Rc<IoUring>,
|
||||||
eng: &Rc<AsyncEngine>,
|
eng: &Rc<AsyncEngine>,
|
||||||
|
eventfd_cache: &Rc<EventfdCache>,
|
||||||
dev: c::dev_t,
|
dev: c::dev_t,
|
||||||
) -> Result<Rc<Self>, CopyDeviceError> {
|
) -> Result<Rc<Self>, CopyDeviceError> {
|
||||||
let core_instance = VulkanCoreInstance::new(Level::Debug)?;
|
let core_instance = VulkanCoreInstance::new(Level::Debug)?;
|
||||||
|
|
@ -404,6 +422,16 @@ impl PhysicalCopyDevice {
|
||||||
}
|
}
|
||||||
return Err(CopyDeviceError::NoVulkanDevice);
|
return Err(CopyDeviceError::NoVulkanDevice);
|
||||||
}
|
}
|
||||||
|
let nodes = get_drm_nodes_from_dev(uapi::major(dev), uapi::minor(dev))
|
||||||
|
.map_err(CopyDeviceError::GetDrmNodes)?;
|
||||||
|
let path = nodes
|
||||||
|
.get(&NodeType::Render)
|
||||||
|
.or_else(|| nodes.get(&NodeType::Primary))
|
||||||
|
.ok_or(CopyDeviceError::NoDeviceNodes)?;
|
||||||
|
let device_fd = uapi::open(path.as_c_str(), c::O_RDWR, 0)
|
||||||
|
.map(Rc::new)
|
||||||
|
.map_err(Into::into)
|
||||||
|
.map_err(CopyDeviceError::OpenDeviceNode)?;
|
||||||
if device_properties.api_version < VULKAN_API_VERSION {
|
if device_properties.api_version < VULKAN_API_VERSION {
|
||||||
return Err(CopyDeviceError::NoVulkan13);
|
return Err(CopyDeviceError::NoVulkan13);
|
||||||
}
|
}
|
||||||
|
|
@ -606,15 +634,21 @@ impl PhysicalCopyDevice {
|
||||||
}
|
}
|
||||||
let memory_info =
|
let memory_info =
|
||||||
unsafe { instance.get_physical_device_memory_properties(physical_device) };
|
unsafe { instance.get_physical_device_memory_properties(physical_device) };
|
||||||
|
let features = core_instance.get_features(physical_device);
|
||||||
|
let supports_timeline_opaque_export =
|
||||||
|
core_instance.supports_timeline_opaque_export(physical_device, &features);
|
||||||
let dev = Rc::new(PhysicalCopyDevice {
|
let dev = Rc::new(PhysicalCopyDevice {
|
||||||
ring: ring.clone(),
|
ring: ring.clone(),
|
||||||
eng: eng.clone(),
|
eng: eng.clone(),
|
||||||
|
eventfd_cache: eventfd_cache.clone(),
|
||||||
|
sync_ctx: Rc::new(SyncobjCtx::new(&device_fd)),
|
||||||
instance: core_instance,
|
instance: core_instance,
|
||||||
physical_device,
|
physical_device,
|
||||||
support,
|
support,
|
||||||
queues_to_allocate,
|
queues_to_allocate,
|
||||||
queues: queue_indices,
|
queues: queue_indices,
|
||||||
supports_dmabuf_export,
|
supports_dmabuf_export,
|
||||||
|
supports_timeline_opaque_export,
|
||||||
memory_types: memory_info.memory_types_as_slice().to_vec(),
|
memory_types: memory_info.memory_types_as_slice().to_vec(),
|
||||||
rects: Default::default(),
|
rects: Default::default(),
|
||||||
buffer_copy_2: Default::default(),
|
buffer_copy_2: Default::default(),
|
||||||
|
|
@ -654,11 +688,14 @@ impl PhysicalCopyDevice {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let extensions = DEVICE_EXTENSIONS.map(|e| e.as_ptr());
|
let extensions = DEVICE_EXTENSIONS.map(|e| e.as_ptr());
|
||||||
|
let mut semaphore_features = PhysicalDeviceTimelineSemaphoreFeatures::default()
|
||||||
|
.timeline_semaphore(self.supports_timeline_opaque_export);
|
||||||
let mut synchronization2_features =
|
let mut synchronization2_features =
|
||||||
PhysicalDeviceSynchronization2Features::default().synchronization2(true);
|
PhysicalDeviceSynchronization2Features::default().synchronization2(true);
|
||||||
let info = DeviceCreateInfo::default()
|
let info = DeviceCreateInfo::default()
|
||||||
.queue_create_infos(&queue_create_info)
|
.queue_create_infos(&queue_create_info)
|
||||||
.enabled_extension_names(&extensions)
|
.enabled_extension_names(&extensions)
|
||||||
|
.push_next(&mut semaphore_features)
|
||||||
.push_next(&mut synchronization2_features);
|
.push_next(&mut synchronization2_features);
|
||||||
unsafe {
|
unsafe {
|
||||||
instance
|
instance
|
||||||
|
|
@ -722,7 +759,11 @@ impl PhysicalCopyDevice {
|
||||||
let task = self.eng.spawn("copy-device-await-pending", future);
|
let task = self.eng.spawn("copy-device-await-pending", future);
|
||||||
tasks.push(task);
|
tasks.push(task);
|
||||||
}
|
}
|
||||||
let queue = Rc::new(CopyDevice { dev, _tasks: tasks });
|
let queue = Rc::new(CopyDevice {
|
||||||
|
timeline_semaphore: dev.create_timeline_semaphore_or_log(),
|
||||||
|
dev,
|
||||||
|
_tasks: tasks,
|
||||||
|
});
|
||||||
Ok(queue)
|
Ok(queue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1129,7 +1170,7 @@ impl CopyDevice {
|
||||||
tt,
|
tt,
|
||||||
ty,
|
ty,
|
||||||
}),
|
}),
|
||||||
_dev: self.clone(),
|
dev: self.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1647,10 +1688,15 @@ impl CopyDeviceCopy {
|
||||||
wait_semaphore = Some(semaphore);
|
wait_semaphore = Some(semaphore);
|
||||||
}
|
}
|
||||||
let command_buffer_info = CommandBufferSubmitInfo::default().command_buffer(cmd);
|
let command_buffer_info = CommandBufferSubmitInfo::default().command_buffer(cmd);
|
||||||
let submit_info = SubmitInfo2::default()
|
let mut semaphore_submit_info = SemaphoreSubmitInfo::default();
|
||||||
|
let mut submit_info = SubmitInfo2::default()
|
||||||
.command_buffer_infos(slice::from_ref(&command_buffer_info))
|
.command_buffer_infos(slice::from_ref(&command_buffer_info))
|
||||||
.wait_semaphore_infos(&wait_semaphores);
|
.wait_semaphore_infos(&wait_semaphores);
|
||||||
let vulkan_sync = slf.dev.create_sync()?;
|
let vulkan_sync = slf.dev.create_sync(
|
||||||
|
self.dev.timeline_semaphore.as_ref(),
|
||||||
|
&mut semaphore_submit_info,
|
||||||
|
&mut submit_info,
|
||||||
|
)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
slf.dev
|
slf.dev
|
||||||
.dev
|
.dev
|
||||||
|
|
@ -1698,10 +1744,15 @@ impl VulkanSemaphore {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CopyDeviceRegistry {
|
impl CopyDeviceRegistry {
|
||||||
pub fn new(ring: &Rc<IoUring>, eng: &Rc<AsyncEngine>) -> Self {
|
pub fn new(
|
||||||
|
ring: &Rc<IoUring>,
|
||||||
|
eng: &Rc<AsyncEngine>,
|
||||||
|
eventfd_cache: &Rc<EventfdCache>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
ring: ring.clone(),
|
ring: ring.clone(),
|
||||||
eng: eng.clone(),
|
eng: eng.clone(),
|
||||||
|
eventfd_cache: eventfd_cache.clone(),
|
||||||
devs: Default::default(),
|
devs: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1714,7 +1765,7 @@ impl CopyDeviceRegistry {
|
||||||
if let Some(dev) = self.devs.get(&dev) {
|
if let Some(dev) = self.devs.get(&dev) {
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
match PhysicalCopyDevice::new(&self.ring, &self.eng, dev).map(Some) {
|
match PhysicalCopyDevice::new(&self.ring, &self.eng, &self.eventfd_cache, dev).map(Some) {
|
||||||
Ok(cd) => {
|
Ok(cd) => {
|
||||||
self.devs.set(dev, cd.clone());
|
self.devs.set(dev, cd.clone());
|
||||||
cd
|
cd
|
||||||
|
|
@ -1977,6 +2028,10 @@ fn allocate_queues(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VulkanDeviceInf for CopyDeviceInner {
|
impl VulkanDeviceInf for CopyDeviceInner {
|
||||||
|
fn instance(&self) -> &VulkanCoreInstance {
|
||||||
|
&self.phy.instance
|
||||||
|
}
|
||||||
|
|
||||||
fn device(&self) -> &Device {
|
fn device(&self) -> &Device {
|
||||||
&self.dev
|
&self.dev
|
||||||
}
|
}
|
||||||
|
|
@ -1984,4 +2039,20 @@ impl VulkanDeviceInf for CopyDeviceInner {
|
||||||
fn external_fence_fd(&self) -> &external_fence_fd::Device {
|
fn external_fence_fd(&self) -> &external_fence_fd::Device {
|
||||||
&self.external_fence_fd
|
&self.external_fence_fd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn external_semaphore_fd(&self) -> &external_semaphore_fd::Device {
|
||||||
|
&self.external_semaphore_fd
|
||||||
|
}
|
||||||
|
|
||||||
|
fn supports_timeline_opaque_export(&self) -> bool {
|
||||||
|
self.phy.supports_timeline_opaque_export
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync_ctx(&self) -> &Rc<SyncobjCtx> {
|
||||||
|
&self.phy.sync_ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eventfd_cache(&self) -> &Rc<EventfdCache> {
|
||||||
|
&self.phy.eventfd_cache
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@ impl EventfdCache {
|
||||||
Rc::new(Self { inner, _task: task })
|
Rc::new(Self { inner, _task: task })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(test), expect(dead_code))]
|
|
||||||
pub fn acquire(&self) -> Result<Eventfd, EventfdError> {
|
pub fn acquire(&self) -> Result<Eventfd, EventfdError> {
|
||||||
let fd = match self.inner.fds.pop() {
|
let fd = match self.inner.fds.pop() {
|
||||||
Some(fd) => fd,
|
Some(fd) => fd,
|
||||||
|
|
|
||||||
|
|
@ -1124,7 +1124,6 @@ impl Debug for ReservedSyncobjPoint {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum FdSync {
|
pub enum FdSync {
|
||||||
SyncFile(SyncFile),
|
SyncFile(SyncFile),
|
||||||
#[expect(dead_code)]
|
|
||||||
Syncobj(Rc<ReservedSyncobjPoint>),
|
Syncobj(Rc<ReservedSyncobjPoint>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ pub use vulkan::create_vulkan_allocator;
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::AsyncEngine,
|
async_engine::AsyncEngine,
|
||||||
|
eventfd_cache::EventfdCache,
|
||||||
gfx_api::{GfxApi, GfxContext, GfxError},
|
gfx_api::{GfxApi, GfxContext, GfxError},
|
||||||
io_uring::IoUring,
|
io_uring::IoUring,
|
||||||
pr_caps::PrCapsThread,
|
pr_caps::PrCapsThread,
|
||||||
|
|
@ -17,6 +18,7 @@ mod vulkan;
|
||||||
pub fn create_gfx_context(
|
pub fn create_gfx_context(
|
||||||
eng: &Rc<AsyncEngine>,
|
eng: &Rc<AsyncEngine>,
|
||||||
ring: &Rc<IoUring>,
|
ring: &Rc<IoUring>,
|
||||||
|
eventfd_cache: &Rc<EventfdCache>,
|
||||||
drm: &Drm,
|
drm: &Drm,
|
||||||
api: GfxApi,
|
api: GfxApi,
|
||||||
caps_thread: Option<&PrCapsThread>,
|
caps_thread: Option<&PrCapsThread>,
|
||||||
|
|
@ -26,7 +28,8 @@ pub fn create_gfx_context(
|
||||||
let mut last_err = None;
|
let mut last_err = None;
|
||||||
for software in [false, true] {
|
for software in [false, true] {
|
||||||
for api in apis {
|
for api in apis {
|
||||||
let res = create_gfx_context_(eng, ring, drm, api, caps_thread, software);
|
let res =
|
||||||
|
create_gfx_context_(eng, ring, eventfd_cache, drm, api, caps_thread, software);
|
||||||
match res {
|
match res {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
log::info!("Created a {api:?} renderer");
|
log::info!("Created a {api:?} renderer");
|
||||||
|
|
@ -48,6 +51,7 @@ pub fn create_gfx_context(
|
||||||
fn create_gfx_context_(
|
fn create_gfx_context_(
|
||||||
eng: &Rc<AsyncEngine>,
|
eng: &Rc<AsyncEngine>,
|
||||||
ring: &Rc<IoUring>,
|
ring: &Rc<IoUring>,
|
||||||
|
eventfd_cache: &Rc<EventfdCache>,
|
||||||
drm: &Drm,
|
drm: &Drm,
|
||||||
api: GfxApi,
|
api: GfxApi,
|
||||||
caps_thread: Option<&PrCapsThread>,
|
caps_thread: Option<&PrCapsThread>,
|
||||||
|
|
@ -55,6 +59,8 @@ fn create_gfx_context_(
|
||||||
) -> Result<Rc<dyn GfxContext>, GfxError> {
|
) -> Result<Rc<dyn GfxContext>, GfxError> {
|
||||||
match api {
|
match api {
|
||||||
GfxApi::OpenGl => gl::create_gfx_context(drm, software),
|
GfxApi::OpenGl => gl::create_gfx_context(drm, software),
|
||||||
GfxApi::Vulkan => vulkan::create_graphics_context(eng, ring, drm, caps_thread, software),
|
GfxApi::Vulkan => {
|
||||||
|
vulkan::create_graphics_context(eng, ring, eventfd_cache, drm, caps_thread, software)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ use {
|
||||||
allocator::{Allocator, AllocatorError},
|
allocator::{Allocator, AllocatorError},
|
||||||
async_engine::AsyncEngine,
|
async_engine::AsyncEngine,
|
||||||
cpu_worker::{CpuWorker, jobs::read_write::ReadWriteJobError},
|
cpu_worker::{CpuWorker, jobs::read_write::ReadWriteJobError},
|
||||||
|
eventfd_cache::EventfdCache,
|
||||||
format::Format,
|
format::Format,
|
||||||
gfx_api::{
|
gfx_api::{
|
||||||
AsyncShmGfxTexture, GfxApi, GfxBlendBuffer, GfxBuffer, GfxContext, GfxError, GfxFormat,
|
AsyncShmGfxTexture, GfxApi, GfxBlendBuffer, GfxBuffer, GfxContext, GfxError, GfxFormat,
|
||||||
|
|
@ -212,6 +213,8 @@ pub enum VulkanError {
|
||||||
}
|
}
|
||||||
|
|
||||||
type VulkanSync = vulkan_core::sync::VulkanSync<VulkanDevice>;
|
type VulkanSync = vulkan_core::sync::VulkanSync<VulkanDevice>;
|
||||||
|
type VulkanTimelineSemaphore =
|
||||||
|
vulkan_core::timeline_semaphore::VulkanTimelineSemaphore<VulkanDevice>;
|
||||||
|
|
||||||
impl From<VulkanError> for GfxError {
|
impl From<VulkanError> for GfxError {
|
||||||
fn from(value: VulkanError) -> Self {
|
fn from(value: VulkanError) -> Self {
|
||||||
|
|
@ -222,6 +225,7 @@ impl From<VulkanError> for GfxError {
|
||||||
pub fn create_graphics_context(
|
pub fn create_graphics_context(
|
||||||
eng: &Rc<AsyncEngine>,
|
eng: &Rc<AsyncEngine>,
|
||||||
ring: &Rc<IoUring>,
|
ring: &Rc<IoUring>,
|
||||||
|
eventfd_cache: &Rc<EventfdCache>,
|
||||||
drm: &Drm,
|
drm: &Drm,
|
||||||
caps_thread: Option<&PrCapsThread>,
|
caps_thread: Option<&PrCapsThread>,
|
||||||
software: bool,
|
software: bool,
|
||||||
|
|
@ -229,22 +233,25 @@ pub fn create_graphics_context(
|
||||||
let instance = VulkanInstance::new(Level::Info)?;
|
let instance = VulkanInstance::new(Level::Info)?;
|
||||||
let device = 'device: {
|
let device = 'device: {
|
||||||
if let Some(t) = caps_thread {
|
if let Some(t) = caps_thread {
|
||||||
match unsafe { t.run(|| instance.create_device(drm, true, software)) } {
|
match unsafe { t.run(|| instance.create_device(drm, eventfd_cache, true, software)) } {
|
||||||
Ok(d) => break 'device d,
|
Ok(d) => break 'device d,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("Could not create high-priority device: {}", ErrorFmt(e));
|
log::warn!("Could not create high-priority device: {}", ErrorFmt(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
instance.create_device(drm, false, software)?
|
instance.create_device(drm, eventfd_cache, false, software)?
|
||||||
};
|
};
|
||||||
let renderer = device.create_renderer(eng, ring)?;
|
let renderer = device.create_renderer(eng, ring)?;
|
||||||
Ok(Rc::new(Context(renderer)))
|
Ok(Rc::new(Context(renderer)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_vulkan_allocator(drm: &Drm) -> Result<Rc<dyn Allocator>, AllocatorError> {
|
pub fn create_vulkan_allocator(
|
||||||
|
drm: &Drm,
|
||||||
|
eventfd_cache: &Rc<EventfdCache>,
|
||||||
|
) -> Result<Rc<dyn Allocator>, AllocatorError> {
|
||||||
let instance = VulkanInstance::new(Level::Debug)?;
|
let instance = VulkanInstance::new(Level::Debug)?;
|
||||||
let device = instance.create_device(drm, false, false)?;
|
let device = instance.create_device(drm, eventfd_cache, false, false)?;
|
||||||
let allocator = device.create_bo_allocator(drm)?;
|
let allocator = device.create_bo_allocator(drm)?;
|
||||||
Ok(Rc::new(allocator))
|
Ok(Rc::new(allocator))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
allocator::BufferObject,
|
allocator::BufferObject,
|
||||||
|
eventfd_cache::EventfdCache,
|
||||||
format::XRGB8888,
|
format::XRGB8888,
|
||||||
gfx_apis::vulkan::{
|
gfx_apis::vulkan::{
|
||||||
VulkanError,
|
VulkanError,
|
||||||
|
|
@ -14,8 +15,8 @@ use {
|
||||||
gbm::{GBM_BO_USE_RENDERING, GbmDevice},
|
gbm::{GBM_BO_USE_RENDERING, GbmDevice},
|
||||||
},
|
},
|
||||||
vulkan_core::{
|
vulkan_core::{
|
||||||
ApiVersionDisplay, Extensions, VULKAN_API_VERSION, device::VulkanDeviceInf,
|
ApiVersionDisplay, Extensions, VULKAN_API_VERSION, VulkanCoreInstance,
|
||||||
map_extension_properties,
|
device::VulkanDeviceInf, map_extension_properties,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
|
|
@ -64,6 +65,7 @@ pub struct VulkanDevice {
|
||||||
pub(super) sync_ctx: Rc<SyncobjCtx>,
|
pub(super) sync_ctx: Rc<SyncobjCtx>,
|
||||||
pub(super) instance: Rc<VulkanInstance>,
|
pub(super) instance: Rc<VulkanInstance>,
|
||||||
pub(super) device: Arc<Device>,
|
pub(super) device: Arc<Device>,
|
||||||
|
pub(super) eventfd_cache: Rc<EventfdCache>,
|
||||||
pub(super) external_memory_fd: external_memory_fd::Device,
|
pub(super) external_memory_fd: external_memory_fd::Device,
|
||||||
pub(super) external_semaphore_fd: external_semaphore_fd::Device,
|
pub(super) external_semaphore_fd: external_semaphore_fd::Device,
|
||||||
pub(super) external_fence_fd: external_fence_fd::Device,
|
pub(super) external_fence_fd: external_fence_fd::Device,
|
||||||
|
|
@ -86,6 +88,7 @@ pub struct VulkanDevice {
|
||||||
pub(super) uniform_buffer_descriptor_size: usize,
|
pub(super) uniform_buffer_descriptor_size: usize,
|
||||||
pub(super) lost: Cell<bool>,
|
pub(super) lost: Cell<bool>,
|
||||||
pub(super) fast_ram_access: bool,
|
pub(super) fast_ram_access: bool,
|
||||||
|
pub(super) supports_timeline_opaque_export: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for VulkanDevice {
|
impl Drop for VulkanDevice {
|
||||||
|
|
@ -338,6 +341,7 @@ impl VulkanInstance {
|
||||||
pub fn create_device(
|
pub fn create_device(
|
||||||
self: &Rc<Self>,
|
self: &Rc<Self>,
|
||||||
drm: &Drm,
|
drm: &Drm,
|
||||||
|
eventfd_cache: &Rc<EventfdCache>,
|
||||||
mut high_priority: bool,
|
mut high_priority: bool,
|
||||||
software: bool,
|
software: bool,
|
||||||
) -> Result<Rc<VulkanDevice>, VulkanError> {
|
) -> Result<Rc<VulkanDevice>, VulkanError> {
|
||||||
|
|
@ -380,6 +384,9 @@ impl VulkanInstance {
|
||||||
}
|
}
|
||||||
transfer_granularity_mask = (width_mask, height_mask);
|
transfer_granularity_mask = (width_mask, height_mask);
|
||||||
}
|
}
|
||||||
|
let features = self.get_features(phy_dev);
|
||||||
|
let supports_timeline_opaque_export =
|
||||||
|
self.supports_timeline_opaque_export(phy_dev, &features);
|
||||||
if !self.supports_semaphore_import(phy_dev) {
|
if !self.supports_semaphore_import(phy_dev) {
|
||||||
return Err(VulkanError::SyncFileImport);
|
return Err(VulkanError::SyncFileImport);
|
||||||
}
|
}
|
||||||
|
|
@ -390,8 +397,8 @@ impl VulkanInstance {
|
||||||
if supports_descriptor_buffer {
|
if supports_descriptor_buffer {
|
||||||
enabled_extensions.push(descriptor_buffer::NAME.as_ptr());
|
enabled_extensions.push(descriptor_buffer::NAME.as_ptr());
|
||||||
}
|
}
|
||||||
let mut semaphore_features =
|
let mut semaphore_features = PhysicalDeviceTimelineSemaphoreFeatures::default()
|
||||||
PhysicalDeviceTimelineSemaphoreFeatures::default().timeline_semaphore(true);
|
.timeline_semaphore(supports_timeline_opaque_export);
|
||||||
let mut synchronization2_features =
|
let mut synchronization2_features =
|
||||||
PhysicalDeviceSynchronization2Features::default().synchronization2(true);
|
PhysicalDeviceSynchronization2Features::default().synchronization2(true);
|
||||||
let mut dynamic_rendering_features =
|
let mut dynamic_rendering_features =
|
||||||
|
|
@ -558,6 +565,7 @@ impl VulkanInstance {
|
||||||
gbm: Rc::new(gbm),
|
gbm: Rc::new(gbm),
|
||||||
instance: self.clone(),
|
instance: self.clone(),
|
||||||
device: Arc::new(device),
|
device: Arc::new(device),
|
||||||
|
eventfd_cache: eventfd_cache.clone(),
|
||||||
external_memory_fd,
|
external_memory_fd,
|
||||||
external_semaphore_fd,
|
external_semaphore_fd,
|
||||||
external_fence_fd,
|
external_fence_fd,
|
||||||
|
|
@ -581,6 +589,7 @@ impl VulkanInstance {
|
||||||
uniform_buffer_descriptor_size,
|
uniform_buffer_descriptor_size,
|
||||||
lost: Cell::new(false),
|
lost: Cell::new(false),
|
||||||
fast_ram_access,
|
fast_ram_access,
|
||||||
|
supports_timeline_opaque_export,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -642,6 +651,10 @@ fn log_device(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VulkanDeviceInf for VulkanDevice {
|
impl VulkanDeviceInf for VulkanDevice {
|
||||||
|
fn instance(&self) -> &VulkanCoreInstance {
|
||||||
|
&self.instance
|
||||||
|
}
|
||||||
|
|
||||||
fn device(&self) -> &Device {
|
fn device(&self) -> &Device {
|
||||||
&self.device
|
&self.device
|
||||||
}
|
}
|
||||||
|
|
@ -649,4 +662,20 @@ impl VulkanDeviceInf for VulkanDevice {
|
||||||
fn external_fence_fd(&self) -> &external_fence_fd::Device {
|
fn external_fence_fd(&self) -> &external_fence_fd::Device {
|
||||||
&self.external_fence_fd
|
&self.external_fence_fd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn external_semaphore_fd(&self) -> &external_semaphore_fd::Device {
|
||||||
|
&self.external_semaphore_fd
|
||||||
|
}
|
||||||
|
|
||||||
|
fn supports_timeline_opaque_export(&self) -> bool {
|
||||||
|
self.supports_timeline_opaque_export
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync_ctx(&self) -> &Rc<SyncobjCtx> {
|
||||||
|
&self.sync_ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eventfd_cache(&self) -> &Rc<EventfdCache> {
|
||||||
|
&self.eventfd_cache
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use {
|
||||||
GfxFormat, GfxTexture, GfxWriteModifier, ReleaseSync,
|
GfxFormat, GfxTexture, GfxWriteModifier, ReleaseSync,
|
||||||
},
|
},
|
||||||
gfx_apis::vulkan::{
|
gfx_apis::vulkan::{
|
||||||
VulkanError, VulkanSync,
|
VulkanError, VulkanSync, VulkanTimelineSemaphore,
|
||||||
allocator::{VulkanAllocator, VulkanThreadedAllocator},
|
allocator::{VulkanAllocator, VulkanThreadedAllocator},
|
||||||
buffer_cache::{GenericBufferWriter, VulkanBuffer, VulkanBufferCache},
|
buffer_cache::{GenericBufferWriter, VulkanBuffer, VulkanBufferCache},
|
||||||
command::{VulkanCommandBuffer, VulkanCommandPool},
|
command::{VulkanCommandBuffer, VulkanCommandPool},
|
||||||
|
|
@ -39,7 +39,9 @@ use {
|
||||||
stack::Stack,
|
stack::Stack,
|
||||||
},
|
},
|
||||||
video::dmabuf::{DMA_BUF_SYNC_READ, DMA_BUF_SYNC_WRITE, dma_buf_export_sync_file},
|
video::dmabuf::{DMA_BUF_SYNC_READ, DMA_BUF_SYNC_WRITE, dma_buf_export_sync_file},
|
||||||
vulkan_core::sync::VulkanDeviceSyncExt,
|
vulkan_core::{
|
||||||
|
sync::VulkanDeviceSyncExt, timeline_semaphore::VulkanDeviceTimelineSemaphoreExt,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
arrayvec::ArrayVec,
|
arrayvec::ArrayVec,
|
||||||
|
|
@ -113,6 +115,8 @@ pub struct VulkanRenderer {
|
||||||
pub(super) blend_buffers: RefCell<AHashMap<(u32, u32), Weak<VulkanImage>>>,
|
pub(super) blend_buffers: RefCell<AHashMap<(u32, u32), Weak<VulkanImage>>>,
|
||||||
pub(super) shader_buffer_cache: Rc<VulkanBufferCache>,
|
pub(super) shader_buffer_cache: Rc<VulkanBufferCache>,
|
||||||
pub(super) uniform_buffer_cache: Rc<VulkanBufferCache>,
|
pub(super) uniform_buffer_cache: Rc<VulkanBufferCache>,
|
||||||
|
pub(super) render_tls: Option<Rc<VulkanTimelineSemaphore>>,
|
||||||
|
pub(super) transfer_tls: Option<Rc<VulkanTimelineSemaphore>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct CachedCommandBuffers {
|
pub(super) struct CachedCommandBuffers {
|
||||||
|
|
@ -407,6 +411,8 @@ impl VulkanDevice {
|
||||||
blend_buffers: Default::default(),
|
blend_buffers: Default::default(),
|
||||||
shader_buffer_cache,
|
shader_buffer_cache,
|
||||||
uniform_buffer_cache,
|
uniform_buffer_cache,
|
||||||
|
render_tls: self.create_timeline_semaphore_or_log(),
|
||||||
|
transfer_tls: self.create_timeline_semaphore_or_log(),
|
||||||
});
|
});
|
||||||
Ok(render)
|
Ok(render)
|
||||||
}
|
}
|
||||||
|
|
@ -1755,11 +1761,16 @@ impl VulkanRenderer {
|
||||||
fn submit(&self, buf: CommandBuffer) -> Result<(), VulkanError> {
|
fn submit(&self, buf: CommandBuffer) -> Result<(), VulkanError> {
|
||||||
zone!("submit");
|
zone!("submit");
|
||||||
let mut memory = self.memory.borrow_mut();
|
let mut memory = self.memory.borrow_mut();
|
||||||
|
let mut semaphore_submit_info = SemaphoreSubmitInfo::default();
|
||||||
let command_buffer_info = CommandBufferSubmitInfo::default().command_buffer(buf);
|
let command_buffer_info = CommandBufferSubmitInfo::default().command_buffer(buf);
|
||||||
let submit_info = SubmitInfo2::default()
|
let mut submit_info = SubmitInfo2::default()
|
||||||
.wait_semaphore_infos(&memory.wait_semaphore_infos)
|
.wait_semaphore_infos(&memory.wait_semaphore_infos)
|
||||||
.command_buffer_infos(slice::from_ref(&command_buffer_info));
|
.command_buffer_infos(slice::from_ref(&command_buffer_info));
|
||||||
let vulkan_sync = self.device.create_sync()?;
|
let vulkan_sync = self.device.create_sync(
|
||||||
|
self.render_tls.as_ref(),
|
||||||
|
&mut semaphore_submit_info,
|
||||||
|
&mut submit_info,
|
||||||
|
)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
self.device
|
self.device
|
||||||
.device
|
.device
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,8 @@ use {
|
||||||
CopyImageToBufferInfo2, DependencyInfoKHR, DeviceSize, Extent3D, ImageAspectFlags,
|
CopyImageToBufferInfo2, DependencyInfoKHR, DeviceSize, Extent3D, ImageAspectFlags,
|
||||||
ImageCreateInfo, ImageLayout, ImageSubresourceLayers, ImageSubresourceRange, ImageTiling,
|
ImageCreateInfo, ImageLayout, ImageSubresourceLayers, ImageSubresourceRange, ImageTiling,
|
||||||
ImageType, ImageUsageFlags, ImageViewCreateInfo, ImageViewType, Offset3D,
|
ImageType, ImageUsageFlags, ImageViewCreateInfo, ImageViewType, Offset3D,
|
||||||
PipelineStageFlags2, QUEUE_FAMILY_FOREIGN_EXT, SampleCountFlags, SharingMode, SubmitInfo2,
|
PipelineStageFlags2, QUEUE_FAMILY_FOREIGN_EXT, SampleCountFlags, SemaphoreSubmitInfo,
|
||||||
|
SharingMode, SubmitInfo2,
|
||||||
},
|
},
|
||||||
gpu_alloc::UsageFlags,
|
gpu_alloc::UsageFlags,
|
||||||
isnt::std_1::primitive::IsntSliceExt,
|
isnt::std_1::primitive::IsntSliceExt,
|
||||||
|
|
@ -269,11 +270,20 @@ impl VulkanShmImage {
|
||||||
};
|
};
|
||||||
let dev = &img.renderer.device.device;
|
let dev = &img.renderer.device.device;
|
||||||
let command_buffer_info = CommandBufferSubmitInfo::default().command_buffer(cmd.buffer);
|
let command_buffer_info = CommandBufferSubmitInfo::default().command_buffer(cmd.buffer);
|
||||||
let submit_info =
|
let mut semaphore_submit_info = SemaphoreSubmitInfo::default();
|
||||||
|
let mut submit_info =
|
||||||
SubmitInfo2::default().command_buffer_infos(slice::from_ref(&command_buffer_info));
|
SubmitInfo2::default().command_buffer_infos(slice::from_ref(&command_buffer_info));
|
||||||
let begin_info =
|
let begin_info =
|
||||||
CommandBufferBeginInfo::default().flags(CommandBufferUsageFlags::ONE_TIME_SUBMIT);
|
CommandBufferBeginInfo::default().flags(CommandBufferUsageFlags::ONE_TIME_SUBMIT);
|
||||||
let vulkan_sync = img.renderer.device.create_sync()?;
|
let tls = match use_transfer_queue {
|
||||||
|
true => &img.renderer.transfer_tls,
|
||||||
|
false => &img.renderer.render_tls,
|
||||||
|
};
|
||||||
|
let vulkan_sync = img.renderer.device.create_sync(
|
||||||
|
tls.as_ref(),
|
||||||
|
&mut semaphore_submit_info,
|
||||||
|
&mut submit_info,
|
||||||
|
)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
dev.begin_command_buffer(cmd.buffer, &begin_info)
|
dev.begin_command_buffer(cmd.buffer, &begin_info)
|
||||||
.map_err(VulkanError::BeginCommandBuffer)?;
|
.map_err(VulkanError::BeginCommandBuffer)?;
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ use {
|
||||||
ash::vk::{
|
ash::vk::{
|
||||||
AccessFlags2, BufferImageCopy2, CommandBufferBeginInfo, CommandBufferSubmitInfo,
|
AccessFlags2, BufferImageCopy2, CommandBufferBeginInfo, CommandBufferSubmitInfo,
|
||||||
CommandBufferUsageFlags, DependencyInfo, Extent3D, ImageAspectFlags, ImageLayout,
|
CommandBufferUsageFlags, DependencyInfo, Extent3D, ImageAspectFlags, ImageLayout,
|
||||||
ImageSubresourceLayers, Offset3D, PipelineStageFlags2, SubmitInfo2,
|
ImageSubresourceLayers, Offset3D, PipelineStageFlags2, SemaphoreSubmitInfo, SubmitInfo2,
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell, RefMut},
|
cell::{Cell, RefCell, RefMut},
|
||||||
|
|
@ -380,9 +380,14 @@ impl VulkanShmImage {
|
||||||
CommandBufferBeginInfo::default().flags(CommandBufferUsageFlags::ONE_TIME_SUBMIT);
|
CommandBufferBeginInfo::default().flags(CommandBufferUsageFlags::ONE_TIME_SUBMIT);
|
||||||
let cmd = img.renderer.gfx_command_buffers.allocate()?;
|
let cmd = img.renderer.gfx_command_buffers.allocate()?;
|
||||||
let command_buffer_info = CommandBufferSubmitInfo::default().command_buffer(cmd.buffer);
|
let command_buffer_info = CommandBufferSubmitInfo::default().command_buffer(cmd.buffer);
|
||||||
let submit_info =
|
let mut semaphore_submit_info = SemaphoreSubmitInfo::default();
|
||||||
|
let mut submit_info =
|
||||||
SubmitInfo2::default().command_buffer_infos(slice::from_ref(&command_buffer_info));
|
SubmitInfo2::default().command_buffer_infos(slice::from_ref(&command_buffer_info));
|
||||||
let vulkan_sync = img.renderer.device.create_sync()?;
|
let vulkan_sync = img.renderer.device.create_sync(
|
||||||
|
img.renderer.render_tls.as_ref(),
|
||||||
|
&mut semaphore_submit_info,
|
||||||
|
&mut submit_info,
|
||||||
|
)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
dev.begin_command_buffer(cmd.buffer, &begin_info)
|
dev.begin_command_buffer(cmd.buffer, &begin_info)
|
||||||
.map_err(VulkanError::BeginCommandBuffer)?;
|
.map_err(VulkanError::BeginCommandBuffer)?;
|
||||||
|
|
|
||||||
|
|
@ -211,7 +211,10 @@ impl TestBackend {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
let udmabuf = ("udmabuf", constructor!(Udmabuf::new()));
|
let udmabuf = ("udmabuf", constructor!(Udmabuf::new()));
|
||||||
let vulkan = ("Vulkan", constructor!(create_vk_allocator(), nomap));
|
let vulkan = (
|
||||||
|
"Vulkan",
|
||||||
|
constructor!(create_vk_allocator(&self.state), nomap),
|
||||||
|
);
|
||||||
let gbm = ("GBM", constructor!(create_gbm_allocator()));
|
let gbm = ("GBM", constructor!(create_gbm_allocator()));
|
||||||
let allocators = match need_drm {
|
let allocators = match need_drm {
|
||||||
true => [vulkan, gbm, udmabuf],
|
true => [vulkan, gbm, udmabuf],
|
||||||
|
|
@ -243,9 +246,10 @@ fn create_gbm_allocator() -> Result<GbmDevice, TestBackendError> {
|
||||||
create_drm_allocator(|drm| GbmDevice::new(&drm).map_err(TestBackendError::CreateGbmDevice))
|
create_drm_allocator(|drm| GbmDevice::new(&drm).map_err(TestBackendError::CreateGbmDevice))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_vk_allocator() -> Result<Rc<dyn Allocator>, TestBackendError> {
|
fn create_vk_allocator(state: &State) -> Result<Rc<dyn Allocator>, TestBackendError> {
|
||||||
create_drm_allocator(|drm| {
|
create_drm_allocator(|drm| {
|
||||||
create_vulkan_allocator(&drm).map_err(TestBackendError::CreateVulkanAllocator)
|
create_vulkan_allocator(&drm, &state.eventfd_cache)
|
||||||
|
.map_err(TestBackendError::CreateVulkanAllocator)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,12 @@ impl TestClient {
|
||||||
|
|
||||||
pub async fn take_screenshot(&self, include_cursor: bool) -> Result<Vec<u8>, TestError> {
|
pub async fn take_screenshot(&self, include_cursor: bool) -> Result<Vec<u8>, TestError> {
|
||||||
let (dmabuf, dev) = self.jc.take_screenshot(include_cursor).await?;
|
let (dmabuf, dev) = self.jc.take_screenshot(include_cursor).await?;
|
||||||
let qoi = buf_to_bytes(dev.as_ref(), &dmabuf, ScreenshotFormat::Qoi)?;
|
let qoi = buf_to_bytes(
|
||||||
|
&self.run.state.eventfd_cache,
|
||||||
|
dev.as_ref(),
|
||||||
|
&dmabuf,
|
||||||
|
ScreenshotFormat::Qoi,
|
||||||
|
)?;
|
||||||
Ok(qoi)
|
Ok(qoi)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -327,7 +327,6 @@ async fn init_dbus_session(dbus: &Dbus, logger: Arc<Logger>, path_sink: OwnedFd)
|
||||||
struct PortalState {
|
struct PortalState {
|
||||||
xrd: String,
|
xrd: String,
|
||||||
ring: Rc<IoUring>,
|
ring: Rc<IoUring>,
|
||||||
#[expect(dead_code)]
|
|
||||||
eventfd_cache: Rc<EventfdCache>,
|
eventfd_cache: Rc<EventfdCache>,
|
||||||
eng: Rc<AsyncEngine>,
|
eng: Rc<AsyncEngine>,
|
||||||
wheel: Rc<Wheel>,
|
wheel: Rc<Wheel>,
|
||||||
|
|
|
||||||
|
|
@ -187,6 +187,7 @@ impl UsrJayRenderCtxOwner for PortalDisplay {
|
||||||
let ctx = match create_gfx_context(
|
let ctx = match create_gfx_context(
|
||||||
&self.state.eng,
|
&self.state.eng,
|
||||||
&self.state.ring,
|
&self.state.ring,
|
||||||
|
&self.state.eventfd_cache,
|
||||||
&drm,
|
&drm,
|
||||||
GfxApi::OpenGl,
|
GfxApi::OpenGl,
|
||||||
None,
|
None,
|
||||||
|
|
|
||||||
|
|
@ -289,7 +289,6 @@ pub struct State {
|
||||||
pub gfx_ctx_changed: EventSource<WlBuffer>,
|
pub gfx_ctx_changed: EventSource<WlBuffer>,
|
||||||
pub copy_device_registry: Rc<CopyDeviceRegistry>,
|
pub copy_device_registry: Rc<CopyDeviceRegistry>,
|
||||||
pub supports_presentation_feedback: Cell<bool>,
|
pub supports_presentation_feedback: Cell<bool>,
|
||||||
#[expect(dead_code)]
|
|
||||||
pub eventfd_cache: Rc<EventfdCache>,
|
pub eventfd_cache: Rc<EventfdCache>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -558,6 +557,7 @@ impl State {
|
||||||
create_gfx_context(
|
create_gfx_context(
|
||||||
&self.eng,
|
&self.eng,
|
||||||
&self.ring,
|
&self.ring,
|
||||||
|
&self.eventfd_cache,
|
||||||
drm,
|
drm,
|
||||||
api.unwrap_or(self.default_gfx_api.get()),
|
api.unwrap_or(self.default_gfx_api.get()),
|
||||||
self.caps_thread.as_ref(),
|
self.caps_thread.as_ref(),
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,33 @@
|
||||||
pub mod syncobj;
|
pub mod syncobj;
|
||||||
mod sys;
|
mod sys;
|
||||||
pub mod wait_for_syncobj;
|
pub mod wait_for_syncobj;
|
||||||
pub use consts::*;
|
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
utils::oserror::OsError,
|
backend,
|
||||||
video::drm::sys::{
|
format::Format,
|
||||||
DRM_DISPLAY_MODE_LEN, DRM_MODE_ATOMIC_TEST_ONLY, DRM_MODE_FB_MODIFIERS,
|
io_uring::{IoUring, IoUringError},
|
||||||
DRM_MODE_OBJECT_BLOB, DRM_MODE_OBJECT_CONNECTOR, DRM_MODE_OBJECT_CRTC,
|
utils::{
|
||||||
DRM_MODE_OBJECT_ENCODER, DRM_MODE_OBJECT_FB, DRM_MODE_OBJECT_PLANE,
|
buf::Buf, errorfmt::ErrorFmt, oserror::OsError, stack::Stack, syncqueue::SyncQueue,
|
||||||
DRM_MODE_OBJECT_PROPERTY, create_lease, drm_event, drm_event_vblank, gem_close,
|
vec_ext::VecExt,
|
||||||
get_cap, get_device_name_from_fd2, get_minor_name_from_fd, get_node_type_from_fd,
|
},
|
||||||
get_nodes, mode_addfb2, mode_atomic, mode_create_blob, mode_destroy_blob,
|
video::{
|
||||||
mode_get_resources, mode_getconnector, mode_getencoder, mode_getplane,
|
INVALID_MODIFIER, Modifier,
|
||||||
mode_getplaneresources, mode_getprobblob, mode_getproperty, mode_obj_getproperties,
|
dmabuf::DmaBuf,
|
||||||
mode_rmfb, prime_fd_to_handle, set_client_cap,
|
drm::sys::{
|
||||||
|
DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP, DRM_CAP_CURSOR_HEIGHT, DRM_CAP_CURSOR_WIDTH,
|
||||||
|
DRM_DISPLAY_MODE_LEN, DRM_MODE_ATOMIC_TEST_ONLY, DRM_MODE_FB_MODIFIERS,
|
||||||
|
DRM_MODE_OBJECT_BLOB, DRM_MODE_OBJECT_CONNECTOR, DRM_MODE_OBJECT_CRTC,
|
||||||
|
DRM_MODE_OBJECT_ENCODER, DRM_MODE_OBJECT_FB, DRM_MODE_OBJECT_PLANE,
|
||||||
|
DRM_MODE_OBJECT_PROPERTY, FORMAT_BLOB_CURRENT, auth_magic, create_lease, drm_event,
|
||||||
|
drm_event_crtc_sequence, drm_event_vblank, drm_format_modifier,
|
||||||
|
drm_format_modifier_blob, drop_master, gem_close, get_cap,
|
||||||
|
get_device_name_from_fd2, get_minor_name_from_fd, get_node_type_from_fd, get_nodes,
|
||||||
|
get_version, mode_addfb2, mode_atomic, mode_create_blob, mode_destroy_blob,
|
||||||
|
mode_get_resources, mode_getconnector, mode_getencoder, mode_getplane,
|
||||||
|
mode_getplaneresources, mode_getprobblob, mode_getproperty, mode_obj_getproperties,
|
||||||
|
mode_rmfb, prime_fd_to_handle, queue_sequence, revoke_lease, set_client_cap,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
|
|
@ -32,26 +44,14 @@ use {
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
uapi::{OwnedFd, Pod, Ustring, c},
|
uapi::{OwnedFd, Pod, Ustring, c},
|
||||||
};
|
};
|
||||||
|
pub use {
|
||||||
use crate::{
|
consts::*,
|
||||||
backend,
|
sys::{
|
||||||
format::Format,
|
DRM_CLIENT_CAP_ATOMIC, DRM_MODE_ATOMIC_ALLOW_MODESET, DRM_MODE_ATOMIC_NONBLOCK,
|
||||||
io_uring::{IoUring, IoUringError},
|
DRM_MODE_PAGE_FLIP_ASYNC, DRM_MODE_PAGE_FLIP_EVENT, drm_mode_modeinfo,
|
||||||
utils::{buf::Buf, errorfmt::ErrorFmt, stack::Stack, syncqueue::SyncQueue, vec_ext::VecExt},
|
get_drm_nodes_from_dev,
|
||||||
video::{
|
|
||||||
INVALID_MODIFIER, Modifier,
|
|
||||||
dmabuf::DmaBuf,
|
|
||||||
drm::sys::{
|
|
||||||
DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP, DRM_CAP_CURSOR_HEIGHT, DRM_CAP_CURSOR_WIDTH,
|
|
||||||
FORMAT_BLOB_CURRENT, auth_magic, drm_event_crtc_sequence, drm_format_modifier,
|
|
||||||
drm_format_modifier_blob, drop_master, get_version, queue_sequence, revoke_lease,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
pub use sys::{
|
|
||||||
DRM_CLIENT_CAP_ATOMIC, DRM_MODE_ATOMIC_ALLOW_MODESET, DRM_MODE_ATOMIC_NONBLOCK,
|
|
||||||
DRM_MODE_PAGE_FLIP_ASYNC, DRM_MODE_PAGE_FLIP_EVENT, drm_mode_modeinfo,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum DrmError {
|
pub enum DrmError {
|
||||||
|
|
@ -123,6 +123,8 @@ pub enum DrmError {
|
||||||
CreateSyncobj(#[source] OsError),
|
CreateSyncobj(#[source] OsError),
|
||||||
#[error("Could not export a syncobj")]
|
#[error("Could not export a syncobj")]
|
||||||
ExportSyncobj(#[source] OsError),
|
ExportSyncobj(#[source] OsError),
|
||||||
|
#[error("Could not query a syncobj")]
|
||||||
|
QuerySyncobj(#[source] OsError),
|
||||||
#[error("Could not register an eventfd with a syncobj")]
|
#[error("Could not register an eventfd with a syncobj")]
|
||||||
RegisterEventfd(#[source] OsError),
|
RegisterEventfd(#[source] OsError),
|
||||||
#[error("Could not create an eventfd")]
|
#[error("Could not create an eventfd")]
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ use {
|
||||||
DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_TIMELINE, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE,
|
DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_TIMELINE, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE,
|
||||||
DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, sync_ioc_merge, syncobj_create,
|
DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, sync_ioc_merge, syncobj_create,
|
||||||
syncobj_destroy, syncobj_eventfd, syncobj_fd_to_handle, syncobj_handle_to_fd,
|
syncobj_destroy, syncobj_eventfd, syncobj_fd_to_handle, syncobj_handle_to_fd,
|
||||||
syncobj_signal, syncobj_transfer,
|
syncobj_query, syncobj_signal, syncobj_transfer,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -329,6 +329,11 @@ impl SyncobjCtx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn query_last_signaled(&self, syncobj: &Syncobj) -> Result<u64, DrmError> {
|
||||||
|
let handle = self.get_handle(syncobj)?;
|
||||||
|
syncobj_query(self.inner.drm.raw(), handle.0).map_err(DrmError::QuerySyncobj)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for SyncobjCtx {
|
impl Drop for SyncobjCtx {
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,10 @@ pub fn get_device_name_from_fd2(fd: c::c_int) -> Result<Ustring, OsError> {
|
||||||
|
|
||||||
pub fn get_nodes(fd: c::c_int) -> Result<AHashMap<NodeType, CString>, OsError> {
|
pub fn get_nodes(fd: c::c_int) -> Result<AHashMap<NodeType, CString>, OsError> {
|
||||||
let (_, maj, min) = drm_stat(fd)?;
|
let (_, maj, min) = drm_stat(fd)?;
|
||||||
|
get_drm_nodes_from_dev(maj, min)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_drm_nodes_from_dev(maj: u64, min: u64) -> Result<AHashMap<NodeType, CString>, OsError> {
|
||||||
let dir = device_dir(maj, min);
|
let dir = device_dir(maj, min);
|
||||||
let mut dir = uapi::opendir(dir)?;
|
let mut dir = uapi::opendir(dir)?;
|
||||||
|
|
||||||
|
|
@ -1334,6 +1337,22 @@ pub fn syncobj_signal(drm: c::c_int, handle: u32, point: u64) -> Result<(), OsEr
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DRM_IOCTL_SYNCOBJ_QUERY: u64 = drm_iowr::<drm_syncobj_timeline_array>(0xCB);
|
||||||
|
|
||||||
|
pub fn syncobj_query(drm: c::c_int, handle: u32) -> Result<u64, OsError> {
|
||||||
|
let mut point = 0u64;
|
||||||
|
let mut res = drm_syncobj_timeline_array {
|
||||||
|
handles: &handle as *const u32 as u64,
|
||||||
|
points: &mut point as *mut u64 as u64,
|
||||||
|
count_handles: 1,
|
||||||
|
flags: 0,
|
||||||
|
};
|
||||||
|
unsafe {
|
||||||
|
ioctl(drm, DRM_IOCTL_SYNCOBJ_QUERY, &mut res)?;
|
||||||
|
}
|
||||||
|
Ok(point)
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct drm_syncobj_transfer {
|
struct drm_syncobj_transfer {
|
||||||
src_handle: u32,
|
src_handle: u32,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use {
|
use {
|
||||||
|
crate::{eventfd_cache::EventfdError, video::drm::DrmError},
|
||||||
ahash::{AHashMap, AHashSet},
|
ahash::{AHashMap, AHashSet},
|
||||||
ash::{
|
ash::{
|
||||||
Entry, Instance, LoadingError,
|
Entry, Instance, LoadingError,
|
||||||
|
|
@ -6,9 +7,13 @@ use {
|
||||||
vk::{
|
vk::{
|
||||||
self, API_VERSION_1_3, ApplicationInfo, Bool32, DebugUtilsMessageSeverityFlagsEXT,
|
self, API_VERSION_1_3, ApplicationInfo, Bool32, DebugUtilsMessageSeverityFlagsEXT,
|
||||||
DebugUtilsMessageTypeFlagsEXT, DebugUtilsMessengerCallbackDataEXT,
|
DebugUtilsMessageTypeFlagsEXT, DebugUtilsMessengerCallbackDataEXT,
|
||||||
DebugUtilsMessengerCreateInfoEXT, DebugUtilsMessengerEXT, ExtensionProperties, FALSE,
|
DebugUtilsMessengerCreateInfoEXT, DebugUtilsMessengerEXT, ExtensionProperties,
|
||||||
InstanceCreateInfo, LayerProperties, ValidationFeaturesEXT, api_version_major,
|
ExternalSemaphoreFeatureFlags, ExternalSemaphoreHandleTypeFlags,
|
||||||
api_version_minor, api_version_patch, api_version_variant,
|
ExternalSemaphoreProperties, FALSE, InstanceCreateInfo, LayerProperties,
|
||||||
|
PhysicalDevice, PhysicalDeviceExternalSemaphoreInfo, PhysicalDeviceFeatures,
|
||||||
|
PhysicalDeviceFeatures2, PhysicalDeviceTimelineSemaphoreFeatures, SemaphoreType,
|
||||||
|
SemaphoreTypeCreateInfo, ValidationFeaturesEXT, api_version_major, api_version_minor,
|
||||||
|
api_version_patch, api_version_variant,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
isnt::std_1::collections::IsntHashMapExt,
|
isnt::std_1::collections::IsntHashMapExt,
|
||||||
|
|
@ -28,6 +33,7 @@ use {
|
||||||
pub mod device;
|
pub mod device;
|
||||||
pub mod fence;
|
pub mod fence;
|
||||||
pub mod sync;
|
pub mod sync;
|
||||||
|
pub mod timeline_semaphore;
|
||||||
|
|
||||||
static VULKAN_ENTRY: Lazy<Result<Entry, Arc<LoadingError>>> =
|
static VULKAN_ENTRY: Lazy<Result<Entry, Arc<LoadingError>>> =
|
||||||
Lazy::new(|| unsafe { Entry::load() }.map_err(Arc::new));
|
Lazy::new(|| unsafe { Entry::load() }.map_err(Arc::new));
|
||||||
|
|
@ -53,6 +59,22 @@ pub enum VulkanCoreError {
|
||||||
CreateFence(#[source] vk::Result),
|
CreateFence(#[source] vk::Result),
|
||||||
#[error("Could not export a sync file from a semaphore")]
|
#[error("Could not export a sync file from a semaphore")]
|
||||||
ExportSyncFile(#[source] vk::Result),
|
ExportSyncFile(#[source] vk::Result),
|
||||||
|
#[error("Could not create a semaphore")]
|
||||||
|
CreateSemaphore(#[source] vk::Result),
|
||||||
|
#[error("Device does not support timeline semaphore export")]
|
||||||
|
TimelineExportNotSupported,
|
||||||
|
#[error("Could not export an opaque fd from a semaphore")]
|
||||||
|
ExportTimelineSemaphore(#[source] vk::Result),
|
||||||
|
#[error("Could not signal the timeline semaphore")]
|
||||||
|
SignalSemaphore(#[source] vk::Result),
|
||||||
|
#[error("Could not query last signaled sync obj point")]
|
||||||
|
QueryLastSignaled(#[source] DrmError),
|
||||||
|
#[error("Mapping between syncobj points and timeline semaphore points is unexpected")]
|
||||||
|
UnsupportedPointMapping,
|
||||||
|
#[error("Could not acquire an eventfd")]
|
||||||
|
AcquireEventfd(#[source] EventfdError),
|
||||||
|
#[error("Could not create a sync obj eventfd wait")]
|
||||||
|
CreateSyncobjWait(#[source] DrmError),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct VulkanCoreInstance {
|
pub struct VulkanCoreInstance {
|
||||||
|
|
@ -61,6 +83,13 @@ pub struct VulkanCoreInstance {
|
||||||
debug_utils: debug_utils::Instance,
|
debug_utils: debug_utils::Instance,
|
||||||
messenger: DebugUtilsMessengerEXT,
|
messenger: DebugUtilsMessengerEXT,
|
||||||
pub log_level: Level,
|
pub log_level: Level,
|
||||||
|
pub validation: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VulkanDeviceFeatures {
|
||||||
|
#[expect(dead_code)]
|
||||||
|
pub features: PhysicalDeviceFeatures,
|
||||||
|
pub semaphore_features: PhysicalDeviceTimelineSemaphoreFeatures<'static>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VulkanCoreInstance {
|
impl VulkanCoreInstance {
|
||||||
|
|
@ -86,7 +115,8 @@ impl VulkanCoreInstance {
|
||||||
let mut severity = DebugUtilsMessageSeverityFlagsEXT::empty()
|
let mut severity = DebugUtilsMessageSeverityFlagsEXT::empty()
|
||||||
| DebugUtilsMessageSeverityFlagsEXT::ERROR
|
| DebugUtilsMessageSeverityFlagsEXT::ERROR
|
||||||
| DebugUtilsMessageSeverityFlagsEXT::WARNING;
|
| DebugUtilsMessageSeverityFlagsEXT::WARNING;
|
||||||
if *VULKAN_VALIDATION {
|
let validation = *VULKAN_VALIDATION;
|
||||||
|
if validation {
|
||||||
severity |= DebugUtilsMessageSeverityFlagsEXT::INFO
|
severity |= DebugUtilsMessageSeverityFlagsEXT::INFO
|
||||||
| DebugUtilsMessageSeverityFlagsEXT::VERBOSE;
|
| DebugUtilsMessageSeverityFlagsEXT::VERBOSE;
|
||||||
}
|
}
|
||||||
|
|
@ -110,7 +140,7 @@ impl VulkanCoreInstance {
|
||||||
.application_info(&app_info)
|
.application_info(&app_info)
|
||||||
.push_next(&mut debug_info);
|
.push_next(&mut debug_info);
|
||||||
let validation_layer_name = VALIDATION_LAYER.as_ptr();
|
let validation_layer_name = VALIDATION_LAYER.as_ptr();
|
||||||
if *VULKAN_VALIDATION {
|
if validation {
|
||||||
if get_available_layers(entry)?.contains(VALIDATION_LAYER) {
|
if get_available_layers(entry)?.contains(VALIDATION_LAYER) {
|
||||||
create_info =
|
create_info =
|
||||||
create_info.enabled_layer_names(slice::from_ref(&validation_layer_name));
|
create_info.enabled_layer_names(slice::from_ref(&validation_layer_name));
|
||||||
|
|
@ -146,8 +176,49 @@ impl VulkanCoreInstance {
|
||||||
debug_utils,
|
debug_utils,
|
||||||
messenger,
|
messenger,
|
||||||
log_level,
|
log_level,
|
||||||
|
validation,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_features(&self, phy_dev: PhysicalDevice) -> VulkanDeviceFeatures {
|
||||||
|
let mut semaphore_features = PhysicalDeviceTimelineSemaphoreFeatures::default();
|
||||||
|
let mut features = PhysicalDeviceFeatures2::default().push_next(&mut semaphore_features);
|
||||||
|
unsafe {
|
||||||
|
self.instance
|
||||||
|
.get_physical_device_features2(phy_dev, &mut features);
|
||||||
|
}
|
||||||
|
VulkanDeviceFeatures {
|
||||||
|
features: features.features,
|
||||||
|
semaphore_features,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn supports_timeline_opaque_export(
|
||||||
|
&self,
|
||||||
|
phy_dev: PhysicalDevice,
|
||||||
|
features: &VulkanDeviceFeatures,
|
||||||
|
) -> bool {
|
||||||
|
if features.semaphore_features.timeline_semaphore == vk::TRUE {
|
||||||
|
return self.supports_semaphore_opaque_export(phy_dev);
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn supports_semaphore_opaque_export(&self, phy_dev: PhysicalDevice) -> bool {
|
||||||
|
let mut props = ExternalSemaphoreProperties::default();
|
||||||
|
let mut type_info =
|
||||||
|
SemaphoreTypeCreateInfo::default().semaphore_type(SemaphoreType::TIMELINE);
|
||||||
|
let info = PhysicalDeviceExternalSemaphoreInfo::default()
|
||||||
|
.handle_type(ExternalSemaphoreHandleTypeFlags::OPAQUE_FD)
|
||||||
|
.push_next(&mut type_info);
|
||||||
|
unsafe {
|
||||||
|
self.instance
|
||||||
|
.get_physical_device_external_semaphore_properties(phy_dev, &info, &mut props);
|
||||||
|
}
|
||||||
|
props
|
||||||
|
.external_semaphore_features
|
||||||
|
.contains(ExternalSemaphoreFeatureFlags::EXPORTABLE)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for VulkanCoreInstance {
|
impl Drop for VulkanCoreInstance {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,21 @@
|
||||||
use ash::{Device, khr::external_fence_fd};
|
use {
|
||||||
|
crate::{
|
||||||
|
eventfd_cache::EventfdCache, video::drm::syncobj::SyncobjCtx,
|
||||||
|
vulkan_core::VulkanCoreInstance,
|
||||||
|
},
|
||||||
|
ash::{
|
||||||
|
Device,
|
||||||
|
khr::{external_fence_fd, external_semaphore_fd},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
pub trait VulkanDeviceInf: Sized {
|
pub trait VulkanDeviceInf: Sized {
|
||||||
|
fn instance(&self) -> &VulkanCoreInstance;
|
||||||
fn device(&self) -> &Device;
|
fn device(&self) -> &Device;
|
||||||
fn external_fence_fd(&self) -> &external_fence_fd::Device;
|
fn external_fence_fd(&self) -> &external_fence_fd::Device;
|
||||||
|
fn external_semaphore_fd(&self) -> &external_semaphore_fd::Device;
|
||||||
|
fn supports_timeline_opaque_export(&self) -> bool;
|
||||||
|
fn sync_ctx(&self) -> &Rc<SyncobjCtx>;
|
||||||
|
fn eventfd_cache(&self) -> &Rc<EventfdCache>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,17 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
gfx_api::FdSync,
|
gfx_api::{FdSync, ReservedSyncobjPoint},
|
||||||
utils::errorfmt::ErrorFmt,
|
utils::errorfmt::ErrorFmt,
|
||||||
|
video::drm::syncobj::SyncobjPoint,
|
||||||
vulkan_core::{
|
vulkan_core::{
|
||||||
VulkanCoreError,
|
VulkanCoreError,
|
||||||
device::VulkanDeviceInf,
|
device::VulkanDeviceInf,
|
||||||
fence::{VulkanDeviceFenceExt, VulkanFence},
|
fence::{VulkanDeviceFenceExt, VulkanFence},
|
||||||
|
timeline_semaphore::VulkanTimelineSemaphore,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ash::vk::Fence,
|
ash::vk::{Fence, PipelineStageFlags2, SemaphoreSubmitInfo, SemaphoreWaitInfo, SubmitInfo2},
|
||||||
std::rc::Rc,
|
std::{rc::Rc, slice},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub enum VulkanSync<D>
|
pub enum VulkanSync<D>
|
||||||
|
|
@ -17,6 +19,10 @@ where
|
||||||
D: VulkanDeviceInf,
|
D: VulkanDeviceInf,
|
||||||
{
|
{
|
||||||
Fence(Rc<VulkanFence<D>>),
|
Fence(Rc<VulkanFence<D>>),
|
||||||
|
TimelineSemaphore {
|
||||||
|
tls: Rc<VulkanTimelineSemaphore<D>>,
|
||||||
|
pending: Rc<ReservedSyncobjPoint>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> VulkanSync<D>
|
impl<D> VulkanSync<D>
|
||||||
|
|
@ -24,12 +30,22 @@ where
|
||||||
D: VulkanDeviceInf,
|
D: VulkanDeviceInf,
|
||||||
{
|
{
|
||||||
pub fn handle_validation(&self) {
|
pub fn handle_validation(&self) {
|
||||||
// nothing
|
if let VulkanSync::TimelineSemaphore { tls, pending } = self
|
||||||
|
&& tls.device.instance().validation
|
||||||
|
{
|
||||||
|
let info = SemaphoreWaitInfo::default()
|
||||||
|
.semaphores(slice::from_ref(&tls.semaphore))
|
||||||
|
.values(slice::from_ref(&pending.point.0));
|
||||||
|
unsafe {
|
||||||
|
let _ = tls.device.device().wait_semaphores(&info, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fence(&self) -> Fence {
|
pub fn fence(&self) -> Fence {
|
||||||
match self {
|
match self {
|
||||||
VulkanSync::Fence(f) => f.fence,
|
VulkanSync::Fence(f) => f.fence,
|
||||||
|
VulkanSync::TimelineSemaphore { .. } => Fence::null(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -47,19 +63,74 @@ where
|
||||||
};
|
};
|
||||||
release_sync_file.map(FdSync::SyncFile)
|
release_sync_file.map(FdSync::SyncFile)
|
||||||
}
|
}
|
||||||
|
VulkanSync::TimelineSemaphore { pending, .. } => Some(FdSync::Syncobj(pending.clone())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait VulkanDeviceSyncExt: VulkanDeviceInf {
|
pub trait VulkanDeviceSyncExt: VulkanDeviceInf {
|
||||||
fn create_sync(self: &Rc<Self>) -> Result<VulkanSync<Self>, VulkanCoreError>;
|
fn create_sync<'a>(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
tls: Option<&Rc<VulkanTimelineSemaphore<Self>>>,
|
||||||
|
semaphore_submit_info: &'a mut SemaphoreSubmitInfo,
|
||||||
|
submit_info: &mut SubmitInfo2<'a>,
|
||||||
|
) -> Result<VulkanSync<Self>, VulkanCoreError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> VulkanDeviceSyncExt for D
|
impl<D> VulkanDeviceSyncExt for D
|
||||||
where
|
where
|
||||||
D: VulkanDeviceInf,
|
D: VulkanDeviceInf,
|
||||||
{
|
{
|
||||||
fn create_sync(self: &Rc<Self>) -> Result<VulkanSync<Self>, VulkanCoreError> {
|
fn create_sync<'a>(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
tls: Option<&Rc<VulkanTimelineSemaphore<Self>>>,
|
||||||
|
semaphore_submit_info: &'a mut SemaphoreSubmitInfo,
|
||||||
|
submit_info: &mut SubmitInfo2<'a>,
|
||||||
|
) -> Result<VulkanSync<Self>, VulkanCoreError> {
|
||||||
|
if let Some(tls) = tls {
|
||||||
|
match create_tls_sync(self, tls, semaphore_submit_info, submit_info) {
|
||||||
|
Ok(s) => return Ok(s),
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("Could not create sync obj sync: {}", ErrorFmt(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
self.create_fence().map(VulkanSync::Fence)
|
self.create_fence().map(VulkanSync::Fence)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_tls_sync<'a, D>(
|
||||||
|
device: &Rc<D>,
|
||||||
|
tls: &Rc<VulkanTimelineSemaphore<D>>,
|
||||||
|
semaphore_submit_info: &'a mut SemaphoreSubmitInfo,
|
||||||
|
submit_info: &mut SubmitInfo2<'a>,
|
||||||
|
) -> Result<VulkanSync<D>, VulkanCoreError>
|
||||||
|
where
|
||||||
|
D: VulkanDeviceInf,
|
||||||
|
{
|
||||||
|
let point = SyncobjPoint(tls.next_point.fetch_add(1));
|
||||||
|
let eventfd = device
|
||||||
|
.eventfd_cache()
|
||||||
|
.acquire()
|
||||||
|
.map_err(VulkanCoreError::AcquireEventfd)?;
|
||||||
|
device
|
||||||
|
.sync_ctx()
|
||||||
|
.wait_for_point(&eventfd.fd, &tls.syncobj, point, true)
|
||||||
|
.map_err(VulkanCoreError::CreateSyncobjWait)?;
|
||||||
|
let pending = Rc::new(ReservedSyncobjPoint {
|
||||||
|
ctx: device.sync_ctx().clone(),
|
||||||
|
syncobj: tls.syncobj.clone(),
|
||||||
|
point,
|
||||||
|
sync_file: Default::default(),
|
||||||
|
signaled: eventfd,
|
||||||
|
});
|
||||||
|
*semaphore_submit_info = SemaphoreSubmitInfo::default()
|
||||||
|
.semaphore(tls.semaphore)
|
||||||
|
.value(point.0)
|
||||||
|
.stage_mask(PipelineStageFlags2::ALL_COMMANDS);
|
||||||
|
*submit_info = submit_info.signal_semaphore_infos(slice::from_ref(semaphore_submit_info));
|
||||||
|
Ok(VulkanSync::TimelineSemaphore {
|
||||||
|
tls: tls.clone(),
|
||||||
|
pending,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
116
src/vulkan_core/timeline_semaphore.rs
Normal file
116
src/vulkan_core/timeline_semaphore.rs
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
utils::{errorfmt::ErrorFmt, numcell::NumCell},
|
||||||
|
video::drm::syncobj::Syncobj,
|
||||||
|
vulkan_core::{VulkanCoreError, device::VulkanDeviceInf},
|
||||||
|
},
|
||||||
|
ash::vk::{
|
||||||
|
ExportSemaphoreCreateInfo, ExternalSemaphoreHandleTypeFlags, Semaphore,
|
||||||
|
SemaphoreCreateInfo, SemaphoreGetFdInfoKHR, SemaphoreSignalInfo, SemaphoreType,
|
||||||
|
SemaphoreTypeCreateInfo,
|
||||||
|
},
|
||||||
|
run_on_drop::on_drop,
|
||||||
|
std::rc::Rc,
|
||||||
|
uapi::OwnedFd,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct VulkanTimelineSemaphore<D>
|
||||||
|
where
|
||||||
|
D: VulkanDeviceInf,
|
||||||
|
{
|
||||||
|
pub(super) device: Rc<D>,
|
||||||
|
pub(super) semaphore: Semaphore,
|
||||||
|
pub(super) syncobj: Rc<Syncobj>,
|
||||||
|
pub(super) next_point: NumCell<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> Drop for VulkanTimelineSemaphore<D>
|
||||||
|
where
|
||||||
|
D: VulkanDeviceInf,
|
||||||
|
{
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
self.device.device().destroy_semaphore(self.semaphore, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait VulkanDeviceTimelineSemaphoreExt: VulkanDeviceInf {
|
||||||
|
fn create_timeline_semaphore(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
) -> Result<Rc<VulkanTimelineSemaphore<Self>>, VulkanCoreError>;
|
||||||
|
|
||||||
|
fn create_timeline_semaphore_or_log(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
) -> Option<Rc<VulkanTimelineSemaphore<Self>>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D> VulkanDeviceTimelineSemaphoreExt for D
|
||||||
|
where
|
||||||
|
D: VulkanDeviceInf,
|
||||||
|
{
|
||||||
|
fn create_timeline_semaphore(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
) -> Result<Rc<VulkanTimelineSemaphore<Self>>, VulkanCoreError> {
|
||||||
|
if !self.supports_timeline_opaque_export() {
|
||||||
|
return Err(VulkanCoreError::TimelineExportNotSupported);
|
||||||
|
}
|
||||||
|
let sem = {
|
||||||
|
let mut export_info = ExportSemaphoreCreateInfo::default()
|
||||||
|
.handle_types(ExternalSemaphoreHandleTypeFlags::OPAQUE_FD);
|
||||||
|
let mut type_info =
|
||||||
|
SemaphoreTypeCreateInfo::default().semaphore_type(SemaphoreType::TIMELINE);
|
||||||
|
let info = SemaphoreCreateInfo::default()
|
||||||
|
.push_next(&mut export_info)
|
||||||
|
.push_next(&mut type_info);
|
||||||
|
let sem = unsafe { self.device().create_semaphore(&info, None) };
|
||||||
|
sem.map_err(VulkanCoreError::CreateSemaphore)?
|
||||||
|
};
|
||||||
|
let destroy_sem = on_drop(|| unsafe { self.device().destroy_semaphore(sem, None) });
|
||||||
|
let syncobj = {
|
||||||
|
let info = SemaphoreGetFdInfoKHR::default()
|
||||||
|
.semaphore(sem)
|
||||||
|
.handle_type(ExternalSemaphoreHandleTypeFlags::OPAQUE_FD);
|
||||||
|
let res = unsafe { self.external_semaphore_fd().get_semaphore_fd(&info) };
|
||||||
|
let fd = res.map_err(VulkanCoreError::ExportTimelineSemaphore)?;
|
||||||
|
Syncobj::new(&Rc::new(OwnedFd::new(fd)))
|
||||||
|
};
|
||||||
|
let signal = |p| {
|
||||||
|
let info = SemaphoreSignalInfo::default().semaphore(sem).value(p);
|
||||||
|
unsafe {
|
||||||
|
self.device()
|
||||||
|
.signal_semaphore(&info)
|
||||||
|
.map_err(VulkanCoreError::SignalSemaphore)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let next_point = NumCell::new(1);
|
||||||
|
for _ in 0..2 {
|
||||||
|
let n = next_point.fetch_add(1);
|
||||||
|
signal(n)?;
|
||||||
|
let signaled = self
|
||||||
|
.sync_ctx()
|
||||||
|
.query_last_signaled(&syncobj)
|
||||||
|
.map_err(VulkanCoreError::QueryLastSignaled)?;
|
||||||
|
if signaled != n {
|
||||||
|
return Err(VulkanCoreError::UnsupportedPointMapping);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
destroy_sem.forget();
|
||||||
|
Ok(Rc::new(VulkanTimelineSemaphore {
|
||||||
|
device: self.clone(),
|
||||||
|
semaphore: sem,
|
||||||
|
syncobj: Rc::new(syncobj),
|
||||||
|
next_point,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_timeline_semaphore_or_log(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
) -> Option<Rc<VulkanTimelineSemaphore<Self>>> {
|
||||||
|
self.create_timeline_semaphore()
|
||||||
|
.inspect_err(|e| {
|
||||||
|
log::warn!("Could not create timeline semaphore: {}", ErrorFmt(e));
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue