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