From 96a59d5884cd12d2932ff9cf9883762c47992a98 Mon Sep 17 00:00:00 2001
From: Marko Bencun <mbencun@gmail.com>
Date: Sun, 8 Sep 2013 20:40:51 +0200
Subject: [PATCH] Image, Sampler

---
 pyopencl/_init.py            |  201 +++---
 pyopencl/cffi_cl.py          |  147 ++++-
 src/c_wrapper/wrap_cl.cpp    | 1123 ++++++++++++++++++----------------
 src/c_wrapper/wrap_cl_core.h |   19 +-
 4 files changed, 826 insertions(+), 664 deletions(-)

diff --git a/pyopencl/_init.py b/pyopencl/_init.py
index d68c610c..52862916 100644
--- a/pyopencl/_init.py
+++ b/pyopencl/_init.py
@@ -239,14 +239,14 @@ def _add_functionality():
                 (Event.get_info, event_info),
             MemoryObjectHolder:
                 (MemoryObjectHolder.get_info, mem_info),
-            # Image:
-            #     (Image.get_image_info, image_info),
+            Image:
+                (Image.get_image_info, image_info),
             Program:
                 (Program.get_info, program_info),
             Kernel:
                 (Kernel.get_info, kernel_info),
-            # Sampler:
-            #     (Sampler.get_info, sampler_info),
+            Sampler:
+                (Sampler.get_info, sampler_info),
             }
 
     def to_string(cls, value, default_format=None):
@@ -510,122 +510,113 @@ def _add_functionality():
 
     # }}}
 
-    # # {{{ Image
+    # {{{ Image
 
-    # image_old_init = Image.__init__
+    image_old_init = Image.__init__
 
-    # def image_init(self, context, flags, format, shape=None, pitches=None,
-    #         hostbuf=None, is_array=False, buffer=None):
+    def image_init(self, context, flags, format, shape=None, pitches=None,
+            hostbuf=None, is_array=False, buffer=None):
 
-    #     if shape is None and hostbuf is None:
-    #         raise Error("'shape' must be passed if 'hostbuf' is not given")
+        if shape is None and hostbuf is None:
+            raise Error("'shape' must be passed if 'hostbuf' is not given")
 
-    #     if shape is None and hostbuf is not None:
-    #         shape = hostbuf.shape
+        if shape is None and hostbuf is not None:
+            shape = hostbuf.shape
 
-    #     if hostbuf is not None and not \
-    #             (flags & (mem_flags.USE_HOST_PTR | mem_flags.COPY_HOST_PTR)):
-    #         from warnings import warn
-    #         warn("'hostbuf' was passed, but no memory flags to make use of it.")
-
-    #     if hostbuf is None and pitches is not None:
-    #         raise Error("'pitches' may only be given if 'hostbuf' is given")
-
-    #     if context._get_cl_version() >= (1, 2) and get_cl_header_version() >= (1, 2):
-    #         if buffer is not None and is_array:
-    #                 raise ValueError(
-    #                         "'buffer' and 'is_array' are mutually exclusive")
+        if hostbuf is not None and not \
+                (flags & (mem_flags.USE_HOST_PTR | mem_flags.COPY_HOST_PTR)):
+            from warnings import warn
+            warn("'hostbuf' was passed, but no memory flags to make use of it.")
+
+        if hostbuf is None and pitches is not None:
+            raise Error("'pitches' may only be given if 'hostbuf' is given")
+
+        if context._get_cl_version() >= (1, 2) and get_cl_header_version() >= (1, 2):
+            if buffer is not None and is_array:
+                    raise ValueError(
+                            "'buffer' and 'is_array' are mutually exclusive")
+
+            if len(shape) == 3:
+                if buffer is not None:
+                    raise TypeError(
+                            "'buffer' argument is not supported for 3D arrays")
+                elif is_array:
+                    image_type = mem_object_type.IMAGE2D_ARRAY
+                else:
+                    image_type = mem_object_type.IMAGE3D
+
+            elif len(shape) == 2:
+                if buffer is not None:
+                    raise TypeError(
+                            "'buffer' argument is not supported for 2D arrays")
+                elif is_array:
+                    image_type = mem_object_type.IMAGE1D_ARRAY
+                else:
+                    image_type = mem_object_type.IMAGE2D
 
-    #         if len(shape) == 3:
-    #             if buffer is not None:
-    #                 raise TypeError(
-    #                         "'buffer' argument is not supported for 3D arrays")
-    #             elif is_array:
-    #                 image_type = mem_object_type.IMAGE2D_ARRAY
-    #             else:
-    #                 image_type = mem_object_type.IMAGE3D
+            elif len(shape) == 1:
+                if buffer is not None:
+                    image_type = mem_object_type.IMAGE1D_BUFFER
+                elif is_array:
+                    raise TypeError("array of zero-dimensional images not supported")
+                else:
+                    image_type = mem_object_type.IMAGE1D
 
-    #         elif len(shape) == 2:
-    #             if buffer is not None:
-    #                 raise TypeError(
-    #                         "'buffer' argument is not supported for 2D arrays")
-    #             elif is_array:
-    #                 image_type = mem_object_type.IMAGE1D_ARRAY
-    #             else:
-    #                 image_type = mem_object_type.IMAGE2D
+            else:
+                raise ValueError("images cannot have more than three dimensions")
 
-    #         elif len(shape) == 1:
-    #             if buffer is not None:
-    #                 image_type = mem_object_type.IMAGE1D_BUFFER
-    #             elif is_array:
-    #                 raise TypeError("array of zero-dimensional images not supported")
-    #             else:
-    #                 image_type = mem_object_type.IMAGE1D
+            desc = ImageDescriptor()
 
-    #         else:
-    #             raise ValueError("images cannot have more than three dimensions")
+            desc.image_type = image_type
+            desc.shape = shape  # also sets desc.array_size
 
-    #         desc = ImageDescriptor()
+            if pitches is None:
+                desc.pitches = (0, 0)
+            else:
+                desc.pitches = pitches
 
-    #         desc.image_type = image_type
-    #         desc.shape = shape  # also sets desc.array_size
+            desc.num_mip_levels = 0  # per CL 1.2 spec
+            desc.num_samples = 0  # per CL 1.2 spec
+            desc.buffer = buffer
 
-    #         if pitches is None:
-    #             desc.pitches = (0, 0)
-    #         else:
-    #             desc.pitches = pitches
+            image_old_init(self, context, flags, format, desc, hostbuf)
+        else:
+            # legacy init for CL 1.1 and older
+            if is_array:
+                raise TypeError("'is_array=True' is not supported for CL < 1.2")
+            #if num_mip_levels is not None:
+                #raise TypeError(
+                #      "'num_mip_levels' argument is not supported for CL < 1.2")
+            #if num_samples is not None:
+                #raise TypeError(
+                #       "'num_samples' argument is not supported for CL < 1.2")
+            if buffer is not None:
+                raise TypeError("'buffer' argument is not supported for CL < 1.2")
+
+            image_old_init(self, context, flags, format, shape,
+                    pitches, hostbuf)
+
+    class _ImageInfoGetter:
+        def __init__(self, event):
+            from warnings import warn
+            warn("Image.image.attr is deprecated. "
+                    "Use Image.attr directly, instead.")
 
-    #         desc.num_mip_levels = 0  # per CL 1.2 spec
-    #         desc.num_samples = 0  # per CL 1.2 spec
-    #         desc.buffer = buffer
+            self.event = event
 
-    #         image_old_init(self, context, flags, format, desc, hostbuf)
-    #     else:
-    #         # legacy init for CL 1.1 and older
-    #         if is_array:
-    #             raise TypeError("'is_array=True' is not supported for CL < 1.2")
-    #         #if num_mip_levels is not None:
-    #             #raise TypeError(
-    #             #      "'num_mip_levels' argument is not supported for CL < 1.2")
-    #         #if num_samples is not None:
-    #             #raise TypeError(
-    #             #       "'num_samples' argument is not supported for CL < 1.2")
-    #         if buffer is not None:
-    #             raise TypeError("'buffer' argument is not supported for CL < 1.2")
-
-    #         image_old_init(self, context, flags, format, shape,
-    #                 pitches, hostbuf)
-
-    # class _ImageInfoGetter:
-    #     def __init__(self, event):
-    #         from warnings import warn
-    #         warn("Image.image.attr is deprecated. "
-    #                 "Use Image.attr directly, instead.")
-
-    #         self.event = event
-
-    #     def __getattr__(self, name):
-    #         try:
-    #             inf_attr = getattr(_cl.image_info, name.upper())
-    #         except AttributeError:
-    #             raise AttributeError("%s has no attribute '%s'"
-    #                     % (type(self), name))
-    #         else:
-    #             return self.event.get_image_info(inf_attr)
-
-    # def image_shape(self):
-    #     if self.type == mem_object_type.IMAGE2D:
-    #         return (self.width, self.height)
-    #     elif self.type == mem_object_type.IMAGE3D:
-    #         return (self.width, self.height, self.depth)
-    #     else:
-    #         raise LogicError("only images have shapes")
+        def __getattr__(self, name):
+            try:
+                inf_attr = getattr(_cl.image_info, name.upper())
+            except AttributeError:
+                raise AttributeError("%s has no attribute '%s'"
+                        % (type(self), name))
+            else:
+                return self.event.get_image_info(inf_attr)
 
-    # Image.__init__ = image_init
-    # Image.image = property(_ImageInfoGetter)
-    # Image.shape = property(image_shape)
+    Image.__init__ = image_init
+    Image.image = property(_ImageInfoGetter)
 
-    # # }}}
+    # }}}
 
     # # {{{ Error
 
@@ -825,7 +816,7 @@ def _mark_copy_deprecated(func):
     return new_func
 
 
-# enqueue_read_image = _mark_copy_deprecated(_cl._enqueue_read_image)
+enqueue_read_image = _mark_copy_deprecated(_cl._enqueue_read_image)
 # enqueue_write_image = _mark_copy_deprecated(_cl._enqueue_write_image)
 # enqueue_copy_image = _mark_copy_deprecated(_cl._enqueue_copy_image)
 # enqueue_copy_image_to_buffer = _mark_copy_deprecated(
diff --git a/pyopencl/cffi_cl.py b/pyopencl/cffi_cl.py
index 463758d6..ceb0fbb0 100644
--- a/pyopencl/cffi_cl.py
+++ b/pyopencl/cffi_cl.py
@@ -204,20 +204,21 @@ class MemoryObjectHolder(_Common):
 class MemoryObject(MemoryObjectHolder):
     pass
 
+
+def _c_buffer_from_obj(obj):
+    if obj is None:
+        return _ffi.NULL, 0
+    # assume numpy array for now
+    return _ffi.cast('void *', obj.__array_interface__['data'][0]), obj.nbytes
+    
 class Buffer(MemoryObject):
     _id = 'buffer'
-
-    @classmethod
-    def _c_buffer_from_obj(cls, obj):
-        # assume numpy array for now
-        return _ffi.cast('void *', obj.__array_interface__['data'][0]), obj.nbytes
-
     def __init__(self, context, flags, size=0, hostbuf=None):
         if hostbuf is not None and not (flags & (mem_flags.USE_HOST_PTR | mem_flags.COPY_HOST_PTR)):
             warnings.warn("'hostbuf' was passed, but no memory flags to make use of it.")
         c_hostbuf = _ffi.NULL
         if hostbuf is not None:
-            c_hostbuf, hostbuf_size = self._c_buffer_from_obj(hostbuf)
+            c_hostbuf, hostbuf_size = _c_buffer_from_obj(hostbuf)
             if size > hostbuf_size:
                 raise RuntimeError("Buffer", status_code.INVALID_VALUE, "specified size is greater than host buffer size")
             if size == 0:
@@ -355,10 +356,15 @@ class Kernel(_Common):
         self.ptr = ptr_kernel[0]
 
     def set_arg(self, arg_index, arg):
-        if isinstance(arg, Buffer):
-            _handle_error(_lib.kernel__set_arg_mem_buffer(self.ptr, arg_index, arg.ptr))
+        if arg is None:
+            _handle_error(_lib.kernel__set_arg_null(self.ptr, arg_index))
+        elif isinstance(arg, MemoryObject):
+            _handle_error(_lib.kernel__set_arg_mem(self.ptr, arg_index, arg.ptr))
+        elif isinstance(arg, Sampler):
+            _handle_error(_lib.kernel__set_arg_sampler(self.ptr, arg_index, arg.ptr))
         else:
-            raise NotImplementedError()
+            c_buf, size = _c_buffer_from_obj(arg)
+            _handle_error(_lib.kernel__set_arg_buf(self.ptr, arg_index, c_buf, size))
 
     def get_work_group_info(self, param, device):
         info = _ffi.new('generic_info *')
@@ -440,8 +446,8 @@ def _c_obj_list(objs=None):
         return _ffi.NULL, 0
     return _ffi.new('void *[]', [ev.ptr for ev in objs]), len(objs)
 
-def _enqueue_read_buffer(queue, mem, buf, device_offset=0, wait_for=None, is_blocking=True):
-    c_buf, size = Buffer._c_buffer_from_obj(buf)
+def _enqueue_read_buffer(queue, mem, hostbuf, device_offset=0, wait_for=None, is_blocking=True):
+    c_buf, size = _c_buffer_from_obj(hostbuf)
     ptr_event = _ffi.new('void **')
     c_wait_for, num_wait_for = _c_obj_list(wait_for)
     _handle_error(_lib._enqueue_read_buffer(
@@ -472,7 +478,7 @@ def _enqueue_copy_buffer(queue, src, dst, byte_count=-1, src_offset=0, dst_offse
     return _create_instance(Event, ptr_event[0])
 
 def _enqueue_write_buffer(queue, mem, hostbuf, device_offset=0, wait_for=None, is_blocking=True):
-    c_buf, size = Buffer._c_buffer_from_obj(hostbuf)
+    c_buf, size = _c_buffer_from_obj(hostbuf)
     ptr_event = _ffi.new('void **')
     c_wait_for, num_wait_for = _c_obj_list(wait_for)
     _handle_error(_lib._enqueue_write_buffer(
@@ -487,6 +493,24 @@ def _enqueue_write_buffer(queue, mem, hostbuf, device_offset=0, wait_for=None, i
     ))
     return _create_instance(Event, ptr_event[0])
 
+def _enqueue_read_image(queue, mem, origin, region, hostbuf, row_pitch=0, slice_pitch=0, wait_for=None, is_blocking=True):
+    c_buf, size = _c_buffer_from_obj(hostbuf)
+    ptr_event = _ffi.new('void **')
+    c_wait_for, num_wait_for = _c_obj_list(wait_for)
+    _handle_error(_lib._enqueue_read_image(
+        ptr_event,
+        queue.ptr,
+        mem.ptr,
+        origin,
+        region,
+        c_buf,
+        size,
+        row_pitch, slice_pitch,
+        c_wait_for, num_wait_for,
+        bool(is_blocking)
+    ))
+    return _create_instance(Event, ptr_event[0])
+
 
 def _create_instance(cls, ptr):
     ins = cls.__new__(cls)
@@ -613,20 +637,103 @@ def get_supported_image_formats(context, flags, image_type):
     _handle_error(_lib._get_supported_image_formats(context.ptr, flags, image_type, info))
     return _generic_info_to_python(info)
 
-
 class Image(MemoryObject):
     _id = 'image'
 
-    def __init__(self, context, flags, format, *args):
-        if len(args) == 2:
+    def __init__(self, *args):
+        if len(args) == 5:
             # > (1,2)
-            desc, hostbuf = args
-        elif len(args) == 3:
-            # <= (1,1)
-            shape, pitches, hostbuf = args
+            context, flags, format, desc, hostbuf = args
+        elif len(args) == 6:
+            # legacy init for CL 1.1 and older
+            self._init_legacy(*args)
+            
         else:
             assert False
 
+    def _init_legacy(self, context, flags, format, shape, pitches, buffer):
+        if shape is None:
+            raise LogicError("Image", status_code.INVALID_VALUE, "'shape' must be given")
+
+        c_buf, size = _c_buffer_from_obj(buffer)
+                
+        dims = len(shape)
+        if dims == 2:
+            width, height = shape
+            pitch = 0
+            if pitches is not None:
+                try:
+                    pitch, = pitches
+                except ValueError:
+                    raise LogicError("Image", status_code.INVALID_VALUE, "invalid length of pitch tuple")
+                
+            # check buffer size
+            if buffer is not None and max(pitch, width*format.itemsize)*height > size:
+                raise LogicError("Image", status_code.INVALID_VALUE, "buffer too small")
+
+            ptr = _ffi.new('void **')
+            _handle_error(_lib._create_image_2d(
+                ptr,
+                context.ptr,
+                flags,
+                _ffi.new('struct _cl_image_format *', (format.channel_order, format.channel_data_type, )),
+                width, height, pitch,
+                c_buf,
+                size))
+            self.ptr = ptr[0]
+        elif dims == 3:
+            width, height, depth = shape
+            pitch_x, pitch_y = 0, 0
+            if pitches is not None:
+                try:
+                    pitch_x, pitch_y = pitches
+                except ValueError:
+                    raise LogicError("Image", status_code.INVALID_VALUE, "invalid length of pitch tuple")
+                    
+            # check buffer size
+            if buffer is not None and max(max(pitch_x, width*format.itemsize)*height, pitch_y)*depth > size:
+                raise LogicError("Image", status_code.INVALID_VALUE, "buffer too small")
+
+            ptr = _ffi.new('void **')
+            _handle_error(_lib._create_image_3d(
+                ptr,
+                context.ptr,
+                flags,
+                _ffi.new('struct _cl_image_format *', (format.channel_order, format.channel_data_type, )),
+                width, height, depth, pitch_x, pitch_y,
+                c_buf,
+                size))
+            self.ptr = ptr[0]
+        else:
+            raise LogicError("Image", status_code.INVALID_VALUE, "invalid dimension");
+        
+    def get_image_info(self, param):
+        info = _ffi.new('generic_info *')
+        _handle_error(_lib.image__get_image_info(self.ptr, param, info))
+        return _generic_info_to_python(info)
+
+    @property
+    def shape(self):
+        if self.type == mem_object_type.IMAGE2D:
+            return (self.width, self.height)
+        elif self.type == mem_object_type.IMAGE3D:
+            return (self.width, self.height, self.depth)
+        else:
+            raise LogicError("Image", status_code.INVALID_VALUE, "only images have shapes")
+
+class Sampler(_Common):
+    _id = 'sampler'
+
+    def __init__(self, context, normalized_coords, addressing_mode, filter_mode):
+        ptr = _ffi.new('void **')
+        _handle_error(_lib._create_sampler(
+            ptr,
+            context.ptr,
+            normalized_coords,
+            addressing_mode,
+            filter_mode))
+        self.ptr = ptr[0]
+
 # class GLTexture(MemoryObject):
 #     _id = 'gl_texture'
     
diff --git a/src/c_wrapper/wrap_cl.cpp b/src/c_wrapper/wrap_cl.cpp
index 8c3c027e..19bd9574 100644
--- a/src/c_wrapper/wrap_cl.cpp
+++ b/src/c_wrapper/wrap_cl.cpp
@@ -61,17 +61,17 @@
       throw pyopencl::error(#NAME, status_code);	\
   }
 
-#define PYOPENCL_CALL_GUARDED_CLEANUP(NAME, ARGLIST) \
-  { \
-    PYOPENCL_PRINT_CALL_TRACE(#NAME); \
-    cl_int status_code; \
-    status_code = NAME ARGLIST; \
-    if (status_code != CL_SUCCESS) \
-      std::cerr \
+#define PYOPENCL_CALL_GUARDED_CLEANUP(NAME, ARGLIST)			\
+  {									\
+    PYOPENCL_PRINT_CALL_TRACE(#NAME);					\
+    cl_int status_code;							\
+    status_code = NAME ARGLIST;						\
+    if (status_code != CL_SUCCESS)					\
+      std::cerr								\
         << "PyOpenCL WARNING: a clean-up operation failed (dead context maybe?)" \
-        << std::endl \
-        << #NAME " failed with code " << status_code \
-        << std::endl; \
+        << std::endl							\
+        << #NAME " failed with code " << status_code			\
+        << std::endl;							\
   }
 
 
@@ -79,25 +79,25 @@
 
 #if PYOPENCL_CL_VERSION >= 0x1020
 
-#define PYOPENCL_GET_EXT_FUN(PLATFORM, NAME, VAR) \
-    NAME##_fn VAR \
-      = (NAME##_fn) \
-      clGetExtensionFunctionAddressForPlatform(PLATFORM, #NAME); \
-    \
-    if (!VAR) \
-      throw error(#NAME, CL_INVALID_VALUE, #NAME \
-          "not available");
+#define PYOPENCL_GET_EXT_FUN(PLATFORM, NAME, VAR)			\
+  NAME##_fn VAR								\
+  = (NAME##_fn)								\
+					 clGetExtensionFunctionAddressForPlatform(PLATFORM, #NAME); \
+									\
+  if (!VAR)								\
+    throw error(#NAME, CL_INVALID_VALUE, #NAME				\
+		"not available");
 
 #else
 
-#define PYOPENCL_GET_EXT_FUN(PLATFORM, NAME, VAR) \
-    NAME##_fn VAR \
-      = (NAME##_fn) \
-      clGetExtensionFunctionAddress(#NAME); \
-    \
-    if (!VAR) \
-      throw error(#NAME, CL_INVALID_VALUE, #NAME \
-          "not available");
+#define PYOPENCL_GET_EXT_FUN(PLATFORM, NAME, VAR)			\
+  NAME##_fn VAR								\
+  = (NAME##_fn)								\
+					 clGetExtensionFunctionAddress(#NAME); \
+									\
+  if (!VAR)								\
+    throw error(#NAME, CL_INVALID_VALUE, #NAME				\
+		"not available");
 
 #endif
 
@@ -260,23 +260,23 @@
 
 #define PYOPENCL_RETRY_IF_MEM_ERROR(OPERATION)	\
   {						\
-  bool failed_with_mem_error = false;		\
-  try						\
-    {						\
-      OPERATION					\
-	}					\
-  catch (pyopencl::error &e)			\
-    {						\
-      failed_with_mem_error = true;		\
-      if (!e.is_out_of_memory())		\
-	throw;					\
-    }						\
+    bool failed_with_mem_error = false;		\
+    try						\
+      {						\
+	OPERATION				\
+	  }					\
+    catch (pyopencl::error &e)			\
+      {						\
+	failed_with_mem_error = true;		\
+	if (!e.is_out_of_memory())		\
+	  throw;				\
+      }						\
 						\
-  if (failed_with_mem_error)			\
-    {						\
-  /* If we get here, we got an error from CL.
-   * We should run the Python GC to try and free up
-   * some memory references. */			\
+    if (failed_with_mem_error)			\
+      {						\
+    /* If we get here, we got an error from CL.
+     * We should run the Python GC to try and free up
+     * some memory references. */			\
 run_python_gc();				\
 \
 /* Now retry the allocation. If it fails again,
@@ -300,8 +300,10 @@ run_python_gc();				\
   case ::CLASS_BUFFER: OPERATION(BUFFER, buffer); break;		\
   case ::CLASS_PROGRAM: OPERATION(PROGRAM, program); break;		\
   case ::CLASS_EVENT: OPERATION(EVENT, event); break;			\
-  case ::CLASS_GL_BUFFER: OPERATION(GL_BUFFER, gl_buffer); break;			\
-  case ::CLASS_GL_RENDERBUFFER: OPERATION(GL_RENDERBUFFER, gl_renderbuffer); break;	\
+  case ::CLASS_GL_BUFFER: OPERATION(GL_BUFFER, gl_buffer); break;	\
+  case ::CLASS_GL_RENDERBUFFER: OPERATION(GL_RENDERBUFFER, gl_renderbuffer); break; \
+  case ::CLASS_IMAGE: OPERATION(IMAGE, image); break; \
+  case ::CLASS_SAMPLER: OPERATION(SAMPLER, sampler); break; \
   default: throw pyopencl::error("unknown class", CL_INVALID_VALUE);	\
   }
 
@@ -315,12 +317,14 @@ run_python_gc();				\
 #define PYOPENCL_CL_EVENT cl_event
 #define PYOPENCL_CL_GL_BUFFER cl_mem
 #define PYOPENCL_CL_GL_RENDERBUFFER cl_mem
+#define PYOPENCL_CL_IMAGE cl_mem
+#define PYOPENCL_CL_SAMPLER cl_sampler
 
 template<class T>
 std::string tostring(const T& v) {
-  std::ostringstream ostr;
-  ostr << v;
-  return ostr.str();
+std::ostringstream ostr;
+ ostr << v;
+ return ostr.str();
 }
 
 
@@ -818,7 +822,7 @@ namespace pyopencl
     ~context()
     {
       PYOPENCL_CALL_GUARDED_CLEANUP(clReleaseContext,
-      			      (m_context));
+				    (m_context));
     }
 
     cl_context data() const
@@ -959,7 +963,7 @@ namespace pyopencl
     ~command_queue()
     {
       PYOPENCL_CALL_GUARDED_CLEANUP(clReleaseCommandQueue,
-          (m_queue));
+				    (m_queue));
     }
 
     const cl_command_queue data() const
@@ -1320,24 +1324,24 @@ namespace pyopencl
 #endif
 	  PYOPENCL_GET_INTEGRAL_INFO(Image, data(), param_name, size_t);
 
-// #if PYOPENCL_CL_VERSION >= 0x1020
-// 	case CL_IMAGE_BUFFER:
-// 	  {
-// 	    cl_mem param_value;
-// 	    PYOPENCL_CALL_GUARDED(clGetImageInfo, (data(), param_name, sizeof(param_value), &param_value, 0));
-// 	    if (param_value == 0)
-//               {
-//                 // no associated memory object? no problem.
-//                 return py::object();
-//               }
-
-// 	    return create_mem_object_wrapper(param_value);
-// 	  }
-
-// 	case CL_IMAGE_NUM_MIP_LEVELS:
-// 	case CL_IMAGE_NUM_SAMPLES:
-// 	  PYOPENCL_GET_INTEGRAL_INFO(Image, data(), param_name, cl_uint);
-// #endif
+#if PYOPENCL_CL_VERSION >= 0x1020
+	  // 	case CL_IMAGE_BUFFER:
+	  // 	  {
+	  // 	    cl_mem param_value;
+	  // 	    PYOPENCL_CALL_GUARDED(clGetImageInfo, (data(), param_name, sizeof(param_value), &param_value, 0));
+	  // 	    if (param_value == 0)
+	  //               {
+	  //                 // no associated memory object? no problem.
+	  //                 return py::object();
+	  //               }
+
+	  // 	    return create_mem_object_wrapper(param_value);
+	  // 	  }
+	  
+	case CL_IMAGE_NUM_MIP_LEVELS:
+	case CL_IMAGE_NUM_SAMPLES:
+	  PYOPENCL_GET_INTEGRAL_INFO(Image, data(), param_name, cl_uint);
+#endif
 
 	default:
 	  throw error("MemoryObject.get_image_info", CL_INVALID_VALUE);
@@ -1366,385 +1370,332 @@ namespace pyopencl
   }
 
 
-//   // }}}
-
-//   // {{{ image creation
-
-//   inline
-//   image *create_image(
-//       context const &ctx,
-//       cl_mem_flags flags,
-//       cl_image_format const &fmt,
-//       py::object shape,
-//       py::object pitches,
-//       py::object buffer)
-//   {
-//     if (shape.ptr() == Py_None)
-//       throw pyopencl::error("Image", CL_INVALID_VALUE,
-//           "'shape' must be given");
-
-//     void *buf = 0;
-//     PYOPENCL_BUFFER_SIZE_T len;
-//     py::object *retained_buf_obj = 0;
-
-//     if (buffer.ptr() != Py_None)
-//     {
-//       if (flags & CL_MEM_USE_HOST_PTR)
-//       {
-//         if (PyObject_AsWriteBuffer(buffer.ptr(), &buf, &len))
-//           throw py::error_already_set();
-//       }
-//       else
-//       {
-//         if (PyObject_AsReadBuffer(
-//               buffer.ptr(), const_cast<const void **>(&buf), &len))
-//           throw py::error_already_set();
-//       }
-
-//       if (flags & CL_MEM_USE_HOST_PTR)
-//         retained_buf_obj = &buffer;
-//     }
-
-//     unsigned dims = py::len(shape);
-//     cl_int status_code;
-//     cl_mem mem;
-//     if (dims == 2)
-//     {
-//       size_t width = py::extract<size_t>(shape[0]);
-//       size_t height = py::extract<size_t>(shape[1]);
-
-//       size_t pitch = 0;
-//       if (pitches.ptr() != Py_None)
-//       {
-//         if (py::len(pitches) != 1)
-//           throw pyopencl::error("Image", CL_INVALID_VALUE,
-//               "invalid length of pitch tuple");
-//         pitch = py::extract<size_t>(pitches[0]);
-//       }
-
-//       // check buffer size
-//       cl_int itemsize = get_image_format_item_size(fmt);
-//       if (buf && std::max(pitch, width*itemsize)*height > cl_uint(len))
-//           throw pyopencl::error("Image", CL_INVALID_VALUE,
-//               "buffer too small");
-
-//       PYOPENCL_PRINT_CALL_TRACE("clCreateImage2D");
-//       PYOPENCL_RETRY_IF_MEM_ERROR(
-//           {
-//             mem = clCreateImage2D(ctx.data(), flags, &fmt,
-//                 width, height, pitch, buf, &status_code);
-//             if (status_code != CL_SUCCESS)
-//               throw pyopencl::error("clCreateImage2D", status_code);
-//           } );
-
-//     }
-//     else if (dims == 3)
-//     {
-//       size_t width = py::extract<size_t>(shape[0]);
-//       size_t height = py::extract<size_t>(shape[1]);
-//       size_t depth = py::extract<size_t>(shape[2]);
-
-//       size_t pitch_x = 0;
-//       size_t pitch_y = 0;
-
-//       if (pitches.ptr() != Py_None)
-//       {
-//         if (py::len(pitches) != 2)
-//           throw pyopencl::error("Image", CL_INVALID_VALUE,
-//               "invalid length of pitch tuple");
-
-//         pitch_x = py::extract<size_t>(pitches[0]);
-//         pitch_y = py::extract<size_t>(pitches[1]);
-//       }
-
-//       // check buffer size
-//       cl_int itemsize = get_image_format_item_size(fmt);
-//       if (buf &&
-//           std::max(std::max(pitch_x, width*itemsize)*height, pitch_y)
-//           * depth > cl_uint(len))
-//         throw pyopencl::error("Image", CL_INVALID_VALUE,
-//             "buffer too small");
-
-//       PYOPENCL_PRINT_CALL_TRACE("clCreateImage3D");
-//       PYOPENCL_RETRY_IF_MEM_ERROR(
-//           {
-//             mem = clCreateImage3D(ctx.data(), flags, &fmt,
-//               width, height, depth, pitch_x, pitch_y, buf, &status_code);
-//             if (status_code != CL_SUCCESS)
-//               throw pyopencl::error("clCreateImage3D", status_code);
-//           } );
-//     }
-//     else
-//       throw pyopencl::error("Image", CL_INVALID_VALUE,
-//           "invalid dimension");
-
-//     try
-//     {
-//       return new image(mem, false, retained_buf_obj);
-//     }
-//     catch (...)
-//     {
-//       PYOPENCL_CALL_GUARDED(clReleaseMemObject, (mem));
-//       throw;
-//     }
-//   }
-
-// #if PYOPENCL_CL_VERSION >= 0x1020
-
-//   inline
-//   image *create_image_from_desc(
-//       context const &ctx,
-//       cl_mem_flags flags,
-//       cl_image_format const &fmt,
-//       cl_image_desc &desc,
-//       py::object buffer)
-//   {
-//     if (buffer.ptr() != Py_None &&
-//         !(flags & (CL_MEM_USE_HOST_PTR | CL_MEM_COPY_HOST_PTR)))
-//       PyErr_Warn(PyExc_UserWarning, "'hostbuf' was passed, "
-//           "but no memory flags to make use of it.");
-
-//     void *buf = 0;
-//     PYOPENCL_BUFFER_SIZE_T len;
-//     py::object *retained_buf_obj = 0;
-
-//     if (buffer.ptr() != Py_None)
-//     {
-//       if (flags & CL_MEM_USE_HOST_PTR)
-//       {
-//         if (PyObject_AsWriteBuffer(buffer.ptr(), &buf, &len))
-//           throw py::error_already_set();
-//       }
-//       else
-//       {
-//         if (PyObject_AsReadBuffer(
-//               buffer.ptr(), const_cast<const void **>(&buf), &len))
-//           throw py::error_already_set();
-//       }
-
-//       if (flags & CL_MEM_USE_HOST_PTR)
-//         retained_buf_obj = &buffer;
-//     }
-
-//     PYOPENCL_PRINT_CALL_TRACE("clCreateImage");
-//     cl_int status_code;
-//     cl_mem mem = clCreateImage(ctx.data(), flags, &fmt, &desc, buf, &status_code);
-//     if (status_code != CL_SUCCESS)
-//       throw pyopencl::error("clCreateImage", status_code);
-
-//     try
-//     {
-//       return new image(mem, false, retained_buf_obj);
-//     }
-//     catch (...)
-//     {
-//       PYOPENCL_CALL_GUARDED(clReleaseMemObject, (mem));
-//       throw;
-//     }
-//   }
-
-// #endif
-
-//   // }}}
-
-//   // {{{ image transfers
-
-//   inline
-//   event *enqueue_read_image(
-//       command_queue &cq,
-//       image &img,
-//       py::object py_origin, py::object py_region,
-//       py::object buffer,
-//       size_t row_pitch, size_t slice_pitch,
-//       py::object py_wait_for,
-//       bool is_blocking)
-//   {
-//     PYOPENCL_PARSE_WAIT_FOR;
-//     COPY_PY_COORD_TRIPLE(origin);
-//     COPY_PY_REGION_TRIPLE(region);
-
-//     void *buf;
-//     PYOPENCL_BUFFER_SIZE_T len;
-
-//     if (PyObject_AsWriteBuffer(buffer.ptr(), &buf, &len))
-//       throw py::error_already_set();
-
-//     cl_event evt;
-
-//     PYOPENCL_RETRY_IF_MEM_ERROR(
-//       PYOPENCL_CALL_GUARDED(clEnqueueReadImage, (
-//             cq.data(),
-//             img.data(),
-//             PYOPENCL_CAST_BOOL(is_blocking),
-//             origin, region, row_pitch, slice_pitch, buf,
-//             PYOPENCL_WAITLIST_ARGS, &evt
-//             ));
-//       );
-//     PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, buffer);
-//   }
-
-
-
-
-//   inline
-//   event *enqueue_write_image(
-//       command_queue &cq,
-//       image &img,
-//       py::object py_origin, py::object py_region,
-//       py::object buffer,
-//       size_t row_pitch, size_t slice_pitch,
-//       py::object py_wait_for,
-//       bool is_blocking)
-//   {
-//     PYOPENCL_PARSE_WAIT_FOR;
-//     COPY_PY_COORD_TRIPLE(origin);
-//     COPY_PY_REGION_TRIPLE(region);
-
-//     const void *buf;
-//     PYOPENCL_BUFFER_SIZE_T len;
-
-//     if (PyObject_AsReadBuffer(buffer.ptr(), &buf, &len))
-//       throw py::error_already_set();
-
-//     cl_event evt;
-//     PYOPENCL_RETRY_IF_MEM_ERROR(
-//       PYOPENCL_CALL_GUARDED(clEnqueueWriteImage, (
-//             cq.data(),
-//             img.data(),
-//             PYOPENCL_CAST_BOOL(is_blocking),
-//             origin, region, row_pitch, slice_pitch, buf,
-//             PYOPENCL_WAITLIST_ARGS, &evt
-//             ));
-//       );
-//     PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, buffer);
-//   }
-
-
-
-
-//   inline
-//   event *enqueue_copy_image(
-//       command_queue &cq,
-//       memory_object_holder &src,
-//       memory_object_holder &dest,
-//       py::object py_src_origin,
-//       py::object py_dest_origin,
-//       py::object py_region,
-//       py::object py_wait_for
-//       )
-//   {
-//     PYOPENCL_PARSE_WAIT_FOR;
-//     COPY_PY_COORD_TRIPLE(src_origin);
-//     COPY_PY_COORD_TRIPLE(dest_origin);
-//     COPY_PY_REGION_TRIPLE(region);
-
-//     cl_event evt;
-//     PYOPENCL_RETRY_IF_MEM_ERROR(
-//       PYOPENCL_CALL_GUARDED(clEnqueueCopyImage, (
-//             cq.data(), src.data(), dest.data(),
-//             src_origin, dest_origin, region,
-//             PYOPENCL_WAITLIST_ARGS, &evt
-//             ));
-//       );
-//     PYOPENCL_RETURN_NEW_EVENT(evt);
-//   }
-
-
-
-
-//   inline
-//   event *enqueue_copy_image_to_buffer(
-//       command_queue &cq,
-//       memory_object_holder &src,
-//       memory_object_holder &dest,
-//       py::object py_origin,
-//       py::object py_region,
-//       size_t offset,
-//       py::object py_wait_for
-//       )
-//   {
-//     PYOPENCL_PARSE_WAIT_FOR;
-//     COPY_PY_COORD_TRIPLE(origin);
-//     COPY_PY_REGION_TRIPLE(region);
-
-//     cl_event evt;
-//     PYOPENCL_RETRY_IF_MEM_ERROR(
-//       PYOPENCL_CALL_GUARDED(clEnqueueCopyImageToBuffer, (
-//             cq.data(), src.data(), dest.data(),
-//             origin, region, offset,
-//             PYOPENCL_WAITLIST_ARGS, &evt
-//             ));
-//       );
-//     PYOPENCL_RETURN_NEW_EVENT(evt);
-//   }
-
-
-
-
-//   inline
-//   event *enqueue_copy_buffer_to_image(
-//       command_queue &cq,
-//       memory_object_holder &src,
-//       memory_object_holder &dest,
-//       size_t offset,
-//       py::object py_origin,
-//       py::object py_region,
-//       py::object py_wait_for
-//       )
-//   {
-//     PYOPENCL_PARSE_WAIT_FOR;
-//     COPY_PY_COORD_TRIPLE(origin);
-//     COPY_PY_REGION_TRIPLE(region);
-
-//     cl_event evt;
-//     PYOPENCL_RETRY_IF_MEM_ERROR(
-//       PYOPENCL_CALL_GUARDED(clEnqueueCopyBufferToImage, (
-//             cq.data(), src.data(), dest.data(),
-//             offset, origin, region,
-//             PYOPENCL_WAITLIST_ARGS, &evt
-//             ));
-//       );
-//     PYOPENCL_RETURN_NEW_EVENT(evt);
-//   }
-
-//   // }}}
-
-// #if PYOPENCL_CL_VERSION >= 0x1020
-//   inline
-//   event *enqueue_fill_image(
-//       command_queue &cq,
-//       memory_object_holder &mem,
-//       py::object color,
-//       py::object py_origin, py::object py_region,
-//       py::object py_wait_for
-//       )
-//   {
-//     PYOPENCL_PARSE_WAIT_FOR;
-
-//     COPY_PY_COORD_TRIPLE(origin);
-//     COPY_PY_REGION_TRIPLE(region);
-
-//     const void *color_buf;
-//     PYOPENCL_BUFFER_SIZE_T color_len;
-
-//     if (PyObject_AsReadBuffer(color.ptr(), &color_buf, &color_len))
-//       throw py::error_already_set();
-
-//     cl_event evt;
-//     PYOPENCL_RETRY_IF_MEM_ERROR(
-//       PYOPENCL_CALL_GUARDED(clEnqueueFillImage, (
-//             cq.data(),
-//             mem.data(),
-//             color_buf, origin, region,
-//             PYOPENCL_WAITLIST_ARGS, &evt
-//             ));
-//       );
-//     PYOPENCL_RETURN_NEW_EVENT(evt);
-//   }
-// #endif
+  // }}}
+
+  // {{{ image creation
+
+  inline
+  image *create_image_2d(context const &ctx,
+			 cl_mem_flags flags,
+			 cl_image_format const &fmt,
+			 size_t width, size_t height,
+			 size_t pitch,
+			 void *buffer, size_t size)
+  {
+    cl_int status_code;
+    cl_mem mem;
+    void *retained_buf_obj = 0;
+    if(flags & CL_MEM_USE_HOST_PTR)
+      retained_buf_obj = buffer;
+
+    PYOPENCL_PRINT_CALL_TRACE("clCreateImage2D");
+    //
+    //PYOPENCL_RETRY_IF_MEM_ERROR(
+    {
+      mem = clCreateImage2D(ctx.data(), flags, &fmt,
+			    width, height, pitch, buffer, &status_code);
+      if (status_code != CL_SUCCESS)
+	throw pyopencl::error("clCreateImage2D", status_code);
+    }
+    //);
+
+    try
+      {
+	return new image(mem, false, retained_buf_obj);
+      }
+    catch (...)
+      {
+	PYOPENCL_CALL_GUARDED(clReleaseMemObject, (mem));
+	throw;
+      }
+  }
+
+  inline
+  image *create_image_3d(context const &ctx,
+			 cl_mem_flags flags,
+			 cl_image_format const &fmt,
+			 size_t width, size_t height, size_t depth,
+			 size_t pitch_x, size_t pitch_y,
+			 void *buffer, size_t size)
+  {
+    cl_int status_code;
+    cl_mem mem;
+    void *retained_buf_obj = 0;
+    if(flags & CL_MEM_USE_HOST_PTR)
+      retained_buf_obj = buffer;
+
+    PYOPENCL_PRINT_CALL_TRACE("clCreateImage3D");
+    //
+    //PYOPENCL_RETRY_IF_MEM_ERROR(
+    {
+      mem = clCreateImage3D(ctx.data(), flags, &fmt,
+			    width, height, depth, pitch_x, pitch_y, buffer, &status_code);
+      if (status_code != CL_SUCCESS)
+	throw pyopencl::error("clCreateImage3D", status_code);
+    }
+    //);
+
+    try
+      {
+	return new image(mem, false, retained_buf_obj);
+      }
+    catch (...)
+      {
+	PYOPENCL_CALL_GUARDED(clReleaseMemObject, (mem));
+	throw;
+      }
+  }
+  
+
+
+  // #if PYOPENCL_CL_VERSION >= 0x1020
+
+  //   inline
+  //   image *create_image_from_desc(
+  //       context const &ctx,
+  //       cl_mem_flags flags,
+  //       cl_image_format const &fmt,
+  //       cl_image_desc &desc,
+  //       py::object buffer)
+  //   {
+  //     if (buffer.ptr() != Py_None &&
+  //         !(flags & (CL_MEM_USE_HOST_PTR | CL_MEM_COPY_HOST_PTR)))
+  //       PyErr_Warn(PyExc_UserWarning, "'hostbuf' was passed, "
+  //           "but no memory flags to make use of it.");
+
+  //     void *buf = 0;
+  //     PYOPENCL_BUFFER_SIZE_T len;
+  //     py::object *retained_buf_obj = 0;
+
+  //     if (buffer.ptr() != Py_None)
+  //     {
+  //       if (flags & CL_MEM_USE_HOST_PTR)
+  //       {
+  //         if (PyObject_AsWriteBuffer(buffer.ptr(), &buf, &len))
+  //           throw py::error_already_set();
+  //       }
+  //       else
+  //       {
+  //         if (PyObject_AsReadBuffer(
+  //               buffer.ptr(), const_cast<const void **>(&buf), &len))
+  //           throw py::error_already_set();
+  //       }
+
+  //       if (flags & CL_MEM_USE_HOST_PTR)
+  //         retained_buf_obj = &buffer;
+  //     }
+
+  //     PYOPENCL_PRINT_CALL_TRACE("clCreateImage");
+  //     cl_int status_code;
+  //     cl_mem mem = clCreateImage(ctx.data(), flags, &fmt, &desc, buf, &status_code);
+  //     if (status_code != CL_SUCCESS)
+  //       throw pyopencl::error("clCreateImage", status_code);
+
+  //     try
+  //     {
+  //       return new image(mem, false, retained_buf_obj);
+  //     }
+  //     catch (...)
+  //     {
+  //       PYOPENCL_CALL_GUARDED(clReleaseMemObject, (mem));
+  //       throw;
+  //     }
+  //   }
+
+  // #endif
 
   // }}}
 
+  // {{{ image transfers
+
+  inline
+  event *enqueue_read_image(command_queue &cq,
+			    image &img,
+			    size_t *origin, size_t *region,
+			    void *buffer, size_t size, 
+			    size_t row_pitch, size_t slice_pitch,
+			    void **wait_for, uint32_t num_wait_for,
+			    bool is_blocking)
+  {
+    PYOPENCL_PARSE_WAIT_FOR;
+
+    cl_event evt;
+    // TODO
+    //PYOPENCL_RETRY_IF_MEM_ERROR(
+    PYOPENCL_CALL_GUARDED(clEnqueueReadImage,
+			  (cq.data(),
+			   img.data(),
+			   PYOPENCL_CAST_BOOL(is_blocking),
+			   origin, region, row_pitch, slice_pitch, buffer,
+			   PYOPENCL_WAITLIST_ARGS, &evt
+			   ));
+    //);
+    PYOPENCL_RETURN_NEW_EVENT(evt);
+    //PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, buffer);
+  }
+
+
+
+
+  //   inline
+  //   event *enqueue_write_image(
+  //       command_queue &cq,
+  //       image &img,
+  //       py::object py_origin, py::object py_region,
+  //       py::object buffer,
+  //       size_t row_pitch, size_t slice_pitch,
+  //       py::object py_wait_for,
+  //       bool is_blocking)
+  //   {
+  //     PYOPENCL_PARSE_WAIT_FOR;
+  //     COPY_PY_COORD_TRIPLE(origin);
+  //     COPY_PY_REGION_TRIPLE(region);
+
+  //     const void *buf;
+  //     PYOPENCL_BUFFER_SIZE_T len;
+
+  //     if (PyObject_AsReadBuffer(buffer.ptr(), &buf, &len))
+  //       throw py::error_already_set();
+
+  //     cl_event evt;
+  //     PYOPENCL_RETRY_IF_MEM_ERROR(
+  //       PYOPENCL_CALL_GUARDED(clEnqueueWriteImage, (
+  //             cq.data(),
+  //             img.data(),
+  //             PYOPENCL_CAST_BOOL(is_blocking),
+  //             origin, region, row_pitch, slice_pitch, buf,
+  //             PYOPENCL_WAITLIST_ARGS, &evt
+  //             ));
+  //       );
+  //     PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, buffer);
+  //   }
+
+
+
+
+  //   inline
+  //   event *enqueue_copy_image(
+  //       command_queue &cq,
+  //       memory_object_holder &src,
+  //       memory_object_holder &dest,
+  //       py::object py_src_origin,
+  //       py::object py_dest_origin,
+  //       py::object py_region,
+  //       py::object py_wait_for
+  //       )
+  //   {
+  //     PYOPENCL_PARSE_WAIT_FOR;
+  //     COPY_PY_COORD_TRIPLE(src_origin);
+  //     COPY_PY_COORD_TRIPLE(dest_origin);
+  //     COPY_PY_REGION_TRIPLE(region);
+
+  //     cl_event evt;
+  //     PYOPENCL_RETRY_IF_MEM_ERROR(
+  //       PYOPENCL_CALL_GUARDED(clEnqueueCopyImage, (
+  //             cq.data(), src.data(), dest.data(),
+  //             src_origin, dest_origin, region,
+  //             PYOPENCL_WAITLIST_ARGS, &evt
+  //             ));
+  //       );
+  //     PYOPENCL_RETURN_NEW_EVENT(evt);
+  //   }
+
+
+
+
+  //   inline
+  //   event *enqueue_copy_image_to_buffer(
+  //       command_queue &cq,
+  //       memory_object_holder &src,
+  //       memory_object_holder &dest,
+  //       py::object py_origin,
+  //       py::object py_region,
+  //       size_t offset,
+  //       py::object py_wait_for
+  //       )
+  //   {
+  //     PYOPENCL_PARSE_WAIT_FOR;
+  //     COPY_PY_COORD_TRIPLE(origin);
+  //     COPY_PY_REGION_TRIPLE(region);
+
+  //     cl_event evt;
+  //     PYOPENCL_RETRY_IF_MEM_ERROR(
+  //       PYOPENCL_CALL_GUARDED(clEnqueueCopyImageToBuffer, (
+  //             cq.data(), src.data(), dest.data(),
+  //             origin, region, offset,
+  //             PYOPENCL_WAITLIST_ARGS, &evt
+  //             ));
+  //       );
+  //     PYOPENCL_RETURN_NEW_EVENT(evt);
+  //   }
+
+
+
+
+  //   inline
+  //   event *enqueue_copy_buffer_to_image(
+  //       command_queue &cq,
+  //       memory_object_holder &src,
+  //       memory_object_holder &dest,
+  //       size_t offset,
+  //       py::object py_origin,
+  //       py::object py_region,
+  //       py::object py_wait_for
+  //       )
+  //   {
+  //     PYOPENCL_PARSE_WAIT_FOR;
+  //     COPY_PY_COORD_TRIPLE(origin);
+  //     COPY_PY_REGION_TRIPLE(region);
+
+  //     cl_event evt;
+  //     PYOPENCL_RETRY_IF_MEM_ERROR(
+  //       PYOPENCL_CALL_GUARDED(clEnqueueCopyBufferToImage, (
+  //             cq.data(), src.data(), dest.data(),
+  //             offset, origin, region,
+  //             PYOPENCL_WAITLIST_ARGS, &evt
+  //             ));
+  //       );
+  //     PYOPENCL_RETURN_NEW_EVENT(evt);
+  //   }
+
+  //   // }}}
+
+  // #if PYOPENCL_CL_VERSION >= 0x1020
+  //   inline
+  //   event *enqueue_fill_image(
+  //       command_queue &cq,
+  //       memory_object_holder &mem,
+  //       py::object color,
+  //       py::object py_origin, py::object py_region,
+  //       py::object py_wait_for
+  //       )
+  //   {
+  //     PYOPENCL_PARSE_WAIT_FOR;
+
+  //     COPY_PY_COORD_TRIPLE(origin);
+  //     COPY_PY_REGION_TRIPLE(region);
+
+  //     const void *color_buf;
+  //     PYOPENCL_BUFFER_SIZE_T color_len;
+
+  //     if (PyObject_AsReadBuffer(color.ptr(), &color_buf, &color_len))
+  //       throw py::error_already_set();
+
+  //     cl_event evt;
+  //     PYOPENCL_RETRY_IF_MEM_ERROR(
+  //       PYOPENCL_CALL_GUARDED(clEnqueueFillImage, (
+  //             cq.data(),
+  //             mem.data(),
+  //             color_buf, origin, region,
+  //             PYOPENCL_WAITLIST_ARGS, &evt
+  //             ));
+  //       );
+  //     PYOPENCL_RETURN_NEW_EVENT(evt);
+  //   }
+  // #endif
+
+// }}}
+
   
   
   // {{{ gl interop
@@ -1911,62 +1862,62 @@ namespace pyopencl
 
 
 
-// #if defined(cl_khr_gl_sharing) && (cl_khr_gl_sharing >= 1)
-//   inline
-//   py::object get_gl_context_info_khr(
-//       py::object py_properties,
-//       cl_gl_context_info param_name,
-//       py::object py_platform
-//       )
-//   {
-//     std::vector<cl_context_properties> props
-//       = parse_context_properties(py_properties);
-
-//     typedef CL_API_ENTRY cl_int (CL_API_CALL
-//       *func_ptr_type)(const cl_context_properties * /* properties */,
-//           cl_gl_context_info            /* param_name */,
-//           size_t                        /* param_value_size */,
-//           void *                        /* param_value */,
-//           size_t *                      /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0;
-
-//     func_ptr_type func_ptr;
-
-// #if PYOPENCL_CL_VERSION >= 0x1020
-//     if (py_platform.ptr() != Py_None)
-//     {
-//       platform &plat = py::extract<platform &>(py_platform);
-
-//       func_ptr = (func_ptr_type) clGetExtensionFunctionAddressForPlatform(
-//             plat.data(), "clGetGLContextInfoKHR");
-//     }
-//     else
-//     {
-//       PYOPENCL_DEPRECATED("get_gl_context_info_khr with platform=None", "2013.1", );
-
-//       func_ptr = (func_ptr_type) clGetExtensionFunctionAddress(
-//             "clGetGLContextInfoKHR");
-//     }
-// #else
-//     func_ptr = (func_ptr_type) clGetExtensionFunctionAddress(
-//           "clGetGLContextInfoKHR");
-// #endif
-
-
-//     if (!func_ptr)
-//       throw error("Context.get_info", CL_INVALID_PLATFORM,
-//           "clGetGLContextInfoKHR extension function not present");
-
-//     cl_context_properties *props_ptr
-//       = props.empty( ) ? NULL : &props.front();
-
-//     switch (param_name)
-//     {
-//       case CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KHR:
-//         {
-//           cl_device_id param_value;
-//           PYOPENCL_CALL_GUARDED(func_ptr,
-//               (props_ptr, param_name, sizeof(param_value), &param_value, 0));
-//           return py::object(handle_from_new_ptr( new device(param_value, /*retain*/ true)));
+  // #if defined(cl_khr_gl_sharing) && (cl_khr_gl_sharing >= 1)
+  //   inline
+  //   py::object get_gl_context_info_khr(
+  //       py::object py_properties,
+  //       cl_gl_context_info param_name,
+  //       py::object py_platform
+  //       )
+  //   {
+  //     std::vector<cl_context_properties> props
+  //       = parse_context_properties(py_properties);
+
+  //     typedef CL_API_ENTRY cl_int (CL_API_CALL
+  //       *func_ptr_type)(const cl_context_properties * /* properties */,
+  //           cl_gl_context_info            /* param_name */,
+  //           size_t                        /* param_value_size */,
+  //           void *                        /* param_value */,
+  //           size_t *                      /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0;
+
+  //     func_ptr_type func_ptr;
+
+  // #if PYOPENCL_CL_VERSION >= 0x1020
+  //     if (py_platform.ptr() != Py_None)
+  //     {
+  //       platform &plat = py::extract<platform &>(py_platform);
+
+  //       func_ptr = (func_ptr_type) clGetExtensionFunctionAddressForPlatform(
+  //             plat.data(), "clGetGLContextInfoKHR");
+  //     }
+  //     else
+  //     {
+  //       PYOPENCL_DEPRECATED("get_gl_context_info_khr with platform=None", "2013.1", );
+
+  //       func_ptr = (func_ptr_type) clGetExtensionFunctionAddress(
+  //             "clGetGLContextInfoKHR");
+  //     }
+  // #else
+  //     func_ptr = (func_ptr_type) clGetExtensionFunctionAddress(
+  //           "clGetGLContextInfoKHR");
+  // #endif
+
+
+  //     if (!func_ptr)
+  //       throw error("Context.get_info", CL_INVALID_PLATFORM,
+  //           "clGetGLContextInfoKHR extension function not present");
+
+  //     cl_context_properties *props_ptr
+  //       = props.empty( ) ? NULL : &props.front();
+
+  //     switch (param_name)
+  //     {
+  //       case CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KHR:
+  //         {
+  //           cl_device_id param_value;
+  //           PYOPENCL_CALL_GUARDED(func_ptr,
+  //               (props_ptr, param_name, sizeof(param_value), &param_value, 0));
+  //           return py::object(handle_from_new_ptr( new device(param_value, /*retain*/ true)));
   //         }
 
   //       case CL_DEVICES_FOR_GL_CONTEXT_KHR:
@@ -2156,7 +2107,75 @@ namespace pyopencl
   // }}}
   // }}}
 
-  
+  // {{{ sampler
+  class sampler // : boost::noncopyable
+  {
+    private:
+      cl_sampler m_sampler;
+
+    public:
+      sampler(context const &ctx, bool normalized_coordinates,
+          cl_addressing_mode am, cl_filter_mode fm)
+      {
+        cl_int status_code;
+        PYOPENCL_PRINT_CALL_TRACE("clCreateSampler");
+        m_sampler = clCreateSampler(
+            ctx.data(),
+            normalized_coordinates,
+            am, fm, &status_code);
+
+        if (status_code != CL_SUCCESS)
+          throw pyopencl::error("Sampler", status_code);
+      }
+
+      sampler(cl_sampler samp, bool retain)
+        : m_sampler(samp)
+      {
+        if (retain)
+          PYOPENCL_CALL_GUARDED(clRetainSampler, (samp));
+      }
+
+      ~sampler()
+      {
+        PYOPENCL_CALL_GUARDED_CLEANUP(clReleaseSampler, (m_sampler));
+      }
+
+      cl_sampler data() const
+      {
+        return m_sampler;
+      }
+
+      PYOPENCL_EQUALITY_TESTS(sampler);
+
+      generic_info get_info(cl_sampler_info param_name) const
+      {
+        switch (param_name)
+        {
+          case CL_SAMPLER_REFERENCE_COUNT:
+            PYOPENCL_GET_INTEGRAL_INFO(Sampler, m_sampler, param_name,
+                cl_uint);
+          case CL_SAMPLER_CONTEXT:
+            PYOPENCL_GET_OPAQUE_INFO(Sampler, m_sampler, param_name,
+				     cl_context, context, CONTEXT);
+          case CL_SAMPLER_ADDRESSING_MODE:
+            PYOPENCL_GET_INTEGRAL_INFO(Sampler, m_sampler, param_name,
+                cl_addressing_mode);
+          case CL_SAMPLER_FILTER_MODE:
+            PYOPENCL_GET_INTEGRAL_INFO(Sampler, m_sampler, param_name,
+                cl_filter_mode);
+          case CL_SAMPLER_NORMALIZED_COORDS:
+            PYOPENCL_GET_INTEGRAL_INFO(Sampler, m_sampler, param_name,
+                cl_bool);
+
+          default:
+            throw error("Sampler.get_info", CL_INVALID_VALUE);
+        }
+      }
+  };
+
+  // }}}
+
+
   // {{{ program
 
   class program : public _common //: boost::noncopyable
@@ -2413,28 +2432,18 @@ namespace pyopencl
 			    (m_kernel, arg_index, loc.size(), 0));
     }
 
-    // void set_arg_sampler(cl_uint arg_index, sampler const &smp)
-    // {
-    //   cl_sampler s = smp.data();
-    //   PYOPENCL_CALL_GUARDED(clSetKernelArg,
-    //       (m_kernel, arg_index, sizeof(cl_sampler), &s));
-    // }
-
-    // void set_arg_buf(cl_uint arg_index, py::object py_buffer)
-    // {
-    //   const void *buf;
-    //   PYOPENCL_BUFFER_SIZE_T len;
-
-    //   if (PyObject_AsReadBuffer(py_buffer.ptr(), &buf, &len))
-    //   {
-    //     PyErr_Clear();
-    //     throw error("Kernel.set_arg", CL_INVALID_VALUE,
-    //         "invalid kernel argument");
-    //   }
+    void set_arg_sampler(cl_uint arg_index, sampler const &smp)
+    {
+      cl_sampler s = smp.data();
+      PYOPENCL_CALL_GUARDED(clSetKernelArg,
+			    (m_kernel, arg_index, sizeof(cl_sampler), &s));
+    }
 
-    //   PYOPENCL_CALL_GUARDED(clSetKernelArg,
-    //       (m_kernel, arg_index, len, buf));
-    // }
+    void set_arg_buf(cl_uint arg_index, void *buffer, size_t size)
+    {
+      PYOPENCL_CALL_GUARDED(clSetKernelArg,
+			    (m_kernel, arg_index, size, buffer));
+    }
 
     // void set_arg(cl_uint arg_index, py::object arg)
     // {
@@ -2568,8 +2577,7 @@ namespace pyopencl
   event *enqueue_read_buffer(
 			     command_queue &cq,
 			     memory_object_holder &mem,
-			     void *buffer,
-			     size_t size, 
+			     void *buffer, size_t size, 
 			     size_t device_offset,
 			     void **wait_for, uint32_t num_wait_for,
 			     bool is_blocking)
@@ -2886,6 +2894,12 @@ void _free2(void **p, uint32_t size) {
   return 0;
 }
 
+::error *_create_sampler(void **ptr_sampler, void *ptr_context, int normalized_coordinates, cl_addressing_mode am, cl_filter_mode fm) {
+  C_HANDLE_ERROR(*ptr_sampler = new pyopencl::sampler(*static_cast<pyopencl::context*>(ptr_context), (bool)normalized_coordinates, am, fm););
+  return 0;
+}
+
+
 ::error *event__get_profiling_info(void *ptr, cl_profiling_info param, generic_info *out) {
   C_HANDLE_ERROR(*out = static_cast<pyopencl::event*>(ptr)->get_profiling_info(param););
   return 0;
@@ -2904,14 +2918,29 @@ void _free2(void **p, uint32_t size) {
   return 0;
 }
 
-::error *kernel__set_arg_mem_buffer(void *ptr_kernel, cl_uint arg_index, void *ptr_buffer) {
-  pyopencl::buffer *buf = static_cast<pyopencl::buffer*>(ptr_buffer);
-  C_HANDLE_ERROR(
-		 static_cast<pyopencl::kernel*>(ptr_kernel)->set_arg_mem(arg_index, *buf);
-		 );
+::error *kernel__set_arg_null(void *ptr_kernel, cl_uint arg_index) {
+  C_HANDLE_ERROR(static_cast<pyopencl::kernel*>(ptr_kernel)->set_arg_null(arg_index););
   return 0;
 }
 
+::error *kernel__set_arg_mem(void *ptr_kernel, cl_uint arg_index, void *ptr_mem) {
+  pyopencl::memory_object *mem = static_cast<pyopencl::memory_object*>(ptr_mem);
+  C_HANDLE_ERROR(static_cast<pyopencl::kernel*>(ptr_kernel)->set_arg_mem(arg_index, *mem););
+  return 0;
+}
+
+::error *kernel__set_arg_sampler(void *ptr_kernel, cl_uint arg_index, void *ptr_sampler) {
+  pyopencl::sampler *sampler = static_cast<pyopencl::sampler*>(ptr_sampler);
+  C_HANDLE_ERROR(static_cast<pyopencl::kernel*>(ptr_kernel)->set_arg_sampler(arg_index, *sampler););
+  return 0;
+}
+
+::error *kernel__set_arg_buf(void *ptr_kernel, cl_uint arg_index, void *buffer, size_t size) {
+  C_HANDLE_ERROR(static_cast<pyopencl::kernel*>(ptr_kernel)->set_arg_buf(arg_index, buffer, size););
+  return 0;
+}
+
+
 ::error *kernel__get_work_group_info(void *ptr, cl_kernel_work_group_info param, void *ptr_device, generic_info *out) {
   C_HANDLE_ERROR(*out = static_cast<pyopencl::kernel*>(ptr)->get_work_group_info(param, *static_cast<pyopencl::device*>(ptr_device)););
   return 0;
@@ -2922,6 +2951,22 @@ void _free2(void **p, uint32_t size) {
   return 0;
 }
 
+error *_create_image_2d(void **ptr_image, void *ptr_context, cl_mem_flags flags, cl_image_format *fmt, size_t width, size_t height, size_t pitch, void *ptr_buffer, size_t size) {
+  C_HANDLE_ERROR(*ptr_image = create_image_2d(*static_cast<pyopencl::context*>(ptr_context), flags, *fmt, width, height, pitch, ptr_buffer, size););
+  return 0;
+}
+
+ 
+error *_create_image_3d(void **ptr_image, void *ptr_context, cl_mem_flags flags, cl_image_format *fmt, size_t width, size_t height, size_t depth, size_t pitch_x, size_t pitch_y, void *ptr_buffer, size_t size) {
+  C_HANDLE_ERROR(*ptr_image = create_image_3d(*static_cast<pyopencl::context*>(ptr_context), flags, *fmt, width, height, depth, pitch_x, pitch_y, ptr_buffer, size););
+  return 0;
+}
+
+::error *image__get_image_info(void *ptr, cl_image_info param, generic_info *out) {
+  C_HANDLE_ERROR(*out = static_cast<pyopencl::image*>(ptr)->get_image_info(param););
+  return 0;
+}
+
 
 ::error *_enqueue_nd_range_kernel(void **ptr_event, void *ptr_command_queue, void *ptr_kernel, cl_uint work_dim, const size_t *global_work_offset, const size_t *global_work_size, const size_t *local_work_size) {
   C_HANDLE_ERROR(
@@ -2937,32 +2982,38 @@ void _free2(void **p, uint32_t size) {
 
 
 ::error *_enqueue_read_buffer(void **ptr_event, void *ptr_command_queue, void *ptr_memory_object_holder, void *buffer, size_t size, size_t device_offset, void **wait_for, uint32_t num_wait_for, int is_blocking) {
-  C_HANDLE_ERROR(
-		 *ptr_event = enqueue_read_buffer(*static_cast<pyopencl::command_queue*>(ptr_command_queue),
+  C_HANDLE_ERROR(*ptr_event = enqueue_read_buffer(*static_cast<pyopencl::command_queue*>(ptr_command_queue),
 						  *static_cast<pyopencl::memory_object_holder*>(ptr_memory_object_holder),
 						  buffer, size, device_offset, wait_for, num_wait_for, (bool)is_blocking);
 		 );
   return 0;
 }
 
-::error *_enqueue_write_buffer(void **ptr_event, void *ptr_command_queue, void *ptr_memory_object_holder, void *buffer, size_t size, size_t device_offset, void **wait_for, uint32_t num_wait_for, int is_blocking) {
-  C_HANDLE_ERROR(
-		 *ptr_event = enqueue_write_buffer(*static_cast<pyopencl::command_queue*>(ptr_command_queue),
-						   *static_cast<pyopencl::memory_object_holder*>(ptr_memory_object_holder),
+::error *_enqueue_write_buffer(void **ptr_event, void *ptr_command_queue, void *ptr_mem, void *buffer, size_t size, size_t device_offset, void **wait_for, uint32_t num_wait_for, int is_blocking) {
+  C_HANDLE_ERROR(*ptr_event = enqueue_write_buffer(*static_cast<pyopencl::command_queue*>(ptr_command_queue),
+						   *static_cast<pyopencl::memory_object_holder*>(ptr_mem),
 						   buffer, size, device_offset, wait_for, num_wait_for, (bool)is_blocking);
 		 );
   return 0;
 }
 
 ::error *_enqueue_copy_buffer(void **ptr_event, void *ptr_command_queue, void *ptr_src, void *ptr_dst, ptrdiff_t byte_count, size_t src_offset, size_t dst_offset, void **wait_for, uint32_t num_wait_for) {
-  C_HANDLE_ERROR(
-		 *ptr_event = enqueue_copy_buffer(*static_cast<pyopencl::command_queue*>(ptr_command_queue),
+  C_HANDLE_ERROR(*ptr_event = enqueue_copy_buffer(*static_cast<pyopencl::command_queue*>(ptr_command_queue),
 						  *static_cast<pyopencl::memory_object_holder*>(ptr_src),
 						  *static_cast<pyopencl::memory_object_holder*>(ptr_dst),
 						  byte_count, src_offset, dst_offset, wait_for, num_wait_for);
 		 );
   return 0;
 }
+
+::error *_enqueue_read_image(void **ptr_event, void *ptr_command_queue, void *ptr_mem, size_t *origin, size_t *region, void *buffer, size_t size, size_t row_pitch, size_t slice_pitch, void **wait_for, uint32_t num_wait_for, int is_blocking) {
+  C_HANDLE_ERROR(*ptr_event = enqueue_read_image(*static_cast<pyopencl::command_queue*>(ptr_command_queue),
+						  *static_cast<pyopencl::image*>(ptr_mem),
+						 origin, region, buffer, size, row_pitch, slice_pitch, wait_for, num_wait_for, (bool)is_blocking);
+		 );
+  return 0;
+}
+
   
 intptr_t _int_ptr(void* ptr, class_t class_) {
 #define INT_PTR(CLSU, CLS) return (intptr_t)(static_cast<pyopencl::CLS*>(ptr)->data());
diff --git a/src/c_wrapper/wrap_cl_core.h b/src/c_wrapper/wrap_cl_core.h
index 22cf2e26..c279df58 100644
--- a/src/c_wrapper/wrap_cl_core.h
+++ b/src/c_wrapper/wrap_cl_core.h
@@ -18,7 +18,9 @@ typedef enum {
   CLASS_EVENT,
   CLASS_COMMAND_QUEUE,
   CLASS_GL_BUFFER,
-  CLASS_GL_RENDERBUFFER
+  CLASS_GL_RENDERBUFFER,
+  CLASS_IMAGE,
+  CLASS_SAMPLER
 } class_t;
 
 
@@ -42,21 +44,32 @@ error *program__build(void *ptr_program, char *options, cl_uint num_devices, voi
 error *program__kind(void *ptr_program, int *kind);
 error *program__get_build_info(void *ptr_program, void *ptr_device, cl_program_build_info param, generic_info *out);
 
+error *_create_sampler(void **ptr_sampler, void *ptr_context, int normalized_coordinates, cl_addressing_mode am, cl_filter_mode fm);
+
 error *event__get_profiling_info(void *ptr_event, cl_profiling_info param, generic_info *out);
 error *event__wait(void *ptr_event);
 
 error *_create_kernel(void **ptr_kernel, void *ptr_program, char *name);
-error *kernel__set_arg_mem_buffer(void *ptr_kernel, cl_uint arg_index, void *ptr_buffer);
+error *kernel__set_arg_null(void *ptr_kernel, cl_uint arg_index);
+error *kernel__set_arg_mem(void *ptr_kernel, cl_uint arg_index, void *ptr_mem);
+error *kernel__set_arg_sampler(void *ptr_kernel, cl_uint arg_index, void *ptr_sampler);
+error *kernel__set_arg_buf(void *ptr_kernel, cl_uint arg_index, void *buffer, size_t size);
+
 error *kernel__get_work_group_info(void *ptr_kernel, cl_kernel_work_group_info param, void *ptr_device, generic_info *out);
 
 error *_get_supported_image_formats(void *ptr_context, cl_mem_flags flags, cl_mem_object_type image_type, generic_info *out);
 
+error *_create_image_2d(void **ptr_image, void *ptr_context, cl_mem_flags flags, cl_image_format *fmt, size_t width, size_t height, size_t pitch, void *ptr_buffer, size_t size);
+error *_create_image_3d(void **ptr_image, void *ptr_context, cl_mem_flags flags, cl_image_format *fmt, size_t width, size_t height, size_t depth, size_t pitch_x, size_t pitch_y, void *ptr_buffer, size_t size);
+error *image__get_image_info(void *ptr_image, cl_image_info param, generic_info *out);
+
 long _hash(void *ptr_platform, class_t);
 
 error *_enqueue_nd_range_kernel(void **ptr_event, void *ptr_command_queue, void *ptr_kernel, cl_uint work_dim, const size_t *global_work_offset, const size_t *global_work_size, const size_t *local_work_size);
-error *_enqueue_read_buffer(void **ptr_event, void *ptr_command_queue, void *ptr_memory_object_holder, void *buffer, size_t size, size_t device_offset, void **wait_for, uint32_t num_wait_for, int is_blocking);
+error *_enqueue_read_buffer(void **ptr_event, void *ptr_command_queue, void *ptr_mem, void *buffer, size_t size, size_t device_offset, void **wait_for, uint32_t num_wait_for, int is_blocking);
 error *_enqueue_copy_buffer(void **ptr_event, void *ptr_command_queue, void *ptr_src, void *ptr_dst, ptrdiff_t byte_count, size_t src_offset, size_t dst_offset, void **wait_for, uint32_t num_wait_for);
 error *_enqueue_write_buffer(void **ptr_event, void *ptr_command_queue, void *ptr_memory_object_holder, void *buffer, size_t size, size_t device_offset, void **wait_for, uint32_t num_wait_for, int is_blocking);
+error *_enqueue_read_image(void **ptr_event, void *ptr_command_queue, void *ptr_mem, size_t *origin, size_t *region, void *buffer, size_t size, size_t row_pitch, size_t slice_pitch, void **wait_for, uint32_t num_wait_for, int is_blocking);
 void populate_constants(void(*add)(const char*, const char*, long value));
 
 intptr_t _int_ptr(void*, class_t);
-- 
GitLab