From 1d0cf8f9dadf69adfbf04413a4a061ce749a0db8 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner <inform@tiker.net> Date: Fri, 28 Mar 2014 19:08:19 -0500 Subject: [PATCH] Make cffi_cl flake8-clean --- pyopencl/cffi_cl.py | 663 +++++++++++++++++++++++++++++++------------- 1 file changed, 476 insertions(+), 187 deletions(-) diff --git a/pyopencl/cffi_cl.py b/pyopencl/cffi_cl.py index 35481c88..8d450041 100644 --- a/pyopencl/cffi_cl.py +++ b/pyopencl/cffi_cl.py @@ -1,9 +1,39 @@ -from pyopencl._cl import PooledBuffer, MemoryPool +from __future__ import division + +__copyright__ = """ +Copyright (C) 2013 Marko Bencun +Copyright (C) 2014 Andreas Kloeckner +""" + +__license__ = """ +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + + +#from pyopencl._cl import PooledBuffer, MemoryPool import warnings import np -import ctypes import sys +# TODO: can we do without ctypes? +import ctypes + from _cffi import _ffi, _lib # are we running on pypy? @@ -12,6 +42,11 @@ _PYPY = '__pypy__' in sys.builtin_module_names bitlog2 = _lib.bitlog2 + +# {{{ wrapper tools + +# {{{ _CArray helper classes + class _CArray(object): def __init__(self, ptr): self.ptr = ptr @@ -28,14 +63,124 @@ class _CArray(object): for i in xrange(self.size[0]): yield self[i] + class _CArrays(_CArray): def __del__(self): _lib._free2(_ffi.cast('void**', self.ptr[0]), self.size[0]) super(_CArrays, self).__del__() -class _NoInit(object): - def __init__(self): - raise RuntimeError("This class cannot be instantiated.") +# }}} + + +# {{{ GetInfo support + +def _generic_info_to_python(info): + type_ = _ffi.string(info.type) + value = _ffi.cast(type_, info.value) + + if info.opaque_class != _lib.CLASS_NONE: + klass = { + _lib.CLASS_PLATFORM: Platform, + _lib.CLASS_DEVICE: Device, + _lib.CLASS_KERNEL: Kernel, + _lib.CLASS_CONTEXT: Context, + _lib.CLASS_BUFFER: Buffer, + _lib.CLASS_PROGRAM: _Program, + _lib.CLASS_EVENT: Event, + _lib.CLASS_COMMAND_QUEUE: CommandQueue + }[info.opaque_class] + + def ci(ptr): + ins = _create_instance(klass, ptr) + if info.opaque_class == _lib.CLASS_PROGRAM: # TODO: HACK? + from . import Program + return Program(ins) + return ins + + if type_.endswith(']'): + ret = map(ci, value) + _lib._free(info.value) + return ret + else: + return ci(value) + if type_ == 'char*': + ret = _ffi.string(value) + elif type_.startswith('char*['): + ret = map(_ffi.string, value) + _lib._free2(info.value, len(value)) + elif type_.endswith(']'): + if type_.startswith('char['): + ret = ''.join(a[0] for a in value) + elif type_.startswith('generic_info['): + ret = list(map(_generic_info_to_python, value)) + elif type_.startswith('cl_image_format['): + ret = [ + ImageFormat( + imf.image_channel_order, + imf.image_channel_data_type) + for imf in value] + else: + ret = list(value) + else: + ret = value[0] + if info.dontfree == 0: + _lib._free(info.value) + return ret + +# }}} + + +def _c_obj_list(objs=None): + if objs is None: + return _ffi.NULL, 0 + return _ffi.new('void *[]', [ev.ptr for ev in objs]), len(objs) + + +def _create_instance(cls, ptr): + ins = cls.__new__(cls) + ins.ptr = ptr + return ins + + +# {{{ common base class + +class _Common(object): + ptr = _ffi.NULL + + @classmethod + def _c_class_type(cls): + return getattr(_lib, 'CLASS_%s' % cls._id.upper()) + + def __del__(self): + _lib._delete(self.ptr, self._c_class_type()) + + def __eq__(self, other): + return hash(self) == hash(other) + + def __hash__(self): + return _lib._hash(self.ptr, self._c_class_type()) + + def get_info(self, param): + info = _ffi.new('generic_info *') + _handle_error(_lib._get_info(self.ptr, self._c_class_type(), param, info)) + return _generic_info_to_python(info) + + @property + def int_ptr(self): + return _lib._int_ptr(self.ptr, self._c_class_type()) + + @classmethod + def from_int_ptr(cls, int_ptr_value): + ptr = _ffi.new('void **') + _lib._from_int_ptr(ptr, int_ptr_value, + getattr(_lib, 'CLASS_%s' % cls._id.upper())) + #getattr(_lib, '%s__from_int_ptr' % cls._id)(ptr, int_ptr_value) + return _create_instance(cls, ptr[0]) + +# }}} + +# }}} + def get_cl_header_version(): v = _lib.get_cl_version() @@ -43,9 +188,49 @@ def get_cl_header_version(): (v >> (1*4)) & 0xff) +# {{{ constants -# {{{ expose constants classes like platform_info, device_type, ... _constants = {} + + +class _NoInit(object): + def __init__(self): + raise RuntimeError("This class cannot be instantiated.") + + +# {{{ constant classes +# These will be overwritten below and exist to placate pyflakes. + +class status_code(_NoInit): + pass + + +class context_properties(_NoInit): + pass + + +class device_type(_NoInit): + pass + + +class mem_flags(_NoInit): + pass + + +class mem_object_type(_NoInit): + pass + + +class channel_order(_NoInit): + pass + + +class channel_type(_NoInit): + pass + +# }}} + + @_ffi.callback('void(const char*, const char* name, long value)') def _constant_callback(type_, name, value): s_type = _ffi.string(type_) @@ -55,6 +240,7 @@ _lib.populate_constants(_constant_callback) for type_, d in _constants.iteritems(): locals()[type_] = type(type_, (_NoInit,), d) + # }}} @@ -67,13 +253,19 @@ class Error(Exception): self.what = msg super(Error, self).__init__(self, msg) + class MemoryError(Error): pass + + class LogicError(Error): pass + + class RuntimeError(Error): pass + def _handle_error(error): if error == _ffi.NULL: return @@ -92,53 +284,64 @@ def _handle_error(error): klass = RuntimeError else: klass = Error - e = klass(routine=_ffi.string(error.routine), code=error.code, msg=_ffi.string(error.msg)) + e = klass(routine=_ffi.string(error.routine), + code=error.code, msg=_ffi.string(error.msg)) _lib._free(error.routine) _lib._free(error.msg) _lib._free(error) raise e + # }}} -class _Common(object): - ptr = _ffi.NULL - - @classmethod - def _c_class_type(cls): - return getattr(_lib, 'CLASS_%s' % cls._id.upper()) - def __del__(self): - _lib._delete(self.ptr, self._c_class_type()) +# {{{ Platform - def __eq__(self, other): - return hash(self) == hash(other) +class Platform(_Common): + _id = 'platform' + # todo: __del__ - def __hash__(self): - return _lib._hash(self.ptr, self._c_class_type()) + def get_devices(self, device_type=device_type.ALL): + devices = _CArray(_ffi.new('void**')) + _handle_error(_lib.platform__get_devices( + self.ptr, devices.ptr, devices.size, device_type)) - def get_info(self, param): - info = _ffi.new('generic_info *') - _handle_error(_lib._get_info(self.ptr, self._c_class_type(), param, info)) - return _generic_info_to_python(info) + result = [] + for i in xrange(devices.size[0]): + # TODO why is the cast needed? + device_ptr = _ffi.cast('void**', devices.ptr[0])[i] + result.append(_create_instance(Device, device_ptr)) + return result - @property - def int_ptr(self): - return _lib._int_ptr(self.ptr, self._c_class_type()) - @classmethod - def from_int_ptr(cls, int_ptr_value): - ptr = _ffi.new('void **') - _lib._from_int_ptr(ptr, int_ptr_value, getattr(_lib, 'CLASS_%s' % cls._id.upper())) - #getattr(_lib, '%s__from_int_ptr' % cls._id)(ptr, int_ptr_value) - return _create_instance(cls, ptr[0]) +def get_platforms(): + platforms = _CArray(_ffi.new('void**')) + _handle_error(_lib.get_platforms(platforms.ptr, platforms.size)) + result = [] + for i in xrange(platforms.size[0]): + # TODO why is the cast needed? + platform_ptr = _ffi.cast('void**', platforms.ptr[0])[i] + result.append(_create_instance(Platform, platform_ptr)) + + return result + +# }}} + + +# {{{ Device class Device(_Common): _id = 'device' - # todo: __del__ + # TODO: __del__ def get_info(self, param): return super(Device, self).get_info(param) +# }}} + + +# {{{ Context + def _parse_context_properties(properties): props = [] if properties is None: @@ -146,16 +349,22 @@ def _parse_context_properties(properties): for prop_tuple in properties: if len(prop_tuple) != 2: - raise RuntimeError("Context", status_code.INVALID_VALUE, "property tuple must have length 2") + raise RuntimeError("Context", status_code.INVALID_VALUE, + "property tuple must have length 2") + prop, value = prop_tuple if prop is None: - raise RuntimeError("Context", status_code.INVALID_VALUE, "invalid context property") + raise RuntimeError("Context", status_code.INVALID_VALUE, + "invalid context property") props.append(prop) if prop == context_properties.PLATFORM: props.append(value.int_ptr) - elif prop == getattr(context_properties, "WGL_HDC_KHR"): # TODO if _WIN32? Why? + + # TODO: used to be ifdef _WIN32? Why? + elif prop == getattr(context_properties, "WGL_HDC_KHR"): props.append(value) + elif prop in [getattr(context_properties, key, None) for key in ( 'CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE', 'GL_CONTEXT_KHR', @@ -163,14 +372,16 @@ def _parse_context_properties(properties): 'GLX_DISPLAY_KHR', 'CGL_SHAREGROUP_KHR', )]: - # TODO: without ctypes? - import ctypes + val = (ctypes.cast(value, ctypes.c_void_p)).value if val is None: - raise LogicError("Context", status_code.INVALID_VALUE, "You most likely have not initialized OpenGL properly.") + raise LogicError("Context", + status_code.INVALID_VALUE, + "You most likely have not initialized OpenGL properly.") props.append(val) else: - raise RuntimeError("Context", status_code.INVALID_VALUE, "invalid context property") + raise RuntimeError("Context", status_code.INVALID_VALUE, + "invalid context property") props.append(0) return _ffi.new('cl_context_properties[]', props) @@ -185,92 +396,148 @@ class Context(_Common): # from device list if devices is not None: if dev_type is not None: - raise RuntimeError("Context", status_code.INVALID_VALUE, "one of 'devices' or 'dev_type' must be None") + raise RuntimeError("Context", status_code.INVALID_VALUE, + "one of 'devices' or 'dev_type' must be None") ptr_devices = _ffi.new('void*[]', [device.ptr for device in devices]) ptr_ctx = _ffi.new('void **') - _handle_error(_lib._create_context(ptr_ctx, c_props, len(ptr_devices), _ffi.cast('void**', ptr_devices))) + _handle_error(_lib._create_context( + ptr_ctx, c_props, len(ptr_devices), + _ffi.cast('void**', ptr_devices))) - else: # from dev_type + else: # TODO: from dev_type raise NotImplementedError() self.ptr = ptr_ctx[0] +# }}} + + +# {{{ CommandQueue + class CommandQueue(_Common): _id = 'command_queue' + def __init__(self, context, device=None, properties=None): if properties is None: properties = 0 + ptr_command_queue = _ffi.new('void **') - _handle_error(_lib._create_command_queue(ptr_command_queue, context.ptr, _ffi.NULL if device is None else device.ptr, properties)) + + _handle_error(_lib._create_command_queue( + ptr_command_queue, context.ptr, + _ffi.NULL if device is None else device.ptr, properties)) + self.ptr = ptr_command_queue[0] + class MemoryObjectHolder(_Common): pass + class MemoryObject(MemoryObjectHolder): pass + def _c_buffer_from_obj(obj, writable=False): - """ - Convert a Python object to a tuple (cdata('void *'), num_bytes, dummy) to be able to pass - a data stream to a C function. The dummy variable exists only to ensure that the Python object referencing the - C buffer is not garbage collected at the end of this function, making the C buffer itself invalid. + """Convert a Python object to a tuple (cdata('void *'), num_bytes, dummy) + to be able to pass a data stream to a C function. The dummy variable exists + only to ensure that the Python object referencing the C buffer is not + garbage collected at the end of this function, making the C buffer itself + invalid. """ if _PYPY: # {{{ special case: numpy (also works with numpypy) + if isinstance(obj, np.ndarray): # numpy array - return _ffi.cast('void *', obj.__array_interface__['data'][0]), obj.nbytes, None + return ( + _ffi.cast('void *', + obj.__array_interface__['data'][0]), + obj.nbytes, + None) if isinstance(obj, np.generic): # numpy scalar - # * obj.__array_interface__ exists in CPython, but the address does not seem to point - # to the actual scalar (not supported/bug?). + # + # * obj.__array_interface__ exists in CPython, but the address does + # not seem to point to the actual scalar (not supported/bug?). + # # * does not exist (yet?) in numpypy. - s_array = np.array([obj]) # obj[()] not supported yet by numpypy - return _ffi.cast('void *', s_array.__array_interface__['data'][0]), s_array.nbytes, s_array + + s_array = np.array([obj]) # obj[()] not supported yet by numpypy + return ( + _ffi.cast('void *', + s_array.__array_interface__['data'][0]), + s_array.nbytes, + s_array) else: - raise LogicError("", status_code.INVALID_VALUE, "PyOpencl on PyPy only accepts numpy arrays and scalars arguments") + raise LogicError("", status_code.INVALID_VALUE, + "PyOpencl on PyPy only accepts numpy arrays " + "and scalars arguments") + # }}} # TODO: is there a cross-interpreter solution? - + # {{{ fall back to the old CPython buffer protocol API + addr = ctypes.c_void_p() length = ctypes.c_ssize_t() + try: if writable: - status = ctypes.pythonapi.PyObject_AsWriteBuffer(ctypes.py_object(obj), ctypes.byref(addr), ctypes.byref(length)) + status = ctypes.pythonapi.PyObject_AsWriteBuffer( + ctypes.py_object(obj), ctypes.byref(addr), ctypes.byref(length)) else: - status = ctypes.pythonapi.PyObject_AsReadBuffer(ctypes.py_object(obj), ctypes.byref(addr), ctypes.byref(length)) + status = ctypes.pythonapi.PyObject_AsReadBuffer( + ctypes.py_object(obj), ctypes.byref(addr), ctypes.byref(length)) except TypeError: - raise LogicError("", status_code.INVALID_VALUE, "PyOpencl does not accept bare Python types as arguments") + raise LogicError("", status_code.INVALID_VALUE, + "PyOpencl does not accept bare Python types as arguments") else: if status: raise Exception('TODO error_already_set') return _ffi.cast('void *', addr.value), length.value, None # }}} - + +# }}} + + +# {{{ Buffer + class Buffer(MemoryObject): _id = 'buffer' + 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.") + 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, _ = _c_buffer_from_obj(hostbuf, writable=flags & mem_flags.USE_HOST_PTR) + c_hostbuf, hostbuf_size, _ = _c_buffer_from_obj( + hostbuf, writable=flags & mem_flags.USE_HOST_PTR) if size > hostbuf_size: - raise RuntimeError("Buffer", status_code.INVALID_VALUE, "specified size is greater than host buffer size") + raise RuntimeError("Buffer", status_code.INVALID_VALUE, + "Specified size is greater than host buffer size") if size == 0: size = hostbuf_size ptr_buffer = _ffi.new('void **') - _handle_error(_lib._create_buffer(ptr_buffer, context.ptr, flags, size, c_hostbuf)) + _handle_error(_lib._create_buffer( + ptr_buffer, context.ptr, flags, size, c_hostbuf)) self.ptr = ptr_buffer[0] +# }}} + + +# {{{ Program + class _Program(_Common): _id = 'program' + def __init__(self, *args): if len(args) == 2: self._init_source(*args) @@ -279,16 +546,20 @@ class _Program(_Common): def _init_source(self, context, src): ptr_program = _ffi.new('void **') - _handle_error(_lib._create_program_with_source(ptr_program, context.ptr, _ffi.new('char[]', src))) + _handle_error(_lib._create_program_with_source( + ptr_program, context.ptr, _ffi.new('char[]', src))) self.ptr = ptr_program[0] def _init_binary(self, context, devices, binaries): if len(devices) != len(binaries): - raise RuntimeError("create_program_with_binary", status_code.INVALID_VALUE, "device and binary counts don't match") + raise RuntimeError("create_program_with_binary", + status_code.INVALID_VALUE, + "device and binary counts don't match") ptr_program = _ffi.new('void **') ptr_devices = _ffi.new('void*[]', [device.ptr for device in devices]) - ptr_binaries = [_ffi.new('char[%i]' % len(binary), binary) for binary in binaries] + ptr_binaries = [_ffi.new('char[%i]' % len(binary), binary) + for binary in binaries] binary_sizes = _ffi.new('size_t[]', map(len, binaries)) _handle_error(_lib._create_program_with_binary( @@ -318,75 +589,21 @@ class _Program(_Common): ptr_devices = _ffi.new('void*[]', [device.ptr for device in devices]) num_devices = len(devices) - _handle_error(_lib.program__build(self.ptr, _ffi.new('char[]', options), num_devices, _ffi.cast('void**', ptr_devices))) - + _handle_error( + _lib.program__build(self.ptr, + _ffi.new('char[]', options), num_devices, + _ffi.cast('void**', ptr_devices))) def get_build_info(self, device, param): info = _ffi.new('generic_info *') - _handle_error(_lib.program__get_build_info(self.ptr, device.ptr, param, info)) + _handle_error(_lib.program__get_build_info( + self.ptr, device.ptr, param, info)) return _generic_info_to_python(info) -class Platform(_Common): - _id = 'platform' - # todo: __del__ - - def get_devices(self, device_type=device_type.ALL): - devices = _CArray(_ffi.new('void**')) - _handle_error(_lib.platform__get_devices(self.ptr, devices.ptr, devices.size, device_type)) - result = [] - for i in xrange(devices.size[0]): - # TODO why is the cast needed? - device_ptr = _ffi.cast('void**', devices.ptr[0])[i] - result.append(_create_instance(Device, device_ptr)) - return result - -def _generic_info_to_python(info): - type_ = _ffi.string(info.type) - value = _ffi.cast(type_, info.value) - if info.opaque_class != _lib.CLASS_NONE: - klass = { - _lib.CLASS_PLATFORM: Platform, - _lib.CLASS_DEVICE: Device, - _lib.CLASS_KERNEL: Kernel, - _lib.CLASS_CONTEXT: Context, - _lib.CLASS_BUFFER: Buffer, - _lib.CLASS_PROGRAM: _Program, - _lib.CLASS_EVENT: Event, - _lib.CLASS_COMMAND_QUEUE: CommandQueue - }[info.opaque_class] +# }}} - def ci(ptr): - ins = _create_instance(klass, ptr) - if info.opaque_class == _lib.CLASS_PROGRAM: # HACK? - from . import Program - return Program(ins) - return ins - if type_.endswith(']'): - ret = map(ci, value) - _lib._free(info.value) - return ret - else: - return ci(value) - if type_ == 'char*': - ret = _ffi.string(value) - elif type_.startswith('char*['): - ret = map(_ffi.string, value) - _lib._free2(info.value, len(value)) - elif type_.endswith(']'): - if type_.startswith('char['): - ret = ''.join(a[0] for a in value) - elif type_.startswith('generic_info['): - ret = list(map(_generic_info_to_python, value)) - elif type_.startswith('cl_image_format['): - ret = [ImageFormat(imf.image_channel_order, imf.image_channel_data_type) for imf in value] - else: - ret = list(value) - else: - ret = value[0] - if info.dontfree == 0: - _lib._free(info.value) - return ret +# {{{ Kernel class Kernel(_Common): _id = 'kernel' @@ -410,23 +627,18 @@ class Kernel(_Common): def get_work_group_info(self, param, device): info = _ffi.new('generic_info *') - _handle_error(_lib.kernel__get_work_group_info(self.ptr, param, device.ptr, info)) + _handle_error(_lib.kernel__get_work_group_info( + self.ptr, param, device.ptr, info)) return _generic_info_to_python(info) +# }}} -def get_platforms(): - platforms = _CArray(_ffi.new('void**')) - _handle_error(_lib.get_platforms(platforms.ptr, platforms.size)) - result = [] - for i in xrange(platforms.size[0]): - # TODO why is the cast needed? - platform_ptr = _ffi.cast('void**', platforms.ptr[0])[i] - result.append(_create_instance(Platform, platform_ptr)) - return result +# {{{ Event class Event(_Common): _id = 'event' + def __init__(self): pass @@ -438,9 +650,19 @@ class Event(_Common): def wait(self): _handle_error(_lib.event__wait(self.ptr)) -def enqueue_nd_range_kernel(queue, kernel, global_work_size, local_work_size, global_work_offset=None, wait_for=None, g_times_l=False): +# }}} + + +# {{{ enqueue_nd_range_kernel + +def enqueue_nd_range_kernel(queue, kernel, + global_work_size, local_work_size, global_work_offset=None, + wait_for=None, g_times_l=False): + if wait_for is not None: + # TODO: implement wait_for raise NotImplementedError("wait_for") + work_dim = len(global_work_size) if local_work_size is not None: @@ -483,12 +705,13 @@ def enqueue_nd_range_kernel(queue, kernel, global_work_size, local_work_size, gl )) return _create_instance(Event, ptr_event[0]) -def _c_obj_list(objs=None): - if objs is None: - return _ffi.NULL, 0 - return _ffi.new('void *[]', [ev.ptr for ev in objs]), len(objs) +# }}} + -def _enqueue_read_buffer(queue, mem, hostbuf, device_offset=0, wait_for=None, is_blocking=True): +# {{{ _enqueue_*_buffer + +def _enqueue_read_buffer(queue, mem, hostbuf, device_offset=0, + wait_for=None, is_blocking=True): c_buf, size, _ = _c_buffer_from_obj(hostbuf, writable=True) ptr_event = _ffi.new('void **') c_wait_for, num_wait_for = _c_obj_list(wait_for) @@ -504,7 +727,9 @@ def _enqueue_read_buffer(queue, mem, hostbuf, device_offset=0, wait_for=None, is )) return _create_instance(Event, ptr_event[0]) -def _enqueue_copy_buffer(queue, src, dst, byte_count=-1, src_offset=0, dst_offset=0, wait_for=None): + +def _enqueue_copy_buffer(queue, src, dst, byte_count=-1, src_offset=0, + dst_offset=0, wait_for=None): ptr_event = _ffi.new('void **') c_wait_for, num_wait_for = _c_obj_list(wait_for) _handle_error(_lib._enqueue_copy_buffer( @@ -519,7 +744,9 @@ 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): + +def _enqueue_write_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) @@ -535,7 +762,13 @@ 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): +# }}} + + +# {{{ _enqueue_*_image + +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, writable=True) ptr_event = _ffi.new('void **') c_wait_for, num_wait_for = _c_obj_list(wait_for) @@ -553,34 +786,37 @@ def _enqueue_read_image(queue, mem, origin, region, hostbuf, row_pitch=0, slice_ )) return _create_instance(Event, ptr_event[0]) +# TODO: write_image? copy_image?... + +# }}} -def _create_instance(cls, ptr): - ins = cls.__new__(cls) - ins.ptr = ptr - return ins # {{{ gl interop def have_gl(): return bool(_lib.have_gl()) + class GLBuffer(MemoryObject): _id = 'gl_buffer' - + def __init__(self, context, flags, bufobj): ptr = _ffi.new('void **') - _handle_error(_lib._create_from_gl_buffer(ptr, context.ptr, flags, bufobj)) + _handle_error(_lib._create_from_gl_buffer( + ptr, context.ptr, flags, bufobj)) self.ptr = ptr[0] + class GLRenderBuffer(MemoryObject): _id = 'gl_renderbuffer' - + def __init__(self, context, flags, bufobj): ptr = _ffi.new('void **') - _handle_error(_lib._create_from_gl_renderbuffer(ptr, context.ptr, flags, bufobj)) + _handle_error(_lib._create_from_gl_renderbuffer( + ptr, context.ptr, flags, bufobj)) self.ptr = ptr[0] - + def _create_gl_enqueue(what): def enqueue_gl_objects(queue, mem_objects, wait_for=None): ptr_event = _ffi.new('void **') @@ -600,12 +836,23 @@ def _create_gl_enqueue(what): enqueue_acquire_gl_objects = _create_gl_enqueue(_lib._enqueue_acquire_gl_objects) enqueue_release_gl_objects = _create_gl_enqueue(_lib._enqueue_release_gl_objects) +# }}} + + +# {{{ ImageFormat + class ImageFormat(object): def __new__(cls, channel_order=0, channel_type=0): args = [channel_order, channel_type] cls = type(cls.__name__, (cls,), {}) - cls.channel_order = property(lambda self: args[0], lambda self, v: args.__setitem__(0, v)) - cls.channel_data_type = property(lambda self: args[1], lambda self, v: args.__setitem__(1, v)) + + cls.channel_order = property( + lambda self: args[0], + lambda self, v: args.__setitem__(0, v)) + cls.channel_data_type = property( + lambda self: args[1], + lambda self, v: args.__setitem__(1, v)) + return object.__new__(cls) @property @@ -645,7 +892,7 @@ class ImageFormat(object): channel_type.UNSIGNED_INT16: 2, channel_type.UNSIGNED_INT32: 4, channel_type.HALF_FLOAT: 2, - channel_type.FLOAT: 4, + channel_type.FLOAT: 4, }[self.channel_data_type] except KeyError: raise LogicError("ImageFormat.channel_dtype_size", @@ -668,17 +915,23 @@ class ImageFormat(object): and self.channel_data_type == other.channel_data_type) def __ne__(self, other): - return not image_format_eq(self, other) + return not self.__eq__(self, other) def __hash__(self): return hash((ImageFormat, self.channel_order, self.channel_data_type)) - + def get_supported_image_formats(context, flags, image_type): info = _ffi.new('generic_info *') - _handle_error(_lib._get_supported_image_formats(context.ptr, flags, image_type, info)) + _handle_error(_lib._get_supported_image_formats( + context.ptr, flags, image_type, info)) return _generic_info_to_python(info) +# }}} + + +# {{{ Image + class Image(MemoryObject): _id = 'image' @@ -689,19 +942,21 @@ class Image(MemoryObject): 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") + raise LogicError("Image", status_code.INVALID_VALUE, + "'shape' must be given") if buffer is None: c_buf, size = _ffi.NULL, 0 else: - c_buf, size, _ = _c_buffer_from_obj(buffer, writable=flags & mem_flags.USE_HOST_PTR) - + c_buf, size, _ = _c_buffer_from_obj( + buffer, writable=flags & mem_flags.USE_HOST_PTR) + dims = len(shape) if dims == 2: width, height = shape @@ -710,18 +965,22 @@ class Image(MemoryObject): try: pitch, = pitches except ValueError: - raise LogicError("Image", status_code.INVALID_VALUE, "invalid length of pitch tuple") - + 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") + 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, )), + _ffi.new('struct _cl_image_format *', + (format.channel_order, format.channel_data_type, )), width, height, pitch, c_buf, size)) @@ -733,25 +992,37 @@ class Image(MemoryObject): try: pitch_x, pitch_y = pitches except ValueError: - raise LogicError("Image", status_code.INVALID_VALUE, "invalid length of pitch tuple") - + 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") + 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, )), + _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"); - + 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)) @@ -764,7 +1035,13 @@ class Image(MemoryObject): 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") + raise LogicError("Image", status_code.INVALID_VALUE, + "only images have shapes") + +# }}} + + +# {{{ Sampler class Sampler(_Common): _id = 'sampler' @@ -779,10 +1056,22 @@ class Sampler(_Common): filter_mode)) self.ptr = ptr[0] -# class GLTexture(Image): -# _id = 'gl_texture' - -# def __init__(self, context, flags, texture_target, miplevel, texture, dims): -# ptr = _ffi.new('void **') -# _handle_error(_lib._create_from_gl_texture(ptr, context.ptr, flags, texture_target, miplevel, texture, dims)) -# self.ptr = ptr[0] +# }}} + + +# {{{ GLTexture (TODO) + +class GLTexture(Image): + _id = 'gl_texture' + + def __init__(self, context, flags, texture_target, miplevel, texture, dims): + raise NotImplementedError("GLTexture") + + ptr = _ffi.new('void **') + _handle_error(_lib._create_from_gl_texture( + ptr, context.ptr, flags, texture_target, miplevel, texture, dims)) + self.ptr = ptr[0] + +# }}} + +# vim: foldmethod=marker -- GitLab