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
create_context(self: &Arc<Self>) -> Option<PipeContext>110 pub fn create_context(self: &Arc<Self>) -> Option<PipeContext> {
111 PipeContext::new(
112 unsafe {
113 self.screen().context_create.unwrap()(
114 self.screen.as_ptr(),
115 ptr::null_mut(),
116 PIPE_CONTEXT_COMPUTE_ONLY | PIPE_CONTEXT_NO_LOD_BIAS,
117 )
118 },
119 self,
120 )
121 }
122
resource_create(&self, tmpl: &pipe_resource) -> Option<PipeResource>123 fn resource_create(&self, tmpl: &pipe_resource) -> Option<PipeResource> {
124 PipeResource::new(
125 unsafe { self.screen().resource_create.unwrap()(self.screen.as_ptr(), tmpl) },
126 false,
127 )
128 }
129
resource_create_from_user( &self, tmpl: &pipe_resource, mem: *mut c_void, ) -> Option<PipeResource>130 fn resource_create_from_user(
131 &self,
132 tmpl: &pipe_resource,
133 mem: *mut c_void,
134 ) -> Option<PipeResource> {
135 PipeResource::new(
136 unsafe { self.screen().resource_from_user_memory?(self.screen.as_ptr(), tmpl, mem) },
137 true,
138 )
139 }
140
resource_create_buffer( &self, size: u32, res_type: ResourceType, pipe_bind: u32, ) -> Option<PipeResource>141 pub fn resource_create_buffer(
142 &self,
143 size: u32,
144 res_type: ResourceType,
145 pipe_bind: u32,
146 ) -> Option<PipeResource> {
147 let mut tmpl = pipe_resource::default();
148
149 tmpl.set_target(pipe_texture_target::PIPE_BUFFER);
150 tmpl.width0 = size;
151 tmpl.height0 = 1;
152 tmpl.depth0 = 1;
153 tmpl.array_size = 1;
154 tmpl.bind = pipe_bind;
155
156 res_type.apply(&mut tmpl);
157
158 self.resource_create(&tmpl)
159 }
160
resource_create_buffer_from_user( &self, size: u32, mem: *mut c_void, pipe_bind: u32, ) -> Option<PipeResource>161 pub fn resource_create_buffer_from_user(
162 &self,
163 size: u32,
164 mem: *mut c_void,
165 pipe_bind: u32,
166 ) -> Option<PipeResource> {
167 let mut tmpl = pipe_resource::default();
168
169 tmpl.set_target(pipe_texture_target::PIPE_BUFFER);
170 tmpl.width0 = size;
171 tmpl.height0 = 1;
172 tmpl.depth0 = 1;
173 tmpl.array_size = 1;
174 tmpl.bind = pipe_bind;
175
176 self.resource_create_from_user(&tmpl, mem)
177 }
178
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>179 pub fn resource_create_texture(
180 &self,
181 width: u32,
182 height: u16,
183 depth: u16,
184 array_size: u16,
185 target: pipe_texture_target,
186 format: pipe_format,
187 res_type: ResourceType,
188 support_image: bool,
189 ) -> Option<PipeResource> {
190 let mut tmpl = pipe_resource::default();
191
192 tmpl.set_target(target);
193 tmpl.set_format(format);
194 tmpl.width0 = width;
195 tmpl.height0 = height;
196 tmpl.depth0 = depth;
197 tmpl.array_size = array_size;
198 tmpl.bind = PIPE_BIND_SAMPLER_VIEW;
199
200 if support_image {
201 tmpl.bind |= PIPE_BIND_SHADER_IMAGE;
202 }
203
204 res_type.apply(&mut tmpl);
205
206 self.resource_create(&tmpl)
207 }
208
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>209 pub fn resource_create_texture_from_user(
210 &self,
211 width: u32,
212 height: u16,
213 depth: u16,
214 array_size: u16,
215 target: pipe_texture_target,
216 format: pipe_format,
217 mem: *mut c_void,
218 support_image: bool,
219 ) -> Option<PipeResource> {
220 let mut tmpl = pipe_resource::default();
221
222 tmpl.set_target(target);
223 tmpl.set_format(format);
224 tmpl.width0 = width;
225 tmpl.height0 = height;
226 tmpl.depth0 = depth;
227 tmpl.array_size = array_size;
228 tmpl.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_LINEAR;
229
230 if support_image {
231 tmpl.bind |= PIPE_BIND_SHADER_IMAGE;
232 }
233
234 self.resource_create_from_user(&tmpl, mem)
235 }
236
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>237 pub fn resource_import_dmabuf(
238 &self,
239 handle: u32,
240 modifier: u64,
241 target: pipe_texture_target,
242 format: pipe_format,
243 stride: u32,
244 width: u32,
245 height: u16,
246 depth: u16,
247 array_size: u16,
248 ) -> Option<PipeResource> {
249 let mut tmpl = pipe_resource::default();
250 let mut handle = winsys_handle {
251 type_: WINSYS_HANDLE_TYPE_FD,
252 handle: handle,
253 modifier: modifier,
254 format: format as u64,
255 stride: stride,
256 ..Default::default()
257 };
258
259 tmpl.set_target(target);
260 tmpl.set_format(format);
261 tmpl.width0 = width;
262 tmpl.height0 = height;
263 tmpl.depth0 = depth;
264 tmpl.array_size = array_size;
265
266 unsafe {
267 PipeResource::new(
268 self.screen().resource_from_handle.unwrap()(
269 self.screen.as_ptr(),
270 &tmpl,
271 &mut handle,
272 0,
273 ),
274 false,
275 )
276 }
277 }
278
param(&self, cap: pipe_cap) -> i32279 pub fn param(&self, cap: pipe_cap) -> i32 {
280 unsafe { self.screen().get_param.unwrap()(self.screen.as_ptr(), cap) }
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) -> String298 pub fn driver_name(&self) -> String {
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 CStr::from_bytes_with_nul(b"v0000-01-01-00\0").unwrap()
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_param)
477 & has_required_feature!(screen, get_shader_param)
478 & has_required_feature!(screen, is_format_supported)
479 & has_required_feature!(screen, resource_create)
480 }
481