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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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