summaryrefslogtreecommitdiff
path: root/boost/compute/kernel.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/compute/kernel.hpp')
-rw-r--r--boost/compute/kernel.hpp394
1 files changed, 394 insertions, 0 deletions
diff --git a/boost/compute/kernel.hpp b/boost/compute/kernel.hpp
new file mode 100644
index 0000000000..9494e46de2
--- /dev/null
+++ b/boost/compute/kernel.hpp
@@ -0,0 +1,394 @@
+//---------------------------------------------------------------------------//
+// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
+//
+// Distributed under the Boost Software License, Version 1.0
+// See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt
+//
+// See http://boostorg.github.com/compute for more information.
+//---------------------------------------------------------------------------//
+
+#ifndef BOOST_COMPUTE_KERNEL_HPP
+#define BOOST_COMPUTE_KERNEL_HPP
+
+#include <string>
+
+#include <boost/assert.hpp>
+#include <boost/utility/enable_if.hpp>
+
+#include <boost/compute/config.hpp>
+#include <boost/compute/program.hpp>
+#include <boost/compute/exception.hpp>
+#include <boost/compute/type_traits/is_fundamental.hpp>
+#include <boost/compute/detail/get_object_info.hpp>
+#include <boost/compute/detail/assert_cl_success.hpp>
+#include <boost/compute/memory/svm_ptr.hpp>
+
+namespace boost {
+namespace compute {
+namespace detail {
+
+template<class T> struct set_kernel_arg;
+
+} // end detail namespace
+
+/// \class kernel
+/// \brief A compute kernel.
+///
+/// \see command_queue, program
+class kernel
+{
+public:
+ /// Creates a null kernel object.
+ kernel()
+ : m_kernel(0)
+ {
+ }
+
+ /// Creates a new kernel object for \p kernel. If \p retain is
+ /// \c true, the reference count for \p kernel will be incremented.
+ explicit kernel(cl_kernel kernel, bool retain = true)
+ : m_kernel(kernel)
+ {
+ if(m_kernel && retain){
+ clRetainKernel(m_kernel);
+ }
+ }
+
+ /// Creates a new kernel object with \p name from \p program.
+ kernel(const program &program, const std::string &name)
+ {
+ cl_int error = 0;
+ m_kernel = clCreateKernel(program.get(), name.c_str(), &error);
+
+ if(!m_kernel){
+ BOOST_THROW_EXCEPTION(opencl_error(error));
+ }
+ }
+
+ /// Creates a new kernel object as a copy of \p other.
+ kernel(const kernel &other)
+ : m_kernel(other.m_kernel)
+ {
+ if(m_kernel){
+ clRetainKernel(m_kernel);
+ }
+ }
+
+ /// Copies the kernel object from \p other to \c *this.
+ kernel& operator=(const kernel &other)
+ {
+ if(this != &other){
+ if(m_kernel){
+ clReleaseKernel(m_kernel);
+ }
+
+ m_kernel = other.m_kernel;
+
+ if(m_kernel){
+ clRetainKernel(m_kernel);
+ }
+ }
+
+ return *this;
+ }
+
+ #ifndef BOOST_COMPUTE_NO_RVALUE_REFERENCES
+ /// Move-constructs a new kernel object from \p other.
+ kernel(kernel&& other) BOOST_NOEXCEPT
+ : m_kernel(other.m_kernel)
+ {
+ other.m_kernel = 0;
+ }
+
+ /// Move-assigns the kernel from \p other to \c *this.
+ kernel& operator=(kernel&& other) BOOST_NOEXCEPT
+ {
+ if(m_kernel){
+ clReleaseKernel(m_kernel);
+ }
+
+ m_kernel = other.m_kernel;
+ other.m_kernel = 0;
+
+ return *this;
+ }
+ #endif // BOOST_COMPUTE_NO_RVALUE_REFERENCES
+
+ /// Destroys the kernel object.
+ ~kernel()
+ {
+ if(m_kernel){
+ BOOST_COMPUTE_ASSERT_CL_SUCCESS(
+ clReleaseKernel(m_kernel)
+ );
+ }
+ }
+
+ /// Returns a reference to the underlying OpenCL kernel object.
+ cl_kernel& get() const
+ {
+ return const_cast<cl_kernel &>(m_kernel);
+ }
+
+ /// Returns the function name for the kernel.
+ std::string name() const
+ {
+ return get_info<std::string>(CL_KERNEL_FUNCTION_NAME);
+ }
+
+ /// Returns the number of arguments for the kernel.
+ size_t arity() const
+ {
+ return get_info<cl_uint>(CL_KERNEL_NUM_ARGS);
+ }
+
+ /// Returns the program for the kernel.
+ program get_program() const
+ {
+ return program(get_info<cl_program>(CL_KERNEL_PROGRAM));
+ }
+
+ /// Returns the context for the kernel.
+ context get_context() const
+ {
+ return context(get_info<cl_context>(CL_KERNEL_CONTEXT));
+ }
+
+ /// Returns information about the kernel.
+ ///
+ /// \see_opencl_ref{clGetKernelInfo}
+ template<class T>
+ T get_info(cl_kernel_info info) const
+ {
+ return detail::get_object_info<T>(clGetKernelInfo, m_kernel, info);
+ }
+
+ /// \overload
+ template<int Enum>
+ typename detail::get_object_info_type<kernel, Enum>::type
+ get_info() const;
+
+ #if defined(CL_VERSION_1_2) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
+ /// Returns information about the argument at \p index.
+ ///
+ /// For example, to get the name of the first argument:
+ /// \code
+ /// std::string arg = kernel.get_arg_info<std::string>(0, CL_KERNEL_ARG_NAME);
+ /// \endcode
+ ///
+ /// Note, this function requires that the program be compiled with the
+ /// \c "-cl-kernel-arg-info" flag. For example:
+ /// \code
+ /// program.build("-cl-kernel-arg-info");
+ /// \endcode
+ ///
+ /// \opencl_version_warning{1,2}
+ ///
+ /// \see_opencl_ref{clGetKernelArgInfo}
+ template<class T>
+ T get_arg_info(size_t index, cl_kernel_arg_info info) const
+ {
+ return detail::get_object_info<T>(clGetKernelArgInfo, m_kernel, info, index);
+ }
+ #endif // CL_VERSION_1_2
+
+ /// Returns work-group information for the kernel with \p device.
+ ///
+ /// \see_opencl_ref{clGetKernelWorkGroupInfo}
+ template<class T>
+ T get_work_group_info(const device &device, cl_kernel_work_group_info info) const
+ {
+ return detail::get_object_info<T>(clGetKernelWorkGroupInfo, m_kernel, info, device.id());
+ }
+
+ /// Sets the argument at \p index to \p value with \p size.
+ ///
+ /// \see_opencl_ref{clSetKernelArg}
+ void set_arg(size_t index, size_t size, const void *value)
+ {
+ BOOST_ASSERT(index < arity());
+
+ cl_int ret = clSetKernelArg(m_kernel,
+ static_cast<cl_uint>(index),
+ size,
+ value);
+ if(ret != CL_SUCCESS){
+ BOOST_THROW_EXCEPTION(opencl_error(ret));
+ }
+ }
+
+ /// Sets the argument at \p index to \p value.
+ ///
+ /// For built-in types (e.g. \c float, \c int4_), this is equivalent to
+ /// calling set_arg(index, sizeof(type), &value).
+ ///
+ /// Additionally, this method is specialized for device memory objects
+ /// such as buffer and image2d. This allows for them to be passed directly
+ /// without having to extract their underlying cl_mem object.
+ ///
+ /// This method is also specialized for device container types such as
+ /// vector<T> and array<T, N>. This allows for them to be passed directly
+ /// as kernel arguments without having to extract their underlying buffer.
+ ///
+ /// For setting local memory arguments (e.g. "__local float *buf"), the
+ /// local_buffer<T> class may be used:
+ /// \code
+ /// // set argument to a local buffer with storage for 32 float's
+ /// kernel.set_arg(0, local_buffer<float>(32));
+ /// \endcode
+ template<class T>
+ void set_arg(size_t index, const T &value)
+ {
+ // if you get a compilation error pointing here it means you
+ // attempted to set a kernel argument from an invalid type.
+ detail::set_kernel_arg<T>()(*this, index, value);
+ }
+
+ /// \internal_
+ void set_arg(size_t index, const cl_mem mem)
+ {
+ set_arg(index, sizeof(cl_mem), static_cast<const void *>(&mem));
+ }
+
+ /// \internal_
+ void set_arg(size_t index, const cl_sampler sampler)
+ {
+ set_arg(index, sizeof(cl_sampler), static_cast<const void *>(&sampler));
+ }
+
+ /// \internal_
+ template<class T>
+ void set_arg(size_t index, const svm_ptr<T> ptr)
+ {
+ #ifdef CL_VERSION_2_0
+ cl_int ret = clSetKernelArgSVMPointer(m_kernel, index, ptr.get());
+ if(ret != CL_SUCCESS){
+ BOOST_THROW_EXCEPTION(opencl_error(ret));
+ }
+ #else
+ BOOST_THROW_EXCEPTION(opencl_error(CL_INVALID_ARG_VALUE));
+ #endif
+ }
+
+ #ifndef BOOST_COMPUTE_NO_VARIADIC_TEMPLATES
+ /// Sets the arguments for the kernel to \p args.
+ template<class... T>
+ void set_args(T&&... args)
+ {
+ BOOST_ASSERT(sizeof...(T) <= arity());
+
+ _set_args<0>(args...);
+ }
+ #endif // BOOST_COMPUTE_NO_VARIADIC_TEMPLATES
+
+ #if defined(CL_VERSION_2_0) || defined(BOOST_COMPUTE_DOXYGEN_INVOKED)
+ /// Sets additional execution information for the kernel.
+ ///
+ /// \opencl_version_warning{2,0}
+ ///
+ /// \see_opencl2_ref{clSetKernelExecInfo}
+ void set_exec_info(cl_kernel_exec_info info, size_t size, const void *value)
+ {
+ cl_int ret = clSetKernelExecInfo(m_kernel, info, size, value);
+ if(ret != CL_SUCCESS){
+ BOOST_THROW_EXCEPTION(opencl_error(ret));
+ }
+ }
+ #endif // CL_VERSION_2_0
+
+ /// Returns \c true if the kernel is the same at \p other.
+ bool operator==(const kernel &other) const
+ {
+ return m_kernel == other.m_kernel;
+ }
+
+ /// Returns \c true if the kernel is different from \p other.
+ bool operator!=(const kernel &other) const
+ {
+ return m_kernel != other.m_kernel;
+ }
+
+ /// \internal_
+ operator cl_kernel() const
+ {
+ return m_kernel;
+ }
+
+ /// \internal_
+ static kernel create_with_source(const std::string &source,
+ const std::string &name,
+ const context &context)
+ {
+ return program::build_with_source(source, context).create_kernel(name);
+ }
+
+private:
+ #ifndef BOOST_NO_VARIADIC_TEMPLATES
+ /// \internal_
+ template<size_t N>
+ void _set_args()
+ {
+ }
+
+ /// \internal_
+ template<size_t N, class T, class... Args>
+ void _set_args(T&& arg, Args&&... rest)
+ {
+ set_arg(N, arg);
+ _set_args<N+1>(rest...);
+ }
+ #endif // BOOST_NO_VARIADIC_TEMPLATES
+
+private:
+ cl_kernel m_kernel;
+};
+
+inline kernel program::create_kernel(const std::string &name) const
+{
+ return kernel(*this, name);
+}
+
+/// \internal_ define get_info() specializations for kernel
+BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(kernel,
+ ((std::string, CL_KERNEL_FUNCTION_NAME))
+ ((cl_uint, CL_KERNEL_NUM_ARGS))
+ ((cl_uint, CL_KERNEL_REFERENCE_COUNT))
+ ((cl_context, CL_KERNEL_CONTEXT))
+ ((cl_program, CL_KERNEL_PROGRAM))
+)
+
+#ifdef CL_VERSION_1_2
+BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(kernel,
+ ((std::string, CL_KERNEL_ATTRIBUTES))
+)
+#endif // CL_VERSION_1_2
+
+namespace detail {
+
+// set_kernel_arg implementation for built-in types
+template<class T>
+struct set_kernel_arg
+{
+ typename boost::enable_if<is_fundamental<T> >::type
+ operator()(kernel &kernel_, size_t index, const T &value)
+ {
+ kernel_.set_arg(index, sizeof(T), &value);
+ }
+};
+
+// set_kernel_arg specialization for char (different from built-in cl_char)
+template<>
+struct set_kernel_arg<char>
+{
+ void operator()(kernel &kernel_, size_t index, const char c)
+ {
+ kernel_.set_arg(index, sizeof(char), &c);
+ }
+};
+
+} // end detail namespace
+} // end namespace compute
+} // end namespace boost
+
+#endif // BOOST_COMPUTE_KERNEL_HPP