Repository: ggml-org/llama.cpp
Pull request: vulkan: Make Vulkan optional at runtime (#11493).

Currently, if the Vulkan backend is enabled but Vulkan is not actually available at runtime, it will crash:

```
terminate called after throwing an instance of 'vk::IncompatibleDriverError'
  what():  vk::createInstance: ErrorIncompatibleDriver

Thread 1 "test-tokenizer-" received signal SIGABRT, Aborted.
0x00007ffff6eaa3fc in __pthread_kill_implementation () from /gnu/store/zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39/lib/libc.so.6
(gdb) 
(gdb) bt
#0  0x00007ffff6eaa3fc in __pthread_kill_implementation () from /gnu/store/zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39/lib/libc.so.6
#1  0x00007ffff6e604c2 in raise () from /gnu/store/zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39/lib/libc.so.6
#2  0x00007ffff6e4a4a3 in abort () from /gnu/store/zvlp3n8iwa1svxmwv4q22pv1pb1c9pjq-glibc-2.39/lib/libc.so.6
#3  0x00007ffff70a586a in ?? () from /gnu/store/zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib/lib/libstdc++.so.6
#4  0x00007ffff70b0e6a in ?? () from /gnu/store/zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib/lib/libstdc++.so.6
#5  0x00007ffff70b0ed5 in std::terminate() () from /gnu/store/zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib/lib/libstdc++.so.6
#6  0x00007ffff70b1128 in __cxa_throw () from /gnu/store/zzpbp6rr43smwxzvzd4qd317z5j7qblj-gcc-11.4.0-lib/lib/libstdc++.so.6
#7  0x00007ffff743b5b7 in vk::detail::throwResultException (message=0x7ffff74c5966 "vk::createInstance", result=vk::Result::eErrorIncompatibleDriver)
    at /gnu/store/14lzxwg5kbq01rnd7r7ir5k43083275j-vulkan-headers-1.3.280.0/include/vulkan/vulkan.hpp:6566
#8  vk::resultCheck (message=0x7ffff74c5966 "vk::createInstance", result=vk::Result::eErrorIncompatibleDriver)
    at /gnu/store/14lzxwg5kbq01rnd7r7ir5k43083275j-vulkan-headers-1.3.280.0/include/vulkan/vulkan.hpp:6757
#9  vk::createInstance<vk::DispatchLoaderStatic> (d=..., allocator=..., createInfo=...) at /gnu/store/14lzxwg5kbq01rnd7r7ir5k43083275j-vulkan-headers-1.3.280.0/include/vulkan/vulkan_funcs.hpp:47
#10 ggml_vk_instance_init () at /tmp/guix-build-llama-cpp-0.0.0-b4549.drv-0/source/ggml/src/ggml-vulkan/ggml-vulkan.cpp:2713
#11 0x00007ffff74772e9 in ggml_vk_get_device_count () at /tmp/guix-build-llama-cpp-0.0.0-b4549.drv-0/source/ggml/src/ggml-vulkan/ggml-vulkan.cpp:7305
#12 ggml_backend_vk_get_device_count () at /tmp/guix-build-llama-cpp-0.0.0-b4549.drv-0/source/ggml/src/ggml-vulkan/ggml-vulkan.cpp:7768
#13 0x00007ffff7477309 in ggml_backend_vk_reg_get_device_count (reg=<optimized out>) at /tmp/guix-build-llama-cpp-0.0.0-b4549.drv-0/source/ggml/src/ggml-vulkan/ggml-vulkan.cpp:8113
#14 0x00007ffff7e54dfa in ggml_backend_registry::register_backend (handle=..., reg=0x7ffff74e19a0 <ggml_backend_vk_reg::reg>, this=0x7ffff7e5d300 <get_reg()::reg>)
    at /tmp/guix-build-llama-cpp-0.0.0-b4549.drv-0/source/ggml/src/ggml-backend-reg.cpp:208
#15 ggml_backend_registry::register_backend (handle=..., reg=0x7ffff74e19a0 <ggml_backend_vk_reg::reg>, this=0x7ffff7e5d300 <get_reg()::reg>)
    at /tmp/guix-build-llama-cpp-0.0.0-b4549.drv-0/source/ggml/src/ggml-backend-reg.cpp:198
#16 ggml_backend_registry::ggml_backend_registry (this=0x7ffff7e5d300 <get_reg()::reg>) at /tmp/guix-build-llama-cpp-0.0.0-b4549.drv-0/source/ggml/src/ggml-backend-reg.cpp:166
#17 get_reg () at /tmp/guix-build-llama-cpp-0.0.0-b4549.drv-0/source/ggml/src/ggml-backend-reg.cpp:292
#18 0x00007ffff7e551e9 in ggml_backend_dev_count () at /tmp/guix-build-llama-cpp-0.0.0-b4549.drv-0/source/ggml/src/ggml-backend-reg.cpp:336
#19 0x00007ffff7eb1a19 in llama_model_load_from_file_impl (path_model=..., splits=..., params=...) at /tmp/guix-build-llama-cpp-0.0.0-b4549.drv-0/source/src/llama.cpp:9409
#20 0x00007ffff7eb1c3b in llama_model_load_from_file (path_model=<optimized out>, params=...) at /tmp/guix-build-llama-cpp-0.0.0-b4549.drv-0/source/src/llama.cpp:9469
#21 0x0000000000410bdb in main (argc=2, argv=0x7fffffff5fe8) at /gnu/store/86fc8bi3mciljxz7c79jx8zr4wsx7xw8-gcc-11.4.0/include/c++/bits/basic_string.h
```

Better to just fall back to CPU. This is what this PR does.

Changed files:
filename: ggml/include/ggml-vulkan.h
patch: @@ -10,8 +10,6 @@ extern "C" {
 #define GGML_VK_NAME "Vulkan"
 #define GGML_VK_MAX_DEVICES 16
 
-GGML_BACKEND_API void ggml_vk_instance_init(void);
-
 // backend API
 GGML_BACKEND_API ggml_backend_t ggml_backend_vk_init(size_t dev_num);
 

filename: ggml/src/ggml-vulkan/ggml-vulkan.cpp
patch: @@ -2793,14 +2793,12 @@ static void ggml_vk_print_gpu_info(size_t idx) {
 static bool ggml_vk_instance_validation_ext_available(const std::vector<vk::ExtensionProperties>& instance_extensions);
 static bool ggml_vk_instance_portability_enumeration_ext_available(const std::vector<vk::ExtensionProperties>& instance_extensions);
 
-void ggml_vk_instance_init() {
+static void ggml_vk_instance_init() {
     if (vk_instance_initialized) {
         return;
     }
     VK_LOG_DEBUG("ggml_vk_instance_init()");
 
-    vk_instance_initialized = true;
-
     uint32_t api_version = vk::enumerateInstanceVersion();
 
     if (api_version < VK_API_VERSION_1_2) {
@@ -2851,6 +2849,7 @@ void ggml_vk_instance_init() {
         GGML_LOG_DEBUG("ggml_vulkan: Validation layers enabled\n");
     }
     vk_instance.instance = vk::createInstance(instance_create_info);
+    vk_instance_initialized = true;
 
     size_t num_available_devices = vk_instance.instance.enumeratePhysicalDevices().size();
 
@@ -2875,7 +2874,7 @@ void ggml_vk_instance_init() {
         // Make sure at least one device exists
         if (devices.empty()) {
             std::cerr << "ggml_vulkan: Error: No devices found." << std::endl;
-            GGML_ABORT("fatal error");
+            return;
         }
 
         // Default to using all dedicated GPUs
@@ -8350,8 +8349,13 @@ ggml_backend_reg_t ggml_backend_vk_reg() {
         /* .iface       = */ ggml_backend_vk_reg_i,
         /* .context     = */ nullptr,
     };
-
-    return &reg;
+    try {
+        ggml_vk_instance_init();
+        return &reg;
+    } catch (const vk::SystemError& e) {
+        VK_LOG_DEBUG("ggml_backend_vk_reg() -> Error: System error: " << e.what());
+        return nullptr;
+    }
 }
 
 // Extension availability