use std;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::marker::PhantomData;
use std::convert::Into;
use error::{Error as OclError, Result as OclResult};
use standard::{Context, Queue, MemLen, EventList, SpatialDims};
use core::{self, OclPrm, Mem as MemCore, MemFlags, MemObjectType, ImageFormat, ImageDescriptor,
ImageInfo, ImageInfoResult, MemInfo, MemInfoResult, ClEventPtrNew, ImageChannelOrder,
ImageChannelDataType};
pub struct ImageBuilder<S: OclPrm> {
flags: MemFlags,
image_format: ImageFormat,
image_desc: ImageDescriptor,
_pixel: PhantomData<S>,
}
impl<S: OclPrm> ImageBuilder<S> {
pub fn new() -> ImageBuilder<S> {
ImageBuilder {
flags: core::MEM_READ_WRITE,
image_format: ImageFormat::new_rgba(),
image_desc: ImageDescriptor::new(MemObjectType::Image1d, 0, 0, 0, 0, 0, 0, None),
_pixel: PhantomData,
}
}
pub fn build(&self, queue: &Queue) -> OclResult<Image<S>> {
Image::new(queue, self.flags, self.image_format.clone(), self.image_desc.clone(),
None)
}
pub fn build_with_data(&self, queue: &Queue, image_data: &[S]) -> OclResult<Image<S>> {
Image::new(queue, self.flags, self.image_format.clone(), self.image_desc.clone(),
Some(image_data))
}
pub fn channel_order<'a>(&'a mut self, order: ImageChannelOrder) -> &'a mut ImageBuilder<S> {
self.image_format.channel_order = order;
self
}
pub fn channel_data_type<'a>(&'a mut self, data_type: ImageChannelDataType) -> &'a mut ImageBuilder<S> {
self.image_format.channel_data_type = data_type;
self
}
pub fn image_type<'a>(&'a mut self, image_type: MemObjectType) -> &'a mut ImageBuilder<S> {
self.image_desc.image_type = image_type;
self
}
pub fn dims<'a, D: MemLen>(&'a mut self, dims: D) -> &'a mut ImageBuilder<S> {
let dims = dims.to_lens();
self.image_desc.image_width = dims[0];
self.image_desc.image_height = dims[1];
self.image_desc.image_depth = dims[2];
self
}
pub fn array_size<'a>(&'a mut self, array_size: usize) -> &'a mut ImageBuilder<S> {
self.image_desc.image_array_size = array_size;
self
}
pub fn row_pitch_bytes<'a>(&'a mut self, row_pitch: usize) -> &'a mut ImageBuilder<S> {
self.image_desc.image_row_pitch = row_pitch;
self
}
pub fn slc_pitch_bytes<'a>(&'a mut self, slc_pitch: usize) -> &'a mut ImageBuilder<S> {
self.image_desc.image_slice_pitch = slc_pitch;
self
}
pub fn buffer_sync<'a>(&'a mut self, buffer: MemCore) -> &'a mut ImageBuilder<S> {
self.image_desc.buffer = Some(buffer);
self
}
pub fn flags<'a>(&'a mut self, flags: MemFlags) -> &'a mut ImageBuilder<S> {
self.flags = flags;
self
}
pub fn image_format<'a>(&'a mut self, image_format: ImageFormat) -> &'a mut ImageBuilder<S> {
self.image_format = image_format;
self
}
pub unsafe fn image_desc<'a>(&'a mut self, image_desc: ImageDescriptor) -> &'a mut ImageBuilder<S> {
self.image_desc = image_desc;
self
}
}
#[derive(Debug)]
pub enum ImageCmdKind<'b, E: 'b> {
Unspecified,
Read { data: &'b mut [E] },
Write { data: &'b [E] },
Fill { color: &'b [E] },
Copy { dst_image: &'b MemCore, dst_origin: [usize; 3] },
CopyToBuffer { buffer: &'b MemCore, dst_origin: usize },
}
impl<'b, E: 'b> ImageCmdKind<'b, E> {
fn is_unspec(&'b self) -> bool {
if let &ImageCmdKind::Unspecified = self {
true
} else {
false
}
}
}
#[allow(dead_code)]
pub struct ImageCmd<'b, E: 'b + OclPrm> {
queue: &'b Queue,
obj_core: &'b MemCore,
block: bool,
lock_block: bool,
origin: [usize; 3],
region: [usize; 3],
row_pitch: usize,
slc_pitch: usize,
kind: ImageCmdKind<'b, E>,
ewait: Option<&'b EventList>,
enew: Option<&'b mut ClEventPtrNew>,
mem_dims: [usize; 3],
}
impl<'b, E: 'b + OclPrm> ImageCmd<'b, E> {
pub fn new(queue: &'b Queue, obj_core: &'b MemCore, dims: [usize; 3])
-> ImageCmd<'b, E>
{
ImageCmd {
queue: queue,
obj_core: obj_core,
block: true,
lock_block: false,
origin: [0, 0, 0],
region: dims,
row_pitch: 0,
slc_pitch: 0,
kind: ImageCmdKind::Unspecified,
ewait: None,
enew: None,
mem_dims: dims,
}
}
pub fn queue(mut self, queue: &'b Queue) -> ImageCmd<'b, E> {
self.queue = queue;
self
}
pub fn block(mut self, block: bool) -> ImageCmd<'b, E> {
if !block && self.lock_block {
panic!("ocl::ImageCmd::block(): Blocking for this command has been disabled by \
the '::read' method. For non-blocking reads use '::read_async'.");
}
self.block = block;
self
}
pub fn origin(mut self, origin: [usize; 3]) -> ImageCmd<'b, E> {
self.origin = origin;
self
}
pub fn region(mut self, region: [usize; 3]) -> ImageCmd<'b, E> {
self.region = region;
self
}
#[allow(unused_variables, unused_mut)]
pub unsafe fn pitch(mut self, row_pitch: usize, slc_pitch: usize) -> ImageCmd<'b, E> {
unimplemented!();
}
pub fn read(mut self, dst_data: &'b mut [E]) -> ImageCmd<'b, E> {
assert!(self.kind.is_unspec(), "ocl::ImageCmd::read(): Operation kind \
already set for this command.");
self.kind = ImageCmdKind::Read { data: dst_data };
self.block = true;
self.lock_block = true;
self
}
pub unsafe fn read_async(mut self, dst_data: &'b mut [E]) -> ImageCmd<'b, E> {
assert!(self.kind.is_unspec(), "ocl::ImageCmd::read(): Operation kind \
already set for this command.");
self.kind = ImageCmdKind::Read { data: dst_data };
self
}
pub fn write(mut self, src_data: &'b [E]) -> ImageCmd<'b, E> {
assert!(self.kind.is_unspec(), "ocl::ImageCmd::write(): Operation kind \
already set for this command.");
self.kind = ImageCmdKind::Write { data: src_data };
self
}
pub fn copy(mut self, dst_image: &'b Image<E>, dst_origin: [usize; 3]) -> ImageCmd<'b, E> {
assert!(self.kind.is_unspec(), "ocl::ImageCmd::copy(): Operation kind \
already set for this command.");
self.kind = ImageCmdKind::Copy {
dst_image: dst_image.core_as_ref(),
dst_origin: dst_origin,
};
self
}
pub fn copy_to_buffer(mut self, buffer: &'b MemCore, dst_origin: usize) -> ImageCmd<'b, E> {
assert!(self.kind.is_unspec(), "ocl::ImageCmd::copy_to_buffer(): Operation kind \
already set for this command.");
self.kind = ImageCmdKind::CopyToBuffer { buffer: buffer, dst_origin: dst_origin };
self
}
pub fn fill(mut self, color: &'b [E]) -> ImageCmd<'b, E> {
assert!(self.kind.is_unspec(), "ocl::ImageCmd::fill(): Operation kind \
already set for this command.");
self.kind = ImageCmdKind::Fill { color: color };
self
}
pub fn ewait(mut self, ewait: &'b EventList) -> ImageCmd<'b, E> {
self.ewait = Some(ewait);
self
}
pub fn ewait_opt(mut self, ewait: Option<&'b EventList>) -> ImageCmd<'b, E> {
self.ewait = ewait;
self
}
pub fn enew(mut self, enew: &'b mut ClEventPtrNew) -> ImageCmd<'b, E> {
self.enew = Some(enew);
self
}
pub fn enew_opt(mut self, enew: Option<&'b mut ClEventPtrNew>) -> ImageCmd<'b, E> {
self.enew = enew;
self
}
pub fn enq(self) -> OclResult<()> {
match self.kind {
ImageCmdKind::Read { data } => {
unsafe { core::enqueue_read_image(self.queue, self.obj_core, self.block,
self.origin, self.region, self.row_pitch, self.slc_pitch, data, self.ewait,
self.enew) }
},
ImageCmdKind::Write { data } => {
core::enqueue_write_image(self.queue, self.obj_core, self.block,
self.origin, self.region, self.row_pitch, self.slc_pitch, data, self.ewait,
self.enew)
},
ImageCmdKind::Copy { dst_image, dst_origin } => {
core::enqueue_copy_image::<E, _>(self.queue, self.obj_core, dst_image, self.origin,
dst_origin, self.region, self.ewait, self.enew)
},
ImageCmdKind::Unspecified => return OclError::err("ocl::ImageCmd::enq(): No operation \
specified. Use '.read(...)', 'write(...)', etc. before calling '.enq()'."),
_ => unimplemented!(),
}
}
}
#[derive(Clone, Debug)]
pub struct Image<E: OclPrm> {
obj_core: MemCore,
queue: Queue,
dims: SpatialDims,
pixel_element_len: usize,
_pixel: PhantomData<E>
}
impl<E: OclPrm> Image<E> {
pub fn supported_formats(context: &Context, flags: MemFlags, mem_obj_type: MemObjectType,
) -> OclResult<Vec<ImageFormat>> {
core::get_supported_image_formats(context, flags, mem_obj_type)
}
pub fn builder() -> ImageBuilder<E> {
ImageBuilder::new()
}
pub fn new(queue: &Queue, flags: MemFlags, image_format: ImageFormat,
image_desc: ImageDescriptor, image_data: Option<&[E]>) -> OclResult<Image<E>>
{
let obj_core = unsafe { try!(core::create_image(
queue.context_core_as_ref(),
flags,
&image_format,
&image_desc,
image_data,
)) };
let pixel_element_len = match core::get_image_info(&obj_core, ImageInfo::ElementSize) {
ImageInfoResult::ElementSize(s) => s / mem::size_of::<E>(),
ImageInfoResult::Error(err) => return Err(*err),
_ => return OclError::err("ocl::Image::element_len(): \
Unexpected 'ImageInfoResult' variant."),
};
let dims = [image_desc.image_width, image_desc.image_height, image_desc.image_depth].into();
let new_img = Image {
obj_core: obj_core,
queue: queue.clone(),
dims: dims,
pixel_element_len: pixel_element_len,
_pixel: PhantomData,
};
Ok(new_img)
}
pub fn cmd<'b>(&'b self) -> ImageCmd<'b, E> {
ImageCmd::new(&self.queue, &self.obj_core,
self.dims.to_lens().expect("ocl::Image::cmd"))
}
pub fn read<'b>(&'b self, data: &'b mut [E]) -> ImageCmd<'b, E> {
self.cmd().read(data)
}
pub fn write<'b>(&'b self, data: &'b [E]) -> ImageCmd<'b, E> {
self.cmd().write(data)
}
pub fn set_default_queue<'a>(&'a mut self, queue: &Queue) -> &'a mut Image<E> {
self.queue = queue.clone();
self
}
pub fn default_queue(&self) -> &Queue {
&self.queue
}
pub fn dims(&self) -> &SpatialDims {
&self.dims
}
pub fn pixel_count(&self) -> usize {
self.dims.to_len()
}
pub fn pixel_element_len(&self) -> usize {
self.pixel_element_len
}
pub fn element_count(&self) -> usize {
self.pixel_count() * self.pixel_element_len()
}
pub fn info(&self, info_kind: ImageInfo) -> ImageInfoResult {
core::get_image_info(&self.obj_core, info_kind)
}
pub fn mem_info(&self, info_kind: MemInfo) -> MemInfoResult {
core::get_mem_object_info(&self.obj_core, info_kind)
}
pub fn core_as_ref(&self) -> &MemCore {
&self.obj_core
}
fn fmt_info(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("Image")
.field("ElementSize", &self.info(ImageInfo::ElementSize))
.field("RowPitch", &self.info(ImageInfo::RowPitch))
.field("SlicePitch", &self.info(ImageInfo::SlicePitch))
.field("Width", &self.info(ImageInfo::Width))
.field("Height", &self.info(ImageInfo::Height))
.field("Depth", &self.info(ImageInfo::Depth))
.field("ArraySize", &self.info(ImageInfo::ArraySize))
.field("Buffer", &self.info(ImageInfo::Buffer))
.field("NumMipLevels", &self.info(ImageInfo::NumMipLevels))
.field("NumSamples", &self.info(ImageInfo::NumSamples))
.finish()
}
fn fmt_mem_info(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("Mem")
.field("Type", &self.mem_info(MemInfo::Type))
.field("Flags", &self.mem_info(MemInfo::Flags))
.field("Size", &self.mem_info(MemInfo::Size))
.field("HostPtr", &self.mem_info(MemInfo::HostPtr))
.field("MapCount", &self.mem_info(MemInfo::MapCount))
.field("ReferenceCount", &self.mem_info(MemInfo::ReferenceCount))
.field("Context", &self.mem_info(MemInfo::Context))
.field("AssociatedMemobject", &self.mem_info(MemInfo::AssociatedMemobject))
.field("Offset", &self.mem_info(MemInfo::Offset))
.finish()
}
}
impl<E: OclPrm> std::fmt::Display for Image<E> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
try!(self.fmt_info(f));
try!(write!(f, " "));
self.fmt_mem_info(f)
}
}
impl<E: OclPrm> Deref for Image<E> {
type Target = MemCore;
fn deref(&self) -> &MemCore {
&self.obj_core
}
}
impl<E: OclPrm> DerefMut for Image<E> {
fn deref_mut(&mut self) -> &mut MemCore {
&mut self.obj_core
}
}