]>
Commit | Line | Data |
---|---|---|
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. | |
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} | |
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} | |
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. | |
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. | |
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. | |
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. | |
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. | |
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. | |
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. | |
169 | 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. | |
176 | 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. | |
188 | 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> | |
197 | 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. | |
208 | 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. | |
214 | bool operator!=(const context &other) const | |
215 | { | |
216 | return m_context != other.m_context; | |
217 | } | |
218 | ||
219 | /// \internal_ | |
220 | 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 CL_VERSION_1_1 | |
237 | BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(context, | |
238 | ((cl_uint, CL_CONTEXT_NUM_DEVICES)) | |
239 | ) | |
240 | #endif // CL_VERSION_1_1 | |
241 | ||
242 | } // end compute namespace | |
243 | } // end boost namespace | |
244 | ||
245 | #endif // BOOST_COMPUTE_CONTEXT_HPP |