perf(window): use HOST_CACHED readback staging in SaveFrame (#74) #108

Merged
catbot merged 1 commit from claude/issue-74 into master 2026-06-17 19:45:17 +02:00
Member

Problem

SaveFrame allocated its readback staging buffer HOST_VISIBLE | HOST_COHERENT. On most discrete GPUs the first such type is write-combined (uncached), and CPU reads from write-combined memory are pathologically slow — the wrong memory type for a path that reads the whole frame back to disk.

Fix

  • Select a HOST_CACHED type (preferring a cached-coherent type when one exists), falling back to any HOST_VISIBLE type if no cached type is advertised (#59 mechanism, via GetMemoryType's required/preferred passes + a catch).
  • Invalidate the mapped range before the CPU read when the chosen type is cached-but-not-coherent — the read-path counterpart of FlushDevice (#60). Gated on the chosen type's actual coherency, not the requested flags. Whole-range invalidate sidesteps nonCoherentAtomSize.
  • Deliberately not routed through the #89 upload-strategy helper, which is upload-only and steers toward write-combined DEVICE_LOCAL|HOST_VISIBLE — the worst type for readback (see issue caveat 4).

Testing

  • crafter-build test — all 19 tests pass (incl. MemoryTypeFallback, which covers the fallback mechanism relied on here).
  • Drove SaveFrame from the VulkanTriangle example on an RTX 4090; the frame reads back with correct pixels and channel order.

Screenshots

SaveFrame readback

Resolves #74

## Problem `SaveFrame` allocated its readback staging buffer `HOST_VISIBLE | HOST_COHERENT`. On most discrete GPUs the first such type is **write-combined (uncached)**, and CPU *reads* from write-combined memory are pathologically slow — the wrong memory type for a path that reads the whole frame back to disk. ## Fix - Select a `HOST_CACHED` type (preferring a cached-coherent type when one exists), falling back to any `HOST_VISIBLE` type if no cached type is advertised (#59 mechanism, via `GetMemoryType`'s required/preferred passes + a catch). - Invalidate the mapped range before the CPU read when the chosen type is cached-but-not-coherent — the read-path counterpart of `FlushDevice` (#60). Gated on the **chosen type's actual coherency**, not the requested flags. Whole-range invalidate sidesteps `nonCoherentAtomSize`. - Deliberately **not** routed through the #89 upload-strategy helper, which is upload-only and steers toward write-combined `DEVICE_LOCAL|HOST_VISIBLE` — the worst type for readback (see issue caveat 4). ## Testing - `crafter-build test` — all 19 tests pass (incl. `MemoryTypeFallback`, which covers the fallback mechanism relied on here). - Drove `SaveFrame` from the VulkanTriangle example on an RTX 4090; the frame reads back with correct pixels and channel order. ## Screenshots ![SaveFrame readback](https://forgejo.catcrafts.net/attachments/05919728-3d6b-44ef-86a4-19c279accc04) Resolves #74
SaveFrame's readback staging buffer was allocated HOST_VISIBLE |
HOST_COHERENT, whose first matching type is write-combined (uncached) on
most discrete GPUs. The CPU then reads the entire frame back from it —
and reads from write-combined memory are pathologically slow.

Select a HOST_CACHED type instead (preferring a cached-coherent type
when one exists), falling back to any HOST_VISIBLE type if no cached type
is advertised (#59 mechanism). When the chosen type is cached-but-not-
coherent, invalidate the mapped range before the CPU read — the read-path
counterpart of FlushDevice (#60) — gated on the chosen type's actual
coherency, not the requested flags. Whole-range invalidate sidesteps
nonCoherentAtomSize.

Deliberately not routed through the #89 upload-strategy helper, which is
upload-only and steers toward write-combined DEVICE_LOCAL|HOST_VISIBLE —
the worst type for readback.

Verified by driving SaveFrame from the VulkanTriangle example: the
barycentric RGB triangle reads back with correct pixels and channel
order on an RTX 4090.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
catbot merged commit d77bd860ba into master 2026-06-17 19:45:17 +02:00
catbot deleted branch claude/issue-74 2026-06-17 19:45:17 +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!108
No description provided.