Merge pull request #764 from mahkoh/jorth/surface-state-auto-cleanup
Use RAII to clean up some surface states
This commit is contained in:
commit
66efc946b6
9 changed files with 203 additions and 154 deletions
|
|
@ -48,6 +48,19 @@ pub struct DmabufBufferParams {
|
||||||
tex_impossible: bool,
|
tex_impossible: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct AttachedBuffer {
|
||||||
|
pub send_release: bool,
|
||||||
|
pub buf: Rc<WlBuffer>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for AttachedBuffer {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if self.send_release && !self.buf.destroyed() {
|
||||||
|
self.buf.send_release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct WlBuffer {
|
pub struct WlBuffer {
|
||||||
pub id: WlBufferId,
|
pub id: WlBufferId,
|
||||||
destroyed: Cell<bool>,
|
destroyed: Cell<bool>,
|
||||||
|
|
@ -507,7 +520,7 @@ impl WlBuffer {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_release(&self) {
|
fn send_release(&self) {
|
||||||
self.client.event(Release { self_id: self.id })
|
self.client.event(Release { self_id: self.id })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ use {
|
||||||
},
|
},
|
||||||
ifs::{
|
ifs::{
|
||||||
color_management::wp_color_management_surface_feedback_v1::WpColorManagementSurfaceFeedbackV1,
|
color_management::wp_color_management_surface_feedback_v1::WpColorManagementSurfaceFeedbackV1,
|
||||||
wl_buffer::WlBuffer,
|
wl_buffer::AttachedBuffer,
|
||||||
wl_callback::WlCallback,
|
wl_callback::WlCallback,
|
||||||
wl_seat::{
|
wl_seat::{
|
||||||
Dnd, NodeSeatState, SeatId, WlSeatGlobal,
|
Dnd, NodeSeatState, SeatId, WlSeatGlobal,
|
||||||
|
|
@ -67,7 +67,7 @@ use {
|
||||||
zwlr_layer_surface_v1::{PendingLayerSurfaceData, ZwlrLayerSurfaceV1Error},
|
zwlr_layer_surface_v1::{PendingLayerSurfaceData, ZwlrLayerSurfaceV1Error},
|
||||||
},
|
},
|
||||||
wp_content_type_v1::ContentType,
|
wp_content_type_v1::ContentType,
|
||||||
wp_presentation_feedback::{VRR_REFRESH_SINCE, WpPresentationFeedback},
|
wp_presentation_feedback::PresentationFeedback,
|
||||||
zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1,
|
zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1,
|
||||||
},
|
},
|
||||||
io_uring::IoUringError,
|
io_uring::IoUringError,
|
||||||
|
|
@ -76,6 +76,7 @@ use {
|
||||||
object::{Object, Version},
|
object::{Object, Version},
|
||||||
rect::{DamageQueue, Rect, Region},
|
rect::{DamageQueue, Rect, Region},
|
||||||
renderer::Renderer,
|
renderer::Renderer,
|
||||||
|
state::State,
|
||||||
tree::{
|
tree::{
|
||||||
BeforeLatchListener, BeforeLatchResult, ContainerNode, FindTreeResult, FoundNode,
|
BeforeLatchListener, BeforeLatchResult, ContainerNode, FindTreeResult, FoundNode,
|
||||||
LatchListener, Node, NodeId, NodeLayerLink, NodeLocation, NodeVisitor, NodeVisitorBase,
|
LatchListener, Node, NodeId, NodeLayerLink, NodeLocation, NodeVisitor, NodeVisitorBase,
|
||||||
|
|
@ -99,6 +100,7 @@ use {
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
isnt::std_1::{primitive::IsntSliceExt, vec::IsntVecExt},
|
isnt::std_1::{primitive::IsntSliceExt, vec::IsntVecExt},
|
||||||
|
smallvec::SmallVec,
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
collections::hash_map::{Entry, OccupiedEntry},
|
collections::hash_map::{Entry, OccupiedEntry},
|
||||||
|
|
@ -211,58 +213,27 @@ impl NodeVisitorBase for SurfaceSendPreferredColorDescription {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SurfaceBufferExplicitRelease {
|
|
||||||
sync_obj: Rc<SyncObj>,
|
|
||||||
point: SyncObjPoint,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SurfaceBuffer {
|
pub struct SurfaceBuffer {
|
||||||
pub buffer: Rc<WlBuffer>,
|
pub buffer: AttachedBuffer,
|
||||||
sync_files: SmallMap<BufferResvUser, SyncFile, 1>,
|
sync_files: SmallMap<BufferResvUser, SyncFile, 1>,
|
||||||
pub release_sync: ReleaseSync,
|
pub release_sync: ReleaseSync,
|
||||||
release: Option<SurfaceBufferExplicitRelease>,
|
release: Option<SyncObjRelease>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for SurfaceBuffer {
|
impl Drop for SurfaceBuffer {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let sync_files = self.sync_files.take();
|
let sync_files = self.sync_files.take();
|
||||||
if let Some(release) = &self.release {
|
if let Some(release) = &mut self.release {
|
||||||
let Some(ctx) = self.buffer.client.state.render_ctx.get() else {
|
release.signal(Some(&sync_files));
|
||||||
log::error!("Cannot signal release point because there is no render context");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let Some(ctx) = ctx.sync_obj_ctx() else {
|
|
||||||
log::error!("Cannot signal release point because there is no syncobj context");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
if sync_files.is_not_empty() {
|
|
||||||
let res = ctx.import_sync_files(
|
|
||||||
&release.sync_obj,
|
|
||||||
release.point,
|
|
||||||
sync_files.iter().map(|f| &f.1),
|
|
||||||
);
|
|
||||||
match res {
|
|
||||||
Ok(_) => return,
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Could not import sync files into sync obj: {}", ErrorFmt(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Err(e) = ctx.signal(&release.sync_obj, release.point) {
|
|
||||||
log::error!("Could not signal release point: {}", ErrorFmt(e));
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Some(dmabuf) = &self.buffer.client_dmabuf {
|
if let Some(dmabuf) = &self.buffer.buf.client_dmabuf {
|
||||||
for (_, sync_file) in &sync_files {
|
for (_, sync_file) in &sync_files {
|
||||||
if let Err(e) = dmabuf.import_sync_file(DMA_BUF_SYNC_READ, sync_file) {
|
if let Err(e) = dmabuf.import_sync_file(DMA_BUF_SYNC_READ, sync_file) {
|
||||||
log::error!("Could not import sync file: {}", ErrorFmt(e));
|
log::error!("Could not import sync file: {}", ErrorFmt(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !self.buffer.destroyed() {
|
|
||||||
self.buffer.send_release();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -310,9 +281,9 @@ pub struct WlSurface {
|
||||||
pub buf_y: NumCell<i32>,
|
pub buf_y: NumCell<i32>,
|
||||||
pub children: RefCell<Option<Box<ParentData>>>,
|
pub children: RefCell<Option<Box<ParentData>>>,
|
||||||
ext: CloneCell<Rc<dyn SurfaceExt>>,
|
ext: CloneCell<Rc<dyn SurfaceExt>>,
|
||||||
frame_requests: RefCell<Vec<Rc<WlCallback>>>,
|
frame_requests: RefCell<Vec<FrameRequest>>,
|
||||||
presentation_feedback: RefCell<Vec<Rc<WpPresentationFeedback>>>,
|
presentation_feedback: RefCell<Vec<PresentationFeedback>>,
|
||||||
latched_presentation_feedback: RefCell<Vec<Rc<WpPresentationFeedback>>>,
|
latched_presentation_feedback: RefCell<Vec<PresentationFeedback>>,
|
||||||
seat_state: NodeSeatState,
|
seat_state: NodeSeatState,
|
||||||
toplevel: CloneCell<Option<Rc<dyn ToplevelNode>>>,
|
toplevel: CloneCell<Option<Rc<dyn ToplevelNode>>>,
|
||||||
cursors: SmallMap<CursorUserId, Rc<CursorSurface>, 1>,
|
cursors: SmallMap<CursorUserId, Rc<CursorSurface>, 1>,
|
||||||
|
|
@ -461,15 +432,15 @@ impl SurfaceExt for NoneSurfaceExt {
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct PendingState {
|
struct PendingState {
|
||||||
buffer: Option<Option<Rc<WlBuffer>>>,
|
buffer: Option<Option<AttachedBuffer>>,
|
||||||
offset: (i32, i32),
|
offset: (i32, i32),
|
||||||
opaque_region: Option<Option<Rc<Region>>>,
|
opaque_region: Option<Option<Rc<Region>>>,
|
||||||
input_region: Option<Option<Rc<Region>>>,
|
input_region: Option<Option<Rc<Region>>>,
|
||||||
frame_request: Vec<Rc<WlCallback>>,
|
frame_request: Vec<FrameRequest>,
|
||||||
damage_full: bool,
|
damage_full: bool,
|
||||||
buffer_damage: Vec<Rect>,
|
buffer_damage: Vec<Rect>,
|
||||||
surface_damage: Vec<Rect>,
|
surface_damage: Vec<Rect>,
|
||||||
presentation_feedback: Vec<Rc<WpPresentationFeedback>>,
|
presentation_feedback: Vec<PresentationFeedback>,
|
||||||
src_rect: Option<Option<[Fixed; 4]>>,
|
src_rect: Option<Option<[Fixed; 4]>>,
|
||||||
dst_size: Option<Option<(i32, i32)>>,
|
dst_size: Option<Option<(i32, i32)>>,
|
||||||
scale: Option<i32>,
|
scale: Option<i32>,
|
||||||
|
|
@ -481,7 +452,7 @@ struct PendingState {
|
||||||
layer_surface: Option<Box<PendingLayerSurfaceData>>,
|
layer_surface: Option<Box<PendingLayerSurfaceData>>,
|
||||||
subsurfaces: AHashMap<SubsurfaceId, AttachedSubsurfaceState>,
|
subsurfaces: AHashMap<SubsurfaceId, AttachedSubsurfaceState>,
|
||||||
acquire_point: Option<(Rc<SyncObj>, SyncObjPoint)>,
|
acquire_point: Option<(Rc<SyncObj>, SyncObjPoint)>,
|
||||||
release_point: Option<(Rc<SyncObj>, SyncObjPoint)>,
|
release_point: Option<SyncObjRelease>,
|
||||||
alpha_multiplier: Option<Option<f32>>,
|
alpha_multiplier: Option<Option<f32>>,
|
||||||
explicit_sync: bool,
|
explicit_sync: bool,
|
||||||
fifo_barrier_set: bool,
|
fifo_barrier_set: bool,
|
||||||
|
|
@ -502,19 +473,7 @@ impl PendingState {
|
||||||
fn merge(&mut self, next: &mut Self, client: &Rc<Client>) {
|
fn merge(&mut self, next: &mut Self, client: &Rc<Client>) {
|
||||||
// discard state
|
// discard state
|
||||||
|
|
||||||
if next.buffer.is_some() {
|
self.presentation_feedback.clear();
|
||||||
if let Some((sync_obj, point)) = self.release_point.take() {
|
|
||||||
client.state.signal_point(&sync_obj, point);
|
|
||||||
} else if let Some(Some(prev)) = self.buffer.take() {
|
|
||||||
if !prev.destroyed() {
|
|
||||||
prev.send_release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for fb in self.presentation_feedback.drain(..) {
|
|
||||||
fb.send_discarded();
|
|
||||||
let _ = client.remove_obj(&*fb);
|
|
||||||
}
|
|
||||||
|
|
||||||
// overwrite state
|
// overwrite state
|
||||||
|
|
||||||
|
|
@ -799,11 +758,8 @@ impl WlSurface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_presentation_feedback(&self, fb: &Rc<WpPresentationFeedback>) {
|
pub fn add_presentation_feedback(&self, fb: PresentationFeedback) {
|
||||||
self.pending
|
self.pending.borrow_mut().presentation_feedback.push(fb);
|
||||||
.borrow_mut()
|
|
||||||
.presentation_feedback
|
|
||||||
.push(fb.clone());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_cursor(&self) -> bool {
|
pub fn is_cursor(&self) -> bool {
|
||||||
|
|
@ -1080,7 +1036,10 @@ impl WlSurfaceRequestHandler for WlSurface {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
pending.buffer = Some(buf);
|
pending.buffer = Some(buf.map(|buf| AttachedBuffer {
|
||||||
|
send_release: false,
|
||||||
|
buf,
|
||||||
|
}));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1094,7 +1053,10 @@ impl WlSurfaceRequestHandler for WlSurface {
|
||||||
let cb = Rc::new(WlCallback::new(req.callback, &self.client));
|
let cb = Rc::new(WlCallback::new(req.callback, &self.client));
|
||||||
track!(self.client, cb);
|
track!(self.client, cb);
|
||||||
self.client.add_client_obj(&cb)?;
|
self.client.add_client_obj(&cb)?;
|
||||||
self.pending.borrow_mut().frame_request.push(cb);
|
self.pending
|
||||||
|
.borrow_mut()
|
||||||
|
.frame_request
|
||||||
|
.push(FrameRequest { now: 0, cb });
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1125,6 +1087,14 @@ impl WlSurfaceRequestHandler for WlSurface {
|
||||||
fn commit(&self, _req: Commit, slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn commit(&self, _req: Commit, slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
let ext = self.ext.get();
|
let ext = self.ext.get();
|
||||||
let pending = &mut *self.pending.borrow_mut();
|
let pending = &mut *self.pending.borrow_mut();
|
||||||
|
if let Some(Some(buffer)) = &mut pending.buffer
|
||||||
|
&& pending.release_point.is_none()
|
||||||
|
{
|
||||||
|
buffer.send_release = true;
|
||||||
|
}
|
||||||
|
if let Some(release) = &mut pending.release_point {
|
||||||
|
release.committed = true;
|
||||||
|
}
|
||||||
self.verify_explicit_sync(pending)?;
|
self.verify_explicit_sync(pending)?;
|
||||||
if ext.commit_requested(pending) == CommitAction::ContinueCommit {
|
if ext.commit_requested(pending) == CommitAction::ContinueCommit {
|
||||||
self.commit_timeline.commit(slf, pending)?;
|
self.commit_timeline.commit(slf, pending)?;
|
||||||
|
|
@ -1230,29 +1200,25 @@ impl WlSurface {
|
||||||
if let Some(buffer_change) = pending.buffer.take() {
|
if let Some(buffer_change) = pending.buffer.take() {
|
||||||
buffer_changed = true;
|
buffer_changed = true;
|
||||||
if let Some(buffer) = self.buffer.take() {
|
if let Some(buffer) = self.buffer.take() {
|
||||||
old_raw_size = Some(buffer.buffer.rect);
|
old_raw_size = Some(buffer.buffer.buf.rect);
|
||||||
}
|
}
|
||||||
if let Some(buffer) = buffer_change {
|
if let Some(buffer) = buffer_change {
|
||||||
if buffer.is_shm() {
|
if buffer.buf.is_shm() {
|
||||||
self.shm_textures.flip();
|
self.shm_textures.flip();
|
||||||
self.shm_textures.front().damage.clear();
|
self.shm_textures.front().damage.clear();
|
||||||
} else {
|
} else {
|
||||||
self.reset_shm_textures();
|
self.reset_shm_textures();
|
||||||
}
|
}
|
||||||
buffer.update_texture_or_log(self, false);
|
buffer.buf.update_texture_or_log(self, false);
|
||||||
let release_sync = match pending.explicit_sync {
|
let release_sync = match pending.explicit_sync {
|
||||||
false => ReleaseSync::Implicit,
|
false => ReleaseSync::Implicit,
|
||||||
true => ReleaseSync::Explicit,
|
true => ReleaseSync::Explicit,
|
||||||
};
|
};
|
||||||
let release = pending
|
|
||||||
.release_point
|
|
||||||
.take()
|
|
||||||
.map(|(sync_obj, point)| SurfaceBufferExplicitRelease { sync_obj, point });
|
|
||||||
let surface_buffer = SurfaceBuffer {
|
let surface_buffer = SurfaceBuffer {
|
||||||
buffer,
|
buffer,
|
||||||
sync_files: Default::default(),
|
sync_files: Default::default(),
|
||||||
release_sync,
|
release_sync,
|
||||||
release,
|
release: pending.release_point.take(),
|
||||||
};
|
};
|
||||||
self.buffer.set(Some(Rc::new(surface_buffer)));
|
self.buffer.set(Some(Rc::new(surface_buffer)));
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1307,11 +1273,10 @@ impl WlSurface {
|
||||||
new_size = Some(size);
|
new_size = Some(size);
|
||||||
}
|
}
|
||||||
if let Some(buffer) = self.buffer.get() {
|
if let Some(buffer) = self.buffer.get() {
|
||||||
|
let buf = &buffer.buffer.buf;
|
||||||
if new_size.is_none() {
|
if new_size.is_none() {
|
||||||
let (mut width, mut height) = self
|
let (mut width, mut height) =
|
||||||
.buffer_transform
|
self.buffer_transform.get().maybe_swap(buf.rect.size());
|
||||||
.get()
|
|
||||||
.maybe_swap(buffer.buffer.rect.size());
|
|
||||||
let scale = self.buffer_scale.get();
|
let scale = self.buffer_scale.get();
|
||||||
if scale != 1 {
|
if scale != 1 {
|
||||||
width = (width + scale - 1) / scale;
|
width = (width + scale - 1) / scale;
|
||||||
|
|
@ -1319,14 +1284,12 @@ impl WlSurface {
|
||||||
}
|
}
|
||||||
new_size = Some((width, height));
|
new_size = Some((width, height));
|
||||||
}
|
}
|
||||||
if transform_changed || Some(buffer.buffer.rect) != old_raw_size {
|
if transform_changed || Some(buf.rect) != old_raw_size {
|
||||||
let (x1, y1, x2, y2) = if self.src_rect.is_none() {
|
let (x1, y1, x2, y2) = if self.src_rect.is_none() {
|
||||||
(0.0, 0.0, 1.0, 1.0)
|
(0.0, 0.0, 1.0, 1.0)
|
||||||
} else {
|
} else {
|
||||||
let (width, height) = self
|
let (width, height) =
|
||||||
.buffer_transform
|
self.buffer_transform.get().maybe_swap(buf.rect.size());
|
||||||
.get()
|
|
||||||
.maybe_swap(buffer.buffer.rect.size());
|
|
||||||
let width = width as f32;
|
let width = width as f32;
|
||||||
let height = height as f32;
|
let height = height as f32;
|
||||||
let x1 = buffer_points.x1 / width;
|
let x1 = buffer_points.x1 / width;
|
||||||
|
|
@ -1345,7 +1308,7 @@ impl WlSurface {
|
||||||
y2,
|
y2,
|
||||||
buffer_transform: self.buffer_transform.get(),
|
buffer_transform: self.buffer_transform.get(),
|
||||||
};
|
};
|
||||||
let (buffer_width, buffer_height) = buffer.buffer.rect.size();
|
let (buffer_width, buffer_height) = buf.rect.size();
|
||||||
let (mut dst_width, mut dst_height) = new_size.unwrap_or_default();
|
let (mut dst_width, mut dst_height) = new_size.unwrap_or_default();
|
||||||
client_wire_scale_to_logical!(self.client, dst_width, dst_height);
|
client_wire_scale_to_logical!(self.client, dst_width, dst_height);
|
||||||
let damage_matrix = DamageMatrix::new(
|
let damage_matrix = DamageMatrix::new(
|
||||||
|
|
@ -1379,10 +1342,7 @@ impl WlSurface {
|
||||||
}
|
}
|
||||||
let has_presentation_feedback = {
|
let has_presentation_feedback = {
|
||||||
let mut fbs = self.presentation_feedback.borrow_mut();
|
let mut fbs = self.presentation_feedback.borrow_mut();
|
||||||
for fb in fbs.drain(..) {
|
fbs.clear();
|
||||||
fb.send_discarded();
|
|
||||||
let _ = self.client.remove_obj(&*fb);
|
|
||||||
}
|
|
||||||
mem::swap(fbs.deref_mut(), &mut pending.presentation_feedback);
|
mem::swap(fbs.deref_mut(), &mut pending.presentation_feedback);
|
||||||
fbs.is_not_empty()
|
fbs.is_not_empty()
|
||||||
};
|
};
|
||||||
|
|
@ -1519,8 +1479,11 @@ impl WlSurface {
|
||||||
let matrix = self.damage_matrix.get();
|
let matrix = self.damage_matrix.get();
|
||||||
if let Some(buffer) = self.buffer.get() {
|
if let Some(buffer) = self.buffer.get() {
|
||||||
for damage in &pending.buffer_damage {
|
for damage in &pending.buffer_damage {
|
||||||
let mut damage =
|
let mut damage = matrix.apply(
|
||||||
matrix.apply(pos.x1(), pos.y1(), damage.intersect(buffer.buffer.rect));
|
pos.x1(),
|
||||||
|
pos.y1(),
|
||||||
|
damage.intersect(buffer.buffer.buf.rect),
|
||||||
|
);
|
||||||
if let Some(bounds) = bounds {
|
if let Some(bounds) = bounds {
|
||||||
damage = damage.intersect(bounds);
|
damage = damage.intersect(bounds);
|
||||||
}
|
}
|
||||||
|
|
@ -2197,10 +2160,10 @@ efrom!(WlSurfaceError, CommitTimelineError);
|
||||||
impl VblankListener for WlSurface {
|
impl VblankListener for WlSurface {
|
||||||
fn after_vblank(self: Rc<Self>) {
|
fn after_vblank(self: Rc<Self>) {
|
||||||
if self.visible.get() {
|
if self.visible.get() {
|
||||||
let now = self.client.state.now_msec();
|
let now = self.client.state.now_msec() as u32;
|
||||||
for fr in self.frame_requests.borrow_mut().drain(..) {
|
for mut fr in self.frame_requests.borrow_mut().drain(..) {
|
||||||
fr.send_done(now as _);
|
fr.now = now;
|
||||||
let _ = fr.client.remove_obj(&*fr);
|
drop(fr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.clear_fifo_on_vblank.take() {
|
if self.clear_fifo_on_vblank.take() {
|
||||||
|
|
@ -2221,10 +2184,7 @@ impl LatchListener for WlSurface {
|
||||||
if self.visible.get() {
|
if self.visible.get() {
|
||||||
if self.latched_commit_version.get() < self.commit_version.get() {
|
if self.latched_commit_version.get() < self.commit_version.get() {
|
||||||
let latched = &mut *self.latched_presentation_feedback.borrow_mut();
|
let latched = &mut *self.latched_presentation_feedback.borrow_mut();
|
||||||
for pf in latched.drain(..) {
|
latched.clear();
|
||||||
pf.send_discarded();
|
|
||||||
let _ = pf.client.remove_obj(&*pf);
|
|
||||||
}
|
|
||||||
latched.append(&mut self.presentation_feedback.borrow_mut());
|
latched.append(&mut self.presentation_feedback.borrow_mut());
|
||||||
if latched.is_not_empty() {
|
if latched.is_not_empty() {
|
||||||
self.presentation_listener
|
self.presentation_listener
|
||||||
|
|
@ -2259,18 +2219,66 @@ impl PresentationListener for WlSurface {
|
||||||
let bindings = output.global.bindings.borrow();
|
let bindings = output.global.bindings.borrow();
|
||||||
let bindings = bindings.get(&self.client.id);
|
let bindings = bindings.get(&self.client.id);
|
||||||
for pf in self.latched_presentation_feedback.borrow_mut().drain(..) {
|
for pf in self.latched_presentation_feedback.borrow_mut().drain(..) {
|
||||||
if let Some(bindings) = bindings {
|
pf.presented(bindings, tv_sec, tv_nsec, refresh, seq, flags, vrr);
|
||||||
for binding in bindings.values() {
|
|
||||||
pf.send_sync_output(binding);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mut refresh = refresh;
|
|
||||||
if vrr && pf.version < VRR_REFRESH_SINCE {
|
|
||||||
refresh = 0;
|
|
||||||
}
|
|
||||||
pf.send_presented(tv_sec, tv_nsec, refresh, seq, flags);
|
|
||||||
let _ = pf.client.remove_obj(&*pf);
|
|
||||||
}
|
}
|
||||||
self.presentation_listener.detach();
|
self.presentation_listener.detach();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct FrameRequest {
|
||||||
|
now: u32,
|
||||||
|
cb: Rc<WlCallback>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for FrameRequest {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.cb.send_done(self.now);
|
||||||
|
let _ = self.cb.client.remove_obj(&*self.cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SyncObjRelease {
|
||||||
|
state: Rc<State>,
|
||||||
|
committed: bool,
|
||||||
|
syncobj: Option<Rc<SyncObj>>,
|
||||||
|
point: SyncObjPoint,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SyncObjRelease {
|
||||||
|
fn signal(&mut self, sync_files: Option<&SmallVec<[(BufferResvUser, SyncFile); 1]>>) {
|
||||||
|
if !self.committed {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let Some(sync_obj) = self.syncobj.take() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(ctx) = self.state.render_ctx.get() else {
|
||||||
|
log::error!("Cannot signal release point because there is no render context");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(ctx) = ctx.sync_obj_ctx() else {
|
||||||
|
log::error!("Cannot signal release point because there is no syncobj context");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if let Some(sync_files) = sync_files
|
||||||
|
&& sync_files.is_not_empty()
|
||||||
|
{
|
||||||
|
let res = ctx.import_sync_files(&sync_obj, self.point, sync_files.iter().map(|f| &f.1));
|
||||||
|
match res {
|
||||||
|
Ok(_) => return,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Could not import sync files into sync obj: {}", ErrorFmt(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Err(e) = ctx.signal(&sync_obj, self.point) {
|
||||||
|
log::error!("Could not signal release point: {}", ErrorFmt(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for SyncObjRelease {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.signal(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -598,6 +598,7 @@ fn schedule_async_upload(
|
||||||
let Some(Some(buf)) = &pending.buffer else {
|
let Some(Some(buf)) = &pending.buffer else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
let buf = &buf.buf;
|
||||||
let Some(WlBufferStorage::Shm {
|
let Some(WlBufferStorage::Shm {
|
||||||
mem,
|
mem,
|
||||||
stride,
|
stride,
|
||||||
|
|
@ -698,6 +699,7 @@ struct CommitDataCollector {
|
||||||
impl CommitDataCollector {
|
impl CommitDataCollector {
|
||||||
fn collect(&mut self, pending: &mut PendingState) {
|
fn collect(&mut self, pending: &mut PendingState) {
|
||||||
if let Some(Some(buffer)) = &pending.buffer {
|
if let Some(Some(buffer)) = &pending.buffer {
|
||||||
|
let buffer = &buffer.buf;
|
||||||
if buffer.is_shm() {
|
if buffer.is_shm() {
|
||||||
self.shm_uploads += 1;
|
self.shm_uploads += 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ use {
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
tree::{Node, NodeLocation, NodeVisitorBase, OutputNode},
|
tree::{Node, NodeLocation, NodeVisitorBase, OutputNode},
|
||||||
},
|
},
|
||||||
std::{cell::Cell, ops::Deref, rc::Rc},
|
std::{cell::Cell, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct CursorSurface {
|
pub struct CursorSurface {
|
||||||
|
|
@ -96,25 +96,19 @@ impl Cursor for CursorSurface {
|
||||||
let extents = self.surface.extents.get();
|
let extents = self.surface.extents.get();
|
||||||
renderer.render_surface(&self.surface, -extents.x1(), -extents.y1(), None);
|
renderer.render_surface(&self.surface, -extents.x1(), -extents.y1(), None);
|
||||||
|
|
||||||
struct FrameRequests(u64);
|
struct FrameRequests(u32);
|
||||||
impl NodeVisitorBase for FrameRequests {
|
impl NodeVisitorBase for FrameRequests {
|
||||||
fn visit_surface(&mut self, node: &Rc<WlSurface>) {
|
fn visit_surface(&mut self, node: &Rc<WlSurface>) {
|
||||||
for fr in node.frame_requests.borrow_mut().drain(..) {
|
for mut fr in node.frame_requests.borrow_mut().drain(..) {
|
||||||
fr.send_done(self.0 as _);
|
fr.now = self.0;
|
||||||
let _ = fr.client.remove_obj(fr.deref());
|
drop(fr);
|
||||||
}
|
|
||||||
for fr in node.presentation_feedback.borrow_mut().drain(..) {
|
|
||||||
fr.send_discarded();
|
|
||||||
let _ = fr.client.remove_obj(fr.deref());
|
|
||||||
}
|
|
||||||
for fr in node.latched_presentation_feedback.borrow_mut().drain(..) {
|
|
||||||
fr.send_discarded();
|
|
||||||
let _ = fr.client.remove_obj(fr.deref());
|
|
||||||
}
|
}
|
||||||
|
node.presentation_feedback.borrow_mut().clear();
|
||||||
|
node.latched_presentation_feedback.borrow_mut().clear();
|
||||||
node.node_visit_children(self);
|
node.node_visit_children(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FrameRequests(self.surface.client.state.now_msec()).visit_surface(&self.surface);
|
FrameRequests(self.surface.client.state.now_msec() as u32).visit_surface(&self.surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extents_at_scale(&self, scale: Scale) -> Rect {
|
fn extents_at_scale(&self, scale: Scale) -> Rect {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientError},
|
||||||
ifs::wl_surface::WlSurface,
|
ifs::wl_surface::{SyncObjRelease, WlSurface},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::{Object, Version},
|
object::{Object, Version},
|
||||||
video::drm::sync_obj::SyncObjPoint,
|
video::drm::sync_obj::SyncObjPoint,
|
||||||
|
|
@ -66,7 +66,12 @@ impl WpLinuxDrmSyncobjSurfaceV1RequestHandler for WpLinuxDrmSyncobjSurfaceV1 {
|
||||||
fn set_release_point(&self, req: SetReleasePoint, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn set_release_point(&self, req: SetReleasePoint, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
let point = SyncObjPoint(req.point);
|
let point = SyncObjPoint(req.point);
|
||||||
let timeline = self.client.lookup(req.timeline)?;
|
let timeline = self.client.lookup(req.timeline)?;
|
||||||
self.surface.pending.borrow_mut().release_point = Some((timeline.sync_obj.clone(), point));
|
self.surface.pending.borrow_mut().release_point = Some(SyncObjRelease {
|
||||||
|
state: self.client.state.clone(),
|
||||||
|
committed: false,
|
||||||
|
syncobj: Some(timeline.sync_obj.clone()),
|
||||||
|
point,
|
||||||
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientError},
|
||||||
globals::{Global, GlobalName},
|
globals::{Global, GlobalName},
|
||||||
ifs::wp_presentation_feedback::WpPresentationFeedback,
|
ifs::wp_presentation_feedback::{PresentationFeedback, WpPresentationFeedback},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::{Object, Version},
|
object::{Object, Version},
|
||||||
state::State,
|
state::State,
|
||||||
|
|
@ -94,7 +94,7 @@ impl WpPresentationRequestHandler for WpPresentation {
|
||||||
});
|
});
|
||||||
track!(self.client, fb);
|
track!(self.client, fb);
|
||||||
self.client.add_client_obj(&fb)?;
|
self.client.add_client_obj(&fb)?;
|
||||||
surface.add_presentation_feedback(&fb);
|
surface.add_presentation_feedback(PresentationFeedback::new(fb));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,55 @@ use {
|
||||||
ifs::{wl_output::WlOutput, wl_surface::WlSurface},
|
ifs::{wl_output::WlOutput, wl_surface::WlSurface},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::{Object, Version},
|
object::{Object, Version},
|
||||||
wire::{WpPresentationFeedbackId, wp_presentation_feedback::*},
|
wire::{WlOutputId, WpPresentationFeedbackId, wp_presentation_feedback::*},
|
||||||
},
|
},
|
||||||
|
ahash::AHashMap,
|
||||||
std::{convert::Infallible, rc::Rc},
|
std::{convert::Infallible, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub struct PresentationFeedback {
|
||||||
|
fb: Option<Rc<WpPresentationFeedback>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PresentationFeedback {
|
||||||
|
pub fn new(fb: Rc<WpPresentationFeedback>) -> Self {
|
||||||
|
Self { fb: Some(fb) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn presented(
|
||||||
|
mut self,
|
||||||
|
outputs: Option<&AHashMap<WlOutputId, Rc<WlOutput>>>,
|
||||||
|
tv_sec: u64,
|
||||||
|
tv_nsec: u32,
|
||||||
|
mut refresh: u32,
|
||||||
|
seq: u64,
|
||||||
|
flags: u32,
|
||||||
|
vrr: bool,
|
||||||
|
) {
|
||||||
|
if let Some(fb) = self.fb.take() {
|
||||||
|
if let Some(outputs) = outputs {
|
||||||
|
for output in outputs.values() {
|
||||||
|
fb.send_sync_output(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if vrr && fb.version < VRR_REFRESH_SINCE {
|
||||||
|
refresh = 0;
|
||||||
|
}
|
||||||
|
fb.send_presented(tv_sec, tv_nsec, refresh, seq, flags);
|
||||||
|
let _ = fb.client.remove_obj(&*fb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for PresentationFeedback {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Some(fb) = self.fb.take() {
|
||||||
|
fb.send_discarded();
|
||||||
|
let _ = fb.client.remove_obj(&*fb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct WpPresentationFeedback {
|
pub struct WpPresentationFeedback {
|
||||||
pub id: WpPresentationFeedbackId,
|
pub id: WpPresentationFeedbackId,
|
||||||
pub client: Rc<Client>,
|
pub client: Rc<Client>,
|
||||||
|
|
@ -33,7 +77,7 @@ impl WpPresentationFeedback {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_presented(&self, tv_sec: u64, tv_nsec: u32, refresh: u32, seq: u64, flags: u32) {
|
fn send_presented(&self, tv_sec: u64, tv_nsec: u32, refresh: u32, seq: u64, flags: u32) {
|
||||||
self.client.event(Presented {
|
self.client.event(Presented {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
tv_sec,
|
tv_sec,
|
||||||
|
|
@ -44,7 +88,7 @@ impl WpPresentationFeedback {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_discarded(&self) {
|
fn send_discarded(&self) {
|
||||||
self.client.event(Discarded { self_id: self.id });
|
self.client.event(Discarded { self_id: self.id });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -468,10 +468,11 @@ impl Renderer<'_> {
|
||||||
tsize: (i32, i32),
|
tsize: (i32, i32),
|
||||||
bounds: Option<&Rect>,
|
bounds: Option<&Rect>,
|
||||||
) {
|
) {
|
||||||
|
let buf = &buffer.buffer.buf;
|
||||||
let alpha = surface.alpha();
|
let alpha = surface.alpha();
|
||||||
let cd = surface.color_description();
|
let cd = surface.color_description();
|
||||||
let alpha_mode = surface.alpha_mode();
|
let alpha_mode = surface.alpha_mode();
|
||||||
if let Some(tex) = buffer.buffer.get_texture(surface) {
|
if let Some(tex) = buf.get_texture(surface) {
|
||||||
let mut opaque = surface.opaque();
|
let mut opaque = surface.opaque();
|
||||||
if !opaque && tex.format().has_alpha {
|
if !opaque && tex.format().has_alpha {
|
||||||
opaque = self.bounds_are_opaque(x, y, bounds, surface);
|
opaque = self.bounds_are_opaque(x, y, bounds, surface);
|
||||||
|
|
@ -492,7 +493,7 @@ impl Renderer<'_> {
|
||||||
&cd,
|
&cd,
|
||||||
alpha_mode,
|
alpha_mode,
|
||||||
);
|
);
|
||||||
} else if let Some(color) = &buffer.buffer.color {
|
} else if let Some(color) = &buf.color {
|
||||||
if let Some(rect) = Rect::new_sized(x, y, tsize.0, tsize.1) {
|
if let Some(rect) = Rect::new_sized(x, y, tsize.0, tsize.1) {
|
||||||
let rect = match bounds {
|
let rect = match bounds {
|
||||||
None => rect,
|
None => rect,
|
||||||
|
|
|
||||||
26
src/state.rs
26
src/state.rs
|
|
@ -121,11 +121,7 @@ use {
|
||||||
},
|
},
|
||||||
video::{
|
video::{
|
||||||
dmabuf::DmaBufIds,
|
dmabuf::DmaBufIds,
|
||||||
drm::{
|
drm::{Drm, wait_for_sync_obj::WaitForSyncObj},
|
||||||
Drm,
|
|
||||||
sync_obj::{SyncObj, SyncObjPoint},
|
|
||||||
wait_for_sync_obj::WaitForSyncObj,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
wheel::Wheel,
|
wheel::Wheel,
|
||||||
wire::{
|
wire::{
|
||||||
|
|
@ -689,10 +685,10 @@ impl State {
|
||||||
for surface in client.data.objects.surfaces.lock().values() {
|
for surface in client.data.objects.surfaces.lock().values() {
|
||||||
let had_shm_texture = surface.reset_shm_textures();
|
let had_shm_texture = surface.reset_shm_textures();
|
||||||
if let Some(buffer) = surface.buffer.get() {
|
if let Some(buffer) = surface.buffer.get() {
|
||||||
let had_buffer_texture =
|
let buf = &buffer.buffer.buf;
|
||||||
*updated_buffers.get(&Rc::as_ptr(&buffer.buffer)).unwrap();
|
let had_buffer_texture = *updated_buffers.get(&Rc::as_ptr(buf)).unwrap();
|
||||||
if had_shm_texture || had_buffer_texture {
|
if had_shm_texture || had_buffer_texture {
|
||||||
buffer.buffer.update_texture_or_log(surface, true);
|
buf.update_texture_or_log(surface, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1360,20 +1356,6 @@ impl State {
|
||||||
seat
|
seat
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn signal_point(&self, sync_obj: &SyncObj, point: SyncObjPoint) {
|
|
||||||
let Some(ctx) = self.render_ctx.get() else {
|
|
||||||
log::error!("Cannot signal sync obj point because there is no render context");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let Some(ctx) = ctx.sync_obj_ctx() else {
|
|
||||||
log::error!("Cannot signal sync obj point because there is no syncobj context");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
if let Err(e) = ctx.signal(sync_obj, point) {
|
|
||||||
log::error!("Could not signal sync obj: {}", ErrorFmt(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_backend_idle(&self, idle: bool) {
|
pub fn set_backend_idle(&self, idle: bool) {
|
||||||
if self.idle.backend_idle.replace(idle) != idle {
|
if self.idle.backend_idle.replace(idle) != idle {
|
||||||
self.root.update_visible(self);
|
self.root.update_visible(self);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue