niri 视觉测试工具(niri-visual-tests)源码级解析:用真实布局代码与 Mock 窗口搭建的开发调试平台
niri 视觉测试工具niri-visual-tests源码级解析用真实布局代码与 Mock 窗口搭建的开发调试平台【免费下载链接】niriA scrollable-tiling Wayland compositor.项目地址: https://gitcode.com/GitHub_Trending/ni/niriniri-visual-tests 是 niri 滚动式平铺 Wayland 合成器仓库中一个仅面向开发的独立应用它把 niri 真实的布局与渲染代码与模拟窗口而非真实 Wayland 客户端组合起来让开发者通过肉眼逐一核对窗口、平铺块、布局动画与渐变边框等渲染效果。阅读本文后你将掌握这个视觉测试工具的设计思路、全部内置测试场景、其底层如何复用 niri 渲染管线GL 上下文接管、动画时钟控制以及如何在本地运行和扩展它。一、定位为什么 niri 需要一个视觉测试应用README 开篇就给出明确警示这是一个仅供开发使用的应用不应被打包分发This is a development-only app, you shouldnt package it.。它不属于 niri 的发布产物而是开发者调试渲染与布局效果的工具。其核心设计可以概括为三点内置硬编码测试场景应用包含一系列预先写死的测试场景hard-coded test scenarios覆盖窗口、平铺块、布局动画与渐变等主题复用真实代码测试时运行的是 niri 真实的 layout 与 rendering 代码而不是复刻的简化版本用 Mock 窗口代替真实客户端由于不需要真实 Wayland 客户端也就不需要完整的 Wayland 会话启动更简单、行为更可控。正如 README 所述使用方式是逐个浏览测试场景检查一切看起来是否正确go through the test scenarios and check that everythinglooksright——它本质是一个面向人眼的渲染回归检查台与 src/tests/ 下基于快照.snap文件的自动化测试形成互补快照测试验证状态机逻辑而视觉测试验证最终像素呈现。二、环境要求与运行方式运行条件非常轻量需要较新的GTK与libadwaita对应 Rust 侧依赖为gtk4v0.10.3featurev4_12与libadwaitav0.8.1featurev1_4见 Cargo.toml直接执行cargo run应用以adw::Application启动NON_UNIQUE标志允许重复实例见 main.rs启动后呈现一个libadwaita 风格的测试浏览器界面左侧为StackSidebar测试列表标题 Tests右侧为测试内容区顶部是导航标题栏底部是一条Slowdown慢放滑块控制条窗口标题为 niri visual tests。日志输出受RUST_LOG环境变量控制默认值为niri-visual-testsdebug,niridebugmain.rs并以 compact 格式输出到终端。三、内置测试场景全景所有场景在 main.rs 中注册进gtk::Stack共四大类 26 个场景3.1 窗口渲染场景Window场景说明Freeform Window自由尺寸窗口初始 100×200任意缩放Fixed Size Window固定尺寸窗口200×400 锁定红色Fixed Size Window - CSD Shadow固定尺寸窗口 64px CSD 阴影扩展这些场景由 cases/window.rs 实现直接调用TestWindow的render_normal()将窗口渲染元素实色缓冲与可选的 CSD 阴影缓冲输出到指定位置。3.2 平铺块场景Tile场景说明Freeform Tile / Fixed Size Tile自由 / 固定尺寸的单个平铺块Fixed Size Tile - CSD Shadow平铺块 CSD 阴影以上三个变体各带 - Open 版本额外触发开窗动画start_open_animation()实现见 cases/tile.rs它直接构造niri::layout::tile::TileTestWindow并调用其render()且将平铺块定位在窗口右下区域以便观察。3.3 布局动画场景Layout场景说明Layout - Open In-Between两个窗口之间插入新窗口Layout - Open Multiple Quickly100/200/300ms 内快速连续开三个窗口Layout - Open Multiple Quickly - Big同上但新窗口占比 0.5Layout - Open To The Left在指定窗口右侧左侧插入开新窗口Layout - Open To The Left - Big同上新窗口占比 0.5这些场景由 cases/layout.rs 实现直接驱动niri::layout::LayoutTestWindow构造输出Output、注册 4px 宽度带活动/非活动/紧急颜色的边框、使用add_window()/add_window_right_of()插入窗口、调用start_open_animation_for_window()触发动画并在预设时间点steps哈希表注入新窗口。3.4 渐变渲染场景Gradient场景说明Gradient - Angle渐变角度从 0 持续旋转动画场景Gradient - Area渐变区域测试Gradient - Srgb / SrgbLinearsRGB 与线性 sRGB 色彩空间插值Gradient - OklabOKLab 色彩空间插值Gradient - Oklch Shorter / Longer / Increasing / DecreasingOKLCH 色调插值四种模式Gradient - Srgb Alpha / SrgbLinear Alpha / Oklab Alpha / Oklch Alpha各空间带 Alpha 通道的插值渐变场景直接构造niri::render_helpers::border::BorderRenderElement见 cases/gradient_angle.rs 与 cases/gradient_oklch_shorter.rs参数与配置语法一一对应GradientInterpolation由color_spaceSrgb/SrgbLinear/Oklab/Oklch默认Srgb与hue_interpolationShorter/Longer/Increasing/Decreasing默认Shorter组成niri-config/src/appearance.rs另有CornerRadius四角独立圆角同上。Gradient - Angle场景通过每帧推进角度每秒 π 弧度展示角度参数对渐变方向的影响。四、架构剖析TestWindow 与 TestCase 抽象4.1 Mock 窗口 TestWindowtest_window.rs 中的TestWindow是贯穿所有场景的模拟窗口实现 niri 的LayoutElementtrait。它没有真实 surface而是用SolidColorBuffer作为内容缓冲freeform(id)100×200 绿色窗口min/max 均为 0即无约束fixed_size(id)通过set_min_size/set_max_size都设为 200×400 锁死尺寸红色CSD 阴影set_csd_shadow_width(n)会在窗口四周扩展 n px 的半透明阴影缓冲渲染时以location - (width, width)偏移输出communicate()模拟一次客户端提交——应用 requested_size并依次被max_size与min_size钳制随后同步调整缓冲尺寸test_window.rs这正是真实 Wayland 窗口中 configure→commit 流程的简化映射。该类型完整实现了LayoutElement的size()、render_normal()、request_size()、min_size()/max_size()等接口因此能被 niri 的Layout、Tile等真实布局代码直接驱动同时将输入、surface、输出进入/离开等无关能力全部置空。4.2 场景统一接口 TestCase所有测试场景实现统一的TestCasetraitcases/mod.rspub trait TestCase { fn resize(mut self, _width: i32, _height: i32) {} fn are_animations_ongoing(self) - bool { false } fn advance_animations(mut self, _current_time: Duration) {} fn render(mut self, renderer: mut GlesRenderer, size: Sizei32, Physical) - VecBoxdyn RenderElementGlesRenderer; }四个方法分别对应窗口尺寸变化、判断是否有动画在跑决定是否持续重绘、推进动画到当前时刻、以及向渲染器提交渲染元素。Args结构体携带逻辑尺寸与一个可克隆的Clock实例cases/mod.rs供场景构造时使用。五、渲染管线GTK GLArea 中的 Smithay 集成这是本工具最巧妙的部分smithay_view.rs。每个场景对应一个自定义 GTK WidgetSmithayView内部包含一个gtk::GLArea并把Smithay 的 GLES 渲染器绑定到 GTK 的 GL 上下文上创建渲染器时通过egl::GetCurrentDisplay()/egl::GetCurrentContext()取得 GTK 当前 EGL 显示与上下文包装成 Smithay 的EGLContext并新建GlesRenderer随后初始化 niri 的resources::init()与shaders::init()加载全部 GL 着色器与纹理资源smithay_view.rs每帧渲染时读取GLArea当前 framebuffer 绑定然后调用case.render()让场景生成 Smithay 渲染元素由于 Smithay 的render()需要一个目标纹理工具创建了一张 1×1 的 dummy 纹理作为靶子在render()完成后立即把 framebuffer 绑定换回GLArea的 framebuffer——一个注释为 HACK 的技巧smithay_view.rs之后清屏深灰色背景[0.3, 0.3, 0.3, 1.]将各渲染元素按 geometry 裁剪后依次draw()对framebuffer_effect元素先capture_framebuffer()再绘制smithay_view.rs。动画推进与慢放控制每帧从 GTK frame clock 取时间写入Clockset_unadjusted并调用case.advance_animations()若场景报告are_animations_ongoing()为真则通过add_tick_callback持续queue_draw()保证动画帧不断刷新底部 Slowdown 滑块0.010.0通过clock.set_rate()调节时间流速值为 0 时set_complete_instantly(true)动画立即完成否则速率为1.0 / value例如设为 2 即以一半速度播放动画smithay_view.rs。这对逐帧检查开窗、移动动画的中间帧非常有用。六、扩展如何新增一个测试场景结合以上结构添加新场景的路径非常清晰在 cases/ 下新建模块或复用现有模块实现TestCasetrait在 cases/mod.rs 中pub mod声明新模块在 main.rs 的build_ui()中调用s.add(Case::new, 场景标题)注册S::add会自动把构造函数包装进SmithayView并加入侧边栏栈main.rs若需要复杂时间线参考 cases/layout.rs 的steps机制用HashMapDuration, FnOnce在指定延迟注入事件。七、与仓库其他测试体系的关系快照测试src/tests/ 下的测试通过insta快照大量.snap文件如niri__tests__window_opening__check_fullscreen_maximize*.snap断言布局状态与配置组合的行为是逻辑正确性的自动化保障视觉测试本工具则验证像素长什么样依赖人工目检覆盖快照测试无法表达的渐变颜色、阴影、动画插值效果niri-config 解析niri-config/tests/wiki-parses.rs 保证 wiki 中的配置示例能被成功解析与视觉测试共同构成配置→渲染的完整验证链。八、结语niri-visual-tests 是一个小而精的开发工具它用约 300 行的核心代码把 niri 的真实布局与渲染管线搬进 libadwaita 桌面应用通过 Mock 窗口与统一TestCase抽象让开发者不启动完整 Wayland 会话即可逐项核对视觉效果并借助 Smithay 渲染器的帧缓冲接管技巧与可调速动画时钟把渲染调试变成一件直观、可重复、可扩展的工作。对希望深入理解 niri 渲染层src/render_helpers/或布局层src/layout/的开发者而言这个工具既是调试入口也是一份绝佳的集成示例。【免费下载链接】niriA scrollable-tiling Wayland compositor.项目地址: https://gitcode.com/GitHub_Trending/ni/niri创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考