feat: add texture pooling on Darwin - #199
Draft
nmfisher wants to merge 7 commits into
Draft
Conversation
…ace leak (#178) MetalTextureWrapper created a fresh CVMetalTextureCache per texture and dropped it on destroy. CVMetalTextureCache is designed to be a long-lived, per-device object; releasing a cache does not synchronously free the IOSurfaces it has cached, so CVMetalTextureCacheCreateTextureFromImage pinned ~one IOSurface per allocation that was never returned. Reuse one process-wide cache (lazily created per MTLDevice) and flush it on teardown (MaximumTextureAge: 0). Root cause isolated and the fix verified in a standalone Flutter reproducer (no thermion dependency): plain / shared cache + flush : flat (~0 MB/cycle) per-instance cache : ~1 surface/cycle leak In thermion's own leak probe, the per-cycle drift on a fresh wrapper dropped from ~2.15 MB/cycle (~1 IOSurface) to ~0.43 MB/cycle (the Flutter-compositor floor). Filament import/destroy is unaffected (still clean). The cache access is not safe for concurrent use; thermion already serializes texture allocation/teardown on its texture-mutation path (documented inline). See docs/DARWIN_IOSURFACE_LEAK_ROOT_CAUSE.md for the full investigation. Co-Authored-By: Claude <noreply@anthropic.com>
Adds an isolation probe that builds an imported color Texture + a depth Texture + a RenderTarget each cycle and destroys RT -> color -> depth, with no Flutter widget and no rendering. Pins that the Filament render-target rebuild is NOT a churn source: measured 0.58 MB drift over 16 cycles (flat), vs 0.08 MB for texture-import-only. This rules out the RT/depth rebuild as the source of the mount/unmount residual and obviates any "retain the RT across mounts" fix. Co-Authored-By: Claude <noreply@anthropic.com>
Adds a probe that builds color+depth+RT and renders 5 frames into it each cycle (no Flutter widget). Result: ~0.55 MB/cycle climb with a -4.48 MB burst reclaim at cycle 9 -> 2.88 MB net over 16 cycles. That burst-reclaim shape is churn (Metal per-frame command-buffer/encoder pools), not a leak. This localizes the mount/unmount residual: texture/RT create-destroy is balanced (filament-rt = 0.58 MB/16); the residual is Metal frame-pool churn during live rendering, which is bounded and self-reclaiming. No Filament GC API is relevant because Filament is not the holder. Co-Authored-By: Claude <noreply@anthropic.com>
…econdary (#178) The created-instance counters (MetalTextureWrapper / FlutterMetalTextureAdapter) are now documented as the authoritative leak check: they are flat across mount/unmount sessions and catch any producer leak unconditionally. phys_footprint drift is demoted to a loose secondary guard with a per-session budget (~1 surface/session) instead of one surface total. This sits above the ~0.8 MB/session Metal render-churn floor (per the filament-rt-render probe) but well below the one-surface-per-session leak the test targets. The old single-surface total budget false-positived on that churn. Main regression now passes on macOS while still guarding the real leak. Co-Authored-By: Claude <noreply@anthropic.com>
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.
The pool reuses one released macOS Flutter texture registration (and its
MetalTextureWrapper) for matching widget dimensions across mount/unmount, instead of registering/allocating a fresh producer each time.It is not required for correctness — #202 fixes the leak on its own. The pool is an optimization:
Not merge-ready / open items
@_cdecllive/created wrapper + adapter counts) and opt-in Darwin leak probes — test-only scaffolding to review (or drop) before merging.