Skip to content

refactor(rhi-webgl): rework canvas resolution API, follow display size by default#3037

Open
luo2430 wants to merge 38 commits into
galacean:dev/2.0from
luo2430:dev/2.0
Open

refactor(rhi-webgl): rework canvas resolution API, follow display size by default#3037
luo2430 wants to merge 38 commits into
galacean:dev/2.0from
luo2430:dev/2.0

Conversation

@luo2430

@luo2430 luo2430 commented Jun 17, 2026

Copy link
Copy Markdown

概述

一次 canvas 分辨率 API 的易用性增强:把 auto-resize 能力归位到 WebCanvas,让渲染分辨率默认自动跟随显示尺寸——大多数应用 create({ canvas }) 之后不用写任何 resize 代码。

原始需求是给 WebGLEngine 加 auto-resize opt-in(@luo2430)。经过讨论从第一性演进成这套重构,方向不变、形态更彻底。

主要改动

1. 归属:auto-resize 全部归 WebCanvas,pump 下沉到基类

observer 观察 canvas、算 canvas 尺寸、改 canvas 分辨率——概念上 100% 属于 canvas。原本放 engine 是因为白屏修复需要帧时序(实现依赖绑架了归属)。现在:

  • auto-resize 逻辑全在 WebCanvas
  • 每帧的 resize pump 下沉到基类 Engine.update()this._canvas._pumpPendingResize()),_pumpPendingResize 是基类 Canvas 的默认 no-op、WebCanvas override——WebGLEngine 不再需要 override update()

2. 默认自动跟随显示尺寸(零配置)

// 之前:用户要显式调 + 自己挂 window.resize 监听
engine.canvas.resizeByClientSize();

// 现在:create 后什么都不用写
WebGLEngine.create({ canvas });
  • ResizeObserver 监听 canvas 元素本身 → 接住窗口、CSS、flex/容器、侧边栏/面板等所有来源的尺寸变化(window.resize 只能接住窗口变化)
  • 0×0 安全:resize 延迟到帧循环,canvas 无布局尺寸时跳过——未挂载的 canvas 永不被设成 0×0 buffer
  • example 中的显式 resize 调用相应删除

3. 两个分辨率入口

engine.canvas.setAutoResolution(scale?)    // 自动:跟随显示尺寸
engine.canvas.setResolution(width, height) // 固定:锁死绝对分辨率(隐式退出自动)
  • scalebase 是物理分辨率1 = 满物理分辨率(原生清晰),0.7 = 降 30% 提性能,2 = 超采样。device pixel ratio 自动吸收,用户无需理解 DPR
  • 想固定分辨率:create({ canvas }) 后调 setResolution(w, h)(退出自动,无闪烁)

4. width / height 改只读

分辨率是原子的整体:单独设 width 不动 height 会产生畸变中间态 + 两次 buffer 重建,且裸写 canvas.width 会让引擎缓存尺寸与真实 buffer 分叉。改只读后,所有分辨率变更走 setResolution 一个原子入口。width/height 是"画布分辨率"的分量。

5. 分数 DPR 精度:devicePixelContentBoxSize

clientWidth * dpr 在分数 DPR(Windows 1.25/1.5)下有 ≤1px 舍入误差。改用 ResizeObserver entry 的 devicePixelContentBoxSize(精确物理像素)消除它,Safari 等不支持的浏览器自动降级回 clientWidth * dpr(特性检测,无人退化)。four 大 web3D 引擎(three.js/Babylon/Pixi/PlayCanvas)均未采用此特性。

6. 删 resizeByClientSize

被默认自动 + setAutoResolution 覆盖。

Breaking Changes

major 版本级

  • canvas.width / canvas.height 改为只读(用 setResolution 设分辨率)
  • 移除 resizeByClientSize
  • auto-resize 默认开启(想要固定分辨率:create 后调 setResolution

设计参照

  • create({...}) 配置模式对齐 three.js / Babylon(web 引擎标准)
  • 默认自动跟随对齐 Unity / UE 的"默认就跟随"心智
  • scale(物理分辨率之上的性能倍数)对齐 UE ScreenPercentage
  • setResolution 命名对齐 Unity / UE(SetResolution / SetScreenResolution

验证

  • tsc 全绿(core + rhi-webgl)
  • 全量单测全过、e2e ×4 全绿
  • devicePixelContentBoxSize 精确路径 + 首帧时序 jsdom 不忠实复现,靠规范 + 代码审查(建议真机验一次)

供讨论。 @luo2430 有不同意见或更好想法请直接回复。

@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

WebCanvas gains an isOffscreenCanvas() method that centralizes the repeated inline OffscreenCanvas type checks; three existing guards in WebCanvas and two in WebGLGraphicDevice are updated to use it. WebGLEngine receives enableAutoResize(pixelRatio?) and disableAutoResize() methods backed by a ResizeObserver with EngineEventType.Shutdown cleanup. New tests cover both isOffscreenCanvas() and the full auto-resize lifecycle.

Changes

OffscreenCanvas detection and auto-resize

Layer / File(s) Summary
WebCanvas.isOffscreenCanvas() method and usage refactor
packages/rhi-webgl/src/WebCanvas.ts, tests/src/rhi-webgl/WebCanvas.test.ts
Adds isOffscreenCanvas(): boolean to WebCanvas and replaces three inline typeof OffscreenCanvas/instanceof guards (in scale getter, scale setter, and resizeByClientSize) with calls to the new method. A new test suite verifies the return value for HTMLCanvasElement, OffscreenCanvas, and post-construction field replacements.
WebGLGraphicDevice context fallback updated
packages/rhi-webgl/src/WebGLGraphicDevice.ts
Updates WebGLGraphicDevice.init to allow the WebGL2 gl variable to be undefined and replaces both experimental-webgl2 and experimental-webgl fallback gating with (canvas as WebCanvas).isOffscreenCanvas().
WebGLEngine enableAutoResize / disableAutoResize
packages/rhi-webgl/src/WebGLEngine.ts, tests/src/rhi-webgl/WebGLEngine.test.ts, tests/vitest.config.ts
Adds EngineEventType import, a private _resizeObserver field and static cleanup helper, and public enableAutoResize(pixelRatio?) / disableAutoResize() methods. enableAutoResize skips OffscreenCanvas, disconnects any prior observer, registers a new ResizeObserver calling canvas.resizeByClientSize, and registers a Shutdown listener. Tests verify listener counts, observer lifecycle and replacement, resizeByClientSize invocation after style mutation, and cleanup on engine.destroy(). screenshotFailures is set to false in the Vitest Playwright config.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant WebGLEngine
  participant ResizeObserver
  participant WebCanvas

  Caller->>WebGLEngine: enableAutoResize(pixelRatio?)
  WebGLEngine->>ResizeObserver: disconnect() (prior observer, if any)
  WebGLEngine->>ResizeObserver: new ResizeObserver(callback)
  WebGLEngine->>ResizeObserver: observe(canvas element)
  WebGLEngine->>WebGLEngine: on(Shutdown, _cleanupResizeObserver)

  Note over ResizeObserver,WebCanvas: canvas client dimensions change
  ResizeObserver->>WebCanvas: resizeByClientSize(pixelRatio)

  Caller->>WebGLEngine: disableAutoResize()
  WebGLEngine->>WebGLEngine: off(Shutdown, _cleanupResizeObserver)
  WebGLEngine->>ResizeObserver: disconnect()

  Note over WebGLEngine: engine.destroy() triggers Shutdown
  WebGLEngine->>WebGLEngine: _cleanupResizeObserver()
  WebGLEngine->>ResizeObserver: disconnect()
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~15 minutes

Poem

🐰 A canvas that knows what it is — how grand!
No more typeof checks scattered by hand.
isOffscreenCanvas() speaks for the whole,
ResizeObserver watches with vigilant soul.
When shutdown arrives, it tidies the nest,
A well-behaved bunny — clean-up's the best! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise and accurately reflects the main change: canvas auto-resizing and display-size-based resolution behavior.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@luo2430 luo2430 marked this pull request as draft June 17, 2026 05:53

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/src/rhi-webgl/WebGLEngine.test.ts`:
- Around line 140-145: The spy on the _cleanupResizeObserver method is created
after enableAutoResize() has already registered the Shutdown listener, meaning
the listener holds a reference to the original function rather than the spied
version. Move the vi.spyOn call for cleanupResizeObserverSpy to before the
enableAutoResize() call to ensure the registered Shutdown listener captures the
spied function reference, allowing the assertion on
cleanupResizeObserverSpy.toHaveBeenCalledTimes(1) to work correctly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ca7819a5-d724-46f3-ad7d-879ae0800382

📥 Commits

Reviewing files that changed from the base of the PR and between 5d74c1d and 887ac8c.

📒 Files selected for processing (3)
  • packages/core/src/input/InputManager.ts
  • packages/rhi-webgl/src/WebGLEngine.ts
  • tests/src/rhi-webgl/WebGLEngine.test.ts

Comment thread tests/src/rhi-webgl/WebGLEngine.test.ts Outdated
@luo2430 luo2430 marked this pull request as ready for review June 17, 2026 05:59
GuoLei1990

This comment was marked as outdated.

GuoLei1990

This comment was marked as outdated.

@luo2430

luo2430 commented Jun 17, 2026

Copy link
Copy Markdown
Author

@GuoLei1990

this指针问题我考虑到了,但不知为何代码经过修改后我的本地测试可以跑通。

image

我会再去处理这个问题,原本以为已经修复了。

GuoLei1990

This comment was marked as outdated.

@cptbtptpbcptdtptp

Copy link
Copy Markdown
Collaborator

这里有一个时序问题需要提一下,根据 W3C 规范,浏览器每帧的渲染管线顺序是:

 Input Events (包括 window resize event) → rAF callbacks(引擎逻辑) → Style/Layout → ResizeObserver callbacks(本次 PR 添加) → Paint

在发生 resize 那帧,引擎绘制 rAF 时使用的还是旧的画布尺寸,随后 ResizeObserver 回调修改画布的尺寸会清空 canvas buffer ,表现就是这一帧会白,但 window 监听 resize 也不可以直接用,因为 window.resize 仅监听浏览器窗口大小变化,所以其他引擎要么完全手动触发,要么轮询检测,避免本帧 resize 与渲染不同步。

@codecov

codecov Bot commented Jun 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 62.50000% with 75 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.42%. Comparing base (721b42a) to head (90a8755).

Files with missing lines Patch % Lines
e2e/case/text-typed.ts 0.00% 11 Missing ⚠️
packages/rhi-webgl/src/WebCanvas.ts 90.66% 7 Missing ⚠️
...cleRenderer-emit-mesh-cone-scale-rotation-world.ts 0.00% 6 Missing ⚠️
.../particleRenderer-emit-mesh-cone-scale-rotation.ts 0.00% 5 Missing ⚠️
...rer-emit-mesh-cone-scale-rotation-life-seperate.ts 0.00% 3 Missing ⚠️
...icleRenderer-emit-mesh-cone-scale-rotation-life.ts 0.00% 3 Missing ⚠️
examples/src/paricle-emit-mesh.ts 0.00% 3 Missing ⚠️
.../case/particleRenderer-emit-billboard-stretched.ts 0.00% 2 Missing ⚠️
e2e/case/animator-additive.ts 0.00% 1 Missing ⚠️
e2e/case/animator-blendShape.ts 0.00% 1 Missing ⚠️
... and 33 more
Additional details and impacted files
@@             Coverage Diff             @@
##           dev/2.0    #3037      +/-   ##
===========================================
+ Coverage    79.37%   79.42%   +0.04%     
===========================================
  Files          903      903              
  Lines       100632   100652      +20     
  Branches     11260    11273      +13     
===========================================
+ Hits         79879    79942      +63     
+ Misses       20569    20526      -43     
  Partials       184      184              
Flag Coverage Δ
unittests 79.42% <62.50%> (+0.04%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@luo2430 luo2430 changed the title feat(rhi-webgl): add auto-resize support via ResizeObserver and refactor input canvas naming refactor(rhi-webgl): extract isOffscreenCanvas helper | feat(rhi-webgl): add WebGLEngine auto-resize support via ResizeObserver | chore(vitest): disable screenshotFailures to avoid taking blank screenshots Jun 18, 2026
@luo2430

luo2430 commented Jun 18, 2026

Copy link
Copy Markdown
Author

@GuoLei1990

代码处理完毕,vitest问题我会去开一个issue,有部分解决方案和提议,但需要验证。另外,isOffscreenCanvas中的typeof OffscreenCanvas !== "undefined"是不是可以直接提成一个全局常量或者静态常量,但项目中似乎没有这种先例,这符合项目规范吗?

GuoLei1990

This comment was marked as outdated.

@luo2430

luo2430 commented Jun 18, 2026

Copy link
Copy Markdown
Author

@GuoLei1990

注释已修改。
可以确定的是isOffscreenCanvas会被设定为一个public api,因为有可以跨包使用的地方。但为了这一处使用而添加一个新的工作区依赖我觉得不值得。

image

GuoLei1990

This comment was marked as outdated.

@luo2430

luo2430 commented Jun 18, 2026

Copy link
Copy Markdown
Author

@cptbtptpbcptdtptp

GuoLei1990

This comment was marked as outdated.

@luo2430

luo2430 commented Jun 21, 2026

Copy link
Copy Markdown
Author

@cptbtptpbcptdtptp 这里有好康的

@cptbtptpbcptdtptp

Copy link
Copy Markdown
Collaborator

@cptbtptpbcptdtptp 这里有好康的

这个是当前 PR 在真实 resize 时的表现
resize

期望应该是这样的(时序导致)
resize1

@luo2430

luo2430 commented Jun 21, 2026

Copy link
Copy Markdown
Author

@cptbtptpbcptdtptp 这个示例能分享一下吗?我用于测试。

@cptbtptpbcptdtptp

Copy link
Copy Markdown
Collaborator

@cptbtptpbcptdtptp 这个示例能分享一下吗?我用于测试。

examples/src/device-restore.ts 这个,设置 enableAutoResize 就可以。

@luo2430

luo2430 commented Jun 21, 2026

Copy link
Copy Markdown
Author

@cptbtptpbcptdtptp 收到

@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Jun 22, 2026
…ents

OffscreenCanvas not following the display size is the correct, only
sensible behavior, not a gap to warn about — so the no-op needs no TODO.
Also drop trailing periods from single-line // comments for consistency.
GuoLei1990

This comment was marked as outdated.

…lback

The callback body already reads as flag-only.
Keep only the non-obvious why: the 0x0 guard exists because an unmounted
canvas has no layout size, and the rounding is a fractional-dpr TODO. Drop
the parts that restate the code (the retained flag, the Math.round).
That an unmounted canvas reports clientWidth 0 is common web knowledge, and
the guard reads clearly on its own.
GuoLei1990

This comment was marked as outdated.

…BoxSize TODO

It is not Baseline (no Safari), so it can't be swapped in unconditionally —
the reason it isn't used yet, invisible from the code.
…ed path

It is a separate exact-pixel path gated by feature detection, with this
clientWidth-based rounding kept as the permanent fallback — not a
replacement (the value can't be polyfilled where the browser lacks it).
…sizing

Capture the observer entry's devicePixelContentBoxSize (exact device
pixels, so only the scale is applied) and fall back to clientWidth * dpr
where it is unavailable (Safari). This removes the fractional-dpr rounding
error on browsers that support it, without changing behavior elsewhere.
Group the @internal method with the other internal methods instead of
placing it between the public scale accessors and setAutoResolution.
The field names and the callback that assigns them are self-explanatory.
The eager synchronous _pendingResize=true ran before the observer's first
entry arrived, so the first resize always took the clientWidth fallback
even where devicePixelContentBoxSize is supported. Drive the first resize
from observe()'s initial callback instead; only reapply synchronously when
already observing (a scale change), reusing the last measured size.
GuoLei1990

This comment was marked as outdated.

…size

These were introduced earlier in this PR and never shipped, so keeping
them as deprecated forwarders was contradictory (new + deprecated in the
same change). The capability lives on the canvas now — use
engine.canvas.setAutoResolution() / setResolution() directly.
Move the per-frame resize pump into Engine.update so WebGLEngine no longer
overrides update. _pumpPendingResize becomes a base Canvas no-op that
WebCanvas overrides, like _exitAutoResize.
GuoLei1990

This comment was marked as outdated.

Just state what it returns; the resolution API is documented on the
WebCanvas/Canvas class it returns, not restated on the getter.

@GuoLei1990 GuoLei1990 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复审 @ f1dc48713(线性追加 3 个 commit:把 per-frame resize pump 从 WebGLEngine.update() override 下沉进基类 Engine.update()WebGLEngine 彻底不再 override update + 两个 docs-only;机制经逐链核对等价、pump-before-render 顺序未回退、e2e×4 全绿实证,approve 维持 gate 清空)

自我上轮 review(5aacc8551)以来 HEAD 线性推进 3 个 commitmerge-base --is-ancestor 5aacc8551 f1dc48713 = 祖先,非 force-push):

  • 4889464b0 refactor: pump pending canvas resize in base Engine.update
  • 24df15f5f docs(core): drop the pump comment in Engine.update
  • f1dc48713 docs(rhi-webgl): simplify the canvas getter doc

git diff 5aacc8551 f1dc48713 --stat = 仅 3 文件Canvas.ts(+1/-1)、Engine.ts(+2)、WebGLEngine.ts(−8)。WebCanvas.ts / WebGLGraphicDevice.ts 与已 approve 的 5aacc8551 逐字节相同git diff 空)——历史全部闭环项在这两文件里,未回退。注意:4889464b0 是 refactor 前缀、动了基类帧循环,我逐链 trace(非信 commit message)。

4889464b0 逐链核对:pump 下沉进基类 Engine.update() —— 是消除「override 只为注入一行」的净收敛,机制严格等价

改动三处,逐一核对:

  1. Canvas._pumpPendingResize()abstract → 基类 no-op {}Canvas.ts:62)。base Canvas 提供无害空实现,WebCanvas._pumpPendingResize()WebCanvas.ts:95,本轮逐字节未动)仍是真实现的 override。commit body 称「像 _exitAutoResize 一样」——核实属实Canvas.ts:66 正是 protected _exitAutoResize(): void {} 同款「基类 no-op + WebCanvas override」既有惯例,_pumpPendingResize 现逐字对齐它。非新增泛化,是复用本文件既有模式。

  2. Engine.update() 顶部新增 this._canvas._pumpPendingResize()Engine.ts:325)。逐链核对顺序与 null 安全

    • pump 是 update() 第一条语句——在 time._update()、所有 script/physics/animation 更新、以及(更下方)this._render(scenes) 之前。故 resize 落 render 前、同帧,白屏 fix 顺序未回退(与旧 WebGLEngine.update() 里「pump 再 super.update()」严格等价)。
    • null 安全_canvas 在构造函数 :252 作为必填首参赋值(早于任何 update() 可能被调),且从构造到 _destroy 从不置 nullthis._canvas._pumpPendingResize() 恒安全。
    • 多态派发正确WebGLEngine 唯一 Engine 子类(git grep "extends Engine" 全仓仅 WebGLEngine.ts:8),_animate 循环(:147/:152)调 this.update() → 基类 update() → 顶部 pump 多态派发到 WebCanvas._pumpPendingResize()。行为与旧 override 逐字等价。
  3. 删掉 WebGLEngine.update() overrideWebGLEngine.ts −6 行)。旧 override 体只有 pump + super.update()(无其它逻辑,diff 坐实),pump 已下沉到基类 → override 现在是纯冗余,删除后 WebGLEngineupdate() override,更干净。测试无回归:本 delta 零测试文件改动,WebGLEngine.test.ts 不调 .update()(resize 测试直戳 _pumpPendingResize / observer 生命周期,均未变)。

判例意义:这条把「resize→render 同帧」的所有权从 WebGL 特定 override 收口进基类帧循环——它本就是基类帧生命周期保证(非 WebGL 独有),归属更正确;且消除了「override 只为注入一行 cross-cutting 调用」这个反模式(对应 skill「隐式委托 / override 只为一行」)。是净架构改进。

24df15f5f + f1dc48713 逐条核对(docs-only)

  • 24df15f5f 删 pump 行的注释// Apply any pending canvas resize before the frame so resize and render land together)——4889464b0 加 pump 时带的这条注释被这个 commit 删掉,留下裸 this._canvas._pumpPendingResize();。见下 [P3]。
  • f1dc48713 简化 getter docWebGLEngine.ts:31):从「The canvas the engine renders to; call setResolution()/setAutoResolution() ...」→「The web canvas the engine renders to.」——合理。resolution API 文档挂在返回类型 WebCanvas/Canvas 上,getter 上重述属冗余。多行 /** */ 块保留、描述带句尾句号,JSDoc 合规。

问题

[P3] packages/core/src/Engine.ts:325 — pump 行「为何在 render 前」的 rationale 现已无处留存(非阻塞)

24df15f5f 删掉 pump 行注释后,this._canvas._pumpPendingResize() 变成裸调用,而「必须在 render 前跑,让 resize 和 render 同帧、避免白屏」这个 why 现在全仓无处留存(git grep "white flash\|same frame\|before render\|land together\|for why" 除无关命中外为空)。这个 why 是 load-bearing 的:pump 调用的位置update() 首行、_render 之前)本身是承载性事实,但裸行不告诉未来读者「为什么必须在这个位置」——一个后续「整理」帧循环顺序的人可能无意把它移到 render 之后而重引白屏。

与我历史 [P3] 的区别:此前那条 [P3] 是「删白屏 why 后 WebGLEngine.ts 留下 see Canvas._pumpPendingResize for why 悬挂交叉引用」——本轮 WebGLEngine.update() override 连同那句 for why 尾巴一起被删了,悬挂引用已消除、那条 [P3] 闭环。本条是新形态(rationale 彻底消失、无悬挂指针),同源但非同一条。非阻塞,纯 doc-hygiene,建议在 pump 行上补一句 why(如 // Pump before render so resize and render land in the same frame),或维持现状——不阻塞合并。

CI

tip f1dc48713build×3(win/mac/ubuntu)/ codecov / codecov/project / e2e×4 / lint / labeler 全部 SUCCESSe2e×4 全绿是关键实证——它跑真机 _animate → update → render 循环,坐实「pump 下沉基类后仍在 render 前落 resize」(白屏 fix 未回退),非仅静态核对。唯一 codecov/patch fail —— 本 delta 是 refactor(挪一行)+ docs 删除,无新增产物覆盖行,patch coverage 天然显示「无新增覆盖」,是覆盖率比值 artifact 非测试失败(codecov job 本身 pass、真 suite 全 pass、e2e×4 全绿),同历轮判定,不作为 finding。

已闭环清单(逐条对 tip 核对,未回退)

  • [P0] 83+ e2e resizeByClientSize 迁移 / 8 单测 suite 崩溃 → 全仓源码/e2e/tests/examples 零 resizeByClientSize(仅 docs 8 文件),e2e×4 全绿。关闭。
  • [P1] _cleanupAutoResize/_releaseCanvas this-loss;lint red(infra 抖动,tip lint SUCCESS)。关闭。
  • [P2] observe 注释撒谎/白屏;isOffscreenCanvas 收成 internal;DPR 调用时固化;scale 校验 throw;devicePixelContentBoxSize 精确设尺;enable/disable deprecated forwarder 删除;[P3] pending 标志/字段位置/注释句号。均关闭、未回退WebCanvas.ts/WebGLGraphicDevice.ts 逐字节未变,Canvas.ts/Engine.ts 除 pump 下沉外机制原样)。
  • [P3] WebGLEngine.tsCanvas._pumpPendingResize for why 悬挂交叉引用 → 本轮 WebGLEngine.update() override 连同 for why 尾巴一并删除,悬挂引用消除、闭环(新形态见上 [P3],同源非同条)。

仍开放(非阻塞,硬去重不重提展开)

  • [P2] docs/README 未随 breaking change 更新(8 文件仍教已删的 resizeByClientSize())+ [P2] 基类 Canvas 抽象契约 breaking 建议标 CHANGELOG:本轮未触,仍开放,建议合并前顺手清。
  • [P3] WebCanvas.ts:110 fallback 注释举 Safari 为例略过时(Safari 16.4+ 已支持 devicePixelContentBoxSize):本轮 WebCanvas.ts 逐字节未动,原样延续,仅作记录。

结论

approve:本轮 3 个 commit——① 4889464b0 把 per-frame resize pump 从 WebGLEngine.update() override 下沉进基类 Engine.update() 首行(_pumpPendingResize 从 abstract 变基类 no-op、WebCanvas 仍 override,逐字对齐既有 _exitAutoResize 惯例),经逐链核对 pump-before-render 顺序严格等价、_canvas 构造期赋值 null 安全、WebGLEngine 唯一 Engine 子类多态派发正确、旧 override 体只有 pump+super 纯冗余删除、测试零改动无回归——是把帧生命周期所有权收口进基类的净架构改进;② 24df15f5f 删 pump 行注释(顺带消除我历史 [P3] 悬挂交叉引用,但白屏 why 现无处留存 = 新 [P3] 非阻塞);③ f1dc48713 getter doc 简化(resolution API 归返回类型,getter 上重述冗余)。WebCanvas.ts/WebGLGraphicDevice.ts 逐字节未变、历史全部闭环项未回退,CI 全绿(唯 codecov/patch 是 refactor+docs 的比值 artifact),e2e×4 实证白屏 fix 未回退。无 P0/P1/P2/新阻塞项。因 HEAD 已推过我上轮 approve 的 commit(reviewDecision = REVIEW_REQUIRED),在新 tip f1dc48713 提交 APPROVE 以维持 gate 清空。剩两条 P2(docs / CHANGELOG)+ 两条 P3(pump why / Safari 注释)均非阻塞,建议合并前顺手清。

Auto-resize stays on by default (create always calls setAutoResolution);
apps wanting a fixed resolution call setResolution afterwards, which exits
auto mode without a flicker. Removes an init-only opt-out that runtime
setResolution already covers.
@GuoLei1990

Copy link
Copy Markdown
Member

+1

@luo2430

luo2430 commented Jul 4, 2026

Copy link
Copy Markdown
Author

+1

@GuoLei1990 我根据pr改动修改了文档,需要commit在这吗?

@GuoLei1990

Copy link
Copy Markdown
Member

嗯嗯,可以的,是我遗漏了!PR 拉到最新帮忙适配下吧🙏

- Updated canvas resizing logic in docs from resizeByClientSize to setAutoResolution and setResolution
- Aligned English and Chinese documentation for physics and platform modules
- Removed deprecated method calls from README and example snippets
- Enhanced clarity on device pixel ratio (DPR) handling and resolution strategies
@luo2430

luo2430 commented Jul 4, 2026

Copy link
Copy Markdown
Author

嗯嗯,可以的,是我遗漏了!PR 拉到最新帮忙适配下吧🙏

@GuoLei1990 提交了,但严格来说要设置lint-staged的,不然直接提交报错 Git: �[0;34m→�[0m lint-staged could not find any staged files matching configured tasks ,目前是用 --no-verify 临时跳过的

@GuoLei1990

Copy link
Copy Markdown
Member

嗯嗯,可以的,是我遗漏了!PR 拉到最新帮忙适配下吧🙏

@GuoLei1990 提交了,但严格来说要设置lint-staged的,不然直接提交报错 Git: �[0;34m→�[0m lint-staged could not find any staged files matching configured tasks ,目前是用 --no-verify 临时跳过的

👌

@GuoLei1990 GuoLei1990 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复审 @ 90a8755382(线性追加 2 个 commit:一个 refactor 删掉本 PR 自引入的 autoResize create 选项 + 一个 docs 把 8 个文档/README 从已删的 resizeByClientSize 迁到 setAutoResolution/setResolution;前者经 Git 历史透镜坐实非 breaking、无残留消费者、无闪烁,后者逐条打开代码验非撒谎——闭环我历史长期 [P2] docs finding,approve 维持 gate 清空)

自我上轮 review(f1dc48713)以来 HEAD 线性推进 2 个 commitcompare f1dc48713...90a8755382 = status: ahead / ahead_by: 2 / behind_by: 0,非 force-push;父链 90a8755382724dd3ceef1dc48713):

  • 724dd3cee refactor(rhi-webgl): drop the autoResize create option
  • 90a8755382 chore(docs): migrate canvas resizing APIs and update guides

724dd3cee 只动 WebGLEngine.ts(+1/-5)+ WebGLEngine.test.ts(+1/-9);90a8755382 只动 8 个 docs/README(docs/{en,zh}/core/canvas.mdx 各 +56/-47、platform.mdx/raycast.mdx 各 ±1、2 个 README ±1)。核心产物 WebCanvas.ts/Canvas.ts/WebGLGraphicDevice.ts/Engine.ts 本轮零改动——历史全部闭环项在这些文件里,未回退。

724dd3cee 逐链核对:删 autoResize create 选项 —— 非 breaking、无残留消费者、无闪烁,是净简化

commit body 称「auto-resize 默认常开(create 恒调 setAutoResolution);要固定分辨率的 app 之后调 setResolution 退出 auto、无闪烁;删掉一个 runtime setResolution 已覆盖的 init-only opt-out」。逐条用 Git 历史透镜 + 代码 trace 核实

  1. 非 breaking 删除(关键,同 9df47a601 判例):拉 dev/2.0(PR base)的 WebGLEngine.ts 原文——WebGLEngineConfiguration根本没有 autoResize 字段(连 setAutoResolution/resizeByClientSize/_releaseCanvas 都没有,整套 auto-resize machinery 全是本 PR 引入的)。删一个本 PR 自引入、从未发版的 create 选项,不是回退任何已发布 API,是消除本 PR 自己加的 init-only opt-out。非静默回退(commit body 诚实记录依据,能力由 runtime setResolution 覆盖)。
  2. 零残留消费者git grep autoResize HEAD(本地 worktree HEAD = 724dd3cee)= ;PR head tree 同(docs commit 不重引 autoResize)。删除后无一处 dangling reference。
  3. 删的测试是配套 revert-safe 清理:删掉的正是 autoResize false disables the default follow 用例——它测的是现已删除的 { canvas, autoResize: false } 路径,随代码一并删除正确(为已删代码留测试才是债)。其余 canvas auto resize 全链路测试(默认建 observer / 重入复用 observer+更新 scale / 帧 pump Math.round resize / 0×0 skip 保留 pending / setResolution 退出 auto+非法值 throw / setAutoResolution 非法 scale throw / destroy 释放 observer)原样保留、反向证伪机制完整;注释 autoResize defaults to truecreate enters auto mode by default 准确。
  4. 「无闪烁」claim 成立(trace setAutoResolution→observer 初始回调→_pumpPendingResize_exitAutoResize):新替代路径 = create({ canvas }) 建 observer + observe()(初始回调异步只置 _pendingResize=true),app 随后同步调 setResolution(w,h)_exitAutoResize()任何帧 pump 之前_pendingResize=false + 断 observer → 无 auto-resize 帧;即便某帧 pump 抢先,也是 _pumpPendingResize 与 render 同帧(本 PR 早已建立的机制),无白屏。唯一代价 = app 立即 setResolution 时一次多余的 observer attach+detach,可忽略。

判例意义:这条与 9df47a601(删 deprecated forwarder)同源——本 PR 在发版前继续收敛自己尚未发布的 API 表面,减一个 config 旋钮 = 少一份用户认知 + 少一条代码分支,是净简化。

90a8755382 逐条核对(docs-only):闭环我历史长期 [P2] 「docs 教已删的 resizeByClientSize

canvas.mdx(en+zh 各 +56/-47)重写适配章节,逐条打开代码验证非 aspirational(撒谎)

  • 「默认自动跟随显示尺寸」← create 恒调 setAutoResolution()
  • setAutoResolution(scale=1) / (0.7) / (2)override setAutoResolution(scale: number = 1) + scale>0 守卫 ✓
  • setAutoResolution 覆盖之前的 setResolution」← re-observe / 新建 observer 分支 ✓
  • setResolution(1920,1080) 锁定固定分辨率、退出 auto ← Canvas.setResolution_exitAutoResize()+_setSize
  • width/height 只读」← read-only getter ✓
  • mermaid「ResizeObserverdevicePixelContentBoxSize×scale;fallback clientWidth×devicePixelRatio」← _pumpPendingResize exact-device-pixel 路径 + Safari fallback 逐字对齐 ✓
  • 「resize deferred 到下一帧 engine.update() 防撕裂」← pump-before-render 机制 ✓
  • Fixed Width 例改用 setResolution(fixedWidth, Math.round(innerHeight/scale))+setScaleMath.round 是好卫生(正值不 throw)✓
  • zh 版是连贯中文翻译,非英文残留 copy-paste ✓

platform.mdx(en+zh)DPR Mode 表格 cell 从「via resizeByClientSize」改「via setAutoResolution」,Auto/Fixed 描述随新模型对齐;raycast.mdx/README/galacean-README 删掉已删的 engine.canvas.resizeByClientSize() 行、注释改「auto-resizes by default」,无 dangling 句子

逐文件核对 PR head(90a8755382)8 个文件的 resizeByClientSize 残留计数 = 全 0。我历史长期 [P2]「docs/README 未随 breaking change 更新」闭环

CI

tip 90a8755382build×3(win/mac/ubuntu)/ codecov / codecov/project / e2e×4 / lint / labeler 全部 SUCCESSe2e×4 全绿是关键实证——724dd3cee 改了 create 期 auto-resize 路径(现无条件 setAutoResolution()),e2e 跑真机 create → run → update → render 循环,坐实默认常开 auto-resize 不回归。唯一 codecov/patch fail = refactor 删行 + docs、无新增产物覆盖行的比值 artifact(codecov job 本身 pass、真 suite 全 pass、e2e×4 全绿),同历轮判定,不作为 finding。

已闭环清单(逐条对 tip 核对,未回退)

  • [P0] 83+ e2e resizeByClientSize 迁移 / 8 单测 suite 崩溃 → e2e×4 全绿。关闭。
  • [P1] _cleanupAutoResize/_releaseCanvas this-loss;lint red → lint SUCCESS。关闭。
  • [P2] observe 注释撒谎/白屏;isOffscreenCanvas 收成 internal;DPR 调用时固化;scale 校验 throw;devicePixelContentBoxSize 精确设尺;enable/disable deprecated forwarder 删除;autoResize create 选项删除;[P3] pending 标志/字段位置/注释句号/_pumpPendingResize 悬挂引用。均关闭、未回退WebCanvas.ts/Canvas.ts/WebGLGraphicDevice.ts/Engine.ts 本轮零改动)。
  • [P2] docs/README 未随 breaking change 更新(8 文件教已删的 resizeByClientSize)→ 本轮 90a8755382 全部迁移,8 文件 resizeByClientSize 残留 = 0。闭环。

仍开放(非阻塞,硬去重不重提展开)

  • [P2] 基类 Canvas 抽象契约 breaking 建议标 CHANGELOGBREAKING CHANGE 已入 commit body):本轮未触,仍开放,建议合并前顺手补。
  • [P3] WebCanvas.ts:110 fallback 注释举 Safari 为例略过时(Safari 16.4+ 已支持 devicePixelContentBoxSize):本轮 WebCanvas.ts 逐字节未动,原样延续,仅作记录。

结论

approve:本轮 2 个 commit——① 724dd3cee 删掉本 PR 自引入、从未发版autoResize create 选项(Git 历史透镜坐实 dev/2.0 base 上 WebGLEngineConfigurationautoResize = 非 breaking、非静默回退),全仓 git grep autoResize = 空零残留消费者,删的测试是测已删代码的配套清理(revert-safe),「无闪烁」claim 经 trace 成立(setResolution_exitAutoResize 在帧 pump 前清 pending),是减一个 config 旋钮的净简化;② 90a8755382 把 8 个 docs/README 从已删的 resizeByClientSize 迁到 setAutoResolution/setResolution,逐条打开代码验所有 claim 非 aspirational、8 文件残留计数全 0、zh 版连贯——闭环我历史长期 [P2] docs finding。核心产物文件本轮零改动、历史全部闭环项未回退,CI 全绿(唯 codecov/patch 是比值 artifact),e2e×4 实证 auto-resize 默认常开不回归。无 P0/P1/P2/新阻塞项。因 HEAD 已推过我上轮 approve 的 commit(reviewDecision = REVIEW_REQUIRED),在新 tip 90a8755382 提交 APPROVE 以维持 gate 清空。剩一条 P2(CHANGELOG)+ 一条 P3(Safari 注释)均非阻塞,建议合并前顺手清。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation engine

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants