├── COPYRIGHT ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── Makefile ├── README.md ├── 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 /COPYRIGHT: -------------------------------------------------------------------------------- 1 | rust-opencl - OpenCL Binding and Higher Level Wrapper for Rust. 2 | Copyright (C) 2013 - The rust-opencl Developers 3 | 4 | Licensed under the Apache License, Version 2.0 5 | or the MIT license , at your option. All files in the project 6 | may not be copied, modified, or distributed except according to those terms. 7 | 8 | Copies of both licenses are included: LICENSE-APACHE and LICENSE-MIT 9 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "opencl" 3 | version = "0.3.0-dev" 4 | authors = [ "Colin Sherratt ", 5 | "Eric Holk ", 6 | "Ian Daniher ", 7 | "Luqman Aden ", 8 | "Milinda Pathirage ", 9 | "Sébastien Crozet ", 10 | "Mathijs Henquet " 11 | ] 12 | repository = "https://github.com/luqmana/rust-opencl" 13 | license = "MIT/Apache-2.0" 14 | description = "OpenCL bindings for Rust." 15 | keywords = ["opencl", "bindings", "ffi", "gpu", "compute"] 16 | 17 | [lib] 18 | name = "opencl" 19 | 20 | [[example]] 21 | name = "demo" 22 | path = "examples/demo/main.rs" 23 | 24 | [[example]] 25 | name = "platform" 26 | path = "examples/platform/main.rs" 27 | 28 | [dependencies] 29 | log = "^0.3.1" 30 | libc = "^0.1.8" -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | http://opensource.org/licenses/MIT 3 | 4 | Permission is hereby granted, free of charge, to any 5 | person obtaining a copy of this software and associated 6 | documentation files (the "Software"), to deal in the 7 | Software without restriction, including without 8 | limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software 11 | is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice 15 | shall be included in all copies or substantial portions 16 | of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 | DEALINGS IN THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | ifndef RUSTC 3 | RUSTC = rustc 4 | endif 5 | 6 | ifndef TARGET_DIR 7 | TARGET_DIR = target/ 8 | endif 9 | 10 | RUSTC_OPTS = -g -L $(TARGET_DIR) --out-dir $(TARGET_DIR) 11 | 12 | OPENCL_SRC = \ 13 | lib.rs \ 14 | CL.rs \ 15 | error.rs \ 16 | hl.rs \ 17 | util.rs \ 18 | mem.rs \ 19 | array.rs 20 | 21 | OPENCL_ROOT = $(shell pwd) 22 | 23 | .PHONY: all 24 | all: lib 25 | 26 | 27 | .PHONY: debug 28 | debug: lib demo 29 | gdb --cd=./ target/demo 30 | 31 | 32 | .PHONY: lib 33 | lib: target_dir $(TARGET_DIR)libopencl.rlib 34 | 35 | $(TARGET_DIR)libopencl.rlib: src/* 36 | rustc $(RUSTC_OPTS) src/lib.rs 37 | 38 | 39 | .PHONY: target_dir 40 | target_dir: $(TARGET_DIR) 41 | 42 | $(TARGET_DIR): 43 | mkdir -p $(TARGET_DIR) 44 | 45 | 46 | .PHONY: demo 47 | demo: target_dir $(TARGET_DIR)demo 48 | 49 | $(TARGET_DIR)demo: $(TARGET_DIR)libopencl.rlib test/demo.rs 50 | env OPENCL_ROOT=$(OPENCL_ROOT) rustc $(RUSTC_OPTS) test/demo.rs 51 | 52 | 53 | .PHONY: check 54 | check: lib 55 | rustc $(RUSTC_OPTS) --test test/test.rs 56 | $(TARGET_DIR)test 57 | 58 | 59 | .PHONY: clean 60 | clean: 61 | rm -rf $(TARGET_DIR) 62 | 63 | .PHONY: docs 64 | docs: 65 | rustdoc src/lib.rs 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rust-opencl 2 | OpenCL bindings for Rust. 3 | -------------------------------------------------------------------------------- /examples/demo/demo.ocl: -------------------------------------------------------------------------------- 1 | __kernel void vector_add(__global const long *A, __global const long *B, __global long *C) { 2 | int i = get_global_id(0); 3 | C[i] = A[i] + B[i]; 4 | } 5 | -------------------------------------------------------------------------------- /examples/demo/main.rs: -------------------------------------------------------------------------------- 1 | extern crate opencl; 2 | 3 | use opencl::mem::CLBuffer; 4 | use std::fmt; 5 | 6 | fn main() 7 | { 8 | let ker = include_str!("demo.ocl"); 9 | println!("ker {}", ker); 10 | 11 | let vec_a = vec![0isize, 1, 2, -3, 4, 5, 6, 7]; 12 | let vec_b = vec![-7isize, -6, 5, -4, 0, -1, 2, 3]; 13 | 14 | let (device, ctx, queue) = opencl::util::create_compute_context().unwrap(); 15 | 16 | println!("{}", device.name()); 17 | 18 | let a: CLBuffer = ctx.create_buffer(vec_a.len(), opencl::cl::CL_MEM_READ_ONLY); 19 | let b: CLBuffer = ctx.create_buffer(vec_a.len(), opencl::cl::CL_MEM_READ_ONLY); 20 | let c: CLBuffer = ctx.create_buffer(vec_a.len(), opencl::cl::CL_MEM_WRITE_ONLY); 21 | 22 | queue.write(&a, &&vec_a[..], ()); 23 | queue.write(&b, &&vec_b[..], ()); 24 | 25 | let program = ctx.create_program_from_source(ker); 26 | program.build(&device).ok().expect("Couldn't build program."); 27 | 28 | 29 | let kernel = program.create_kernel("vector_add"); 30 | 31 | kernel.set_arg(0, &a); 32 | kernel.set_arg(1, &b); 33 | kernel.set_arg(2, &c); 34 | 35 | let event = queue.enqueue_async_kernel(&kernel, vec_a.len(), None, ()); 36 | 37 | let vec_c: Vec = queue.get(&c, &event); 38 | 39 | println!(" {}", string_from_slice(&vec_a[..])); 40 | println!("+ {}", string_from_slice(&vec_b[..])); 41 | println!("= {}", string_from_slice(&vec_c[..])); 42 | } 43 | 44 | fn string_from_slice(slice: &[T]) -> String { 45 | let mut st = String::from("["); 46 | let mut first = true; 47 | 48 | for i in slice.iter() { 49 | if !first { 50 | st.push_str(", "); 51 | } 52 | else { 53 | first = false; 54 | } 55 | st.push_str(&*i.to_string()) 56 | } 57 | 58 | st.push_str("]"); 59 | return st 60 | } 61 | -------------------------------------------------------------------------------- /examples/platform/main.rs: -------------------------------------------------------------------------------- 1 | extern crate opencl; 2 | 3 | use opencl::hl; 4 | 5 | fn main() { 6 | for platform in hl::get_platforms().iter() { 7 | println!("Platform: {}", platform.name()); 8 | println!("Platform Version: {}", platform.version()); 9 | println!("Vendor: {}", platform.vendor()); 10 | println!("Profile: {}", platform.profile()); 11 | println!("Available extensions: {}", platform.extensions()); 12 | println!("Available devices:"); 13 | for device in platform.get_devices().iter() { 14 | println!(" Name: {}", device.name()); 15 | println!(" Type: {}", device.device_type()); 16 | println!(" Profile: {}", device.profile()); 17 | println!(" Compute Units: {}", device.compute_units()); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/OpenCL/error.rs: -------------------------------------------------------------------------------- 1 | //! Error handling utilities. 2 | 3 | use CL::*; 4 | use std::fmt::{Show, Formatter, Result}; 5 | 6 | impl Show for CLStatus { 7 | fn fmt(&self, f: &mut Formatter) -> Result { 8 | write!(f.buf, "{:?}", *self) 9 | } 10 | } 11 | 12 | macro_rules! convert( 13 | ($e: expr, $x: ident) => (if $e == $x as cl_int { 14 | Some($x) 15 | } else { None }); 16 | 17 | ($e: expr, $x: ident, $($xs: ident),+) => (if $e == $x as cl_int { 18 | Some($x) 19 | } else { convert!($e, $($xs),+) }) 20 | ) 21 | 22 | pub fn try_convert(status: cl_int) -> Option { 23 | convert!(status, 24 | CL_SUCCESS, 25 | CL_DEVICE_NOT_FOUND, 26 | CL_DEVICE_NOT_AVAILABLE, 27 | CL_COMPILER_NOT_AVAILABLE, 28 | CL_MEM_OBJECT_ALLOCATION_FAILURE, 29 | CL_OUT_OF_RESOURCES, 30 | CL_OUT_OF_HOST_MEMORY, 31 | CL_PROFILING_INFO_NOT_AVAILABLE, 32 | CL_MEM_COPY_OVERLAP, 33 | CL_IMAGE_FORMAT_MISMATCH, 34 | CL_IMAGE_FORMAT_NOT_SUPPORTED, 35 | CL_BUILD_PROGRAM_FAILURE, 36 | CL_MAP_FAILURE, 37 | CL_MISALIGNED_SUB_BUFFER_OFFSET, 38 | CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST, 39 | CL_INVALID_VALUE, 40 | CL_INVALID_DEVICE_TYPE, 41 | CL_INVALID_PLATFORM, 42 | CL_INVALID_DEVICE, 43 | CL_INVALID_CONTEXT, 44 | CL_INVALID_QUEUE_PROPERTIES, 45 | CL_INVALID_COMMAND_QUEUE, 46 | CL_INVALID_HOST_PTR, 47 | CL_INVALID_MEM_OBJECT, 48 | CL_INVALID_IMAGE_FORMAT_DESCRIPTOR, 49 | CL_INVALID_IMAGE_SIZE, 50 | CL_INVALID_SAMPLER, 51 | CL_INVALID_BINARY, 52 | CL_INVALID_BUILD_OPTIONS, 53 | CL_INVALID_PROGRAM, 54 | CL_INVALID_PROGRAM_EXECUTABLE, 55 | CL_INVALID_KERNEL_NAME, 56 | CL_INVALID_KERNEL_DEFINITION, 57 | CL_INVALID_KERNEL, 58 | CL_INVALID_ARG_INDEX, 59 | CL_INVALID_ARG_VALUE, 60 | CL_INVALID_ARG_SIZE, 61 | CL_INVALID_KERNEL_ARGS, 62 | CL_INVALID_WORK_DIMENSION, 63 | CL_INVALID_WORK_GROUP_SIZE, 64 | CL_INVALID_WORK_ITEM_SIZE, 65 | CL_INVALID_GLOBAL_OFFSET, 66 | CL_INVALID_EVENT_WAIT_LIST, 67 | CL_INVALID_EVENT, 68 | CL_INVALID_OPERATION, 69 | CL_INVALID_GL_OBJECT, 70 | CL_INVALID_BUFFER_SIZE, 71 | CL_INVALID_MIP_LEVEL, 72 | CL_INVALID_GLOBAL_WORK_SIZE, 73 | CL_INVALID_PROPERTY) 74 | } 75 | 76 | pub fn convert(status: cl_int) -> CLStatus { 77 | match try_convert(status) { 78 | Some(s) => s, 79 | None => fail!(format!("Unknown OpenCL Status Code: {:?}", status)) 80 | } 81 | } 82 | 83 | fn error_str(status: cl_int) -> ~str { 84 | match try_convert(status) { 85 | Some(s) => s.to_str(), 86 | None => format!("Unknown Error: {:?}", status) 87 | } 88 | } 89 | 90 | pub fn check(status: cl_int, message: &str) { 91 | if status != CL_SUCCESS as cl_int { 92 | fail!(format!("{:?} ({:?})", message, error_str(status))) 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/array.rs: -------------------------------------------------------------------------------- 1 | //! Two- and three-dimensional array support. 2 | 3 | use cl::*; 4 | use cl::ll::*; 5 | use mem::*; 6 | use std::marker::PhantomData; 7 | use std::mem; 8 | use std::vec::Vec; 9 | use libc::{size_t, c_void}; 10 | 11 | use hl::KernelArg; 12 | 13 | pub struct Array3D { 14 | width: usize, 15 | height: usize, 16 | depth: usize, 17 | dat: Vec 18 | } 19 | 20 | pub struct Array3DCL { 21 | width: usize, 22 | height: usize, 23 | depth: usize, 24 | buf: cl_mem, 25 | phantom: PhantomData, 26 | } 27 | 28 | impl Array3D { 29 | pub fn new(width: usize, height: usize, depth: usize, 30 | val: F) 31 | -> Array3D 32 | where F: Fn(usize, usize, usize) -> T 33 | { 34 | let mut dat: Vec = Vec::new(); 35 | for x in 0 .. width { 36 | for y in 0 .. height { 37 | for z in 0 .. depth { 38 | dat.push(val(x, y, z)); 39 | } 40 | } 41 | } 42 | 43 | Array3D { 44 | width: width, 45 | height: height, 46 | depth: depth, 47 | dat: dat 48 | } 49 | } 50 | 51 | pub fn set(&mut self, x: usize, y: usize, z: usize, val: T) 52 | { 53 | self.dat[self.width*self.height*z + self.width*y + x] = val; 54 | } 55 | 56 | pub fn get(&self, x: usize, y: usize, z: usize) -> T 57 | { 58 | (&self.dat[..])[self.width*self.height*z + self.width*y + x].clone() 59 | } 60 | } 61 | 62 | impl Drop for Array3DCL { 63 | fn drop(&mut self) { 64 | unsafe { 65 | clReleaseMemObject(self.buf); 66 | } 67 | } 68 | } 69 | 70 | impl<'r, T> Put, Array3DCL> for &'r Array3D 71 | { 72 | fn put(&self, f: F) 73 | -> Array3DCL 74 | where F: FnOnce(*const c_void, size_t) -> cl_mem 75 | { 76 | let p = self.dat.as_ptr(); 77 | let len = self.dat.len(); 78 | let out = f(p as *const c_void, (len * mem::size_of::()) as size_t); 79 | 80 | Array3DCL{ 81 | width: self.width, 82 | height: self.height, 83 | depth: self.depth, 84 | buf: out, 85 | phantom: PhantomData, 86 | } 87 | } 88 | } 89 | 90 | 91 | impl Get, Array3D> for Array3D 92 | { 93 | fn get(arr: &Array3DCL, f: F) 94 | -> Array3D 95 | where F: FnOnce(size_t, *mut c_void, size_t) 96 | { 97 | let mut v: Vec = Vec::with_capacity(arr.len()); 98 | unsafe { 99 | v.set_len(arr.len()); 100 | } 101 | 102 | let p = v.as_mut_ptr(); 103 | let len = v.len(); 104 | f(0, p as *mut c_void, (len * mem::size_of::()) as size_t); 105 | 106 | Array3D { 107 | width: arr.width, 108 | height: arr.height, 109 | depth: arr.depth, 110 | dat: v, 111 | } 112 | } 113 | } 114 | 115 | impl Write for Array3D { 116 | fn write(&self, f: F) 117 | where F: FnOnce(size_t, *const c_void, size_t) 118 | { 119 | let p = self.dat.as_ptr(); 120 | let len = self.dat.len(); 121 | f(0, p as *const c_void, (len * mem::size_of::()) as size_t) 122 | } 123 | } 124 | 125 | impl Read for Array3D { 126 | fn read(&mut self, f: F) 127 | where F: FnOnce(size_t, *mut c_void, size_t) 128 | { 129 | let p = self.dat.as_ptr(); 130 | let len = self.dat.len(); 131 | f(0, p as *mut c_void, (len * mem::size_of::()) as size_t) 132 | } 133 | } 134 | 135 | impl Buffer for Array3DCL { 136 | unsafe fn id_ptr(&self) -> *const cl_mem { 137 | &self.buf as *const cl_mem 138 | } 139 | 140 | fn len(&self) -> usize { 141 | self.width * self.height * self.depth 142 | } 143 | } 144 | 145 | impl KernelArg for Array3DCL { 146 | fn get_value(&self) -> (size_t, *const c_void) 147 | { 148 | (mem::size_of::() as size_t, 149 | unsafe { self.id_ptr() } as *const c_void) 150 | } 151 | } 152 | 153 | pub struct Array2D { 154 | width: usize, 155 | height: usize, 156 | dat: Vec, 157 | } 158 | 159 | pub struct Array2DCL { 160 | width: usize, 161 | height: usize, 162 | buf: cl_mem, 163 | phantom: PhantomData, 164 | } 165 | 166 | impl Array2D { 167 | pub fn new(width: usize, height: usize, val: F) -> Array2D 168 | where F: Fn(usize, usize) -> T 169 | { 170 | let mut dat: Vec = Vec::new(); 171 | for x in 0 .. width { 172 | for y in 0 .. height { 173 | dat.push(val(x, y)); 174 | } 175 | } 176 | Array2D { 177 | width: width, 178 | height: height, 179 | dat: dat, 180 | } 181 | } 182 | 183 | pub fn set(&mut self, x: usize, y: usize, val: T) { 184 | self.dat[self.width*y + x] = val; 185 | } 186 | 187 | pub fn get(&self, x: usize, y: usize) -> T { 188 | (&self.dat[..])[self.width*y + x].clone() 189 | } 190 | } 191 | 192 | impl Drop for Array2DCL { 193 | fn drop(&mut self) { 194 | unsafe { 195 | clReleaseMemObject(self.buf); 196 | } 197 | } 198 | } 199 | 200 | impl<'r, T> Put, Array2DCL> for &'r Array2D 201 | { 202 | fn put(&self, f: F) -> Array2DCL 203 | where F: FnOnce(*const c_void, size_t) -> cl_mem 204 | { 205 | let p = self.dat.as_ptr(); 206 | let len = self.dat.len(); 207 | let out = f(p as *const c_void, (len * mem::size_of::()) as size_t); 208 | 209 | Array2DCL{ 210 | width: self.width, 211 | height: self.height, 212 | buf: out, 213 | phantom: PhantomData, 214 | } 215 | } 216 | } 217 | 218 | 219 | impl Get, Array2D> for Array2D 220 | { 221 | fn get(arr: &Array2DCL, f: F) 222 | -> Array2D 223 | where F: FnOnce(size_t, *mut c_void, size_t) 224 | { 225 | let mut v: Vec = Vec::with_capacity(arr.len()); 226 | unsafe { 227 | v.set_len(arr.len()) 228 | } 229 | 230 | let p = v.as_mut_ptr(); 231 | let len = v.len(); 232 | f(0, p as *mut c_void, (len * mem::size_of::()) as size_t); 233 | 234 | Array2D { 235 | width: arr.width, 236 | height: arr.height, 237 | dat: v 238 | } 239 | } 240 | } 241 | 242 | impl Write for Array2D { 243 | fn write(&self, f: F) 244 | where F: FnOnce(size_t, *const c_void, size_t) 245 | { 246 | let p = self.dat.as_ptr(); 247 | let len = self.dat.len(); 248 | f(0, p as *const c_void, (len * mem::size_of::()) as size_t) 249 | } 250 | } 251 | 252 | impl Read for Array2D { 253 | fn read(&mut self, f: F) 254 | where F: FnOnce(size_t, *mut c_void, size_t) 255 | { 256 | let p = self.dat.as_ptr(); 257 | let len = self.dat.len(); 258 | f(0, p as *mut c_void, (len * mem::size_of::()) as size_t) 259 | } 260 | } 261 | 262 | impl Buffer for Array2DCL { 263 | unsafe fn id_ptr(&self) -> *const cl_mem { 264 | &self.buf as *const cl_mem 265 | } 266 | 267 | fn len(&self) -> usize { 268 | self.width * self.height 269 | } 270 | } 271 | 272 | impl KernelArg for Array2DCL { 273 | fn get_value(&self) -> (size_t, *const c_void) 274 | { 275 | (mem::size_of::() as size_t, 276 | unsafe { self.id_ptr() } as *const c_void) 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /src/cl.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_camel_case_types, dead_code)] 2 | 3 | extern crate std; 4 | 5 | use libc; 6 | use std::fmt; 7 | 8 | /* Opaque types */ 9 | pub type cl_platform_id = *mut libc::c_void; 10 | pub type cl_device_id = *mut libc::c_void; 11 | pub type cl_context = *mut libc::c_void; 12 | pub type cl_command_queue = *mut libc::c_void; 13 | pub type cl_mem = *mut libc::c_void; 14 | pub type cl_program = *mut libc::c_void; 15 | pub type cl_kernel = *mut libc::c_void; 16 | pub type cl_event = *mut libc::c_void; 17 | pub type cl_sampler = *mut libc::c_void; 18 | 19 | /* Scalar types */ 20 | pub type cl_char = i8; 21 | pub type cl_uchar = u8; 22 | pub type cl_short = i16; 23 | pub type cl_ushort = u16; 24 | pub type cl_int = i32; 25 | pub type cl_uint = u32; 26 | pub type cl_long = i64; 27 | pub type cl_ulong = u64; 28 | 29 | pub type cl_half = u16; 30 | pub type cl_float = f32; 31 | pub type cl_double = f64; 32 | 33 | pub type cl_bool = cl_uint; 34 | pub type cl_bitfield = cl_ulong; 35 | pub type cl_device_type = cl_bitfield; 36 | pub type cl_platform_info = cl_uint; 37 | pub type cl_device_info = cl_uint; 38 | pub type cl_device_fp_config = cl_bitfield; 39 | pub type cl_device_mem_cache_type = cl_uint; 40 | pub type cl_device_local_mem_type = cl_uint; 41 | pub type cl_device_exec_capabilities = cl_bitfield; 42 | pub type cl_command_queue_properties = cl_bitfield; 43 | 44 | pub type cl_context_properties = libc::intptr_t; 45 | pub type cl_context_info = cl_uint; 46 | pub type cl_command_queue_info = cl_uint; 47 | pub type cl_channel_order = cl_uint; 48 | pub type cl_channel_type = cl_uint; 49 | pub type cl_mem_flags = cl_bitfield; 50 | pub type cl_mem_object_type = cl_uint; 51 | pub type cl_mem_info = cl_uint; 52 | pub type cl_image_info = cl_uint; 53 | pub type cl_buffer_create_type = cl_uint; 54 | pub type cl_addressing_mode = cl_uint; 55 | pub type cl_filter_mode = cl_uint; 56 | pub type cl_sampler_info = cl_uint; 57 | pub type cl_map_flags = cl_bitfield; 58 | pub type cl_program_info = cl_uint; 59 | pub type cl_program_build_info = cl_uint; 60 | pub type cl_build_status = cl_int; 61 | pub type cl_kernel_info = cl_uint; 62 | pub type cl_kernel_work_group_info = cl_uint; 63 | pub type cl_event_info = cl_uint; 64 | pub type cl_command_type = cl_uint; 65 | pub type cl_profiling_info = cl_uint; 66 | 67 | pub struct cl_image_format { 68 | image_channel_order: cl_channel_order, 69 | image_channel_data_type: cl_channel_type 70 | } 71 | 72 | pub struct cl_buffer_region { 73 | origin: libc::size_t, 74 | size: libc::size_t 75 | } 76 | 77 | 78 | /// OpenCL error codes. 79 | #[derive(PartialEq, Debug)] 80 | #[repr()] 81 | pub enum CLStatus { 82 | CL_SUCCESS = 0, 83 | CL_DEVICE_NOT_FOUND = -1, 84 | CL_DEVICE_NOT_AVAILABLE = -2, 85 | CL_COMPILER_NOT_AVAILABLE = -3, 86 | CL_MEM_OBJECT_ALLOCATION_FAILURE = -4, 87 | CL_OUT_OF_RESOURCES = -5, 88 | CL_OUT_OF_HOST_MEMORY = -6, 89 | CL_PROFILING_INFO_NOT_AVAILABLE = -7, 90 | CL_MEM_COPY_OVERLAP = -8, 91 | CL_IMAGE_FORMAT_MISMATCH = -9, 92 | CL_IMAGE_FORMAT_NOT_SUPPORTED = -10, 93 | CL_BUILD_PROGRAM_FAILURE = -11, 94 | CL_MAP_FAILURE = -12, 95 | CL_MISALIGNED_SUB_BUFFER_OFFSET = -13, 96 | CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST = -14, 97 | CL_INVALID_VALUE = -30, 98 | CL_INVALID_DEVICE_TYPE = -31, 99 | CL_INVALID_PLATFORM = -32, 100 | CL_INVALID_DEVICE = -33, 101 | CL_INVALID_CONTEXT = -34, 102 | CL_INVALID_QUEUE_PROPERTIES = -35, 103 | CL_INVALID_COMMAND_QUEUE = -36, 104 | CL_INVALID_HOST_PTR = -37, 105 | CL_INVALID_MEM_OBJECT = -38, 106 | CL_INVALID_IMAGE_FORMAT_DESCRIPTOR = -39, 107 | CL_INVALID_IMAGE_SIZE = -40, 108 | CL_INVALID_SAMPLER = -41, 109 | CL_INVALID_BINARY = -42, 110 | CL_INVALID_BUILD_OPTIONS = -43, 111 | CL_INVALID_PROGRAM = -44, 112 | CL_INVALID_PROGRAM_EXECUTABLE = -45, 113 | CL_INVALID_KERNEL_NAME = -46, 114 | CL_INVALID_KERNEL_DEFINITION = -47, 115 | CL_INVALID_KERNEL = -48, 116 | CL_INVALID_ARG_INDEX = -49, 117 | CL_INVALID_ARG_VALUE = -50, 118 | CL_INVALID_ARG_SIZE = -51, 119 | CL_INVALID_KERNEL_ARGS = -52, 120 | CL_INVALID_WORK_DIMENSION = -53, 121 | CL_INVALID_WORK_GROUP_SIZE = -54, 122 | CL_INVALID_WORK_ITEM_SIZE = -55, 123 | CL_INVALID_GLOBAL_OFFSET = -56, 124 | CL_INVALID_EVENT_WAIT_LIST = -57, 125 | CL_INVALID_EVENT = -58, 126 | CL_INVALID_OPERATION = -59, 127 | CL_INVALID_GL_OBJECT = -60, 128 | CL_INVALID_BUFFER_SIZE = -61, 129 | CL_INVALID_MIP_LEVEL = -62, 130 | CL_INVALID_GLOBAL_WORK_SIZE = -63, 131 | CL_INVALID_PROPERTY = -64, 132 | CL_PLATFORM_NOT_FOUND_KHR = -1001, 133 | } 134 | 135 | impl fmt::Display for CLStatus { 136 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 137 | write!(f, "{:?}", self) 138 | } 139 | } 140 | 141 | /* OpenCL Version */ 142 | pub static CL_VERSION_1_0: cl_bool = 1; 143 | pub static CL_VERSION_1_1: cl_bool = 1; 144 | 145 | /* cl_bool */ 146 | pub static CL_FALSE: cl_bool = 0; 147 | pub static CL_TRUE: cl_bool = 1; 148 | 149 | /* cl_platform_info */ 150 | pub static CL_PLATFORM_PROFILE: cl_uint = 0x0900; 151 | pub static CL_PLATFORM_VERSION: cl_uint = 0x0901; 152 | pub static CL_PLATFORM_NAME: cl_uint = 0x0902; 153 | pub static CL_PLATFORM_VENDOR: cl_uint = 0x0903; 154 | pub static CL_PLATFORM_EXTENSIONS: cl_uint = 0x0904; 155 | 156 | /* cl_device_type - bitfield */ 157 | pub static CL_DEVICE_TYPE_DEFAULT: cl_bitfield = 1 << 0; 158 | pub static CL_DEVICE_TYPE_CPU: cl_bitfield = 1 << 1; 159 | pub static CL_DEVICE_TYPE_GPU: cl_bitfield = 1 << 2; 160 | pub static CL_DEVICE_TYPE_ACCELERATOR: cl_bitfield = 1 << 3; 161 | pub static CL_DEVICE_TYPE_ALL: cl_bitfield = 0xFFFFFFFF; 162 | 163 | /* cl_device_info */ 164 | pub static CL_DEVICE_TYPE: cl_uint = 0x1000; 165 | pub static CL_DEVICE_VENDOR_ID: cl_uint = 0x1001; 166 | pub static CL_DEVICE_MAX_COMPUTE_UNITS: cl_uint = 0x1002; 167 | pub static CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS: cl_uint = 0x1003; 168 | pub static CL_DEVICE_MAX_WORK_GROUP_SIZE: cl_uint = 0x1004; 169 | pub static CL_DEVICE_MAX_WORK_ITEM_SIZES: cl_uint = 0x1005; 170 | pub static CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR: cl_uint = 0x1006; 171 | pub static CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT: cl_uint = 0x1007; 172 | pub static CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT: cl_uint = 0x1008; 173 | pub static CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG: cl_uint = 0x1009; 174 | pub static CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT: cl_uint = 0x100A; 175 | pub static CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE: cl_uint = 0x100B; 176 | pub static CL_DEVICE_MAX_CLOCK_FREQUENCY: cl_uint = 0x100C; 177 | pub static CL_DEVICE_ADDRESS_BITS: cl_uint = 0x100D; 178 | pub static CL_DEVICE_MAX_READ_IMAGE_ARGS: cl_uint = 0x100E; 179 | pub static CL_DEVICE_MAX_WRITE_IMAGE_ARGS: cl_uint = 0x100F; 180 | pub static CL_DEVICE_MAX_MEM_ALLOC_SIZE: cl_uint = 0x1010; 181 | pub static CL_DEVICE_IMAGE2D_MAX_WIDTH: cl_uint = 0x1011; 182 | pub static CL_DEVICE_IMAGE2D_MAX_HEIGHT: cl_uint = 0x1012; 183 | pub static CL_DEVICE_IMAGE3D_MAX_WIDTH: cl_uint = 0x1013; 184 | pub static CL_DEVICE_IMAGE3D_MAX_HEIGHT: cl_uint = 0x1014; 185 | pub static CL_DEVICE_IMAGE3D_MAX_DEPTH: cl_uint = 0x1015; 186 | pub static CL_DEVICE_IMAGE_SUPPORT: cl_uint = 0x1016; 187 | pub static CL_DEVICE_MAX_PARAMETER_SIZE: cl_uint = 0x1017; 188 | pub static CL_DEVICE_MAX_SAMPLERS: cl_uint = 0x1018; 189 | pub static CL_DEVICE_MEM_BASE_ADDR_ALIGN: cl_uint = 0x1019; 190 | pub static CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE: cl_uint = 0x101A; 191 | pub static CL_DEVICE_SINGLE_FP_CONFIG: cl_uint = 0x101B; 192 | pub static CL_DEVICE_GLOBAL_MEM_CACHE_TYPE: cl_uint = 0x101C; 193 | pub static CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE: cl_uint = 0x101D; 194 | pub static CL_DEVICE_GLOBAL_MEM_CACHE_SIZE: cl_uint = 0x101E; 195 | pub static CL_DEVICE_GLOBAL_MEM_SIZE: cl_uint = 0x101F; 196 | pub static CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE: cl_uint = 0x1020; 197 | pub static CL_DEVICE_MAX_CONSTANT_ARGS: cl_uint = 0x1021; 198 | pub static CL_DEVICE_LOCAL_MEM_TYPE: cl_uint = 0x1022; 199 | pub static CL_DEVICE_LOCAL_MEM_SIZE: cl_uint = 0x1023; 200 | pub static CL_DEVICE_ERROR_CORRECTION_SUPPORT: cl_uint = 0x1024; 201 | pub static CL_DEVICE_PROFILING_TIMER_RESOLUTION: cl_uint = 0x1025; 202 | pub static CL_DEVICE_ENDIAN_LITTLE: cl_uint = 0x1026; 203 | pub static CL_DEVICE_AVAILABLE: cl_uint = 0x1027; 204 | pub static CL_DEVICE_COMPILER_AVAILABLE: cl_uint = 0x1028; 205 | pub static CL_DEVICE_EXECUTION_CAPABILITIES: cl_uint = 0x1029; 206 | pub static CL_DEVICE_QUEUE_PROPERTIES: cl_uint = 0x102A; 207 | pub static CL_DEVICE_NAME: cl_uint = 0x102B; 208 | pub static CL_DEVICE_VENDOR: cl_uint = 0x102C; 209 | pub static CL_DRIVER_VERSION: cl_uint = 0x102D; 210 | pub static CL_DEVICE_PROFILE: cl_uint = 0x102E; 211 | pub static CL_DEVICE_VERSION: cl_uint = 0x102F; 212 | pub static CL_DEVICE_EXTENSIONS: cl_uint = 0x1030; 213 | pub static CL_DEVICE_PLATFORM: cl_uint = 0x1031; 214 | /* 0x1032 reserved for CL_DEVICE_DOUBLE_FP_CONFIG */ 215 | /* 0x1033 reserved for CL_DEVICE_HALF_FP_CONFIG */ 216 | pub static CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF: cl_uint = 0x1034; 217 | pub static CL_DEVICE_HOST_UNIFIED_MEMORY: cl_uint = 0x1035; 218 | pub static CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR: cl_uint = 0x1036; 219 | pub static CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT: cl_uint = 0x1037; 220 | pub static CL_DEVICE_NATIVE_VECTOR_WIDTH_INT: cl_uint = 0x1038; 221 | pub static CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG: cl_uint = 0x1039; 222 | pub static CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT: cl_uint = 0x103A; 223 | pub static CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE: cl_uint = 0x103B; 224 | pub static CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF: cl_uint = 0x103C; 225 | pub static CL_DEVICE_OPENCL_C_VERSION: cl_uint = 0x103D; 226 | 227 | /* cl_device_fp_config - bitfield */ 228 | pub static CL_FP_DENORM: cl_bitfield = 1 << 0; 229 | pub static CL_FP_INF_NAN: cl_bitfield = 1 << 1; 230 | pub static CL_FP_ROUND_TO_NEAREST: cl_bitfield = 1 << 2; 231 | pub static CL_FP_ROUND_TO_ZERO: cl_bitfield = 1 << 3; 232 | pub static CL_FP_ROUND_TO_INF: cl_bitfield = 1 << 4; 233 | pub static CL_FP_FMA: cl_bitfield = 1 << 5; 234 | pub static CL_FP_SOFT_FLOAT: cl_bitfield = 1 << 6; 235 | 236 | /* cl_device_mem_cache_type */ 237 | pub static CL_NONE: cl_uint = 0x0; 238 | pub static CL_READ_ONLY_CACHE: cl_uint = 0x1; 239 | pub static CL_READ_WRITE_CACHE: cl_uint = 0x2; 240 | 241 | /* cl_device_local_mem_type */ 242 | pub static CL_LOCAL: cl_uint = 0x1; 243 | pub static CL_GLOBAL: cl_uint = 0x2; 244 | 245 | /* cl_device_exec_capabilities - bitfield */ 246 | pub static CL_EXEC_KERNEL: cl_bitfield = 1 << 0; 247 | pub static CL_EXEC_NATIVE_KERNEL: cl_bitfield = 1 << 1; 248 | 249 | /* cl_command_queue_properties - bitfield */ 250 | pub static CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE: cl_bitfield = 1 << 0; 251 | pub static CL_QUEUE_PROFILING_ENABLE: cl_bitfield = 1 << 1; 252 | 253 | /* cl_context_info */ 254 | pub static CL_CONTEXT_REFERENCE_COUNT: cl_uint = 0x1080; 255 | pub static CL_CONTEXT_DEVICES: cl_uint = 0x1081; 256 | pub static CL_CONTEXT_PROPERTIES: cl_uint = 0x1082; 257 | pub static CL_CONTEXT_NUM_DEVICES: cl_uint = 0x1083; 258 | 259 | /* cl_context_info + cl_context_properties */ 260 | pub static CL_CONTEXT_PLATFORM: libc::intptr_t = 0x1084; 261 | 262 | /* cl_command_queue_info */ 263 | pub static CL_QUEUE_CONTEXT: cl_uint = 0x1090; 264 | pub static CL_QUEUE_DEVICE: cl_uint = 0x1091; 265 | pub static CL_QUEUE_REFERENCE_COUNT: cl_uint = 0x1092; 266 | pub static CL_QUEUE_PROPERTIES: cl_uint = 0x1093; 267 | 268 | /* cl_mem_flags - bitfield */ 269 | pub static CL_MEM_READ_WRITE: cl_bitfield = 1 << 0; 270 | pub static CL_MEM_WRITE_ONLY: cl_bitfield = 1 << 1; 271 | pub static CL_MEM_READ_ONLY: cl_bitfield = 1 << 2; 272 | pub static CL_MEM_USE_HOST_PTR: cl_bitfield = 1 << 3; 273 | pub static CL_MEM_ALLOC_HOST_PTR: cl_bitfield = 1 << 4; 274 | pub static CL_MEM_COPY_HOST_PTR: cl_bitfield = 1 << 5; 275 | 276 | /* cl_channel_order */ 277 | pub static CL_R: cl_uint = 0x10B0; 278 | pub static CL_A: cl_uint = 0x10B1; 279 | pub static CL_RG: cl_uint = 0x10B2; 280 | pub static CL_RA: cl_uint = 0x10B3; 281 | pub static CL_RGB: cl_uint = 0x10B4; 282 | pub static CL_RGBA: cl_uint = 0x10B5; 283 | pub static CL_BGRA: cl_uint = 0x10B6; 284 | pub static CL_ARGB: cl_uint = 0x10B7; 285 | pub static CL_INTENSITY: cl_uint = 0x10B8; 286 | pub static CL_LUMINANCE: cl_uint = 0x10B9; 287 | pub static CL_Rx: cl_uint = 0x10BA; 288 | pub static CL_RGx: cl_uint = 0x10BB; 289 | pub static CL_RGBx: cl_uint = 0x10BC; 290 | 291 | /* cl_channel_type */ 292 | pub static CL_SNORM_INT8: cl_uint = 0x10D0; 293 | pub static CL_SNORM_INT16: cl_uint = 0x10D1; 294 | pub static CL_UNORM_INT8: cl_uint = 0x10D2; 295 | pub static CL_UNORM_INT16: cl_uint = 0x10D3; 296 | pub static CL_UNORM_SHORT_565: cl_uint = 0x10D4; 297 | pub static CL_UNORM_SHORT_555: cl_uint = 0x10D5; 298 | pub static CL_UNORM_INT_101010: cl_uint = 0x10D6; 299 | pub static CL_SIGNED_INT8: cl_uint = 0x10D7; 300 | pub static CL_SIGNED_INT16: cl_uint = 0x10D8; 301 | pub static CL_SIGNED_INT32: cl_uint = 0x10D9; 302 | pub static CL_UNSIGNED_INT8: cl_uint = 0x10DA; 303 | pub static CL_UNSIGNED_INT16: cl_uint = 0x10DB; 304 | pub static CL_UNSIGNED_INT32: cl_uint = 0x10DC; 305 | pub static CL_HALF_FLOAT: cl_uint = 0x10DD; 306 | pub static CL_FLOAT: cl_uint = 0x10DE; 307 | 308 | /* cl_mem_object_type */ 309 | pub static CL_MEM_OBJECT_BUFFER: cl_uint = 0x10F0; 310 | pub static CL_MEM_OBJECT_IMAGE2D: cl_uint = 0x10F1; 311 | pub static CL_MEM_OBJECT_IMAGE3D: cl_uint = 0x10F2; 312 | 313 | /* cl_mem_info */ 314 | pub static CL_MEM_TYPE: cl_uint = 0x1100; 315 | pub static CL_MEM_FLAGS: cl_uint = 0x1101; 316 | pub static CL_MEM_SIZE: cl_uint = 0x1102; 317 | pub static CL_MEM_HOST_PTR: cl_uint = 0x1103; 318 | pub static CL_MEM_MAP_COUNT: cl_uint = 0x1104; 319 | pub static CL_MEM_REFERENCE_COUNT: cl_uint = 0x1105; 320 | pub static CL_MEM_CONTEXT: cl_uint = 0x1106; 321 | pub static CL_MEM_ASSOCIATED_MEMOBJECT: cl_uint = 0x1107; 322 | pub static CL_MEM_OFFSET: cl_uint = 0x1108; 323 | 324 | /* cl_image_info */ 325 | pub static CL_IMAGE_FORMAT: cl_uint = 0x1110; 326 | pub static CL_IMAGE_ELEMENT_SIZE: cl_uint = 0x1111; 327 | pub static CL_IMAGE_ROW_PITCH: cl_uint = 0x1112; 328 | pub static CL_IMAGE_SLICE_PITCH: cl_uint = 0x1113; 329 | pub static CL_IMAGE_WIDTH: cl_uint = 0x1114; 330 | pub static CL_IMAGE_HEIGHT: cl_uint = 0x1115; 331 | pub static CL_IMAGE_DEPTH: cl_uint = 0x1116; 332 | 333 | /* cl_addressing_mode */ 334 | pub static CL_ADDRESS_NONE: cl_uint = 0x1130; 335 | pub static CL_ADDRESS_CLAMP_TO_EDGE: cl_uint = 0x1131; 336 | pub static CL_ADDRESS_CLAMP: cl_uint = 0x1132; 337 | pub static CL_ADDRESS_REPEAT: cl_uint = 0x1133; 338 | pub static CL_ADDRESS_MIRRORED_REPEAT: cl_uint = 0x1134; 339 | 340 | /* cl_filter_mode */ 341 | pub static CL_FILTER_NEAREST: cl_uint = 0x1140; 342 | pub static CL_FILTER_LINEAR: cl_uint = 0x1141; 343 | 344 | /* cl_sampler_info */ 345 | pub static CL_SAMPLER_REFERENCE_COUNT: cl_uint = 0x1150; 346 | pub static CL_SAMPLER_CONTEXT: cl_uint = 0x1151; 347 | pub static CL_SAMPLER_NORMALIZED_COORDS: cl_uint = 0x1152; 348 | pub static CL_SAMPLER_ADDRESSING_MODE: cl_uint = 0x1153; 349 | pub static CL_SAMPLER_FILTER_MODE: cl_uint = 0x1154; 350 | 351 | /* cl_map_flags - bitfield */ 352 | pub static CL_MAP_READ: cl_bitfield = 1 << 0; 353 | pub static CL_MAP_WRITE: cl_bitfield = 1 << 1; 354 | 355 | /* cl_program_info */ 356 | pub static CL_PROGRAM_REFERENCE_COUNT: cl_uint = 0x1160; 357 | pub static CL_PROGRAM_CONTEXT: cl_uint = 0x1161; 358 | pub static CL_PROGRAM_NUM_DEVICES: cl_uint = 0x1162; 359 | pub static CL_PROGRAM_DEVICES: cl_uint = 0x1163; 360 | pub static CL_PROGRAM_SOURCE: cl_uint = 0x1164; 361 | pub static CL_PROGRAM_BINARY_SIZES: cl_uint = 0x1165; 362 | pub static CL_PROGRAM_BINARIES: cl_uint = 0x1166; 363 | 364 | /* cl_program_build_info */ 365 | pub static CL_PROGRAM_BUILD_STATUS: cl_uint = 0x1181; 366 | pub static CL_PROGRAM_BUILD_OPTIONS: cl_uint = 0x1182; 367 | pub static CL_PROGRAM_BUILD_LOG: cl_uint = 0x1183; 368 | 369 | /* cl_build_status */ 370 | pub static CL_BUILD_SUCCESS: cl_uint = 0; 371 | pub static CL_BUILD_NONE: cl_uint = (-1isize) as cl_uint; 372 | pub static CL_BUILD_ERROR: cl_uint = -2isize as cl_uint; 373 | pub static CL_BUILD_IN_PROGRESS: cl_uint = -3isize as cl_uint; 374 | 375 | /* cl_kernel_info */ 376 | pub static CL_KERNEL_FUNCTION_NAME: cl_uint = 0x1190; 377 | pub static CL_KERNEL_NUM_ARGS: cl_uint = 0x1191; 378 | pub static CL_KERNEL_REFERENCE_COUNT: cl_uint = 0x1192; 379 | pub static CL_KERNEL_CONTEXT: cl_uint = 0x1193; 380 | pub static CL_KERNEL_PROGRAM: cl_uint = 0x1194; 381 | 382 | /* cl_kernel_work_group_info */ 383 | pub static CL_KERNEL_WORK_GROUP_SIZE: cl_uint = 0x11B0; 384 | pub static CL_KERNEL_COMPILE_WORK_GROUP_SIZE: cl_uint = 0x11B1; 385 | pub static CL_KERNEL_LOCAL_MEM_SIZE: cl_uint = 0x11B2; 386 | pub static CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE: cl_uint = 0x11B3; 387 | pub static CL_KERNEL_PRIVATE_MEM_SIZE: cl_uint = 0x11B4; 388 | 389 | /* cl_event_info */ 390 | pub static CL_EVENT_COMMAND_QUEUE: cl_uint = 0x11D0; 391 | pub static CL_EVENT_COMMAND_TYPE: cl_uint = 0x11D1; 392 | pub static CL_EVENT_REFERENCE_COUNT: cl_uint = 0x11D2; 393 | pub static CL_EVENT_COMMAND_EXECUTION_STATUS: cl_uint = 0x11D3; 394 | pub static CL_EVENT_CONTEXT: cl_uint = 0x11D4; 395 | 396 | /* cl_command_type */ 397 | pub static CL_COMMAND_NDRANGE_KERNEL: cl_uint = 0x11F0; 398 | pub static CL_COMMAND_TASK: cl_uint = 0x11F1; 399 | pub static CL_COMMAND_NATIVE_KERNEL: cl_uint = 0x11F2; 400 | pub static CL_COMMAND_READ_BUFFER: cl_uint = 0x11F3; 401 | pub static CL_COMMAND_WRITE_BUFFER: cl_uint = 0x11F4; 402 | pub static CL_COMMAND_COPY_BUFFER: cl_uint = 0x11F5; 403 | pub static CL_COMMAND_READ_IMAGE: cl_uint = 0x11F6; 404 | pub static CL_COMMAND_WRITE_IMAGE: cl_uint = 0x11F7; 405 | pub static CL_COMMAND_COPY_IMAGE: cl_uint = 0x11F8; 406 | pub static CL_COMMAND_COPY_IMAGE_TO_BUFFER: cl_uint = 0x11F9; 407 | pub static CL_COMMAND_COPY_BUFFER_TO_IMAGE: cl_uint = 0x11FA; 408 | pub static CL_COMMAND_MAP_BUFFER: cl_uint = 0x11FB; 409 | pub static CL_COMMAND_MAP_IMAGE: cl_uint = 0x11FC; 410 | pub static CL_COMMAND_UNMAP_MEM_OBJECT: cl_uint = 0x11FD; 411 | pub static CL_COMMAND_MARKER: cl_uint = 0x11FE; 412 | pub static CL_COMMAND_ACQUIRE_GL_OBJECTS: cl_uint = 0x11FF; 413 | pub static CL_COMMAND_RELEASE_GL_OBJECTS: cl_uint = 0x1200; 414 | pub static CL_COMMAND_READ_BUFFER_RECT: cl_uint = 0x1201; 415 | pub static CL_COMMAND_WRITE_BUFFER_RECT: cl_uint = 0x1202; 416 | pub static CL_COMMAND_COPY_BUFFER_RECT: cl_uint = 0x1203; 417 | pub static CL_COMMAND_USER: cl_uint = 0x1204; 418 | 419 | /* command execution status */ 420 | pub static CL_COMPLETE: cl_uint = 0x0; 421 | pub static CL_RUNNING: cl_uint = 0x1; 422 | pub static CL_SUBMITTED: cl_uint = 0x2; 423 | pub static CL_QUEUED: cl_uint = 0x3; 424 | 425 | /* cl_buffer_create_type */ 426 | pub static CL_BUFFER_CREATE_TYPE_REGION: cl_uint = 0x1220; 427 | 428 | /* cl_profiling_info */ 429 | pub static CL_PROFILING_COMMAND_QUEUED: cl_uint = 0x1280; 430 | pub static CL_PROFILING_COMMAND_SUBMIT: cl_uint = 0x1281; 431 | pub static CL_PROFILING_COMMAND_START: cl_uint = 0x1282; 432 | pub static CL_PROFILING_COMMAND_END: cl_uint = 0x1283; 433 | 434 | 435 | pub mod ll { 436 | use cl::*; 437 | use libc; 438 | 439 | 440 | extern 441 | { 442 | /* Platform APIs */ 443 | pub fn clGetPlatformIDs(num_entries: cl_uint, 444 | platforms: *mut cl_platform_id, 445 | num_platforms: *mut cl_uint) -> cl_int; 446 | pub fn clGetPlatformInfo(platform: cl_platform_id, 447 | param_name: cl_platform_info, 448 | param_value_size: libc::size_t, 449 | param_value: *mut libc::c_void, 450 | param_value_size_ret: *mut libc::size_t) -> cl_int; 451 | 452 | /* Device APIs */ 453 | pub fn clGetDeviceIDs(platform: cl_platform_id, 454 | device_type: cl_device_type, 455 | num_entries: cl_uint, 456 | devices: *mut cl_device_id, 457 | num_devices: *mut cl_uint) -> cl_int; 458 | pub fn clGetDeviceInfo(device: cl_device_id, 459 | param_name: cl_device_info, 460 | param_value_size: libc::size_t, 461 | param_value: *mut libc::c_void, 462 | param_value_size_ret: *mut libc::size_t) -> cl_int; 463 | 464 | /* Context APIs */ 465 | pub fn clCreateContext(properties: *const cl_context_properties, 466 | num_devices: cl_uint, 467 | devices: *const cl_device_id, 468 | pfn_notify: extern fn (*const libc::c_char, *const libc::c_void, libc::size_t, *mut libc::c_void), 469 | user_data: *mut libc::c_void, 470 | errcode_ret: *mut cl_int) -> cl_context; 471 | pub fn clCreateContextFromType(properties: *mut cl_context_properties, 472 | device_type: cl_device_type, 473 | pfn_notify: extern fn (*mut libc::c_char, *mut libc::c_void, libc::size_t, *mut libc::c_void), 474 | user_data: *mut libc::c_void, 475 | errcode_ret: *mut cl_int) -> cl_context; 476 | pub fn clRetainContext(context: cl_context) -> cl_int; 477 | pub fn clReleaseContext(context: cl_context) -> cl_int; 478 | pub fn clGetContextInfo(context: cl_context, 479 | param_name: cl_context_info, 480 | param_value_size: libc::size_t, 481 | param_value: *mut libc::c_void, 482 | param_value_size_ret: *mut libc::size_t) -> cl_int; 483 | 484 | /* Command Queue APIs */ 485 | pub fn clCreateCommandQueue(context: cl_context, 486 | device: cl_device_id, 487 | properties: cl_command_queue_properties, 488 | errcode_ret: *mut cl_int) -> cl_command_queue; 489 | pub fn clRetainCommandQueue(command_queue: cl_command_queue) -> cl_int; 490 | pub fn clReleaseCommandQueue(command_queue: cl_command_queue) -> cl_int; 491 | pub fn clGetCommandQueueInfo(command_queue: cl_command_queue, 492 | param_name: cl_command_queue_info, 493 | param_value_size: libc::size_t, 494 | param_value: *mut libc::c_void, 495 | param_value_size_ret: *mut libc::size_t) -> cl_int; 496 | 497 | /* Memory Object APIs */ 498 | pub fn clCreateBuffer(context: cl_context, 499 | flags: cl_mem_flags, 500 | size: libc::size_t, 501 | host_ptr: *mut libc::c_void, 502 | errcode_ret: *mut cl_int) -> cl_mem; 503 | pub fn clCreateSubBuffer(buffer: cl_mem, 504 | flags: cl_mem_flags, 505 | buffer_create_type: cl_buffer_create_type, 506 | buffer_create_info: *mut libc::c_void, 507 | errcode_ret: *mut cl_int) -> cl_mem; 508 | pub fn clCreateImage2D(context: cl_context, 509 | flags: cl_mem_flags, 510 | image_format: *mut cl_image_format, 511 | image_width: libc::size_t, 512 | image_height: libc::size_t, 513 | image_row_pitch: libc::size_t, 514 | host_ptr: *mut libc::c_void, 515 | errcode_ret: *mut cl_int) -> cl_mem; 516 | pub fn clCreateImage3D(context: cl_context, 517 | flags: cl_mem_flags, 518 | image_format: *mut cl_image_format, 519 | image_width: libc::size_t, 520 | image_height: libc::size_t, 521 | image_depth: libc::size_t, 522 | image_row_pitch: libc::size_t, 523 | image_depth: libc::size_t, 524 | image_row_pitch: libc::size_t, 525 | image_slice_pitch: libc::size_t, 526 | host_ptr: *mut libc::c_void, 527 | errcode_ret: *mut cl_int) -> cl_mem; 528 | pub fn clRetainMemObject(memobj: cl_mem) -> cl_int; 529 | pub fn clReleaseMemObject(memobj: cl_mem) -> cl_int; 530 | pub fn clGetSupportedImageFormats(context: cl_context, 531 | flags: cl_mem_flags, 532 | image_type: cl_mem_object_type, 533 | num_entries: cl_uint, 534 | image_formats: *mut cl_image_format, 535 | num_image_formats: *mut cl_uint) -> cl_int; 536 | pub fn clGetMemObjectInfo(memobj: cl_mem, 537 | param_name: cl_mem_info, 538 | param_value_size: libc::size_t, 539 | param_value: *mut libc::c_void, 540 | param_value_size_ret: *mut libc::size_t) -> cl_int; 541 | pub fn clGetImageInfo(image: cl_mem, 542 | param_name: cl_image_info, 543 | param_value_size: libc::size_t, 544 | param_value: *mut libc::c_void, 545 | param_value_size_ret: *mut libc::size_t) -> cl_int; 546 | pub fn clSetMemObjectDestructorCallback(memobj: cl_mem, 547 | pfn_notify: extern fn (cl_mem, *mut libc::c_void), 548 | user_data: *mut libc::c_void) -> cl_int; 549 | 550 | /*mut * Sampler APIs */ 551 | pub fn clCreateSampler(context: cl_context, 552 | normalize_coords: cl_bool, 553 | addressing_mode: cl_addressing_mode, 554 | filter_mode: cl_filter_mode, 555 | errcode_ret: *mut cl_int) -> cl_sampler; 556 | pub fn clRetainSampler(sampler: cl_sampler) -> cl_int; 557 | pub fn clReleaseSampler(sampler: cl_sampler) ->cl_int; 558 | pub fn clGetSamplerInfo(sampler: cl_sampler, 559 | param_name: cl_sampler_info, 560 | param_value_size: libc::size_t, 561 | param_value: *mut libc::c_void, 562 | param_value_size_ret: *mut libc::size_t) -> cl_int; 563 | 564 | /* Program Object APIs */ 565 | pub fn clCreateProgramWithSource(context: cl_context, 566 | count: cl_uint, 567 | strings: *const *const libc::c_char, 568 | lengths: *const libc::size_t, 569 | errcode_ret: *mut cl_int) -> cl_program; 570 | pub fn clCreateProgramWithBinary(context: cl_context, 571 | num_devices: cl_uint, 572 | device_list: *const cl_device_id, 573 | lengths: *const libc::size_t, 574 | binaries: *const *const libc::c_uchar, 575 | binary_status: *mut cl_int, 576 | errcode_ret: *mut cl_int) -> cl_program; 577 | pub fn clRetainProgram(program: cl_program) -> cl_int; 578 | pub fn clReleaseProgram(program: cl_program) -> cl_int; 579 | pub fn clBuildProgram(program: cl_program, 580 | num_devices: cl_uint, 581 | device_list: *const cl_device_id, 582 | options: *const libc::c_char, 583 | pfn_notify: extern fn (cl_program, *mut libc::c_void), 584 | user_data: *mut libc::c_void) -> cl_int; 585 | pub fn clUnloadCompiler() -> cl_int; 586 | pub fn clGetProgramInfo(program: cl_program, 587 | param_name: cl_program_info, 588 | param_value_size: libc::size_t, 589 | param_value: *mut libc::c_void, 590 | param_value_size_ret: *mut libc::size_t) -> cl_int; 591 | pub fn clGetProgramBuildInfo(program: cl_program, 592 | device: cl_device_id, 593 | param_name: cl_program_info, 594 | param_value_size: libc::size_t, 595 | param_value: *mut libc::c_void, 596 | param_value_size_ret: *mut libc::size_t) -> cl_int; 597 | 598 | /* Kernel Object APIs */ 599 | pub fn clCreateKernel(program: cl_program, 600 | kernel_name: *const libc::c_char, 601 | errcode_ret: *mut cl_int) -> cl_kernel; 602 | pub fn clCreateKernelsInProgram(program: cl_program, 603 | num_kernels: cl_uint, 604 | kernels: *mut cl_kernel, 605 | num_kernels_ret: *mut cl_uint) -> cl_int; 606 | pub fn clRetainKernel(kernel: cl_kernel) -> cl_int; 607 | pub fn clReleaseKernel(kernel: cl_kernel) -> cl_int; 608 | pub fn clSetKernelArg(kernel: cl_kernel, 609 | arg_index: cl_uint, 610 | arg_size: libc::size_t, 611 | arg_value: *const libc::c_void) -> cl_int; 612 | pub fn clGetKernelInfo(kernel: cl_kernel, 613 | param_name: cl_kernel_info, 614 | param_value_size: libc::size_t, 615 | param_value: *mut libc::c_void, 616 | param_value_size_ret: *mut libc::size_t) -> cl_int; 617 | pub fn clGetKernelWorkGroupInfo(kernel: cl_kernel, 618 | device: cl_device_id, 619 | param_name: cl_kernel_work_group_info, 620 | param_value_size: libc::size_t, 621 | param_value: *mut libc::c_void, 622 | param_value_size_ret: *mut libc::size_t) -> cl_int; 623 | 624 | /* Event Object APIs */ 625 | pub fn clWaitForEvents(num_events: cl_uint, 626 | event_list: *const cl_event) -> cl_int; 627 | pub fn clGetEventInfo(event: cl_event, 628 | param_name: cl_event_info, 629 | param_value_size: libc::size_t, 630 | param_value: *mut libc::c_void, 631 | param_value_size_ret: *mut libc::size_t) -> cl_int; 632 | pub fn clCreateUserEvent(context: cl_context, 633 | errcode_ret: *mut cl_int) -> cl_event; 634 | pub fn clRetainEvent(event: cl_event) -> cl_int; 635 | pub fn clReleaseEvent(event: cl_event) -> cl_int; 636 | pub fn clSetUserEventStatus(event: cl_event, 637 | execution_status: cl_int) -> cl_int; 638 | pub fn clSetEventCallback(event: cl_event, 639 | command_exec_callback_type: cl_int, 640 | pfn_notify: extern fn (cl_event, cl_int, *mut libc::c_void), 641 | user_data: *mut libc::c_void) -> cl_int; 642 | 643 | /* Profiling APIs */ 644 | pub fn clGetEventProfilingInfo(event: cl_event, 645 | param_name: cl_profiling_info, 646 | param_value_size: libc::size_t, 647 | param_value: *mut libc::c_void, 648 | param_value_size_ret: *mut libc::size_t) -> cl_int; 649 | 650 | /* Flush and Finish APIs */ 651 | pub fn clFlush(command_queue: cl_command_queue) -> cl_int; 652 | pub fn clFinish(command_queue: cl_command_queue) -> cl_int; 653 | 654 | /* Enqueued Commands APIs */ 655 | pub fn clEnqueueReadBuffer(command_queue: cl_command_queue, 656 | buffer: cl_mem, 657 | blocking_read: cl_bool, 658 | offset: libc::size_t, 659 | cb: libc::size_t, 660 | ptr: *mut libc::c_void, 661 | num_events_in_wait_list: cl_uint, 662 | event_wait_list: *const cl_event, 663 | event: *mut cl_event) -> cl_int; 664 | pub fn clEnqueueReadBufferRect(command_queue: cl_command_queue, 665 | buffer: cl_mem, 666 | blocking_read: cl_bool, 667 | buffer_origin: *mut libc::size_t, 668 | host_origin: *mut libc::size_t, 669 | region: *mut libc::size_t, 670 | buffer_row_pitch: libc::size_t, 671 | buffer_slice_pitch: libc::size_t, 672 | host_row_pitch: libc::size_t, 673 | host_slice_pitch: libc::size_t, 674 | ptr: *mut libc::c_void, 675 | num_events_in_wait_list: cl_uint, 676 | event_wait_list: *const cl_event, 677 | event: *mut cl_event) -> cl_int; 678 | pub fn clEnqueueWriteBuffer(command_queue: cl_command_queue, 679 | buffer: cl_mem, 680 | blocking_write: cl_bool, 681 | offset: libc::size_t, 682 | cb: libc::size_t, 683 | ptr: *const libc::c_void, 684 | num_events_in_wait_list: cl_uint, 685 | event_wait_list: *const cl_event, 686 | event: *mut cl_event) -> cl_int; 687 | pub fn clEnqueueWriteBufferRect(command_queue: cl_command_queue, 688 | blocking_write: cl_bool, 689 | buffer_origin: *mut libc::size_t, 690 | host_origin: *mut libc::size_t, 691 | region: *mut libc::size_t, 692 | buffer_row_pitch: libc::size_t, 693 | buffer_slice_pitch: libc::size_t, 694 | host_row_pitch: libc::size_t, 695 | host_slice_pitch: libc::size_t, 696 | ptr: *mut libc::c_void, 697 | num_events_in_wait_list: cl_uint, 698 | event_wait_list: *const cl_event, 699 | event: *mut cl_event) -> cl_int; 700 | pub fn clEnqueueCopyBuffer(command_queue: cl_command_queue, 701 | src_buffer: cl_mem, 702 | dst_buffer: cl_mem, 703 | src_offset: libc::size_t, 704 | dst_offset: libc::size_t, 705 | cb: libc::size_t, 706 | num_events_in_wait_list: cl_uint, 707 | event_wait_list: *const cl_event, 708 | event: *mut cl_event) -> cl_int; 709 | pub fn clEnqueueCopyBufferRect(command_queue: cl_command_queue, 710 | src_buffer: cl_mem, 711 | dst_buffer: cl_mem, 712 | src_origin: *mut libc::size_t, 713 | dst_origin: *mut libc::size_t, 714 | region: *mut libc::size_t, 715 | src_row_pitch: libc::size_t, 716 | src_slice_pitch: libc::size_t, 717 | dst_row_pitch: libc::size_t, 718 | dst_slice_pitch: libc::size_t, 719 | num_events_in_wait_list: cl_uint, 720 | event_wait_list: *const cl_event, 721 | event: *mut cl_event) -> cl_int; 722 | pub fn clEnqueueReadImage(command_queue: cl_command_queue, 723 | image: cl_mem, 724 | blocking_read: cl_bool, 725 | origin: *mut libc::size_t, 726 | region: *mut libc::size_t, 727 | row_pitch: libc::size_t, 728 | slice_pitch: libc::size_t, 729 | ptr: *mut libc::c_void, 730 | num_events_in_wait_list: cl_uint, 731 | event_wait_list: *const cl_event, 732 | event: *mut cl_event) -> cl_int; 733 | pub fn clEnqueueWriteImage(command_queue: cl_command_queue, 734 | image: cl_mem, 735 | blocking_write: cl_bool, 736 | origin: *mut libc::size_t, 737 | region: *mut libc::size_t, 738 | input_row_pitch: libc::size_t, 739 | input_slice_pitch: libc::size_t, 740 | ptr: *mut libc::c_void, 741 | num_events_in_wait_list: cl_uint, 742 | event_wait_list: *const cl_event, 743 | event: *mut cl_event) -> cl_int; 744 | pub fn clEnqueueCopyImage(command_queue: cl_command_queue, 745 | src_image: cl_mem, 746 | dst_image: cl_mem, 747 | src_origin: *mut libc::size_t, 748 | dst_origin: *mut libc::size_t, 749 | region: *mut libc::size_t, 750 | num_events_in_wait_list: cl_uint, 751 | event_wait_list: *const cl_event, 752 | event: *mut cl_event) -> cl_int; 753 | pub fn clEnqueueCopyImageToBuffer(command_queue: cl_command_queue, 754 | src_image: cl_mem, 755 | dst_buffer: cl_mem, 756 | src_origin: *mut libc::size_t, 757 | region: *mut libc::size_t, 758 | dst_offset: libc::size_t, 759 | num_events_in_wait_list: cl_uint, 760 | event_wait_list: *const cl_event, 761 | event: *mut cl_event) -> cl_int; 762 | pub fn clEnqueueCopyBufferToImage(command_queue: cl_command_queue, 763 | src_buffer: cl_mem, 764 | dst_image: cl_mem, 765 | src_offset: libc::size_t, 766 | dst_origin: *mut libc::size_t, 767 | region: *mut libc::size_t, 768 | num_events_in_wait_list: cl_uint, 769 | event_wait_list: *const cl_event, 770 | event: *mut cl_event) -> cl_int; 771 | pub fn clEnqueueMapBuffer(command_queue: cl_command_queue, 772 | buffer: cl_mem, 773 | blocking_map: cl_bool, 774 | map_flags: cl_map_flags, 775 | offset: libc::size_t, 776 | cb: libc::size_t, 777 | num_events_in_wait_list: cl_uint, 778 | event_wait_list: *const cl_event, 779 | event: *mut cl_event, 780 | errorcode_ret: *mut cl_int); 781 | pub fn clEnqueueMapImage(command_queue: cl_command_queue, 782 | image: cl_mem, 783 | blocking_map: cl_bool, 784 | map_flags: cl_map_flags, 785 | origin: *mut libc::size_t, 786 | region: *mut libc::size_t, 787 | image_row_pitch: libc::size_t, 788 | image_slice_pitch: libc::size_t, 789 | num_events_in_wait_list: cl_uint, 790 | event_wait_list: *const cl_event, 791 | event: *mut cl_event, 792 | errorcode_ret: *mut cl_int); 793 | pub fn clEnqueueUnmapMemObject(command_queue: cl_command_queue, 794 | memobj: cl_mem, 795 | mapped_ptr: *mut libc::c_void, 796 | num_events_in_wait_list: cl_uint, 797 | event_wait_list: *const cl_event, 798 | event: *mut cl_event) -> cl_int; 799 | pub fn clEnqueueNDRangeKernel(command_queue: cl_command_queue, 800 | kernel: cl_kernel, 801 | work_dim: cl_uint, 802 | global_work_offset: *const libc::size_t, 803 | global_work_size: *const libc::size_t, 804 | local_work_size: *const libc::size_t, 805 | num_events_in_wait_list: cl_uint, 806 | event_wait_list: *const cl_event, 807 | event: *mut cl_event) -> cl_int; 808 | pub fn clEnqueueTask(command_queue: cl_command_queue, 809 | kernel: cl_kernel, 810 | num_events_in_wait_list: cl_uint, 811 | event_wait_list: *const cl_event, 812 | event: *mut cl_event) -> cl_int; 813 | pub fn clEnqueueNativeKernel(command_queue: cl_command_queue, 814 | user_func: extern fn (*mut libc::c_void), 815 | args: *mut libc::c_void, 816 | cb_args: libc::size_t, 817 | num_mem_objects: cl_uint, 818 | mem_list: *const cl_mem, 819 | args_mem_loc: *const *const libc::c_void, 820 | num_events_in_wait_list: cl_uint, 821 | event_wait_list: *const cl_event, 822 | event: *mut cl_event) -> cl_int; 823 | pub fn clEnqueueMarker(command_queue: cl_command_queue, 824 | event: *mut cl_event) -> cl_int; 825 | pub fn clEnqueueWaitForEvents(command_queue: cl_command_queue, 826 | num_events: cl_uint, 827 | event_list: *mut cl_event) -> cl_int; 828 | pub fn clEnqueueBarrier(command_queue: cl_command_queue) -> cl_int; 829 | 830 | /* Extension function access 831 | * 832 | * Returns the extension function address for the given function name, 833 | * or NULL if a valid function can not be found. The client must 834 | * check to make sure the address is not NULL, before using or 835 | * or calling the returned function address. 836 | */ 837 | pub fn clGetExtensionFunctionAddress(func_name: *const libc::c_char) -> *mut libc::c_void; 838 | } 839 | } 840 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | //! Error handling utilities. 2 | 3 | use cl::{CLStatus, cl_int}; 4 | use cl::CLStatus::CL_SUCCESS; 5 | 6 | fn error_str(status_code: cl_int) -> String { 7 | match status_code { 8 | 0 => CLStatus::CL_SUCCESS.to_string(), 9 | -1 => CLStatus::CL_DEVICE_NOT_FOUND.to_string(), 10 | -2 => CLStatus::CL_DEVICE_NOT_AVAILABLE.to_string(), 11 | -3 => CLStatus::CL_COMPILER_NOT_AVAILABLE.to_string(), 12 | -4 => CLStatus::CL_MEM_OBJECT_ALLOCATION_FAILURE.to_string(), 13 | -5 => CLStatus::CL_OUT_OF_RESOURCES.to_string(), 14 | -6 => CLStatus::CL_OUT_OF_HOST_MEMORY.to_string(), 15 | -7 => CLStatus::CL_PROFILING_INFO_NOT_AVAILABLE.to_string(), 16 | -8 => CLStatus::CL_MEM_COPY_OVERLAP.to_string(), 17 | -9 => CLStatus::CL_IMAGE_FORMAT_MISMATCH.to_string(), 18 | -10 => CLStatus::CL_IMAGE_FORMAT_NOT_SUPPORTED.to_string(), 19 | -11 => CLStatus::CL_BUILD_PROGRAM_FAILURE.to_string(), 20 | -12 => CLStatus::CL_MAP_FAILURE.to_string(), 21 | -13 => CLStatus::CL_MISALIGNED_SUB_BUFFER_OFFSET.to_string(), 22 | -14 => CLStatus::CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST.to_string(), 23 | -30 => CLStatus::CL_INVALID_VALUE.to_string(), 24 | -31 => CLStatus::CL_INVALID_DEVICE_TYPE.to_string(), 25 | -32 => CLStatus::CL_INVALID_PLATFORM.to_string(), 26 | -33 => CLStatus::CL_INVALID_DEVICE.to_string(), 27 | -34 => CLStatus::CL_INVALID_CONTEXT.to_string(), 28 | -35 => CLStatus::CL_INVALID_QUEUE_PROPERTIES.to_string(), 29 | -36 => CLStatus::CL_INVALID_COMMAND_QUEUE.to_string(), 30 | -37 => CLStatus::CL_INVALID_HOST_PTR.to_string(), 31 | -38 => CLStatus::CL_INVALID_MEM_OBJECT.to_string(), 32 | -39 => CLStatus::CL_INVALID_IMAGE_FORMAT_DESCRIPTOR.to_string(), 33 | -40 => CLStatus::CL_INVALID_IMAGE_SIZE.to_string(), 34 | -41 => CLStatus::CL_INVALID_SAMPLER.to_string(), 35 | -42 => CLStatus::CL_INVALID_BINARY.to_string(), 36 | -43 => CLStatus::CL_INVALID_BUILD_OPTIONS.to_string(), 37 | -44 => CLStatus::CL_INVALID_PROGRAM.to_string(), 38 | -45 => CLStatus::CL_INVALID_PROGRAM_EXECUTABLE.to_string(), 39 | -46 => CLStatus::CL_INVALID_KERNEL_NAME.to_string(), 40 | -47 => CLStatus::CL_INVALID_KERNEL_DEFINITION.to_string(), 41 | -48 => CLStatus::CL_INVALID_KERNEL.to_string(), 42 | -49 => CLStatus::CL_INVALID_ARG_INDEX.to_string(), 43 | -50 => CLStatus::CL_INVALID_ARG_VALUE.to_string(), 44 | -51 => CLStatus::CL_INVALID_ARG_SIZE.to_string(), 45 | -52 => CLStatus::CL_INVALID_KERNEL_ARGS.to_string(), 46 | -53 => CLStatus::CL_INVALID_WORK_DIMENSION.to_string(), 47 | -54 => CLStatus::CL_INVALID_WORK_GROUP_SIZE.to_string(), 48 | -55 => CLStatus::CL_INVALID_WORK_ITEM_SIZE.to_string(), 49 | -56 => CLStatus::CL_INVALID_GLOBAL_OFFSET.to_string(), 50 | -57 => CLStatus::CL_INVALID_EVENT_WAIT_LIST.to_string(), 51 | -58 => CLStatus::CL_INVALID_EVENT.to_string(), 52 | -59 => CLStatus::CL_INVALID_OPERATION.to_string(), 53 | -60 => CLStatus::CL_INVALID_GL_OBJECT.to_string(), 54 | -61 => CLStatus::CL_INVALID_BUFFER_SIZE.to_string(), 55 | -62 => CLStatus::CL_INVALID_MIP_LEVEL.to_string(), 56 | -63 => CLStatus::CL_INVALID_GLOBAL_WORK_SIZE.to_string(), 57 | -64 => CLStatus::CL_INVALID_PROPERTY.to_string(), 58 | -1001 => CLStatus::CL_PLATFORM_NOT_FOUND_KHR.to_string(), 59 | _ => format!("Unknown Error: {}", status_code) 60 | } 61 | } 62 | 63 | pub fn check(status: cl_int, message: &str) { 64 | if status != CL_SUCCESS as cl_int { 65 | panic!("{} ({})", message, error_str(status)) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/ext.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused, 2 | unused_attributes, 3 | non_camel_case_types, 4 | non_snake_case)] 5 | 6 | /// All of the extensions defined for OpenCL 1.1, from 7 | /// [`cl_ext.h`](https://www.khronos.org/registry/cl/api/1.1/cl_ext.h). 8 | 9 | // Macro to define a struct-style extension pointer loader. 10 | // Defines a (`Copy`, `Sync`) `struct Functions` that has extension function pointers as members (and methods, 11 | // for convenience). 12 | // Call `$ext::load()` to get an Option<$ext::Functions, String>. (It's safe to call extension function pointers in other threads, right?) 13 | macro_rules! cl_extension_loader { 14 | ( 15 | $ext_name:expr; 16 | $(extern fn $function:ident ($($arg:ident : $arg_type:ty),*) -> $ret:ty),* 17 | ) => ( 18 | // Define struct Functions 19 | ext_struct_def!{ $($function, ($($arg, $arg_type),*) $ret)* } 20 | impl Functions { 21 | // Make function pointers available as methods so they don't have to be called as (struct.member)(arg) 22 | $( #[inline(always)] unsafe fn $function (&self, $($arg:$arg_type),*) -> $ret { (self.$function)($($arg),*) } )* 23 | } 24 | 25 | pub fn load(platform: cl_platform_id) -> Result { 26 | use hl; 27 | use std::mem; 28 | use std::ptr; 29 | use std::ffi::CString; 30 | use cl::ll::clGetExtensionFunctionAddress; 31 | 32 | // Read in the available extensions 33 | // We have to do this, since loading function pointers for an 34 | // unavailable extension can return non-NULL. 35 | // TODO read in extensions lazily and store them in a global HashSet? 36 | let available = unsafe { 37 | let hl_platform = hl::Platform::from_platform_id(platform); 38 | let available = hl_platform.extensions().contains($ext_name); 39 | mem::forget(hl_platform); 40 | available 41 | }; 42 | if !available { 43 | let platform_name; 44 | unsafe { 45 | let hl_platform = hl::Platform::from_platform_id(platform); 46 | platform_name = hl_platform.name(); 47 | mem::forget(hl_platform); 48 | } 49 | return Err(format!("extension {} unavailable for platform {}", $ext_name, platform_name)); 50 | } 51 | // Return a struct with all functions loaded 52 | Ok(ext_struct_literal!($ext_name, platform, $($function),*)) 53 | } 54 | ) 55 | } 56 | // We only need these helper macros so we can special-case for unit structs 57 | // (Since writing `struct name {}` is a failing error for some reason) 58 | // Whatever functions we're calling aren't necessarily thread-safe, but since this is a low-level 59 | // interface we'll let the callers worry about that 60 | macro_rules! ext_struct_def { 61 | () => (#[derive(Copy, Clone)] pub struct Functions;); 62 | ($($function:ident, ($($arg:ident, $arg_type:ty),+) $ret:ty)+) => 63 | ( 64 | #[derive(Copy, Clone)] 65 | pub struct Functions { 66 | $(pub $function: (extern fn ($($arg : $arg_type),+) -> $ret)),+ 67 | } 68 | ); 69 | } 70 | // (So is writing `name {}` as a literal) 71 | macro_rules! ext_struct_literal { 72 | ($ext_name:expr, $plat:ident,) => (Functions); 73 | ($ext_name:expr, $plat:ident, $($function:ident),+) => 74 | ( 75 | Functions { 76 | $($function: { 77 | let mut fn_name 78 | = CString::new(stringify!($function)).unwrap(); 79 | // TODO use clGetExtensionFunctionAddressForPlatform() when it's available; more 80 | // reliable. 81 | let fn_ptr = unsafe { clGetExtensionFunctionAddress(fn_name.as_ptr()) }; 82 | if fn_ptr == ptr::null_mut() { 83 | let platform_name; 84 | 85 | unsafe { 86 | let hl_platform = hl::Platform::from_platform_id($plat); 87 | platform_name = hl_platform.name(); 88 | mem::forget(hl_platform); 89 | } 90 | 91 | return Err(format!("extension {} apparently available for platform with id {}, but couldn't load function {}", 92 | $ext_name, 93 | platform_name, 94 | stringify!($function))); 95 | } 96 | unsafe { 97 | // Cast from *mut libc::void to the function pointer type we want 98 | mem::transmute(fn_ptr) 99 | } 100 | }),+ 101 | } 102 | ); 103 | } 104 | 105 | pub mod cl_khr_fp64 { 106 | use cl::*; 107 | static CL_DEVICE_DOUBLE_FP_CONFIG: cl_uint = 0x1032; 108 | cl_extension_loader! { 109 | "cl_khr_fp64"; 110 | } 111 | } 112 | 113 | pub mod cl_khr_fp16 { 114 | use cl::*; 115 | pub static CL_DEVICE_HALF_FP_CONFIG: cl_uint = 0x1033; 116 | cl_extension_loader! { 117 | "cl_khr_pf16"; 118 | } 119 | } 120 | 121 | pub mod cl_APPLE_SetMemObjectDestructor { 122 | use libc; 123 | use cl::*; 124 | cl_extension_loader! { 125 | "cl_APPLE_SetMemObjectDestructor"; 126 | extern fn clSetMemObjectDestructorAPPLE(memobj: cl_mem, 127 | pfn_notify: (extern fn(memobj: cl_mem, 128 | user_data: *mut libc::c_void)), 129 | user_data: *mut libc::c_void) -> () // Note: returning () is necessary to satisfy macros 130 | } 131 | } 132 | 133 | pub mod cl_APPLE_ContextLoggingFunctions { 134 | use libc; 135 | use cl::*; 136 | cl_extension_loader! { 137 | "cl_APPLE_ContextLoggingFunctions"; 138 | extern fn clLogMessagesToSystemLogAPPLE(errstr: *const libc::c_char, 139 | private_info: *const libc::c_void, 140 | cb: libc::size_t, 141 | user_data: *mut libc::c_void) -> (), 142 | extern fn clLogMessagesToStdoutAPPLE(errstr: *const libc::c_char, 143 | private_info: *const libc::c_void, 144 | cb: libc::size_t, 145 | user_data: *mut libc::c_void) -> (), 146 | extern fn clLogMessagesToStderrAPPLE(errstr: *const libc::c_char, 147 | private_info: *const libc::c_void, 148 | cb: libc::size_t, 149 | user_data: *mut libc::c_void) -> () 150 | } 151 | } 152 | 153 | pub mod cl_khr_icd { 154 | use libc; 155 | use cl::*; 156 | pub static CL_PLATFORM_ICD_SUFFIX: cl_uint = 0x0920; 157 | // Note: this is an error code, but we can't extend CLStatus with it... hmm. 158 | pub static CL_PLATFORM_NOT_FOUND_KHR: cl_int = -1001; 159 | cl_extension_loader! { 160 | "cl_khr_icd"; 161 | extern fn clIcdGetPlatformIDsKHR(num_entries: cl_uint, 162 | platform: *mut cl_platform_id, 163 | num_platforms: *mut cl_uint) -> cl_int 164 | } 165 | } 166 | 167 | pub mod cl_nv_device_attribute_query { 168 | use cl::*; 169 | pub static CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV: cl_uint = 0x4000; 170 | pub static CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV: cl_uint = 0x4001; 171 | pub static CL_DEVICE_REGISTERS_PER_BLOCK_NV: cl_uint = 0x4002; 172 | pub static CL_DEVICE_WARP_SIZE_NV: cl_uint = 0x4003; 173 | pub static CL_DEVICE_GPU_OVERLAP_NV: cl_uint = 0x4004; 174 | pub static CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV: cl_uint = 0x4005; 175 | pub static CL_DEVICE_INTEGRATED_MEMORY_NV: cl_uint = 0x4006; 176 | cl_extension_loader! { 177 | "cl_nv_device_attribute_query"; 178 | } 179 | } 180 | 181 | pub mod cl_amd_device_attribute_query { 182 | use cl::*; 183 | pub static CL_DEVICE_PROFILING_TIMER_OFFSET_AMD: cl_uint = 0x4036; 184 | cl_extension_loader! { 185 | "cl_amd_device_attribute_query"; 186 | } 187 | } 188 | 189 | pub mod cl_arm_printf { 190 | use cl::*; 191 | pub static CL_PRINTF_CALLBACK_ARM: cl_uint = 0x40B0; 192 | pub static CL_PRINTF_BUFFERSIZE_ARM: cl_uint = 0x40B1; 193 | cl_extension_loader! { 194 | "cl_arm_printf"; 195 | } 196 | } 197 | 198 | pub mod cl_ext_device_fission { 199 | use cl::*; 200 | pub type cl_device_partition_property_ext = cl_ulong; 201 | pub static CL_DEVICE_PARTITION_EQUALLY_EXT: cl_device_partition_property_ext = 0x4050; 202 | pub static CL_DEVICE_PARTITION_BY_COUNTS_EXT: cl_device_partition_property_ext = 0x4051; 203 | pub static CL_DEVICE_PARTITION_BY_NAMES_EXT: cl_device_partition_property_ext = 0x4052; 204 | pub static CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN_EXT: cl_device_partition_property_ext = 0x4053; 205 | pub static CL_DEVICE_PARENT_DEVICE_EXT: cl_device_info = 0x4054; 206 | pub static CL_DEVICE_PARTITION_TYPES_EXT: cl_device_info = 0x4055; 207 | pub static CL_DEVICE_AFFINITY_DOMAINS_EXT: cl_device_info = 0x4056; 208 | pub static CL_DEVICE_REFERENCE_COUNT_EXT: cl_device_info = 0x4057; 209 | pub static CL_DEVICE_PARTITION_STYLE_EXT: cl_device_info = 0x4058; 210 | pub static CL_DEVICE_PARTITION_FAILED_EXT: cl_int = -1057; 211 | pub static CL_INVALID_PARTITION_COUNT_EXT: cl_int = -1058; 212 | pub static CL_INVALID_PARTITION_NAME_EXT: cl_int = -1059; 213 | pub static CL_AFFINITY_DOMAIN_L1_CACHE_EXT: cl_uint = 0x1; 214 | pub static CL_AFFINITY_DOMAIN_L2_CACHE_EXT: cl_uint = 0x2; 215 | pub static CL_AFFINITY_DOMAIN_L3_CACHE_EXT: cl_uint = 0x3; 216 | pub static CL_AFFINITY_DOMAIN_L4_CACHE_EXT: cl_uint = 0x4; 217 | pub static CL_AFFINITY_DOMAIN_NUMA_EXT: cl_uint = 0x10; 218 | pub static CL_AFFINITY_DOMAIN_NEXT_FISSIONABLE_EXT: cl_uint = 0x100; 219 | pub static CL_PROPERTIES_LIST_END_EXT: cl_device_partition_property_ext = 0; 220 | pub static CL_PARTITION_BY_COUNTS_LIST_END_EXT: cl_device_partition_property_ext = 0; 221 | pub static CL_PARTITION_BY_NAMES_LIST_END_EXT: cl_device_partition_property_ext = std::u64::MAX; 222 | cl_extension_loader! { 223 | "cl_ext_device_fission"; 224 | extern fn clReleaseDeviceEXT(device: cl_device_id) -> cl_int, 225 | extern fn clRetainDeviceEXT(device: cl_device_id) -> cl_int, 226 | extern fn clCreateSubDevicesExt(in_device: cl_device_id, 227 | properties: *const cl_device_partition_property_ext, 228 | num_entries: cl_uint, 229 | out_devices: *mut cl_device_id, 230 | num_devices: *mut cl_uint) -> cl_int 231 | } 232 | } 233 | 234 | pub mod cl_qcom_ext_host_ptr { 235 | use libc; 236 | use cl::*; 237 | pub type cl_image_pitch_info_qcom = cl_uint; 238 | pub struct cl_mem_ext_host_ptr { 239 | pub allocation_type: cl_uint, 240 | pub host_cache_policy: cl_uint 241 | } 242 | pub static CL_MEM_EXT_HOST_PTR_QCOM: cl_uint = (1 << 29); 243 | pub static CL_DEVICE_EXT_MEM_PADDING_IN_BYTES_QCOM: cl_uint = 0x40A0; 244 | pub static CL_DEVICE_PAGE_SIZE_QCOM: cl_uint = 0x40A1; 245 | pub static CL_IMAGE_ROW_ALIGNMENT_QCOM: cl_uint = 0x40A2; 246 | pub static CL_IMAGE_SLICE_ALIGNMENT_QCOM: cl_uint = 0x40A3; 247 | pub static CL_MEM_HOST_UNCACHED_QCOM: cl_uint = 0x40A4; 248 | pub static CL_MEM_HOST_WRITEBACK_QCOM: cl_uint = 0x40A5; 249 | pub static CL_MEM_HOST_WRITETHROUGH_QCOM: cl_uint = 0x40A6; 250 | pub static CL_MEM_HOST_WRITE_COMBINING_QCOM: cl_uint = 0x40A7; 251 | cl_extension_loader! { 252 | "cl_qcom_ext_host_ptr"; 253 | extern fn clGetDeviceImageInfoQCOM(device: cl_device_id, 254 | image_width: libc::size_t, 255 | image_height: libc::size_t, 256 | image_format: *const cl_image_format, 257 | param_name: cl_image_pitch_info_qcom, 258 | param_value_size: libc::size_t, 259 | param_value: *mut libc::c_void, 260 | param_value_size_ret: *mut libc::size_t) -> () 261 | } 262 | } 263 | 264 | // This extension depends on the previous one. Should we try to express that? 265 | pub mod cl_qcom_ion_host_ptr { 266 | use libc; 267 | use cl::*; 268 | use super::cl_qcom_ext_host_ptr; 269 | struct cl_mem_ion_host_ptr { 270 | pub ext_host_ptr: cl_qcom_ext_host_ptr::cl_mem_ext_host_ptr, 271 | pub ion_filedesc: libc::c_int, 272 | pub ion_hostptr: *mut libc::c_void 273 | } 274 | pub static CL_MEM_ION_HOST_PTR_QCOM: cl_uint = 0x40A8; 275 | 276 | cl_extension_loader! { 277 | "cl_qcom_ion_host_ptr"; 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /src/hl.rs: -------------------------------------------------------------------------------- 1 | //! A higher level API. 2 | 3 | use libc; 4 | use std::ffi::CString; 5 | use std::iter::repeat; 6 | use std::marker::PhantomData; 7 | use std::mem; 8 | use std::ptr; 9 | use std::string::String; 10 | use std::vec::Vec; 11 | 12 | use cl; 13 | use cl::*; 14 | use cl::ll::*; 15 | use cl::CLStatus::CL_SUCCESS; 16 | use error::check; 17 | use mem::{Put, Get, Write, Read, Buffer, CLBuffer}; 18 | 19 | #[derive(Copy, Clone)] 20 | pub enum DeviceType { 21 | CPU, GPU 22 | } 23 | 24 | fn convert_device_type(device: DeviceType) -> cl_device_type { 25 | match device { 26 | DeviceType::CPU => CL_DEVICE_TYPE_CPU, 27 | DeviceType::GPU => CL_DEVICE_TYPE_GPU | CL_DEVICE_TYPE_ACCELERATOR 28 | } 29 | } 30 | 31 | pub struct Platform { 32 | id: cl_platform_id 33 | } 34 | 35 | impl Platform { 36 | fn get_devices_internal(&self, dtype: cl_device_type) -> Vec 37 | { 38 | unsafe 39 | { 40 | let mut num_devices = 0; 41 | 42 | info!("Looking for devices matching {}", dtype); 43 | 44 | clGetDeviceIDs(self.id, dtype, 0, ptr::null_mut(), 45 | (&mut num_devices)); 46 | 47 | let mut ids: Vec = repeat(0 as cl_device_id) 48 | .take(num_devices as usize).collect(); 49 | clGetDeviceIDs(self.id, dtype, ids.len() as cl_uint, 50 | ids.as_mut_ptr(), (&mut num_devices)); 51 | ids.iter().map(|id| { Device {id: *id }}).collect() 52 | } 53 | } 54 | 55 | pub fn get_devices(&self) -> Vec 56 | { 57 | self.get_devices_internal(CL_DEVICE_TYPE_ALL) 58 | } 59 | 60 | pub fn get_devices_by_types(&self, types: &[DeviceType]) -> Vec 61 | { 62 | let mut dtype = 0; 63 | for &t in types.iter() { 64 | dtype |= convert_device_type(t); 65 | } 66 | 67 | self.get_devices_internal(dtype) 68 | } 69 | 70 | fn profile_info(&self, name: cl_platform_info) -> String 71 | { 72 | unsafe { 73 | let mut size = 0 as libc::size_t; 74 | 75 | let status = clGetPlatformInfo(self.id, 76 | name, 77 | 0, 78 | ptr::null_mut(), 79 | &mut size); 80 | check(status, "Could not determine platform info string length"); 81 | 82 | let mut buf : Vec 83 | = repeat(0u8).take(size as usize).collect(); 84 | 85 | let status = clGetPlatformInfo(self.id, 86 | name, 87 | size, 88 | buf.as_mut_ptr() as *mut libc::c_void, 89 | ptr::null_mut()); 90 | check(status, "Could not get platform info string"); 91 | 92 | String::from_utf8_unchecked(buf) 93 | } 94 | } 95 | 96 | pub fn get_id(&self) -> cl_platform_id { 97 | self.id 98 | } 99 | 100 | pub fn name(&self) -> String 101 | { 102 | self.profile_info(CL_PLATFORM_NAME) 103 | } 104 | 105 | pub fn version(&self) -> String 106 | { 107 | self.profile_info(CL_PLATFORM_VERSION) 108 | } 109 | 110 | pub fn profile(&self) -> String 111 | { 112 | self.profile_info(CL_PLATFORM_PROFILE) 113 | } 114 | 115 | pub fn vendor(&self) -> String 116 | { 117 | self.profile_info(CL_PLATFORM_VENDOR) 118 | } 119 | 120 | pub fn extensions(&self) -> String 121 | { 122 | self.profile_info(CL_PLATFORM_EXTENSIONS) 123 | } 124 | 125 | pub unsafe fn from_platform_id(id: cl_platform_id) -> Platform { 126 | Platform { id: id } 127 | } 128 | } 129 | 130 | // This mutex is used to work around weak OpenCL implementations. 131 | // On some implementations concurrent calls to clGetPlatformIDs 132 | // will cause the implantation to return invalid status. 133 | static mut platforms_mutex: std::sync::StaticMutex = std::sync::MUTEX_INIT; 134 | 135 | pub fn get_platforms() -> Vec 136 | { 137 | let mut num_platforms = 0 as cl_uint; 138 | 139 | unsafe 140 | { 141 | let guard = platforms_mutex.lock(); 142 | let status = clGetPlatformIDs(0, 143 | ptr::null_mut(), 144 | (&mut num_platforms)); 145 | // unlock this before the check in case the check fails 146 | check(status, "could not get platform count."); 147 | 148 | let mut ids: Vec = repeat(0 as cl_device_id) 149 | .take(num_platforms as usize).collect(); 150 | 151 | let status = clGetPlatformIDs(num_platforms, 152 | ids.as_mut_ptr(), 153 | (&mut num_platforms)); 154 | check(status, "could not get platforms."); 155 | 156 | let _ = guard; 157 | 158 | ids.iter().map(|id| { Platform { id: *id } }).collect() 159 | } 160 | } 161 | 162 | pub fn create_context_with_properties(dev: &[Device], prop: &[cl_context_properties]) -> Context 163 | { 164 | unsafe 165 | { 166 | // TODO: Support for multiple devices 167 | let mut errcode = 0; 168 | let dev: Vec = dev.iter().map(|dev| dev.id).collect(); 169 | 170 | // TODO: Proper error messages 171 | let ctx = clCreateContext(&prop[0], 172 | dev.len() as u32, 173 | &dev[0], 174 | mem::transmute(ptr::null::()), 175 | ptr::null_mut(), 176 | &mut errcode); 177 | 178 | check(errcode, "Failed to create opencl context!"); 179 | 180 | Context { ctx: ctx } 181 | } 182 | } 183 | 184 | #[derive(Copy, Clone)] 185 | pub struct Device { 186 | id: cl_device_id 187 | } 188 | 189 | unsafe impl Sync for Device {} 190 | unsafe impl Send for Device {} 191 | 192 | impl Device { 193 | fn profile_info(&self, name: cl_device_info) -> String 194 | { 195 | unsafe { 196 | let mut size = 0 as libc::size_t; 197 | 198 | let status = clGetDeviceInfo( 199 | self.id, 200 | name, 201 | 0, 202 | ptr::null_mut(), 203 | &mut size); 204 | check(status, "Could not determine device info string length"); 205 | 206 | let mut buf : Vec 207 | = repeat(0u8).take(size as usize).collect(); 208 | 209 | let status = clGetDeviceInfo(self.id, 210 | name, 211 | size, 212 | buf.as_mut_ptr() as *mut libc::c_void, 213 | ptr::null_mut()); 214 | check(status, "Could not get device info string"); 215 | 216 | String::from_utf8_unchecked(buf) 217 | } 218 | } 219 | 220 | pub fn name(&self) -> String 221 | { 222 | self.profile_info(CL_DEVICE_NAME) 223 | } 224 | pub fn vendor(&self) -> String 225 | { 226 | self.profile_info(CL_DEVICE_VENDOR) 227 | } 228 | pub fn profile(&self) -> String 229 | { 230 | self.profile_info(CL_DEVICE_PROFILE) 231 | } 232 | pub fn device_type(&self) -> String 233 | { 234 | self.profile_info(CL_DEVICE_TYPE) 235 | } 236 | 237 | pub fn compute_units(&self) -> usize { 238 | unsafe { 239 | let mut ct: usize = 0; 240 | let status = clGetDeviceInfo( 241 | self.id, 242 | CL_DEVICE_MAX_COMPUTE_UNITS, 243 | 8, 244 | (&mut ct as *mut usize) as *mut libc::c_void, 245 | ptr::null_mut()); 246 | check(status, "Could not get number of device compute units."); 247 | return ct; 248 | } 249 | } 250 | 251 | 252 | pub fn create_context(&self) -> Context 253 | { 254 | unsafe 255 | { 256 | // TODO: Support for multiple devices 257 | let mut errcode = 0; 258 | 259 | // TODO: Proper error messages 260 | let ctx = clCreateContext(ptr::null(), 261 | 1, 262 | &self.id, 263 | mem::transmute(ptr::null::()), 264 | ptr::null_mut(), 265 | (&mut errcode)); 266 | 267 | check(errcode, "Failed to create opencl context!"); 268 | 269 | Context { ctx: ctx } 270 | } 271 | } 272 | } 273 | 274 | pub struct Context { 275 | pub ctx: cl_context, 276 | } 277 | 278 | unsafe impl Sync for Context {} 279 | unsafe impl Send for Context {} 280 | 281 | impl Context { 282 | pub fn create_buffer(&self, size: usize, flags: cl_mem_flags) -> CLBuffer 283 | { 284 | unsafe { 285 | let mut status = 0; 286 | let buf = clCreateBuffer(self.ctx, 287 | flags, 288 | (size*mem::size_of::()) as libc::size_t , 289 | ptr::null_mut(), 290 | (&mut status)); 291 | check(status, "Could not allocate buffer"); 292 | CLBuffer { 293 | cl_buffer: buf, 294 | phantom: PhantomData, 295 | } 296 | } 297 | } 298 | 299 | 300 | pub fn create_buffer_from>(&self, create: IN, flags: cl_mem_flags) -> U 301 | { 302 | create.put(|p, len| { 303 | let mut status = 0; 304 | let buf = unsafe { 305 | clCreateBuffer(self.ctx, 306 | flags | CL_MEM_COPY_HOST_PTR, 307 | len, 308 | mem::transmute(p), 309 | (&mut status)) 310 | }; 311 | check(status, "Could not allocate buffer"); 312 | buf 313 | }) 314 | } 315 | 316 | pub fn create_command_queue(&self, device: &Device) -> CommandQueue 317 | { 318 | unsafe 319 | { 320 | let mut errcode = 0; 321 | 322 | let cqueue = clCreateCommandQueue(self.ctx, 323 | device.id, 324 | CL_QUEUE_PROFILING_ENABLE, 325 | (&mut errcode)); 326 | 327 | check(errcode, "Failed to create command queue!"); 328 | 329 | CommandQueue { 330 | cqueue: cqueue 331 | } 332 | } 333 | } 334 | 335 | pub fn create_program_from_source(&self, src: &str) -> Program 336 | { 337 | unsafe 338 | { 339 | let src = CString::new(src).unwrap(); 340 | 341 | let mut status = CL_SUCCESS as cl_int; 342 | let program = clCreateProgramWithSource( 343 | self.ctx, 344 | 1, 345 | &src.as_ptr(), 346 | ptr::null(), 347 | (&mut status)); 348 | check(status, "Could not create program"); 349 | 350 | Program { prg: program } 351 | } 352 | } 353 | 354 | pub fn create_program_from_binary(&self, bin: &str, device: &Device) -> Program { 355 | let src = CString::new(bin).unwrap(); 356 | let mut status = CL_SUCCESS as cl_int; 357 | let len = bin.len() as libc::size_t; 358 | let program = unsafe { 359 | clCreateProgramWithBinary( 360 | self.ctx, 361 | 1, 362 | &device.id, 363 | (&len), 364 | (src.as_ptr() as *const *const i8) as *const *const libc::c_uchar, 365 | ptr::null_mut(), 366 | (&mut status)) 367 | }; 368 | check(status, "Could not create program"); 369 | 370 | Program {prg: program} 371 | } 372 | } 373 | 374 | impl Drop for Context 375 | { 376 | fn drop(&mut self) { 377 | unsafe { 378 | clReleaseContext(self.ctx); 379 | } 380 | } 381 | } 382 | 383 | impl<'r, T> KernelArg for &'r (Buffer + 'r) { 384 | fn get_value(&self) -> (libc::size_t, *const libc::c_void) 385 | { 386 | unsafe { 387 | (mem::size_of::() as libc::size_t, 388 | self.id_ptr() as *const libc::c_void) 389 | } 390 | } 391 | } 392 | 393 | impl<'r, T> KernelArg for Box + 'r> { 394 | fn get_value(&self) -> (libc::size_t, *const libc::c_void) 395 | { 396 | unsafe { 397 | (mem::size_of::() as libc::size_t, 398 | self.id_ptr() as *const libc::c_void) 399 | } 400 | } 401 | } 402 | 403 | 404 | pub struct CommandQueue { 405 | pub cqueue: cl_command_queue 406 | } 407 | 408 | unsafe impl Sync for CommandQueue {} 409 | unsafe impl Send for CommandQueue {} 410 | 411 | impl CommandQueue 412 | { 413 | //synchronous 414 | pub fn enqueue_kernel(&self, k: &Kernel, global: I, local: Option, wait_on: E) 415 | -> Event 416 | { 417 | unsafe 418 | { 419 | wait_on.as_event_list(|event_list, event_list_length| { 420 | let mut e: cl_event = ptr::null_mut(); 421 | let mut status = clEnqueueNDRangeKernel( 422 | self.cqueue, 423 | k.kernel, 424 | KernelIndex::num_dimensions(None::), 425 | ptr::null(), 426 | global.get_ptr(), 427 | match local { 428 | Some(ref l) => l.get_ptr() as *const libc::size_t, 429 | None => ptr::null() 430 | }, 431 | event_list_length, 432 | event_list, 433 | (&mut e)); 434 | check(status, "Error enqueuing kernel."); 435 | status = clFinish(self.cqueue); 436 | check(status, "Error finishing kernel."); 437 | Event { event: e } 438 | }) 439 | } 440 | } 441 | 442 | //asynchronous 443 | pub fn enqueue_async_kernel(&self, k: &Kernel, global: I, local: Option, wait_on: E) 444 | -> Event 445 | { 446 | unsafe 447 | { 448 | wait_on.as_event_list(|event_list, event_list_length| { 449 | let mut e: cl_event = ptr::null_mut(); 450 | let status = clEnqueueNDRangeKernel( 451 | self.cqueue, 452 | k.kernel, 453 | KernelIndex::num_dimensions(None::), 454 | ptr::null(), 455 | global.get_ptr(), 456 | match local { 457 | Some(ref l) => l.get_ptr() as *const libc::size_t, 458 | None => ptr::null() 459 | }, 460 | event_list_length, 461 | event_list, 462 | (&mut e)); 463 | check(status, "Error enqueuing kernel."); 464 | Event { event: e } 465 | }) 466 | } 467 | } 468 | 469 | pub fn get, G: Get, E: EventList>(&self, buf: &B, event: E) -> G 470 | { 471 | event.as_event_list(|event_list, event_list_length| { 472 | Get::get(buf, |offset, ptr, len| { 473 | unsafe { 474 | let err = clEnqueueReadBuffer(self.cqueue, 475 | buf.id(), 476 | CL_TRUE, 477 | offset as libc::size_t, 478 | len, 479 | ptr, 480 | event_list_length, 481 | event_list, 482 | ptr::null_mut()); 483 | 484 | check(err, "Failed to read buffer"); 485 | } 486 | }) 487 | }) 488 | } 489 | 490 | pub fn write>(&self, mem: &B, write: &U, event: E) 491 | { 492 | unsafe { 493 | event.as_event_list(|event_list, event_list_length| { 494 | write.write(|offset, p, len| { 495 | let err = clEnqueueWriteBuffer(self.cqueue, 496 | mem.id(), 497 | CL_TRUE, 498 | offset as libc::size_t, 499 | len as libc::size_t, 500 | p as *const libc::c_void, 501 | event_list_length, 502 | event_list, 503 | ptr::null_mut()); 504 | 505 | check(err, "Failed to write buffer"); 506 | }) 507 | }) 508 | } 509 | } 510 | 511 | pub fn write_async>(&self, mem: &B, write: &U, event: E) -> Event 512 | { 513 | let mut out_event = None; 514 | unsafe { 515 | event.as_event_list(|evt, evt_len| { 516 | write.write(|offset, p, len| { 517 | let mut e: cl_event = ptr::null_mut(); 518 | let err = clEnqueueWriteBuffer(self.cqueue, 519 | mem.id(), 520 | CL_FALSE, 521 | offset as libc::size_t, 522 | len as libc::size_t, 523 | p as *const libc::c_void, 524 | evt_len, 525 | evt, 526 | &mut e); 527 | out_event = Some(e); 528 | check(err, "Failed to write buffer"); 529 | }) 530 | }) 531 | } 532 | Event { event: out_event.unwrap() } 533 | } 534 | 535 | pub fn read>(&self, mem: &B, read: &mut U, event: E) 536 | { 537 | event.as_event_list(|event_list, event_list_length| { 538 | read.read(|offset, p, len| { 539 | unsafe { 540 | let err = clEnqueueReadBuffer(self.cqueue, 541 | mem.id(), 542 | CL_TRUE, 543 | offset as libc::size_t, 544 | len as libc::size_t, 545 | p as *mut libc::c_void, 546 | event_list_length, 547 | event_list, 548 | ptr::null_mut()); 549 | 550 | check(err, "Failed to read buffer"); 551 | } 552 | }) 553 | }) 554 | } 555 | } 556 | 557 | impl Drop for CommandQueue 558 | { 559 | fn drop(&mut self) { 560 | unsafe { 561 | clReleaseCommandQueue(self.cqueue); 562 | } 563 | } 564 | } 565 | 566 | 567 | /// Represents an OpenCL program, which is a collection of kernels. 568 | /// 569 | /// Create these using 570 | /// [`Context::create_program_from_source`](struct.Context.html#method.create_program_from_source) 571 | /// or 572 | /// [`Context::create_program_from_binary`](struct.Context.html#method.create_program_from_binary). 573 | pub struct Program 574 | { 575 | prg: cl_program, 576 | } 577 | 578 | impl Drop for Program 579 | { 580 | fn drop(&mut self) { 581 | unsafe { 582 | clReleaseProgram(self.prg); 583 | } 584 | } 585 | } 586 | 587 | impl Program 588 | { 589 | /// Build the program for a given device. 590 | /// 591 | /// Both Ok and Err returns include the build log. 592 | pub fn build(&self, device: &Device) -> Result 593 | { 594 | unsafe 595 | { 596 | let ret = clBuildProgram(self.prg, 1, &device.id, 597 | ptr::null(), 598 | mem::transmute(ptr::null::()), 599 | ptr::null_mut()); 600 | // Get the build log. 601 | let mut size = 0 as libc::size_t; 602 | let status = clGetProgramBuildInfo( 603 | self.prg, 604 | device.id, 605 | CL_PROGRAM_BUILD_LOG, 606 | 0, 607 | ptr::null_mut(), 608 | (&mut size)); 609 | check(status, "Could not get build log"); 610 | 611 | let mut buf : Vec = repeat(0u8).take(size as usize).collect(); 612 | let status = clGetProgramBuildInfo( 613 | self.prg, 614 | device.id, 615 | CL_PROGRAM_BUILD_LOG, 616 | buf.len() as libc::size_t, 617 | buf.as_mut_ptr() as *mut libc::c_void, 618 | ptr::null_mut()); 619 | check(status, "Could not get build log"); 620 | 621 | let log = String::from_utf8_lossy(&buf[..]); 622 | if ret == CL_SUCCESS as cl_int { 623 | Ok(log.into_owned()) 624 | } else { 625 | Err(log.into_owned()) 626 | } 627 | } 628 | } 629 | 630 | pub fn create_kernel(&self, name: &str) -> Kernel { 631 | create_kernel(self, name) 632 | } 633 | } 634 | 635 | pub struct Kernel { 636 | kernel: cl_kernel, 637 | } 638 | 639 | impl Drop for Kernel 640 | { 641 | fn drop(&mut self) { 642 | unsafe { 643 | clReleaseKernel(self.kernel); 644 | } 645 | } 646 | } 647 | 648 | impl Kernel { 649 | pub fn set_arg(&self, i: usize, x: &T) 650 | { 651 | set_kernel_arg(self, i as cl::cl_uint, x) 652 | } 653 | } 654 | 655 | pub fn create_kernel(program: &Program, kernel: & str) -> Kernel 656 | { 657 | unsafe { 658 | let mut errcode = 0; 659 | let str = CString::new(kernel).unwrap(); 660 | let kernel = clCreateKernel(program.prg, 661 | str.as_ptr(), 662 | (&mut errcode)); 663 | 664 | check(errcode, "Failed to create kernel!"); 665 | 666 | Kernel { kernel: kernel } 667 | } 668 | } 669 | 670 | pub trait KernelArg { 671 | fn get_value(&self) -> (libc::size_t, *const libc::c_void); 672 | } 673 | 674 | macro_rules! scalar_kernel_arg ( 675 | ($t:ty) => (impl KernelArg for $t { 676 | fn get_value(&self) -> (libc::size_t, *const libc::c_void) { 677 | (mem::size_of::<$t>() as libc::size_t, 678 | (self as *const $t) as *const libc::c_void) 679 | } 680 | }) 681 | ); 682 | 683 | scalar_kernel_arg!(isize); 684 | scalar_kernel_arg!(usize); 685 | scalar_kernel_arg!(u32); 686 | scalar_kernel_arg!(u64); 687 | scalar_kernel_arg!(i32); 688 | scalar_kernel_arg!(i64); 689 | scalar_kernel_arg!(f32); 690 | scalar_kernel_arg!(f64); 691 | scalar_kernel_arg!([f32; 2]); 692 | scalar_kernel_arg!([f64; 2]); 693 | 694 | impl KernelArg for [f32; 3] { 695 | fn get_value(&self) -> (libc::size_t, *const libc::c_void) { 696 | (4 * mem::size_of::() as libc::size_t, 697 | (self as *const f32) as *const libc::c_void) 698 | } 699 | } 700 | 701 | impl KernelArg for [f64; 3] { 702 | fn get_value(&self) -> (libc::size_t, *const libc::c_void) { 703 | (4 * mem::size_of::() as libc::size_t, 704 | (self as *const f64) as *const libc::c_void) 705 | } 706 | } 707 | 708 | pub fn set_kernel_arg(kernel: & Kernel, 709 | position: cl_uint, 710 | arg: &T) 711 | { 712 | unsafe 713 | { 714 | let (size, p) = arg.get_value(); 715 | let ret = clSetKernelArg(kernel.kernel, position, 716 | size, 717 | p); 718 | 719 | check(ret, "Failed to set kernel arg!"); 720 | } 721 | } 722 | 723 | 724 | pub struct Event 725 | { 726 | pub event: cl_event, 727 | } 728 | 729 | impl Event { 730 | fn get_time(&self, param: cl_uint) -> u64 731 | { 732 | unsafe { 733 | let mut time: cl_ulong = 0; 734 | let ret = clGetEventProfilingInfo(self.event, 735 | param, 736 | mem::size_of::() as libc::size_t, 737 | (&mut time as *mut u64) as *mut libc::c_void, 738 | ptr::null_mut()); 739 | 740 | check(ret, "Failed to get profiling info"); 741 | time as u64 742 | } 743 | } 744 | 745 | pub fn queue_time(&self) -> u64 746 | { 747 | self.get_time(CL_PROFILING_COMMAND_QUEUED) 748 | } 749 | 750 | pub fn submit_time(&self) -> u64 751 | { 752 | self.get_time(CL_PROFILING_COMMAND_SUBMIT) 753 | } 754 | 755 | pub fn start_time(&self) -> u64 756 | { 757 | self.get_time(CL_PROFILING_COMMAND_START) 758 | } 759 | 760 | pub fn end_time(&self) -> u64 761 | { 762 | self.get_time(CL_PROFILING_COMMAND_END) 763 | } 764 | } 765 | 766 | impl Drop for Event 767 | { 768 | fn drop(&mut self) { 769 | unsafe { 770 | clReleaseEvent(self.event); 771 | } 772 | } 773 | } 774 | 775 | pub trait EventList { 776 | fn as_event_list T>(&self, F) -> T; 777 | 778 | fn wait(&self) { 779 | self.as_event_list(|p, len| { 780 | unsafe { 781 | let status = clWaitForEvents(len, p); 782 | check(status, "Error waiting for event(s)"); 783 | } 784 | }) 785 | } 786 | } 787 | 788 | impl<'r> EventList for &'r Event { 789 | fn as_event_list(&self, f: F) -> T 790 | where F: FnOnce(*const cl_event, cl_uint) -> T 791 | { 792 | f(&self.event, 1 as cl_uint) 793 | } 794 | } 795 | 796 | impl EventList for Event { 797 | fn as_event_list(&self, f: F) -> T 798 | where F: FnOnce(*const cl_event, cl_uint) -> T 799 | { 800 | f(&self.event, 1 as cl_uint) 801 | } 802 | } 803 | 804 | impl EventList for Option { 805 | fn as_event_list(&self, f: F) -> T2 806 | where F: FnOnce(*const cl_event, cl_uint) -> T2 807 | { 808 | match *self { 809 | None => f(ptr::null(), 0), 810 | Some(ref s) => s.as_event_list(f) 811 | } 812 | } 813 | } 814 | 815 | impl<'r> EventList for &'r [Event] { 816 | fn as_event_list(&self, f: F) -> T 817 | where F: FnOnce(*const cl_event, cl_uint) -> T 818 | { 819 | let mut vec: Vec = Vec::with_capacity(self.len()); 820 | for item in self.iter(){ 821 | vec.push(item.event); 822 | } 823 | 824 | f(vec.as_ptr(), vec.len() as cl_uint) 825 | } 826 | } 827 | 828 | /* this seems VERY hackey */ 829 | impl EventList for () { 830 | fn as_event_list(&self, f: F) -> T 831 | where F: FnOnce(*const cl_event, cl_uint) -> T 832 | { 833 | f(ptr::null(), 0) 834 | } 835 | } 836 | 837 | 838 | pub trait KernelIndex 839 | { 840 | fn num_dimensions(dummy_self: Option) -> cl_uint where Self: Sized; 841 | fn get_ptr(&self) -> *const libc::size_t; 842 | } 843 | 844 | impl KernelIndex for isize 845 | { 846 | fn num_dimensions(_: Option) -> cl_uint { 1 } 847 | 848 | fn get_ptr(&self) -> *const libc::size_t 849 | { 850 | (self as *const isize) as *const libc::size_t 851 | } 852 | } 853 | 854 | impl KernelIndex for (isize, isize) { 855 | fn num_dimensions(_: Option<(isize, isize)>) -> cl_uint { 2 } 856 | 857 | fn get_ptr(&self) -> *const libc::size_t { 858 | (self as *const (isize, isize)) as *const libc::size_t 859 | } 860 | } 861 | 862 | impl KernelIndex for (isize, isize, isize) 863 | { 864 | fn num_dimensions(_: Option<(isize, isize, isize)>) -> cl_uint { 3 } 865 | 866 | fn get_ptr(&self) -> *const libc::size_t { 867 | (self as *const (isize, isize, isize)) as *const libc::size_t 868 | } 869 | } 870 | 871 | impl KernelIndex for usize 872 | { 873 | fn num_dimensions(_: Option) -> cl_uint { 1 } 874 | 875 | fn get_ptr(&self) -> *const libc::size_t { 876 | (self as *const usize) as *const libc::size_t 877 | } 878 | } 879 | 880 | impl KernelIndex for (usize, usize) 881 | { 882 | fn num_dimensions(_: Option<(usize, usize)>) -> cl_uint { 2 } 883 | 884 | fn get_ptr(&self) -> *const libc::size_t { 885 | (self as *const (usize, usize)) as *const libc::size_t 886 | } 887 | } 888 | 889 | impl KernelIndex for (usize, usize, usize) 890 | { 891 | fn num_dimensions(_: Option<(usize, usize, usize)>) -> cl_uint { 3 } 892 | 893 | fn get_ptr(&self) -> *const libc::size_t { 894 | (self as *const (usize, usize, usize)) as *const libc::size_t 895 | } 896 | } 897 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(improper_ctypes)] 2 | #![allow(missing_copy_implementations)] 3 | #![allow(non_upper_case_globals)] 4 | 5 | #![feature(static_mutex)] 6 | 7 | //! OpenCL bindings for Rust. 8 | 9 | extern crate libc; 10 | #[macro_use] 11 | extern crate log; 12 | 13 | #[link(name = "OpenCL", kind = "framework")] 14 | #[cfg(target_os = "macos")] 15 | extern { } 16 | 17 | #[link(name = "OpenCL")] 18 | #[cfg(target_os = "linux")] 19 | extern { } 20 | 21 | /// Low-level OpenCL bindings. These should primarily be used by the 22 | /// higher level features in this library. 23 | pub mod cl; 24 | /// OpenCL extensions 25 | pub mod ext; 26 | pub mod error; 27 | pub mod hl; 28 | pub mod util; 29 | pub mod mem; 30 | pub mod array; 31 | -------------------------------------------------------------------------------- /src/mem.rs: -------------------------------------------------------------------------------- 1 | //! High level buffer management. 2 | 3 | use libc::{size_t, c_void}; 4 | use std::marker::{PhantomData}; 5 | use std::mem; 6 | use std::ptr; 7 | use std::vec::Vec; 8 | 9 | use cl::*; 10 | use cl::ll::*; 11 | 12 | use hl::KernelArg; 13 | use error::check; 14 | 15 | pub trait Buffer { 16 | unsafe fn id_ptr(&self) -> *const cl_mem; 17 | 18 | fn id(&self) -> cl_mem { 19 | unsafe { 20 | *self.id_ptr() 21 | } 22 | } 23 | 24 | fn byte_len(&self) -> size_t 25 | { 26 | unsafe { 27 | let mut size : size_t = 0; 28 | let err = clGetMemObjectInfo(self.id(), 29 | CL_MEM_SIZE, 30 | mem::size_of::() as size_t, 31 | (&mut size as *mut size_t) as *mut c_void, 32 | ptr::null_mut()); 33 | 34 | check(err, "Failed to read memory size"); 35 | size 36 | } 37 | } 38 | 39 | fn len(&self) -> usize { self.byte_len() as usize / mem::size_of::() } 40 | } 41 | 42 | pub struct CLBuffer { 43 | pub cl_buffer: cl_mem, 44 | pub phantom: PhantomData, 45 | } 46 | 47 | impl Drop for CLBuffer { 48 | fn drop(&mut self) { 49 | unsafe { 50 | clReleaseMemObject(self.cl_buffer); 51 | } 52 | } 53 | } 54 | 55 | impl Buffer for CLBuffer { 56 | unsafe fn id_ptr(&self) -> *const cl_mem 57 | { 58 | &self.cl_buffer as *const cl_mem 59 | } 60 | } 61 | 62 | impl KernelArg for CLBuffer { 63 | fn get_value(&self) -> (size_t, *const c_void) 64 | { 65 | unsafe { 66 | (mem::size_of::() as size_t, 67 | self.id_ptr() as *const c_void) 68 | } 69 | } 70 | } 71 | 72 | /* memory life cycle 73 | * | Trait | Exists in rust | Exists in OpenCL | Direction | 74 | * | Put | X | | rust -> opencl | 75 | * | Get | | X | opencl -> rust | 76 | * | Write | X | X | rust -> opencl | 77 | * | Read | X | X | opencl -> rust | 78 | *mut */ 79 | 80 | pub trait Put { 81 | fn put(&self, F) -> B 82 | where F: FnOnce(*const c_void, size_t) -> cl_mem; 83 | } 84 | 85 | pub trait Get { 86 | fn get(mem: &B, F) -> Self; 87 | } 88 | 89 | pub trait Write { 90 | fn write(&self, F); 91 | } 92 | 93 | pub trait Read { 94 | fn read(&mut self, F); 95 | } 96 | 97 | impl<'r, T> Put> for &'r [T] 98 | { 99 | fn put(&self, f: F) -> CLBuffer 100 | where F: FnOnce(*const c_void, size_t) -> cl_mem 101 | { 102 | CLBuffer { 103 | cl_buffer: f(self.as_ptr() as *const c_void, 104 | (self.len() * mem::size_of::()) as size_t), 105 | phantom: PhantomData, 106 | } 107 | } 108 | } 109 | 110 | impl<'r, T> Put> for &'r Vec 111 | { 112 | fn put(&self, f: F) -> CLBuffer 113 | where F: FnOnce(*const c_void, size_t) -> cl_mem 114 | { 115 | CLBuffer { 116 | cl_buffer: f(self.as_ptr() as *const c_void, (self.len() * mem::size_of::()) as size_t), 117 | phantom: PhantomData, 118 | } 119 | } 120 | } 121 | 122 | impl Put> for Vec 123 | { 124 | fn put(&self, f: F) -> CLBuffer 125 | where F: FnOnce(*const c_void, size_t) -> cl_mem 126 | { 127 | CLBuffer { 128 | cl_buffer: f(self.as_ptr() as *const c_void, (self.len() * mem::size_of::()) as size_t), 129 | phantom: PhantomData, 130 | } 131 | } 132 | } 133 | 134 | impl Get, T> for Vec 135 | { 136 | fn get(mem: &CLBuffer, f: F) -> Vec 137 | where F: FnOnce(size_t, *mut c_void, size_t) 138 | { 139 | let mut v: Vec = Vec::with_capacity(mem.len()); 140 | unsafe { 141 | v.set_len(mem.len()); 142 | } 143 | f(0, v.as_ptr() as *mut c_void, (v.len() * mem::size_of::()) as size_t); 144 | v 145 | } 146 | } 147 | 148 | impl<'r, T> Write for &'r [T] 149 | { 150 | fn write(&self, f: F) 151 | where F: FnOnce(size_t, *const c_void, size_t) 152 | { 153 | f(0, self.as_ptr() as *const c_void, (self.len() * mem::size_of::()) as size_t) 154 | } 155 | } 156 | 157 | impl<'r, T> Read for &'r mut [T] 158 | { 159 | fn read(&mut self, f: F) 160 | where F: FnOnce(size_t, *mut c_void, size_t) 161 | { 162 | let p = (*self).as_mut_ptr(); 163 | let len = self.len(); 164 | f(0, p as *mut c_void, (len * mem::size_of::()) as size_t) 165 | } 166 | } 167 | 168 | macro_rules! get_arg ( 169 | ($t:ty) => (impl Get, $t> for $t 170 | { 171 | fn get(_: &CLBuffer<$t>, f: F) -> $t 172 | where F: FnOnce(size_t, *mut c_void, size_t) 173 | { 174 | let mut v: $t = 0 as $t; 175 | f(0, (&mut v as *mut $t) as *mut c_void, mem::size_of::<$t>() as size_t); 176 | v as $t 177 | } 178 | }) 179 | ); 180 | 181 | get_arg!(isize); 182 | get_arg!(usize); 183 | get_arg!(u32); 184 | get_arg!(u64); 185 | get_arg!(i32); 186 | get_arg!(i64); 187 | get_arg!(f32); 188 | get_arg!(f64); 189 | 190 | macro_rules! put_arg ( 191 | ($t:ty) => (impl Put<$t, CLBuffer<$t>> for $t 192 | { 193 | fn put(&self, f: F) -> CLBuffer<$t> 194 | where F: FnOnce(*const c_void, size_t) -> cl_mem 195 | { 196 | CLBuffer { 197 | cl_buffer: f((self as *const $t) as *const c_void, mem::size_of::<$t>() as size_t), 198 | phantom: PhantomData, 199 | } 200 | } 201 | } 202 | ) 203 | ); 204 | 205 | put_arg!(isize); 206 | put_arg!(usize); 207 | put_arg!(u32); 208 | put_arg!(u64); 209 | put_arg!(i32); 210 | put_arg!(i64); 211 | put_arg!(f32); 212 | put_arg!(f64); 213 | 214 | macro_rules! read_arg ( 215 | ($t:ty) => (impl Read for $t 216 | { 217 | fn read(&mut self, f: F) 218 | where F: FnOnce(size_t, *mut c_void, size_t) 219 | { 220 | f(0, (self as *mut $t) as *mut c_void, mem::size_of::<$t>() as size_t) 221 | } 222 | } 223 | ) 224 | ); 225 | 226 | read_arg!(isize); 227 | read_arg!(usize); 228 | read_arg!(u32); 229 | read_arg!(u64); 230 | read_arg!(i32); 231 | read_arg!(i64); 232 | read_arg!(f32); 233 | read_arg!(f64); 234 | 235 | macro_rules! write_arg ( 236 | ($t:ty) => (impl Write for $t 237 | { 238 | fn write(&self, f: F) 239 | where F: FnOnce(size_t, *const c_void, size_t) 240 | { 241 | f(0, (self as *const $t) as *const c_void, mem::size_of::<$t>() as size_t) 242 | } 243 | } 244 | ) 245 | ); 246 | 247 | write_arg!(isize); 248 | write_arg!(usize); 249 | write_arg!(u32); 250 | write_arg!(u64); 251 | write_arg!(i32); 252 | write_arg!(i64); 253 | write_arg!(f32); 254 | write_arg!(f64); 255 | -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | //! Utility functions 2 | 3 | use hl::*; 4 | 5 | pub fn create_compute_context() -> Result<(Device, Context, CommandQueue), &'static str> 6 | { 7 | let platforms = get_platforms(); 8 | if platforms.len() == 0 { 9 | return Err("No platform found"); 10 | } 11 | 12 | let mut devices = platforms[0].get_devices(); 13 | if devices.len() == 0 { 14 | Err("No device found") 15 | } else { 16 | let device = devices.remove(0); 17 | let context = device.create_context(); 18 | let queue = context.create_command_queue(&device); 19 | Ok((device, context, queue)) 20 | } 21 | } 22 | 23 | #[derive(Copy, Clone)] 24 | pub enum PreferedType { 25 | Any, 26 | 27 | CPUPrefered, 28 | GPUPrefered, 29 | 30 | CPUOnly, 31 | GPUOnly, 32 | } 33 | 34 | pub fn create_compute_context_prefer(cltype: PreferedType) -> Result<(Device, Context, CommandQueue), &'static str> 35 | { 36 | let platforms = get_platforms(); 37 | for platform in platforms.iter() { 38 | let types = match cltype { 39 | PreferedType::Any => vec![DeviceType::CPU, DeviceType::GPU], 40 | PreferedType::CPUPrefered | PreferedType::CPUOnly => vec![DeviceType::CPU], 41 | PreferedType::GPUPrefered | PreferedType::GPUOnly => vec![DeviceType::GPU] 42 | }; 43 | 44 | let mut devices = platform.get_devices_by_types(&types[..]); 45 | if devices.len() > 0 { 46 | let device = devices.remove(0); 47 | let context = device.create_context(); 48 | let queue = context.create_command_queue(&device); 49 | return Ok((device, context, queue)) 50 | } 51 | } 52 | 53 | 54 | match cltype { 55 | PreferedType::Any | 56 | PreferedType::CPUPrefered | 57 | PreferedType::GPUPrefered => create_compute_context(), 58 | _ => Err("Could not find valid implementation") 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /tests/test.rs: -------------------------------------------------------------------------------- 1 | #![feature(slice_bytes)] 2 | 3 | #[macro_use] 4 | extern crate log; 5 | 6 | extern crate opencl; 7 | 8 | use opencl::hl::*; 9 | 10 | macro_rules! expect ( 11 | ($test: expr, $expected: expr) => ({ 12 | let test = $test; 13 | let expected = $expected; 14 | if test != expected { 15 | panic!(format!("Test failure in {}:", // " expected {}, got {}", 16 | stringify!($test)/*, 17 | expected, test*/)) 18 | } 19 | } 20 | ) 21 | ); 22 | 23 | pub fn test_all_platforms_devices(test: &mut F) 24 | where F: FnMut(&Device, &Context, &CommandQueue) 25 | { 26 | let platforms = get_platforms(); 27 | for p in platforms.iter() { 28 | let devices = p.get_devices(); 29 | for d in devices.iter() { 30 | let context = d.create_context(); 31 | let queue = context.create_command_queue(d); 32 | test(d, &context, &queue); 33 | } 34 | } 35 | } 36 | 37 | mod mem { 38 | use std::slice; 39 | use opencl::mem::{Read, Write}; 40 | 41 | fn read_write(src: &W, dst: &mut R) 42 | { 43 | // find the max size of the input buffer 44 | let mut max = 0; 45 | src.write(|off, _, len| { 46 | if max < off + len { 47 | max = off + len; 48 | } 49 | }); 50 | let max = max as usize; 51 | 52 | let mut buffer: Vec = Vec::new(); 53 | unsafe { 54 | buffer.reserve(max); 55 | buffer.set_len(max); 56 | } 57 | 58 | // copy from input into buffer 59 | src.write(|off, ptr, len| { 60 | let off = off as usize; 61 | let len = len as usize; 62 | assert!(buffer.len() >= (off + len) as usize); 63 | let target = &mut buffer[off .. off + len]; 64 | unsafe { 65 | let ptr = ptr as *const u8; 66 | let src = slice::from_raw_parts(ptr, len); 67 | slice::bytes::copy_memory(src, target); 68 | } 69 | }); 70 | 71 | // copy from buffer into output 72 | dst.read(|off, ptr, len| { 73 | let off = off as usize; 74 | let len = len as usize; 75 | assert!(buffer.len() >= (off + len) as usize); 76 | let src = &buffer[off .. off + len]; 77 | unsafe { 78 | let ptr = ptr as *mut u8; 79 | let mut dst = slice::from_raw_parts_mut(ptr, len); 80 | slice::bytes::copy_memory(src, dst); 81 | } 82 | }) 83 | } 84 | 85 | #[test] 86 | fn read_write_slice() 87 | { 88 | let input: &[isize] = &[0, 1, 2, 3, 4, 5, 6, 7]; 89 | let mut output: &mut [isize] = &mut [0, 0, 0, 0, 0, 0, 0, 0]; 90 | read_write(&input, &mut output); 91 | expect!(input, output); 92 | } 93 | 94 | #[test] 95 | fn read_write_int() 96 | { 97 | let input: isize = 3141; 98 | let mut output: isize = 0; 99 | read_write(&input, &mut output); 100 | expect!(input, output); 101 | } 102 | 103 | #[test] 104 | fn read_write_uint() 105 | { 106 | let input : usize = 3141; 107 | let mut output : usize = 0; 108 | read_write(&input, &mut output); 109 | expect!(input, output); 110 | } 111 | 112 | #[test] 113 | fn read_write_f32() 114 | { 115 | let input : f32 = 3141.; 116 | let mut output : f32 = 0.; 117 | read_write(&input, &mut output); 118 | expect!(input, output); 119 | } 120 | 121 | #[test] 122 | fn read_write_f64() 123 | { 124 | let input : f64 = 3141.; 125 | let mut output : f64 = 0.; 126 | read_write(&input, &mut output); 127 | expect!(input, output); 128 | } 129 | } 130 | 131 | #[cfg(test)] 132 | mod hl { 133 | use opencl::cl::*; 134 | use opencl::hl::*; 135 | use opencl::mem::*; 136 | use opencl::util; 137 | 138 | #[test] 139 | fn program_build() { 140 | let src = "__kernel void test(__global int *i) { \ 141 | *i += 1; \ 142 | }"; 143 | ::test_all_platforms_devices(&mut |device, ctx, _| { 144 | let prog = ctx.create_program_from_source(src); 145 | prog.build(device).unwrap(); 146 | }) 147 | } 148 | 149 | #[test] 150 | fn simple_kernel() { 151 | let src = "__kernel void test(__global int *i) { \ 152 | *i += 1; \ 153 | }"; 154 | ::test_all_platforms_devices(&mut |device, ctx, queue| { 155 | let prog = ctx.create_program_from_source(src); 156 | prog.build(device).unwrap(); 157 | 158 | let k = prog.create_kernel("test"); 159 | let v = ctx.create_buffer_from(vec![1isize], CL_MEM_READ_WRITE); 160 | 161 | k.set_arg(0, &v); 162 | 163 | queue.enqueue_async_kernel(&k, 1isize, None, ()).wait(); 164 | 165 | let v: Vec = queue.get(&v, ()); 166 | 167 | expect!(v[0], 2); 168 | }) 169 | } 170 | 171 | #[test] 172 | fn add_k() { 173 | let src = "__kernel void test(__global int *i, long int k) { \ 174 | *i += k; \ 175 | }"; 176 | 177 | ::test_all_platforms_devices(&mut |device, ctx, queue| { 178 | let prog = ctx.create_program_from_source(src); 179 | prog.build(device).unwrap(); 180 | 181 | let k = prog.create_kernel("test"); 182 | 183 | let v = ctx.create_buffer_from(vec![1isize], CL_MEM_READ_WRITE); 184 | 185 | k.set_arg(0, &v); 186 | k.set_arg(1, &42isize); 187 | 188 | queue.enqueue_async_kernel(&k, 1isize, None, ()).wait(); 189 | 190 | let v: Vec = queue.get(&v, ()); 191 | 192 | expect!(v[0], 43); 193 | }) 194 | } 195 | 196 | #[test] 197 | fn simple_kernel_index() { 198 | let src = "__kernel void test(__global int *i) { \ 199 | *i += 1; \ 200 | }"; 201 | 202 | ::test_all_platforms_devices(&mut |device, ctx, queue| { 203 | let prog = ctx.create_program_from_source(src); 204 | prog.build(device).unwrap(); 205 | 206 | let k = prog.create_kernel("test"); 207 | 208 | let v = ctx.create_buffer_from(vec![1isize], CL_MEM_READ_WRITE); 209 | 210 | k.set_arg(0, &v); 211 | 212 | queue.enqueue_async_kernel(&k, 1isize, None, ()).wait(); 213 | 214 | let v: Vec = queue.get(&v, ()); 215 | 216 | expect!(v[0], 2); 217 | }) 218 | } 219 | 220 | #[test] 221 | fn chain_kernel_event() { 222 | let src = "__kernel void test(__global int *i) { \ 223 | *i += 1; \ 224 | }"; 225 | 226 | ::test_all_platforms_devices(&mut |device, ctx, queue| { 227 | let prog = ctx.create_program_from_source(src); 228 | prog.build(device).unwrap(); 229 | 230 | let k = prog.create_kernel("test"); 231 | let v = ctx.create_buffer_from(vec![1isize], CL_MEM_READ_WRITE); 232 | 233 | k.set_arg(0, &v); 234 | 235 | let mut e : Option = None; 236 | for _ in 0isize .. 8 { 237 | e = Some(queue.enqueue_async_kernel(&k, 1isize, None, e)); 238 | } 239 | e.wait(); 240 | 241 | let v: Vec = queue.get(&v, ()); 242 | 243 | expect!(v[0], 9); 244 | }) 245 | } 246 | 247 | #[test] 248 | fn chain_kernel_event_list() { 249 | let src = "__kernel void inc(__global int *i) { \ 250 | *i += 1; \ 251 | } \ 252 | __kernel void add(__global int *a, __global int *b, __global int *c) { \ 253 | *c = *a + *b; \ 254 | }"; 255 | 256 | ::test_all_platforms_devices(&mut |device, ctx, queue| { 257 | let prog = ctx.create_program_from_source(src); 258 | prog.build(device).unwrap(); 259 | 260 | let k_inc_a = prog.create_kernel("inc"); 261 | let k_inc_b = prog.create_kernel("inc"); 262 | let k_add = prog.create_kernel("add"); 263 | 264 | let a = ctx.create_buffer_from(vec![1isize], CL_MEM_READ_WRITE); 265 | let b = ctx.create_buffer_from(vec![1isize], CL_MEM_READ_WRITE); 266 | let c = ctx.create_buffer_from(vec![1isize], CL_MEM_READ_WRITE); 267 | 268 | k_inc_a.set_arg(0, &a); 269 | k_inc_b.set_arg(0, &b); 270 | 271 | let event_list = [ 272 | queue.enqueue_async_kernel(&k_inc_a, 1isize, None, ()), 273 | queue.enqueue_async_kernel(&k_inc_b, 1isize, None, ()), 274 | ]; 275 | 276 | k_add.set_arg(0, &a); 277 | k_add.set_arg(1, &b); 278 | k_add.set_arg(2, &c); 279 | 280 | let event = queue.enqueue_async_kernel(&k_add, 1isize, None, &event_list[..]); 281 | 282 | let v: Vec = queue.get(&c, event); 283 | 284 | expect!(v[0], 4); 285 | }) 286 | } 287 | 288 | #[test] 289 | fn kernel_2d() 290 | { 291 | let src = "__kernel void test(__global long int *N) { \ 292 | int i = get_global_id(0); \ 293 | int j = get_global_id(1); \ 294 | int s = get_global_size(0); \ 295 | N[i * s + j] = i * j; 296 | }"; 297 | ::test_all_platforms_devices(&mut |device, ctx, queue| { 298 | let prog = ctx.create_program_from_source(src); 299 | 300 | match prog.build(device) { 301 | Ok(_) => (), 302 | Err(build_log) => { 303 | println!("Error building program:\n"); 304 | println!("{}", build_log); 305 | panic!(""); 306 | } 307 | } 308 | 309 | let k = prog.create_kernel("test"); 310 | 311 | let v = ctx.create_buffer_from(&[1isize, 2, 3, 4, 5, 6, 7, 8, 9][..], CL_MEM_READ_ONLY); 312 | 313 | k.set_arg(0, &v); 314 | 315 | queue.enqueue_async_kernel(&k, (3isize, 3isize), None, ()).wait(); 316 | 317 | let v: Vec = queue.get(&v, ()); 318 | 319 | expect!(v, vec!(0, 0, 0, 0, 1, 2, 0, 2, 4)); 320 | }) 321 | } 322 | 323 | #[test] 324 | fn memory_read_write() 325 | { 326 | ::test_all_platforms_devices(&mut |_, ctx, queue| { 327 | let buffer: CLBuffer = ctx.create_buffer(8, CL_MEM_READ_ONLY); 328 | 329 | let input = [0isize, 1, 2, 3, 4, 5, 6, 7]; 330 | let mut output = [0isize, 0, 0, 0, 0, 0, 0, 0]; 331 | 332 | queue.write(&buffer, &&input[..], ()); 333 | queue.read(&buffer, &mut &mut output[..], ()); 334 | 335 | expect!(input, output); 336 | }) 337 | } 338 | 339 | #[test] 340 | fn memory_read_vec() 341 | { 342 | ::test_all_platforms_devices(&mut |_, ctx, queue| { 343 | let input = [0isize, 1, 2, 3, 4, 5, 6, 7]; 344 | let buffer = ctx.create_buffer_from(&input[..], CL_MEM_READ_WRITE); 345 | let output: Vec = queue.get(&buffer, ()); 346 | expect!(&input[..], &output[..]); 347 | }) 348 | } 349 | 350 | 351 | #[test] 352 | fn memory_read_owned() 353 | { 354 | ::test_all_platforms_devices(&mut |_, ctx, queue| { 355 | let input = vec!(0isize, 1, 2, 3, 4, 5, 6, 7); 356 | let buffer = ctx.create_buffer_from(&input, CL_MEM_READ_WRITE); 357 | let output: Vec = queue.get(&buffer, ()); 358 | expect!(input, output); 359 | }) 360 | } 361 | 362 | #[test] 363 | fn memory_read_owned_clone() 364 | { 365 | ::test_all_platforms_devices(&mut |_, ctx, queue| { 366 | let input = vec!(0isize, 1, 2, 3, 4, 5, 6, 7); 367 | let buffer = ctx.create_buffer_from(input.clone(), CL_MEM_READ_WRITE); 368 | let output: Vec = queue.get(&buffer, ()); 369 | expect!(input, output); 370 | }) 371 | } 372 | 373 | #[test] 374 | fn event_get_times() { 375 | let src = "__kernel void test(__global int *i) { \ 376 | *i += 1; \ 377 | }"; 378 | 379 | let (device, ctx, queue) = util::create_compute_context().unwrap(); 380 | let prog = ctx.create_program_from_source(src); 381 | prog.build(&device).unwrap(); 382 | 383 | let k = prog.create_kernel("test"); 384 | let v = ctx.create_buffer_from(vec![1isize], CL_MEM_READ_WRITE); 385 | 386 | k.set_arg(0, &v); 387 | 388 | let e = queue.enqueue_async_kernel(&k, 1isize, None, ()); 389 | e.wait(); 390 | 391 | // the that are returned are not useful for unit test, this test 392 | // is mostly testing that opencl returns no error 393 | e.queue_time(); 394 | e.submit_time(); 395 | e.start_time(); 396 | e.end_time(); 397 | } 398 | } 399 | 400 | 401 | #[cfg(test)] 402 | mod array { 403 | use opencl::array::*; 404 | use opencl::cl::CL_MEM_READ_WRITE; 405 | 406 | #[test] 407 | fn put_get_2d() 408 | { 409 | ::test_all_platforms_devices(&mut |_, ctx, queue| { 410 | let arr_in = Array2D::new(8, 8, |x, y| {(x+y) as isize}); 411 | let arr_cl = ctx.create_buffer_from(&arr_in, CL_MEM_READ_WRITE); 412 | let arr_out: Array2D = queue.get(&arr_cl, ()); 413 | 414 | for x in 0usize.. 8usize { 415 | for y in 0usize..8usize { 416 | expect!(arr_in.get(x, y), arr_out.get(x, y)); 417 | } 418 | } 419 | }) 420 | } 421 | 422 | 423 | #[test] 424 | fn read_write_2d() 425 | { 426 | ::test_all_platforms_devices(&mut |_, ctx, queue| { 427 | let added = Array2D::new(8, 8, |x, y| {(x+y) as isize}); 428 | let zero = Array2D::new(8, 8, |_, _| {(0) as isize}); 429 | let mut out = Array2D::new(8, 8, |_, _| {(0) as isize}); 430 | 431 | /* both are zeroed */ 432 | let a_cl = ctx.create_buffer_from(&zero, CL_MEM_READ_WRITE); 433 | 434 | queue.write(&a_cl, &added, ()); 435 | queue.read(&a_cl, &mut out, ()); 436 | 437 | for x in 0usize .. 8usize { 438 | for y in 0usize .. 8usize { 439 | expect!(added.get(x, y), out.get(x, y)); 440 | } 441 | } 442 | }) 443 | } 444 | 445 | 446 | #[test] 447 | fn kernel_2d() 448 | { 449 | ::test_all_platforms_devices(&mut |device, ctx, queue| { 450 | let mut a = Array2D::new(8, 8, |_, _| {(0) as i32}); 451 | let b = Array2D::new(8, 8, |x, y| {(x*y) as i32}); 452 | let a_cl = ctx.create_buffer_from(&a, CL_MEM_READ_WRITE); 453 | 454 | let src = "__kernel void test(__global int *a) { \ 455 | int x = get_global_id(0); \ 456 | int y = get_global_id(1); \ 457 | int size_x = get_global_size(0); \ 458 | a[size_x*y + x] = x*y; \ 459 | }"; 460 | let prog = ctx.create_program_from_source(src); 461 | match prog.build(device) { 462 | Ok(_) => (), 463 | Err(build_log) => { 464 | println!("Error building program:\n"); 465 | println!("{}", build_log); 466 | panic!(""); 467 | } 468 | } 469 | let k = prog.create_kernel("test"); 470 | 471 | k.set_arg(0, &a_cl); 472 | let event = queue.enqueue_async_kernel(&k, (8isize, 8isize), None, ()); 473 | queue.read(&a_cl, &mut a, &event); 474 | 475 | for x in 0usize .. 8usize { 476 | for y in 0usize .. 8usize { 477 | expect!(a.get(x, y), b.get(x, y)); 478 | } 479 | } 480 | }) 481 | } 482 | 483 | #[test] 484 | fn put_get_3d() 485 | { 486 | ::test_all_platforms_devices(&mut |_, ctx, queue| { 487 | let arr_in = Array3D::new(8, 8, 8, |x, y, z| {(x+y+z) as isize}); 488 | let arr_cl = ctx.create_buffer_from(&arr_in, CL_MEM_READ_WRITE); 489 | let arr_out: Array3D = queue.get(&arr_cl, ()); 490 | 491 | for x in 0usize .. 8usize { 492 | for y in 0usize .. 8usize { 493 | for z in 0usize .. 8usize { 494 | expect!(arr_in.get(x, y, z), arr_out.get(x, y, z)); 495 | } 496 | } 497 | } 498 | }) 499 | } 500 | 501 | 502 | #[test] 503 | fn read_write_3d() 504 | { 505 | ::test_all_platforms_devices(&mut |_, ctx, queue| { 506 | let added = Array3D::new(8, 8, 8, |x, y, z| {(x+y+z) as isize}); 507 | let zero = Array3D::new(8, 8, 8, |_, _, _| {(0) as isize}); 508 | let mut out = Array3D::new(8, 8, 8, |_, _, _| {(0) as isize}); 509 | 510 | /* both are zeroed */ 511 | let a_cl = ctx.create_buffer_from(&zero, CL_MEM_READ_WRITE); 512 | 513 | queue.write(&a_cl, &added, ()); 514 | queue.read(&a_cl, &mut out, ()); 515 | 516 | for x in 0usize .. 8usize { 517 | for y in 0usize .. 8usize { 518 | for z in 0usize .. 8usize { 519 | expect!(added.get(x, y, z), out.get(x, y, z)); 520 | } 521 | } 522 | } 523 | }) 524 | } 525 | 526 | 527 | #[test] 528 | fn kernel_3d() 529 | { 530 | ::test_all_platforms_devices(&mut |device, ctx, queue| { 531 | let mut a = Array3D::new(8, 8, 8, |_, _, _| {(0) as i32}); 532 | let b = Array3D::new(8, 8, 8, |x, y, z| {(x*y*z) as i32}); 533 | let a_cl = ctx.create_buffer_from(&a, CL_MEM_READ_WRITE); 534 | 535 | let src = "__kernel void test(__global int *a) { \ 536 | int x = get_global_id(0); \ 537 | int y = get_global_id(1); \ 538 | int z = get_global_id(2); \ 539 | int size_x = get_global_size(0); \ 540 | int size_y = get_global_size(1); \ 541 | a[size_x*size_y*z + size_x*y + x] = x*y*z; \ 542 | }"; 543 | let prog = ctx.create_program_from_source(src); 544 | match prog.build(device) { 545 | Ok(_) => (), 546 | Err(build_log) => { 547 | println!("Error building program:\n"); 548 | println!("{}", build_log); 549 | panic!(""); 550 | } 551 | } 552 | let k = prog.create_kernel("test"); 553 | 554 | k.set_arg(0, &a_cl); 555 | let event = queue.enqueue_async_kernel(&k, (8isize, 8isize, 8isize), None, ()); 556 | queue.read(&a_cl, &mut a, &event); 557 | 558 | for x in 0usize .. 8usize { 559 | for y in 0usize .. 8usize { 560 | for z in 0usize .. 8usize { 561 | expect!(a.get(x, y, z), b.get(x, y, z)); 562 | } 563 | } 564 | } 565 | }) 566 | } 567 | } 568 | 569 | #[cfg(test)] 570 | mod ext { 571 | use opencl::ext; 572 | use opencl::hl::*; 573 | 574 | #[test] 575 | fn try_load_all_extensions() { 576 | let platforms = get_platforms(); 577 | 578 | for platform in platforms.into_iter() { 579 | let platform_id = platform.get_id(); 580 | 581 | macro_rules! check_ext { 582 | ($ext:ident) => { 583 | match ext::$ext::load(platform_id) { 584 | Ok(_) => { 585 | info!("Extension {} loaded successfully.", 586 | stringify!($ext)) 587 | } 588 | Err(_) => { 589 | info!("Error loading extension {}.", 590 | stringify!($ext)) 591 | } 592 | } 593 | } 594 | } 595 | 596 | check_ext!(cl_khr_fp64); 597 | check_ext!(cl_khr_fp16); 598 | check_ext!(cl_APPLE_SetMemObjectDestructor); 599 | check_ext!(cl_APPLE_ContextLoggingFunctions); 600 | check_ext!(cl_khr_icd); 601 | check_ext!(cl_nv_device_attribute_query); 602 | check_ext!(cl_amd_device_attribute_query); 603 | check_ext!(cl_arm_printf); 604 | check_ext!(cl_ext_device_fission); 605 | check_ext!(cl_qcom_ext_host_ptr); 606 | check_ext!(cl_qcom_ion_host_ptr); 607 | } 608 | } 609 | } 610 | 611 | #[cfg(test)] 612 | mod cl { 613 | use opencl::cl::CLStatus::*; 614 | 615 | #[test] 616 | fn clstatus_str() { 617 | let x = CL_SUCCESS; 618 | expect!(format!("{}", x), "CL_SUCCESS"); 619 | 620 | let y = CL_DEVICE_NOT_FOUND; 621 | expect!(y.to_string(), "CL_DEVICE_NOT_FOUND"); 622 | } 623 | } 624 | --------------------------------------------------------------------------------