rusticl: Add functions to create CL ctxs from GL, and also to query them

Reviewed-by: Karol Herbst <kherbst@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/21305>
This commit is contained in:
Antonio Gomes 2023-08-12 01:57:16 -03:00 committed by Marge Bot
parent 425d7acd4a
commit 57dfc013a6
6 changed files with 214 additions and 5 deletions

View file

@ -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]

View file

@ -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,

View file

@ -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,
})
}

View file

@ -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()
}

View file

@ -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,
}
}

View file

@ -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