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