metal: implement direct scanout
This commit is contained in:
parent
fed2ceb8b5
commit
da84e9ec27
25 changed files with 682 additions and 148 deletions
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue