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::ptr;
11 use std::ptr::addr_of;
12 use std::ptr::addr_of_mut;
13 use std::sync::Once;
14
15 /// Maximum size a pixel can be across all supported image formats.
16 pub const MAX_PIXEL_SIZE_BYTES: u64 = 4 * 4;
17
18 #[repr(C)]
19 pub struct Platform {
20 dispatch: &'static cl_icd_dispatch,
21 pub devs: Vec<Device>,
22 }
23
24 pub enum PerfDebugLevel {
25 None,
26 Once,
27 Spam,
28 }
29
30 pub struct PlatformDebug {
31 pub allow_invalid_spirv: bool,
32 pub clc: bool,
33 pub max_grid_size: u64,
34 pub nir: bool,
35 pub no_variants: bool,
36 pub perf: PerfDebugLevel,
37 pub program: bool,
38 pub reuse_context: bool,
39 pub sync_every_event: bool,
40 pub validate_spirv: bool,
41 }
42
43 pub struct PlatformFeatures {
44 pub fp16: bool,
45 pub fp64: bool,
46 }
47
48 static PLATFORM_ENV_ONCE: Once = Once::new();
49 static PLATFORM_ONCE: Once = Once::new();
50
51 macro_rules! gen_cl_exts {
52 (@COUNT $e:expr) => { 1 };
53 (@COUNT $e:expr, $($es:expr),+) => { 1 + gen_cl_exts!(@COUNT $($es),*) };
54
55 (@CONCAT $e:tt) => { $e };
56 (@CONCAT $e:tt, $($es:tt),+) => { concat!($e, ' ', gen_cl_exts!(@CONCAT $($es),*)) };
57
58 ([$(($major:expr, $minor:expr, $patch:expr, $ext:tt)$(,)?)+]) => {
59 pub static PLATFORM_EXTENSION_STR: &str = concat!(gen_cl_exts!(@CONCAT $($ext),*));
60 pub static PLATFORM_EXTENSIONS: [cl_name_version; gen_cl_exts!(@COUNT $($ext),*)] = [
61 $(mk_cl_version_ext($major, $minor, $patch, $ext)),+
62 ];
63 }
64 }
65 gen_cl_exts!([
66 (1, 0, 0, "cl_khr_byte_addressable_store"),
67 (1, 0, 0, "cl_khr_create_command_queue"),
68 (1, 0, 0, "cl_khr_expect_assume"),
69 (1, 0, 0, "cl_khr_extended_versioning"),
70 (1, 0, 0, "cl_khr_icd"),
71 (1, 0, 0, "cl_khr_il_program"),
72 (1, 0, 0, "cl_khr_spirv_no_integer_wrap_decoration"),
73 (1, 0, 0, "cl_khr_suggested_local_work_size"),
74 ]);
75
76 static mut PLATFORM: Platform = Platform {
77 dispatch: &DISPATCH,
78 devs: Vec::new(),
79 };
80 static mut PLATFORM_DBG: PlatformDebug = PlatformDebug {
81 allow_invalid_spirv: false,
82 clc: false,
83 max_grid_size: 0,
84 nir: false,
85 no_variants: false,
86 perf: PerfDebugLevel::None,
87 program: false,
88 reuse_context: true,
89 sync_every_event: false,
90 validate_spirv: false,
91 };
92 static mut PLATFORM_FEATURES: PlatformFeatures = PlatformFeatures {
93 fp16: false,
94 fp64: false,
95 };
96
load_env()97 fn load_env() {
98 // SAFETY: no other references exist at this point
99 let debug = unsafe { &mut *addr_of_mut!(PLATFORM_DBG) };
100 if let Ok(debug_flags) = env::var("RUSTICL_DEBUG") {
101 for flag in debug_flags.split(',') {
102 match flag {
103 "allow_invalid_spirv" => debug.allow_invalid_spirv = true,
104 "clc" => debug.clc = true,
105 "nir" => debug.nir = true,
106 "no_reuse_context" => debug.reuse_context = false,
107 "no_variants" => debug.no_variants = true,
108 "perf" => debug.perf = PerfDebugLevel::Once,
109 "perfspam" => debug.perf = PerfDebugLevel::Spam,
110 "program" => debug.program = true,
111 "sync" => debug.sync_every_event = true,
112 "validate" => debug.validate_spirv = true,
113 "" => (),
114 _ => eprintln!("Unknown RUSTICL_DEBUG flag found: {}", flag),
115 }
116 }
117 }
118
119 debug.max_grid_size = env::var("RUSTICL_MAX_WORK_GROUPS")
120 .ok()
121 .and_then(|s| s.parse().ok())
122 .unwrap_or(u64::MAX);
123
124 // SAFETY: no other references exist at this point
125 let features = unsafe { &mut *addr_of_mut!(PLATFORM_FEATURES) };
126 if let Ok(feature_flags) = env::var("RUSTICL_FEATURES") {
127 for flag in feature_flags.split(',') {
128 match flag {
129 "fp16" => features.fp16 = true,
130 "fp64" => features.fp64 = true,
131 "" => (),
132 _ => eprintln!("Unknown RUSTICL_FEATURES flag found: {}", flag),
133 }
134 }
135 }
136 }
137
138 impl Platform {
as_ptr(&self) -> cl_platform_id139 pub fn as_ptr(&self) -> cl_platform_id {
140 ptr::from_ref(self) as cl_platform_id
141 }
142
get() -> &'static Self143 pub fn get() -> &'static Self {
144 debug_assert!(PLATFORM_ONCE.is_completed());
145 // SAFETY: no mut references exist at this point
146 unsafe { &*addr_of!(PLATFORM) }
147 }
148
dbg() -> &'static PlatformDebug149 pub fn dbg() -> &'static PlatformDebug {
150 debug_assert!(PLATFORM_ENV_ONCE.is_completed());
151 unsafe { &*addr_of!(PLATFORM_DBG) }
152 }
153
features() -> &'static PlatformFeatures154 pub fn features() -> &'static PlatformFeatures {
155 debug_assert!(PLATFORM_ENV_ONCE.is_completed());
156 unsafe { &*addr_of!(PLATFORM_FEATURES) }
157 }
158
init(&mut self)159 fn init(&mut self) {
160 unsafe {
161 glsl_type_singleton_init_or_ref();
162 }
163
164 self.devs = Device::all().collect();
165 }
166
init_once()167 pub fn init_once() {
168 PLATFORM_ENV_ONCE.call_once(load_env);
169 // SAFETY: no concurrent static mut access due to std::Once
170 PLATFORM_ONCE.call_once(|| unsafe { PLATFORM.init() });
171 }
172 }
173
174 impl Drop for Platform {
drop(&mut self)175 fn drop(&mut self) {
176 unsafe {
177 glsl_type_singleton_decref();
178 }
179 }
180 }
181
182 pub trait GetPlatformRef {
get_ref(&self) -> CLResult<&'static Platform>183 fn get_ref(&self) -> CLResult<&'static Platform>;
184 }
185
186 impl GetPlatformRef for cl_platform_id {
get_ref(&self) -> CLResult<&'static Platform>187 fn get_ref(&self) -> CLResult<&'static Platform> {
188 if !self.is_null() && *self == Platform::get().as_ptr() {
189 Ok(Platform::get())
190 } else {
191 Err(CL_INVALID_PLATFORM)
192 }
193 }
194 }
195
196 #[macro_export]
197 macro_rules! perf_warning {
198 (@PRINT $format:tt, $($arg:tt)*) => {
199 eprintln!(std::concat!("=== Rusticl perf warning: ", $format, " ==="), $($arg)*)
200 };
201
202 ($format:tt $(, $arg:tt)*) => {
203 match $crate::core::platform::Platform::dbg().perf {
204 $crate::core::platform::PerfDebugLevel::Once => {
205 static PERF_WARN_ONCE: std::sync::Once = std::sync::Once::new();
206 PERF_WARN_ONCE.call_once(|| {
207 perf_warning!(@PRINT $format, $($arg)*);
208 })
209 },
210 $crate::core::platform::PerfDebugLevel::Spam => perf_warning!(@PRINT $format, $($arg)*),
211 _ => (),
212 }
213 };
214 }
215