1 use crate::api::icd::CLResult;
2 use crate::api::icd::DISPATCH;
3 use crate::core::device::*;
4 use crate::core::version::*;
5
6 use mesa_rust_gen::*;
7 use rusticl_opencl_gen::*;
8
9 use std::env;
10 use std::sync::Once;
11
12 #[repr(C)]
13 pub struct Platform {
14 dispatch: &'static cl_icd_dispatch,
15 pub devs: Vec<Device>,
16 }
17
18 pub struct PlatformDebug {
19 pub allow_invalid_spirv: bool,
20 pub clc: bool,
21 pub program: bool,
22 pub sync_every_event: bool,
23 pub validate_spirv: bool,
24 }
25
26 pub struct PlatformFeatures {
27 pub fp16: bool,
28 pub fp64: bool,
29 }
30
31 static PLATFORM_ENV_ONCE: Once = Once::new();
32 static PLATFORM_ONCE: Once = Once::new();
33
34 macro_rules! gen_cl_exts {
35 (@COUNT $e:expr) => { 1 };
36 (@COUNT $e:expr, $($es:expr),+) => { 1 + gen_cl_exts!(@COUNT $($es),*) };
37
38 (@CONCAT $e:tt) => { $e };
39 (@CONCAT $e:tt, $($es:tt),+) => { concat!($e, ' ', gen_cl_exts!(@CONCAT $($es),*)) };
40
41 ([$(($major:expr, $minor:expr, $patch:expr, $ext:tt)$(,)?)+]) => {
42 pub static PLATFORM_EXTENSION_STR: &str = concat!(gen_cl_exts!(@CONCAT $($ext),*));
43 pub static PLATFORM_EXTENSIONS: [cl_name_version; gen_cl_exts!(@COUNT $($ext),*)] = [
44 $(mk_cl_version_ext($major, $minor, $patch, $ext)),+
45 ];
46 }
47 }
48 gen_cl_exts!([
49 (1, 0, 0, "cl_khr_byte_addressable_store"),
50 (1, 0, 0, "cl_khr_create_command_queue"),
51 (1, 0, 0, "cl_khr_expect_assume"),
52 (1, 0, 0, "cl_khr_extended_versioning"),
53 (1, 0, 0, "cl_khr_icd"),
54 (1, 0, 0, "cl_khr_il_program"),
55 (1, 0, 0, "cl_khr_spirv_no_integer_wrap_decoration"),
56 ]);
57
58 static mut PLATFORM: Platform = Platform {
59 dispatch: &DISPATCH,
60 devs: Vec::new(),
61 };
62 static mut PLATFORM_DBG: PlatformDebug = PlatformDebug {
63 allow_invalid_spirv: false,
64 clc: false,
65 program: false,
66 sync_every_event: false,
67 validate_spirv: false,
68 };
69 static mut PLATFORM_FEATURES: PlatformFeatures = PlatformFeatures {
70 fp16: false,
71 fp64: false,
72 };
73
load_env()74 fn load_env() {
75 let debug = unsafe { &mut PLATFORM_DBG };
76 if let Ok(debug_flags) = env::var("RUSTICL_DEBUG") {
77 for flag in debug_flags.split(',') {
78 match flag {
79 "allow_invalid_spirv" => debug.allow_invalid_spirv = true,
80 "clc" => debug.clc = true,
81 "program" => debug.program = true,
82 "sync" => debug.sync_every_event = true,
83 "validate" => debug.validate_spirv = true,
84 "" => (),
85 _ => eprintln!("Unknown RUSTICL_DEBUG flag found: {}", flag),
86 }
87 }
88 }
89
90 let features = unsafe { &mut PLATFORM_FEATURES };
91 if let Ok(feature_flags) = env::var("RUSTICL_FEATURES") {
92 for flag in feature_flags.split(',') {
93 match flag {
94 "fp16" => features.fp16 = true,
95 "fp64" => features.fp64 = true,
96 "" => (),
97 _ => eprintln!("Unknown RUSTICL_FEATURES flag found: {}", flag),
98 }
99 }
100 }
101 }
102
103 impl Platform {
as_ptr(&self) -> cl_platform_id104 pub fn as_ptr(&self) -> cl_platform_id {
105 (self as *const Self) as cl_platform_id
106 }
107
get() -> &'static Self108 pub fn get() -> &'static Self {
109 debug_assert!(PLATFORM_ONCE.is_completed());
110 // SAFETY: no mut references exist at this point
111 unsafe { &PLATFORM }
112 }
113
dbg() -> &'static PlatformDebug114 pub fn dbg() -> &'static PlatformDebug {
115 debug_assert!(PLATFORM_ENV_ONCE.is_completed());
116 unsafe { &PLATFORM_DBG }
117 }
118
features() -> &'static PlatformFeatures119 pub fn features() -> &'static PlatformFeatures {
120 debug_assert!(PLATFORM_ENV_ONCE.is_completed());
121 unsafe { &PLATFORM_FEATURES }
122 }
123
init(&mut self)124 fn init(&mut self) {
125 unsafe {
126 glsl_type_singleton_init_or_ref();
127 }
128
129 self.devs = Device::all().collect();
130 }
131
init_once()132 pub fn init_once() {
133 PLATFORM_ENV_ONCE.call_once(load_env);
134 // SAFETY: no concurrent static mut access due to std::Once
135 PLATFORM_ONCE.call_once(|| unsafe { PLATFORM.init() });
136 }
137 }
138
139 impl Drop for Platform {
drop(&mut self)140 fn drop(&mut self) {
141 unsafe {
142 glsl_type_singleton_decref();
143 }
144 }
145 }
146
147 pub trait GetPlatformRef {
get_ref(&self) -> CLResult<&'static Platform>148 fn get_ref(&self) -> CLResult<&'static Platform>;
149 }
150
151 impl GetPlatformRef for cl_platform_id {
get_ref(&self) -> CLResult<&'static Platform>152 fn get_ref(&self) -> CLResult<&'static Platform> {
153 if !self.is_null() && *self == Platform::get().as_ptr() {
154 Ok(Platform::get())
155 } else {
156 Err(CL_INVALID_PLATFORM)
157 }
158 }
159 }
160