diff --git a/pyopencl/c_wrapper/wrap_cl_core.h b/pyopencl/c_wrapper/wrap_cl_core.h index 1a211fe5b376d8210a680738b3e2ba74ea300077..52bb18759b64fe84e30225f710758c9dbdbb2563 100644 --- a/pyopencl/c_wrapper/wrap_cl_core.h +++ b/pyopencl/c_wrapper/wrap_cl_core.h @@ -74,7 +74,6 @@ error *memory_map__release(clobj_t _map, clobj_t _queue, const clobj_t *_wait_for, uint32_t num_wait_for, clobj_t *evt); void *memory_map__data(clobj_t _map); -size_t memory_map__size(clobj_t _map); // Program error *create_program_with_source(clobj_t *program, clobj_t context, const char *src); @@ -174,6 +173,13 @@ error *enqueue_write_image(clobj_t *_evt, clobj_t _queue, clobj_t _mem, size_t slice_pitch, const clobj_t *_wait_for, uint32_t num_wait_for, int is_blocking, void *pyobj); +error *enqueue_map_image(clobj_t *_evt, clobj_t *map, clobj_t _queue, + clobj_t _mem, cl_map_flags flags, + const size_t *_origin, size_t origin_l, + const size_t *_region, size_t region_l, + size_t *row_pitch, size_t *slice_pitch, + const clobj_t *_wait_for, uint32_t num_wait_for, + int block); // CL Object intptr_t clobj__int_ptr(clobj_t obj); error *clobj__get_info(clobj_t obj, cl_uint param, generic_info *out); diff --git a/pyopencl/cffi_cl.py b/pyopencl/cffi_cl.py index 250de9aeca64a55e3946a7a721ab5bf807936a53..486ab73513df4bacd216610d990039b4af830dc7 100644 --- a/pyopencl/cffi_cl.py +++ b/pyopencl/cffi_cl.py @@ -468,6 +468,14 @@ class MemoryMap(_Common): self.ptr, queue.ptr if queue is not None else _ffi.NULL, c_wait_for, num_wait_for, _event)) return _create_instance(Event, _event[0]) + def _init_array(self, shape, typestr, strides): + self.__array_interface__ = { + 'shape': shape, + 'typestr': typestr, + 'strides': strides, + 'data': (int(_lib.clobj__int_ptr(self.ptr)), False), + 'version': 3 + } def _c_buffer_from_obj(obj, writable=False): """Convert a Python object to a tuple (cdata('void *'), num_bytes, dummy) @@ -880,13 +888,7 @@ def enqueue_map_buffer(queue, buf, flags, offset, shape, dtype, num_wait_for, bool(is_blocking))) event = _create_instance(Event, _event[0]) map = _create_instance(MemoryMap, _map[0]) - map.__array_interface__ = { - 'shape': shape, - 'typestr': dtype.str, - 'strides': strides, - 'data': (int(_lib.clobj__int_ptr(_map[0])), False), - 'version': 3 - } + map._init_array(shape, dtype.str, strides) return np.asarray(map), event def _enqueue_fill_buffer(queue, mem, pattern, offset, size, wait_for=None): @@ -937,14 +939,32 @@ def _enqueue_write_image(queue, mem, origin, region, hostbuf, row_pitch=0, bool(is_blocking), _ffi.new_handle(c_buf))) return _create_instance(NannyEvent, _event[0]) +def enqueue_map_image(queue, img, flags, origin, region, shape, dtype, + order="C", strides=None, wait_for=None, is_blocking=True): + origin_l = len(origin) + region_l = len(region) + if origin_l > 3 or region_l > 3: + raise RuntimeError("origin or region has too many components", + "enqueue_read_image") + _event = _ffi.new('clobj_t*') + _map = _ffi.new('clobj_t*') + _row_pitch = _ffi.new('size_t*') + _slice_pitch = _ffi.new('size_t*') + c_wait_for, num_wait_for = _clobj_list(wait_for) + _handle_error(_lib.enqueue_map_image(_event, _map, queue.ptr, img.ptr, + flags, origin, origin_l, region, + region_l, _row_pitch, _slice_pitch, + c_wait_for, num_wait_for, is_blocking)) + event = _create_instance(Event, _event[0]) + map = _create_instance(MemoryMap, _map[0]) + map._init_array(shape, dtype.str, strides) + return np.asarray(map), event, _row_pitch[0], _slice_pitch[0] + # TODO: copy_image fill_image # copy_buffer_to_image copy_image_to_buffer # }}} -# TODO -# enqueue_map_image - # {{{ gl interop def have_gl(): diff --git a/src/c_wrapper/utils.h b/src/c_wrapper/utils.h index 57bdad7909080a254f95ac94cd7ad78d6becbb77..052453789a01df7f1a9e4ed30359633537138030 100644 --- a/src/c_wrapper/utils.h +++ b/src/c_wrapper/utils.h @@ -69,6 +69,26 @@ public: namespace pyopencl { +template<typename T, size_t n> +class ConstBuffer { +private: + T m_intern_buf[n]; + const T *m_buf; +public: + ConstBuffer(const T *buf, size_t l) + : m_buf(buf) + { + if (l < n) { + memcpy(m_intern_buf, buf, sizeof(T) * std::min(l, n)); + m_buf = m_intern_buf; + } + } + operator const T*() + { + return m_buf; + } +}; + template<typename T> static inline cl_bool cast_bool(const T &v) diff --git a/src/c_wrapper/wrap_cl.cpp b/src/c_wrapper/wrap_cl.cpp index bd6e969fc155922af5f4b206c7ceb05fe3e0a145..23b82e78ad99d24df7a4090e3e87b00bcb12b9da 100644 --- a/src/c_wrapper/wrap_cl.cpp +++ b/src/c_wrapper/wrap_cl.cpp @@ -1514,11 +1514,9 @@ private: command_queue m_queue; memory_object m_mem; void *m_ptr; - size_t m_size; public: - memory_map(const command_queue *queue, const memory_object *mem, - void *ptr, size_t size) - : m_valid(true), m_queue(*queue), m_mem(*mem), m_ptr(ptr), m_size(size) + memory_map(const command_queue *queue, const memory_object *mem, void *ptr) + : m_valid(true), m_queue(*queue), m_mem(*mem), m_ptr(ptr) {} ~memory_map() { @@ -1558,11 +1556,6 @@ public: { return m_valid ? m_ptr : NULL; } - size_t - size() const - { - return m_valid ? m_size : 0; - } }; // }}} @@ -2073,12 +2066,6 @@ memory_map__data(clobj_t _map) return static_cast<memory_map*>(_map)->data(); } -size_t -memory_map__size(clobj_t _map) -{ - return static_cast<memory_map*>(_map)->size(); -} - // Program error* create_program_with_source(clobj_t *prog, clobj_t _ctx, const char *src) @@ -2412,6 +2399,24 @@ enqueue_barrier(clobj_t _queue) }); } +static memory_map* +_convert_memory_map(clobj_t *_evt, cl_event evt, command_queue *queue, + memory_object *buf, void *res) +{ + try { + *_evt = new event(evt, false); + evt = 0; + return new memory_map(queue, buf, res); + } catch (...) { + if (evt) { + pyopencl_call_guarded_cleanup(clReleaseEvent, evt); + } + pyopencl_call_guarded_cleanup(clEnqueueUnmapMemObject, queue->data(), + buf->data(), res, 0, NULL, NULL); + throw; + } +} + // {{{ enqueue_*_buffer* error* @@ -2505,19 +2510,7 @@ enqueue_map_buffer(clobj_t *_evt, clobj_t *map, clobj_t _queue, clobj_t _mem, cast_bool(block), flags, offset, size, num_wait_for, wait_for.get(), &evt); }); - try { - *_evt = new event(evt, false); - evt = 0; - *map = new memory_map(queue, buf, res, size); - } catch (...) { - if (evt) { - pyopencl_call_guarded_cleanup(clReleaseEvent, evt); - } - pyopencl_call_guarded_cleanup(clEnqueueUnmapMemObject, - queue->data(), buf->data(), - res, 0, NULL, NULL); - throw; - } + *map = _convert_memory_map(_evt, evt, queue, buf, res); }); } @@ -2547,8 +2540,8 @@ enqueue_fill_buffer(clobj_t *_evt, clobj_t _queue, clobj_t _mem, void *pattern, error* enqueue_read_image(clobj_t *_evt, clobj_t _queue, clobj_t _mem, - const size_t *origin, size_t origin_l, - const size_t *region, size_t region_l, void *buffer, + const size_t *_origin, size_t origin_l, + const size_t *_region, size_t region_l, void *buffer, size_t row_pitch, size_t slice_pitch, const clobj_t *_wait_for, uint32_t num_wait_for, int is_blocking, void *pyobj) @@ -2556,16 +2549,8 @@ enqueue_read_image(clobj_t *_evt, clobj_t _queue, clobj_t _mem, auto wait_for = buf_from_class<event>(_wait_for, num_wait_for); auto queue = static_cast<command_queue*>(_queue); auto img = static_cast<image*>(_mem); - size_t _origin[3] = {0}; - if (origin_l < 3) { - memcpy(_origin, origin, sizeof(size_t) * origin_l); - origin = _origin; - } - size_t _region[3] = {0}; - if (region_l < 3) { - memcpy(_region, region, sizeof(size_t) * region_l); - region = _region; - } + ConstBuffer<size_t, 3> origin(_origin, origin_l); + ConstBuffer<size_t, 3> region(_region, region_l); return c_handle_error([&] { cl_event evt; retry_mem_error<void>([&] { @@ -2581,8 +2566,8 @@ enqueue_read_image(clobj_t *_evt, clobj_t _queue, clobj_t _mem, error* enqueue_write_image(clobj_t *_evt, clobj_t _queue, clobj_t _mem, - const size_t *origin, size_t origin_l, - const size_t *region, size_t region_l, + const size_t *_origin, size_t origin_l, + const size_t *_region, size_t region_l, const void *buffer, size_t row_pitch, size_t slice_pitch, const clobj_t *_wait_for, uint32_t num_wait_for, int is_blocking, void *pyobj) @@ -2590,16 +2575,8 @@ enqueue_write_image(clobj_t *_evt, clobj_t _queue, clobj_t _mem, auto wait_for = buf_from_class<event>(_wait_for, num_wait_for); auto queue = static_cast<command_queue*>(_queue); auto img = static_cast<image*>(_mem); - size_t _origin[3] = {0}; - if (origin_l < 3) { - memcpy(_origin, origin, sizeof(size_t) * origin_l); - origin = _origin; - } - size_t _region[3] = {0}; - if (region_l < 3) { - memcpy(_region, region, sizeof(size_t) * region_l); - region = _region; - } + ConstBuffer<size_t, 3> origin(_origin, origin_l); + ConstBuffer<size_t, 3> region(_region, region_l); return c_handle_error([&] { cl_event evt; retry_mem_error<void>([&] { @@ -2613,6 +2590,30 @@ enqueue_write_image(clobj_t *_evt, clobj_t _queue, clobj_t _mem, }); } +error* +enqueue_map_image(clobj_t *_evt, clobj_t *map, clobj_t _queue, clobj_t _mem, + cl_map_flags flags, const size_t *_origin, size_t origin_l, + const size_t *_region, size_t region_l, size_t *row_pitch, + size_t *slice_pitch, const clobj_t *_wait_for, + uint32_t num_wait_for, int block) +{ + auto wait_for = buf_from_class<event>(_wait_for, num_wait_for); + auto queue = static_cast<command_queue*>(_queue); + auto img = static_cast<image*>(_mem); + ConstBuffer<size_t, 3> origin(_origin, origin_l); + ConstBuffer<size_t, 3> region(_region, region_l); + return c_handle_error([&] { + cl_event evt; + void *res = retry_mem_error<void*>([&] { + return pyopencl_call_guarded( + clEnqueueMapImage, queue->data(), img->data(), + cast_bool(block), flags, origin, region, row_pitch, + slice_pitch, num_wait_for, wait_for.get(), &evt); + }); + *map = _convert_memory_map(_evt, evt, queue, img, res); + }); +} + // }}} intptr_t