diff --git a/pyopencl/cffi_cl.py b/pyopencl/cffi_cl.py index a39a467eab4f24eeb057bac3dbbce92851535d56..16edab641c5a9f86d00ed0f1b005c8042bb6fd47 100644 --- a/pyopencl/cffi_cl.py +++ b/pyopencl/cffi_cl.py @@ -1,6 +1,8 @@ -#from pyopencl._cl import PooledBuffer, MemoryPool +from pyopencl._cl import PooledBuffer, MemoryPool from _cffi import _ffi, _lib import warnings +import np +import ctypes bitlog2 = _lib.bitlog2 @@ -53,7 +55,7 @@ for type_, d in _constants.iteritems(): # {{{ exceptions class Error(Exception): - def __init__(self, routine, code, msg=""): + def __init__(self, msg='', routine='', code=0): self.routine = routine self.code = code self.what = msg @@ -84,7 +86,7 @@ def _handle_error(error): klass = RuntimeError else: klass = Error - e = klass(_ffi.string(error.routine), error.code, _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) @@ -203,11 +205,30 @@ class MemoryObject(MemoryObjectHolder): pass -def _c_buffer_from_obj(obj): +def _c_buffer_from_obj(obj, writable=False): if obj is None: return _ffi.NULL, 0 - # assume numpy array for now - return _ffi.cast('void *', obj.__array_interface__['data'][0]), obj.nbytes + + # numpy array + if hasattr(obj, '__array_interface__'): # if writeable == False, some tests fail... + return _ffi.cast('void *', obj.__array_interface__['data'][0]), obj.nbytes + + # ... ? + + # fall back to 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)) + else: + 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") + else: + if status: + raise Exception('TODO error_already_set') + return _ffi.cast('void *', addr.value), length.value class Buffer(MemoryObject): _id = 'buffer' @@ -216,7 +237,7 @@ class Buffer(MemoryObject): 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) + 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") if size == 0: @@ -446,7 +467,7 @@ def _c_obj_list(objs=None): 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): - c_buf, size = _c_buffer_from_obj(hostbuf) + 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) _handle_error(_lib._enqueue_read_buffer( @@ -493,7 +514,7 @@ 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) + 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) _handle_error(_lib._enqueue_read_image( @@ -654,7 +675,7 @@ class Image(MemoryObject): if shape is None: raise LogicError("Image", status_code.INVALID_VALUE, "'shape' must be given") - c_buf, size = _c_buffer_from_obj(buffer) + c_buf, size = _c_buffer_from_obj(buffer, writable=flags & mem_flags.USE_HOST_PTR) dims = len(shape) if dims == 2: