1 use crate::compiler::nir::NirShader;
2 use crate::pipe::context::*;
3 use crate::pipe::device::*;
4 use crate::pipe::resource::*;
5 use crate::util::disk_cache::*;
6
7 use mesa_rust_gen::*;
8 use mesa_rust_util::has_required_feature;
9 use mesa_rust_util::ptr::ThreadSafeCPtr;
10
11 use std::convert::TryInto;
12 use std::ffi::CStr;
13 use std::mem::size_of;
14 use std::os::raw::c_schar;
15 use std::os::raw::c_uchar;
16 use std::os::raw::c_void;
17 use std::ptr;
18 use std::sync::Arc;
19
20 #[derive(PartialEq)]
21 pub struct PipeScreen {
22 ldev: PipeLoaderDevice,
23 screen: ThreadSafeCPtr<pipe_screen>,
24 }
25
26 pub const UUID_SIZE: usize = PIPE_UUID_SIZE as usize;
27 const LUID_SIZE: usize = PIPE_LUID_SIZE as usize;
28
29 // until we have a better solution
30 pub trait ComputeParam<T> {
compute_param(&self, cap: pipe_compute_cap) -> T31 fn compute_param(&self, cap: pipe_compute_cap) -> T;
32 }
33
34 macro_rules! compute_param_impl {
35 ($ty:ty) => {
36 impl ComputeParam<$ty> for PipeScreen {
37 fn compute_param(&self, cap: pipe_compute_cap) -> $ty {
38 let size = self.compute_param_wrapped(cap, ptr::null_mut());
39 let mut d = [0; size_of::<$ty>()];
40 if size == 0 {
41 return Default::default();
42 }
43 assert_eq!(size as usize, d.len());
44 self.compute_param_wrapped(cap, d.as_mut_ptr().cast());
45 <$ty>::from_ne_bytes(d)
46 }
47 }
48 };
49 }
50
51 compute_param_impl!(u32);
52 compute_param_impl!(u64);
53
54 impl ComputeParam<Vec<u64>> for PipeScreen {
compute_param(&self, cap: pipe_compute_cap) -> Vec<u64>55 fn compute_param(&self, cap: pipe_compute_cap) -> Vec<u64> {
56 let size = self.compute_param_wrapped(cap, ptr::null_mut());
57 let elems = (size / 8) as usize;
58
59 let mut res: Vec<u64> = Vec::new();
60 let mut d: Vec<u8> = vec![0; size as usize];
61
62 self.compute_param_wrapped(cap, d.as_mut_ptr().cast());
63 for i in 0..elems {
64 let offset = i * 8;
65 let slice = &d[offset..offset + 8];
66 res.push(u64::from_ne_bytes(slice.try_into().expect("")));
67 }
68 res
69 }
70 }
71
72 #[derive(Clone, Copy, PartialEq, Eq)]
73 pub enum ResourceType {
74 Normal,
75 Staging,
76 }
77
78 impl ResourceType {
apply(&self, tmpl: &mut pipe_resource)79 fn apply(&self, tmpl: &mut pipe_resource) {
80 match self {
81 Self::Staging => {
82 tmpl.set_usage(pipe_resource_usage::PIPE_USAGE_STAGING);
83 tmpl.flags |= PIPE_RESOURCE_FLAG_MAP_PERSISTENT | PIPE_RESOURCE_FLAG_MAP_COHERENT;
84 tmpl.bind |= PIPE_BIND_LINEAR;
85 }
86 Self::Normal => {}
87 }
88 }
89 }
90
91 impl PipeScreen {
new(ldev: PipeLoaderDevice, screen: *mut pipe_screen) -> Option<Self>92 pub(super) fn new(ldev: PipeLoaderDevice, screen: *mut pipe_screen) -> Option<Self> {
93 if screen.is_null() || !has_required_cbs(screen) {
94 return None;
95 }
96
97 Some(Self {
98 ldev,
99 // SAFETY: `pipe_screen` is considered a thread-safe type
100 screen: unsafe { ThreadSafeCPtr::new(screen)? },
101 })
102 }
103
screen(&self) -> &pipe_screen104 fn screen(&self) -> &pipe_screen {
105 // SAFETY: We own the pointer, so it's valid for every caller of this function as we are
106 // responsible of freeing it.
107 unsafe { self.screen.as_ref() }
108 }
109
caps(&self) -> &pipe_caps110 pub fn caps(&self) -> &pipe_caps {
111 &self.screen().caps
112 }
113
create_context(self: &Arc<Self>) -> Option<PipeContext>114 pub fn create_context(self: &Arc<Self>) -> Option<PipeContext> {
115 PipeContext::new(
116 unsafe {
117 self.screen().context_create.unwrap()(
118 self.screen.as_ptr(),
119 ptr::null_mut(),
120 PIPE_CONTEXT_COMPUTE_ONLY | PIPE_CONTEXT_NO_LOD_BIAS,
121 )
122 },
123 self,
124 )
125 }
126
resource_create(&self, tmpl: &pipe_resource) -> Option<PipeResource>127 fn resource_create(&self, tmpl: &pipe_resource) -> Option<PipeResource> {
128 PipeResource::new(
129 unsafe { self.screen().resource_create.unwrap()(self.screen.as_ptr(), tmpl) },
130 false,
131 )
132 }
133
resource_create_from_user( &self, tmpl: &pipe_resource, mem: *mut c_void, ) -> Option<PipeResource>134 fn resource_create_from_user(
135 &self,
136 tmpl: &pipe_resource,
137 mem: *mut c_void,
138 ) -> Option<PipeResource> {
139 PipeResource::new(
140 unsafe { self.screen().resource_from_user_memory?(self.screen.as_ptr(), tmpl, mem) },
141 true,
142 )
143 }
144
resource_create_buffer( &self, size: u32, res_type: ResourceType, pipe_bind: u32, ) -> Option<PipeResource>145 pub fn resource_create_buffer(
146 &self,
147 size: u32,
148 res_type: ResourceType,
149 pipe_bind: u32,
150 ) -> Option<PipeResource> {
151 let mut tmpl = pipe_resource::default();
152
153 tmpl.set_target(pipe_texture_target::PIPE_BUFFER);
154 tmpl.width0 = size;
155 tmpl.height0 = 1;
156 tmpl.depth0 = 1;
157 tmpl.array_size = 1;
158 tmpl.bind = pipe_bind;
159
160 res_type.apply(&mut tmpl);
161
162 self.resource_create(&tmpl)
163 }
164
resource_create_buffer_from_user( &self, size: u32, mem: *mut c_void, pipe_bind: u32, ) -> Option<PipeResource>165 pub fn resource_create_buffer_from_user(
166 &self,
167 size: u32,
168 mem: *mut c_void,
169 pipe_bind: u32,
170 ) -> Option<PipeResource> {
171 let mut tmpl = pipe_resource::default();
172
173 tmpl.set_target(pipe_texture_target::PIPE_BUFFER);
174 tmpl.width0 = size;
175 tmpl.height0 = 1;
176 tmpl.depth0 = 1;
177 tmpl.array_size = 1;
178 tmpl.bind = pipe_bind;
179
180 self.resource_create_from_user(&tmpl, mem)
181 }
182
resource_create_texture( &self, width: u32, height: u16, depth: u16, array_size: u16, target: pipe_texture_target, format: pipe_format, res_type: ResourceType, support_image: bool, ) -> Option<PipeResource>183 pub fn resource_create_texture(
184 &self,
185 width: u32,
186 height: u16,
187 depth: u16,
188 array_size: u16,
189 target: pipe_texture_target,
190 format: pipe_format,
191 res_type: ResourceType,
192 support_image: bool,
193 ) -> Option<PipeResource> {
194 let mut tmpl = pipe_resource::default();
195
196 tmpl.set_target(target);
197 tmpl.set_format(format);
198 tmpl.width0 = width;
199 tmpl.height0 = height;
200 tmpl.depth0 = depth;
201 tmpl.array_size = array_size;
202 tmpl.bind = PIPE_BIND_SAMPLER_VIEW;
203
204 if support_image {
205 tmpl.bind |= PIPE_BIND_SHADER_IMAGE;
206 }
207
208 res_type.apply(&mut tmpl);
209
210 self.resource_create(&tmpl)
211 }
212
resource_create_texture_from_user( &self, width: u32, height: u16, depth: u16, array_size: u16, target: pipe_texture_target, format: pipe_format, mem: *mut c_void, support_image: bool, ) -> Option<PipeResource>213 pub fn resource_create_texture_from_user(
214 &self,
215 width: u32,
216 height: u16,
217 depth: u16,
218 array_size: u16,
219 target: pipe_texture_target,
220 format: pipe_format,
221 mem: *mut c_void,
222 support_image: bool,
223 ) -> Option<PipeResource> {
224 let mut tmpl = pipe_resource::default();
225
226 tmpl.set_target(target);
227 tmpl.set_format(format);
228 tmpl.width0 = width;
229 tmpl.height0 = height;
230 tmpl.depth0 = depth;
231 tmpl.array_size = array_size;
232 tmpl.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_LINEAR;
233
234 if support_image {
235 tmpl.bind |= PIPE_BIND_SHADER_IMAGE;
236 }
237
238 self.resource_create_from_user(&tmpl, mem)
239 }
240
resource_import_dmabuf( &self, handle: u32, modifier: u64, target: pipe_texture_target, format: pipe_format, stride: u32, width: u32, height: u16, depth: u16, array_size: u16, ) -> Option<PipeResource>241 pub fn resource_import_dmabuf(
242 &self,
243 handle: u32,
244 modifier: u64,
245 target: pipe_texture_target,
246 format: pipe_format,
247 stride: u32,
248 width: u32,
249 height: u16,
250 depth: u16,
251 array_size: u16,
252 ) -> Option<PipeResource> {
253 let mut tmpl = pipe_resource::default();
254 let mut handle = winsys_handle {
255 type_: WINSYS_HANDLE_TYPE_FD,
256 handle: handle,
257 modifier: modifier,
258 format: format as u64,
259 stride: stride,
260 ..Default::default()
261 };
262
263 tmpl.set_target(target);
264 tmpl.set_format(format);
265 tmpl.width0 = width;
266 tmpl.height0 = height;
267 tmpl.depth0 = depth;
268 tmpl.array_size = array_size;
269
270 unsafe {
271 PipeResource::new(
272 self.screen().resource_from_handle.unwrap()(
273 self.screen.as_ptr(),
274 &tmpl,
275 &mut handle,
276 0,
277 ),
278 false,
279 )
280 }
281 }
282
shader_param(&self, t: pipe_shader_type, cap: pipe_shader_cap) -> i32283 pub fn shader_param(&self, t: pipe_shader_type, cap: pipe_shader_cap) -> i32 {
284 unsafe { self.screen().get_shader_param.unwrap()(self.screen.as_ptr(), t, cap) }
285 }
286
compute_param_wrapped(&self, cap: pipe_compute_cap, ptr: *mut c_void) -> i32287 fn compute_param_wrapped(&self, cap: pipe_compute_cap, ptr: *mut c_void) -> i32 {
288 unsafe {
289 self.screen().get_compute_param.unwrap()(
290 self.screen.as_ptr(),
291 pipe_shader_ir::PIPE_SHADER_IR_NIR,
292 cap,
293 ptr,
294 )
295 }
296 }
297
driver_name(&self) -> &CStr298 pub fn driver_name(&self) -> &CStr {
299 self.ldev.driver_name()
300 }
301
name(&self) -> &CStr302 pub fn name(&self) -> &CStr {
303 unsafe { CStr::from_ptr(self.screen().get_name.unwrap()(self.screen.as_ptr())) }
304 }
305
device_node_mask(&self) -> Option<u32>306 pub fn device_node_mask(&self) -> Option<u32> {
307 unsafe { Some(self.screen().get_device_node_mask?(self.screen.as_ptr())) }
308 }
309
device_uuid(&self) -> Option<[c_uchar; UUID_SIZE]>310 pub fn device_uuid(&self) -> Option<[c_uchar; UUID_SIZE]> {
311 let mut uuid = [0; UUID_SIZE];
312 let ptr = uuid.as_mut_ptr();
313 unsafe {
314 self.screen().get_device_uuid?(self.screen.as_ptr(), ptr.cast());
315 }
316
317 Some(uuid)
318 }
319
device_luid(&self) -> Option<[c_uchar; LUID_SIZE]>320 pub fn device_luid(&self) -> Option<[c_uchar; LUID_SIZE]> {
321 let mut luid = [0; LUID_SIZE];
322 let ptr = luid.as_mut_ptr();
323 unsafe { self.screen().get_device_luid?(self.screen.as_ptr(), ptr.cast()) }
324
325 Some(luid)
326 }
327
device_vendor(&self) -> &CStr328 pub fn device_vendor(&self) -> &CStr {
329 unsafe {
330 CStr::from_ptr(self.screen().get_device_vendor.unwrap()(
331 self.screen.as_ptr(),
332 ))
333 }
334 }
335
device_type(&self) -> pipe_loader_device_type336 pub fn device_type(&self) -> pipe_loader_device_type {
337 self.ldev.device_type()
338 }
339
driver_uuid(&self) -> Option<[c_schar; UUID_SIZE]>340 pub fn driver_uuid(&self) -> Option<[c_schar; UUID_SIZE]> {
341 let mut uuid = [0; UUID_SIZE];
342 let ptr = uuid.as_mut_ptr();
343 unsafe {
344 self.screen().get_driver_uuid?(self.screen.as_ptr(), ptr.cast());
345 }
346
347 Some(uuid)
348 }
349
cl_cts_version(&self) -> &CStr350 pub fn cl_cts_version(&self) -> &CStr {
351 unsafe {
352 let ptr = self
353 .screen()
354 .get_cl_cts_version
355 .map_or(ptr::null(), |get_cl_cts_version| {
356 get_cl_cts_version(self.screen.as_ptr())
357 });
358 if ptr.is_null() {
359 // this string is good enough to pass the CTS
360 c"v0000-01-01-00"
361 } else {
362 CStr::from_ptr(ptr)
363 }
364 }
365 }
366
is_format_supported( &self, format: pipe_format, target: pipe_texture_target, bindings: u32, ) -> bool367 pub fn is_format_supported(
368 &self,
369 format: pipe_format,
370 target: pipe_texture_target,
371 bindings: u32,
372 ) -> bool {
373 unsafe {
374 self.screen().is_format_supported.unwrap()(
375 self.screen.as_ptr(),
376 format,
377 target,
378 0,
379 0,
380 bindings,
381 )
382 }
383 }
384
get_timestamp(&self) -> u64385 pub fn get_timestamp(&self) -> u64 {
386 unsafe {
387 self.screen()
388 .get_timestamp
389 .unwrap_or(u_default_get_timestamp)(self.screen.as_ptr())
390 }
391 }
392
is_res_handle_supported(&self) -> bool393 pub fn is_res_handle_supported(&self) -> bool {
394 self.screen().resource_from_handle.is_some() && self.screen().resource_get_handle.is_some()
395 }
396
nir_shader_compiler_options( &self, shader: pipe_shader_type, ) -> *const nir_shader_compiler_options397 pub fn nir_shader_compiler_options(
398 &self,
399 shader: pipe_shader_type,
400 ) -> *const nir_shader_compiler_options {
401 unsafe {
402 self.screen().get_compiler_options.unwrap()(
403 self.screen.as_ptr(),
404 pipe_shader_ir::PIPE_SHADER_IR_NIR,
405 shader,
406 )
407 .cast()
408 }
409 }
410
shader_cache(&self) -> Option<DiskCacheBorrowed>411 pub fn shader_cache(&self) -> Option<DiskCacheBorrowed> {
412 let ptr = unsafe { self.screen().get_disk_shader_cache?(self.screen.as_ptr()) };
413
414 DiskCacheBorrowed::from_ptr(ptr)
415 }
416
417 /// returns true if finalize_nir was called
finalize_nir(&self, nir: &NirShader) -> bool418 pub fn finalize_nir(&self, nir: &NirShader) -> bool {
419 if let Some(func) = self.screen().finalize_nir {
420 unsafe {
421 func(self.screen.as_ptr(), nir.get_nir().cast());
422 }
423 true
424 } else {
425 false
426 }
427 }
428
unref_fence(&self, mut fence: *mut pipe_fence_handle)429 pub(super) fn unref_fence(&self, mut fence: *mut pipe_fence_handle) {
430 unsafe {
431 self.screen().fence_reference.unwrap()(
432 self.screen.as_ptr(),
433 &mut fence,
434 ptr::null_mut(),
435 );
436 }
437 }
438
fence_finish(&self, fence: *mut pipe_fence_handle)439 pub(super) fn fence_finish(&self, fence: *mut pipe_fence_handle) {
440 unsafe {
441 self.screen().fence_finish.unwrap()(
442 self.screen.as_ptr(),
443 ptr::null_mut(),
444 fence,
445 OS_TIMEOUT_INFINITE as u64,
446 );
447 }
448 }
449
query_memory_info(&self) -> Option<pipe_memory_info>450 pub fn query_memory_info(&self) -> Option<pipe_memory_info> {
451 let mut info = pipe_memory_info::default();
452 unsafe {
453 self.screen().query_memory_info?(self.screen.as_ptr(), &mut info);
454 }
455 Some(info)
456 }
457 }
458
459 impl Drop for PipeScreen {
drop(&mut self)460 fn drop(&mut self) {
461 unsafe { self.screen().destroy.unwrap()(self.screen.as_ptr()) }
462 }
463 }
464
has_required_cbs(screen: *mut pipe_screen) -> bool465 fn has_required_cbs(screen: *mut pipe_screen) -> bool {
466 let screen = unsafe { *screen };
467 // Use '&' to evaluate all features and to not stop
468 // on first missing one to list all missing features.
469 has_required_feature!(screen, context_create)
470 & has_required_feature!(screen, destroy)
471 & has_required_feature!(screen, fence_finish)
472 & has_required_feature!(screen, fence_reference)
473 & has_required_feature!(screen, get_compiler_options)
474 & has_required_feature!(screen, get_compute_param)
475 & has_required_feature!(screen, get_name)
476 & has_required_feature!(screen, get_shader_param)
477 & has_required_feature!(screen, is_format_supported)
478 & has_required_feature!(screen, resource_create)
479 }
480