1use crate::{AsRaw, BufferObject, BufferObjectFlags, Format, Gbm, Modifier, Ptr, Surface};
2
3use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd};
4
5use std::{
6 ffi::CStr,
7 fmt,
8 io::{Error as IoError, Result as IoResult},
9 ops::{Deref, DerefMut},
10 sync::Arc,
11};
12
13#[cfg(feature = "import-wayland")]
14use wayland_server::protocol::wl_buffer::WlBuffer;
15
16#[cfg(feature = "import-egl")]
17pub type EGLImage = *mut libc::c_void;
19
20#[cfg(feature = "drm-support")]
21use drm::control::Device as DrmControlDevice;
22#[cfg(feature = "drm-support")]
23use drm::Device as DrmDevice;
24
25pub struct Device<T: AsFd> {
27 ffi: Ptr<ffi::gbm_device>,
29 fd: T,
30 gbm: Arc<Gbm>,
31}
32
33impl<T: AsFd> fmt::Debug for Device<T> {
34 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35 f.debug_struct("Device")
36 .field("ptr", &format_args!("{:p}", &self.ffi))
37 .finish()
38 }
39}
40
41impl<T: AsFd + Clone> Clone for Device<T> {
42 fn clone(&self) -> Device<T> {
43 Device {
44 fd: self.fd.clone(),
45 ffi: self.ffi.clone(),
46 gbm: self.gbm.clone(),
47 }
48 }
49}
50
51impl<T: AsFd> AsFd for Device<T> {
52 fn as_fd(&'_ self) -> BorrowedFd<'_> {
53 unsafe { BorrowedFd::borrow_raw(self.gbm.gbm_device_get_fd(*self.ffi)) }
54 }
55}
56
57impl<T: AsFd> AsRaw<ffi::gbm_device> for Device<T> {
58 fn as_raw(&self) -> *const ffi::gbm_device {
59 *self.ffi
60 }
61}
62
63impl<T: AsFd> Deref for Device<T> {
64 type Target = T;
65
66 fn deref(&self) -> &T {
67 &self.fd
68 }
69}
70
71impl<T: AsFd> DerefMut for Device<T> {
72 fn deref_mut(&mut self) -> &mut T {
73 &mut self.fd
74 }
75}
76
77impl<T: AsFd> Device<T> {
78 pub fn new(fd: T) -> IoResult<Device<T>> {
85 let gbm = Arc::new(Gbm::new()?);
86 let ptr = unsafe { gbm.gbm_create_device(fd.as_fd().as_raw_fd()) };
87 if ptr.is_null() {
88 Err(IoError::last_os_error())
89 } else {
90 let gbm_ = gbm.clone();
91 Ok(Device {
92 fd,
93 ffi: Ptr::<ffi::gbm_device>::new(ptr, move |ptr| unsafe {
94 gbm_.gbm_device_destroy(ptr)
95 }),
96 gbm,
97 })
98 }
99 }
100
101 pub fn backend_name(&self) -> &str {
103 unsafe {
104 CStr::from_ptr(self.gbm.gbm_device_get_backend_name(*self.ffi))
105 .to_str()
106 .expect("GBM passed invalid utf8 string")
107 }
108 }
109
110 pub fn is_format_supported(&self, format: Format, usage: BufferObjectFlags) -> bool {
112 unsafe {
113 self.gbm
114 .gbm_device_is_format_supported(*self.ffi, format as u32, usage.bits())
115 != 0
116 }
117 }
118
119 pub fn format_modifier_plane_count(&self, format: Format, modifier: Modifier) -> Option<u32> {
125 unsafe {
126 self.gbm
127 .gbm_device_get_format_modifier_plane_count(
128 *self.ffi,
129 format as u32,
130 modifier.into(),
131 )
132 .try_into()
133 .ok()
134 }
135 }
136
137 pub fn create_surface<U: 'static>(
139 &self,
140 width: u32,
141 height: u32,
142 format: Format,
143 usage: BufferObjectFlags,
144 ) -> IoResult<Surface<U>> {
145 let ptr = unsafe {
146 self.gbm
147 .gbm_surface_create(*self.ffi, width, height, format as u32, usage.bits())
148 };
149 if ptr.is_null() {
150 Err(IoError::last_os_error())
151 } else {
152 Ok(unsafe { Surface::new(ptr, self.ffi.clone(), self.gbm.clone()) })
153 }
154 }
155
156 pub fn create_surface_with_modifiers<U: 'static>(
158 &self,
159 width: u32,
160 height: u32,
161 format: Format,
162 modifiers: impl Iterator<Item = Modifier>,
163 ) -> IoResult<Surface<U>> {
164 let mods = modifiers.map(|m| m.into()).collect::<Vec<u64>>();
165 let ptr = unsafe {
166 self.gbm.gbm_surface_create_with_modifiers(
167 *self.ffi,
168 width,
169 height,
170 format as u32,
171 mods.as_ptr(),
172 mods.len() as u32,
173 )
174 };
175 if ptr.is_null() {
176 Err(IoError::last_os_error())
177 } else {
178 Ok(unsafe { Surface::new(ptr, self.ffi.clone(), self.gbm.clone()) })
179 }
180 }
181
182 pub fn create_surface_with_modifiers2<U: 'static>(
184 &self,
185 width: u32,
186 height: u32,
187 format: Format,
188 modifiers: impl Iterator<Item = Modifier>,
189 usage: BufferObjectFlags,
190 ) -> IoResult<Surface<U>> {
191 let mods = modifiers.map(|m| m.into()).collect::<Vec<u64>>();
192 let ptr = unsafe {
193 self.gbm.gbm_surface_create_with_modifiers2(
194 *self.ffi,
195 width,
196 height,
197 format as u32,
198 mods.as_ptr(),
199 mods.len() as u32,
200 usage.bits(),
201 )
202 };
203 if ptr.is_null() {
204 Err(IoError::last_os_error())
205 } else {
206 Ok(unsafe { Surface::new(ptr, self.ffi.clone(), self.gbm.clone()) })
207 }
208 }
209
210 pub fn create_buffer_object<U: 'static>(
212 &self,
213 width: u32,
214 height: u32,
215 format: Format,
216 usage: BufferObjectFlags,
217 ) -> IoResult<BufferObject<U>> {
218 let ptr = unsafe {
219 self.gbm
220 .gbm_bo_create(*self.ffi, width, height, format as u32, usage.bits())
221 };
222 if ptr.is_null() {
223 Err(IoError::last_os_error())
224 } else {
225 Ok(unsafe { BufferObject::new(ptr, self.ffi.clone(), self.gbm.clone()) })
226 }
227 }
228
229 pub fn create_buffer_object_with_modifiers<U: 'static>(
232 &self,
233 width: u32,
234 height: u32,
235 format: Format,
236 modifiers: impl Iterator<Item = Modifier>,
237 ) -> IoResult<BufferObject<U>> {
238 let mods = modifiers.map(|m| m.into()).collect::<Vec<u64>>();
239 let ptr = unsafe {
240 self.gbm.gbm_bo_create_with_modifiers(
241 *self.ffi,
242 width,
243 height,
244 format as u32,
245 mods.as_ptr(),
246 mods.len() as u32,
247 )
248 };
249 if ptr.is_null() {
250 Err(IoError::last_os_error())
251 } else {
252 Ok(unsafe { BufferObject::new(ptr, self.ffi.clone(), self.gbm.clone()) })
253 }
254 }
255
256 pub fn create_buffer_object_with_modifiers2<U: 'static>(
259 &self,
260 width: u32,
261 height: u32,
262 format: Format,
263 modifiers: impl Iterator<Item = Modifier>,
264 usage: BufferObjectFlags,
265 ) -> IoResult<BufferObject<U>> {
266 let mods = modifiers.map(|m| m.into()).collect::<Vec<u64>>();
267 let ptr = unsafe {
268 self.gbm.gbm_bo_create_with_modifiers2(
269 *self.ffi,
270 width,
271 height,
272 format as u32,
273 mods.as_ptr(),
274 mods.len() as u32,
275 usage.bits(),
276 )
277 };
278 if ptr.is_null() {
279 Err(IoError::last_os_error())
280 } else {
281 Ok(unsafe { BufferObject::new(ptr, self.ffi.clone(), self.gbm.clone()) })
282 }
283 }
284
285 #[cfg(feature = "import-wayland")]
294 pub fn import_buffer_object_from_wayland<U: 'static>(
295 &self,
296 buffer: &WlBuffer,
297 usage: BufferObjectFlags,
298 ) -> IoResult<BufferObject<U>> {
299 use wayland_server::Resource;
300
301 let ptr = unsafe {
302 self.gbm.gbm_bo_import(
303 *self.ffi,
304 ffi::GBM_BO_IMPORT_WL_BUFFER,
305 buffer.id().as_ptr() as *mut _,
306 usage.bits(),
307 )
308 };
309 if ptr.is_null() {
310 Err(IoError::last_os_error())
311 } else {
312 Ok(unsafe { BufferObject::new(ptr, self.ffi.clone(), self.gbm.clone()) })
313 }
314 }
315
316 #[cfg(feature = "import-egl")]
330 pub unsafe fn import_buffer_object_from_egl<U: 'static>(
331 &self,
332 buffer: EGLImage,
333 usage: BufferObjectFlags,
334 ) -> IoResult<BufferObject<U>> {
335 let ptr = self.gbm.gbm_bo_import(
336 *self.ffi,
337 ffi::GBM_BO_IMPORT_EGL_IMAGE,
338 buffer,
339 usage.bits(),
340 );
341 if ptr.is_null() {
342 Err(IoError::last_os_error())
343 } else {
344 Ok(BufferObject::new(ptr, self.ffi.clone(), self.gbm.clone()))
345 }
346 }
347
348 pub fn import_buffer_object_from_dma_buf<U: 'static>(
357 &self,
358 buffer: BorrowedFd<'_>,
359 width: u32,
360 height: u32,
361 stride: u32,
362 format: Format,
363 usage: BufferObjectFlags,
364 ) -> IoResult<BufferObject<U>> {
365 let mut fd_data = ffi::gbm_import_fd_data {
366 fd: buffer.as_raw_fd(),
367 width,
368 height,
369 stride,
370 format: format as u32,
371 };
372
373 let ptr = unsafe {
374 self.gbm.gbm_bo_import(
375 *self.ffi,
376 ffi::GBM_BO_IMPORT_FD,
377 &mut fd_data as *mut ffi::gbm_import_fd_data as *mut _,
378 usage.bits(),
379 )
380 };
381 if ptr.is_null() {
382 Err(IoError::last_os_error())
383 } else {
384 Ok(unsafe { BufferObject::new(ptr, self.ffi.clone(), self.gbm.clone()) })
385 }
386 }
387
388 #[allow(clippy::too_many_arguments)]
397 pub fn import_buffer_object_from_dma_buf_with_modifiers<U: 'static>(
398 &self,
399 len: u32,
400 buffers: [Option<BorrowedFd<'_>>; 4],
401 width: u32,
402 height: u32,
403 format: Format,
404 usage: BufferObjectFlags,
405 strides: [i32; 4],
406 offsets: [i32; 4],
407 modifier: Modifier,
408 ) -> IoResult<BufferObject<U>> {
409 let fds = buffers.map(|fd| fd.map_or(-1, |x| x.as_raw_fd()));
410 let mut fd_data = ffi::gbm_import_fd_modifier_data {
411 fds,
412 width,
413 height,
414 format: format as u32,
415 strides,
416 offsets,
417 modifier: modifier.into(),
418 num_fds: len,
419 };
420
421 let ptr = unsafe {
422 self.gbm.gbm_bo_import(
423 *self.ffi,
424 ffi::GBM_BO_IMPORT_FD_MODIFIER,
425 &mut fd_data as *mut ffi::gbm_import_fd_modifier_data as *mut _,
426 usage.bits(),
427 )
428 };
429 if ptr.is_null() {
430 Err(IoError::last_os_error())
431 } else {
432 Ok(unsafe { BufferObject::new(ptr, self.ffi.clone(), self.gbm.clone()) })
433 }
434 }
435}
436
437#[cfg(feature = "drm-support")]
438impl<T: DrmDevice + AsFd> DrmDevice for Device<T> {}
439
440#[cfg(feature = "drm-support")]
441impl<T: DrmControlDevice + AsFd> DrmControlDevice for Device<T> {}