fixes, disable semaphore sharing on Nvidia + non-Nvidia

This commit is contained in:
Ruben Ortlam
2026-08-25 11:42:13 +02:00
parent bf316ac516
commit 3e53e38de3
+36 -11
View File
@@ -2590,7 +2590,16 @@ vk_instance_t::~vk_instance_t() {
{
std::lock_guard<std::mutex> guard(vk_d2d_cache_mutex);
for (auto& entry : vk_d2d_cache) {
ggml_vk_d2d_destroy_shared_semaphore(entry.second);
// Neutralize entries without Vulkan API calls — device.destroy()
// in each device's destructor will implicitly free associated resources.
// Explicit Vulkan calls here are unsafe because the validation layer's
// static data may already be destroyed.
entry.second.async_capable = false;
entry.second.sem_src = VK_NULL_HANDLE;
entry.second.sem_dst = VK_NULL_HANDLE;
entry.second.hop1_fence = VK_NULL_HANDLE;
entry.second.hop1_fence_pending = false;
entry.second.hop1_cmd_pool.pool = nullptr;
if (entry.second.host_ptr) {
free(entry.second.host_ptr);
entry.second.host_ptr = nullptr;
@@ -4014,10 +4023,10 @@ static bool ggml_vk_d2d_check_timeline_semaphore_export(vk_device& dev) {
ext_sem_info.handleType = vk::ExternalSemaphoreHandleTypeFlagBits::eOpaqueFd;
ext_sem_info.pNext = &sem_type;
vk::ExternalSemaphoreProperties ext_sem_props = dev->physical_device.getExternalSemaphoreProperties(ext_sem_info);
vk::ExternalSemaphoreProperties props = dev->physical_device.getExternalSemaphoreProperties(ext_sem_info);
return (ext_sem_props.externalSemaphoreFeatures & vk::ExternalSemaphoreFeatureFlagBits::eExportable) &&
(ext_sem_props.externalSemaphoreFeatures & vk::ExternalSemaphoreFeatureFlagBits::eImportable);
return (props.externalSemaphoreFeatures & vk::ExternalSemaphoreFeatureFlagBits::eExportable) &&
(props.externalSemaphoreFeatures & vk::ExternalSemaphoreFeatureFlagBits::eImportable);
}
static bool ggml_vk_d2d_create_shared_semaphore(vk_device& src_dev, vk_device& dst_dev, vk_d2d_path& path) {
@@ -4025,6 +4034,12 @@ static bool ggml_vk_d2d_create_shared_semaphore(vk_device& src_dev, vk_device& d
return false;
}
bool src_nvidia = src_dev->vendor_id == VK_VENDOR_ID_NVIDIA;
bool dst_nvidia = dst_dev->vendor_id == VK_VENDOR_ID_NVIDIA;
if (src_nvidia != dst_nvidia) {
return false;
}
if (!ggml_vk_d2d_check_timeline_semaphore_export(src_dev) ||
!ggml_vk_d2d_check_timeline_semaphore_export(dst_dev)) {
VK_LOG_DEBUG("ggml_vk_d2d_create_shared_semaphore: timeline semaphore export/import not supported");
@@ -4034,9 +4049,7 @@ static bool ggml_vk_d2d_create_shared_semaphore(vk_device& src_dev, vk_device& d
vk::ExportSemaphoreCreateInfo export_ci;
export_ci.handleTypes = vk::ExternalSemaphoreHandleTypeFlagBits::eOpaqueFd;
vk::SemaphoreTypeCreateInfo type_ci;
type_ci.semaphoreType = vk::SemaphoreType::eTimeline;
type_ci.initialValue = 0;
vk::SemaphoreTypeCreateInfo type_ci{ vk::SemaphoreType::eTimeline, 0 };
type_ci.pNext = &export_ci;
vk::SemaphoreCreateInfo sem_ci;
@@ -4099,14 +4112,24 @@ static bool ggml_vk_d2d_create_shared_semaphore(vk_device& src_dev, vk_device& d
}
// fd ownership transferred to driver on successful import
try {
path.hop1_cmd_pool.init(src_dev, &src_dev->transfer_queue);
path.hop1_fence = src_dev->device.createFence({});
} catch (const vk::SystemError& e) {
VK_LOG_DEBUG("ggml_vk_d2d_create_shared_semaphore: cmd pool/fence creation failed: " << e.what());
if (path.hop1_cmd_pool.pool) {
path.hop1_cmd_pool.destroy(src_dev->device);
}
dst_dev->device.destroySemaphore(dst_sem);
src_dev->device.destroySemaphore(src_sem);
return false;
}
path.sem_src = src_sem;
path.sem_dst = dst_sem;
path.sem_value = 0;
path.sem_src_device = src_dev.get();
path.sem_dst_device = dst_dev.get();
path.hop1_cmd_pool.init(src_dev, &src_dev->transfer_queue);
path.hop1_fence = src_dev->device.createFence({});
path.hop1_fence_pending = false;
path.hop1_device = src_dev.get();
@@ -9463,7 +9486,9 @@ static bool ggml_vk_buffer_copy_async_d2d(
path.hop1_fence_pending = true;
}
// Hop 2: record into dst compute context — waits on semaphore, copies shared buffer -> VRAM
// Hop 2: start a new submission in the dst compute context so this copy
// waits only for its own hop1, not for later hop1s that overwrite the shared buffer.
ggml_vk_ctx_begin(dst->device, dst_compute_ctx);
dst_compute_ctx->s->wait_semaphores.push_back({ path.sem_dst, signal_value });
VkBufferCopy bc2{ 0, dst_offset, size };