xref: /aosp_15_r20/external/mesa3d/src/gallium/frontends/rusticl/api/context.rs (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 use crate::api::icd::*;
2 use crate::api::types::*;
3 use crate::api::util::*;
4 use crate::core::context::*;
5 use crate::core::device::*;
6 use crate::core::gl::*;
7 use crate::core::platform::*;
8 
9 use mesa_rust::pipe::screen::UUID_SIZE;
10 use mesa_rust_util::properties::Properties;
11 use rusticl_opencl_gen::*;
12 use rusticl_proc_macros::cl_entrypoint;
13 use rusticl_proc_macros::cl_info_entrypoint;
14 
15 use std::ffi::c_char;
16 use std::ffi::c_void;
17 use std::mem::transmute;
18 use std::mem::MaybeUninit;
19 use std::ptr;
20 use std::slice;
21 
22 #[cl_info_entrypoint(clGetContextInfo)]
23 impl CLInfo<cl_context_info> for cl_context {
query(&self, q: cl_context_info, _: &[u8]) -> CLResult<Vec<MaybeUninit<u8>>>24     fn query(&self, q: cl_context_info, _: &[u8]) -> CLResult<Vec<MaybeUninit<u8>>> {
25         let ctx = Context::ref_from_raw(*self)?;
26         Ok(match q {
27             CL_CONTEXT_DEVICES => cl_prop::<Vec<cl_device_id>>(
28                 ctx.devs
29                     .iter()
30                     .map(|&d| cl_device_id::from_ptr(d))
31                     .collect(),
32             ),
33             CL_CONTEXT_NUM_DEVICES => cl_prop::<cl_uint>(ctx.devs.len() as u32),
34             CL_CONTEXT_PROPERTIES => cl_prop::<&Properties<cl_context_properties>>(&ctx.properties),
35             CL_CONTEXT_REFERENCE_COUNT => cl_prop::<cl_uint>(Context::refcnt(*self)?),
36             // CL_INVALID_VALUE if param_name is not one of the supported values
37             _ => return Err(CL_INVALID_VALUE),
38         })
39     }
40 }
41 
42 impl CLInfo<cl_gl_context_info> for GLCtxManager {
query(&self, q: cl_gl_context_info, _: &[u8]) -> CLResult<Vec<MaybeUninit<u8>>>43     fn query(&self, q: cl_gl_context_info, _: &[u8]) -> CLResult<Vec<MaybeUninit<u8>>> {
44         let info = self.interop_dev_info;
45 
46         Ok(match q {
47             CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KHR => {
48                 let ptr = match get_dev_for_uuid(info.device_uuid) {
49                     Some(dev) => dev,
50                     None => ptr::null(),
51                 };
52                 cl_prop::<cl_device_id>(cl_device_id::from_ptr(ptr))
53             }
54             CL_DEVICES_FOR_GL_CONTEXT_KHR => {
55                 // TODO: support multiple devices
56                 let devs = get_dev_for_uuid(info.device_uuid)
57                     .iter()
58                     .map(|&d| cl_device_id::from_ptr(d))
59                     .collect();
60                 cl_prop::<&Vec<cl_device_id>>(&devs)
61             }
62             _ => return Err(CL_INVALID_VALUE),
63         })
64     }
65 }
66 
67 #[cl_entrypoint(clGetGLContextInfoKHR)]
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<()>68 pub fn get_gl_context_info_khr(
69     properties: *const cl_context_properties,
70     param_name: cl_gl_context_info,
71     param_value_size: usize,
72     param_value: *mut ::std::os::raw::c_void,
73     param_value_size_ret: *mut usize,
74 ) -> CLResult<()> {
75     let mut egl_display: EGLDisplay = ptr::null_mut();
76     let mut glx_display: *mut _XDisplay = ptr::null_mut();
77     let mut gl_context: *mut c_void = ptr::null_mut();
78 
79     // CL_INVALID_PROPERTY [...] if the same property name is specified more than once.
80     let props = Properties::from_ptr(properties).ok_or(CL_INVALID_PROPERTY)?;
81     for p in &props.props {
82         match p.0 as u32 {
83             // CL_INVALID_PLATFORM [...] if platform value specified in properties is not a valid platform.
84             CL_CONTEXT_PLATFORM => {
85                 (p.1 as cl_platform_id).get_ref()?;
86             }
87             CL_EGL_DISPLAY_KHR => {
88                 egl_display = p.1 as *mut _;
89             }
90             CL_GL_CONTEXT_KHR => {
91                 gl_context = p.1 as *mut _;
92             }
93             CL_GLX_DISPLAY_KHR => {
94                 glx_display = p.1 as *mut _;
95             }
96             // CL_INVALID_PROPERTY if context property name in properties is not a supported property name
97             _ => return Err(CL_INVALID_PROPERTY),
98         }
99     }
100 
101     let gl_ctx_manager = GLCtxManager::new(gl_context, glx_display, egl_display)?;
102     gl_ctx_manager
103         .ok_or(CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR)?
104         .get_info(
105             param_name,
106             param_value_size,
107             param_value,
108             param_value_size_ret,
109         )
110 }
111 
112 #[cl_entrypoint(clCreateContext)]
create_context( properties: *const cl_context_properties, num_devices: cl_uint, devices: *const cl_device_id, pfn_notify: Option<FuncCreateContextCB>, user_data: *mut ::std::os::raw::c_void, ) -> CLResult<cl_context>113 fn create_context(
114     properties: *const cl_context_properties,
115     num_devices: cl_uint,
116     devices: *const cl_device_id,
117     pfn_notify: Option<FuncCreateContextCB>,
118     user_data: *mut ::std::os::raw::c_void,
119 ) -> CLResult<cl_context> {
120     // TODO: Actually hook this callback up so it gets called when appropriate.
121     // SAFETY: The requirements on `CreateContextCB::try_new` match the requirements
122     // imposed by the OpenCL specification. It is the caller's duty to uphold them.
123     let _cb_opt = unsafe { CreateContextCB::try_new(pfn_notify, user_data)? };
124 
125     // CL_INVALID_VALUE if devices is NULL.
126     if devices.is_null() {
127         return Err(CL_INVALID_VALUE);
128     }
129 
130     // CL_INVALID_VALUE if num_devices is equal to zero.
131     if num_devices == 0 {
132         return Err(CL_INVALID_VALUE);
133     }
134 
135     let mut egl_display: EGLDisplay = ptr::null_mut();
136     let mut glx_display: *mut _XDisplay = ptr::null_mut();
137     let mut gl_context: *mut c_void = ptr::null_mut();
138 
139     // CL_INVALID_PROPERTY [...] if the same property name is specified more than once.
140     let props = Properties::from_ptr(properties).ok_or(CL_INVALID_PROPERTY)?;
141     for p in &props.props {
142         match p.0 as u32 {
143             // CL_INVALID_PLATFORM [...] if platform value specified in properties is not a valid platform.
144             CL_CONTEXT_PLATFORM => {
145                 (p.1 as cl_platform_id).get_ref()?;
146             }
147             CL_CONTEXT_INTEROP_USER_SYNC => {
148                 check_cl_bool(p.1).ok_or(CL_INVALID_PROPERTY)?;
149             }
150             CL_EGL_DISPLAY_KHR => {
151                 egl_display = p.1 as *mut _;
152             }
153             CL_GL_CONTEXT_KHR => {
154                 gl_context = p.1 as *mut _;
155             }
156             CL_GLX_DISPLAY_KHR => {
157                 glx_display = p.1 as *mut _;
158             }
159             // CL_INVALID_PROPERTY if context property name in properties is not a supported property name
160             _ => return Err(CL_INVALID_PROPERTY),
161         }
162     }
163 
164     // Duplicate devices specified in devices are ignored.
165     let mut devs = unsafe { slice::from_raw_parts(devices, num_devices as usize) }.to_owned();
166     devs.sort();
167     devs.dedup();
168     let devs: Result<_, _> = devs.into_iter().map(Device::ref_from_raw).collect();
169     let devs: Vec<&Device> = devs?;
170 
171     let gl_ctx_manager = GLCtxManager::new(gl_context, glx_display, egl_display)?;
172     if let Some(gl_ctx_manager) = &gl_ctx_manager {
173         // errcode_ret returns CL_INVALID_OPERATION if a context was specified as described above
174         // and any of the following conditions hold:
175         // ...
176         // Any of the devices specified in the devices argument cannot support OpenCL objects which
177         // share the data store of an OpenGL object.
178 
179         let [dev] = devs.as_slice() else {
180             return Err(CL_INVALID_OPERATION);
181         };
182 
183         if !dev.is_gl_sharing_supported() {
184             return Err(CL_INVALID_OPERATION);
185         }
186 
187         // gl sharing is only supported on devices with an UUID, so we can simply unwrap it
188         let dev_uuid: [c_char; UUID_SIZE] =
189             unsafe { transmute(dev.screen().device_uuid().unwrap_or_default()) };
190         if gl_ctx_manager.interop_dev_info.device_uuid != dev_uuid {
191             // we only support gl_sharing on the same device
192             return Err(CL_INVALID_OPERATION);
193         }
194     }
195 
196     Ok(Context::new(devs, props, gl_ctx_manager).into_cl())
197 }
198 
199 #[cl_entrypoint(clCreateContextFromType)]
create_context_from_type( properties: *const cl_context_properties, device_type: cl_device_type, pfn_notify: Option<FuncCreateContextCB>, user_data: *mut ::std::os::raw::c_void, ) -> CLResult<cl_context>200 fn create_context_from_type(
201     properties: *const cl_context_properties,
202     device_type: cl_device_type,
203     pfn_notify: Option<FuncCreateContextCB>,
204     user_data: *mut ::std::os::raw::c_void,
205 ) -> CLResult<cl_context> {
206     // CL_INVALID_DEVICE_TYPE if device_type is not a valid value.
207     check_cl_device_type(device_type)?;
208 
209     let devs: Vec<_> = get_devs_for_type(device_type)
210         .into_iter()
211         .map(|d| cl_device_id::from_ptr(d))
212         .collect();
213 
214     // CL_DEVICE_NOT_FOUND if no devices that match device_type and property values specified in properties were found.
215     if devs.is_empty() {
216         return Err(CL_DEVICE_NOT_FOUND);
217     }
218 
219     // errors are essentially the same and we will always pass in a valid
220     // device list, so that's fine as well.
221     create_context(
222         properties,
223         devs.len() as u32,
224         devs.as_ptr(),
225         pfn_notify,
226         user_data,
227     )
228 }
229 
230 #[cl_entrypoint(clRetainContext)]
retain_context(context: cl_context) -> CLResult<()>231 fn retain_context(context: cl_context) -> CLResult<()> {
232     Context::retain(context)
233 }
234 
235 #[cl_entrypoint(clReleaseContext)]
release_context(context: cl_context) -> CLResult<()>236 fn release_context(context: cl_context) -> CLResult<()> {
237     Context::release(context)
238 }
239 
240 #[cl_entrypoint(clSetContextDestructorCallback)]
set_context_destructor_callback( context: cl_context, pfn_notify: ::std::option::Option<FuncDeleteContextCB>, user_data: *mut ::std::os::raw::c_void, ) -> CLResult<()>241 fn set_context_destructor_callback(
242     context: cl_context,
243     pfn_notify: ::std::option::Option<FuncDeleteContextCB>,
244     user_data: *mut ::std::os::raw::c_void,
245 ) -> CLResult<()> {
246     let c = Context::ref_from_raw(context)?;
247 
248     // SAFETY: The requirements on `DeleteContextCB::new` match the requirements
249     // imposed by the OpenCL specification. It is the caller's duty to uphold them.
250     let cb = unsafe { DeleteContextCB::new(pfn_notify, user_data)? };
251 
252     c.dtors.lock().unwrap().push(cb);
253     Ok(())
254 }
255