• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #![allow(non_upper_case_globals)]
2 
3 use crate::api::event::create_and_queue;
4 use crate::api::icd::*;
5 use crate::api::types::*;
6 use crate::api::util::*;
7 use crate::core::context::Context;
8 use crate::core::device::*;
9 use crate::core::event::EventSig;
10 use crate::core::format::*;
11 use crate::core::gl::*;
12 use crate::core::memory::*;
13 use crate::core::queue::*;
14 
15 use mesa_rust_util::properties::Properties;
16 use mesa_rust_util::ptr::*;
17 use mesa_rust_util::static_assert;
18 use rusticl_opencl_gen::*;
19 use rusticl_proc_macros::cl_entrypoint;
20 use rusticl_proc_macros::cl_info_entrypoint;
21 
22 use std::alloc;
23 use std::alloc::Layout;
24 use std::cmp::Ordering;
25 use std::mem::{self, MaybeUninit};
26 use std::os::raw::c_void;
27 use std::ptr;
28 use std::slice;
29 use std::sync::Arc;
30 
validate_mem_flags(flags: cl_mem_flags, images: bool) -> CLResult<()>31 fn validate_mem_flags(flags: cl_mem_flags, images: bool) -> CLResult<()> {
32     let mut valid_flags = cl_bitfield::from(
33         CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY | CL_MEM_KERNEL_READ_AND_WRITE,
34     );
35 
36     if !images {
37         valid_flags |= cl_bitfield::from(
38             CL_MEM_USE_HOST_PTR
39                 | CL_MEM_ALLOC_HOST_PTR
40                 | CL_MEM_COPY_HOST_PTR
41                 | CL_MEM_HOST_WRITE_ONLY
42                 | CL_MEM_HOST_READ_ONLY
43                 | CL_MEM_HOST_NO_ACCESS,
44         );
45     }
46 
47     let read_write_group =
48         cl_bitfield::from(CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY);
49 
50     let alloc_host_group = cl_bitfield::from(CL_MEM_ALLOC_HOST_PTR | CL_MEM_USE_HOST_PTR);
51 
52     let copy_host_group = cl_bitfield::from(CL_MEM_COPY_HOST_PTR | CL_MEM_USE_HOST_PTR);
53 
54     let host_read_write_group =
55         cl_bitfield::from(CL_MEM_HOST_WRITE_ONLY | CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_NO_ACCESS);
56 
57     if (flags & !valid_flags != 0)
58         || (flags & read_write_group).count_ones() > 1
59         || (flags & alloc_host_group).count_ones() > 1
60         || (flags & copy_host_group).count_ones() > 1
61         || (flags & host_read_write_group).count_ones() > 1
62     {
63         return Err(CL_INVALID_VALUE);
64     }
65     Ok(())
66 }
67 
validate_map_flags_common(map_flags: cl_mem_flags) -> CLResult<()>68 fn validate_map_flags_common(map_flags: cl_mem_flags) -> CLResult<()> {
69     // CL_INVALID_VALUE ... if values specified in map_flags are not valid.
70     let valid_flags =
71         cl_bitfield::from(CL_MAP_READ | CL_MAP_WRITE | CL_MAP_WRITE_INVALIDATE_REGION);
72     let read_write_group = cl_bitfield::from(CL_MAP_READ | CL_MAP_WRITE);
73     let invalidate_group = cl_bitfield::from(CL_MAP_WRITE_INVALIDATE_REGION);
74 
75     if (map_flags & !valid_flags != 0)
76         || ((map_flags & read_write_group != 0) && (map_flags & invalidate_group != 0))
77     {
78         return Err(CL_INVALID_VALUE);
79     }
80 
81     Ok(())
82 }
83 
validate_map_flags(m: &MemBase, map_flags: cl_mem_flags) -> CLResult<()>84 fn validate_map_flags(m: &MemBase, map_flags: cl_mem_flags) -> CLResult<()> {
85     validate_map_flags_common(map_flags)?;
86 
87     // CL_INVALID_OPERATION if buffer has been created with CL_MEM_HOST_WRITE_ONLY or
88     // CL_MEM_HOST_NO_ACCESS and CL_MAP_READ is set in map_flags
89     if bit_check(m.flags, CL_MEM_HOST_WRITE_ONLY | CL_MEM_HOST_NO_ACCESS) &&
90       bit_check(map_flags, CL_MAP_READ) ||
91       // or if buffer has been created with CL_MEM_HOST_READ_ONLY or CL_MEM_HOST_NO_ACCESS and
92       // CL_MAP_WRITE or CL_MAP_WRITE_INVALIDATE_REGION is set in map_flags.
93       bit_check(m.flags, CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_NO_ACCESS) &&
94       bit_check(map_flags, CL_MAP_WRITE | CL_MAP_WRITE_INVALIDATE_REGION)
95     {
96         return Err(CL_INVALID_OPERATION);
97     }
98 
99     Ok(())
100 }
101 
filter_image_access_flags(flags: cl_mem_flags) -> cl_mem_flags102 fn filter_image_access_flags(flags: cl_mem_flags) -> cl_mem_flags {
103     flags
104         & (CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY | CL_MEM_READ_ONLY | CL_MEM_KERNEL_READ_AND_WRITE)
105             as cl_mem_flags
106 }
107 
inherit_mem_flags(mut flags: cl_mem_flags, mem: &MemBase) -> cl_mem_flags108 fn inherit_mem_flags(mut flags: cl_mem_flags, mem: &MemBase) -> cl_mem_flags {
109     let read_write_mask = cl_bitfield::from(
110         CL_MEM_READ_WRITE |
111       CL_MEM_WRITE_ONLY |
112       CL_MEM_READ_ONLY |
113       // not in spec, but...
114       CL_MEM_KERNEL_READ_AND_WRITE,
115     );
116     let host_ptr_mask =
117         cl_bitfield::from(CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR | CL_MEM_COPY_HOST_PTR);
118     let host_mask =
119         cl_bitfield::from(CL_MEM_HOST_WRITE_ONLY | CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_NO_ACCESS);
120 
121     // For CL_MEM_OBJECT_IMAGE1D_BUFFER image type, or an image created from another memory object
122     // (image or buffer)...
123     //
124     // ... if the CL_MEM_READ_WRITE, CL_MEM_READ_ONLY or CL_MEM_WRITE_ONLY values are not
125     // specified in flags, they are inherited from the corresponding memory access qualifiers
126     // associated with mem_object. ...
127     if flags & read_write_mask == 0 {
128         flags |= mem.flags & read_write_mask;
129     }
130 
131     // ... The CL_MEM_USE_HOST_PTR, CL_MEM_ALLOC_HOST_PTR and CL_MEM_COPY_HOST_PTR values cannot
132     // be specified in flags but are inherited from the corresponding memory access qualifiers
133     // associated with mem_object. ...
134     flags &= !host_ptr_mask;
135     flags |= mem.flags & host_ptr_mask;
136 
137     // ... If the CL_MEM_HOST_WRITE_ONLY, CL_MEM_HOST_READ_ONLY or CL_MEM_HOST_NO_ACCESS values
138     // are not specified in flags, they are inherited from the corresponding memory access
139     // qualifiers associated with mem_object.
140     if flags & host_mask == 0 {
141         flags |= mem.flags & host_mask;
142     }
143 
144     flags
145 }
146 
image_type_valid(image_type: cl_mem_object_type) -> bool147 fn image_type_valid(image_type: cl_mem_object_type) -> bool {
148     CL_IMAGE_TYPES.contains(&image_type)
149 }
150 
validate_addressing_mode(addressing_mode: cl_addressing_mode) -> CLResult<()>151 fn validate_addressing_mode(addressing_mode: cl_addressing_mode) -> CLResult<()> {
152     match addressing_mode {
153         CL_ADDRESS_NONE
154         | CL_ADDRESS_CLAMP_TO_EDGE
155         | CL_ADDRESS_CLAMP
156         | CL_ADDRESS_REPEAT
157         | CL_ADDRESS_MIRRORED_REPEAT => Ok(()),
158         _ => Err(CL_INVALID_VALUE),
159     }
160 }
161 
validate_filter_mode(filter_mode: cl_filter_mode) -> CLResult<()>162 fn validate_filter_mode(filter_mode: cl_filter_mode) -> CLResult<()> {
163     match filter_mode {
164         CL_FILTER_NEAREST | CL_FILTER_LINEAR => Ok(()),
165         _ => Err(CL_INVALID_VALUE),
166     }
167 }
168 
validate_host_ptr(host_ptr: *mut ::std::os::raw::c_void, flags: cl_mem_flags) -> CLResult<()>169 fn validate_host_ptr(host_ptr: *mut ::std::os::raw::c_void, flags: cl_mem_flags) -> CLResult<()> {
170     // CL_INVALID_HOST_PTR if host_ptr is NULL and CL_MEM_USE_HOST_PTR or CL_MEM_COPY_HOST_PTR are
171     // set in flags
172     if host_ptr.is_null()
173         && flags & (cl_mem_flags::from(CL_MEM_USE_HOST_PTR | CL_MEM_COPY_HOST_PTR)) != 0
174     {
175         return Err(CL_INVALID_HOST_PTR);
176     }
177 
178     // or if host_ptr is not NULL but CL_MEM_COPY_HOST_PTR or CL_MEM_USE_HOST_PTR are not set in
179     // flags.
180     if !host_ptr.is_null()
181         && flags & (cl_mem_flags::from(CL_MEM_USE_HOST_PTR | CL_MEM_COPY_HOST_PTR)) == 0
182     {
183         return Err(CL_INVALID_HOST_PTR);
184     }
185 
186     Ok(())
187 }
188 
validate_matching_buffer_flags(mem: &MemBase, flags: cl_mem_flags) -> CLResult<()>189 fn validate_matching_buffer_flags(mem: &MemBase, flags: cl_mem_flags) -> CLResult<()> {
190     // CL_INVALID_VALUE if an image is being created from another memory object (buffer or image)
191     // under one of the following circumstances:
192     //
193     // 1) mem_object was created with CL_MEM_WRITE_ONLY and
194     //    flags specifies CL_MEM_READ_WRITE or CL_MEM_READ_ONLY,
195     if bit_check(mem.flags, CL_MEM_WRITE_ONLY) && bit_check(flags, CL_MEM_READ_WRITE | CL_MEM_READ_ONLY) ||
196       // 2) mem_object was created with CL_MEM_READ_ONLY and
197       //    flags specifies CL_MEM_READ_WRITE or CL_MEM_WRITE_ONLY,
198       bit_check(mem.flags, CL_MEM_READ_ONLY) && bit_check(flags, CL_MEM_READ_WRITE | CL_MEM_WRITE_ONLY) ||
199       // 3) flags specifies CL_MEM_USE_HOST_PTR or CL_MEM_ALLOC_HOST_PTR or CL_MEM_COPY_HOST_PTR.
200       bit_check(flags, CL_MEM_USE_HOST_PTR | CL_MEM_ALLOC_HOST_PTR | CL_MEM_COPY_HOST_PTR) ||
201       // CL_INVALID_VALUE if an image is being created from another memory object (buffer or image)
202       // and mem_object was created with CL_MEM_HOST_WRITE_ONLY and flags specifies CL_MEM_HOST_READ_ONLY
203       bit_check(mem.flags, CL_MEM_HOST_WRITE_ONLY) && bit_check(flags, CL_MEM_HOST_READ_ONLY) ||
204       // or if mem_object was created with CL_MEM_HOST_READ_ONLY and flags specifies CL_MEM_HOST_WRITE_ONLY
205       bit_check(mem.flags, CL_MEM_HOST_READ_ONLY) && bit_check(flags, CL_MEM_HOST_WRITE_ONLY) ||
206       // or if mem_object was created with CL_MEM_HOST_NO_ACCESS and_flags_ specifies CL_MEM_HOST_READ_ONLY or CL_MEM_HOST_WRITE_ONLY.
207       bit_check(mem.flags, CL_MEM_HOST_NO_ACCESS) && bit_check(flags, CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_WRITE_ONLY)
208     {
209         return Err(CL_INVALID_VALUE);
210     }
211 
212     Ok(())
213 }
214 
215 #[cl_info_entrypoint(cl_get_mem_object_info)]
216 impl CLInfo<cl_mem_info> for cl_mem {
query(&self, q: cl_mem_info, _: &[u8]) -> CLResult<Vec<MaybeUninit<u8>>>217     fn query(&self, q: cl_mem_info, _: &[u8]) -> CLResult<Vec<MaybeUninit<u8>>> {
218         let mem = MemBase::ref_from_raw(*self)?;
219         Ok(match *q {
220             CL_MEM_ASSOCIATED_MEMOBJECT => {
221                 let ptr = match mem.parent.as_ref() {
222                     // Note we use as_ptr here which doesn't increase the reference count.
223                     Some(Mem::Buffer(buffer)) => cl_mem::from_ptr(Arc::as_ptr(buffer)),
224                     Some(Mem::Image(image)) => cl_mem::from_ptr(Arc::as_ptr(image)),
225                     None => ptr::null_mut(),
226                 };
227                 cl_prop::<cl_mem>(ptr.cast())
228             }
229             CL_MEM_CONTEXT => {
230                 // Note we use as_ptr here which doesn't increase the reference count.
231                 let ptr = Arc::as_ptr(&mem.context);
232                 cl_prop::<cl_context>(cl_context::from_ptr(ptr))
233             }
234             CL_MEM_FLAGS => cl_prop::<cl_mem_flags>(mem.flags),
235             // TODO debugging feature
236             CL_MEM_MAP_COUNT => cl_prop::<cl_uint>(0),
237             CL_MEM_HOST_PTR => cl_prop::<*mut c_void>(mem.host_ptr()),
238             CL_MEM_OFFSET => cl_prop::<usize>(if mem.is_buffer() {
239                 Buffer::ref_from_raw(*self)?.offset
240             } else {
241                 0
242             }),
243             CL_MEM_PROPERTIES => cl_prop::<&Vec<cl_mem_properties>>(&mem.props),
244             CL_MEM_REFERENCE_COUNT => cl_prop::<cl_uint>(if mem.is_buffer() {
245                 Buffer::refcnt(*self)?
246             } else {
247                 Image::refcnt(*self)?
248             }),
249             CL_MEM_SIZE => cl_prop::<usize>(mem.size),
250             CL_MEM_TYPE => cl_prop::<cl_mem_object_type>(mem.mem_type),
251             CL_MEM_USES_SVM_POINTER | CL_MEM_USES_SVM_POINTER_ARM => {
252                 cl_prop::<cl_bool>(mem.is_svm().into())
253             }
254             _ => return Err(CL_INVALID_VALUE),
255         })
256     }
257 }
258 
259 #[cl_entrypoint]
create_buffer_with_properties( context: cl_context, properties: *const cl_mem_properties, flags: cl_mem_flags, size: usize, host_ptr: *mut ::std::os::raw::c_void, ) -> CLResult<cl_mem>260 fn create_buffer_with_properties(
261     context: cl_context,
262     properties: *const cl_mem_properties,
263     flags: cl_mem_flags,
264     size: usize,
265     host_ptr: *mut ::std::os::raw::c_void,
266 ) -> CLResult<cl_mem> {
267     let c = Context::arc_from_raw(context)?;
268 
269     // CL_INVALID_VALUE if values specified in flags are not valid as defined in the Memory Flags table.
270     validate_mem_flags(flags, false)?;
271 
272     // CL_INVALID_BUFFER_SIZE if size is 0
273     if size == 0 {
274         return Err(CL_INVALID_BUFFER_SIZE);
275     }
276 
277     // ... or if size is greater than CL_DEVICE_MAX_MEM_ALLOC_SIZE for all devices in context.
278     if checked_compare(size, Ordering::Greater, c.max_mem_alloc()) {
279         return Err(CL_INVALID_BUFFER_SIZE);
280     }
281 
282     validate_host_ptr(host_ptr, flags)?;
283 
284     let props = Properties::from_ptr_raw(properties);
285     // CL_INVALID_PROPERTY if a property name in properties is not a supported property name, if
286     // the value specified for a supported property name is not valid, or if the same property name
287     // is specified more than once.
288     if props.len() > 1 {
289         // we don't support any properties besides the 0 property
290         return Err(CL_INVALID_PROPERTY);
291     }
292 
293     Ok(MemBase::new_buffer(c, flags, size, host_ptr, props)?.into_cl())
294 }
295 
296 #[cl_entrypoint]
create_buffer( context: cl_context, flags: cl_mem_flags, size: usize, host_ptr: *mut ::std::os::raw::c_void, ) -> CLResult<cl_mem>297 fn create_buffer(
298     context: cl_context,
299     flags: cl_mem_flags,
300     size: usize,
301     host_ptr: *mut ::std::os::raw::c_void,
302 ) -> CLResult<cl_mem> {
303     create_buffer_with_properties(context, ptr::null(), flags, size, host_ptr)
304 }
305 
306 #[cl_entrypoint]
create_sub_buffer( buffer: cl_mem, mut flags: cl_mem_flags, buffer_create_type: cl_buffer_create_type, buffer_create_info: *const ::std::os::raw::c_void, ) -> CLResult<cl_mem>307 fn create_sub_buffer(
308     buffer: cl_mem,
309     mut flags: cl_mem_flags,
310     buffer_create_type: cl_buffer_create_type,
311     buffer_create_info: *const ::std::os::raw::c_void,
312 ) -> CLResult<cl_mem> {
313     let b = Buffer::arc_from_raw(buffer)?;
314 
315     // CL_INVALID_MEM_OBJECT if buffer ... is a sub-buffer object.
316     if b.parent.is_some() {
317         return Err(CL_INVALID_MEM_OBJECT);
318     }
319 
320     validate_matching_buffer_flags(&b, flags)?;
321 
322     flags = inherit_mem_flags(flags, &b);
323     validate_mem_flags(flags, false)?;
324 
325     let (offset, size) = match buffer_create_type {
326         CL_BUFFER_CREATE_TYPE_REGION => {
327             // buffer_create_info is a pointer to a cl_buffer_region structure specifying a region of
328             // the buffer.
329             // CL_INVALID_VALUE if value(s) specified in buffer_create_info (for a given
330             // buffer_create_type) is not valid or if buffer_create_info is NULL.
331             let region = unsafe { buffer_create_info.cast::<cl_buffer_region>().as_ref() }
332                 .ok_or(CL_INVALID_VALUE)?;
333 
334             // CL_INVALID_BUFFER_SIZE if the size field of the cl_buffer_region structure passed in
335             // buffer_create_info is 0.
336             if region.size == 0 {
337                 return Err(CL_INVALID_BUFFER_SIZE);
338             }
339 
340             // CL_INVALID_VALUE if the region specified by the cl_buffer_region structure passed in
341             // buffer_create_info is out of bounds in buffer.
342             if region.origin + region.size > b.size {
343                 return Err(CL_INVALID_VALUE);
344             }
345 
346             (region.origin, region.size)
347         }
348         // CL_INVALID_VALUE if the value specified in buffer_create_type is not valid.
349         _ => return Err(CL_INVALID_VALUE),
350     };
351 
352     Ok(MemBase::new_sub_buffer(b, flags, offset, size).into_cl())
353 
354     // TODO
355     // CL_MISALIGNED_SUB_BUFFER_OFFSET if there are no devices in context associated with buffer for which the origin field of the cl_buffer_region structure passed in buffer_create_info is aligned to the CL_DEVICE_MEM_BASE_ADDR_ALIGN value.
356 }
357 
358 #[cl_entrypoint]
set_mem_object_destructor_callback( memobj: cl_mem, pfn_notify: Option<FuncMemCB>, user_data: *mut ::std::os::raw::c_void, ) -> CLResult<()>359 fn set_mem_object_destructor_callback(
360     memobj: cl_mem,
361     pfn_notify: Option<FuncMemCB>,
362     user_data: *mut ::std::os::raw::c_void,
363 ) -> CLResult<()> {
364     let m = MemBase::ref_from_raw(memobj)?;
365 
366     // SAFETY: The requirements on `MemCB::new` match the requirements
367     // imposed by the OpenCL specification. It is the caller's duty to uphold them.
368     let cb = unsafe { MemCB::new(pfn_notify, user_data)? };
369 
370     m.cbs.lock().unwrap().push(cb);
371     Ok(())
372 }
373 
validate_image_format<'a>( image_format: *const cl_image_format, ) -> CLResult<(&'a cl_image_format, u8)>374 fn validate_image_format<'a>(
375     image_format: *const cl_image_format,
376 ) -> CLResult<(&'a cl_image_format, u8)> {
377     // CL_INVALID_IMAGE_FORMAT_DESCRIPTOR ... if image_format is NULL.
378     let format = unsafe { image_format.as_ref() }.ok_or(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR)?;
379     let pixel_size = format
380         .pixel_size()
381         .ok_or(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR)?;
382 
383     // special validation
384     let valid_combination = match format.image_channel_data_type {
385         CL_UNORM_SHORT_565 | CL_UNORM_SHORT_555 | CL_UNORM_INT_101010 => {
386             [CL_RGB, CL_RGBx].contains(&format.image_channel_order)
387         }
388         CL_UNORM_INT_101010_2 => format.image_channel_order == CL_RGBA,
389         _ => true,
390     };
391     if !valid_combination {
392         return Err(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR);
393     }
394 
395     Ok((format, pixel_size))
396 }
397 
validate_image_desc( image_desc: *const cl_image_desc, host_ptr: *mut ::std::os::raw::c_void, elem_size: usize, devs: &[&Device], ) -> CLResult<(cl_image_desc, Option<Mem>)>398 fn validate_image_desc(
399     image_desc: *const cl_image_desc,
400     host_ptr: *mut ::std::os::raw::c_void,
401     elem_size: usize,
402     devs: &[&Device],
403 ) -> CLResult<(cl_image_desc, Option<Mem>)> {
404     // CL_INVALID_IMAGE_DESCRIPTOR if values specified in image_desc are not valid
405     const err: cl_int = CL_INVALID_IMAGE_DESCRIPTOR;
406 
407     // CL_INVALID_IMAGE_DESCRIPTOR ... if image_desc is NULL.
408     let mut desc = *unsafe { image_desc.as_ref() }.ok_or(err)?;
409 
410     // image_type describes the image type and must be either CL_MEM_OBJECT_IMAGE1D,
411     // CL_MEM_OBJECT_IMAGE1D_BUFFER, CL_MEM_OBJECT_IMAGE1D_ARRAY, CL_MEM_OBJECT_IMAGE2D,
412     // CL_MEM_OBJECT_IMAGE2D_ARRAY, or CL_MEM_OBJECT_IMAGE3D.
413     if !CL_IMAGE_TYPES.contains(&desc.image_type) {
414         return Err(err);
415     }
416 
417     let (dims, array) = desc.type_info();
418 
419     // image_width is the width of the image in pixels. For a 2D image and image array, the image
420     // width must be a value ≥ 1 and ≤ CL_DEVICE_IMAGE2D_MAX_WIDTH. For a 3D image, the image width
421     // must be a value ≥ 1 and ≤ CL_DEVICE_IMAGE3D_MAX_WIDTH. For a 1D image buffer, the image width
422     // must be a value ≥ 1 and ≤ CL_DEVICE_IMAGE_MAX_BUFFER_SIZE. For a 1D image and 1D image array,
423     // the image width must be a value ≥ 1 and ≤ CL_DEVICE_IMAGE2D_MAX_WIDTH.
424     //
425     // image_height is the height of the image in pixels. This is only used if the image is a 2D or
426     // 3D image, or a 2D image array. For a 2D image or image array, the image height must be a
427     // value ≥ 1 and ≤ CL_DEVICE_IMAGE2D_MAX_HEIGHT. For a 3D image, the image height must be a
428     // value ≥ 1 and ≤ CL_DEVICE_IMAGE3D_MAX_HEIGHT.
429     //
430     // image_depth is the depth of the image in pixels. This is only used if the image is a 3D image
431     // and must be a value ≥ 1 and ≤ CL_DEVICE_IMAGE3D_MAX_DEPTH.
432     if desc.image_width < 1
433         || desc.image_height < 1 && dims >= 2
434         || desc.image_depth < 1 && dims >= 3
435         || desc.image_array_size < 1 && array
436     {
437         return Err(err);
438     }
439 
440     let max_size = if dims == 3 {
441         devs.iter().map(|d| d.image_3d_size()).min()
442     } else if desc.image_type == CL_MEM_OBJECT_IMAGE1D_BUFFER {
443         devs.iter().map(|d| d.image_buffer_size()).min()
444     } else {
445         devs.iter().map(|d| d.image_2d_size()).min()
446     }
447     .unwrap();
448     let max_array = devs.iter().map(|d| d.image_array_size()).min().unwrap();
449 
450     // CL_INVALID_IMAGE_SIZE if image dimensions specified in image_desc exceed the maximum image
451     // dimensions described in the Device Queries table for all devices in context.
452     if desc.image_width > max_size
453         || desc.image_height > max_size && dims >= 2
454         || desc.image_depth > max_size && dims >= 3
455         || desc.image_array_size > max_array && array
456     {
457         return Err(CL_INVALID_IMAGE_SIZE);
458     }
459 
460     // num_mip_levels and num_samples must be 0.
461     if desc.num_mip_levels != 0 || desc.num_samples != 0 {
462         return Err(err);
463     }
464 
465     // mem_object may refer to a valid buffer or image memory object. mem_object can be a buffer
466     // memory object if image_type is CL_MEM_OBJECT_IMAGE1D_BUFFER or CL_MEM_OBJECT_IMAGE2D.
467     // mem_object can be an image object if image_type is CL_MEM_OBJECT_IMAGE2D. Otherwise it must
468     // be NULL.
469     //
470     // TODO: cl_khr_image2d_from_buffer is an optional feature
471     let p = unsafe { &desc.anon_1.mem_object };
472     let parent = if !p.is_null() {
473         let p = MemBase::arc_from_raw(*p)?;
474         if !match desc.image_type {
475             CL_MEM_OBJECT_IMAGE1D_BUFFER => p.is_buffer(),
476             CL_MEM_OBJECT_IMAGE2D => {
477                 (p.is_buffer() && devs.iter().any(|d| d.image2d_from_buffer_supported()))
478                     || p.mem_type == CL_MEM_OBJECT_IMAGE2D
479             }
480             _ => false,
481         } {
482             return Err(CL_INVALID_OPERATION);
483         }
484         Some(p)
485     } else {
486         None
487     };
488 
489     // image_row_pitch is the scan-line pitch in bytes. This must be 0 if host_ptr is NULL and can
490     // be either 0 or ≥ image_width × size of element in bytes if host_ptr is not NULL. If host_ptr
491     // is not NULL and image_row_pitch = 0, image_row_pitch is calculated as image_width × size of
492     // element in bytes. If image_row_pitch is not 0, it must be a multiple of the image element
493     // size in bytes. For a 2D image created from a buffer, the pitch specified (or computed if
494     // pitch specified is 0) must be a multiple of the maximum of the
495     // CL_DEVICE_IMAGE_PITCH_ALIGNMENT value for all devices in the context associated with the
496     // buffer specified by mem_object that support images.
497     //
498     // image_slice_pitch is the size in bytes of each 2D slice in the 3D image or the size in bytes
499     // of each image in a 1D or 2D image array. This must be 0 if host_ptr is NULL. If host_ptr is
500     // not NULL, image_slice_pitch can be either 0 or ≥ image_row_pitch × image_height for a 2D
501     // image array or 3D image and can be either 0 or ≥ image_row_pitch for a 1D image array. If
502     // host_ptr is not NULL and image_slice_pitch = 0, image_slice_pitch is calculated as
503     // image_row_pitch × image_height for a 2D image array or 3D image and image_row_pitch for a 1D
504     // image array. If image_slice_pitch is not 0, it must be a multiple of the image_row_pitch.
505     let has_buf_parent = parent.as_ref().map_or(false, |p| p.is_buffer());
506     if host_ptr.is_null() {
507         if (desc.image_row_pitch != 0 || desc.image_slice_pitch != 0) && !has_buf_parent {
508             return Err(err);
509         }
510 
511         if desc.image_row_pitch == 0 {
512             desc.image_row_pitch = desc.image_width * elem_size;
513         }
514         if desc.image_slice_pitch == 0 {
515             desc.image_slice_pitch = desc.image_row_pitch * desc.image_height;
516         }
517 
518         if has_buf_parent && desc.image_type != CL_MEM_OBJECT_IMAGE1D_BUFFER {
519             let pitch_alignment = devs
520                 .iter()
521                 .map(|d| d.image_pitch_alignment())
522                 .max()
523                 .unwrap() as usize;
524             if desc.image_row_pitch % (pitch_alignment * elem_size) != 0 {
525                 return Err(err);
526             }
527         }
528     } else {
529         if desc.image_row_pitch == 0 {
530             desc.image_row_pitch = desc.image_width * elem_size;
531         } else if desc.image_row_pitch % elem_size != 0 {
532             return Err(err);
533         }
534 
535         if dims == 3 || array {
536             let valid_slice_pitch =
537                 desc.image_row_pitch * if dims == 1 { 1 } else { desc.image_height };
538             if desc.image_slice_pitch == 0 {
539                 desc.image_slice_pitch = valid_slice_pitch;
540             } else if desc.image_slice_pitch < valid_slice_pitch
541                 || desc.image_slice_pitch % desc.image_row_pitch != 0
542             {
543                 return Err(err);
544             }
545         }
546     }
547 
548     Ok((desc, parent))
549 }
550 
validate_image_bounds(i: &Image, origin: CLVec<usize>, region: CLVec<usize>) -> CLResult<()>551 fn validate_image_bounds(i: &Image, origin: CLVec<usize>, region: CLVec<usize>) -> CLResult<()> {
552     let dims = i.image_desc.dims_with_array();
553     let bound = region + origin;
554     if bound > i.image_desc.size() {
555         return Err(CL_INVALID_VALUE);
556     }
557 
558     // If image is a 2D image object, origin[2] must be 0. If image is a 1D image or 1D image buffer
559     // object, origin[1] and origin[2] must be 0. If image is a 1D image array object, origin[2]
560     // must be 0.
561     if dims < 3 && origin[2] != 0 || dims < 2 && origin[1] != 0 {
562         return Err(CL_INVALID_VALUE);
563     }
564 
565     // If image is a 2D image object, region[2] must be 1. If image is a 1D image or 1D image buffer
566     // object, region[1] and region[2] must be 1. If image is a 1D image array object, region[2]
567     // must be 1. The values in region cannot be 0.
568     if dims < 3 && region[2] != 1 || dims < 2 && region[1] != 1 || region.contains(&0) {
569         return Err(CL_INVALID_VALUE);
570     }
571 
572     Ok(())
573 }
574 
desc_eq_no_buffer(a: &cl_image_desc, b: &cl_image_desc) -> bool575 fn desc_eq_no_buffer(a: &cl_image_desc, b: &cl_image_desc) -> bool {
576     a.image_type == b.image_type
577         && a.image_width == b.image_width
578         && a.image_height == b.image_height
579         && a.image_depth == b.image_depth
580         && a.image_array_size == b.image_array_size
581         && a.image_row_pitch == b.image_row_pitch
582         && a.image_slice_pitch == b.image_slice_pitch
583         && a.num_mip_levels == b.num_mip_levels
584         && a.num_samples == b.num_samples
585 }
586 
validate_buffer( desc: &cl_image_desc, mut flags: cl_mem_flags, format: &cl_image_format, host_ptr: *mut ::std::os::raw::c_void, elem_size: usize, ) -> CLResult<cl_mem_flags>587 fn validate_buffer(
588     desc: &cl_image_desc,
589     mut flags: cl_mem_flags,
590     format: &cl_image_format,
591     host_ptr: *mut ::std::os::raw::c_void,
592     elem_size: usize,
593 ) -> CLResult<cl_mem_flags> {
594     // CL_INVALID_IMAGE_DESCRIPTOR if values specified in image_desc are not valid
595     const err: cl_int = CL_INVALID_IMAGE_DESCRIPTOR;
596     let mem_object = unsafe { desc.anon_1.mem_object };
597 
598     // mem_object may refer to a valid buffer or image memory object. mem_object can be a buffer
599     // memory object if image_type is CL_MEM_OBJECT_IMAGE1D_BUFFER or CL_MEM_OBJECT_IMAGE2D
600     // mem_object can be an image object if image_type is CL_MEM_OBJECT_IMAGE2D. Otherwise it must
601     // be NULL. The image pixels are taken from the memory objects data store. When the contents of
602     // the specified memory objects data store are modified, those changes are reflected in the
603     // contents of the image object and vice-versa at corresponding synchronization points.
604     if !mem_object.is_null() {
605         let mem = MemBase::ref_from_raw(mem_object)?;
606 
607         match mem.mem_type {
608             CL_MEM_OBJECT_BUFFER => {
609                 match desc.image_type {
610                     // For a 1D image buffer created from a buffer object, the image_width × size of
611                     // element in bytes must be ≤ size of the buffer object.
612                     CL_MEM_OBJECT_IMAGE1D_BUFFER => {
613                         if desc.image_width * elem_size > mem.size {
614                             return Err(err);
615                         }
616                     }
617                     // For a 2D image created from a buffer object, the image_row_pitch × image_height
618                     // must be ≤ size of the buffer object specified by mem_object.
619                     CL_MEM_OBJECT_IMAGE2D => {
620                         //TODO
621                         //• CL_INVALID_IMAGE_FORMAT_DESCRIPTOR if a 2D image is created from a buffer and the row pitch and base address alignment does not follow the rules described for creating a 2D image from a buffer.
622                         if desc.image_row_pitch * desc.image_height > mem.size {
623                             return Err(err);
624                         }
625                     }
626                     _ => return Err(err),
627                 }
628             }
629             // For an image object created from another image object, the values specified in the
630             // image descriptor except for mem_object must match the image descriptor information
631             // associated with mem_object.
632             CL_MEM_OBJECT_IMAGE2D => {
633                 let image = Image::ref_from_raw(mem_object).unwrap();
634                 if desc.image_type != mem.mem_type || !desc_eq_no_buffer(desc, &image.image_desc) {
635                     return Err(err);
636                 }
637 
638                 // CL_INVALID_IMAGE_FORMAT_DESCRIPTOR if a 2D image is created from a 2D image object
639                 // and the rules described above are not followed.
640 
641                 // Creating a 2D image object from another 2D image object creates a new 2D image
642                 // object that shares the image data store with mem_object but views the pixels in the
643                 //  image with a different image channel order. Restrictions are:
644                 //
645                 // The image channel data type specified in image_format must match the image channel
646                 // data type associated with mem_object.
647                 if format.image_channel_data_type != image.image_format.image_channel_data_type {
648                     return Err(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR);
649                 }
650 
651                 // The image channel order specified in image_format must be compatible with the image
652                 // channel order associated with mem_object. Compatible image channel orders are:
653                 if format.image_channel_order != image.image_format.image_channel_order {
654                     // in image_format | in  mem_object:
655                     // CL_sBGRA | CL_BGRA
656                     // CL_BGRA  | CL_sBGRA
657                     // CL_sRGBA | CL_RGBA
658                     // CL_RGBA  | CL_sRGBA
659                     // CL_sRGB  | CL_RGB
660                     // CL_RGB   | CL_sRGB
661                     // CL_sRGBx | CL_RGBx
662                     // CL_RGBx  | CL_sRGBx
663                     // CL_DEPTH | CL_R
664                     match (
665                         format.image_channel_order,
666                         image.image_format.image_channel_order,
667                     ) {
668                         (CL_sBGRA, CL_BGRA)
669                         | (CL_BGRA, CL_sBGRA)
670                         | (CL_sRGBA, CL_RGBA)
671                         | (CL_RGBA, CL_sRGBA)
672                         | (CL_sRGB, CL_RGB)
673                         | (CL_RGB, CL_sRGB)
674                         | (CL_sRGBx, CL_RGBx)
675                         | (CL_RGBx, CL_sRGBx)
676                         | (CL_DEPTH, CL_R) => (),
677                         _ => return Err(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR),
678                     }
679                 }
680             }
681             _ => return Err(err),
682         }
683 
684         // If the buffer object specified by mem_object was created with CL_MEM_USE_HOST_PTR, the
685         // host_ptr specified to clCreateBuffer or clCreateBufferWithProperties must be aligned to
686         // the maximum of the CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT value for all devices in the
687         // context associated with the buffer specified by mem_object that support images.
688         if mem.flags & CL_MEM_USE_HOST_PTR as cl_mem_flags != 0 {
689             for dev in &mem.context.devs {
690                 let addr_alignment = dev.image_base_address_alignment();
691                 if addr_alignment == 0 {
692                     return Err(CL_INVALID_OPERATION);
693                 } else if !is_alligned(host_ptr, addr_alignment as usize) {
694                     return Err(err);
695                 }
696             }
697         }
698 
699         validate_matching_buffer_flags(mem, flags)?;
700 
701         flags = inherit_mem_flags(flags, mem);
702     // implied by spec
703     } else if desc.image_type == CL_MEM_OBJECT_IMAGE1D_BUFFER {
704         return Err(err);
705     }
706 
707     Ok(flags)
708 }
709 
710 #[cl_info_entrypoint(cl_get_image_info)]
711 impl CLInfo<cl_image_info> for cl_mem {
query(&self, q: cl_image_info, _: &[u8]) -> CLResult<Vec<MaybeUninit<u8>>>712     fn query(&self, q: cl_image_info, _: &[u8]) -> CLResult<Vec<MaybeUninit<u8>>> {
713         let mem = Image::ref_from_raw(*self)?;
714         Ok(match *q {
715             CL_IMAGE_ARRAY_SIZE => cl_prop::<usize>(mem.image_desc.image_array_size),
716             CL_IMAGE_BUFFER => cl_prop::<cl_mem>(unsafe { mem.image_desc.anon_1.buffer }),
717             CL_IMAGE_DEPTH => cl_prop::<usize>(mem.image_desc.image_depth),
718             CL_IMAGE_ELEMENT_SIZE => cl_prop::<usize>(mem.image_elem_size.into()),
719             CL_IMAGE_FORMAT => cl_prop::<cl_image_format>(mem.image_format),
720             CL_IMAGE_HEIGHT => cl_prop::<usize>(mem.image_desc.image_height),
721             CL_IMAGE_NUM_MIP_LEVELS => cl_prop::<cl_uint>(mem.image_desc.num_mip_levels),
722             CL_IMAGE_NUM_SAMPLES => cl_prop::<cl_uint>(mem.image_desc.num_samples),
723             CL_IMAGE_ROW_PITCH => cl_prop::<usize>(mem.image_desc.image_row_pitch),
724             CL_IMAGE_SLICE_PITCH => cl_prop::<usize>(mem.image_desc.image_slice_pitch),
725             CL_IMAGE_WIDTH => cl_prop::<usize>(mem.image_desc.image_width),
726             _ => return Err(CL_INVALID_VALUE),
727         })
728     }
729 }
730 
731 #[cl_entrypoint]
create_image_with_properties( context: cl_context, properties: *const cl_mem_properties, mut flags: cl_mem_flags, image_format: *const cl_image_format, image_desc: *const cl_image_desc, host_ptr: *mut ::std::os::raw::c_void, ) -> CLResult<cl_mem>732 fn create_image_with_properties(
733     context: cl_context,
734     properties: *const cl_mem_properties,
735     mut flags: cl_mem_flags,
736     image_format: *const cl_image_format,
737     image_desc: *const cl_image_desc,
738     host_ptr: *mut ::std::os::raw::c_void,
739 ) -> CLResult<cl_mem> {
740     let c = Context::arc_from_raw(context)?;
741 
742     // CL_INVALID_OPERATION if there are no devices in context that support images (i.e.
743     // CL_DEVICE_IMAGE_SUPPORT specified in the Device Queries table is CL_FALSE).
744     c.devs
745         .iter()
746         .find(|d| d.image_supported())
747         .ok_or(CL_INVALID_OPERATION)?;
748 
749     let (format, elem_size) = validate_image_format(image_format)?;
750     let (desc, parent) = validate_image_desc(image_desc, host_ptr, elem_size.into(), &c.devs)?;
751 
752     // validate host_ptr before merging flags
753     validate_host_ptr(host_ptr, flags)?;
754 
755     flags = validate_buffer(&desc, flags, format, host_ptr, elem_size.into())?;
756 
757     // For all image types except CL_MEM_OBJECT_IMAGE1D_BUFFER, if the value specified for flags is 0, the
758     // default is used which is CL_MEM_READ_WRITE.
759     if flags == 0 && desc.image_type != CL_MEM_OBJECT_IMAGE1D_BUFFER {
760         flags = CL_MEM_READ_WRITE.into();
761     }
762 
763     validate_mem_flags(flags, false)?;
764 
765     let filtered_flags = filter_image_access_flags(flags);
766     // CL_IMAGE_FORMAT_NOT_SUPPORTED if there are no devices in context that support image_format.
767     c.devs
768         .iter()
769         .filter_map(|d| d.formats.get(format))
770         .filter_map(|f| f.get(&desc.image_type))
771         .find(|f| *f & filtered_flags == filtered_flags)
772         .ok_or(CL_IMAGE_FORMAT_NOT_SUPPORTED)?;
773 
774     let props = Properties::from_ptr_raw(properties);
775     // CL_INVALID_PROPERTY if a property name in properties is not a supported property name, if
776     // the value specified for a supported property name is not valid, or if the same property name
777     // is specified more than once.
778     if props.len() > 1 {
779         // we don't support any properties besides the 0 property
780         return Err(CL_INVALID_PROPERTY);
781     }
782 
783     Ok(MemBase::new_image(
784         c,
785         parent,
786         desc.image_type,
787         flags,
788         format,
789         desc,
790         elem_size,
791         host_ptr,
792         props,
793     )?
794     .into_cl())
795 }
796 
797 #[cl_entrypoint]
create_image( context: cl_context, flags: cl_mem_flags, image_format: *const cl_image_format, image_desc: *const cl_image_desc, host_ptr: *mut ::std::os::raw::c_void, ) -> CLResult<cl_mem>798 fn create_image(
799     context: cl_context,
800     flags: cl_mem_flags,
801     image_format: *const cl_image_format,
802     image_desc: *const cl_image_desc,
803     host_ptr: *mut ::std::os::raw::c_void,
804 ) -> CLResult<cl_mem> {
805     create_image_with_properties(
806         context,
807         ptr::null(),
808         flags,
809         image_format,
810         image_desc,
811         host_ptr,
812     )
813 }
814 
815 #[cl_entrypoint]
create_image_2d( context: cl_context, flags: cl_mem_flags, image_format: *const cl_image_format, image_width: usize, image_height: usize, image_row_pitch: usize, host_ptr: *mut ::std::os::raw::c_void, ) -> CLResult<cl_mem>816 fn create_image_2d(
817     context: cl_context,
818     flags: cl_mem_flags,
819     image_format: *const cl_image_format,
820     image_width: usize,
821     image_height: usize,
822     image_row_pitch: usize,
823     host_ptr: *mut ::std::os::raw::c_void,
824 ) -> CLResult<cl_mem> {
825     let image_desc = cl_image_desc {
826         image_type: CL_MEM_OBJECT_IMAGE2D,
827         image_width: image_width,
828         image_height: image_height,
829         image_row_pitch: image_row_pitch,
830         ..Default::default()
831     };
832 
833     create_image(context, flags, image_format, &image_desc, host_ptr)
834 }
835 
836 #[cl_entrypoint]
create_image_3d( context: cl_context, flags: cl_mem_flags, image_format: *const cl_image_format, image_width: usize, image_height: usize, image_depth: usize, image_row_pitch: usize, image_slice_pitch: usize, host_ptr: *mut ::std::os::raw::c_void, ) -> CLResult<cl_mem>837 fn create_image_3d(
838     context: cl_context,
839     flags: cl_mem_flags,
840     image_format: *const cl_image_format,
841     image_width: usize,
842     image_height: usize,
843     image_depth: usize,
844     image_row_pitch: usize,
845     image_slice_pitch: usize,
846     host_ptr: *mut ::std::os::raw::c_void,
847 ) -> CLResult<cl_mem> {
848     let image_desc = cl_image_desc {
849         image_type: CL_MEM_OBJECT_IMAGE3D,
850         image_width: image_width,
851         image_height: image_height,
852         image_depth: image_depth,
853         image_row_pitch: image_row_pitch,
854         image_slice_pitch: image_slice_pitch,
855         ..Default::default()
856     };
857 
858     create_image(context, flags, image_format, &image_desc, host_ptr)
859 }
860 
861 #[cl_entrypoint]
get_supported_image_formats( context: cl_context, flags: cl_mem_flags, image_type: cl_mem_object_type, num_entries: cl_uint, image_formats: *mut cl_image_format, num_image_formats: *mut cl_uint, ) -> CLResult<()>862 fn get_supported_image_formats(
863     context: cl_context,
864     flags: cl_mem_flags,
865     image_type: cl_mem_object_type,
866     num_entries: cl_uint,
867     image_formats: *mut cl_image_format,
868     num_image_formats: *mut cl_uint,
869 ) -> CLResult<()> {
870     let c = Context::ref_from_raw(context)?;
871 
872     // CL_INVALID_VALUE if flags
873     validate_mem_flags(flags, true)?;
874 
875     // or image_type are not valid
876     if !image_type_valid(image_type) {
877         return Err(CL_INVALID_VALUE);
878     }
879 
880     // CL_INVALID_VALUE ... if num_entries is 0 and image_formats is not NULL.
881     if num_entries == 0 && !image_formats.is_null() {
882         return Err(CL_INVALID_VALUE);
883     }
884 
885     let mut res = Vec::<cl_image_format>::new();
886     let filtered_flags = filter_image_access_flags(flags);
887     for dev in &c.devs {
888         for f in &dev.formats {
889             let s = f.1.get(&image_type).unwrap_or(&0);
890 
891             if filtered_flags & s == filtered_flags {
892                 res.push(*f.0);
893             }
894         }
895     }
896 
897     res.sort();
898     res.dedup();
899 
900     num_image_formats.write_checked(res.len() as cl_uint);
901     unsafe { image_formats.copy_checked(res.as_ptr(), res.len()) };
902 
903     Ok(())
904 }
905 
906 #[cl_info_entrypoint(cl_get_sampler_info)]
907 impl CLInfo<cl_sampler_info> for cl_sampler {
query(&self, q: cl_sampler_info, _: &[u8]) -> CLResult<Vec<MaybeUninit<u8>>>908     fn query(&self, q: cl_sampler_info, _: &[u8]) -> CLResult<Vec<MaybeUninit<u8>>> {
909         let sampler = Sampler::ref_from_raw(*self)?;
910         Ok(match q {
911             CL_SAMPLER_ADDRESSING_MODE => cl_prop::<cl_addressing_mode>(sampler.addressing_mode),
912             CL_SAMPLER_CONTEXT => {
913                 // Note we use as_ptr here which doesn't increase the reference count.
914                 let ptr = Arc::as_ptr(&sampler.context);
915                 cl_prop::<cl_context>(cl_context::from_ptr(ptr))
916             }
917             CL_SAMPLER_FILTER_MODE => cl_prop::<cl_filter_mode>(sampler.filter_mode),
918             CL_SAMPLER_NORMALIZED_COORDS => cl_prop::<bool>(sampler.normalized_coords),
919             CL_SAMPLER_REFERENCE_COUNT => cl_prop::<cl_uint>(Sampler::refcnt(*self)?),
920             CL_SAMPLER_PROPERTIES => {
921                 cl_prop::<&Option<Properties<cl_sampler_properties>>>(&sampler.props)
922             }
923             // CL_INVALID_VALUE if param_name is not one of the supported values
924             _ => return Err(CL_INVALID_VALUE),
925         })
926     }
927 }
928 
create_sampler_impl( context: cl_context, normalized_coords: cl_bool, addressing_mode: cl_addressing_mode, filter_mode: cl_filter_mode, props: Option<Properties<cl_sampler_properties>>, ) -> CLResult<cl_sampler>929 fn create_sampler_impl(
930     context: cl_context,
931     normalized_coords: cl_bool,
932     addressing_mode: cl_addressing_mode,
933     filter_mode: cl_filter_mode,
934     props: Option<Properties<cl_sampler_properties>>,
935 ) -> CLResult<cl_sampler> {
936     let c = Context::arc_from_raw(context)?;
937 
938     // CL_INVALID_OPERATION if images are not supported by any device associated with context (i.e.
939     // CL_DEVICE_IMAGE_SUPPORT specified in the Device Queries table is CL_FALSE).
940     c.devs
941         .iter()
942         .find(|d| d.image_supported())
943         .ok_or(CL_INVALID_OPERATION)?;
944 
945     // CL_INVALID_VALUE if addressing_mode, filter_mode, normalized_coords or a combination of these
946     // arguements are not valid.
947     validate_addressing_mode(addressing_mode)?;
948     validate_filter_mode(filter_mode)?;
949 
950     let sampler = Sampler::new(
951         c,
952         check_cl_bool(normalized_coords).ok_or(CL_INVALID_VALUE)?,
953         addressing_mode,
954         filter_mode,
955         props,
956     );
957     Ok(sampler.into_cl())
958 }
959 
960 #[cl_entrypoint]
create_sampler( context: cl_context, normalized_coords: cl_bool, addressing_mode: cl_addressing_mode, filter_mode: cl_filter_mode, ) -> CLResult<cl_sampler>961 fn create_sampler(
962     context: cl_context,
963     normalized_coords: cl_bool,
964     addressing_mode: cl_addressing_mode,
965     filter_mode: cl_filter_mode,
966 ) -> CLResult<cl_sampler> {
967     create_sampler_impl(
968         context,
969         normalized_coords,
970         addressing_mode,
971         filter_mode,
972         None,
973     )
974 }
975 
976 #[cl_entrypoint]
create_sampler_with_properties( context: cl_context, sampler_properties: *const cl_sampler_properties, ) -> CLResult<cl_sampler>977 fn create_sampler_with_properties(
978     context: cl_context,
979     sampler_properties: *const cl_sampler_properties,
980 ) -> CLResult<cl_sampler> {
981     let mut normalized_coords = CL_TRUE;
982     let mut addressing_mode = CL_ADDRESS_CLAMP;
983     let mut filter_mode = CL_FILTER_NEAREST;
984 
985     // CL_INVALID_VALUE if the same property name is specified more than once.
986     let sampler_properties = if sampler_properties.is_null() {
987         None
988     } else {
989         let sampler_properties =
990             Properties::from_ptr(sampler_properties).ok_or(CL_INVALID_VALUE)?;
991         for p in &sampler_properties.props {
992             match p.0 as u32 {
993                 CL_SAMPLER_ADDRESSING_MODE => addressing_mode = p.1 as u32,
994                 CL_SAMPLER_FILTER_MODE => filter_mode = p.1 as u32,
995                 CL_SAMPLER_NORMALIZED_COORDS => normalized_coords = p.1 as u32,
996                 // CL_INVALID_VALUE if the property name in sampler_properties is not a supported
997                 // property name
998                 _ => return Err(CL_INVALID_VALUE),
999             }
1000         }
1001         Some(sampler_properties)
1002     };
1003 
1004     create_sampler_impl(
1005         context,
1006         normalized_coords,
1007         addressing_mode,
1008         filter_mode,
1009         sampler_properties,
1010     )
1011 }
1012 
1013 #[cl_entrypoint]
retain_sampler(sampler: cl_sampler) -> CLResult<()>1014 fn retain_sampler(sampler: cl_sampler) -> CLResult<()> {
1015     Sampler::retain(sampler)
1016 }
1017 
1018 #[cl_entrypoint]
release_sampler(sampler: cl_sampler) -> CLResult<()>1019 fn release_sampler(sampler: cl_sampler) -> CLResult<()> {
1020     Sampler::release(sampler)
1021 }
1022 
1023 #[cl_entrypoint]
enqueue_read_buffer( command_queue: cl_command_queue, buffer: cl_mem, blocking_read: cl_bool, offset: usize, cb: usize, ptr: *mut ::std::os::raw::c_void, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>1024 fn enqueue_read_buffer(
1025     command_queue: cl_command_queue,
1026     buffer: cl_mem,
1027     blocking_read: cl_bool,
1028     offset: usize,
1029     cb: usize,
1030     ptr: *mut ::std::os::raw::c_void,
1031     num_events_in_wait_list: cl_uint,
1032     event_wait_list: *const cl_event,
1033     event: *mut cl_event,
1034 ) -> CLResult<()> {
1035     let q = Queue::arc_from_raw(command_queue)?;
1036     let b = Buffer::arc_from_raw(buffer)?;
1037     let block = check_cl_bool(blocking_read).ok_or(CL_INVALID_VALUE)?;
1038     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
1039 
1040     // CL_INVALID_VALUE if the region being read or written specified by (offset, size) is out of
1041     // bounds or if ptr is a NULL value.
1042     if offset + cb > b.size || ptr.is_null() {
1043         return Err(CL_INVALID_VALUE);
1044     }
1045 
1046     // CL_INVALID_CONTEXT if the context associated with command_queue and buffer are not the same
1047     if b.context != q.context {
1048         return Err(CL_INVALID_CONTEXT);
1049     }
1050 
1051     // CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST if the read and write operations are blocking
1052     // and the execution status of any of the events in event_wait_list is a negative integer value.
1053     if block && evs.iter().any(|e| e.is_error()) {
1054         return Err(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
1055     }
1056 
1057     // CL_INVALID_OPERATION if clEnqueueReadBuffer is called on buffer which has been created with
1058     // CL_MEM_HOST_WRITE_ONLY or CL_MEM_HOST_NO_ACCESS.
1059     if bit_check(b.flags, CL_MEM_HOST_WRITE_ONLY | CL_MEM_HOST_NO_ACCESS) {
1060         return Err(CL_INVALID_OPERATION);
1061     }
1062 
1063     // SAFETY: it's required that applications do not cause data races
1064     let ptr = unsafe { MutMemoryPtr::from_ptr(ptr) };
1065     create_and_queue(
1066         q,
1067         CL_COMMAND_READ_BUFFER,
1068         evs,
1069         event,
1070         block,
1071         Box::new(move |q, ctx| b.read(q, ctx, offset, ptr, cb)),
1072     )
1073 
1074     // TODO
1075     // CL_MISALIGNED_SUB_BUFFER_OFFSET if buffer is a sub-buffer object and offset specified when the sub-buffer object is created is not aligned to CL_DEVICE_MEM_BASE_ADDR_ALIGN value for device associated with queue.
1076 }
1077 
1078 #[cl_entrypoint]
enqueue_write_buffer( command_queue: cl_command_queue, buffer: cl_mem, blocking_write: cl_bool, offset: usize, cb: usize, ptr: *const ::std::os::raw::c_void, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>1079 fn enqueue_write_buffer(
1080     command_queue: cl_command_queue,
1081     buffer: cl_mem,
1082     blocking_write: cl_bool,
1083     offset: usize,
1084     cb: usize,
1085     ptr: *const ::std::os::raw::c_void,
1086     num_events_in_wait_list: cl_uint,
1087     event_wait_list: *const cl_event,
1088     event: *mut cl_event,
1089 ) -> CLResult<()> {
1090     let q = Queue::arc_from_raw(command_queue)?;
1091     let b = Buffer::arc_from_raw(buffer)?;
1092     let block = check_cl_bool(blocking_write).ok_or(CL_INVALID_VALUE)?;
1093     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
1094 
1095     // CL_INVALID_VALUE if the region being read or written specified by (offset, size) is out of
1096     // bounds or if ptr is a NULL value.
1097     if offset + cb > b.size || ptr.is_null() {
1098         return Err(CL_INVALID_VALUE);
1099     }
1100 
1101     // CL_INVALID_CONTEXT if the context associated with command_queue and buffer are not the same
1102     if b.context != q.context {
1103         return Err(CL_INVALID_CONTEXT);
1104     }
1105 
1106     // CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST if the read and write operations are blocking
1107     // and the execution status of any of the events in event_wait_list is a negative integer value.
1108     if block && evs.iter().any(|e| e.is_error()) {
1109         return Err(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
1110     }
1111 
1112     // CL_INVALID_OPERATION if clEnqueueWriteBuffer is called on buffer which has been created with
1113     // CL_MEM_HOST_READ_ONLY or CL_MEM_HOST_NO_ACCESS.
1114     if bit_check(b.flags, CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_NO_ACCESS) {
1115         return Err(CL_INVALID_OPERATION);
1116     }
1117 
1118     // SAFETY: it's required that applications do not cause data races
1119     let ptr = unsafe { ConstMemoryPtr::from_ptr(ptr) };
1120     create_and_queue(
1121         q,
1122         CL_COMMAND_WRITE_BUFFER,
1123         evs,
1124         event,
1125         block,
1126         Box::new(move |q, ctx| b.write(q, ctx, offset, ptr, cb)),
1127     )
1128 
1129     // TODO
1130     // CL_MISALIGNED_SUB_BUFFER_OFFSET if buffer is a sub-buffer object and offset specified when the sub-buffer object is created is not aligned to CL_DEVICE_MEM_BASE_ADDR_ALIGN value for device associated with queue.
1131 }
1132 
1133 #[cl_entrypoint]
enqueue_copy_buffer( command_queue: cl_command_queue, src_buffer: cl_mem, dst_buffer: cl_mem, src_offset: usize, dst_offset: usize, size: usize, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>1134 fn enqueue_copy_buffer(
1135     command_queue: cl_command_queue,
1136     src_buffer: cl_mem,
1137     dst_buffer: cl_mem,
1138     src_offset: usize,
1139     dst_offset: usize,
1140     size: usize,
1141     num_events_in_wait_list: cl_uint,
1142     event_wait_list: *const cl_event,
1143     event: *mut cl_event,
1144 ) -> CLResult<()> {
1145     let q = Queue::arc_from_raw(command_queue)?;
1146     let src = Buffer::arc_from_raw(src_buffer)?;
1147     let dst = Buffer::arc_from_raw(dst_buffer)?;
1148     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
1149 
1150     // CL_INVALID_CONTEXT if the context associated with command_queue, src_buffer and dst_buffer
1151     // are not the same
1152     if q.context != src.context || q.context != dst.context {
1153         return Err(CL_INVALID_CONTEXT);
1154     }
1155 
1156     // CL_INVALID_VALUE if src_offset, dst_offset, size, src_offset + size or dst_offset + size
1157     // require accessing elements outside the src_buffer and dst_buffer buffer objects respectively.
1158     if src_offset + size > src.size || dst_offset + size > dst.size {
1159         return Err(CL_INVALID_VALUE);
1160     }
1161 
1162     // CL_MEM_COPY_OVERLAP if src_buffer and dst_buffer are the same buffer or sub-buffer object
1163     // and the source and destination regions overlap or if src_buffer and dst_buffer are different
1164     // sub-buffers of the same associated buffer object and they overlap. The regions overlap if
1165     // src_offset ≤ dst_offset ≤ src_offset + size - 1 or if dst_offset ≤ src_offset ≤ dst_offset + size - 1.
1166     if src.has_same_parent(&dst) {
1167         let src_offset = src_offset + src.offset;
1168         let dst_offset = dst_offset + dst.offset;
1169 
1170         if (src_offset <= dst_offset && dst_offset < src_offset + size)
1171             || (dst_offset <= src_offset && src_offset < dst_offset + size)
1172         {
1173             return Err(CL_MEM_COPY_OVERLAP);
1174         }
1175     }
1176 
1177     create_and_queue(
1178         q,
1179         CL_COMMAND_COPY_BUFFER,
1180         evs,
1181         event,
1182         false,
1183         Box::new(move |q, ctx| src.copy_to_buffer(q, ctx, &dst, src_offset, dst_offset, size)),
1184     )
1185 
1186     // TODO
1187     //• CL_MISALIGNED_SUB_BUFFER_OFFSET if src_buffer is a sub-buffer object and offset specified when the sub-buffer object is created is not aligned to CL_DEVICE_MEM_BASE_ADDR_ALIGN value for device associated with queue.
1188     //• CL_MISALIGNED_SUB_BUFFER_OFFSET if dst_buffer is a sub-buffer object and offset specified when the sub-buffer object is created is not aligned to CL_DEVICE_MEM_BASE_ADDR_ALIGN value for device associated with queue.
1189     //• CL_MEM_OBJECT_ALLOCATION_FAILURE if there is a failure to allocate memory for data store associated with src_buffer or dst_buffer.
1190 }
1191 
1192 #[cl_entrypoint]
enqueue_read_buffer_rect( command_queue: cl_command_queue, buffer: cl_mem, blocking_read: cl_bool, buffer_origin: *const usize, host_origin: *const usize, region: *const usize, mut buffer_row_pitch: usize, mut buffer_slice_pitch: usize, mut host_row_pitch: usize, mut host_slice_pitch: usize, ptr: *mut ::std::os::raw::c_void, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>1193 fn enqueue_read_buffer_rect(
1194     command_queue: cl_command_queue,
1195     buffer: cl_mem,
1196     blocking_read: cl_bool,
1197     buffer_origin: *const usize,
1198     host_origin: *const usize,
1199     region: *const usize,
1200     mut buffer_row_pitch: usize,
1201     mut buffer_slice_pitch: usize,
1202     mut host_row_pitch: usize,
1203     mut host_slice_pitch: usize,
1204     ptr: *mut ::std::os::raw::c_void,
1205     num_events_in_wait_list: cl_uint,
1206     event_wait_list: *const cl_event,
1207     event: *mut cl_event,
1208 ) -> CLResult<()> {
1209     let block = check_cl_bool(blocking_read).ok_or(CL_INVALID_VALUE)?;
1210     let q = Queue::arc_from_raw(command_queue)?;
1211     let buf = Buffer::arc_from_raw(buffer)?;
1212     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
1213 
1214     // CL_INVALID_OPERATION if clEnqueueReadBufferRect is called on buffer which has been created
1215     // with CL_MEM_HOST_WRITE_ONLY or CL_MEM_HOST_NO_ACCESS.
1216     if bit_check(buf.flags, CL_MEM_HOST_WRITE_ONLY | CL_MEM_HOST_NO_ACCESS) {
1217         return Err(CL_INVALID_OPERATION);
1218     }
1219 
1220     // CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST if the read and write operations are blocking
1221     // and the execution status of any of the events in event_wait_list is a negative integer value.
1222     if block && evs.iter().any(|e| e.is_error()) {
1223         return Err(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
1224     }
1225 
1226     // CL_INVALID_VALUE if buffer_origin, host_origin, or region is NULL.
1227     if buffer_origin.is_null() ||
1228       host_origin.is_null() ||
1229       region.is_null() ||
1230       // CL_INVALID_VALUE if ptr is NULL.
1231       ptr.is_null()
1232     {
1233         return Err(CL_INVALID_VALUE);
1234     }
1235 
1236     let r = unsafe { CLVec::from_raw(region) };
1237     let buf_ori = unsafe { CLVec::from_raw(buffer_origin) };
1238     let host_ori = unsafe { CLVec::from_raw(host_origin) };
1239 
1240     // CL_INVALID_VALUE if any region array element is 0.
1241     if r.contains(&0) ||
1242       // CL_INVALID_VALUE if buffer_row_pitch is not 0 and is less than region[0].
1243       buffer_row_pitch != 0 && buffer_row_pitch < r[0] ||
1244       // CL_INVALID_VALUE if host_row_pitch is not 0 and is less than region[0].
1245       host_row_pitch != 0 && host_row_pitch < r[0]
1246     {
1247         return Err(CL_INVALID_VALUE);
1248     }
1249 
1250     // If buffer_row_pitch is 0, buffer_row_pitch is computed as region[0].
1251     if buffer_row_pitch == 0 {
1252         buffer_row_pitch = r[0];
1253     }
1254 
1255     // If host_row_pitch is 0, host_row_pitch is computed as region[0].
1256     if host_row_pitch == 0 {
1257         host_row_pitch = r[0];
1258     }
1259 
1260     // CL_INVALID_VALUE if buffer_slice_pitch is not 0 and is less than region[1] × buffer_row_pitch and not a multiple of buffer_row_pitch.
1261     if buffer_slice_pitch != 0 && buffer_slice_pitch < r[1] * buffer_row_pitch && buffer_slice_pitch % buffer_row_pitch != 0 ||
1262       // CL_INVALID_VALUE if host_slice_pitch is not 0 and is less than region[1] × host_row_pitch and not a multiple of host_row_pitch.
1263       host_slice_pitch != 0 && host_slice_pitch < r[1] * host_row_pitch && host_slice_pitch % host_row_pitch != 0
1264     {
1265         return Err(CL_INVALID_VALUE);
1266     }
1267 
1268     // If buffer_slice_pitch is 0, buffer_slice_pitch is computed as region[1] × buffer_row_pitch.
1269     if buffer_slice_pitch == 0 {
1270         buffer_slice_pitch = r[1] * buffer_row_pitch;
1271     }
1272 
1273     // If host_slice_pitch is 0, host_slice_pitch is computed as region[1] × host_row_pitch.
1274     if host_slice_pitch == 0 {
1275         host_slice_pitch = r[1] * host_row_pitch
1276     }
1277 
1278     // CL_INVALID_VALUE if the region being read or written specified by (buffer_origin, region,
1279     // buffer_row_pitch, buffer_slice_pitch) is out of bounds.
1280     if CLVec::calc_size(r + buf_ori, [1, buffer_row_pitch, buffer_slice_pitch]) > buf.size {
1281         return Err(CL_INVALID_VALUE);
1282     }
1283 
1284     // CL_INVALID_CONTEXT if the context associated with command_queue and buffer are not the same
1285     if q.context != buf.context {
1286         return Err(CL_INVALID_CONTEXT);
1287     }
1288 
1289     // SAFETY: it's required that applications do not cause data races
1290     let ptr = unsafe { MutMemoryPtr::from_ptr(ptr) };
1291     create_and_queue(
1292         q,
1293         CL_COMMAND_READ_BUFFER_RECT,
1294         evs,
1295         event,
1296         block,
1297         Box::new(move |q, ctx| {
1298             buf.read_rect(
1299                 ptr,
1300                 q,
1301                 ctx,
1302                 &r,
1303                 &buf_ori,
1304                 buffer_row_pitch,
1305                 buffer_slice_pitch,
1306                 &host_ori,
1307                 host_row_pitch,
1308                 host_slice_pitch,
1309             )
1310         }),
1311     )
1312 
1313     // TODO
1314     // CL_MISALIGNED_SUB_BUFFER_OFFSET if buffer is a sub-buffer object and offset specified when the sub-buffer object is created is not aligned to CL_DEVICE_MEM_BASE_ADDR_ALIGN value for device associated with queue.
1315 }
1316 
1317 #[cl_entrypoint]
enqueue_write_buffer_rect( command_queue: cl_command_queue, buffer: cl_mem, blocking_write: cl_bool, buffer_origin: *const usize, host_origin: *const usize, region: *const usize, mut buffer_row_pitch: usize, mut buffer_slice_pitch: usize, mut host_row_pitch: usize, mut host_slice_pitch: usize, ptr: *const ::std::os::raw::c_void, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>1318 fn enqueue_write_buffer_rect(
1319     command_queue: cl_command_queue,
1320     buffer: cl_mem,
1321     blocking_write: cl_bool,
1322     buffer_origin: *const usize,
1323     host_origin: *const usize,
1324     region: *const usize,
1325     mut buffer_row_pitch: usize,
1326     mut buffer_slice_pitch: usize,
1327     mut host_row_pitch: usize,
1328     mut host_slice_pitch: usize,
1329     ptr: *const ::std::os::raw::c_void,
1330     num_events_in_wait_list: cl_uint,
1331     event_wait_list: *const cl_event,
1332     event: *mut cl_event,
1333 ) -> CLResult<()> {
1334     let block = check_cl_bool(blocking_write).ok_or(CL_INVALID_VALUE)?;
1335     let q = Queue::arc_from_raw(command_queue)?;
1336     let buf = Buffer::arc_from_raw(buffer)?;
1337     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
1338 
1339     // CL_INVALID_OPERATION if clEnqueueWriteBufferRect is called on buffer which has been created
1340     // with CL_MEM_HOST_READ_ONLY or CL_MEM_HOST_NO_ACCESS.
1341     if bit_check(buf.flags, CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_NO_ACCESS) {
1342         return Err(CL_INVALID_OPERATION);
1343     }
1344 
1345     // CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST if the read and write operations are blocking
1346     // and the execution status of any of the events in event_wait_list is a negative integer value.
1347     if block && evs.iter().any(|e| e.is_error()) {
1348         return Err(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
1349     }
1350 
1351     // CL_INVALID_VALUE if buffer_origin, host_origin, or region is NULL.
1352     if buffer_origin.is_null() ||
1353       host_origin.is_null() ||
1354       region.is_null() ||
1355       // CL_INVALID_VALUE if ptr is NULL.
1356       ptr.is_null()
1357     {
1358         return Err(CL_INVALID_VALUE);
1359     }
1360 
1361     let r = unsafe { CLVec::from_raw(region) };
1362     let buf_ori = unsafe { CLVec::from_raw(buffer_origin) };
1363     let host_ori = unsafe { CLVec::from_raw(host_origin) };
1364 
1365     // CL_INVALID_VALUE if any region array element is 0.
1366     if r.contains(&0) ||
1367       // CL_INVALID_VALUE if buffer_row_pitch is not 0 and is less than region[0].
1368       buffer_row_pitch != 0 && buffer_row_pitch < r[0] ||
1369       // CL_INVALID_VALUE if host_row_pitch is not 0 and is less than region[0].
1370       host_row_pitch != 0 && host_row_pitch < r[0]
1371     {
1372         return Err(CL_INVALID_VALUE);
1373     }
1374 
1375     // If buffer_row_pitch is 0, buffer_row_pitch is computed as region[0].
1376     if buffer_row_pitch == 0 {
1377         buffer_row_pitch = r[0];
1378     }
1379 
1380     // If host_row_pitch is 0, host_row_pitch is computed as region[0].
1381     if host_row_pitch == 0 {
1382         host_row_pitch = r[0];
1383     }
1384 
1385     // CL_INVALID_VALUE if buffer_slice_pitch is not 0 and is less than region[1] × buffer_row_pitch and not a multiple of buffer_row_pitch.
1386     if buffer_slice_pitch != 0 && buffer_slice_pitch < r[1] * buffer_row_pitch && buffer_slice_pitch % buffer_row_pitch != 0 ||
1387       // CL_INVALID_VALUE if host_slice_pitch is not 0 and is less than region[1] × host_row_pitch and not a multiple of host_row_pitch.
1388       host_slice_pitch != 0 && host_slice_pitch < r[1] * host_row_pitch && host_slice_pitch % host_row_pitch != 0
1389     {
1390         return Err(CL_INVALID_VALUE);
1391     }
1392 
1393     // If buffer_slice_pitch is 0, buffer_slice_pitch is computed as region[1] × buffer_row_pitch.
1394     if buffer_slice_pitch == 0 {
1395         buffer_slice_pitch = r[1] * buffer_row_pitch;
1396     }
1397 
1398     // If host_slice_pitch is 0, host_slice_pitch is computed as region[1] × host_row_pitch.
1399     if host_slice_pitch == 0 {
1400         host_slice_pitch = r[1] * host_row_pitch
1401     }
1402 
1403     // CL_INVALID_VALUE if the region being read or written specified by (buffer_origin, region,
1404     // buffer_row_pitch, buffer_slice_pitch) is out of bounds.
1405     if CLVec::calc_size(r + buf_ori, [1, buffer_row_pitch, buffer_slice_pitch]) > buf.size {
1406         return Err(CL_INVALID_VALUE);
1407     }
1408 
1409     // CL_INVALID_CONTEXT if the context associated with command_queue and buffer are not the same
1410     if q.context != buf.context {
1411         return Err(CL_INVALID_CONTEXT);
1412     }
1413 
1414     // SAFETY: it's required that applications do not cause data races
1415     let ptr = unsafe { ConstMemoryPtr::from_ptr(ptr) };
1416     create_and_queue(
1417         q,
1418         CL_COMMAND_WRITE_BUFFER_RECT,
1419         evs,
1420         event,
1421         block,
1422         Box::new(move |q, ctx| {
1423             buf.write_rect(
1424                 ptr,
1425                 q,
1426                 ctx,
1427                 &r,
1428                 &host_ori,
1429                 host_row_pitch,
1430                 host_slice_pitch,
1431                 &buf_ori,
1432                 buffer_row_pitch,
1433                 buffer_slice_pitch,
1434             )
1435         }),
1436     )
1437 
1438     // TODO
1439     // CL_MISALIGNED_SUB_BUFFER_OFFSET if buffer is a sub-buffer object and offset specified when the sub-buffer object is created is not aligned to CL_DEVICE_MEM_BASE_ADDR_ALIGN value for device associated with queue.
1440 }
1441 
1442 #[cl_entrypoint]
enqueue_copy_buffer_rect( command_queue: cl_command_queue, src_buffer: cl_mem, dst_buffer: cl_mem, src_origin: *const usize, dst_origin: *const usize, region: *const usize, mut src_row_pitch: usize, mut src_slice_pitch: usize, mut dst_row_pitch: usize, mut dst_slice_pitch: usize, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>1443 fn enqueue_copy_buffer_rect(
1444     command_queue: cl_command_queue,
1445     src_buffer: cl_mem,
1446     dst_buffer: cl_mem,
1447     src_origin: *const usize,
1448     dst_origin: *const usize,
1449     region: *const usize,
1450     mut src_row_pitch: usize,
1451     mut src_slice_pitch: usize,
1452     mut dst_row_pitch: usize,
1453     mut dst_slice_pitch: usize,
1454     num_events_in_wait_list: cl_uint,
1455     event_wait_list: *const cl_event,
1456     event: *mut cl_event,
1457 ) -> CLResult<()> {
1458     let q = Queue::arc_from_raw(command_queue)?;
1459     let src = Buffer::arc_from_raw(src_buffer)?;
1460     let dst = Buffer::arc_from_raw(dst_buffer)?;
1461     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
1462 
1463     // CL_INVALID_VALUE if src_origin, dst_origin, or region is NULL.
1464     if src_origin.is_null() || dst_origin.is_null() || region.is_null() {
1465         return Err(CL_INVALID_VALUE);
1466     }
1467 
1468     let r = unsafe { CLVec::from_raw(region) };
1469     let src_ori = unsafe { CLVec::from_raw(src_origin) };
1470     let dst_ori = unsafe { CLVec::from_raw(dst_origin) };
1471 
1472     // CL_INVALID_VALUE if any region array element is 0.
1473     if r.contains(&0) ||
1474       // CL_INVALID_VALUE if src_row_pitch is not 0 and is less than region[0].
1475       src_row_pitch != 0 && src_row_pitch < r[0] ||
1476       // CL_INVALID_VALUE if dst_row_pitch is not 0 and is less than region[0].
1477       dst_row_pitch != 0 && dst_row_pitch < r[0]
1478     {
1479         return Err(CL_INVALID_VALUE);
1480     }
1481 
1482     // If src_row_pitch is 0, src_row_pitch is computed as region[0].
1483     if src_row_pitch == 0 {
1484         src_row_pitch = r[0];
1485     }
1486 
1487     // If dst_row_pitch is 0, dst_row_pitch is computed as region[0].
1488     if dst_row_pitch == 0 {
1489         dst_row_pitch = r[0];
1490     }
1491 
1492     // CL_INVALID_VALUE if src_slice_pitch is not 0 and is less than region[1] × src_row_pitch
1493     if src_slice_pitch != 0 && src_slice_pitch < r[1] * src_row_pitch ||
1494       // CL_INVALID_VALUE if dst_slice_pitch is not 0 and is less than region[1] × dst_row_pitch
1495       dst_slice_pitch != 0 && dst_slice_pitch < r[1] * dst_row_pitch ||
1496       // if src_slice_pitch is not 0 and is not a multiple of src_row_pitch.
1497       src_slice_pitch != 0 && src_slice_pitch % src_row_pitch != 0 ||
1498       // if dst_slice_pitch is not 0 and is not a multiple of dst_row_pitch.
1499       dst_slice_pitch != 0 && dst_slice_pitch % dst_row_pitch != 0
1500     {
1501         return Err(CL_INVALID_VALUE);
1502     }
1503 
1504     // If src_slice_pitch is 0, src_slice_pitch is computed as region[1] × src_row_pitch.
1505     if src_slice_pitch == 0 {
1506         src_slice_pitch = r[1] * src_row_pitch;
1507     }
1508 
1509     // If dst_slice_pitch is 0, dst_slice_pitch is computed as region[1] × dst_row_pitch.
1510     if dst_slice_pitch == 0 {
1511         dst_slice_pitch = r[1] * dst_row_pitch;
1512     }
1513 
1514     // CL_INVALID_VALUE if src_buffer and dst_buffer are the same buffer object and src_slice_pitch
1515     // is not equal to dst_slice_pitch and src_row_pitch is not equal to dst_row_pitch.
1516     if src_buffer == dst_buffer
1517         && src_slice_pitch != dst_slice_pitch
1518         && src_row_pitch != dst_row_pitch
1519     {
1520         return Err(CL_INVALID_VALUE);
1521     }
1522 
1523     // CL_INVALID_VALUE if (src_origin, region, src_row_pitch, src_slice_pitch) or (dst_origin,
1524     // region, dst_row_pitch, dst_slice_pitch) require accessing elements outside the src_buffer
1525     // and dst_buffer buffer objects respectively.
1526     if CLVec::calc_size(r + src_ori, [1, src_row_pitch, src_slice_pitch]) > src.size
1527         || CLVec::calc_size(r + dst_ori, [1, dst_row_pitch, dst_slice_pitch]) > dst.size
1528     {
1529         return Err(CL_INVALID_VALUE);
1530     }
1531 
1532     // CL_MEM_COPY_OVERLAP if src_buffer and dst_buffer are the same buffer or sub-buffer object and
1533     // the source and destination regions overlap or if src_buffer and dst_buffer are different
1534     // sub-buffers of the same associated buffer object and they overlap.
1535     if src.has_same_parent(&dst)
1536         && check_copy_overlap(
1537             &src_ori,
1538             src.offset,
1539             &dst_ori,
1540             dst.offset,
1541             &r,
1542             src_row_pitch,
1543             src_slice_pitch,
1544         )
1545     {
1546         return Err(CL_MEM_COPY_OVERLAP);
1547     }
1548 
1549     // CL_INVALID_CONTEXT if the context associated with command_queue, src_buffer and dst_buffer
1550     // are not the same
1551     if src.context != q.context || dst.context != q.context {
1552         return Err(CL_INVALID_CONTEXT);
1553     }
1554 
1555     create_and_queue(
1556         q,
1557         CL_COMMAND_COPY_BUFFER_RECT,
1558         evs,
1559         event,
1560         false,
1561         Box::new(move |q, ctx| {
1562             src.copy_rect(
1563                 &dst,
1564                 q,
1565                 ctx,
1566                 &r,
1567                 &src_ori,
1568                 src_row_pitch,
1569                 src_slice_pitch,
1570                 &dst_ori,
1571                 dst_row_pitch,
1572                 dst_slice_pitch,
1573             )
1574         }),
1575     )
1576 
1577     // TODO
1578     // CL_MISALIGNED_SUB_BUFFER_OFFSET if src_buffer is a sub-buffer object and offset specified when the sub-buffer object is created is not aligned to CL_DEVICE_MEM_BASE_ADDR_ALIGN value for device associated with queue.
1579 }
1580 
1581 #[cl_entrypoint]
enqueue_fill_buffer( command_queue: cl_command_queue, buffer: cl_mem, pattern: *const ::std::os::raw::c_void, pattern_size: usize, offset: usize, size: usize, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>1582 fn enqueue_fill_buffer(
1583     command_queue: cl_command_queue,
1584     buffer: cl_mem,
1585     pattern: *const ::std::os::raw::c_void,
1586     pattern_size: usize,
1587     offset: usize,
1588     size: usize,
1589     num_events_in_wait_list: cl_uint,
1590     event_wait_list: *const cl_event,
1591     event: *mut cl_event,
1592 ) -> CLResult<()> {
1593     let q = Queue::arc_from_raw(command_queue)?;
1594     let b = Buffer::arc_from_raw(buffer)?;
1595     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
1596 
1597     // CL_INVALID_VALUE if offset or offset + size require accessing elements outside the buffer
1598     // buffer object respectively.
1599     if offset + size > b.size {
1600         return Err(CL_INVALID_VALUE);
1601     }
1602 
1603     // CL_INVALID_VALUE if pattern is NULL or if pattern_size is 0 or if pattern_size is not one of
1604     // { 1, 2, 4, 8, 16, 32, 64, 128 }.
1605     if pattern.is_null() || pattern_size.count_ones() != 1 || pattern_size > 128 {
1606         return Err(CL_INVALID_VALUE);
1607     }
1608 
1609     // CL_INVALID_VALUE if offset and size are not a multiple of pattern_size.
1610     if offset % pattern_size != 0 || size % pattern_size != 0 {
1611         return Err(CL_INVALID_VALUE);
1612     }
1613 
1614     // CL_INVALID_CONTEXT if the context associated with command_queue and buffer are not the same
1615     if b.context != q.context {
1616         return Err(CL_INVALID_CONTEXT);
1617     }
1618 
1619     // we have to copy memory
1620     let pattern = unsafe { slice::from_raw_parts(pattern.cast(), pattern_size).to_vec() };
1621     create_and_queue(
1622         q,
1623         CL_COMMAND_FILL_BUFFER,
1624         evs,
1625         event,
1626         false,
1627         Box::new(move |q, ctx| b.fill(q, ctx, &pattern, offset, size)),
1628     )
1629 
1630     // TODO
1631     //• CL_MISALIGNED_SUB_BUFFER_OFFSET if buffer is a sub-buffer object and offset specified when the sub-buffer object is created is not aligned to CL_DEVICE_MEM_BASE_ADDR_ALIGN value for device associated with queue.
1632     //• CL_MEM_OBJECT_ALLOCATION_FAILURE if there is a failure to allocate memory for data store associated with buffer.
1633 }
1634 
1635 #[cl_entrypoint]
enqueue_map_buffer( command_queue: cl_command_queue, buffer: cl_mem, blocking_map: cl_bool, map_flags: cl_map_flags, offset: usize, size: usize, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<*mut c_void>1636 fn enqueue_map_buffer(
1637     command_queue: cl_command_queue,
1638     buffer: cl_mem,
1639     blocking_map: cl_bool,
1640     map_flags: cl_map_flags,
1641     offset: usize,
1642     size: usize,
1643     num_events_in_wait_list: cl_uint,
1644     event_wait_list: *const cl_event,
1645     event: *mut cl_event,
1646 ) -> CLResult<*mut c_void> {
1647     let q = Queue::arc_from_raw(command_queue)?;
1648     let b = Buffer::arc_from_raw(buffer)?;
1649     let block = check_cl_bool(blocking_map).ok_or(CL_INVALID_VALUE)?;
1650     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
1651 
1652     validate_map_flags(&b, map_flags)?;
1653 
1654     // CL_INVALID_VALUE if region being mapped given by (offset, size) is out of bounds or if size
1655     // is 0
1656     if offset + size > b.size || size == 0 {
1657         return Err(CL_INVALID_VALUE);
1658     }
1659 
1660     // CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST if the map operation is blocking and the
1661     // execution status of any of the events in event_wait_list is a negative integer value.
1662     if block && evs.iter().any(|e| e.is_error()) {
1663         return Err(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
1664     }
1665 
1666     // CL_INVALID_CONTEXT if context associated with command_queue and buffer are not the same
1667     if b.context != q.context {
1668         return Err(CL_INVALID_CONTEXT);
1669     }
1670 
1671     let ptr = b.map(q.device, offset)?;
1672     create_and_queue(
1673         q,
1674         CL_COMMAND_MAP_BUFFER,
1675         evs,
1676         event,
1677         block,
1678         Box::new(move |q, ctx| b.sync_shadow(q, ctx, ptr)),
1679     )?;
1680 
1681     Ok(ptr.as_ptr())
1682 
1683     // TODO
1684     // CL_MISALIGNED_SUB_BUFFER_OFFSET if buffer is a sub-buffer object and offset specified when the sub-buffer object is created is not aligned to CL_DEVICE_MEM_BASE_ADDR_ALIGN value for the device associated with queue. This error code is missing before version 1.1.
1685     // CL_MAP_FAILURE if there is a failure to map the requested region into the host address space. This error cannot occur for buffer objects created with CL_MEM_USE_HOST_PTR or CL_MEM_ALLOC_HOST_PTR.
1686     // CL_INVALID_OPERATION if mapping would lead to overlapping regions being mapped for writing.
1687 }
1688 
1689 #[cl_entrypoint]
enqueue_read_image( command_queue: cl_command_queue, image: cl_mem, blocking_read: cl_bool, origin: *const usize, region: *const usize, mut row_pitch: usize, mut slice_pitch: usize, ptr: *mut ::std::os::raw::c_void, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>1690 fn enqueue_read_image(
1691     command_queue: cl_command_queue,
1692     image: cl_mem,
1693     blocking_read: cl_bool,
1694     origin: *const usize,
1695     region: *const usize,
1696     mut row_pitch: usize,
1697     mut slice_pitch: usize,
1698     ptr: *mut ::std::os::raw::c_void,
1699     num_events_in_wait_list: cl_uint,
1700     event_wait_list: *const cl_event,
1701     event: *mut cl_event,
1702 ) -> CLResult<()> {
1703     let q = Queue::arc_from_raw(command_queue)?;
1704     let i = Image::arc_from_raw(image)?;
1705     let block = check_cl_bool(blocking_read).ok_or(CL_INVALID_VALUE)?;
1706     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
1707     let pixel_size = i.image_format.pixel_size().unwrap() as usize;
1708 
1709     // CL_INVALID_CONTEXT if the context associated with command_queue and image are not the same
1710     if i.context != q.context {
1711         return Err(CL_INVALID_CONTEXT);
1712     }
1713 
1714     // CL_INVALID_OPERATION if clEnqueueReadImage is called on image which has been created with
1715     // CL_MEM_HOST_WRITE_ONLY or CL_MEM_HOST_NO_ACCESS.
1716     if bit_check(i.flags, CL_MEM_HOST_WRITE_ONLY | CL_MEM_HOST_NO_ACCESS) {
1717         return Err(CL_INVALID_OPERATION);
1718     }
1719 
1720     // CL_INVALID_VALUE if origin or region is NULL.
1721     // CL_INVALID_VALUE if ptr is NULL.
1722     if origin.is_null() || region.is_null() || ptr.is_null() {
1723         return Err(CL_INVALID_VALUE);
1724     }
1725 
1726     // CL_INVALID_VALUE if image is a 1D or 2D image and slice_pitch or input_slice_pitch is not 0.
1727     if !i.image_desc.has_slice() && slice_pitch != 0 {
1728         return Err(CL_INVALID_VALUE);
1729     }
1730 
1731     let r = unsafe { CLVec::from_raw(region) };
1732     let o = unsafe { CLVec::from_raw(origin) };
1733 
1734     // CL_INVALID_VALUE if the region being read or written specified by origin and region is out of
1735     // bounds.
1736     // CL_INVALID_VALUE if values in origin and region do not follow rules described in the argument
1737     // description for origin and region.
1738     validate_image_bounds(&i, o, r)?;
1739 
1740     // If row_pitch (or input_row_pitch) is set to 0, the appropriate row pitch is calculated based
1741     // on the size of each element in bytes multiplied by width.
1742     if row_pitch == 0 {
1743         row_pitch = r[0] * pixel_size;
1744     }
1745 
1746     // If slice_pitch (or input_slice_pitch) is set to 0, the appropriate slice pitch is calculated
1747     // based on the row_pitch × height.
1748     if slice_pitch == 0 {
1749         slice_pitch = row_pitch * r[1];
1750     }
1751 
1752     // SAFETY: it's required that applications do not cause data races
1753     let ptr = unsafe { MutMemoryPtr::from_ptr(ptr) };
1754     create_and_queue(
1755         q,
1756         CL_COMMAND_READ_IMAGE,
1757         evs,
1758         event,
1759         block,
1760         Box::new(move |q, ctx| i.read(ptr, q, ctx, &r, &o, row_pitch, slice_pitch)),
1761     )
1762 
1763     //• CL_INVALID_IMAGE_SIZE if image dimensions (image width, height, specified or compute row and/or slice pitch) for image are not supported by device associated with queue.
1764     //• CL_IMAGE_FORMAT_NOT_SUPPORTED if image format (image channel order and data type) for image are not supported by device associated with queue.
1765     //• CL_INVALID_OPERATION if the device associated with command_queue does not support images (i.e. CL_DEVICE_IMAGE_SUPPORT specified in the Device Queries table is CL_FALSE).
1766     //• CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST if the read and write operations are blocking and the execution status of any of the events in event_wait_list is a negative integer value.
1767 }
1768 
1769 #[cl_entrypoint]
enqueue_write_image( command_queue: cl_command_queue, image: cl_mem, blocking_write: cl_bool, origin: *const usize, region: *const usize, mut row_pitch: usize, mut slice_pitch: usize, ptr: *const ::std::os::raw::c_void, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>1770 fn enqueue_write_image(
1771     command_queue: cl_command_queue,
1772     image: cl_mem,
1773     blocking_write: cl_bool,
1774     origin: *const usize,
1775     region: *const usize,
1776     mut row_pitch: usize,
1777     mut slice_pitch: usize,
1778     ptr: *const ::std::os::raw::c_void,
1779     num_events_in_wait_list: cl_uint,
1780     event_wait_list: *const cl_event,
1781     event: *mut cl_event,
1782 ) -> CLResult<()> {
1783     let q = Queue::arc_from_raw(command_queue)?;
1784     let i = Image::arc_from_raw(image)?;
1785     let block = check_cl_bool(blocking_write).ok_or(CL_INVALID_VALUE)?;
1786     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
1787     let pixel_size = i.image_format.pixel_size().unwrap() as usize;
1788 
1789     // CL_INVALID_CONTEXT if the context associated with command_queue and image are not the same
1790     if i.context != q.context {
1791         return Err(CL_INVALID_CONTEXT);
1792     }
1793 
1794     // CL_INVALID_OPERATION if clEnqueueWriteImage is called on image which has been created with
1795     // CL_MEM_HOST_READ_ONLY or CL_MEM_HOST_NO_ACCESS.
1796     if bit_check(i.flags, CL_MEM_HOST_READ_ONLY | CL_MEM_HOST_NO_ACCESS) {
1797         return Err(CL_INVALID_OPERATION);
1798     }
1799 
1800     // CL_INVALID_VALUE if origin or region is NULL.
1801     // CL_INVALID_VALUE if ptr is NULL.
1802     if origin.is_null() || region.is_null() || ptr.is_null() {
1803         return Err(CL_INVALID_VALUE);
1804     }
1805 
1806     // CL_INVALID_VALUE if image is a 1D or 2D image and slice_pitch or input_slice_pitch is not 0.
1807     if !i.image_desc.has_slice() && slice_pitch != 0 {
1808         return Err(CL_INVALID_VALUE);
1809     }
1810 
1811     let r = unsafe { CLVec::from_raw(region) };
1812     let o = unsafe { CLVec::from_raw(origin) };
1813 
1814     // CL_INVALID_VALUE if the region being read or written specified by origin and region is out of
1815     // bounds.
1816     // CL_INVALID_VALUE if values in origin and region do not follow rules described in the argument
1817     // description for origin and region.
1818     validate_image_bounds(&i, o, r)?;
1819 
1820     // If row_pitch (or input_row_pitch) is set to 0, the appropriate row pitch is calculated based
1821     // on the size of each element in bytes multiplied by width.
1822     if row_pitch == 0 {
1823         row_pitch = r[0] * pixel_size;
1824     }
1825 
1826     // If slice_pitch (or input_slice_pitch) is set to 0, the appropriate slice pitch is calculated
1827     // based on the row_pitch × height.
1828     if slice_pitch == 0 {
1829         slice_pitch = row_pitch * r[1];
1830     }
1831 
1832     // SAFETY: it's required that applications do not cause data races
1833     let ptr = unsafe { ConstMemoryPtr::from_ptr(ptr) };
1834     create_and_queue(
1835         q,
1836         CL_COMMAND_WRITE_BUFFER_RECT,
1837         evs,
1838         event,
1839         block,
1840         Box::new(move |q, ctx| i.write(ptr, q, ctx, &r, row_pitch, slice_pitch, &o)),
1841     )
1842 
1843     //• CL_INVALID_IMAGE_SIZE if image dimensions (image width, height, specified or compute row and/or slice pitch) for image are not supported by device associated with queue.
1844     //• CL_IMAGE_FORMAT_NOT_SUPPORTED if image format (image channel order and data type) for image are not supported by device associated with queue.
1845     //• CL_INVALID_OPERATION if the device associated with command_queue does not support images (i.e. CL_DEVICE_IMAGE_SUPPORT specified in the Device Queries table is CL_FALSE).
1846     //• CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST if the read and write operations are blocking and the execution status of any of the events in event_wait_list is a negative integer value.
1847 }
1848 
1849 #[cl_entrypoint]
enqueue_copy_image( command_queue: cl_command_queue, src_image: cl_mem, dst_image: cl_mem, src_origin: *const usize, dst_origin: *const usize, region: *const usize, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>1850 fn enqueue_copy_image(
1851     command_queue: cl_command_queue,
1852     src_image: cl_mem,
1853     dst_image: cl_mem,
1854     src_origin: *const usize,
1855     dst_origin: *const usize,
1856     region: *const usize,
1857     num_events_in_wait_list: cl_uint,
1858     event_wait_list: *const cl_event,
1859     event: *mut cl_event,
1860 ) -> CLResult<()> {
1861     let q = Queue::arc_from_raw(command_queue)?;
1862     let src_image = Image::arc_from_raw(src_image)?;
1863     let dst_image = Image::arc_from_raw(dst_image)?;
1864     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
1865 
1866     // CL_INVALID_CONTEXT if the context associated with command_queue, src_image and dst_image are not the same
1867     if src_image.context != q.context || dst_image.context != q.context {
1868         return Err(CL_INVALID_CONTEXT);
1869     }
1870 
1871     // CL_IMAGE_FORMAT_MISMATCH if src_image and dst_image do not use the same image format.
1872     if src_image.image_format != dst_image.image_format {
1873         return Err(CL_IMAGE_FORMAT_MISMATCH);
1874     }
1875 
1876     // CL_INVALID_VALUE if src_origin, dst_origin, or region is NULL.
1877     if src_origin.is_null() || dst_origin.is_null() || region.is_null() {
1878         return Err(CL_INVALID_VALUE);
1879     }
1880 
1881     let region = unsafe { CLVec::from_raw(region) };
1882     let dst_origin = unsafe { CLVec::from_raw(dst_origin) };
1883     let src_origin = unsafe { CLVec::from_raw(src_origin) };
1884 
1885     // CL_INVALID_VALUE if the 2D or 3D rectangular region specified by src_origin and
1886     // src_origin + region refers to a region outside src_image, or if the 2D or 3D rectangular
1887     // region specified by dst_origin and dst_origin + region refers to a region outside dst_image.
1888     // CL_INVALID_VALUE if values in src_origin, dst_origin and region do not follow rules described
1889     // in the argument description for src_origin, dst_origin and region.
1890     validate_image_bounds(&src_image, src_origin, region)?;
1891     validate_image_bounds(&dst_image, dst_origin, region)?;
1892 
1893     create_and_queue(
1894         q,
1895         CL_COMMAND_COPY_IMAGE,
1896         evs,
1897         event,
1898         false,
1899         Box::new(move |q, ctx| {
1900             src_image.copy_to_image(q, ctx, &dst_image, src_origin, dst_origin, &region)
1901         }),
1902     )
1903 
1904     //• CL_INVALID_IMAGE_SIZE if image dimensions (image width, height, specified or compute row and/or slice pitch) for src_image or dst_image are not supported by device associated with queue.
1905     //• CL_IMAGE_FORMAT_NOT_SUPPORTED if image format (image channel order and data type) for src_image or dst_image are not supported by device associated with queue.
1906     //• CL_INVALID_OPERATION if the device associated with command_queue does not support images (i.e. CL_DEVICE_IMAGE_SUPPORT specified in the Device Queries table is CL_FALSE).
1907     //• CL_MEM_COPY_OVERLAP if src_image and dst_image are the same image object and the source and destination regions overlap.
1908 }
1909 
1910 #[cl_entrypoint]
enqueue_fill_image( command_queue: cl_command_queue, image: cl_mem, fill_color: *const ::std::os::raw::c_void, origin: *const [usize; 3], region: *const [usize; 3], num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>1911 fn enqueue_fill_image(
1912     command_queue: cl_command_queue,
1913     image: cl_mem,
1914     fill_color: *const ::std::os::raw::c_void,
1915     origin: *const [usize; 3],
1916     region: *const [usize; 3],
1917     num_events_in_wait_list: cl_uint,
1918     event_wait_list: *const cl_event,
1919     event: *mut cl_event,
1920 ) -> CLResult<()> {
1921     let q = Queue::arc_from_raw(command_queue)?;
1922     let i = Image::arc_from_raw(image)?;
1923     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
1924 
1925     // CL_INVALID_CONTEXT if the context associated with command_queue and image are not the same
1926     if i.context != q.context {
1927         return Err(CL_INVALID_CONTEXT);
1928     }
1929 
1930     // CL_INVALID_VALUE if fill_color is NULL.
1931     // CL_INVALID_VALUE if origin or region is NULL.
1932     if fill_color.is_null() || origin.is_null() || region.is_null() {
1933         return Err(CL_INVALID_VALUE);
1934     }
1935 
1936     let region = unsafe { CLVec::from_raw(region.cast()) };
1937     let origin = unsafe { CLVec::from_raw(origin.cast()) };
1938 
1939     // CL_INVALID_VALUE if the region being filled as specified by origin and region is out of
1940     // bounds.
1941     // CL_INVALID_VALUE if values in origin and region do not follow rules described in the argument
1942     // description for origin and region.
1943     validate_image_bounds(&i, origin, region)?;
1944 
1945     // we have to copy memory and it's always a 4 component int value
1946     // TODO but not for CL_DEPTH
1947     let fill_color = unsafe { slice::from_raw_parts(fill_color.cast(), 4).to_vec() };
1948     create_and_queue(
1949         q,
1950         CL_COMMAND_FILL_BUFFER,
1951         evs,
1952         event,
1953         false,
1954         Box::new(move |q, ctx| i.fill(q, ctx, &fill_color, &origin, &region)),
1955     )
1956 
1957     //• CL_INVALID_IMAGE_SIZE if image dimensions (image width, height, specified or compute row and/or slice pitch) for image are not supported by device associated with queue.
1958     //• CL_IMAGE_FORMAT_NOT_SUPPORTED if image format (image channel order and data type) for
1959     //image are not supported by device associated with queue.
1960 }
1961 
1962 #[cl_entrypoint]
enqueue_copy_buffer_to_image( command_queue: cl_command_queue, src_buffer: cl_mem, dst_image: cl_mem, src_offset: usize, dst_origin: *const usize, region: *const usize, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>1963 fn enqueue_copy_buffer_to_image(
1964     command_queue: cl_command_queue,
1965     src_buffer: cl_mem,
1966     dst_image: cl_mem,
1967     src_offset: usize,
1968     dst_origin: *const usize,
1969     region: *const usize,
1970     num_events_in_wait_list: cl_uint,
1971     event_wait_list: *const cl_event,
1972     event: *mut cl_event,
1973 ) -> CLResult<()> {
1974     let q = Queue::arc_from_raw(command_queue)?;
1975     let src = Buffer::arc_from_raw(src_buffer)?;
1976     let dst = Image::arc_from_raw(dst_image)?;
1977     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
1978 
1979     // CL_INVALID_CONTEXT if the context associated with command_queue, src_buffer and dst_image
1980     // are not the same
1981     if q.context != src.context || q.context != dst.context {
1982         return Err(CL_INVALID_CONTEXT);
1983     }
1984 
1985     // CL_INVALID_VALUE if dst_origin or region is NULL.
1986     if dst_origin.is_null() || region.is_null() {
1987         return Err(CL_INVALID_VALUE);
1988     }
1989 
1990     let region = unsafe { CLVec::from_raw(region) };
1991     let dst_origin = unsafe { CLVec::from_raw(dst_origin) };
1992 
1993     // CL_INVALID_VALUE if values in dst_origin and region do not follow rules described in the
1994     // argument description for dst_origin and region.
1995     // CL_INVALID_VALUE if the 1D, 2D or 3D rectangular region specified by dst_origin and
1996     // dst_origin + region refer to a region outside dst_image,
1997     validate_image_bounds(&dst, dst_origin, region)?;
1998 
1999     create_and_queue(
2000         q,
2001         CL_COMMAND_COPY_BUFFER_TO_IMAGE,
2002         evs,
2003         event,
2004         false,
2005         Box::new(move |q, ctx| src.copy_to_image(q, ctx, &dst, src_offset, dst_origin, &region)),
2006     )
2007 
2008     //• CL_INVALID_MEM_OBJECT if src_buffer is not a valid buffer object or dst_image is not a valid image object or if dst_image is a 1D image buffer object created from src_buffer.
2009     //• CL_INVALID_VALUE ... if the region specified by src_offset and src_offset + src_cb refer to a region outside src_buffer.
2010     //• CL_MISALIGNED_SUB_BUFFER_OFFSET if src_buffer is a sub-buffer object and offset specified when the sub-buffer object is created is not aligned to CL_DEVICE_MEM_BASE_ADDR_ALIGN value for device associated with queue.
2011     //• CL_INVALID_IMAGE_SIZE if image dimensions (image width, height, specified or compute row and/or slice pitch) for dst_image are not supported by device associated with queue.
2012     //• CL_IMAGE_FORMAT_NOT_SUPPORTED if image format (image channel order and data type) for dst_image are not supported by device associated with queue.
2013     //• CL_MEM_OBJECT_ALLOCATION_FAILURE if there is a failure to allocate memory for data store associated with src_buffer or dst_image.
2014     //• CL_INVALID_OPERATION if the device associated with command_queue does not support images (i.e. CL_DEVICE_IMAGE_SUPPORT specified in the Device Queries table is CL_FALSE).
2015 }
2016 
2017 #[cl_entrypoint]
enqueue_copy_image_to_buffer( command_queue: cl_command_queue, src_image: cl_mem, dst_buffer: cl_mem, src_origin: *const usize, region: *const usize, dst_offset: usize, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>2018 fn enqueue_copy_image_to_buffer(
2019     command_queue: cl_command_queue,
2020     src_image: cl_mem,
2021     dst_buffer: cl_mem,
2022     src_origin: *const usize,
2023     region: *const usize,
2024     dst_offset: usize,
2025     num_events_in_wait_list: cl_uint,
2026     event_wait_list: *const cl_event,
2027     event: *mut cl_event,
2028 ) -> CLResult<()> {
2029     let q = Queue::arc_from_raw(command_queue)?;
2030     let src = Image::arc_from_raw(src_image)?;
2031     let dst = Buffer::arc_from_raw(dst_buffer)?;
2032     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
2033 
2034     // CL_INVALID_CONTEXT if the context associated with command_queue, src_image and dst_buffer
2035     // are not the same
2036     if q.context != src.context || q.context != dst.context {
2037         return Err(CL_INVALID_CONTEXT);
2038     }
2039 
2040     // CL_INVALID_VALUE if src_origin or region is NULL.
2041     if src_origin.is_null() || region.is_null() {
2042         return Err(CL_INVALID_VALUE);
2043     }
2044 
2045     let region = unsafe { CLVec::from_raw(region) };
2046     let src_origin = unsafe { CLVec::from_raw(src_origin) };
2047 
2048     // CL_INVALID_VALUE if values in src_origin and region do not follow rules described in the
2049     // argument description for src_origin and region.
2050     // CL_INVALID_VALUE if the 1D, 2D or 3D rectangular region specified by src_origin and
2051     // src_origin + region refers to a region outside src_image, or if the region specified by
2052     // dst_offset and dst_offset + dst_cb to a region outside dst_buffer.
2053     validate_image_bounds(&src, src_origin, region)?;
2054 
2055     create_and_queue(
2056         q,
2057         CL_COMMAND_COPY_IMAGE_TO_BUFFER,
2058         evs,
2059         event,
2060         false,
2061         Box::new(move |q, ctx| src.copy_to_buffer(q, ctx, &dst, src_origin, dst_offset, &region)),
2062     )
2063 
2064     //• CL_INVALID_MEM_OBJECT if src_image is not a valid image object or dst_buffer is not a valid buffer object or if src_image is a 1D image buffer object created from dst_buffer.
2065     //• CL_INVALID_VALUE ... if the region specified by dst_offset and dst_offset + dst_cb to a region outside dst_buffer.
2066     //• CL_MISALIGNED_SUB_BUFFER_OFFSET if dst_buffer is a sub-buffer object and offset specified when the sub-buffer object is created is not aligned to CL_DEVICE_MEM_BASE_ADDR_ALIGN value for device associated with queue. This error code is missing before version 1.1.
2067     //• CL_INVALID_IMAGE_SIZE if image dimensions (image width, height, specified or compute row and/or slice pitch) for src_image are not supported by device associated with queue.
2068     //• CL_IMAGE_FORMAT_NOT_SUPPORTED if image format (image channel order and data type) for src_image are not supported by device associated with queue.
2069     //• CL_MEM_OBJECT_ALLOCATION_FAILURE if there is a failure to allocate memory for data store associated with src_image or dst_buffer.
2070     //• CL_INVALID_OPERATION if the device associated with command_queue does not support images (i.e. CL_DEVICE_IMAGE_SUPPORT specified in the Device Queries table is CL_FALSE).
2071 }
2072 
2073 #[cl_entrypoint]
enqueue_map_image( command_queue: cl_command_queue, image: cl_mem, blocking_map: cl_bool, map_flags: cl_map_flags, origin: *const usize, region: *const usize, image_row_pitch: *mut usize, image_slice_pitch: *mut usize, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<*mut ::std::os::raw::c_void>2074 fn enqueue_map_image(
2075     command_queue: cl_command_queue,
2076     image: cl_mem,
2077     blocking_map: cl_bool,
2078     map_flags: cl_map_flags,
2079     origin: *const usize,
2080     region: *const usize,
2081     image_row_pitch: *mut usize,
2082     image_slice_pitch: *mut usize,
2083     num_events_in_wait_list: cl_uint,
2084     event_wait_list: *const cl_event,
2085     event: *mut cl_event,
2086 ) -> CLResult<*mut ::std::os::raw::c_void> {
2087     let q = Queue::arc_from_raw(command_queue)?;
2088     let i = Image::arc_from_raw(image)?;
2089     let block = check_cl_bool(blocking_map).ok_or(CL_INVALID_VALUE)?;
2090     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
2091 
2092     // CL_INVALID_VALUE ... or if values specified in map_flags are not valid.
2093     validate_map_flags(&i, map_flags)?;
2094 
2095     // CL_INVALID_CONTEXT if context associated with command_queue and image are not the same
2096     if i.context != q.context {
2097         return Err(CL_INVALID_CONTEXT);
2098     }
2099 
2100     // CL_INVALID_VALUE if origin or region is NULL.
2101     // CL_INVALID_VALUE if image_row_pitch is NULL.
2102     if origin.is_null() || region.is_null() || image_row_pitch.is_null() {
2103         return Err(CL_INVALID_VALUE);
2104     }
2105 
2106     let region = unsafe { CLVec::from_raw(region) };
2107     let origin = unsafe { CLVec::from_raw(origin) };
2108 
2109     // CL_INVALID_VALUE if region being mapped given by (origin, origin + region) is out of bounds
2110     // CL_INVALID_VALUE if values in origin and region do not follow rules described in the argument
2111     // description for origin and region.
2112     validate_image_bounds(&i, origin, region)?;
2113 
2114     let mut dummy_slice_pitch: usize = 0;
2115     let image_slice_pitch = if image_slice_pitch.is_null() {
2116         // CL_INVALID_VALUE if image is a 3D image, 1D or 2D image array object and
2117         // image_slice_pitch is NULL.
2118         if i.image_desc.is_array() || i.image_desc.image_type == CL_MEM_OBJECT_IMAGE3D {
2119             return Err(CL_INVALID_VALUE);
2120         }
2121         &mut dummy_slice_pitch
2122     } else {
2123         unsafe { image_slice_pitch.as_mut().unwrap() }
2124     };
2125 
2126     let ptr = i.map(
2127         q.device,
2128         &origin,
2129         unsafe { image_row_pitch.as_mut().unwrap() },
2130         image_slice_pitch,
2131     )?;
2132 
2133     // SAFETY: it's required that applications do not cause data races
2134     let sync_ptr = unsafe { MutMemoryPtr::from_ptr(ptr) };
2135     create_and_queue(
2136         q,
2137         CL_COMMAND_MAP_IMAGE,
2138         evs,
2139         event,
2140         block,
2141         Box::new(move |q, ctx| i.sync_shadow(q, ctx, sync_ptr)),
2142     )?;
2143 
2144     Ok(ptr)
2145 
2146     //• CL_INVALID_IMAGE_SIZE if image dimensions (image width, height, specified or compute row and/or slice pitch) for image are not supported by device associated with queue.
2147     //• CL_IMAGE_FORMAT_NOT_SUPPORTED if image format (image channel order and data type) for image are not supported by device associated with queue.
2148     //• CL_MAP_FAILURE if there is a failure to map the requested region into the host address space. This error cannot occur for image objects created with CL_MEM_USE_HOST_PTR or CL_MEM_ALLOC_HOST_PTR.
2149     //• CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST if the map operation is blocking and the execution status of any of the events in event_wait_list is a negative integer value.
2150     //• CL_INVALID_OPERATION if the device associated with command_queue does not support images (i.e. CL_DEVICE_IMAGE_SUPPORT specified in the Device Queries table is CL_FALSE).
2151     //• CL_INVALID_OPERATION if mapping would lead to overlapping regions being mapped for writing.
2152 }
2153 
2154 #[cl_entrypoint]
retain_mem_object(mem: cl_mem) -> CLResult<()>2155 fn retain_mem_object(mem: cl_mem) -> CLResult<()> {
2156     let m = MemBase::ref_from_raw(mem)?;
2157     match m.base.get_type()? {
2158         RusticlTypes::Buffer => Buffer::retain(mem),
2159         RusticlTypes::Image => Image::retain(mem),
2160         _ => Err(CL_INVALID_MEM_OBJECT),
2161     }
2162 }
2163 
2164 #[cl_entrypoint]
release_mem_object(mem: cl_mem) -> CLResult<()>2165 fn release_mem_object(mem: cl_mem) -> CLResult<()> {
2166     let m = MemBase::ref_from_raw(mem)?;
2167     match m.base.get_type()? {
2168         RusticlTypes::Buffer => Buffer::release(mem),
2169         RusticlTypes::Image => Image::release(mem),
2170         _ => Err(CL_INVALID_MEM_OBJECT),
2171     }
2172 }
2173 
2174 #[cl_entrypoint]
enqueue_unmap_mem_object( command_queue: cl_command_queue, memobj: cl_mem, mapped_ptr: *mut ::std::os::raw::c_void, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>2175 fn enqueue_unmap_mem_object(
2176     command_queue: cl_command_queue,
2177     memobj: cl_mem,
2178     mapped_ptr: *mut ::std::os::raw::c_void,
2179     num_events_in_wait_list: cl_uint,
2180     event_wait_list: *const cl_event,
2181     event: *mut cl_event,
2182 ) -> CLResult<()> {
2183     let q = Queue::arc_from_raw(command_queue)?;
2184     let m = MemBase::arc_from_raw(memobj)?;
2185     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
2186 
2187     // CL_INVALID_CONTEXT if context associated with command_queue and memobj are not the same
2188     if q.context != m.context {
2189         return Err(CL_INVALID_CONTEXT);
2190     }
2191 
2192     // CL_INVALID_VALUE if mapped_ptr is not a valid pointer returned by clEnqueueMapBuffer or
2193     // clEnqueueMapImage for memobj.
2194     if !m.is_mapped_ptr(mapped_ptr) {
2195         return Err(CL_INVALID_VALUE);
2196     }
2197 
2198     // SAFETY: it's required that applications do not cause data races
2199     let mapped_ptr = unsafe { MutMemoryPtr::from_ptr(mapped_ptr) };
2200     create_and_queue(
2201         q,
2202         CL_COMMAND_UNMAP_MEM_OBJECT,
2203         evs,
2204         event,
2205         false,
2206         Box::new(move |q, ctx| m.unmap(q, ctx, mapped_ptr)),
2207     )
2208 }
2209 
2210 #[cl_entrypoint]
enqueue_migrate_mem_objects( command_queue: cl_command_queue, num_mem_objects: cl_uint, mem_objects: *const cl_mem, flags: cl_mem_migration_flags, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>2211 fn enqueue_migrate_mem_objects(
2212     command_queue: cl_command_queue,
2213     num_mem_objects: cl_uint,
2214     mem_objects: *const cl_mem,
2215     flags: cl_mem_migration_flags,
2216     num_events_in_wait_list: cl_uint,
2217     event_wait_list: *const cl_event,
2218     event: *mut cl_event,
2219 ) -> CLResult<()> {
2220     let q = Queue::arc_from_raw(command_queue)?;
2221     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
2222     let bufs = MemBase::refs_from_arr(mem_objects, num_mem_objects)?;
2223 
2224     // CL_INVALID_VALUE if num_mem_objects is zero or if mem_objects is NULL.
2225     if bufs.is_empty() {
2226         return Err(CL_INVALID_VALUE);
2227     }
2228 
2229     // CL_INVALID_CONTEXT if the context associated with command_queue and memory objects in
2230     // mem_objects are not the same
2231     if bufs.iter().any(|b| b.context != q.context) {
2232         return Err(CL_INVALID_CONTEXT);
2233     }
2234 
2235     // CL_INVALID_VALUE if flags is not 0 or is not any of the values described in the table above.
2236     if flags != 0
2237         && bit_check(
2238             flags,
2239             !(CL_MIGRATE_MEM_OBJECT_HOST | CL_MIGRATE_MEM_OBJECT_CONTENT_UNDEFINED),
2240         )
2241     {
2242         return Err(CL_INVALID_VALUE);
2243     }
2244 
2245     // we should do something, but it's legal to not do anything at all
2246     create_and_queue(
2247         q,
2248         CL_COMMAND_MIGRATE_MEM_OBJECTS,
2249         evs,
2250         event,
2251         false,
2252         Box::new(|_, _| Ok(())),
2253     )
2254 
2255     //• CL_MEM_OBJECT_ALLOCATION_FAILURE if there is a failure to allocate memory for the specified set of memory objects in mem_objects.
2256 }
2257 
2258 #[cl_info_entrypoint(cl_get_pipe_info)]
2259 impl CLInfo<cl_pipe_info> for cl_mem {
query(&self, _q: cl_pipe_info, _: &[u8]) -> CLResult<Vec<MaybeUninit<u8>>>2260     fn query(&self, _q: cl_pipe_info, _: &[u8]) -> CLResult<Vec<MaybeUninit<u8>>> {
2261         // CL_INVALID_MEM_OBJECT if pipe is a not a valid pipe object.
2262         Err(CL_INVALID_MEM_OBJECT)
2263     }
2264 }
2265 
svm_alloc( context: cl_context, flags: cl_svm_mem_flags, size: usize, mut alignment: cl_uint, ) -> CLResult<*mut c_void>2266 pub fn svm_alloc(
2267     context: cl_context,
2268     flags: cl_svm_mem_flags,
2269     size: usize,
2270     mut alignment: cl_uint,
2271 ) -> CLResult<*mut c_void> {
2272     // clSVMAlloc will fail if
2273 
2274     // context is not a valid context
2275     let c = Context::ref_from_raw(context)?;
2276 
2277     // or no devices in context support SVM.
2278     if !c.has_svm_devs() {
2279         return Err(CL_INVALID_OPERATION);
2280     }
2281 
2282     // flags does not contain CL_MEM_SVM_FINE_GRAIN_BUFFER but does contain CL_MEM_SVM_ATOMICS.
2283     if !bit_check(flags, CL_MEM_SVM_FINE_GRAIN_BUFFER) && bit_check(flags, CL_MEM_SVM_ATOMICS) {
2284         return Err(CL_INVALID_VALUE);
2285     }
2286 
2287     // size is 0 or > CL_DEVICE_MAX_MEM_ALLOC_SIZE value for any device in context.
2288     if size == 0 || checked_compare(size, Ordering::Greater, c.max_mem_alloc()) {
2289         return Err(CL_INVALID_VALUE);
2290     }
2291 
2292     if alignment == 0 {
2293         alignment = mem::size_of::<[u64; 16]>() as cl_uint;
2294     }
2295 
2296     // alignment is not a power of two
2297     if !alignment.is_power_of_two() {
2298         return Err(CL_INVALID_VALUE);
2299     }
2300 
2301     let layout;
2302     let ptr;
2303 
2304     // SAFETY: we already verify the parameters to from_size_align above and layout is of non zero
2305     // size
2306     unsafe {
2307         layout = Layout::from_size_align_unchecked(size, alignment as usize);
2308         ptr = alloc::alloc(layout);
2309     }
2310 
2311     if ptr.is_null() {
2312         return Err(CL_OUT_OF_HOST_MEMORY);
2313     }
2314 
2315     c.add_svm_ptr(ptr as usize, layout);
2316     Ok(ptr.cast())
2317 
2318     // Values specified in flags do not follow rules described for supported values in the SVM Memory Flags table.
2319     // CL_MEM_SVM_FINE_GRAIN_BUFFER or CL_MEM_SVM_ATOMICS is specified in flags and these are not supported by at least one device in context.
2320     // The values specified in flags are not valid, i.e. don’t match those defined in the SVM Memory Flags table.
2321     // the OpenCL implementation cannot support the specified alignment for at least one device in context.
2322     // There was a failure to allocate resources.
2323 }
2324 
svm_free_impl(c: &Context, svm_pointer: usize)2325 fn svm_free_impl(c: &Context, svm_pointer: usize) {
2326     if let Some(layout) = c.remove_svm_ptr(svm_pointer) {
2327         // SAFETY: we make sure that svm_pointer is a valid allocation and reuse the same layout
2328         // from the allocation
2329         unsafe {
2330             alloc::dealloc(svm_pointer as *mut u8, layout);
2331         }
2332     }
2333 }
2334 
svm_free(context: cl_context, svm_pointer: usize) -> CLResult<()>2335 pub fn svm_free(context: cl_context, svm_pointer: usize) -> CLResult<()> {
2336     let c = Context::ref_from_raw(context)?;
2337     svm_free_impl(c, svm_pointer);
2338     Ok(())
2339 }
2340 
enqueue_svm_free_impl( command_queue: cl_command_queue, num_svm_pointers: cl_uint, svm_pointers: *mut *mut c_void, pfn_free_func: Option<FuncSVMFreeCb>, user_data: *mut c_void, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, cmd_type: cl_command_type, ) -> CLResult<()>2341 fn enqueue_svm_free_impl(
2342     command_queue: cl_command_queue,
2343     num_svm_pointers: cl_uint,
2344     svm_pointers: *mut *mut c_void,
2345     pfn_free_func: Option<FuncSVMFreeCb>,
2346     user_data: *mut c_void,
2347     num_events_in_wait_list: cl_uint,
2348     event_wait_list: *const cl_event,
2349     event: *mut cl_event,
2350     cmd_type: cl_command_type,
2351 ) -> CLResult<()> {
2352     let q = Queue::arc_from_raw(command_queue)?;
2353     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
2354 
2355     // CL_INVALID_VALUE if num_svm_pointers is 0 and svm_pointers is non-NULL, or if svm_pointers is
2356     // NULL and num_svm_pointers is not 0.
2357     if num_svm_pointers == 0 && !svm_pointers.is_null()
2358         || num_svm_pointers != 0 && svm_pointers.is_null()
2359     {
2360         return Err(CL_INVALID_VALUE);
2361     }
2362 
2363     // CL_INVALID_OPERATION if the device associated with command queue does not support SVM.
2364     if !q.device.svm_supported() {
2365         return Err(CL_INVALID_OPERATION);
2366     }
2367 
2368     // The application is allowed to reuse or free the memory referenced by `svm_pointers` after this
2369     // function returns so we have to make a copy.
2370     // SAFETY: num_svm_pointers specifies the amount of elements in svm_pointers
2371     let mut svm_pointers =
2372         unsafe { slice::from_raw_parts(svm_pointers.cast(), num_svm_pointers as usize) }.to_vec();
2373     // SAFETY: The requirements on `SVMFreeCb::new` match the requirements
2374     // imposed by the OpenCL specification. It is the caller's duty to uphold them.
2375     let cb_opt = unsafe { SVMFreeCb::new(pfn_free_func, user_data) }.ok();
2376 
2377     create_and_queue(
2378         q,
2379         cmd_type,
2380         evs,
2381         event,
2382         false,
2383         Box::new(move |q, _| {
2384             if let Some(cb) = cb_opt {
2385                 cb.call(q, &mut svm_pointers);
2386             } else {
2387                 for ptr in svm_pointers {
2388                     svm_free_impl(&q.context, ptr);
2389                 }
2390             }
2391 
2392             Ok(())
2393         }),
2394     )
2395 }
2396 
2397 #[cl_entrypoint]
enqueue_svm_free( command_queue: cl_command_queue, num_svm_pointers: cl_uint, svm_pointers: *mut *mut c_void, pfn_free_func: Option<FuncSVMFreeCb>, user_data: *mut c_void, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>2398 fn enqueue_svm_free(
2399     command_queue: cl_command_queue,
2400     num_svm_pointers: cl_uint,
2401     svm_pointers: *mut *mut c_void,
2402     pfn_free_func: Option<FuncSVMFreeCb>,
2403     user_data: *mut c_void,
2404     num_events_in_wait_list: cl_uint,
2405     event_wait_list: *const cl_event,
2406     event: *mut cl_event,
2407 ) -> CLResult<()> {
2408     enqueue_svm_free_impl(
2409         command_queue,
2410         num_svm_pointers,
2411         svm_pointers,
2412         pfn_free_func,
2413         user_data,
2414         num_events_in_wait_list,
2415         event_wait_list,
2416         event,
2417         CL_COMMAND_SVM_FREE,
2418     )
2419 }
2420 
2421 #[cl_entrypoint]
enqueue_svm_free_arm( command_queue: cl_command_queue, num_svm_pointers: cl_uint, svm_pointers: *mut *mut c_void, pfn_free_func: Option<FuncSVMFreeCb>, user_data: *mut c_void, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>2422 fn enqueue_svm_free_arm(
2423     command_queue: cl_command_queue,
2424     num_svm_pointers: cl_uint,
2425     svm_pointers: *mut *mut c_void,
2426     pfn_free_func: Option<FuncSVMFreeCb>,
2427     user_data: *mut c_void,
2428     num_events_in_wait_list: cl_uint,
2429     event_wait_list: *const cl_event,
2430     event: *mut cl_event,
2431 ) -> CLResult<()> {
2432     enqueue_svm_free_impl(
2433         command_queue,
2434         num_svm_pointers,
2435         svm_pointers,
2436         pfn_free_func,
2437         user_data,
2438         num_events_in_wait_list,
2439         event_wait_list,
2440         event,
2441         CL_COMMAND_SVM_FREE_ARM,
2442     )
2443 }
2444 
enqueue_svm_memcpy_impl( command_queue: cl_command_queue, blocking_copy: cl_bool, dst_ptr: *mut c_void, src_ptr: *const c_void, size: usize, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, cmd_type: cl_command_type, ) -> CLResult<()>2445 fn enqueue_svm_memcpy_impl(
2446     command_queue: cl_command_queue,
2447     blocking_copy: cl_bool,
2448     dst_ptr: *mut c_void,
2449     src_ptr: *const c_void,
2450     size: usize,
2451     num_events_in_wait_list: cl_uint,
2452     event_wait_list: *const cl_event,
2453     event: *mut cl_event,
2454     cmd_type: cl_command_type,
2455 ) -> CLResult<()> {
2456     let q = Queue::arc_from_raw(command_queue)?;
2457     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
2458     let block = check_cl_bool(blocking_copy).ok_or(CL_INVALID_VALUE)?;
2459 
2460     // CL_INVALID_OPERATION if the device associated with command queue does not support SVM.
2461     if !q.device.svm_supported() {
2462         return Err(CL_INVALID_OPERATION);
2463     }
2464 
2465     // CL_MEM_COPY_OVERLAP if the values specified for dst_ptr, src_ptr and size result in an
2466     // overlapping copy.
2467     let dst_ptr_addr = dst_ptr as usize;
2468     let src_ptr_addr = src_ptr as usize;
2469     if (src_ptr_addr <= dst_ptr_addr && dst_ptr_addr < src_ptr_addr + size)
2470         || (dst_ptr_addr <= src_ptr_addr && src_ptr_addr < dst_ptr_addr + size)
2471     {
2472         return Err(CL_MEM_COPY_OVERLAP);
2473     }
2474 
2475     // CAST: We have no idea about the type or initialization status of these bytes.
2476     // MaybeUninit<u8> is the safe bet.
2477     let src_ptr = src_ptr.cast::<MaybeUninit<u8>>();
2478 
2479     // CAST: We have no idea about the type or initialization status of these bytes.
2480     // MaybeUninit<u8> is the safe bet.
2481     let dst_ptr = dst_ptr.cast::<MaybeUninit<u8>>();
2482 
2483     // SAFETY: It is up to the application to ensure the memory is valid to read for `size` bytes
2484     // and that it doesn't modify it until the command has completed.
2485     let src = unsafe { cl_slice::from_raw_parts(src_ptr, size)? };
2486 
2487     // SAFETY: We've ensured there's no aliasing between src and dst. It is up to the application
2488     // to ensure the memory is valid to read and write for `size` bytes and that it doesn't modify
2489     // or read from it until the command has completed.
2490     let dst = unsafe { cl_slice::from_raw_parts_mut(dst_ptr, size)? };
2491 
2492     create_and_queue(
2493         q,
2494         cmd_type,
2495         evs,
2496         event,
2497         block,
2498         Box::new(move |_, _| {
2499             dst.copy_from_slice(src);
2500             Ok(())
2501         }),
2502     )
2503 }
2504 
2505 #[cl_entrypoint]
enqueue_svm_memcpy( command_queue: cl_command_queue, blocking_copy: cl_bool, dst_ptr: *mut c_void, src_ptr: *const c_void, size: usize, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>2506 fn enqueue_svm_memcpy(
2507     command_queue: cl_command_queue,
2508     blocking_copy: cl_bool,
2509     dst_ptr: *mut c_void,
2510     src_ptr: *const c_void,
2511     size: usize,
2512     num_events_in_wait_list: cl_uint,
2513     event_wait_list: *const cl_event,
2514     event: *mut cl_event,
2515 ) -> CLResult<()> {
2516     enqueue_svm_memcpy_impl(
2517         command_queue,
2518         blocking_copy,
2519         dst_ptr,
2520         src_ptr,
2521         size,
2522         num_events_in_wait_list,
2523         event_wait_list,
2524         event,
2525         CL_COMMAND_SVM_MEMCPY,
2526     )
2527 }
2528 
2529 #[cl_entrypoint]
enqueue_svm_memcpy_arm( command_queue: cl_command_queue, blocking_copy: cl_bool, dst_ptr: *mut c_void, src_ptr: *const c_void, size: usize, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>2530 fn enqueue_svm_memcpy_arm(
2531     command_queue: cl_command_queue,
2532     blocking_copy: cl_bool,
2533     dst_ptr: *mut c_void,
2534     src_ptr: *const c_void,
2535     size: usize,
2536     num_events_in_wait_list: cl_uint,
2537     event_wait_list: *const cl_event,
2538     event: *mut cl_event,
2539 ) -> CLResult<()> {
2540     enqueue_svm_memcpy_impl(
2541         command_queue,
2542         blocking_copy,
2543         dst_ptr,
2544         src_ptr,
2545         size,
2546         num_events_in_wait_list,
2547         event_wait_list,
2548         event,
2549         CL_COMMAND_SVM_MEMCPY_ARM,
2550     )
2551 }
2552 
enqueue_svm_mem_fill_impl( command_queue: cl_command_queue, svm_ptr: *mut ::std::os::raw::c_void, pattern: *const ::std::os::raw::c_void, pattern_size: usize, size: usize, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, cmd_type: cl_command_type, ) -> CLResult<()>2553 fn enqueue_svm_mem_fill_impl(
2554     command_queue: cl_command_queue,
2555     svm_ptr: *mut ::std::os::raw::c_void,
2556     pattern: *const ::std::os::raw::c_void,
2557     pattern_size: usize,
2558     size: usize,
2559     num_events_in_wait_list: cl_uint,
2560     event_wait_list: *const cl_event,
2561     event: *mut cl_event,
2562     cmd_type: cl_command_type,
2563 ) -> CLResult<()> {
2564     let q = Queue::arc_from_raw(command_queue)?;
2565     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
2566 
2567     // CL_INVALID_OPERATION if the device associated with command queue does not support SVM.
2568     if !q.device.svm_supported() {
2569         return Err(CL_INVALID_OPERATION);
2570     }
2571 
2572     // CL_INVALID_VALUE if pattern is NULL [...]
2573     if pattern.is_null() {
2574         return Err(CL_INVALID_VALUE);
2575     }
2576 
2577     // CL_INVALID_VALUE if size is not a multiple of pattern_size.
2578     if size % pattern_size != 0 {
2579         return Err(CL_INVALID_VALUE);
2580     }
2581 
2582     // The provided `$bytesize` must equal `pattern_size`.
2583     macro_rules! generate_fill_closure {
2584         ($bytesize:literal) => {{
2585             // We need the value of `$bytesize`` at compile time, so we need to pass it in, but it
2586             // should always match `pattern_size`.
2587             assert!($bytesize == pattern_size);
2588 
2589             // Three reasons we define our own bag-of-bytes type here:
2590             //
2591             // We'd otherwise have to pass a type to this macro. Verifying that the type we passed
2592             // upholds all the properties we need or want is more trouble than defining our own.
2593             //
2594             // The primitive Rust types only go up to `u128` anyway and their alignments are
2595             // platfrom defined. E.g. At the time of this writing `u128` only has an alignment of 8
2596             // on x86-64, even though its size is 16. Defining our own type with an alignment of 16
2597             // allows the compiler to generate better code.
2598             //
2599             // The alignment of OpenCL types is currently what we need on x86-64, but the spec
2600             // explicitly states that's just a recommendation and ultimately it's up to the
2601             // cl_platform.h header. The very descriptive names of the CL types don't make
2602             // verifying the match calling this macro any easier on a glance.
2603             // "Was `cl_uint` 4 byte or 8 byte? Eh, I'm sure nobody got it wrong by accident."
2604             #[repr(C)]
2605             #[repr(align($bytesize))]
2606             #[derive(Copy, Clone)]
2607             struct Pattern([u8; $bytesize]);
2608 
2609             // Just to make sure the compiler didn't generate anything weird.
2610             static_assert!($bytesize == mem::size_of::<Pattern>());
2611             static_assert!($bytesize == mem::align_of::<Pattern>());
2612 
2613             // CAST: We don't know exactly which type `pattern` points to, but we know it's an
2614             // Application Scalar Data Type (cl_char, cl_ulong, etc.) or an Application Vector Data
2615             // Type (cl_double4, etc.). All of them are `Copy`, do not contain padding bytes, and
2616             // have no invalid bit patterns. AKA they are POD data types.
2617             // Since we only copy it around, we can cast to any POD type as long as its size
2618             // matches `pattern_size`.
2619             let pattern_ptr = pattern.cast::<Pattern>();
2620 
2621             // The application is allowed to reuse or free the memory referenced by `pattern_ptr`
2622             // after this function returns, so we need to create a copy.
2623             //
2624             // There's no explicit alignment guarantee and we don't rely on `Pattern` matching the
2625             // alignment of whichever Application Data Type we're actually presented with. Thus, do
2626             // an unaligned read.
2627             //
2628             // SAFETY: We've checked that `pattern_ptr` is not NULL above. It is otherwise the
2629             // calling application's responsibility to ensure that it is valid for reads of
2630             // `pattern_size` bytes and properly initialized.
2631             // Creating a bitwise copy can't create memory safety issues, since `Pattern` is `Copy`.
2632             let pattern = unsafe { pattern_ptr.read_unaligned() };
2633 
2634             // CAST: Same as with `pattern`, we don't know the exact type of `svm_ptr`, but we do
2635             // know it's fine if we choose the same type here. The application might reasonably
2636             // give us uninitialized memory though, so cast to a `MaybeUninit<Pattern>`, which has
2637             // the same layout as `Pattern`.
2638             let svm_ptr = svm_ptr.cast::<MaybeUninit<Pattern>>();
2639 
2640             // SAFETY: It is the calling application's responsibility to ensure that `svm_ptr` is
2641             // valid for reads and writes up to `size` bytes.
2642             // Since `pattern_size == mem::size_of::<Pattern>()` and `MaybeUninit<Pattern>` has the
2643             // same layout as `Pattern`, we know that
2644             // `size / pattern_size * mem::size_of<MaybeUninit<Pattern>>` equals `size`.
2645             //
2646             // Since we're creating a `&[MaybeUninit<Pattern>]` the initialization status does not
2647             // matter.
2648             //
2649             // From here on out we only access the referenced memory though this slice. In
2650             // particular, since we've made a copy of `pattern`, it doesn't matter if the memory
2651             // region referenced by `pattern` aliases the one referenced by this slice. It is up to
2652             // the application not to access it at all until this command has been completed.
2653             let svm_slice = unsafe { cl_slice::from_raw_parts_mut(svm_ptr, size / pattern_size)? };
2654 
2655             Box::new(move |_, _| {
2656                 for x in svm_slice {
2657                     x.write(pattern);
2658                 }
2659 
2660                 Ok(())
2661             })
2662         }};
2663     }
2664 
2665     // Generate optimized code paths for each of the possible pattern sizes.
2666     let work: EventSig = match pattern_size {
2667         1 => generate_fill_closure!(1),
2668         2 => generate_fill_closure!(2),
2669         4 => generate_fill_closure!(4),
2670         8 => generate_fill_closure!(8),
2671         16 => generate_fill_closure!(16),
2672         32 => generate_fill_closure!(32),
2673         64 => generate_fill_closure!(64),
2674         128 => generate_fill_closure!(128),
2675         _ => {
2676             // CL_INVALID_VALUE if [...] pattern_size is 0 or if pattern_size is not one of
2677             // {1, 2, 4, 8, 16, 32, 64, 128}.
2678             return Err(CL_INVALID_VALUE);
2679         }
2680     };
2681 
2682     create_and_queue(q, cmd_type, evs, event, false, work)
2683 }
2684 
2685 #[cl_entrypoint]
enqueue_svm_mem_fill( command_queue: cl_command_queue, svm_ptr: *mut ::std::os::raw::c_void, pattern: *const ::std::os::raw::c_void, pattern_size: usize, size: usize, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>2686 fn enqueue_svm_mem_fill(
2687     command_queue: cl_command_queue,
2688     svm_ptr: *mut ::std::os::raw::c_void,
2689     pattern: *const ::std::os::raw::c_void,
2690     pattern_size: usize,
2691     size: usize,
2692     num_events_in_wait_list: cl_uint,
2693     event_wait_list: *const cl_event,
2694     event: *mut cl_event,
2695 ) -> CLResult<()> {
2696     enqueue_svm_mem_fill_impl(
2697         command_queue,
2698         svm_ptr,
2699         pattern,
2700         pattern_size,
2701         size,
2702         num_events_in_wait_list,
2703         event_wait_list,
2704         event,
2705         CL_COMMAND_SVM_MEMFILL,
2706     )
2707 }
2708 
2709 #[cl_entrypoint]
enqueue_svm_mem_fill_arm( command_queue: cl_command_queue, svm_ptr: *mut ::std::os::raw::c_void, pattern: *const ::std::os::raw::c_void, pattern_size: usize, size: usize, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>2710 fn enqueue_svm_mem_fill_arm(
2711     command_queue: cl_command_queue,
2712     svm_ptr: *mut ::std::os::raw::c_void,
2713     pattern: *const ::std::os::raw::c_void,
2714     pattern_size: usize,
2715     size: usize,
2716     num_events_in_wait_list: cl_uint,
2717     event_wait_list: *const cl_event,
2718     event: *mut cl_event,
2719 ) -> CLResult<()> {
2720     enqueue_svm_mem_fill_impl(
2721         command_queue,
2722         svm_ptr,
2723         pattern,
2724         pattern_size,
2725         size,
2726         num_events_in_wait_list,
2727         event_wait_list,
2728         event,
2729         CL_COMMAND_SVM_MEMFILL_ARM,
2730     )
2731 }
2732 
enqueue_svm_map_impl( command_queue: cl_command_queue, blocking_map: cl_bool, flags: cl_map_flags, svm_ptr: *mut ::std::os::raw::c_void, size: usize, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, cmd_type: cl_command_type, ) -> CLResult<()>2733 fn enqueue_svm_map_impl(
2734     command_queue: cl_command_queue,
2735     blocking_map: cl_bool,
2736     flags: cl_map_flags,
2737     svm_ptr: *mut ::std::os::raw::c_void,
2738     size: usize,
2739     num_events_in_wait_list: cl_uint,
2740     event_wait_list: *const cl_event,
2741     event: *mut cl_event,
2742     cmd_type: cl_command_type,
2743 ) -> CLResult<()> {
2744     let q = Queue::arc_from_raw(command_queue)?;
2745     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
2746     let block = check_cl_bool(blocking_map).ok_or(CL_INVALID_VALUE)?;
2747 
2748     // CL_INVALID_OPERATION if the device associated with command queue does not support SVM.
2749     if !q.device.svm_supported() {
2750         return Err(CL_INVALID_OPERATION);
2751     }
2752 
2753     // CL_INVALID_VALUE if svm_ptr is NULL.
2754     if svm_ptr.is_null() {
2755         return Err(CL_INVALID_VALUE);
2756     }
2757 
2758     // CL_INVALID_VALUE if size is 0 ...
2759     if size == 0 {
2760         return Err(CL_INVALID_VALUE);
2761     }
2762 
2763     // ... or if values specified in map_flags are not valid.
2764     validate_map_flags_common(flags)?;
2765 
2766     create_and_queue(q, cmd_type, evs, event, block, Box::new(|_, _| Ok(())))
2767 }
2768 
2769 #[cl_entrypoint]
enqueue_svm_map( command_queue: cl_command_queue, blocking_map: cl_bool, flags: cl_map_flags, svm_ptr: *mut ::std::os::raw::c_void, size: usize, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>2770 fn enqueue_svm_map(
2771     command_queue: cl_command_queue,
2772     blocking_map: cl_bool,
2773     flags: cl_map_flags,
2774     svm_ptr: *mut ::std::os::raw::c_void,
2775     size: usize,
2776     num_events_in_wait_list: cl_uint,
2777     event_wait_list: *const cl_event,
2778     event: *mut cl_event,
2779 ) -> CLResult<()> {
2780     enqueue_svm_map_impl(
2781         command_queue,
2782         blocking_map,
2783         flags,
2784         svm_ptr,
2785         size,
2786         num_events_in_wait_list,
2787         event_wait_list,
2788         event,
2789         CL_COMMAND_SVM_MAP,
2790     )
2791 }
2792 
2793 #[cl_entrypoint]
enqueue_svm_map_arm( command_queue: cl_command_queue, blocking_map: cl_bool, flags: cl_map_flags, svm_ptr: *mut ::std::os::raw::c_void, size: usize, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>2794 fn enqueue_svm_map_arm(
2795     command_queue: cl_command_queue,
2796     blocking_map: cl_bool,
2797     flags: cl_map_flags,
2798     svm_ptr: *mut ::std::os::raw::c_void,
2799     size: usize,
2800     num_events_in_wait_list: cl_uint,
2801     event_wait_list: *const cl_event,
2802     event: *mut cl_event,
2803 ) -> CLResult<()> {
2804     enqueue_svm_map_impl(
2805         command_queue,
2806         blocking_map,
2807         flags,
2808         svm_ptr,
2809         size,
2810         num_events_in_wait_list,
2811         event_wait_list,
2812         event,
2813         CL_COMMAND_SVM_MAP_ARM,
2814     )
2815 }
2816 
enqueue_svm_unmap_impl( command_queue: cl_command_queue, svm_ptr: *mut ::std::os::raw::c_void, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, cmd_type: cl_command_type, ) -> CLResult<()>2817 fn enqueue_svm_unmap_impl(
2818     command_queue: cl_command_queue,
2819     svm_ptr: *mut ::std::os::raw::c_void,
2820     num_events_in_wait_list: cl_uint,
2821     event_wait_list: *const cl_event,
2822     event: *mut cl_event,
2823     cmd_type: cl_command_type,
2824 ) -> CLResult<()> {
2825     let q = Queue::arc_from_raw(command_queue)?;
2826     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
2827 
2828     // CL_INVALID_OPERATION if the device associated with command queue does not support SVM.
2829     if !q.device.svm_supported() {
2830         return Err(CL_INVALID_OPERATION);
2831     }
2832 
2833     // CL_INVALID_VALUE if svm_ptr is NULL.
2834     if svm_ptr.is_null() {
2835         return Err(CL_INVALID_VALUE);
2836     }
2837 
2838     create_and_queue(q, cmd_type, evs, event, false, Box::new(|_, _| Ok(())))
2839 }
2840 
2841 #[cl_entrypoint]
enqueue_svm_unmap( command_queue: cl_command_queue, svm_ptr: *mut ::std::os::raw::c_void, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>2842 fn enqueue_svm_unmap(
2843     command_queue: cl_command_queue,
2844     svm_ptr: *mut ::std::os::raw::c_void,
2845     num_events_in_wait_list: cl_uint,
2846     event_wait_list: *const cl_event,
2847     event: *mut cl_event,
2848 ) -> CLResult<()> {
2849     enqueue_svm_unmap_impl(
2850         command_queue,
2851         svm_ptr,
2852         num_events_in_wait_list,
2853         event_wait_list,
2854         event,
2855         CL_COMMAND_SVM_UNMAP,
2856     )
2857 }
2858 
2859 #[cl_entrypoint]
enqueue_svm_unmap_arm( command_queue: cl_command_queue, svm_ptr: *mut ::std::os::raw::c_void, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>2860 fn enqueue_svm_unmap_arm(
2861     command_queue: cl_command_queue,
2862     svm_ptr: *mut ::std::os::raw::c_void,
2863     num_events_in_wait_list: cl_uint,
2864     event_wait_list: *const cl_event,
2865     event: *mut cl_event,
2866 ) -> CLResult<()> {
2867     enqueue_svm_unmap_impl(
2868         command_queue,
2869         svm_ptr,
2870         num_events_in_wait_list,
2871         event_wait_list,
2872         event,
2873         CL_COMMAND_SVM_UNMAP_ARM,
2874     )
2875 }
2876 
2877 #[cl_entrypoint]
enqueue_svm_migrate_mem( command_queue: cl_command_queue, num_svm_pointers: cl_uint, svm_pointers: *mut *const ::std::os::raw::c_void, sizes: *const usize, flags: cl_mem_migration_flags, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>2878 fn enqueue_svm_migrate_mem(
2879     command_queue: cl_command_queue,
2880     num_svm_pointers: cl_uint,
2881     svm_pointers: *mut *const ::std::os::raw::c_void,
2882     sizes: *const usize,
2883     flags: cl_mem_migration_flags,
2884     num_events_in_wait_list: cl_uint,
2885     event_wait_list: *const cl_event,
2886     event: *mut cl_event,
2887 ) -> CLResult<()> {
2888     let q = Queue::arc_from_raw(command_queue)?;
2889     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
2890 
2891     // CL_INVALID_OPERATION if the device associated with command queue does not support SVM.
2892     if !q.device.svm_supported() {
2893         return Err(CL_INVALID_OPERATION);
2894     }
2895 
2896     // CL_INVALID_VALUE if num_svm_pointers is zero
2897     if num_svm_pointers == 0 {
2898         return Err(CL_INVALID_VALUE);
2899     }
2900 
2901     let num_svm_pointers = num_svm_pointers as usize;
2902     // SAFETY: Just hoping the application is alright.
2903     let mut svm_pointers: Vec<usize> =
2904         unsafe { cl_slice::from_raw_parts(svm_pointers.cast(), num_svm_pointers)? }.to_owned();
2905     // if sizes is NULL, every allocation containing the pointers need to be migrated
2906     let mut sizes = if sizes.is_null() {
2907         vec![0; num_svm_pointers]
2908     } else {
2909         unsafe { cl_slice::from_raw_parts(sizes, num_svm_pointers)? }.to_owned()
2910     };
2911 
2912     // CL_INVALID_VALUE if sizes[i] is non-zero range [svm_pointers[i], svm_pointers[i]+sizes[i]) is
2913     // not contained within an existing clSVMAlloc allocation.
2914     for (ptr, size) in svm_pointers.iter_mut().zip(&mut sizes) {
2915         if let Some((alloc, layout)) = q.context.find_svm_alloc(*ptr) {
2916             let ptr_addr = *ptr;
2917             let alloc_addr = alloc as usize;
2918 
2919             // if the offset + size is bigger than the allocation we are out of bounds
2920             if (ptr_addr - alloc_addr) + *size <= layout.size() {
2921                 // if the size is 0, the entire allocation should be migrated
2922                 if *size == 0 {
2923                     *ptr = alloc as usize;
2924                     *size = layout.size();
2925                 }
2926                 continue;
2927             }
2928         }
2929 
2930         return Err(CL_INVALID_VALUE);
2931     }
2932 
2933     let to_device = !bit_check(flags, CL_MIGRATE_MEM_OBJECT_HOST);
2934     let content_undefined = bit_check(flags, CL_MIGRATE_MEM_OBJECT_CONTENT_UNDEFINED);
2935 
2936     create_and_queue(
2937         q,
2938         CL_COMMAND_SVM_MIGRATE_MEM,
2939         evs,
2940         event,
2941         false,
2942         Box::new(move |_, ctx| {
2943             ctx.svm_migrate(&svm_pointers, &sizes, to_device, content_undefined);
2944             Ok(())
2945         }),
2946     )
2947 }
2948 
2949 #[cl_entrypoint]
create_pipe( _context: cl_context, _flags: cl_mem_flags, _pipe_packet_size: cl_uint, _pipe_max_packets: cl_uint, _properties: *const cl_pipe_properties, ) -> CLResult<cl_mem>2950 fn create_pipe(
2951     _context: cl_context,
2952     _flags: cl_mem_flags,
2953     _pipe_packet_size: cl_uint,
2954     _pipe_max_packets: cl_uint,
2955     _properties: *const cl_pipe_properties,
2956 ) -> CLResult<cl_mem> {
2957     Err(CL_INVALID_OPERATION)
2958 }
2959 
2960 #[cl_info_entrypoint(cl_get_gl_texture_info)]
2961 impl CLInfo<cl_gl_texture_info> for cl_mem {
query(&self, q: cl_gl_texture_info, _: &[u8]) -> CLResult<Vec<MaybeUninit<u8>>>2962     fn query(&self, q: cl_gl_texture_info, _: &[u8]) -> CLResult<Vec<MaybeUninit<u8>>> {
2963         let mem = MemBase::ref_from_raw(*self)?;
2964         Ok(match *q {
2965             CL_GL_MIPMAP_LEVEL => cl_prop::<cl_GLint>(0),
2966             CL_GL_TEXTURE_TARGET => cl_prop::<cl_GLenum>(
2967                 mem.gl_obj
2968                     .as_ref()
2969                     .ok_or(CL_INVALID_GL_OBJECT)?
2970                     .gl_object_target,
2971             ),
2972             _ => return Err(CL_INVALID_VALUE),
2973         })
2974     }
2975 }
2976 
create_from_gl( context: cl_context, flags: cl_mem_flags, target: cl_GLenum, miplevel: cl_GLint, texture: cl_GLuint, ) -> CLResult<cl_mem>2977 fn create_from_gl(
2978     context: cl_context,
2979     flags: cl_mem_flags,
2980     target: cl_GLenum,
2981     miplevel: cl_GLint,
2982     texture: cl_GLuint,
2983 ) -> CLResult<cl_mem> {
2984     let c = Context::arc_from_raw(context)?;
2985     let gl_ctx_manager = &c.gl_ctx_manager;
2986 
2987     // CL_INVALID_CONTEXT if context associated with command_queue was not created from an OpenGL context
2988     if gl_ctx_manager.is_none() {
2989         return Err(CL_INVALID_CONTEXT);
2990     }
2991 
2992     // CL_INVALID_VALUE if values specified in flags are not valid or if value specified in
2993     // texture_target is not one of the values specified in the description of texture_target.
2994     validate_mem_flags(flags, target == GL_ARRAY_BUFFER)?;
2995 
2996     // CL_INVALID_MIP_LEVEL if miplevel is greather than zero and the OpenGL
2997     // implementation does not support creating from non-zero mipmap levels.
2998     if miplevel > 0 {
2999         return Err(CL_INVALID_MIP_LEVEL);
3000     }
3001 
3002     // CL_INVALID_CONTEXT if context [..] was not created from a GL context.
3003     if let Some(gl_ctx_manager) = gl_ctx_manager {
3004         let gl_export_manager =
3005             gl_ctx_manager.export_object(&c, target, flags as u32, miplevel, texture)?;
3006 
3007         Ok(MemBase::from_gl(c, flags, &gl_export_manager)?)
3008     } else {
3009         Err(CL_INVALID_CONTEXT)
3010     }
3011 }
3012 
3013 #[cl_entrypoint]
create_from_gl_texture( context: cl_context, flags: cl_mem_flags, target: cl_GLenum, miplevel: cl_GLint, texture: cl_GLuint, ) -> CLResult<cl_mem>3014 fn create_from_gl_texture(
3015     context: cl_context,
3016     flags: cl_mem_flags,
3017     target: cl_GLenum,
3018     miplevel: cl_GLint,
3019     texture: cl_GLuint,
3020 ) -> CLResult<cl_mem> {
3021     // CL_INVALID_VALUE if values specified in flags are not valid or if value specified in
3022     // texture_target is not one of the values specified in the description of texture_target.
3023     if !is_valid_gl_texture(target) {
3024         return Err(CL_INVALID_VALUE);
3025     }
3026 
3027     create_from_gl(context, flags, target, miplevel, texture)
3028 }
3029 
3030 #[cl_entrypoint]
create_from_gl_texture_2d( context: cl_context, flags: cl_mem_flags, target: cl_GLenum, miplevel: cl_GLint, texture: cl_GLuint, ) -> CLResult<cl_mem>3031 fn create_from_gl_texture_2d(
3032     context: cl_context,
3033     flags: cl_mem_flags,
3034     target: cl_GLenum,
3035     miplevel: cl_GLint,
3036     texture: cl_GLuint,
3037 ) -> CLResult<cl_mem> {
3038     // CL_INVALID_VALUE if values specified in flags are not valid or if value specified in
3039     // texture_target is not one of the values specified in the description of texture_target.
3040     if !is_valid_gl_texture_2d(target) {
3041         return Err(CL_INVALID_VALUE);
3042     }
3043 
3044     create_from_gl(context, flags, target, miplevel, texture)
3045 }
3046 
3047 #[cl_entrypoint]
create_from_gl_texture_3d( context: cl_context, flags: cl_mem_flags, target: cl_GLenum, miplevel: cl_GLint, texture: cl_GLuint, ) -> CLResult<cl_mem>3048 fn create_from_gl_texture_3d(
3049     context: cl_context,
3050     flags: cl_mem_flags,
3051     target: cl_GLenum,
3052     miplevel: cl_GLint,
3053     texture: cl_GLuint,
3054 ) -> CLResult<cl_mem> {
3055     // CL_INVALID_VALUE if values specified in flags are not valid or if value specified in
3056     // texture_target is not one of the values specified in the description of texture_target.
3057     if target != GL_TEXTURE_3D {
3058         return Err(CL_INVALID_VALUE);
3059     }
3060 
3061     create_from_gl(context, flags, target, miplevel, texture)
3062 }
3063 
3064 #[cl_entrypoint]
create_from_gl_buffer( context: cl_context, flags: cl_mem_flags, bufobj: cl_GLuint, ) -> CLResult<cl_mem>3065 fn create_from_gl_buffer(
3066     context: cl_context,
3067     flags: cl_mem_flags,
3068     bufobj: cl_GLuint,
3069 ) -> CLResult<cl_mem> {
3070     create_from_gl(context, flags, GL_ARRAY_BUFFER, 0, bufobj)
3071 }
3072 
3073 #[cl_entrypoint]
create_from_gl_renderbuffer( context: cl_context, flags: cl_mem_flags, renderbuffer: cl_GLuint, ) -> CLResult<cl_mem>3074 fn create_from_gl_renderbuffer(
3075     context: cl_context,
3076     flags: cl_mem_flags,
3077     renderbuffer: cl_GLuint,
3078 ) -> CLResult<cl_mem> {
3079     create_from_gl(context, flags, GL_RENDERBUFFER, 0, renderbuffer)
3080 }
3081 
3082 #[cl_entrypoint]
get_gl_object_info( memobj: cl_mem, gl_object_type: *mut cl_gl_object_type, gl_object_name: *mut cl_GLuint, ) -> CLResult<()>3083 fn get_gl_object_info(
3084     memobj: cl_mem,
3085     gl_object_type: *mut cl_gl_object_type,
3086     gl_object_name: *mut cl_GLuint,
3087 ) -> CLResult<()> {
3088     let m = MemBase::ref_from_raw(memobj)?;
3089 
3090     match &m.gl_obj {
3091         Some(gl_obj) => {
3092             gl_object_type.write_checked(gl_obj.gl_object_type);
3093             gl_object_name.write_checked(gl_obj.gl_object_name);
3094         }
3095         None => {
3096             // CL_INVALID_GL_OBJECT if there is no GL object associated with memobj.
3097             return Err(CL_INVALID_GL_OBJECT);
3098         }
3099     }
3100 
3101     Ok(())
3102 }
3103 
3104 #[cl_entrypoint]
enqueue_acquire_gl_objects( command_queue: cl_command_queue, num_objects: cl_uint, mem_objects: *const cl_mem, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>3105 fn enqueue_acquire_gl_objects(
3106     command_queue: cl_command_queue,
3107     num_objects: cl_uint,
3108     mem_objects: *const cl_mem,
3109     num_events_in_wait_list: cl_uint,
3110     event_wait_list: *const cl_event,
3111     event: *mut cl_event,
3112 ) -> CLResult<()> {
3113     let q = Queue::arc_from_raw(command_queue)?;
3114     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
3115     let objs = MemBase::arcs_from_arr(mem_objects, num_objects)?;
3116     let gl_ctx_manager = &q.context.gl_ctx_manager;
3117 
3118     // CL_INVALID_CONTEXT if context associated with command_queue was not created from an OpenGL context
3119     if gl_ctx_manager.is_none() {
3120         return Err(CL_INVALID_CONTEXT);
3121     }
3122 
3123     // CL_INVALID_GL_OBJECT if memory objects in mem_objects have not been created from a GL object(s).
3124     if objs.iter().any(|o| o.gl_obj.is_none()) {
3125         return Err(CL_INVALID_GL_OBJECT);
3126     }
3127 
3128     create_and_queue(
3129         q,
3130         CL_COMMAND_ACQUIRE_GL_OBJECTS,
3131         evs,
3132         event,
3133         false,
3134         Box::new(move |q, ctx| copy_cube_to_slice(q, ctx, &objs)),
3135     )
3136 }
3137 
3138 #[cl_entrypoint]
enqueue_release_gl_objects( command_queue: cl_command_queue, num_objects: cl_uint, mem_objects: *const cl_mem, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, ) -> CLResult<()>3139 fn enqueue_release_gl_objects(
3140     command_queue: cl_command_queue,
3141     num_objects: cl_uint,
3142     mem_objects: *const cl_mem,
3143     num_events_in_wait_list: cl_uint,
3144     event_wait_list: *const cl_event,
3145     event: *mut cl_event,
3146 ) -> CLResult<()> {
3147     let q = Queue::arc_from_raw(command_queue)?;
3148     let evs = event_list_from_cl(&q, num_events_in_wait_list, event_wait_list)?;
3149     let objs = MemBase::arcs_from_arr(mem_objects, num_objects)?;
3150     let gl_ctx_manager = &q.context.gl_ctx_manager;
3151 
3152     // CL_INVALID_CONTEXT if context associated with command_queue was not created from an OpenGL context
3153     if gl_ctx_manager.is_none() {
3154         return Err(CL_INVALID_CONTEXT);
3155     }
3156 
3157     // CL_INVALID_GL_OBJECT if memory objects in mem_objects have not been created from a GL object(s).
3158     if objs.iter().any(|o| o.gl_obj.is_none()) {
3159         return Err(CL_INVALID_GL_OBJECT);
3160     }
3161 
3162     create_and_queue(
3163         q,
3164         CL_COMMAND_RELEASE_GL_OBJECTS,
3165         evs,
3166         event,
3167         false,
3168         Box::new(move |q, ctx| copy_slice_to_cube(q, ctx, &objs)),
3169     )
3170 }
3171