metal: block screencopies behind cross-device copies
This commit is contained in:
parent
cc56632c68
commit
fbf32f44ce
2 changed files with 59 additions and 14 deletions
|
|
@ -6,6 +6,7 @@ use {
|
||||||
transaction::{DrmConnectorState, DrmPlaneState},
|
transaction::{DrmConnectorState, DrmPlaneState},
|
||||||
video::{
|
video::{
|
||||||
MetalConnector, MetalCrtc, MetalHardwareCursorChange, MetalPlane, RenderBuffer,
|
MetalConnector, MetalCrtc, MetalHardwareCursorChange, MetalPlane, RenderBuffer,
|
||||||
|
RenderBufferCopy,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
cmm::cmm_description::ColorDescription,
|
cmm::cmm_description::ColorDescription,
|
||||||
|
|
@ -71,7 +72,7 @@ pub struct PresentFb {
|
||||||
fb: Rc<DrmFramebuffer>,
|
fb: Rc<DrmFramebuffer>,
|
||||||
tex: Rc<dyn GfxTexture>,
|
tex: Rc<dyn GfxTexture>,
|
||||||
direct_scanout_data: Option<DirectScanoutData>,
|
direct_scanout_data: Option<DirectScanoutData>,
|
||||||
sync_file: Option<SyncFile>,
|
copy: RenderBufferCopy,
|
||||||
pub locked: bool,
|
pub locked: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -103,6 +104,12 @@ pub const DEFAULT_PRE_COMMIT_MARGIN: u64 = 16_000_000; // 16ms
|
||||||
pub const DEFAULT_POST_COMMIT_MARGIN: u64 = 1_500_000; // 1.5ms;
|
pub const DEFAULT_POST_COMMIT_MARGIN: u64 = 1_500_000; // 1.5ms;
|
||||||
pub const POST_COMMIT_MARGIN_DELTA: u64 = 500_000; // 500us
|
pub const POST_COMMIT_MARGIN_DELTA: u64 = 500_000; // 500us
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
enum PresentFbWait {
|
||||||
|
Render,
|
||||||
|
Scanout,
|
||||||
|
}
|
||||||
|
|
||||||
impl MetalConnector {
|
impl MetalConnector {
|
||||||
pub fn schedule_present(&self) {
|
pub fn schedule_present(&self) {
|
||||||
self.present_trigger.trigger();
|
self.present_trigger.trigger();
|
||||||
|
|
@ -227,6 +234,13 @@ impl MetalConnector {
|
||||||
direct_scanout_id = fb.direct_scanout_data.as_ref().map(|d| d.dma_buf_id);
|
direct_scanout_id = fb.direct_scanout_data.as_ref().map(|d| d.dma_buf_id);
|
||||||
present_fb = Some(fb);
|
present_fb = Some(fb);
|
||||||
}
|
}
|
||||||
|
self.await_present_fb(present_fb.as_mut(), PresentFbWait::Render)
|
||||||
|
.await;
|
||||||
|
// perform_screencopies should return a sync file that we wait on before
|
||||||
|
// presentation since during screencopy the buffer layout might be mutated which
|
||||||
|
// could interfere with scanout. However, perform_screencopies just uses the
|
||||||
|
// current PresentFb if present_fb is None, potentially mutating the fb that is
|
||||||
|
// currently being scanned out, which would render such a wait absurd.
|
||||||
self.perform_screencopies(&present_fb, &node, &cd);
|
self.perform_screencopies(&present_fb, &node, &cd);
|
||||||
if let Some(sync_file) = self.cursor_sync_file.take()
|
if let Some(sync_file) = self.cursor_sync_file.take()
|
||||||
&& let Err(e) = self.state.ring.readable(&sync_file).await
|
&& let Err(e) = self.state.ring.readable(&sync_file).await
|
||||||
|
|
@ -236,7 +250,8 @@ impl MetalConnector {
|
||||||
ErrorFmt(e)
|
ErrorFmt(e)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
self.await_present_fb(present_fb.as_mut()).await;
|
self.await_present_fb(present_fb.as_mut(), PresentFbWait::Scanout)
|
||||||
|
.await;
|
||||||
let mut changed_planes = ArrayVec::new();
|
let mut changed_planes = ArrayVec::new();
|
||||||
let mut res = self.program_connector(
|
let mut res = self.program_connector(
|
||||||
version,
|
version,
|
||||||
|
|
@ -259,7 +274,8 @@ impl MetalConnector {
|
||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
present_fb = Some(fb);
|
present_fb = Some(fb);
|
||||||
self.await_present_fb(present_fb.as_mut()).await;
|
self.await_present_fb(present_fb.as_mut(), PresentFbWait::Scanout)
|
||||||
|
.await;
|
||||||
res = self.program_connector(
|
res = self.program_connector(
|
||||||
version,
|
version,
|
||||||
&crtc,
|
&crtc,
|
||||||
|
|
@ -330,17 +346,26 @@ impl MetalConnector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn await_present_fb(&self, new_fb: Option<&mut PresentFb>) {
|
async fn await_present_fb(&self, new_fb: Option<&mut PresentFb>, wait: PresentFbWait) {
|
||||||
|
use PresentFbWait as W;
|
||||||
let Some(fb) = new_fb else {
|
let Some(fb) = new_fb else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let Some(sync_file) = fb.sync_file.take() else {
|
let field = match wait {
|
||||||
|
W::Render => &mut fb.copy.render_block,
|
||||||
|
W::Scanout => &mut fb.copy.present_block,
|
||||||
|
};
|
||||||
|
let Some(sync_file) = field.take() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if let Err(e) = self.state.ring.readable(&sync_file).await {
|
if let Err(e) = self.state.ring.readable(&sync_file).await {
|
||||||
|
let name = match wait {
|
||||||
|
W::Render => "render",
|
||||||
|
W::Scanout => "scanout",
|
||||||
|
};
|
||||||
log::error!(
|
log::error!(
|
||||||
"Could not wait for primary sync file to complete: {}",
|
"Could not wait for primary {name} sync file to complete: {}",
|
||||||
ErrorFmt(e)
|
ErrorFmt(e),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -532,7 +557,7 @@ impl MetalConnector {
|
||||||
let swap_buffers = c.cursor_swap_buffer.is_some();
|
let swap_buffers = c.cursor_swap_buffer.is_some();
|
||||||
self.cursor_swap_buffer.set(swap_buffers);
|
self.cursor_swap_buffer.set(swap_buffers);
|
||||||
if let Some(sf) = c.cursor_swap_buffer.take() {
|
if let Some(sf) = c.cursor_swap_buffer.take() {
|
||||||
let sf = c.cursor_buffer.copy_to_dev(cd, sf)?;
|
let sf = c.cursor_buffer.copy_to_dev(cd, sf)?.present_block;
|
||||||
self.cursor_sync_file.set(sf);
|
self.cursor_sync_file.set(sf);
|
||||||
}
|
}
|
||||||
let mut cursor_changed = false;
|
let mut cursor_changed = false;
|
||||||
|
|
@ -831,7 +856,7 @@ impl MetalConnector {
|
||||||
};
|
};
|
||||||
log::debug!("{} direct scanout on {}", change, self.kernel_id());
|
log::debug!("{} direct scanout on {}", change, self.kernel_id());
|
||||||
}
|
}
|
||||||
let sync_file;
|
let copy;
|
||||||
let fb;
|
let fb;
|
||||||
let tex;
|
let tex;
|
||||||
match &direct_scanout_data {
|
match &direct_scanout_data {
|
||||||
|
|
@ -848,17 +873,18 @@ impl MetalConnector {
|
||||||
blend_cd,
|
blend_cd,
|
||||||
)
|
)
|
||||||
.map_err(MetalError::RenderFrame)?;
|
.map_err(MetalError::RenderFrame)?;
|
||||||
sync_file = buffer.copy_to_dev(cd, sf)?;
|
copy = buffer.copy_to_dev(cd, sf)?;
|
||||||
fb = buffer.drm.clone();
|
fb = buffer.drm.clone();
|
||||||
tex = buffer.render_tex.clone();
|
tex = buffer.render_tex.clone();
|
||||||
}
|
}
|
||||||
Some(dsd) => {
|
Some(dsd) => {
|
||||||
sync_file = match &dsd.acquire_sync {
|
let sf = match &dsd.acquire_sync {
|
||||||
AcquireSync::None => None,
|
AcquireSync::None => None,
|
||||||
AcquireSync::Implicit => None,
|
AcquireSync::Implicit => None,
|
||||||
AcquireSync::SyncFile { sync_file } => Some(sync_file.clone()),
|
AcquireSync::SyncFile { sync_file } => Some(sync_file.clone()),
|
||||||
AcquireSync::Unnecessary => None,
|
AcquireSync::Unnecessary => None,
|
||||||
};
|
};
|
||||||
|
copy = RenderBufferCopy::for_both(sf);
|
||||||
fb = dsd.fb.clone();
|
fb = dsd.fb.clone();
|
||||||
tex = dsd.tex.clone();
|
tex = dsd.tex.clone();
|
||||||
}
|
}
|
||||||
|
|
@ -867,7 +893,7 @@ impl MetalConnector {
|
||||||
fb,
|
fb,
|
||||||
tex,
|
tex,
|
||||||
direct_scanout_data,
|
direct_scanout_data,
|
||||||
sync_file,
|
copy,
|
||||||
locked: latched.locked,
|
locked: latched.locked,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2965,6 +2965,21 @@ pub struct RenderBuffer {
|
||||||
pub render_fb: Option<Rc<dyn GfxFramebuffer>>,
|
pub render_fb: Option<Rc<dyn GfxFramebuffer>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct RenderBufferCopy {
|
||||||
|
pub render_block: Option<SyncFile>,
|
||||||
|
pub present_block: Option<SyncFile>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderBufferCopy {
|
||||||
|
pub fn for_both(sf: Option<SyncFile>) -> Self {
|
||||||
|
Self {
|
||||||
|
render_block: sf.clone(),
|
||||||
|
present_block: sf,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl RenderBuffer {
|
impl RenderBuffer {
|
||||||
pub fn render_fb(&self) -> Rc<dyn GfxFramebuffer> {
|
pub fn render_fb(&self) -> Rc<dyn GfxFramebuffer> {
|
||||||
self.render_fb
|
self.render_fb
|
||||||
|
|
@ -2976,9 +2991,12 @@ impl RenderBuffer {
|
||||||
&self,
|
&self,
|
||||||
cd: &Rc<ColorDescription>,
|
cd: &Rc<ColorDescription>,
|
||||||
sync_file: Option<SyncFile>,
|
sync_file: Option<SyncFile>,
|
||||||
) -> Result<Option<SyncFile>, MetalError> {
|
) -> Result<RenderBufferCopy, MetalError> {
|
||||||
let Some(tex) = &self.dev_tex else {
|
let Some(tex) = &self.dev_tex else {
|
||||||
return Ok(sync_file);
|
return Ok(RenderBufferCopy {
|
||||||
|
render_block: None,
|
||||||
|
present_block: sync_file,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
self.dev_fb
|
self.dev_fb
|
||||||
.copy_texture(
|
.copy_texture(
|
||||||
|
|
@ -2994,6 +3012,7 @@ impl RenderBuffer {
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
.map_err(MetalError::CopyToOutput)
|
.map_err(MetalError::CopyToOutput)
|
||||||
|
.map(RenderBufferCopy::for_both)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn damage_full(&self) {
|
pub fn damage_full(&self) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue