Module: Mesa Branch: main Commit: 57dfc013a6693736ee431224a5983f4fc7224c74 URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=57dfc013a6693736ee431224a5983f4fc7224c74
Author: Antonio Gomes <antoniospg...@gmail.com> Date: Sat Aug 12 01:57:16 2023 -0300 rusticl: Add functions to create CL ctxs from GL, and also to query them Reviewed-by: Karol Herbst <kher...@redhat.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/21305> --- src/gallium/frontends/rusticl/api/context.rs | 95 ++++++++++++++++++++++- src/gallium/frontends/rusticl/api/icd.rs | 5 +- src/gallium/frontends/rusticl/core/context.rs | 4 + src/gallium/frontends/rusticl/core/device.rs | 21 ++++- src/gallium/frontends/rusticl/core/gl.rs | 92 ++++++++++++++++++++++ src/gallium/frontends/rusticl/mesa/pipe/screen.rs | 2 +- 6 files changed, 214 insertions(+), 5 deletions(-) diff --git a/src/gallium/frontends/rusticl/api/context.rs b/src/gallium/frontends/rusticl/api/context.rs index d04a81fa71c..1af67ca8b22 100644 --- a/src/gallium/frontends/rusticl/api/context.rs +++ b/src/gallium/frontends/rusticl/api/context.rs @@ -2,7 +2,8 @@ use crate::api::icd::*; use crate::api::types::*; use crate::api::util::*; use crate::core::context::*; -use crate::core::device::get_devs_for_type; +use crate::core::device::{get_dev_for_uuid, get_devs_for_type, get_devs_with_gl_interop}; +use crate::core::gl::*; use crate::core::platform::*; use mesa_rust_util::properties::Properties; @@ -11,8 +12,10 @@ use rusticl_proc_macros::cl_entrypoint; use rusticl_proc_macros::cl_info_entrypoint; use std::collections::HashSet; +use std::ffi::c_void; use std::iter::FromIterator; use std::mem::MaybeUninit; +use std::ptr; use std::slice; #[cl_info_entrypoint(cl_get_context_info)] @@ -35,6 +38,75 @@ impl CLInfo<cl_context_info> for cl_context { } } +impl CLInfo<cl_gl_context_info> for GLCtxManager { + fn query(&self, q: cl_gl_context_info, _: &[u8]) -> CLResult<Vec<MaybeUninit<u8>>> { + let info = self.interop_dev_info; + + Ok(match q { + CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KHR => { + let ptr = match get_dev_for_uuid(info.device_uuid) { + Some(dev) => dev, + None => ptr::null(), + }; + cl_prop::<cl_device_id>(cl_device_id::from_ptr(ptr)) + } + CL_DEVICES_FOR_GL_CONTEXT_KHR => { + let devs = get_devs_with_gl_interop() + .iter() + .map(|&d| cl_device_id::from_ptr(d)) + .collect(); + cl_prop::<&Vec<cl_device_id>>(&devs) + } + _ => return Err(CL_INVALID_VALUE), + }) + } +} + +#[cl_entrypoint] +pub fn get_gl_context_info_khr( + properties: *const cl_context_properties, + param_name: cl_gl_context_info, + param_value_size: usize, + param_value: *mut ::std::os::raw::c_void, + param_value_size_ret: *mut usize, +) -> CLResult<()> { + let mut egl_display: EGLDisplay = ptr::null_mut(); + let mut glx_display: *mut _XDisplay = ptr::null_mut(); + let mut gl_context: *mut c_void = ptr::null_mut(); + + // CL_INVALID_PROPERTY [...] if the same property name is specified more than once. + let props = Properties::from_ptr(properties).ok_or(CL_INVALID_PROPERTY)?; + for p in &props.props { + match p.0 as u32 { + // CL_INVALID_PLATFORM [...] if platform value specified in properties is not a valid platform. + CL_CONTEXT_PLATFORM => { + (p.1 as cl_platform_id).get_ref()?; + } + CL_EGL_DISPLAY_KHR => { + egl_display = p.1 as *mut _; + } + CL_GL_CONTEXT_KHR => { + gl_context = p.1 as *mut _; + } + CL_GLX_DISPLAY_KHR => { + glx_display = p.1 as *mut _; + } + // CL_INVALID_PROPERTY if context property name in properties is not a supported property name + _ => return Err(CL_INVALID_PROPERTY), + } + } + + let gl_ctx_manager = GLCtxManager::new(gl_context, glx_display, egl_display)?; + gl_ctx_manager + .ok_or(CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR)? + .get_info( + param_name, + param_value_size, + param_value, + param_value_size_ret, + ) +} + #[cl_entrypoint] fn create_context( properties: *const cl_context_properties, @@ -58,6 +130,10 @@ fn create_context( return Err(CL_INVALID_VALUE); } + let mut egl_display: EGLDisplay = ptr::null_mut(); + let mut glx_display: *mut _XDisplay = ptr::null_mut(); + let mut gl_context: *mut c_void = ptr::null_mut(); + // CL_INVALID_PROPERTY [...] if the same property name is specified more than once. let props = Properties::from_ptr(properties).ok_or(CL_INVALID_PROPERTY)?; for p in &props.props { @@ -69,17 +145,32 @@ fn create_context( CL_CONTEXT_INTEROP_USER_SYNC => { check_cl_bool(p.1).ok_or(CL_INVALID_PROPERTY)?; } + CL_EGL_DISPLAY_KHR => { + egl_display = p.1 as *mut _; + } + CL_GL_CONTEXT_KHR => { + gl_context = p.1 as *mut _; + } + CL_GLX_DISPLAY_KHR => { + glx_display = p.1 as *mut _; + } // CL_INVALID_PROPERTY if context property name in properties is not a supported property name _ => return Err(CL_INVALID_PROPERTY), } } + let gl_ctx_manager = GLCtxManager::new(gl_context, glx_display, egl_display)?; + // Duplicate devices specified in devices are ignored. let set: HashSet<_> = HashSet::from_iter(unsafe { slice::from_raw_parts(devices, num_devices as usize) }.iter()); let devs: Result<_, _> = set.into_iter().map(cl_device_id::get_ref).collect(); - Ok(cl_context::from_arc(Context::new(devs?, props))) + Ok(cl_context::from_arc(Context::new( + devs?, + props, + gl_ctx_manager, + ))) } #[cl_entrypoint] diff --git a/src/gallium/frontends/rusticl/api/icd.rs b/src/gallium/frontends/rusticl/api/icd.rs index ea7e3f7c2b8..29fbbf4015b 100644 --- a/src/gallium/frontends/rusticl/api/icd.rs +++ b/src/gallium/frontends/rusticl/api/icd.rs @@ -93,7 +93,7 @@ pub static DISPATCH: cl_icd_dispatch = cl_icd_dispatch { clGetGLTextureInfo: None, clEnqueueAcquireGLObjects: None, clEnqueueReleaseGLObjects: None, - clGetGLContextInfoKHR: None, + clGetGLContextInfoKHR: Some(cl_get_gl_context_info_khr), clGetDeviceIDsFromD3D10KHR: ptr::null_mut(), clCreateFromD3D10BufferKHR: ptr::null_mut(), clCreateFromD3D10Texture2DKHR: ptr::null_mut(), @@ -413,6 +413,9 @@ extern "C" fn cl_get_extension_function_address( // cl_khr_il_program "clCreateProgramWithILKHR" => cl_create_program_with_il as *mut ::std::ffi::c_void, + // cl_khr_gl_sharing + "clGetGLContextInfoKHR" => cl_get_gl_context_info_khr as *mut ::std::ffi::c_void, + // cl_arm_shared_virtual_memory "clEnqueueSVMFreeARM" => cl_enqueue_svm_free_arm as *mut ::std::ffi::c_void, "clEnqueueSVMMapARM" => cl_enqueue_svm_map_arm as *mut ::std::ffi::c_void, diff --git a/src/gallium/frontends/rusticl/core/context.rs b/src/gallium/frontends/rusticl/core/context.rs index 937a41812b1..e475374ef0f 100644 --- a/src/gallium/frontends/rusticl/core/context.rs +++ b/src/gallium/frontends/rusticl/core/context.rs @@ -2,6 +2,7 @@ use crate::api::icd::*; use crate::api::types::DeleteContextCB; use crate::core::device::*; use crate::core::format::*; +use crate::core::gl::*; use crate::core::memory::*; use crate::core::util::*; use crate::impl_cl_type_trait; @@ -26,6 +27,7 @@ pub struct Context { pub properties: Properties<cl_context_properties>, pub dtors: Mutex<Vec<DeleteContextCB>>, pub svm_ptrs: Mutex<BTreeMap<*const c_void, Layout>>, + pub gl_ctx_manager: Option<GLCtxManager>, } impl_cl_type_trait!(cl_context, Context, CL_INVALID_CONTEXT); @@ -34,6 +36,7 @@ impl Context { pub fn new( devs: Vec<&'static Device>, properties: Properties<cl_context_properties>, + gl_ctx_manager: Option<GLCtxManager>, ) -> Arc<Context> { Arc::new(Self { base: CLObjectBase::new(), @@ -41,6 +44,7 @@ impl Context { properties: properties, dtors: Mutex::new(Vec::new()), svm_ptrs: Mutex::new(BTreeMap::new()), + gl_ctx_manager: gl_ctx_manager, }) } diff --git a/src/gallium/frontends/rusticl/core/device.rs b/src/gallium/frontends/rusticl/core/device.rs index 59ce525886c..3b3cb306097 100644 --- a/src/gallium/frontends/rusticl/core/device.rs +++ b/src/gallium/frontends/rusticl/core/device.rs @@ -25,6 +25,7 @@ use std::collections::HashMap; use std::convert::TryInto; use std::env; use std::ffi::CString; +use std::mem::transmute; use std::os::raw::*; use std::sync::Arc; use std::sync::Mutex; @@ -1003,7 +1004,7 @@ impl Device { } } -fn devs() -> &'static Vec<Arc<Device>> { +pub fn devs() -> &'static Vec<Arc<Device>> { &Platform::get().devs } @@ -1014,3 +1015,21 @@ pub fn get_devs_for_type(device_type: cl_device_type) -> Vec<&'static Device> { .map(Arc::as_ref) .collect() } + +pub fn get_dev_for_uuid(uuid: [c_char; UUID_SIZE]) -> Option<&'static Device> { + devs() + .iter() + .find(|d| { + let uuid: [c_uchar; UUID_SIZE] = unsafe { transmute(uuid) }; + uuid == d.screen().device_uuid().unwrap() + }) + .map(Arc::as_ref) +} + +pub fn get_devs_with_gl_interop() -> Vec<&'static Device> { + devs() + .iter() + .filter(|d| d.is_gl_sharing_supported()) + .map(Arc::as_ref) + .collect() +} diff --git a/src/gallium/frontends/rusticl/core/gl.rs b/src/gallium/frontends/rusticl/core/gl.rs index bf986470e16..3a0e4491b71 100644 --- a/src/gallium/frontends/rusticl/core/gl.rs +++ b/src/gallium/frontends/rusticl/core/gl.rs @@ -5,6 +5,7 @@ use rusticl_opencl_gen::*; use std::ffi::CString; use std::mem; +use std::os::raw::c_void; use std::ptr; pub struct XPlatManager { @@ -89,3 +90,94 @@ impl XPlatManager { self.get_func::<PFNMESAGLINTEROPGLXFLUSHOBJECTSPROC>("glXGLInteropFlushObjectsMESA") } } + +#[allow(clippy::upper_case_acronyms)] +#[derive(PartialEq, Eq)] +enum GLCtx { + EGL(EGLDisplay, EGLContext), + GLX(*mut _XDisplay, *mut __GLXcontextRec), +} + +pub struct GLCtxManager { + pub interop_dev_info: mesa_glinterop_device_info, + pub xplat_manager: XPlatManager, + gl_ctx: GLCtx, +} + +impl GLCtxManager { + pub fn new( + gl_context: *mut c_void, + glx_display: *mut _XDisplay, + egl_display: EGLDisplay, + ) -> CLResult<Option<Self>> { + let mut info = mesa_glinterop_device_info { + version: 3, + ..Default::default() + }; + let xplat_manager = XPlatManager::new(); + + // More than one of the attributes CL_CGL_SHAREGROUP_KHR, CL_EGL_DISPLAY_KHR, + // CL_GLX_DISPLAY_KHR, and CL_WGL_HDC_KHR is set to a non-default value. + if !egl_display.is_null() && !glx_display.is_null() { + return Err(CL_INVALID_OPERATION); + } + + if gl_context.is_null() { + return Ok(None); + } + + if !egl_display.is_null() { + let egl_query_device_info_func = xplat_manager + .MesaGLInteropEGLQueryDeviceInfo()? + .ok_or(CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR)?; + + let err = unsafe { + egl_query_device_info_func(egl_display.cast(), gl_context.cast(), &mut info) + }; + + if err != MESA_GLINTEROP_SUCCESS as i32 { + return Err(interop_to_cl_error(err)); + } + + Ok(Some(GLCtxManager { + gl_ctx: GLCtx::EGL(egl_display.cast(), gl_context), + interop_dev_info: info, + xplat_manager: xplat_manager, + })) + } else if !glx_display.is_null() { + let glx_query_device_info_func = xplat_manager + .MesaGLInteropGLXQueryDeviceInfo()? + .ok_or(CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR)?; + + let err = unsafe { + glx_query_device_info_func(glx_display.cast(), gl_context.cast(), &mut info) + }; + + if err != MESA_GLINTEROP_SUCCESS as i32 { + return Err(interop_to_cl_error(err)); + } + + Ok(Some(GLCtxManager { + gl_ctx: GLCtx::GLX(glx_display.cast(), gl_context.cast()), + interop_dev_info: info, + xplat_manager: xplat_manager, + })) + } else { + Err(CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR) + } + } +} + +pub fn interop_to_cl_error(error: i32) -> CLError { + match error.try_into().unwrap() { + MESA_GLINTEROP_OUT_OF_RESOURCES => CL_OUT_OF_RESOURCES, + MESA_GLINTEROP_OUT_OF_HOST_MEMORY => CL_OUT_OF_HOST_MEMORY, + MESA_GLINTEROP_INVALID_OPERATION => CL_INVALID_OPERATION, + MESA_GLINTEROP_INVALID_CONTEXT | MESA_GLINTEROP_INVALID_DISPLAY => { + CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR + } + MESA_GLINTEROP_INVALID_TARGET | MESA_GLINTEROP_INVALID_OBJECT => CL_INVALID_GL_OBJECT, + MESA_GLINTEROP_INVALID_MIP_LEVEL => CL_INVALID_MIP_LEVEL, + _ => CL_OUT_OF_HOST_MEMORY, + } +} diff --git a/src/gallium/frontends/rusticl/mesa/pipe/screen.rs b/src/gallium/frontends/rusticl/mesa/pipe/screen.rs index 1c1b442fe35..bcac249cefc 100644 --- a/src/gallium/frontends/rusticl/mesa/pipe/screen.rs +++ b/src/gallium/frontends/rusticl/mesa/pipe/screen.rs @@ -23,7 +23,7 @@ pub struct PipeScreen { screen: *mut pipe_screen, } -const UUID_SIZE: usize = PIPE_UUID_SIZE as usize; +pub const UUID_SIZE: usize = PIPE_UUID_SIZE as usize; const LUID_SIZE: usize = PIPE_LUID_SIZE as usize; // until we have a better solution