1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
//! An OpenCL context.
// TEMPORARY:
#![allow(dead_code)]
// use formatting::MT;
use std;
use std::ops::{Deref, DerefMut};
use core::{self, Context as ContextCore, ContextProperties, ContextInfo, ContextInfoResult,
DeviceInfo, DeviceInfoResult, PlatformId as PlatformIdCore, PlatformInfo, PlatformInfoResult,
CreateContextCallbackFn, UserDataPtr};
use error::{Result as OclResult, Error as OclError};
use standard::{Platform, Device, DeviceSpecifier};
/// A builder for `Context`.
///
/// TODO: Implement index-searching-round-robin-ing methods (and thier '_exact' counterparts).
pub struct ContextBuilder {
properties: Option<ContextProperties>,
platform: Option<Platform>,
device_spec: Option<DeviceSpecifier>,
}
impl ContextBuilder {
/// Creates a new `ContextBuilder`
///
/// Use `Context::builder().build().unwrap()` for defaults.
///
/// ## Defaults
///
/// * The first avaliable platform
/// * All devices associated with the first available platform
/// * No notify callback function or user data.
///
/// [TODO]:
/// - That stuff above (find a valid context, devices, etc. first thing).
/// - Handle context creation callbacks.
///
pub fn new() -> ContextBuilder {
ContextBuilder {
properties: None,
platform: None,
device_spec: None,
}
}
/// Returns a new `Context` with the parameters hitherinforthto specified (say what?).
///
/// Returns a newly created context with the specified platform and set of device types.
pub fn build(&self) -> OclResult<Context> {
let properties = match self.properties {
Some(ref props) => {
assert!(self.platform.is_none(), "ocl::ContextBuilder::build: Internal error. 'platform' \
and 'properties' have both been set.");
Some(props.clone())
},
None => {
let platform = match self.platform {
Some(ref plat) => plat.clone(),
None => Platform::default(),
};
Some(ContextProperties::new().platform::<PlatformIdCore>(platform.into()))
},
};
Context::new(properties, self.device_spec.clone(), None, None)
}
/// Specifies a platform.
///
/// ## Panics
///
/// Panics if either platform or properties has already been specified.
///
pub fn platform<'a>(&'a mut self, platform: Platform) -> &'a mut ContextBuilder {
assert!(self.platform.is_none(), "ocl::ContextBuilder::platform: Platform already specified");
assert!(self.properties.is_none(), "ocl::ContextBuilder::platform: Properties already specified");
self.platform = Some(platform);
self
}
/// Specify context properties directly.
///
/// ## Panics
///
/// Panics if either properties or platform has already been specified.
///
pub fn properties<'a>(&'a mut self, properties: ContextProperties) -> &'a mut ContextBuilder {
assert!(self.platform.is_none(), "ocl::ContextBuilder::platform: Platform already specified");
assert!(self.properties.is_none(), "ocl::ContextBuilder::platform: Properties already specified");
self.properties = Some(properties);
self
}
/// Specifies a `DeviceSpecifer` which specifies how specifically
/// the relevant devices shall be specified.
///
/// See [`DeviceSpecifier`](/ocl/ocl/enum.DeviceSpecifier.html) for actually
/// useful documentation.
///
/// ## Panics
///
/// Panics if any devices have already been specified.
///
pub fn devices<'a, D: Into<DeviceSpecifier>>(&'a mut self, device_spec: D)
-> &'a mut ContextBuilder
{
assert!(self.device_spec.is_none(), "ocl::ContextBuilder::devices: Devices already specified");
self.device_spec = Some(device_spec.into());
self
}
// // [FIXME: Add these]
//
// pub fn device_idx_round_robin
// pub fn context_idx_round_robin
//
//
}
/// A context for a particular platform and set of device types.
///
/// Thread safety and destruction for any enclosed pointers are all handled automatically.
/// Clone, store, and share between threads to your heart's content.
///
/// [TODO]: Consider removing contained copies of the device id list and
/// platform id. Can be easily ascertained via the API.
///
#[derive(Debug, Clone)]
pub struct Context {
obj_core: ContextCore,
platform: Option<Platform>,
devices: Vec<Device>,
}
impl Context {
/// Returns a [`ContextBuilder`](/ocl/ocl/struct.ContextBuilder.html).
///
/// This is the preferred way to create a Context.
pub fn builder() -> ContextBuilder {
ContextBuilder::new()
}
/// Returns a newly created context.
///
/// Prefer `Context::builder()...` instead of this method unless you know
/// what you're doing. Please also immediately contact us if you do, in
/// fact, know what you're doing so that you can be added to the
/// development team as the one who does.
///
/// ## Defaults
///
/// * The 'NULL' platform (which is not to be relied on but is generally
/// the first avaliable).
/// * All devices associated with the 'NULL' platform
/// * No notify callback function or user data.
///
/// Don't rely on these defaults, instead rely on the `ContextBuilder`
/// defaults. In other words, use: `Context::builder().build().unwrap()`
/// rather than `Context::new(None, None, None, None).unwrap()`.
///
/// ## Panics
///
/// [TEMPORARY] Passing a `Some` variant for `pfn_notify` or `user_data` is
/// not yet supported.
///
pub fn new(properties: Option<ContextProperties>, device_spec: Option<DeviceSpecifier>,
pfn_notify: Option<CreateContextCallbackFn>, user_data: Option<UserDataPtr>)
-> OclResult<Context>
{
assert!(pfn_notify.is_none() && user_data.is_none(),
"Context creation callbacks not yet implemented.");
let platform: Option<Platform> = match properties {
Some(ref props) => props.get_platform().clone().map(|p| Platform::new(p)),
None => None,
};
let device_spec = match device_spec {
Some(ds) => ds,
None => DeviceSpecifier::All,
};
let device_list = try!(device_spec.to_device_list(platform.clone()));
let obj_core = try!(core::create_context(&properties, &device_list, pfn_notify, user_data));
Ok(Context {
obj_core: obj_core,
platform: platform,
devices: device_list,
})
}
/// Resolves a list of zero-based device indices into a list of Devices.
///
/// If any index is out of bounds it will wrap around zero (%) to the next
/// valid device index.
///
pub fn resolve_wrapping_device_idxs(&self, idxs: &[usize]) -> Vec<Device> {
Device::resolve_idxs_wrap(idxs, &self.devices)
}
/// Returns a device by its ordinal count within this context.
///
/// Round-robins (%) to the next valid device.
///
pub fn get_device_by_wrapping_index(&self, index: usize) -> Device {
self.resolve_wrapping_device_idxs(&[index; 1])[0].clone()
}
/// Returns info about the platform associated with the context.
pub fn platform_info(&self, info_kind: PlatformInfo) -> PlatformInfoResult {
// match core::get_platform_info(self.platform_id_core.clone(), info_kind) {
// match core::get_platform_info(self.platform().clone(), info_kind) {
// Ok(pi) => pi,
// Err(err) => PlatformInfoResult::Error(Box::new(err)),
// }
core::get_platform_info(self.platform().clone(), info_kind)
}
/// Returns info about the device indexed by `index` associated with this
/// context.
pub fn device_info(&self, index: usize, info_kind: DeviceInfo) -> DeviceInfoResult {
let device = match self.devices.get(index) {
Some(d) => d,
None => {
return DeviceInfoResult::Error(Box::new(
OclError::new("Context::device_info: Invalid device index")));
},
};
// match core::get_device_info(device, info_kind) {
// Ok(pi) => pi,
// Err(err) => DeviceInfoResult::Error(Box::new(err)),
// }
core::get_device_info(device, info_kind)
}
/// Returns info about the context.
pub fn info(&self, info_kind: ContextInfo) -> ContextInfoResult {
// match core::get_context_info(&self.obj_core, info_kind) {
// Ok(pi) => pi,
// Err(err) => ContextInfoResult::Error(Box::new(err)),
// }
core::get_context_info(&self.obj_core, info_kind)
}
// /// Returns a string containing a formatted list of context properties.
// pub fn to_string(&self) -> String {
// String::new()
// }
/// Returns a reference to the core pointer wrapper, usable by functions in
/// the `core` module.
pub fn core_as_ref(&self) -> &ContextCore {
&self.obj_core
}
/// Returns the list of devices associated with this context.
pub fn devices(&self) -> &[Device] {
&self.devices[..]
}
/// Returns the platform this context is associated with.
pub fn platform(&self) -> Option<Platform> {
self.platform.clone()
}
fn fmt_info(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("Context")
.field("ReferenceCount", &self.info(ContextInfo::ReferenceCount))
.field("Devices", &self.info(ContextInfo::Devices))
.field("Properties", &self.info(ContextInfo::Properties))
.field("NumDevices", &self.info(ContextInfo::NumDevices))
.finish()
}
}
impl std::fmt::Display for Context {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.fmt_info(f)
}
}
impl Deref for Context {
type Target = ContextCore;
fn deref(&self) -> &ContextCore {
&self.obj_core
}
}
impl DerefMut for Context {
fn deref_mut(&mut self) -> &mut ContextCore {
&mut self.obj_core
}
}