Skip to content

bugfix: キャッシュ運用の不具合調査#283

Merged
ienaga merged 2 commits into
mainfrom
develop
May 5, 2026
Merged

bugfix: キャッシュ運用の不具合調査#283
ienaga merged 2 commits into
mainfrom
develop

Conversation

@ienaga
Copy link
Copy Markdown
Member

@ienaga ienaga commented May 5, 2026

No description provided.

ienaga and others added 2 commits May 4, 2026 20:53
- CacheStoreGetService: get時にtrash_storeからもエントリを除外し、
  removeTimer後の参照で削除予定がスキップされる問題を解消
- DisplayObjectContainerGenerateRenderQueueUseCase: cacheAsBitmap更新時の
  $removeIds.push漏れを修正し、Worker側にもキャッシュ削除を伝搬
- FillTexturePool: バケット上限32/総数上限256を導入し、超過時はdestroy
  することでGPUメモリの単調増加を防止
- 各変更に対するユニットテストを追加

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 5, 2026 01:13
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses suspected cache lifecycle issues (GPU textures / atlas nodes) by tightening pool limits, ensuring old cached GPU resources are released before overwrites, and refining CacheStore “trash/timer” behavior to avoid unintended wipes and render races.

Changes:

  • Add per-bucket and total caps to the WebGPU fill/render texture pools, destroying textures when limits are exceeded (with new unit tests).
  • Fix GPU/atlas leaks by releasing previously cached filter textures/attachments before overwriting cache entries (WebGL/WebGPU), and by removing stale atlas Nodes on MISS paths when Main/Worker caches get out of sync.
  • Improve cache cleanup orchestration: add CacheStore.cancelRemoveTimer, cancel scheduled removals on get(), and centralize cache-value disposal via Context.releaseTextureCache() used by CommandRemoveCacheService.

Reviewed changes

Copilot reviewed 27 out of 28 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/index.ts Bumps displayed player version string.
packages/webgpu/src/FillTexturePool.ts Adds bucket/total caps and count tracking for pooled GPUTextures.
packages/webgpu/src/FillTexturePool.test.ts New tests validating pool reuse and destruction when limits are exceeded.
packages/webgpu/src/Context/usecase/ContextContainerEndLayerUseCase.ts Releases old cached filter attachment before overwriting cache entry.
packages/webgpu/src/Context.ts Adds releaseTextureCache() to dispose Node/attachment-like cache values.
packages/webgl/src/Context/usecase/ContextContainerEndLayerUseCase.ts Releases old cached filter texture before overwriting cache entry.
packages/webgl/src/Context/usecase/ContextApplyFilterUseCase.ts Releases cached texture when filter key changes; avoids reuse when cache is null.
packages/webgl/src/Context.ts Adds releaseTextureCache() to dispose Node/texture-like cache values.
packages/text/src/TextField/usecase/TextFieldResetUseCase.ts Stops pushing removeIds from Main to avoid Worker wipe race; adds rationale comment.
packages/renderer/src/Video/usecase/VideoRenderUseCase.ts Removes stale cached Node before creating a new Node on MISS to prevent atlas leaks.
packages/renderer/src/Video/usecase/VideoRenderUseCase.test.ts Updates RendererUtil mock to include removeNode.
packages/renderer/src/TextField/usecase/TextFieldRenderUseCase.ts Removes stale cached Node before creating a new Node on MISS.
packages/renderer/src/Shape/usecase/ShapeRenderUseCase.ts Removes stale cached Node before creating a new Node on MISS (bitmap and scaled paths).
packages/renderer/src/Command/service/CommandRemoveCacheService.ts Uses Context.releaseTextureCache() to dispose mixed cache values safely.
packages/renderer/src/Command/service/CommandRemoveCacheService.test.ts Updates expectations to match releaseTextureCache() usage.
packages/display/src/Shape/usecase/ShapeClearBitmapBufferUseCase.ts Stops pushing removeIds from Main to avoid Worker wipe race; adds rationale comment.
packages/display/src/MovieClip/service/MovieClipGetChildrenService.ts Schedules cleanup by instanceId (timer if main entry exists, else push removeIds).
packages/display/src/DisplayObjectContainer/usecase/DisplayObjectContainerGenerateRenderQueueUseCase.ts Changes container filter cache marker from dynamic key to "filterKey" value; adjusts HIT/MISS flow.
packages/display/src/DisplayObject/service/DisplayObjectDispatchRemovedToStageEventService.ts Adds instanceId-based cache cleanup scheduling on removal.
packages/display/src/DisplayObject/service/DisplayObjectDispatchAddedToStageEventService.ts Cancels pending remove timers on re-add to prevent delayed wipe after revival.
packages/cache/src/CacheStore/service/CacheStoreGetService.ts Cancels pending deletion on get() by removing from trash_store and clearing marker.
packages/cache/src/CacheStore/service/CacheStoreGetService.test.ts Updates tests for new signature and adds trash-cancel coverage.
packages/cache/src/CacheStore/service/CacheStoreCancelRemoveTimerService.ts New service to cancel scheduled removal and clear "trash" marker.
packages/cache/src/CacheStore/service/CacheStoreCancelRemoveTimerService.test.ts New tests for cancelRemoveTimer behavior.
packages/cache/src/CacheStore.ts Adds cancelRemoveTimer() API; routes get() through updated GetService signature.
packages/cache/src/CacheStore.test.ts Adds integration-style tests for trash flow (but includes a misnamed test title).
package.json Version bump to 3.3.0 and dev dependency patch bumps.
package-lock.json Lockfile updates consistent with package.json changes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

data.delete("trash");
}

return data.get(key) || null;

describe("CacheStore trash flow integration", () =>
{
it("removeTimer -> get -> removeTimerScheduledCache should still delete the entry", () =>
Comment on lines 55 to 68
const hasNode = Boolean(render_queue[index++]);

node = hasNode
? $cacheStore.get(uniqueKey, `${cacheKey}`) as Node
: $context.createNode(width, height);

if (!hasNode) {
if (hasNode) {
node = $cacheStore.get(uniqueKey, `${cacheKey}`) as Node;
} else {
// Main 側のみ wipe された race を考慮し、新規作成前に旧 Node を解放
// (Shape/TextField MISS パスと同じ防御策。通常は no-op)
const oldNode = $cacheStore.get(uniqueKey, `${cacheKey}`) as Node | null;
if (oldNode) {
$context.removeNode(oldNode);
}
node = $context.createNode(width, height);
$cacheStore.set(uniqueKey, `${cacheKey}`, node);
}
Comment on lines 64 to 77
const hasNode = Boolean(render_queue[index++]);

node = hasNode
? $cacheStore.get(uniqueKey, `${cacheKey}`) as Node
: $context.createNode(width, height);

if (!hasNode) {
if (hasNode) {
node = $cacheStore.get(uniqueKey, `${cacheKey}`) as Node;
} else {
// TextFieldResetUseCase 等で Main 側のみ wipe された場合、
// Worker には旧 Node が残っているため、新規作成前に解放してアトラスリーク防止
const oldNode = $cacheStore.get(uniqueKey, `${cacheKey}`) as Node | null;
if (oldNode) {
$context.removeNode(oldNode);
}
node = $context.createNode(width, height);
$cacheStore.set(uniqueKey, `${cacheKey}`, node);
}
Comment on lines +74 to 82
// ShapeClearBitmapBufferUseCase 等で Main 側のみ wipe された場合、
// Worker には旧 Node が残っているため、新規作成前に解放してアトラスリーク防止
const oldBitmapNode = $cacheStore.get(uniqueKey, `${cacheKey}`) as Node | null;
if (oldBitmapNode) {
$context.removeNode(oldBitmapNode);
}
node = $context.createNode(width, height);
$cacheStore.set(uniqueKey, `${cacheKey}`, node);

Comment on lines +117 to 125
// ShapeClearBitmapBufferUseCase 等で Main 側のみ wipe された場合、
// Worker には旧 Node が残っているため、新規作成前に解放してアトラスリーク防止
const oldNode = $cacheStore.get(uniqueKey, `${cacheKey}`) as Node | null;
if (oldNode) {
$context.removeNode(oldNode);
}
node = $context.createNode(width, height);
$cacheStore.set(uniqueKey, `${cacheKey}`, node);

@ienaga ienaga merged commit 19c76d9 into main May 5, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants