1#![allow(dead_code)]
20
21use alloc::{collections::BTreeMap, vec, vec::Vec};
22
23use crate::error::KernelError;
24
25pub const ZWP_LINUX_DMABUF_V1: &str = "zwp_linux_dmabuf_v1";
31
32pub const ZWP_LINUX_DMABUF_V1_VERSION: u32 = 4;
34
35pub const ZWP_LINUX_DMABUF_V1_DESTROY: u16 = 0;
38pub const ZWP_LINUX_DMABUF_V1_CREATE_PARAMS: u16 = 1;
40pub const ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK: u16 = 2;
42pub const ZWP_LINUX_DMABUF_V1_GET_SURFACE_FEEDBACK: u16 = 3;
44
45pub const ZWP_LINUX_DMABUF_V1_FORMAT: u16 = 0;
48pub const ZWP_LINUX_DMABUF_V1_MODIFIER: u16 = 1;
51
52pub const ZWP_LINUX_BUFFER_PARAMS_V1_DESTROY: u16 = 0;
55pub const ZWP_LINUX_BUFFER_PARAMS_V1_ADD: u16 = 1;
57pub const ZWP_LINUX_BUFFER_PARAMS_V1_CREATE: u16 = 2;
59pub const ZWP_LINUX_BUFFER_PARAMS_V1_CREATE_IMMED: u16 = 3;
61
62pub const ZWP_LINUX_BUFFER_PARAMS_V1_CREATED: u16 = 0;
65pub const ZWP_LINUX_BUFFER_PARAMS_V1_FAILED: u16 = 1;
67
68pub const ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT: u32 = 1;
71pub const ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_INTERLACED: u32 = 2;
73pub const ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_BOTTOM_FIRST: u32 = 4;
75
76pub const MAX_PLANES: usize = 4;
78
79pub mod fourcc {
88 pub const DRM_FORMAT_ARGB8888: u32 = 0x34325241; pub const DRM_FORMAT_XRGB8888: u32 = 0x34325258; pub const DRM_FORMAT_ABGR8888: u32 = 0x34324241; pub const DRM_FORMAT_XBGR8888: u32 = 0x34324258; pub const DRM_FORMAT_RGB888: u32 = 0x34324752; pub const DRM_FORMAT_BGR888: u32 = 0x34324742; pub const DRM_FORMAT_NV12: u32 = 0x3231564E; pub const DRM_FORMAT_YUYV: u32 = 0x56595559; pub const DRM_FORMAT_RGB565: u32 = 0x36314752; }
107
108pub mod modifiers {
114 pub const DRM_FORMAT_MOD_INVALID: u64 = 0x00FF_FFFF_FFFF_FFFF;
116 pub const DRM_FORMAT_MOD_LINEAR: u64 = 0;
118 pub const I915_FORMAT_MOD_X_TILED: u64 = (1u64 << 56) | 1;
120 pub const I915_FORMAT_MOD_Y_TILED: u64 = (1u64 << 56) | 2;
122 pub const I915_FORMAT_MOD_4_TILED: u64 = (1u64 << 56) | 9;
124}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq)]
136pub struct DmaBufFormat {
137 pub fourcc: u32,
139 pub modifier_hi: u32,
141 pub modifier_lo: u32,
143}
144
145impl DmaBufFormat {
146 pub fn new(fourcc: u32, modifier: u64) -> Self {
148 Self {
149 fourcc,
150 modifier_hi: (modifier >> 32) as u32,
151 modifier_lo: modifier as u32,
152 }
153 }
154
155 pub fn modifier(&self) -> u64 {
157 ((self.modifier_hi as u64) << 32) | (self.modifier_lo as u64)
158 }
159
160 pub fn is_linear(&self) -> bool {
162 self.modifier() == modifiers::DRM_FORMAT_MOD_LINEAR
163 }
164}
165
166#[derive(Debug, Clone)]
170pub struct DmaBufParams {
171 pub id: u32,
173 pub width: u32,
175 pub height: u32,
177 pub format: u32,
179 pub flags: u32,
181 pub planes: Vec<DmaBufPlane>,
183}
184
185impl DmaBufParams {
186 pub fn new(id: u32) -> Self {
188 Self {
189 id,
190 width: 0,
191 height: 0,
192 format: 0,
193 flags: 0,
194 planes: Vec::new(),
195 }
196 }
197}
198
199#[derive(Debug, Clone, Copy)]
204pub struct DmaBufPlane {
205 pub resource_id: u32,
210 pub offset: u32,
212 pub stride: u32,
214 pub modifier_hi: u32,
216 pub modifier_lo: u32,
218}
219
220impl DmaBufPlane {
221 pub fn modifier(&self) -> u64 {
223 ((self.modifier_hi as u64) << 32) | (self.modifier_lo as u64)
224 }
225}
226
227pub struct DmaBufBuffer {
232 pub id: u32,
234 pub params: DmaBufParams,
236 pub wl_buffer_id: u32,
238}
239
240pub struct DmaBufManager {
249 supported_formats: Vec<DmaBufFormat>,
251 params: BTreeMap<u32, DmaBufParams>,
253 buffers: BTreeMap<u32, DmaBufBuffer>,
255 next_params_id: u32,
257 next_buffer_id: u32,
259}
260
261impl DmaBufManager {
262 pub fn new() -> Self {
267 let supported_formats = vec![
268 DmaBufFormat::new(
269 fourcc::DRM_FORMAT_ARGB8888,
270 modifiers::DRM_FORMAT_MOD_LINEAR,
271 ),
272 DmaBufFormat::new(
273 fourcc::DRM_FORMAT_XRGB8888,
274 modifiers::DRM_FORMAT_MOD_LINEAR,
275 ),
276 ];
277
278 Self {
279 supported_formats,
280 params: BTreeMap::new(),
281 buffers: BTreeMap::new(),
282 next_params_id: 1,
283 next_buffer_id: 1,
284 }
285 }
286
287 pub fn get_supported_formats(&self) -> &[DmaBufFormat] {
289 &self.supported_formats
290 }
291
292 pub fn add_supported_format(&mut self, format: DmaBufFormat) {
294 if !self.supported_formats.contains(&format) {
295 self.supported_formats.push(format);
296 }
297 }
298
299 pub fn is_format_supported(&self, fourcc: u32, modifier: u64) -> bool {
301 self.supported_formats
302 .iter()
303 .any(|f| f.fourcc == fourcc && f.modifier() == modifier)
304 }
305
306 pub fn create_params(&mut self) -> u32 {
311 let id = self.next_params_id;
312 self.next_params_id += 1;
313
314 self.params.insert(id, DmaBufParams::new(id));
315 id
316 }
317
318 pub fn add_plane(&mut self, params_id: u32, plane: DmaBufPlane) -> Result<(), KernelError> {
320 let params = self
321 .params
322 .get_mut(¶ms_id)
323 .ok_or(KernelError::NotFound {
324 resource: "dmabuf_params",
325 id: params_id as u64,
326 })?;
327
328 if params.planes.len() >= MAX_PLANES {
329 return Err(KernelError::InvalidArgument {
330 name: "plane_count",
331 value: "exceeds_max_planes",
332 });
333 }
334
335 params.planes.push(plane);
336 Ok(())
337 }
338
339 pub fn create_buffer(
344 &mut self,
345 params_id: u32,
346 width: u32,
347 height: u32,
348 format: u32,
349 flags: u32,
350 ) -> Result<u32, KernelError> {
351 let mut params = self
352 .params
353 .remove(¶ms_id)
354 .ok_or(KernelError::NotFound {
355 resource: "dmabuf_params",
356 id: params_id as u64,
357 })?;
358
359 if params.planes.is_empty() {
361 return Err(KernelError::InvalidArgument {
362 name: "planes",
363 value: "no_planes_added",
364 });
365 }
366
367 if width == 0 || height == 0 {
369 return Err(KernelError::InvalidArgument {
370 name: "dimensions",
371 value: "zero_width_or_height",
372 });
373 }
374
375 let first_modifier = params.planes[0].modifier();
377 for plane in ¶ms.planes[1..] {
378 if plane.modifier() != first_modifier {
379 return Err(KernelError::InvalidArgument {
380 name: "modifier",
381 value: "planes_have_different_modifiers",
382 });
383 }
384 }
385
386 if !self.is_format_supported(format, first_modifier) {
388 return Err(KernelError::InvalidArgument {
389 name: "format",
390 value: "unsupported_format_modifier",
391 });
392 }
393
394 params.width = width;
396 params.height = height;
397 params.format = format;
398 params.flags = flags;
399
400 let buffer_id = self.next_buffer_id;
402 self.next_buffer_id += 1;
403
404 let buffer = DmaBufBuffer {
405 id: buffer_id,
406 params,
407 wl_buffer_id: 0, };
409
410 self.buffers.insert(buffer_id, buffer);
411 Ok(buffer_id)
412 }
413
414 pub fn destroy_buffer(&mut self, buffer_id: u32) -> Result<(), KernelError> {
416 self.buffers
417 .remove(&buffer_id)
418 .ok_or(KernelError::NotFound {
419 resource: "dmabuf_buffer",
420 id: buffer_id as u64,
421 })?;
422 Ok(())
423 }
424
425 pub fn import_from_virtio_gpu(
431 &mut self,
432 resource_id: u32,
433 width: u32,
434 height: u32,
435 format: u32,
436 ) -> Result<u32, KernelError> {
437 let bpp: u32 = match format {
438 fourcc::DRM_FORMAT_ARGB8888
439 | fourcc::DRM_FORMAT_XRGB8888
440 | fourcc::DRM_FORMAT_ABGR8888
441 | fourcc::DRM_FORMAT_XBGR8888 => 4,
442 fourcc::DRM_FORMAT_RGB888 | fourcc::DRM_FORMAT_BGR888 => 3,
443 fourcc::DRM_FORMAT_RGB565 => 2,
444 _ => {
445 return Err(KernelError::InvalidArgument {
446 name: "format",
447 value: "unknown_format_bpp",
448 });
449 }
450 };
451
452 let stride = width * bpp;
453 let params_id = self.create_params();
454
455 let plane = DmaBufPlane {
456 resource_id,
457 offset: 0,
458 stride,
459 modifier_hi: 0,
460 modifier_lo: 0, };
462
463 self.add_plane(params_id, plane)?;
464 self.create_buffer(params_id, width, height, format, 0)
465 }
466
467 pub fn get_buffer(&self, buffer_id: u32) -> Option<&DmaBufBuffer> {
469 self.buffers.get(&buffer_id)
470 }
471
472 pub fn get_buffer_mut(&mut self, buffer_id: u32) -> Option<&mut DmaBufBuffer> {
474 self.buffers.get_mut(&buffer_id)
475 }
476
477 pub fn destroy_params(&mut self, params_id: u32) -> Result<(), KernelError> {
479 self.params
480 .remove(¶ms_id)
481 .ok_or(KernelError::NotFound {
482 resource: "dmabuf_params",
483 id: params_id as u64,
484 })?;
485 Ok(())
486 }
487
488 pub fn buffer_count(&self) -> usize {
490 self.buffers.len()
491 }
492
493 pub fn params_count(&self) -> usize {
495 self.params.len()
496 }
497}
498
499impl Default for DmaBufManager {
500 fn default() -> Self {
501 Self::new()
502 }
503}
504
505#[cfg(test)]
510mod tests {
511 use super::*;
512
513 #[test]
514 fn test_default_formats() {
515 let mgr = DmaBufManager::new();
516 let formats = mgr.get_supported_formats();
517 assert_eq!(formats.len(), 2);
518 assert!(mgr.is_format_supported(
519 fourcc::DRM_FORMAT_ARGB8888,
520 modifiers::DRM_FORMAT_MOD_LINEAR
521 ));
522 assert!(mgr.is_format_supported(
523 fourcc::DRM_FORMAT_XRGB8888,
524 modifiers::DRM_FORMAT_MOD_LINEAR
525 ));
526 assert!(!mgr.is_format_supported(fourcc::DRM_FORMAT_NV12, modifiers::DRM_FORMAT_MOD_LINEAR));
527 }
528
529 #[test]
530 fn test_create_buffer_single_plane() {
531 let mut mgr = DmaBufManager::new();
532 let params_id = mgr.create_params();
533
534 let plane = DmaBufPlane {
535 resource_id: 42,
536 offset: 0,
537 stride: 1280 * 4,
538 modifier_hi: 0,
539 modifier_lo: 0,
540 };
541
542 mgr.add_plane(params_id, plane).unwrap();
543 let buf_id = mgr
544 .create_buffer(params_id, 1280, 720, fourcc::DRM_FORMAT_ARGB8888, 0)
545 .unwrap();
546
547 let buf = mgr.get_buffer(buf_id).unwrap();
548 assert_eq!(buf.params.width, 1280);
549 assert_eq!(buf.params.height, 720);
550 assert_eq!(buf.params.planes.len(), 1);
551 assert_eq!(buf.params.planes[0].resource_id, 42);
552 }
553
554 #[test]
555 fn test_create_buffer_no_planes_fails() {
556 let mut mgr = DmaBufManager::new();
557 let params_id = mgr.create_params();
558
559 let result = mgr.create_buffer(params_id, 100, 100, fourcc::DRM_FORMAT_ARGB8888, 0);
560 assert!(result.is_err());
561 }
562
563 #[test]
564 fn test_create_buffer_zero_dimensions_fails() {
565 let mut mgr = DmaBufManager::new();
566 let params_id = mgr.create_params();
567
568 let plane = DmaBufPlane {
569 resource_id: 1,
570 offset: 0,
571 stride: 0,
572 modifier_hi: 0,
573 modifier_lo: 0,
574 };
575 mgr.add_plane(params_id, plane).unwrap();
576
577 let result = mgr.create_buffer(params_id, 0, 100, fourcc::DRM_FORMAT_ARGB8888, 0);
578 assert!(result.is_err());
579 }
580
581 #[test]
582 fn test_create_buffer_unsupported_format_fails() {
583 let mut mgr = DmaBufManager::new();
584 let params_id = mgr.create_params();
585
586 let plane = DmaBufPlane {
587 resource_id: 1,
588 offset: 0,
589 stride: 100,
590 modifier_hi: 0,
591 modifier_lo: 0,
592 };
593 mgr.add_plane(params_id, plane).unwrap();
594
595 let result = mgr.create_buffer(params_id, 100, 100, fourcc::DRM_FORMAT_NV12, 0);
597 assert!(result.is_err());
598 }
599
600 #[test]
601 fn test_mismatched_modifiers_fails() {
602 let mut mgr = DmaBufManager::new();
603 let params_id = mgr.create_params();
604
605 let plane1 = DmaBufPlane {
606 resource_id: 1,
607 offset: 0,
608 stride: 100,
609 modifier_hi: 0,
610 modifier_lo: 0, };
612 let plane2 = DmaBufPlane {
613 resource_id: 2,
614 offset: 0,
615 stride: 50,
616 modifier_hi: 1,
617 modifier_lo: 1, };
619
620 mgr.add_plane(params_id, plane1).unwrap();
621 mgr.add_plane(params_id, plane2).unwrap();
622
623 let result = mgr.create_buffer(params_id, 100, 100, fourcc::DRM_FORMAT_ARGB8888, 0);
624 assert!(result.is_err());
625 }
626
627 #[test]
628 fn test_too_many_planes_fails() {
629 let mut mgr = DmaBufManager::new();
630 let params_id = mgr.create_params();
631
632 for i in 0..MAX_PLANES {
633 let plane = DmaBufPlane {
634 resource_id: i as u32,
635 offset: 0,
636 stride: 100,
637 modifier_hi: 0,
638 modifier_lo: 0,
639 };
640 mgr.add_plane(params_id, plane).unwrap();
641 }
642
643 let extra_plane = DmaBufPlane {
645 resource_id: 99,
646 offset: 0,
647 stride: 100,
648 modifier_hi: 0,
649 modifier_lo: 0,
650 };
651 assert!(mgr.add_plane(params_id, extra_plane).is_err());
652 }
653
654 #[test]
655 fn test_destroy_buffer() {
656 let mut mgr = DmaBufManager::new();
657 let params_id = mgr.create_params();
658 let plane = DmaBufPlane {
659 resource_id: 1,
660 offset: 0,
661 stride: 400,
662 modifier_hi: 0,
663 modifier_lo: 0,
664 };
665 mgr.add_plane(params_id, plane).unwrap();
666 let buf_id = mgr
667 .create_buffer(params_id, 100, 100, fourcc::DRM_FORMAT_ARGB8888, 0)
668 .unwrap();
669
670 assert_eq!(mgr.buffer_count(), 1);
671 mgr.destroy_buffer(buf_id).unwrap();
672 assert_eq!(mgr.buffer_count(), 0);
673 }
674
675 #[test]
676 fn test_destroy_nonexistent_buffer_fails() {
677 let mut mgr = DmaBufManager::new();
678 assert!(mgr.destroy_buffer(999).is_err());
679 }
680
681 #[test]
682 fn test_import_from_virtio_gpu() {
683 let mut mgr = DmaBufManager::new();
684 let buf_id = mgr
685 .import_from_virtio_gpu(7, 640, 480, fourcc::DRM_FORMAT_ARGB8888)
686 .unwrap();
687
688 let buf = mgr.get_buffer(buf_id).unwrap();
689 assert_eq!(buf.params.width, 640);
690 assert_eq!(buf.params.height, 480);
691 assert_eq!(buf.params.format, fourcc::DRM_FORMAT_ARGB8888);
692 assert_eq!(buf.params.planes.len(), 1);
693 assert_eq!(buf.params.planes[0].resource_id, 7);
694 assert_eq!(buf.params.planes[0].stride, 640 * 4);
695 }
696
697 #[test]
698 fn test_import_unknown_format_fails() {
699 let mut mgr = DmaBufManager::new();
700 let result = mgr.import_from_virtio_gpu(1, 100, 100, 0xDEADBEEF);
701 assert!(result.is_err());
702 }
703
704 #[test]
705 fn test_destroy_params() {
706 let mut mgr = DmaBufManager::new();
707 let params_id = mgr.create_params();
708 assert_eq!(mgr.params_count(), 1);
709 mgr.destroy_params(params_id).unwrap();
710 assert_eq!(mgr.params_count(), 0);
711 }
712
713 #[test]
714 fn test_add_supported_format() {
715 let mut mgr = DmaBufManager::new();
716 assert_eq!(mgr.get_supported_formats().len(), 2);
717
718 mgr.add_supported_format(DmaBufFormat::new(
719 fourcc::DRM_FORMAT_NV12,
720 modifiers::DRM_FORMAT_MOD_LINEAR,
721 ));
722 assert_eq!(mgr.get_supported_formats().len(), 3);
723
724 mgr.add_supported_format(DmaBufFormat::new(
726 fourcc::DRM_FORMAT_NV12,
727 modifiers::DRM_FORMAT_MOD_LINEAR,
728 ));
729 assert_eq!(mgr.get_supported_formats().len(), 3);
730 }
731
732 #[test]
733 fn test_format_is_linear() {
734 let linear = DmaBufFormat::new(
735 fourcc::DRM_FORMAT_ARGB8888,
736 modifiers::DRM_FORMAT_MOD_LINEAR,
737 );
738 assert!(linear.is_linear());
739
740 let tiled = DmaBufFormat::new(
741 fourcc::DRM_FORMAT_ARGB8888,
742 modifiers::I915_FORMAT_MOD_X_TILED,
743 );
744 assert!(!tiled.is_linear());
745 }
746
747 #[test]
748 fn test_format_modifier_roundtrip() {
749 let f = DmaBufFormat::new(
750 fourcc::DRM_FORMAT_ARGB8888,
751 modifiers::I915_FORMAT_MOD_Y_TILED,
752 );
753 assert_eq!(f.modifier(), modifiers::I915_FORMAT_MOD_Y_TILED);
754 }
755
756 #[test]
757 fn test_plane_modifier_roundtrip() {
758 let p = DmaBufPlane {
759 resource_id: 0,
760 offset: 0,
761 stride: 0,
762 modifier_hi: 0x0001_0000,
763 modifier_lo: 0x0000_0002,
764 };
765 assert_eq!(p.modifier(), 0x0001_0000_0000_0002);
766 }
767}