ocl/standard/
image.rs

1//! An OpenCL Image.
2//!
3//
4// * NOTE: `Image` does not have the latest command builders nor does it have
5//   support for mapping yet. (TODO: implement)
6//
7
8use crate::core::{
9    self, AsMem, ImageChannelDataType, ImageChannelOrder, ImageDescriptor, ImageFormat,
10    ImageFormatParseResult, ImageInfo, ImageInfoResult, MapFlags, Mem as MemCore, MemCmdAll,
11    MemCmdRw, MemFlags, MemInfo, MemInfoResult, MemObjectType, OclPrm,
12};
13use crate::error::{Error as OclError, Result as OclResult};
14use crate::standard::{
15    ClNullEventPtrEnum, ClWaitListPtrEnum, Context, HostSlice, QueCtx, Queue, SpatialDims,
16};
17use crate::MemMap;
18use std;
19use std::marker::PhantomData;
20use std::mem;
21use std::ops::{Deref, DerefMut};
22
23#[cfg(not(feature = "opencl_vendor_mesa"))]
24use crate::core::GlTextureTarget;
25#[cfg(not(feature = "opencl_vendor_mesa"))]
26use crate::ffi::{cl_GLint, cl_GLuint};
27
28use crate::ffi::{cl_id3d11_texture2d, cl_id3d11_texture3d, cl_uint};
29
30/// The type of operation to be performed by a command.
31#[derive(Debug)]
32pub enum ImageCmdKind<'c, T: 'c> {
33    Unspecified,
34    Read {
35        data: &'c mut [T],
36    },
37    Write {
38        data: &'c [T],
39    },
40    Map,
41    Fill {
42        color: T,
43    },
44    Copy {
45        dst_image: &'c MemCore,
46        dst_origin: [usize; 3],
47    },
48    CopyToBuffer {
49        buffer: &'c MemCore,
50        dst_offset: usize,
51    },
52    GLAcquire,
53    GLRelease,
54    D3D11Acquire,
55    D3D11Release,
56}
57
58impl<'c, T: 'c> ImageCmdKind<'c, T> {
59    fn is_unspec(&'c self) -> bool {
60        if let ImageCmdKind::Unspecified = *self {
61            true
62        } else {
63            false
64        }
65    }
66}
67
68/// An image command builder for enqueuing reads, writes, fills, and copies.
69///
70/// ## Examples
71///
72/// ```rust,ignore
73///
74/// // Copies one image to another:
75/// src_image.cmd().copy(&dst_image, [0, 0, 0]).enq().unwrap();
76///
77/// // Writes from a vector to an image, waiting on an event:
78/// image.write(&src_vec).ewait(&event).enq().unwrap();
79///
80/// // Reads from a image into a vector, waiting on an event list and
81/// // filling a new empty event:
82/// image.read(&dst_vec).ewait(&event_list).enew(&empty_event).enq().unwrap();
83///
84/// // Reads without blocking:
85/// image.cmd().read_async(&dst_vec).enew(&empty_event).enq().unwrap();
86///
87/// ```
88///
89/// [FIXME]: Fills not yet implemented.
90#[must_use = "commands do nothing unless enqueued"]
91#[allow(dead_code)]
92pub struct ImageCmd<'c, T: 'c> {
93    queue: Option<&'c Queue>,
94    obj_core: &'c MemCore,
95    block: bool,
96    origin: [usize; 3],
97    region: [usize; 3],
98    row_pitch_bytes: usize,
99    slc_pitch_bytes: usize,
100    kind: ImageCmdKind<'c, T>,
101    ewait: Option<ClWaitListPtrEnum<'c>>,
102    enew: Option<ClNullEventPtrEnum<'c>>,
103    mem_dims: [usize; 3],
104    ext_fns: Option<&'c core::ExtensionFunctions>,
105}
106
107/// [UNSTABLE]: All methods still in a state of adjustifulsomeness.
108impl<'c, T: 'c + OclPrm> ImageCmd<'c, T> {
109    /// Returns a new image command builder associated with with the
110    /// memory object `obj_core` along with a default `queue` and `to_len`
111    /// (the length of the device side image).
112    fn new(
113        queue: Option<&'c Queue>,
114        obj_core: &'c MemCore,
115        dims: [usize; 3],
116        ext_fns: Option<&'c core::ExtensionFunctions>,
117    ) -> ImageCmd<'c, T> {
118        ImageCmd {
119            queue,
120            obj_core,
121            block: true,
122            origin: [0, 0, 0],
123            region: dims,
124            row_pitch_bytes: 0,
125            slc_pitch_bytes: 0,
126            kind: ImageCmdKind::Unspecified,
127            ewait: None,
128            enew: None,
129            mem_dims: dims,
130            ext_fns,
131        }
132    }
133
134    /// Specifies that this command will be a blocking read operation.
135    ///
136    /// After calling this method, the blocking state of this command will
137    /// be locked to true and a call to `::block` will cause a panic.
138    ///
139    /// ## Panics
140    ///
141    /// The command operation kind must not have already been specified.
142    ///
143    /// ### More Information
144    ///
145    /// See [SDK][read_image] docs for more details.
146    ///
147    /// [read_image]: https://www.khronos.org/registry/OpenCL/sdk/1.2/docs/man/xhtml/clEnqueueReadImage.html
148    pub fn read<'d>(mut self, dst_data: &'d mut [T]) -> ImageCmd<'c, T>
149    where
150        'd: 'c,
151    {
152        assert!(
153            self.kind.is_unspec(),
154            "ocl::ImageCmd::read(): Operation kind \
155            already set for this command."
156        );
157        self.kind = ImageCmdKind::Read { data: dst_data };
158        self.block = true;
159        self
160    }
161
162    /// Specifies that this command will be a write operation.
163    ///
164    /// ## Panics
165    ///
166    /// The command operation kind must not have already been specified
167    ///
168    /// ### More Information
169    ///
170    /// See [SDK][read_buffer] docs for more details.
171    ///
172    /// [read_buffer]: https://www.khronos.org/registry/OpenCL/sdk/1.2/docs/man/xhtml/clEnqueueReadBuffer.html
173    pub fn write<'d>(mut self, src_data: &'d [T]) -> ImageCmd<'c, T>
174    where
175        'd: 'c,
176    {
177        assert!(
178            self.kind.is_unspec(),
179            "ocl::ImageCmd::write(): Operation kind \
180            already set for this command."
181        );
182        self.kind = ImageCmdKind::Write { data: src_data };
183        self
184    }
185
186    /// Specifies that this command will be a map operation.
187    ///
188    /// If `.block(..)` has been set it will be ignored. Non-blocking map
189    /// commands are enqueued using `::enq_async`.
190    ///
191    /// ## Safety
192    ///
193    /// The caller must ensure that only one mapping of a particular memory
194    /// region exists at a time.
195    ///
196    /// ## Panics
197    ///
198    /// The command operation kind must not have already been specified
199    ///
200    /// ### More Information
201    ///
202    /// See [SDK][map_image] docs for more details.
203    ///
204    /// [map_image]: https://www.khronos.org/registry/OpenCL/sdk/1.2/docs/man/xhtml/clEnqueueMapImage.html
205    pub unsafe fn map(mut self) -> ImageMapCmd<'c, T> {
206        assert!(
207            self.kind.is_unspec(),
208            "ocl::BufferCmd::write(): Operation kind \
209            already set for this command."
210        );
211        self.kind = ImageCmdKind::Map;
212
213        unimplemented!();
214        // ImageMapCmd { cmd: self }
215    }
216
217    /// Specifies that this command will be a copy operation.
218    ///
219    /// If `.block(..)` has been set it will be ignored.
220    ///
221    /// ## Errors
222    ///
223    /// If this is a rectangular copy, `dst_origin` and `len` must be zero.
224    ///
225    /// ## Panics
226    ///
227    /// The command operation kind must not have already been specified
228    ///
229    pub fn copy<'d>(mut self, dst_image: &'d Image<T>, dst_origin: [usize; 3]) -> ImageCmd<'c, T>
230    where
231        'd: 'c,
232    {
233        assert!(
234            self.kind.is_unspec(),
235            "ocl::ImageCmd::copy(): Operation kind \
236            already set for this command."
237        );
238        self.kind = ImageCmdKind::Copy {
239            dst_image: dst_image.as_core(),
240            dst_origin,
241        };
242        self
243    }
244
245    /// Specifies that this command will be a copy to image.
246    ///
247    /// If `.block(..)` has been set it will be ignored.
248    ///
249    /// ## Panics
250    ///
251    /// The command operation kind must not have already been specified
252    ///
253    pub fn copy_to_buffer<'d>(mut self, buffer: &'d MemCore, dst_offset: usize) -> ImageCmd<'c, T>
254    where
255        'd: 'c,
256    {
257        assert!(
258            self.kind.is_unspec(),
259            "ocl::ImageCmd::copy_to_buffer(): Operation kind \
260            already set for this command."
261        );
262        self.kind = ImageCmdKind::CopyToBuffer { buffer, dst_offset };
263        self
264    }
265
266    /// Specifies that this command will acquire a GL buffer.
267    ///
268    /// If `.block(..)` has been set it will be ignored.
269    ///
270    /// ## Panics
271    ///
272    /// The command operation kind must not have already been specified
273    ///
274    pub fn gl_acquire(mut self) -> ImageCmd<'c, T> {
275        assert!(
276            self.kind.is_unspec(),
277            "ocl::ImageCmd::gl_acquire(): Operation kind \
278            already set for this command."
279        );
280        self.kind = ImageCmdKind::GLAcquire;
281        self
282    }
283
284    /// Specifies that this command will release a GL buffer.
285    ///
286    /// If `.block(..)` has been set it will be ignored.
287    ///
288    /// ## Panics
289    ///
290    /// The command operation kind must not have already been specified
291    ///
292    pub fn gl_release(mut self) -> ImageCmd<'c, T> {
293        assert!(
294            self.kind.is_unspec(),
295            "ocl::ImageCmd::gl_release(): Operation kind \
296            already set for this command."
297        );
298        self.kind = ImageCmdKind::GLRelease;
299        self
300    }
301
302    /// Specifies that this command will acquire a D3D11 buffer.
303    ///
304    /// If `.block(..)` has been set it will be ignored.
305    ///
306    /// ## Panics
307    ///
308    /// The command operation kind must not have already been specified
309    ///
310    pub fn d3d11_acquire(mut self) -> ImageCmd<'c, T> {
311        assert!(
312            self.kind.is_unspec(),
313            "ocl::ImageCmd::d3d11_acquire(): Operation kind \
314            already set for this command."
315        );
316        self.kind = ImageCmdKind::D3D11Acquire;
317        self
318    }
319
320    /// Specifies that this command will release a D3D11 buffer.
321    ///
322    /// If `.block(..)` has been set it will be ignored.
323    ///
324    /// ## Panics
325    ///
326    /// The command operation kind must not have already been specified
327    ///
328    pub fn d3d11_release(mut self) -> ImageCmd<'c, T> {
329        assert!(
330            self.kind.is_unspec(),
331            "ocl::ImageCmd::d3d11_release(): Operation kind \
332            already set for this command."
333        );
334        self.kind = ImageCmdKind::D3D11Release;
335        self
336    }
337
338    /// Specifies that this command will be a fill.
339    ///
340    /// If `.block(..)` has been set it will be ignored.
341    ///
342    /// ## Panics
343    ///
344    /// The command operation kind must not have already been specified
345    ///
346    pub fn fill(mut self, color: T) -> ImageCmd<'c, T> {
347        assert!(
348            self.kind.is_unspec(),
349            "ocl::ImageCmd::fill(): Operation kind \
350            already set for this command."
351        );
352        self.kind = ImageCmdKind::Fill { color };
353        self
354    }
355
356    /// Specifies a queue to use for this call only.
357    ///
358    /// Overrides the image's default queue if one is set. If no default queue
359    /// is set, this method **must** be called before enqueuing the command.
360    pub fn queue(mut self, queue: &'c Queue) -> ImageCmd<'c, T> {
361        self.queue = Some(queue);
362        self
363    }
364
365    /// Specifies whether or not to block the current thread until completion.
366    ///
367    /// Ignored if this is not a read or write operation.
368    ///
369    /// Default is `block = true`.
370    ///
371    /// ## Safety
372    ///
373    /// When performing non-blocking reads or writes, the caller must ensure
374    /// that the data being read from or written to is not accessed improperly
375    /// until the command completes. Use events (`Event::wait_for`) or the
376    /// command queue (`Queue::finish`) to synchronize.
377    ///
378    /// If possible, prefer instead to use [`::map`] with [`::enq_async`] for
379    /// optimal performance and data integrity.
380    ///
381    /// [`::map`]: struct.ImageMapCmd.html
382    /// [`::enq_async`]: struct.ImageMapCmd.html#method.enq_async
383    ///
384    pub unsafe fn block(mut self, block: bool) -> ImageCmd<'c, T> {
385        self.block = block;
386        self
387    }
388
389    /// Sets the three dimensional offset, the origin point, for an operation.
390    ///
391    /// Defaults to [0, 0, 0] if not set.
392    ///
393    /// ## Panics
394    ///
395    /// The 'shape' may not have already been set to rectangular by the
396    /// `::rect` function.
397    pub fn origin<D>(mut self, origin: D) -> ImageCmd<'c, T>
398    where
399        D: Into<SpatialDims>,
400    {
401        self.origin = origin.into().to_offset().unwrap();
402        self
403    }
404
405    /// Sets the region size for an operation.
406    ///
407    /// Defaults to the full region size of the image(s) as defined when first
408    /// created if not set.
409    ///
410    /// ## Panics [TENATIVE]
411    ///
412    /// Panics if the region is out of range on any of the three dimensions.
413    ///
414    /// [FIXME]: Probably delay checking this until enq().
415    ///
416    pub fn region<D>(mut self, region: D) -> ImageCmd<'c, T>
417    where
418        D: Into<SpatialDims>,
419    {
420        self.region = region.into().to_lens().unwrap();
421        self
422    }
423
424    /// Sets the row and slice pitch for a read or write operation in bytes.
425    ///
426    /// `row_pitch_bytes`: Must be greater than or equal to the region width
427    /// in bytes (region[0] * sizeof(T)).
428    ///
429    /// `slice_pitch: Must be greater than or equal to `row_pitch` * region
430    /// height in bytes (region[1] * sizeof(T)).
431    ///
432    /// Only needs to be set if region has been set to something other than
433    /// the (default) image buffer size.
434    ///
435    pub unsafe fn pitch_bytes(
436        mut self,
437        row_pitch_bytes: usize,
438        slc_pitch_bytes: usize,
439    ) -> ImageCmd<'c, T> {
440        self.row_pitch_bytes = row_pitch_bytes;
441        self.slc_pitch_bytes = slc_pitch_bytes;
442        self
443    }
444
445    /// Specifies an event or list of events to wait on before the command
446    /// will run.
447    ///
448    /// When events generated using the `::enew` method of **other**,
449    /// previously enqueued commands are passed here (either individually or
450    /// as part of an [`EventList`]), this command will not execute until
451    /// those commands have completed.
452    ///
453    /// Using events can compliment the use of queues to order commands by
454    /// creating temporal dependencies between them (where commands in one
455    /// queue must wait for the completion of commands in another). Events can
456    /// also supplant queues altogether when, for example, using out-of-order
457    /// queues.
458    ///
459    /// # Example
460    ///
461    /// ```rust,ignore
462    /// // Create an event list:
463    /// let mut event_list = EventList::new();
464    /// // Enqueue a kernel on `queue_1`, creating an event representing the kernel
465    /// // command in our list:
466    /// kernel.cmd().queue(&queue_1).enew(&mut event_list).enq()?;
467    /// // Read from a buffer using `queue_2`, ensuring the read does not begin until
468    /// // after the kernel command has completed:
469    /// buffer.read(rwvec.clone()).queue(&queue_2).ewait(&event_list).enq_async()?;
470    /// ```
471    ///
472    /// [`EventList`]: struct.EventList.html
473    pub fn ewait<'e, Ewl>(mut self, ewait: Ewl) -> ImageCmd<'c, T>
474    where
475        'e: 'c,
476        Ewl: Into<ClWaitListPtrEnum<'e>>,
477    {
478        self.ewait = Some(ewait.into());
479        self
480    }
481
482    /// Specifies the destination to store a new, optionally created event
483    /// associated with this command.
484    ///
485    /// The destination can be a mutable reference to an empty event (created
486    /// using [`Event::empty`]) or a mutable reference to an event list.
487    ///
488    /// After this command is enqueued, the event in the destination can be
489    /// passed to the `::ewait` method of another command. Doing so will cause
490    /// the other command to wait until this command has completed before
491    /// executing.
492    ///
493    /// Using events can compliment the use of queues to order commands by
494    /// creating temporal dependencies between them (where commands in one
495    /// queue must wait for the completion of commands in another). Events can
496    /// also supplant queues altogether when, for example, using out-of-order
497    /// queues.
498    ///
499    /// # Example
500    ///
501    /// ```rust,ignore
502    /// // Create an event list:
503    /// let mut event = Event::empty();
504    /// // Enqueue a kernel on `queue_1`, creating an event representing the kernel
505    /// // command in our list:
506    /// kernel.cmd().queue(&queue_1).enew(&mut event).enq()?;
507    /// // Read from a buffer using `queue_2`, ensuring the read does not begin until
508    /// // after the kernel command has completed:
509    /// buffer.read(rwvec.clone()).queue(&queue_2).ewait(&event).enq_async()?;
510    /// ```
511    ///
512    /// [`Event::empty`]: struct.Event.html#method.empty
513    pub fn enew<'e, En>(mut self, enew: En) -> ImageCmd<'c, T>
514    where
515        'e: 'c,
516        En: Into<ClNullEventPtrEnum<'e>>,
517    {
518        self.enew = Some(enew.into());
519        self
520    }
521
522    /// Enqueues this command.
523    ///
524    /// * TODO: FOR COPY, FILL, AND COPYTOBUFFER -- ENSURE PITCHES ARE BOTH
525    ///   UNSET.
526    pub fn enq(self) -> OclResult<()> {
527        let queue = match self.queue {
528            Some(q) => q,
529            None => return Err("ImageCmd::enq: No queue set.".into()),
530        };
531
532        match self.kind {
533            ImageCmdKind::Read { data } => {
534                unsafe { core::enqueue_read_image(queue, self.obj_core, self.block,
535                    self.origin, self.region, self.row_pitch_bytes, self.slc_pitch_bytes, data, self.ewait,
536                    self.enew) }
537            },
538            ImageCmdKind::Write { data } => {
539                unsafe {
540                    core::enqueue_write_image(queue, self.obj_core, self.block,
541                        self.origin, self.region, self.row_pitch_bytes, self.slc_pitch_bytes, data, self.ewait,
542                        self.enew)
543                }
544            },
545            ImageCmdKind::Copy { dst_image, dst_origin } => {
546                core::enqueue_copy_image(queue, self.obj_core, dst_image, self.origin,
547                    dst_origin, self.region, self.ewait, self.enew)
548            },
549            ImageCmdKind::CopyToBuffer { buffer, dst_offset } => {
550                core::enqueue_copy_image_to_buffer::<T, _, _, _>(queue, self.obj_core, buffer, self.origin,
551                    self.region, dst_offset, self.ewait, self.enew)
552            },
553
554            #[cfg(not(feature="opencl_vendor_mesa"))]
555            ImageCmdKind::GLAcquire => {
556                // core::enqueue_acquire_gl_buffer(queue, self.obj_core, self.ewait, self.enew)
557                let buf_slc = unsafe { std::slice::from_raw_parts(self.obj_core, 1) };
558                core::enqueue_acquire_gl_objects(queue, buf_slc, self.ewait, self.enew)
559            },
560
561            #[cfg(not(feature="opencl_vendor_mesa"))]
562            ImageCmdKind::GLRelease => {
563                // core::enqueue_release_gl_buffer(queue, self.obj_core, self.ewait, self.enew)
564                let buf_slc = unsafe { std::slice::from_raw_parts(self.obj_core, 1) };
565                core::enqueue_release_gl_objects(queue, buf_slc, self.ewait, self.enew)
566            },
567
568            ImageCmdKind::D3D11Acquire => {
569                match self.ext_fns {
570                    Some(fns) => {
571                        let buf_slc = unsafe { std::slice::from_raw_parts(self.obj_core, 1) };
572                        core::enqueue_acquire_d3d11_objects(queue, buf_slc, self.ewait, self.enew, fns)
573                    }
574                    None => Err("ocl::ImageCmd::enq(): The function pointer to clEnqueueAcquireD3D11Objects was not resolved.".into())
575                }
576            },
577            ImageCmdKind::D3D11Release => {
578                match self.ext_fns {
579                    Some(fns) => {
580                        let buf_slc = unsafe { std::slice::from_raw_parts(self.obj_core, 1) };
581                        core::enqueue_release_d3d11_objects(queue, buf_slc, self.ewait, self.enew, fns)
582                    }
583                    None => Err("ocl::ImageCmd::enq(): The function pointer to clEnqueueReleaseD3D11Objects was not resolved.".into())
584                }
585            },
586
587            ImageCmdKind::Unspecified => Err("ocl::ImageCmd::enq(): No operation \
588                specified. Use '.read(...)', 'write(...)', etc. before calling '.enq()'.".into()),
589            _ => unimplemented!(),
590        }.map_err(OclError::from)
591    }
592}
593
594/// A buffer command builder used to enqueue maps.
595///
596/// See [SDK][map_buffer] docs for more details.
597///
598/// [map_buffer]: https://www.khronos.org/registry/OpenCL/sdk/1.2/docs/man/xhtml/clEnqueueMapBuffer.html
599
600// const size_t  * origin ,
601// const size_t  * region ,
602// size_t  *image_row_pitch ,
603// size_t  *image_slice_pitch ,
604
605pub struct ImageMapCmd<'c, T>
606where
607    T: 'c,
608{
609    cmd: ImageCmd<'c, T>,
610    flags: Option<MapFlags>,
611}
612
613impl<'c, T> ImageMapCmd<'c, T>
614where
615    T: OclPrm,
616{
617    /// Specifies the flags to be used with this map command.
618    ///
619    /// See [SDK] docs for more details.
620    ///
621    /// [SDK]: https://www.khronos.org/registry/OpenCL/sdk/1.2/docs/man/xhtml/clEnqueueMapBuffer.html
622    pub fn flags(mut self, flags: MapFlags) -> ImageMapCmd<'c, T> {
623        self.flags = Some(flags);
624        self
625    }
626
627    /// Sets the three dimensional offset, the origin point, for an operation.
628    ///
629    /// Defaults to [0, 0, 0] if not set.
630    ///
631    /// ## Panics
632    ///
633    /// The 'shape' may not have already been set to rectangular by the
634    /// `::rect` function.
635    pub fn origin(mut self, origin: [usize; 3]) -> ImageMapCmd<'c, T> {
636        self.cmd.origin = origin;
637        self
638    }
639
640    /// Sets the region size for an operation.
641    ///
642    /// Defaults to the full region size of the image(s) as defined when first
643    /// created if not set.
644    ///
645    /// ## Panics [TENATIVE]
646    ///
647    /// Panics if the region is out of range on any of the three dimensions.
648    ///
649    /// [FIXME]: Probably delay checking this until enq().
650    ///
651    pub fn region(mut self, region: [usize; 3]) -> ImageMapCmd<'c, T> {
652        self.cmd.region = region;
653        self
654    }
655
656    /// Specifies an event or list of events to wait on before the command
657    /// will run.
658    ///
659    /// When events generated using the `::enew` method of **other**,
660    /// previously enqueued commands are passed here (either individually or
661    /// as part of an [`EventList`]), this command will not execute until
662    /// those commands have completed.
663    ///
664    /// Using events can compliment the use of queues to order commands by
665    /// creating temporal dependencies between them (where commands in one
666    /// queue must wait for the completion of commands in another). Events can
667    /// also supplant queues altogether when, for example, using out-of-order
668    /// queues.
669    ///
670    /// # Example
671    ///
672    /// ```rust,ignore
673    /// // Create an event list:
674    /// let mut event_list = EventList::new();
675    /// // Enqueue a kernel on `queue_1`, creating an event representing the kernel
676    /// // command in our list:
677    /// kernel.cmd().queue(&queue_1).enew(&mut event_list).enq()?;
678    /// // Read from a buffer using `queue_2`, ensuring the read does not begin until
679    /// // after the kernel command has completed:
680    /// buffer.read(rwvec.clone()).queue(&queue_2).ewait(&event_list).enq_async()?;
681    /// ```
682    ///
683    /// [`EventList`]: struct.EventList.html
684    pub fn ewait<'e, Ewl>(mut self, ewait: Ewl) -> ImageMapCmd<'c, T>
685    where
686        'e: 'c,
687        Ewl: Into<ClWaitListPtrEnum<'e>>,
688    {
689        self.cmd.ewait = Some(ewait.into());
690        self
691    }
692
693    /// Specifies the destination to store a new, optionally created event
694    /// associated with this command.
695    ///
696    /// The destination can be a mutable reference to an empty event (created
697    /// using [`Event::empty`]) or a mutable reference to an event list.
698    ///
699    /// After this command is enqueued, the event in the destination can be
700    /// passed to the `::ewait` method of another command. Doing so will cause
701    /// the other command to wait until this command has completed before
702    /// executing.
703    ///
704    /// Using events can compliment the use of queues to order commands by
705    /// creating temporal dependencies between them (where commands in one
706    /// queue must wait for the completion of commands in another). Events can
707    /// also supplant queues altogether when, for example, using out-of-order
708    /// queues.
709    ///
710    /// # Example
711    ///
712    /// ```rust,ignore
713    /// // Create an event list:
714    /// let mut event = Event::empty();
715    /// // Enqueue a kernel on `queue_1`, creating an event representing the kernel
716    /// // command in our list:
717    /// kernel.cmd().queue(&queue_1).enew(&mut event).enq()?;
718    /// // Read from a buffer using `queue_2`, ensuring the read does not begin until
719    /// // after the kernel command has completed:
720    /// buffer.read(rwvec.clone()).queue(&queue_2).ewait(&event).enq_async()?;
721    /// ```
722    ///
723    /// [`Event::empty`]: struct.Event.html#method.empty
724    pub fn enew<'e, En>(mut self, enew: En) -> ImageMapCmd<'c, T>
725    where
726        'e: 'c,
727        En: Into<ClNullEventPtrEnum<'e>>,
728    {
729        self.cmd.enew = Some(enew.into());
730        self
731    }
732
733    /// Enqueues this command.
734    ///
735    /// * TODO: FOR COPY, FILL, AND COPYTOBUFFER -- ENSURE PITCHES ARE BOTH UNSET.
736    #[allow(unused_variables, unreachable_code)]
737    pub fn enq(self) -> OclResult<MemMap<T>> {
738        let queue = match self.cmd.queue {
739            Some(q) => q,
740            None => return Err("ImageCmd::enq: No queue set.".into()),
741        };
742
743        let flags = self.flags.unwrap_or(MapFlags::empty());
744
745        match self.cmd.kind {
746            ImageCmdKind::Map => {
747                // try!(check_len(self.cmd.to_len, data.len(), offset));
748
749                let mut row_pitch_bytes = 0usize;
750                let mut slc_pitch_bytes = 0usize;
751
752                unsafe {
753                    let mm_core = core::enqueue_map_image::<T, _, _, _>(
754                        queue,
755                        self.cmd.obj_core,
756                        self.cmd.block,
757                        flags,
758                        self.cmd.origin,
759                        self.cmd.region,
760                        &mut row_pitch_bytes,
761                        &mut slc_pitch_bytes,
762                        self.cmd.ewait,
763                        self.cmd.enew,
764                    )?;
765
766                    let len_bytes = if slc_pitch_bytes == 0 {
767                        // 1D or 2D image.
768                        unimplemented!();
769                    } else {
770                        // 1D image array, 2D image array, or 3D image.
771                        unimplemented!();
772                    };
773
774                    // let unmap_event = None;
775
776                    // * TODO: Create a special container for mapped images
777                    // that can take into account row and slice pitch. It
778                    // cannot deref into a &[T] as the size of rows (and
779                    // slices) can vary with byte-sized precision.
780
781                    // Ok(MemMap::new(mm_core, 0, unmap_event, self.cmd.obj_core.clone(),
782                    //     queue.core().clone()))
783                }
784            }
785            _ => unreachable!(),
786        }
787    }
788}
789
790/// A section of device memory which represents one or many images.
791///
792/// Use `::builder` for an easy way to create. [UNIMPLEMENTED]
793///
794#[derive(Clone, Debug)]
795pub struct Image<T: OclPrm> {
796    obj_core: MemCore,
797    queue: Option<Queue>,
798    dims: SpatialDims,
799    pixel_element_len: usize,
800    extension_functions: Option<core::ExtensionFunctions>,
801    _pixel: PhantomData<T>,
802}
803
804impl<T: OclPrm> Image<T> {
805    /// Returns a list of supported image formats.
806    pub fn supported_formats(
807        context: &Context,
808        flags: MemFlags,
809        mem_obj_type: MemObjectType,
810    ) -> OclResult<Vec<ImageFormatParseResult>> {
811        core::get_supported_image_formats(context, flags, mem_obj_type).map_err(OclError::from)
812    }
813
814    /// Returns an `ImageBuilder`. This is the recommended method to create
815    /// a new `Image`.
816    pub fn builder<'a>() -> ImageBuilder<'a, T> {
817        ImageBuilder::new()
818    }
819
820    /// Returns a new `Image`.
821    ///
822    /// Prefer `::builder` to create a new image.
823    pub unsafe fn new<'o, Q>(
824        que_ctx: Q,
825        flags: MemFlags,
826        image_format: ImageFormat,
827        image_desc: ImageDescriptor,
828        host_data: Option<&[T]>,
829    ) -> OclResult<Image<T>>
830    where
831        Q: Into<QueCtx<'o>>,
832    {
833        let que_ctx = que_ctx.into();
834        let context = que_ctx.context_cloned();
835        let device_versions = context.device_versions()?;
836
837        let obj_core = core::create_image(
838            &context,
839            flags,
840            &image_format,
841            &image_desc,
842            host_data,
843            Some(&device_versions),
844        )?;
845
846        let pixel_element_len = match core::get_image_info(&obj_core, ImageInfo::ElementSize)? {
847            ImageInfoResult::ElementSize(s) => s / mem::size_of::<T>(),
848            _ => {
849                return Err("ocl::Image::element_len(): \
850                Unexpected 'ImageInfoResult' variant."
851                    .into())
852            }
853        };
854
855        let dims = [
856            image_desc.image_width,
857            image_desc.image_height,
858            image_desc.image_depth,
859        ]
860        .into();
861
862        let new_img = Image {
863            obj_core,
864            queue: que_ctx.into(),
865            dims,
866            pixel_element_len,
867            extension_functions: None,
868            _pixel: PhantomData,
869        };
870
871        Ok(new_img)
872    }
873
874    /// Returns a new `Image` from an existant GL texture2D/3D.
875    ///
876    /// Remember to specify the GL context when creating the CL context,
877    /// using `.properties(ocl_interop::get_properties_list())`
878    ///
879    /// Don't forget to `.cmd().gl_acquire().enq()` before using it and
880    /// `.cmd().gl_release().enq()` after.
881    ///
882    // [WORK IN PROGRESS]
883    #[cfg(not(feature = "opencl_vendor_mesa"))]
884    pub fn from_gl_texture<'o, Q>(
885        que_ctx: Q,
886        flags: MemFlags,
887        image_desc: ImageDescriptor,
888        texture_target: GlTextureTarget,
889        miplevel: cl_GLint,
890        texture: cl_GLuint,
891    ) -> OclResult<Image<T>>
892    where
893        Q: Into<QueCtx<'o>>,
894    {
895        let que_ctx = que_ctx.into();
896        let context = que_ctx.context_cloned();
897        let device_versions = context.device_versions()?;
898
899        if texture_target == GlTextureTarget::GlTextureBuffer && miplevel != 0 {
900            return Err(
901                "If texture_target is GL_TEXTURE_BUFFER, miplevel must be 0.\
902                Implementations may return CL_INVALID_OPERATION for miplevel values > 0"
903                    .into(),
904            );
905        }
906
907        let obj_core = unsafe {
908            core::create_from_gl_texture(
909                &context,
910                texture_target as u32,
911                miplevel,
912                texture,
913                flags,
914                Some(&device_versions),
915            )?
916        };
917
918        // FIXME can I do this from a GLTexture ?
919        let pixel_element_len = match core::get_image_info(&obj_core, ImageInfo::ElementSize)? {
920            ImageInfoResult::ElementSize(s) => s / mem::size_of::<T>(),
921            _ => {
922                return Err("ocl::Image::element_len(): Unexpected \
923                'ImageInfoResult' variant."
924                    .into())
925            }
926        };
927
928        let dims = [
929            image_desc.image_width,
930            image_desc.image_height,
931            image_desc.image_depth,
932        ]
933        .into();
934
935        let new_img = Image {
936            obj_core,
937            queue: que_ctx.into(),
938            dims,
939            pixel_element_len,
940            extension_functions: None,
941            _pixel: PhantomData,
942        };
943
944        Ok(new_img)
945    }
946
947    /// Returns a new `Image` from an existant renderbuffer.
948    ///
949    /// Remember to specify the GL context when creating the CL context,
950    /// using `.properties(ocl_interop::get_properties_list())`
951    ///
952    /// Don't forget to `.cmd().gl_acquire().enq()` before using it and
953    /// `.cmd().gl_release().enq()` after.
954    ///
955    // [WORK IN PROGRESS]
956    #[cfg(not(feature = "opencl_vendor_mesa"))]
957    pub fn from_gl_renderbuffer<'o, Q>(
958        que_ctx: Q,
959        flags: MemFlags,
960        image_desc: ImageDescriptor,
961        renderbuffer: cl_GLuint,
962    ) -> OclResult<Image<T>>
963    where
964        Q: Into<QueCtx<'o>>,
965    {
966        let que_ctx = que_ctx.into();
967        let context = que_ctx.context_cloned();
968
969        let obj_core = unsafe { core::create_from_gl_renderbuffer(&context, renderbuffer, flags)? };
970
971        // FIXME can I do this from a renderbuffer ?
972        let pixel_element_len = match core::get_image_info(&obj_core, ImageInfo::ElementSize)? {
973            ImageInfoResult::ElementSize(s) => s / mem::size_of::<T>(),
974            _ => {
975                return Err("ocl::Image::element_len(): \
976                Unexpected 'ImageInfoResult' variant."
977                    .into())
978            }
979        };
980
981        let dims = [image_desc.image_width, image_desc.image_height].into();
982
983        let new_img = Image {
984            obj_core,
985            queue: que_ctx.into(),
986            dims,
987            pixel_element_len,
988            extension_functions: None,
989            _pixel: PhantomData,
990        };
991
992        Ok(new_img)
993    }
994
995    /// Returns a new `Image` from an existant ID3D11Texture2D.
996    ///
997    /// Remember to specify the D3D11 device when creating the CL context,
998    /// using `.properties()` and `.set_property_value(ContextPropertyValue::D3d11DeviceKhr(<pointer to ID3D11Device>))`
999    ///
1000    /// Don't forget to `.cmd().d3d11_acquire().enq()` before using it and
1001    /// `.cmd().d3d11_release().enq()` after.
1002    ///
1003    pub fn from_d3d11_texture2d<'o, Q>(
1004        que_ctx: Q,
1005        flags: MemFlags,
1006        image_desc: ImageDescriptor,
1007        texture: cl_id3d11_texture2d,
1008        subresource: u32,
1009    ) -> OclResult<Image<T>>
1010    where
1011        Q: Into<QueCtx<'o>>,
1012    {
1013        let que_ctx = que_ctx.into();
1014        let context = que_ctx.context_cloned();
1015        let device_versions = context.device_versions()?;
1016
1017        let extension_fns = match context.platform()? {
1018            Some(platform) => core::ExtensionFunctions::resolve_all(*platform)?,
1019            _ => {
1020                return Err(
1021                    "ocl::Image::from_d3d11_texture2d(): Platform must be set in context.".into(),
1022                )
1023            }
1024        };
1025
1026        let obj_core = unsafe {
1027            core::create_from_d3d11_texture2d(
1028                &context,
1029                texture,
1030                subresource as cl_uint,
1031                flags,
1032                Some(&device_versions),
1033                &extension_fns,
1034            )?
1035        };
1036
1037        let pixel_element_len = match core::get_image_info(&obj_core, ImageInfo::ElementSize)? {
1038            ImageInfoResult::ElementSize(s) => s / mem::size_of::<T>(),
1039            _ => {
1040                return Err("ocl::Image::element_len(): Unexpected \
1041                'ImageInfoResult' variant."
1042                    .into())
1043            }
1044        };
1045
1046        let dims = [
1047            image_desc.image_width,
1048            image_desc.image_height,
1049            image_desc.image_depth,
1050        ]
1051        .into();
1052
1053        let new_img = Image {
1054            obj_core,
1055            queue: que_ctx.into(),
1056            dims,
1057            pixel_element_len,
1058            extension_functions: Some(extension_fns),
1059            _pixel: PhantomData,
1060        };
1061
1062        Ok(new_img)
1063    }
1064
1065    /// Returns a new `Image` from an existant ID3D11Texture2D.
1066    ///
1067    /// Remember to specify the D3D11 device when creating the CL context,
1068    /// using `.properties()` and `.set_property_value(ContextPropertyValue::D3d11DeviceKhr(<pointer to ID3D11Device>))`
1069    ///
1070    /// Don't forget to `.cmd().d3d11_acquire().enq()` before using it and
1071    /// `.cmd().d3d11_release().enq()` after.
1072    ///
1073    pub fn from_d3d11_texture3d<'o, Q>(
1074        que_ctx: Q,
1075        flags: MemFlags,
1076        image_desc: ImageDescriptor,
1077        texture: cl_id3d11_texture3d,
1078        subresource: u32,
1079    ) -> OclResult<Image<T>>
1080    where
1081        Q: Into<QueCtx<'o>>,
1082    {
1083        let que_ctx = que_ctx.into();
1084        let context = que_ctx.context_cloned();
1085        let device_versions = context.device_versions()?;
1086
1087        let extension_fns = match context.platform()? {
1088            Some(platform) => core::ExtensionFunctions::resolve_all(*platform)?,
1089            _ => {
1090                return Err(
1091                    "ocl::Image::from_d3d11_texture3d(): Platform must be set in context.".into(),
1092                )
1093            }
1094        };
1095
1096        let obj_core = unsafe {
1097            core::create_from_d3d11_texture3d(
1098                &context,
1099                texture,
1100                subresource as cl_uint,
1101                flags,
1102                Some(&device_versions),
1103                &extension_fns,
1104            )?
1105        };
1106
1107        let pixel_element_len = match core::get_image_info(&obj_core, ImageInfo::ElementSize)? {
1108            ImageInfoResult::ElementSize(s) => s / mem::size_of::<T>(),
1109            _ => {
1110                return Err("ocl::Image::element_len(): Unexpected \
1111                'ImageInfoResult' variant."
1112                    .into())
1113            }
1114        };
1115
1116        let dims = [
1117            image_desc.image_width,
1118            image_desc.image_height,
1119            image_desc.image_depth,
1120        ]
1121        .into();
1122
1123        let new_img = Image {
1124            obj_core,
1125            queue: que_ctx.into(),
1126            dims,
1127            pixel_element_len,
1128            extension_functions: Some(extension_fns),
1129            _pixel: PhantomData,
1130        };
1131
1132        Ok(new_img)
1133    }
1134
1135    /// Returns an image command builder used to read, write, copy, etc.
1136    ///
1137    /// Call `.enq()` to enqueue the command.
1138    ///
1139    /// See the [command builder documentation](struct.ImageCmd)
1140    /// for more details.
1141    pub fn cmd(&self) -> ImageCmd<T> {
1142        ImageCmd::new(
1143            self.queue.as_ref(),
1144            &self.obj_core,
1145            self.dims.to_lens().expect("ocl::Image::cmd"),
1146            self.extension_functions.as_ref(),
1147        )
1148    }
1149
1150    /// Returns an image command builder set to read.
1151    ///
1152    /// Call `.enq()` to enqueue the command.
1153    ///
1154    /// See the [command builder documentation](struct.ImageCmd#method.read)
1155    /// for more details.
1156    pub fn read<'c, 'd>(&'c self, data: &'d mut [T]) -> ImageCmd<'c, T>
1157    where
1158        'd: 'c,
1159    {
1160        self.cmd().read(data)
1161    }
1162
1163    /// Returns an image command builder set to write.
1164    ///
1165    /// Call `.enq()` to enqueue the command.
1166    ///
1167    /// See the [command builder documentation](struct.ImageCmd#method.write)
1168    /// for more details.
1169    pub fn write<'c, 'd>(&'c self, data: &'d [T]) -> ImageCmd<'c, T>
1170    where
1171        'd: 'c,
1172    {
1173        self.cmd().write(data)
1174    }
1175
1176    /// Returns a command builder used to map data for reading or writing.
1177    ///
1178    /// Call `.enq()` to enqueue the command.
1179    ///
1180    /// ## Safety
1181    ///
1182    /// The caller must ensure that only one mapping of a particular memory
1183    /// region exists at a time.
1184    ///
1185    /// See the [command builder documentation](struct.ImageCmd#method.map)
1186    /// for more details.
1187    ///
1188    #[inline]
1189    pub unsafe fn map<'c>(&'c self) -> ImageMapCmd<'c, T> {
1190        unimplemented!();
1191        // self.cmd().map()
1192    }
1193
1194    // /// Specifies that this command will be a copy operation.
1195    // ///
1196    // /// Call `.enq()` to enqueue the command.
1197    // ///
1198    // /// See the [command builder documentation](struct.ImageCmd#method.copy)
1199    // /// for more details.
1200    // ///
1201    // #[inline]
1202    // pub fn copy<'c, M>(&'c self, dst_buffer: &'c M, dst_offset: Option<usize>, len: Option<usize>)
1203    //         -> BufferCmd<'c, T>
1204    //         where M: AsMem
1205    // {
1206    //     self.cmd().copy(dst_buffer, dst_offset, len)
1207    // }
1208
1209    /// Changes the default queue.
1210    ///
1211    /// Returns a ref for chaining i.e.:
1212    ///
1213    /// `image.set_default_queue(queue).write(....);`
1214    ///
1215    /// [NOTE]: Even when used as above, the queue is changed permanently,
1216    /// not just for the one call. Changing the queue is cheap so feel free
1217    /// to change as often as needed.
1218    ///
1219    /// The new queue must be associated with a valid device.
1220    ///
1221    pub fn set_default_queue<'a>(&'a mut self, queue: Queue) -> &'a mut Image<T> {
1222        // self.command_queue_obj_core = queue.core().clone();
1223        self.queue = Some(queue);
1224        self
1225    }
1226
1227    /// Returns a reference to the default queue.
1228    pub fn default_queue(&self) -> Option<&Queue> {
1229        self.queue.as_ref()
1230    }
1231
1232    /// Returns this image's dimensions.
1233    pub fn dims(&self) -> &SpatialDims {
1234        &self.dims
1235    }
1236
1237    /// Returns the total number of pixels in this image.
1238    pub fn pixel_count(&self) -> usize {
1239        self.dims.to_len()
1240    }
1241
1242    /// Returns the length of each pixel element.
1243    pub fn pixel_element_len(&self) -> usize {
1244        self.pixel_element_len
1245    }
1246
1247    /// Returns the total number of pixel elements in this image. Equivalent to its length.
1248    pub fn element_count(&self) -> usize {
1249        self.pixel_count() * self.pixel_element_len()
1250    }
1251
1252    /// Get information about this image.
1253    pub fn info(&self, info_kind: ImageInfo) -> OclResult<ImageInfoResult> {
1254        // match core::get_image_info(&self.obj_core, info_kind) {
1255        //     Ok(res) => res,
1256        //     Err(err) => ImageInfoResult::Error(Box::new(err)),
1257        // }
1258        core::get_image_info(&self.obj_core, info_kind).map_err(OclError::from)
1259    }
1260
1261    /// Returns info about this image's memory.
1262    pub fn mem_info(&self, info_kind: MemInfo) -> OclResult<MemInfoResult> {
1263        // match core::get_mem_object_info(&self.obj_core, info_kind) {
1264        //     Ok(res) => res,
1265        //     Err(err) => MemInfoResult::Error(Box::new(err)),
1266        // }
1267        core::get_mem_object_info(&self.obj_core, info_kind).map_err(OclError::from)
1268    }
1269
1270    /// Returns a reference to the core pointer wrapper, usable by functions in
1271    /// the `core` module.
1272    #[inline]
1273    pub fn as_core(&self) -> &MemCore {
1274        &self.obj_core
1275    }
1276
1277    /// Format image info.
1278    fn fmt_info(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1279        f.debug_struct("Image")
1280            .field("ElementSize", &self.info(ImageInfo::ElementSize))
1281            .field("RowPitch", &self.info(ImageInfo::RowPitch))
1282            .field("SlicePitch", &self.info(ImageInfo::SlicePitch))
1283            .field("Width", &self.info(ImageInfo::Width))
1284            .field("Height", &self.info(ImageInfo::Height))
1285            .field("Depth", &self.info(ImageInfo::Depth))
1286            .field("ArraySize", &self.info(ImageInfo::ArraySize))
1287            .field("Buffer", &self.info(ImageInfo::Buffer))
1288            .field("NumMipLevels", &self.info(ImageInfo::NumMipLevels))
1289            .field("NumSamples", &self.info(ImageInfo::NumSamples))
1290            .finish()
1291    }
1292
1293    /// Format image mem info.
1294    fn fmt_mem_info(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1295        f.debug_struct("Mem")
1296            .field("Type", &self.mem_info(MemInfo::Type))
1297            .field("Flags", &self.mem_info(MemInfo::Flags))
1298            .field("Size", &self.mem_info(MemInfo::Size))
1299            .field("HostPtr", &self.mem_info(MemInfo::HostPtr))
1300            .field("MapCount", &self.mem_info(MemInfo::MapCount))
1301            .field("ReferenceCount", &self.mem_info(MemInfo::ReferenceCount))
1302            .field("Context", &self.mem_info(MemInfo::Context))
1303            .field(
1304                "AssociatedMemobject",
1305                &self.mem_info(MemInfo::AssociatedMemobject),
1306            )
1307            .field("Offset", &self.mem_info(MemInfo::Offset))
1308            .finish()
1309    }
1310}
1311
1312impl<T: OclPrm> std::fmt::Display for Image<T> {
1313    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1314        self.fmt_info(f)?;
1315        write!(f, " ")?;
1316        self.fmt_mem_info(f)
1317    }
1318}
1319
1320impl<T: OclPrm> Deref for Image<T> {
1321    type Target = MemCore;
1322
1323    fn deref(&self) -> &MemCore {
1324        &self.obj_core
1325    }
1326}
1327
1328impl<T: OclPrm> DerefMut for Image<T> {
1329    fn deref_mut(&mut self) -> &mut MemCore {
1330        &mut self.obj_core
1331    }
1332}
1333
1334impl<T: OclPrm> AsMem<T> for Image<T> {
1335    fn as_mem(&self) -> &MemCore {
1336        &self.obj_core
1337    }
1338}
1339
1340unsafe impl<'a, T> MemCmdRw for Image<T> where T: OclPrm {}
1341unsafe impl<'a, T> MemCmdRw for &'a Image<T> where T: OclPrm {}
1342unsafe impl<'a, T> MemCmdRw for &'a mut Image<T> where T: OclPrm {}
1343unsafe impl<'a, T> MemCmdAll for Image<T> where T: OclPrm {}
1344unsafe impl<'a, T> MemCmdAll for &'a Image<T> where T: OclPrm {}
1345unsafe impl<'a, T> MemCmdAll for &'a mut Image<T> where T: OclPrm {}
1346
1347/// A builder for `Image`.
1348#[must_use = "builders do nothing unless '::build' is called"]
1349pub struct ImageBuilder<'a, T>
1350where
1351    T: 'a,
1352{
1353    queue_option: Option<QueCtx<'a>>,
1354    flags: MemFlags,
1355    host_slice: HostSlice<'a, T>,
1356    image_format: ImageFormat,
1357    image_desc: ImageDescriptor,
1358    _pixel: PhantomData<T>,
1359}
1360
1361impl<'a, T> ImageBuilder<'a, T>
1362where
1363    T: 'a + OclPrm,
1364{
1365    /// Returns a new `ImageBuilder` with very basic defaults.
1366    ///
1367    /// ## Defaults
1368    ///
1369    /// * Flags:
1370    ///
1371    /// ```rust,ignore
1372    /// ocl::MEM_READ_WRITE
1373    /// ```
1374    ///
1375    /// * Image Format:
1376    ///
1377    /// ```rust,ignore
1378    /// ocl::ImageFormat {
1379    ///    channel_order: ocl::ImageChannelOrder::Rgba,
1380    ///    channel_data_type: ocl::ImageChannelDataType::SnormInt8,
1381    /// }
1382    /// ```
1383    ///
1384    /// * Descriptor (stores everything else - width, height, pitch, etc.):
1385    ///
1386    /// ```rust,ignore
1387    /// ImageDescriptor::new(MemObjectType::Image1d, 0, 0, 0, 0, 0, 0, None)
1388    /// ```
1389    ///
1390    /// ## Reference
1391    ///
1392    /// See the [official SDK documentation] for more information.
1393    ///
1394    /// Some descriptions here are adapted from various SDK docs.
1395    ///
1396    /// [official SDK docs]: https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clCreateImage.html
1397    pub fn new() -> ImageBuilder<'a, T> {
1398        ImageBuilder {
1399            queue_option: None,
1400            flags: core::MEM_READ_WRITE,
1401            host_slice: HostSlice::None,
1402            image_format: ImageFormat::new_rgba(),
1403            image_desc: ImageDescriptor::new(MemObjectType::Image1d, 0, 0, 0, 0, 0, 0, None),
1404            _pixel: PhantomData,
1405        }
1406    }
1407
1408    /// Sets the context with which to associate the buffer.
1409    ///
1410    /// May not be used in combination with `::queue` (use one or the other).
1411    pub fn context<'o>(mut self, context: &'o Context) -> ImageBuilder<'a, T>
1412    where
1413        'o: 'a,
1414    {
1415        assert!(self.queue_option.is_none());
1416        self.queue_option = Some(QueCtx::Context(context));
1417        self
1418    }
1419
1420    /// Sets the default queue.
1421    ///
1422    /// If this is set, the context associated with the `default_queue` will
1423    /// be used when creating the buffer (use one or the other).
1424    pub fn queue<'b>(mut self, default_queue: Queue) -> ImageBuilder<'a, T> {
1425        assert!(self.queue_option.is_none());
1426        self.queue_option = Some(QueCtx::Queue(default_queue));
1427        self
1428    }
1429
1430    /// Sets the flags used when creating the image.
1431    ///
1432    /// Defaults to `flags::MEM_READ_WRITE` aka.
1433    /// `MemFlags::new().read_write()` if this is not set. See the [SDK Docs]
1434    /// for more information about flags. Note that the names of all flags in
1435    /// this library have the `CL_` prefix removed for brevity.
1436    ///
1437    /// ### Panics
1438    ///
1439    /// Due to its unsafety, setting the
1440    /// `MEM_USE_HOST_PTR`/`MemFlags::new()::use_host_ptr()` flag will cause a
1441    /// panic. Use the `::use_host_slice` method instead.
1442    ///
1443    /// [SDK Docs]: https://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clCreateBuffer.html
1444    pub fn flags(mut self, flags: MemFlags) -> ImageBuilder<'a, T> {
1445        assert!(
1446            !flags.contains(MemFlags::new().use_host_ptr()),
1447            "The `ImageBuilder::flags` method may not be used to set the \
1448            `MEM_USE_HOST_PTR` flag. Use the `::use_host_ptr` method instead."
1449        );
1450        self.flags = flags;
1451        self
1452    }
1453
1454    /// Specifies a region of host memory to use as storage for the image.
1455    ///
1456    /// OpenCL implementations are allowed to cache the image contents
1457    /// pointed to by `host_slice` in device memory. This cached copy can be
1458    /// used when kernels are executed on a device.
1459    ///
1460    /// The result of OpenCL commands that operate on multiple image objects
1461    /// created with the same `host_slice` or overlapping host regions is
1462    /// considered to be undefined
1463    ///
1464    /// Refer to the [description of the alignment][align_rules] rules for
1465    /// `host_slice` for memory objects (buffer and images) created using
1466    /// this method.
1467    ///
1468    /// Automatically sets the `flags::MEM_USE_HOST_PTR` aka.
1469    /// `MemFlags::new().use_host_ptr()` flag.
1470    ///
1471    /// ### Panics
1472    ///
1473    /// `::copy_host_slice` or `::use_host_slice` must not have already been
1474    /// called.
1475    ///
1476    /// ### Safety
1477    ///
1478    /// The caller must ensure that `host_slice` lives until the image is
1479    /// destroyed. The caller must also ensure that only one image uses
1480    /// `host_slice` and that it is not tampered with inappropriately.
1481    ///
1482    /// [align_rules]: https://www.khronos.org/registry/OpenCL/sdk/1.2/docs/man/xhtml/dataTypes.html
1483    pub unsafe fn use_host_slice<'d>(mut self, host_slice: &'d [T]) -> ImageBuilder<'a, T>
1484    where
1485        'd: 'a,
1486    {
1487        assert!(
1488            self.host_slice.is_none(),
1489            "ImageBuilder::use_host_slice: \
1490            A host slice has already been specified."
1491        );
1492        self.host_slice = HostSlice::Use(host_slice);
1493        self
1494    }
1495
1496    /// Specifies a region of memory to copy into the image upon creation.
1497    ///
1498    /// Automatically sets the `flags::MEM_COPY_HOST_PTR` aka.
1499    /// `MemFlags::new().copy_host_ptr()` flag.
1500    ///
1501    /// ### Panics
1502    ///
1503    /// `::copy_host_slice` or `::use_host_slice` must not have already been
1504    /// called.
1505    ///
1506    pub fn copy_host_slice<'d>(mut self, host_slice: &'d [T]) -> ImageBuilder<'a, T>
1507    where
1508        'd: 'a,
1509    {
1510        assert!(
1511            self.host_slice.is_none(),
1512            "ImageBuilder::copy_host_slice: \
1513            A host slice has already been specified."
1514        );
1515        self.host_slice = HostSlice::Copy(host_slice);
1516        self
1517    }
1518
1519    pub fn channel_order(mut self, order: ImageChannelOrder) -> ImageBuilder<'a, T> {
1520        self.image_format.channel_order = order;
1521        self
1522    }
1523
1524    pub fn channel_data_type(mut self, data_type: ImageChannelDataType) -> ImageBuilder<'a, T> {
1525        self.image_format.channel_data_type = data_type;
1526        self
1527    }
1528
1529    /// Sets the type of image (technically the type of memory buffer).
1530    ///
1531    /// Describes the image type and must be either `Image1d`, `Image1dBuffer`,
1532    /// `Image1dArray`, `Image2d`, `Image2dArray`, or `Image3d`.
1533    ///
1534    pub fn image_type(mut self, image_type: MemObjectType) -> ImageBuilder<'a, T> {
1535        self.image_desc.image_type = image_type;
1536        self
1537    }
1538
1539    /// The width, height, and depth of an image or image array:
1540    ///
1541    /// Some notes adapted from SDK docs:
1542    ///
1543    /// ## Width
1544    ///
1545    /// The width of the image in pixels. For a 2D image and image array, the
1546    /// image width must be ≤ `DeviceInfo::Image2dMaxWidth`. For a 3D image, the
1547    /// image width must be ≤ `DeviceInfo::Image3dMaxWidth`. For a 1D image buffer,
1548    /// the image width must be ≤ `DeviceInfo::ImageMaxBufferSize`. For a 1D image
1549    /// and 1D image array, the image width must be ≤ `DeviceInfo::Image2dMaxWidth`.
1550    ///
1551    /// ## Height
1552    ///
1553    /// The height of the image in pixels. This is only used if the
1554    /// image is a 2D, 3D or 2D image array. For a 2D image or image array, the
1555    /// image height must be ≤ `DeviceInfo::Image2dMaxHeight`. For a 3D image, the
1556    /// image height must be ≤ `DeviceInfo::Image3dMaxHeight`.
1557    ///
1558    /// ## Depth
1559    ///
1560    /// image_depth The depth of the image in pixels. This is only used if the
1561    /// image is a 3D image and must be a value ≥ 1 and ≤
1562    /// `DeviceInfo::Image3dMaxDepth`.
1563    ///
1564    /// ## Examples
1565    ///
1566    /// * To set the dimensions of a 2d image use:
1567    ///   `SpatialDims::Two(width, height)`.
1568    /// * To set the dimensions of a 2d image array use:
1569    ///   `SpatialDims::Three(width, height, array_length)`.
1570    /// * To set the dimensions of a 3d image use:
1571    ///   `SpatialDims::Three(width, height, depth)`.
1572    ///
1573    pub fn dims<D>(mut self, dims: D) -> ImageBuilder<'a, T>
1574    where
1575        D: Into<SpatialDims>,
1576    {
1577        let dims = dims.into().to_lens().unwrap();
1578        self.image_desc.image_width = dims[0];
1579        self.image_desc.image_height = dims[1];
1580        self.image_desc.image_depth = dims[2];
1581        self
1582    }
1583
1584    /// Image array size.
1585    ///
1586    /// The number of images in the image array. This is only used if the image is
1587    /// a 1D or 2D image array. The values for image_array_size, if specified,
1588    /// must be a value ≥ 1 and ≤ `DeviceInfo::ImageMaxArraySize`.
1589    ///
1590    /// Note that reading and writing 2D image arrays from a kernel with
1591    /// image_array_size = 1 may be lower performance than 2D images.
1592    ///
1593    pub fn array_size(mut self, array_size: usize) -> ImageBuilder<'a, T> {
1594        self.image_desc.image_array_size = array_size;
1595        self
1596    }
1597
1598    /// Image row pitch.
1599    ///
1600    /// The scan-line pitch in bytes. This must be 0 if host data is `None` and
1601    /// can be either 0 or ≥ image_width * size of element in bytes if host data
1602    /// is not `None`. If host data is not `None` and image_row_pitch = 0,
1603    /// image_row_pitch is calculated as image_width * size of element in bytes.
1604    /// If image_row_pitch is not 0, it must be a multiple of the image element
1605    /// size in bytes.
1606    ///
1607    pub fn row_pitch_bytes(mut self, row_pitch: usize) -> ImageBuilder<'a, T> {
1608        self.image_desc.image_row_pitch = row_pitch;
1609        self
1610    }
1611
1612    /// Image slice pitch.
1613    ///
1614    /// The size in bytes of each 2D slice in the 3D image or the size in bytes of
1615    /// each image in a 1D or 2D image array. This must be 0 if host data is
1616    /// `None`. If host data is not `None`, image_slice_pitch can be either 0 or ≥
1617    /// image_row_pitch * image_height for a 2D image array or 3D image and can be
1618    /// either 0 or ≥ image_row_pitch for a 1D image array. If host data is not
1619    /// `None` and image_slice_pitch = 0, image_slice_pitch is calculated as
1620    /// image_row_pitch * image_height for a 2D image array or 3D image and
1621    /// image_row_pitch for a 1D image array. If image_slice_pitch is not 0, it
1622    /// must be a multiple of the image_row_pitch.
1623    ///
1624    pub fn slc_pitch_bytes(mut self, slc_pitch: usize) -> ImageBuilder<'a, T> {
1625        self.image_desc.image_slice_pitch = slc_pitch;
1626        self
1627    }
1628
1629    /// Buffer synchronization.
1630    ///
1631    /// Refers to a valid buffer memory object if image_type is
1632    /// `MemObjectType::Image1dBuffer`. Otherwise it must be `None` (default).
1633    /// For a 1D image buffer object, the image pixels are taken from the buffer
1634    /// object's data store. When the contents of a buffer object's data store are
1635    /// modified, those changes are reflected in the contents of the 1D image
1636    /// buffer object and vice-versa at corresponding sychronization points. The
1637    /// image_width * size of element in bytes must be ≤ size of buffer object
1638    /// data store.
1639    ///
1640    pub fn buffer_sync(mut self, buffer: MemCore) -> ImageBuilder<'a, T> {
1641        self.image_desc.buffer = Some(buffer);
1642        self
1643    }
1644
1645    /// Specifies the image pixel format.
1646    ///
1647    /// If unspecified, defaults to:
1648    ///
1649    /// ```rust,ignore
1650    /// ImageFormat {
1651    ///    channel_order: ImageChannelOrder::Rgba,
1652    ///    channel_data_type: ImageChannelDataType::SnormInt8,
1653    /// }
1654    /// ```
1655    pub fn image_format(mut self, image_format: ImageFormat) -> ImageBuilder<'a, T> {
1656        self.image_format = image_format;
1657        self
1658    }
1659
1660    /// Specifies the image descriptor containing a number of important settings.
1661    ///
1662    /// If unspecified (not recommended), defaults to:
1663    ///
1664    /// ```rust,ignore
1665    /// ImageDescriptor {
1666    ///     image_type: MemObjectType::Image1d,
1667    ///     image_width: 0,
1668    ///     image_height: 0,
1669    ///     image_depth: 0,
1670    ///     image_array_size: 0,
1671    ///     image_row_pitch: 0,
1672    ///     image_slice_pitch: 0,
1673    ///     num_mip_levels: 0,
1674    ///     num_samples: 0,
1675    ///     buffer: None,
1676    /// }
1677    /// ```
1678    ///
1679    /// If you are unsure, just set the first four by using
1680    /// `ImageDescriptor::new`. Ex.:
1681    ///
1682    /// ```rust,ignore
1683    /// ocl::Image::builder()
1684    ///    .image_desc(ocl::ImageDescriptor::new(
1685    ///       ocl::MemObjectType::Image2d, 1280, 800, 1))
1686    ///    ...
1687    ///    ...
1688    ///    .build()
1689    /// ```
1690    ///
1691    /// Setting this overwrites any previously set type, dimensions, array size, pitch, etc.
1692    ///
1693    pub unsafe fn image_desc(mut self, image_desc: ImageDescriptor) -> ImageBuilder<'a, T> {
1694        self.image_desc = image_desc;
1695        self
1696    }
1697
1698    /// Builds with no host side image data memory specified and returns a
1699    /// new `Image`.
1700    pub fn build(mut self) -> OclResult<Image<T>> {
1701        let host_slice = match self.host_slice {
1702            HostSlice::Use(hs) => {
1703                self.flags.insert(MemFlags::new().use_host_ptr());
1704                Some(hs)
1705            }
1706            HostSlice::Copy(hs) => {
1707                self.flags.insert(MemFlags::new().copy_host_ptr());
1708                Some(hs)
1709            }
1710            HostSlice::None => None,
1711        };
1712
1713        match self.queue_option {
1714            Some(qo) => unsafe {
1715                Image::new(
1716                    qo,
1717                    self.flags,
1718                    self.image_format.clone(),
1719                    self.image_desc.clone(),
1720                    host_slice,
1721                )
1722            },
1723            None => panic!(
1724                "ocl::ImageBuilder::build: A context or default queue must be set \
1725                with '.context(...)' or '.queue(...)'."
1726            ),
1727        }
1728    }
1729}