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, support_image: bool, ) -> 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 support_image: bool,
253 ) -> Option<PipeResource> {
254 let mut tmpl = pipe_resource::default();
255 let mut handle = winsys_handle {
256 type_: WINSYS_HANDLE_TYPE_FD,
257 handle: handle,
258 modifier: modifier,
259 format: format as u64,
260 stride: stride,
261 ..Default::default()
262 };
263
264 tmpl.set_target(target);
265 tmpl.set_format(format);
266 tmpl.width0 = width;
267 tmpl.height0 = height;
268 tmpl.depth0 = depth;
269 tmpl.array_size = array_size;
270
271 if target == pipe_texture_target::PIPE_BUFFER {
272 tmpl.bind = PIPE_BIND_GLOBAL
273 } else {
274 tmpl.bind = PIPE_BIND_SAMPLER_VIEW;
275 if support_image {
276 tmpl.bind |= PIPE_BIND_SHADER_IMAGE;
277 }
278 }
279
280 unsafe {
281 PipeResource::new(
282 self.screen().resource_from_handle.unwrap()(
283 self.screen.as_ptr(),
284 &tmpl,
285 &mut handle,
286 0,
287 ),
288 false,
289 )
290 }
291 }
292
shader_param(&self, t: pipe_shader_type, cap: pipe_shader_cap) -> i32293 pub fn shader_param(&self, t: pipe_shader_type, cap: pipe_shader_cap) -> i32 {
294 unsafe { self.screen().get_shader_param.unwrap()(self.screen.as_ptr(), t, cap) }
295 }
296
compute_param_wrapped(&self, cap: pipe_compute_cap, ptr: *mut c_void) -> i32297 fn compute_param_wrapped(&self, cap: pipe_compute_cap, ptr: *mut c_void) -> i32 {
298 unsafe {
299 self.screen().get_compute_param.unwrap()(
300 self.screen.as_ptr(),
301 pipe_shader_ir::PIPE_SHADER_IR_NIR,
302 cap,
303 ptr,
304 )
305 }
306 }
307
driver_name(&self) -> &CStr308 pub fn driver_name(&self) -> &CStr {
309 self.ldev.driver_name()
310 }
311
name(&self) -> &CStr312 pub fn name(&self) -> &CStr {
313 unsafe { CStr::from_ptr(self.screen().get_name.unwrap()(self.screen.as_ptr())) }
314 }
315
device_node_mask(&self) -> Option<u32>316 pub fn device_node_mask(&self) -> Option<u32> {
317 unsafe { Some(self.screen().get_device_node_mask?(self.screen.as_ptr())) }
318 }
319
device_uuid(&self) -> Option<[c_uchar; UUID_SIZE]>320 pub fn device_uuid(&self) -> Option<[c_uchar; UUID_SIZE]> {
321 let mut uuid = [0; UUID_SIZE];
322 let ptr = uuid.as_mut_ptr();
323 unsafe {
324 self.screen().get_device_uuid?(self.screen.as_ptr(), ptr.cast());
325 }
326
327 Some(uuid)
328 }
329
device_luid(&self) -> Option<[c_uchar; LUID_SIZE]>330 pub fn device_luid(&self) -> Option<[c_uchar; LUID_SIZE]> {
331 let mut luid = [0; LUID_SIZE];
332 let ptr = luid.as_mut_ptr();
333 unsafe { self.screen().get_device_luid?(self.screen.as_ptr(), ptr.cast()) }
334
335 Some(luid)
336 }
337
device_vendor(&self) -> &CStr338 pub fn device_vendor(&self) -> &CStr {
339 unsafe {
340 CStr::from_ptr(self.screen().get_device_vendor.unwrap()(
341 self.screen.as_ptr(),
342 ))
343 }
344 }
345
device_type(&self) -> pipe_loader_device_type346 pub fn device_type(&self) -> pipe_loader_device_type {
347 self.ldev.device_type()
348 }
349
driver_uuid(&self) -> Option<[c_schar; UUID_SIZE]>350 pub fn driver_uuid(&self) -> Option<[c_schar; UUID_SIZE]> {
351 let mut uuid = [0; UUID_SIZE];
352 let ptr = uuid.as_mut_ptr();
353 unsafe {
354 self.screen().get_driver_uuid?(self.screen.as_ptr(), ptr.cast());
355 }
356
357 Some(uuid)
358 }
359
cl_cts_version(&self) -> &CStr360 pub fn cl_cts_version(&self) -> &CStr {
361 unsafe {
362 let ptr = self
363 .screen()
364 .get_cl_cts_version
365 .map_or(ptr::null(), |get_cl_cts_version| {
366 get_cl_cts_version(self.screen.as_ptr())
367 });
368 if ptr.is_null() {
369 // this string is good enough to pass the CTS
370 c"v0000-01-01-00"
371 } else {
372 CStr::from_ptr(ptr)
373 }
374 }
375 }
376
is_format_supported( &self, format: pipe_format, target: pipe_texture_target, bindings: u32, ) -> bool377 pub fn is_format_supported(
378 &self,
379 format: pipe_format,
380 target: pipe_texture_target,
381 bindings: u32,
382 ) -> bool {
383 unsafe {
384 self.screen().is_format_supported.unwrap()(
385 self.screen.as_ptr(),
386 format,
387 target,
388 0,
389 0,
390 bindings,
391 )
392 }
393 }
394
get_timestamp(&self) -> u64395 pub fn get_timestamp(&self) -> u64 {
396 unsafe {
397 self.screen()
398 .get_timestamp
399 .unwrap_or(u_default_get_timestamp)(self.screen.as_ptr())
400 }
401 }
402
is_res_handle_supported(&self) -> bool403 pub fn is_res_handle_supported(&self) -> bool {
404 self.screen().resource_from_handle.is_some() && self.screen().resource_get_handle.is_some()
405 }
406
nir_shader_compiler_options( &self, shader: pipe_shader_type, ) -> *const nir_shader_compiler_options407 pub fn nir_shader_compiler_options(
408 &self,
409 shader: pipe_shader_type,
410 ) -> *const nir_shader_compiler_options {
411 unsafe {
412 self.screen().get_compiler_options.unwrap()(
413 self.screen.as_ptr(),
414 pipe_shader_ir::PIPE_SHADER_IR_NIR,
415 shader,
416 )
417 .cast()
418 }
419 }
420
shader_cache(&self) -> Option<DiskCacheBorrowed>421 pub fn shader_cache(&self) -> Option<DiskCacheBorrowed> {
422 let ptr = unsafe { self.screen().get_disk_shader_cache?(self.screen.as_ptr()) };
423
424 DiskCacheBorrowed::from_ptr(ptr)
425 }
426
427 /// returns true if finalize_nir was called
finalize_nir(&self, nir: &NirShader) -> bool428 pub fn finalize_nir(&self, nir: &NirShader) -> bool {
429 if let Some(func) = self.screen().finalize_nir {
430 unsafe {
431 func(self.screen.as_ptr(), nir.get_nir().cast());
432 }
433 true
434 } else {
435 false
436 }
437 }
438
unref_fence(&self, mut fence: *mut pipe_fence_handle)439 pub(super) fn unref_fence(&self, mut fence: *mut pipe_fence_handle) {
440 unsafe {
441 self.screen().fence_reference.unwrap()(
442 self.screen.as_ptr(),
443 &mut fence,
444 ptr::null_mut(),
445 );
446 }
447 }
448
fence_finish(&self, fence: *mut pipe_fence_handle)449 pub(super) fn fence_finish(&self, fence: *mut pipe_fence_handle) {
450 unsafe {
451 self.screen().fence_finish.unwrap()(
452 self.screen.as_ptr(),
453 ptr::null_mut(),
454 fence,
455 OS_TIMEOUT_INFINITE as u64,
456 );
457 }
458 }
459
query_memory_info(&self) -> Option<pipe_memory_info>460 pub fn query_memory_info(&self) -> Option<pipe_memory_info> {
461 let mut info = pipe_memory_info::default();
462 unsafe {
463 self.screen().query_memory_info?(self.screen.as_ptr(), &mut info);
464 }
465 Some(info)
466 }
467 }
468
469 impl Drop for PipeScreen {
drop(&mut self)470 fn drop(&mut self) {
471 unsafe { self.screen().destroy.unwrap()(self.screen.as_ptr()) }
472 }
473 }
474
has_required_cbs(screen: *mut pipe_screen) -> bool475 fn has_required_cbs(screen: *mut pipe_screen) -> bool {
476 let screen = unsafe { *screen };
477 // Use '&' to evaluate all features and to not stop
478 // on first missing one to list all missing features.
479 has_required_feature!(screen, context_create)
480 & has_required_feature!(screen, destroy)
481 & has_required_feature!(screen, fence_finish)
482 & has_required_feature!(screen, fence_reference)
483 & has_required_feature!(screen, get_compiler_options)
484 & has_required_feature!(screen, get_compute_param)
485 & has_required_feature!(screen, get_name)
486 & has_required_feature!(screen, get_shader_param)
487 & has_required_feature!(screen, is_format_supported)
488 & has_required_feature!(screen, resource_create)
489 }
490