Repository: luqmana/rust-opencl Branch: master Commit: a104f56efb9c Files: 20 Total size: 137.0 KB Directory structure: gitextract_m_jlpnxy/ ├── .gitignore ├── .travis.yml ├── COPYRIGHT ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── Makefile ├── examples/ │ ├── demo/ │ │ ├── demo.ocl │ │ └── main.rs │ └── platform/ │ └── main.rs ├── src/ │ ├── OpenCL/ │ │ └── error.rs │ ├── array.rs │ ├── cl.rs │ ├── error.rs │ ├── ext.rs │ ├── hl.rs │ ├── lib.rs │ ├── mem.rs │ └── util.rs └── tests/ └── test.rs ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *~ *.so *.dylib *.dSYM opencl-test target/ .rust bin/ doc/ Cargo.lock build/ ================================================ FILE: .travis.yml ================================================ language: rust rust: nightly env: global: - secure: TUA5IHO5hwaQvgA1gAvslQ4QWhHEym5bFmmm7nAKHVIxRDchpCmjaLPmu3DirxRJBXi0b5zOZypIH75TMlivfnciQSWr9rj3PaaK+P6LpGScHvYsi/JEawtPJ8V5+xAvOKJ/HsNk5wGS+BBDv4YCPAG5itixMaFxQAVmKw1VMeo= - RUST_THREADS=4 install: - sudo apt-get update - sudo apt-get install fglrx opencl-headers after_script: - curl http://www.rust-ci.org/artifacts/put?t=$RUSTCI_TOKEN | sh ================================================ FILE: COPYRIGHT ================================================ rust-opencl - OpenCL Binding and Higher Level Wrapper for Rust. Copyright (C) 2013 - The rust-opencl Developers Licensed under the Apache License, Version 2.0 or the MIT license , at your option. All files in the project may not be copied, modified, or distributed except according to those terms. Copies of both licenses are included: LICENSE-APACHE and LICENSE-MIT ================================================ FILE: Cargo.toml ================================================ [package] name = "opencl" version = "0.3.0-dev" authors = [ "Colin Sherratt ", "Eric Holk ", "Ian Daniher ", "Luqman Aden ", "Milinda Pathirage ", "Sébastien Crozet ", "Mathijs Henquet " ] repository = "https://github.com/luqmana/rust-opencl" license = "MIT/Apache-2.0" description = "OpenCL bindings for Rust." keywords = ["opencl", "bindings", "ffi", "gpu", "compute"] [lib] name = "opencl" [[example]] name = "demo" path = "examples/demo/main.rs" [[example]] name = "platform" path = "examples/platform/main.rs" [dependencies] log = "^0.3.1" libc = "^0.1.8" ================================================ FILE: LICENSE-APACHE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: LICENSE-MIT ================================================ MIT License http://opensource.org/licenses/MIT Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Makefile ================================================ ifndef RUSTC RUSTC = rustc endif ifndef TARGET_DIR TARGET_DIR = target/ endif RUSTC_OPTS = -g -L $(TARGET_DIR) --out-dir $(TARGET_DIR) OPENCL_SRC = \ lib.rs \ CL.rs \ error.rs \ hl.rs \ util.rs \ mem.rs \ array.rs OPENCL_ROOT = $(shell pwd) .PHONY: all all: lib .PHONY: debug debug: lib demo gdb --cd=./ target/demo .PHONY: lib lib: target_dir $(TARGET_DIR)libopencl.rlib $(TARGET_DIR)libopencl.rlib: src/* rustc $(RUSTC_OPTS) src/lib.rs .PHONY: target_dir target_dir: $(TARGET_DIR) $(TARGET_DIR): mkdir -p $(TARGET_DIR) .PHONY: demo demo: target_dir $(TARGET_DIR)demo $(TARGET_DIR)demo: $(TARGET_DIR)libopencl.rlib test/demo.rs env OPENCL_ROOT=$(OPENCL_ROOT) rustc $(RUSTC_OPTS) test/demo.rs .PHONY: check check: lib rustc $(RUSTC_OPTS) --test test/test.rs $(TARGET_DIR)test .PHONY: clean clean: rm -rf $(TARGET_DIR) .PHONY: docs docs: rustdoc src/lib.rs ================================================ FILE: examples/demo/demo.ocl ================================================ __kernel void vector_add(__global const long *A, __global const long *B, __global long *C) { int i = get_global_id(0); C[i] = A[i] + B[i]; } ================================================ FILE: examples/demo/main.rs ================================================ extern crate opencl; use opencl::mem::CLBuffer; use std::fmt; fn main() { let ker = include_str!("demo.ocl"); println!("ker {}", ker); let vec_a = vec![0isize, 1, 2, -3, 4, 5, 6, 7]; let vec_b = vec![-7isize, -6, 5, -4, 0, -1, 2, 3]; let (device, ctx, queue) = opencl::util::create_compute_context().unwrap(); println!("{}", device.name()); let a: CLBuffer = ctx.create_buffer(vec_a.len(), opencl::cl::CL_MEM_READ_ONLY); let b: CLBuffer = ctx.create_buffer(vec_a.len(), opencl::cl::CL_MEM_READ_ONLY); let c: CLBuffer = ctx.create_buffer(vec_a.len(), opencl::cl::CL_MEM_WRITE_ONLY); queue.write(&a, &&vec_a[..], ()); queue.write(&b, &&vec_b[..], ()); let program = ctx.create_program_from_source(ker); program.build(&device).ok().expect("Couldn't build program."); let kernel = program.create_kernel("vector_add"); kernel.set_arg(0, &a); kernel.set_arg(1, &b); kernel.set_arg(2, &c); let event = queue.enqueue_async_kernel(&kernel, vec_a.len(), None, ()); let vec_c: Vec = queue.get(&c, &event); println!(" {}", string_from_slice(&vec_a[..])); println!("+ {}", string_from_slice(&vec_b[..])); println!("= {}", string_from_slice(&vec_c[..])); } fn string_from_slice(slice: &[T]) -> String { let mut st = String::from("["); let mut first = true; for i in slice.iter() { if !first { st.push_str(", "); } else { first = false; } st.push_str(&*i.to_string()) } st.push_str("]"); return st } ================================================ FILE: examples/platform/main.rs ================================================ extern crate opencl; use opencl::hl; fn main() { for platform in hl::get_platforms().iter() { println!("Platform: {}", platform.name()); println!("Platform Version: {}", platform.version()); println!("Vendor: {}", platform.vendor()); println!("Profile: {}", platform.profile()); println!("Available extensions: {}", platform.extensions()); println!("Available devices:"); for device in platform.get_devices().iter() { println!(" Name: {}", device.name()); println!(" Type: {}", device.device_type()); println!(" Profile: {}", device.profile()); println!(" Compute Units: {}", device.compute_units()); } } } ================================================ FILE: src/OpenCL/error.rs ================================================ //! Error handling utilities. use CL::*; use std::fmt::{Show, Formatter, Result}; impl Show for CLStatus { fn fmt(&self, f: &mut Formatter) -> Result { write!(f.buf, "{:?}", *self) } } macro_rules! convert( ($e: expr, $x: ident) => (if $e == $x as cl_int { Some($x) } else { None }); ($e: expr, $x: ident, $($xs: ident),+) => (if $e == $x as cl_int { Some($x) } else { convert!($e, $($xs),+) }) ) pub fn try_convert(status: cl_int) -> Option { convert!(status, CL_SUCCESS, CL_DEVICE_NOT_FOUND, CL_DEVICE_NOT_AVAILABLE, CL_COMPILER_NOT_AVAILABLE, CL_MEM_OBJECT_ALLOCATION_FAILURE, CL_OUT_OF_RESOURCES, CL_OUT_OF_HOST_MEMORY, CL_PROFILING_INFO_NOT_AVAILABLE, CL_MEM_COPY_OVERLAP, CL_IMAGE_FORMAT_MISMATCH, CL_IMAGE_FORMAT_NOT_SUPPORTED, CL_BUILD_PROGRAM_FAILURE, CL_MAP_FAILURE, CL_MISALIGNED_SUB_BUFFER_OFFSET, CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST, CL_INVALID_VALUE, CL_INVALID_DEVICE_TYPE, CL_INVALID_PLATFORM, CL_INVALID_DEVICE, CL_INVALID_CONTEXT, CL_INVALID_QUEUE_PROPERTIES, CL_INVALID_COMMAND_QUEUE, CL_INVALID_HOST_PTR, CL_INVALID_MEM_OBJECT, CL_INVALID_IMAGE_FORMAT_DESCRIPTOR, CL_INVALID_IMAGE_SIZE, CL_INVALID_SAMPLER, CL_INVALID_BINARY, CL_INVALID_BUILD_OPTIONS, CL_INVALID_PROGRAM, CL_INVALID_PROGRAM_EXECUTABLE, CL_INVALID_KERNEL_NAME, CL_INVALID_KERNEL_DEFINITION, CL_INVALID_KERNEL, CL_INVALID_ARG_INDEX, CL_INVALID_ARG_VALUE, CL_INVALID_ARG_SIZE, CL_INVALID_KERNEL_ARGS, CL_INVALID_WORK_DIMENSION, CL_INVALID_WORK_GROUP_SIZE, CL_INVALID_WORK_ITEM_SIZE, CL_INVALID_GLOBAL_OFFSET, CL_INVALID_EVENT_WAIT_LIST, CL_INVALID_EVENT, CL_INVALID_OPERATION, CL_INVALID_GL_OBJECT, CL_INVALID_BUFFER_SIZE, CL_INVALID_MIP_LEVEL, CL_INVALID_GLOBAL_WORK_SIZE, CL_INVALID_PROPERTY) } pub fn convert(status: cl_int) -> CLStatus { match try_convert(status) { Some(s) => s, None => fail!(format!("Unknown OpenCL Status Code: {:?}", status)) } } fn error_str(status: cl_int) -> ~str { match try_convert(status) { Some(s) => s.to_str(), None => format!("Unknown Error: {:?}", status) } } pub fn check(status: cl_int, message: &str) { if status != CL_SUCCESS as cl_int { fail!(format!("{:?} ({:?})", message, error_str(status))) } } ================================================ FILE: src/array.rs ================================================ //! Two- and three-dimensional array support. use cl::*; use cl::ll::*; use mem::*; use std::marker::PhantomData; use std::mem; use std::vec::Vec; use libc::{size_t, c_void}; use hl::KernelArg; pub struct Array3D { width: usize, height: usize, depth: usize, dat: Vec } pub struct Array3DCL { width: usize, height: usize, depth: usize, buf: cl_mem, phantom: PhantomData, } impl Array3D { pub fn new(width: usize, height: usize, depth: usize, val: F) -> Array3D where F: Fn(usize, usize, usize) -> T { let mut dat: Vec = Vec::new(); for x in 0 .. width { for y in 0 .. height { for z in 0 .. depth { dat.push(val(x, y, z)); } } } Array3D { width: width, height: height, depth: depth, dat: dat } } pub fn set(&mut self, x: usize, y: usize, z: usize, val: T) { self.dat[self.width*self.height*z + self.width*y + x] = val; } pub fn get(&self, x: usize, y: usize, z: usize) -> T { (&self.dat[..])[self.width*self.height*z + self.width*y + x].clone() } } impl Drop for Array3DCL { fn drop(&mut self) { unsafe { clReleaseMemObject(self.buf); } } } impl<'r, T> Put, Array3DCL> for &'r Array3D { fn put(&self, f: F) -> Array3DCL where F: FnOnce(*const c_void, size_t) -> cl_mem { let p = self.dat.as_ptr(); let len = self.dat.len(); let out = f(p as *const c_void, (len * mem::size_of::()) as size_t); Array3DCL{ width: self.width, height: self.height, depth: self.depth, buf: out, phantom: PhantomData, } } } impl Get, Array3D> for Array3D { fn get(arr: &Array3DCL, f: F) -> Array3D where F: FnOnce(size_t, *mut c_void, size_t) { let mut v: Vec = Vec::with_capacity(arr.len()); unsafe { v.set_len(arr.len()); } let p = v.as_mut_ptr(); let len = v.len(); f(0, p as *mut c_void, (len * mem::size_of::()) as size_t); Array3D { width: arr.width, height: arr.height, depth: arr.depth, dat: v, } } } impl Write for Array3D { fn write(&self, f: F) where F: FnOnce(size_t, *const c_void, size_t) { let p = self.dat.as_ptr(); let len = self.dat.len(); f(0, p as *const c_void, (len * mem::size_of::()) as size_t) } } impl Read for Array3D { fn read(&mut self, f: F) where F: FnOnce(size_t, *mut c_void, size_t) { let p = self.dat.as_ptr(); let len = self.dat.len(); f(0, p as *mut c_void, (len * mem::size_of::()) as size_t) } } impl Buffer for Array3DCL { unsafe fn id_ptr(&self) -> *const cl_mem { &self.buf as *const cl_mem } fn len(&self) -> usize { self.width * self.height * self.depth } } impl KernelArg for Array3DCL { fn get_value(&self) -> (size_t, *const c_void) { (mem::size_of::() as size_t, unsafe { self.id_ptr() } as *const c_void) } } pub struct Array2D { width: usize, height: usize, dat: Vec, } pub struct Array2DCL { width: usize, height: usize, buf: cl_mem, phantom: PhantomData, } impl Array2D { pub fn new(width: usize, height: usize, val: F) -> Array2D where F: Fn(usize, usize) -> T { let mut dat: Vec = Vec::new(); for x in 0 .. width { for y in 0 .. height { dat.push(val(x, y)); } } Array2D { width: width, height: height, dat: dat, } } pub fn set(&mut self, x: usize, y: usize, val: T) { self.dat[self.width*y + x] = val; } pub fn get(&self, x: usize, y: usize) -> T { (&self.dat[..])[self.width*y + x].clone() } } impl Drop for Array2DCL { fn drop(&mut self) { unsafe { clReleaseMemObject(self.buf); } } } impl<'r, T> Put, Array2DCL> for &'r Array2D { fn put(&self, f: F) -> Array2DCL where F: FnOnce(*const c_void, size_t) -> cl_mem { let p = self.dat.as_ptr(); let len = self.dat.len(); let out = f(p as *const c_void, (len * mem::size_of::()) as size_t); Array2DCL{ width: self.width, height: self.height, buf: out, phantom: PhantomData, } } } impl Get, Array2D> for Array2D { fn get(arr: &Array2DCL, f: F) -> Array2D where F: FnOnce(size_t, *mut c_void, size_t) { let mut v: Vec = Vec::with_capacity(arr.len()); unsafe { v.set_len(arr.len()) } let p = v.as_mut_ptr(); let len = v.len(); f(0, p as *mut c_void, (len * mem::size_of::()) as size_t); Array2D { width: arr.width, height: arr.height, dat: v } } } impl Write for Array2D { fn write(&self, f: F) where F: FnOnce(size_t, *const c_void, size_t) { let p = self.dat.as_ptr(); let len = self.dat.len(); f(0, p as *const c_void, (len * mem::size_of::()) as size_t) } } impl Read for Array2D { fn read(&mut self, f: F) where F: FnOnce(size_t, *mut c_void, size_t) { let p = self.dat.as_ptr(); let len = self.dat.len(); f(0, p as *mut c_void, (len * mem::size_of::()) as size_t) } } impl Buffer for Array2DCL { unsafe fn id_ptr(&self) -> *const cl_mem { &self.buf as *const cl_mem } fn len(&self) -> usize { self.width * self.height } } impl KernelArg for Array2DCL { fn get_value(&self) -> (size_t, *const c_void) { (mem::size_of::() as size_t, unsafe { self.id_ptr() } as *const c_void) } } ================================================ FILE: src/cl.rs ================================================ #![allow(non_camel_case_types, dead_code)] extern crate std; use libc; use std::fmt; /* Opaque types */ pub type cl_platform_id = *mut libc::c_void; pub type cl_device_id = *mut libc::c_void; pub type cl_context = *mut libc::c_void; pub type cl_command_queue = *mut libc::c_void; pub type cl_mem = *mut libc::c_void; pub type cl_program = *mut libc::c_void; pub type cl_kernel = *mut libc::c_void; pub type cl_event = *mut libc::c_void; pub type cl_sampler = *mut libc::c_void; /* Scalar types */ pub type cl_char = i8; pub type cl_uchar = u8; pub type cl_short = i16; pub type cl_ushort = u16; pub type cl_int = i32; pub type cl_uint = u32; pub type cl_long = i64; pub type cl_ulong = u64; pub type cl_half = u16; pub type cl_float = f32; pub type cl_double = f64; pub type cl_bool = cl_uint; pub type cl_bitfield = cl_ulong; pub type cl_device_type = cl_bitfield; pub type cl_platform_info = cl_uint; pub type cl_device_info = cl_uint; pub type cl_device_fp_config = cl_bitfield; pub type cl_device_mem_cache_type = cl_uint; pub type cl_device_local_mem_type = cl_uint; pub type cl_device_exec_capabilities = cl_bitfield; pub type cl_command_queue_properties = cl_bitfield; pub type cl_context_properties = libc::intptr_t; pub type cl_context_info = cl_uint; pub type cl_command_queue_info = cl_uint; pub type cl_channel_order = cl_uint; pub type cl_channel_type = cl_uint; pub type cl_mem_flags = cl_bitfield; pub type cl_mem_object_type = cl_uint; pub type cl_mem_info = cl_uint; pub type cl_image_info = cl_uint; pub type cl_buffer_create_type = cl_uint; pub type cl_addressing_mode = cl_uint; pub type cl_filter_mode = cl_uint; pub type cl_sampler_info = cl_uint; pub type cl_map_flags = cl_bitfield; pub type cl_program_info = cl_uint; pub type cl_program_build_info = cl_uint; pub type cl_build_status = cl_int; pub type cl_kernel_info = cl_uint; pub type cl_kernel_work_group_info = cl_uint; pub type cl_event_info = cl_uint; pub type cl_command_type = cl_uint; pub type cl_profiling_info = cl_uint; pub struct cl_image_format { image_channel_order: cl_channel_order, image_channel_data_type: cl_channel_type } pub struct cl_buffer_region { origin: libc::size_t, size: libc::size_t } /// OpenCL error codes. #[derive(PartialEq, Debug)] #[repr()] pub enum CLStatus { CL_SUCCESS = 0, CL_DEVICE_NOT_FOUND = -1, CL_DEVICE_NOT_AVAILABLE = -2, CL_COMPILER_NOT_AVAILABLE = -3, CL_MEM_OBJECT_ALLOCATION_FAILURE = -4, CL_OUT_OF_RESOURCES = -5, CL_OUT_OF_HOST_MEMORY = -6, CL_PROFILING_INFO_NOT_AVAILABLE = -7, CL_MEM_COPY_OVERLAP = -8, CL_IMAGE_FORMAT_MISMATCH = -9, CL_IMAGE_FORMAT_NOT_SUPPORTED = -10, CL_BUILD_PROGRAM_FAILURE = -11, CL_MAP_FAILURE = -12, CL_MISALIGNED_SUB_BUFFER_OFFSET = -13, CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST = -14, CL_INVALID_VALUE = -30, CL_INVALID_DEVICE_TYPE = -31, CL_INVALID_PLATFORM = -32, CL_INVALID_DEVICE = -33, CL_INVALID_CONTEXT = -34, CL_INVALID_QUEUE_PROPERTIES = -35, CL_INVALID_COMMAND_QUEUE = -36, CL_INVALID_HOST_PTR = -37, CL_INVALID_MEM_OBJECT = -38, CL_INVALID_IMAGE_FORMAT_DESCRIPTOR = -39, CL_INVALID_IMAGE_SIZE = -40, CL_INVALID_SAMPLER = -41, CL_INVALID_BINARY = -42, CL_INVALID_BUILD_OPTIONS = -43, CL_INVALID_PROGRAM = -44, CL_INVALID_PROGRAM_EXECUTABLE = -45, CL_INVALID_KERNEL_NAME = -46, CL_INVALID_KERNEL_DEFINITION = -47, CL_INVALID_KERNEL = -48, CL_INVALID_ARG_INDEX = -49, CL_INVALID_ARG_VALUE = -50, CL_INVALID_ARG_SIZE = -51, CL_INVALID_KERNEL_ARGS = -52, CL_INVALID_WORK_DIMENSION = -53, CL_INVALID_WORK_GROUP_SIZE = -54, CL_INVALID_WORK_ITEM_SIZE = -55, CL_INVALID_GLOBAL_OFFSET = -56, CL_INVALID_EVENT_WAIT_LIST = -57, CL_INVALID_EVENT = -58, CL_INVALID_OPERATION = -59, CL_INVALID_GL_OBJECT = -60, CL_INVALID_BUFFER_SIZE = -61, CL_INVALID_MIP_LEVEL = -62, CL_INVALID_GLOBAL_WORK_SIZE = -63, CL_INVALID_PROPERTY = -64, CL_PLATFORM_NOT_FOUND_KHR = -1001, } impl fmt::Display for CLStatus { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?}", self) } } /* OpenCL Version */ pub static CL_VERSION_1_0: cl_bool = 1; pub static CL_VERSION_1_1: cl_bool = 1; /* cl_bool */ pub static CL_FALSE: cl_bool = 0; pub static CL_TRUE: cl_bool = 1; /* cl_platform_info */ pub static CL_PLATFORM_PROFILE: cl_uint = 0x0900; pub static CL_PLATFORM_VERSION: cl_uint = 0x0901; pub static CL_PLATFORM_NAME: cl_uint = 0x0902; pub static CL_PLATFORM_VENDOR: cl_uint = 0x0903; pub static CL_PLATFORM_EXTENSIONS: cl_uint = 0x0904; /* cl_device_type - bitfield */ pub static CL_DEVICE_TYPE_DEFAULT: cl_bitfield = 1 << 0; pub static CL_DEVICE_TYPE_CPU: cl_bitfield = 1 << 1; pub static CL_DEVICE_TYPE_GPU: cl_bitfield = 1 << 2; pub static CL_DEVICE_TYPE_ACCELERATOR: cl_bitfield = 1 << 3; pub static CL_DEVICE_TYPE_ALL: cl_bitfield = 0xFFFFFFFF; /* cl_device_info */ pub static CL_DEVICE_TYPE: cl_uint = 0x1000; pub static CL_DEVICE_VENDOR_ID: cl_uint = 0x1001; pub static CL_DEVICE_MAX_COMPUTE_UNITS: cl_uint = 0x1002; pub static CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS: cl_uint = 0x1003; pub static CL_DEVICE_MAX_WORK_GROUP_SIZE: cl_uint = 0x1004; pub static CL_DEVICE_MAX_WORK_ITEM_SIZES: cl_uint = 0x1005; pub static CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR: cl_uint = 0x1006; pub static CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT: cl_uint = 0x1007; pub static CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT: cl_uint = 0x1008; pub static CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG: cl_uint = 0x1009; pub static CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT: cl_uint = 0x100A; pub static CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE: cl_uint = 0x100B; pub static CL_DEVICE_MAX_CLOCK_FREQUENCY: cl_uint = 0x100C; pub static CL_DEVICE_ADDRESS_BITS: cl_uint = 0x100D; pub static CL_DEVICE_MAX_READ_IMAGE_ARGS: cl_uint = 0x100E; pub static CL_DEVICE_MAX_WRITE_IMAGE_ARGS: cl_uint = 0x100F; pub static CL_DEVICE_MAX_MEM_ALLOC_SIZE: cl_uint = 0x1010; pub static CL_DEVICE_IMAGE2D_MAX_WIDTH: cl_uint = 0x1011; pub static CL_DEVICE_IMAGE2D_MAX_HEIGHT: cl_uint = 0x1012; pub static CL_DEVICE_IMAGE3D_MAX_WIDTH: cl_uint = 0x1013; pub static CL_DEVICE_IMAGE3D_MAX_HEIGHT: cl_uint = 0x1014; pub static CL_DEVICE_IMAGE3D_MAX_DEPTH: cl_uint = 0x1015; pub static CL_DEVICE_IMAGE_SUPPORT: cl_uint = 0x1016; pub static CL_DEVICE_MAX_PARAMETER_SIZE: cl_uint = 0x1017; pub static CL_DEVICE_MAX_SAMPLERS: cl_uint = 0x1018; pub static CL_DEVICE_MEM_BASE_ADDR_ALIGN: cl_uint = 0x1019; pub static CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE: cl_uint = 0x101A; pub static CL_DEVICE_SINGLE_FP_CONFIG: cl_uint = 0x101B; pub static CL_DEVICE_GLOBAL_MEM_CACHE_TYPE: cl_uint = 0x101C; pub static CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE: cl_uint = 0x101D; pub static CL_DEVICE_GLOBAL_MEM_CACHE_SIZE: cl_uint = 0x101E; pub static CL_DEVICE_GLOBAL_MEM_SIZE: cl_uint = 0x101F; pub static CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE: cl_uint = 0x1020; pub static CL_DEVICE_MAX_CONSTANT_ARGS: cl_uint = 0x1021; pub static CL_DEVICE_LOCAL_MEM_TYPE: cl_uint = 0x1022; pub static CL_DEVICE_LOCAL_MEM_SIZE: cl_uint = 0x1023; pub static CL_DEVICE_ERROR_CORRECTION_SUPPORT: cl_uint = 0x1024; pub static CL_DEVICE_PROFILING_TIMER_RESOLUTION: cl_uint = 0x1025; pub static CL_DEVICE_ENDIAN_LITTLE: cl_uint = 0x1026; pub static CL_DEVICE_AVAILABLE: cl_uint = 0x1027; pub static CL_DEVICE_COMPILER_AVAILABLE: cl_uint = 0x1028; pub static CL_DEVICE_EXECUTION_CAPABILITIES: cl_uint = 0x1029; pub static CL_DEVICE_QUEUE_PROPERTIES: cl_uint = 0x102A; pub static CL_DEVICE_NAME: cl_uint = 0x102B; pub static CL_DEVICE_VENDOR: cl_uint = 0x102C; pub static CL_DRIVER_VERSION: cl_uint = 0x102D; pub static CL_DEVICE_PROFILE: cl_uint = 0x102E; pub static CL_DEVICE_VERSION: cl_uint = 0x102F; pub static CL_DEVICE_EXTENSIONS: cl_uint = 0x1030; pub static CL_DEVICE_PLATFORM: cl_uint = 0x1031; /* 0x1032 reserved for CL_DEVICE_DOUBLE_FP_CONFIG */ /* 0x1033 reserved for CL_DEVICE_HALF_FP_CONFIG */ pub static CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF: cl_uint = 0x1034; pub static CL_DEVICE_HOST_UNIFIED_MEMORY: cl_uint = 0x1035; pub static CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR: cl_uint = 0x1036; pub static CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT: cl_uint = 0x1037; pub static CL_DEVICE_NATIVE_VECTOR_WIDTH_INT: cl_uint = 0x1038; pub static CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG: cl_uint = 0x1039; pub static CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT: cl_uint = 0x103A; pub static CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE: cl_uint = 0x103B; pub static CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF: cl_uint = 0x103C; pub static CL_DEVICE_OPENCL_C_VERSION: cl_uint = 0x103D; /* cl_device_fp_config - bitfield */ pub static CL_FP_DENORM: cl_bitfield = 1 << 0; pub static CL_FP_INF_NAN: cl_bitfield = 1 << 1; pub static CL_FP_ROUND_TO_NEAREST: cl_bitfield = 1 << 2; pub static CL_FP_ROUND_TO_ZERO: cl_bitfield = 1 << 3; pub static CL_FP_ROUND_TO_INF: cl_bitfield = 1 << 4; pub static CL_FP_FMA: cl_bitfield = 1 << 5; pub static CL_FP_SOFT_FLOAT: cl_bitfield = 1 << 6; /* cl_device_mem_cache_type */ pub static CL_NONE: cl_uint = 0x0; pub static CL_READ_ONLY_CACHE: cl_uint = 0x1; pub static CL_READ_WRITE_CACHE: cl_uint = 0x2; /* cl_device_local_mem_type */ pub static CL_LOCAL: cl_uint = 0x1; pub static CL_GLOBAL: cl_uint = 0x2; /* cl_device_exec_capabilities - bitfield */ pub static CL_EXEC_KERNEL: cl_bitfield = 1 << 0; pub static CL_EXEC_NATIVE_KERNEL: cl_bitfield = 1 << 1; /* cl_command_queue_properties - bitfield */ pub static CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE: cl_bitfield = 1 << 0; pub static CL_QUEUE_PROFILING_ENABLE: cl_bitfield = 1 << 1; /* cl_context_info */ pub static CL_CONTEXT_REFERENCE_COUNT: cl_uint = 0x1080; pub static CL_CONTEXT_DEVICES: cl_uint = 0x1081; pub static CL_CONTEXT_PROPERTIES: cl_uint = 0x1082; pub static CL_CONTEXT_NUM_DEVICES: cl_uint = 0x1083; /* cl_context_info + cl_context_properties */ pub static CL_CONTEXT_PLATFORM: libc::intptr_t = 0x1084; /* cl_command_queue_info */ pub static CL_QUEUE_CONTEXT: cl_uint = 0x1090; pub static CL_QUEUE_DEVICE: cl_uint = 0x1091; pub static CL_QUEUE_REFERENCE_COUNT: cl_uint = 0x1092; pub static CL_QUEUE_PROPERTIES: cl_uint = 0x1093; /* cl_mem_flags - bitfield */ pub static CL_MEM_READ_WRITE: cl_bitfield = 1 << 0; pub static CL_MEM_WRITE_ONLY: cl_bitfield = 1 << 1; pub static CL_MEM_READ_ONLY: cl_bitfield = 1 << 2; pub static CL_MEM_USE_HOST_PTR: cl_bitfield = 1 << 3; pub static CL_MEM_ALLOC_HOST_PTR: cl_bitfield = 1 << 4; pub static CL_MEM_COPY_HOST_PTR: cl_bitfield = 1 << 5; /* cl_channel_order */ pub static CL_R: cl_uint = 0x10B0; pub static CL_A: cl_uint = 0x10B1; pub static CL_RG: cl_uint = 0x10B2; pub static CL_RA: cl_uint = 0x10B3; pub static CL_RGB: cl_uint = 0x10B4; pub static CL_RGBA: cl_uint = 0x10B5; pub static CL_BGRA: cl_uint = 0x10B6; pub static CL_ARGB: cl_uint = 0x10B7; pub static CL_INTENSITY: cl_uint = 0x10B8; pub static CL_LUMINANCE: cl_uint = 0x10B9; pub static CL_Rx: cl_uint = 0x10BA; pub static CL_RGx: cl_uint = 0x10BB; pub static CL_RGBx: cl_uint = 0x10BC; /* cl_channel_type */ pub static CL_SNORM_INT8: cl_uint = 0x10D0; pub static CL_SNORM_INT16: cl_uint = 0x10D1; pub static CL_UNORM_INT8: cl_uint = 0x10D2; pub static CL_UNORM_INT16: cl_uint = 0x10D3; pub static CL_UNORM_SHORT_565: cl_uint = 0x10D4; pub static CL_UNORM_SHORT_555: cl_uint = 0x10D5; pub static CL_UNORM_INT_101010: cl_uint = 0x10D6; pub static CL_SIGNED_INT8: cl_uint = 0x10D7; pub static CL_SIGNED_INT16: cl_uint = 0x10D8; pub static CL_SIGNED_INT32: cl_uint = 0x10D9; pub static CL_UNSIGNED_INT8: cl_uint = 0x10DA; pub static CL_UNSIGNED_INT16: cl_uint = 0x10DB; pub static CL_UNSIGNED_INT32: cl_uint = 0x10DC; pub static CL_HALF_FLOAT: cl_uint = 0x10DD; pub static CL_FLOAT: cl_uint = 0x10DE; /* cl_mem_object_type */ pub static CL_MEM_OBJECT_BUFFER: cl_uint = 0x10F0; pub static CL_MEM_OBJECT_IMAGE2D: cl_uint = 0x10F1; pub static CL_MEM_OBJECT_IMAGE3D: cl_uint = 0x10F2; /* cl_mem_info */ pub static CL_MEM_TYPE: cl_uint = 0x1100; pub static CL_MEM_FLAGS: cl_uint = 0x1101; pub static CL_MEM_SIZE: cl_uint = 0x1102; pub static CL_MEM_HOST_PTR: cl_uint = 0x1103; pub static CL_MEM_MAP_COUNT: cl_uint = 0x1104; pub static CL_MEM_REFERENCE_COUNT: cl_uint = 0x1105; pub static CL_MEM_CONTEXT: cl_uint = 0x1106; pub static CL_MEM_ASSOCIATED_MEMOBJECT: cl_uint = 0x1107; pub static CL_MEM_OFFSET: cl_uint = 0x1108; /* cl_image_info */ pub static CL_IMAGE_FORMAT: cl_uint = 0x1110; pub static CL_IMAGE_ELEMENT_SIZE: cl_uint = 0x1111; pub static CL_IMAGE_ROW_PITCH: cl_uint = 0x1112; pub static CL_IMAGE_SLICE_PITCH: cl_uint = 0x1113; pub static CL_IMAGE_WIDTH: cl_uint = 0x1114; pub static CL_IMAGE_HEIGHT: cl_uint = 0x1115; pub static CL_IMAGE_DEPTH: cl_uint = 0x1116; /* cl_addressing_mode */ pub static CL_ADDRESS_NONE: cl_uint = 0x1130; pub static CL_ADDRESS_CLAMP_TO_EDGE: cl_uint = 0x1131; pub static CL_ADDRESS_CLAMP: cl_uint = 0x1132; pub static CL_ADDRESS_REPEAT: cl_uint = 0x1133; pub static CL_ADDRESS_MIRRORED_REPEAT: cl_uint = 0x1134; /* cl_filter_mode */ pub static CL_FILTER_NEAREST: cl_uint = 0x1140; pub static CL_FILTER_LINEAR: cl_uint = 0x1141; /* cl_sampler_info */ pub static CL_SAMPLER_REFERENCE_COUNT: cl_uint = 0x1150; pub static CL_SAMPLER_CONTEXT: cl_uint = 0x1151; pub static CL_SAMPLER_NORMALIZED_COORDS: cl_uint = 0x1152; pub static CL_SAMPLER_ADDRESSING_MODE: cl_uint = 0x1153; pub static CL_SAMPLER_FILTER_MODE: cl_uint = 0x1154; /* cl_map_flags - bitfield */ pub static CL_MAP_READ: cl_bitfield = 1 << 0; pub static CL_MAP_WRITE: cl_bitfield = 1 << 1; /* cl_program_info */ pub static CL_PROGRAM_REFERENCE_COUNT: cl_uint = 0x1160; pub static CL_PROGRAM_CONTEXT: cl_uint = 0x1161; pub static CL_PROGRAM_NUM_DEVICES: cl_uint = 0x1162; pub static CL_PROGRAM_DEVICES: cl_uint = 0x1163; pub static CL_PROGRAM_SOURCE: cl_uint = 0x1164; pub static CL_PROGRAM_BINARY_SIZES: cl_uint = 0x1165; pub static CL_PROGRAM_BINARIES: cl_uint = 0x1166; /* cl_program_build_info */ pub static CL_PROGRAM_BUILD_STATUS: cl_uint = 0x1181; pub static CL_PROGRAM_BUILD_OPTIONS: cl_uint = 0x1182; pub static CL_PROGRAM_BUILD_LOG: cl_uint = 0x1183; /* cl_build_status */ pub static CL_BUILD_SUCCESS: cl_uint = 0; pub static CL_BUILD_NONE: cl_uint = (-1isize) as cl_uint; pub static CL_BUILD_ERROR: cl_uint = -2isize as cl_uint; pub static CL_BUILD_IN_PROGRESS: cl_uint = -3isize as cl_uint; /* cl_kernel_info */ pub static CL_KERNEL_FUNCTION_NAME: cl_uint = 0x1190; pub static CL_KERNEL_NUM_ARGS: cl_uint = 0x1191; pub static CL_KERNEL_REFERENCE_COUNT: cl_uint = 0x1192; pub static CL_KERNEL_CONTEXT: cl_uint = 0x1193; pub static CL_KERNEL_PROGRAM: cl_uint = 0x1194; /* cl_kernel_work_group_info */ pub static CL_KERNEL_WORK_GROUP_SIZE: cl_uint = 0x11B0; pub static CL_KERNEL_COMPILE_WORK_GROUP_SIZE: cl_uint = 0x11B1; pub static CL_KERNEL_LOCAL_MEM_SIZE: cl_uint = 0x11B2; pub static CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE: cl_uint = 0x11B3; pub static CL_KERNEL_PRIVATE_MEM_SIZE: cl_uint = 0x11B4; /* cl_event_info */ pub static CL_EVENT_COMMAND_QUEUE: cl_uint = 0x11D0; pub static CL_EVENT_COMMAND_TYPE: cl_uint = 0x11D1; pub static CL_EVENT_REFERENCE_COUNT: cl_uint = 0x11D2; pub static CL_EVENT_COMMAND_EXECUTION_STATUS: cl_uint = 0x11D3; pub static CL_EVENT_CONTEXT: cl_uint = 0x11D4; /* cl_command_type */ pub static CL_COMMAND_NDRANGE_KERNEL: cl_uint = 0x11F0; pub static CL_COMMAND_TASK: cl_uint = 0x11F1; pub static CL_COMMAND_NATIVE_KERNEL: cl_uint = 0x11F2; pub static CL_COMMAND_READ_BUFFER: cl_uint = 0x11F3; pub static CL_COMMAND_WRITE_BUFFER: cl_uint = 0x11F4; pub static CL_COMMAND_COPY_BUFFER: cl_uint = 0x11F5; pub static CL_COMMAND_READ_IMAGE: cl_uint = 0x11F6; pub static CL_COMMAND_WRITE_IMAGE: cl_uint = 0x11F7; pub static CL_COMMAND_COPY_IMAGE: cl_uint = 0x11F8; pub static CL_COMMAND_COPY_IMAGE_TO_BUFFER: cl_uint = 0x11F9; pub static CL_COMMAND_COPY_BUFFER_TO_IMAGE: cl_uint = 0x11FA; pub static CL_COMMAND_MAP_BUFFER: cl_uint = 0x11FB; pub static CL_COMMAND_MAP_IMAGE: cl_uint = 0x11FC; pub static CL_COMMAND_UNMAP_MEM_OBJECT: cl_uint = 0x11FD; pub static CL_COMMAND_MARKER: cl_uint = 0x11FE; pub static CL_COMMAND_ACQUIRE_GL_OBJECTS: cl_uint = 0x11FF; pub static CL_COMMAND_RELEASE_GL_OBJECTS: cl_uint = 0x1200; pub static CL_COMMAND_READ_BUFFER_RECT: cl_uint = 0x1201; pub static CL_COMMAND_WRITE_BUFFER_RECT: cl_uint = 0x1202; pub static CL_COMMAND_COPY_BUFFER_RECT: cl_uint = 0x1203; pub static CL_COMMAND_USER: cl_uint = 0x1204; /* command execution status */ pub static CL_COMPLETE: cl_uint = 0x0; pub static CL_RUNNING: cl_uint = 0x1; pub static CL_SUBMITTED: cl_uint = 0x2; pub static CL_QUEUED: cl_uint = 0x3; /* cl_buffer_create_type */ pub static CL_BUFFER_CREATE_TYPE_REGION: cl_uint = 0x1220; /* cl_profiling_info */ pub static CL_PROFILING_COMMAND_QUEUED: cl_uint = 0x1280; pub static CL_PROFILING_COMMAND_SUBMIT: cl_uint = 0x1281; pub static CL_PROFILING_COMMAND_START: cl_uint = 0x1282; pub static CL_PROFILING_COMMAND_END: cl_uint = 0x1283; pub mod ll { use cl::*; use libc; extern { /* Platform APIs */ pub fn clGetPlatformIDs(num_entries: cl_uint, platforms: *mut cl_platform_id, num_platforms: *mut cl_uint) -> cl_int; pub fn clGetPlatformInfo(platform: cl_platform_id, param_name: cl_platform_info, param_value_size: libc::size_t, param_value: *mut libc::c_void, param_value_size_ret: *mut libc::size_t) -> cl_int; /* Device APIs */ pub fn clGetDeviceIDs(platform: cl_platform_id, device_type: cl_device_type, num_entries: cl_uint, devices: *mut cl_device_id, num_devices: *mut cl_uint) -> cl_int; pub fn clGetDeviceInfo(device: cl_device_id, param_name: cl_device_info, param_value_size: libc::size_t, param_value: *mut libc::c_void, param_value_size_ret: *mut libc::size_t) -> cl_int; /* Context APIs */ pub fn clCreateContext(properties: *const cl_context_properties, num_devices: cl_uint, devices: *const cl_device_id, pfn_notify: extern fn (*const libc::c_char, *const libc::c_void, libc::size_t, *mut libc::c_void), user_data: *mut libc::c_void, errcode_ret: *mut cl_int) -> cl_context; pub fn clCreateContextFromType(properties: *mut cl_context_properties, device_type: cl_device_type, pfn_notify: extern fn (*mut libc::c_char, *mut libc::c_void, libc::size_t, *mut libc::c_void), user_data: *mut libc::c_void, errcode_ret: *mut cl_int) -> cl_context; pub fn clRetainContext(context: cl_context) -> cl_int; pub fn clReleaseContext(context: cl_context) -> cl_int; pub fn clGetContextInfo(context: cl_context, param_name: cl_context_info, param_value_size: libc::size_t, param_value: *mut libc::c_void, param_value_size_ret: *mut libc::size_t) -> cl_int; /* Command Queue APIs */ pub fn clCreateCommandQueue(context: cl_context, device: cl_device_id, properties: cl_command_queue_properties, errcode_ret: *mut cl_int) -> cl_command_queue; pub fn clRetainCommandQueue(command_queue: cl_command_queue) -> cl_int; pub fn clReleaseCommandQueue(command_queue: cl_command_queue) -> cl_int; pub fn clGetCommandQueueInfo(command_queue: cl_command_queue, param_name: cl_command_queue_info, param_value_size: libc::size_t, param_value: *mut libc::c_void, param_value_size_ret: *mut libc::size_t) -> cl_int; /* Memory Object APIs */ pub fn clCreateBuffer(context: cl_context, flags: cl_mem_flags, size: libc::size_t, host_ptr: *mut libc::c_void, errcode_ret: *mut cl_int) -> cl_mem; pub fn clCreateSubBuffer(buffer: cl_mem, flags: cl_mem_flags, buffer_create_type: cl_buffer_create_type, buffer_create_info: *mut libc::c_void, errcode_ret: *mut cl_int) -> cl_mem; pub fn clCreateImage2D(context: cl_context, flags: cl_mem_flags, image_format: *mut cl_image_format, image_width: libc::size_t, image_height: libc::size_t, image_row_pitch: libc::size_t, host_ptr: *mut libc::c_void, errcode_ret: *mut cl_int) -> cl_mem; pub fn clCreateImage3D(context: cl_context, flags: cl_mem_flags, image_format: *mut cl_image_format, image_width: libc::size_t, image_height: libc::size_t, image_depth: libc::size_t, image_row_pitch: libc::size_t, image_depth: libc::size_t, image_row_pitch: libc::size_t, image_slice_pitch: libc::size_t, host_ptr: *mut libc::c_void, errcode_ret: *mut cl_int) -> cl_mem; pub fn clRetainMemObject(memobj: cl_mem) -> cl_int; pub fn clReleaseMemObject(memobj: cl_mem) -> cl_int; pub fn clGetSupportedImageFormats(context: cl_context, flags: cl_mem_flags, image_type: cl_mem_object_type, num_entries: cl_uint, image_formats: *mut cl_image_format, num_image_formats: *mut cl_uint) -> cl_int; pub fn clGetMemObjectInfo(memobj: cl_mem, param_name: cl_mem_info, param_value_size: libc::size_t, param_value: *mut libc::c_void, param_value_size_ret: *mut libc::size_t) -> cl_int; pub fn clGetImageInfo(image: cl_mem, param_name: cl_image_info, param_value_size: libc::size_t, param_value: *mut libc::c_void, param_value_size_ret: *mut libc::size_t) -> cl_int; pub fn clSetMemObjectDestructorCallback(memobj: cl_mem, pfn_notify: extern fn (cl_mem, *mut libc::c_void), user_data: *mut libc::c_void) -> cl_int; /*mut * Sampler APIs */ pub fn clCreateSampler(context: cl_context, normalize_coords: cl_bool, addressing_mode: cl_addressing_mode, filter_mode: cl_filter_mode, errcode_ret: *mut cl_int) -> cl_sampler; pub fn clRetainSampler(sampler: cl_sampler) -> cl_int; pub fn clReleaseSampler(sampler: cl_sampler) ->cl_int; pub fn clGetSamplerInfo(sampler: cl_sampler, param_name: cl_sampler_info, param_value_size: libc::size_t, param_value: *mut libc::c_void, param_value_size_ret: *mut libc::size_t) -> cl_int; /* Program Object APIs */ pub fn clCreateProgramWithSource(context: cl_context, count: cl_uint, strings: *const *const libc::c_char, lengths: *const libc::size_t, errcode_ret: *mut cl_int) -> cl_program; pub fn clCreateProgramWithBinary(context: cl_context, num_devices: cl_uint, device_list: *const cl_device_id, lengths: *const libc::size_t, binaries: *const *const libc::c_uchar, binary_status: *mut cl_int, errcode_ret: *mut cl_int) -> cl_program; pub fn clRetainProgram(program: cl_program) -> cl_int; pub fn clReleaseProgram(program: cl_program) -> cl_int; pub fn clBuildProgram(program: cl_program, num_devices: cl_uint, device_list: *const cl_device_id, options: *const libc::c_char, pfn_notify: extern fn (cl_program, *mut libc::c_void), user_data: *mut libc::c_void) -> cl_int; pub fn clUnloadCompiler() -> cl_int; pub fn clGetProgramInfo(program: cl_program, param_name: cl_program_info, param_value_size: libc::size_t, param_value: *mut libc::c_void, param_value_size_ret: *mut libc::size_t) -> cl_int; pub fn clGetProgramBuildInfo(program: cl_program, device: cl_device_id, param_name: cl_program_info, param_value_size: libc::size_t, param_value: *mut libc::c_void, param_value_size_ret: *mut libc::size_t) -> cl_int; /* Kernel Object APIs */ pub fn clCreateKernel(program: cl_program, kernel_name: *const libc::c_char, errcode_ret: *mut cl_int) -> cl_kernel; pub fn clCreateKernelsInProgram(program: cl_program, num_kernels: cl_uint, kernels: *mut cl_kernel, num_kernels_ret: *mut cl_uint) -> cl_int; pub fn clRetainKernel(kernel: cl_kernel) -> cl_int; pub fn clReleaseKernel(kernel: cl_kernel) -> cl_int; pub fn clSetKernelArg(kernel: cl_kernel, arg_index: cl_uint, arg_size: libc::size_t, arg_value: *const libc::c_void) -> cl_int; pub fn clGetKernelInfo(kernel: cl_kernel, param_name: cl_kernel_info, param_value_size: libc::size_t, param_value: *mut libc::c_void, param_value_size_ret: *mut libc::size_t) -> cl_int; pub fn clGetKernelWorkGroupInfo(kernel: cl_kernel, device: cl_device_id, param_name: cl_kernel_work_group_info, param_value_size: libc::size_t, param_value: *mut libc::c_void, param_value_size_ret: *mut libc::size_t) -> cl_int; /* Event Object APIs */ pub fn clWaitForEvents(num_events: cl_uint, event_list: *const cl_event) -> cl_int; pub fn clGetEventInfo(event: cl_event, param_name: cl_event_info, param_value_size: libc::size_t, param_value: *mut libc::c_void, param_value_size_ret: *mut libc::size_t) -> cl_int; pub fn clCreateUserEvent(context: cl_context, errcode_ret: *mut cl_int) -> cl_event; pub fn clRetainEvent(event: cl_event) -> cl_int; pub fn clReleaseEvent(event: cl_event) -> cl_int; pub fn clSetUserEventStatus(event: cl_event, execution_status: cl_int) -> cl_int; pub fn clSetEventCallback(event: cl_event, command_exec_callback_type: cl_int, pfn_notify: extern fn (cl_event, cl_int, *mut libc::c_void), user_data: *mut libc::c_void) -> cl_int; /* Profiling APIs */ pub fn clGetEventProfilingInfo(event: cl_event, param_name: cl_profiling_info, param_value_size: libc::size_t, param_value: *mut libc::c_void, param_value_size_ret: *mut libc::size_t) -> cl_int; /* Flush and Finish APIs */ pub fn clFlush(command_queue: cl_command_queue) -> cl_int; pub fn clFinish(command_queue: cl_command_queue) -> cl_int; /* Enqueued Commands APIs */ pub fn clEnqueueReadBuffer(command_queue: cl_command_queue, buffer: cl_mem, blocking_read: cl_bool, offset: libc::size_t, cb: libc::size_t, ptr: *mut libc::c_void, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event) -> cl_int; pub fn clEnqueueReadBufferRect(command_queue: cl_command_queue, buffer: cl_mem, blocking_read: cl_bool, buffer_origin: *mut libc::size_t, host_origin: *mut libc::size_t, region: *mut libc::size_t, buffer_row_pitch: libc::size_t, buffer_slice_pitch: libc::size_t, host_row_pitch: libc::size_t, host_slice_pitch: libc::size_t, ptr: *mut libc::c_void, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event) -> cl_int; pub fn clEnqueueWriteBuffer(command_queue: cl_command_queue, buffer: cl_mem, blocking_write: cl_bool, offset: libc::size_t, cb: libc::size_t, ptr: *const libc::c_void, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event) -> cl_int; pub fn clEnqueueWriteBufferRect(command_queue: cl_command_queue, blocking_write: cl_bool, buffer_origin: *mut libc::size_t, host_origin: *mut libc::size_t, region: *mut libc::size_t, buffer_row_pitch: libc::size_t, buffer_slice_pitch: libc::size_t, host_row_pitch: libc::size_t, host_slice_pitch: libc::size_t, ptr: *mut libc::c_void, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event) -> cl_int; pub fn clEnqueueCopyBuffer(command_queue: cl_command_queue, src_buffer: cl_mem, dst_buffer: cl_mem, src_offset: libc::size_t, dst_offset: libc::size_t, cb: libc::size_t, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event) -> cl_int; pub fn clEnqueueCopyBufferRect(command_queue: cl_command_queue, src_buffer: cl_mem, dst_buffer: cl_mem, src_origin: *mut libc::size_t, dst_origin: *mut libc::size_t, region: *mut libc::size_t, src_row_pitch: libc::size_t, src_slice_pitch: libc::size_t, dst_row_pitch: libc::size_t, dst_slice_pitch: libc::size_t, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event) -> cl_int; pub fn clEnqueueReadImage(command_queue: cl_command_queue, image: cl_mem, blocking_read: cl_bool, origin: *mut libc::size_t, region: *mut libc::size_t, row_pitch: libc::size_t, slice_pitch: libc::size_t, ptr: *mut libc::c_void, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event) -> cl_int; pub fn clEnqueueWriteImage(command_queue: cl_command_queue, image: cl_mem, blocking_write: cl_bool, origin: *mut libc::size_t, region: *mut libc::size_t, input_row_pitch: libc::size_t, input_slice_pitch: libc::size_t, ptr: *mut libc::c_void, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event) -> cl_int; pub fn clEnqueueCopyImage(command_queue: cl_command_queue, src_image: cl_mem, dst_image: cl_mem, src_origin: *mut libc::size_t, dst_origin: *mut libc::size_t, region: *mut libc::size_t, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event) -> cl_int; pub fn clEnqueueCopyImageToBuffer(command_queue: cl_command_queue, src_image: cl_mem, dst_buffer: cl_mem, src_origin: *mut libc::size_t, region: *mut libc::size_t, dst_offset: libc::size_t, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event) -> cl_int; pub fn clEnqueueCopyBufferToImage(command_queue: cl_command_queue, src_buffer: cl_mem, dst_image: cl_mem, src_offset: libc::size_t, dst_origin: *mut libc::size_t, region: *mut libc::size_t, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event) -> cl_int; pub fn clEnqueueMapBuffer(command_queue: cl_command_queue, buffer: cl_mem, blocking_map: cl_bool, map_flags: cl_map_flags, offset: libc::size_t, cb: libc::size_t, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, errorcode_ret: *mut cl_int); pub fn clEnqueueMapImage(command_queue: cl_command_queue, image: cl_mem, blocking_map: cl_bool, map_flags: cl_map_flags, origin: *mut libc::size_t, region: *mut libc::size_t, image_row_pitch: libc::size_t, image_slice_pitch: libc::size_t, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event, errorcode_ret: *mut cl_int); pub fn clEnqueueUnmapMemObject(command_queue: cl_command_queue, memobj: cl_mem, mapped_ptr: *mut libc::c_void, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event) -> cl_int; pub fn clEnqueueNDRangeKernel(command_queue: cl_command_queue, kernel: cl_kernel, work_dim: cl_uint, global_work_offset: *const libc::size_t, global_work_size: *const libc::size_t, local_work_size: *const libc::size_t, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event) -> cl_int; pub fn clEnqueueTask(command_queue: cl_command_queue, kernel: cl_kernel, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event) -> cl_int; pub fn clEnqueueNativeKernel(command_queue: cl_command_queue, user_func: extern fn (*mut libc::c_void), args: *mut libc::c_void, cb_args: libc::size_t, num_mem_objects: cl_uint, mem_list: *const cl_mem, args_mem_loc: *const *const libc::c_void, num_events_in_wait_list: cl_uint, event_wait_list: *const cl_event, event: *mut cl_event) -> cl_int; pub fn clEnqueueMarker(command_queue: cl_command_queue, event: *mut cl_event) -> cl_int; pub fn clEnqueueWaitForEvents(command_queue: cl_command_queue, num_events: cl_uint, event_list: *mut cl_event) -> cl_int; pub fn clEnqueueBarrier(command_queue: cl_command_queue) -> cl_int; /* Extension function access * * Returns the extension function address for the given function name, * or NULL if a valid function can not be found. The client must * check to make sure the address is not NULL, before using or * or calling the returned function address. */ pub fn clGetExtensionFunctionAddress(func_name: *const libc::c_char) -> *mut libc::c_void; } } ================================================ FILE: src/error.rs ================================================ //! Error handling utilities. use cl::{CLStatus, cl_int}; use cl::CLStatus::CL_SUCCESS; fn error_str(status_code: cl_int) -> String { match status_code { 0 => CLStatus::CL_SUCCESS.to_string(), -1 => CLStatus::CL_DEVICE_NOT_FOUND.to_string(), -2 => CLStatus::CL_DEVICE_NOT_AVAILABLE.to_string(), -3 => CLStatus::CL_COMPILER_NOT_AVAILABLE.to_string(), -4 => CLStatus::CL_MEM_OBJECT_ALLOCATION_FAILURE.to_string(), -5 => CLStatus::CL_OUT_OF_RESOURCES.to_string(), -6 => CLStatus::CL_OUT_OF_HOST_MEMORY.to_string(), -7 => CLStatus::CL_PROFILING_INFO_NOT_AVAILABLE.to_string(), -8 => CLStatus::CL_MEM_COPY_OVERLAP.to_string(), -9 => CLStatus::CL_IMAGE_FORMAT_MISMATCH.to_string(), -10 => CLStatus::CL_IMAGE_FORMAT_NOT_SUPPORTED.to_string(), -11 => CLStatus::CL_BUILD_PROGRAM_FAILURE.to_string(), -12 => CLStatus::CL_MAP_FAILURE.to_string(), -13 => CLStatus::CL_MISALIGNED_SUB_BUFFER_OFFSET.to_string(), -14 => CLStatus::CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST.to_string(), -30 => CLStatus::CL_INVALID_VALUE.to_string(), -31 => CLStatus::CL_INVALID_DEVICE_TYPE.to_string(), -32 => CLStatus::CL_INVALID_PLATFORM.to_string(), -33 => CLStatus::CL_INVALID_DEVICE.to_string(), -34 => CLStatus::CL_INVALID_CONTEXT.to_string(), -35 => CLStatus::CL_INVALID_QUEUE_PROPERTIES.to_string(), -36 => CLStatus::CL_INVALID_COMMAND_QUEUE.to_string(), -37 => CLStatus::CL_INVALID_HOST_PTR.to_string(), -38 => CLStatus::CL_INVALID_MEM_OBJECT.to_string(), -39 => CLStatus::CL_INVALID_IMAGE_FORMAT_DESCRIPTOR.to_string(), -40 => CLStatus::CL_INVALID_IMAGE_SIZE.to_string(), -41 => CLStatus::CL_INVALID_SAMPLER.to_string(), -42 => CLStatus::CL_INVALID_BINARY.to_string(), -43 => CLStatus::CL_INVALID_BUILD_OPTIONS.to_string(), -44 => CLStatus::CL_INVALID_PROGRAM.to_string(), -45 => CLStatus::CL_INVALID_PROGRAM_EXECUTABLE.to_string(), -46 => CLStatus::CL_INVALID_KERNEL_NAME.to_string(), -47 => CLStatus::CL_INVALID_KERNEL_DEFINITION.to_string(), -48 => CLStatus::CL_INVALID_KERNEL.to_string(), -49 => CLStatus::CL_INVALID_ARG_INDEX.to_string(), -50 => CLStatus::CL_INVALID_ARG_VALUE.to_string(), -51 => CLStatus::CL_INVALID_ARG_SIZE.to_string(), -52 => CLStatus::CL_INVALID_KERNEL_ARGS.to_string(), -53 => CLStatus::CL_INVALID_WORK_DIMENSION.to_string(), -54 => CLStatus::CL_INVALID_WORK_GROUP_SIZE.to_string(), -55 => CLStatus::CL_INVALID_WORK_ITEM_SIZE.to_string(), -56 => CLStatus::CL_INVALID_GLOBAL_OFFSET.to_string(), -57 => CLStatus::CL_INVALID_EVENT_WAIT_LIST.to_string(), -58 => CLStatus::CL_INVALID_EVENT.to_string(), -59 => CLStatus::CL_INVALID_OPERATION.to_string(), -60 => CLStatus::CL_INVALID_GL_OBJECT.to_string(), -61 => CLStatus::CL_INVALID_BUFFER_SIZE.to_string(), -62 => CLStatus::CL_INVALID_MIP_LEVEL.to_string(), -63 => CLStatus::CL_INVALID_GLOBAL_WORK_SIZE.to_string(), -64 => CLStatus::CL_INVALID_PROPERTY.to_string(), -1001 => CLStatus::CL_PLATFORM_NOT_FOUND_KHR.to_string(), _ => format!("Unknown Error: {}", status_code) } } pub fn check(status: cl_int, message: &str) { if status != CL_SUCCESS as cl_int { panic!("{} ({})", message, error_str(status)) } } ================================================ FILE: src/ext.rs ================================================ #![allow(unused, unused_attributes, non_camel_case_types, non_snake_case)] /// All of the extensions defined for OpenCL 1.1, from /// [`cl_ext.h`](https://www.khronos.org/registry/cl/api/1.1/cl_ext.h). // Macro to define a struct-style extension pointer loader. // Defines a (`Copy`, `Sync`) `struct Functions` that has extension function pointers as members (and methods, // for convenience). // Call `$ext::load()` to get an Option<$ext::Functions, String>. (It's safe to call extension function pointers in other threads, right?) macro_rules! cl_extension_loader { ( $ext_name:expr; $(extern fn $function:ident ($($arg:ident : $arg_type:ty),*) -> $ret:ty),* ) => ( // Define struct Functions ext_struct_def!{ $($function, ($($arg, $arg_type),*) $ret)* } impl Functions { // Make function pointers available as methods so they don't have to be called as (struct.member)(arg) $( #[inline(always)] unsafe fn $function (&self, $($arg:$arg_type),*) -> $ret { (self.$function)($($arg),*) } )* } pub fn load(platform: cl_platform_id) -> Result { use hl; use std::mem; use std::ptr; use std::ffi::CString; use cl::ll::clGetExtensionFunctionAddress; // Read in the available extensions // We have to do this, since loading function pointers for an // unavailable extension can return non-NULL. // TODO read in extensions lazily and store them in a global HashSet? let available = unsafe { let hl_platform = hl::Platform::from_platform_id(platform); let available = hl_platform.extensions().contains($ext_name); mem::forget(hl_platform); available }; if !available { let platform_name; unsafe { let hl_platform = hl::Platform::from_platform_id(platform); platform_name = hl_platform.name(); mem::forget(hl_platform); } return Err(format!("extension {} unavailable for platform {}", $ext_name, platform_name)); } // Return a struct with all functions loaded Ok(ext_struct_literal!($ext_name, platform, $($function),*)) } ) } // We only need these helper macros so we can special-case for unit structs // (Since writing `struct name {}` is a failing error for some reason) // Whatever functions we're calling aren't necessarily thread-safe, but since this is a low-level // interface we'll let the callers worry about that macro_rules! ext_struct_def { () => (#[derive(Copy, Clone)] pub struct Functions;); ($($function:ident, ($($arg:ident, $arg_type:ty),+) $ret:ty)+) => ( #[derive(Copy, Clone)] pub struct Functions { $(pub $function: (extern fn ($($arg : $arg_type),+) -> $ret)),+ } ); } // (So is writing `name {}` as a literal) macro_rules! ext_struct_literal { ($ext_name:expr, $plat:ident,) => (Functions); ($ext_name:expr, $plat:ident, $($function:ident),+) => ( Functions { $($function: { let mut fn_name = CString::new(stringify!($function)).unwrap(); // TODO use clGetExtensionFunctionAddressForPlatform() when it's available; more // reliable. let fn_ptr = unsafe { clGetExtensionFunctionAddress(fn_name.as_ptr()) }; if fn_ptr == ptr::null_mut() { let platform_name; unsafe { let hl_platform = hl::Platform::from_platform_id($plat); platform_name = hl_platform.name(); mem::forget(hl_platform); } return Err(format!("extension {} apparently available for platform with id {}, but couldn't load function {}", $ext_name, platform_name, stringify!($function))); } unsafe { // Cast from *mut libc::void to the function pointer type we want mem::transmute(fn_ptr) } }),+ } ); } pub mod cl_khr_fp64 { use cl::*; static CL_DEVICE_DOUBLE_FP_CONFIG: cl_uint = 0x1032; cl_extension_loader! { "cl_khr_fp64"; } } pub mod cl_khr_fp16 { use cl::*; pub static CL_DEVICE_HALF_FP_CONFIG: cl_uint = 0x1033; cl_extension_loader! { "cl_khr_pf16"; } } pub mod cl_APPLE_SetMemObjectDestructor { use libc; use cl::*; cl_extension_loader! { "cl_APPLE_SetMemObjectDestructor"; extern fn clSetMemObjectDestructorAPPLE(memobj: cl_mem, pfn_notify: (extern fn(memobj: cl_mem, user_data: *mut libc::c_void)), user_data: *mut libc::c_void) -> () // Note: returning () is necessary to satisfy macros } } pub mod cl_APPLE_ContextLoggingFunctions { use libc; use cl::*; cl_extension_loader! { "cl_APPLE_ContextLoggingFunctions"; extern fn clLogMessagesToSystemLogAPPLE(errstr: *const libc::c_char, private_info: *const libc::c_void, cb: libc::size_t, user_data: *mut libc::c_void) -> (), extern fn clLogMessagesToStdoutAPPLE(errstr: *const libc::c_char, private_info: *const libc::c_void, cb: libc::size_t, user_data: *mut libc::c_void) -> (), extern fn clLogMessagesToStderrAPPLE(errstr: *const libc::c_char, private_info: *const libc::c_void, cb: libc::size_t, user_data: *mut libc::c_void) -> () } } pub mod cl_khr_icd { use libc; use cl::*; pub static CL_PLATFORM_ICD_SUFFIX: cl_uint = 0x0920; // Note: this is an error code, but we can't extend CLStatus with it... hmm. pub static CL_PLATFORM_NOT_FOUND_KHR: cl_int = -1001; cl_extension_loader! { "cl_khr_icd"; extern fn clIcdGetPlatformIDsKHR(num_entries: cl_uint, platform: *mut cl_platform_id, num_platforms: *mut cl_uint) -> cl_int } } pub mod cl_nv_device_attribute_query { use cl::*; pub static CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV: cl_uint = 0x4000; pub static CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV: cl_uint = 0x4001; pub static CL_DEVICE_REGISTERS_PER_BLOCK_NV: cl_uint = 0x4002; pub static CL_DEVICE_WARP_SIZE_NV: cl_uint = 0x4003; pub static CL_DEVICE_GPU_OVERLAP_NV: cl_uint = 0x4004; pub static CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV: cl_uint = 0x4005; pub static CL_DEVICE_INTEGRATED_MEMORY_NV: cl_uint = 0x4006; cl_extension_loader! { "cl_nv_device_attribute_query"; } } pub mod cl_amd_device_attribute_query { use cl::*; pub static CL_DEVICE_PROFILING_TIMER_OFFSET_AMD: cl_uint = 0x4036; cl_extension_loader! { "cl_amd_device_attribute_query"; } } pub mod cl_arm_printf { use cl::*; pub static CL_PRINTF_CALLBACK_ARM: cl_uint = 0x40B0; pub static CL_PRINTF_BUFFERSIZE_ARM: cl_uint = 0x40B1; cl_extension_loader! { "cl_arm_printf"; } } pub mod cl_ext_device_fission { use cl::*; pub type cl_device_partition_property_ext = cl_ulong; pub static CL_DEVICE_PARTITION_EQUALLY_EXT: cl_device_partition_property_ext = 0x4050; pub static CL_DEVICE_PARTITION_BY_COUNTS_EXT: cl_device_partition_property_ext = 0x4051; pub static CL_DEVICE_PARTITION_BY_NAMES_EXT: cl_device_partition_property_ext = 0x4052; pub static CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN_EXT: cl_device_partition_property_ext = 0x4053; pub static CL_DEVICE_PARENT_DEVICE_EXT: cl_device_info = 0x4054; pub static CL_DEVICE_PARTITION_TYPES_EXT: cl_device_info = 0x4055; pub static CL_DEVICE_AFFINITY_DOMAINS_EXT: cl_device_info = 0x4056; pub static CL_DEVICE_REFERENCE_COUNT_EXT: cl_device_info = 0x4057; pub static CL_DEVICE_PARTITION_STYLE_EXT: cl_device_info = 0x4058; pub static CL_DEVICE_PARTITION_FAILED_EXT: cl_int = -1057; pub static CL_INVALID_PARTITION_COUNT_EXT: cl_int = -1058; pub static CL_INVALID_PARTITION_NAME_EXT: cl_int = -1059; pub static CL_AFFINITY_DOMAIN_L1_CACHE_EXT: cl_uint = 0x1; pub static CL_AFFINITY_DOMAIN_L2_CACHE_EXT: cl_uint = 0x2; pub static CL_AFFINITY_DOMAIN_L3_CACHE_EXT: cl_uint = 0x3; pub static CL_AFFINITY_DOMAIN_L4_CACHE_EXT: cl_uint = 0x4; pub static CL_AFFINITY_DOMAIN_NUMA_EXT: cl_uint = 0x10; pub static CL_AFFINITY_DOMAIN_NEXT_FISSIONABLE_EXT: cl_uint = 0x100; pub static CL_PROPERTIES_LIST_END_EXT: cl_device_partition_property_ext = 0; pub static CL_PARTITION_BY_COUNTS_LIST_END_EXT: cl_device_partition_property_ext = 0; pub static CL_PARTITION_BY_NAMES_LIST_END_EXT: cl_device_partition_property_ext = std::u64::MAX; cl_extension_loader! { "cl_ext_device_fission"; extern fn clReleaseDeviceEXT(device: cl_device_id) -> cl_int, extern fn clRetainDeviceEXT(device: cl_device_id) -> cl_int, extern fn clCreateSubDevicesExt(in_device: cl_device_id, properties: *const cl_device_partition_property_ext, num_entries: cl_uint, out_devices: *mut cl_device_id, num_devices: *mut cl_uint) -> cl_int } } pub mod cl_qcom_ext_host_ptr { use libc; use cl::*; pub type cl_image_pitch_info_qcom = cl_uint; pub struct cl_mem_ext_host_ptr { pub allocation_type: cl_uint, pub host_cache_policy: cl_uint } pub static CL_MEM_EXT_HOST_PTR_QCOM: cl_uint = (1 << 29); pub static CL_DEVICE_EXT_MEM_PADDING_IN_BYTES_QCOM: cl_uint = 0x40A0; pub static CL_DEVICE_PAGE_SIZE_QCOM: cl_uint = 0x40A1; pub static CL_IMAGE_ROW_ALIGNMENT_QCOM: cl_uint = 0x40A2; pub static CL_IMAGE_SLICE_ALIGNMENT_QCOM: cl_uint = 0x40A3; pub static CL_MEM_HOST_UNCACHED_QCOM: cl_uint = 0x40A4; pub static CL_MEM_HOST_WRITEBACK_QCOM: cl_uint = 0x40A5; pub static CL_MEM_HOST_WRITETHROUGH_QCOM: cl_uint = 0x40A6; pub static CL_MEM_HOST_WRITE_COMBINING_QCOM: cl_uint = 0x40A7; cl_extension_loader! { "cl_qcom_ext_host_ptr"; extern fn clGetDeviceImageInfoQCOM(device: cl_device_id, image_width: libc::size_t, image_height: libc::size_t, image_format: *const cl_image_format, param_name: cl_image_pitch_info_qcom, param_value_size: libc::size_t, param_value: *mut libc::c_void, param_value_size_ret: *mut libc::size_t) -> () } } // This extension depends on the previous one. Should we try to express that? pub mod cl_qcom_ion_host_ptr { use libc; use cl::*; use super::cl_qcom_ext_host_ptr; struct cl_mem_ion_host_ptr { pub ext_host_ptr: cl_qcom_ext_host_ptr::cl_mem_ext_host_ptr, pub ion_filedesc: libc::c_int, pub ion_hostptr: *mut libc::c_void } pub static CL_MEM_ION_HOST_PTR_QCOM: cl_uint = 0x40A8; cl_extension_loader! { "cl_qcom_ion_host_ptr"; } } ================================================ FILE: src/hl.rs ================================================ //! A higher level API. use libc; use std::ffi::CString; use std::iter::repeat; use std::marker::PhantomData; use std::mem; use std::ptr; use std::string::String; use std::vec::Vec; use cl; use cl::*; use cl::ll::*; use cl::CLStatus::CL_SUCCESS; use error::check; use mem::{Put, Get, Write, Read, Buffer, CLBuffer}; #[derive(Copy, Clone)] pub enum DeviceType { CPU, GPU } fn convert_device_type(device: DeviceType) -> cl_device_type { match device { DeviceType::CPU => CL_DEVICE_TYPE_CPU, DeviceType::GPU => CL_DEVICE_TYPE_GPU | CL_DEVICE_TYPE_ACCELERATOR } } pub struct Platform { id: cl_platform_id } impl Platform { fn get_devices_internal(&self, dtype: cl_device_type) -> Vec { unsafe { let mut num_devices = 0; info!("Looking for devices matching {}", dtype); clGetDeviceIDs(self.id, dtype, 0, ptr::null_mut(), (&mut num_devices)); let mut ids: Vec = repeat(0 as cl_device_id) .take(num_devices as usize).collect(); clGetDeviceIDs(self.id, dtype, ids.len() as cl_uint, ids.as_mut_ptr(), (&mut num_devices)); ids.iter().map(|id| { Device {id: *id }}).collect() } } pub fn get_devices(&self) -> Vec { self.get_devices_internal(CL_DEVICE_TYPE_ALL) } pub fn get_devices_by_types(&self, types: &[DeviceType]) -> Vec { let mut dtype = 0; for &t in types.iter() { dtype |= convert_device_type(t); } self.get_devices_internal(dtype) } fn profile_info(&self, name: cl_platform_info) -> String { unsafe { let mut size = 0 as libc::size_t; let status = clGetPlatformInfo(self.id, name, 0, ptr::null_mut(), &mut size); check(status, "Could not determine platform info string length"); let mut buf : Vec = repeat(0u8).take(size as usize).collect(); let status = clGetPlatformInfo(self.id, name, size, buf.as_mut_ptr() as *mut libc::c_void, ptr::null_mut()); check(status, "Could not get platform info string"); String::from_utf8_unchecked(buf) } } pub fn get_id(&self) -> cl_platform_id { self.id } pub fn name(&self) -> String { self.profile_info(CL_PLATFORM_NAME) } pub fn version(&self) -> String { self.profile_info(CL_PLATFORM_VERSION) } pub fn profile(&self) -> String { self.profile_info(CL_PLATFORM_PROFILE) } pub fn vendor(&self) -> String { self.profile_info(CL_PLATFORM_VENDOR) } pub fn extensions(&self) -> String { self.profile_info(CL_PLATFORM_EXTENSIONS) } pub unsafe fn from_platform_id(id: cl_platform_id) -> Platform { Platform { id: id } } } // This mutex is used to work around weak OpenCL implementations. // On some implementations concurrent calls to clGetPlatformIDs // will cause the implantation to return invalid status. static mut platforms_mutex: std::sync::StaticMutex = std::sync::MUTEX_INIT; pub fn get_platforms() -> Vec { let mut num_platforms = 0 as cl_uint; unsafe { let guard = platforms_mutex.lock(); let status = clGetPlatformIDs(0, ptr::null_mut(), (&mut num_platforms)); // unlock this before the check in case the check fails check(status, "could not get platform count."); let mut ids: Vec = repeat(0 as cl_device_id) .take(num_platforms as usize).collect(); let status = clGetPlatformIDs(num_platforms, ids.as_mut_ptr(), (&mut num_platforms)); check(status, "could not get platforms."); let _ = guard; ids.iter().map(|id| { Platform { id: *id } }).collect() } } pub fn create_context_with_properties(dev: &[Device], prop: &[cl_context_properties]) -> Context { unsafe { // TODO: Support for multiple devices let mut errcode = 0; let dev: Vec = dev.iter().map(|dev| dev.id).collect(); // TODO: Proper error messages let ctx = clCreateContext(&prop[0], dev.len() as u32, &dev[0], mem::transmute(ptr::null::()), ptr::null_mut(), &mut errcode); check(errcode, "Failed to create opencl context!"); Context { ctx: ctx } } } #[derive(Copy, Clone)] pub struct Device { id: cl_device_id } unsafe impl Sync for Device {} unsafe impl Send for Device {} impl Device { fn profile_info(&self, name: cl_device_info) -> String { unsafe { let mut size = 0 as libc::size_t; let status = clGetDeviceInfo( self.id, name, 0, ptr::null_mut(), &mut size); check(status, "Could not determine device info string length"); let mut buf : Vec = repeat(0u8).take(size as usize).collect(); let status = clGetDeviceInfo(self.id, name, size, buf.as_mut_ptr() as *mut libc::c_void, ptr::null_mut()); check(status, "Could not get device info string"); String::from_utf8_unchecked(buf) } } pub fn name(&self) -> String { self.profile_info(CL_DEVICE_NAME) } pub fn vendor(&self) -> String { self.profile_info(CL_DEVICE_VENDOR) } pub fn profile(&self) -> String { self.profile_info(CL_DEVICE_PROFILE) } pub fn device_type(&self) -> String { self.profile_info(CL_DEVICE_TYPE) } pub fn compute_units(&self) -> usize { unsafe { let mut ct: usize = 0; let status = clGetDeviceInfo( self.id, CL_DEVICE_MAX_COMPUTE_UNITS, 8, (&mut ct as *mut usize) as *mut libc::c_void, ptr::null_mut()); check(status, "Could not get number of device compute units."); return ct; } } pub fn create_context(&self) -> Context { unsafe { // TODO: Support for multiple devices let mut errcode = 0; // TODO: Proper error messages let ctx = clCreateContext(ptr::null(), 1, &self.id, mem::transmute(ptr::null::()), ptr::null_mut(), (&mut errcode)); check(errcode, "Failed to create opencl context!"); Context { ctx: ctx } } } } pub struct Context { pub ctx: cl_context, } unsafe impl Sync for Context {} unsafe impl Send for Context {} impl Context { pub fn create_buffer(&self, size: usize, flags: cl_mem_flags) -> CLBuffer { unsafe { let mut status = 0; let buf = clCreateBuffer(self.ctx, flags, (size*mem::size_of::()) as libc::size_t , ptr::null_mut(), (&mut status)); check(status, "Could not allocate buffer"); CLBuffer { cl_buffer: buf, phantom: PhantomData, } } } pub fn create_buffer_from>(&self, create: IN, flags: cl_mem_flags) -> U { create.put(|p, len| { let mut status = 0; let buf = unsafe { clCreateBuffer(self.ctx, flags | CL_MEM_COPY_HOST_PTR, len, mem::transmute(p), (&mut status)) }; check(status, "Could not allocate buffer"); buf }) } pub fn create_command_queue(&self, device: &Device) -> CommandQueue { unsafe { let mut errcode = 0; let cqueue = clCreateCommandQueue(self.ctx, device.id, CL_QUEUE_PROFILING_ENABLE, (&mut errcode)); check(errcode, "Failed to create command queue!"); CommandQueue { cqueue: cqueue } } } pub fn create_program_from_source(&self, src: &str) -> Program { unsafe { let src = CString::new(src).unwrap(); let mut status = CL_SUCCESS as cl_int; let program = clCreateProgramWithSource( self.ctx, 1, &src.as_ptr(), ptr::null(), (&mut status)); check(status, "Could not create program"); Program { prg: program } } } pub fn create_program_from_binary(&self, bin: &str, device: &Device) -> Program { let src = CString::new(bin).unwrap(); let mut status = CL_SUCCESS as cl_int; let len = bin.len() as libc::size_t; let program = unsafe { clCreateProgramWithBinary( self.ctx, 1, &device.id, (&len), (src.as_ptr() as *const *const i8) as *const *const libc::c_uchar, ptr::null_mut(), (&mut status)) }; check(status, "Could not create program"); Program {prg: program} } } impl Drop for Context { fn drop(&mut self) { unsafe { clReleaseContext(self.ctx); } } } impl<'r, T> KernelArg for &'r (Buffer + 'r) { fn get_value(&self) -> (libc::size_t, *const libc::c_void) { unsafe { (mem::size_of::() as libc::size_t, self.id_ptr() as *const libc::c_void) } } } impl<'r, T> KernelArg for Box + 'r> { fn get_value(&self) -> (libc::size_t, *const libc::c_void) { unsafe { (mem::size_of::() as libc::size_t, self.id_ptr() as *const libc::c_void) } } } pub struct CommandQueue { pub cqueue: cl_command_queue } unsafe impl Sync for CommandQueue {} unsafe impl Send for CommandQueue {} impl CommandQueue { //synchronous pub fn enqueue_kernel(&self, k: &Kernel, global: I, local: Option, wait_on: E) -> Event { unsafe { wait_on.as_event_list(|event_list, event_list_length| { let mut e: cl_event = ptr::null_mut(); let mut status = clEnqueueNDRangeKernel( self.cqueue, k.kernel, KernelIndex::num_dimensions(None::), ptr::null(), global.get_ptr(), match local { Some(ref l) => l.get_ptr() as *const libc::size_t, None => ptr::null() }, event_list_length, event_list, (&mut e)); check(status, "Error enqueuing kernel."); status = clFinish(self.cqueue); check(status, "Error finishing kernel."); Event { event: e } }) } } //asynchronous pub fn enqueue_async_kernel(&self, k: &Kernel, global: I, local: Option, wait_on: E) -> Event { unsafe { wait_on.as_event_list(|event_list, event_list_length| { let mut e: cl_event = ptr::null_mut(); let status = clEnqueueNDRangeKernel( self.cqueue, k.kernel, KernelIndex::num_dimensions(None::), ptr::null(), global.get_ptr(), match local { Some(ref l) => l.get_ptr() as *const libc::size_t, None => ptr::null() }, event_list_length, event_list, (&mut e)); check(status, "Error enqueuing kernel."); Event { event: e } }) } } pub fn get, G: Get, E: EventList>(&self, buf: &B, event: E) -> G { event.as_event_list(|event_list, event_list_length| { Get::get(buf, |offset, ptr, len| { unsafe { let err = clEnqueueReadBuffer(self.cqueue, buf.id(), CL_TRUE, offset as libc::size_t, len, ptr, event_list_length, event_list, ptr::null_mut()); check(err, "Failed to read buffer"); } }) }) } pub fn write>(&self, mem: &B, write: &U, event: E) { unsafe { event.as_event_list(|event_list, event_list_length| { write.write(|offset, p, len| { let err = clEnqueueWriteBuffer(self.cqueue, mem.id(), CL_TRUE, offset as libc::size_t, len as libc::size_t, p as *const libc::c_void, event_list_length, event_list, ptr::null_mut()); check(err, "Failed to write buffer"); }) }) } } pub fn write_async>(&self, mem: &B, write: &U, event: E) -> Event { let mut out_event = None; unsafe { event.as_event_list(|evt, evt_len| { write.write(|offset, p, len| { let mut e: cl_event = ptr::null_mut(); let err = clEnqueueWriteBuffer(self.cqueue, mem.id(), CL_FALSE, offset as libc::size_t, len as libc::size_t, p as *const libc::c_void, evt_len, evt, &mut e); out_event = Some(e); check(err, "Failed to write buffer"); }) }) } Event { event: out_event.unwrap() } } pub fn read>(&self, mem: &B, read: &mut U, event: E) { event.as_event_list(|event_list, event_list_length| { read.read(|offset, p, len| { unsafe { let err = clEnqueueReadBuffer(self.cqueue, mem.id(), CL_TRUE, offset as libc::size_t, len as libc::size_t, p as *mut libc::c_void, event_list_length, event_list, ptr::null_mut()); check(err, "Failed to read buffer"); } }) }) } } impl Drop for CommandQueue { fn drop(&mut self) { unsafe { clReleaseCommandQueue(self.cqueue); } } } /// Represents an OpenCL program, which is a collection of kernels. /// /// Create these using /// [`Context::create_program_from_source`](struct.Context.html#method.create_program_from_source) /// or /// [`Context::create_program_from_binary`](struct.Context.html#method.create_program_from_binary). pub struct Program { prg: cl_program, } impl Drop for Program { fn drop(&mut self) { unsafe { clReleaseProgram(self.prg); } } } impl Program { /// Build the program for a given device. /// /// Both Ok and Err returns include the build log. pub fn build(&self, device: &Device) -> Result { unsafe { let ret = clBuildProgram(self.prg, 1, &device.id, ptr::null(), mem::transmute(ptr::null::()), ptr::null_mut()); // Get the build log. let mut size = 0 as libc::size_t; let status = clGetProgramBuildInfo( self.prg, device.id, CL_PROGRAM_BUILD_LOG, 0, ptr::null_mut(), (&mut size)); check(status, "Could not get build log"); let mut buf : Vec = repeat(0u8).take(size as usize).collect(); let status = clGetProgramBuildInfo( self.prg, device.id, CL_PROGRAM_BUILD_LOG, buf.len() as libc::size_t, buf.as_mut_ptr() as *mut libc::c_void, ptr::null_mut()); check(status, "Could not get build log"); let log = String::from_utf8_lossy(&buf[..]); if ret == CL_SUCCESS as cl_int { Ok(log.into_owned()) } else { Err(log.into_owned()) } } } pub fn create_kernel(&self, name: &str) -> Kernel { create_kernel(self, name) } } pub struct Kernel { kernel: cl_kernel, } impl Drop for Kernel { fn drop(&mut self) { unsafe { clReleaseKernel(self.kernel); } } } impl Kernel { pub fn set_arg(&self, i: usize, x: &T) { set_kernel_arg(self, i as cl::cl_uint, x) } } pub fn create_kernel(program: &Program, kernel: & str) -> Kernel { unsafe { let mut errcode = 0; let str = CString::new(kernel).unwrap(); let kernel = clCreateKernel(program.prg, str.as_ptr(), (&mut errcode)); check(errcode, "Failed to create kernel!"); Kernel { kernel: kernel } } } pub trait KernelArg { fn get_value(&self) -> (libc::size_t, *const libc::c_void); } macro_rules! scalar_kernel_arg ( ($t:ty) => (impl KernelArg for $t { fn get_value(&self) -> (libc::size_t, *const libc::c_void) { (mem::size_of::<$t>() as libc::size_t, (self as *const $t) as *const libc::c_void) } }) ); scalar_kernel_arg!(isize); scalar_kernel_arg!(usize); scalar_kernel_arg!(u32); scalar_kernel_arg!(u64); scalar_kernel_arg!(i32); scalar_kernel_arg!(i64); scalar_kernel_arg!(f32); scalar_kernel_arg!(f64); scalar_kernel_arg!([f32; 2]); scalar_kernel_arg!([f64; 2]); impl KernelArg for [f32; 3] { fn get_value(&self) -> (libc::size_t, *const libc::c_void) { (4 * mem::size_of::() as libc::size_t, (self as *const f32) as *const libc::c_void) } } impl KernelArg for [f64; 3] { fn get_value(&self) -> (libc::size_t, *const libc::c_void) { (4 * mem::size_of::() as libc::size_t, (self as *const f64) as *const libc::c_void) } } pub fn set_kernel_arg(kernel: & Kernel, position: cl_uint, arg: &T) { unsafe { let (size, p) = arg.get_value(); let ret = clSetKernelArg(kernel.kernel, position, size, p); check(ret, "Failed to set kernel arg!"); } } pub struct Event { pub event: cl_event, } impl Event { fn get_time(&self, param: cl_uint) -> u64 { unsafe { let mut time: cl_ulong = 0; let ret = clGetEventProfilingInfo(self.event, param, mem::size_of::() as libc::size_t, (&mut time as *mut u64) as *mut libc::c_void, ptr::null_mut()); check(ret, "Failed to get profiling info"); time as u64 } } pub fn queue_time(&self) -> u64 { self.get_time(CL_PROFILING_COMMAND_QUEUED) } pub fn submit_time(&self) -> u64 { self.get_time(CL_PROFILING_COMMAND_SUBMIT) } pub fn start_time(&self) -> u64 { self.get_time(CL_PROFILING_COMMAND_START) } pub fn end_time(&self) -> u64 { self.get_time(CL_PROFILING_COMMAND_END) } } impl Drop for Event { fn drop(&mut self) { unsafe { clReleaseEvent(self.event); } } } pub trait EventList { fn as_event_list T>(&self, F) -> T; fn wait(&self) { self.as_event_list(|p, len| { unsafe { let status = clWaitForEvents(len, p); check(status, "Error waiting for event(s)"); } }) } } impl<'r> EventList for &'r Event { fn as_event_list(&self, f: F) -> T where F: FnOnce(*const cl_event, cl_uint) -> T { f(&self.event, 1 as cl_uint) } } impl EventList for Event { fn as_event_list(&self, f: F) -> T where F: FnOnce(*const cl_event, cl_uint) -> T { f(&self.event, 1 as cl_uint) } } impl EventList for Option { fn as_event_list(&self, f: F) -> T2 where F: FnOnce(*const cl_event, cl_uint) -> T2 { match *self { None => f(ptr::null(), 0), Some(ref s) => s.as_event_list(f) } } } impl<'r> EventList for &'r [Event] { fn as_event_list(&self, f: F) -> T where F: FnOnce(*const cl_event, cl_uint) -> T { let mut vec: Vec = Vec::with_capacity(self.len()); for item in self.iter(){ vec.push(item.event); } f(vec.as_ptr(), vec.len() as cl_uint) } } /* this seems VERY hackey */ impl EventList for () { fn as_event_list(&self, f: F) -> T where F: FnOnce(*const cl_event, cl_uint) -> T { f(ptr::null(), 0) } } pub trait KernelIndex { fn num_dimensions(dummy_self: Option) -> cl_uint where Self: Sized; fn get_ptr(&self) -> *const libc::size_t; } impl KernelIndex for isize { fn num_dimensions(_: Option) -> cl_uint { 1 } fn get_ptr(&self) -> *const libc::size_t { (self as *const isize) as *const libc::size_t } } impl KernelIndex for (isize, isize) { fn num_dimensions(_: Option<(isize, isize)>) -> cl_uint { 2 } fn get_ptr(&self) -> *const libc::size_t { (self as *const (isize, isize)) as *const libc::size_t } } impl KernelIndex for (isize, isize, isize) { fn num_dimensions(_: Option<(isize, isize, isize)>) -> cl_uint { 3 } fn get_ptr(&self) -> *const libc::size_t { (self as *const (isize, isize, isize)) as *const libc::size_t } } impl KernelIndex for usize { fn num_dimensions(_: Option) -> cl_uint { 1 } fn get_ptr(&self) -> *const libc::size_t { (self as *const usize) as *const libc::size_t } } impl KernelIndex for (usize, usize) { fn num_dimensions(_: Option<(usize, usize)>) -> cl_uint { 2 } fn get_ptr(&self) -> *const libc::size_t { (self as *const (usize, usize)) as *const libc::size_t } } impl KernelIndex for (usize, usize, usize) { fn num_dimensions(_: Option<(usize, usize, usize)>) -> cl_uint { 3 } fn get_ptr(&self) -> *const libc::size_t { (self as *const (usize, usize, usize)) as *const libc::size_t } } ================================================ FILE: src/lib.rs ================================================ #![allow(improper_ctypes)] #![allow(missing_copy_implementations)] #![allow(non_upper_case_globals)] #![feature(static_mutex)] //! OpenCL bindings for Rust. extern crate libc; #[macro_use] extern crate log; #[link(name = "OpenCL", kind = "framework")] #[cfg(target_os = "macos")] extern { } #[link(name = "OpenCL")] #[cfg(target_os = "linux")] extern { } /// Low-level OpenCL bindings. These should primarily be used by the /// higher level features in this library. pub mod cl; /// OpenCL extensions pub mod ext; pub mod error; pub mod hl; pub mod util; pub mod mem; pub mod array; ================================================ FILE: src/mem.rs ================================================ //! High level buffer management. use libc::{size_t, c_void}; use std::marker::{PhantomData}; use std::mem; use std::ptr; use std::vec::Vec; use cl::*; use cl::ll::*; use hl::KernelArg; use error::check; pub trait Buffer { unsafe fn id_ptr(&self) -> *const cl_mem; fn id(&self) -> cl_mem { unsafe { *self.id_ptr() } } fn byte_len(&self) -> size_t { unsafe { let mut size : size_t = 0; let err = clGetMemObjectInfo(self.id(), CL_MEM_SIZE, mem::size_of::() as size_t, (&mut size as *mut size_t) as *mut c_void, ptr::null_mut()); check(err, "Failed to read memory size"); size } } fn len(&self) -> usize { self.byte_len() as usize / mem::size_of::() } } pub struct CLBuffer { pub cl_buffer: cl_mem, pub phantom: PhantomData, } impl Drop for CLBuffer { fn drop(&mut self) { unsafe { clReleaseMemObject(self.cl_buffer); } } } impl Buffer for CLBuffer { unsafe fn id_ptr(&self) -> *const cl_mem { &self.cl_buffer as *const cl_mem } } impl KernelArg for CLBuffer { fn get_value(&self) -> (size_t, *const c_void) { unsafe { (mem::size_of::() as size_t, self.id_ptr() as *const c_void) } } } /* memory life cycle * | Trait | Exists in rust | Exists in OpenCL | Direction | * | Put | X | | rust -> opencl | * | Get | | X | opencl -> rust | * | Write | X | X | rust -> opencl | * | Read | X | X | opencl -> rust | *mut */ pub trait Put { fn put(&self, F) -> B where F: FnOnce(*const c_void, size_t) -> cl_mem; } pub trait Get { fn get(mem: &B, F) -> Self; } pub trait Write { fn write(&self, F); } pub trait Read { fn read(&mut self, F); } impl<'r, T> Put> for &'r [T] { fn put(&self, f: F) -> CLBuffer where F: FnOnce(*const c_void, size_t) -> cl_mem { CLBuffer { cl_buffer: f(self.as_ptr() as *const c_void, (self.len() * mem::size_of::()) as size_t), phantom: PhantomData, } } } impl<'r, T> Put> for &'r Vec { fn put(&self, f: F) -> CLBuffer where F: FnOnce(*const c_void, size_t) -> cl_mem { CLBuffer { cl_buffer: f(self.as_ptr() as *const c_void, (self.len() * mem::size_of::()) as size_t), phantom: PhantomData, } } } impl Put> for Vec { fn put(&self, f: F) -> CLBuffer where F: FnOnce(*const c_void, size_t) -> cl_mem { CLBuffer { cl_buffer: f(self.as_ptr() as *const c_void, (self.len() * mem::size_of::()) as size_t), phantom: PhantomData, } } } impl Get, T> for Vec { fn get(mem: &CLBuffer, f: F) -> Vec where F: FnOnce(size_t, *mut c_void, size_t) { let mut v: Vec = Vec::with_capacity(mem.len()); unsafe { v.set_len(mem.len()); } f(0, v.as_ptr() as *mut c_void, (v.len() * mem::size_of::()) as size_t); v } } impl<'r, T> Write for &'r [T] { fn write(&self, f: F) where F: FnOnce(size_t, *const c_void, size_t) { f(0, self.as_ptr() as *const c_void, (self.len() * mem::size_of::()) as size_t) } } impl<'r, T> Read for &'r mut [T] { fn read(&mut self, f: F) where F: FnOnce(size_t, *mut c_void, size_t) { let p = (*self).as_mut_ptr(); let len = self.len(); f(0, p as *mut c_void, (len * mem::size_of::()) as size_t) } } macro_rules! get_arg ( ($t:ty) => (impl Get, $t> for $t { fn get(_: &CLBuffer<$t>, f: F) -> $t where F: FnOnce(size_t, *mut c_void, size_t) { let mut v: $t = 0 as $t; f(0, (&mut v as *mut $t) as *mut c_void, mem::size_of::<$t>() as size_t); v as $t } }) ); get_arg!(isize); get_arg!(usize); get_arg!(u32); get_arg!(u64); get_arg!(i32); get_arg!(i64); get_arg!(f32); get_arg!(f64); macro_rules! put_arg ( ($t:ty) => (impl Put<$t, CLBuffer<$t>> for $t { fn put(&self, f: F) -> CLBuffer<$t> where F: FnOnce(*const c_void, size_t) -> cl_mem { CLBuffer { cl_buffer: f((self as *const $t) as *const c_void, mem::size_of::<$t>() as size_t), phantom: PhantomData, } } } ) ); put_arg!(isize); put_arg!(usize); put_arg!(u32); put_arg!(u64); put_arg!(i32); put_arg!(i64); put_arg!(f32); put_arg!(f64); macro_rules! read_arg ( ($t:ty) => (impl Read for $t { fn read(&mut self, f: F) where F: FnOnce(size_t, *mut c_void, size_t) { f(0, (self as *mut $t) as *mut c_void, mem::size_of::<$t>() as size_t) } } ) ); read_arg!(isize); read_arg!(usize); read_arg!(u32); read_arg!(u64); read_arg!(i32); read_arg!(i64); read_arg!(f32); read_arg!(f64); macro_rules! write_arg ( ($t:ty) => (impl Write for $t { fn write(&self, f: F) where F: FnOnce(size_t, *const c_void, size_t) { f(0, (self as *const $t) as *const c_void, mem::size_of::<$t>() as size_t) } } ) ); write_arg!(isize); write_arg!(usize); write_arg!(u32); write_arg!(u64); write_arg!(i32); write_arg!(i64); write_arg!(f32); write_arg!(f64); ================================================ FILE: src/util.rs ================================================ //! Utility functions use hl::*; pub fn create_compute_context() -> Result<(Device, Context, CommandQueue), &'static str> { let platforms = get_platforms(); if platforms.len() == 0 { return Err("No platform found"); } let mut devices = platforms[0].get_devices(); if devices.len() == 0 { Err("No device found") } else { let device = devices.remove(0); let context = device.create_context(); let queue = context.create_command_queue(&device); Ok((device, context, queue)) } } #[derive(Copy, Clone)] pub enum PreferedType { Any, CPUPrefered, GPUPrefered, CPUOnly, GPUOnly, } pub fn create_compute_context_prefer(cltype: PreferedType) -> Result<(Device, Context, CommandQueue), &'static str> { let platforms = get_platforms(); for platform in platforms.iter() { let types = match cltype { PreferedType::Any => vec![DeviceType::CPU, DeviceType::GPU], PreferedType::CPUPrefered | PreferedType::CPUOnly => vec![DeviceType::CPU], PreferedType::GPUPrefered | PreferedType::GPUOnly => vec![DeviceType::GPU] }; let mut devices = platform.get_devices_by_types(&types[..]); if devices.len() > 0 { let device = devices.remove(0); let context = device.create_context(); let queue = context.create_command_queue(&device); return Ok((device, context, queue)) } } match cltype { PreferedType::Any | PreferedType::CPUPrefered | PreferedType::GPUPrefered => create_compute_context(), _ => Err("Could not find valid implementation") } } ================================================ FILE: tests/test.rs ================================================ #![feature(slice_bytes)] #[macro_use] extern crate log; extern crate opencl; use opencl::hl::*; macro_rules! expect ( ($test: expr, $expected: expr) => ({ let test = $test; let expected = $expected; if test != expected { panic!(format!("Test failure in {}:", // " expected {}, got {}", stringify!($test)/*, expected, test*/)) } } ) ); pub fn test_all_platforms_devices(test: &mut F) where F: FnMut(&Device, &Context, &CommandQueue) { let platforms = get_platforms(); for p in platforms.iter() { let devices = p.get_devices(); for d in devices.iter() { let context = d.create_context(); let queue = context.create_command_queue(d); test(d, &context, &queue); } } } mod mem { use std::slice; use opencl::mem::{Read, Write}; fn read_write(src: &W, dst: &mut R) { // find the max size of the input buffer let mut max = 0; src.write(|off, _, len| { if max < off + len { max = off + len; } }); let max = max as usize; let mut buffer: Vec = Vec::new(); unsafe { buffer.reserve(max); buffer.set_len(max); } // copy from input into buffer src.write(|off, ptr, len| { let off = off as usize; let len = len as usize; assert!(buffer.len() >= (off + len) as usize); let target = &mut buffer[off .. off + len]; unsafe { let ptr = ptr as *const u8; let src = slice::from_raw_parts(ptr, len); slice::bytes::copy_memory(src, target); } }); // copy from buffer into output dst.read(|off, ptr, len| { let off = off as usize; let len = len as usize; assert!(buffer.len() >= (off + len) as usize); let src = &buffer[off .. off + len]; unsafe { let ptr = ptr as *mut u8; let mut dst = slice::from_raw_parts_mut(ptr, len); slice::bytes::copy_memory(src, dst); } }) } #[test] fn read_write_slice() { let input: &[isize] = &[0, 1, 2, 3, 4, 5, 6, 7]; let mut output: &mut [isize] = &mut [0, 0, 0, 0, 0, 0, 0, 0]; read_write(&input, &mut output); expect!(input, output); } #[test] fn read_write_int() { let input: isize = 3141; let mut output: isize = 0; read_write(&input, &mut output); expect!(input, output); } #[test] fn read_write_uint() { let input : usize = 3141; let mut output : usize = 0; read_write(&input, &mut output); expect!(input, output); } #[test] fn read_write_f32() { let input : f32 = 3141.; let mut output : f32 = 0.; read_write(&input, &mut output); expect!(input, output); } #[test] fn read_write_f64() { let input : f64 = 3141.; let mut output : f64 = 0.; read_write(&input, &mut output); expect!(input, output); } } #[cfg(test)] mod hl { use opencl::cl::*; use opencl::hl::*; use opencl::mem::*; use opencl::util; #[test] fn program_build() { let src = "__kernel void test(__global int *i) { \ *i += 1; \ }"; ::test_all_platforms_devices(&mut |device, ctx, _| { let prog = ctx.create_program_from_source(src); prog.build(device).unwrap(); }) } #[test] fn simple_kernel() { let src = "__kernel void test(__global int *i) { \ *i += 1; \ }"; ::test_all_platforms_devices(&mut |device, ctx, queue| { let prog = ctx.create_program_from_source(src); prog.build(device).unwrap(); let k = prog.create_kernel("test"); let v = ctx.create_buffer_from(vec![1isize], CL_MEM_READ_WRITE); k.set_arg(0, &v); queue.enqueue_async_kernel(&k, 1isize, None, ()).wait(); let v: Vec = queue.get(&v, ()); expect!(v[0], 2); }) } #[test] fn add_k() { let src = "__kernel void test(__global int *i, long int k) { \ *i += k; \ }"; ::test_all_platforms_devices(&mut |device, ctx, queue| { let prog = ctx.create_program_from_source(src); prog.build(device).unwrap(); let k = prog.create_kernel("test"); let v = ctx.create_buffer_from(vec![1isize], CL_MEM_READ_WRITE); k.set_arg(0, &v); k.set_arg(1, &42isize); queue.enqueue_async_kernel(&k, 1isize, None, ()).wait(); let v: Vec = queue.get(&v, ()); expect!(v[0], 43); }) } #[test] fn simple_kernel_index() { let src = "__kernel void test(__global int *i) { \ *i += 1; \ }"; ::test_all_platforms_devices(&mut |device, ctx, queue| { let prog = ctx.create_program_from_source(src); prog.build(device).unwrap(); let k = prog.create_kernel("test"); let v = ctx.create_buffer_from(vec![1isize], CL_MEM_READ_WRITE); k.set_arg(0, &v); queue.enqueue_async_kernel(&k, 1isize, None, ()).wait(); let v: Vec = queue.get(&v, ()); expect!(v[0], 2); }) } #[test] fn chain_kernel_event() { let src = "__kernel void test(__global int *i) { \ *i += 1; \ }"; ::test_all_platforms_devices(&mut |device, ctx, queue| { let prog = ctx.create_program_from_source(src); prog.build(device).unwrap(); let k = prog.create_kernel("test"); let v = ctx.create_buffer_from(vec![1isize], CL_MEM_READ_WRITE); k.set_arg(0, &v); let mut e : Option = None; for _ in 0isize .. 8 { e = Some(queue.enqueue_async_kernel(&k, 1isize, None, e)); } e.wait(); let v: Vec = queue.get(&v, ()); expect!(v[0], 9); }) } #[test] fn chain_kernel_event_list() { let src = "__kernel void inc(__global int *i) { \ *i += 1; \ } \ __kernel void add(__global int *a, __global int *b, __global int *c) { \ *c = *a + *b; \ }"; ::test_all_platforms_devices(&mut |device, ctx, queue| { let prog = ctx.create_program_from_source(src); prog.build(device).unwrap(); let k_inc_a = prog.create_kernel("inc"); let k_inc_b = prog.create_kernel("inc"); let k_add = prog.create_kernel("add"); let a = ctx.create_buffer_from(vec![1isize], CL_MEM_READ_WRITE); let b = ctx.create_buffer_from(vec![1isize], CL_MEM_READ_WRITE); let c = ctx.create_buffer_from(vec![1isize], CL_MEM_READ_WRITE); k_inc_a.set_arg(0, &a); k_inc_b.set_arg(0, &b); let event_list = [ queue.enqueue_async_kernel(&k_inc_a, 1isize, None, ()), queue.enqueue_async_kernel(&k_inc_b, 1isize, None, ()), ]; k_add.set_arg(0, &a); k_add.set_arg(1, &b); k_add.set_arg(2, &c); let event = queue.enqueue_async_kernel(&k_add, 1isize, None, &event_list[..]); let v: Vec = queue.get(&c, event); expect!(v[0], 4); }) } #[test] fn kernel_2d() { let src = "__kernel void test(__global long int *N) { \ int i = get_global_id(0); \ int j = get_global_id(1); \ int s = get_global_size(0); \ N[i * s + j] = i * j; }"; ::test_all_platforms_devices(&mut |device, ctx, queue| { let prog = ctx.create_program_from_source(src); match prog.build(device) { Ok(_) => (), Err(build_log) => { println!("Error building program:\n"); println!("{}", build_log); panic!(""); } } let k = prog.create_kernel("test"); let v = ctx.create_buffer_from(&[1isize, 2, 3, 4, 5, 6, 7, 8, 9][..], CL_MEM_READ_ONLY); k.set_arg(0, &v); queue.enqueue_async_kernel(&k, (3isize, 3isize), None, ()).wait(); let v: Vec = queue.get(&v, ()); expect!(v, vec!(0, 0, 0, 0, 1, 2, 0, 2, 4)); }) } #[test] fn memory_read_write() { ::test_all_platforms_devices(&mut |_, ctx, queue| { let buffer: CLBuffer = ctx.create_buffer(8, CL_MEM_READ_ONLY); let input = [0isize, 1, 2, 3, 4, 5, 6, 7]; let mut output = [0isize, 0, 0, 0, 0, 0, 0, 0]; queue.write(&buffer, &&input[..], ()); queue.read(&buffer, &mut &mut output[..], ()); expect!(input, output); }) } #[test] fn memory_read_vec() { ::test_all_platforms_devices(&mut |_, ctx, queue| { let input = [0isize, 1, 2, 3, 4, 5, 6, 7]; let buffer = ctx.create_buffer_from(&input[..], CL_MEM_READ_WRITE); let output: Vec = queue.get(&buffer, ()); expect!(&input[..], &output[..]); }) } #[test] fn memory_read_owned() { ::test_all_platforms_devices(&mut |_, ctx, queue| { let input = vec!(0isize, 1, 2, 3, 4, 5, 6, 7); let buffer = ctx.create_buffer_from(&input, CL_MEM_READ_WRITE); let output: Vec = queue.get(&buffer, ()); expect!(input, output); }) } #[test] fn memory_read_owned_clone() { ::test_all_platforms_devices(&mut |_, ctx, queue| { let input = vec!(0isize, 1, 2, 3, 4, 5, 6, 7); let buffer = ctx.create_buffer_from(input.clone(), CL_MEM_READ_WRITE); let output: Vec = queue.get(&buffer, ()); expect!(input, output); }) } #[test] fn event_get_times() { let src = "__kernel void test(__global int *i) { \ *i += 1; \ }"; let (device, ctx, queue) = util::create_compute_context().unwrap(); let prog = ctx.create_program_from_source(src); prog.build(&device).unwrap(); let k = prog.create_kernel("test"); let v = ctx.create_buffer_from(vec![1isize], CL_MEM_READ_WRITE); k.set_arg(0, &v); let e = queue.enqueue_async_kernel(&k, 1isize, None, ()); e.wait(); // the that are returned are not useful for unit test, this test // is mostly testing that opencl returns no error e.queue_time(); e.submit_time(); e.start_time(); e.end_time(); } } #[cfg(test)] mod array { use opencl::array::*; use opencl::cl::CL_MEM_READ_WRITE; #[test] fn put_get_2d() { ::test_all_platforms_devices(&mut |_, ctx, queue| { let arr_in = Array2D::new(8, 8, |x, y| {(x+y) as isize}); let arr_cl = ctx.create_buffer_from(&arr_in, CL_MEM_READ_WRITE); let arr_out: Array2D = queue.get(&arr_cl, ()); for x in 0usize.. 8usize { for y in 0usize..8usize { expect!(arr_in.get(x, y), arr_out.get(x, y)); } } }) } #[test] fn read_write_2d() { ::test_all_platforms_devices(&mut |_, ctx, queue| { let added = Array2D::new(8, 8, |x, y| {(x+y) as isize}); let zero = Array2D::new(8, 8, |_, _| {(0) as isize}); let mut out = Array2D::new(8, 8, |_, _| {(0) as isize}); /* both are zeroed */ let a_cl = ctx.create_buffer_from(&zero, CL_MEM_READ_WRITE); queue.write(&a_cl, &added, ()); queue.read(&a_cl, &mut out, ()); for x in 0usize .. 8usize { for y in 0usize .. 8usize { expect!(added.get(x, y), out.get(x, y)); } } }) } #[test] fn kernel_2d() { ::test_all_platforms_devices(&mut |device, ctx, queue| { let mut a = Array2D::new(8, 8, |_, _| {(0) as i32}); let b = Array2D::new(8, 8, |x, y| {(x*y) as i32}); let a_cl = ctx.create_buffer_from(&a, CL_MEM_READ_WRITE); let src = "__kernel void test(__global int *a) { \ int x = get_global_id(0); \ int y = get_global_id(1); \ int size_x = get_global_size(0); \ a[size_x*y + x] = x*y; \ }"; let prog = ctx.create_program_from_source(src); match prog.build(device) { Ok(_) => (), Err(build_log) => { println!("Error building program:\n"); println!("{}", build_log); panic!(""); } } let k = prog.create_kernel("test"); k.set_arg(0, &a_cl); let event = queue.enqueue_async_kernel(&k, (8isize, 8isize), None, ()); queue.read(&a_cl, &mut a, &event); for x in 0usize .. 8usize { for y in 0usize .. 8usize { expect!(a.get(x, y), b.get(x, y)); } } }) } #[test] fn put_get_3d() { ::test_all_platforms_devices(&mut |_, ctx, queue| { let arr_in = Array3D::new(8, 8, 8, |x, y, z| {(x+y+z) as isize}); let arr_cl = ctx.create_buffer_from(&arr_in, CL_MEM_READ_WRITE); let arr_out: Array3D = queue.get(&arr_cl, ()); for x in 0usize .. 8usize { for y in 0usize .. 8usize { for z in 0usize .. 8usize { expect!(arr_in.get(x, y, z), arr_out.get(x, y, z)); } } } }) } #[test] fn read_write_3d() { ::test_all_platforms_devices(&mut |_, ctx, queue| { let added = Array3D::new(8, 8, 8, |x, y, z| {(x+y+z) as isize}); let zero = Array3D::new(8, 8, 8, |_, _, _| {(0) as isize}); let mut out = Array3D::new(8, 8, 8, |_, _, _| {(0) as isize}); /* both are zeroed */ let a_cl = ctx.create_buffer_from(&zero, CL_MEM_READ_WRITE); queue.write(&a_cl, &added, ()); queue.read(&a_cl, &mut out, ()); for x in 0usize .. 8usize { for y in 0usize .. 8usize { for z in 0usize .. 8usize { expect!(added.get(x, y, z), out.get(x, y, z)); } } } }) } #[test] fn kernel_3d() { ::test_all_platforms_devices(&mut |device, ctx, queue| { let mut a = Array3D::new(8, 8, 8, |_, _, _| {(0) as i32}); let b = Array3D::new(8, 8, 8, |x, y, z| {(x*y*z) as i32}); let a_cl = ctx.create_buffer_from(&a, CL_MEM_READ_WRITE); let src = "__kernel void test(__global int *a) { \ int x = get_global_id(0); \ int y = get_global_id(1); \ int z = get_global_id(2); \ int size_x = get_global_size(0); \ int size_y = get_global_size(1); \ a[size_x*size_y*z + size_x*y + x] = x*y*z; \ }"; let prog = ctx.create_program_from_source(src); match prog.build(device) { Ok(_) => (), Err(build_log) => { println!("Error building program:\n"); println!("{}", build_log); panic!(""); } } let k = prog.create_kernel("test"); k.set_arg(0, &a_cl); let event = queue.enqueue_async_kernel(&k, (8isize, 8isize, 8isize), None, ()); queue.read(&a_cl, &mut a, &event); for x in 0usize .. 8usize { for y in 0usize .. 8usize { for z in 0usize .. 8usize { expect!(a.get(x, y, z), b.get(x, y, z)); } } } }) } } #[cfg(test)] mod ext { use opencl::ext; use opencl::hl::*; #[test] fn try_load_all_extensions() { let platforms = get_platforms(); for platform in platforms.into_iter() { let platform_id = platform.get_id(); macro_rules! check_ext { ($ext:ident) => { match ext::$ext::load(platform_id) { Ok(_) => { info!("Extension {} loaded successfully.", stringify!($ext)) } Err(_) => { info!("Error loading extension {}.", stringify!($ext)) } } } } check_ext!(cl_khr_fp64); check_ext!(cl_khr_fp16); check_ext!(cl_APPLE_SetMemObjectDestructor); check_ext!(cl_APPLE_ContextLoggingFunctions); check_ext!(cl_khr_icd); check_ext!(cl_nv_device_attribute_query); check_ext!(cl_amd_device_attribute_query); check_ext!(cl_arm_printf); check_ext!(cl_ext_device_fission); check_ext!(cl_qcom_ext_host_ptr); check_ext!(cl_qcom_ion_host_ptr); } } } #[cfg(test)] mod cl { use opencl::cl::CLStatus::*; #[test] fn clstatus_str() { let x = CL_SUCCESS; expect!(format!("{}", x), "CL_SUCCESS"); let y = CL_DEVICE_NOT_FOUND; expect!(y.to_string(), "CL_DEVICE_NOT_FOUND"); } }