| |
| |
|
|
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <cstring> |
| #include "loader.h" |
|
|
| #define DXCORE_MAX_PATH 260 |
|
|
| #if defined(_WIN32) |
| #include "windows.h" |
| #define _getAddr GetProcAddress |
| #define _Handle HMODULE |
| static const size_t sysrootName64_length = (sizeof("System32") - 1); |
| static const char* sysrootName64 = "System32"; |
| static const size_t libcudaName64_length = (sizeof("\\nvcuda64.dll") - 1); |
| static const char* libcudaName64 = "\\nvcuda64.dll"; |
| static const size_t sysrootNameX86_length = (sizeof("SysWOW64") - 1); |
| static const char* sysrootNameX86 = "SysWOW64"; |
| static const size_t libcudaNameX86_length = (sizeof("\\nvcuda32.dll") - 1); |
| static const char* libcudaNameX86 = "\\nvcuda32.dll"; |
| static size_t sysrootName_length = NULL; |
| static const char* sysrootName = NULL; |
|
|
| #else |
| #include <dlfcn.h> |
| #include <unistd.h> |
| #define _getAddr dlsym |
| #define _Handle void* |
| static const size_t libcudaNameLinux_length = (sizeof("/libcuda.so.1.1") - 1); |
| static const char* libcudaNameLinux = "/libcuda.so.1.1"; |
| #endif |
| static size_t libcudaName_length = 0; |
| static const char* libcudaName = NULL; |
|
|
| struct dxcore_enumAdapters2; |
| struct dxcore_queryAdapterInfo; |
|
|
| typedef int (*pfnDxcoreEnumAdapters2)(const dxcore_enumAdapters2 *pParams); |
| typedef int (*pfnDxcoreQueryAdapterInfo)(const dxcore_queryAdapterInfo *pParams); |
|
|
| struct dxcore_lib { |
| _Handle hDxcoreLib; |
| pfnDxcoreEnumAdapters2 pDxcoreEnumAdapters2; |
| pfnDxcoreQueryAdapterInfo pDxcoreQueryAdapterInfo; |
| }; |
|
|
| struct dxcore_luid |
| { |
| unsigned int lowPart; |
| int highPart; |
| }; |
|
|
| struct dxcore_adapterInfo |
| { |
| unsigned int hAdapter; |
| struct dxcore_luid AdapterLuid; |
| unsigned int NumOfSources; |
| unsigned int bPresentMoveRegionsPreferred; |
| }; |
|
|
| struct dxcore_enumAdapters2 |
| { |
| unsigned int NumAdapters; |
| struct dxcore_adapterInfo *pAdapters; |
| }; |
|
|
| enum dxcore_kmtqueryAdapterInfoType |
| { |
| DXCORE_QUERYDRIVERVERSION = 13, |
| DXCORE_QUERYREGISTRY = 48, |
| }; |
|
|
| enum dxcore_queryregistry_type { |
| DXCORE_QUERYREGISTRY_DRIVERSTOREPATH = 2, |
| }; |
|
|
| enum dxcore_queryregistry_status { |
| DXCORE_QUERYREGISTRY_STATUS_SUCCESS = 0, |
| DXCORE_QUERYREGISTRY_STATUS_BUFFER_OVERFLOW = 1, |
| DXCORE_QUERYREGISTRY_STATUS_FAIL = 2, |
| }; |
|
|
| struct dxcore_queryregistry_info { |
| enum dxcore_queryregistry_type QueryType; |
| unsigned int QueryFlags; |
| wchar_t ValueName[DXCORE_MAX_PATH]; |
| unsigned int ValueType; |
| unsigned int PhysicalAdapterIndex; |
| unsigned int OutputValueSize; |
| enum dxcore_queryregistry_status Status; |
| union { |
| unsigned long long OutputQword; |
| wchar_t Output; |
| }; |
| }; |
|
|
| struct dxcore_queryAdapterInfo |
| { |
| unsigned int hAdapter; |
| enum dxcore_kmtqueryAdapterInfoType Type; |
| void *pPrivateDriverData; |
| unsigned int PrivateDriverDataSize; |
| }; |
|
|
| static int dxcore_query_adapter_info_helper(struct dxcore_lib* pLib, |
| unsigned int hAdapter, |
| enum dxcore_kmtqueryAdapterInfoType type, |
| void* pPrivateDriverDate, |
| unsigned int privateDriverDataSize) |
| { |
| struct dxcore_queryAdapterInfo queryAdapterInfo = {}; |
|
|
| queryAdapterInfo.hAdapter = hAdapter; |
| queryAdapterInfo.Type = type; |
| queryAdapterInfo.pPrivateDriverData = pPrivateDriverDate; |
| queryAdapterInfo.PrivateDriverDataSize = privateDriverDataSize; |
|
|
| return pLib->pDxcoreQueryAdapterInfo(&queryAdapterInfo); |
| } |
|
|
| static int dxcore_query_adapter_wddm_version(struct dxcore_lib* pLib, unsigned int hAdapter, unsigned int* version) |
| { |
| return dxcore_query_adapter_info_helper(pLib, |
| hAdapter, |
| DXCORE_QUERYDRIVERVERSION, |
| (void*)version, |
| (unsigned int)sizeof(*version)); |
| } |
|
|
| static int dxcore_query_adapter_driverstore_path(struct dxcore_lib* pLib, unsigned int hAdapter, char** ppDriverStorePath) |
| { |
| struct dxcore_queryregistry_info params = {}; |
| struct dxcore_queryregistry_info* pValue = NULL; |
| wchar_t* pOutput; |
| size_t outputSizeInBytes; |
| size_t outputSize; |
|
|
| |
| params.QueryType = DXCORE_QUERYREGISTRY_DRIVERSTOREPATH; |
|
|
| if (dxcore_query_adapter_info_helper(pLib, |
| hAdapter, |
| DXCORE_QUERYREGISTRY, |
| (void*)¶ms, |
| (unsigned int)sizeof(struct dxcore_queryregistry_info))) |
| { |
| return (-1); |
| } |
|
|
| if (params.OutputValueSize > DXCORE_MAX_PATH * sizeof(wchar_t)) { |
| return (-1); |
| } |
|
|
| outputSizeInBytes = (size_t)params.OutputValueSize; |
| outputSize = outputSizeInBytes / sizeof(wchar_t); |
|
|
| |
| pValue = (struct dxcore_queryregistry_info*)calloc(sizeof(struct dxcore_queryregistry_info) + outputSizeInBytes + sizeof(wchar_t), 1); |
| if (!pValue) { |
| return (-1); |
| } |
|
|
| pValue->QueryType = DXCORE_QUERYREGISTRY_DRIVERSTOREPATH; |
| pValue->OutputValueSize = (unsigned int)outputSizeInBytes; |
|
|
| if (dxcore_query_adapter_info_helper(pLib, |
| hAdapter, |
| DXCORE_QUERYREGISTRY, |
| (void*)pValue, |
| (unsigned int)(sizeof(struct dxcore_queryregistry_info) + outputSizeInBytes))) |
| { |
| free(pValue); |
| return (-1); |
| } |
| pOutput = (wchar_t*)(&pValue->Output); |
|
|
| |
| pOutput[outputSize] = L'\0'; |
|
|
| |
| *ppDriverStorePath = (char*)calloc(outputSize + 1, sizeof(char)); |
| if (!*ppDriverStorePath) { |
| free(pValue); |
| return (-1); |
| } |
| wcstombs(*ppDriverStorePath, pOutput, outputSize); |
|
|
| free(pValue); |
|
|
| return 0; |
| } |
|
|
| static char* replaceSystemPath(char* path) |
| { |
| char *replacedPath = (char*)calloc(DXCORE_MAX_PATH + 1, sizeof(char)); |
|
|
| #if defined(_WIN32) |
| wchar_t *systemPath = (wchar_t*)calloc(DXCORE_MAX_PATH + 1, sizeof(wchar_t)); |
| |
| if (GetSystemDirectoryW(systemPath, DXCORE_MAX_PATH) == 0) { |
| free(replacedPath); |
| free(systemPath); |
| return NULL; |
| } |
| wcstombs(replacedPath, systemPath, DXCORE_MAX_PATH); |
| free(systemPath); |
|
|
| |
| |
| char* sysrootPath = strstr(path, sysrootName); |
| strncat(replacedPath, sysrootPath + sysrootName_length, DXCORE_MAX_PATH - strlen(replacedPath)); |
| #else |
| strncat(replacedPath, path, DXCORE_MAX_PATH); |
| #endif |
|
|
| |
| if (libcudaName_length < DXCORE_MAX_PATH - strlen(replacedPath)) { |
| strncat(replacedPath, libcudaName, libcudaName_length); |
| } |
| else { |
| strncat(replacedPath, libcudaName, DXCORE_MAX_PATH - strlen(replacedPath)); |
| } |
|
|
| return replacedPath; |
| } |
|
|
| static int dxcore_check_adapter(struct dxcore_lib *pLib, char *libPath, struct dxcore_adapterInfo *pAdapterInfo) |
| { |
| unsigned int wddmVersion = 0; |
| char* driverStorePath = NULL; |
|
|
| if (dxcore_query_adapter_wddm_version(pLib, pAdapterInfo->hAdapter, &wddmVersion)) { |
| return 1; |
| } |
|
|
| if (wddmVersion < 2500) { |
| return 1; |
| } |
|
|
| if (dxcore_query_adapter_driverstore_path(pLib, pAdapterInfo->hAdapter, &driverStorePath)) { |
| return 1; |
| } |
|
|
| |
| char* replacedPath = replaceSystemPath(driverStorePath); |
| if (!replacedPath) { |
| free(driverStorePath); |
| free(replacedPath); |
| return 1; |
| } |
|
|
| |
| #if defined(_WIN32) |
| if (GetFileAttributes(replacedPath) == INVALID_FILE_ATTRIBUTES) { |
| free(driverStorePath); |
| free(replacedPath); |
| return 1; |
| } |
| #else |
| if (access(replacedPath, F_OK) < 0) { |
| free(driverStorePath); |
| free(replacedPath); |
| return 1; |
| } |
| #endif |
|
|
| memcpy(libPath, replacedPath, DXCORE_MAX_PATH); |
| free(driverStorePath); |
| free(replacedPath); |
|
|
| return 0; |
| } |
|
|
| static int dxcore_enum_adapters(struct dxcore_lib *pLib, char *libPath) |
| { |
| struct dxcore_enumAdapters2 params = {0}; |
| unsigned int adapterIndex = 0; |
|
|
| if (pLib->pDxcoreEnumAdapters2(¶ms)) { |
| return 1; |
| } |
| params.pAdapters = (dxcore_adapterInfo*)calloc(params.NumAdapters, sizeof(struct dxcore_adapterInfo)); |
| if (pLib->pDxcoreEnumAdapters2(¶ms)) { |
| free(params.pAdapters); |
| return 1; |
| } |
|
|
| for (adapterIndex = 0; adapterIndex < params.NumAdapters; adapterIndex++) { |
| if (!dxcore_check_adapter(pLib, libPath, ¶ms.pAdapters[adapterIndex])) { |
| free(params.pAdapters); |
| return 0; |
| } |
| } |
|
|
| free(params.pAdapters); |
| return 1; |
| } |
|
|
| int getCUDALibraryPath(char *libPath, bool isBit64) |
| { |
| struct dxcore_lib lib = {0}; |
|
|
| if (!libPath) { |
| return 1; |
| } |
|
|
| |
| #if defined(_WIN32) |
| if (isBit64) { |
| sysrootName_length = sysrootName64_length; |
| sysrootName = sysrootName64; |
| libcudaName_length = libcudaName64_length; |
| libcudaName = libcudaName64; |
| } |
| else { |
| sysrootName_length = sysrootNameX86_length; |
| sysrootName = sysrootNameX86; |
| libcudaName_length = libcudaNameX86_length; |
| libcudaName = libcudaNameX86; |
| } |
| #else |
| libcudaName_length = libcudaNameLinux_length; |
| libcudaName = libcudaNameLinux; |
| #endif |
|
|
| #if defined(_WIN32) |
| lib.hDxcoreLib = LoadLibraryExW(L"gdi32.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); |
| #else |
| lib.hDxcoreLib = dlopen("libdxcore.so", RTLD_LAZY); |
| #endif |
| if (!lib.hDxcoreLib) { |
| return 1; |
| } |
|
|
| lib.pDxcoreEnumAdapters2 = (pfnDxcoreEnumAdapters2)_getAddr(lib.hDxcoreLib, "D3DKMTEnumAdapters2"); |
| if (!lib.pDxcoreEnumAdapters2) { |
| return 1; |
| } |
| lib.pDxcoreQueryAdapterInfo = (pfnDxcoreQueryAdapterInfo)_getAddr(lib.hDxcoreLib, "D3DKMTQueryAdapterInfo"); |
| if (!lib.pDxcoreQueryAdapterInfo) { |
| return 1; |
| } |
|
|
| if (dxcore_enum_adapters(&lib, libPath)) { |
| return 1; |
| } |
| return 0; |
| } |
|
|