      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
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322

    //! An `OpenCL` context.

    use std;
    use std::ops::{Deref, DerefMut};
    use ffi::cl_context;
    use core::{self, Context as ContextCore, ContextProperties, ContextPropertyValue, ContextInfo,
        ContextInfoResult, DeviceInfo, DeviceInfoResult, PlatformInfo, PlatformInfoResult,
        CreateContextCallbackFn, UserDataPtr, OpenclVersion, ClContextPtr, ClVersions};
    use core::error::{Result as OclCoreResult, Error as OclCoreError};
    use error::{Result as OclResult};
    use standard::{Platform, Device, DeviceSpecifier};

    /// 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: Remove contained copies of the device id list and platform id.
    //   Can be easily ascertained via the API. [UPDATE]: devices list removed.
    //   Need to parse the `ContextProperties` out of the
    //   `ContextInfoResult::Properties` before we can eliminate `platform`.
    //
    #[derive(Debug, Clone)]
    pub struct Context(ContextCore);

    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. File an issue if you need this.
        ///
        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 - file issue if you need this.");

            let platform: Option<Platform> = match properties {
                Some(ref props) => props.get_platform().map(Platform::new),
                None => None,
            };

            let device_spec = match device_spec {
                Some(ds) => ds,
                None => DeviceSpecifier::All,
            };

            let device_list = device_spec.to_device_list(platform)?;

            let obj_core = core::create_context(properties.as_ref(), &device_list, pfn_notify, user_data)?;

            Ok(Context(obj_core))
        }

        /// 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]
        }

        /// Returns info about the platform associated with the context.
        pub fn platform_info(&self, info_kind: PlatformInfo) -> OclCoreResult<PlatformInfoResult> {
            match self.platform() {
                Ok(plat_opt) => match plat_opt {
                    Some(ref p) => core::get_platform_info(p, info_kind),
                    None => Err(OclCoreError::from("Context::platform_info: \
                        This context has no associated platform.")),
                },
                Err(err) => Err(OclCoreError::from(err)),
            }
        }

        /// Returns info about the device indexed by `index` associated with this
        /// context.
        pub fn device_info(&self, index: usize, info_kind: DeviceInfo) -> OclCoreResult<DeviceInfoResult> {
            match self.devices().get(index) {
                Some(d) => core::get_device_info(d, info_kind),
                None => {
                    return Err(OclCoreError::from("Context::device_info: Invalid device index"));
                },
            }
        }

        /// Returns info about the context.
        pub fn info(&self, info_kind: ContextInfo) -> OclCoreResult<ContextInfoResult> {
            core::get_context_info(&self.0, info_kind)
        }

        /// Returns a reference to the core pointer wrapper, usable by functions in
        /// the `core` module.
        #[inline]
        pub fn as_core(&self) -> &ContextCore {
            &self.0
        }

        /// Returns the list of devices associated with this context.
        ///
        /// Panics upon any OpenCL error.
        pub fn devices(&self) -> Vec<Device> {
            Device::list_from_core(self.0.devices().unwrap())
        }

        /// Returns the list of device versions associated with this context.
        pub fn device_versions(&self) -> OclCoreResult<Vec<OpenclVersion>> {
            Device::list_from_core(self.0.devices()?).into_iter().map(|d| d.version()).collect()
        }

        /// Returns the platform this context is associated with.
        pub fn platform(&self) -> OclCoreResult<Option<Platform>> {
            self.0.platform().map(|opt| opt.map(Platform::from))
        }

        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 From<ContextCore> for Context {
        fn from(c: ContextCore) -> Context {
            Context(c)
        }
    }

    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.0
        }
    }

    impl DerefMut for Context {
        fn deref_mut(&mut self) -> &mut ContextCore {
            &mut self.0
        }
    }

    unsafe impl<'a> ClContextPtr for &'a Context {
        fn as_ptr(&self) -> cl_context {
            self.0.as_ptr()
        }
    }

    impl ClVersions for Context {
        fn device_versions(&self) -> OclCoreResult<Vec<OpenclVersion>> { self.0.device_versions() }
        fn platform_version(&self) -> OclCoreResult<OpenclVersion> { self.0.platform_version() }
    }

    impl<'a> ClVersions for &'a Context {
        fn device_versions(&self) -> OclCoreResult<Vec<OpenclVersion>> { self.0.device_versions() }
        fn platform_version(&self) -> OclCoreResult<OpenclVersion> { self.0.platform_version() }
    }

    /// A builder for `Context`.
    ///
    // * TODO:
    //   - Handle context creation callbacks.
    //
    #[must_use = "builders do nothing unless '::build' is called"]
    pub struct ContextBuilder {
        properties: ContextProperties,
        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.
        ///
        pub fn new() -> ContextBuilder {
            // Default platform will be set within `::build` if unspecified by that time.
            let properties = ContextProperties::new();

            ContextBuilder {
                properties: properties,
                device_spec: None,
            }
        }

        /// Specifies all context properties directly.
        ///
        /// Overwrites all previously specified properties.
        ///
        pub fn properties<'a>(&'a mut self, properties: ContextProperties) -> &'a mut ContextBuilder {
            self.properties = properties;
            self
        }

        /// Specifies a context property.
        ///
        /// Overwrites any property with the same variant (i.e.: if
        /// `ContextPropertyValue::Platform` was already set, it would be
        /// overwritten if `prop_val` is also `ContextPropertyValue::Platform`).
        ///
        pub fn property<'a>(&'a mut self, prop_val: ContextPropertyValue) -> &'a mut ContextBuilder {
            self.properties.set_property_value(prop_val);
            self
        }

        /// Specifies a platform.
        ///
        /// Overwrites any previously specified platform.
        ///
        pub fn platform(&mut self, platform: Platform) -> &mut ContextBuilder {
            self.properties.set_platform(platform);
            self
        }

        /// Specifies an OpenGL context to associate with.
        ///
        /// Overwrites any previously specified OpenGL context.
        ///
        pub fn gl_context(&mut self, gl_handle: *mut ::ffi::c_void) -> &mut ContextBuilder {
            self.properties.set_gl_context(gl_handle);
            self
        }

        /// Specifies a Display pointer for the GLX context.
        ///
        /// Overwrites any previously specified GLX context.
        ///
        pub fn glx_display(&mut self, glx_display: *mut ::ffi::c_void) -> &mut ContextBuilder {
            self.properties.set_glx_display(glx_display);
            self
        }

        /// Specifies a list of devices with which to associate the context.
        ///
        /// Devices may be specified in any number of ways including simply
        /// passing a device or slice of devices. See the [`impl From`] section of
        /// [`DeviceSpecifier`][device_specifier] for more information.
        ///
        ///
        /// ## Panics
        ///
        /// Devices must not have already been specified.
        ///
        /// [device_specifier_from]: enum.DeviceSpecifier.html#method.from
        /// [device_specifier]: enum.DeviceSpecifier.html
        ///
        pub fn devices<D: Into<DeviceSpecifier>>(&mut self, device_spec: D)
                -> &mut ContextBuilder {
            assert!(self.device_spec.is_none(), "ocl::ContextBuilder::devices: Devices already specified");
            self.device_spec = Some(device_spec.into());
            self
        }

        /// 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.
        ///
        // * TODO:
        //   - Handle context creation callbacks.
        //
        pub fn build(&self) -> OclResult<Context> {
            let mut props = self.properties.clone();

            if props.get_platform().is_none() {
                props.set_platform(Platform::default());
            }

            Context::new(Some(props), self.device_spec.clone(), None, None)
        }
    }

# Help

## Keyboard Shortcuts

`?`
  Show this help dialog
`S`
  Focus the search field
`↑`
  Move up in search results
`↓`
  Move down in search results
`↹`
  Switch tab
`⏎`
  Go to active search result
`+`
  Expand all sections
`-`
  Collapse all sections

## Search Tricks

Prefix searches with a type followed by a colon (e.g. `fn:`) to restrict the search to a given type.

Accepted types are: `fn`, `mod`, `struct`, `enum`, `trait`, `type`, `macro`, and `const`.

Search functions by type signature (e.g. `vec -> usize` or `* -> vec`)