1
0
Fork 0
forked from wry/wry

metal: track per-framebuffer damage

This commit is contained in:
Julian Orth 2025-02-18 16:43:30 +01:00
parent f80ac20220
commit 07fb198eb4
17 changed files with 334 additions and 151 deletions

View file

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

View file

@ -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 {