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