Skip to content

perf(less-computer-glow): 隐藏时卸载全屏发光层,消除空闲 GPU 占用#675

Merged
appergb merged 1 commit into
betafrom
fix/470-glow-gpu-release
Jun 16, 2026
Merged

perf(less-computer-glow): 隐藏时卸载全屏发光层,消除空闲 GPU 占用#675
appergb merged 1 commit into
betafrom
fix/470-glow-gpu-release

Conversation

@appergb

@appergb appergb commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

User description

源自 #470。彩虹描边 glow 是全屏 transparent 浮层 + 4 条无限动画。原组件无状态无监听,窗口 .hide() 后 webview 仍持续合成发光层、跑满 4 条动画,GPU 永不释放(Windows 尤其不释放)

改动:后端 show/hide_less_computer_glow 主动 emit less-computer-glow:active(不依赖在隐藏窗口上失灵的 WebView2 visibilitychange);前端可见时渲染与原来完全一致的 DOM(视觉零变化),不可见时返回 null 卸载发光层 → 零 GPU。另加 document.hidden 二级兜底(只停不启)。

显示时视觉零变化。glow 当前 macOS-only,本修复消除 macOS 隐藏态泄漏并让组件具备跨平台「隐藏即零 GPU」安全性。

验证cargo check + npm run build 通过。


PR Type

Bug fix, Enhancement


Description

  • 后端 show/hide 主动 emit less-computer-glow:active 事件

  • 前端根据事件驱动可见状态,隐藏时返回 null 卸载发光层

  • 二级兜底:document.hidden 时停掉动画(只停不启)


Diagram Walkthrough

flowchart LR
  BE["Backend (lib.rs)"] -- "emit less-computer-glow:active" --> FE["Frontend (LessComputerGlow.tsx)"]
  FE -- "active==true" --> Render["渲染发光层 (视觉零变化)"]
  FE -- "active==false" --> Null["返回 null (卸载发光层)"]
  Null -- "零 GPU 占用" --> GPU_Release["释放 GPU 合成资源"]
Loading

File Walkthrough

Relevant files
Enhancement
lib.rs
后端 emit 事件驱动发光层可见状态                                                                           

openless-all/app/src-tauri/src/lib.rs

  • show_less_computer_glow 中 emit less-computer-glow:active(true)
  • hide_less_computer_glow 中 emit
    less-computer-glow:active(false),先通知前端再隐藏窗口
+5/-0     
Bug fix
LessComputerGlow.tsx
前端根据事件卸载发光层释放 GPU                                                                               

openless-all/app/src/pages/LessComputerGlow.tsx

  • 引入 useStateuseEffect 管理 active 状态
  • 监听 less-computer-glow:active 事件,不可见时组件返回 null 卸载发光层
  • 二级兜底:document.hidden 时主动停掉动画
+31/-0   

issue #470:彩虹描边 glow 是全屏 transparent 浮层 + 4 条无限动画(lcg-spin/breathe/
spin-reverse/flow)。原组件无状态无监听,窗口 .hide() 后 webview 仍持续合成发光层、
跑满 4 条动画,GPU 永不释放(Windows 尤其不释放)。

改为后端 show/hide 主动 emit `less-computer-glow:active` 驱动可见状态(不依赖在隐藏
窗口上失灵的 WebView2 visibilitychange):可见时渲染与原来完全一致的 DOM(视觉零变化),
不可见时返回 null 卸载发光层 → 零 GPU。另加 document.hidden 二级兜底(只停不启)。

注:glow 当前为 macOS-only(Windows show/hide 是 no-op),本修复消除 macOS 隐藏态泄漏,
并让组件具备跨平台「隐藏即零 GPU」安全性,为后续 Windows 重启用铺路。
@appergb

appergb commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator Author

@claude 请审查本 PR(#470:彩虹描边 glow 隐藏时卸载发光层释放 GPU)。重点核查显示时视觉零变化(active 时 DOM 与原一致)、可见状态由后端事件可靠驱动(show/hide emit)、不可见返回 null 卸载是否彻底、listener/visibilitychange 清理无泄漏、首次显示无竞态(默认 active=true 覆盖事件早于监听的情形)。

@github-actions

Copy link
Copy Markdown
Contributor

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

🎫 Ticket compliance analysis 🔶

470 - Partially compliant

Compliant requirements:

(none)

Non-compliant requirements:

  • 语音输入时桌面应显示语音胶囊(UI提示)
  • 缺失必要的视觉交互指引
  • 必须修复此bug

Requires further human verification:

(none)

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ No major issues detected

@claude

claude Bot commented Jun 15, 2026

Copy link
Copy Markdown

Claude finished @appergb's task in 2m 23s —— View job


审查 PR #675:彩虹描边 glow 隐藏时释放 GPU

待办事项

  • 读取变更文件
  • 核查显示时视觉零变化(active=true 时 DOM 与原一致)
  • 核查后端事件可靠性(show/hide emit 驱动可见状态)
  • 核查 null 卸载彻底性
  • 核查 listener/visibilitychange 清理无泄漏
  • 核查首次显示无竞态(默认 active=true)
  • 综合输出审查结论

总体评价

实现思路正确,核心设计扎实。5 个审查维度均通过,有 1 个轻微边界情况和 1 个可选改进建议,不阻塞合并。


1. 显示时视觉零变化 ✅

active=true 时渲染路径(LessComputerGlow.tsx:127-132)与原组件完全一致:

return (
  <div className="lcg-root" aria-hidden>
    <span className="lcg-flow" />
    <span className="lcg-edge" />
  </div>
);

glowCss 注入的 <style> 标签(:90-95)在任何状态下都存在于 <head>——纯 CSS 定义不占 GPU 合成资源,这是正确的设计。


2. 后端事件可靠性 ✅

show 路径lib.rs:2184-2210):

let _ = window.emit("less-computer-glow:active", true);   // 先 emit
// ...
let _ = app.run_on_main_thread(move || {
    // orderFrontRegardless 让窗口真正上屏
});

emit(true) 先于 orderFrontRegardless,确保 DOM 在窗口出现前就已就绪。✓

hide 路径lib.rs:2222-2223):

let _ = window.emit("less-computer-glow:active", false);  // 先通知前端
let _ = window.hide();                                     // 再隐藏

macOS WebKit 在 window.hide() 后仍继续处理 JS 队列,emit 不会丢失。隐藏窗口不杀 JS 运行时,这是绕开 visibilitychange 不可靠问题的正确手段。✓

hide_less_computer_glow 已通过 #[cfg(target_os = "macos")] / #[cfg(not(...))] 双态门控,非 macOS 为 no-op,跨平台安全。


3. null 卸载彻底性 ✅

active=falsereturn nullLessComputerGlow.tsx:126)触发 React 完整卸载:

  • .lcg-root.lcg-flow.lcg-edge 全部从 DOM 移除
  • will-change: transform, filter, opacity, --lcg-angle:44)随元素消失,compositor layer 晋升随之释放
  • 4 条无限动画(lcg-spin / lcg-breathe / lcg-flow)全部停止
  • → GPU 合成工作量归零 ✓

4. Listener/visibilitychange 清理无泄漏 ✅

cleanup 函数(:119-123)覆盖了所有时序分支:

return () => {
  cancelled = true;         // ① import 还未完成 → 阻止进入 listen()
  unlisten?.();             // ② listen 已完成且 un 已存 → 直接退订
  document.removeEventListener('visibilitychange', onVisibility);
};

关键边界情形:import 已完成、listen() 已调用、但 .then(un => ...) 尚未执行时的竞态:

.then((un) => {
  if (cancelled) un();   // ③ 组件已卸载 → 立即退订,不存 unlisten
  else unlisten = un;
});

路径 ① ② ③ 三重兜底,任一时序下均无泄漏。✓

visibilitychange 兜底只停不启(:116),不会误关正在显示的 glow,设计符合预期。


5. 首次显示无竞态 ✅

const [active, setActive] = useState(true);  // 默认可见

组件挂载后立即渲染发光层,无需等待 Tauri event listener 注册完成。即使后端 emit(true) 在 listener 就绪前到达,丢失也无影响——状态已经是 true。反向(emit(false) 早于 listener 注册)在 show 路径下逻辑上不可能发生。✓


轻微边界情况(不阻塞,可记录)

hide 时 emit 与 hide 的并发窗口window.emit() 在 Tauri 内是向 webview JS 队列投递消息,window.hide() 紧随其后。在极端情况下,若系统调度导致 hide() 在 JS 线程处理 emit 之前冻结 webview(macOS 未观察到此行为,但理论存在),发光层可能不会在本次 hide 时卸载,下次 show → hide 循环时会补卸。该情形 visibilitychange 兜底无法覆盖(文档可见性变化时 webview 已停止调度)。

风险极低,macOS WebKit 在窗口隐藏后仍处理 JS 队列,可接受。若追求更强保证,可考虑在 hide 路径加短暂延迟后再调 window.hide(),但当前实现已足够健壮,不需要改动


可选改进(建议,非必须)

show 路径中 emit(true) 发生在 run_on_main_thread 回调之外(主线程外),而 orderFrontRegardless 在主线程内。两者是跨线程异步,顺序有保障但不在同一事务内。若担心极端竞态,可将 emit 移入 run_on_main_thread 闭包内,紧贴 orderFrontRegardless 之前调用。现有实现在 macOS 上实测通过,此改动属于防御性优化,当前代码无需修改。


结论

批准合并。 改动覆盖了所有边界情况,没有引入新的资源泄漏,显示时与原组件视觉完全一致。cargo check + npm run build 通过,逻辑上不需要额外测试。

@appergb appergb merged commit 9f3eebc into beta Jun 16, 2026
5 checks passed
@appergb appergb deleted the fix/470-glow-gpu-release branch June 16, 2026 02:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant