autocommit 2022-04-27 20:37:49 CEST
This commit is contained in:
parent
57899b3f35
commit
324eb835bb
24 changed files with 478 additions and 68 deletions
|
|
@ -33,6 +33,10 @@ pub trait Backend {
|
|||
fn is_freestanding(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn supports_presentation_feedback(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
|
||||
|
|
|
|||
|
|
@ -187,6 +187,10 @@ impl Backend for MetalBackend {
|
|||
fn is_freestanding(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn supports_presentation_feedback(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn dup_async_fd(state: &Rc<State>, fd: c::c_int) -> Result<AsyncFd, MetalError> {
|
||||
|
|
|
|||
|
|
@ -1,17 +1,19 @@
|
|||
use {
|
||||
crate::{
|
||||
async_engine::{AsyncFd, SpawnedFuture},
|
||||
async_engine::{AsyncFd, Phase, SpawnedFuture},
|
||||
backend::{
|
||||
BackendEvent, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId, MonitorInfo,
|
||||
},
|
||||
backends::metal::{DrmId, MetalBackend, MetalError},
|
||||
edid::Descriptor,
|
||||
format::{Format, XRGB8888},
|
||||
render::{Framebuffer, RenderContext},
|
||||
ifs::wp_presentation_feedback::ExecutedPresentation,
|
||||
render::{Framebuffer, RenderContext, RenderResult},
|
||||
state::State,
|
||||
utils::{
|
||||
bitflags::BitflagsExt, clonecell::CloneCell, debug_fn::debug_fn, errorfmt::ErrorFmt,
|
||||
numcell::NumCell, oserror::OsError, syncqueue::SyncQueue,
|
||||
asyncevent::AsyncEvent, bitflags::BitflagsExt, clonecell::CloneCell,
|
||||
debug_fn::debug_fn, errorfmt::ErrorFmt, numcell::NumCell, oserror::OsError,
|
||||
syncqueue::SyncQueue,
|
||||
},
|
||||
video::{
|
||||
drm::{
|
||||
|
|
@ -28,15 +30,13 @@ use {
|
|||
ahash::{AHashMap, AHashSet},
|
||||
bstr::{BString, ByteSlice},
|
||||
std::{
|
||||
cell::Cell,
|
||||
cell::{Cell, RefCell},
|
||||
ffi::CString,
|
||||
fmt::{Debug, Formatter},
|
||||
rc::Rc,
|
||||
},
|
||||
uapi::c,
|
||||
};
|
||||
use crate::async_engine::Phase;
|
||||
use crate::utils::asyncevent::AsyncEvent;
|
||||
|
||||
pub struct PendingDrmDevice {
|
||||
pub id: DrmId,
|
||||
|
|
@ -91,6 +91,7 @@ pub struct MetalConnector {
|
|||
pub crtcs: AHashMap<DrmCrtc, Rc<MetalCrtc>>,
|
||||
pub modes: Vec<DrmModeInfo>,
|
||||
pub mode: CloneCell<Option<Rc<DrmModeInfo>>>,
|
||||
pub refresh: Cell<u32>,
|
||||
|
||||
pub monitor_manufacturer: String,
|
||||
pub monitor_name: String,
|
||||
|
|
@ -120,6 +121,8 @@ pub struct MetalConnector {
|
|||
pub on_change: OnChange,
|
||||
|
||||
pub present_trigger: AsyncEvent,
|
||||
|
||||
pub render_result: RefCell<RenderResult>,
|
||||
}
|
||||
|
||||
pub struct ConnectorFutures {
|
||||
|
|
@ -179,9 +182,17 @@ impl MetalConnector {
|
|||
};
|
||||
let buffer = &buffers[self.next_buffer.fetch_add(1) % buffers.len()];
|
||||
if let Some(node) = self.state.root.outputs.get(&self.connector_id) {
|
||||
buffer
|
||||
.egl
|
||||
.render(&*node, &self.state, Some(node.global.pos.get()));
|
||||
let mut rr = self.render_result.borrow_mut();
|
||||
buffer.egl.render(
|
||||
&*node,
|
||||
&self.state,
|
||||
Some(node.global.pos.get()),
|
||||
true,
|
||||
&mut rr,
|
||||
);
|
||||
for fr in rr.frame_requests.drain(..) {
|
||||
fr.client.dispatch_frame_requests.push(fr.clone());
|
||||
}
|
||||
}
|
||||
let mut changes = self.master.change();
|
||||
changes.change_object(plane.id, |c| {
|
||||
|
|
@ -285,7 +296,13 @@ fn get_connectors(
|
|||
state: &Rc<State>,
|
||||
dev: &Rc<MetalDrmDeviceStatic>,
|
||||
ids: &[DrmConnector],
|
||||
) -> Result<(AHashMap<DrmConnector, Rc<MetalConnector>>, Vec<ConnectorFutures>), DrmError> {
|
||||
) -> Result<
|
||||
(
|
||||
AHashMap<DrmConnector, Rc<MetalConnector>>,
|
||||
Vec<ConnectorFutures>,
|
||||
),
|
||||
DrmError,
|
||||
> {
|
||||
let mut connectors = AHashMap::new();
|
||||
let mut futures = vec![];
|
||||
for connector in ids {
|
||||
|
|
@ -385,13 +402,19 @@ fn create_connector(
|
|||
serial_number = edid.base_block.id_serial_number.to_string();
|
||||
}
|
||||
}
|
||||
let mode = info.modes.first().cloned().map(Rc::new);
|
||||
let refresh = mode
|
||||
.as_ref()
|
||||
.map(|m| 1_000_000_000_000u64 / (m.refresh_rate_millihz() as u64))
|
||||
.unwrap_or(0) as u32;
|
||||
let slf = Rc::new(MetalConnector {
|
||||
id: connector,
|
||||
master: dev.master.clone(),
|
||||
state: state.clone(),
|
||||
connector_id: state.connector_ids.next(),
|
||||
crtcs,
|
||||
mode: CloneCell::new(info.modes.first().cloned().map(Rc::new)),
|
||||
mode: CloneCell::new(mode),
|
||||
refresh: Cell::new(refresh),
|
||||
monitor_manufacturer: manufacturer,
|
||||
monitor_name: name,
|
||||
monitor_serial_number: serial_number,
|
||||
|
|
@ -411,7 +434,8 @@ fn create_connector(
|
|||
crtc_id: props.get("CRTC_ID")?.map(|v| DrmCrtc(v as _)),
|
||||
crtc: Default::default(),
|
||||
on_change: Default::default(),
|
||||
present_trigger: Default::default()
|
||||
present_trigger: Default::default(),
|
||||
render_result: RefCell::new(Default::default()),
|
||||
});
|
||||
let futures = ConnectorFutures {
|
||||
present: state.eng.spawn2(Phase::Present, slf.clone().present_loop()),
|
||||
|
|
@ -655,7 +679,11 @@ impl MetalBackend {
|
|||
|
||||
let (connectors, futures) = get_connectors(&self.state, &dev, &resources.connectors)?;
|
||||
|
||||
let slf = Rc::new(MetalDrmDevice { dev, connectors, futures });
|
||||
let slf = Rc::new(MetalDrmDevice {
|
||||
dev,
|
||||
connectors,
|
||||
futures,
|
||||
});
|
||||
|
||||
self.init_drm_device(&slf)?;
|
||||
|
||||
|
|
@ -782,9 +810,9 @@ impl MetalBackend {
|
|||
self: &Rc<Self>,
|
||||
dev: &Rc<MetalDrmDevice>,
|
||||
crtc_id: DrmCrtc,
|
||||
_tv_sec: u32,
|
||||
_tv_usec: u32,
|
||||
_sequence: u32,
|
||||
tv_sec: u32,
|
||||
tv_usec: u32,
|
||||
sequence: u32,
|
||||
) {
|
||||
let crtc = match dev.dev.crtcs.get(&crtc_id) {
|
||||
Some(c) => c,
|
||||
|
|
@ -798,6 +826,27 @@ impl MetalBackend {
|
|||
if connector.has_damage.get() {
|
||||
connector.schedule_present();
|
||||
}
|
||||
{
|
||||
let global = self.state.outputs.get(&connector.connector_id);
|
||||
let mut rr = connector.render_result.borrow_mut();
|
||||
for fb in rr.presentation_feedbacks.drain(..) {
|
||||
match &global {
|
||||
Some(g) => {
|
||||
fb.client
|
||||
.dispatch_presentation_feedback
|
||||
.push(ExecutedPresentation {
|
||||
feedback: fb.clone(),
|
||||
output: g.node.global.clone(),
|
||||
tv_sec: tv_sec as _,
|
||||
tv_nsec: tv_usec * 1000,
|
||||
seq: sequence as _,
|
||||
refresh: connector.refresh.get(),
|
||||
})
|
||||
}
|
||||
_ => fb.client.discard_presentation_feedback.push(fb.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn reset_planes(&self, dev: &MetalDrmDevice, changes: &mut Change) {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use {
|
|||
fixed::Fixed,
|
||||
format::XRGB8888,
|
||||
ifs::wl_seat::PX_PER_SCROLL,
|
||||
render::{Framebuffer, RenderContext, RenderError},
|
||||
render::{Framebuffer, RenderContext, RenderError, RenderResult},
|
||||
state::State,
|
||||
utils::{
|
||||
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell,
|
||||
|
|
@ -53,6 +53,7 @@ use {
|
|||
collections::VecDeque,
|
||||
error::Error,
|
||||
future::pending,
|
||||
ops::DerefMut,
|
||||
rc::Rc,
|
||||
},
|
||||
thiserror::Error,
|
||||
|
|
@ -222,6 +223,7 @@ pub async fn create(state: &Rc<State>) -> Result<Rc<XBackend>, XBackendError> {
|
|||
root,
|
||||
scheduled_present: Default::default(),
|
||||
grab_requests: Default::default(),
|
||||
render_result: Default::default(),
|
||||
});
|
||||
data.add_output().await?;
|
||||
|
||||
|
|
@ -250,6 +252,7 @@ pub struct XBackend {
|
|||
root: u32,
|
||||
scheduled_present: AsyncQueue<Rc<XOutput>>,
|
||||
grab_requests: AsyncQueue<(Rc<XSeat>, bool)>,
|
||||
render_result: RefCell<RenderResult>,
|
||||
}
|
||||
|
||||
impl XBackend {
|
||||
|
|
@ -673,8 +676,18 @@ impl XBackend {
|
|||
image.last_serial.set(serial);
|
||||
|
||||
if let Some(node) = self.state.root.outputs.get(&output.id) {
|
||||
let mut rr = self.render_result.borrow_mut();
|
||||
let fb = image.fb.get();
|
||||
fb.render(&*node, &self.state, Some(node.global.pos.get()));
|
||||
fb.render(
|
||||
&*node,
|
||||
&self.state,
|
||||
Some(node.global.pos.get()),
|
||||
true,
|
||||
rr.deref_mut(),
|
||||
);
|
||||
for fr in rr.frame_requests.drain(..) {
|
||||
fr.client.dispatch_frame_requests.push(fr.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let pp = PresentPixmap {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,12 @@ use {
|
|||
crate::{
|
||||
async_engine::{AsyncFd, SpawnedFuture},
|
||||
client::{error::LookupError, objects::Objects},
|
||||
ifs::{wl_callback::WlCallback, wl_display::WlDisplay, wl_registry::WlRegistry},
|
||||
ifs::{
|
||||
wl_callback::WlCallback,
|
||||
wl_display::WlDisplay,
|
||||
wl_registry::WlRegistry,
|
||||
wp_presentation_feedback::{ExecutedPresentation, WpPresentationFeedback},
|
||||
},
|
||||
leaks::Tracker,
|
||||
object::{Interface, Object, ObjectId, WL_DISPLAY_ID},
|
||||
state::State,
|
||||
|
|
@ -132,6 +137,8 @@ impl Clients {
|
|||
flush_request: Default::default(),
|
||||
shutdown: Default::default(),
|
||||
dispatch_frame_requests: AsyncQueue::new(),
|
||||
discard_presentation_feedback: Default::default(),
|
||||
dispatch_presentation_feedback: Default::default(),
|
||||
tracker: Default::default(),
|
||||
is_xwayland,
|
||||
secure,
|
||||
|
|
@ -239,6 +246,8 @@ pub struct Client {
|
|||
flush_request: AsyncEvent,
|
||||
shutdown: AsyncEvent,
|
||||
pub dispatch_frame_requests: AsyncQueue<Rc<WlCallback>>,
|
||||
pub discard_presentation_feedback: AsyncQueue<Rc<WpPresentationFeedback>>,
|
||||
pub dispatch_presentation_feedback: AsyncQueue<ExecutedPresentation>,
|
||||
pub tracker: Tracker<Client>,
|
||||
pub is_xwayland: bool,
|
||||
pub secure: bool,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use {
|
|||
crate::{
|
||||
async_engine::Phase,
|
||||
client::{Client, ClientError},
|
||||
ifs::wp_presentation_feedback::{KIND_HW_COMPLETION, KIND_VSYNC},
|
||||
object::ObjectId,
|
||||
utils::{
|
||||
buffd::{BufFdIn, BufFdOut, MsgParser},
|
||||
|
|
@ -16,6 +17,8 @@ use {
|
|||
pub async fn client(data: Rc<Client>) {
|
||||
let mut recv = data.state.eng.spawn(receive(data.clone())).fuse();
|
||||
let mut dispatch_fr = data.state.eng.spawn(dispatch_fr(data.clone())).fuse();
|
||||
let discard_fb = data.state.eng.spawn(discard_fb(data.clone())).fuse();
|
||||
let dispatch_fb = data.state.eng.spawn(dispatch_fb(data.clone())).fuse();
|
||||
let mut shutdown = data.shutdown.triggered().fuse();
|
||||
let _send = data.state.eng.spawn2(Phase::PostLayout, send(data.clone()));
|
||||
select! {
|
||||
|
|
@ -25,6 +28,8 @@ pub async fn client(data: Rc<Client>) {
|
|||
}
|
||||
drop(recv);
|
||||
drop(dispatch_fr);
|
||||
drop(discard_fb);
|
||||
drop(dispatch_fb);
|
||||
data.flush_request.trigger();
|
||||
match data.state.eng.timeout(5000) {
|
||||
Ok(timeout) => {
|
||||
|
|
@ -56,6 +61,38 @@ async fn dispatch_fr(data: Rc<Client>) {
|
|||
}
|
||||
}
|
||||
|
||||
async fn discard_fb(data: Rc<Client>) {
|
||||
loop {
|
||||
data.discard_presentation_feedback.non_empty().await;
|
||||
while let Some(fr) = data.discard_presentation_feedback.try_pop() {
|
||||
fr.send_discarded();
|
||||
let _ = data.remove_obj(&*fr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn dispatch_fb(data: Rc<Client>) {
|
||||
loop {
|
||||
data.dispatch_presentation_feedback.non_empty().await;
|
||||
while let Some(fr) = data.dispatch_presentation_feedback.try_pop() {
|
||||
let bindings = fr.output.bindings.borrow_mut();
|
||||
if let Some(bindings) = bindings.get(&data.id) {
|
||||
for binding in bindings.values() {
|
||||
fr.feedback.send_sync_output(binding);
|
||||
}
|
||||
}
|
||||
fr.feedback.send_presented(
|
||||
fr.tv_sec,
|
||||
fr.tv_nsec,
|
||||
fr.refresh,
|
||||
fr.seq,
|
||||
KIND_VSYNC | KIND_HW_COMPLETION,
|
||||
);
|
||||
let _ = data.remove_obj(&*fr.feedback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn receive(data: Rc<Client>) {
|
||||
let display = data.display().unwrap();
|
||||
let recv = async {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use {
|
|||
wl_seat::WlSeatGlobal,
|
||||
wl_shm::WlShmGlobal,
|
||||
wl_subcompositor::WlSubcompositorGlobal,
|
||||
wp_presentation::WpPresentationGlobal,
|
||||
xdg_wm_base::XdgWmBaseGlobal,
|
||||
zwlr_layer_shell_v1::ZwlrLayerShellV1Global,
|
||||
zwp_idle_inhibit_manager_v1::ZwpIdleInhibitManagerV1Global,
|
||||
|
|
@ -135,6 +136,10 @@ impl Globals {
|
|||
if backend.supports_idle() {
|
||||
add_singleton!(ZwpIdleInhibitManagerV1Global);
|
||||
}
|
||||
|
||||
if backend.supports_presentation_feedback() {
|
||||
add_singleton!(WpPresentationGlobal);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> GlobalName {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ pub mod wl_shm;
|
|||
pub mod wl_shm_pool;
|
||||
pub mod wl_subcompositor;
|
||||
pub mod wl_surface;
|
||||
pub mod wp_presentation;
|
||||
pub mod wp_presentation_feedback;
|
||||
pub mod xdg_positioner;
|
||||
pub mod xdg_wm_base;
|
||||
pub mod zwlr_layer_shell_v1;
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ use {
|
|||
};
|
||||
|
||||
pub struct WlCallback {
|
||||
client: Rc<Client>,
|
||||
id: WlCallbackId,
|
||||
pub client: Rc<Client>,
|
||||
pub id: WlCallbackId,
|
||||
pub tracker: Tracker<Self>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use {
|
|||
cursor::CursorSurface, wl_subsurface::WlSubsurface, xdg_surface::XdgSurfaceError,
|
||||
zwlr_layer_surface_v1::ZwlrLayerSurfaceV1Error,
|
||||
},
|
||||
wp_presentation_feedback::WpPresentationFeedback,
|
||||
},
|
||||
leaks::Tracker,
|
||||
object::Object,
|
||||
|
|
@ -97,6 +98,7 @@ pub struct WlSurface {
|
|||
pub children: RefCell<Option<Box<ParentData>>>,
|
||||
ext: CloneCell<Rc<dyn SurfaceExt>>,
|
||||
pub frame_requests: RefCell<Vec<Rc<WlCallback>>>,
|
||||
pub presentation_feedback: RefCell<Vec<Rc<WpPresentationFeedback>>>,
|
||||
seat_state: NodeSeatState,
|
||||
toplevel: CloneCell<Option<Rc<dyn ToplevelNode>>>,
|
||||
cursors: SmallMap<SeatId, Rc<CursorSurface>, 1>,
|
||||
|
|
@ -181,6 +183,7 @@ struct PendingState {
|
|||
input_region: Cell<Option<Option<Rc<Region>>>>,
|
||||
frame_request: RefCell<Vec<Rc<WlCallback>>>,
|
||||
damage: Cell<bool>,
|
||||
presentation_feedback: RefCell<Vec<Rc<WpPresentationFeedback>>>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
@ -215,6 +218,7 @@ impl WlSurface {
|
|||
children: Default::default(),
|
||||
ext: CloneCell::new(client.state.none_surface_ext.clone()),
|
||||
frame_requests: Default::default(),
|
||||
presentation_feedback: Default::default(),
|
||||
seat_state: Default::default(),
|
||||
toplevel: Default::default(),
|
||||
cursors: Default::default(),
|
||||
|
|
@ -236,6 +240,13 @@ impl WlSurface {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn add_presentation_feedback(&self, fb: &Rc<WpPresentationFeedback>) {
|
||||
self.pending
|
||||
.presentation_feedback
|
||||
.borrow_mut()
|
||||
.push(fb.clone());
|
||||
}
|
||||
|
||||
pub fn is_cursor(&self) -> bool {
|
||||
self.role.get() == SurfaceRole::Cursor
|
||||
}
|
||||
|
|
@ -497,6 +508,15 @@ impl WlSurface {
|
|||
let mut pfr = self.pending.frame_request.borrow_mut();
|
||||
self.frame_requests.borrow_mut().extend(pfr.drain(..));
|
||||
}
|
||||
{
|
||||
let mut fbs = self.presentation_feedback.borrow_mut();
|
||||
for fb in fbs.drain(..) {
|
||||
fb.send_discarded();
|
||||
let _ = self.client.remove_obj(&*fb);
|
||||
}
|
||||
let mut pfbs = self.pending.presentation_feedback.borrow_mut();
|
||||
mem::swap(fbs.deref_mut(), pfbs.deref_mut());
|
||||
}
|
||||
{
|
||||
if let Some(region) = self.pending.input_region.take() {
|
||||
self.input_region.set(region);
|
||||
|
|
|
|||
|
|
@ -328,21 +328,6 @@ impl XdgToplevel {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn notify_parent(&self) {
|
||||
let parent = match self.toplevel_data.parent.get() {
|
||||
Some(p) => p,
|
||||
_ => return,
|
||||
};
|
||||
let extents = self.xdg.extents.get();
|
||||
parent.clone().node_child_active_changed(
|
||||
self,
|
||||
self.toplevel_data.active_children.get() > 0,
|
||||
1,
|
||||
);
|
||||
parent.node_child_size_changed(self, extents.width(), extents.height());
|
||||
parent.node_child_title_changed(self, self.toplevel_data.title.borrow_mut().deref());
|
||||
}
|
||||
|
||||
fn map_floating(self: &Rc<Self>, workspace: &Rc<WorkspaceNode>) {
|
||||
let (width, height) = self.toplevel_data.float_size(workspace);
|
||||
self.state
|
||||
|
|
@ -460,9 +445,6 @@ impl ToplevelNode for XdgToplevel {
|
|||
}
|
||||
|
||||
fn tl_set_active(&self, active: bool) {
|
||||
if let Some(parent) = self.toplevel_data.parent.get() {
|
||||
parent.node_child_active_changed(self, active, 1);
|
||||
}
|
||||
let changed = {
|
||||
let mut states = self.states.borrow_mut();
|
||||
match active {
|
||||
|
|
@ -587,10 +569,8 @@ impl XdgSurfaceExt for XdgToplevel {
|
|||
}
|
||||
|
||||
fn extents_changed(&self) {
|
||||
self.notify_parent();
|
||||
if self.toplevel_data.parent.get().is_some() {
|
||||
self.state.tree_changed();
|
||||
}
|
||||
self.toplevel_data.pos.set(self.xdg.extents.get());
|
||||
self.tl_extents_changed();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -307,7 +307,8 @@ impl SurfaceExt for Xwindow {
|
|||
}
|
||||
|
||||
fn extents_changed(&self) {
|
||||
self.tl_notify_parent();
|
||||
self.toplevel_data.pos.set(self.surface.extents.get());
|
||||
self.tl_extents_changed();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -391,12 +392,6 @@ impl ToplevelNode for Xwindow {
|
|||
&& self.data.info.input_model.get() != XInputModel::None
|
||||
}
|
||||
|
||||
fn tl_set_active(&self, active: bool) {
|
||||
if let Some(pn) = self.toplevel_data.parent.get() {
|
||||
pn.node_child_active_changed(self, active, 1);
|
||||
}
|
||||
}
|
||||
|
||||
fn tl_on_activate(&self) {
|
||||
self.data
|
||||
.state
|
||||
|
|
|
|||
|
|
@ -307,6 +307,7 @@ impl ZwlrLayerSurfaceV1 {
|
|||
self.mapped.set(false);
|
||||
self.surface.destroy_node();
|
||||
self.seat_state.destroy_node(self);
|
||||
self.client.state.tree_changed();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
116
src/ifs/wp_presentation.rs
Normal file
116
src/ifs/wp_presentation.rs
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
pub use crate::wire::{wp_presentation::*, WpPresentationId};
|
||||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
globals::{Global, GlobalName},
|
||||
ifs::wp_presentation_feedback::WpPresentationFeedback,
|
||||
leaks::Tracker,
|
||||
object::Object,
|
||||
utils::buffd::{MsgParser, MsgParserError},
|
||||
},
|
||||
std::rc::Rc,
|
||||
thiserror::Error,
|
||||
uapi::c,
|
||||
};
|
||||
|
||||
pub struct WpPresentationGlobal {
|
||||
pub name: GlobalName,
|
||||
}
|
||||
|
||||
impl WpPresentationGlobal {
|
||||
pub fn new(name: GlobalName) -> Self {
|
||||
Self { name }
|
||||
}
|
||||
|
||||
fn bind_(
|
||||
self: Rc<Self>,
|
||||
id: WpPresentationId,
|
||||
client: &Rc<Client>,
|
||||
_version: u32,
|
||||
) -> Result<(), WpPresentationError> {
|
||||
let obj = Rc::new(WpPresentation {
|
||||
id,
|
||||
client: client.clone(),
|
||||
tracker: Default::default(),
|
||||
});
|
||||
track!(client, obj);
|
||||
client.add_client_obj(&obj)?;
|
||||
obj.send_clock_id();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
global_base!(WpPresentationGlobal, WpPresentation, WpPresentationError);
|
||||
|
||||
impl Global for WpPresentationGlobal {
|
||||
fn singleton(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn version(&self) -> u32 {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
simple_add_global!(WpPresentationGlobal);
|
||||
|
||||
pub struct WpPresentation {
|
||||
pub id: WpPresentationId,
|
||||
pub client: Rc<Client>,
|
||||
pub tracker: Tracker<Self>,
|
||||
}
|
||||
|
||||
impl WpPresentation {
|
||||
fn send_clock_id(&self) {
|
||||
self.client.event(ClockId {
|
||||
self_id: self.id,
|
||||
clk_id: c::CLOCK_MONOTONIC as _,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), WpPresentationError> {
|
||||
let _req: Destroy = self.client.parse(self, parser)?;
|
||||
self.client.remove_obj(self)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn feedback(&self, parser: MsgParser<'_, '_>) -> Result<(), WpPresentationError> {
|
||||
let req: Feedback = self.client.parse(self, parser)?;
|
||||
let surface = self.client.lookup(req.surface)?;
|
||||
let fb = Rc::new(WpPresentationFeedback {
|
||||
id: req.callback,
|
||||
client: self.client.clone(),
|
||||
surface: surface.clone(),
|
||||
tracker: Default::default(),
|
||||
});
|
||||
track!(self.client, fb);
|
||||
self.client.add_client_obj(&fb)?;
|
||||
surface.add_presentation_feedback(&fb);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
object_base2! {
|
||||
WpPresentation;
|
||||
|
||||
DESTROY => destroy,
|
||||
FEEDBACK => feedback,
|
||||
}
|
||||
|
||||
impl Object for WpPresentation {
|
||||
fn num_requests(&self) -> u32 {
|
||||
FEEDBACK + 1
|
||||
}
|
||||
}
|
||||
|
||||
simple_add_obj!(WpPresentation);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum WpPresentationError {
|
||||
#[error("Parsing failed")]
|
||||
MsgParserError(#[source] Box<MsgParserError>),
|
||||
#[error(transparent)]
|
||||
ClientError(Box<ClientError>),
|
||||
}
|
||||
efrom!(WpPresentationError, MsgParserError);
|
||||
efrom!(WpPresentationError, ClientError);
|
||||
78
src/ifs/wp_presentation_feedback.rs
Normal file
78
src/ifs/wp_presentation_feedback.rs
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
use {
|
||||
crate::{
|
||||
client::Client,
|
||||
ifs::{
|
||||
wl_output::{WlOutput, WlOutputGlobal},
|
||||
wl_surface::WlSurface,
|
||||
},
|
||||
leaks::Tracker,
|
||||
object::Object,
|
||||
wire::{wp_presentation_feedback::*, WpPresentationFeedbackId},
|
||||
},
|
||||
std::rc::Rc,
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
pub struct WpPresentationFeedback {
|
||||
pub id: WpPresentationFeedbackId,
|
||||
pub client: Rc<Client>,
|
||||
pub surface: Rc<WlSurface>,
|
||||
pub tracker: Tracker<Self>,
|
||||
}
|
||||
|
||||
pub struct ExecutedPresentation {
|
||||
pub feedback: Rc<WpPresentationFeedback>,
|
||||
pub output: Rc<WlOutputGlobal>,
|
||||
pub tv_sec: u64,
|
||||
pub tv_nsec: u32,
|
||||
pub seq: u64,
|
||||
pub refresh: u32,
|
||||
}
|
||||
|
||||
pub const KIND_VSYNC: u32 = 0x1;
|
||||
#[allow(dead_code)]
|
||||
pub const KIND_HW_CLOCK: u32 = 0x2;
|
||||
pub const KIND_HW_COMPLETION: u32 = 0x4;
|
||||
#[allow(dead_code)]
|
||||
pub const KIND_ZERO_COPY: u32 = 0x8;
|
||||
|
||||
impl WpPresentationFeedback {
|
||||
pub fn send_sync_output(&self, output: &WlOutput) {
|
||||
self.client.event(SyncOutput {
|
||||
self_id: self.id,
|
||||
output: output.id,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_presented(&self, tv_sec: u64, tv_nsec: u32, refresh: u32, seq: u64, flags: u32) {
|
||||
self.client.event(Presented {
|
||||
self_id: self.id,
|
||||
tv_sec_hi: (tv_sec >> 32) as u32,
|
||||
tv_sec_lo: tv_sec as u32,
|
||||
tv_nsec,
|
||||
refresh,
|
||||
seq_hi: (seq >> 32) as u32,
|
||||
seq_lo: seq as u32,
|
||||
flags,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_discarded(&self) {
|
||||
self.client.event(Discarded { self_id: self.id });
|
||||
}
|
||||
}
|
||||
|
||||
object_base2! {
|
||||
WpPresentationFeedback;
|
||||
}
|
||||
|
||||
impl Object for WpPresentationFeedback {
|
||||
fn num_requests(&self) -> u32 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
simple_add_obj!(WpPresentationFeedback);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum WpPresentationFeedbackError {}
|
||||
|
|
@ -11,6 +11,7 @@ use {
|
|||
},
|
||||
renderer::{context::RenderContext, renderer::Renderer},
|
||||
sys::{glBlendFunc, glFlush, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
|
||||
RenderResult,
|
||||
},
|
||||
state::State,
|
||||
tree::Node,
|
||||
|
|
@ -45,7 +46,14 @@ impl Framebuffer {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn render(&self, node: &dyn Node, state: &State, cursor_rect: Option<Rect>) {
|
||||
pub fn render(
|
||||
&self,
|
||||
node: &dyn Node,
|
||||
state: &State,
|
||||
cursor_rect: Option<Rect>,
|
||||
on_output: bool,
|
||||
result: &mut RenderResult,
|
||||
) {
|
||||
let _ = self.ctx.ctx.with_current(|| {
|
||||
let c = state.theme.background_color.get();
|
||||
unsafe {
|
||||
|
|
@ -59,6 +67,8 @@ impl Framebuffer {
|
|||
ctx: &self.ctx,
|
||||
fb: &self.gl,
|
||||
state,
|
||||
on_output,
|
||||
result,
|
||||
};
|
||||
node.node_render(&mut renderer, 0, 0);
|
||||
if let Some(rect) = cursor_rect {
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@ use {
|
|||
format::{Format, ARGB8888},
|
||||
ifs::{
|
||||
wl_buffer::WlBuffer,
|
||||
wl_callback::WlCallback,
|
||||
wl_surface::{
|
||||
xdg_surface::XdgSurface, zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, WlSurface,
|
||||
},
|
||||
wp_presentation_feedback::WpPresentationFeedback,
|
||||
},
|
||||
rect::Rect,
|
||||
render::{
|
||||
|
|
@ -31,13 +33,32 @@ use {
|
|||
},
|
||||
utils::rc_eq::rc_eq,
|
||||
},
|
||||
std::{ops::Deref, rc::Rc, slice},
|
||||
std::{
|
||||
fmt::{Debug, Formatter},
|
||||
ops::Deref,
|
||||
rc::Rc,
|
||||
slice,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RenderResult {
|
||||
pub frame_requests: Vec<Rc<WlCallback>>,
|
||||
pub presentation_feedbacks: Vec<Rc<WpPresentationFeedback>>,
|
||||
}
|
||||
|
||||
impl Debug for RenderResult {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("RenderResult").finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Renderer<'a> {
|
||||
pub(super) ctx: &'a Rc<RenderContext>,
|
||||
pub(super) fb: &'a GlFrameBuffer,
|
||||
pub(super) state: &'a State,
|
||||
pub(super) on_output: bool,
|
||||
pub(super) result: &'a mut RenderResult,
|
||||
}
|
||||
|
||||
impl Renderer<'_> {
|
||||
|
|
@ -271,9 +292,15 @@ impl Renderer<'_> {
|
|||
} else {
|
||||
self.render_buffer(&buffer, x, y);
|
||||
}
|
||||
let mut fr = surface.frame_requests.borrow_mut();
|
||||
for cb in fr.drain(..) {
|
||||
surface.client.dispatch_frame_requests.push(cb);
|
||||
if self.on_output {
|
||||
{
|
||||
let mut fr = surface.frame_requests.borrow_mut();
|
||||
self.result.frame_requests.extend(fr.drain(..));
|
||||
}
|
||||
{
|
||||
let mut fbs = surface.presentation_feedback.borrow_mut();
|
||||
self.result.presentation_feedbacks.extend(fbs.drain(..));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,13 @@ pub fn take_screenshot(state: &State) -> Result<Screenshot, ScreenshooterError>
|
|||
GBM_BO_USE_RENDERING | GBM_BO_USE_LINEAR,
|
||||
)?;
|
||||
let fb = ctx.dmabuf_fb(bo.dmabuf())?;
|
||||
fb.render(state.root.deref(), state, Some(state.root.extents.get()));
|
||||
fb.render(
|
||||
state.root.deref(),
|
||||
state,
|
||||
Some(state.root.extents.get()),
|
||||
false,
|
||||
&mut Default::default(),
|
||||
);
|
||||
let drm = ctx.gbm.drm.dup_render()?.fd().clone();
|
||||
Ok(Screenshot { drm, bo })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use std::fmt::{Debug, Formatter};
|
||||
use {
|
||||
crate::{
|
||||
async_engine::{AsyncEngine, SpawnedFuture},
|
||||
|
|
@ -42,6 +41,7 @@ use {
|
|||
jay_config::Direction,
|
||||
std::{
|
||||
cell::{Cell, RefCell},
|
||||
fmt::{Debug, Formatter},
|
||||
num::Wrapping,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
|
|
|
|||
|
|
@ -351,6 +351,7 @@ impl ContainerNode {
|
|||
} else {
|
||||
self.perform_split_layout();
|
||||
}
|
||||
self.state.tree_changed();
|
||||
self.schedule_compute_render_data();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,13 +38,20 @@ pub trait ToplevelNode: Node {
|
|||
}
|
||||
|
||||
fn tl_surface_active_changed(&self, active: bool) {
|
||||
let data = self.tl_data();
|
||||
if active {
|
||||
if self.tl_data().active_children.fetch_add(1) == 0 {
|
||||
if data.active_children.fetch_add(1) == 0 {
|
||||
self.tl_set_active(true);
|
||||
if let Some(parent) = data.parent.get() {
|
||||
parent.node_child_active_changed(self.tl_as_node(), true, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if self.tl_data().active_children.fetch_sub(1) == 1 {
|
||||
if data.active_children.fetch_sub(1) == 1 {
|
||||
self.tl_set_active(false);
|
||||
if let Some(parent) = data.parent.get() {
|
||||
parent.node_child_active_changed(self.tl_as_node(), false, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -83,7 +90,9 @@ pub trait ToplevelNode: Node {
|
|||
let data = self.tl_data();
|
||||
data.parent.set(Some(parent.clone()));
|
||||
data.is_floating.set(parent.node_is_float());
|
||||
self.tl_notify_parent();
|
||||
self.tl_extents_changed();
|
||||
self.tl_title_changed();
|
||||
self.tl_active_changed();
|
||||
self.tl_after_parent_set(parent);
|
||||
}
|
||||
|
||||
|
|
@ -91,14 +100,13 @@ pub trait ToplevelNode: Node {
|
|||
let _ = parent;
|
||||
}
|
||||
|
||||
fn tl_notify_parent(&self) {
|
||||
fn tl_active_changed(&self) {
|
||||
let data = self.tl_data();
|
||||
let parent = match data.parent.get() {
|
||||
Some(p) => p,
|
||||
_ => return,
|
||||
};
|
||||
let node = self.tl_as_node();
|
||||
let pos = data.pos.get();
|
||||
let depth = if data.active.get() {
|
||||
1
|
||||
} else if data.active_children.get() > 0 {
|
||||
|
|
@ -109,10 +117,18 @@ pub trait ToplevelNode: Node {
|
|||
if depth > 0 {
|
||||
parent.clone().node_child_active_changed(node, true, depth);
|
||||
}
|
||||
}
|
||||
|
||||
fn tl_extents_changed(&self) {
|
||||
let data = self.tl_data();
|
||||
let parent = match data.parent.get() {
|
||||
Some(p) => p,
|
||||
_ => return,
|
||||
};
|
||||
let node = self.tl_as_node();
|
||||
let pos = data.pos.get();
|
||||
parent.node_child_size_changed(node, pos.width(), pos.height());
|
||||
parent
|
||||
.clone()
|
||||
.node_child_title_changed(node, data.title.borrow_mut().deref());
|
||||
data.state.tree_changed();
|
||||
}
|
||||
|
||||
fn tl_set_workspace(self: Rc<Self>, ws: &Rc<WorkspaceNode>) {
|
||||
|
|
@ -253,6 +269,7 @@ impl ToplevelData {
|
|||
placeholder,
|
||||
workspace: ws.clone(),
|
||||
});
|
||||
drop(data);
|
||||
self.is_fullscreen.set(true);
|
||||
ws.fullscreen.set(Some(node.clone()));
|
||||
node.tl_set_parent(ws.clone());
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use std::fmt::{Debug, Formatter};
|
||||
use {
|
||||
crate::utils::numcell::NumCell,
|
||||
std::{
|
||||
cell::Cell,
|
||||
fmt::{Debug, Formatter},
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
task::{Context, Poll, Waker},
|
||||
|
|
@ -17,7 +17,9 @@ pub struct AsyncEvent {
|
|||
|
||||
impl Debug for AsyncEvent {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("AsyncEvent").field("triggers", &self.triggers.get()).finish_non_exhaustive()
|
||||
f.debug_struct("AsyncEvent")
|
||||
.field("triggers", &self.triggers.get())
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
15
wire/wp_presentation.txt
Normal file
15
wire/wp_presentation.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# requests
|
||||
|
||||
msg destroy = 0 {
|
||||
}
|
||||
|
||||
msg feedback = 1 {
|
||||
surface: id(wl_surface),
|
||||
callback: id(wp_presentation_feedback),
|
||||
}
|
||||
|
||||
# events
|
||||
|
||||
msg clock_id = 0 {
|
||||
clk_id: u32,
|
||||
}
|
||||
19
wire/wp_presentation_feedback.txt
Normal file
19
wire/wp_presentation_feedback.txt
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# events
|
||||
|
||||
msg sync_output = 0 {
|
||||
output: id(wl_output),
|
||||
}
|
||||
|
||||
msg presented = 1 {
|
||||
tv_sec_hi : u32,
|
||||
tv_sec_lo : u32,
|
||||
tv_nsec : u32,
|
||||
refresh : u32,
|
||||
seq_hi : u32,
|
||||
seq_lo : u32,
|
||||
flags : u32,
|
||||
}
|
||||
|
||||
msg discarded = 2 {
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue