xref: /aosp_15_r20/external/mesa3d/src/gallium/frontends/rusticl/core/platform.rs (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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