• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
3 //
4 // Distributed under the Boost Software License, Version 1.0
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
7 //
8 // See http://boostorg.github.com/compute for more information.
9 //---------------------------------------------------------------------------//
10 
11 #ifndef BOOST_COMPUTE_CONTEXT_HPP
12 #define BOOST_COMPUTE_CONTEXT_HPP
13 
14 #include <vector>
15 
16 #include <boost/throw_exception.hpp>
17 
18 #include <boost/compute/config.hpp>
19 #include <boost/compute/device.hpp>
20 #include <boost/compute/exception/opencl_error.hpp>
21 #include <boost/compute/detail/assert_cl_success.hpp>
22 
23 namespace boost {
24 namespace compute {
25 
26 /// \class context
27 /// \brief A compute context.
28 ///
29 /// The context class represents a compute context.
30 ///
31 /// A context object manages a set of OpenCL resources including memory
32 /// buffers and program objects. Before allocating memory on the device or
33 /// executing kernels you must set up a context object.
34 ///
35 /// To create a context for the default device on the system:
36 /// \code
37 /// // get the default compute device
38 /// boost::compute::device gpu = boost::compute::system::default_device();
39 ///
40 /// // create a context for the device
41 /// boost::compute::context context(gpu);
42 /// \endcode
43 ///
44 /// Once a context is created, memory can be allocated using the buffer class
45 /// and kernels can be executed using the command_queue class.
46 ///
47 /// \see device, command_queue
48 class context
49 {
50 public:
51     /// Create a null context object.
context()52     context()
53         : m_context(0)
54     {
55     }
56 
57     /// Creates a new context for \p device with \p properties.
58     ///
59     /// \see_opencl_ref{clCreateContext}
context(const device & device,const cl_context_properties * properties=0)60     explicit context(const device &device,
61                      const cl_context_properties *properties = 0)
62     {
63         BOOST_ASSERT(device.id() != 0);
64 
65         cl_device_id device_id = device.id();
66 
67         cl_int error = 0;
68         m_context = clCreateContext(properties, 1, &device_id, 0, 0, &error);
69 
70         if(!m_context){
71             BOOST_THROW_EXCEPTION(opencl_error(error));
72         }
73     }
74 
75     /// Creates a new context for \p devices with \p properties.
76     ///
77     /// \see_opencl_ref{clCreateContext}
context(const std::vector<device> & devices,const cl_context_properties * properties=0)78     explicit context(const std::vector<device> &devices,
79                      const cl_context_properties *properties = 0)
80     {
81         BOOST_ASSERT(!devices.empty());
82 
83         cl_int error = 0;
84 
85         m_context = clCreateContext(
86             properties,
87             static_cast<cl_uint>(devices.size()),
88             reinterpret_cast<const cl_device_id *>(&devices[0]),
89             0,
90             0,
91             &error
92         );
93 
94         if(!m_context){
95             BOOST_THROW_EXCEPTION(opencl_error(error));
96         }
97     }
98 
99     /// Creates a new context object for \p context. If \p retain is
100     /// \c true, the reference count for \p context will be incremented.
context(cl_context context,bool retain=true)101     explicit context(cl_context context, bool retain = true)
102         : m_context(context)
103     {
104         if(m_context && retain){
105             clRetainContext(m_context);
106         }
107     }
108 
109     /// Creates a new context object as a copy of \p other.
context(const context & other)110     context(const context &other)
111         : m_context(other.m_context)
112     {
113         if(m_context){
114             clRetainContext(m_context);
115         }
116     }
117 
118     /// Copies the context object from \p other to \c *this.
operator =(const context & other)119     context& operator=(const context &other)
120     {
121         if(this != &other){
122             if(m_context){
123                 clReleaseContext(m_context);
124             }
125 
126             m_context = other.m_context;
127 
128             if(m_context){
129                 clRetainContext(m_context);
130             }
131         }
132 
133         return *this;
134     }
135 
136     #ifndef BOOST_COMPUTE_NO_RVALUE_REFERENCES
137     /// Move-constructs a new context object from \p other.
context(context && other)138     context(context&& other) BOOST_NOEXCEPT
139         : m_context(other.m_context)
140     {
141         other.m_context = 0;
142     }
143 
144     /// Move-assigns the context from \p other to \c *this.
operator =(context && other)145     context& operator=(context&& other) BOOST_NOEXCEPT
146     {
147         if(m_context){
148             clReleaseContext(m_context);
149         }
150 
151         m_context = other.m_context;
152         other.m_context = 0;
153 
154         return *this;
155     }
156     #endif // BOOST_COMPUTE_NO_RVALUE_REFERENCES
157 
158     /// Destroys the context object.
~context()159     ~context()
160     {
161         if(m_context){
162             BOOST_COMPUTE_ASSERT_CL_SUCCESS(
163                 clReleaseContext(m_context)
164             );
165         }
166     }
167 
168     /// Returns the underlying OpenCL context.
get() const169     cl_context& get() const
170     {
171         return const_cast<cl_context &>(m_context);
172     }
173 
174     /// Returns the device for the context. If the context contains multiple
175     /// devices, the first is returned.
get_device() const176     device get_device() const
177     {
178         std::vector<device> devices = get_devices();
179 
180         if(devices.empty()) {
181             return device();
182         }
183 
184         return devices.front();
185     }
186 
187     /// Returns a vector of devices for the context.
get_devices() const188     std::vector<device> get_devices() const
189     {
190         return get_info<std::vector<device> >(CL_CONTEXT_DEVICES);
191     }
192 
193     /// Returns information about the context.
194     ///
195     /// \see_opencl_ref{clGetContextInfo}
196     template<class T>
get_info(cl_context_info info) const197     T get_info(cl_context_info info) const
198     {
199         return detail::get_object_info<T>(clGetContextInfo, m_context, info);
200     }
201 
202     /// \overload
203     template<int Enum>
204     typename detail::get_object_info_type<context, Enum>::type
205     get_info() const;
206 
207     /// Returns \c true if the context is the same as \p other.
operator ==(const context & other) const208     bool operator==(const context &other) const
209     {
210         return m_context == other.m_context;
211     }
212 
213     /// Returns \c true if the context is different from \p other.
operator !=(const context & other) const214     bool operator!=(const context &other) const
215     {
216         return m_context != other.m_context;
217     }
218 
219     /// \internal_
operator cl_context() const220     operator cl_context() const
221     {
222         return m_context;
223     }
224 
225 private:
226     cl_context m_context;
227 };
228 
229 /// \internal_ define get_info() specializations for context
230 BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(context,
231     ((cl_uint, CL_CONTEXT_REFERENCE_COUNT))
232     ((std::vector<cl_device_id>, CL_CONTEXT_DEVICES))
233     ((std::vector<cl_context_properties>, CL_CONTEXT_PROPERTIES))
234 )
235 
236 #ifdef BOOST_COMPUTE_CL_VERSION_1_1
237 BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(context,
238     ((cl_uint, CL_CONTEXT_NUM_DEVICES))
239 )
240 #endif // BOOST_COMPUTE_CL_VERSION_1_1
241 
242 } // end compute namespace
243 } // end boost namespace
244 
245 #endif // BOOST_COMPUTE_CONTEXT_HPP
246