rusticl: implement cl_khr_external_semaphore
Acked-by: Alyssa Rosenzweig <alyssa@rosenzweig.io> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36007>
This commit is contained in:
+2
-2
@@ -839,9 +839,9 @@ Rusticl extensions:
|
||||
cl_khr_external_memory_dma_buf not started
|
||||
cl_khr_external_memory_opaque_fd not started
|
||||
cl_khr_external_memory_win32 not started
|
||||
cl_khr_external_semaphore not started
|
||||
cl_khr_external_semaphore DONE (radeonsi, zink)
|
||||
cl_khr_external_semaphore_opaque_fd not started
|
||||
cl_khr_external_semaphore_sync_fd not started
|
||||
cl_khr_external_semaphore_sync_fd DONE (radeonsi, zink)
|
||||
cl_khr_external_semaphore_win32 not started
|
||||
cl_khr_fp16 DONE (asahi, freedreno, llvmpipe, panfrost, radeonsi, zink)
|
||||
cl_khr_gl_depth_images not started
|
||||
|
||||
@@ -12,3 +12,5 @@ VK_KHR_shader_untyped_pointers on anv and RADV
|
||||
VK_KHR_maintenance8 on NVK
|
||||
VK_KHR_maintenance9 on NVK
|
||||
cl_khr_semaphore on radeonsi and zink
|
||||
cl_khr_external_semaphore on radeonsi and zink
|
||||
cl_khr_external_semaphore_sync_fd on radeonsi and zink
|
||||
|
||||
@@ -273,6 +273,20 @@ unsafe impl CLInfo<cl_device_info> for cl_device_id {
|
||||
(CL_QUEUE_PROFILING_ENABLE | CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE).into(),
|
||||
),
|
||||
CL_DEVICE_REFERENCE_COUNT => v.write::<cl_uint>(1),
|
||||
CL_DEVICE_SEMAPHORE_EXPORT_HANDLE_TYPES_KHR
|
||||
if dev.are_external_semaphores_supported() =>
|
||||
{
|
||||
v.write::<&[cl_external_semaphore_handle_type_khr]>(&[
|
||||
CL_SEMAPHORE_HANDLE_SYNC_FD_KHR,
|
||||
])
|
||||
}
|
||||
CL_DEVICE_SEMAPHORE_IMPORT_HANDLE_TYPES_KHR
|
||||
if dev.are_external_semaphores_supported() =>
|
||||
{
|
||||
v.write::<&[cl_external_semaphore_handle_type_khr]>(&[
|
||||
CL_SEMAPHORE_HANDLE_SYNC_FD_KHR,
|
||||
])
|
||||
}
|
||||
CL_DEVICE_SEMAPHORE_TYPES_KHR if dev.are_semaphores_supported() => {
|
||||
v.write::<&[cl_semaphore_type_khr]>(&[CL_SEMAPHORE_TYPE_BINARY_KHR])
|
||||
}
|
||||
|
||||
@@ -27,6 +27,24 @@ unsafe impl CLInfo<cl_platform_info> for cl_platform_id {
|
||||
CL_PLATFORM_NAME => v.write::<&CStr>(c"rusticl"),
|
||||
CL_PLATFORM_NUMERIC_VERSION => v.write::<cl_version>(CLVersion::Cl3_0.into()),
|
||||
CL_PLATFORM_PROFILE => v.write::<&CStr>(c"FULL_PROFILE"),
|
||||
CL_PLATFORM_SEMAPHORE_EXPORT_HANDLE_TYPES_KHR => {
|
||||
v.write::<&[cl_external_semaphore_handle_type_khr]>(
|
||||
if Platform::get().all_devs_have_external_semaphores() {
|
||||
&[CL_SEMAPHORE_HANDLE_SYNC_FD_KHR]
|
||||
} else {
|
||||
&[]
|
||||
},
|
||||
)
|
||||
}
|
||||
CL_PLATFORM_SEMAPHORE_IMPORT_HANDLE_TYPES_KHR => {
|
||||
v.write::<&[cl_external_semaphore_handle_type_khr]>(
|
||||
if Platform::get().all_devs_have_external_semaphores() {
|
||||
&[CL_SEMAPHORE_HANDLE_SYNC_FD_KHR]
|
||||
} else {
|
||||
&[]
|
||||
},
|
||||
)
|
||||
}
|
||||
CL_PLATFORM_SEMAPHORE_TYPES_KHR => {
|
||||
v.write::<&[cl_semaphore_type_khr]>(if Platform::get().all_devs_have_semaphores() {
|
||||
&[CL_SEMAPHORE_TYPE_BINARY_KHR]
|
||||
|
||||
@@ -8,13 +8,23 @@ use {
|
||||
icd::{ArcedCLObject, BaseCLObject, CLResult, ReferenceCountedAPIPointer},
|
||||
util::{event_list_from_cl, CLInfo, CLInfoRes, CLInfoValue},
|
||||
},
|
||||
core::{context::Context, device::Device, queue::Queue, semaphore::Semaphore},
|
||||
core::{
|
||||
context::Context,
|
||||
device::Device,
|
||||
queue::Queue,
|
||||
semaphore::{Semaphore, SemaphoreHandle},
|
||||
},
|
||||
},
|
||||
mesa_rust_util::{
|
||||
conversion::TryIntoWithErr,
|
||||
properties::{MultiValProperties, Properties},
|
||||
ptr::CheckedPtr,
|
||||
},
|
||||
mesa_rust_util::{conversion::TryIntoWithErr, properties::MultiValProperties},
|
||||
rusticl_opencl_gen::*,
|
||||
rusticl_proc_macros::{cl_entrypoint, cl_info_entrypoint},
|
||||
std::{
|
||||
ffi::{c_int, c_void},
|
||||
mem,
|
||||
sync::Arc,
|
||||
},
|
||||
};
|
||||
@@ -36,7 +46,11 @@ unsafe impl CLInfo<cl_semaphore_info_khr> for cl_semaphore_khr {
|
||||
// is fine here.
|
||||
v.write::<Option<cl_external_semaphore_handle_type_khr>>(None)
|
||||
}
|
||||
CL_SEMAPHORE_EXPORTABLE_KHR => v.write::<cl_bool>(CL_FALSE),
|
||||
// Exporting a semaphore handle from a semaphore that was created by importing an
|
||||
// external semaphore handle is not permitted.
|
||||
CL_SEMAPHORE_EXPORTABLE_KHR => {
|
||||
v.write::<cl_bool>((!sema.imported && sema.handle_type.is_some()).into())
|
||||
}
|
||||
CL_SEMAPHORE_PAYLOAD_KHR => {
|
||||
v.write::<cl_semaphore_payload_khr>(sema.is_signalled().into())
|
||||
}
|
||||
@@ -62,8 +76,10 @@ fn create_semaphore(
|
||||
return Err(CL_INVALID_VALUE);
|
||||
}
|
||||
|
||||
let mut handle = None;
|
||||
let mut sema_type = 0;
|
||||
let mut dev = None;
|
||||
let mut handle_type = None;
|
||||
let sema_props = unsafe {
|
||||
MultiValProperties::new(
|
||||
sema_props,
|
||||
@@ -99,12 +115,29 @@ fn create_semaphore(
|
||||
dev = Some(dev_in);
|
||||
}
|
||||
CL_SEMAPHORE_EXPORT_HANDLE_TYPES_KHR => {
|
||||
// CL_INVALID_VALUE if more than one semaphore handle type is specified in the
|
||||
// CL_SEMAPHORE_EXPORT_HANDLE_TYPES_KHR list.
|
||||
if vals.len() > 1 {
|
||||
return Err(CL_INVALID_VALUE);
|
||||
if let Some((&handle_type_in, remaining)) = vals.split_first() {
|
||||
// CL_INVALID_VALUE if more than one semaphore handle type is specified in the
|
||||
// CL_SEMAPHORE_EXPORT_HANDLE_TYPES_KHR list.
|
||||
if !remaining.is_empty() {
|
||||
return Err(CL_INVALID_VALUE);
|
||||
}
|
||||
|
||||
let handle_type_in = handle_type_in.try_into_with_err(CL_INVALID_PROPERTY)?;
|
||||
if handle_type_in != CL_SEMAPHORE_HANDLE_SYNC_FD_KHR {
|
||||
return Err(CL_INVALID_PROPERTY);
|
||||
}
|
||||
handle_type = Some(handle_type_in);
|
||||
}
|
||||
}
|
||||
CL_SEMAPHORE_HANDLE_SYNC_FD_KHR => {
|
||||
handle = Some(SemaphoreHandle::SyncFD(
|
||||
// we cast to a signed int to be able to handle negative FDs such as -1.
|
||||
//
|
||||
// CL_INVALID_PROPERTY [..] if the value specified for a supported property name
|
||||
// is not valid
|
||||
(vals[0] as i64).try_into_with_err(CL_INVALID_PROPERTY)?,
|
||||
));
|
||||
}
|
||||
CL_SEMAPHORE_TYPE_KHR => {
|
||||
// CL_INVALID_PROPERTY [..] if the value specified for a supported property name is
|
||||
// not valid
|
||||
@@ -141,11 +174,16 @@ fn create_semaphore(
|
||||
return Err(CL_INVALID_VALUE);
|
||||
}
|
||||
|
||||
Ok(Semaphore::new(context, sema_props, dev)?.into_cl())
|
||||
// CL_INVALID_OPERATION If props_list specifies a cl_external_semaphore_handle_type_khr followed
|
||||
// by a handle as well as CL_SEMAPHORE_EXPORT_HANDLE_TYPES_KHR. Exporting a semaphore handle
|
||||
// from a semaphore that was created by importing an external semaphore handle is not permitted.
|
||||
if handle_type.is_some() && handle.is_some() {
|
||||
return Err(CL_INVALID_OPERATION);
|
||||
}
|
||||
|
||||
Ok(Semaphore::new(context, sema_props, dev, handle_type, handle)?.into_cl())
|
||||
|
||||
// CL_INVALID_DEVICE if one or more devices identified by properties CL_SEMAPHORE_DEVICE_HANDLE_LIST_KHR cannot import the requested external semaphore handle type.
|
||||
// CL_INVALID_OPERATION If props_list specifies a cl_external_semaphore_handle_type_khr followed by a handle as well as CL_SEMAPHORE_EXPORT_HANDLE_TYPES_KHR. Exporting a semaphore handle from a semaphore that was created by importing an external semaphore handle is not permitted.
|
||||
// CL_INVALID_PROPERTY if sema_props includes more than one external semaphore handle.
|
||||
}
|
||||
|
||||
#[cl_entrypoint(clEnqueueSignalSemaphoresKHR)]
|
||||
@@ -186,14 +224,8 @@ fn enqueue_signal_semaphores(
|
||||
}
|
||||
}
|
||||
|
||||
create_and_queue(
|
||||
q,
|
||||
CL_COMMAND_SEMAPHORE_SIGNAL_KHR,
|
||||
evs,
|
||||
event,
|
||||
false,
|
||||
Semaphore::gpu_signal(semas),
|
||||
)
|
||||
let work = Semaphore::gpu_signal(semas, &q);
|
||||
create_and_queue(q, CL_COMMAND_SEMAPHORE_SIGNAL_KHR, evs, event, false, work)
|
||||
|
||||
// CL_INVALID_VALUE if any of the semaphore objects specified by sema_objects requires a semaphore payload and sema_payload_list is NULL.
|
||||
}
|
||||
@@ -255,14 +287,43 @@ fn enqueue_wait_semaphores(
|
||||
|
||||
#[cl_entrypoint(clGetSemaphoreHandleForTypeKHR)]
|
||||
fn get_semaphore_handle_for_type(
|
||||
_sema_object: cl_semaphore_khr,
|
||||
_device: cl_device_id,
|
||||
_handle_type: cl_external_semaphore_handle_type_khr,
|
||||
_handle_size: usize,
|
||||
_handle_ptr: *mut c_void,
|
||||
_handle_size_ret: *mut usize,
|
||||
sema_object: cl_semaphore_khr,
|
||||
device: cl_device_id,
|
||||
handle_type: cl_external_semaphore_handle_type_khr,
|
||||
handle_size: usize,
|
||||
handle_ptr: *mut c_void,
|
||||
handle_size_ret: *mut usize,
|
||||
) -> CLResult<()> {
|
||||
Err(CL_INVALID_OPERATION)
|
||||
let sema = Semaphore::ref_from_raw(sema_object)?;
|
||||
let dev = Device::ref_from_raw(device)?;
|
||||
|
||||
// CL_INVALID_DEVICE [..] if sema_object belongs to a context that is not associated with
|
||||
// device.
|
||||
if !sema.ctx.devs.contains(&dev) {
|
||||
return Err(CL_INVALID_DEVICE);
|
||||
}
|
||||
|
||||
// CL_INVALID_VALUE if the requested external semaphore handle type was not specified when
|
||||
// sema_object was created.
|
||||
if sema.handle_type != Some(handle_type) {
|
||||
return Err(CL_INVALID_VALUE);
|
||||
}
|
||||
|
||||
unsafe { handle_size_ret.write_checked(mem::size_of::<c_int>()) };
|
||||
if !handle_ptr.is_null() {
|
||||
// CL_INVALID_VALUE if the size in bytes specified by handle_size is less than size of the
|
||||
// requested handle and handle_ptr is not NULL.
|
||||
if handle_size < mem::size_of::<c_int>() {
|
||||
return Err(CL_INVALID_VALUE);
|
||||
}
|
||||
|
||||
let fd = sema.fd()?;
|
||||
unsafe {
|
||||
handle_ptr.cast::<c_int>().write(fd);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cl_entrypoint(clReleaseSemaphoreKHR)]
|
||||
@@ -277,9 +338,28 @@ fn retain_semaphore(sema_object: cl_semaphore_khr) -> CLResult<()> {
|
||||
|
||||
#[cl_entrypoint(clReImportSemaphoreSyncFdKHR)]
|
||||
fn re_import_semaphore_sync_fd(
|
||||
_sema_object: cl_semaphore_khr,
|
||||
_reimport_props: *mut cl_semaphore_reimport_properties_khr,
|
||||
_fd: c_int,
|
||||
sema_object: cl_semaphore_khr,
|
||||
reimport_props: *mut cl_semaphore_reimport_properties_khr,
|
||||
fd: c_int,
|
||||
) -> CLResult<()> {
|
||||
Err(CL_INVALID_OPERATION)
|
||||
let sema = Semaphore::ref_from_raw(sema_object)?;
|
||||
|
||||
// CL_INVALID_SEMAPHORE_KHR if a CL_SEMAPHORE_HANDLE_SYNC_FD_KHR handle was not imported when
|
||||
// sema_object was created.
|
||||
if !sema.imported {
|
||||
return Err(CL_INVALID_SEMAPHORE_KHR);
|
||||
}
|
||||
|
||||
// reimport_props is an optional list of properties that affect the re-import behavior. [..] If
|
||||
// no properties are required, reimport_props may be NULL. This extension does not define any
|
||||
// optional properties.
|
||||
// SAFETY: The list is terminated with the special property 0.
|
||||
let props = unsafe { Properties::new(reimport_props) }.ok_or(CL_INVALID_PROPERTY)?;
|
||||
if !props.is_empty() {
|
||||
// We don't support any optional properties, so just throw an error for now.
|
||||
return Err(CL_INVALID_PROPERTY);
|
||||
}
|
||||
|
||||
// CL_INVALID_VALUE if fd is invalid.
|
||||
sema.reimport(fd)
|
||||
}
|
||||
|
||||
@@ -771,6 +771,10 @@ impl DeviceBase {
|
||||
}
|
||||
|
||||
if self.are_semaphores_supported() {
|
||||
if self.are_external_semaphores_supported() {
|
||||
add_ext(1, 0, 1, "cl_khr_external_semaphore");
|
||||
add_ext(1, 0, 1, "cl_khr_external_semaphore_sync_fd");
|
||||
}
|
||||
add_ext(1, 0, 1, "cl_khr_semaphore");
|
||||
}
|
||||
|
||||
@@ -1258,6 +1262,10 @@ impl DeviceBase {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn are_external_semaphores_supported(&self) -> bool {
|
||||
self.caps.has_create_fence_fd && self.screen().has_fence_get_fd()
|
||||
}
|
||||
|
||||
pub fn are_semaphores_supported(&self) -> bool {
|
||||
self.screen().caps().fence_signal && self.screen().has_semaphore_create()
|
||||
}
|
||||
|
||||
@@ -281,6 +281,12 @@ impl Platform {
|
||||
pub fn all_devs_have_semaphores(&self) -> bool {
|
||||
self.devs.iter().all(|dev| dev.are_semaphores_supported())
|
||||
}
|
||||
|
||||
pub fn all_devs_have_external_semaphores(&self) -> bool {
|
||||
self.devs
|
||||
.iter()
|
||||
.all(|dev| dev.are_external_semaphores_supported())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Platform {
|
||||
|
||||
@@ -4,42 +4,87 @@
|
||||
use {
|
||||
crate::{
|
||||
api::icd::{CLObjectBase, CLResult, RusticlTypes},
|
||||
core::{context::Context, device::Device, event::EventSig},
|
||||
core::{
|
||||
context::Context,
|
||||
device::{Device, HelperContextWrapper},
|
||||
event::EventSig,
|
||||
queue::Queue,
|
||||
},
|
||||
impl_cl_type_trait,
|
||||
},
|
||||
mesa_rust::pipe::{context::PipeContext, fence::PipeFence},
|
||||
mesa_rust::pipe::{
|
||||
context::PipeContext,
|
||||
fence::{FenceFd, PipeFence},
|
||||
},
|
||||
mesa_rust_gen::pipe_fd_type,
|
||||
mesa_rust_util::properties::MultiValProperties,
|
||||
rusticl_opencl_gen::*,
|
||||
std::sync::{Arc, Condvar, Mutex, MutexGuard},
|
||||
std::{
|
||||
ffi::c_int,
|
||||
sync::{Arc, Condvar, Mutex, MutexGuard, Weak},
|
||||
},
|
||||
};
|
||||
|
||||
pub enum SemaphoreHandle {
|
||||
SyncFD(c_int),
|
||||
}
|
||||
|
||||
struct RealFence {
|
||||
fence: PipeFence,
|
||||
is_signalled: bool,
|
||||
}
|
||||
|
||||
enum Fence {
|
||||
AlwaysSignalled,
|
||||
Fence(RealFence),
|
||||
}
|
||||
|
||||
impl Fence {
|
||||
fn from_fence(fence: PipeFence) -> Self {
|
||||
Self::Fence(RealFence {
|
||||
fence: fence,
|
||||
is_signalled: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct SemaphoreState {
|
||||
fence: RealFence,
|
||||
fence: Fence,
|
||||
last_queue: Option<Weak<Queue>>,
|
||||
}
|
||||
|
||||
enum SemaphoreWaitAction {
|
||||
Signal,
|
||||
Wait,
|
||||
WaitImported,
|
||||
}
|
||||
|
||||
impl SemaphoreState {
|
||||
fn gpu_signal(&mut self, ctx: &PipeContext) {
|
||||
self.fence.fence.gpu_signal(ctx);
|
||||
self.fence.is_signalled = true;
|
||||
match &mut self.fence {
|
||||
Fence::AlwaysSignalled => {}
|
||||
Fence::Fence(fence) => {
|
||||
fence.fence.gpu_signal(ctx);
|
||||
fence.is_signalled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gpu_wait(&mut self, ctx: &PipeContext) {
|
||||
self.fence.fence.gpu_wait(ctx);
|
||||
self.fence.is_signalled = false;
|
||||
match &mut self.fence {
|
||||
Fence::AlwaysSignalled => {}
|
||||
Fence::Fence(fence) => {
|
||||
fence.fence.gpu_wait(ctx);
|
||||
fence.is_signalled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_signalled(&self) -> bool {
|
||||
self.fence.is_signalled
|
||||
match &self.fence {
|
||||
Fence::AlwaysSignalled => true,
|
||||
Fence::Fence(fence) => fence.is_signalled,
|
||||
}
|
||||
}
|
||||
|
||||
fn do_action(
|
||||
@@ -48,12 +93,20 @@ impl SemaphoreState {
|
||||
action: SemaphoreWaitAction,
|
||||
ctx: &PipeContext,
|
||||
) -> CLResult<()> {
|
||||
// We need to wait until is_signalled gets set to the proper state.
|
||||
let is_signalled_expected = !matches!(action, SemaphoreWaitAction::Signal);
|
||||
// If we are always signalled we can just skip this call.
|
||||
if matches!(this.fence, Fence::AlwaysSignalled) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
this = cv
|
||||
.wait_while(this, |state| state.is_signalled() != is_signalled_expected)
|
||||
.or(Err(CL_OUT_OF_HOST_MEMORY))?;
|
||||
// On imported waits we ignore the state of this fence as it might have been waited on
|
||||
// somewhere else and this is out of our control.
|
||||
if !matches!(action, SemaphoreWaitAction::WaitImported) {
|
||||
// We need to wait until is_signalled gets set to the proper state.
|
||||
let is_signalled_expected = !matches!(action, SemaphoreWaitAction::Signal);
|
||||
this = cv
|
||||
.wait_while(this, |state| state.is_signalled() != is_signalled_expected)
|
||||
.or(Err(CL_OUT_OF_HOST_MEMORY))?;
|
||||
}
|
||||
|
||||
match action {
|
||||
// If this semaphore was already signalled, we need to wait until something
|
||||
@@ -61,7 +114,7 @@ impl SemaphoreState {
|
||||
SemaphoreWaitAction::Signal => this.gpu_signal(ctx),
|
||||
|
||||
// We need to wait until something signals this semaphore before we can wait on it.
|
||||
SemaphoreWaitAction::Wait => this.gpu_wait(ctx),
|
||||
SemaphoreWaitAction::Wait | SemaphoreWaitAction::WaitImported => this.gpu_wait(ctx),
|
||||
}
|
||||
|
||||
drop(this);
|
||||
@@ -78,6 +131,8 @@ pub struct Semaphore {
|
||||
pub ctx: Arc<Context>,
|
||||
pub props: MultiValProperties<cl_semaphore_properties_khr>,
|
||||
pub dev: &'static Device,
|
||||
pub handle_type: Option<cl_external_semaphore_handle_type_khr>,
|
||||
pub imported: bool,
|
||||
state: Mutex<SemaphoreState>,
|
||||
/// Condition Variable used for waiting on a gpu_signal or gpu_wait operation to executed on the
|
||||
/// queue thread.
|
||||
@@ -87,31 +142,100 @@ pub struct Semaphore {
|
||||
impl_cl_type_trait!(cl_semaphore_khr, Semaphore, CL_INVALID_SEMAPHORE_KHR);
|
||||
|
||||
impl Semaphore {
|
||||
fn create_semaphore(dev: &Device, handle: Option<SemaphoreHandle>) -> CLResult<Fence> {
|
||||
Ok(match handle {
|
||||
None => Fence::from_fence(
|
||||
dev.screen()
|
||||
.create_semaphore()
|
||||
.ok_or(CL_OUT_OF_HOST_MEMORY)?,
|
||||
),
|
||||
Some(SemaphoreHandle::SyncFD(fd)) => {
|
||||
// The special value -1 for fd is treated like a valid sync file descriptor
|
||||
// referring to an object that has already signaled. The import operation will
|
||||
// succeed and the semaphore will have a temporarily imported payload as if a valid
|
||||
// file descriptor had been provided.
|
||||
if fd == -1 {
|
||||
Fence::AlwaysSignalled
|
||||
} else {
|
||||
// Importing a semaphore payload from a file descriptor transfers ownership of
|
||||
// the file descriptor from the application to the OpenCL implementation. The
|
||||
// application must not perform any operations on the file descriptor after a
|
||||
// successful import.
|
||||
let fence_fd = FenceFd { fd: fd };
|
||||
let fence = dev
|
||||
.helper_ctx()
|
||||
.import_fence(&fence_fd, pipe_fd_type::PIPE_FD_TYPE_NATIVE_SYNC)?;
|
||||
Fence::from_fence(fence)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
ctx: Arc<Context>,
|
||||
props: MultiValProperties<cl_semaphore_properties_khr>,
|
||||
dev: &'static Device,
|
||||
export_handle_type: Option<cl_external_semaphore_handle_type_khr>,
|
||||
handle: Option<SemaphoreHandle>,
|
||||
) -> CLResult<Arc<Self>> {
|
||||
Ok(Arc::new(Self {
|
||||
base: CLObjectBase::new(RusticlTypes::Semaphore),
|
||||
ctx: ctx,
|
||||
props: props,
|
||||
dev: dev,
|
||||
handle_type: export_handle_type,
|
||||
imported: handle.is_some(),
|
||||
state: Mutex::new(SemaphoreState {
|
||||
fence: RealFence {
|
||||
fence: dev
|
||||
.screen()
|
||||
.create_semaphore()
|
||||
.ok_or(CL_OUT_OF_HOST_MEMORY)?,
|
||||
is_signalled: false,
|
||||
},
|
||||
fence: Self::create_semaphore(dev, handle)?,
|
||||
last_queue: None,
|
||||
}),
|
||||
signal_cv: Condvar::new(),
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn fd(&self) -> CLResult<c_int> {
|
||||
let mut state = self.state();
|
||||
if !state.is_signalled() {
|
||||
// Some drivers might block until the semaphore was signalled, so we need to flush
|
||||
// the last queue the semaphore was used on.
|
||||
if let Some(queue) = state.last_queue.take() {
|
||||
if let Some(queue) = queue.upgrade() {
|
||||
queue.flush(false).ok().ok_or(CL_OUT_OF_RESOURCES)?;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we need to wait until the semaphore gets signalled.
|
||||
state = self
|
||||
.signal_cv
|
||||
.wait_while(state, |state| !state.is_signalled())
|
||||
.or(Err(CL_OUT_OF_HOST_MEMORY))?;
|
||||
}
|
||||
|
||||
Ok(match &mut state.fence {
|
||||
Fence::Fence(fence) => {
|
||||
// Do the spinny
|
||||
loop {
|
||||
let fd = fence.fence.export_fd();
|
||||
if fd != -1 {
|
||||
// After exporting a semaphore it's safe to re-signal it.
|
||||
fence.is_signalled = false;
|
||||
break fd;
|
||||
}
|
||||
}
|
||||
}
|
||||
Fence::AlwaysSignalled => -1,
|
||||
})
|
||||
}
|
||||
|
||||
/// Makes the GPU signal the semaphore.
|
||||
pub fn gpu_signal(semas: Vec<Arc<Self>>) -> EventSig {
|
||||
pub fn gpu_signal(semas: Vec<Arc<Self>>, q: &Arc<Queue>) -> EventSig {
|
||||
for sema in &semas {
|
||||
let mut state = sema.state();
|
||||
if !matches!(state.fence, Fence::AlwaysSignalled) {
|
||||
state.last_queue = Some(Arc::downgrade(q));
|
||||
}
|
||||
}
|
||||
|
||||
Box::new(move |_, ctx| {
|
||||
for sema in semas {
|
||||
SemaphoreState::do_action(
|
||||
@@ -130,7 +254,11 @@ impl Semaphore {
|
||||
SemaphoreState::do_action(
|
||||
self.state(),
|
||||
&self.signal_cv,
|
||||
SemaphoreWaitAction::Wait,
|
||||
if self.imported {
|
||||
SemaphoreWaitAction::WaitImported
|
||||
} else {
|
||||
SemaphoreWaitAction::Wait
|
||||
},
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
@@ -139,6 +267,12 @@ impl Semaphore {
|
||||
self.state().is_signalled()
|
||||
}
|
||||
|
||||
pub fn reimport(&self, fd: c_int) -> CLResult<()> {
|
||||
let new_fence = Self::create_semaphore(self.dev, Some(SemaphoreHandle::SyncFD(fd)))?;
|
||||
self.state().fence = new_fence;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn state(&self) -> MutexGuard<SemaphoreState> {
|
||||
self.state.lock().unwrap()
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use libc_rust_gen::close;
|
||||
use mesa_rust_gen::*;
|
||||
use mesa_rust_util::ptr::ThreadSafeCPtr;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::{ffi::c_int, sync::Arc};
|
||||
|
||||
pub struct FenceFd {
|
||||
pub fd: i32,
|
||||
@@ -36,6 +36,10 @@ impl PipeFence {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn export_fd(&self) -> c_int {
|
||||
self.screen.fence_get_fd(self.fence.as_ptr())
|
||||
}
|
||||
|
||||
pub fn gpu_signal(&self, ctx: &PipeContext) {
|
||||
debug_assert!(ctx.has_fence_server());
|
||||
unsafe {
|
||||
|
||||
@@ -12,6 +12,7 @@ use mesa_rust_gen::*;
|
||||
use mesa_rust_util::has_required_feature;
|
||||
use mesa_rust_util::ptr::ThreadSafeCPtr;
|
||||
|
||||
use std::ffi::c_int;
|
||||
use std::ffi::CStr;
|
||||
use std::num::NonZeroU64;
|
||||
use std::os::raw::c_schar;
|
||||
@@ -469,6 +470,10 @@ impl PipeScreen {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn fence_get_fd(&self, fence: *mut pipe_fence_handle) -> c_int {
|
||||
unsafe { self.screen().fence_get_fd.unwrap()(self.screen.as_ptr(), fence) }
|
||||
}
|
||||
|
||||
pub fn query_memory_info(&self) -> Option<pipe_memory_info> {
|
||||
let mut info = pipe_memory_info::default();
|
||||
unsafe {
|
||||
@@ -477,6 +482,10 @@ impl PipeScreen {
|
||||
Some(info)
|
||||
}
|
||||
|
||||
pub fn has_fence_get_fd(&self) -> bool {
|
||||
self.screen().fence_get_fd.is_some()
|
||||
}
|
||||
|
||||
pub fn has_semaphore_create(&self) -> bool {
|
||||
self.screen().semaphore_create.is_some()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user