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