refactor(state): split 1598-LOC state.rs into directory + extract 13 Dispatch impls
Step 4a + 4b combined. - src/state.rs (1594 LOC) -> src/state/mod.rs (struct + inherent methods + types + helpers; 999 LOC) + src/state/dispatch/ (13 Dispatch impls across 6 files: registry.rs / wl_output.rs / dmabuf.rs / screencopy.rs / output_mgr.rs / buffer.rs). Per Oracle audit: orphan rule permits Dispatch impls in submodules because Dispatch is a foreign trait on local type State<S>. All State fields the impls touch are already pub/pub(crate) — no visibility widening needed. Verification (all green): - cargo build / cargo build --release - cargo test (79 lib + 3 integration = 82 pass, 1 ignored — unchanged) - cargo clippy --all-targets -- -D warnings - cargo fmt --check - cargo check --bin vaapi_import_bench --bin sw_encode_bench
This commit is contained in:
@@ -0,0 +1,19 @@
|
|||||||
|
use wayland_client::protocol::wl_buffer::WlBuffer;
|
||||||
|
use wayland_client::{Dispatch, Proxy, QueueHandle};
|
||||||
|
|
||||||
|
use crate::state::{CaptureSource, State};
|
||||||
|
|
||||||
|
impl<S: CaptureSource> Dispatch<WlBuffer, ()> for State<S> {
|
||||||
|
fn event(
|
||||||
|
_state: &mut Self,
|
||||||
|
_proxy: &WlBuffer,
|
||||||
|
event: <WlBuffer as Proxy>::Event,
|
||||||
|
_data: &(),
|
||||||
|
_conn: &wayland_client::Connection,
|
||||||
|
_qhandle: &QueueHandle<State<S>>,
|
||||||
|
) {
|
||||||
|
if let wayland_client::protocol::wl_buffer::Event::Release = event {
|
||||||
|
tracing::trace!("WlBuffer released");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
use std::mem;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use wayland_client::{Dispatch, Proxy, QueueHandle};
|
||||||
|
use wayland_protocols::wp::linux_dmabuf::zv1::client::zwp_linux_buffer_params_v1::{
|
||||||
|
Event as BufferParamsEvent, ZwpLinuxBufferParamsV1,
|
||||||
|
};
|
||||||
|
use wayland_protocols::wp::linux_dmabuf::zv1::client::zwp_linux_dmabuf_feedback_v1::{
|
||||||
|
Event as DmabufFeedbackEvent, ZwpLinuxDmabufFeedbackV1,
|
||||||
|
};
|
||||||
|
use wayland_protocols::wp::linux_dmabuf::zv1::client::zwp_linux_dmabuf_v1::{
|
||||||
|
Event as DmabufEvent, ZwpLinuxDmabufV1,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::state::{CaptureSource, EncConstructionStage, InFlightSurface, State};
|
||||||
|
|
||||||
|
impl<S: CaptureSource> Dispatch<ZwpLinuxDmabufV1, ()> for State<S> {
|
||||||
|
fn event(
|
||||||
|
_state: &mut Self,
|
||||||
|
_proxy: &ZwpLinuxDmabufV1,
|
||||||
|
event: <ZwpLinuxDmabufV1 as Proxy>::Event,
|
||||||
|
_data: &(),
|
||||||
|
_conn: &wayland_client::Connection,
|
||||||
|
_qhandle: &QueueHandle<State<S>>,
|
||||||
|
) {
|
||||||
|
match event {
|
||||||
|
DmabufEvent::Format { .. } => {}
|
||||||
|
DmabufEvent::Modifier { .. } => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: CaptureSource> Dispatch<ZwpLinuxDmabufFeedbackV1, ()> for State<S> {
|
||||||
|
fn event(
|
||||||
|
state: &mut Self,
|
||||||
|
_proxy: &ZwpLinuxDmabufFeedbackV1,
|
||||||
|
event: <ZwpLinuxDmabufFeedbackV1 as Proxy>::Event,
|
||||||
|
_data: &(),
|
||||||
|
_conn: &wayland_client::Connection,
|
||||||
|
_qhandle: &QueueHandle<State<S>>,
|
||||||
|
) {
|
||||||
|
match event {
|
||||||
|
DmabufFeedbackEvent::MainDevice { device } => {
|
||||||
|
if device.len() >= 8 {
|
||||||
|
let dev_bytes: [u8; 8] = device[..8].try_into().unwrap_or([0u8; 8]);
|
||||||
|
let dev = u64::from_ne_bytes(dev_bytes);
|
||||||
|
let minor = ((dev & 0xFF) | ((dev >> 12) & 0xFFFFFF00)) as u32;
|
||||||
|
let path = PathBuf::from(format!("/dev/dri/renderD{}", minor));
|
||||||
|
if path.exists() {
|
||||||
|
tracing::info!(
|
||||||
|
"Compositor DRM device: {} (dev_t: {})",
|
||||||
|
path.display(),
|
||||||
|
dev
|
||||||
|
);
|
||||||
|
state.drm_device_from_compositor = Some(path);
|
||||||
|
} else {
|
||||||
|
tracing::warn!(
|
||||||
|
"Compositor reported DRM device {} (dev_t: {}) but path does not exist",
|
||||||
|
path.display(),
|
||||||
|
dev
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tracing::warn!(
|
||||||
|
"main_device event with unexpected data length: {}",
|
||||||
|
device.len()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DmabufFeedbackEvent::FormatTable { .. } => {}
|
||||||
|
DmabufFeedbackEvent::Done => {}
|
||||||
|
DmabufFeedbackEvent::TrancheDone => {}
|
||||||
|
DmabufFeedbackEvent::TrancheTargetDevice { .. } => {}
|
||||||
|
DmabufFeedbackEvent::TrancheFormats { .. } => {}
|
||||||
|
DmabufFeedbackEvent::TrancheFlags { .. } => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: CaptureSource> Dispatch<ZwpLinuxBufferParamsV1, ()> for State<S> {
|
||||||
|
fn event(
|
||||||
|
state: &mut Self,
|
||||||
|
proxy: &ZwpLinuxBufferParamsV1,
|
||||||
|
event: <ZwpLinuxBufferParamsV1 as Proxy>::Event,
|
||||||
|
_data: &(),
|
||||||
|
_conn: &wayland_client::Connection,
|
||||||
|
_qhandle: &QueueHandle<State<S>>,
|
||||||
|
) {
|
||||||
|
match event {
|
||||||
|
BufferParamsEvent::Created { .. } => {
|
||||||
|
tracing::debug!("DMA-BUF buffer created");
|
||||||
|
}
|
||||||
|
BufferParamsEvent::Failed => {
|
||||||
|
tracing::error!("DMA-BUF buffer creation failed");
|
||||||
|
let taken = mem::replace(&mut state.in_flight_surface, InFlightSurface::None);
|
||||||
|
match taken {
|
||||||
|
InFlightSurface::CopyQueued { buffer, frame, .. } => {
|
||||||
|
drop(buffer);
|
||||||
|
if let EncConstructionStage::Streaming { cap, .. } = &mut state.stage {
|
||||||
|
cap.on_done_with_frame(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other => {
|
||||||
|
state.in_flight_surface = other;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
proxy.destroy();
|
||||||
|
state.errored = true;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
mod buffer;
|
||||||
|
mod dmabuf;
|
||||||
|
mod output_mgr;
|
||||||
|
mod registry;
|
||||||
|
mod screencopy;
|
||||||
|
mod wl_output;
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
use wayland_client::{event_created_child, Dispatch, Proxy, QueueHandle};
|
||||||
|
use wayland_protocols::xdg::xdg_output::zv1::client::zxdg_output_manager_v1::ZxdgOutputManagerV1;
|
||||||
|
use wayland_protocols_wlr::output_management::v1::client::zwlr_output_head_v1::{
|
||||||
|
self, Event as WlrHeadEvent, ZwlrOutputHeadV1,
|
||||||
|
};
|
||||||
|
use wayland_protocols_wlr::output_management::v1::client::zwlr_output_manager_v1::{
|
||||||
|
self, Event as WlrOutputManagerEvent, ZwlrOutputManagerV1,
|
||||||
|
};
|
||||||
|
use wayland_protocols_wlr::output_management::v1::client::zwlr_output_mode_v1::ZwlrOutputModeV1;
|
||||||
|
|
||||||
|
use crate::state::{CaptureSource, EncConstructionStage, State, WlrHeadInfo};
|
||||||
|
|
||||||
|
impl<S: CaptureSource> Dispatch<ZxdgOutputManagerV1, ()> for State<S> {
|
||||||
|
fn event(
|
||||||
|
_state: &mut Self,
|
||||||
|
_proxy: &ZxdgOutputManagerV1,
|
||||||
|
_event: <ZxdgOutputManagerV1 as Proxy>::Event,
|
||||||
|
_data: &(),
|
||||||
|
_conn: &wayland_client::Connection,
|
||||||
|
_qhandle: &QueueHandle<State<S>>,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: CaptureSource> Dispatch<ZwlrOutputManagerV1, ()> for State<S> {
|
||||||
|
fn event(
|
||||||
|
state: &mut Self,
|
||||||
|
_proxy: &ZwlrOutputManagerV1,
|
||||||
|
event: <ZwlrOutputManagerV1 as Proxy>::Event,
|
||||||
|
_data: &(),
|
||||||
|
_conn: &wayland_client::Connection,
|
||||||
|
_qhandle: &QueueHandle<State<S>>,
|
||||||
|
) {
|
||||||
|
match event {
|
||||||
|
WlrOutputManagerEvent::Head { head } => {
|
||||||
|
let _head: ZwlrOutputHeadV1 = head;
|
||||||
|
tracing::debug!("wlr output head advertised");
|
||||||
|
}
|
||||||
|
WlrOutputManagerEvent::Done { .. } => {
|
||||||
|
if let EncConstructionStage::ProbingOutputs {
|
||||||
|
wlr_manager_done,
|
||||||
|
outputs,
|
||||||
|
..
|
||||||
|
} = &mut state.stage
|
||||||
|
{
|
||||||
|
*wlr_manager_done = true;
|
||||||
|
let count = outputs.len();
|
||||||
|
for idx in 0..count {
|
||||||
|
state.try_finalize_output(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WlrOutputManagerEvent::Finished => {
|
||||||
|
tracing::warn!("zwlr_output_manager_v1::Finished received during probing");
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event_created_child!(State<S>, ZwlrOutputManagerV1, [
|
||||||
|
zwlr_output_manager_v1::EVT_HEAD_OPCODE => (ZwlrOutputHeadV1, ()),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: CaptureSource> Dispatch<ZwlrOutputHeadV1, ()> for State<S> {
|
||||||
|
fn event(
|
||||||
|
state: &mut Self,
|
||||||
|
proxy: &ZwlrOutputHeadV1,
|
||||||
|
event: <ZwlrOutputHeadV1 as Proxy>::Event,
|
||||||
|
_data: &(),
|
||||||
|
_conn: &wayland_client::Connection,
|
||||||
|
_qhandle: &QueueHandle<State<S>>,
|
||||||
|
) {
|
||||||
|
match event {
|
||||||
|
WlrHeadEvent::Name { name } => {
|
||||||
|
if let EncConstructionStage::ProbingOutputs {
|
||||||
|
wlr_heads,
|
||||||
|
wlr_head_proxy_to_name,
|
||||||
|
..
|
||||||
|
} = &mut state.stage
|
||||||
|
{
|
||||||
|
wlr_heads.entry(name.clone()).or_insert(WlrHeadInfo {});
|
||||||
|
wlr_head_proxy_to_name.insert(proxy.id(), name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WlrHeadEvent::Position { .. } => {}
|
||||||
|
WlrHeadEvent::Finished => {
|
||||||
|
tracing::debug!("zwlr_output_head_v1::Finished received");
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event_created_child!(State<S>, ZwlrOutputHeadV1, [
|
||||||
|
zwlr_output_head_v1::EVT_MODE_OPCODE => (ZwlrOutputModeV1, ()),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: CaptureSource> Dispatch<ZwlrOutputModeV1, ()> for State<S> {
|
||||||
|
fn event(
|
||||||
|
_state: &mut Self,
|
||||||
|
_proxy: &ZwlrOutputModeV1,
|
||||||
|
_event: <ZwlrOutputModeV1 as Proxy>::Event,
|
||||||
|
_data: &(),
|
||||||
|
_conn: &wayland_client::Connection,
|
||||||
|
_qhandle: &QueueHandle<State<S>>,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
use wayland_client::globals::GlobalListContents;
|
||||||
|
use wayland_client::protocol::wl_output::WlOutput;
|
||||||
|
use wayland_client::protocol::wl_registry::WlRegistry;
|
||||||
|
use wayland_client::{Dispatch, QueueHandle};
|
||||||
|
use wayland_protocols::wp::linux_dmabuf::zv1::client::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1;
|
||||||
|
use wayland_protocols::xdg::xdg_output::zv1::client::zxdg_output_manager_v1::ZxdgOutputManagerV1;
|
||||||
|
use wayland_protocols_wlr::output_management::v1::client::zwlr_output_manager_v1::ZwlrOutputManagerV1;
|
||||||
|
use wayland_protocols_wlr::screencopy::v1::client::zwlr_screencopy_manager_v1::ZwlrScreencopyManagerV1;
|
||||||
|
|
||||||
|
use crate::state::{CaptureSource, EncConstructionStage, OutputId, PartialOutputInfo, State};
|
||||||
|
|
||||||
|
impl<S: CaptureSource> Dispatch<WlRegistry, GlobalListContents> for State<S> {
|
||||||
|
fn event(
|
||||||
|
state: &mut Self,
|
||||||
|
registry: &WlRegistry,
|
||||||
|
event: wayland_client::protocol::wl_registry::Event,
|
||||||
|
_data: &GlobalListContents,
|
||||||
|
_conn: &wayland_client::Connection,
|
||||||
|
qhandle: &QueueHandle<State<S>>,
|
||||||
|
) {
|
||||||
|
use wayland_client::protocol::wl_registry::Event as RegistryEvent;
|
||||||
|
|
||||||
|
match event {
|
||||||
|
RegistryEvent::Global {
|
||||||
|
name,
|
||||||
|
interface,
|
||||||
|
version,
|
||||||
|
} => match interface.as_str() {
|
||||||
|
"zwlr_screencopy_manager_v1" => {
|
||||||
|
let v = version.min(3);
|
||||||
|
tracing::debug!("Binding zwlr_screencopy_manager_v1 v{v} (name={name})");
|
||||||
|
let mgr: ZwlrScreencopyManagerV1 = registry.bind(name, v, qhandle, ());
|
||||||
|
if let EncConstructionStage::ProbingOutputs {
|
||||||
|
screencopy_manager, ..
|
||||||
|
} = &mut state.stage
|
||||||
|
{
|
||||||
|
*screencopy_manager = Some(mgr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"zwp_linux_dmabuf_v1" => {
|
||||||
|
let v = version.min(4);
|
||||||
|
tracing::debug!("Binding zwp_linux_dmabuf_v1 v{v} (name={name})");
|
||||||
|
let proxy: ZwpLinuxDmabufV1 = registry.bind(name, v, qhandle, ());
|
||||||
|
if let EncConstructionStage::ProbingOutputs {
|
||||||
|
dmabuf,
|
||||||
|
dmabuf_feedback,
|
||||||
|
..
|
||||||
|
} = &mut state.stage
|
||||||
|
{
|
||||||
|
*dmabuf = Some(proxy.clone());
|
||||||
|
if v >= 4 {
|
||||||
|
let feedback = proxy.get_default_feedback(qhandle, ());
|
||||||
|
*dmabuf_feedback = Some(feedback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"wl_output" => {
|
||||||
|
let v = version.min(4);
|
||||||
|
tracing::debug!("Binding wl_output v{v} (name={name})");
|
||||||
|
let output: WlOutput = registry.bind(name, v, qhandle, OutputId(name));
|
||||||
|
if let EncConstructionStage::ProbingOutputs {
|
||||||
|
outputs,
|
||||||
|
bound_outputs,
|
||||||
|
output_names,
|
||||||
|
xdg_output_manager,
|
||||||
|
..
|
||||||
|
} = &mut state.stage
|
||||||
|
{
|
||||||
|
outputs.push(PartialOutputInfo::default());
|
||||||
|
bound_outputs.push(output.clone());
|
||||||
|
output_names.push(name);
|
||||||
|
if let Some(xdg_mgr) = xdg_output_manager {
|
||||||
|
let output_id = OutputId(name);
|
||||||
|
xdg_mgr.get_xdg_output(&output, qhandle, output_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"zxdg_output_manager_v1" => {
|
||||||
|
let v = version.min(3);
|
||||||
|
tracing::debug!("Binding zxdg_output_manager_v1 v{v} (name={name})");
|
||||||
|
let xdg_mgr: ZxdgOutputManagerV1 = registry.bind(name, v, qhandle, ());
|
||||||
|
if let EncConstructionStage::ProbingOutputs {
|
||||||
|
bound_outputs,
|
||||||
|
xdg_output_manager,
|
||||||
|
output_names,
|
||||||
|
..
|
||||||
|
} = &mut state.stage
|
||||||
|
{
|
||||||
|
for (i, output) in bound_outputs.iter().enumerate() {
|
||||||
|
let oname = output_names.get(i).copied().unwrap_or(0);
|
||||||
|
let output_id = OutputId(oname);
|
||||||
|
xdg_mgr.get_xdg_output(output, qhandle, output_id);
|
||||||
|
}
|
||||||
|
*xdg_output_manager = Some(xdg_mgr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"zwlr_output_manager_v1" => {
|
||||||
|
let v = version.min(4);
|
||||||
|
tracing::debug!("Binding zwlr_output_manager_v1 v{v} (name={name})");
|
||||||
|
let mgr: ZwlrOutputManagerV1 = registry.bind(name, v, qhandle, ());
|
||||||
|
if let EncConstructionStage::ProbingOutputs {
|
||||||
|
wlr_output_manager, ..
|
||||||
|
} = &mut state.stage
|
||||||
|
{
|
||||||
|
*wlr_output_manager = Some(mgr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
RegistryEvent::GlobalRemove { name } => {
|
||||||
|
tracing::debug!("Global removed: name={name}");
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
use wayland_client::{Dispatch, Proxy, QueueHandle};
|
||||||
|
use wayland_protocols_wlr::screencopy::v1::client::zwlr_screencopy_frame_v1::{
|
||||||
|
Event as ScreencopyFrameEvent, ZwlrScreencopyFrameV1,
|
||||||
|
};
|
||||||
|
use wayland_protocols_wlr::screencopy::v1::client::zwlr_screencopy_manager_v1::ZwlrScreencopyManagerV1;
|
||||||
|
|
||||||
|
use crate::cap_wlr_screencopy::CapWlrScreencopy;
|
||||||
|
use crate::state::{EncConstructionStage, InFlightSurface, State};
|
||||||
|
|
||||||
|
impl Dispatch<ZwlrScreencopyFrameV1, ()> for State<CapWlrScreencopy> {
|
||||||
|
fn event(
|
||||||
|
state: &mut Self,
|
||||||
|
proxy: &ZwlrScreencopyFrameV1,
|
||||||
|
event: <ZwlrScreencopyFrameV1 as Proxy>::Event,
|
||||||
|
_data: &(),
|
||||||
|
_conn: &wayland_client::Connection,
|
||||||
|
_qhandle: &QueueHandle<State<CapWlrScreencopy>>,
|
||||||
|
) {
|
||||||
|
match event {
|
||||||
|
// SHM buffer offer — in v3 the compositor enumerates supported buffer
|
||||||
|
// types (buffer and/or linux_dmabuf) before buffer_done. We only
|
||||||
|
// support DMA-BUF, so just log and wait for linux_dmabuf / buffer_done.
|
||||||
|
ScreencopyFrameEvent::Buffer { .. } => {
|
||||||
|
tracing::debug!("Received SHM Buffer offer — only DMA-BUF capture is supported");
|
||||||
|
}
|
||||||
|
ScreencopyFrameEvent::LinuxDmabuf {
|
||||||
|
format,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
} => {
|
||||||
|
tracing::debug!("Screencopy LinuxDmabuf: format={format}, {width}x{height}");
|
||||||
|
|
||||||
|
if !matches!(state.in_flight_surface, InFlightSurface::AllocQueued) {
|
||||||
|
tracing::warn!("Received LinuxDmabuf while no frame allocation was queued");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches!(state.stage, EncConstructionStage::EverythingButFmt { .. }) {
|
||||||
|
state.negotiate_format(format, width, height);
|
||||||
|
if state.errored {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let EncConstructionStage::Streaming { cap, .. } = &mut state.stage {
|
||||||
|
cap.current_frame = Some(proxy.clone());
|
||||||
|
}
|
||||||
|
state.on_frame_allocd((), format, width, height);
|
||||||
|
}
|
||||||
|
// v3 terminal event: all buffer offers have been enumerated.
|
||||||
|
// If still AllocQueued, the compositor never sent linux_dmabuf —
|
||||||
|
// DMA-BUF screencopy is unsupported, so we must error out.
|
||||||
|
ScreencopyFrameEvent::BufferDone => {
|
||||||
|
if matches!(state.in_flight_surface, InFlightSurface::AllocQueued) {
|
||||||
|
tracing::error!(
|
||||||
|
"Compositor did not offer DMA-BUF screencopy (only SHM); \
|
||||||
|
DMA-BUF capture is required"
|
||||||
|
);
|
||||||
|
state.in_flight_surface = InFlightSurface::None;
|
||||||
|
proxy.destroy();
|
||||||
|
state.errored = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ScreencopyFrameEvent::Ready {
|
||||||
|
tv_sec_hi,
|
||||||
|
tv_sec_lo,
|
||||||
|
tv_nsec,
|
||||||
|
} => {
|
||||||
|
let tv_sec = (tv_sec_hi as u64) << 32 | tv_sec_lo as u64;
|
||||||
|
let tv_usec = tv_nsec / 1000;
|
||||||
|
tracing::trace!("Screencopy ready: tv_sec={tv_sec}, tv_usec={tv_usec}");
|
||||||
|
state.on_copy_complete(tv_sec, tv_usec);
|
||||||
|
}
|
||||||
|
ScreencopyFrameEvent::Failed => {
|
||||||
|
tracing::error!("Screencopy frame failed");
|
||||||
|
state.on_copy_fail();
|
||||||
|
}
|
||||||
|
ScreencopyFrameEvent::Damage { .. } => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: crate::state::CaptureSource> Dispatch<ZwlrScreencopyManagerV1, ()> for State<S> {
|
||||||
|
fn event(
|
||||||
|
_state: &mut Self,
|
||||||
|
_proxy: &ZwlrScreencopyManagerV1,
|
||||||
|
_event: <ZwlrScreencopyManagerV1 as Proxy>::Event,
|
||||||
|
_data: &(),
|
||||||
|
_conn: &wayland_client::Connection,
|
||||||
|
_qhandle: &QueueHandle<State<S>>,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
use wayland_client::protocol::wl_output::WlOutput;
|
||||||
|
use wayland_client::{Dispatch, Proxy, QueueHandle};
|
||||||
|
use wayland_protocols::xdg::xdg_output::zv1::client::zxdg_output_v1::{
|
||||||
|
Event as XdgOutputEvent, ZxdgOutputV1,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::state::{CaptureSource, EncConstructionStage, OutputId, State, Transform};
|
||||||
|
|
||||||
|
impl<S: CaptureSource> Dispatch<WlOutput, OutputId> for State<S> {
|
||||||
|
fn event(
|
||||||
|
state: &mut Self,
|
||||||
|
_proxy: &WlOutput,
|
||||||
|
event: wayland_client::protocol::wl_output::Event,
|
||||||
|
data: &OutputId,
|
||||||
|
_conn: &wayland_client::Connection,
|
||||||
|
_qhandle: &QueueHandle<State<S>>,
|
||||||
|
) {
|
||||||
|
use wayland_client::protocol::wl_output::Event as OutputEvent;
|
||||||
|
use wayland_client::protocol::wl_output::Mode as WlMode;
|
||||||
|
use wayland_client::protocol::wl_output::Transform as WlTransform;
|
||||||
|
|
||||||
|
let OutputId(target_name) = data;
|
||||||
|
let idx = match &state.stage {
|
||||||
|
EncConstructionStage::ProbingOutputs { output_names, .. } => {
|
||||||
|
output_names.iter().position(|&n| n == *target_name)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
let idx = match idx {
|
||||||
|
Some(i) => i,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
match event {
|
||||||
|
OutputEvent::Geometry { transform, .. } => {
|
||||||
|
let t = match transform {
|
||||||
|
wayland_client::WEnum::Value(WlTransform::Normal) => Transform::Normal,
|
||||||
|
wayland_client::WEnum::Value(WlTransform::_90) => Transform::Normal90,
|
||||||
|
wayland_client::WEnum::Value(WlTransform::_180) => Transform::Normal180,
|
||||||
|
wayland_client::WEnum::Value(WlTransform::_270) => Transform::Normal270,
|
||||||
|
wayland_client::WEnum::Value(WlTransform::Flipped) => Transform::Flipped,
|
||||||
|
wayland_client::WEnum::Value(WlTransform::Flipped90) => Transform::Flipped90,
|
||||||
|
wayland_client::WEnum::Value(WlTransform::Flipped180) => Transform::Flipped180,
|
||||||
|
wayland_client::WEnum::Value(WlTransform::Flipped270) => Transform::Flipped270,
|
||||||
|
_ => Transform::Normal,
|
||||||
|
};
|
||||||
|
if let EncConstructionStage::ProbingOutputs { outputs, .. } = &mut state.stage {
|
||||||
|
if let Some(info) = outputs.get_mut(idx) {
|
||||||
|
info.transform = Some(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputEvent::Mode {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
flags,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let is_current = matches!(flags, wayland_client::WEnum::Value(WlMode::Current));
|
||||||
|
if is_current {
|
||||||
|
if let EncConstructionStage::ProbingOutputs { outputs, .. } = &mut state.stage {
|
||||||
|
if let Some(info) = outputs.get_mut(idx) {
|
||||||
|
info.mode_size = Some((width, height));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputEvent::Done => {
|
||||||
|
if let EncConstructionStage::ProbingOutputs { outputs, .. } = &mut state.stage {
|
||||||
|
if let Some(info) = outputs.get_mut(idx) {
|
||||||
|
info.done_count += 1;
|
||||||
|
if info.done_count >= 1 {
|
||||||
|
state.try_finalize_output(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputEvent::Name { name } => {
|
||||||
|
if let EncConstructionStage::ProbingOutputs { outputs, .. } = &mut state.stage {
|
||||||
|
if let Some(info) = outputs.get_mut(idx) {
|
||||||
|
info.wl_name = Some(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: CaptureSource> Dispatch<ZxdgOutputV1, OutputId> for State<S> {
|
||||||
|
fn event(
|
||||||
|
state: &mut Self,
|
||||||
|
_proxy: &ZxdgOutputV1,
|
||||||
|
event: <ZxdgOutputV1 as Proxy>::Event,
|
||||||
|
data: &OutputId,
|
||||||
|
_conn: &wayland_client::Connection,
|
||||||
|
_qhandle: &QueueHandle<State<S>>,
|
||||||
|
) {
|
||||||
|
let target_name = data.0;
|
||||||
|
let idx = match &state.stage {
|
||||||
|
EncConstructionStage::ProbingOutputs { output_names, .. } => {
|
||||||
|
output_names.iter().position(|&n| n == target_name)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
let idx = match idx {
|
||||||
|
Some(i) => i,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
match event {
|
||||||
|
XdgOutputEvent::Name { name } => {
|
||||||
|
if let EncConstructionStage::ProbingOutputs { outputs, .. } = &mut state.stage {
|
||||||
|
if let Some(info) = outputs.get_mut(idx) {
|
||||||
|
info.name = Some(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
XdgOutputEvent::LogicalSize { .. } => {}
|
||||||
|
XdgOutputEvent::Done => {
|
||||||
|
if let EncConstructionStage::ProbingOutputs { outputs, .. } = &mut state.stage {
|
||||||
|
if let Some(info) = outputs.get_mut(idx) {
|
||||||
|
info.done_count += 1;
|
||||||
|
if info.done_count >= 1 {
|
||||||
|
state.try_finalize_output(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,34 +9,16 @@ use std::time::Instant;
|
|||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use wayland_client::backend::ObjectId;
|
use wayland_client::backend::ObjectId;
|
||||||
use wayland_client::globals::{GlobalList, GlobalListContents};
|
use wayland_client::globals::GlobalList;
|
||||||
use wayland_client::protocol::wl_buffer::WlBuffer;
|
use wayland_client::protocol::wl_buffer::WlBuffer;
|
||||||
use wayland_client::protocol::wl_output::WlOutput;
|
use wayland_client::protocol::wl_output::WlOutput;
|
||||||
use wayland_client::protocol::wl_registry::WlRegistry;
|
use wayland_client::{Dispatch, QueueHandle};
|
||||||
use wayland_client::{event_created_child, Dispatch, Proxy, QueueHandle};
|
use wayland_protocols::wp::linux_dmabuf::zv1::client::zwp_linux_buffer_params_v1::Flags as BufferParamsFlags;
|
||||||
use wayland_protocols::wp::linux_dmabuf::zv1::client::zwp_linux_buffer_params_v1::{
|
use wayland_protocols::wp::linux_dmabuf::zv1::client::zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1;
|
||||||
Event as BufferParamsEvent, Flags as BufferParamsFlags, ZwpLinuxBufferParamsV1,
|
use wayland_protocols::wp::linux_dmabuf::zv1::client::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1;
|
||||||
};
|
|
||||||
use wayland_protocols::wp::linux_dmabuf::zv1::client::zwp_linux_dmabuf_feedback_v1::{
|
|
||||||
Event as DmabufFeedbackEvent, ZwpLinuxDmabufFeedbackV1,
|
|
||||||
};
|
|
||||||
use wayland_protocols::wp::linux_dmabuf::zv1::client::zwp_linux_dmabuf_v1::{
|
|
||||||
Event as DmabufEvent, ZwpLinuxDmabufV1,
|
|
||||||
};
|
|
||||||
use wayland_protocols::xdg::xdg_output::zv1::client::zxdg_output_manager_v1::ZxdgOutputManagerV1;
|
use wayland_protocols::xdg::xdg_output::zv1::client::zxdg_output_manager_v1::ZxdgOutputManagerV1;
|
||||||
use wayland_protocols::xdg::xdg_output::zv1::client::zxdg_output_v1::{
|
use wayland_protocols_wlr::output_management::v1::client::zwlr_output_manager_v1::ZwlrOutputManagerV1;
|
||||||
Event as XdgOutputEvent, ZxdgOutputV1,
|
use wayland_protocols_wlr::screencopy::v1::client::zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1;
|
||||||
};
|
|
||||||
use wayland_protocols_wlr::output_management::v1::client::zwlr_output_head_v1::{
|
|
||||||
self, Event as WlrHeadEvent, ZwlrOutputHeadV1,
|
|
||||||
};
|
|
||||||
use wayland_protocols_wlr::output_management::v1::client::zwlr_output_manager_v1::{
|
|
||||||
self, Event as WlrOutputManagerEvent, ZwlrOutputManagerV1,
|
|
||||||
};
|
|
||||||
use wayland_protocols_wlr::output_management::v1::client::zwlr_output_mode_v1::ZwlrOutputModeV1;
|
|
||||||
use wayland_protocols_wlr::screencopy::v1::client::zwlr_screencopy_frame_v1::{
|
|
||||||
Event as ScreencopyFrameEvent, ZwlrScreencopyFrameV1,
|
|
||||||
};
|
|
||||||
use wayland_protocols_wlr::screencopy::v1::client::zwlr_screencopy_manager_v1::ZwlrScreencopyManagerV1;
|
use wayland_protocols_wlr::screencopy::v1::client::zwlr_screencopy_manager_v1::ZwlrScreencopyManagerV1;
|
||||||
|
|
||||||
use ffmpeg_next as ff;
|
use ffmpeg_next as ff;
|
||||||
@@ -44,12 +26,13 @@ use ffmpeg_next::ffi;
|
|||||||
|
|
||||||
use crate::args::Args;
|
use crate::args::Args;
|
||||||
use crate::avhw::{AvHwDevCtx, EncState, EncodedH264Frame, SwEncState};
|
use crate::avhw::{AvHwDevCtx, EncState, EncodedH264Frame, SwEncState};
|
||||||
use crate::cap_wlr_screencopy::CapWlrScreencopy;
|
|
||||||
use crate::fps_limit::FpsLimit;
|
use crate::fps_limit::FpsLimit;
|
||||||
use crate::stats::{FrameTimings, PipelineStats};
|
use crate::stats::{FrameTimings, PipelineStats};
|
||||||
use crate::transform::{transpose_if_transform_transposed, Transform};
|
use crate::transform::{transpose_if_transform_transposed, Transform};
|
||||||
use crate::webrtc::WebRtcState;
|
use crate::webrtc::WebRtcState;
|
||||||
|
|
||||||
|
mod dispatch;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// CaptureSource trait
|
// CaptureSource trait
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -1014,581 +997,3 @@ impl<S: CaptureSource> State<S> {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// Dispatch<WlRegistry, GlobalListContents>
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
impl<S: CaptureSource> Dispatch<WlRegistry, GlobalListContents> for State<S> {
|
|
||||||
fn event(
|
|
||||||
state: &mut Self,
|
|
||||||
registry: &WlRegistry,
|
|
||||||
event: wayland_client::protocol::wl_registry::Event,
|
|
||||||
_data: &GlobalListContents,
|
|
||||||
_conn: &wayland_client::Connection,
|
|
||||||
qhandle: &QueueHandle<State<S>>,
|
|
||||||
) {
|
|
||||||
use wayland_client::protocol::wl_registry::Event as RegistryEvent;
|
|
||||||
|
|
||||||
match event {
|
|
||||||
RegistryEvent::Global {
|
|
||||||
name,
|
|
||||||
interface,
|
|
||||||
version,
|
|
||||||
} => match interface.as_str() {
|
|
||||||
"zwlr_screencopy_manager_v1" => {
|
|
||||||
let v = version.min(3);
|
|
||||||
tracing::debug!("Binding zwlr_screencopy_manager_v1 v{v} (name={name})");
|
|
||||||
let mgr: ZwlrScreencopyManagerV1 = registry.bind(name, v, qhandle, ());
|
|
||||||
if let EncConstructionStage::ProbingOutputs {
|
|
||||||
screencopy_manager, ..
|
|
||||||
} = &mut state.stage
|
|
||||||
{
|
|
||||||
*screencopy_manager = Some(mgr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"zwp_linux_dmabuf_v1" => {
|
|
||||||
let v = version.min(4);
|
|
||||||
tracing::debug!("Binding zwp_linux_dmabuf_v1 v{v} (name={name})");
|
|
||||||
let proxy: ZwpLinuxDmabufV1 = registry.bind(name, v, qhandle, ());
|
|
||||||
if let EncConstructionStage::ProbingOutputs {
|
|
||||||
dmabuf,
|
|
||||||
dmabuf_feedback,
|
|
||||||
..
|
|
||||||
} = &mut state.stage
|
|
||||||
{
|
|
||||||
*dmabuf = Some(proxy.clone());
|
|
||||||
if v >= 4 {
|
|
||||||
let feedback = proxy.get_default_feedback(qhandle, ());
|
|
||||||
*dmabuf_feedback = Some(feedback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"wl_output" => {
|
|
||||||
let v = version.min(4);
|
|
||||||
tracing::debug!("Binding wl_output v{v} (name={name})");
|
|
||||||
let output: WlOutput = registry.bind(name, v, qhandle, OutputId(name));
|
|
||||||
if let EncConstructionStage::ProbingOutputs {
|
|
||||||
outputs,
|
|
||||||
bound_outputs,
|
|
||||||
output_names,
|
|
||||||
xdg_output_manager,
|
|
||||||
..
|
|
||||||
} = &mut state.stage
|
|
||||||
{
|
|
||||||
outputs.push(PartialOutputInfo::default());
|
|
||||||
bound_outputs.push(output.clone());
|
|
||||||
output_names.push(name);
|
|
||||||
if let Some(xdg_mgr) = xdg_output_manager {
|
|
||||||
let output_id = OutputId(name);
|
|
||||||
xdg_mgr.get_xdg_output(&output, qhandle, output_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"zxdg_output_manager_v1" => {
|
|
||||||
let v = version.min(3);
|
|
||||||
tracing::debug!("Binding zxdg_output_manager_v1 v{v} (name={name})");
|
|
||||||
let xdg_mgr: ZxdgOutputManagerV1 = registry.bind(name, v, qhandle, ());
|
|
||||||
if let EncConstructionStage::ProbingOutputs {
|
|
||||||
bound_outputs,
|
|
||||||
xdg_output_manager,
|
|
||||||
output_names,
|
|
||||||
..
|
|
||||||
} = &mut state.stage
|
|
||||||
{
|
|
||||||
for (i, output) in bound_outputs.iter().enumerate() {
|
|
||||||
let oname = output_names.get(i).copied().unwrap_or(0);
|
|
||||||
let output_id = OutputId(oname);
|
|
||||||
xdg_mgr.get_xdg_output(output, qhandle, output_id);
|
|
||||||
}
|
|
||||||
*xdg_output_manager = Some(xdg_mgr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"zwlr_output_manager_v1" => {
|
|
||||||
let v = version.min(4);
|
|
||||||
tracing::debug!("Binding zwlr_output_manager_v1 v{v} (name={name})");
|
|
||||||
let mgr: ZwlrOutputManagerV1 = registry.bind(name, v, qhandle, ());
|
|
||||||
if let EncConstructionStage::ProbingOutputs {
|
|
||||||
wlr_output_manager, ..
|
|
||||||
} = &mut state.stage
|
|
||||||
{
|
|
||||||
*wlr_output_manager = Some(mgr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
RegistryEvent::GlobalRemove { name } => {
|
|
||||||
tracing::debug!("Global removed: name={name}");
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// Dispatch<WlOutput, ()>
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
impl<S: CaptureSource> Dispatch<WlOutput, OutputId> for State<S> {
|
|
||||||
fn event(
|
|
||||||
state: &mut Self,
|
|
||||||
_proxy: &WlOutput,
|
|
||||||
event: wayland_client::protocol::wl_output::Event,
|
|
||||||
data: &OutputId,
|
|
||||||
_conn: &wayland_client::Connection,
|
|
||||||
_qhandle: &QueueHandle<State<S>>,
|
|
||||||
) {
|
|
||||||
use wayland_client::protocol::wl_output::Event as OutputEvent;
|
|
||||||
use wayland_client::protocol::wl_output::Mode as WlMode;
|
|
||||||
use wayland_client::protocol::wl_output::Transform as WlTransform;
|
|
||||||
|
|
||||||
let OutputId(target_name) = data;
|
|
||||||
let idx = match &state.stage {
|
|
||||||
EncConstructionStage::ProbingOutputs { output_names, .. } => {
|
|
||||||
output_names.iter().position(|&n| n == *target_name)
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
let idx = match idx {
|
|
||||||
Some(i) => i,
|
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
|
|
||||||
match event {
|
|
||||||
OutputEvent::Geometry { transform, .. } => {
|
|
||||||
let t = match transform {
|
|
||||||
wayland_client::WEnum::Value(WlTransform::Normal) => Transform::Normal,
|
|
||||||
wayland_client::WEnum::Value(WlTransform::_90) => Transform::Normal90,
|
|
||||||
wayland_client::WEnum::Value(WlTransform::_180) => Transform::Normal180,
|
|
||||||
wayland_client::WEnum::Value(WlTransform::_270) => Transform::Normal270,
|
|
||||||
wayland_client::WEnum::Value(WlTransform::Flipped) => Transform::Flipped,
|
|
||||||
wayland_client::WEnum::Value(WlTransform::Flipped90) => Transform::Flipped90,
|
|
||||||
wayland_client::WEnum::Value(WlTransform::Flipped180) => Transform::Flipped180,
|
|
||||||
wayland_client::WEnum::Value(WlTransform::Flipped270) => Transform::Flipped270,
|
|
||||||
_ => Transform::Normal,
|
|
||||||
};
|
|
||||||
if let EncConstructionStage::ProbingOutputs { outputs, .. } = &mut state.stage {
|
|
||||||
if let Some(info) = outputs.get_mut(idx) {
|
|
||||||
info.transform = Some(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OutputEvent::Mode {
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
flags,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
let is_current = matches!(flags, wayland_client::WEnum::Value(WlMode::Current));
|
|
||||||
if is_current {
|
|
||||||
if let EncConstructionStage::ProbingOutputs { outputs, .. } = &mut state.stage {
|
|
||||||
if let Some(info) = outputs.get_mut(idx) {
|
|
||||||
info.mode_size = Some((width, height));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OutputEvent::Done => {
|
|
||||||
if let EncConstructionStage::ProbingOutputs { outputs, .. } = &mut state.stage {
|
|
||||||
if let Some(info) = outputs.get_mut(idx) {
|
|
||||||
info.done_count += 1;
|
|
||||||
if info.done_count >= 1 {
|
|
||||||
state.try_finalize_output(idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OutputEvent::Name { name } => {
|
|
||||||
if let EncConstructionStage::ProbingOutputs { outputs, .. } = &mut state.stage {
|
|
||||||
if let Some(info) = outputs.get_mut(idx) {
|
|
||||||
info.wl_name = Some(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// Dispatch<ZxdgOutputV1, OutputId>
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
impl<S: CaptureSource> Dispatch<ZxdgOutputV1, OutputId> for State<S> {
|
|
||||||
fn event(
|
|
||||||
state: &mut Self,
|
|
||||||
_proxy: &ZxdgOutputV1,
|
|
||||||
event: <ZxdgOutputV1 as Proxy>::Event,
|
|
||||||
data: &OutputId,
|
|
||||||
_conn: &wayland_client::Connection,
|
|
||||||
_qhandle: &QueueHandle<State<S>>,
|
|
||||||
) {
|
|
||||||
let target_name = data.0;
|
|
||||||
let idx = match &state.stage {
|
|
||||||
EncConstructionStage::ProbingOutputs { output_names, .. } => {
|
|
||||||
output_names.iter().position(|&n| n == target_name)
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
let idx = match idx {
|
|
||||||
Some(i) => i,
|
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
|
|
||||||
match event {
|
|
||||||
XdgOutputEvent::Name { name } => {
|
|
||||||
if let EncConstructionStage::ProbingOutputs { outputs, .. } = &mut state.stage {
|
|
||||||
if let Some(info) = outputs.get_mut(idx) {
|
|
||||||
info.name = Some(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
XdgOutputEvent::LogicalSize { .. } => {}
|
|
||||||
XdgOutputEvent::Done => {
|
|
||||||
if let EncConstructionStage::ProbingOutputs { outputs, .. } = &mut state.stage {
|
|
||||||
if let Some(info) = outputs.get_mut(idx) {
|
|
||||||
info.done_count += 1;
|
|
||||||
if info.done_count >= 1 {
|
|
||||||
state.try_finalize_output(idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// Dispatch<ZwpLinuxDmabufV1, ()>
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
impl<S: CaptureSource> Dispatch<ZwpLinuxDmabufV1, ()> for State<S> {
|
|
||||||
fn event(
|
|
||||||
_state: &mut Self,
|
|
||||||
_proxy: &ZwpLinuxDmabufV1,
|
|
||||||
event: <ZwpLinuxDmabufV1 as Proxy>::Event,
|
|
||||||
_data: &(),
|
|
||||||
_conn: &wayland_client::Connection,
|
|
||||||
_qhandle: &QueueHandle<State<S>>,
|
|
||||||
) {
|
|
||||||
match event {
|
|
||||||
DmabufEvent::Format { .. } => {}
|
|
||||||
DmabufEvent::Modifier { .. } => {}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: CaptureSource> Dispatch<ZwpLinuxDmabufFeedbackV1, ()> for State<S> {
|
|
||||||
fn event(
|
|
||||||
state: &mut Self,
|
|
||||||
_proxy: &ZwpLinuxDmabufFeedbackV1,
|
|
||||||
event: <ZwpLinuxDmabufFeedbackV1 as Proxy>::Event,
|
|
||||||
_data: &(),
|
|
||||||
_conn: &wayland_client::Connection,
|
|
||||||
_qhandle: &QueueHandle<State<S>>,
|
|
||||||
) {
|
|
||||||
match event {
|
|
||||||
DmabufFeedbackEvent::MainDevice { device } => {
|
|
||||||
if device.len() >= 8 {
|
|
||||||
let dev_bytes: [u8; 8] = device[..8].try_into().unwrap_or([0u8; 8]);
|
|
||||||
let dev = u64::from_ne_bytes(dev_bytes);
|
|
||||||
let minor = ((dev & 0xFF) | ((dev >> 12) & 0xFFFFFF00)) as u32;
|
|
||||||
let path = PathBuf::from(format!("/dev/dri/renderD{}", minor));
|
|
||||||
if path.exists() {
|
|
||||||
tracing::info!(
|
|
||||||
"Compositor DRM device: {} (dev_t: {})",
|
|
||||||
path.display(),
|
|
||||||
dev
|
|
||||||
);
|
|
||||||
state.drm_device_from_compositor = Some(path);
|
|
||||||
} else {
|
|
||||||
tracing::warn!(
|
|
||||||
"Compositor reported DRM device {} (dev_t: {}) but path does not exist",
|
|
||||||
path.display(),
|
|
||||||
dev
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tracing::warn!(
|
|
||||||
"main_device event with unexpected data length: {}",
|
|
||||||
device.len()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DmabufFeedbackEvent::FormatTable { .. } => {}
|
|
||||||
DmabufFeedbackEvent::Done => {}
|
|
||||||
DmabufFeedbackEvent::TrancheDone => {}
|
|
||||||
DmabufFeedbackEvent::TrancheTargetDevice { .. } => {}
|
|
||||||
DmabufFeedbackEvent::TrancheFormats { .. } => {}
|
|
||||||
DmabufFeedbackEvent::TrancheFlags { .. } => {}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// Dispatch<ZwpLinuxBufferParamsV1, ()>
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
impl<S: CaptureSource> Dispatch<ZwpLinuxBufferParamsV1, ()> for State<S> {
|
|
||||||
fn event(
|
|
||||||
state: &mut Self,
|
|
||||||
proxy: &ZwpLinuxBufferParamsV1,
|
|
||||||
event: <ZwpLinuxBufferParamsV1 as Proxy>::Event,
|
|
||||||
_data: &(),
|
|
||||||
_conn: &wayland_client::Connection,
|
|
||||||
_qhandle: &QueueHandle<State<S>>,
|
|
||||||
) {
|
|
||||||
match event {
|
|
||||||
BufferParamsEvent::Created { .. } => {
|
|
||||||
tracing::debug!("DMA-BUF buffer created");
|
|
||||||
}
|
|
||||||
BufferParamsEvent::Failed => {
|
|
||||||
tracing::error!("DMA-BUF buffer creation failed");
|
|
||||||
let taken = mem::replace(&mut state.in_flight_surface, InFlightSurface::None);
|
|
||||||
match taken {
|
|
||||||
InFlightSurface::CopyQueued { buffer, frame, .. } => {
|
|
||||||
drop(buffer);
|
|
||||||
if let EncConstructionStage::Streaming { cap, .. } = &mut state.stage {
|
|
||||||
cap.on_done_with_frame(frame);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
other => {
|
|
||||||
state.in_flight_surface = other;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
proxy.destroy();
|
|
||||||
state.errored = true;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// Dispatch<ZwlrScreencopyFrameV1, ()> for CapWlrScreencopy
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
impl Dispatch<ZwlrScreencopyFrameV1, ()> for State<CapWlrScreencopy> {
|
|
||||||
fn event(
|
|
||||||
state: &mut Self,
|
|
||||||
proxy: &ZwlrScreencopyFrameV1,
|
|
||||||
event: <ZwlrScreencopyFrameV1 as Proxy>::Event,
|
|
||||||
_data: &(),
|
|
||||||
_conn: &wayland_client::Connection,
|
|
||||||
_qhandle: &QueueHandle<State<CapWlrScreencopy>>,
|
|
||||||
) {
|
|
||||||
match event {
|
|
||||||
// SHM buffer offer — in v3 the compositor enumerates supported buffer
|
|
||||||
// types (buffer and/or linux_dmabuf) before buffer_done. We only
|
|
||||||
// support DMA-BUF, so just log and wait for linux_dmabuf / buffer_done.
|
|
||||||
ScreencopyFrameEvent::Buffer { .. } => {
|
|
||||||
tracing::debug!("Received SHM Buffer offer — only DMA-BUF capture is supported");
|
|
||||||
}
|
|
||||||
ScreencopyFrameEvent::LinuxDmabuf {
|
|
||||||
format,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
} => {
|
|
||||||
tracing::debug!("Screencopy LinuxDmabuf: format={format}, {width}x{height}");
|
|
||||||
|
|
||||||
if !matches!(state.in_flight_surface, InFlightSurface::AllocQueued) {
|
|
||||||
tracing::warn!("Received LinuxDmabuf while no frame allocation was queued");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if matches!(state.stage, EncConstructionStage::EverythingButFmt { .. }) {
|
|
||||||
state.negotiate_format(format, width, height);
|
|
||||||
if state.errored {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let EncConstructionStage::Streaming { cap, .. } = &mut state.stage {
|
|
||||||
cap.current_frame = Some(proxy.clone());
|
|
||||||
}
|
|
||||||
state.on_frame_allocd((), format, width, height);
|
|
||||||
}
|
|
||||||
// v3 terminal event: all buffer offers have been enumerated.
|
|
||||||
// If still AllocQueued, the compositor never sent linux_dmabuf —
|
|
||||||
// DMA-BUF screencopy is unsupported, so we must error out.
|
|
||||||
ScreencopyFrameEvent::BufferDone => {
|
|
||||||
if matches!(state.in_flight_surface, InFlightSurface::AllocQueued) {
|
|
||||||
tracing::error!(
|
|
||||||
"Compositor did not offer DMA-BUF screencopy (only SHM); \
|
|
||||||
DMA-BUF capture is required"
|
|
||||||
);
|
|
||||||
state.in_flight_surface = InFlightSurface::None;
|
|
||||||
proxy.destroy();
|
|
||||||
state.errored = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ScreencopyFrameEvent::Ready {
|
|
||||||
tv_sec_hi,
|
|
||||||
tv_sec_lo,
|
|
||||||
tv_nsec,
|
|
||||||
} => {
|
|
||||||
let tv_sec = (tv_sec_hi as u64) << 32 | tv_sec_lo as u64;
|
|
||||||
let tv_usec = tv_nsec / 1000;
|
|
||||||
tracing::trace!("Screencopy ready: tv_sec={tv_sec}, tv_usec={tv_usec}");
|
|
||||||
state.on_copy_complete(tv_sec, tv_usec);
|
|
||||||
}
|
|
||||||
ScreencopyFrameEvent::Failed => {
|
|
||||||
tracing::error!("Screencopy frame failed");
|
|
||||||
state.on_copy_fail();
|
|
||||||
}
|
|
||||||
ScreencopyFrameEvent::Damage { .. } => {}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// Dispatch<ZxdgOutputManagerV1, ()>
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
impl<S: CaptureSource> Dispatch<ZxdgOutputManagerV1, ()> for State<S> {
|
|
||||||
fn event(
|
|
||||||
_state: &mut Self,
|
|
||||||
_proxy: &ZxdgOutputManagerV1,
|
|
||||||
_event: <ZxdgOutputManagerV1 as Proxy>::Event,
|
|
||||||
_data: &(),
|
|
||||||
_conn: &wayland_client::Connection,
|
|
||||||
_qhandle: &QueueHandle<State<S>>,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// Dispatch<ZwlrOutputManagerV1, ()>
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
impl<S: CaptureSource> Dispatch<ZwlrOutputManagerV1, ()> for State<S> {
|
|
||||||
fn event(
|
|
||||||
state: &mut Self,
|
|
||||||
_proxy: &ZwlrOutputManagerV1,
|
|
||||||
event: <ZwlrOutputManagerV1 as Proxy>::Event,
|
|
||||||
_data: &(),
|
|
||||||
_conn: &wayland_client::Connection,
|
|
||||||
_qhandle: &QueueHandle<State<S>>,
|
|
||||||
) {
|
|
||||||
match event {
|
|
||||||
WlrOutputManagerEvent::Head { head } => {
|
|
||||||
let _head: ZwlrOutputHeadV1 = head;
|
|
||||||
tracing::debug!("wlr output head advertised");
|
|
||||||
}
|
|
||||||
WlrOutputManagerEvent::Done { .. } => {
|
|
||||||
if let EncConstructionStage::ProbingOutputs {
|
|
||||||
wlr_manager_done,
|
|
||||||
outputs,
|
|
||||||
..
|
|
||||||
} = &mut state.stage
|
|
||||||
{
|
|
||||||
*wlr_manager_done = true;
|
|
||||||
let count = outputs.len();
|
|
||||||
for idx in 0..count {
|
|
||||||
state.try_finalize_output(idx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WlrOutputManagerEvent::Finished => {
|
|
||||||
tracing::warn!("zwlr_output_manager_v1::Finished received during probing");
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
event_created_child!(State<S>, ZwlrOutputManagerV1, [
|
|
||||||
zwlr_output_manager_v1::EVT_HEAD_OPCODE => (ZwlrOutputHeadV1, ()),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// Dispatch<ZwlrOutputHeadV1, ()>
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
impl<S: CaptureSource> Dispatch<ZwlrOutputHeadV1, ()> for State<S> {
|
|
||||||
fn event(
|
|
||||||
state: &mut Self,
|
|
||||||
proxy: &ZwlrOutputHeadV1,
|
|
||||||
event: <ZwlrOutputHeadV1 as Proxy>::Event,
|
|
||||||
_data: &(),
|
|
||||||
_conn: &wayland_client::Connection,
|
|
||||||
_qhandle: &QueueHandle<State<S>>,
|
|
||||||
) {
|
|
||||||
match event {
|
|
||||||
WlrHeadEvent::Name { name } => {
|
|
||||||
if let EncConstructionStage::ProbingOutputs {
|
|
||||||
wlr_heads,
|
|
||||||
wlr_head_proxy_to_name,
|
|
||||||
..
|
|
||||||
} = &mut state.stage
|
|
||||||
{
|
|
||||||
wlr_heads.entry(name.clone()).or_insert(WlrHeadInfo {});
|
|
||||||
wlr_head_proxy_to_name.insert(proxy.id(), name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WlrHeadEvent::Position { .. } => {}
|
|
||||||
WlrHeadEvent::Finished => {
|
|
||||||
tracing::debug!("zwlr_output_head_v1::Finished received");
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
event_created_child!(State<S>, ZwlrOutputHeadV1, [
|
|
||||||
zwlr_output_head_v1::EVT_MODE_OPCODE => (ZwlrOutputModeV1, ()),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// Dispatch<ZwlrOutputModeV1, ()>
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
impl<S: CaptureSource> Dispatch<ZwlrOutputModeV1, ()> for State<S> {
|
|
||||||
fn event(
|
|
||||||
_state: &mut Self,
|
|
||||||
_proxy: &ZwlrOutputModeV1,
|
|
||||||
_event: <ZwlrOutputModeV1 as Proxy>::Event,
|
|
||||||
_data: &(),
|
|
||||||
_conn: &wayland_client::Connection,
|
|
||||||
_qhandle: &QueueHandle<State<S>>,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// Dispatch<ZwlrScreencopyManagerV1, ()>
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
impl<S: CaptureSource> Dispatch<ZwlrScreencopyManagerV1, ()> for State<S> {
|
|
||||||
fn event(
|
|
||||||
_state: &mut Self,
|
|
||||||
_proxy: &ZwlrScreencopyManagerV1,
|
|
||||||
_event: <ZwlrScreencopyManagerV1 as Proxy>::Event,
|
|
||||||
_data: &(),
|
|
||||||
_conn: &wayland_client::Connection,
|
|
||||||
_qhandle: &QueueHandle<State<S>>,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// Dispatch<WlBuffer, ()>
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
impl<S: CaptureSource> Dispatch<WlBuffer, ()> for State<S> {
|
|
||||||
fn event(
|
|
||||||
_state: &mut Self,
|
|
||||||
_proxy: &WlBuffer,
|
|
||||||
event: <WlBuffer as Proxy>::Event,
|
|
||||||
_data: &(),
|
|
||||||
_conn: &wayland_client::Connection,
|
|
||||||
_qhandle: &QueueHandle<State<S>>,
|
|
||||||
) {
|
|
||||||
if let wayland_client::protocol::wl_buffer::Event::Release = event {
|
|
||||||
tracing::trace!("WlBuffer released");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user