15db71995Sopenharmony_ci/* 25db71995Sopenharmony_ci * 35db71995Sopenharmony_ci * Copyright (c) 2014-2022 The Khronos Group Inc. 45db71995Sopenharmony_ci * Copyright (c) 2014-2022 Valve Corporation 55db71995Sopenharmony_ci * Copyright (c) 2014-2022 LunarG, Inc. 65db71995Sopenharmony_ci * Copyright (C) 2015 Google Inc. 75db71995Sopenharmony_ci * 85db71995Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 95db71995Sopenharmony_ci * you may not use this file except in compliance with the License. 105db71995Sopenharmony_ci * You may obtain a copy of the License at 115db71995Sopenharmony_ci * 125db71995Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 135db71995Sopenharmony_ci * 145db71995Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 155db71995Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 165db71995Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 175db71995Sopenharmony_ci * See the License for the specific language governing permissions and 185db71995Sopenharmony_ci * limitations under the License. 195db71995Sopenharmony_ci * 205db71995Sopenharmony_ci * Author: Jon Ashburn <jon@lunarg.com> 215db71995Sopenharmony_ci * Author: Courtney Goeltzenleuchter <courtney@LunarG.com> 225db71995Sopenharmony_ci * Author: Chia-I Wu <olvaffe@gmail.com> 235db71995Sopenharmony_ci * Author: Chia-I Wu <olv@lunarg.com> 245db71995Sopenharmony_ci * Author: Mark Lobodzinski <mark@LunarG.com> 255db71995Sopenharmony_ci * Author: Lenny Komow <lenny@lunarg.com> 265db71995Sopenharmony_ci * Author: Charles Giessen <charles@lunarg.com> 275db71995Sopenharmony_ci * 285db71995Sopenharmony_ci */ 295db71995Sopenharmony_ci// Windows only header file, guard it so that accidental inclusion doesn't cause unknown header include errors 305db71995Sopenharmony_ci#if defined(_WIN32) 315db71995Sopenharmony_ci 325db71995Sopenharmony_ci// This needs to be defined first, or else we'll get redefinitions on NTSTATUS values 335db71995Sopenharmony_ci#define UMDF_USING_NTSTATUS 345db71995Sopenharmony_ci#include <ntstatus.h> 355db71995Sopenharmony_ci 365db71995Sopenharmony_ci#include "loader_windows.h" 375db71995Sopenharmony_ci 385db71995Sopenharmony_ci#include "allocation.h" 395db71995Sopenharmony_ci#include "loader_environment.h" 405db71995Sopenharmony_ci#include "loader.h" 415db71995Sopenharmony_ci#include "log.h" 425db71995Sopenharmony_ci 435db71995Sopenharmony_ci#include <cfgmgr32.h> 445db71995Sopenharmony_ci#include <initguid.h> 455db71995Sopenharmony_ci#include <devpkey.h> 465db71995Sopenharmony_ci#include <winternl.h> 475db71995Sopenharmony_ci#include <strsafe.h> 485db71995Sopenharmony_ci#if defined(__MINGW32__) 495db71995Sopenharmony_ci#undef strcpy // fix error with redefined strcpy when building with MinGW-w64 505db71995Sopenharmony_ci#endif 515db71995Sopenharmony_ci#include <dxgi1_6.h> 525db71995Sopenharmony_ci#include "adapters.h" 535db71995Sopenharmony_ci 545db71995Sopenharmony_ci#if !defined(__MINGW32__) 555db71995Sopenharmony_ci// not yet available with MinGW-w64 stable 565db71995Sopenharmony_ci#include <appmodel.h> 575db71995Sopenharmony_ci#endif 585db71995Sopenharmony_ci 595db71995Sopenharmony_ci#if !defined(NDEBUG) 605db71995Sopenharmony_ci#include <crtdbg.h> 615db71995Sopenharmony_ci#endif 625db71995Sopenharmony_ci 635db71995Sopenharmony_citypedef HRESULT(APIENTRY *PFN_CreateDXGIFactory1)(REFIID riid, void **ppFactory); 645db71995Sopenharmony_ciPFN_CreateDXGIFactory1 fpCreateDXGIFactory1; 655db71995Sopenharmony_ci 665db71995Sopenharmony_ci// Empty function just so windows_initialization can find the current module location 675db71995Sopenharmony_civoid function_for_finding_the_current_module(void) {} 685db71995Sopenharmony_ci 695db71995Sopenharmony_civoid windows_initialization(void) { 705db71995Sopenharmony_ci char dll_location[MAX_PATH]; 715db71995Sopenharmony_ci HMODULE module_handle = NULL; 725db71995Sopenharmony_ci 735db71995Sopenharmony_ci // Get a module handle to a static function inside of this source 745db71995Sopenharmony_ci if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, 755db71995Sopenharmony_ci (LPCSTR)&function_for_finding_the_current_module, &module_handle) != 0 && 765db71995Sopenharmony_ci GetModuleFileName(module_handle, dll_location, sizeof(dll_location)) != 0) { 775db71995Sopenharmony_ci loader_log(NULL, VULKAN_LOADER_INFO_BIT, 0, "Using Vulkan Loader %s", dll_location); 785db71995Sopenharmony_ci } 795db71995Sopenharmony_ci 805db71995Sopenharmony_ci // This is needed to ensure that newer APIs are available right away 815db71995Sopenharmony_ci // and not after the first call that has been statically linked 825db71995Sopenharmony_ci LoadLibrary("gdi32.dll"); 835db71995Sopenharmony_ci 845db71995Sopenharmony_ci wchar_t systemPath[MAX_PATH] = L""; 855db71995Sopenharmony_ci GetSystemDirectoryW(systemPath, MAX_PATH); 865db71995Sopenharmony_ci StringCchCatW(systemPath, MAX_PATH, L"\\dxgi.dll"); 875db71995Sopenharmony_ci HMODULE dxgi_module = LoadLibraryW(systemPath); 885db71995Sopenharmony_ci fpCreateDXGIFactory1 = 895db71995Sopenharmony_ci dxgi_module == NULL ? NULL : (PFN_CreateDXGIFactory1)(void *)GetProcAddress(dxgi_module, "CreateDXGIFactory1"); 905db71995Sopenharmony_ci 915db71995Sopenharmony_ci#if !defined(NDEBUG) 925db71995Sopenharmony_ci _set_error_mode(_OUT_TO_STDERR); 935db71995Sopenharmony_ci _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); 945db71995Sopenharmony_ci _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); 955db71995Sopenharmony_ci#endif 965db71995Sopenharmony_ci} 975db71995Sopenharmony_ci 985db71995Sopenharmony_ciBOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved) { 995db71995Sopenharmony_ci (void)hinst; 1005db71995Sopenharmony_ci switch (reason) { 1015db71995Sopenharmony_ci case DLL_PROCESS_ATTACH: 1025db71995Sopenharmony_ci loader_initialize(); 1035db71995Sopenharmony_ci break; 1045db71995Sopenharmony_ci case DLL_PROCESS_DETACH: 1055db71995Sopenharmony_ci if (NULL == reserved) { 1065db71995Sopenharmony_ci loader_release(); 1075db71995Sopenharmony_ci } 1085db71995Sopenharmony_ci break; 1095db71995Sopenharmony_ci default: 1105db71995Sopenharmony_ci // Do nothing 1115db71995Sopenharmony_ci break; 1125db71995Sopenharmony_ci } 1135db71995Sopenharmony_ci return TRUE; 1145db71995Sopenharmony_ci} 1155db71995Sopenharmony_ci 1165db71995Sopenharmony_cibool windows_add_json_entry(const struct loader_instance *inst, 1175db71995Sopenharmony_ci char **reg_data, // list of JSON files 1185db71995Sopenharmony_ci PDWORD total_size, // size of reg_data 1195db71995Sopenharmony_ci LPCSTR key_name, // key name - used for debug prints - i.e. VulkanDriverName 1205db71995Sopenharmony_ci DWORD key_type, // key data type 1215db71995Sopenharmony_ci LPSTR json_path, // JSON string to add to the list reg_data 1225db71995Sopenharmony_ci DWORD json_size, // size in bytes of json_path 1235db71995Sopenharmony_ci VkResult *result) { 1245db71995Sopenharmony_ci // Check for and ignore duplicates. 1255db71995Sopenharmony_ci if (*reg_data && strstr(*reg_data, json_path)) { 1265db71995Sopenharmony_ci // Success. The json_path is already in the list. 1275db71995Sopenharmony_ci return true; 1285db71995Sopenharmony_ci } 1295db71995Sopenharmony_ci 1305db71995Sopenharmony_ci if (NULL == *reg_data) { 1315db71995Sopenharmony_ci *reg_data = loader_instance_heap_alloc(inst, *total_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 1325db71995Sopenharmony_ci if (NULL == *reg_data) { 1335db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 1345db71995Sopenharmony_ci "windows_add_json_entry: Failed to allocate space for registry data for key %s", json_path); 1355db71995Sopenharmony_ci *result = VK_ERROR_OUT_OF_HOST_MEMORY; 1365db71995Sopenharmony_ci return false; 1375db71995Sopenharmony_ci } 1385db71995Sopenharmony_ci *reg_data[0] = '\0'; 1395db71995Sopenharmony_ci } else if (strlen(*reg_data) + json_size + 1 > *total_size) { 1405db71995Sopenharmony_ci void *new_ptr = 1415db71995Sopenharmony_ci loader_instance_heap_realloc(inst, *reg_data, *total_size, *total_size * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 1425db71995Sopenharmony_ci if (NULL == new_ptr) { 1435db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 1445db71995Sopenharmony_ci "windows_add_json_entry: Failed to reallocate space for registry value of size %d for key %s", 1455db71995Sopenharmony_ci *total_size * 2, json_path); 1465db71995Sopenharmony_ci *result = VK_ERROR_OUT_OF_HOST_MEMORY; 1475db71995Sopenharmony_ci return false; 1485db71995Sopenharmony_ci } 1495db71995Sopenharmony_ci *reg_data = new_ptr; 1505db71995Sopenharmony_ci *total_size *= 2; 1515db71995Sopenharmony_ci } 1525db71995Sopenharmony_ci 1535db71995Sopenharmony_ci for (char *curr_filename = json_path; curr_filename[0] != '\0'; curr_filename += strlen(curr_filename) + 1) { 1545db71995Sopenharmony_ci if (strlen(*reg_data) == 0) { 1555db71995Sopenharmony_ci (void)snprintf(*reg_data, json_size + 1, "%s", curr_filename); 1565db71995Sopenharmony_ci } else { 1575db71995Sopenharmony_ci (void)snprintf(*reg_data + strlen(*reg_data), json_size + 2, "%c%s", PATH_SEPARATOR, curr_filename); 1585db71995Sopenharmony_ci } 1595db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, "%s: Located json file \"%s\" from PnP registry: %s", __FUNCTION__, 1605db71995Sopenharmony_ci curr_filename, key_name); 1615db71995Sopenharmony_ci 1625db71995Sopenharmony_ci if (key_type == REG_SZ) { 1635db71995Sopenharmony_ci break; 1645db71995Sopenharmony_ci } 1655db71995Sopenharmony_ci } 1665db71995Sopenharmony_ci return true; 1675db71995Sopenharmony_ci} 1685db71995Sopenharmony_ci 1695db71995Sopenharmony_cibool windows_get_device_registry_entry(const struct loader_instance *inst, char **reg_data, PDWORD total_size, DEVINST dev_id, 1705db71995Sopenharmony_ci LPCSTR value_name, VkResult *result) { 1715db71995Sopenharmony_ci HKEY hkrKey = INVALID_HANDLE_VALUE; 1725db71995Sopenharmony_ci DWORD requiredSize, data_type; 1735db71995Sopenharmony_ci char *manifest_path = NULL; 1745db71995Sopenharmony_ci bool found = false; 1755db71995Sopenharmony_ci 1765db71995Sopenharmony_ci assert(reg_data != NULL && "windows_get_device_registry_entry: reg_data is a NULL pointer"); 1775db71995Sopenharmony_ci assert(total_size != NULL && "windows_get_device_registry_entry: total_size is a NULL pointer"); 1785db71995Sopenharmony_ci 1795db71995Sopenharmony_ci CONFIGRET status = CM_Open_DevNode_Key(dev_id, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hkrKey, CM_REGISTRY_SOFTWARE); 1805db71995Sopenharmony_ci if (status != CR_SUCCESS) { 1815db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 1825db71995Sopenharmony_ci "windows_get_device_registry_entry: Failed to open registry key for DeviceID(%d)", dev_id); 1835db71995Sopenharmony_ci *result = VK_ERROR_INCOMPATIBLE_DRIVER; 1845db71995Sopenharmony_ci return false; 1855db71995Sopenharmony_ci } 1865db71995Sopenharmony_ci 1875db71995Sopenharmony_ci // query value 1885db71995Sopenharmony_ci LSTATUS ret = RegQueryValueEx(hkrKey, value_name, NULL, NULL, NULL, &requiredSize); 1895db71995Sopenharmony_ci 1905db71995Sopenharmony_ci if (ret != ERROR_SUCCESS) { 1915db71995Sopenharmony_ci if (ret == ERROR_FILE_NOT_FOUND) { 1925db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 1935db71995Sopenharmony_ci "windows_get_device_registry_entry: Device ID(%d) Does not contain a value for \"%s\"", dev_id, value_name); 1945db71995Sopenharmony_ci } else { 1955db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 1965db71995Sopenharmony_ci "windows_get_device_registry_entry: DeviceID(%d) Failed to obtain %s size", dev_id, value_name); 1975db71995Sopenharmony_ci } 1985db71995Sopenharmony_ci goto out; 1995db71995Sopenharmony_ci } 2005db71995Sopenharmony_ci 2015db71995Sopenharmony_ci manifest_path = loader_instance_heap_alloc(inst, requiredSize, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 2025db71995Sopenharmony_ci if (manifest_path == NULL) { 2035db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 2045db71995Sopenharmony_ci "windows_get_device_registry_entry: Failed to allocate space for DriverName."); 2055db71995Sopenharmony_ci *result = VK_ERROR_OUT_OF_HOST_MEMORY; 2065db71995Sopenharmony_ci goto out; 2075db71995Sopenharmony_ci } 2085db71995Sopenharmony_ci 2095db71995Sopenharmony_ci ret = RegQueryValueEx(hkrKey, value_name, NULL, &data_type, (BYTE *)manifest_path, &requiredSize); 2105db71995Sopenharmony_ci 2115db71995Sopenharmony_ci if (ret != ERROR_SUCCESS) { 2125db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 2135db71995Sopenharmony_ci "windows_get_device_registry_entry: DeviceID(%d) Failed to obtain %s", value_name); 2145db71995Sopenharmony_ci *result = VK_ERROR_INCOMPATIBLE_DRIVER; 2155db71995Sopenharmony_ci goto out; 2165db71995Sopenharmony_ci } 2175db71995Sopenharmony_ci 2185db71995Sopenharmony_ci if (data_type != REG_SZ && data_type != REG_MULTI_SZ) { 2195db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_DRIVER_BIT, 0, 2205db71995Sopenharmony_ci "windows_get_device_registry_entry: Invalid %s data type. Expected REG_SZ or REG_MULTI_SZ.", value_name); 2215db71995Sopenharmony_ci *result = VK_ERROR_INCOMPATIBLE_DRIVER; 2225db71995Sopenharmony_ci goto out; 2235db71995Sopenharmony_ci } 2245db71995Sopenharmony_ci 2255db71995Sopenharmony_ci found = windows_add_json_entry(inst, reg_data, total_size, value_name, data_type, manifest_path, requiredSize, result); 2265db71995Sopenharmony_ci 2275db71995Sopenharmony_ciout: 2285db71995Sopenharmony_ci loader_instance_heap_free(inst, manifest_path); 2295db71995Sopenharmony_ci RegCloseKey(hkrKey); 2305db71995Sopenharmony_ci return found; 2315db71995Sopenharmony_ci} 2325db71995Sopenharmony_ci 2335db71995Sopenharmony_ciVkResult windows_get_device_registry_files(const struct loader_instance *inst, uint32_t log_target_flag, char **reg_data, 2345db71995Sopenharmony_ci PDWORD reg_data_size, LPCSTR value_name) { 2355db71995Sopenharmony_ci const wchar_t *softwareComponentGUID = L"{5c4c3332-344d-483c-8739-259e934c9cc8}"; 2365db71995Sopenharmony_ci const wchar_t *displayGUID = L"{4d36e968-e325-11ce-bfc1-08002be10318}"; 2375db71995Sopenharmony_ci#if defined(CM_GETIDLIST_FILTER_PRESENT) 2385db71995Sopenharmony_ci const ULONG flags = CM_GETIDLIST_FILTER_CLASS | CM_GETIDLIST_FILTER_PRESENT; 2395db71995Sopenharmony_ci#else 2405db71995Sopenharmony_ci const ULONG flags = 0x300; 2415db71995Sopenharmony_ci#endif 2425db71995Sopenharmony_ci 2435db71995Sopenharmony_ci wchar_t childGuid[MAX_GUID_STRING_LEN + 2]; // +2 for brackets {} 2445db71995Sopenharmony_ci for (uint32_t i = 0; i < MAX_GUID_STRING_LEN + 2; i++) { 2455db71995Sopenharmony_ci childGuid[i] = L'\0'; 2465db71995Sopenharmony_ci } 2475db71995Sopenharmony_ci ULONG childGuidSize = sizeof(childGuid); 2485db71995Sopenharmony_ci 2495db71995Sopenharmony_ci DEVINST devID = 0, childID = 0; 2505db71995Sopenharmony_ci wchar_t *pDeviceNames = NULL; 2515db71995Sopenharmony_ci ULONG deviceNamesSize = 0; 2525db71995Sopenharmony_ci VkResult result = VK_SUCCESS; 2535db71995Sopenharmony_ci bool found = false; 2545db71995Sopenharmony_ci 2555db71995Sopenharmony_ci assert(reg_data != NULL && "windows_get_device_registry_files: reg_data is NULL"); 2565db71995Sopenharmony_ci 2575db71995Sopenharmony_ci // if after obtaining the DeviceNameSize, new device is added start over 2585db71995Sopenharmony_ci do { 2595db71995Sopenharmony_ci CM_Get_Device_ID_List_SizeW(&deviceNamesSize, displayGUID, flags); 2605db71995Sopenharmony_ci 2615db71995Sopenharmony_ci loader_instance_heap_free(inst, pDeviceNames); 2625db71995Sopenharmony_ci 2635db71995Sopenharmony_ci pDeviceNames = loader_instance_heap_alloc(inst, deviceNamesSize * sizeof(wchar_t), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 2645db71995Sopenharmony_ci if (pDeviceNames == NULL) { 2655db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT | log_target_flag, 0, 2665db71995Sopenharmony_ci "windows_get_device_registry_files: Failed to allocate space for display device names."); 2675db71995Sopenharmony_ci result = VK_ERROR_OUT_OF_HOST_MEMORY; 2685db71995Sopenharmony_ci return result; 2695db71995Sopenharmony_ci } 2705db71995Sopenharmony_ci } while (CM_Get_Device_ID_ListW(displayGUID, pDeviceNames, deviceNamesSize, flags) == CR_BUFFER_SMALL); 2715db71995Sopenharmony_ci 2725db71995Sopenharmony_ci if (pDeviceNames) { 2735db71995Sopenharmony_ci for (wchar_t *deviceName = pDeviceNames; *deviceName; deviceName += wcslen(deviceName) + 1) { 2745db71995Sopenharmony_ci CONFIGRET status = CM_Locate_DevNodeW(&devID, deviceName, CM_LOCATE_DEVNODE_NORMAL); 2755db71995Sopenharmony_ci if (CR_SUCCESS != status) { 2765db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT | log_target_flag, 0, 2775db71995Sopenharmony_ci "windows_get_device_registry_files: failed to open DevNode %ls", deviceName); 2785db71995Sopenharmony_ci continue; 2795db71995Sopenharmony_ci } 2805db71995Sopenharmony_ci ULONG ulStatus, ulProblem; 2815db71995Sopenharmony_ci status = CM_Get_DevNode_Status(&ulStatus, &ulProblem, devID, 0); 2825db71995Sopenharmony_ci 2835db71995Sopenharmony_ci if (CR_SUCCESS != status) { 2845db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT | log_target_flag, 0, 2855db71995Sopenharmony_ci "windows_get_device_registry_files: failed to probe device status %ls", deviceName); 2865db71995Sopenharmony_ci continue; 2875db71995Sopenharmony_ci } 2885db71995Sopenharmony_ci if ((ulStatus & DN_HAS_PROBLEM) && (ulProblem == CM_PROB_NEED_RESTART || ulProblem == DN_NEED_RESTART)) { 2895db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | log_target_flag, 0, 2905db71995Sopenharmony_ci "windows_get_device_registry_files: device %ls is pending reboot, skipping ...", deviceName); 2915db71995Sopenharmony_ci continue; 2925db71995Sopenharmony_ci } 2935db71995Sopenharmony_ci 2945db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | log_target_flag, 0, "windows_get_device_registry_files: opening device %ls", 2955db71995Sopenharmony_ci deviceName); 2965db71995Sopenharmony_ci 2975db71995Sopenharmony_ci if (windows_get_device_registry_entry(inst, reg_data, reg_data_size, devID, value_name, &result)) { 2985db71995Sopenharmony_ci found = true; 2995db71995Sopenharmony_ci continue; 3005db71995Sopenharmony_ci } else if (result == VK_ERROR_OUT_OF_HOST_MEMORY) { 3015db71995Sopenharmony_ci break; 3025db71995Sopenharmony_ci } 3035db71995Sopenharmony_ci 3045db71995Sopenharmony_ci status = CM_Get_Child(&childID, devID, 0); 3055db71995Sopenharmony_ci if (status != CR_SUCCESS) { 3065db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | log_target_flag, 0, 3075db71995Sopenharmony_ci "windows_get_device_registry_files: unable to open child-device error:%d", status); 3085db71995Sopenharmony_ci continue; 3095db71995Sopenharmony_ci } 3105db71995Sopenharmony_ci 3115db71995Sopenharmony_ci do { 3125db71995Sopenharmony_ci wchar_t buffer[MAX_DEVICE_ID_LEN]; 3135db71995Sopenharmony_ci CM_Get_Device_IDW(childID, buffer, MAX_DEVICE_ID_LEN, 0); 3145db71995Sopenharmony_ci 3155db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | log_target_flag, 0, 3165db71995Sopenharmony_ci "windows_get_device_registry_files: Opening child device %d - %ls", childID, buffer); 3175db71995Sopenharmony_ci 3185db71995Sopenharmony_ci status = CM_Get_DevNode_Registry_PropertyW(childID, CM_DRP_CLASSGUID, NULL, &childGuid, &childGuidSize, 0); 3195db71995Sopenharmony_ci if (status != CR_SUCCESS) { 3205db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT | log_target_flag, 0, 3215db71995Sopenharmony_ci "windows_get_device_registry_files: unable to obtain GUID for:%d error:%d", childID, status); 3225db71995Sopenharmony_ci 3235db71995Sopenharmony_ci result = VK_ERROR_INCOMPATIBLE_DRIVER; 3245db71995Sopenharmony_ci continue; 3255db71995Sopenharmony_ci } 3265db71995Sopenharmony_ci 3275db71995Sopenharmony_ci if (wcscmp(childGuid, softwareComponentGUID) != 0) { 3285db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_DEBUG_BIT | log_target_flag, 0, 3295db71995Sopenharmony_ci "windows_get_device_registry_files: GUID for %d is not SoftwareComponent skipping", childID); 3305db71995Sopenharmony_ci continue; 3315db71995Sopenharmony_ci } 3325db71995Sopenharmony_ci 3335db71995Sopenharmony_ci if (windows_get_device_registry_entry(inst, reg_data, reg_data_size, childID, value_name, &result)) { 3345db71995Sopenharmony_ci found = true; 3355db71995Sopenharmony_ci break; // check next-display-device 3365db71995Sopenharmony_ci } 3375db71995Sopenharmony_ci 3385db71995Sopenharmony_ci } while (CM_Get_Sibling(&childID, childID, 0) == CR_SUCCESS); 3395db71995Sopenharmony_ci } 3405db71995Sopenharmony_ci 3415db71995Sopenharmony_ci loader_instance_heap_free(inst, pDeviceNames); 3425db71995Sopenharmony_ci } 3435db71995Sopenharmony_ci 3445db71995Sopenharmony_ci if (!found && result != VK_ERROR_OUT_OF_HOST_MEMORY) { 3455db71995Sopenharmony_ci loader_log(inst, log_target_flag, 0, "windows_get_device_registry_files: found no registry files"); 3465db71995Sopenharmony_ci result = VK_ERROR_INCOMPATIBLE_DRIVER; 3475db71995Sopenharmony_ci } 3485db71995Sopenharmony_ci 3495db71995Sopenharmony_ci return result; 3505db71995Sopenharmony_ci} 3515db71995Sopenharmony_ci 3525db71995Sopenharmony_ciVkResult windows_get_registry_files(const struct loader_instance *inst, char *location, bool use_secondary_hive, char **reg_data, 3535db71995Sopenharmony_ci PDWORD reg_data_size) { 3545db71995Sopenharmony_ci // This list contains all of the allowed ICDs. This allows us to verify that a device is actually present from the vendor 3555db71995Sopenharmony_ci // specified. This does disallow other vendors, but any new driver should use the device-specific registries anyway. 3565db71995Sopenharmony_ci const struct { 3575db71995Sopenharmony_ci const char *filename; 3585db71995Sopenharmony_ci unsigned int vendor_id; 3595db71995Sopenharmony_ci } known_drivers[] = { 3605db71995Sopenharmony_ci#if defined(_WIN64) 3615db71995Sopenharmony_ci { 3625db71995Sopenharmony_ci .filename = "igvk64.json", 3635db71995Sopenharmony_ci .vendor_id = 0x8086, 3645db71995Sopenharmony_ci }, 3655db71995Sopenharmony_ci { 3665db71995Sopenharmony_ci .filename = "nv-vk64.json", 3675db71995Sopenharmony_ci .vendor_id = 0x10de, 3685db71995Sopenharmony_ci }, 3695db71995Sopenharmony_ci { 3705db71995Sopenharmony_ci .filename = "amd-vulkan64.json", 3715db71995Sopenharmony_ci .vendor_id = 0x1002, 3725db71995Sopenharmony_ci }, 3735db71995Sopenharmony_ci { 3745db71995Sopenharmony_ci .filename = "amdvlk64.json", 3755db71995Sopenharmony_ci .vendor_id = 0x1002, 3765db71995Sopenharmony_ci }, 3775db71995Sopenharmony_ci#else 3785db71995Sopenharmony_ci { 3795db71995Sopenharmony_ci .filename = "igvk32.json", 3805db71995Sopenharmony_ci .vendor_id = 0x8086, 3815db71995Sopenharmony_ci }, 3825db71995Sopenharmony_ci { 3835db71995Sopenharmony_ci .filename = "nv-vk32.json", 3845db71995Sopenharmony_ci .vendor_id = 0x10de, 3855db71995Sopenharmony_ci }, 3865db71995Sopenharmony_ci { 3875db71995Sopenharmony_ci .filename = "amd-vulkan32.json", 3885db71995Sopenharmony_ci .vendor_id = 0x1002, 3895db71995Sopenharmony_ci }, 3905db71995Sopenharmony_ci { 3915db71995Sopenharmony_ci .filename = "amdvlk32.json", 3925db71995Sopenharmony_ci .vendor_id = 0x1002, 3935db71995Sopenharmony_ci }, 3945db71995Sopenharmony_ci#endif 3955db71995Sopenharmony_ci }; 3965db71995Sopenharmony_ci 3975db71995Sopenharmony_ci LONG rtn_value; 3985db71995Sopenharmony_ci HKEY hive = DEFAULT_VK_REGISTRY_HIVE, key; 3995db71995Sopenharmony_ci DWORD access_flags; 4005db71995Sopenharmony_ci char name[2048]; 4015db71995Sopenharmony_ci char *loc = location; 4025db71995Sopenharmony_ci char *next; 4035db71995Sopenharmony_ci DWORD name_size = sizeof(name); 4045db71995Sopenharmony_ci DWORD value; 4055db71995Sopenharmony_ci DWORD value_size = sizeof(value); 4065db71995Sopenharmony_ci VkResult result = VK_SUCCESS; 4075db71995Sopenharmony_ci bool found = false; 4085db71995Sopenharmony_ci IDXGIFactory1 *dxgi_factory = NULL; 4095db71995Sopenharmony_ci bool is_driver = !strcmp(location, VK_DRIVERS_INFO_REGISTRY_LOC); 4105db71995Sopenharmony_ci uint32_t log_target_flag = is_driver ? VULKAN_LOADER_DRIVER_BIT : VULKAN_LOADER_LAYER_BIT; 4115db71995Sopenharmony_ci 4125db71995Sopenharmony_ci assert(reg_data != NULL && "windows_get_registry_files: reg_data is a NULL pointer"); 4135db71995Sopenharmony_ci 4145db71995Sopenharmony_ci if (is_driver) { 4155db71995Sopenharmony_ci HRESULT hres = fpCreateDXGIFactory1(&IID_IDXGIFactory1, (void **)&dxgi_factory); 4165db71995Sopenharmony_ci if (hres != S_OK) { 4175db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | log_target_flag, 0, 4185db71995Sopenharmony_ci "windows_get_registry_files: Failed to create dxgi factory for ICD registry verification. No ICDs will be " 4195db71995Sopenharmony_ci "added from " 4205db71995Sopenharmony_ci "legacy registry locations"); 4215db71995Sopenharmony_ci goto out; 4225db71995Sopenharmony_ci } 4235db71995Sopenharmony_ci } 4245db71995Sopenharmony_ci 4255db71995Sopenharmony_ci while (*loc) { 4265db71995Sopenharmony_ci next = loader_get_next_path(loc); 4275db71995Sopenharmony_ci access_flags = KEY_QUERY_VALUE; 4285db71995Sopenharmony_ci rtn_value = RegOpenKeyEx(hive, loc, 0, access_flags, &key); 4295db71995Sopenharmony_ci if (ERROR_SUCCESS == rtn_value) { 4305db71995Sopenharmony_ci for (DWORD idx = 0; 4315db71995Sopenharmony_ci (rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL, NULL, (LPBYTE)&value, &value_size)) == ERROR_SUCCESS; 4325db71995Sopenharmony_ci name_size = sizeof(name), value_size = sizeof(value)) { 4335db71995Sopenharmony_ci if (value_size == sizeof(value) && value == 0) { 4345db71995Sopenharmony_ci if (NULL == *reg_data) { 4355db71995Sopenharmony_ci *reg_data = loader_instance_heap_alloc(inst, *reg_data_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 4365db71995Sopenharmony_ci if (NULL == *reg_data) { 4375db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT | log_target_flag, 0, 4385db71995Sopenharmony_ci "windows_get_registry_files: Failed to allocate space for registry data for key %s", name); 4395db71995Sopenharmony_ci RegCloseKey(key); 4405db71995Sopenharmony_ci result = VK_ERROR_OUT_OF_HOST_MEMORY; 4415db71995Sopenharmony_ci goto out; 4425db71995Sopenharmony_ci } 4435db71995Sopenharmony_ci *reg_data[0] = '\0'; 4445db71995Sopenharmony_ci } else if (strlen(*reg_data) + name_size + 1 > *reg_data_size) { 4455db71995Sopenharmony_ci void *new_ptr = loader_instance_heap_realloc(inst, *reg_data, *reg_data_size, *reg_data_size * 2, 4465db71995Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 4475db71995Sopenharmony_ci if (NULL == new_ptr) { 4485db71995Sopenharmony_ci loader_log( 4495db71995Sopenharmony_ci inst, VULKAN_LOADER_ERROR_BIT | log_target_flag, 0, 4505db71995Sopenharmony_ci "windows_get_registry_files: Failed to reallocate space for registry value of size %d for key %s", 4515db71995Sopenharmony_ci *reg_data_size * 2, name); 4525db71995Sopenharmony_ci RegCloseKey(key); 4535db71995Sopenharmony_ci result = VK_ERROR_OUT_OF_HOST_MEMORY; 4545db71995Sopenharmony_ci goto out; 4555db71995Sopenharmony_ci } 4565db71995Sopenharmony_ci *reg_data = new_ptr; 4575db71995Sopenharmony_ci *reg_data_size *= 2; 4585db71995Sopenharmony_ci } 4595db71995Sopenharmony_ci 4605db71995Sopenharmony_ci // We've now found a json file. If this is an ICD, we still need to check if there is actually a device 4615db71995Sopenharmony_ci // that matches this ICD 4625db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | log_target_flag, 0, 4635db71995Sopenharmony_ci "Located json file \"%s\" from registry \"%s\\%s\"", name, 4645db71995Sopenharmony_ci hive == DEFAULT_VK_REGISTRY_HIVE ? DEFAULT_VK_REGISTRY_HIVE_STR : SECONDARY_VK_REGISTRY_HIVE_STR, 4655db71995Sopenharmony_ci location); 4665db71995Sopenharmony_ci if (is_driver) { 4675db71995Sopenharmony_ci uint32_t i = 0; 4685db71995Sopenharmony_ci for (i = 0; i < sizeof(known_drivers) / sizeof(known_drivers[0]); ++i) { 4695db71995Sopenharmony_ci if (!strcmp(name + strlen(name) - strlen(known_drivers[i].filename), known_drivers[i].filename)) { 4705db71995Sopenharmony_ci break; 4715db71995Sopenharmony_ci } 4725db71995Sopenharmony_ci } 4735db71995Sopenharmony_ci if (i == sizeof(known_drivers) / sizeof(known_drivers[0])) { 4745db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | log_target_flag, 0, 4755db71995Sopenharmony_ci "Driver %s is not recognized as a known driver. It will be assumed to be active", name); 4765db71995Sopenharmony_ci } else { 4775db71995Sopenharmony_ci bool found_gpu = false; 4785db71995Sopenharmony_ci for (int j = 0;; ++j) { 4795db71995Sopenharmony_ci IDXGIAdapter1 *adapter; 4805db71995Sopenharmony_ci HRESULT hres = dxgi_factory->lpVtbl->EnumAdapters1(dxgi_factory, j, &adapter); 4815db71995Sopenharmony_ci if (hres == DXGI_ERROR_NOT_FOUND) { 4825db71995Sopenharmony_ci break; 4835db71995Sopenharmony_ci } else if (hres != S_OK) { 4845db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | log_target_flag, 0, 4855db71995Sopenharmony_ci "Failed to enumerate DXGI adapters at index %d. As a result, drivers may be skipped", 4865db71995Sopenharmony_ci j); 4875db71995Sopenharmony_ci continue; 4885db71995Sopenharmony_ci } 4895db71995Sopenharmony_ci 4905db71995Sopenharmony_ci DXGI_ADAPTER_DESC1 description; 4915db71995Sopenharmony_ci hres = adapter->lpVtbl->GetDesc1(adapter, &description); 4925db71995Sopenharmony_ci if (hres != S_OK) { 4935db71995Sopenharmony_ci loader_log( 4945db71995Sopenharmony_ci inst, VULKAN_LOADER_INFO_BIT | log_target_flag, 0, 4955db71995Sopenharmony_ci "Failed to get DXGI adapter information at index %d. As a result, drivers may be skipped", 4965db71995Sopenharmony_ci j); 4975db71995Sopenharmony_ci continue; 4985db71995Sopenharmony_ci } 4995db71995Sopenharmony_ci 5005db71995Sopenharmony_ci if (description.VendorId == known_drivers[i].vendor_id) { 5015db71995Sopenharmony_ci found_gpu = true; 5025db71995Sopenharmony_ci break; 5035db71995Sopenharmony_ci } 5045db71995Sopenharmony_ci } 5055db71995Sopenharmony_ci 5065db71995Sopenharmony_ci if (!found_gpu) { 5075db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT | log_target_flag, 0, 5085db71995Sopenharmony_ci "Dropping driver %s as no corresponding DXGI adapter was found", name); 5095db71995Sopenharmony_ci continue; 5105db71995Sopenharmony_ci } 5115db71995Sopenharmony_ci } 5125db71995Sopenharmony_ci } 5135db71995Sopenharmony_ci 5145db71995Sopenharmony_ci if (strlen(*reg_data) == 0) { 5155db71995Sopenharmony_ci // The list is emtpy. Add the first entry. 5165db71995Sopenharmony_ci (void)snprintf(*reg_data, name_size + 1, "%s", name); 5175db71995Sopenharmony_ci found = true; 5185db71995Sopenharmony_ci } else { 5195db71995Sopenharmony_ci // At this point the reg_data variable contains other JSON paths, likely from the PNP/device section 5205db71995Sopenharmony_ci // of the registry that we want to have precedence over this non-device specific section of the registry. 5215db71995Sopenharmony_ci // To make sure we avoid enumerating old JSON files/drivers that might be present in the non-device specific 5225db71995Sopenharmony_ci // area of the registry when a newer device specific JSON file is present, do a check before adding. 5235db71995Sopenharmony_ci // Find the file name, without path, of the JSON file found in the non-device specific registry location. 5245db71995Sopenharmony_ci // If the same JSON file name is already found in the list, don't add it again. 5255db71995Sopenharmony_ci bool foundDuplicate = false; 5265db71995Sopenharmony_ci char *pLastSlashName = strrchr(name, '\\'); 5275db71995Sopenharmony_ci if (pLastSlashName != NULL) { 5285db71995Sopenharmony_ci char *foundMatch = strstr(*reg_data, pLastSlashName + 1); 5295db71995Sopenharmony_ci if (foundMatch != NULL) { 5305db71995Sopenharmony_ci foundDuplicate = true; 5315db71995Sopenharmony_ci } 5325db71995Sopenharmony_ci } 5335db71995Sopenharmony_ci // Only skip if we are adding a driver and a duplicate was found 5345db71995Sopenharmony_ci if (!is_driver || (is_driver && foundDuplicate == false)) { 5355db71995Sopenharmony_ci // Add the new entry to the list. 5365db71995Sopenharmony_ci (void)snprintf(*reg_data + strlen(*reg_data), name_size + 2, "%c%s", PATH_SEPARATOR, name); 5375db71995Sopenharmony_ci found = true; 5385db71995Sopenharmony_ci } else { 5395db71995Sopenharmony_ci loader_log( 5405db71995Sopenharmony_ci inst, VULKAN_LOADER_INFO_BIT | log_target_flag, 0, 5415db71995Sopenharmony_ci "Skipping adding of json file \"%s\" from registry \"%s\\%s\" to the list due to duplication", name, 5425db71995Sopenharmony_ci hive == DEFAULT_VK_REGISTRY_HIVE ? DEFAULT_VK_REGISTRY_HIVE_STR : SECONDARY_VK_REGISTRY_HIVE_STR, 5435db71995Sopenharmony_ci location); 5445db71995Sopenharmony_ci } 5455db71995Sopenharmony_ci } 5465db71995Sopenharmony_ci } 5475db71995Sopenharmony_ci } 5485db71995Sopenharmony_ci RegCloseKey(key); 5495db71995Sopenharmony_ci } 5505db71995Sopenharmony_ci 5515db71995Sopenharmony_ci // Advance the location - if the next location is in the secondary hive, then reset the locations and advance the hive 5525db71995Sopenharmony_ci if (use_secondary_hive && (hive == DEFAULT_VK_REGISTRY_HIVE) && (*next == '\0')) { 5535db71995Sopenharmony_ci loc = location; 5545db71995Sopenharmony_ci hive = SECONDARY_VK_REGISTRY_HIVE; 5555db71995Sopenharmony_ci } else { 5565db71995Sopenharmony_ci loc = next; 5575db71995Sopenharmony_ci } 5585db71995Sopenharmony_ci } 5595db71995Sopenharmony_ci 5605db71995Sopenharmony_ci if (!found && result != VK_ERROR_OUT_OF_HOST_MEMORY) { 5615db71995Sopenharmony_ci loader_log(inst, log_target_flag, 0, "Found no registry files in %s\\%s", 5625db71995Sopenharmony_ci (hive == DEFAULT_VK_REGISTRY_HIVE) ? DEFAULT_VK_REGISTRY_HIVE_STR : SECONDARY_VK_REGISTRY_HIVE_STR, location); 5635db71995Sopenharmony_ci result = VK_ERROR_INCOMPATIBLE_DRIVER; 5645db71995Sopenharmony_ci } 5655db71995Sopenharmony_ci 5665db71995Sopenharmony_ciout: 5675db71995Sopenharmony_ci if (is_driver && dxgi_factory != NULL) { 5685db71995Sopenharmony_ci dxgi_factory->lpVtbl->Release(dxgi_factory); 5695db71995Sopenharmony_ci } 5705db71995Sopenharmony_ci 5715db71995Sopenharmony_ci return result; 5725db71995Sopenharmony_ci} 5735db71995Sopenharmony_ci 5745db71995Sopenharmony_ci// Read manifest JSON files using the Windows driver interface 5755db71995Sopenharmony_ciVkResult windows_read_manifest_from_d3d_adapters(const struct loader_instance *inst, char **reg_data, PDWORD reg_data_size, 5765db71995Sopenharmony_ci const wchar_t *value_name) { 5775db71995Sopenharmony_ci VkResult result = VK_INCOMPLETE; 5785db71995Sopenharmony_ci LoaderEnumAdapters2 adapters = {.adapter_count = 0, .adapters = NULL}; 5795db71995Sopenharmony_ci LoaderQueryRegistryInfo *full_info = NULL; 5805db71995Sopenharmony_ci size_t full_info_size = 0; 5815db71995Sopenharmony_ci char *json_path = NULL; 5825db71995Sopenharmony_ci size_t json_path_size = 0; 5835db71995Sopenharmony_ci 5845db71995Sopenharmony_ci HMODULE gdi32_dll = GetModuleHandle("gdi32.dll"); 5855db71995Sopenharmony_ci if (gdi32_dll == NULL) { 5865db71995Sopenharmony_ci result = VK_ERROR_INCOMPATIBLE_DRIVER; 5875db71995Sopenharmony_ci goto out; 5885db71995Sopenharmony_ci } 5895db71995Sopenharmony_ci 5905db71995Sopenharmony_ci PFN_LoaderEnumAdapters2 fpLoaderEnumAdapters2 = 5915db71995Sopenharmony_ci (PFN_LoaderEnumAdapters2)(void *)GetProcAddress(gdi32_dll, "D3DKMTEnumAdapters2"); 5925db71995Sopenharmony_ci PFN_LoaderQueryAdapterInfo fpLoaderQueryAdapterInfo = 5935db71995Sopenharmony_ci (PFN_LoaderQueryAdapterInfo)(void *)GetProcAddress(gdi32_dll, "D3DKMTQueryAdapterInfo"); 5945db71995Sopenharmony_ci if (fpLoaderEnumAdapters2 == NULL || fpLoaderQueryAdapterInfo == NULL) { 5955db71995Sopenharmony_ci result = VK_ERROR_INCOMPATIBLE_DRIVER; 5965db71995Sopenharmony_ci goto out; 5975db71995Sopenharmony_ci } 5985db71995Sopenharmony_ci 5995db71995Sopenharmony_ci // Get all of the adapters 6005db71995Sopenharmony_ci NTSTATUS status = fpLoaderEnumAdapters2(&adapters); 6015db71995Sopenharmony_ci if (status == STATUS_SUCCESS && adapters.adapter_count > 0) { 6025db71995Sopenharmony_ci adapters.adapters = loader_instance_heap_alloc(inst, sizeof(*adapters.adapters) * adapters.adapter_count, 6035db71995Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 6045db71995Sopenharmony_ci if (adapters.adapters == NULL) { 6055db71995Sopenharmony_ci goto out; 6065db71995Sopenharmony_ci } 6075db71995Sopenharmony_ci status = fpLoaderEnumAdapters2(&adapters); 6085db71995Sopenharmony_ci } 6095db71995Sopenharmony_ci if (status != STATUS_SUCCESS) { 6105db71995Sopenharmony_ci goto out; 6115db71995Sopenharmony_ci } 6125db71995Sopenharmony_ci 6135db71995Sopenharmony_ci // If that worked, we need to get the manifest file(s) for each adapter 6145db71995Sopenharmony_ci for (ULONG i = 0; i < adapters.adapter_count; ++i) { 6155db71995Sopenharmony_ci // The first query should just check if the field exists and how big it is 6165db71995Sopenharmony_ci LoaderQueryRegistryInfo filename_info = { 6175db71995Sopenharmony_ci .query_type = LOADER_QUERY_REGISTRY_ADAPTER_KEY, 6185db71995Sopenharmony_ci .query_flags = 6195db71995Sopenharmony_ci { 6205db71995Sopenharmony_ci .translate_path = true, 6215db71995Sopenharmony_ci }, 6225db71995Sopenharmony_ci .value_type = REG_MULTI_SZ, 6235db71995Sopenharmony_ci .physical_adapter_index = 0, 6245db71995Sopenharmony_ci }; 6255db71995Sopenharmony_ci size_t value_name_size = wcslen(value_name); 6265db71995Sopenharmony_ci wcsncpy_s(filename_info.value_name, MAX_PATH, value_name, value_name_size); 6275db71995Sopenharmony_ci LoaderQueryAdapterInfo query_info; 6285db71995Sopenharmony_ci query_info.handle = adapters.adapters[i].handle; 6295db71995Sopenharmony_ci query_info.type = LOADER_QUERY_TYPE_REGISTRY; 6305db71995Sopenharmony_ci query_info.private_data = &filename_info; 6315db71995Sopenharmony_ci query_info.private_data_size = sizeof(filename_info); 6325db71995Sopenharmony_ci status = fpLoaderQueryAdapterInfo(&query_info); 6335db71995Sopenharmony_ci 6345db71995Sopenharmony_ci // This error indicates that the type didn't match, so we'll try a REG_SZ 6355db71995Sopenharmony_ci if (status != STATUS_SUCCESS) { 6365db71995Sopenharmony_ci filename_info.value_type = REG_SZ; 6375db71995Sopenharmony_ci status = fpLoaderQueryAdapterInfo(&query_info); 6385db71995Sopenharmony_ci } 6395db71995Sopenharmony_ci 6405db71995Sopenharmony_ci if (status != STATUS_SUCCESS || filename_info.status != LOADER_QUERY_REGISTRY_STATUS_BUFFER_OVERFLOW) { 6415db71995Sopenharmony_ci continue; 6425db71995Sopenharmony_ci } 6435db71995Sopenharmony_ci 6445db71995Sopenharmony_ci while (status == STATUS_SUCCESS && 6455db71995Sopenharmony_ci ((LoaderQueryRegistryInfo *)query_info.private_data)->status == LOADER_QUERY_REGISTRY_STATUS_BUFFER_OVERFLOW) { 6465db71995Sopenharmony_ci bool needs_copy = (full_info == NULL); 6475db71995Sopenharmony_ci size_t full_size = sizeof(LoaderQueryRegistryInfo) + filename_info.output_value_size; 6485db71995Sopenharmony_ci void *buffer = 6495db71995Sopenharmony_ci loader_instance_heap_realloc(inst, full_info, full_info_size, full_size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 6505db71995Sopenharmony_ci if (buffer == NULL) { 6515db71995Sopenharmony_ci result = VK_ERROR_OUT_OF_HOST_MEMORY; 6525db71995Sopenharmony_ci goto out; 6535db71995Sopenharmony_ci } 6545db71995Sopenharmony_ci full_info = buffer; 6555db71995Sopenharmony_ci full_info_size = full_size; 6565db71995Sopenharmony_ci 6575db71995Sopenharmony_ci if (needs_copy) { 6585db71995Sopenharmony_ci memcpy(full_info, &filename_info, sizeof(LoaderQueryRegistryInfo)); 6595db71995Sopenharmony_ci } 6605db71995Sopenharmony_ci query_info.private_data = full_info; 6615db71995Sopenharmony_ci query_info.private_data_size = (UINT)full_info_size; 6625db71995Sopenharmony_ci status = fpLoaderQueryAdapterInfo(&query_info); 6635db71995Sopenharmony_ci } 6645db71995Sopenharmony_ci 6655db71995Sopenharmony_ci if (status != STATUS_SUCCESS || full_info->status != LOADER_QUERY_REGISTRY_STATUS_SUCCESS) { 6665db71995Sopenharmony_ci goto out; 6675db71995Sopenharmony_ci } 6685db71995Sopenharmony_ci 6695db71995Sopenharmony_ci // Convert the wide string to a narrow string 6705db71995Sopenharmony_ci void *buffer = loader_instance_heap_realloc(inst, json_path, json_path_size, full_info->output_value_size, 6715db71995Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 6725db71995Sopenharmony_ci if (buffer == NULL) { 6735db71995Sopenharmony_ci result = VK_ERROR_OUT_OF_HOST_MEMORY; 6745db71995Sopenharmony_ci goto out; 6755db71995Sopenharmony_ci } 6765db71995Sopenharmony_ci json_path = buffer; 6775db71995Sopenharmony_ci json_path_size = full_info->output_value_size; 6785db71995Sopenharmony_ci 6795db71995Sopenharmony_ci // Iterate over each component string 6805db71995Sopenharmony_ci for (const wchar_t *curr_path = full_info->output_string; curr_path[0] != '\0'; curr_path += wcslen(curr_path) + 1) { 6815db71995Sopenharmony_ci WideCharToMultiByte(CP_UTF8, 0, curr_path, -1, json_path, (int)json_path_size, NULL, NULL); 6825db71995Sopenharmony_ci 6835db71995Sopenharmony_ci // Add the string to the output list 6845db71995Sopenharmony_ci result = VK_SUCCESS; 6855db71995Sopenharmony_ci windows_add_json_entry(inst, reg_data, reg_data_size, (LPCTSTR)L"EnumAdapters", REG_SZ, json_path, 6865db71995Sopenharmony_ci (DWORD)strlen(json_path) + 1, &result); 6875db71995Sopenharmony_ci if (result != VK_SUCCESS) { 6885db71995Sopenharmony_ci goto out; 6895db71995Sopenharmony_ci } 6905db71995Sopenharmony_ci 6915db71995Sopenharmony_ci // If this is a string and not a multi-string, we don't want to go through the loop more than once 6925db71995Sopenharmony_ci if (full_info->value_type == REG_SZ) { 6935db71995Sopenharmony_ci break; 6945db71995Sopenharmony_ci } 6955db71995Sopenharmony_ci } 6965db71995Sopenharmony_ci } 6975db71995Sopenharmony_ci 6985db71995Sopenharmony_ciout: 6995db71995Sopenharmony_ci loader_instance_heap_free(inst, json_path); 7005db71995Sopenharmony_ci loader_instance_heap_free(inst, full_info); 7015db71995Sopenharmony_ci loader_instance_heap_free(inst, adapters.adapters); 7025db71995Sopenharmony_ci 7035db71995Sopenharmony_ci return result; 7045db71995Sopenharmony_ci} 7055db71995Sopenharmony_ci 7065db71995Sopenharmony_ci// Look for data files in the registry. 7075db71995Sopenharmony_ciVkResult windows_read_data_files_in_registry(const struct loader_instance *inst, enum loader_data_files_type data_file_type, 7085db71995Sopenharmony_ci bool warn_if_not_present, char *registry_location, 7095db71995Sopenharmony_ci struct loader_string_list *out_files) { 7105db71995Sopenharmony_ci VkResult vk_result = VK_SUCCESS; 7115db71995Sopenharmony_ci char *search_path = NULL; 7125db71995Sopenharmony_ci uint32_t log_target_flag = 0; 7135db71995Sopenharmony_ci 7145db71995Sopenharmony_ci if (data_file_type == LOADER_DATA_FILE_MANIFEST_DRIVER) { 7155db71995Sopenharmony_ci log_target_flag = VULKAN_LOADER_DRIVER_BIT; 7165db71995Sopenharmony_ci loader_log(inst, log_target_flag, 0, "Checking for Driver Manifest files in Registry at %s\\%s", 7175db71995Sopenharmony_ci DEFAULT_VK_REGISTRY_HIVE_STR, registry_location); 7185db71995Sopenharmony_ci } else { 7195db71995Sopenharmony_ci log_target_flag = VULKAN_LOADER_LAYER_BIT; 7205db71995Sopenharmony_ci loader_log(inst, log_target_flag, 0, "Checking for Layer Manifest files in Registry at %s\\%s", 7215db71995Sopenharmony_ci DEFAULT_VK_REGISTRY_HIVE_STR, registry_location); 7225db71995Sopenharmony_ci } 7235db71995Sopenharmony_ci 7245db71995Sopenharmony_ci // These calls look at the PNP/Device section of the registry. 7255db71995Sopenharmony_ci VkResult regHKR_result = VK_SUCCESS; 7265db71995Sopenharmony_ci DWORD reg_size = 4096; 7275db71995Sopenharmony_ci if (!strncmp(registry_location, VK_DRIVERS_INFO_REGISTRY_LOC, sizeof(VK_DRIVERS_INFO_REGISTRY_LOC))) { 7285db71995Sopenharmony_ci // If we're looking for drivers we need to try enumerating adapters 7295db71995Sopenharmony_ci regHKR_result = windows_read_manifest_from_d3d_adapters(inst, &search_path, ®_size, LoaderPnpDriverRegistryWide()); 7305db71995Sopenharmony_ci if (regHKR_result == VK_INCOMPLETE) { 7315db71995Sopenharmony_ci regHKR_result = 7325db71995Sopenharmony_ci windows_get_device_registry_files(inst, log_target_flag, &search_path, ®_size, LoaderPnpDriverRegistry()); 7335db71995Sopenharmony_ci } 7345db71995Sopenharmony_ci } else if (!strncmp(registry_location, VK_ELAYERS_INFO_REGISTRY_LOC, sizeof(VK_ELAYERS_INFO_REGISTRY_LOC))) { 7355db71995Sopenharmony_ci regHKR_result = windows_read_manifest_from_d3d_adapters(inst, &search_path, ®_size, LoaderPnpELayerRegistryWide()); 7365db71995Sopenharmony_ci if (regHKR_result == VK_INCOMPLETE) { 7375db71995Sopenharmony_ci regHKR_result = 7385db71995Sopenharmony_ci windows_get_device_registry_files(inst, log_target_flag, &search_path, ®_size, LoaderPnpELayerRegistry()); 7395db71995Sopenharmony_ci } 7405db71995Sopenharmony_ci } else if (!strncmp(registry_location, VK_ILAYERS_INFO_REGISTRY_LOC, sizeof(VK_ILAYERS_INFO_REGISTRY_LOC))) { 7415db71995Sopenharmony_ci regHKR_result = windows_read_manifest_from_d3d_adapters(inst, &search_path, ®_size, LoaderPnpILayerRegistryWide()); 7425db71995Sopenharmony_ci if (regHKR_result == VK_INCOMPLETE) { 7435db71995Sopenharmony_ci regHKR_result = 7445db71995Sopenharmony_ci windows_get_device_registry_files(inst, log_target_flag, &search_path, ®_size, LoaderPnpILayerRegistry()); 7455db71995Sopenharmony_ci } 7465db71995Sopenharmony_ci } 7475db71995Sopenharmony_ci 7485db71995Sopenharmony_ci if (regHKR_result == VK_ERROR_OUT_OF_HOST_MEMORY) { 7495db71995Sopenharmony_ci vk_result = VK_ERROR_OUT_OF_HOST_MEMORY; 7505db71995Sopenharmony_ci goto out; 7515db71995Sopenharmony_ci } 7525db71995Sopenharmony_ci 7535db71995Sopenharmony_ci // This call looks into the Khronos non-device specific section of the registry for layer files. 7545db71995Sopenharmony_ci bool use_secondary_hive = (data_file_type != LOADER_DATA_FILE_MANIFEST_DRIVER) && (!is_high_integrity()); 7555db71995Sopenharmony_ci VkResult reg_result = windows_get_registry_files(inst, registry_location, use_secondary_hive, &search_path, ®_size); 7565db71995Sopenharmony_ci if (reg_result == VK_ERROR_OUT_OF_HOST_MEMORY) { 7575db71995Sopenharmony_ci vk_result = VK_ERROR_OUT_OF_HOST_MEMORY; 7585db71995Sopenharmony_ci goto out; 7595db71995Sopenharmony_ci } 7605db71995Sopenharmony_ci 7615db71995Sopenharmony_ci if ((VK_SUCCESS != reg_result && VK_SUCCESS != regHKR_result) || NULL == search_path) { 7625db71995Sopenharmony_ci if (data_file_type == LOADER_DATA_FILE_MANIFEST_DRIVER) { 7635db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT | log_target_flag, 0, 7645db71995Sopenharmony_ci "windows_read_data_files_in_registry: Registry lookup failed to get ICD manifest files. Possibly missing " 7655db71995Sopenharmony_ci "Vulkan driver?"); 7665db71995Sopenharmony_ci vk_result = VK_ERROR_INCOMPATIBLE_DRIVER; 7675db71995Sopenharmony_ci } else { 7685db71995Sopenharmony_ci if (warn_if_not_present) { 7695db71995Sopenharmony_ci if (data_file_type == LOADER_DATA_FILE_MANIFEST_IMPLICIT_LAYER || 7705db71995Sopenharmony_ci data_file_type == LOADER_DATA_FILE_MANIFEST_EXPLICIT_LAYER) { 7715db71995Sopenharmony_ci // This is only a warning for layers 7725db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | log_target_flag, 0, 7735db71995Sopenharmony_ci "windows_read_data_files_in_registry: Registry lookup failed to get layer manifest files."); 7745db71995Sopenharmony_ci } else { 7755db71995Sopenharmony_ci // This is only a warning for general data files 7765db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT | log_target_flag, 0, 7775db71995Sopenharmony_ci "windows_read_data_files_in_registry: Registry lookup failed to get data files."); 7785db71995Sopenharmony_ci } 7795db71995Sopenharmony_ci } 7805db71995Sopenharmony_ci // Return success for now since it's not critical for layers 7815db71995Sopenharmony_ci vk_result = VK_SUCCESS; 7825db71995Sopenharmony_ci } 7835db71995Sopenharmony_ci goto out; 7845db71995Sopenharmony_ci } 7855db71995Sopenharmony_ci 7865db71995Sopenharmony_ci // Now, parse the paths and add any manifest files found in them. 7875db71995Sopenharmony_ci vk_result = add_data_files(inst, search_path, out_files, false); 7885db71995Sopenharmony_ci 7895db71995Sopenharmony_ciout: 7905db71995Sopenharmony_ci 7915db71995Sopenharmony_ci loader_instance_heap_free(inst, search_path); 7925db71995Sopenharmony_ci 7935db71995Sopenharmony_ci return vk_result; 7945db71995Sopenharmony_ci} 7955db71995Sopenharmony_ci 7965db71995Sopenharmony_ciVkResult enumerate_adapter_physical_devices(struct loader_instance *inst, struct loader_icd_term *icd_term, uint32_t icd_idx, 7975db71995Sopenharmony_ci LUID luid, uint32_t *icd_phys_devs_array_count, 7985db71995Sopenharmony_ci struct loader_icd_physical_devices *icd_phys_devs_array) { 7995db71995Sopenharmony_ci uint32_t count = 0; 8005db71995Sopenharmony_ci VkResult res = icd_term->scanned_icd->EnumerateAdapterPhysicalDevices(icd_term->instance, luid, &count, NULL); 8015db71995Sopenharmony_ci if (res == VK_ERROR_OUT_OF_HOST_MEMORY) { 8025db71995Sopenharmony_ci return res; 8035db71995Sopenharmony_ci } else if (res == VK_ERROR_INCOMPATIBLE_DRIVER) { 8045db71995Sopenharmony_ci return VK_SUCCESS; // This driver doesn't support the adapter 8055db71995Sopenharmony_ci } else if (res != VK_SUCCESS) { 8065db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, 8075db71995Sopenharmony_ci "Failed to convert DXGI adapter into Vulkan physical device with unexpected error code"); 8085db71995Sopenharmony_ci return res; 8095db71995Sopenharmony_ci } else if (0 == count) { 8105db71995Sopenharmony_ci return VK_SUCCESS; // This driver doesn't support the adapter 8115db71995Sopenharmony_ci } 8125db71995Sopenharmony_ci 8135db71995Sopenharmony_ci // Take a pointer to the last element of icd_phys_devs_array to simplify usage 8145db71995Sopenharmony_ci struct loader_icd_physical_devices *next_icd_phys_devs = &icd_phys_devs_array[*icd_phys_devs_array_count]; 8155db71995Sopenharmony_ci 8165db71995Sopenharmony_ci // Get the actual physical devices 8175db71995Sopenharmony_ci do { 8185db71995Sopenharmony_ci next_icd_phys_devs->physical_devices = loader_instance_heap_realloc( 8195db71995Sopenharmony_ci inst, next_icd_phys_devs->physical_devices, next_icd_phys_devs->device_count * sizeof(VkPhysicalDevice), 8205db71995Sopenharmony_ci count * sizeof(VkPhysicalDevice), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 8215db71995Sopenharmony_ci if (next_icd_phys_devs->physical_devices == NULL) { 8225db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 8235db71995Sopenharmony_ci } 8245db71995Sopenharmony_ci next_icd_phys_devs->device_count = count; 8255db71995Sopenharmony_ci } while ((res = icd_term->scanned_icd->EnumerateAdapterPhysicalDevices(icd_term->instance, luid, &count, 8265db71995Sopenharmony_ci next_icd_phys_devs->physical_devices)) == VK_INCOMPLETE); 8275db71995Sopenharmony_ci 8285db71995Sopenharmony_ci if (res != VK_SUCCESS) { 8295db71995Sopenharmony_ci loader_instance_heap_free(inst, next_icd_phys_devs->physical_devices); 8305db71995Sopenharmony_ci next_icd_phys_devs->physical_devices = NULL; 8315db71995Sopenharmony_ci // Unless OOHM occurs, only return VK_SUCCESS 8325db71995Sopenharmony_ci if (res != VK_ERROR_OUT_OF_HOST_MEMORY) { 8335db71995Sopenharmony_ci res = VK_SUCCESS; 8345db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, "Failed to convert DXGI adapter into Vulkan physical device"); 8355db71995Sopenharmony_ci } 8365db71995Sopenharmony_ci return res; 8375db71995Sopenharmony_ci } 8385db71995Sopenharmony_ci 8395db71995Sopenharmony_ci // Because the loader calls EnumerateAdapterPhysicalDevices on all drivers with each DXGI Adapter, if there are multiple drivers 8405db71995Sopenharmony_ci // that share a luid the physical device will get queried multiple times. We can prevent that by not adding them if the 8415db71995Sopenharmony_ci // enumerated physical devices have already been added. 8425db71995Sopenharmony_ci bool already_enumerated = false; 8435db71995Sopenharmony_ci for (uint32_t j = 0; j < *icd_phys_devs_array_count; j++) { 8445db71995Sopenharmony_ci if (count == icd_phys_devs_array[j].device_count) { 8455db71995Sopenharmony_ci bool matches = true; 8465db71995Sopenharmony_ci for (uint32_t k = 0; k < icd_phys_devs_array[j].device_count; k++) { 8475db71995Sopenharmony_ci if (icd_phys_devs_array[j].physical_devices[k] != next_icd_phys_devs->physical_devices[k]) { 8485db71995Sopenharmony_ci matches = false; 8495db71995Sopenharmony_ci break; 8505db71995Sopenharmony_ci } 8515db71995Sopenharmony_ci } 8525db71995Sopenharmony_ci if (matches) { 8535db71995Sopenharmony_ci already_enumerated = true; 8545db71995Sopenharmony_ci } 8555db71995Sopenharmony_ci } 8565db71995Sopenharmony_ci } 8575db71995Sopenharmony_ci if (!already_enumerated) { 8585db71995Sopenharmony_ci next_icd_phys_devs->device_count = count; 8595db71995Sopenharmony_ci next_icd_phys_devs->icd_index = icd_idx; 8605db71995Sopenharmony_ci next_icd_phys_devs->icd_term = icd_term; 8615db71995Sopenharmony_ci next_icd_phys_devs->windows_adapter_luid = luid; 8625db71995Sopenharmony_ci (*icd_phys_devs_array_count)++; 8635db71995Sopenharmony_ci } 8645db71995Sopenharmony_ci 8655db71995Sopenharmony_ci return VK_SUCCESS; 8665db71995Sopenharmony_ci} 8675db71995Sopenharmony_ci 8685db71995Sopenharmony_ci// Whenever there are multiple drivers for the same hardware and one of the drivers is an implementation layered on top of another 8695db71995Sopenharmony_ci// API (such as the Dozen driver which converts vulkan to Dx12), we want to make sure the layered driver appears after the 'native' 8705db71995Sopenharmony_ci// driver. This function iterates over all physical devices and make sure any with matching LUID's are sorted such that drivers with 8715db71995Sopenharmony_ci// a underlyingAPI of VK_LAYERED_DRIVER_UNDERLYING_API_D3D12_MSFT are ordered after drivers without it. 8725db71995Sopenharmony_civoid sort_physical_devices_with_same_luid(struct loader_instance *inst, uint32_t icd_phys_devs_array_count, 8735db71995Sopenharmony_ci struct loader_icd_physical_devices *icd_phys_devs_array) { 8745db71995Sopenharmony_ci bool app_is_vulkan_1_1 = loader_check_version_meets_required(LOADER_VERSION_1_1_0, inst->app_api_version); 8755db71995Sopenharmony_ci 8765db71995Sopenharmony_ci for (uint32_t i = 0; icd_phys_devs_array_count > 1 && i < icd_phys_devs_array_count - 1; i++) { 8775db71995Sopenharmony_ci for (uint32_t j = i + 1; j < icd_phys_devs_array_count; j++) { 8785db71995Sopenharmony_ci // Only want to reorder physical devices if their ICD's LUID's match 8795db71995Sopenharmony_ci if ((icd_phys_devs_array[i].windows_adapter_luid.HighPart != icd_phys_devs_array[j].windows_adapter_luid.HighPart) || 8805db71995Sopenharmony_ci (icd_phys_devs_array[i].windows_adapter_luid.LowPart != icd_phys_devs_array[j].windows_adapter_luid.LowPart)) { 8815db71995Sopenharmony_ci continue; 8825db71995Sopenharmony_ci } 8835db71995Sopenharmony_ci 8845db71995Sopenharmony_ci VkLayeredDriverUnderlyingApiMSFT underlyingAPI = VK_LAYERED_DRIVER_UNDERLYING_API_NONE_MSFT; 8855db71995Sopenharmony_ci VkPhysicalDeviceLayeredDriverPropertiesMSFT layered_driver_properties_msft = {0}; 8865db71995Sopenharmony_ci layered_driver_properties_msft.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_DRIVER_PROPERTIES_MSFT; 8875db71995Sopenharmony_ci VkPhysicalDeviceProperties2 props2 = {0}; 8885db71995Sopenharmony_ci props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; 8895db71995Sopenharmony_ci props2.pNext = (void *)&layered_driver_properties_msft; 8905db71995Sopenharmony_ci 8915db71995Sopenharmony_ci // Because there may be multiple physical devices associated with each ICD, we need to check each physical device 8925db71995Sopenharmony_ci // whether it is layered 8935db71995Sopenharmony_ci for (uint32_t k = 0; k < icd_phys_devs_array[i].device_count; k++) { 8945db71995Sopenharmony_ci VkPhysicalDeviceProperties dev_props = {0}; 8955db71995Sopenharmony_ci icd_phys_devs_array[i].icd_term->dispatch.GetPhysicalDeviceProperties(icd_phys_devs_array[i].physical_devices[k], 8965db71995Sopenharmony_ci &dev_props); 8975db71995Sopenharmony_ci 8985db71995Sopenharmony_ci bool device_is_1_1_capable = 8995db71995Sopenharmony_ci loader_check_version_meets_required(LOADER_VERSION_1_1_0, loader_make_version(dev_props.apiVersion)); 9005db71995Sopenharmony_ci 9015db71995Sopenharmony_ci PFN_vkGetPhysicalDeviceProperties2 GetPhysDevProps2 = NULL; 9025db71995Sopenharmony_ci if (app_is_vulkan_1_1 && device_is_1_1_capable) { 9035db71995Sopenharmony_ci GetPhysDevProps2 = icd_phys_devs_array[i].icd_term->dispatch.GetPhysicalDeviceProperties2; 9045db71995Sopenharmony_ci } else { 9055db71995Sopenharmony_ci GetPhysDevProps2 = (PFN_vkGetPhysicalDeviceProperties2)icd_phys_devs_array[i] 9065db71995Sopenharmony_ci .icd_term->dispatch.GetPhysicalDeviceProperties2KHR; 9075db71995Sopenharmony_ci } 9085db71995Sopenharmony_ci if (GetPhysDevProps2) { 9095db71995Sopenharmony_ci GetPhysDevProps2(icd_phys_devs_array[i].physical_devices[k], &props2); 9105db71995Sopenharmony_ci if (layered_driver_properties_msft.underlyingAPI != VK_LAYERED_DRIVER_UNDERLYING_API_NONE_MSFT) { 9115db71995Sopenharmony_ci underlyingAPI = layered_driver_properties_msft.underlyingAPI; 9125db71995Sopenharmony_ci break; 9135db71995Sopenharmony_ci } 9145db71995Sopenharmony_ci } 9155db71995Sopenharmony_ci } 9165db71995Sopenharmony_ci if (underlyingAPI == VK_LAYERED_DRIVER_UNDERLYING_API_D3D12_MSFT) { 9175db71995Sopenharmony_ci struct loader_icd_physical_devices swap_icd = icd_phys_devs_array[i]; 9185db71995Sopenharmony_ci icd_phys_devs_array[i] = icd_phys_devs_array[j]; 9195db71995Sopenharmony_ci icd_phys_devs_array[j] = swap_icd; 9205db71995Sopenharmony_ci } 9215db71995Sopenharmony_ci } 9225db71995Sopenharmony_ci } 9235db71995Sopenharmony_ci} 9245db71995Sopenharmony_ci 9255db71995Sopenharmony_ci// This function allocates icd_phys_devs_array which must be freed by the caller if not null 9265db71995Sopenharmony_ciVkResult windows_read_sorted_physical_devices(struct loader_instance *inst, uint32_t *icd_phys_devs_array_count, 9275db71995Sopenharmony_ci struct loader_icd_physical_devices **icd_phys_devs_array) { 9285db71995Sopenharmony_ci VkResult res = VK_SUCCESS; 9295db71995Sopenharmony_ci 9305db71995Sopenharmony_ci uint32_t icd_phys_devs_array_size = 0; 9315db71995Sopenharmony_ci struct loader_icd_term *icd_term = NULL; 9325db71995Sopenharmony_ci IDXGIFactory6 *dxgi_factory = NULL; 9335db71995Sopenharmony_ci HRESULT hres = fpCreateDXGIFactory1(&IID_IDXGIFactory6, (void **)&dxgi_factory); 9345db71995Sopenharmony_ci if (hres != S_OK) { 9355db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, "Failed to create DXGI factory 6. Physical devices will not be sorted"); 9365db71995Sopenharmony_ci goto out; 9375db71995Sopenharmony_ci } 9385db71995Sopenharmony_ci icd_phys_devs_array_size = 16; 9395db71995Sopenharmony_ci *icd_phys_devs_array = loader_instance_heap_calloc(inst, icd_phys_devs_array_size * sizeof(struct loader_icd_physical_devices), 9405db71995Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 9415db71995Sopenharmony_ci if (*icd_phys_devs_array == NULL) { 9425db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 9435db71995Sopenharmony_ci goto out; 9445db71995Sopenharmony_ci } 9455db71995Sopenharmony_ci 9465db71995Sopenharmony_ci for (uint32_t i = 0;; ++i) { 9475db71995Sopenharmony_ci IDXGIAdapter1 *adapter; 9485db71995Sopenharmony_ci hres = dxgi_factory->lpVtbl->EnumAdapterByGpuPreference(dxgi_factory, i, DXGI_GPU_PREFERENCE_UNSPECIFIED, 9495db71995Sopenharmony_ci &IID_IDXGIAdapter1, (void **)&adapter); 9505db71995Sopenharmony_ci if (hres == DXGI_ERROR_NOT_FOUND) { 9515db71995Sopenharmony_ci break; // No more adapters 9525db71995Sopenharmony_ci } else if (hres != S_OK) { 9535db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, 9545db71995Sopenharmony_ci "Failed to enumerate adapters by GPU preference at index %u. This adapter will not be sorted", i); 9555db71995Sopenharmony_ci break; 9565db71995Sopenharmony_ci } 9575db71995Sopenharmony_ci 9585db71995Sopenharmony_ci DXGI_ADAPTER_DESC1 description; 9595db71995Sopenharmony_ci hres = adapter->lpVtbl->GetDesc1(adapter, &description); 9605db71995Sopenharmony_ci if (hres != S_OK) { 9615db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, "Failed to get adapter LUID index %u. This adapter will not be sorted", i); 9625db71995Sopenharmony_ci continue; 9635db71995Sopenharmony_ci } 9645db71995Sopenharmony_ci 9655db71995Sopenharmony_ci if (icd_phys_devs_array_size <= i) { 9665db71995Sopenharmony_ci uint32_t old_size = icd_phys_devs_array_size * sizeof(struct loader_icd_physical_devices); 9675db71995Sopenharmony_ci *icd_phys_devs_array = loader_instance_heap_realloc(inst, *icd_phys_devs_array, old_size, 2 * old_size, 9685db71995Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 9695db71995Sopenharmony_ci if (*icd_phys_devs_array == NULL) { 9705db71995Sopenharmony_ci adapter->lpVtbl->Release(adapter); 9715db71995Sopenharmony_ci res = VK_ERROR_OUT_OF_HOST_MEMORY; 9725db71995Sopenharmony_ci goto out; 9735db71995Sopenharmony_ci } 9745db71995Sopenharmony_ci icd_phys_devs_array_size *= 2; 9755db71995Sopenharmony_ci } 9765db71995Sopenharmony_ci (*icd_phys_devs_array)[*icd_phys_devs_array_count].device_count = 0; 9775db71995Sopenharmony_ci (*icd_phys_devs_array)[*icd_phys_devs_array_count].physical_devices = NULL; 9785db71995Sopenharmony_ci 9795db71995Sopenharmony_ci icd_term = inst->icd_terms; 9805db71995Sopenharmony_ci for (uint32_t icd_idx = 0; NULL != icd_term; icd_term = icd_term->next, icd_idx++) { 9815db71995Sopenharmony_ci // This is the new behavior, which cannot be run unless the ICD provides EnumerateAdapterPhysicalDevices 9825db71995Sopenharmony_ci if (icd_term->scanned_icd->EnumerateAdapterPhysicalDevices == NULL) { 9835db71995Sopenharmony_ci continue; 9845db71995Sopenharmony_ci } 9855db71995Sopenharmony_ci 9865db71995Sopenharmony_ci res = enumerate_adapter_physical_devices(inst, icd_term, icd_idx, description.AdapterLuid, icd_phys_devs_array_count, 9875db71995Sopenharmony_ci *icd_phys_devs_array); 9885db71995Sopenharmony_ci if (res == VK_ERROR_OUT_OF_HOST_MEMORY) { 9895db71995Sopenharmony_ci adapter->lpVtbl->Release(adapter); 9905db71995Sopenharmony_ci goto out; 9915db71995Sopenharmony_ci } 9925db71995Sopenharmony_ci } 9935db71995Sopenharmony_ci 9945db71995Sopenharmony_ci adapter->lpVtbl->Release(adapter); 9955db71995Sopenharmony_ci } 9965db71995Sopenharmony_ci 9975db71995Sopenharmony_ci dxgi_factory->lpVtbl->Release(dxgi_factory); 9985db71995Sopenharmony_ci 9995db71995Sopenharmony_ci sort_physical_devices_with_same_luid(inst, *icd_phys_devs_array_count, *icd_phys_devs_array); 10005db71995Sopenharmony_ci 10015db71995Sopenharmony_ciout: 10025db71995Sopenharmony_ci if (*icd_phys_devs_array_count == 0 && *icd_phys_devs_array != NULL) { 10035db71995Sopenharmony_ci loader_instance_heap_free(inst, *icd_phys_devs_array); 10045db71995Sopenharmony_ci *icd_phys_devs_array = NULL; 10055db71995Sopenharmony_ci } 10065db71995Sopenharmony_ci return res; 10075db71995Sopenharmony_ci} 10085db71995Sopenharmony_ci 10095db71995Sopenharmony_ciVkLoaderFeatureFlags windows_initialize_dxgi(void) { 10105db71995Sopenharmony_ci VkLoaderFeatureFlags feature_flags = 0; 10115db71995Sopenharmony_ci IDXGIFactory6 *dxgi_factory = NULL; 10125db71995Sopenharmony_ci HRESULT hres = fpCreateDXGIFactory1(&IID_IDXGIFactory6, (void **)&dxgi_factory); 10135db71995Sopenharmony_ci if (hres == S_OK) { 10145db71995Sopenharmony_ci feature_flags |= VK_LOADER_FEATURE_PHYSICAL_DEVICE_SORTING; 10155db71995Sopenharmony_ci dxgi_factory->lpVtbl->Release(dxgi_factory); 10165db71995Sopenharmony_ci } 10175db71995Sopenharmony_ci return feature_flags; 10185db71995Sopenharmony_ci} 10195db71995Sopenharmony_ci 10205db71995Sopenharmony_ci// Sort the VkPhysicalDevices that are part of the current group with the list passed in from the sorted list. 10215db71995Sopenharmony_ci// Multiple groups could have devices out of the same sorted list, however, a single group's devices must all come 10225db71995Sopenharmony_ci// from the same sorted list. 10235db71995Sopenharmony_civoid windows_sort_devices_in_group(struct loader_instance *inst, struct VkPhysicalDeviceGroupProperties *group_props, 10245db71995Sopenharmony_ci struct loader_icd_physical_devices *icd_sorted_list) { 10255db71995Sopenharmony_ci uint32_t cur_index = 0; 10265db71995Sopenharmony_ci for (uint32_t dev = 0; dev < icd_sorted_list->device_count; ++dev) { 10275db71995Sopenharmony_ci for (uint32_t grp_dev = cur_index; grp_dev < group_props->physicalDeviceCount; ++grp_dev) { 10285db71995Sopenharmony_ci if (icd_sorted_list->physical_devices[dev] == group_props->physicalDevices[grp_dev]) { 10295db71995Sopenharmony_ci if (cur_index != grp_dev) { 10305db71995Sopenharmony_ci VkPhysicalDevice swap_dev = group_props->physicalDevices[cur_index]; 10315db71995Sopenharmony_ci group_props->physicalDevices[cur_index] = group_props->physicalDevices[grp_dev]; 10325db71995Sopenharmony_ci group_props->physicalDevices[grp_dev] = swap_dev; 10335db71995Sopenharmony_ci } 10345db71995Sopenharmony_ci cur_index++; 10355db71995Sopenharmony_ci break; 10365db71995Sopenharmony_ci } 10375db71995Sopenharmony_ci } 10385db71995Sopenharmony_ci } 10395db71995Sopenharmony_ci if (cur_index == 0) { 10405db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, 10415db71995Sopenharmony_ci "windows_sort_devices_in_group: Never encountered a device in the sorted list group"); 10425db71995Sopenharmony_ci } 10435db71995Sopenharmony_ci} 10445db71995Sopenharmony_ci 10455db71995Sopenharmony_ci// This function sorts an array in physical device groups based on the sorted physical device information 10465db71995Sopenharmony_ciVkResult windows_sort_physical_device_groups(struct loader_instance *inst, const uint32_t group_count, 10475db71995Sopenharmony_ci struct loader_physical_device_group_term *sorted_group_term, 10485db71995Sopenharmony_ci const uint32_t sorted_device_count, 10495db71995Sopenharmony_ci struct loader_icd_physical_devices *sorted_phys_dev_array) { 10505db71995Sopenharmony_ci if (0 == group_count || NULL == sorted_group_term) { 10515db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_WARN_BIT, 0, 10525db71995Sopenharmony_ci "windows_sort_physical_device_groups: Called with invalid information (Group count %d, Sorted Info %p)", 10535db71995Sopenharmony_ci group_count, sorted_group_term); 10545db71995Sopenharmony_ci return VK_ERROR_INITIALIZATION_FAILED; 10555db71995Sopenharmony_ci } 10565db71995Sopenharmony_ci 10575db71995Sopenharmony_ci uint32_t new_index = 0; 10585db71995Sopenharmony_ci for (uint32_t icd = 0; icd < sorted_device_count; ++icd) { 10595db71995Sopenharmony_ci for (uint32_t dev = 0; dev < sorted_phys_dev_array[icd].device_count; ++dev) { 10605db71995Sopenharmony_ci // Find a group associated with a given device 10615db71995Sopenharmony_ci for (uint32_t group = new_index; group < group_count; ++group) { 10625db71995Sopenharmony_ci bool device_found = false; 10635db71995Sopenharmony_ci // Look for the current sorted device in a group and put it in the correct location if it isn't already 10645db71995Sopenharmony_ci for (uint32_t grp_dev = 0; grp_dev < sorted_group_term[group].group_props.physicalDeviceCount; ++grp_dev) { 10655db71995Sopenharmony_ci if (sorted_group_term[group].group_props.physicalDevices[grp_dev] == 10665db71995Sopenharmony_ci sorted_phys_dev_array[icd].physical_devices[dev]) { 10675db71995Sopenharmony_ci // First, sort devices inside of group to be in priority order 10685db71995Sopenharmony_ci windows_sort_devices_in_group(inst, &sorted_group_term[group].group_props, &sorted_phys_dev_array[icd]); 10695db71995Sopenharmony_ci 10705db71995Sopenharmony_ci // Second, move the group up in priority if it needs to be 10715db71995Sopenharmony_ci if (new_index != group) { 10725db71995Sopenharmony_ci struct loader_physical_device_group_term tmp = sorted_group_term[new_index]; 10735db71995Sopenharmony_ci sorted_group_term[new_index] = sorted_group_term[group]; 10745db71995Sopenharmony_ci sorted_group_term[group] = tmp; 10755db71995Sopenharmony_ci } 10765db71995Sopenharmony_ci device_found = true; 10775db71995Sopenharmony_ci new_index++; 10785db71995Sopenharmony_ci break; 10795db71995Sopenharmony_ci } 10805db71995Sopenharmony_ci } 10815db71995Sopenharmony_ci if (device_found) { 10825db71995Sopenharmony_ci break; 10835db71995Sopenharmony_ci } 10845db71995Sopenharmony_ci } 10855db71995Sopenharmony_ci } 10865db71995Sopenharmony_ci } 10875db71995Sopenharmony_ci return VK_SUCCESS; 10885db71995Sopenharmony_ci} 10895db71995Sopenharmony_ci 10905db71995Sopenharmony_cichar *windows_get_app_package_manifest_path(const struct loader_instance *inst) { 10915db71995Sopenharmony_ci // These functions are only available on Windows 8 and above, load them dynamically for compatibility with Windows 7 10925db71995Sopenharmony_ci typedef LONG(WINAPI * PFN_GetPackagesByPackageFamily)(PCWSTR, UINT32 *, PWSTR *, UINT32 *, WCHAR *); 10935db71995Sopenharmony_ci PFN_GetPackagesByPackageFamily fpGetPackagesByPackageFamily = 10945db71995Sopenharmony_ci (PFN_GetPackagesByPackageFamily)(void *)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetPackagesByPackageFamily"); 10955db71995Sopenharmony_ci if (!fpGetPackagesByPackageFamily) { 10965db71995Sopenharmony_ci return NULL; 10975db71995Sopenharmony_ci } 10985db71995Sopenharmony_ci typedef LONG(WINAPI * PFN_GetPackagePathByFullName)(PCWSTR, UINT32 *, PWSTR); 10995db71995Sopenharmony_ci PFN_GetPackagePathByFullName fpGetPackagePathByFullName = 11005db71995Sopenharmony_ci (PFN_GetPackagePathByFullName)(void *)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetPackagePathByFullName"); 11015db71995Sopenharmony_ci if (!fpGetPackagePathByFullName) { 11025db71995Sopenharmony_ci return NULL; 11035db71995Sopenharmony_ci } 11045db71995Sopenharmony_ci 11055db71995Sopenharmony_ci UINT32 numPackages = 0, bufferLength = 0; 11065db71995Sopenharmony_ci /* This literal string identifies the Microsoft-published OpenCL and OpenGL Compatibility Pack 11075db71995Sopenharmony_ci * (so named at the time this is being added), which contains OpenGLOn12 and OpenCLOn12 mapping 11085db71995Sopenharmony_ci * layers, and will contain VulkanOn12 (aka Dozen) going forward. 11095db71995Sopenharmony_ci */ 11105db71995Sopenharmony_ci PCWSTR familyName = L"Microsoft.D3DMappingLayers_8wekyb3d8bbwe"; 11115db71995Sopenharmony_ci if (ERROR_INSUFFICIENT_BUFFER != fpGetPackagesByPackageFamily(familyName, &numPackages, NULL, &bufferLength, NULL) || 11125db71995Sopenharmony_ci numPackages == 0 || bufferLength == 0) { 11135db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_INFO_BIT, 0, 11145db71995Sopenharmony_ci "windows_get_app_package_manifest_path: Failed to find mapping layers packages by family name"); 11155db71995Sopenharmony_ci return NULL; 11165db71995Sopenharmony_ci } 11175db71995Sopenharmony_ci 11185db71995Sopenharmony_ci char *ret = NULL; 11195db71995Sopenharmony_ci WCHAR *buffer = loader_instance_heap_alloc(inst, sizeof(WCHAR) * bufferLength, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 11205db71995Sopenharmony_ci PWSTR *packages = loader_instance_heap_alloc(inst, sizeof(PWSTR) * numPackages, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 11215db71995Sopenharmony_ci if (!buffer || !packages) { 11225db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 11235db71995Sopenharmony_ci "windows_get_app_package_manifest_path: Failed to allocate memory for package names"); 11245db71995Sopenharmony_ci goto cleanup; 11255db71995Sopenharmony_ci } 11265db71995Sopenharmony_ci 11275db71995Sopenharmony_ci if (ERROR_SUCCESS != fpGetPackagesByPackageFamily(familyName, &numPackages, packages, &bufferLength, buffer)) { 11285db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 11295db71995Sopenharmony_ci "windows_get_app_package_manifest_path: Failed to mapping layers package full names"); 11305db71995Sopenharmony_ci goto cleanup; 11315db71995Sopenharmony_ci } 11325db71995Sopenharmony_ci 11335db71995Sopenharmony_ci UINT32 pathLength = 0; 11345db71995Sopenharmony_ci WCHAR path[MAX_PATH]; 11355db71995Sopenharmony_ci memset(path, 0, sizeof(path)); 11365db71995Sopenharmony_ci if (ERROR_INSUFFICIENT_BUFFER != fpGetPackagePathByFullName(packages[0], &pathLength, NULL) || pathLength > MAX_PATH || 11375db71995Sopenharmony_ci ERROR_SUCCESS != fpGetPackagePathByFullName(packages[0], &pathLength, path)) { 11385db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 11395db71995Sopenharmony_ci "windows_get_app_package_manifest_path: Failed to get mapping layers package path"); 11405db71995Sopenharmony_ci goto cleanup; 11415db71995Sopenharmony_ci } 11425db71995Sopenharmony_ci 11435db71995Sopenharmony_ci int narrowPathLength = WideCharToMultiByte(CP_ACP, 0, path, -1, NULL, 0, NULL, NULL); 11445db71995Sopenharmony_ci if (narrowPathLength == 0) { 11455db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, 11465db71995Sopenharmony_ci "windows_get_app_package_manifest_path: Failed to convert path from wide to narrow"); 11475db71995Sopenharmony_ci goto cleanup; 11485db71995Sopenharmony_ci } 11495db71995Sopenharmony_ci 11505db71995Sopenharmony_ci ret = loader_instance_heap_alloc(inst, narrowPathLength, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 11515db71995Sopenharmony_ci if (!ret) { 11525db71995Sopenharmony_ci loader_log(inst, VULKAN_LOADER_ERROR_BIT, 0, "windows_get_app_package_manifest_path: Failed to allocate path"); 11535db71995Sopenharmony_ci goto cleanup; 11545db71995Sopenharmony_ci } 11555db71995Sopenharmony_ci 11565db71995Sopenharmony_ci narrowPathLength = WideCharToMultiByte(CP_ACP, 0, path, -1, ret, narrowPathLength, NULL, NULL); 11575db71995Sopenharmony_ci assert((size_t)narrowPathLength == strlen(ret) + 1); 11585db71995Sopenharmony_ci 11595db71995Sopenharmony_cicleanup: 11605db71995Sopenharmony_ci loader_instance_heap_free(inst, buffer); 11615db71995Sopenharmony_ci loader_instance_heap_free(inst, packages); 11625db71995Sopenharmony_ci return ret; 11635db71995Sopenharmony_ci} 11645db71995Sopenharmony_ci 11655db71995Sopenharmony_ciVkResult get_settings_path_if_exists_in_registry_key(const struct loader_instance *inst, char **out_path, HKEY key) { 11665db71995Sopenharmony_ci VkResult result = VK_ERROR_INITIALIZATION_FAILED; 11675db71995Sopenharmony_ci 11685db71995Sopenharmony_ci char name[MAX_STRING_SIZE] = {0}; 11695db71995Sopenharmony_ci DWORD name_size = sizeof(name); 11705db71995Sopenharmony_ci 11715db71995Sopenharmony_ci *out_path = NULL; 11725db71995Sopenharmony_ci 11735db71995Sopenharmony_ci LONG rtn_value = ERROR_SUCCESS; 11745db71995Sopenharmony_ci for (DWORD idx = 0; rtn_value == ERROR_SUCCESS; idx++) { 11755db71995Sopenharmony_ci DWORD value = 0; 11765db71995Sopenharmony_ci DWORD value_size = sizeof(value); 11775db71995Sopenharmony_ci rtn_value = RegEnumValue(key, idx, name, &name_size, NULL, NULL, (LPBYTE)&value, &value_size); 11785db71995Sopenharmony_ci 11795db71995Sopenharmony_ci if (ERROR_SUCCESS != rtn_value) { 11805db71995Sopenharmony_ci break; 11815db71995Sopenharmony_ci } 11825db71995Sopenharmony_ci 11835db71995Sopenharmony_ci uint32_t start_of_path_filename = 0; 11845db71995Sopenharmony_ci for (uint32_t last_char = name_size; last_char > 0; last_char--) { 11855db71995Sopenharmony_ci if (name[last_char] == '\\') { 11865db71995Sopenharmony_ci start_of_path_filename = last_char + 1; 11875db71995Sopenharmony_ci break; 11885db71995Sopenharmony_ci } 11895db71995Sopenharmony_ci } 11905db71995Sopenharmony_ci 11915db71995Sopenharmony_ci // Make sure the path exists first 11925db71995Sopenharmony_ci if (*out_path && !loader_platform_file_exists(name)) { 11935db71995Sopenharmony_ci return VK_ERROR_INITIALIZATION_FAILED; 11945db71995Sopenharmony_ci } 11955db71995Sopenharmony_ci 11965db71995Sopenharmony_ci if (strcmp(VK_LOADER_SETTINGS_FILENAME, &(name[start_of_path_filename])) == 0) { 11975db71995Sopenharmony_ci *out_path = loader_instance_heap_calloc(inst, name_size + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 11985db71995Sopenharmony_ci if (*out_path == NULL) { 11995db71995Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 12005db71995Sopenharmony_ci } 12015db71995Sopenharmony_ci loader_strncpy(*out_path, name_size + 1, name, name_size); 12025db71995Sopenharmony_ci (*out_path)[name_size] = '\0'; 12035db71995Sopenharmony_ci result = VK_SUCCESS; 12045db71995Sopenharmony_ci break; 12055db71995Sopenharmony_ci } 12065db71995Sopenharmony_ci } 12075db71995Sopenharmony_ci 12085db71995Sopenharmony_ci return result; 12095db71995Sopenharmony_ci} 12105db71995Sopenharmony_ci 12115db71995Sopenharmony_ciVkResult windows_get_loader_settings_file_path(const struct loader_instance *inst, char **out_path) { 12125db71995Sopenharmony_ci VkResult result = VK_SUCCESS; 12135db71995Sopenharmony_ci DWORD access_flags = KEY_QUERY_VALUE; 12145db71995Sopenharmony_ci HKEY key = NULL; 12155db71995Sopenharmony_ci 12165db71995Sopenharmony_ci *out_path = NULL; 12175db71995Sopenharmony_ci 12185db71995Sopenharmony_ci // if we are running with admin privileges, only check HKEY_LOCAL_MACHINE. 12195db71995Sopenharmony_ci // Otherwise check HKEY_CURRENT_USER, and if nothing is there, look in HKEY_LOCAL_MACHINE 12205db71995Sopenharmony_ci 12215db71995Sopenharmony_ci if (is_high_integrity()) { 12225db71995Sopenharmony_ci LONG rtn_value = RegOpenKeyEx(HKEY_LOCAL_MACHINE, VK_SETTINGS_INFO_REGISTRY_LOC, 0, access_flags, &key); 12235db71995Sopenharmony_ci if (ERROR_SUCCESS != rtn_value) { 12245db71995Sopenharmony_ci result = VK_ERROR_FEATURE_NOT_PRESENT; 12255db71995Sopenharmony_ci goto out; 12265db71995Sopenharmony_ci } 12275db71995Sopenharmony_ci result = get_settings_path_if_exists_in_registry_key(inst, out_path, key); 12285db71995Sopenharmony_ci } else { 12295db71995Sopenharmony_ci LONG rtn_value = RegOpenKeyEx(HKEY_CURRENT_USER, VK_SETTINGS_INFO_REGISTRY_LOC, 0, access_flags, &key); 12305db71995Sopenharmony_ci if (ERROR_SUCCESS == rtn_value) { 12315db71995Sopenharmony_ci result = get_settings_path_if_exists_in_registry_key(inst, out_path, key); 12325db71995Sopenharmony_ci RegCloseKey(key); 12335db71995Sopenharmony_ci // Either we got OOM and *must* exit or we successfully found the settings file and can exit 12345db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY || result == VK_SUCCESS) { 12355db71995Sopenharmony_ci goto out; 12365db71995Sopenharmony_ci } 12375db71995Sopenharmony_ci } 12385db71995Sopenharmony_ci 12395db71995Sopenharmony_ci rtn_value = RegOpenKeyEx(HKEY_LOCAL_MACHINE, VK_SETTINGS_INFO_REGISTRY_LOC, 0, access_flags, &key); 12405db71995Sopenharmony_ci if (ERROR_SUCCESS != rtn_value) { 12415db71995Sopenharmony_ci result = VK_ERROR_FEATURE_NOT_PRESENT; 12425db71995Sopenharmony_ci goto out; 12435db71995Sopenharmony_ci } 12445db71995Sopenharmony_ci 12455db71995Sopenharmony_ci result = get_settings_path_if_exists_in_registry_key(inst, out_path, key); 12465db71995Sopenharmony_ci if (result == VK_ERROR_OUT_OF_HOST_MEMORY) { 12475db71995Sopenharmony_ci goto out; 12485db71995Sopenharmony_ci } 12495db71995Sopenharmony_ci } 12505db71995Sopenharmony_ci 12515db71995Sopenharmony_ciout: 12525db71995Sopenharmony_ci if (NULL != key) { 12535db71995Sopenharmony_ci RegCloseKey(key); 12545db71995Sopenharmony_ci } 12555db71995Sopenharmony_ci 12565db71995Sopenharmony_ci return result; 12575db71995Sopenharmony_ci} 12585db71995Sopenharmony_ci 12595db71995Sopenharmony_ci#endif // _WIN32 1260