perf(window): cache per-frame heap-bind structs across frames #77

Merged
catbot merged 1 commit from claude/issue-42 into master 2026-06-16 17:27:55 +02:00
Member

Summary

Every frame, Window::Render() rebuilt two VkBindHeapInfoEXT structs and recomputed reservedRangeOffset via a runtime subtract + bitmask against Device::descriptorHeapProperties. The heap address/size per slot are stable for a given heap; only currentBuffer varies.

This precomputes numFrames resource/sampler bind structs and caches them, recording the cached struct for currentBuffer each frame.

Invalidation

The cache is keyed on the descriptorHeap pointer (cachedDescriptorHeap). It rebuilds whenever the heap is (re)assigned and otherwise just indexes by currentBuffer. Since descriptorHeap is a public field assigned directly (window.descriptorHeap = &heap) with no setter to hook, pointer-keyed invalidation is the equivalent — and strictly safer — hook: it fires on any reassignment, exactly when a setter would, and is independent of onResize (heaps never resize today, per the issue's correctness caveat).

Testing

  • crafter-build test — green (3 passed).
  • Built and ran the VulkanTriangle example natively (sets descriptorHeap, renders + presents). Vulkan validation layers reported no errors on the heap-bind path; the ray-traced triangle presents correctly.

Screenshots

result

Resolves #42

## Summary Every frame, `Window::Render()` rebuilt two `VkBindHeapInfoEXT` structs and recomputed `reservedRangeOffset` via a runtime subtract + bitmask against `Device::descriptorHeapProperties`. The heap address/size per slot are stable for a given heap; only `currentBuffer` varies. This precomputes `numFrames` resource/sampler bind structs and caches them, recording the cached struct for `currentBuffer` each frame. ## Invalidation The cache is keyed on the `descriptorHeap` pointer (`cachedDescriptorHeap`). It rebuilds whenever the heap is (re)assigned and otherwise just indexes by `currentBuffer`. Since `descriptorHeap` is a public field assigned directly (`window.descriptorHeap = &heap`) with no setter to hook, pointer-keyed invalidation is the equivalent — and strictly safer — hook: it fires on any reassignment, exactly when a setter would, and is independent of `onResize` (heaps never resize today, per the issue's correctness caveat). ## Testing - `crafter-build test` — green (3 passed). - Built and ran the VulkanTriangle example natively (sets `descriptorHeap`, renders + presents). Vulkan validation layers reported no errors on the heap-bind path; the ray-traced triangle presents correctly. ## Screenshots ![result](https://forgejo.catcrafts.net/attachments/8053688e-5b3f-4032-bb4e-bd6a65b87330) Resolves #42
Render() rebuilt two VkBindHeapInfoEXT structs every frame and
recomputed reservedRangeOffset via a runtime subtract + bitmask
against Device::descriptorHeapProperties. The heap address/size per
slot are stable for a given heap; only currentBuffer varies.

Precompute numFrames resource/sampler bind structs and cache them,
keyed on the descriptorHeap pointer. The cache rebuilds whenever the
heap is (re)assigned and otherwise just indexes by currentBuffer.
Pointer-keyed invalidation catches any heap reassignment — the same
point a setter hook would fire — and is independent of onResize, as
the heaps never resize today (per the issue's correctness caveat).

Resolves #42

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
catbot merged commit cea57f9af8 into master 2026-06-16 17:27:55 +02:00
catbot deleted branch claude/issue-42 2026-06-16 17:27:55 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Catcrafts/Crafter.Graphics!77
No description provided.