Skip to content

Commit a1fc093

Browse files
committed
metal: log direct scanout errors
1 parent 9ad815e commit a1fc093

4 files changed

Lines changed: 142 additions & 49 deletions

File tree

src/backends/metal/present.rs

Lines changed: 77 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use crate::cmm::cmm_render_intent::RenderIntent;
1818
use crate::gfx_api::AcquireSync;
1919
use crate::gfx_api::BufferResv;
2020
use crate::gfx_api::CopyTexture;
21+
use crate::gfx_api::DirectScanoutError;
2122
use crate::gfx_api::DirectScanoutPosition;
2223
use crate::gfx_api::GfxRenderPass;
2324
use crate::gfx_api::GfxTexture;
@@ -50,6 +51,7 @@ use arrayvec::ArrayVec;
5051
use jay_proc::jay_hash;
5152
use std::rc::Rc;
5253
use std::rc::Weak;
54+
use thiserror::Error;
5355
use uapi::OwnedFd;
5456
use uapi::c;
5557

@@ -150,6 +152,30 @@ enum PresentFbWait {
150152
Scanout,
151153
}
152154

155+
#[derive(Copy, Clone, Debug, PartialEq, Error)]
156+
pub enum MetalDirectScanoutError {
157+
#[error(transparent)]
158+
GfxApi(#[from] DirectScanoutError),
159+
#[error("The client buffer has pending lazy work")]
160+
LazyWork,
161+
#[error("Cross-device direct scanout is not supported")]
162+
CrossDevice,
163+
#[error("Shm buffers cannot be scanned out")]
164+
Shm,
165+
#[error("The buffer is already marked as impossible")]
166+
MarkedImpossible,
167+
#[error("The buffer could not imported as a framebuffer")]
168+
ImportFb,
169+
#[error("The buffer format is not supported")]
170+
UnsupportedFormat,
171+
#[error("The modifier is not supported")]
172+
UnsupportedModifier,
173+
#[error("There is no suitable color management programming")]
174+
NoCmProgramming,
175+
#[error("The commit failed")]
176+
Commit,
177+
}
178+
153179
impl MetalConnector {
154180
pub fn schedule_present(&self) {
155181
self.present_trigger.trigger();
@@ -308,7 +334,7 @@ impl MetalConnector {
308334
&mut changed_planes,
309335
&mut connector_drm_state,
310336
);
311-
if res.is_err()
337+
if let Err(error) = &res
312338
&& let Some(dsk) = direct_scanout_key
313339
{
314340
let fb = self.prepare_present_fb(
@@ -324,7 +350,7 @@ impl MetalConnector {
324350
present_fb = Some(fb);
325351
self.await_present_fb(present_fb.as_mut(), PresentFbWait::Scanout)
326352
.await;
327-
res = self.program_connector(
353+
let new_res = self.program_connector(
328354
version,
329355
&crtc,
330356
&plane,
@@ -333,9 +359,14 @@ impl MetalConnector {
333359
&mut changed_planes,
334360
&mut connector_drm_state,
335361
);
336-
if res.is_ok() {
362+
if new_res.is_ok() {
337363
self.scanout_impossible_cache.insert(dsk, ());
364+
let log = self.handle_direct_scanout_error(MetalDirectScanoutError::Commit);
365+
if log {
366+
log::debug!("Commit error: {}", ErrorFmt(error));
367+
}
338368
}
369+
res = new_res;
339370
}
340371
let reset_damage = || {
341372
for buffer in &*buffers {
@@ -369,6 +400,7 @@ impl MetalConnector {
369400
buffer.damage_queue.clear();
370401
} else {
371402
reset_damage();
403+
self.last_direct_scanout_error.take();
372404
}
373405
buffer.locked.set(fb.core.locked);
374406
self.cm.apply(&fb.cm_programming);
@@ -696,7 +728,7 @@ impl MetalConnector {
696728
blend_cd: &Rc<ColorDescription>,
697729
gamma_lut: Option<&Rc<BackendGammaLut>>,
698730
cd: &Rc<ColorDescription>,
699-
) -> Option<(DirectScanoutData, DirectScanoutDataCore)> {
731+
) -> Result<(DirectScanoutData, DirectScanoutDataCore), MetalDirectScanoutError> {
700732
let (ct, position) = pass.prepare_direct_scanout(
701733
plane.mode_w.get(),
702734
plane.mode_h.get(),
@@ -719,7 +751,7 @@ impl MetalConnector {
719751
// if there is lazy work, the tex dmabuf is not up-to-date. going into
720752
// the compositing path ensures that it's up-to-date on the next
721753
// frame.
722-
return None;
754+
return Err(MetalDirectScanoutError::LazyWork);
723755
}
724756
fb_resv = None;
725757
dmabuf = ct.tex.dmabuf();
@@ -731,12 +763,12 @@ impl MetalConnector {
731763
// until the FB is no longer being scanned out, but if a notification pops up
732764
// then we must be able to disable direct scanout immediately.
733765
// https://gitlab.freedesktop.org/drm/amd/-/issues/3186
734-
return None;
766+
return Err(MetalDirectScanoutError::CrossDevice);
735767
}
736768
};
737769
let Some(dmabuf) = dmabuf else {
738770
// Shm buffers cannot be scanned out.
739-
return None;
771+
return Err(MetalDirectScanoutError::Shm);
740772
};
741773
let key = DirectScanoutKey {
742774
dma_buf_id: dmabuf.id,
@@ -751,10 +783,10 @@ impl MetalConnector {
751783
};
752784
if let Some(v) = self.scanout_impossible_cache.get(&key) {
753785
v.mark_used();
754-
return None;
786+
return Err(MetalDirectScanoutError::MarkedImpossible);
755787
}
756788
let res = self.prepare_direct_scanout2(plane, crtc, gamma_lut, cd, ct, dmabuf);
757-
if res.is_none() {
789+
if res.is_err() {
758790
self.scanout_impossible_cache.insert(key, ());
759791
}
760792
res.map(|(fb, cm_programming)| {
@@ -786,30 +818,33 @@ impl MetalConnector {
786818
cd: &Rc<ColorDescription>,
787819
ct: &CopyTexture,
788820
dmabuf: &Rc<DmaBuf>,
789-
) -> Option<(Rc<DrmFramebuffer>, MetalCmProgramming)> {
821+
) -> Result<(Rc<DrmFramebuffer>, MetalCmProgramming), MetalDirectScanoutError> {
790822
let fb = self.prepare_direct_scanout3(plane, dmabuf)?;
791-
let cm_programming = self.cm.find_programming(
792-
&self.master,
793-
plane,
794-
crtc,
795-
&ct.cd,
796-
cd,
797-
ct.render_intent,
798-
gamma_lut,
799-
self.cursor_enabled.get(),
800-
self.dev.use_plane_color_pipelines.get(),
801-
)?;
802-
Some((fb, cm_programming))
823+
let cm_programming = self
824+
.cm
825+
.find_programming(
826+
&self.master,
827+
plane,
828+
crtc,
829+
&ct.cd,
830+
cd,
831+
ct.render_intent,
832+
gamma_lut,
833+
self.cursor_enabled.get(),
834+
self.dev.use_plane_color_pipelines.get(),
835+
)
836+
.ok_or(MetalDirectScanoutError::NoCmProgramming)?;
837+
Ok((fb, cm_programming))
803838
}
804839

805840
fn prepare_direct_scanout3(
806841
&self,
807842
plane: &Rc<MetalPlane>,
808843
dmabuf: &Rc<DmaBuf>,
809-
) -> Option<Rc<DrmFramebuffer>> {
844+
) -> Result<Rc<DrmFramebuffer>, MetalDirectScanoutError> {
810845
let mut cache = self.scanout_buffers.borrow_mut();
811846
if let Some(buffer) = cache.get(&dmabuf.id) {
812-
return buffer.fb.clone();
847+
return buffer.fb.clone().ok_or(MetalDirectScanoutError::ImportFb);
813848
}
814849
let format = 'format: {
815850
if let Some(f) = plane.formats.get(&dmabuf.format.drm) {
@@ -821,10 +856,10 @@ impl MetalConnector {
821856
{
822857
break 'format f;
823858
}
824-
return None;
859+
return Err(MetalDirectScanoutError::UnsupportedFormat);
825860
};
826861
if !format.modifiers.contains(&dmabuf.modifier) {
827-
return None;
862+
return Err(MetalDirectScanoutError::UnsupportedModifier);
828863
}
829864
let fb = match self.dev.master.add_fb(dmabuf, Some(format.format)) {
830865
Ok(fb) => Some(Rc::new(fb)),
@@ -843,7 +878,7 @@ impl MetalConnector {
843878
fb: fb.clone(),
844879
},
845880
);
846-
fb
881+
fb.ok_or(MetalDirectScanoutError::ImportFb)
847882
}
848883

849884
fn prepare_present_fb(
@@ -861,8 +896,12 @@ impl MetalConnector {
861896
let try_direct_scanout = try_direct_scanout && self.dev.direct_scanout_enabled();
862897
let mut direct_scanout_data = None;
863898
if try_direct_scanout {
864-
direct_scanout_data =
865-
self.prepare_direct_scanout(&latched.pass, plane, crtc, blend_cd, gamma_lut, cd);
899+
direct_scanout_data = self
900+
.prepare_direct_scanout(&latched.pass, plane, crtc, blend_cd, gamma_lut, cd)
901+
.inspect_err(|e| {
902+
self.handle_direct_scanout_error(*e);
903+
})
904+
.ok();
866905
}
867906
let direct_scanout_active = direct_scanout_data.is_some();
868907
if self.direct_scanout_active.replace(direct_scanout_active) != direct_scanout_active {
@@ -996,4 +1035,13 @@ impl MetalConnector {
9961035
}
9971036
}
9981037
}
1038+
1039+
fn handle_direct_scanout_error(&self, e: MetalDirectScanoutError) -> bool {
1040+
let some = Some(e);
1041+
if self.last_direct_scanout_error.replace(some) == some {
1042+
return false;
1043+
}
1044+
log::debug!("Cannot perform direct scanout: {}", ErrorFmt(e));
1045+
true
1046+
}
9991047
}

src/backends/metal/video.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use crate::backends::metal::present::DEFAULT_POST_COMMIT_MARGIN;
3030
use crate::backends::metal::present::DEFAULT_PRE_COMMIT_MARGIN;
3131
use crate::backends::metal::present::DirectScanoutCache;
3232
use crate::backends::metal::present::DirectScanoutKey;
33+
use crate::backends::metal::present::MetalDirectScanoutError;
3334
use crate::backends::metal::present::POST_COMMIT_MARGIN_DELTA;
3435
use crate::backends::metal::present::PresentFbCore;
3536
use crate::backends::metal::transaction::DrmConnectorState;
@@ -647,6 +648,8 @@ pub struct MetalConnector {
647648

648649
pub gamma_lut: CloneCell<Option<Rc<BackendGammaLut>>>,
649650
pub cm: MetalCmConnector,
651+
652+
pub last_direct_scanout_error: Cell<Option<MetalDirectScanoutError>>,
650653
}
651654

652655
impl Debug for MetalConnector {
@@ -1211,6 +1214,7 @@ fn create_connector(
12111214
presentation_is_zero_copy: Cell::new(false),
12121215
gamma_lut: Default::default(),
12131216
cm: MetalCmConnector::new(&dev.cm),
1217+
last_direct_scanout_error: Default::default(),
12141218
});
12151219
let futures = ConnectorFutures {
12161220
_present: backend.state.eng.spawn2(

0 commit comments

Comments
 (0)