Repository navigation
Conversation
|
pkg.pr.new packages benchmark commit |
Bundle size comparison (
|
| 🟢 Decreased | ➖ Unchanged | 🔴 Increased | ❔ Unknown |
|---|---|---|---|
| 0 | 355 | 0 | 0 |
No notable changes.
If you wish to run a comparison for other, slower bundlers, run the 'Tree-shake test' from the GitHub Actions menu.
Resolution Time Benchmark---
config:
themeVariables:
xyChart:
plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
title "Random Branching (🔴 PR | 🔵 main | 🟢 release)"
x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
y-axis "time (ms)"
line [1.12, 2.15, 4.86, 7.53, 8.48, 13.10, 28.11, 27.79]
line [1.06, 2.18, 5.12, 8.00, 9.13, 16.23, 28.97, 28.30]
line [1.06, 2.19, 4.68, 7.62, 9.54, 13.99, 26.32, 27.18]
---
config:
themeVariables:
xyChart:
plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
title "Linear Recursion (🔴 PR | 🔵 main | 🟢 release)"
x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
y-axis "time (ms)"
line [0.34, 0.56, 0.74, 0.93, 1.25, 1.28, 1.52, 1.73]
line [0.35, 0.59, 0.82, 0.92, 1.24, 1.37, 1.57, 1.72]
line [0.34, 0.53, 0.77, 0.89, 1.21, 1.35, 1.55, 1.71]
---
config:
themeVariables:
xyChart:
plotColorPalette: "#E63946, #3B82F6, #059669"
---
xychart
title "Full Tree (🔴 PR | 🔵 main | 🟢 release)"
x-axis "max depth" [1, 2, 3, 4, 5, 6, 7, 8]
y-axis "time (ms)"
line [0.86, 2.49, 4.39, 8.39, 14.64, 29.39, 61.25, 125.42]
line [1.02, 2.43, 4.14, 8.18, 14.76, 29.42, 63.56, 128.75]
line [1.02, 2.31, 4.07, 7.54, 15.57, 29.82, 62.00, 126.88]
|
…FinalizationRegistry
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues are reported for the WebGL sampler-lifetime cleanup changes.
No open issues 🎉
What changed in this PR
Fixes #3287 by allowing unused WebGL sampler wrappers to be collected while their root remains alive, preventing long-lived roots from retaining every sampler.
Changes:
- Tracks native sampler handles and uses
FinalizationRegistryto release unused samplers. - Preserves cleanup on
root.destroy(), including a fallback for runtimes withoutFinalizationRegistry. - Adds tests for collection, pipeline retention, root independence, and exactly-once cleanup.
| File | Description |
|---|---|
packages/typegpu-gl/tests/garbageCollection.test.ts |
Adds sampler lifetime and cleanup regression tests. |
packages/typegpu-gl/src/tgpuRootWebGL.ts |
Replaces wrapper retention with native-handle tracking and finalizer cleanup. |
Review effort: Balanced
There was a problem hiding this comment.
✅ No new issues found ( ◦°^°◦)
Ahoy — I verified the sampler GC fix end to end and found nary a leak nor a double-delete.
Reviewed changes
This run reviewed the full PR at 727adf7 (2 commits, 2 files).
- Sampler tracking switched to native handles —
#samplers(WebGLSamplerImpl[]) is replaced by#rawSamplers(Set<WebGLSampler>), so the root no longer strongly retains sampler wrappers. FinalizationRegistry-based release — a per-root registry deletes a sampler's native handle once its wrapper is collected, with the#rawSamplers.delete(raw)guard making deletion idempotent.destroy()preserves its contract — unregisters and deletes each remaining handle exactly once, then clears the set, so a late finalizer is a no-op.- No-
FinalizationRegistryfallback — handles stay tracked but are released only ondestroy()(previous behaviour) rather than failing to construct. - Five new GC tests — unused-sampler collection, pipeline retention then collection, exactly-once delete on destroy, a retained sampler not pinning its root or siblings, and the fallback path.
I confirmed the load-bearing invariant myself: pipelines retain the same WebGLSamplerImpl instance that createSampler returns (via TgpuWebGLRenderPipelineImpl.#textureBindings[].sampler, and asTgpuSampler is only a cast), so a sampler in use can never be finalized early. Verified locally: vitest packages/typegpu-gl → 159 passed / 2 skipped; tsc -p packages/typegpu-gl/tsconfig.json → exit 0.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

Fixes #3287.
The GL root kept every sampler wrapper in an array until
root.destroy(). It now tracks only the native handles, and aFinalizationRegistrydeletes a sampler's native handle (and its bookkeeping entry) once the wrapper is collected. Pipelines still keep the samplers they use alive through their texture bindings.root.destroy()deletes the remaining handles exactly once and unregisters them.On runtimes without
FinalizationRegistry, the root still tracks only the native handles, but releases them only onroot.destroy()(the previous behaviour), instead of failing to construct.Tests (in
garbageCollection.test.ts):main).main).root.destroy()deletes each remaining sampler exactly once, with no extra deletes from finalizers afterwards.FinalizationRegistry, samplers are still released onroot.destroy().Not done here:
texture.destroy()orroot.destroy()), for now. Only samplers are released when they become unreachable.