fix(device): add preferred mask + required-only fallback to GetMemoryType (#59)
GetMemoryType was a bare first-superset match that threw whenever no memory type satisfied the requested property flags. Callers combining a mandatory flag with a perf-only one (HOST_VISIBLE | DEVICE_LOCAL for the descriptor heaps) would then fail allocation on any device without a host-visible device-local heap (no resizable BAR). It now takes a `preferred` mask distinct from `required`: a type satisfying both is chosen first, falling back to a required-only match when the preference is unavailable, and throwing only when even `required` cannot be met. VulkanBuffer::Create/Resize gain an optional trailing `preferredPropertyFlags`, and the descriptor heaps now treat DEVICE_LOCAL as a preference on top of mandatory HOST_VISIBLE. This does not touch any flush/barrier behaviour — coherency is not assumed anywhere here. Adds tests/MemoryTypeFallback, a pure-CPU test that installs synthetic memory layouts and exercises selection, preference, fallback, and the unsatisfiable-required throw. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
0b00d9d680
commit
294c1378b5
6 changed files with 218 additions and 13 deletions
|
|
@ -811,17 +811,32 @@ void Device::Initialize() {
|
|||
}
|
||||
}
|
||||
|
||||
std::uint32_t Device::GetMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties) {
|
||||
for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++)
|
||||
std::uint32_t Device::GetMemoryType(uint32_t typeBits, VkMemoryPropertyFlags required, VkMemoryPropertyFlags preferred) {
|
||||
// First pass: honour the preferred bits on top of the required ones.
|
||||
// Second pass (when nothing matched, or no preferences were given): drop
|
||||
// the preferences and match the required bits alone. Vulkan orders the
|
||||
// memory types so first-superset-match is generally optimal, so a plain
|
||||
// linear scan suffices for each pass. We only throw when even `required`
|
||||
// cannot be satisfied — i.e. no valid memory exists for the allocation.
|
||||
for (VkMemoryPropertyFlags wanted : {required | preferred, required})
|
||||
{
|
||||
if ((typeBits & 1) == 1)
|
||||
uint32_t bits = typeBits;
|
||||
for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++)
|
||||
{
|
||||
if ((memoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
|
||||
if ((bits & 1) == 1)
|
||||
{
|
||||
return i;
|
||||
if ((memoryProperties.memoryTypes[i].propertyFlags & wanted) == wanted)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
bits >>= 1;
|
||||
}
|
||||
|
||||
// No preferences to fall back from — the second pass would be identical.
|
||||
if (preferred == 0) {
|
||||
break;
|
||||
}
|
||||
typeBits >>= 1;
|
||||
}
|
||||
|
||||
throw std::runtime_error("Could not find a matching memory type");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue