diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index e80808621b..e93f3478d1 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -291,10 +291,16 @@ MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, M return std::move(*commit); } // Commit has failed, allocate more memory. - const u64 chunk_size = AllocationChunkSize(requirements.size); + u64 chunk_size = AllocationChunkSize(requirements.size); if (!TryAllocMemory(flags, type_mask, chunk_size)) { - // TODO(Rodrigo): Handle out of memory situations in some way like flushing to guest memory. - throw vk::Exception(VK_ERROR_OUT_OF_DEVICE_MEMORY); + const u64 floor = std::max(requirements.size, 4ull << 20); + while (chunk_size > floor && !TryAllocMemory(flags, type_mask, (chunk_size >>= 1))) { + // keep halving until we can make progress + } + if (chunk_size <= floor && !TryAllocMemory(flags, type_mask, floor)) { + // TODO(Rodrigo): Handle out of memory situations in some way like flushing to guest memory. + throw vk::Exception(VK_ERROR_OUT_OF_DEVICE_MEMORY); + } } // Commit again, this time it won't fail since there's a fresh allocation above. // If it does, there's a bug. @@ -331,11 +337,26 @@ void MemoryAllocator::ReleaseMemory(MemoryAllocation* alloc) { std::optional MemoryAllocator::TryCommit(const VkMemoryRequirements& requirements, VkMemoryPropertyFlags flags) { + //conservative, spec-compliant alignment for suballocation + VkDeviceSize eff_align = requirements.alignment; + const auto& limits = device.GetPhysical().GetProperties().limits; + if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && + !(flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { + // Non-coherent memory must be invalidated on atom boundary + if (limits.nonCoherentAtomSize > eff_align) eff_align = limits.nonCoherentAtomSize; + } + // Separate buffers to avoid stalls on tilers + if (buffer_image_granularity > eff_align) + { + eff_align = buffer_image_granularity; + } + eff_align = std::bit_ceil(eff_align); + for (auto& allocation : allocations) { if (!allocation->IsCompatible(flags, requirements.memoryTypeBits)) { continue; } - if (auto commit = allocation->Commit(requirements.size, requirements.alignment)) { + if (auto commit = allocation->Commit(requirements.size, eff_align)) { return commit; } }