Skip to content

Commit d2f7e1f

Browse files
committed
anvil: fallback to primary gpu for display only devices
1 parent e27ee63 commit d2f7e1f

File tree

1 file changed

+116
-57
lines changed

1 file changed

+116
-57
lines changed

anvil/src/udev.rs

+116-57
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@ use smithay::{
2828
dmabuf::Dmabuf,
2929
format::FormatSet,
3030
gbm::{GbmAllocator, GbmBufferFlags, GbmDevice},
31-
Fourcc,
31+
Fourcc, Modifier,
3232
},
3333
drm::{
3434
compositor::{DrmCompositor, FrameFlags},
35+
exporter::gbm::GbmFramebufferExporter,
3536
output::{DrmOutput, DrmOutputManager, DrmOutputRenderElements},
3637
CreateDrmNodeError, DrmAccessError, DrmDevice, DrmDeviceFd, DrmError, DrmEvent, DrmEventMetadata,
3738
DrmNode, DrmSurface, GbmBufferedSurface, NodeType,
@@ -422,21 +423,26 @@ pub fn run_udev() {
422423
state.backend_data.dmabuf_state = Some((dmabuf_state, global));
423424

424425
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+
});
437444
});
438445
});
439-
});
440446

441447
// Expose syncobj protocol if supported by primary GPU
442448
if let Some(primary_node) = state
@@ -592,11 +598,11 @@ pub type GbmDrmCompositor = DrmCompositor<
592598
struct SurfaceData {
593599
dh: DisplayHandle,
594600
device_id: DrmNode,
595-
render_node: DrmNode,
601+
render_node: Option<DrmNode>,
596602
global: Option<GlobalId>,
597603
drm_output: DrmOutput<
598604
GbmAllocator<DrmDeviceFd>,
599-
GbmDevice<DrmDeviceFd>,
605+
GbmFramebufferExporter<DrmDeviceFd>,
600606
Option<OutputPresentationFeedback>,
601607
DrmDeviceFd,
602608
>,
@@ -623,12 +629,12 @@ struct BackendData {
623629
active_leases: Vec<DrmLease>,
624630
drm_output_manager: DrmOutputManager<
625631
GbmAllocator<DrmDeviceFd>,
626-
GbmDevice<DrmDeviceFd>,
632+
GbmFramebufferExporter<DrmDeviceFd>,
627633
Option<OutputPresentationFeedback>,
628634
DrmDeviceFd,
629635
>,
630636
drm_scanner: DrmScanner,
631-
render_node: DrmNode,
637+
render_node: Option<DrmNode>,
632638
registration_token: RegistrationToken,
633639
}
634640

@@ -644,20 +650,30 @@ enum DeviceAddError {
644650
DrmNode(CreateDrmNodeError),
645651
#[error("Failed to add device to GpuManager: {0}")]
646652
AddNode(egl::Error),
653+
#[error("The device has no render node")]
654+
NoRenderNode,
655+
#[error("Primary GPU is missing")]
656+
PrimaryGpuMissing,
647657
}
648658

649659
fn get_surface_dmabuf_feedback(
650660
primary_gpu: DrmNode,
651-
render_node: DrmNode,
661+
render_node: Option<DrmNode>,
662+
scanout_node: DrmNode,
652663
gpus: &mut GpuManager<GbmGlesBackend<GlesRenderer, DrmDeviceFd>>,
653664
surface: &DrmSurface,
654665
) -> Option<SurfaceDmabufFeedback> {
655666
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+
};
657672

658673
let all_render_formats = primary_formats
659674
.iter()
660675
.chain(render_formats.iter())
676+
.filter(|format| render_node.is_some() || format.modifier == Modifier::Linear)
661677
.copied()
662678
.collect::<FormatSet>();
663679

@@ -678,19 +694,23 @@ fn get_surface_dmabuf_feedback(
678694
.collect::<FormatSet>();
679695

680696
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+
};
686706

687707
let scanout_feedback = builder
688708
.add_preference_tranche(
689709
surface.device_fd().dev_id().unwrap(),
690710
Some(zwp_linux_dmabuf_feedback_v1::TrancheFlags::Scanout),
691711
planes_formats,
692712
)
693-
.add_preference_tranche(render_node.dev_id(), None, render_formats)
713+
.add_preference_tranche(scanout_node.dev_id(), None, render_formats)
694714
.build()
695715
.unwrap();
696716

@@ -733,30 +753,71 @@ impl AnvilState<UdevData> {
733753
)
734754
.unwrap();
735755

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)?;
740759

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());
746797

747-
let allocator = GbmAllocator::new(gbm.clone(), GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT);
748798
let color_formats = if std::env::var("ANVIL_DISABLE_10BIT").is_ok() {
749799
SUPPORTED_FORMATS_8BIT_ONLY
750800
} else {
751801
SUPPORTED_FORMATS
752802
};
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>();
755816

756-
let drm_device_manager = DrmOutputManager::new(
817+
let drm_output_manager = DrmOutputManager::new(
757818
drm,
758819
allocator,
759-
gbm.clone(),
820+
framebuffer_exporter,
760821
Some(gbm),
761822
color_formats.iter().copied(),
762823
render_formats,
@@ -766,7 +827,7 @@ impl AnvilState<UdevData> {
766827
node,
767828
BackendData {
768829
registration_token,
769-
drm_output_manager: drm_device_manager,
830+
drm_output_manager,
770831
drm_scanner: DrmScanner::new(),
771832
non_desktop_connectors: Vec::new(),
772833
render_node,
@@ -792,11 +853,8 @@ impl AnvilState<UdevData> {
792853
return;
793854
};
794855

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();
800858

801859
let output_name = format!("{}-{}", connector.interface().as_str(), connector.interface_id());
802860
info!(?crtc, "Trying to setup connector {}", output_name,);
@@ -935,6 +993,7 @@ impl AnvilState<UdevData> {
935993
get_surface_dmabuf_feedback(
936994
self.backend_data.primary_gpu,
937995
device.render_node,
996+
node,
938997
&mut self.backend_data.gpus,
939998
compositor.surface(),
940999
)
@@ -998,11 +1057,8 @@ impl AnvilState<UdevData> {
9981057
}
9991058
}
10001059

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();
10061062
let _ = device.drm_output_manager.try_to_restore_modifiers::<_, OutputRenderElements<
10071063
UdevRenderer<'_>,
10081064
WindowRenderElement<UdevRenderer<'_>>,
@@ -1079,10 +1135,9 @@ impl AnvilState<UdevData> {
10791135
leasing_global.disable_global::<AnvilState<UdevData>>();
10801136
}
10811137

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+
}
10861141

10871142
self.handle.remove(backend_data.registration_token);
10881143

@@ -1218,7 +1273,11 @@ impl AnvilState<UdevData> {
12181273
// and do some prediction for the next repaint.
12191274
let repaint_delay = Duration::from_secs_f64(frame_duration.as_secs_f64() * 0.6f64);
12201275

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+
{
12221281
// However, if we need to do a copy, that might not be enough.
12231282
// (And without actual comparision to previous frames we cannot really know.)
12241283
// So lets ignore that in those cases to avoid thrashing performance.
@@ -1300,8 +1359,8 @@ impl AnvilState<UdevData> {
13001359
.pointer_image
13011360
.get_image(1 /*scale*/, self.clock.now().into());
13021361

1303-
let render_node = surface.render_node;
13041362
let primary_gpu = self.backend_data.primary_gpu;
1363+
let render_node = surface.render_node.unwrap_or(primary_gpu);
13051364
let mut renderer = if primary_gpu == render_node {
13061365
self.backend_data.gpus.single_renderer(&render_node)
13071366
} else {

0 commit comments

Comments
 (0)