|
- // Tencent is pleased to support the open source community by making ncnn available.
- //
- // Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
- //
- // Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
- // in compliance with the License. You may obtain a copy of the License at
- //
- // https://opensource.org/licenses/BSD-3-Clause
- //
- // Unless required by applicable law or agreed to in writing, software distributed
- // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
- // CONDITIONS OF ANY KIND, either express or implied. See the License for the
- // specific language governing permissions and limitations under the License.
-
- #include "platform.h"
-
- #if NCNN_VULKAN
- #if NCNN_SIMPLEVK
-
- #include "simplevk.h"
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #if defined _WIN32
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
- #else
- #include <dlfcn.h>
- #include <sys/types.h>
- #include <unistd.h>
- #if defined __ANDROID__
- #include <dirent.h>
- #include <fcntl.h>
- #include <sys/stat.h>
- #endif
- #endif
-
- #if __APPLE__
-
- // always use static vulkan linkage on apple platform
- extern "C" VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char* pName);
-
- #endif
-
- namespace ncnn {
-
- // vulkan loader entrypoint
- PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = 0;
-
- // vulkan global functions
- PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties = 0;
- PFN_vkCreateInstance vkCreateInstance = 0;
- PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties = 0;
-
- #if __APPLE__
-
- int load_vulkan_driver(const char* /*driver_path*/)
- {
- unload_vulkan_driver();
-
- vkGetInstanceProcAddr = ::vkGetInstanceProcAddr;
- vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties");
- vkCreateInstance = (PFN_vkCreateInstance)vkGetInstanceProcAddr(NULL, "vkCreateInstance");
- vkEnumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties)vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceLayerProperties");
- return 0;
- }
-
- void unload_vulkan_driver()
- {
- vkGetInstanceProcAddr = 0;
- vkEnumerateInstanceExtensionProperties = 0;
- vkCreateInstance = 0;
- vkEnumerateInstanceLayerProperties = 0;
- }
-
- #else // __APPLE__
-
- #if defined _WIN32
- static HMODULE g_libvulkan = 0;
- #else
- static void* g_libvulkan = 0;
- #if defined __ANDROID__
-
- struct hw_module_t;
- struct hw_module_methods_t;
- struct hw_device_t;
-
- struct hw_module_methods_t
- {
- /** Open a specific device */
- int (*open)(const hw_module_t* mod, const char* id, hw_device_t** device);
- };
-
- struct hw_device_t
- {
- /** tag must be initialized to HARDWARE_DEVICE_TAG */
- uint32_t tag;
- uint32_t version;
- /** reference to the module this device belongs to */
- hw_module_t* mod;
- /** padding reserved for future use */
- #ifdef __LP64__
- uint64_t reserved[12];
- #else
- uint32_t reserved[12];
- #endif
- /** Close this device */
- int (*close)(hw_device_t* device);
- };
-
- struct hw_module_t
- {
- /** tag must be initialized to HARDWARE_MODULE_TAG */
- uint32_t tag;
- uint16_t module_api_version;
- uint16_t hal_api_version;
- const char* id;
- const char* name;
- const char* author;
- hw_module_methods_t* methods;
- void* dso;
- #ifdef __LP64__
- uint64_t reserved[32 - 7];
- #else
- /** padding to 128 bytes, reserved for future use */
- uint32_t reserved[32 - 7];
- #endif
- };
-
- struct hwvulkan_module_t : public hw_module_t
- {
- };
-
- struct hwvulkan_device_t : public hw_device_t
- {
- PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties;
- PFN_vkCreateInstance CreateInstance;
- PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
- };
-
- // android hal vulkan loader
- static hwvulkan_device_t* g_hvkdi = 0;
- #endif
- #endif
-
- static std::string get_driver_path_from_icd(const char* icd_path)
- {
- FILE* fp = fopen(icd_path, "rb");
- if (!fp)
- return std::string();
-
- std::string driver_path;
-
- char line[256];
- while (!feof(fp))
- {
- char* s = fgets(line, 256, fp);
- if (!s)
- break;
-
- // "library_path": "path to driver library",
- char path[256];
- int nscan = sscanf(line, " \"library_path\" : \"%255[^\"]\"", path);
- if (nscan == 1)
- {
- if (path[0] == '.' || (path[0] != '/' && !strchr(path, ':') && (strchr(path, '/') || strchr(path, '\\'))))
- {
- // relative to the icd file path
- std::string icd_dir = icd_path;
- size_t dirpos = icd_dir.find_last_of("/\\");
- if (dirpos != std::string::npos)
- {
- icd_dir = icd_dir.substr(0, dirpos + 1);
- }
- else
- {
- icd_dir = "./";
- }
-
- driver_path = icd_dir + path;
- }
- else
- {
- // filename or absolute path
- driver_path = path;
- }
-
- break;
- }
- }
-
- fclose(fp);
-
- return driver_path;
- }
-
- static std::string get_driver_path_from_icd_env()
- {
- const char* icd_path = getenv("VK_ICD_FILENAMES");
- if (!icd_path)
- return std::string();
-
- return get_driver_path_from_icd(icd_path);
- }
-
- static std::string get_driver_path_from_ncnn_env()
- {
- const char* driver_path = getenv("NCNN_VULKAN_DRIVER");
- if (!driver_path)
- return std::string();
-
- return std::string(driver_path);
- }
-
- #if defined _WIN32
- static std::string search_file(const std::string& dirpath, const std::string& needle)
- {
- WIN32_FIND_DATA file;
- HANDLE handle = FindFirstFileA((dirpath + "\\*").c_str(), &file);
- if (handle == INVALID_HANDLE_VALUE)
- return std::string();
-
- int found = 0;
- std::vector<std::string> subdirs;
-
- do
- {
- std::string name = file.cFileName;
-
- if (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- {
- if (name != "." && name != "..")
- subdirs.push_back(name);
- }
- else if (name == needle)
- {
- found = 1;
- break;
- }
- } while (FindNextFileA(handle, &file));
-
- FindClose(handle);
-
- if (found)
- return dirpath + "\\" + needle;
-
- // recurse into subdirs
- for (int i = 0; i < subdirs.size(); ++i)
- {
- std::string found_path = search_file(dirpath + "\\" + subdirs[i], needle);
- if (!found_path.empty())
- return found_path;
- }
-
- return std::string();
- }
-
- static int load_vulkan_windows(const char* driver_path)
- {
- const char* libpath = driver_path ? driver_path : "vulkan-1.dll";
-
- HMODULE libvulkan = LoadLibraryA(libpath);
- if (!libvulkan)
- {
- NCNN_LOGE("LoadLibraryA %s failed %d", libpath, GetLastError());
- return -1;
- }
-
- PFN_vkGetInstanceProcAddr GetInstanceProcAddr = 0;
-
- GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)GetProcAddress(libvulkan, "vk_icdGetInstanceProcAddr");
- if (GetInstanceProcAddr)
- {
- // load icd driver
- typedef VkResult(VKAPI_PTR * PFN_icdNegotiateLoaderICDInterfaceVersion)(uint32_t * pSupportedVersion);
- PFN_icdNegotiateLoaderICDInterfaceVersion icdNegotiateLoaderICDInterfaceVersion = (PFN_icdNegotiateLoaderICDInterfaceVersion)GetProcAddress(libvulkan, "vk_icdNegotiateLoaderICDInterfaceVersion");
- if (icdNegotiateLoaderICDInterfaceVersion)
- {
- uint32_t supported_version = 5;
- VkResult ret = icdNegotiateLoaderICDInterfaceVersion(&supported_version);
- if (ret != VK_SUCCESS)
- {
- NCNN_LOGE("icdNegotiateLoaderICDInterfaceVersion failed");
- FreeLibrary(libvulkan);
- return -1;
- }
- }
- }
- else
- {
- GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)GetProcAddress(libvulkan, "vkGetInstanceProcAddr");
- if (!GetInstanceProcAddr)
- {
- NCNN_LOGE("GetProcAddress failed %d", GetLastError());
- FreeLibrary(libvulkan);
- return -1;
- }
- }
-
- g_libvulkan = libvulkan;
- vkGetInstanceProcAddr = GetInstanceProcAddr;
- vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties");
- vkCreateInstance = (PFN_vkCreateInstance)vkGetInstanceProcAddr(NULL, "vkCreateInstance");
- vkEnumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties)vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceLayerProperties");
- return 0;
- }
- #else
- static int load_vulkan_linux(const char* driver_path)
- {
- #if __APPLE__
- const char* libpath = driver_path ? driver_path : "libvulkan.dylib";
- #else
- const char* libpath = driver_path ? driver_path : "libvulkan.so";
- #endif
-
- void* libvulkan = dlopen(libpath, RTLD_LOCAL | RTLD_NOW);
- if (!libvulkan)
- {
- NCNN_LOGE("dlopen failed %s", dlerror());
- return -1;
- }
-
- PFN_vkGetInstanceProcAddr GetInstanceProcAddr = 0;
-
- GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym(libvulkan, "vk_icdGetInstanceProcAddr");
- if (GetInstanceProcAddr)
- {
- // load icd driver
- typedef VkResult(VKAPI_PTR * PFN_icdNegotiateLoaderICDInterfaceVersion)(uint32_t * pSupportedVersion);
- PFN_icdNegotiateLoaderICDInterfaceVersion icdNegotiateLoaderICDInterfaceVersion = (PFN_icdNegotiateLoaderICDInterfaceVersion)dlsym(libvulkan, "vk_icdNegotiateLoaderICDInterfaceVersion");
- if (icdNegotiateLoaderICDInterfaceVersion)
- {
- uint32_t supported_version = 5;
- VkResult ret = icdNegotiateLoaderICDInterfaceVersion(&supported_version);
- if (ret != VK_SUCCESS)
- {
- NCNN_LOGE("icdNegotiateLoaderICDInterfaceVersion failed");
- dlclose(libvulkan);
- return -1;
- }
- }
- }
- else
- {
- GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym(libvulkan, "vkGetInstanceProcAddr");
- if (!GetInstanceProcAddr)
- {
- NCNN_LOGE("dlsym failed %s", dlerror());
- dlclose(libvulkan);
- return -1;
- }
- }
-
- g_libvulkan = libvulkan;
- vkGetInstanceProcAddr = GetInstanceProcAddr;
- vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties");
- vkCreateInstance = (PFN_vkCreateInstance)vkGetInstanceProcAddr(NULL, "vkCreateInstance");
- vkEnumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties)vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceLayerProperties");
- return 0;
- }
-
- #if defined __ANDROID__
- static int load_vulkan_android(const char* driver_path)
- {
- char hal_driver_path[256];
- if (!driver_path)
- {
- // https://source.android.com/docs/core/graphics/implement-vulkan#driver_emun
-
- // /vendor/lib/hw/vulkan.<ro.hardware.vulkan>.so
- // /vendor/lib/hw/vulkan.<ro.product.platform>.so
- // /vendor/lib64/hw/vulkan.<ro.hardware.vulkan>.so
- // /vendor/lib64/hw/vulkan.<ro.product.platform>.so
-
- #ifdef __LP64__
- DIR* d = opendir("/vendor/lib64/hw");
- #else
- DIR* d = opendir("/vendor/lib/hw");
- #endif
- if (!d)
- return -1;
-
- int hal_driver_found = 0;
- struct dirent* dir;
- while ((dir = readdir(d)) != NULL)
- {
- char platform[256];
- int nscan = sscanf(dir->d_name, "vulkan.%255s.so", platform);
- if (nscan == 1)
- {
- #ifdef __LP64__
- snprintf(hal_driver_path, 256, "/vendor/lib64/hw/%s", dir->d_name);
- #else
- snprintf(hal_driver_path, 256, "/vendor/lib/hw/%s", dir->d_name);
- #endif
- hal_driver_found = 1;
- break;
- }
- }
- closedir(d);
-
- if (!hal_driver_found)
- {
- NCNN_LOGE("no hal driver found");
- return -1;
- }
-
- NCNN_LOGE("hal_driver_path = %s", hal_driver_path);
- }
-
- const char* libpath = driver_path ? driver_path : hal_driver_path;
-
- void* libvulkan = dlopen(libpath, RTLD_LOCAL | RTLD_NOW);
- if (!libvulkan)
- {
- NCNN_LOGE("dlopen failed %s", dlerror());
- return -1;
- }
-
- // resolve entrypoint from android hal module
- hw_module_t* hmi = 0;
- hmi = (hw_module_t*)dlsym(libvulkan, "HMI");
- if (!hmi)
- {
- NCNN_LOGE("dlsym failed %s", dlerror());
- dlclose(libvulkan);
- return -1;
- }
-
- if (strcmp(hmi->id, "vulkan") != 0)
- {
- NCNN_LOGE("hmi->id != vulkan");
- dlclose(libvulkan);
- return -1;
- }
-
- hwvulkan_module_t* hvkmi = (hwvulkan_module_t*)hmi;
-
- // NCNN_LOGE("hvkmi name = %s", hvkmi->name);
- // NCNN_LOGE("hvkmi author = %s", hvkmi->author);
-
- hwvulkan_device_t* hvkdi = 0;
- int result = hvkmi->methods->open(hvkmi, "vk0", (hw_device_t**)&hvkdi);
- if (result != 0)
- {
- NCNN_LOGE("hmi->open failed %d", result);
- dlclose(libvulkan);
- return -1;
- }
-
- g_libvulkan = libvulkan;
- g_hvkdi = hvkdi;
- vkGetInstanceProcAddr = hvkdi->GetInstanceProcAddr;
- vkEnumerateInstanceExtensionProperties = hvkdi->EnumerateInstanceExtensionProperties;
- vkCreateInstance = hvkdi->CreateInstance;
- vkEnumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties)vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceLayerProperties");
- return 0;
- }
- #endif // __ANDROID__
- #endif // _WIN32
-
- int load_vulkan_driver(const char* driver_path)
- {
- unload_vulkan_driver();
-
- int ret = 0;
-
- std::string driver_path_from_icd_env;
- std::string driver_path_from_ncnn_env;
- if (driver_path == 0)
- {
- driver_path_from_icd_env = get_driver_path_from_icd_env();
- if (!driver_path_from_icd_env.empty())
- {
- driver_path = driver_path_from_icd_env.c_str();
- }
- else
- {
- driver_path_from_ncnn_env = get_driver_path_from_ncnn_env();
- if (!driver_path_from_ncnn_env.empty())
- {
- driver_path = driver_path_from_ncnn_env.c_str();
- }
- }
- }
-
- // first try, load from driver_path
- #if defined _WIN32
- ret = load_vulkan_windows(driver_path);
- #else
- ret = load_vulkan_linux(driver_path);
- #if defined __ANDROID__
- if (ret != 0)
- {
- // second try, load from android hal module
- ret = load_vulkan_android(driver_path);
- }
- #endif // __ANDROID__
- #endif // _WIN32
- if (driver_path != 0 && ret != 0)
- {
- // third try, load from system vulkan
- #if defined _WIN32
- ret = load_vulkan_windows(0);
- #else
- ret = load_vulkan_linux(0);
- #if defined __ANDROID__
- if (ret != 0)
- {
- // fourth try, load from any android hal module found
- ret = load_vulkan_android(0);
- }
- #endif // __ANDROID__
- #endif // _WIN32
- }
- if (ret != 0)
- {
- // fifth try, load from well-known path
- #if defined _WIN32
- const char* well_known_path[] = {
- #if defined(__x86_64__) || defined(_M_X64)
- "nvoglv64.dll",
- "amdvlk64.dll",
- "igvk64.dll"
- #else
- "nvoglv32.dll",
- "amdvlk32.dll",
- "igvk32.dll"
- #endif
- };
- #elif defined __ANDROID__
- const char* well_known_path[] = {
- #ifdef __LP64__
- "/vendor/lib64/hw/vulkan.adreno.so",
- "/vendor/lib64/egl/libGLES_mali.so"
- #else
- "/vendor/lib/hw/vulkan.adreno.so",
- "/vendor/lib/egl/libGLES_mali.so"
- #endif
- };
- #else
- const char* well_known_path[] = {
- "libGLX_nvidia.so.0",
- "libvulkan_radeon.so",
- "libvulkan_intel.so",
- "libMaliVulkan.so.1",
- "libVK_IMG.so"
- };
- #endif
-
- const int well_known_path_count = sizeof(well_known_path) / sizeof(const char*);
- for (int i = 0; i < well_known_path_count; i++)
- {
- #if defined _WIN32
- // find driver dll in %SystemRoot%\System32\DriverStore\FileRepository (32bit and 64bit both and in here)
- std::string dllpath = search_file("%SystemRoot%\\System32\\DriverStore\\FileRepository", well_known_path[i]);
- if (dllpath.empty())
- continue;
-
- ret = load_vulkan_windows(well_known_path[i]);
- #elif defined __ANDROID__
- ret = load_vulkan_android(well_known_path[i]);
- #else
- ret = load_vulkan_linux(well_known_path[i]);
- #endif
- if (ret == 0)
- break;
- }
- }
-
- return ret;
- }
-
- void unload_vulkan_driver()
- {
- vkGetInstanceProcAddr = 0;
- vkEnumerateInstanceExtensionProperties = 0;
- vkCreateInstance = 0;
- vkEnumerateInstanceLayerProperties = 0;
-
- #if defined _WIN32
- if (g_libvulkan)
- {
- FreeLibrary(g_libvulkan);
- g_libvulkan = 0;
- }
- #else
- #if defined __ANDROID__
- if (g_hvkdi)
- {
- if (g_hvkdi->close)
- {
- g_hvkdi->close(g_hvkdi);
- }
- g_hvkdi = 0;
- }
- #endif // __ANDROID__
-
- if (g_libvulkan)
- {
- dlclose(g_libvulkan);
- g_libvulkan = 0;
- }
- #endif // _WIN32
- }
-
- #endif // __APPLE__
-
- } // namespace ncnn
-
- #endif // NCNN_SIMPLEVK
- #endif // NCNN_VULKAN
|