diff --git a/src/wrapper/wrap_cl.hpp b/src/wrapper/wrap_cl.hpp index f17ee69c92a7ab746ae031b60d95a6771293cf17..415dc6d348c636918a26f1f357598d4a2bbb5dca 100644 --- a/src/wrapper/wrap_cl.hpp +++ b/src/wrapper/wrap_cl.hpp @@ -7,6 +7,7 @@ // {{{ includes #define CL_USE_DEPRECATED_OPENCL_1_1_APIS +// #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #ifdef __APPLE__ @@ -69,6 +70,10 @@ #endif + +#if PY_VERSION_HEX >= 0x03000000 +#define PYOPENCL_USE_NEW_BUFFER_INTERFACE +#endif // }}} @@ -403,6 +408,40 @@ namespace pyopencl // }}} + + // {{{ buffer interface helper + // +#ifdef PYOPENCL_USE_NEW_BUFFER_INTERFACE + class py_buffer_wrapper : public boost::noncopyable + { + private: + bool m_initialized; + + public: + Py_buffer m_buf; + + py_buffer_wrapper() + : m_initialized(false) + {} + + void get(PyObject *obj, int flags) + { + if (PyObject_GetBuffer(obj, &m_buf, flags)) + throw py::error_already_set(); + + m_initialized = true; + } + + virtual ~py_buffer_wrapper() + { + if (m_initialized) + PyBuffer_Release(&m_buf); + } + }; +#endif + + // }}} + inline py::tuple get_cl_header_version() { @@ -412,6 +451,7 @@ namespace pyopencl ); } + // {{{ platform class platform : boost::noncopyable { @@ -1311,6 +1351,42 @@ namespace pyopencl } }; +#ifdef PYOPENCL_USE_NEW_BUFFER_INTERFACE + class nanny_event : public event + { + // In addition to everything an event does, the nanny event holds a reference + // to a Python object and waits for its own completion upon destruction. + + protected: + std::auto_ptr<py_buffer_wrapper> m_ward; + + public: + + nanny_event(cl_event evt, bool retain, std::auto_ptr<py_buffer_wrapper> &ward) + : event(evt, retain), m_ward(ward) + { } + + ~nanny_event() + { wait(); } + + py::object get_ward() const + { + if (m_ward.get()) + { + return py::object(py::handle<>(py::borrowed( + m_ward->m_buf.obj))); + } + else + return py::object(); + } + + virtual void wait() + { + event::wait(); + m_ward.reset(); + } + }; +#else class nanny_event : public event { // In addition to everything an event does, the nanny event holds a reference @@ -1341,6 +1417,7 @@ namespace pyopencl m_ward = py::object(); } }; +#endif @@ -1496,23 +1573,29 @@ namespace pyopencl class memory_object : boost::noncopyable, public memory_object_holder { + public: +#ifdef PYOPENCL_USE_NEW_BUFFER_INTERFACE + typedef std::auto_ptr<py_buffer_wrapper> hostbuf_t; +#else + typedef py::object hostbuf_t; +#endif + private: bool m_valid; cl_mem m_mem; - py::object m_hostbuf; + hostbuf_t m_hostbuf; public: - memory_object(cl_mem mem, bool retain, py::object *hostbuf=0) + memory_object(cl_mem mem, bool retain, hostbuf_t hostbuf=hostbuf_t()) : m_valid(true), m_mem(mem) { if (retain) PYOPENCL_CALL_GUARDED(clRetainMemObject, (mem)); - if (hostbuf) - m_hostbuf = *hostbuf; + m_hostbuf = hostbuf; } - memory_object(memory_object const &src) + memory_object(memory_object &src) : m_valid(true), m_mem(src.m_mem), m_hostbuf(src.m_hostbuf) { PYOPENCL_CALL_GUARDED(clRetainMemObject, (m_mem)); @@ -1540,7 +1623,19 @@ namespace pyopencl } py::object hostbuf() - { return m_hostbuf; } + { +#ifdef PYOPENCL_USE_NEW_BUFFER_INTERFACE + if (m_hostbuf.get()) + { + return py::object(py::handle<>(py::borrowed( + m_hostbuf->m_buf.obj))); + } + else + return py::object(); +#else + return m_hostbuf; +#endif + } const cl_mem data() const { return m_mem; } @@ -1685,7 +1780,7 @@ namespace pyopencl class buffer : public memory_object { public: - buffer(cl_mem mem, bool retain, py::object *hostbuf=0) + buffer(cl_mem mem, bool retain, hostbuf_t hostbuf=hostbuf_t()) : memory_object(mem, retain, hostbuf) { } @@ -1760,7 +1855,31 @@ namespace pyopencl "but no memory flags to make use of it."); void *buf = 0; - py::object *retained_buf_obj = 0; + +#ifdef PYOPENCL_USE_NEW_BUFFER_INTERFACE + std::auto_ptr<py_buffer_wrapper> retained_buf_obj; + if (py_hostbuf.ptr() != Py_None) + { + retained_buf_obj = std::auto_ptr<py_buffer_wrapper>(new py_buffer_wrapper); + + int py_buf_flags = PyBUF_ANY_CONTIGUOUS; + if ((flags & CL_MEM_USE_HOST_PTR) + && ((flags & CL_MEM_READ_WRITE) + || (flags & CL_MEM_WRITE_ONLY))) + py_buf_flags |= PyBUF_WRITABLE; + + retained_buf_obj->get(py_hostbuf.ptr(), py_buf_flags); + + buf = retained_buf_obj->m_buf.buf; + + if (size > size_t(retained_buf_obj->m_buf.len)) + throw pyopencl::error("Buffer", CL_INVALID_VALUE, + "specified size is greater than host buffer size"); + if (size == 0) + size = retained_buf_obj->m_buf.len; + } +#else + py::object retained_buf_obj; if (py_hostbuf.ptr() != Py_None) { PYOPENCL_BUFFER_SIZE_T len; @@ -1779,7 +1898,7 @@ namespace pyopencl } if (flags & CL_MEM_USE_HOST_PTR) - retained_buf_obj = &py_hostbuf; + retained_buf_obj = py_hostbuf; if (size > size_t(len)) throw pyopencl::error("Buffer", CL_INVALID_VALUE, @@ -1787,9 +1906,15 @@ namespace pyopencl if (size == 0) size = len; } +#endif cl_mem mem = create_buffer_gc(ctx.data(), flags, size, buf); +#ifdef PYOPENCL_USE_NEW_BUFFER_INTERFACE + if (!(flags & CL_MEM_USE_HOST_PTR)) + retained_buf_obj.reset(); +#endif + try { return new buffer(mem, false, retained_buf_obj); @@ -1821,8 +1946,18 @@ namespace pyopencl void *buf; PYOPENCL_BUFFER_SIZE_T len; +#ifdef PYOPENCL_USE_NEW_BUFFER_INTERFACE + std::auto_ptr<py_buffer_wrapper> ward(new py_buffer_wrapper); + + ward->get(buffer.ptr(), PyBUF_ANY_CONTIGUOUS | PyBUF_WRITABLE); + + buf = ward->m_buf.buf; + len = ward->m_buf.len; +#else + py::object ward = buffer; if (PyObject_AsWriteBuffer(buffer.ptr(), &buf, &len)) throw py::error_already_set(); +#endif cl_event evt; PYOPENCL_RETRY_IF_MEM_ERROR( @@ -1834,7 +1969,7 @@ namespace pyopencl PYOPENCL_WAITLIST_ARGS, &evt )) ); - PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, buffer); + PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, ward); } @@ -1854,8 +1989,18 @@ namespace pyopencl const void *buf; PYOPENCL_BUFFER_SIZE_T len; +#ifdef PYOPENCL_USE_NEW_BUFFER_INTERFACE + std::auto_ptr<py_buffer_wrapper> ward(new py_buffer_wrapper); + + ward->get(buffer.ptr(), PyBUF_ANY_CONTIGUOUS); + + buf = ward->m_buf.buf; + len = ward->m_buf.len; +#else + py::object ward = buffer; if (PyObject_AsReadBuffer(buffer.ptr(), &buf, &len)) throw py::error_already_set(); +#endif cl_event evt; PYOPENCL_RETRY_IF_MEM_ERROR( @@ -1867,7 +2012,7 @@ namespace pyopencl PYOPENCL_WAITLIST_ARGS, &evt )) ); - PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, buffer); + PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, ward); } @@ -1937,10 +2082,20 @@ namespace pyopencl COPY_PY_PITCH_TUPLE(host_pitches); void *buf; - PYOPENCL_BUFFER_SIZE_T len; +#ifdef PYOPENCL_USE_NEW_BUFFER_INTERFACE + std::auto_ptr<py_buffer_wrapper> ward(new py_buffer_wrapper); + + ward->get(buffer.ptr(), PyBUF_ANY_CONTIGUOUS | PyBUF_WRITABLE); + + buf = ward->m_buf.buf; +#else + py::object ward = buffer; + + PYOPENCL_BUFFER_SIZE_T len; if (PyObject_AsWriteBuffer(buffer.ptr(), &buf, &len)) throw py::error_already_set(); +#endif cl_event evt; PYOPENCL_RETRY_IF_MEM_ERROR( @@ -1955,7 +2110,7 @@ namespace pyopencl PYOPENCL_WAITLIST_ARGS, &evt )) ); - PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, buffer); + PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, ward); } @@ -1983,10 +2138,19 @@ namespace pyopencl COPY_PY_PITCH_TUPLE(host_pitches); const void *buf; - PYOPENCL_BUFFER_SIZE_T len; +#ifdef PYOPENCL_USE_NEW_BUFFER_INTERFACE + std::auto_ptr<py_buffer_wrapper> ward(new py_buffer_wrapper); + + ward->get(buffer.ptr(), PyBUF_ANY_CONTIGUOUS); + + buf = ward->m_buf.buf; +#else + py::object ward = buffer; + PYOPENCL_BUFFER_SIZE_T len; if (PyObject_AsReadBuffer(buffer.ptr(), &buf, &len)) throw py::error_already_set(); +#endif cl_event evt; PYOPENCL_RETRY_IF_MEM_ERROR( @@ -2001,7 +2165,7 @@ namespace pyopencl PYOPENCL_WAITLIST_ARGS, &evt )) ); - PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, buffer); + PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, ward); } @@ -2064,8 +2228,18 @@ namespace pyopencl const void *pattern_buf; PYOPENCL_BUFFER_SIZE_T pattern_len; +#ifdef PYOPENCL_USE_NEW_BUFFER_INTERFACE + std::auto_ptr<py_buffer_wrapper> ward(new py_buffer_wrapper); + + ward->get(pattern.ptr(), PyBUF_ANY_CONTIGUOUS); + + pattern_buf = ward->m_buf.buf; + pattern_len = ward->m_buf.len; +#else + py::object ward = pattern; if (PyObject_AsReadBuffer(pattern.ptr(), &pattern_buf, &pattern_len)) throw py::error_already_set(); +#endif cl_event evt; PYOPENCL_RETRY_IF_MEM_ERROR( @@ -2076,7 +2250,7 @@ namespace pyopencl PYOPENCL_WAITLIST_ARGS, &evt )) ); - PYOPENCL_RETURN_NEW_EVENT(evt); + PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, ward); } #endif @@ -2087,7 +2261,7 @@ namespace pyopencl class image : public memory_object { public: - image(cl_mem mem, bool retain, py::object *hostbuf=0) + image(cl_mem mem, bool retain, hostbuf_t hostbuf=hostbuf_t()) : memory_object(mem, retain, hostbuf) { } @@ -2242,8 +2416,24 @@ namespace pyopencl void *buf = 0; PYOPENCL_BUFFER_SIZE_T len; - py::object *retained_buf_obj = 0; +#ifdef PYOPENCL_USE_NEW_BUFFER_INTERFACE + std::auto_ptr<py_buffer_wrapper> retained_buf_obj; + if (buffer.ptr() != Py_None) + { + int py_buf_flags = PyBUF_ANY_CONTIGUOUS; + if ((flags & CL_MEM_USE_HOST_PTR) + && ((flags & CL_MEM_READ_WRITE) + || (flags & CL_MEM_WRITE_ONLY))) + py_buf_flags |= PyBUF_WRITABLE; + + retained_buf_obj->get(buffer.ptr(), py_buf_flags); + + buf = retained_buf_obj->m_buf.buf; + len = retained_buf_obj->m_buf.len; + } +#else + py::object retained_buf_obj; if (buffer.ptr() != Py_None) { if ((flags & CL_MEM_USE_HOST_PTR) @@ -2261,8 +2451,9 @@ namespace pyopencl } if (flags & CL_MEM_USE_HOST_PTR) - retained_buf_obj = &buffer; + retained_buf_obj = buffer; } +#endif unsigned dims = py::len(shape); cl_int status_code; @@ -2337,6 +2528,11 @@ namespace pyopencl throw pyopencl::error("Image", CL_INVALID_VALUE, "invalid dimension"); +#ifdef PYOPENCL_USE_NEW_BUFFER_INTERFACE + if (!(flags & CL_MEM_USE_HOST_PTR)) + retained_buf_obj.reset(); +#endif + try { return new image(mem, false, retained_buf_obj); @@ -2364,9 +2560,24 @@ namespace pyopencl "but no memory flags to make use of it."); void *buf = 0; - PYOPENCL_BUFFER_SIZE_T len; - py::object *retained_buf_obj = 0; +#ifdef PYOPENCL_USE_NEW_BUFFER_INTERFACE + std::auto_ptr<py_buffer_wrapper> retained_buf_obj; + if (buffer.ptr() != Py_None) + { + int py_buf_flags = PyBUF_ANY_CONTIGUOUS; + if ((flags & CL_MEM_USE_HOST_PTR) + && ((flags & CL_MEM_READ_WRITE) + || (flags & CL_MEM_WRITE_ONLY))) + py_buf_flags |= PyBUF_WRITABLE; + + retained_buf_obj->get(buffer.ptr(), py_buf_flags); + + buf = retained_buf_obj->m_buf.buf; + } +#else + py::object retained_buf_obj; + PYOPENCL_BUFFER_SIZE_T len; if (buffer.ptr() != Py_None) { if ((flags & CL_MEM_USE_HOST_PTR) @@ -2384,8 +2595,9 @@ namespace pyopencl } if (flags & CL_MEM_USE_HOST_PTR) - retained_buf_obj = &buffer; + retained_buf_obj = buffer; } +#endif PYOPENCL_PRINT_CALL_TRACE("clCreateImage"); cl_int status_code; @@ -2393,6 +2605,11 @@ namespace pyopencl if (status_code != CL_SUCCESS) throw pyopencl::error("clCreateImage", status_code); +#ifdef PYOPENCL_USE_NEW_BUFFER_INTERFACE + if (!(flags & CL_MEM_USE_HOST_PTR)) + retained_buf_obj.reset(); +#endif + try { return new image(mem, false, retained_buf_obj); @@ -2425,10 +2642,19 @@ namespace pyopencl COPY_PY_REGION_TRIPLE(region); void *buf; - PYOPENCL_BUFFER_SIZE_T len; +#ifdef PYOPENCL_USE_NEW_BUFFER_INTERFACE + std::auto_ptr<py_buffer_wrapper> ward(new py_buffer_wrapper); + + ward->get(buffer.ptr(), PyBUF_ANY_CONTIGUOUS | PyBUF_WRITABLE); + + buf = ward->m_buf.buf; +#else + py::object ward = buffer; + PYOPENCL_BUFFER_SIZE_T len; if (PyObject_AsWriteBuffer(buffer.ptr(), &buf, &len)) throw py::error_already_set(); +#endif cl_event evt; @@ -2441,7 +2667,7 @@ namespace pyopencl PYOPENCL_WAITLIST_ARGS, &evt )); ); - PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, buffer); + PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, ward); } @@ -2462,10 +2688,19 @@ namespace pyopencl COPY_PY_REGION_TRIPLE(region); const void *buf; - PYOPENCL_BUFFER_SIZE_T len; +#ifdef PYOPENCL_USE_NEW_BUFFER_INTERFACE + std::auto_ptr<py_buffer_wrapper> ward(new py_buffer_wrapper); + + ward->get(buffer.ptr(), PyBUF_ANY_CONTIGUOUS); + + buf = ward->m_buf.buf; +#else + py::object ward = buffer; + PYOPENCL_BUFFER_SIZE_T len; if (PyObject_AsReadBuffer(buffer.ptr(), &buf, &len)) throw py::error_already_set(); +#endif cl_event evt; PYOPENCL_RETRY_IF_MEM_ERROR( @@ -2477,7 +2712,7 @@ namespace pyopencl PYOPENCL_WAITLIST_ARGS, &evt )); ); - PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, buffer); + PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, ward); } @@ -2586,10 +2821,19 @@ namespace pyopencl COPY_PY_REGION_TRIPLE(region); const void *color_buf; - PYOPENCL_BUFFER_SIZE_T color_len; +#ifdef PYOPENCL_USE_NEW_BUFFER_INTERFACE + std::auto_ptr<py_buffer_wrapper> ward(new py_buffer_wrapper); + + ward->get(color.ptr(), PyBUF_ANY_CONTIGUOUS); + + color_buf = ward->m_buf.buf; +#else + py::object ward = color; + PYOPENCL_BUFFER_SIZE_T color_len; if (PyObject_AsReadBuffer(color.ptr(), &color_buf, &color_len)) throw py::error_already_set(); +#endif cl_event evt; PYOPENCL_RETRY_IF_MEM_ERROR( @@ -2600,7 +2844,7 @@ namespace pyopencl PYOPENCL_WAITLIST_ARGS, &evt )); ); - PYOPENCL_RETURN_NEW_EVENT(evt); + PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, ward); } #endif @@ -3119,9 +3363,18 @@ namespace pyopencl const void *buf; PYOPENCL_BUFFER_SIZE_T len; +#ifdef PYOPENCL_USE_NEW_BUFFER_INTERFACE + py_buffer_wrapper buf_wrapper; + + buf_wrapper.get(py::object(py_binaries[i]).ptr(), PyBUF_ANY_CONTIGUOUS); + + buf = buf_wrapper.m_buf.buf; + len = buf_wrapper.m_buf.len; +#else if (PyObject_AsReadBuffer( py::object(py_binaries[i]).ptr(), &buf, &len)) throw py::error_already_set(); +#endif binaries.push_back(reinterpret_cast<const unsigned char *>(buf)); sizes.push_back(len); @@ -3332,12 +3585,21 @@ namespace pyopencl const void *buf; PYOPENCL_BUFFER_SIZE_T len; +#ifdef PYOPENCL_USE_NEW_BUFFER_INTERFACE + py_buffer_wrapper buf_wrapper; + + buf_wrapper.get(py_buffer.ptr(), PyBUF_ANY_CONTIGUOUS); + + buf = buf_wrapper.m_buf.buf; + len = buf_wrapper.m_buf.len; +#else if (PyObject_AsReadBuffer(py_buffer.ptr(), &buf, &len)) { PyErr_Clear(); throw error("Kernel.set_arg", CL_INVALID_VALUE, "invalid kernel argument"); } +#endif PYOPENCL_CALL_GUARDED(clSetKernelArg, (m_kernel, arg_index, len, buf));