散らかし跡の描画を差分更新にして全画面再描画をやめる#9
Closed
winebarrel wants to merge 3 commits into
Closed
Conversation
Address the converged performance finding (#3, plus #5): the overlay was invalidated wholesale (litterView.needsDisplay = true) and draw() cleared the entire multi-screen bounds every pass, so an active cat forced a full virtual-screen recomposite ~10-60fps. - LitterField.update now returns the global rects of marks that appeared or vanished (added, aged out, or evicted by the cap); onTick invalidates only those via LitterView.invalidateGlobal. fadingRects() drives the ~10fps refresh of marks in their fade window. - draw() clears only dirtyRect and skips marks that don't intersect it. - Cache the two base CGColors and apply per-mark opacity with ctx.setAlpha, so no color object is allocated per mark per frame. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pp772scLq2mo9cDaybWrLu
winebarrel
force-pushed
the
litter-incremental-repaint
branch
from
July 12, 2026 06:30
363f24d to
4d8bb36
Compare
Follow-up to the incremental repaint: draw() cleared the whole dirtyRect, which AppKit hands as the union bounding box of all invalidated rects. When marks are scattered — a long trail, or a whole tail fading at once via fadingRects() — that union spans most of the screen even though the real changed area is tiny, degrading back toward the old full-screen cost. Use getRectsBeingDrawn(_:count:) to clear and hit-test each disjoint sub-rect AppKit actually invalidated, so cost tracks changed pixels rather than how far apart the changes are. Also document that LitterView depends on being non-layer-backed: the incremental model trusts pixels outside the invalidated rects to survive, which a wantsLayer=true view would not guarantee. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pp772scLq2mo9cDaybWrLu
The per-sub-rect approach added overhead (per-mark rects.contains scan, extra region bookkeeping) that raised load in practice rather than lowering it, so drop it and keep the simpler #3 model: clear the single dirtyRect AppKit hands us and repaint marks intersecting it. The non-layer-backed dependency note on LitterView still applies and is kept. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pp772scLq2mo9cDaybWrLu
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概要
PR #8 の crit レビューで収束したパフォーマンス指摘(#3、および #5)に対応します。
これまで散らかし跡のオーバーレイは
litterView.needsDisplay = trueで全体を無効化し、draw()が全ディスプレイ union 全体をクリアしていたため、猫が走行・爪とぎしている間はフルスクリーン相当の再合成が ~10〜60fps で走り続けていました。変更
LitterField.updateが、このtickで出現/消滅した mark のグローバル矩形(追加・寿命切れ・キャップ退避)を返すように変更。onTickはその矩形だけをLitterView.invalidateGlobalで無効化する。fadingRects()を追加し、フェード中の mark だけを ~10fps で部分無効化。draw()はdirtyRectのみクリアし、dirtyRectと交差しない mark はスキップ。CGColorを2つキャッシュし、濃淡はctx.setAlphaで適用(mark ごと・フレームごとの色オブジェクト生成をゼロに)。これで再描画コストが「変更ピクセル数」に比例し、画面面積に依存しなくなります。常駐ペットとしての電力・CPU 負荷を大きく下げます。
見送った指摘(記録どおり)
確認
xcodebuild)🤖 Generated with Claude Code