wrap_cl_part_2.cpp 20.43 KiB
// Wrap CL
//
// Copyright (C) 2009-18 Andreas Kloeckner
//
// 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.
#include <memory>
#define NO_IMPORT_ARRAY
#define PY_ARRAY_UNIQUE_SYMBOL pyopencl_ARRAY_API
#include "wrap_cl.hpp"
namespace pyopencl {
#if PYOPENCL_CL_VERSION >= 0x1020
py::object image_desc_dummy_getter(cl_image_desc &desc)
{
return py::none();
}
void image_desc_set_shape(cl_image_desc &desc, py::object py_shape)
{
COPY_PY_REGION_TRIPLE(shape);
desc.image_width = shape[0];
desc.image_height = shape[1];
desc.image_depth = shape[2];
desc.image_array_size = shape[2];
}
void image_desc_set_pitches(cl_image_desc &desc, py::object py_pitches)
{
COPY_PY_PITCH_TUPLE(pitches);
desc.image_row_pitch = pitches[0];
desc.image_slice_pitch = pitches[1];
}
void image_desc_set_buffer(cl_image_desc &desc, memory_object *mobj)
{
if (mobj)
desc.buffer = mobj->data();
else
desc.buffer = 0;
}
#endif
#if PYOPENCL_CL_VERSION >= 0x2000
class svm_pointer_as_buffer
{
private:
svm_pointer &m_ptr;
public:
svm_pointer_as_buffer(svm_pointer &ptr)
: m_ptr(ptr)
{ }
svm_pointer &ptr() const
{ return m_ptr; }
};
#endif
}
using namespace pyopencl;
void pyopencl_expose_part_2(py::module_ &m)
{
// {{{ image
#if PYOPENCL_CL_VERSION >= 0x1020
{
typedef cl_image_desc cls;
py::class_<cls>(m, "ImageDescriptor")
.def(py::init<>())
.def_readwrite("image_type", &cls::image_type)
.def_property("shape", &image_desc_dummy_getter, image_desc_set_shape)
.def_readwrite("array_size", &cls::image_array_size)
.def_property("pitches", &image_desc_dummy_getter, image_desc_set_pitches)
.def_readwrite("num_mip_levels", &cls::num_mip_levels)
.def_readwrite("num_samples", &cls::num_samples)
.def_property("buffer", &image_desc_dummy_getter, image_desc_set_buffer)
;
}
#endif
{
typedef image cls;
py::class_<cls, memory_object>(m, "Image", py::dynamic_attr())
.def(
py::init(
[](
context const &ctx,
cl_mem_flags flags,
cl_image_format const &fmt,
py::sequence shape,
py::sequence pitches,
py::object buffer)
{
return create_image(ctx, flags, fmt, shape, pitches, buffer);
}),
py::arg("context"),
py::arg("flags"),
py::arg("format"),
py::arg("shape")=py::none(),
py::arg("pitches")=py::none(),
py::arg("hostbuf")=py::none()
)
#if PYOPENCL_CL_VERSION >= 0x1020
.def(
py::init(
[](
context const &ctx,
cl_mem_flags flags,
cl_image_format const &fmt,
cl_image_desc &desc,
py::object buffer)
{
return create_image_from_desc(ctx, flags, fmt, desc, buffer);
}),
py::arg("context"),
py::arg("flags"),
py::arg("format"),
py::arg("desc"),
py::arg("hostbuf")=py::none()
)
#endif
.DEF_SIMPLE_METHOD(get_image_info)
;
}
{
typedef cl_image_format cls;
py::class_<cls>(m, "ImageFormat")
.def(
py::init(
[](cl_channel_order ord, cl_channel_type tp)
{
return make_image_format(ord, tp);
}))
.def_readwrite("channel_order", &cls::image_channel_order)
.def_readwrite("channel_data_type", &cls::image_channel_data_type)
.def_property_readonly("channel_count", &get_image_format_channel_count)
.def_property_readonly("dtype_size", &get_image_format_channel_dtype_size)
.def_property_readonly("itemsize", &get_image_format_item_size)
;
}
DEF_SIMPLE_FUNCTION(get_supported_image_formats);
m.def("_enqueue_read_image", enqueue_read_image,
py::arg("queue"),
py::arg("mem"),
py::arg("origin"),
py::arg("region"),
py::arg("hostbuf"),
py::arg("row_pitch")=0,
py::arg("slice_pitch")=0,
py::arg("wait_for")=py::none(),
py::arg("is_blocking")=true
);
m.def("_enqueue_write_image", enqueue_write_image,
py::arg("queue"),
py::arg("mem"),
py::arg("origin"),
py::arg("region"),
py::arg("hostbuf"),
py::arg("row_pitch")=0,
py::arg("slice_pitch")=0,
py::arg("wait_for")=py::none(),
py::arg("is_blocking")=true
);
m.def("_enqueue_copy_image", enqueue_copy_image,
py::arg("queue"),
py::arg("src"),
py::arg("dest"),
py::arg("src_origin"),
py::arg("dest_origin"),
py::arg("region"),
py::arg("wait_for")=py::none()
);
m.def("_enqueue_copy_image_to_buffer", enqueue_copy_image_to_buffer,
py::arg("queue"),
py::arg("src"),
py::arg("dest"),
py::arg("origin"),
py::arg("region"),
py::arg("offset"),
py::arg("wait_for")=py::none()
);
m.def("_enqueue_copy_buffer_to_image", enqueue_copy_buffer_to_image,
py::arg("queue"),
py::arg("src"),
py::arg("dest"),
py::arg("offset"),
py::arg("origin"),
py::arg("region"),
py::arg("wait_for")=py::none()
);
#if PYOPENCL_CL_VERSION >= 0x1020
m.def("enqueue_fill_image", enqueue_fill_image,
py::arg("queue"),
py::arg("mem"),
py::arg("color"),
py::arg("origin"),
py::arg("region"),
py::arg("wait_for")=py::none()
);
#endif
// }}}
// {{{ pipe
{
typedef pyopencl::pipe cls;
py::class_<cls, memory_object>(m, "Pipe", py::dynamic_attr())
#if PYOPENCL_CL_VERSION >= 0x2000
.def(
py::init(
[](
context const &ctx,
cl_mem_flags flags,
cl_uint pipe_packet_size,
cl_uint pipe_max_packets,
py::sequence py_props)
{
return create_pipe(ctx, flags, pipe_packet_size, pipe_max_packets, py_props);
}),
py::arg("context"),
py::arg("flags"),
py::arg("packet_size"),
py::arg("max_packets"),
py::arg("properties")=py::make_tuple()
)
#endif
.DEF_SIMPLE_METHOD(get_pipe_info)
;
}
// }}}
// {{{ memory_map
{
typedef memory_map cls;
py::class_<cls>(m, "MemoryMap", py::dynamic_attr())
.def("release", &cls::release,
py::arg("queue").none(true)=nullptr,
py::arg("wait_for").none(true)=py::none()
)
;
}
// FIXME: Reenable in pypy
#ifndef PYPY_VERSION
m.def("enqueue_map_buffer", enqueue_map_buffer,
py::arg("queue"),
py::arg("buf"),
py::arg("flags"),
py::arg("offset"),
py::arg("shape"),
py::arg("dtype"),
py::arg("order")="C",
py::arg("strides").none(true)=py::none(),
py::arg("wait_for").none(true)=py::none(),
py::arg("is_blocking")=true);
m.def("enqueue_map_image", enqueue_map_image,
py::arg("queue"),
py::arg("img"),
py::arg("flags"),
py::arg("origin"),
py::arg("region"),
py::arg("shape"),
py::arg("dtype"),
py::arg("order")="C",
py::arg("strides").none(true)=py::none(),
py::arg("wait_for").none(true)=py::none(),
py::arg("is_blocking")=true);
#endif
// }}}
// {{{ svm_pointer
#if PYOPENCL_CL_VERSION >= 0x2000
{
typedef svm_pointer cls;
py::class_<cls>(m, "SVMPointer", py::dynamic_attr())
// For consistency, it may seem appropriate to use int_ptr here, but
// that would work on both buffers and SVM, and passing a buffer pointer to
// a kernel is going to lead to a bad time.
.def_property_readonly("svm_ptr",
[](cls &self) { return (intptr_t) self.svm_ptr(); })
.def_property_readonly("size", [](cls &self) -> py::object
{
try
{
return py::cast(self.size());
}
catch (size_not_available)
{
return py::none();
}
})
.def_property_readonly("buf", [](cls &self) -> svm_pointer_as_buffer * {
return new svm_pointer_as_buffer(self);
}, py::return_value_policy::reference_internal)
;
}
{
typedef svm_pointer_as_buffer cls;
py::class_<cls>(m, "_SVMPointerAsBuffer", pybind11::buffer_protocol())
.def_buffer([](cls &self) -> pybind11::buffer_info
{
size_t size;
try
{
size = self.ptr().size();
}
catch (size_not_available)
{
throw pyopencl::error("SVMPointer buffer protocol", CL_INVALID_VALUE,
"size of SVM is not known");
}
return pybind11::buffer_info(
// Pointer to buffer
self.ptr().svm_ptr(),
// Size of one scalar
sizeof(unsigned char),
// Python struct-style format descriptor
pybind11::format_descriptor<unsigned char>::format(),
// Number of dimensions
1,
// Buffer dimensions
{ size },
// Strides (in bytes) for each index
{ sizeof(unsigned char) }
);
})
;
}
// }}}
// {{{ svm_arg_wrapper
{
typedef svm_arg_wrapper cls;
py::class_<cls, svm_pointer>(m, "SVM", py::dynamic_attr())
.def(py::init<py::object>())
;
}
// }}}
// {{{ svm_allocation
{
typedef svm_allocation cls;
py::class_<cls, svm_pointer>(m, "SVMAllocation", py::dynamic_attr())
.def(py::init<std::shared_ptr<context>, size_t, cl_uint, cl_svm_mem_flags, const command_queue *>(),
py::arg("context"),
py::arg("size"),
py::arg("alignment"),
py::arg("flags"),
py::arg("queue").none(true)=py::none()
)
.DEF_SIMPLE_METHOD(release)
.def("enqueue_release", &cls::enqueue_release,
":returns: a :class:`pyopencl.Event`\n\n"
"|std-enqueue-blurb|",
py::arg("queue").none(true)=py::none(),
py::arg("wait_for").none(true)=py::none()
)
.def(py::self == py::self)
.def(py::self != py::self)
.def("__hash__", [](cls &self) { return (intptr_t) self.svm_ptr(); })
.def("bind_to_queue", &cls::bind_to_queue,
py::arg("queue"))
.DEF_SIMPLE_METHOD(unbind_from_queue)
// only for diagnostic/debugging/testing purposes!
.def_property_readonly("_queue",
[](cls const &self) -> py::object
{
cl_command_queue queue = self.queue();
if (queue)
return py::cast(new command_queue(queue, true));
else
return py::none();
})
;
}
// }}}
// {{{ svm operations
m.def("_enqueue_svm_memcpy", enqueue_svm_memcpy,
py::arg("queue"),
py::arg("is_blocking"),
py::arg("dst"),
py::arg("src"),
py::arg("wait_for").none(true)=py::none(),
py::arg("byte_count").none(true)=py::none()
);
m.def("_enqueue_svm_memfill", enqueue_svm_memfill,
py::arg("queue"),
py::arg("dst"),
py::arg("pattern"),
py::arg("byte_count").none(true)=py::none(),
py::arg("wait_for").none(true)=py::none()
);
m.def("_enqueue_svm_map", enqueue_svm_map,
py::arg("queue"),
py::arg("is_blocking"),
py::arg("flags"),
py::arg("svm"),
py::arg("wait_for").none(true)=py::none(),
py::arg("size").none(true)=py::none()
);
m.def("_enqueue_svm_unmap", enqueue_svm_unmap,
py::arg("queue"),
py::arg("svm"),
py::arg("wait_for").none(true)=py::none()
);
#endif
#if PYOPENCL_CL_VERSION >= 0x2010
m.def("_enqueue_svm_migrate_mem", enqueue_svm_migratemem,
py::arg("queue"),
py::arg("svms"),
py::arg("flags").none(true)=py::none(),
py::arg("wait_for").none(true)=py::none()
);
#endif
// }}}
// {{{ sampler
{
typedef sampler cls;
py::class_<cls>(m, "Sampler", py::dynamic_attr())
#if PYOPENCL_CL_VERSION >= 0x2000
.def(py::init<context const &, py::sequence>())
#endif
.def(py::init<context const &, bool, cl_addressing_mode, cl_filter_mode>())
.DEF_SIMPLE_METHOD(get_info)
.def(py::self == py::self)
.def(py::self != py::self)
.def("__hash__", &cls::hash)
PYOPENCL_EXPOSE_TO_FROM_INT_PTR(cl_sampler)
;
}
// }}}
// {{{ program
{
typedef program cls;
py::enum_<cls::program_kind_type>(m, "program_kind")
.value("UNKNOWN", cls::KND_UNKNOWN)
.value("SOURCE", cls::KND_SOURCE)
.value("BINARY", cls::KND_BINARY)
.value("IL", cls::KND_IL)
;
py::class_<cls>(m, "_Program", py::dynamic_attr())
.def(
py::init(
[](context &ctx, std::string const &src)
{
return create_program_with_source(ctx, src);
}),
py::arg("context"),
py::arg("src"))
.def(
py::init(
[](context &ctx, py::sequence devices, py::sequence binaries)
{
return create_program_with_binary(ctx, devices, binaries);
}),
py::arg("context"),
py::arg("devices"),
py::arg("binaries"))
#if (PYOPENCL_CL_VERSION >= 0x1020) || \
((PYOPENCL_CL_VERSION >= 0x1030) && defined(__APPLE__))
.def_static("create_with_built_in_kernels",
create_program_with_built_in_kernels,
py::arg("context"),
py::arg("devices"),
py::arg("kernel_names"))
#endif
.DEF_SIMPLE_METHOD(kind)
.DEF_SIMPLE_METHOD(get_info)
.DEF_SIMPLE_METHOD(get_build_info)
.def("_build", &cls::build,
py::arg("options")="",
py::arg("devices").none(true)=py::none())
#if PYOPENCL_CL_VERSION >= 0x1020
.def("compile", &cls::compile,
py::arg("options")="",
py::arg("devices").none(true)=py::none(),
py::arg("headers")=py::list())
.def_static("link", &link_program,
py::arg("context"),
py::arg("programs"),
py::arg("options")="",
py::arg("devices").none(true)=py::none()
)
#endif
#if PYOPENCL_CL_VERSION >= 0x2020
.def("set_specialization_constant", &cls::set_specialization_constant,
py::arg("spec_id"),
py::arg("buffer"))
#endif
.def(py::self == py::self)
.def(py::self != py::self)
.def("__hash__", &cls::hash)
.def("all_kernels", create_kernels_in_program)
PYOPENCL_EXPOSE_TO_FROM_INT_PTR(cl_program)
;
}
#if (PYOPENCL_CL_VERSION >= 0x2010)
m.def("_create_program_with_il", create_program_with_il);
#endif
#if PYOPENCL_CL_VERSION >= 0x1020
m.def("unload_platform_compiler", unload_platform_compiler);
#endif
// }}}
// {{{ kernel
{
typedef kernel cls;
py::class_<cls>(m, "Kernel", py::dynamic_attr())
.def(py::init<const program &, std::string const &>())
.DEF_SIMPLE_METHOD(get_info)
.DEF_SIMPLE_METHOD(get_work_group_info)
#if PYOPENCL_CL_VERSION >= 0x2010
.DEF_SIMPLE_METHOD(clone)
#endif
.def("_set_arg_null", &cls::set_arg_null)
.def("_set_arg_buf", &cls::set_arg_buf)
#if PYOPENCL_CL_VERSION >= 0x2000
.def("_set_arg_svm", &cls::set_arg_svm)
#endif
.def("_set_arg_multi",
[](cls &knl, py::tuple indices_and_args)
{
set_arg_multi(
[&](cl_uint i, py::handle arg) { knl.set_arg(i, arg); },
indices_and_args);
})
.def("_set_arg_buf_multi",
[](cls &knl, py::tuple indices_and_args)
{
set_arg_multi(
[&](cl_uint i, py::handle arg) { knl.set_arg_buf(i, arg); },
indices_and_args);
})
.def("_set_arg_buf_pack_multi",
[](cls &knl, py::tuple indices_chars_and_args)
{
set_arg_multi(
[&](cl_uint i, py::handle typechar, py::handle arg)
{ knl.set_arg_buf_pack(i, typechar, arg); },
indices_chars_and_args);
})
.DEF_SIMPLE_METHOD(set_arg)
#if PYOPENCL_CL_VERSION >= 0x1020
.DEF_SIMPLE_METHOD(get_arg_info)
#endif
.def(py::self == py::self)
.def(py::self != py::self)
.def("__hash__", &cls::hash)
PYOPENCL_EXPOSE_TO_FROM_INT_PTR(cl_kernel)
#if PYOPENCL_CL_VERSION >= 0x2010
.def("get_sub_group_info", &cls::get_sub_group_info,
py::arg("device"),
py::arg("param"),
py::arg("input_value").none(true)=py::none()
)
#endif
;
}
{
typedef local_memory cls;
py::class_<cls>(m, "LocalMemory", py::dynamic_attr())
.def(
py::init<size_t>(),
py::arg("size"))
.def_property_readonly("size", &cls::size)
;
}
m.def("enqueue_nd_range_kernel", enqueue_nd_range_kernel,
py::arg("queue"),
py::arg("kernel"),
py::arg("global_work_size"),
py::arg("local_work_size").none(true),
py::arg("global_work_offset").none(true)=py::none(),
py::arg("wait_for").none(true)=py::none(),
py::arg("g_times_l")=false,
py::arg("allow_empty_ndrange")=false
);
// TODO: clEnqueueNativeKernel
// }}}
// {{{ GL interop
DEF_SIMPLE_FUNCTION(have_gl);
#ifdef HAVE_GL
#ifdef __APPLE__
DEF_SIMPLE_FUNCTION(get_apple_cgl_share_group);
#endif /* __APPLE__ */
{
typedef gl_buffer cls;
py::class_<cls, memory_object>(m, "GLBuffer", py::dynamic_attr())
.def(
py::init(
[](context &ctx, cl_mem_flags flags, GLuint bufobj)
{
return create_from_gl_buffer(ctx, flags, bufobj);
}),
py::arg("context"),
py::arg("flags"),
py::arg("bufobj"))
.def("get_gl_object_info", get_gl_object_info)
;
}
{
typedef gl_renderbuffer cls;
py::class_<cls, memory_object>(m, "GLRenderBuffer", py::dynamic_attr())
.def(
py::init(
[](context &ctx, cl_mem_flags flags, GLuint bufobj)
{
return create_from_gl_renderbuffer(ctx, flags, bufobj);
}),
py::arg("context"),
py::arg("flags"),
py::arg("bufobj"))
.def("get_gl_object_info", get_gl_object_info)
;
}
{
typedef gl_texture cls;
py::class_<cls, image>(m, "GLTexture", py::dynamic_attr())
.def(
py::init(
[](context &ctx, cl_mem_flags flags, GLenum texture_target,
GLint miplevel, GLuint texture, unsigned dims)
{
return create_from_gl_texture(ctx, flags, texture_target, miplevel, texture, dims);
}),
py::arg("context"),
py::arg("flags"),
py::arg("texture_target"),
py::arg("miplevel"),
py::arg("texture"),
py::arg("dims"))
.def("get_gl_object_info", get_gl_object_info)
.DEF_SIMPLE_METHOD(get_gl_texture_info)
;
}
m.def("enqueue_acquire_gl_objects", enqueue_acquire_gl_objects,
py::arg("queue"),
py::arg("mem_objects"),
py::arg("wait_for").none(true)=py::none()
);
m.def("enqueue_release_gl_objects", enqueue_release_gl_objects,
py::arg("queue"),
py::arg("mem_objects"),
py::arg("wait_for").none(true)=py::none()
);
#if defined(cl_khr_gl_sharing) && (cl_khr_gl_sharing >= 1)
m.def("get_gl_context_info_khr", get_gl_context_info_khr,
py::arg("properties"),
py::arg("param_name"),
py::arg("platform").none(true)=py::none()
);
#endif
#endif
// }}}
}
// vim: foldmethod=marker