docs(state): [3/3] 中文注释 state.rs 帧捕获与输出管理
This commit is contained in:
@@ -1854,7 +1854,18 @@ impl<S: CaptureSource> Dispatch<ZwpLinuxBufferParamsV1, ()> for State<S> {
|
|||||||
// Dispatch<ZwlrScreencopyFrameV1, ()> for CapWlrScreencopy
|
// Dispatch<ZwlrScreencopyFrameV1, ()> for CapWlrScreencopy
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// 注意本 impl 的 receiver 是 `State<CapWlrScreencopy>`(具体类型)而非 `State<S: CaptureSource>`
|
||||||
|
// (泛型)——wlr-screencopy 协议是 wlroots 后端独有,Portal/PipeWire 路径不会触发本事件。
|
||||||
|
// 把 Dispatch 限定到具体 State<CapWlrScreencopy> 后,编译器只在 wlr 路径编译此分支,
|
||||||
|
// Portal 路径不会误捕获 ZwlrScreencopyFrameV1 事件(类型系统层面的后端隔离)。
|
||||||
|
// 协议语义:截屏一帧从 capture_destruction 之外的所有事件都通过本 protocol 对象回送:
|
||||||
|
// Buffer/LinuxDmabuf(compositor 列出支持的 buffer 类型)→ BufferDone(v3 终止事件)
|
||||||
|
// → Ready(成功,附 PTS)/ Failed(失败)/ Damage(脏矩形,本实现不消费)。
|
||||||
|
// 状态机交互:LinuxDmabuf 触发 negotiate_format + on_frame_allocd(分配 AVHwFrames);
|
||||||
|
// Ready 触发 on_copy_complete(送入编码器);BufferDone 收到却没 LinuxDmabuf → 报错。
|
||||||
impl Dispatch<ZwlrScreencopyFrameV1, ()> for State<CapWlrScreencopy> {
|
impl Dispatch<ZwlrScreencopyFrameV1, ()> for State<CapWlrScreencopy> {
|
||||||
|
// 参数 `proxy: &ZwlrScreencopyFrameV1`:本帧的 protocol 对象,ready 后用 proxy.destroy() 释放。
|
||||||
|
// 参数 `_qhandle`:本 impl 内不创建子对象,所以队列句柄未用(前缀 `_`)。
|
||||||
fn event(
|
fn event(
|
||||||
state: &mut Self,
|
state: &mut Self,
|
||||||
proxy: &ZwlrScreencopyFrameV1,
|
proxy: &ZwlrScreencopyFrameV1,
|
||||||
@@ -1863,13 +1874,18 @@ impl Dispatch<ZwlrScreencopyFrameV1, ()> for State<CapWlrScreencopy> {
|
|||||||
_conn: &wayland_client::Connection,
|
_conn: &wayland_client::Connection,
|
||||||
_qhandle: &QueueHandle<State<CapWlrScreencopy>>,
|
_qhandle: &QueueHandle<State<CapWlrScreencopy>>,
|
||||||
) {
|
) {
|
||||||
|
// ScreencopyFrameEvent 是 wayland-scanner 生成的 enum,包含本帧生命周期所有事件。
|
||||||
match event {
|
match event {
|
||||||
// SHM buffer offer — in v3 the compositor enumerates supported buffer
|
// SHM buffer offer — in v3 the compositor enumerates supported buffer
|
||||||
// types (buffer and/or linux_dmabuf) before buffer_done. We only
|
// types (buffer and/or linux_dmabuf) before buffer_done. We only
|
||||||
// support DMA-BUF, so just log and wait for linux_dmabuf / buffer_done.
|
// support DMA-BUF, so just log and wait for linux_dmabuf / buffer_done.
|
||||||
|
// 上方英文注释保留:compositor 在 v3 协议中先广播所有可用 buffer 类型,再发 BufferDone。
|
||||||
|
// 本实现只支持 DMA-BUF(零拷贝),SHM 路径只用 debug 日志记录后忽略。
|
||||||
ScreencopyFrameEvent::Buffer { .. } => {
|
ScreencopyFrameEvent::Buffer { .. } => {
|
||||||
tracing::debug!("Received SHM Buffer offer — only DMA-BUF capture is supported");
|
tracing::debug!("Received SHM Buffer offer — only DMA-BUF capture is supported");
|
||||||
}
|
}
|
||||||
|
// LinuxDmabuf:compositor 愿意把帧写到 DMA-BUF。format 是 DRM fourcc(如 XRGB8888),
|
||||||
|
// width/height 是 buffer 尺寸(物理像素)。
|
||||||
ScreencopyFrameEvent::LinuxDmabuf {
|
ScreencopyFrameEvent::LinuxDmabuf {
|
||||||
format,
|
format,
|
||||||
width,
|
width,
|
||||||
@@ -1877,51 +1893,74 @@ impl Dispatch<ZwlrScreencopyFrameV1, ()> for State<CapWlrScreencopy> {
|
|||||||
} => {
|
} => {
|
||||||
tracing::debug!("Screencopy LinuxDmabuf: format={format}, {width}x{height}");
|
tracing::debug!("Screencopy LinuxDmabuf: format={format}, {width}x{height}");
|
||||||
|
|
||||||
|
// 守卫:若 in_flight_surface 不是 AllocQueued,说明这个 LinuxDmabuf 是迟到的
|
||||||
|
// 或重复的事件,按协议不该再处理。直接 return 不更新状态。
|
||||||
if !matches!(state.in_flight_surface, InFlightSurface::AllocQueued) {
|
if !matches!(state.in_flight_surface, InFlightSurface::AllocQueued) {
|
||||||
tracing::warn!("Received LinuxDmabuf while no frame allocation was queued");
|
tracing::warn!("Received LinuxDmabuf while no frame allocation was queued");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EverythingButFmt 阶段:第一帧需要 negotiate_format 完成 EncConstructionStage
|
||||||
|
// 切换(建编码器、配 VAAPI 上下文)。后续帧直接复用已建好的 cap。
|
||||||
if matches!(state.stage, EncConstructionStage::EverythingButFmt { .. }) {
|
if matches!(state.stage, EncConstructionStage::EverythingButFmt { .. }) {
|
||||||
state.negotiate_format(format, width, height);
|
state.negotiate_format(format, width, height);
|
||||||
|
// negotiate_format 内部失败会把 state.errored 置 true,提前 return 避免后续
|
||||||
|
// on_frame_allocd 访问未初始化的硬件帧上下文。
|
||||||
if state.errored {
|
if state.errored {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Streaming 阶段:把当前帧的 proxy 存入 cap.current_frame,ready 后用它 destroy。
|
||||||
|
// proxy.clone() 增加 wayland proxy 引用计数(不复制底层数据)。
|
||||||
if let EncConstructionStage::Streaming { cap, .. } = &mut state.stage {
|
if let EncConstructionStage::Streaming { cap, .. } = &mut state.stage {
|
||||||
cap.current_frame = Some(proxy.clone());
|
cap.current_frame = Some(proxy.clone());
|
||||||
}
|
}
|
||||||
|
// 调度硬件帧分配(AVHwFramesContext + av_hwframe_get_buffer),完成后 in_flight_surface
|
||||||
|
// 切换为 AllocatedDma。wlr 路径的 user_data 是 () (无 PipeWire serial)。
|
||||||
state.on_frame_allocd((), format, width, height);
|
state.on_frame_allocd((), format, width, height);
|
||||||
}
|
}
|
||||||
// v3 terminal event: all buffer offers have been enumerated.
|
// v3 terminal event: all buffer offers have been enumerated.
|
||||||
// If still AllocQueued, the compositor never sent linux_dmabuf —
|
// If still AllocQueued, the compositor never sent linux_dmabuf —
|
||||||
// DMA-BUF screencopy is unsupported, so we must error out.
|
// DMA-BUF screencopy is unsupported, so we must error out.
|
||||||
|
// 上方英文注释保留:BufferDone 是 v3 新增的终止事件。如果到这里 in_flight_surface 还是
|
||||||
|
// AllocQueued,说明 compositor 没发 LinuxDmabuf(不支持 DMA-BUF 截屏),必须报错退出。
|
||||||
ScreencopyFrameEvent::BufferDone => {
|
ScreencopyFrameEvent::BufferDone => {
|
||||||
if matches!(state.in_flight_surface, InFlightSurface::AllocQueued) {
|
if matches!(state.in_flight_surface, InFlightSurface::AllocQueued) {
|
||||||
tracing::error!(
|
tracing::error!(
|
||||||
"Compositor did not offer DMA-BUF screencopy (only SHM); \
|
"Compositor did not offer DMA-BUF screencopy (only SHM); \
|
||||||
DMA-BUF capture is required"
|
DMA-BUF capture is required"
|
||||||
);
|
);
|
||||||
|
// 状态机回滚:清空 in_flight_surface,销毁 proxy,置 errored 让主循环退出。
|
||||||
state.in_flight_surface = InFlightSurface::None;
|
state.in_flight_surface = InFlightSurface::None;
|
||||||
proxy.destroy();
|
proxy.destroy();
|
||||||
state.errored = true;
|
state.errored = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Ready:compositor 已完成本帧 copy。tv_sec_hi/tv_sec_lo 是 64 位时间戳被拆成两个
|
||||||
|
// 32 位字段(Wayland 协议原生只支持 32 位 u32,所以 u64 必须拆 hi/lo)。
|
||||||
|
// tv_nsec 是纳秒分量(0..1_000_000_000)。
|
||||||
ScreencopyFrameEvent::Ready {
|
ScreencopyFrameEvent::Ready {
|
||||||
tv_sec_hi,
|
tv_sec_hi,
|
||||||
tv_sec_lo,
|
tv_sec_lo,
|
||||||
tv_nsec,
|
tv_nsec,
|
||||||
} => {
|
} => {
|
||||||
|
// 重组 u64:高 32 位左移 32 + 低 32 位 OR(Wayland 协议常用模式)。
|
||||||
let tv_sec = (tv_sec_hi as u64) << 32 | tv_sec_lo as u64;
|
let tv_sec = (tv_sec_hi as u64) << 32 | tv_sec_lo as u64;
|
||||||
|
// 转 microsecond(FFmpeg PTS 用 μs),向下取整不影响 90kHz 时钟精度。
|
||||||
let tv_usec = tv_nsec / 1000;
|
let tv_usec = tv_nsec / 1000;
|
||||||
tracing::trace!("Screencopy ready: tv_sec={tv_sec}, tv_usec={tv_usec}");
|
tracing::trace!("Screencopy ready: tv_sec={tv_sec}, tv_usec={tv_usec}");
|
||||||
|
// on_copy_complete:取出已分配的 dmabuf 帧、计算 PTS、送入编码器、调度下一帧。
|
||||||
state.on_copy_complete(tv_sec, tv_usec);
|
state.on_copy_complete(tv_sec, tv_usec);
|
||||||
}
|
}
|
||||||
|
// Failed:compositor 报告本帧 copy 失败(如资源争用、buffer 不可用)。
|
||||||
|
// on_copy_fail 会重置 in_flight_surface 并安排重试(不直接终止流水线)。
|
||||||
ScreencopyFrameEvent::Failed => {
|
ScreencopyFrameEvent::Failed => {
|
||||||
tracing::error!("Screencopy frame failed");
|
tracing::error!("Screencopy frame failed");
|
||||||
state.on_copy_fail();
|
state.on_copy_fail();
|
||||||
}
|
}
|
||||||
|
// Damage 事件:compositor 报告本帧脏矩形区域。截屏全帧采集,无需增量更新,忽略。
|
||||||
ScreencopyFrameEvent::Damage { .. } => {}
|
ScreencopyFrameEvent::Damage { .. } => {}
|
||||||
|
// 兜底 arm:未来协议版本新增事件时不会编译失败(向前兼容)。
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1931,6 +1970,10 @@ impl Dispatch<ZwlrScreencopyFrameV1, ()> for State<CapWlrScreencopy> {
|
|||||||
// Dispatch<ZxdgOutputManagerV1, ()>
|
// Dispatch<ZxdgOutputManagerV1, ()>
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// ZxdgOutputManagerV1 是 xdg-output 协议的工厂对象:客户端调用 get_xdg_output(wl_output)
|
||||||
|
// 创建 ZxdgOutputV1 子对象。manager 自身不发任何事件(仅响应请求),所以本 event() 空实现。
|
||||||
|
// 必须实现 Dispatch trait:wayland-client 要求每个 bind 的 protocol 都有对应 Dispatch impl,
|
||||||
|
// 否则编译期类型错误(即使 event 体为空,签名也要满足 trait contract)。
|
||||||
impl<S: CaptureSource> Dispatch<ZxdgOutputManagerV1, ()> for State<S> {
|
impl<S: CaptureSource> Dispatch<ZxdgOutputManagerV1, ()> for State<S> {
|
||||||
fn event(
|
fn event(
|
||||||
_state: &mut Self,
|
_state: &mut Self,
|
||||||
@@ -1947,6 +1990,12 @@ impl<S: CaptureSource> Dispatch<ZxdgOutputManagerV1, ()> for State<S> {
|
|||||||
// Dispatch<ZwlrOutputManagerV1, ()>
|
// Dispatch<ZwlrOutputManagerV1, ()>
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// ZwlrOutputManagerV1:wlr-output-management-unstable-v1 协议的顶层 manager。
|
||||||
|
// 协议语义:compositor 在 wl_registry 全局里广播本 manager;客户端 bind 后,
|
||||||
|
// compositor 会发出 Head(每个显示器一个 head proxy)/ Done(一轮快照完成)/ Finished
|
||||||
|
// 事件。客户端据此构建多显示器拓扑(位置、分辨率、命名)。
|
||||||
|
// 本实现用途:probing 阶段通过 head 的 Name/Position 事件为每个输出建立 WlrHeadInfo;
|
||||||
|
// Done 收齐后逐个 try_finalize_output 选定目标输出。运行期不再消费本协议事件。
|
||||||
impl<S: CaptureSource> Dispatch<ZwlrOutputManagerV1, ()> for State<S> {
|
impl<S: CaptureSource> Dispatch<ZwlrOutputManagerV1, ()> for State<S> {
|
||||||
fn event(
|
fn event(
|
||||||
state: &mut Self,
|
state: &mut Self,
|
||||||
@@ -1957,11 +2006,17 @@ impl<S: CaptureSource> Dispatch<ZwlrOutputManagerV1, ()> for State<S> {
|
|||||||
qhandle: &QueueHandle<State<S>>,
|
qhandle: &QueueHandle<State<S>>,
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
|
// Head 事件:compositor 新建一个 ZwlrOutputHeadV1 子对象。`head` 是 wayland-client
|
||||||
|
// 通过 event_created_child! 宏(见本 impl 末尾)自动 dispatch 到 Dispatch<ZwlrOutputHeadV1> 的。
|
||||||
WlrOutputManagerEvent::Head { head } => {
|
WlrOutputManagerEvent::Head { head } => {
|
||||||
|
// 显式类型注解 + let _ 绑定:wayland-client 自动生成的 head 类型在编译期才确定,
|
||||||
|
// 显式注解让读者知道类型;这里仅记录日志,不持有引用(head 已被 child dispatch 接管)。
|
||||||
let _head: ZwlrOutputHeadV1 = head;
|
let _head: ZwlrOutputHeadV1 = head;
|
||||||
tracing::debug!("wlr output head advertised");
|
tracing::debug!("wlr output head advertised");
|
||||||
}
|
}
|
||||||
|
// Done 事件:本轮 head 增删已全部上报,可以基于稳定快照做输出选择。
|
||||||
WlrOutputManagerEvent::Done { .. } => {
|
WlrOutputManagerEvent::Done { .. } => {
|
||||||
|
// 仅 ProbingOutputs 阶段响应 Done(运行期 Done 说明配置变更,本实现不支持热插拔)。
|
||||||
if let EncConstructionStage::ProbingOutputs {
|
if let EncConstructionStage::ProbingOutputs {
|
||||||
wlr_manager_done,
|
wlr_manager_done,
|
||||||
outputs,
|
outputs,
|
||||||
@@ -1969,12 +2024,14 @@ impl<S: CaptureSource> Dispatch<ZwlrOutputManagerV1, ()> for State<S> {
|
|||||||
} = &mut state.stage
|
} = &mut state.stage
|
||||||
{
|
{
|
||||||
*wlr_manager_done = true;
|
*wlr_manager_done = true;
|
||||||
|
// 遍历每个输出索引,尝试 finalize。try_finalize_output 内部会判断输出是否就绪。
|
||||||
let count = outputs.len();
|
let count = outputs.len();
|
||||||
for idx in 0..count {
|
for idx in 0..count {
|
||||||
state.try_finalize_output(idx);
|
state.try_finalize_output(idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Finished:compositor 主动关闭本 manager(通常 compositor 退出)。本实现仅 warn。
|
||||||
WlrOutputManagerEvent::Finished { .. } => {
|
WlrOutputManagerEvent::Finished { .. } => {
|
||||||
tracing::warn!("zwlr_output_manager_v1::Finished received during probing");
|
tracing::warn!("zwlr_output_manager_v1::Finished received during probing");
|
||||||
}
|
}
|
||||||
@@ -1982,6 +2039,11 @@ impl<S: CaptureSource> Dispatch<ZwlrOutputManagerV1, ()> for State<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// event_created_child! 是 wayland-client 提供的过程宏:当 manager 收到 Head 事件时,
|
||||||
|
// 自动把 EVT_HEAD_OPCODE 对应的子对象(ZwlrOutputHeadV1)注册到事件队列,
|
||||||
|
// 让 Dispatch<ZwlrOutputHeadV1>::event 接管子对象事件。
|
||||||
|
// 类比 Go 的 http.Handle 注册 handler,但这里是编译期生成的 dispatcher。
|
||||||
|
// 元组第二项 (ZwlrOutputHeadV1, ()) = (子对象类型, 子对象 user_data 类型)。
|
||||||
event_created_child!(State<S>, ZwlrOutputManagerV1, [
|
event_created_child!(State<S>, ZwlrOutputManagerV1, [
|
||||||
zwlr_output_manager_v1::EVT_HEAD_OPCODE => (ZwlrOutputHeadV1, ()),
|
zwlr_output_manager_v1::EVT_HEAD_OPCODE => (ZwlrOutputHeadV1, ()),
|
||||||
]);
|
]);
|
||||||
@@ -1991,6 +2053,14 @@ impl<S: CaptureSource> Dispatch<ZwlrOutputManagerV1, ()> for State<S> {
|
|||||||
// Dispatch<ZwlrOutputHeadV1, ()>
|
// Dispatch<ZwlrOutputHeadV1, ()>
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// ZwlrOutputHeadV1:单个显示器的 metadata 子对象(由 ZwlrOutputManagerV1::Head 事件创建)。
|
||||||
|
// 协议事件:Name(输出名,如 "eDP-1")/ Description / Position(x,y 偏移)/ Mode /
|
||||||
|
// Geometry / Finished(compositor 移除本输出)。本实现只消费 Name + Position。
|
||||||
|
// 状态交互:Name 写入 ProbingOutputs.wlr_heads(HashMap<name, WlrHeadInfo>),
|
||||||
|
// Position 更新对应 head 的 position 字段;try_finalize_output 用 head position 判断
|
||||||
|
// 多显示器场景下目标输出在虚拟桌面上的位置(决定截屏 ROI 起点)。
|
||||||
|
// 注意 Name 先到、Position 后到的事件顺序假设:实现用 wlr_head_proxy_to_name 临时映射
|
||||||
|
// proxy.id() → name,Position 事件到来时反查 name 再更新 wlr_heads。
|
||||||
impl<S: CaptureSource> Dispatch<ZwlrOutputHeadV1, ()> for State<S> {
|
impl<S: CaptureSource> Dispatch<ZwlrOutputHeadV1, ()> for State<S> {
|
||||||
fn event(
|
fn event(
|
||||||
state: &mut Self,
|
state: &mut Self,
|
||||||
@@ -2001,19 +2071,26 @@ impl<S: CaptureSource> Dispatch<ZwlrOutputHeadV1, ()> for State<S> {
|
|||||||
_qhandle: &QueueHandle<State<S>>,
|
_qhandle: &QueueHandle<State<S>>,
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
|
// Name 事件:compositor 告知本输出的名字(如 "eDP-1"、"HDMI-A-1")。
|
||||||
WlrHeadEvent::Name { name } => {
|
WlrHeadEvent::Name { name } => {
|
||||||
|
// 仅 ProbingOutputs 阶段消费 head 事件;其它阶段忽略(防御式编程)。
|
||||||
if let EncConstructionStage::ProbingOutputs {
|
if let EncConstructionStage::ProbingOutputs {
|
||||||
wlr_heads,
|
wlr_heads,
|
||||||
wlr_head_proxy_to_name,
|
wlr_head_proxy_to_name,
|
||||||
..
|
..
|
||||||
} = &mut state.stage
|
} = &mut state.stage
|
||||||
{
|
{
|
||||||
|
// HashMap entry API:若 name 不存在则插入空 WlrHeadInfo,已存在则不动。
|
||||||
|
// .or_insert() 返回 &mut value,便于后续更新字段。
|
||||||
wlr_heads
|
wlr_heads
|
||||||
.entry(name.clone())
|
.entry(name.clone())
|
||||||
.or_insert(WlrHeadInfo { position: None });
|
.or_insert(WlrHeadInfo { position: None });
|
||||||
|
// 反向索引:proxy.id()(wayland 对象 id) → name,供后续 Position 事件反查。
|
||||||
|
// 注意这里 name 已被 entry() 消费,所以上面 .clone()。
|
||||||
wlr_head_proxy_to_name.insert(proxy.id(), name);
|
wlr_head_proxy_to_name.insert(proxy.id(), name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Position 事件:本输出在虚拟桌面上的 (x, y) 偏移(像素)。
|
||||||
WlrHeadEvent::Position { x, y } => {
|
WlrHeadEvent::Position { x, y } => {
|
||||||
if let EncConstructionStage::ProbingOutputs {
|
if let EncConstructionStage::ProbingOutputs {
|
||||||
wlr_heads,
|
wlr_heads,
|
||||||
@@ -2021,6 +2098,8 @@ impl<S: CaptureSource> Dispatch<ZwlrOutputHeadV1, ()> for State<S> {
|
|||||||
..
|
..
|
||||||
} = &mut state.stage
|
} = &mut state.stage
|
||||||
{
|
{
|
||||||
|
// 双层 Option 反查:proxy.id() → name → &mut WlrHeadInfo。
|
||||||
|
// 任何一环失败(事件乱序/compositor bug)→ 静默忽略,不 panic。
|
||||||
if let Some(name) = wlr_head_proxy_to_name.get(&proxy.id()) {
|
if let Some(name) = wlr_head_proxy_to_name.get(&proxy.id()) {
|
||||||
if let Some(head) = wlr_heads.get_mut(name) {
|
if let Some(head) = wlr_heads.get_mut(name) {
|
||||||
head.position = Some((x, y));
|
head.position = Some((x, y));
|
||||||
@@ -2028,6 +2107,7 @@ impl<S: CaptureSource> Dispatch<ZwlrOutputHeadV1, ()> for State<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Finished:head 被移除。本实现仅日志(不清理 wlr_heads,因为 probing 期已快照)。
|
||||||
WlrHeadEvent::Finished { .. } => {
|
WlrHeadEvent::Finished { .. } => {
|
||||||
tracing::debug!("zwlr_output_head_v1::Finished received");
|
tracing::debug!("zwlr_output_head_v1::Finished received");
|
||||||
}
|
}
|
||||||
@@ -2035,6 +2115,9 @@ impl<S: CaptureSource> Dispatch<ZwlrOutputHeadV1, ()> for State<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// event_created_child! 注册子对象 dispatcher:head 收到 Mode 事件时,把 ZwlrOutputModeV1
|
||||||
|
// 子对象路由到 Dispatch<ZwlrOutputModeV1>。本实现不消费 Mode 详情(分辨率/刷新率),
|
||||||
|
// 但仍需注册,否则 wayland-client 在收到 Mode 事件时会 panic(unknown child opcode)。
|
||||||
event_created_child!(State<S>, ZwlrOutputHeadV1, [
|
event_created_child!(State<S>, ZwlrOutputHeadV1, [
|
||||||
zwlr_output_head_v1::EVT_MODE_OPCODE => (ZwlrOutputModeV1, ()),
|
zwlr_output_head_v1::EVT_MODE_OPCODE => (ZwlrOutputModeV1, ()),
|
||||||
]);
|
]);
|
||||||
@@ -2044,6 +2127,9 @@ impl<S: CaptureSource> Dispatch<ZwlrOutputHeadV1, ()> for State<S> {
|
|||||||
// Dispatch<ZwlrOutputModeV1, ()>
|
// Dispatch<ZwlrOutputModeV1, ()>
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// ZwlrOutputModeV1:head 的一个分辨率/刷新率组合(head 可有多个 mode)。
|
||||||
|
// 本实现不消费 mode 详情(截屏只关心 head 名字 + 位置,分辨率从 dmabuf feedback 拿),
|
||||||
|
// 但必须实现 Dispatch trait,否则 wayland-client 收到 EVT_MODE_OPCODE 子对象会 panic。
|
||||||
impl<S: CaptureSource> Dispatch<ZwlrOutputModeV1, ()> for State<S> {
|
impl<S: CaptureSource> Dispatch<ZwlrOutputModeV1, ()> for State<S> {
|
||||||
fn event(
|
fn event(
|
||||||
_state: &mut Self,
|
_state: &mut Self,
|
||||||
@@ -2060,6 +2146,9 @@ impl<S: CaptureSource> Dispatch<ZwlrOutputModeV1, ()> for State<S> {
|
|||||||
// Dispatch<ZwlrScreencopyManagerV1, ()>
|
// Dispatch<ZwlrScreencopyManagerV1, ()>
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// ZwlrScreencopyManagerV1:截屏协议的工厂对象。客户端调用 capture_output 创建
|
||||||
|
// ZwlrScreencopyFrameV1 子对象(一帧一个)。manager 自身不发任何事件,所以空实现。
|
||||||
|
// 必须实现 Dispatch trait 以满足 wayland-client 类型 contract(同 ZxdgOutputManagerV1)。
|
||||||
impl<S: CaptureSource> Dispatch<ZwlrScreencopyManagerV1, ()> for State<S> {
|
impl<S: CaptureSource> Dispatch<ZwlrScreencopyManagerV1, ()> for State<S> {
|
||||||
fn event(
|
fn event(
|
||||||
_state: &mut Self,
|
_state: &mut Self,
|
||||||
@@ -2076,6 +2165,10 @@ impl<S: CaptureSource> Dispatch<ZwlrScreencopyManagerV1, ()> for State<S> {
|
|||||||
// Dispatch<WlBuffer, ()>
|
// Dispatch<WlBuffer, ()>
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// WlBuffer:Wayland 核心 buffer 协议。本 impl 处理 buffer::Release 事件——compositor
|
||||||
|
// 完成读后通知客户端可以复用或释放该 buffer(生命周期管理的核心信号)。
|
||||||
|
// 截屏流水线交互:本 impl 只 trace 日志,不持有 buffer(实际 buffer 生命周期由
|
||||||
|
// state.rs on_copy_complete 通过 AVFrame/AVHwFramesContext 管理)。
|
||||||
impl<S: CaptureSource> Dispatch<WlBuffer, ()> for State<S> {
|
impl<S: CaptureSource> Dispatch<WlBuffer, ()> for State<S> {
|
||||||
fn event(
|
fn event(
|
||||||
_state: &mut Self,
|
_state: &mut Self,
|
||||||
@@ -2085,6 +2178,9 @@ impl<S: CaptureSource> Dispatch<WlBuffer, ()> for State<S> {
|
|||||||
_conn: &wayland_client::Connection,
|
_conn: &wayland_client::Connection,
|
||||||
_qhandle: &QueueHandle<State<S>>,
|
_qhandle: &QueueHandle<State<S>>,
|
||||||
) {
|
) {
|
||||||
|
// if let 模式匹配:WlBuffer 只有一个事件 Release,但协议 enum 仍可能扩展,
|
||||||
|
// 用 if let 而非 match 让未来新增事件编译期不报错(向前兼容)。
|
||||||
|
// `wayland_client::protocol::wl_buffer::Event::Release` 是 wayland-scanner 生成的全路径枚举。
|
||||||
if let wayland_client::protocol::wl_buffer::Event::Release = event {
|
if let wayland_client::protocol::wl_buffer::Event::Release = event {
|
||||||
tracing::trace!("WlBuffer released");
|
tracing::trace!("WlBuffer released");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user