Skip to content
Snippets Groups Projects
Commit 1d0cf8f9 authored by Andreas Klöckner's avatar Andreas Klöckner
Browse files

Make cffi_cl flake8-clean

parent d558affc
No related branches found
No related tags found
No related merge requests found
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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment