• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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