metal: track per-framebuffer damage
This commit is contained in:
parent
f80ac20220
commit
07fb198eb4
17 changed files with 334 additions and 151 deletions
|
|
@ -11,6 +11,7 @@ use {
|
|||
create_render_pass, AcquireSync, BufferResv, GfxApiOpt, GfxRenderPass, GfxTexture,
|
||||
ReleaseSync, SyncFile,
|
||||
},
|
||||
rect::Region,
|
||||
theme::Color,
|
||||
time::Time,
|
||||
tracy::FrameName,
|
||||
|
|
@ -30,7 +31,8 @@ use {
|
|||
|
||||
struct Latched {
|
||||
pass: GfxRenderPass,
|
||||
damage: u64,
|
||||
damage_count: u64,
|
||||
damage: Region,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -172,24 +174,24 @@ impl MetalConnector {
|
|||
Some(b) => b,
|
||||
_ => return Ok(()),
|
||||
};
|
||||
let buffer = &buffers[self.next_buffer.get() % buffers.len()];
|
||||
|
||||
if self.has_damage.get() > 0 || self.cursor_damage.get() {
|
||||
node.schedule.commit_cursor();
|
||||
}
|
||||
self.latch_cursor(&node)?;
|
||||
let cursor_programming = self.compute_cursor_programming();
|
||||
let latched = self.latch(&node);
|
||||
let latched = self.latch(&node, buffer);
|
||||
node.latched(self.try_async_flip());
|
||||
|
||||
if cursor_programming.is_none() && latched.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let buffer = &buffers[self.next_buffer.get() % buffers.len()];
|
||||
let mut present_fb = None;
|
||||
let mut direct_scanout_id = None;
|
||||
if let Some(latched) = &latched {
|
||||
let fb = self.prepare_present_fb(buffer, &plane, &latched.pass, true)?;
|
||||
let fb = self.prepare_present_fb(buffer, &plane, latched, true)?;
|
||||
direct_scanout_id = fb.direct_scanout_data.as_ref().map(|d| d.dma_buf_id);
|
||||
present_fb = Some(fb);
|
||||
}
|
||||
|
|
@ -212,12 +214,8 @@ impl MetalConnector {
|
|||
);
|
||||
if res.is_err() {
|
||||
if let Some(dsd_id) = direct_scanout_id {
|
||||
let fb = self.prepare_present_fb(
|
||||
buffer,
|
||||
&plane,
|
||||
&latched.as_ref().unwrap().pass,
|
||||
false,
|
||||
)?;
|
||||
let fb =
|
||||
self.prepare_present_fb(buffer, &plane, latched.as_ref().unwrap(), false)?;
|
||||
present_fb = Some(fb);
|
||||
self.await_present_fb(present_fb.as_mut()).await;
|
||||
res = self.program_connector(
|
||||
|
|
@ -241,7 +239,14 @@ impl MetalConnector {
|
|||
}
|
||||
}
|
||||
}
|
||||
let reset_damage = || {
|
||||
for buffer in &*buffers {
|
||||
buffer.damage_queue.clear();
|
||||
}
|
||||
buffers[0].damage_full();
|
||||
};
|
||||
if let Err(e) = res {
|
||||
reset_damage();
|
||||
if let MetalError::Commit(DrmError::Atomic(OsError(c::EACCES))) = e {
|
||||
log::debug!("Could not perform atomic commit, likely because we're no longer the DRM master");
|
||||
return Ok(());
|
||||
|
|
@ -265,7 +270,10 @@ impl MetalConnector {
|
|||
self.presentation_is_zero_copy
|
||||
.set(fb.direct_scanout_data.is_some());
|
||||
if fb.direct_scanout_data.is_none() {
|
||||
buffer.damage_queue.clear();
|
||||
self.next_buffer.fetch_add(1);
|
||||
} else {
|
||||
reset_damage();
|
||||
}
|
||||
self.next_framebuffer.set(Some(fb));
|
||||
}
|
||||
|
|
@ -275,7 +283,7 @@ impl MetalConnector {
|
|||
}
|
||||
self.can_present.set(false);
|
||||
if let Some(latched) = latched {
|
||||
self.has_damage.fetch_sub(latched.damage);
|
||||
self.has_damage.fetch_sub(latched.damage_count);
|
||||
}
|
||||
self.cursor_changed.set(false);
|
||||
Ok(())
|
||||
|
|
@ -487,12 +495,19 @@ impl MetalConnector {
|
|||
Some(programming)
|
||||
}
|
||||
|
||||
fn latch(&self, node: &Rc<OutputNode>) -> Option<Latched> {
|
||||
let damage = self.has_damage.get();
|
||||
if damage == 0 {
|
||||
fn latch(&self, node: &Rc<OutputNode>, buffer: &RenderBuffer) -> Option<Latched> {
|
||||
let damage_count = self.has_damage.get();
|
||||
if damage_count == 0 {
|
||||
return None;
|
||||
}
|
||||
node.global.connector.damaged.set(false);
|
||||
let damage = {
|
||||
node.global.add_visualizer_damage();
|
||||
let damage = &mut *node.global.connector.damage.borrow_mut();
|
||||
buffer.damage_queue.damage(damage);
|
||||
damage.clear();
|
||||
buffer.damage_queue.get()
|
||||
};
|
||||
let render_hw_cursor = !self.cursor_enabled.get();
|
||||
let mode = node.global.mode.get();
|
||||
let pass = create_render_pass(
|
||||
|
|
@ -508,7 +523,11 @@ impl MetalConnector {
|
|||
node.global.persistent.transform.get(),
|
||||
Some(&self.state.damage_visualizer),
|
||||
);
|
||||
Some(Latched { pass, damage })
|
||||
Some(Latched {
|
||||
pass,
|
||||
damage_count,
|
||||
damage,
|
||||
})
|
||||
}
|
||||
|
||||
fn trim_scanout_cache(&self) {
|
||||
|
|
@ -692,7 +711,7 @@ impl MetalConnector {
|
|||
&self,
|
||||
buffer: &RenderBuffer,
|
||||
plane: &Rc<MetalPlane>,
|
||||
pass: &GfxRenderPass,
|
||||
latched: &Latched,
|
||||
try_direct_scanout: bool,
|
||||
) -> Result<PresentFb, MetalError> {
|
||||
self.trim_scanout_cache();
|
||||
|
|
@ -706,7 +725,7 @@ impl MetalConnector {
|
|||
&& self.dev.is_render_device();
|
||||
let mut direct_scanout_data = None;
|
||||
if try_direct_scanout {
|
||||
direct_scanout_data = self.prepare_direct_scanout(&pass, plane);
|
||||
direct_scanout_data = self.prepare_direct_scanout(&latched.pass, plane);
|
||||
}
|
||||
let direct_scanout_active = direct_scanout_data.is_some();
|
||||
if self.direct_scanout_active.replace(direct_scanout_active) != direct_scanout_active {
|
||||
|
|
@ -723,7 +742,12 @@ impl MetalConnector {
|
|||
None => {
|
||||
let sf = buffer
|
||||
.render_fb()
|
||||
.perform_render_pass(AcquireSync::Unnecessary, ReleaseSync::Explicit, pass)
|
||||
.perform_render_pass(
|
||||
AcquireSync::Unnecessary,
|
||||
ReleaseSync::Explicit,
|
||||
&latched.pass,
|
||||
&latched.damage,
|
||||
)
|
||||
.map_err(MetalError::RenderFrame)?;
|
||||
sync_file = buffer.copy_to_dev(sf)?;
|
||||
fb = buffer.drm.clone();
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ use {
|
|||
wl_output::OutputId,
|
||||
wp_presentation_feedback::{KIND_HW_COMPLETION, KIND_VSYNC, KIND_ZERO_COPY},
|
||||
},
|
||||
rect::{DamageQueue, Rect},
|
||||
state::State,
|
||||
tree::OutputNode,
|
||||
udev::UdevDevice,
|
||||
|
|
@ -2600,12 +2601,26 @@ impl MetalBackend {
|
|||
ctx: &MetalRenderContext,
|
||||
cursor: bool,
|
||||
) -> Result<[RenderBuffer; N], MetalError> {
|
||||
let create =
|
||||
|| self.create_scanout_buffer(dev, format, plane_modifiers, width, height, ctx, cursor);
|
||||
let mut damage_queue = ArrayVec::from(DamageQueue::new::<N>());
|
||||
let mut create = || {
|
||||
self.create_scanout_buffer(
|
||||
dev,
|
||||
format,
|
||||
plane_modifiers,
|
||||
width,
|
||||
height,
|
||||
ctx,
|
||||
cursor,
|
||||
damage_queue.pop().unwrap(),
|
||||
)
|
||||
};
|
||||
let mut array = ArrayVec::<_, N>::new();
|
||||
for _ in 0..N {
|
||||
array.push(create()?);
|
||||
}
|
||||
if let Some(buffer) = array.first() {
|
||||
buffer.damage_full();
|
||||
}
|
||||
Ok(array.into_inner().unwrap())
|
||||
}
|
||||
|
||||
|
|
@ -2618,6 +2633,7 @@ impl MetalBackend {
|
|||
height: i32,
|
||||
render_ctx: &MetalRenderContext,
|
||||
cursor: bool,
|
||||
damage_queue: DamageQueue,
|
||||
) -> Result<RenderBuffer, MetalError> {
|
||||
let ctx = dev.ctx.get();
|
||||
let dev_gfx_formats = ctx.gfx.formats();
|
||||
|
|
@ -2746,7 +2762,8 @@ impl MetalBackend {
|
|||
};
|
||||
Ok(RenderBuffer {
|
||||
drm: drm_fb,
|
||||
_dev_bo: dev_bo,
|
||||
damage_queue,
|
||||
dev_bo,
|
||||
_render_bo: render_bo,
|
||||
dev_fb,
|
||||
dev_tex,
|
||||
|
|
@ -2970,7 +2987,8 @@ impl MetalBackend {
|
|||
#[derive(Debug)]
|
||||
pub struct RenderBuffer {
|
||||
pub drm: Rc<DrmFramebuffer>,
|
||||
pub _dev_bo: GbmBo,
|
||||
pub damage_queue: DamageQueue,
|
||||
pub dev_bo: GbmBo,
|
||||
pub _render_bo: Option<GbmBo>,
|
||||
// ctx = dev
|
||||
// buffer location = dev
|
||||
|
|
@ -3010,6 +3028,12 @@ impl RenderBuffer {
|
|||
)
|
||||
.map_err(MetalError::CopyToOutput)
|
||||
}
|
||||
|
||||
pub fn damage_full(&self) {
|
||||
let dmabuf = self.dev_bo.dmabuf();
|
||||
let rect = Rect::new_sized_unchecked(0, 0, dmabuf.width, dmabuf.height);
|
||||
self.damage_queue.damage(&[rect]);
|
||||
}
|
||||
}
|
||||
|
||||
fn modes_equal(a: &DrmModeInfo, b: &DrmModeInfo) -> bool {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue