oxihuman_export/
opencl_export.rs1#![allow(dead_code)]
4
5pub struct ClKernelArg {
9 pub type_name: String,
10 pub name: String,
11 pub is_global: bool,
12}
13
14pub struct ClKernel {
16 pub name: String,
17 pub args: Vec<ClKernelArg>,
18 pub body: String,
19}
20
21pub struct OpenClExport {
23 pub kernels: Vec<ClKernel>,
24 pub pragmas: Vec<String>,
25}
26
27pub fn new_opencl_export() -> OpenClExport {
29 OpenClExport {
30 kernels: Vec::new(),
31 pragmas: vec!["#pragma OPENCL EXTENSION cl_khr_fp64 : enable".to_string()],
32 }
33}
34
35pub fn add_cl_kernel(exp: &mut OpenClExport, name: &str, body: &str) {
37 exp.kernels.push(ClKernel {
38 name: name.to_string(),
39 args: Vec::new(),
40 body: body.to_string(),
41 });
42}
43
44pub fn add_cl_kernel_arg(
46 exp: &mut OpenClExport,
47 type_name: &str,
48 arg_name: &str,
49 is_global: bool,
50) -> bool {
51 if let Some(k) = exp.kernels.last_mut() {
52 k.args.push(ClKernelArg {
53 type_name: type_name.to_string(),
54 name: arg_name.to_string(),
55 is_global,
56 });
57 true
58 } else {
59 false
60 }
61}
62
63pub fn cl_kernel_count(exp: &OpenClExport) -> usize {
65 exp.kernels.len()
66}
67
68pub fn find_cl_kernel<'a>(exp: &'a OpenClExport, name: &str) -> Option<&'a ClKernel> {
70 exp.kernels.iter().find(|k| k.name == name)
71}
72
73pub fn render_opencl_source(exp: &OpenClExport) -> String {
75 let mut s = String::new();
76 for p in &exp.pragmas {
77 s.push_str(p);
78 s.push('\n');
79 }
80 for k in &exp.kernels {
81 let args: Vec<String> = k
82 .args
83 .iter()
84 .map(|a| {
85 if a.is_global {
86 format!("__global {} {}", a.type_name, a.name)
87 } else {
88 format!("{} {}", a.type_name, a.name)
89 }
90 })
91 .collect();
92 s.push_str(&format!(
93 "__kernel void {}({}) {{\n {}\n}}\n",
94 k.name,
95 args.join(", "),
96 k.body
97 ));
98 }
99 s
100}
101
102pub fn validate_opencl_export(exp: &OpenClExport) -> bool {
104 !exp.kernels.is_empty()
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn new_export_empty() {
113 let exp = new_opencl_export();
114 assert_eq!(cl_kernel_count(&exp), 0 );
115 }
116
117 #[test]
118 fn add_kernel_increments() {
119 let mut exp = new_opencl_export();
120 add_cl_kernel(&mut exp, "my_kernel", "int id = get_global_id(0);");
121 assert_eq!(cl_kernel_count(&exp), 1 );
122 }
123
124 #[test]
125 fn add_arg_to_kernel() {
126 let mut exp = new_opencl_export();
127 add_cl_kernel(&mut exp, "k", "");
128 let ok = add_cl_kernel_arg(&mut exp, "float*", "data", true);
129 assert!(ok );
130 assert_eq!(exp.kernels[0].args.len(), 1 );
131 }
132
133 #[test]
134 fn add_arg_no_kernel_fails() {
135 let mut exp = new_opencl_export();
136 assert!(!add_cl_kernel_arg(&mut exp, "int", "x", false) );
137 }
138
139 #[test]
140 fn find_kernel_by_name() {
141 let mut exp = new_opencl_export();
142 add_cl_kernel(&mut exp, "sum", "");
143 assert!(find_cl_kernel(&exp, "sum").is_some() );
144 }
145
146 #[test]
147 fn find_missing_none() {
148 let exp = new_opencl_export();
149 assert!(find_cl_kernel(&exp, "x").is_none() );
150 }
151
152 #[test]
153 fn render_contains_kernel_keyword() {
154 let mut exp = new_opencl_export();
155 add_cl_kernel(&mut exp, "k", "");
156 let src = render_opencl_source(&exp);
157 assert!(src.contains("__kernel") );
158 }
159
160 #[test]
161 fn render_contains_global_arg() {
162 let mut exp = new_opencl_export();
163 add_cl_kernel(&mut exp, "k", "");
164 add_cl_kernel_arg(&mut exp, "float*", "buf", true);
165 let src = render_opencl_source(&exp);
166 assert!(src.contains("__global") );
167 }
168
169 #[test]
170 fn validate_empty_fails() {
171 let exp = new_opencl_export();
172 assert!(!validate_opencl_export(&exp) );
173 }
174}