Upgrading pool pattern

This commit is contained in:
2026-09-20 20:52:09 -07:00
parent fe40d4a629
commit 16f7bb7da3
18 changed files with 268 additions and 332 deletions
+31 -10
View File
@@ -3,34 +3,55 @@
## ResourceRegistry
A ResourceRegistry owns GPU-backed resources on the caller's behalf and hands out
lightweight Handles instead of pointers or ownership.
lightweight Handles instead of pointers or ownership. It is engine-internal:
frontend code never sees it, and reaches it through a ResourceRegistryRef.
Internally it's a collection of per-type pools, each responsible for one
resource type:
Internally it's a collection of per-type pools, each a `Pool<T, Handle>`
(a generation-checked slot pool). A type that needs extra behaviour wraps its
pool in a thin class instead:
```
ResourceRegistry
├── MeshPool → MeshHandle
├── TexturePool → TextureHandle (planned)
└── MaterialPool → MaterialHandle (planned)
├── meshes Pool<Mesh, MeshHandle>
├── renderTargets RenderTargetPool → RenderTargetHandle
│ (wraps Pool; waits for the GPU on release, applies resizes)
├── scenes Pool<Scene, SceneHandle>
├── textures (planned)
└── materials (planned)
```
Engine code (`Application`, `ImGuiRenderer`, `SceneRenderer`) uses the pools
directly, e.g. `resources.renderTargets.get(handle)`.
A Handle is a small (index, generation) pair. The index locates the slot in
the pool; the generation is bumped when that slot is released, so a Handle
kept around after release() is detected as stale instead of resolving to
someone else's resource (or freed memory).
Think: "Where does the engine keep every GPU resource, and how does it look one
up by handle?"
## ResourceRegistryRef
A ResourceRegistryRef is the frontend's non-owning, cheap-to-copy view of the
ResourceRegistry, returned by `Application::resources()`. It exposes only what
frontend code needs and hands out no pools, so no Vulkan-facing types leak
through the public API:
```
create<T>(...) load<T>(path) release<T>(handle)
requestResize(target, w, h) getExtent(target) isAlive(handle)
```
Typical lifecycle:
```
load<Mesh>(path) / create<Mesh>(...) → MeshHandle
│
get<Mesh>(handle) → const Mesh&
│
release<Mesh>(handle)
```
Think: "Where do I get or release a GPU resource by handle, without owning its
Think: "How do I create or release a GPU resource by handle, without owning its
lifetime directly?"
## Buffer
@@ -257,7 +278,7 @@ A PanelRegistry owns Panels on the caller's behalf and hands out lightweight
PanelHandles instead of pointers or ownership.
Internally it's a generation-checked slot pool, the same shape ResourceRegistry's
per-type pools use:
`Pool<T, Handle>` uses:
```
PanelRegistry