Add Device::PreferDirectDeviceWrite(size) so the memory-placement cluster
(#65/#72/#73/#75) no longer re-derives where a CPU-written, GPU-read buffer
should live. It picks the strategy at runtime from Device::memoryProperties:
- No DEVICE_LOCAL|HOST_VISIBLE type (no resizable BAR) -> false (must stage).
- ReBAR/UMA (BAR heap >= 90% of largest DEVICE_LOCAL heap) -> true: map and
write directly; a staging copy would be pure overhead.
- Small BAR window (BAR heap << VRAM) -> true only for buffers within a
per-window budget (1/8 of the window); large buffers stage so they don't
exhaust the window (#58).
Complements GetMemoryType (#59): #59 picks the memory *type*, this picks the
*strategy*. Upload-only — readback (#74) wants HOST_CACHED and stays separate.
A VK_EXT_memory_budget-driven remaining-space check is noted as a follow-up.
Tested by tests/UploadStrategy (pure CPU over synthetic ReBAR / UMA /
small-window / no-BAR layouts, no GPU device needed), mirroring
MemoryTypeFallback.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>