[perf][MEDIUM] Descriptor heaps force HOST_VISIBLE|DEVICE_LOCAL with no fallback #58

Closed
opened 2026-06-16 16:51:33 +02:00 by jorijnvdgraaf · 1 comment

Subsystem: Device / DescriptorHeap
Location: interfaces/Crafter.Graphics-DescriptorHeapVulkan.cppm:86-89 (root cause implementations/Crafter.Graphics-Device.cpp:814-827)
Impact: MEDIUM (robustness/portability) · Effort: Small · Setup-time
Related: #59 (the fallback mechanism this needs), #89 (upload-strategy helper — generalizes the "don't over-commit the small BAR window" budget logic referenced below)

Problem

Initialize allocates 3 heap copies requesting HOST_VISIBLE|DEVICE_LOCAL. GetMemoryType returns the first match and throws if none exists. On a discrete non-ReBAR GPU the only such type is the ~256 MB pinned BAR heap, so the bindless heaps compete for scarce BAR memory — or the app hard-throws.

Proposed fix

Make GetMemoryType prefer-but-not-require DEVICE_LOCAL for host-visible heaps: try HOST_VISIBLE|DEVICE_LOCAL, fall back to plain HOST_VISIBLE. Keep HOST_VISIBLE a hard requirement.

Correctness caveat

The per-frame triplication is correct by design (each frame-slot binds its own heap copy; collapsing to one shared region is a write-after-read race — keep it). If the fallback type lacks HOST_COHERENT, correctness then depends on the existing FlushDevice/FlushHost paths being called.

**Subsystem:** Device / DescriptorHeap **Location:** `interfaces/Crafter.Graphics-DescriptorHeapVulkan.cppm:86-89` (root cause `implementations/Crafter.Graphics-Device.cpp:814-827`) **Impact:** MEDIUM (robustness/portability) · **Effort:** Small · Setup-time **Related:** #59 (the fallback mechanism this needs), #89 (upload-strategy helper — generalizes the "don't over-commit the small BAR window" budget logic referenced below) ### Problem `Initialize` allocates 3 heap copies requesting `HOST_VISIBLE|DEVICE_LOCAL`. `GetMemoryType` returns the first match and **throws** if none exists. On a discrete non-ReBAR GPU the only such type is the ~256 MB pinned BAR heap, so the bindless heaps compete for scarce BAR memory — or the app hard-throws. ### Proposed fix Make `GetMemoryType` prefer-but-not-require DEVICE_LOCAL for host-visible heaps: try `HOST_VISIBLE|DEVICE_LOCAL`, fall back to plain `HOST_VISIBLE`. Keep HOST_VISIBLE a hard requirement. ### Correctness caveat The per-frame triplication is **correct by design** (each frame-slot binds its own heap copy; collapsing to one shared region is a write-after-read race — keep it). If the fallback type lacks HOST_COHERENT, correctness then depends on the existing `FlushDevice`/`FlushHost` paths being called.
Member

Investigated — this is already fully resolved by #59 (commit 294c137, merged via PR #87). #58 and #59 are duplicate findings from the same audit, and #59 implements the exact fix proposed here, touching the same files and lines.

What is already in master:

  • Device::GetMemoryType (implementations/Crafter.Graphics-Device.cpp:814-843) now takes a preferred mask distinct from required. It tries required | preferred first, falls back to required alone, and throws only when even required cannot be satisfied. HOST_VISIBLE stays a hard requirement; DEVICE_LOCAL is a preference.
  • The descriptor heaps (interfaces/Crafter.Graphics-DescriptorHeapVulkan.cppm:86-93 — the exact lines this issue cites) now call Resize(..., VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, size, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT), i.e. host-visible required + device-local preferred. On a discrete non-ReBAR GPU they get a host-visible-only allocation instead of competing for BAR memory or hard-throwing.
  • Correctness caveat handled: the per-frame triplication is preserved (one heap copy per frame-slot), and descriptor writes are followed by FlushDevice() (implementations/Crafter.Graphics-UI.cpp:69,77,304,327,344), so a fallback memory type without HOST_COHERENT is still safe.
  • A regression test (tests/MemoryTypeFallback) exercises selection, preference, fallback, and the unsatisfiable-required throw. It passes: crafter-build test → 8 passed, including MemoryTypeFallback.

No code change is needed. Recommend closing this as a duplicate of #59. No PR opened (there would be no diff).

Investigated — **this is already fully resolved by #59** (commit `294c137`, merged via PR #87). #58 and #59 are duplicate findings from the same audit, and #59 implements the exact fix proposed here, touching the same files and lines. What is already in `master`: - **`Device::GetMemoryType`** (`implementations/Crafter.Graphics-Device.cpp:814-843`) now takes a `preferred` mask distinct from `required`. It tries `required | preferred` first, falls back to `required` alone, and throws only when even `required` cannot be satisfied. `HOST_VISIBLE` stays a hard requirement; `DEVICE_LOCAL` is a preference. - **The descriptor heaps** (`interfaces/Crafter.Graphics-DescriptorHeapVulkan.cppm:86-93` — the exact lines this issue cites) now call `Resize(..., VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, size, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)`, i.e. host-visible required + device-local preferred. On a discrete non-ReBAR GPU they get a host-visible-only allocation instead of competing for BAR memory or hard-throwing. - **Correctness caveat handled:** the per-frame triplication is preserved (one heap copy per frame-slot), and descriptor writes are followed by `FlushDevice()` (`implementations/Crafter.Graphics-UI.cpp:69,77,304,327,344`), so a fallback memory type without `HOST_COHERENT` is still safe. - A regression test (`tests/MemoryTypeFallback`) exercises selection, preference, fallback, and the unsatisfiable-required throw. It passes: `crafter-build test` → 8 passed, including `MemoryTypeFallback`. No code change is needed. Recommend closing this as a duplicate of #59. No PR opened (there would be no diff).
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
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#58
No description provided.