1
0
Fork 0
forked from wry/wry

metal: implement direct scanout

This commit is contained in:
Julian Orth 2024-02-18 20:29:23 +01:00
parent fed2ceb8b5
commit da84e9ec27
25 changed files with 682 additions and 148 deletions

View file

@ -202,9 +202,13 @@ impl WlOutputGlobal {
Ok(())
}
pub fn have_shm_screencopies(&self) -> bool {
self.pending_captures.iter().any(|c| c.is_shm.get())
}
pub fn perform_screencopies(
&self,
fb: &dyn GfxFramebuffer,
fb: Option<&dyn GfxFramebuffer>,
tex: &Rc<dyn GfxTexture>,
render_hardware_cursors: bool,
) {
@ -232,12 +236,13 @@ impl WlOutputGlobal {
wl_buffer.storage.borrow_mut().deref()
{
let acc = mem.access(|mem| {
fb.copy_to_shm(
rect.x1(),
rect.y1(),
rect.width(),
rect.height(),
XRGB8888,
tex.clone().read_pixels(
capture.rect.x1(),
capture.rect.y1(),
capture.rect.width(),
capture.rect.height(),
*stride,
wl_buffer.format,
mem,
)
});
@ -249,24 +254,25 @@ impl WlOutputGlobal {
}
};
if res.is_err() {
let acc = mem.access(|mem| {
tex.clone().read_pixels(
capture.rect.x1(),
capture.rect.y1(),
capture.rect.width(),
capture.rect.height(),
*stride,
wl_buffer.format,
mem,
)
});
res = match acc {
Ok(res) => res,
Err(e) => {
capture.client.error(e);
continue;
}
};
if let Some(fb) = fb {
let acc = mem.access(|mem| {
fb.copy_to_shm(
rect.x1(),
rect.y1(),
rect.width(),
rect.height(),
XRGB8888,
mem,
)
});
res = match acc {
Ok(res) => res,
Err(e) => {
capture.client.error(e);
continue;
}
};
}
}
if let Err(e) = res {
log::warn!("Could not read texture to memory: {}", ErrorFmt(e));

View file

@ -14,6 +14,7 @@ use {
crate::{
backend::KeyState,
client::{Client, ClientError, RequestParser},
drm_feedback::DrmFeedback,
fixed::Fixed,
gfx_api::{BufferPoint, BufferPoints},
ifs::{
@ -36,6 +37,7 @@ use {
},
wp_content_type_v1::ContentType,
wp_presentation_feedback::WpPresentationFeedback,
zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1,
},
leaks::Tracker,
object::Object,
@ -53,7 +55,10 @@ use {
numcell::NumCell,
smallmap::SmallMap,
},
wire::{wl_surface::*, WlOutputId, WlSurfaceId, ZwpIdleInhibitorV1Id},
wire::{
wl_surface::*, WlOutputId, WlSurfaceId, ZwpIdleInhibitorV1Id,
ZwpLinuxDmabufFeedbackV1Id,
},
xkbcommon::ModifierState,
xwayland::XWaylandEvent,
},
@ -259,6 +264,7 @@ pub struct WlSurface {
version: u32,
pub has_content_type_manager: Cell<bool>,
content_type: Cell<Option<ContentType>>,
pub drm_feedback: CopyHashMap<ZwpLinuxDmabufFeedbackV1Id, Rc<ZwpLinuxDmabufFeedbackV1>>,
}
impl Debug for WlSurface {
@ -411,6 +417,7 @@ impl WlSurface {
version,
has_content_type_manager: Default::default(),
content_type: Default::default(),
drm_feedback: Default::default(),
}
}
@ -762,7 +769,23 @@ impl WlSurface {
if let Some(buffer) = self.buffer.take() {
old_raw_size = Some(buffer.rect);
if !buffer.destroyed() {
buffer.send_release();
'handle_release: {
if let Some(tex) = buffer.texture.get() {
let resv = tex.reservations();
if resv.has_reservation() {
let buffer = Rc::downgrade(&buffer);
resv.on_released(move || {
if let Some(buffer) = buffer.upgrade() {
if !buffer.destroyed() {
buffer.send_release();
}
}
});
break 'handle_release;
}
}
buffer.send_release();
}
}
}
if let Some(buffer) = buffer_change {
@ -1065,6 +1088,12 @@ impl WlSurface {
tl.tl_data().request_attention(tl.tl_as_node());
}
}
pub fn send_feedback(&self, fb: &DrmFeedback) {
for consumer in self.drm_feedback.lock().values() {
consumer.send_feedback(fb);
}
}
}
object_base! {
@ -1100,6 +1129,7 @@ impl Object for WlSurface {
self.fractional_scale.take();
self.tearing_control.take();
self.constraints.clear();
self.drm_feedback.clear();
}
}

View file

@ -424,6 +424,10 @@ impl ToplevelNode for Xwindow {
self.display_link.borrow_mut().take();
self.x.surface.destroy_node();
}
fn tl_scanout_surface(&self) -> Option<Rc<WlSurface>> {
Some(self.x.surface.clone())
}
}
impl StackedNode for Xwindow {

View file

@ -8,7 +8,10 @@ use {
ifs::{
ext_foreign_toplevel_list_v1::ExtForeignToplevelListV1,
wl_seat::{NodeSeatState, SeatId, WlSeatGlobal},
wl_surface::xdg_surface::{XdgSurface, XdgSurfaceError, XdgSurfaceExt},
wl_surface::{
xdg_surface::{XdgSurface, XdgSurfaceError, XdgSurfaceExt},
WlSurface,
},
},
leaks::Tracker,
object::Object,
@ -544,6 +547,10 @@ impl ToplevelNode for XdgToplevel {
// self.map_tiled()
// }
// }
fn tl_scanout_surface(&self) -> Option<Rc<WlSurface>> {
Some(self.xdg.surface.clone())
}
}
impl XdgSurfaceExt for XdgToplevel {

View file

@ -33,6 +33,7 @@ pub struct ZwlrScreencopyFrameV1 {
pub with_damage: Cell<bool>,
pub output_link: Cell<Option<LinkedNode<Rc<Self>>>>,
pub buffer: Cell<Option<Rc<WlBuffer>>>,
pub is_shm: Cell<bool>,
pub version: u32,
}
@ -119,6 +120,14 @@ impl ZwlrScreencopyFrameV1 {
return Err(ZwlrScreencopyFrameV1Error::InvalidBufferStride);
}
}
let is_shm = match &*buffer.storage.borrow() {
None => false,
Some(s) => match s {
WlBufferStorage::Shm { .. } => true,
WlBufferStorage::Dmabuf(_) => false,
},
};
self.is_shm.set(is_shm);
self.buffer.set(Some(buffer));
if !with_damage {
self.output.connector.connector.damage();

View file

@ -112,6 +112,7 @@ impl ZwlrScreencopyManagerV1 {
with_damage: Cell::new(false),
output_link: Cell::new(None),
buffer: Cell::new(None),
is_shm: Cell::new(false),
version: self.version,
});
track!(self.client, frame);

View file

@ -1,13 +1,14 @@
use {
crate::{
client::{Client, ClientError},
drm_feedback::DrmFeedback,
drm_feedback::{DrmFeedback, DrmFeedbackId},
ifs::wl_surface::WlSurface,
leaks::Tracker,
object::Object,
utils::buffd::{MsgParser, MsgParserError},
wire::{zwp_linux_dmabuf_feedback_v1::*, ZwpLinuxDmabufFeedbackV1Id},
},
std::rc::Rc,
std::{cell::Cell, rc::Rc},
thiserror::Error,
uapi::{c, OwnedFd},
};
@ -19,24 +20,37 @@ pub struct ZwpLinuxDmabufFeedbackV1 {
pub id: ZwpLinuxDmabufFeedbackV1Id,
pub client: Rc<Client>,
pub tracker: Tracker<Self>,
pub last_feedback: Cell<Option<DrmFeedbackId>>,
pub surface: Option<Rc<WlSurface>>,
}
impl ZwpLinuxDmabufFeedbackV1 {
pub fn new(id: ZwpLinuxDmabufFeedbackV1Id, client: &Rc<Client>) -> Self {
pub fn new(
id: ZwpLinuxDmabufFeedbackV1Id,
client: &Rc<Client>,
surface: Option<&Rc<WlSurface>>,
) -> Self {
Self {
id,
client: client.clone(),
tracker: Default::default(),
last_feedback: Default::default(),
surface: surface.cloned(),
}
}
pub fn send_feedback(&self, feedback: &DrmFeedback) {
self.send_format_table(&feedback.fd, feedback.size);
self.send_main_device(feedback.main_device);
self.send_tranche_target_device(feedback.main_device);
self.send_tranche_formats(&feedback.indices);
self.send_tranche_flags(0);
self.send_tranche_done();
if self.last_feedback.replace(Some(feedback.id)) == Some(feedback.id) {
return;
}
self.send_format_table(&feedback.shared.fd, feedback.shared.size);
self.send_main_device(feedback.shared.main_device);
for tranch in &feedback.tranches {
self.send_tranche_target_device(tranch.device);
self.send_tranche_formats(&tranch.indices);
self.send_tranche_flags(if tranch.scanout { SCANOUT } else { 0 });
self.send_tranche_done();
}
self.send_done();
}
@ -96,6 +110,9 @@ impl ZwpLinuxDmabufFeedbackV1 {
.state
.drm_feedback_consumers
.remove(&(self.client.id, self.id));
if let Some(surface) = &self.surface {
surface.drm_feedback.remove(&self.id);
}
}
}

View file

@ -3,7 +3,7 @@ use {
client::{Client, ClientError},
globals::{Global, GlobalName},
ifs::{
zwp_linux_buffer_params_v1::ZwpLinuxBufferParamsV1,
wl_surface::WlSurface, zwp_linux_buffer_params_v1::ZwpLinuxBufferParamsV1,
zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1,
},
leaks::Tracker,
@ -120,8 +120,9 @@ impl ZwpLinuxDmabufV1 {
fn get_feedback(
self: &Rc<Self>,
id: ZwpLinuxDmabufFeedbackV1Id,
) -> Result<(), ZwpLinuxDmabufV1Error> {
let fb = Rc::new(ZwpLinuxDmabufFeedbackV1::new(id, &self.client));
surface: Option<&Rc<WlSurface>>,
) -> Result<Rc<ZwpLinuxDmabufFeedbackV1>, ZwpLinuxDmabufV1Error> {
let fb = Rc::new(ZwpLinuxDmabufFeedbackV1::new(id, &self.client, surface));
track!(self.client, fb);
self.client.add_client_obj(&fb)?;
self.client
@ -131,7 +132,7 @@ impl ZwpLinuxDmabufV1 {
if let Some(feedback) = self.client.state.drm_feedback.get() {
fb.send_feedback(&feedback);
}
Ok(())
Ok(fb)
}
fn get_default_feedback(
@ -139,7 +140,8 @@ impl ZwpLinuxDmabufV1 {
parser: MsgParser<'_, '_>,
) -> Result<(), ZwpLinuxDmabufV1Error> {
let req: GetDefaultFeedback = self.client.parse(&**self, parser)?;
self.get_feedback(req.id)
self.get_feedback(req.id, None)?;
Ok(())
}
fn get_surface_feedback(
@ -147,8 +149,10 @@ impl ZwpLinuxDmabufV1 {
parser: MsgParser<'_, '_>,
) -> Result<(), ZwpLinuxDmabufV1Error> {
let req: GetSurfaceFeedback = self.client.parse(&**self, parser)?;
let _surface = self.client.lookup(req.surface)?;
self.get_feedback(req.id)
let surface = self.client.lookup(req.surface)?;
let fb = self.get_feedback(req.id, Some(&surface))?;
surface.drm_feedback.set(req.id, fb);
Ok(())
}
}