1 | use crate::{AsRaw, BufferObject, BufferObjectFlags, Format, Modifier, Ptr, Surface}; |
2 | |
3 | use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd}; |
4 | |
5 | use std::ffi::CStr; |
6 | use std::fmt; |
7 | use std::io::{Error as IoError, Result as IoResult}; |
8 | use std::ops::{Deref, DerefMut}; |
9 | |
10 | #[cfg (feature = "import-wayland" )] |
11 | use wayland_server::protocol::wl_buffer::WlBuffer; |
12 | |
13 | #[cfg (feature = "import-egl" )] |
14 | /// An EGLImage handle |
15 | pub type EGLImage = *mut libc::c_void; |
16 | |
17 | #[cfg (feature = "drm-support" )] |
18 | use drm::control::Device as DrmControlDevice; |
19 | #[cfg (feature = "drm-support" )] |
20 | use drm::Device as DrmDevice; |
21 | |
22 | /// An open GBM device |
23 | pub struct Device<T: AsFd> { |
24 | // Declare `ffi` first so it is dropped before `fd` |
25 | ffi: Ptr<ffi::gbm_device>, |
26 | fd: T, |
27 | } |
28 | |
29 | impl<T: AsFd> fmt::Debug for Device<T> { |
30 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
31 | f&mut DebugStruct<'_, '_>.debug_struct("Device" ) |
32 | .field(name:"ptr" , &format_args!(" {:p}" , &self.ffi)) |
33 | .finish() |
34 | } |
35 | } |
36 | |
37 | impl<T: AsFd + Clone> Clone for Device<T> { |
38 | fn clone(&self) -> Device<T> { |
39 | Device { |
40 | fd: self.fd.clone(), |
41 | ffi: self.ffi.clone(), |
42 | } |
43 | } |
44 | } |
45 | |
46 | impl<T: AsFd> AsFd for Device<T> { |
47 | fn as_fd(&self) -> BorrowedFd { |
48 | unsafe { BorrowedFd::borrow_raw(fd:ffi::gbm_device_get_fd(*self.ffi)) } |
49 | } |
50 | } |
51 | |
52 | impl<T: AsFd> AsRaw<ffi::gbm_device> for Device<T> { |
53 | fn as_raw(&self) -> *const ffi::gbm_device { |
54 | *self.ffi |
55 | } |
56 | } |
57 | |
58 | impl<T: AsFd> Deref for Device<T> { |
59 | type Target = T; |
60 | fn deref(&self) -> &T { |
61 | &self.fd |
62 | } |
63 | } |
64 | |
65 | impl<T: AsFd> DerefMut for Device<T> { |
66 | fn deref_mut(&mut self) -> &mut T { |
67 | &mut self.fd |
68 | } |
69 | } |
70 | |
71 | impl<T: AsFd> Device<T> { |
72 | /// Open a GBM device from a given open DRM device. |
73 | /// |
74 | /// The underlying file descriptor passed in is used by the backend to communicate with |
75 | /// platform for allocating the memory. For allocations using DRI this would be |
76 | /// the file descriptor returned when opening a device such as `/dev/dri/card0`. |
77 | pub fn new(fd: T) -> IoResult<Device<T>> { |
78 | let ptr = unsafe { ffi::gbm_create_device(fd.as_fd().as_raw_fd()) }; |
79 | if ptr.is_null() { |
80 | Err(IoError::last_os_error()) |
81 | } else { |
82 | Ok(Device { |
83 | fd, |
84 | ffi: Ptr::<ffi::gbm_device>::new(ptr, |ptr| unsafe { |
85 | ffi::gbm_device_destroy(ptr) |
86 | }), |
87 | }) |
88 | } |
89 | } |
90 | |
91 | /// Get the backend name |
92 | pub fn backend_name(&self) -> &str { |
93 | unsafe { |
94 | CStr::from_ptr(ffi::gbm_device_get_backend_name(*self.ffi)) |
95 | .to_str() |
96 | .expect("GBM passed invalid utf8 string" ) |
97 | } |
98 | } |
99 | |
100 | /// Test if a format is supported for a given set of usage flags |
101 | pub fn is_format_supported(&self, format: Format, usage: BufferObjectFlags) -> bool { |
102 | unsafe { ffi::gbm_device_is_format_supported(*self.ffi, format as u32, usage.bits()) != 0 } |
103 | } |
104 | |
105 | /// Get the required number of planes for a given format and modifier |
106 | /// |
107 | /// Some combination (e.g. when using a `Modifier::Invalid`) might not |
108 | /// have a defined/fixed number of planes. In these cases the function |
109 | /// might return `Option::None`. |
110 | pub fn format_modifier_plane_count(&self, format: Format, modifier: Modifier) -> Option<u32> { |
111 | unsafe { |
112 | ffi::gbm_device_get_format_modifier_plane_count( |
113 | *self.ffi, |
114 | format as u32, |
115 | modifier.into(), |
116 | ) |
117 | .try_into() |
118 | .ok() |
119 | } |
120 | } |
121 | |
122 | /// Allocate a new surface object |
123 | pub fn create_surface<U: 'static>( |
124 | &self, |
125 | width: u32, |
126 | height: u32, |
127 | format: Format, |
128 | usage: BufferObjectFlags, |
129 | ) -> IoResult<Surface<U>> { |
130 | let ptr = unsafe { |
131 | ffi::gbm_surface_create(*self.ffi, width, height, format as u32, usage.bits()) |
132 | }; |
133 | if ptr.is_null() { |
134 | Err(IoError::last_os_error()) |
135 | } else { |
136 | Ok(unsafe { Surface::new(ptr, self.ffi.clone()) }) |
137 | } |
138 | } |
139 | |
140 | /// Allocate a new surface object with explicit modifiers |
141 | pub fn create_surface_with_modifiers<U: 'static>( |
142 | &self, |
143 | width: u32, |
144 | height: u32, |
145 | format: Format, |
146 | modifiers: impl Iterator<Item = Modifier>, |
147 | ) -> IoResult<Surface<U>> { |
148 | let mods = modifiers.map(|m| m.into()).collect::<Vec<u64>>(); |
149 | let ptr = unsafe { |
150 | ffi::gbm_surface_create_with_modifiers( |
151 | *self.ffi, |
152 | width, |
153 | height, |
154 | format as u32, |
155 | mods.as_ptr(), |
156 | mods.len() as u32, |
157 | ) |
158 | }; |
159 | if ptr.is_null() { |
160 | Err(IoError::last_os_error()) |
161 | } else { |
162 | Ok(unsafe { Surface::new(ptr, self.ffi.clone()) }) |
163 | } |
164 | } |
165 | |
166 | /// Allocate a new surface object with explicit modifiers and flags |
167 | pub fn create_surface_with_modifiers2<U: 'static>( |
168 | &self, |
169 | width: u32, |
170 | height: u32, |
171 | format: Format, |
172 | modifiers: impl Iterator<Item = Modifier>, |
173 | usage: BufferObjectFlags, |
174 | ) -> IoResult<Surface<U>> { |
175 | let mods = modifiers.map(|m| m.into()).collect::<Vec<u64>>(); |
176 | let ptr = unsafe { |
177 | ffi::gbm_surface_create_with_modifiers2( |
178 | *self.ffi, |
179 | width, |
180 | height, |
181 | format as u32, |
182 | mods.as_ptr(), |
183 | mods.len() as u32, |
184 | usage.bits(), |
185 | ) |
186 | }; |
187 | if ptr.is_null() { |
188 | Err(IoError::last_os_error()) |
189 | } else { |
190 | Ok(unsafe { Surface::new(ptr, self.ffi.clone()) }) |
191 | } |
192 | } |
193 | |
194 | /// Allocate a buffer object for the given dimensions |
195 | pub fn create_buffer_object<U: 'static>( |
196 | &self, |
197 | width: u32, |
198 | height: u32, |
199 | format: Format, |
200 | usage: BufferObjectFlags, |
201 | ) -> IoResult<BufferObject<U>> { |
202 | let ptr = |
203 | unsafe { ffi::gbm_bo_create(*self.ffi, width, height, format as u32, usage.bits()) }; |
204 | if ptr.is_null() { |
205 | Err(IoError::last_os_error()) |
206 | } else { |
207 | Ok(unsafe { BufferObject::new(ptr, self.ffi.clone()) }) |
208 | } |
209 | } |
210 | |
211 | /// Allocate a buffer object for the given dimensions with explicit modifiers |
212 | pub fn create_buffer_object_with_modifiers<U: 'static>( |
213 | &self, |
214 | width: u32, |
215 | height: u32, |
216 | format: Format, |
217 | modifiers: impl Iterator<Item = Modifier>, |
218 | ) -> IoResult<BufferObject<U>> { |
219 | let mods = modifiers.map(|m| m.into()).collect::<Vec<u64>>(); |
220 | let ptr = unsafe { |
221 | ffi::gbm_bo_create_with_modifiers( |
222 | *self.ffi, |
223 | width, |
224 | height, |
225 | format as u32, |
226 | mods.as_ptr(), |
227 | mods.len() as u32, |
228 | ) |
229 | }; |
230 | if ptr.is_null() { |
231 | Err(IoError::last_os_error()) |
232 | } else { |
233 | Ok(unsafe { BufferObject::new(ptr, self.ffi.clone()) }) |
234 | } |
235 | } |
236 | |
237 | /// Allocate a buffer object for the given dimensions with explicit modifiers and flags |
238 | pub fn create_buffer_object_with_modifiers2<U: 'static>( |
239 | &self, |
240 | width: u32, |
241 | height: u32, |
242 | format: Format, |
243 | modifiers: impl Iterator<Item = Modifier>, |
244 | usage: BufferObjectFlags, |
245 | ) -> IoResult<BufferObject<U>> { |
246 | let mods = modifiers.map(|m| m.into()).collect::<Vec<u64>>(); |
247 | let ptr = unsafe { |
248 | ffi::gbm_bo_create_with_modifiers2( |
249 | *self.ffi, |
250 | width, |
251 | height, |
252 | format as u32, |
253 | mods.as_ptr(), |
254 | mods.len() as u32, |
255 | usage.bits(), |
256 | ) |
257 | }; |
258 | if ptr.is_null() { |
259 | Err(IoError::last_os_error()) |
260 | } else { |
261 | Ok(unsafe { BufferObject::new(ptr, self.ffi.clone()) }) |
262 | } |
263 | } |
264 | |
265 | /// Create a GBM buffer object from a wayland buffer |
266 | /// |
267 | /// This function imports a foreign [`WlBuffer`] object and creates a new GBM |
268 | /// buffer object for it. |
269 | /// This enables using the foreign object with a display API such as KMS. |
270 | /// |
271 | /// The GBM bo shares the underlying pixels but its life-time is |
272 | /// independent of the foreign object. |
273 | #[cfg (feature = "import-wayland" )] |
274 | pub fn import_buffer_object_from_wayland<U: 'static>( |
275 | &self, |
276 | buffer: &WlBuffer, |
277 | usage: BufferObjectFlags, |
278 | ) -> IoResult<BufferObject<U>> { |
279 | use wayland_server::Resource; |
280 | |
281 | let ptr = unsafe { |
282 | ffi::gbm_bo_import( |
283 | *self.ffi, |
284 | ffi::GBM_BO_IMPORT_WL_BUFFER, |
285 | buffer.id().as_ptr() as *mut _, |
286 | usage.bits(), |
287 | ) |
288 | }; |
289 | if ptr.is_null() { |
290 | Err(IoError::last_os_error()) |
291 | } else { |
292 | Ok(unsafe { BufferObject::new(ptr, self.ffi.clone()) }) |
293 | } |
294 | } |
295 | |
296 | /// Create a GBM buffer object from an egl buffer |
297 | /// |
298 | /// This function imports a foreign [`EGLImage`] object and creates a new GBM |
299 | /// buffer object for it. |
300 | /// This enables using the foreign object with a display API such as KMS. |
301 | /// |
302 | /// The GBM bo shares the underlying pixels but its life-time is |
303 | /// independent of the foreign object. |
304 | /// |
305 | /// # Safety |
306 | /// |
307 | /// The given [`EGLImage`] is a raw pointer. Passing null or an invalid [`EGLImage`] will |
308 | /// cause undefined behavior. |
309 | #[cfg (feature = "import-egl" )] |
310 | pub unsafe fn import_buffer_object_from_egl<U: 'static>( |
311 | &self, |
312 | buffer: EGLImage, |
313 | usage: BufferObjectFlags, |
314 | ) -> IoResult<BufferObject<U>> { |
315 | let ptr = ffi::gbm_bo_import( |
316 | *self.ffi, |
317 | ffi::GBM_BO_IMPORT_EGL_IMAGE, |
318 | buffer, |
319 | usage.bits(), |
320 | ); |
321 | if ptr.is_null() { |
322 | Err(IoError::last_os_error()) |
323 | } else { |
324 | Ok(BufferObject::new(ptr, self.ffi.clone())) |
325 | } |
326 | } |
327 | |
328 | /// Create a GBM buffer object from a dma buffer |
329 | /// |
330 | /// This function imports a foreign dma buffer from an open file descriptor |
331 | /// and creates a new GBM buffer object for it. |
332 | /// This enables using the foreign object with a display API such as KMS. |
333 | /// |
334 | /// The GBM bo shares the underlying pixels but its life-time is |
335 | /// independent of the foreign object. |
336 | pub fn import_buffer_object_from_dma_buf<U: 'static>( |
337 | &self, |
338 | buffer: BorrowedFd<'_>, |
339 | width: u32, |
340 | height: u32, |
341 | stride: u32, |
342 | format: Format, |
343 | usage: BufferObjectFlags, |
344 | ) -> IoResult<BufferObject<U>> { |
345 | let mut fd_data = ffi::gbm_import_fd_data { |
346 | fd: buffer.as_raw_fd(), |
347 | width, |
348 | height, |
349 | stride, |
350 | format: format as u32, |
351 | }; |
352 | |
353 | let ptr = unsafe { |
354 | ffi::gbm_bo_import( |
355 | *self.ffi, |
356 | ffi::GBM_BO_IMPORT_FD, |
357 | &mut fd_data as *mut ffi::gbm_import_fd_data as *mut _, |
358 | usage.bits(), |
359 | ) |
360 | }; |
361 | if ptr.is_null() { |
362 | Err(IoError::last_os_error()) |
363 | } else { |
364 | Ok(unsafe { BufferObject::new(ptr, self.ffi.clone()) }) |
365 | } |
366 | } |
367 | |
368 | /// Create a GBM buffer object from a dma buffer with explicit modifiers |
369 | /// |
370 | /// This function imports a foreign dma buffer from an open file descriptor |
371 | /// and creates a new GBM buffer object for it. |
372 | /// This enables using the foreign object with a display API such as KMS. |
373 | /// |
374 | /// The GBM bo shares the underlying pixels but its life-time is |
375 | /// independent of the foreign object. |
376 | #[allow (clippy::too_many_arguments)] |
377 | pub fn import_buffer_object_from_dma_buf_with_modifiers<U: 'static>( |
378 | &self, |
379 | len: u32, |
380 | buffers: [Option<BorrowedFd<'_>>; 4], |
381 | width: u32, |
382 | height: u32, |
383 | format: Format, |
384 | usage: BufferObjectFlags, |
385 | strides: [i32; 4], |
386 | offsets: [i32; 4], |
387 | modifier: Modifier, |
388 | ) -> IoResult<BufferObject<U>> { |
389 | let fds = buffers.map(|fd| fd.map_or(-1, |x| x.as_raw_fd())); |
390 | let mut fd_data = ffi::gbm_import_fd_modifier_data { |
391 | fds, |
392 | width, |
393 | height, |
394 | format: format as u32, |
395 | strides, |
396 | offsets, |
397 | modifier: modifier.into(), |
398 | num_fds: len, |
399 | }; |
400 | |
401 | let ptr = unsafe { |
402 | ffi::gbm_bo_import( |
403 | *self.ffi, |
404 | ffi::GBM_BO_IMPORT_FD_MODIFIER, |
405 | &mut fd_data as *mut ffi::gbm_import_fd_modifier_data as *mut _, |
406 | usage.bits(), |
407 | ) |
408 | }; |
409 | if ptr.is_null() { |
410 | Err(IoError::last_os_error()) |
411 | } else { |
412 | Ok(unsafe { BufferObject::new(ptr, self.ffi.clone()) }) |
413 | } |
414 | } |
415 | } |
416 | |
417 | #[cfg (feature = "drm-support" )] |
418 | impl<T: DrmDevice + AsFd> DrmDevice for Device<T> {} |
419 | |
420 | #[cfg (feature = "drm-support" )] |
421 | impl<T: DrmControlDevice + AsFd> DrmControlDevice for Device<T> {} |
422 | |