From 76c44178274def573daec4ddae60afa1918dbd9f Mon Sep 17 00:00:00 2001 From: Ruben Ortlam Date: Mon, 29 Jun 2026 13:51:47 +0200 Subject: [PATCH] add dmabuf capability check --- ggml/src/ggml-vulkan/ggml-vulkan.cpp | 56 ++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/ggml/src/ggml-vulkan/ggml-vulkan.cpp b/ggml/src/ggml-vulkan/ggml-vulkan.cpp index e2ca9fc6b0..611bd51c7e 100644 --- a/ggml/src/ggml-vulkan/ggml-vulkan.cpp +++ b/ggml/src/ggml-vulkan/ggml-vulkan.cpp @@ -15720,14 +15720,41 @@ static void ggml_vk_bench_pair( stg.free_resources(); } + // Check whether exporting dma-buf from one device and importing on + // another is supported for the given buffer usage flags. + auto check_dmabuf_caps = [](vk_device & exp_dev, vk::BufferUsageFlags exp_usage, + vk_device & imp_dev, vk::BufferUsageFlags imp_usage, + const char * label) -> bool { + vk::PhysicalDeviceExternalBufferInfo info{}; + info.handleType = vk::ExternalMemoryHandleTypeFlagBits::eDmaBufEXT; + + info.usage = exp_usage; + auto exp_caps = exp_dev->physical_device.getExternalBufferProperties(info); + if (!(exp_caps.externalMemoryProperties.externalMemoryFeatures & vk::ExternalMemoryFeatureFlagBits::eExportable)) { + std::cerr << " " << std::left << std::setw(24) << label << ": SKIPPED (export not supported)" << std::endl; + return false; + } + + info.usage = imp_usage; + auto imp_caps = imp_dev->physical_device.getExternalBufferProperties(info); + if (!(imp_caps.externalMemoryProperties.externalMemoryFeatures & vk::ExternalMemoryFeatureFlagBits::eImportable)) { + std::cerr << " " << std::left << std::setw(24) << label << ": SKIPPED (import not supported)" << std::endl; + return false; + } + return true; + }; + + const auto transfer_src_dst = vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst; + // ================================================================= // 6. DMA-BUF P2P: import source device memory directly on dest // device via dma-buf fd — true zero-copy if PCIe P2P works. // Setup (export/import) is outside the timing loop. // ================================================================= - if (dev0->external_memory_dma_buf && dev1->external_memory_dma_buf && - !((dev0->vendor_id == VK_VENDOR_ID_NVIDIA) != (dev1->vendor_id == VK_VENDOR_ID_NVIDIA))) { - bool setup_ok = true; + if (dev0->external_memory_dma_buf && dev1->external_memory_dma_buf) { + bool setup_ok = check_dmabuf_caps(dev0, transfer_src_dst, + dev1, vk::BufferUsageFlagBits::eTransferSrc, + "dmabuf_p2p"); // Create exportable source buffer on dev0 vk::Buffer exp_buffer{}; @@ -15740,7 +15767,7 @@ static void ggml_vk_bench_pair( exp_bci.usage = vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst; exp_bci.setPNext(&exp_ext_bci); - try { + if (setup_ok) try { exp_buffer = dev0->device.createBuffer(exp_bci); vk::MemoryRequirements exp_mem_req = dev0->device.getBufferMemoryRequirements(exp_buffer); @@ -15894,7 +15921,9 @@ static void ggml_vk_bench_pair( // import on both devices, two-hop GPU copy through shared GTT. // ================================================================= if (dev0->external_memory_dma_buf && dev1->external_memory_dma_buf) { - bool setup_ok = true; + bool setup_ok = check_dmabuf_caps(dev0, transfer_src_dst, + dev1, transfer_src_dst, + "dmabuf_gtt"); vk::Buffer gtt_buffer{}; vk::DeviceMemory gtt_mem{}; @@ -15909,7 +15938,7 @@ static void ggml_vk_bench_pair( bci.usage = vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst; bci.setPNext(&ext_bci); - try { + if (setup_ok) try { gtt_buffer = dev0->device.createBuffer(bci); vk::MemoryRequirements mem_req = dev0->device.getBufferMemoryRequirements(gtt_buffer); @@ -16084,7 +16113,9 @@ static void ggml_vk_bench_pair( // are importable but dev0's are not. // ================================================================= if (dev0->external_memory_dma_buf && dev1->external_memory_dma_buf) { - bool setup_ok = true; + bool setup_ok = check_dmabuf_caps(dev1, transfer_src_dst, + dev0, transfer_src_dst, + "dmabuf_gtt_rev"); vk::Buffer gtt_buffer{}; vk::DeviceMemory gtt_mem{}; @@ -16099,7 +16130,7 @@ static void ggml_vk_bench_pair( bci.usage = vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst; bci.setPNext(&ext_bci); - try { + if (setup_ok) try { gtt_buffer = dev1->device.createBuffer(bci); vk::MemoryRequirements mem_req = dev1->device.getBufferMemoryRequirements(gtt_buffer); @@ -16271,9 +16302,10 @@ static void ggml_vk_bench_pair( // 6d. DMA-BUF P2P (reversed): dest device exports VRAM, source // device imports and writes into it via P2P. // ================================================================= - if (dev0->external_memory_dma_buf && dev1->external_memory_dma_buf && - !((dev0->vendor_id == VK_VENDOR_ID_NVIDIA) != (dev1->vendor_id == VK_VENDOR_ID_NVIDIA))) { - bool setup_ok = true; + if (dev0->external_memory_dma_buf && dev1->external_memory_dma_buf) { + bool setup_ok = check_dmabuf_caps(dev1, transfer_src_dst, + dev0, vk::BufferUsageFlagBits::eTransferDst, + "dmabuf_p2p_rev"); // Create exportable VRAM buffer on dev1 (destination) vk::Buffer exp_buffer{}; @@ -16286,7 +16318,7 @@ static void ggml_vk_bench_pair( exp_bci.usage = vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst; exp_bci.setPNext(&exp_ext_bci); - try { + if (setup_ok) try { exp_buffer = dev1->device.createBuffer(exp_bci); vk::MemoryRequirements exp_mem_req = dev1->device.getBufferMemoryRequirements(exp_buffer);