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