diff --git a/ggml/src/ggml-vulkan/ggml-vulkan.cpp b/ggml/src/ggml-vulkan/ggml-vulkan.cpp index 766158b04..f7bcb5afc 100644 --- a/ggml/src/ggml-vulkan/ggml-vulkan.cpp +++ b/ggml/src/ggml-vulkan/ggml-vulkan.cpp @@ -18385,11 +18385,27 @@ static bool ggml_backend_vk_register_host_buffer(void * buffer, size_t size) { uint8_t * p = static_cast(buffer); size_t remaining = size; bool dev_success = false; + bool import_ok = true; // flips to false once VK_EXT_external_memory_host import fails while (remaining > 0) { size_t cur = std::min(remaining, chunk); - vk_buffer buf = ggml_vk_buffer_from_host_ptr(device, p, cur); + vk_buffer buf; + if (import_ok) { + buf = ggml_vk_buffer_from_host_ptr(device, p, cur); + } if (!buf || !buf->buffer) { - break; + // Fallback for drivers that can't import file-backed mmap pages (e.g. RADV): + // make a one-time copy of the region into a host-visible Vulkan buffer. The GPU + // then DMAs straight from it every eval at full PCIe bandwidth, instead of paying + // a slow single-threaded pageable memcpy into the staging buffer each time. + import_ok = false; + buf = ggml_vk_create_buffer_check(device, cur, + vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostCached, + vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent); + if (buf && buf->buffer && buf->ptr) { + memcpy(buf->ptr, p, cur); + } else { + break; + } } { std::lock_guard guard(device->pinned_memory_mutex);