diff --git a/doc/source/runtime.rst b/doc/source/runtime.rst index 7479b78b47e433e26da99f4fe7186d83dd7829d3..3c39da4d17da4720ee57488160ecd1b877c64d62 100644 --- a/doc/source/runtime.rst +++ b/doc/source/runtime.rst @@ -431,7 +431,7 @@ Image Formats Images ^^^^^^ -.. class:: Image(context, flags, format, shape=None, pitches=None, hostbuf=None) +.. class:: Image(context, flags, format, shape=None, pitches=None, hostbuf=None, is_array=False, buffer=None): See :class:`mem_flags` for values of *flags*. *shape* is a 2- or 3-tuple. *format* is an instance of :class:`ImageFormat`. @@ -458,6 +458,9 @@ Images .. versionadded:: 0.91 + .. versionchanged:: 2011.2 + Added *is_array* and *buffer*, which are only available on CL 1.2 and newer. + .. attribute:: info Lower case versions of the :class:`mem_info` diff --git a/pyopencl/__init__.py b/pyopencl/__init__.py index f4e3158c5c7f10e0002af9abf0fe2a9b5b2ea09b..73f29218afc0921955ce25be2ea2b5d233acf328 100644 --- a/pyopencl/__init__.py +++ b/pyopencl/__init__.py @@ -1,4 +1,4 @@ -from pyopencl.version import VERSION, VERSION_STATUS, VERSION_TEXT + try: import pyopencl._cl as _cl @@ -134,6 +134,115 @@ def link_program(context, programs, options=[], devices=None): # }}} +# {{{ Image + +class Image(_cl._ImageBase): + def __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 not None: + shape = hostbuf.shape + + if hostbuf is 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 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 + + 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 + + else: + raise ValueError("images cannot have more than three dimensions") + + desc = ImageDescriptor() + + desc.image_type = image_type + desc.shape = shape # also sets desc.array_size + + if pitches is None: + desc.pitches = (0, 0) + else: + desc.pitches = pitches + + desc.num_mip_levels = 0 # per CL 1.2 spec + desc.num_samples = 0 # per CL 1.2 spec + desc.buffer = buffer + + _cl._ImageBase.__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") + + _cl._ImageBase.__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) + + image = property(_ImageInfoGetter) + + @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("only images have shapes") + +# }}} + def _add_functionality(): cls_to_info_cls = { _cl.Platform: @@ -148,8 +257,8 @@ def _add_functionality(): (_cl.Event.get_info, _cl.event_info), _cl.MemoryObjectHolder: (MemoryObjectHolder.get_info,_cl.mem_info), - _cl.Image: - (Image.get_image_info, _cl.image_info), + Image: + (_cl._ImageBase.get_image_info, _cl.image_info), Program: (Program.get_info, _cl.program_info), _cl.Kernel: @@ -412,38 +521,6 @@ def _add_functionality(): # }}} - # {{{ Image - - 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") - - _cl.Image.image = property(ImageInfoGetter) - _cl.Image.shape = property(image_shape) - - # }}} - # {{{ Error def error_str(self): diff --git a/src/wrapper/wrap_cl.hpp b/src/wrapper/wrap_cl.hpp index 509e83f889dc798d1d1f6e97ead57a0742339133..d7cbc62fd4aeeab8524558b0f90153f51a21a693 100644 --- a/src/wrapper/wrap_cl.hpp +++ b/src/wrapper/wrap_cl.hpp @@ -1,8 +1,7 @@ #ifndef _AFJHAYYTA_PYOPENCL_HEADER_SEEN_WRAP_CL_HPP #define _AFJHAYYTA_PYOPENCL_HEADER_SEEN_WRAP_CL_HPP -// CL 1.2 TODO: -// python interface for new-style image creation +// CL 1.2 undecided: // clSetPrintfCallback // {{{ includes @@ -2110,19 +2109,9 @@ namespace pyopencl py::object pitches, 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."); - if (shape.ptr() == Py_None) - { - if (buffer.ptr() == Py_None) - throw pyopencl::error("Image", CL_INVALID_VALUE, - "'shape' must be passed if 'hostbuf' is not given"); - - shape = buffer.attr("shape"); - } + throw pyopencl::error("Image", CL_INVALID_VALUE, + "'shape' must be given"); void *buf = 0; PYOPENCL_BUFFER_SIZE_T len; diff --git a/src/wrapper/wrap_cl_part_2.cpp b/src/wrapper/wrap_cl_part_2.cpp index d6a5c678ed0ae1a1a9718c990029cb494c3ebfd2..8fd8a63299e802827a356d105aea08e29c281988 100644 --- a/src/wrapper/wrap_cl_part_2.cpp +++ b/src/wrapper/wrap_cl_part_2.cpp @@ -16,6 +16,7 @@ namespace pyopencl { desc.image_width = shape[0]; desc.image_height = shape[1]; desc.image_depth = shape[2]; + desc.image_array_size = shape[2]; } void image_desc_set_pitches(cl_image_desc &desc, py::object py_pitches) @@ -25,9 +26,12 @@ namespace pyopencl { desc.image_slice_pitch = pitches[1]; } - void image_desc_set_buffer(cl_image_desc &desc, memory_object &mobj) + void image_desc_set_buffer(cl_image_desc &desc, memory_object *mobj) { - desc.buffer = mobj.data(); + if (mobj) + desc.buffer = mobj->data(); + else + desc.buffer = 0; } #endif @@ -63,7 +67,7 @@ void pyopencl_expose_part_2() { typedef image cls; py::class_, boost::noncopyable>( - "Image", py::no_init) + "_ImageBase", py::no_init) .def("__init__", make_constructor(create_image, py::default_call_policies(), (py::args("context", "flags", "format"),