diff --git a/pyopencl/c_wrapper/wrap_cl_core.h b/pyopencl/c_wrapper/wrap_cl_core.h index 879abcbbd11a85e79d87d171aa453907775fe22f..804848c51e805ce8e36ce162341d39b845bac195 100644 --- a/pyopencl/c_wrapper/wrap_cl_core.h +++ b/pyopencl/c_wrapper/wrap_cl_core.h @@ -91,6 +91,7 @@ error *buffer__get_sub_region(clobj_t *_sub_buf, clobj_t _buf, size_t orig, error *buffer__getitem(clobj_t *_ret, clobj_t _buf, ssize_t start, ssize_t end); // Memory Object error *memory_object__release(clobj_t obj); +error *memory_object__get_host_array(clobj_t, void **hostptr, size_t *size); // Memory Map error *memory_map__release(clobj_t _map, clobj_t _queue, const clobj_t *_wait_for, uint32_t num_wait_for, diff --git a/pyopencl/cffi_cl.py b/pyopencl/cffi_cl.py index 5980453c8809b4c595ec8cf806fa22d3b8056614..0fc9a6d106191f9fd9102aed3af1fdbaa38f3572 100644 --- a/pyopencl/cffi_cl.py +++ b/pyopencl/cffi_cl.py @@ -620,8 +620,53 @@ class CommandQueue(_Common): _handle_error(_lib.command_queue__flush(self.ptr)) # TODO set_property + +def _norm_shape_dtype(shape, dtype, order="C", strides=None, name=""): + dtype = np.dtype(dtype) + if not isinstance(shape, tuple): + try: + shape = tuple(shape) + except: + shape = (shape,) + if strides is None: + if order == "cC": + strides = c_contigous_strides(byte_size, shape) + elif order == "cF": + strides = f_contigous_strides(byte_size, shape) + else: + raise RuntimeError("unrecognized order specifier %s" % order, + status_code.INVALID_VALUE, name) + return dtype, shape, strides + + +class cffi_array(np.ndarray): + __array_priority__ = -100.0 + def __new__(cls, ptr, shape, dtype, strides, base=None): + self = np.ndarray.__new__(cls, shape, dtype=dtype, + buffer=ffi.buffer(ptr), + strides=strides) + if base is None: + base = ptr + self.__base = base + return self + @property + def base(self): + return self.__base + + class MemoryObjectHolder(_Common): - pass + def get_host_array(self, shape, dtype, order="C"): + dtype, shape, strides = _norm_shape_dtype( + shape, dtype, order, None, 'MemoryObjectHolder.get_host_array') + _hostptr = _ffi.new('void**') + _size = _ffi.new('size_t*') + _handle_error(memory_object__get_host_array(self.ptr, _hostptr, _size)) + ary = cffi_array(_hostptr[0], shape, dtype, strides, self) + if ary.nbytes > _size[0]: + raise LogicError("Resulting array is larger than memory object.", + status_code.INVALID_VALUE, + "MemoryObjectHolder.get_host_array") + return ary class MemoryObject(MemoryObjectHolder): @@ -1176,21 +1221,9 @@ def _enqueue_copy_buffer_rect(queue, src, dst, src_origin, dst_origin, region, def enqueue_map_buffer(queue, buf, flags, offset, shape, dtype, order="C", strides=None, wait_for=None, is_blocking=True): - dtype = np.dtype(dtype) - if not isinstance(shape, tuple): - try: - shape = tuple(shape) - except: - shape = (shape,) + dtype, shape, strides = _norm_shape_dtype(shape, dtype, order, strides, + 'enqueue_map_buffer') byte_size = dtype.itemsize - if strides is None: - if order == "cC": - strides = c_contigous_strides(byte_size, shape) - elif order == "cF": - strides = f_contigous_strides(byte_size, shape) - else: - raise RuntimeError("unrecognized order specifier %s" % order, - status_code.INVALID_VALUE, 'enqueue_map_buffer') for s in shape: byte_size *= s c_wait_for, num_wait_for = _clobj_list(wait_for) @@ -1281,6 +1314,8 @@ def enqueue_map_image(queue, img, flags, origin, region, shape, dtype, if origin_l > 3 or region_l > 3: raise RuntimeError("origin or region has too many components", status_code.INVALID_VALUE, "enqueue_map_image") + dtype, shape, strides = _norm_shape_dtype(shape, dtype, order, strides, + 'enqueue_map_image') _event = _ffi.new('clobj_t*') _map = _ffi.new('clobj_t*') _row_pitch = _ffi.new('size_t*') diff --git a/src/c_wrapper/memory_object.cpp b/src/c_wrapper/memory_object.cpp index b347e7436c6b2af63f09b96cd67743cdd6447f30..103de78a4dd91f643802a77b08e54ac9cad3c24e 100644 --- a/src/c_wrapper/memory_object.cpp +++ b/src/c_wrapper/memory_object.cpp @@ -76,3 +76,15 @@ memory_object__release(clobj_t obj) static_cast<memory_object*>(obj)->release(); }); } + +error* +memory_object__get_host_array(clobj_t _obj, void **hostptr, size_t *size) +{ + auto obj = static_cast<memory_object*>(_obj); + return c_handle_error([&] { + pyopencl_call_guarded(clGetMemObjectInfo, obj, CL_MEM_HOST_PTR, + size_arg(*hostptr), nullptr); + pyopencl_call_guarded(clGetMemObjectInfo, obj, CL_MEM_SIZE, + size_arg(*size), nullptr); + }); +}