Files
Daniel Hiltgen 89a171cc70 llm: use host Vulkan loader on Windows (#16869)
Stop bundling the Vulkan loader and resolve the host runtime for Windows Vulkan discovery and backend dependency loading.

Fixes #16677
2026-06-24 10:35:48 -07:00

110 lines
2.8 KiB
Go

//go:build windows
package llm
import (
"errors"
"log/slog"
"os"
"path/filepath"
"strings"
"golang.org/x/sys/windows"
)
const windowsVulkanRuntimeDLLName = "vulkan-1.dll"
func WindowsVulkanRuntimeDLLPath(libDirs []string) (string, error) {
systemDir, err := windows.GetSystemDirectory()
if err != nil {
return "", err
}
return windowsVulkanRuntimeDLLPath(systemDir, os.Getenv("PATH"), libDirs, fileExists)
}
func adjustWindowsVulkanLibraryPaths(paths, gpuLibs []string) []string {
vulkanDir := firstWindowsVulkanLibDir(gpuLibs)
if vulkanDir == "" {
return paths
}
vulkanPath, err := WindowsVulkanRuntimeDLLPath(gpuLibs)
if err != nil {
slog.Debug("windows Vulkan loader selection unavailable", "error", err)
return paths
}
slog.Debug("selected windows Vulkan loader", "path", vulkanPath)
return insertPathBefore(paths, filepath.Dir(vulkanPath), vulkanDir)
}
// Use the host Vulkan loader supplied by the installed Vulkan runtime or GPU
// driver. Ollama no longer packages the loader; exclude backend library
// directories from PATH probing so stale app-local copies from older installs
// cannot shadow the host runtime.
func windowsVulkanRuntimeDLLPath(
systemDir string,
pathEnv string,
libDirs []string,
exists func(string) bool,
) (string, error) {
systemDir = filepath.Clean(systemDir)
systemPath := filepath.Join(systemDir, windowsVulkanRuntimeDLLName)
if exists(systemPath) {
return systemPath, nil
}
if path := firstWindowsVulkanRuntimeDLLOnPath(pathEnv, libDirs, exists); path != "" {
return path, nil
}
return "", errors.New("no host vulkan-1.dll runtime DLL found")
}
func firstWindowsVulkanRuntimeDLLOnPath(pathEnv string, excludedDirs []string, exists func(string) bool) string {
for _, dir := range filepath.SplitList(pathEnv) {
dir = strings.Trim(filepath.Clean(strings.Trim(dir, `"`)), `"`)
if dir == "." || dir == "" || windowsDirInList(dir, excludedDirs) {
continue
}
path := filepath.Join(dir, windowsVulkanRuntimeDLLName)
if exists(path) {
return filepath.Clean(path)
}
}
return ""
}
func windowsDirInList(dir string, dirs []string) bool {
dir = strings.ToLower(filepath.Clean(dir))
for _, candidate := range dirs {
candidate = strings.ToLower(filepath.Clean(candidate))
if candidate == "" || candidate == "." {
continue
}
if dir == candidate || strings.HasPrefix(dir, candidate+string(filepath.Separator)) {
return true
}
}
return false
}
func firstWindowsVulkanLibDir(libDirs []string) string {
for _, dir := range libDirs {
if dir == "" {
continue
}
base := strings.ToLower(filepath.Base(dir))
if strings.Contains(base, "vulkan") {
return filepath.Clean(dir)
}
if fileExists(filepath.Join(dir, "ggml-vulkan.dll")) || fileExists(filepath.Join(dir, "libggml-vulkan.dll")) {
return filepath.Clean(dir)
}
}
return ""
}