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

Reply via email to