Skip to content
Snippets Groups Projects
wrap_cl_part_2.cpp 20.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • // 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.
    
    
    
    #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)
      {
    
      }
    
      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
    
    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)
    
        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(),
    
      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(),
    
      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()
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
      // {{{ 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()
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
              )
    #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);
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
    
    #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
    
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
      {
        typedef svm_arg_wrapper cls;
    
        py::class_<cls, svm_pointer>(m, "SVM", py::dynamic_attr())
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
          .def(py::init<py::object>())
          ;
      }
    
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
      {
        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()
              )
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
          .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()
              )
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
          .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();
              })
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
      m.def("_enqueue_svm_memcpy", enqueue_svm_memcpy,
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
          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()
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
          );
    
      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()
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
          );
    
      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()
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
          );
    
      m.def("_enqueue_svm_unmap", enqueue_svm_unmap,
          py::arg("queue"),
          py::arg("svm"),
    
          py::arg("wait_for").none(true)=py::none()
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
          );
    #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()
    
      // {{{ 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("devices").none(true)=py::none())
    
    #if PYOPENCL_CL_VERSION >= 0x1020
          .def("compile", &cls::compile,
    
              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)
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
          .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
    
    Andreas Klöckner's avatar
    Andreas Klöckner committed
          .def("_set_arg_svm", &cls::set_arg_svm)
    #endif
    
              [](cls &knl, py::tuple indices_and_args)
    
                    [&](cl_uint i, py::handle arg) { knl.set_arg(i, arg); },
    
              [](cls &knl, py::tuple indices_and_args)
    
                    [&](cl_uint i, py::handle arg) { knl.set_arg_buf(i, arg); },
    
          .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()
    
          ;
      }
    
      {
        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()
    
    }
    
    
    // vim: foldmethod=marker