@@ -28,10 +28,11 @@ use smithay::{
28
28
dmabuf:: Dmabuf ,
29
29
format:: FormatSet ,
30
30
gbm:: { GbmAllocator , GbmBufferFlags , GbmDevice } ,
31
- Fourcc ,
31
+ Fourcc , Modifier ,
32
32
} ,
33
33
drm:: {
34
34
compositor:: { DrmCompositor , FrameFlags } ,
35
+ exporter:: gbm:: GbmFramebufferExporter ,
35
36
output:: { DrmOutput , DrmOutputManager , DrmOutputRenderElements } ,
36
37
CreateDrmNodeError , DrmAccessError , DrmDevice , DrmDeviceFd , DrmError , DrmEvent , DrmEventMetadata ,
37
38
DrmNode , DrmSurface , GbmBufferedSurface , NodeType ,
@@ -422,21 +423,26 @@ pub fn run_udev() {
422
423
state. backend_data . dmabuf_state = Some ( ( dmabuf_state, global) ) ;
423
424
424
425
let gpus = & mut state. backend_data . gpus ;
425
- state. backend_data . backends . values_mut ( ) . for_each ( |backend_data| {
426
- // Update the per drm surface dmabuf feedback
427
- backend_data. surfaces . values_mut ( ) . for_each ( |surface_data| {
428
- surface_data. dmabuf_feedback = surface_data. dmabuf_feedback . take ( ) . or_else ( || {
429
- surface_data. drm_output . with_compositor ( |compositor| {
430
- get_surface_dmabuf_feedback (
431
- primary_gpu,
432
- surface_data. render_node ,
433
- gpus,
434
- compositor. surface ( ) ,
435
- )
436
- } )
426
+ state
427
+ . backend_data
428
+ . backends
429
+ . iter_mut ( )
430
+ . for_each ( |( node, backend_data) | {
431
+ // Update the per drm surface dmabuf feedback
432
+ backend_data. surfaces . values_mut ( ) . for_each ( |surface_data| {
433
+ surface_data. dmabuf_feedback = surface_data. dmabuf_feedback . take ( ) . or_else ( || {
434
+ surface_data. drm_output . with_compositor ( |compositor| {
435
+ get_surface_dmabuf_feedback (
436
+ primary_gpu,
437
+ surface_data. render_node ,
438
+ * node,
439
+ gpus,
440
+ compositor. surface ( ) ,
441
+ )
442
+ } )
443
+ } ) ;
437
444
} ) ;
438
445
} ) ;
439
- } ) ;
440
446
441
447
// Expose syncobj protocol if supported by primary GPU
442
448
if let Some ( primary_node) = state
@@ -592,11 +598,11 @@ pub type GbmDrmCompositor = DrmCompositor<
592
598
struct SurfaceData {
593
599
dh : DisplayHandle ,
594
600
device_id : DrmNode ,
595
- render_node : DrmNode ,
601
+ render_node : Option < DrmNode > ,
596
602
global : Option < GlobalId > ,
597
603
drm_output : DrmOutput <
598
604
GbmAllocator < DrmDeviceFd > ,
599
- GbmDevice < DrmDeviceFd > ,
605
+ GbmFramebufferExporter < DrmDeviceFd > ,
600
606
Option < OutputPresentationFeedback > ,
601
607
DrmDeviceFd ,
602
608
> ,
@@ -623,12 +629,12 @@ struct BackendData {
623
629
active_leases : Vec < DrmLease > ,
624
630
drm_output_manager : DrmOutputManager <
625
631
GbmAllocator < DrmDeviceFd > ,
626
- GbmDevice < DrmDeviceFd > ,
632
+ GbmFramebufferExporter < DrmDeviceFd > ,
627
633
Option < OutputPresentationFeedback > ,
628
634
DrmDeviceFd ,
629
635
> ,
630
636
drm_scanner : DrmScanner ,
631
- render_node : DrmNode ,
637
+ render_node : Option < DrmNode > ,
632
638
registration_token : RegistrationToken ,
633
639
}
634
640
@@ -644,20 +650,30 @@ enum DeviceAddError {
644
650
DrmNode ( CreateDrmNodeError ) ,
645
651
#[ error( "Failed to add device to GpuManager: {0}" ) ]
646
652
AddNode ( egl:: Error ) ,
653
+ #[ error( "The device has no render node" ) ]
654
+ NoRenderNode ,
655
+ #[ error( "Primary GPU is missing" ) ]
656
+ PrimaryGpuMissing ,
647
657
}
648
658
649
659
fn get_surface_dmabuf_feedback (
650
660
primary_gpu : DrmNode ,
651
- render_node : DrmNode ,
661
+ render_node : Option < DrmNode > ,
662
+ scanout_node : DrmNode ,
652
663
gpus : & mut GpuManager < GbmGlesBackend < GlesRenderer , DrmDeviceFd > > ,
653
664
surface : & DrmSurface ,
654
665
) -> Option < SurfaceDmabufFeedback > {
655
666
let primary_formats = gpus. single_renderer ( & primary_gpu) . ok ( ) ?. dmabuf_formats ( ) ;
656
- let render_formats = gpus. single_renderer ( & render_node) . ok ( ) ?. dmabuf_formats ( ) ;
667
+ let render_formats = if let Some ( render_node) = render_node {
668
+ gpus. single_renderer ( & render_node) . ok ( ) ?. dmabuf_formats ( )
669
+ } else {
670
+ FormatSet :: default ( )
671
+ } ;
657
672
658
673
let all_render_formats = primary_formats
659
674
. iter ( )
660
675
. chain ( render_formats. iter ( ) )
676
+ . filter ( |format| render_node. is_some ( ) || format. modifier == Modifier :: Linear )
661
677
. copied ( )
662
678
. collect :: < FormatSet > ( ) ;
663
679
@@ -678,19 +694,23 @@ fn get_surface_dmabuf_feedback(
678
694
. collect :: < FormatSet > ( ) ;
679
695
680
696
let builder = DmabufFeedbackBuilder :: new ( primary_gpu. dev_id ( ) , primary_formats) ;
681
- let render_feedback = builder
682
- . clone ( )
683
- . add_preference_tranche ( render_node. dev_id ( ) , None , render_formats. clone ( ) )
684
- . build ( )
685
- . unwrap ( ) ;
697
+ let render_feedback = if let Some ( render_node) = render_node {
698
+ builder
699
+ . clone ( )
700
+ . add_preference_tranche ( render_node. dev_id ( ) , None , render_formats. clone ( ) )
701
+ . build ( )
702
+ . unwrap ( )
703
+ } else {
704
+ builder. clone ( ) . build ( ) . unwrap ( )
705
+ } ;
686
706
687
707
let scanout_feedback = builder
688
708
. add_preference_tranche (
689
709
surface. device_fd ( ) . dev_id ( ) . unwrap ( ) ,
690
710
Some ( zwp_linux_dmabuf_feedback_v1:: TrancheFlags :: Scanout ) ,
691
711
planes_formats,
692
712
)
693
- . add_preference_tranche ( render_node . dev_id ( ) , None , render_formats)
713
+ . add_preference_tranche ( scanout_node . dev_id ( ) , None , render_formats)
694
714
. build ( )
695
715
. unwrap ( ) ;
696
716
@@ -733,30 +753,71 @@ impl AnvilState<UdevData> {
733
753
)
734
754
. unwrap ( ) ;
735
755
736
- let render_node = EGLDevice :: device_for_display ( & unsafe { EGLDisplay :: new ( gbm. clone ( ) ) . unwrap ( ) } )
737
- . ok ( )
738
- . and_then ( |x| x. try_get_render_node ( ) . ok ( ) . flatten ( ) )
739
- . unwrap_or ( node) ;
756
+ let mut try_initialize_gpu = || {
757
+ let display = unsafe { EGLDisplay :: new ( gbm. clone ( ) ) . map_err ( DeviceAddError :: AddNode ) ? } ;
758
+ let egl_device = EGLDevice :: device_for_display ( & display) . map_err ( DeviceAddError :: AddNode ) ?;
740
759
741
- self . backend_data
742
- . gpus
743
- . as_mut ( )
744
- . add_node ( render_node, gbm. clone ( ) )
745
- . map_err ( DeviceAddError :: AddNode ) ?;
760
+ let render_node = egl_device
761
+ . try_get_render_node ( )
762
+ . map_err ( DeviceAddError :: AddNode ) ?
763
+ . ok_or ( DeviceAddError :: NoRenderNode ) ?;
764
+ self . backend_data
765
+ . gpus
766
+ . as_mut ( )
767
+ . add_node ( render_node, gbm. clone ( ) )
768
+ . map_err ( DeviceAddError :: AddNode ) ?;
769
+
770
+ std:: result:: Result :: < DrmNode , DeviceAddError > :: Ok ( render_node)
771
+ } ;
772
+
773
+ let render_node = try_initialize_gpu ( )
774
+ . inspect_err ( |err| {
775
+ warn ! ( ?err, "failed to initialize gpu" ) ;
776
+ } )
777
+ . ok ( ) ;
778
+
779
+ let allocator = render_node
780
+ . is_some ( )
781
+ . then ( || GbmAllocator :: new ( gbm. clone ( ) , GbmBufferFlags :: RENDERING | GbmBufferFlags :: SCANOUT ) )
782
+ . or_else ( || {
783
+ self . backend_data
784
+ . backends
785
+ . get ( & self . backend_data . primary_gpu )
786
+ . or_else ( || {
787
+ self . backend_data
788
+ . backends
789
+ . values ( )
790
+ . find ( |backend| backend. render_node == Some ( self . backend_data . primary_gpu ) )
791
+ } )
792
+ . map ( |backend| backend. drm_output_manager . allocator ( ) . clone ( ) )
793
+ } )
794
+ . ok_or ( DeviceAddError :: PrimaryGpuMissing ) ?;
795
+
796
+ let framebuffer_exporter = GbmFramebufferExporter :: new ( gbm. clone ( ) ) ;
746
797
747
- let allocator = GbmAllocator :: new ( gbm. clone ( ) , GbmBufferFlags :: RENDERING | GbmBufferFlags :: SCANOUT ) ;
748
798
let color_formats = if std:: env:: var ( "ANVIL_DISABLE_10BIT" ) . is_ok ( ) {
749
799
SUPPORTED_FORMATS_8BIT_ONLY
750
800
} else {
751
801
SUPPORTED_FORMATS
752
802
} ;
753
- let mut renderer = self . backend_data . gpus . single_renderer ( & render_node) . unwrap ( ) ;
754
- let render_formats = renderer. as_mut ( ) . egl_context ( ) . dmabuf_render_formats ( ) . clone ( ) ;
803
+ let mut renderer = self
804
+ . backend_data
805
+ . gpus
806
+ . single_renderer ( & render_node. unwrap_or ( self . backend_data . primary_gpu ) )
807
+ . unwrap ( ) ;
808
+ let render_formats = renderer
809
+ . as_mut ( )
810
+ . egl_context ( )
811
+ . dmabuf_render_formats ( )
812
+ . iter ( )
813
+ . filter ( |format| render_node. is_some ( ) || format. modifier == Modifier :: Linear )
814
+ . copied ( )
815
+ . collect :: < FormatSet > ( ) ;
755
816
756
- let drm_device_manager = DrmOutputManager :: new (
817
+ let drm_output_manager = DrmOutputManager :: new (
757
818
drm,
758
819
allocator,
759
- gbm . clone ( ) ,
820
+ framebuffer_exporter ,
760
821
Some ( gbm) ,
761
822
color_formats. iter ( ) . copied ( ) ,
762
823
render_formats,
@@ -766,7 +827,7 @@ impl AnvilState<UdevData> {
766
827
node,
767
828
BackendData {
768
829
registration_token,
769
- drm_output_manager : drm_device_manager ,
830
+ drm_output_manager,
770
831
drm_scanner : DrmScanner :: new ( ) ,
771
832
non_desktop_connectors : Vec :: new ( ) ,
772
833
render_node,
@@ -792,11 +853,8 @@ impl AnvilState<UdevData> {
792
853
return ;
793
854
} ;
794
855
795
- let mut renderer = self
796
- . backend_data
797
- . gpus
798
- . single_renderer ( & device. render_node )
799
- . unwrap ( ) ;
856
+ let render_node = device. render_node . unwrap_or ( self . backend_data . primary_gpu ) ;
857
+ let mut renderer = self . backend_data . gpus . single_renderer ( & render_node) . unwrap ( ) ;
800
858
801
859
let output_name = format ! ( "{}-{}" , connector. interface( ) . as_str( ) , connector. interface_id( ) ) ;
802
860
info ! ( ?crtc, "Trying to setup connector {}" , output_name, ) ;
@@ -935,6 +993,7 @@ impl AnvilState<UdevData> {
935
993
get_surface_dmabuf_feedback (
936
994
self . backend_data . primary_gpu ,
937
995
device. render_node ,
996
+ node,
938
997
& mut self . backend_data . gpus ,
939
998
compositor. surface ( ) ,
940
999
)
@@ -998,11 +1057,8 @@ impl AnvilState<UdevData> {
998
1057
}
999
1058
}
1000
1059
1001
- let mut renderer = self
1002
- . backend_data
1003
- . gpus
1004
- . single_renderer ( & device. render_node )
1005
- . unwrap ( ) ;
1060
+ let render_node = device. render_node . unwrap_or ( self . backend_data . primary_gpu ) ;
1061
+ let mut renderer = self . backend_data . gpus . single_renderer ( & render_node) . unwrap ( ) ;
1006
1062
let _ = device. drm_output_manager . try_to_restore_modifiers :: < _ , OutputRenderElements <
1007
1063
UdevRenderer < ' _ > ,
1008
1064
WindowRenderElement < UdevRenderer < ' _ > > ,
@@ -1079,10 +1135,9 @@ impl AnvilState<UdevData> {
1079
1135
leasing_global. disable_global :: < AnvilState < UdevData > > ( ) ;
1080
1136
}
1081
1137
1082
- self . backend_data
1083
- . gpus
1084
- . as_mut ( )
1085
- . remove_node ( & backend_data. render_node ) ;
1138
+ if let Some ( render_node) = backend_data. render_node {
1139
+ self . backend_data . gpus . as_mut ( ) . remove_node ( & render_node) ;
1140
+ }
1086
1141
1087
1142
self . handle . remove ( backend_data. registration_token ) ;
1088
1143
@@ -1218,7 +1273,11 @@ impl AnvilState<UdevData> {
1218
1273
// and do some prediction for the next repaint.
1219
1274
let repaint_delay = Duration :: from_secs_f64 ( frame_duration. as_secs_f64 ( ) * 0.6f64 ) ;
1220
1275
1221
- let timer = if self . backend_data . primary_gpu != surface. render_node {
1276
+ let timer = if surface
1277
+ . render_node
1278
+ . map ( |render_node| render_node != self . backend_data . primary_gpu )
1279
+ . unwrap_or ( true )
1280
+ {
1222
1281
// However, if we need to do a copy, that might not be enough.
1223
1282
// (And without actual comparision to previous frames we cannot really know.)
1224
1283
// So lets ignore that in those cases to avoid thrashing performance.
@@ -1300,8 +1359,8 @@ impl AnvilState<UdevData> {
1300
1359
. pointer_image
1301
1360
. get_image ( 1 /*scale*/ , self . clock . now ( ) . into ( ) ) ;
1302
1361
1303
- let render_node = surface. render_node ;
1304
1362
let primary_gpu = self . backend_data . primary_gpu ;
1363
+ let render_node = surface. render_node . unwrap_or ( primary_gpu) ;
1305
1364
let mut renderer = if primary_gpu == render_node {
1306
1365
self . backend_data . gpus . single_renderer ( & render_node)
1307
1366
} else {
0 commit comments