Home | History | Annotate | Download | only in loader
      1 /*
      2  * Copyright (c) 2015-2017 The Khronos Group Inc.
      3  * Copyright (c) 2015-2017 Valve Corporation
      4  * Copyright (c) 2015-2017 LunarG, Inc.
      5  *
      6  * Licensed under the Apache License, Version 2.0 (the "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *     http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  *
     18  * Author: Mark Young <marky (at) lunarg.com>
     19  * Author: Lenny Komow <lenny (at) lunarg.com>
     20  */
     21 
     22 #define _GNU_SOURCE
     23 #include <stdio.h>
     24 #include <stdlib.h>
     25 #include <string.h>
     26 #include "vk_loader_platform.h"
     27 #include "loader.h"
     28 #include "vk_loader_extensions.h"
     29 #include <vulkan/vk_icd.h>
     30 #include "wsi.h"
     31 #include "debug_report.h"
     32 
     33 // ---- Manually added trampoline/terminator functions
     34 
     35 // These functions, for whatever reason, require more complex changes than
     36 // can easily be automatically generated.
     37 VkResult setupLoaderTrampPhysDevGroups(VkInstance instance);
     38 VkResult setupLoaderTermPhysDevGroups(struct loader_instance *inst);
     39 
     40 // ---- VK_KHX_device_group extension trampoline/terminators
     41 
     42 VKAPI_ATTR VkResult VKAPI_CALL EnumeratePhysicalDeviceGroupsKHX(
     43     VkInstance instance, uint32_t *pPhysicalDeviceGroupCount,
     44     VkPhysicalDeviceGroupPropertiesKHX *pPhysicalDeviceGroupProperties) {
     45     VkResult res = VK_SUCCESS;
     46     uint32_t count;
     47     uint32_t i;
     48     struct loader_instance *inst = NULL;
     49 
     50     loader_platform_thread_lock_mutex(&loader_lock);
     51 
     52     inst = loader_get_instance(instance);
     53     if (NULL == inst) {
     54         res = VK_ERROR_INITIALIZATION_FAILED;
     55         goto out;
     56     }
     57 
     58     if (NULL == pPhysicalDeviceGroupCount) {
     59         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
     60                    "vkEnumeratePhysicalDeviceGroupsKHX: Received NULL pointer for physical "
     61                    "device group count return value.");
     62         res = VK_ERROR_INITIALIZATION_FAILED;
     63         goto out;
     64     }
     65 
     66     VkResult setup_res = setupLoaderTrampPhysDevGroups(instance);
     67     if (VK_SUCCESS != setup_res) {
     68         res = setup_res;
     69         goto out;
     70     }
     71 
     72     count = inst->phys_dev_group_count_tramp;
     73 
     74     // Wrap the PhysDev object for loader usage, return wrapped objects
     75     if (NULL != pPhysicalDeviceGroupProperties) {
     76         if (inst->phys_dev_group_count_tramp > *pPhysicalDeviceGroupCount) {
     77             loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
     78                        "vkEnumeratePhysicalDeviceGroupsKHX: Trimming device group count down"
     79                        " by application request from %d to %d physical device groups",
     80                        inst->phys_dev_group_count_tramp, *pPhysicalDeviceGroupCount);
     81             count = *pPhysicalDeviceGroupCount;
     82             res = VK_INCOMPLETE;
     83         }
     84         for (i = 0; i < count; i++) {
     85             memcpy(&pPhysicalDeviceGroupProperties[i], inst->phys_dev_groups_tramp[i],
     86                    sizeof(VkPhysicalDeviceGroupPropertiesKHX));
     87         }
     88     }
     89 
     90     *pPhysicalDeviceGroupCount = count;
     91 
     92 out:
     93 
     94     loader_platform_thread_unlock_mutex(&loader_lock);
     95     return res;
     96 }
     97 
     98 VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDeviceGroupsKHX(
     99     VkInstance instance, uint32_t *pPhysicalDeviceGroupCount,
    100     VkPhysicalDeviceGroupPropertiesKHX *pPhysicalDeviceGroupProperties) {
    101     struct loader_instance *inst = (struct loader_instance *)instance;
    102     VkResult res = VK_SUCCESS;
    103 
    104     // Always call the setup loader terminator physical device groups because they may
    105     // have changed at any point.
    106     res = setupLoaderTermPhysDevGroups(inst);
    107     if (VK_SUCCESS != res) {
    108         goto out;
    109     }
    110 
    111     uint32_t copy_count = inst->phys_dev_group_count_term;
    112     if (NULL != pPhysicalDeviceGroupProperties) {
    113         if (copy_count > *pPhysicalDeviceGroupCount) {
    114             copy_count = *pPhysicalDeviceGroupCount;
    115             res = VK_INCOMPLETE;
    116         }
    117 
    118         for (uint32_t i = 0; i < copy_count; i++) {
    119             memcpy(&pPhysicalDeviceGroupProperties[i], inst->phys_dev_groups_term[i],
    120                    sizeof(VkPhysicalDeviceGroupPropertiesKHX));
    121         }
    122     }
    123 
    124     *pPhysicalDeviceGroupCount = copy_count;
    125 
    126 out:
    127 
    128     return res;
    129 }
    130 
    131 // ---- VK_NV_external_memory_capabilities extension trampoline/terminators
    132 
    133 VKAPI_ATTR VkResult VKAPI_CALL
    134 GetPhysicalDeviceExternalImageFormatPropertiesNV(
    135     VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
    136     VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags,
    137     VkExternalMemoryHandleTypeFlagsNV externalHandleType,
    138     VkExternalImageFormatPropertiesNV *pExternalImageFormatProperties) {
    139     const VkLayerInstanceDispatchTable *disp;
    140     VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
    141     disp = loader_get_instance_layer_dispatch(physicalDevice);
    142 
    143     return disp->GetPhysicalDeviceExternalImageFormatPropertiesNV(
    144         unwrapped_phys_dev, format, type, tiling, usage, flags,
    145         externalHandleType, pExternalImageFormatProperties);
    146 }
    147 
    148 VKAPI_ATTR VkResult VKAPI_CALL
    149 terminator_GetPhysicalDeviceExternalImageFormatPropertiesNV(
    150     VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
    151     VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags,
    152     VkExternalMemoryHandleTypeFlagsNV externalHandleType,
    153     VkExternalImageFormatPropertiesNV *pExternalImageFormatProperties) {
    154     struct loader_physical_device_term *phys_dev_term =
    155         (struct loader_physical_device_term *)physicalDevice;
    156     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
    157 
    158     if (!icd_term->dispatch.GetPhysicalDeviceExternalImageFormatPropertiesNV) {
    159         if (externalHandleType) {
    160             return VK_ERROR_FORMAT_NOT_SUPPORTED;
    161         }
    162 
    163         if (!icd_term->dispatch.GetPhysicalDeviceImageFormatProperties) {
    164             return VK_ERROR_INITIALIZATION_FAILED;
    165         }
    166 
    167         pExternalImageFormatProperties->externalMemoryFeatures = 0;
    168         pExternalImageFormatProperties->exportFromImportedHandleTypes = 0;
    169         pExternalImageFormatProperties->compatibleHandleTypes = 0;
    170 
    171         return icd_term->dispatch.GetPhysicalDeviceImageFormatProperties(
    172             phys_dev_term->phys_dev, format, type, tiling, usage, flags,
    173             &pExternalImageFormatProperties->imageFormatProperties);
    174     }
    175 
    176     return icd_term->dispatch.GetPhysicalDeviceExternalImageFormatPropertiesNV(
    177         phys_dev_term->phys_dev, format, type, tiling, usage, flags,
    178         externalHandleType, pExternalImageFormatProperties);
    179 }
    180 
    181 // ---- VK_KHR_get_physical_device_properties2 extension trampoline/terminators
    182 
    183 VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceFeatures2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2KHR *pFeatures) {
    184     const VkLayerInstanceDispatchTable *disp;
    185     VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
    186     disp = loader_get_instance_layer_dispatch(physicalDevice);
    187     disp->GetPhysicalDeviceFeatures2KHR(unwrapped_phys_dev, pFeatures);
    188 }
    189 
    190 VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFeatures2KHR(VkPhysicalDevice physicalDevice,
    191                                                                     VkPhysicalDeviceFeatures2KHR *pFeatures) {
    192     struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
    193     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
    194 
    195     if (icd_term->dispatch.GetPhysicalDeviceFeatures2KHR != NULL) {
    196         // Pass the call to the driver
    197         icd_term->dispatch.GetPhysicalDeviceFeatures2KHR(phys_dev_term->phys_dev, pFeatures);
    198     } else {
    199         // Emulate the call
    200         loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
    201                    "vkGetPhysicalDeviceFeatures2KHR: Emulating call in ICD \"%s\" using vkGetPhysicalDeviceFeatures",
    202                    icd_term->scanned_icd->lib_name);
    203 
    204         // Write to the VkPhysicalDeviceFeatures2KHR struct
    205         icd_term->dispatch.GetPhysicalDeviceFeatures(phys_dev_term->phys_dev, &pFeatures->features);
    206 
    207         void *pNext = pFeatures->pNext;
    208         while (pNext != NULL) {
    209             switch (*(VkStructureType *)pNext) {
    210                 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHX: {
    211                     // Skip the check if VK_KHX_multiview is enabled because it's a device extension
    212                     // Write to the VkPhysicalDeviceMultiviewFeaturesKHX struct
    213                     VkPhysicalDeviceMultiviewFeaturesKHX *multiview_features = pNext;
    214                     multiview_features->multiview = VK_FALSE;
    215                     multiview_features->multiviewGeometryShader = VK_FALSE;
    216                     multiview_features->multiviewTessellationShader = VK_FALSE;
    217 
    218                     pNext = multiview_features->pNext;
    219                     break;
    220                 }
    221                 default: {
    222                     loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
    223                                "vkGetPhysicalDeviceFeatures2KHR: Emulation found unrecognized structure type in pFeatures->pNext - "
    224                                "this struct will be ignored");
    225 
    226                     struct VkStructureHeader *header = pNext;
    227                     pNext = (void *)header->pNext;
    228                     break;
    229                 }
    230             }
    231         }
    232     }
    233 }
    234 
    235 VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceProperties2KHR(VkPhysicalDevice physicalDevice,
    236                                                            VkPhysicalDeviceProperties2KHR *pProperties) {
    237     const VkLayerInstanceDispatchTable *disp;
    238     VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
    239     disp = loader_get_instance_layer_dispatch(physicalDevice);
    240     disp->GetPhysicalDeviceProperties2KHR(unwrapped_phys_dev, pProperties);
    241 }
    242 
    243 VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceProperties2KHR(VkPhysicalDevice physicalDevice,
    244                                                                       VkPhysicalDeviceProperties2KHR *pProperties) {
    245     struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
    246     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
    247 
    248     if (icd_term->dispatch.GetPhysicalDeviceProperties2KHR != NULL) {
    249         // Pass the call to the driver
    250         icd_term->dispatch.GetPhysicalDeviceProperties2KHR(phys_dev_term->phys_dev, pProperties);
    251     } else {
    252         // Emulate the call
    253         loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
    254                    "vkGetPhysicalDeviceProperties2KHR: Emulating call in ICD \"%s\" using vkGetPhysicalDeviceProperties",
    255                    icd_term->scanned_icd->lib_name);
    256 
    257         // Write to the VkPhysicalDeviceProperties2KHR struct
    258         icd_term->dispatch.GetPhysicalDeviceProperties(phys_dev_term->phys_dev, &pProperties->properties);
    259 
    260         void *pNext = pProperties->pNext;
    261         while (pNext != NULL) {
    262             switch (*(VkStructureType *)pNext) {
    263                 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR: {
    264                     VkPhysicalDeviceIDPropertiesKHR *id_properties = pNext;
    265 
    266                     // Verify that "VK_KHR_external_memory_capabilities" is enabled
    267                     if (icd_term->this_instance->enabled_known_extensions.khr_external_memory_capabilities) {
    268                         loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
    269                                    "vkGetPhysicalDeviceProperties2KHR: Emulation cannot generate unique IDs for struct "
    270                                    "VkPhysicalDeviceIDPropertiesKHR - setting IDs to zero instead");
    271 
    272                         // Write to the VkPhysicalDeviceIDPropertiesKHR struct
    273                         memset(id_properties->deviceUUID, 0, VK_UUID_SIZE);
    274                         memset(id_properties->driverUUID, 0, VK_UUID_SIZE);
    275                         id_properties->deviceLUIDValid = VK_FALSE;
    276                     }
    277 
    278                     pNext = id_properties->pNext;
    279                     break;
    280                 }
    281                 default: {
    282                     loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
    283                                "vkGetPhysicalDeviceProperties2KHR: Emulation found unrecognized structure type in "
    284                                "pProperties->pNext - this struct will be ignored");
    285 
    286                     struct VkStructureHeader *header = pNext;
    287                     pNext = (void *)header->pNext;
    288                     break;
    289                 }
    290             }
    291         }
    292     }
    293 }
    294 
    295 VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceFormatProperties2KHR(VkPhysicalDevice physicalDevice, VkFormat format,
    296                                                                  VkFormatProperties2KHR *pFormatProperties) {
    297     const VkLayerInstanceDispatchTable *disp;
    298     VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
    299     disp = loader_get_instance_layer_dispatch(physicalDevice);
    300     disp->GetPhysicalDeviceFormatProperties2KHR(unwrapped_phys_dev, format, pFormatProperties);
    301 }
    302 
    303 VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFormatProperties2KHR(VkPhysicalDevice physicalDevice, VkFormat format,
    304                                                                             VkFormatProperties2KHR *pFormatProperties) {
    305     struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
    306     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
    307 
    308     if (icd_term->dispatch.GetPhysicalDeviceFormatProperties2KHR != NULL) {
    309         // Pass the call to the driver
    310         icd_term->dispatch.GetPhysicalDeviceFormatProperties2KHR(phys_dev_term->phys_dev, format, pFormatProperties);
    311     } else {
    312         // Emulate the call
    313         loader_log(
    314             icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
    315             "vkGetPhysicalDeviceFormatProperties2KHR: Emulating call in ICD \"%s\" using vkGetPhysicalDeviceFormatProperties",
    316             icd_term->scanned_icd->lib_name);
    317 
    318         // Write to the VkFormatProperties2KHR struct
    319         icd_term->dispatch.GetPhysicalDeviceFormatProperties(phys_dev_term->phys_dev, format, &pFormatProperties->formatProperties);
    320 
    321         if (pFormatProperties->pNext != NULL) {
    322             loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
    323                        "vkGetPhysicalDeviceFormatProperties2KHR: Emulation found unrecognized structure type in "
    324                        "pFormatProperties->pNext - this struct will be ignored");
    325         }
    326     }
    327 }
    328 
    329 VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceImageFormatProperties2KHR(
    330     VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2KHR *pImageFormatInfo,
    331     VkImageFormatProperties2KHR *pImageFormatProperties) {
    332     const VkLayerInstanceDispatchTable *disp;
    333     VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
    334     disp = loader_get_instance_layer_dispatch(physicalDevice);
    335     return disp->GetPhysicalDeviceImageFormatProperties2KHR(unwrapped_phys_dev, pImageFormatInfo, pImageFormatProperties);
    336 }
    337 
    338 VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceImageFormatProperties2KHR(
    339     VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2KHR *pImageFormatInfo,
    340     VkImageFormatProperties2KHR *pImageFormatProperties) {
    341     struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
    342     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
    343 
    344     if (icd_term->dispatch.GetPhysicalDeviceImageFormatProperties2KHR != NULL) {
    345         // Pass the call to the driver
    346         return icd_term->dispatch.GetPhysicalDeviceImageFormatProperties2KHR(phys_dev_term->phys_dev, pImageFormatInfo,
    347                                                                              pImageFormatProperties);
    348     } else {
    349         // Emulate the call
    350         loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
    351                    "vkGetPhysicalDeviceImageFormatProperties2KHR: Emulating call in ICD \"%s\" using "
    352                    "vkGetPhysicalDeviceImageFormatProperties",
    353                    icd_term->scanned_icd->lib_name);
    354 
    355         // If there is more info in  either pNext, then this is unsupported
    356         if (pImageFormatInfo->pNext != NULL || pImageFormatProperties->pNext != NULL) {
    357             return VK_ERROR_FORMAT_NOT_SUPPORTED;
    358         }
    359 
    360         // Write to the VkImageFormatProperties2KHR struct
    361         return icd_term->dispatch.GetPhysicalDeviceImageFormatProperties(
    362             phys_dev_term->phys_dev, pImageFormatInfo->format, pImageFormatInfo->type, pImageFormatInfo->tiling,
    363             pImageFormatInfo->usage, pImageFormatInfo->flags, &pImageFormatProperties->imageFormatProperties);
    364     }
    365 }
    366 
    367 VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice,
    368                                                                       uint32_t *pQueueFamilyPropertyCount,
    369                                                                       VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
    370     const VkLayerInstanceDispatchTable *disp;
    371     VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
    372     disp = loader_get_instance_layer_dispatch(physicalDevice);
    373     disp->GetPhysicalDeviceQueueFamilyProperties2KHR(unwrapped_phys_dev, pQueueFamilyPropertyCount, pQueueFamilyProperties);
    374 }
    375 
    376 VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceQueueFamilyProperties2KHR(
    377     VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties2KHR *pQueueFamilyProperties) {
    378     struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
    379     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
    380 
    381     if (icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties2KHR != NULL) {
    382         // Pass the call to the driver
    383         icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties2KHR(phys_dev_term->phys_dev, pQueueFamilyPropertyCount,
    384                                                                       pQueueFamilyProperties);
    385     } else {
    386         // Emulate the call
    387         loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
    388                    "vkGetPhysicalDeviceQueueFamilyProperties2KHR: Emulating call in ICD \"%s\" using "
    389                    "vkGetPhysicalDeviceQueueFamilyProperties",
    390                    icd_term->scanned_icd->lib_name);
    391 
    392         if (pQueueFamilyProperties == NULL || *pQueueFamilyPropertyCount == 0) {
    393             // Write to pQueueFamilyPropertyCount
    394             icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties(phys_dev_term->phys_dev, pQueueFamilyPropertyCount, NULL);
    395         } else {
    396             // Allocate a temporary array for the output of the old function
    397             VkQueueFamilyProperties *properties = loader_stack_alloc(*pQueueFamilyPropertyCount * sizeof(VkQueueFamilyProperties));
    398             if (properties == NULL) {
    399                 *pQueueFamilyPropertyCount = 0;
    400                 loader_log(
    401                     icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
    402                     "vkGetPhysicalDeviceQueueFamilyProperties2KHR: Out of memory - Failed to allocate array for loader emulation.");
    403                 return;
    404             }
    405 
    406             icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties(phys_dev_term->phys_dev, pQueueFamilyPropertyCount,
    407                                                                       properties);
    408             for (uint32_t i = 0; i < *pQueueFamilyPropertyCount; ++i) {
    409                 // Write to the VkQueueFamilyProperties2KHR struct
    410                 memcpy(&pQueueFamilyProperties[i].queueFamilyProperties, &properties[i], sizeof(VkQueueFamilyProperties));
    411 
    412                 if (pQueueFamilyProperties[i].pNext != NULL) {
    413                     loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
    414                                "vkGetPhysicalDeviceQueueFamilyProperties2KHR: Emulation found unrecognized structure type in "
    415                                "pQueueFamilyProperties[%d].pNext - this struct will be ignored",
    416                                i);
    417                 }
    418             }
    419         }
    420     }
    421 }
    422 
    423 VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceMemoryProperties2KHR(VkPhysicalDevice physicalDevice,
    424                                                                  VkPhysicalDeviceMemoryProperties2KHR *pMemoryProperties) {
    425     const VkLayerInstanceDispatchTable *disp;
    426     VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
    427     disp = loader_get_instance_layer_dispatch(physicalDevice);
    428     disp->GetPhysicalDeviceMemoryProperties2KHR(unwrapped_phys_dev, pMemoryProperties);
    429 }
    430 
    431 VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceMemoryProperties2KHR(
    432     VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2KHR *pMemoryProperties) {
    433     struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
    434     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
    435 
    436     if (icd_term->dispatch.GetPhysicalDeviceMemoryProperties2KHR != NULL) {
    437         // Pass the call to the driver
    438         icd_term->dispatch.GetPhysicalDeviceMemoryProperties2KHR(phys_dev_term->phys_dev, pMemoryProperties);
    439     } else {
    440         // Emulate the call
    441         loader_log(
    442             icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
    443             "vkGetPhysicalDeviceMemoryProperties2KHR: Emulating call in ICD \"%s\" using vkGetPhysicalDeviceMemoryProperties",
    444             icd_term->scanned_icd->lib_name);
    445 
    446         // Write to the VkPhysicalDeviceMemoryProperties2KHR struct
    447         icd_term->dispatch.GetPhysicalDeviceMemoryProperties(phys_dev_term->phys_dev, &pMemoryProperties->memoryProperties);
    448 
    449         if (pMemoryProperties->pNext != NULL) {
    450             loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
    451                        "vkGetPhysicalDeviceMemoryProperties2KHR: Emulation found unrecognized structure type in "
    452                        "pMemoryProperties->pNext - this struct will be ignored");
    453         }
    454     }
    455 }
    456 
    457 VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceSparseImageFormatProperties2KHR(
    458     VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2KHR *pFormatInfo, uint32_t *pPropertyCount,
    459     VkSparseImageFormatProperties2KHR *pProperties) {
    460     const VkLayerInstanceDispatchTable *disp;
    461     VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
    462     disp = loader_get_instance_layer_dispatch(physicalDevice);
    463     disp->GetPhysicalDeviceSparseImageFormatProperties2KHR(unwrapped_phys_dev, pFormatInfo, pPropertyCount, pProperties);
    464 }
    465 
    466 VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceSparseImageFormatProperties2KHR(
    467     VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2KHR *pFormatInfo, uint32_t *pPropertyCount,
    468     VkSparseImageFormatProperties2KHR *pProperties) {
    469     struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
    470     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
    471 
    472     if (icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties2KHR != NULL) {
    473         // Pass the call to the driver
    474         icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties2KHR(phys_dev_term->phys_dev, pFormatInfo, pPropertyCount,
    475                                                                             pProperties);
    476     } else {
    477         // Emulate the call
    478         loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
    479                    "vkGetPhysicalDeviceSparseImageFormatProperties2KHR: Emulating call in ICD \"%s\" using "
    480                    "vkGetPhysicalDeviceSparseImageFormatProperties",
    481                    icd_term->scanned_icd->lib_name);
    482 
    483         if (pFormatInfo->pNext != NULL) {
    484             loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
    485                        "vkGetPhysicalDeviceSparseImageFormatProperties2KHR: Emulation found unrecognized structure type in "
    486                        "pFormatInfo->pNext - this struct will be ignored");
    487         }
    488 
    489         if (pProperties == NULL || *pPropertyCount == 0) {
    490             // Write to pPropertyCount
    491             icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties(
    492                 phys_dev_term->phys_dev, pFormatInfo->format, pFormatInfo->type, pFormatInfo->samples, pFormatInfo->usage,
    493                 pFormatInfo->tiling, pPropertyCount, NULL);
    494         } else {
    495             // Allocate a temporary array for the output of the old function
    496             VkSparseImageFormatProperties *properties =
    497                 loader_stack_alloc(*pPropertyCount * sizeof(VkSparseImageMemoryRequirements));
    498             if (properties == NULL) {
    499                 *pPropertyCount = 0;
    500                 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
    501                            "vkGetPhysicalDeviceSparseImageFormatProperties2KHR: Out of memory - Failed to allocate array for "
    502                            "loader emulation.");
    503                 return;
    504             }
    505 
    506             icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties(
    507                 phys_dev_term->phys_dev, pFormatInfo->format, pFormatInfo->type, pFormatInfo->samples, pFormatInfo->usage,
    508                 pFormatInfo->tiling, pPropertyCount, properties);
    509             for (uint32_t i = 0; i < *pPropertyCount; ++i) {
    510                 // Write to the VkSparseImageFormatProperties2KHR struct
    511                 memcpy(&pProperties[i].properties, &properties[i], sizeof(VkSparseImageFormatProperties));
    512 
    513                 if (pProperties[i].pNext != NULL) {
    514                     loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
    515                                "vkGetPhysicalDeviceSparseImageFormatProperties2KHR: Emulation found unrecognized structure type in "
    516                                "pProperties[%d].pNext - this struct will be ignored",
    517                                i);
    518                 }
    519             }
    520         }
    521     }
    522 }
    523 
    524 // ---- VK_KHR_get_surface_capabilities2 extension trampoline/terminators
    525 
    526 VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice physicalDevice,
    527                                                                         const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
    528                                                                         VkSurfaceCapabilities2KHR *pSurfaceCapabilities) {
    529     const VkLayerInstanceDispatchTable *disp;
    530     VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
    531     disp = loader_get_instance_layer_dispatch(physicalDevice);
    532     return disp->GetPhysicalDeviceSurfaceCapabilities2KHR(unwrapped_phys_dev, pSurfaceInfo, pSurfaceCapabilities);
    533 }
    534 
    535 VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceSurfaceCapabilities2KHR(
    536     VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
    537     VkSurfaceCapabilities2KHR *pSurfaceCapabilities) {
    538     struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
    539     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
    540 
    541     VkIcdSurface *icd_surface = (VkIcdSurface *)(pSurfaceInfo->surface);
    542     uint8_t icd_index = phys_dev_term->icd_index;
    543 
    544     if (icd_term->dispatch.GetPhysicalDeviceSurfaceCapabilities2KHR != NULL) {
    545         // Pass the call to the driver, possibly unwrapping the ICD surface
    546         if (icd_surface->real_icd_surfaces != NULL && (void *)icd_surface->real_icd_surfaces[icd_index] != NULL) {
    547             VkPhysicalDeviceSurfaceInfo2KHR info_copy = *pSurfaceInfo;
    548             info_copy.surface = icd_surface->real_icd_surfaces[icd_index];
    549             return icd_term->dispatch.GetPhysicalDeviceSurfaceCapabilities2KHR(phys_dev_term->phys_dev, &info_copy,
    550                                                                                pSurfaceCapabilities);
    551         } else {
    552             return icd_term->dispatch.GetPhysicalDeviceSurfaceCapabilities2KHR(phys_dev_term->phys_dev, pSurfaceInfo,
    553                                                                                pSurfaceCapabilities);
    554         }
    555     } else {
    556         // Emulate the call
    557         loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
    558                    "vkGetPhysicalDeviceSurfaceCapabilities2KHR: Emulating call in ICD \"%s\" using "
    559                    "vkGetPhysicalDeviceSurfaceCapabilitiesKHR",
    560                    icd_term->scanned_icd->lib_name);
    561 
    562         if (pSurfaceInfo->pNext != NULL) {
    563             loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
    564                        "vkGetPhysicalDeviceSurfaceCapabilities2KHR: Emulation found unrecognized structure type in "
    565                        "pSurfaceInfo->pNext - this struct will be ignored");
    566         }
    567 
    568         // Write to the VkSurfaceCapabilities2KHR struct
    569         VkSurfaceKHR surface = pSurfaceInfo->surface;
    570         if (icd_surface->real_icd_surfaces != NULL && (void *)icd_surface->real_icd_surfaces[icd_index] != NULL) {
    571             surface = icd_surface->real_icd_surfaces[icd_index];
    572         }
    573         VkResult res = icd_term->dispatch.GetPhysicalDeviceSurfaceCapabilitiesKHR(phys_dev_term->phys_dev, surface,
    574                                                                                   &pSurfaceCapabilities->surfaceCapabilities);
    575 
    576         if (pSurfaceCapabilities->pNext != NULL) {
    577             loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
    578                        "vkGetPhysicalDeviceSurfaceCapabilities2KHR: Emulation found unrecognized structure type in "
    579                        "pSurfaceCapabilities->pNext - this struct will be ignored");
    580         }
    581         return res;
    582     }
    583 }
    584 
    585 VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice,
    586                                                                    const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
    587                                                                    uint32_t *pSurfaceFormatCount,
    588                                                                    VkSurfaceFormat2KHR *pSurfaceFormats) {
    589     const VkLayerInstanceDispatchTable *disp;
    590     VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
    591     disp = loader_get_instance_layer_dispatch(physicalDevice);
    592     return disp->GetPhysicalDeviceSurfaceFormats2KHR(unwrapped_phys_dev, pSurfaceInfo, pSurfaceFormatCount, pSurfaceFormats);
    593 }
    594 
    595 VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice,
    596                                                                               const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
    597                                                                               uint32_t *pSurfaceFormatCount,
    598                                                                               VkSurfaceFormat2KHR *pSurfaceFormats) {
    599     struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
    600     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
    601 
    602     VkIcdSurface *icd_surface = (VkIcdSurface *)(pSurfaceInfo->surface);
    603     uint8_t icd_index = phys_dev_term->icd_index;
    604 
    605     if (icd_term->dispatch.GetPhysicalDeviceSurfaceFormats2KHR != NULL) {
    606         // Pass the call to the driver, possibly unwrapping the ICD surface
    607         if (icd_surface->real_icd_surfaces != NULL && (void *)icd_surface->real_icd_surfaces[icd_index] != NULL) {
    608             VkPhysicalDeviceSurfaceInfo2KHR info_copy = *pSurfaceInfo;
    609             info_copy.surface = icd_surface->real_icd_surfaces[icd_index];
    610             return icd_term->dispatch.GetPhysicalDeviceSurfaceFormats2KHR(phys_dev_term->phys_dev, &info_copy, pSurfaceFormatCount,
    611                                                                           pSurfaceFormats);
    612         } else {
    613             return icd_term->dispatch.GetPhysicalDeviceSurfaceFormats2KHR(phys_dev_term->phys_dev, pSurfaceInfo,
    614                                                                           pSurfaceFormatCount, pSurfaceFormats);
    615         }
    616     } else {
    617         // Emulate the call
    618         loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
    619                    "vkGetPhysicalDeviceSurfaceFormats2KHR: Emulating call in ICD \"%s\" using vkGetPhysicalDeviceSurfaceFormatsKHR",
    620                    icd_term->scanned_icd->lib_name);
    621 
    622         if (pSurfaceInfo->pNext != NULL) {
    623             loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
    624                        "vkGetPhysicalDeviceSurfaceFormats2KHR: Emulation found unrecognized structure type in pSurfaceInfo->pNext "
    625                        "- this struct will be ignored");
    626         }
    627 
    628         VkSurfaceKHR surface = pSurfaceInfo->surface;
    629         if (icd_surface->real_icd_surfaces != NULL && (void *)icd_surface->real_icd_surfaces[icd_index] != NULL) {
    630             surface = icd_surface->real_icd_surfaces[icd_index];
    631         }
    632 
    633         if (*pSurfaceFormatCount == 0 || pSurfaceFormats == NULL) {
    634             // Write to pSurfaceFormatCount
    635             return icd_term->dispatch.GetPhysicalDeviceSurfaceFormatsKHR(phys_dev_term->phys_dev, surface, pSurfaceFormatCount,
    636                                                                          NULL);
    637         } else {
    638             // Allocate a temporary array for the output of the old function
    639             VkSurfaceFormatKHR *formats = loader_stack_alloc(*pSurfaceFormatCount * sizeof(VkSurfaceFormatKHR));
    640             if (formats == NULL) {
    641                 return VK_ERROR_OUT_OF_HOST_MEMORY;
    642             }
    643 
    644             VkResult res = icd_term->dispatch.GetPhysicalDeviceSurfaceFormatsKHR(phys_dev_term->phys_dev, surface,
    645                                                                                  pSurfaceFormatCount, formats);
    646             for (uint32_t i = 0; i < *pSurfaceFormatCount; ++i) {
    647                 pSurfaceFormats[i].surfaceFormat = formats[i];
    648                 if (pSurfaceFormats[i].pNext != NULL) {
    649                     loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
    650                                "vkGetPhysicalDeviceSurfaceFormats2KHR: Emulation found unrecognized structure type in "
    651                                "pSurfaceFormats[%d].pNext - this struct will be ignored",
    652                                i);
    653                 }
    654             }
    655             return res;
    656         }
    657     }
    658 }
    659 
    660 // ---- VK_EXT_display_surface_counter extension trampoline/terminators
    661 
    662 VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilities2EXT(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
    663                                                                         VkSurfaceCapabilities2EXT *pSurfaceCapabilities) {
    664     const VkLayerInstanceDispatchTable *disp;
    665     VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
    666     disp = loader_get_instance_layer_dispatch(physicalDevice);
    667     return disp->GetPhysicalDeviceSurfaceCapabilities2EXT(unwrapped_phys_dev, surface, pSurfaceCapabilities);
    668 }
    669 
    670 VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceSurfaceCapabilities2EXT(
    671     VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilities2EXT *pSurfaceCapabilities) {
    672     struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
    673     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
    674 
    675     VkIcdSurface *icd_surface = (VkIcdSurface *)(surface);
    676     uint8_t icd_index = phys_dev_term->icd_index;
    677 
    678     // Unwrap the surface if needed
    679     VkSurfaceKHR unwrapped_surface = surface;
    680     if (icd_surface->real_icd_surfaces != NULL && (void *)icd_surface->real_icd_surfaces[icd_index] != NULL) {
    681         unwrapped_surface = icd_surface->real_icd_surfaces[icd_index];
    682     }
    683 
    684     if (icd_term->dispatch.GetPhysicalDeviceSurfaceCapabilities2EXT != NULL) {
    685         // Pass the call to the driver
    686         return icd_term->dispatch.GetPhysicalDeviceSurfaceCapabilities2EXT(phys_dev_term->phys_dev, unwrapped_surface,
    687                                                                            pSurfaceCapabilities);
    688     } else {
    689         // Emulate the call
    690         loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
    691                    "vkGetPhysicalDeviceSurfaceCapabilities2EXT: Emulating call in ICD \"%s\" using "
    692                    "vkGetPhysicalDeviceSurfaceCapabilitiesKHR",
    693                    icd_term->scanned_icd->lib_name);
    694 
    695         VkSurfaceCapabilitiesKHR surface_caps;
    696         VkResult res =
    697             icd_term->dispatch.GetPhysicalDeviceSurfaceCapabilitiesKHR(phys_dev_term->phys_dev, unwrapped_surface, &surface_caps);
    698         pSurfaceCapabilities->minImageCount = surface_caps.minImageCount;
    699         pSurfaceCapabilities->maxImageCount = surface_caps.maxImageCount;
    700         pSurfaceCapabilities->currentExtent = surface_caps.currentExtent;
    701         pSurfaceCapabilities->minImageExtent = surface_caps.minImageExtent;
    702         pSurfaceCapabilities->maxImageExtent = surface_caps.maxImageExtent;
    703         pSurfaceCapabilities->maxImageArrayLayers = surface_caps.maxImageArrayLayers;
    704         pSurfaceCapabilities->supportedTransforms = surface_caps.supportedTransforms;
    705         pSurfaceCapabilities->currentTransform = surface_caps.currentTransform;
    706         pSurfaceCapabilities->supportedCompositeAlpha = surface_caps.supportedCompositeAlpha;
    707         pSurfaceCapabilities->supportedUsageFlags = surface_caps.supportedUsageFlags;
    708         pSurfaceCapabilities->supportedSurfaceCounters = 0;
    709 
    710         if (pSurfaceCapabilities->pNext != NULL) {
    711             loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
    712                        "vkGetPhysicalDeviceSurfaceCapabilities2EXT: Emulation found unrecognized structure type in "
    713                        "pSurfaceCapabilities->pNext - this struct will be ignored");
    714         }
    715 
    716         return res;
    717     }
    718 }
    719 
    720 // ---- VK_EXT_direct_mode_display extension trampoline/terminators
    721 
    722 VKAPI_ATTR VkResult VKAPI_CALL ReleaseDisplayEXT(VkPhysicalDevice physicalDevice, VkDisplayKHR display) {
    723     const VkLayerInstanceDispatchTable *disp;
    724     VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
    725     disp = loader_get_instance_layer_dispatch(physicalDevice);
    726     return disp->ReleaseDisplayEXT(unwrapped_phys_dev, display);
    727 }
    728 
    729 VKAPI_ATTR VkResult VKAPI_CALL terminator_ReleaseDisplayEXT(VkPhysicalDevice physicalDevice, VkDisplayKHR display) {
    730     struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
    731     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
    732 
    733     if (icd_term->dispatch.ReleaseDisplayEXT == NULL) {
    734         loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
    735                    "ICD \"%s\" associated with VkPhysicalDevice does not support vkReleaseDisplayEXT - Consequently, the call is "
    736                    "invalid because it should not be possible to acquire a display on this device",
    737                    icd_term->scanned_icd->lib_name);
    738     }
    739     return icd_term->dispatch.ReleaseDisplayEXT(phys_dev_term->phys_dev, display);
    740 }
    741 
    742 // ---- VK_EXT_acquire_xlib_display extension trampoline/terminators
    743 
    744 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
    745 VKAPI_ATTR VkResult VKAPI_CALL AcquireXlibDisplayEXT(VkPhysicalDevice physicalDevice, Display *dpy, VkDisplayKHR display) {
    746     const VkLayerInstanceDispatchTable *disp;
    747     VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
    748     disp = loader_get_instance_layer_dispatch(physicalDevice);
    749     return disp->AcquireXlibDisplayEXT(unwrapped_phys_dev, dpy, display);
    750 }
    751 
    752 VKAPI_ATTR VkResult VKAPI_CALL terminator_AcquireXlibDisplayEXT(VkPhysicalDevice physicalDevice, Display *dpy,
    753                                                                 VkDisplayKHR display) {
    754     struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
    755     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
    756 
    757     if (icd_term->dispatch.AcquireXlibDisplayEXT != NULL) {
    758         // Pass the call to the driver
    759         return icd_term->dispatch.AcquireXlibDisplayEXT(phys_dev_term->phys_dev, dpy, display);
    760     } else {
    761         // Emulate the call
    762         loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
    763                    "vkAcquireXLibDisplayEXT: Emulating call in ICD \"%s\" by returning error", icd_term->scanned_icd->lib_name);
    764 
    765         // Fail for the unsupported command
    766         return VK_ERROR_INITIALIZATION_FAILED;
    767     }
    768 }
    769 
    770 VKAPI_ATTR VkResult VKAPI_CALL GetRandROutputDisplayEXT(VkPhysicalDevice physicalDevice, Display *dpy, RROutput rrOutput,
    771                                                         VkDisplayKHR *pDisplay) {
    772     const VkLayerInstanceDispatchTable *disp;
    773     VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
    774     disp = loader_get_instance_layer_dispatch(physicalDevice);
    775     return disp->GetRandROutputDisplayEXT(unwrapped_phys_dev, dpy, rrOutput, pDisplay);
    776 }
    777 
    778 VKAPI_ATTR VkResult VKAPI_CALL terminator_GetRandROutputDisplayEXT(VkPhysicalDevice physicalDevice, Display *dpy, RROutput rrOutput,
    779                                                                    VkDisplayKHR *pDisplay) {
    780     struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
    781     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
    782 
    783     if (icd_term->dispatch.GetRandROutputDisplayEXT != NULL) {
    784         // Pass the call to the driver
    785         return icd_term->dispatch.GetRandROutputDisplayEXT(phys_dev_term->phys_dev, dpy, rrOutput, pDisplay);
    786     } else {
    787         // Emulate the call
    788         loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
    789                    "vkGetRandROutputDisplayEXT: Emulating call in ICD \"%s\" by returning null display",
    790                    icd_term->scanned_icd->lib_name);
    791 
    792         // Return a null handle to indicate this can't be done
    793         *pDisplay = VK_NULL_HANDLE;
    794         return VK_SUCCESS;
    795     }
    796 }
    797 
    798 #endif  // VK_USE_PLATFORM_XLIB_XRANDR_EXT
    799 
    800 // ---- VK_KHR_external_memory_capabilities extension trampoline/terminators
    801 
    802 VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceExternalBufferPropertiesKHR(
    803     VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfoKHR *pExternalBufferInfo,
    804     VkExternalBufferPropertiesKHR *pExternalBufferProperties) {
    805     const VkLayerInstanceDispatchTable *disp;
    806     VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
    807     disp = loader_get_instance_layer_dispatch(physicalDevice);
    808     disp->GetPhysicalDeviceExternalBufferPropertiesKHR(unwrapped_phys_dev, pExternalBufferInfo, pExternalBufferProperties);
    809 }
    810 
    811 VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceExternalBufferPropertiesKHR(
    812     VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfoKHR *pExternalBufferInfo,
    813     VkExternalBufferPropertiesKHR *pExternalBufferProperties) {
    814     struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
    815     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
    816 
    817     if (icd_term->dispatch.GetPhysicalDeviceExternalBufferPropertiesKHR) {
    818         // Pass the call to the driver
    819         icd_term->dispatch.GetPhysicalDeviceExternalBufferPropertiesKHR(phys_dev_term->phys_dev, pExternalBufferInfo,
    820                                                                         pExternalBufferProperties);
    821     } else {
    822         // Emulate the call
    823         loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
    824                    "vkGetPhysicalDeviceExternalBufferPropertiesKHR: Emulating call in ICD \"%s\"", icd_term->scanned_icd->lib_name);
    825 
    826         if (pExternalBufferInfo->pNext != NULL) {
    827             loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
    828                        "vkGetPhysicalDeviceExternalBufferPropertiesKHR: Emulation found unrecognized structure type in "
    829                        "pExternalBufferInfo->pNext - this struct will be ignored");
    830         }
    831 
    832         // Fill in everything being unsupported
    833         memset(&pExternalBufferProperties->externalMemoryProperties, 0, sizeof(VkExternalMemoryPropertiesKHR));
    834 
    835         if (pExternalBufferProperties->pNext != NULL) {
    836             loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
    837                        "vkGetPhysicalDeviceExternalBufferPropertiesKHR: Emulation found unrecognized structure type in "
    838                        "pExternalBufferProperties->pNext - this struct will be ignored");
    839         }
    840     }
    841 }
    842 
    843 // ---- VK_KHR_external_semaphore_capabilities extension trampoline/terminators
    844 
    845 VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceExternalSemaphorePropertiesKHR(
    846     VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfoKHR *pExternalSemaphoreInfo,
    847     VkExternalSemaphorePropertiesKHR *pExternalSemaphoreProperties) {
    848     const VkLayerInstanceDispatchTable *disp;
    849     VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
    850     disp = loader_get_instance_layer_dispatch(physicalDevice);
    851     disp->GetPhysicalDeviceExternalSemaphorePropertiesKHR(unwrapped_phys_dev, pExternalSemaphoreInfo, pExternalSemaphoreProperties);
    852 }
    853 
    854 VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceExternalSemaphorePropertiesKHR(
    855     VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfoKHR *pExternalSemaphoreInfo,
    856     VkExternalSemaphorePropertiesKHR *pExternalSemaphoreProperties) {
    857     struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
    858     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
    859 
    860     if (icd_term->dispatch.GetPhysicalDeviceExternalSemaphorePropertiesKHR != NULL) {
    861         // Pass the call to the driver
    862         icd_term->dispatch.GetPhysicalDeviceExternalSemaphorePropertiesKHR(phys_dev_term->phys_dev, pExternalSemaphoreInfo,
    863                                                                            pExternalSemaphoreProperties);
    864     } else {
    865         // Emulate the call
    866         loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
    867                    "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR: Emulating call in ICD \"%s\"",
    868                    icd_term->scanned_icd->lib_name);
    869 
    870         if (pExternalSemaphoreInfo->pNext != NULL) {
    871             loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
    872                        "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR: Emulation found unrecognized structure type in "
    873                        "pExternalSemaphoreInfo->pNext - this struct will be ignored");
    874         }
    875 
    876         // Fill in everything being unsupported
    877         pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
    878         pExternalSemaphoreProperties->compatibleHandleTypes = 0;
    879         pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
    880 
    881         if (pExternalSemaphoreProperties->pNext != NULL) {
    882             loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
    883                        "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR: Emulation found unrecognized structure type in "
    884                        "pExternalSemaphoreProperties->pNext - this struct will be ignored");
    885         }
    886     }
    887 }
    888 
    889 // ---- VK_KHR_external_fence_capabilities extension trampoline/terminators
    890 
    891 VKAPI_ATTR void VKAPI_CALL GetPhysicalDeviceExternalFencePropertiesKHR(
    892     VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfoKHR *pExternalFenceInfo,
    893     VkExternalFencePropertiesKHR *pExternalFenceProperties) {
    894     const VkLayerInstanceDispatchTable *disp;
    895     VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
    896     disp = loader_get_instance_layer_dispatch(physicalDevice);
    897     disp->GetPhysicalDeviceExternalFencePropertiesKHR(unwrapped_phys_dev, pExternalFenceInfo, pExternalFenceProperties);
    898 }
    899 
    900 VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceExternalFencePropertiesKHR(
    901     VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfoKHR *pExternalFenceInfo,
    902     VkExternalFencePropertiesKHR *pExternalFenceProperties) {
    903     struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
    904     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
    905 
    906     if (icd_term->dispatch.GetPhysicalDeviceExternalFencePropertiesKHR != NULL) {
    907         // Pass the call to the driver
    908         icd_term->dispatch.GetPhysicalDeviceExternalFencePropertiesKHR(phys_dev_term->phys_dev, pExternalFenceInfo,
    909                                                                        pExternalFenceProperties);
    910     } else {
    911         // Emulate the call
    912         loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
    913                    "vkGetPhysicalDeviceExternalFencePropertiesKHR: Emulating call in ICD \"%s\"", icd_term->scanned_icd->lib_name);
    914 
    915         if (pExternalFenceInfo->pNext != NULL) {
    916             loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
    917                        "vkGetPhysicalDeviceExternalFencePropertiesKHR: Emulation found unrecognized structure type in "
    918                        "pExternalFenceInfo->pNext - this struct will be ignored");
    919         }
    920 
    921         // Fill in everything being unsupported
    922         pExternalFenceProperties->exportFromImportedHandleTypes = 0;
    923         pExternalFenceProperties->compatibleHandleTypes = 0;
    924         pExternalFenceProperties->externalFenceFeatures = 0;
    925 
    926         if (pExternalFenceProperties->pNext != NULL) {
    927             loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
    928                        "vkGetPhysicalDeviceExternalFencePropertiesKHR: Emulation found unrecognized structure type in "
    929                        "pExternalFenceProperties->pNext - this struct will be ignored");
    930         }
    931     }
    932 }
    933 
    934 // ---- Helper functions
    935 
    936 VkResult setupLoaderTrampPhysDevGroups(VkInstance instance) {
    937     VkResult res = VK_SUCCESS;
    938     struct loader_instance *inst;
    939     uint32_t total_count = 0;
    940     VkPhysicalDeviceGroupPropertiesKHX **new_phys_dev_groups = NULL;
    941     VkPhysicalDeviceGroupPropertiesKHX *local_phys_dev_groups = NULL;
    942 
    943     inst = loader_get_instance(instance);
    944     if (NULL == inst) {
    945         res = VK_ERROR_INITIALIZATION_FAILED;
    946         goto out;
    947     }
    948 
    949     // Setup the trampoline loader physical devices.  This will actually
    950     // call down and setup the terminator loader physical devices during the
    951     // process.
    952     VkResult setup_res = setupLoaderTrampPhysDevs(instance);
    953     if (setup_res != VK_SUCCESS && setup_res != VK_INCOMPLETE) {
    954         res = setup_res;
    955         goto out;
    956     }
    957 
    958     // Query how many physical device groups there
    959     res = inst->disp->layer_inst_disp.EnumeratePhysicalDeviceGroupsKHX(instance, &total_count, NULL);
    960     if (res != VK_SUCCESS) {
    961         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
    962                    "setupLoaderTrampPhysDevGroups:  Failed during dispatch call of "
    963                    "\'EnumeratePhysicalDeviceGroupsKHX\' to lower layers or "
    964                    "loader to get count.");
    965         goto out;
    966     }
    967 
    968     // Create an array for the new physical device groups, which will be stored
    969     // in the instance for the trampoline code.
    970     new_phys_dev_groups = (VkPhysicalDeviceGroupPropertiesKHX **)loader_instance_heap_alloc(
    971         inst, total_count * sizeof(VkPhysicalDeviceGroupPropertiesKHX *), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
    972     if (NULL == new_phys_dev_groups) {
    973         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
    974                    "setupLoaderTrampPhysDevGroups:  Failed to allocate new physical device"
    975                    " group array of size %d",
    976                    total_count);
    977         res = VK_ERROR_OUT_OF_HOST_MEMORY;
    978         goto out;
    979     }
    980     memset(new_phys_dev_groups, 0, total_count * sizeof(VkPhysicalDeviceGroupPropertiesKHX *));
    981 
    982     // Create a temporary array (on the stack) to keep track of the
    983     // returned VkPhysicalDevice values.
    984     local_phys_dev_groups = loader_stack_alloc(sizeof(VkPhysicalDeviceGroupPropertiesKHX) * total_count);
    985     if (NULL == local_phys_dev_groups) {
    986         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
    987                    "setupLoaderTrampPhysDevGroups:  Failed to allocate local "
    988                    "physical device group array of size %d",
    989                    total_count);
    990         res = VK_ERROR_OUT_OF_HOST_MEMORY;
    991         goto out;
    992     }
    993     // Initialize the memory to something valid
    994     memset(local_phys_dev_groups, 0, sizeof(VkPhysicalDeviceGroupPropertiesKHX) * total_count);
    995     for (uint32_t group = 0; group < total_count; group++) {
    996         local_phys_dev_groups[group].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHX;
    997         local_phys_dev_groups[group].pNext = NULL;
    998         local_phys_dev_groups[group].subsetAllocation = false;
    999     }
   1000 
   1001     // Call down and get the content
   1002     res = inst->disp->layer_inst_disp.EnumeratePhysicalDeviceGroupsKHX(instance, &total_count, local_phys_dev_groups);
   1003     if (VK_SUCCESS != res) {
   1004         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
   1005                    "setupLoaderTrampPhysDevGroups:  Failed during dispatch call of "
   1006                    "\'EnumeratePhysicalDeviceGroupsKHX\' to lower layers or "
   1007                    "loader to get content.");
   1008         goto out;
   1009     }
   1010 
   1011     // Replace all the physical device IDs with the proper loader values
   1012     for (uint32_t group = 0; group < total_count; group++) {
   1013         for (uint32_t group_gpu = 0; group_gpu < local_phys_dev_groups[group].physicalDeviceCount; group_gpu++) {
   1014             bool found = false;
   1015             for (uint32_t tramp_gpu = 0; tramp_gpu < inst->phys_dev_count_tramp; tramp_gpu++) {
   1016                 if (local_phys_dev_groups[group].physicalDevices[group_gpu] == inst->phys_devs_tramp[tramp_gpu]->phys_dev) {
   1017                     local_phys_dev_groups[group].physicalDevices[group_gpu] = (VkPhysicalDevice)inst->phys_devs_tramp[tramp_gpu];
   1018                     found = true;
   1019                     break;
   1020                 }
   1021             }
   1022             if (!found) {
   1023                 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
   1024                            "setupLoaderTrampPhysDevGroups:  Failed to find GPU %d in group %d"
   1025                            " returned by \'EnumeratePhysicalDeviceGroupsKHX\' in list returned"
   1026                            " by \'EnumeratePhysicalDevices\'", group_gpu, group);
   1027                 res = VK_ERROR_INITIALIZATION_FAILED;
   1028                 goto out;
   1029             }
   1030         }
   1031     }
   1032 
   1033     // Copy or create everything to fill the new array of physical device groups
   1034     for (uint32_t new_idx = 0; new_idx < total_count; new_idx++) {
   1035         // Check if this physical device group with the same contents is already in the old buffer
   1036         for (uint32_t old_idx = 0; old_idx < inst->phys_dev_group_count_tramp; old_idx++) {
   1037             if (local_phys_dev_groups[new_idx].physicalDeviceCount == inst->phys_dev_groups_tramp[old_idx]->physicalDeviceCount) {
   1038                 bool found_all_gpus = true;
   1039                 for (uint32_t old_gpu = 0; old_gpu < inst->phys_dev_groups_tramp[old_idx]->physicalDeviceCount; old_gpu++) {
   1040                     bool found_gpu = false;
   1041                     for (uint32_t new_gpu = 0; new_gpu < local_phys_dev_groups[new_idx].physicalDeviceCount; new_gpu++) {
   1042                         if (local_phys_dev_groups[new_idx].physicalDevices[new_gpu] == inst->phys_dev_groups_tramp[old_idx]->physicalDevices[old_gpu]) {
   1043                             found_gpu = true;
   1044                             break;
   1045                         }
   1046                     }
   1047 
   1048                     if (!found_gpu) {
   1049                         found_all_gpus = false;
   1050                         break;
   1051                     }
   1052                 }
   1053                 if (!found_all_gpus) {
   1054                     continue;
   1055                 } else {
   1056                     new_phys_dev_groups[new_idx] = inst->phys_dev_groups_tramp[old_idx];
   1057                     break;
   1058                 }
   1059             }
   1060         }
   1061 
   1062         // If this physical device group isn't in the old buffer, create it
   1063         if (NULL == new_phys_dev_groups[new_idx]) {
   1064             new_phys_dev_groups[new_idx] = (VkPhysicalDeviceGroupPropertiesKHX *)loader_instance_heap_alloc(
   1065                 inst, sizeof(VkPhysicalDeviceGroupPropertiesKHX), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
   1066             if (NULL == new_phys_dev_groups[new_idx]) {
   1067                 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
   1068                            "setupLoaderTrampPhysDevGroups:  Failed to allocate "
   1069                            "physical device group trampoline object %d",
   1070                            new_idx);
   1071                 total_count = new_idx;
   1072                 res = VK_ERROR_OUT_OF_HOST_MEMORY;
   1073                 goto out;
   1074             }
   1075             memcpy(new_phys_dev_groups[new_idx], &local_phys_dev_groups[new_idx],
   1076                    sizeof(VkPhysicalDeviceGroupPropertiesKHX));
   1077         }
   1078     }
   1079 
   1080 out:
   1081 
   1082     if (VK_SUCCESS != res) {
   1083         if (NULL != new_phys_dev_groups) {
   1084             for (uint32_t i = 0; i < total_count; i++) {
   1085                 loader_instance_heap_free(inst, new_phys_dev_groups[i]);
   1086             }
   1087             loader_instance_heap_free(inst, new_phys_dev_groups);
   1088         }
   1089         total_count = 0;
   1090     } else {
   1091         // Free everything that didn't carry over to the new array of
   1092         // physical device groups
   1093         if (NULL != inst->phys_dev_groups_tramp) {
   1094             for (uint32_t i = 0; i < inst->phys_dev_group_count_tramp; i++) {
   1095                 bool found = false;
   1096                 for (uint32_t j = 0; j < total_count; j++) {
   1097                     if (inst->phys_dev_groups_tramp[i] == new_phys_dev_groups[j]) {
   1098                         found = true;
   1099                         break;
   1100                     }
   1101                 }
   1102                 if (!found) {
   1103                     loader_instance_heap_free(inst, inst->phys_dev_groups_tramp[i]);
   1104                 }
   1105             }
   1106             loader_instance_heap_free(inst, inst->phys_dev_groups_tramp);
   1107         }
   1108 
   1109         // Swap in the new physical device group list
   1110         inst->phys_dev_group_count_tramp = total_count;
   1111         inst->phys_dev_groups_tramp = new_phys_dev_groups;
   1112     }
   1113 
   1114     return res;
   1115 }
   1116 
   1117 VkResult setupLoaderTermPhysDevGroups(struct loader_instance *inst) {
   1118     VkResult res = VK_SUCCESS;
   1119     struct loader_icd_term *icd_term;
   1120     uint32_t total_count = 0;
   1121     uint32_t cur_icd_group_count = 0;
   1122     VkPhysicalDeviceGroupPropertiesKHX **new_phys_dev_groups = NULL;
   1123     VkPhysicalDeviceGroupPropertiesKHX *local_phys_dev_groups = NULL;
   1124 
   1125     if (0 == inst->phys_dev_count_term) {
   1126         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
   1127                    "setupLoaderTermPhysDevGroups:  Loader failed to setup physical "
   1128                    "device terminator info before calling \'EnumeratePhysicalDeviceGroupsKHX\'.");
   1129         assert(false);
   1130         res = VK_ERROR_INITIALIZATION_FAILED;
   1131         goto out;
   1132     }
   1133 
   1134     // For each ICD, query the number of physical device groups, and then get an
   1135     // internal value for those physical devices.
   1136     icd_term = inst->icd_terms;
   1137     for (uint32_t icd_idx = 0; NULL != icd_term; icd_term = icd_term->next, icd_idx++) {
   1138         cur_icd_group_count = 0;
   1139         if (NULL == icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHX) {
   1140             // Treat each ICD's GPU as it's own group if the extension isn't supported
   1141             res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &cur_icd_group_count, NULL);
   1142             if (res != VK_SUCCESS) {
   1143                 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
   1144                            "setupLoaderTermPhysDevGroups:  Failed during dispatch call of "
   1145                            "\'EnumeratePhysicalDevices\' to ICD %d to get plain phys dev count.",
   1146                            icd_idx);
   1147                 goto out;
   1148             }
   1149         } else {
   1150             // Query the actual group info
   1151             res = icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHX(icd_term->instance, &cur_icd_group_count, NULL);
   1152             if (res != VK_SUCCESS) {
   1153                 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
   1154                            "setupLoaderTermPhysDevGroups:  Failed during dispatch call of "
   1155                            "\'EnumeratePhysicalDeviceGroupsKHX\' to ICD %d to get count.",
   1156                            icd_idx);
   1157                 goto out;
   1158             }
   1159         }
   1160         total_count += cur_icd_group_count;
   1161     }
   1162 
   1163     // Create an array for the new physical device groups, which will be stored
   1164     // in the instance for the Terminator code.
   1165     new_phys_dev_groups = (VkPhysicalDeviceGroupPropertiesKHX **)loader_instance_heap_alloc(
   1166         inst, total_count * sizeof(VkPhysicalDeviceGroupPropertiesKHX *), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
   1167     if (NULL == new_phys_dev_groups) {
   1168         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
   1169                    "setupLoaderTermPhysDevGroups:  Failed to allocate new physical device"
   1170                    " group array of size %d",
   1171                    total_count);
   1172         res = VK_ERROR_OUT_OF_HOST_MEMORY;
   1173         goto out;
   1174     }
   1175     memset(new_phys_dev_groups, 0, total_count * sizeof(VkPhysicalDeviceGroupPropertiesKHX *));
   1176 
   1177     // Create a temporary array (on the stack) to keep track of the
   1178     // returned VkPhysicalDevice values.
   1179     local_phys_dev_groups = loader_stack_alloc(sizeof(VkPhysicalDeviceGroupPropertiesKHX) * total_count);
   1180     if (NULL == local_phys_dev_groups) {
   1181         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
   1182                    "setupLoaderTermPhysDevGroups:  Failed to allocate local "
   1183                    "physical device group array of size %d",
   1184                    total_count);
   1185         res = VK_ERROR_OUT_OF_HOST_MEMORY;
   1186         goto out;
   1187     }
   1188     // Initialize the memory to something valid
   1189     memset(local_phys_dev_groups, 0, sizeof(VkPhysicalDeviceGroupPropertiesKHX) * total_count);
   1190     for (uint32_t group = 0; group < total_count; group++) {
   1191         local_phys_dev_groups[group].sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHX;
   1192         local_phys_dev_groups[group].pNext = NULL;
   1193         local_phys_dev_groups[group].subsetAllocation = false;
   1194     }
   1195 
   1196     cur_icd_group_count = 0;
   1197     icd_term = inst->icd_terms;
   1198     for (uint32_t icd_idx = 0; NULL != icd_term; icd_term = icd_term->next, icd_idx++) {
   1199         uint32_t count_this_time = total_count - cur_icd_group_count;
   1200 
   1201         if (NULL == icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHX) {
   1202             VkPhysicalDevice* phys_dev_array = loader_stack_alloc(sizeof(VkPhysicalDevice) * count_this_time);
   1203             if (NULL == phys_dev_array) {
   1204                 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
   1205                            "setupLoaderTermPhysDevGroups:  Failed to allocate local "
   1206                            "physical device array of size %d",
   1207                            count_this_time);
   1208                 res = VK_ERROR_OUT_OF_HOST_MEMORY;
   1209                 goto out;
   1210             }
   1211 
   1212             res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &count_this_time, phys_dev_array);
   1213             if (res != VK_SUCCESS) {
   1214                 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
   1215                            "setupLoaderTermPhysDevGroups:  Failed during dispatch call of "
   1216                            "\'EnumeratePhysicalDevices\' to ICD %d to get plain phys dev count.",
   1217                            icd_idx);
   1218                 goto out;
   1219             }
   1220 
   1221             // Add each GPU as it's own group
   1222             for (uint32_t indiv_gpu = 0; indiv_gpu < count_this_time; indiv_gpu++) {
   1223                 local_phys_dev_groups[indiv_gpu + cur_icd_group_count].physicalDeviceCount = 1;
   1224                 local_phys_dev_groups[indiv_gpu + cur_icd_group_count].physicalDevices[0] = phys_dev_array[indiv_gpu];
   1225             }
   1226 
   1227         } else {
   1228             res = icd_term->dispatch.EnumeratePhysicalDeviceGroupsKHX(icd_term->instance, &count_this_time, &local_phys_dev_groups[cur_icd_group_count]);
   1229             if (VK_SUCCESS != res) {
   1230                 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
   1231                            "setupLoaderTermPhysDevGroups:  Failed during dispatch call of "
   1232                            "\'EnumeratePhysicalDeviceGroupsKHX\' to ICD %d to get content.",
   1233                            icd_idx);
   1234                 goto out;
   1235             }
   1236         }
   1237 
   1238         cur_icd_group_count += count_this_time;
   1239     }
   1240 
   1241     // Replace all the physical device IDs with the proper loader values
   1242     for (uint32_t group = 0; group < total_count; group++) {
   1243         for (uint32_t group_gpu = 0; group_gpu < local_phys_dev_groups[group].physicalDeviceCount; group_gpu++) {
   1244             bool found = false;
   1245             for (uint32_t term_gpu = 0; term_gpu < inst->phys_dev_count_term; term_gpu++) {
   1246                 if (local_phys_dev_groups[group].physicalDevices[group_gpu] == inst->phys_devs_term[term_gpu]->phys_dev) {
   1247                     local_phys_dev_groups[group].physicalDevices[group_gpu] = (VkPhysicalDevice)inst->phys_devs_term[term_gpu];
   1248                     found = true;
   1249                     break;
   1250                 }
   1251             }
   1252             if (!found) {
   1253                 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
   1254                            "setupLoaderTermPhysDevGroups:  Failed to find GPU %d in group %d"
   1255                            " returned by \'EnumeratePhysicalDeviceGroupsKHX\' in list returned"
   1256                            " by \'EnumeratePhysicalDevices\'", group_gpu, group);
   1257                 res = VK_ERROR_INITIALIZATION_FAILED;
   1258                 goto out;
   1259             }
   1260         }
   1261     }
   1262 
   1263     // Copy or create everything to fill the new array of physical device groups
   1264     for (uint32_t new_idx = 0; new_idx < total_count; new_idx++) {
   1265         // Check if this physical device group with the same contents is already in the old buffer
   1266         for (uint32_t old_idx = 0; old_idx < inst->phys_dev_group_count_term; old_idx++) {
   1267             if (local_phys_dev_groups[new_idx].physicalDeviceCount == inst->phys_dev_groups_term[old_idx]->physicalDeviceCount) {
   1268                 bool found_all_gpus = true;
   1269                 for (uint32_t old_gpu = 0; old_gpu < inst->phys_dev_groups_term[old_idx]->physicalDeviceCount; old_gpu++) {
   1270                     bool found_gpu = false;
   1271                     for (uint32_t new_gpu = 0; new_gpu < local_phys_dev_groups[new_idx].physicalDeviceCount; new_gpu++) {
   1272                         if (local_phys_dev_groups[new_idx].physicalDevices[new_gpu] == inst->phys_dev_groups_term[old_idx]->physicalDevices[old_gpu]) {
   1273                             found_gpu = true;
   1274                             break;
   1275                         }
   1276                     }
   1277 
   1278                     if (!found_gpu) {
   1279                         found_all_gpus = false;
   1280                         break;
   1281                     }
   1282                 }
   1283                 if (!found_all_gpus) {
   1284                     continue;
   1285                 } else {
   1286                     new_phys_dev_groups[new_idx] = inst->phys_dev_groups_term[old_idx];
   1287                     break;
   1288                 }
   1289             }
   1290         }
   1291 
   1292         // If this physical device group isn't in the old buffer, create it
   1293         if (NULL == new_phys_dev_groups[new_idx]) {
   1294             new_phys_dev_groups[new_idx] = (VkPhysicalDeviceGroupPropertiesKHX *)loader_instance_heap_alloc(
   1295                 inst, sizeof(VkPhysicalDeviceGroupPropertiesKHX), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
   1296             if (NULL == new_phys_dev_groups[new_idx]) {
   1297                 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
   1298                            "setupLoaderTermPhysDevGroups:  Failed to allocate "
   1299                            "physical device group Terminator object %d",
   1300                            new_idx);
   1301                 total_count = new_idx;
   1302                 res = VK_ERROR_OUT_OF_HOST_MEMORY;
   1303                 goto out;
   1304             }
   1305             memcpy(new_phys_dev_groups[new_idx], &local_phys_dev_groups[new_idx],
   1306                    sizeof(VkPhysicalDeviceGroupPropertiesKHX));
   1307         }
   1308     }
   1309 
   1310 out:
   1311 
   1312     if (VK_SUCCESS != res) {
   1313         if (NULL != new_phys_dev_groups) {
   1314             for (uint32_t i = 0; i < total_count; i++) {
   1315                 loader_instance_heap_free(inst, new_phys_dev_groups[i]);
   1316             }
   1317             loader_instance_heap_free(inst, new_phys_dev_groups);
   1318         }
   1319         total_count = 0;
   1320     } else {
   1321         // Free everything that didn't carry over to the new array of
   1322         // physical device groups
   1323         if (NULL != inst->phys_dev_groups_term) {
   1324             for (uint32_t i = 0; i < inst->phys_dev_group_count_term; i++) {
   1325                 bool found = false;
   1326                 for (uint32_t j = 0; j < total_count; j++) {
   1327                     if (inst->phys_dev_groups_term[i] == new_phys_dev_groups[j]) {
   1328                         found = true;
   1329                         break;
   1330                     }
   1331                 }
   1332                 if (!found) {
   1333                     loader_instance_heap_free(inst, inst->phys_dev_groups_term[i]);
   1334                 }
   1335             }
   1336             loader_instance_heap_free(inst, inst->phys_dev_groups_term);
   1337         }
   1338 
   1339         // Swap in the new physical device group list
   1340         inst->phys_dev_group_count_term = total_count;
   1341         inst->phys_dev_groups_term = new_phys_dev_groups;
   1342     }
   1343 
   1344     return res;
   1345 }
   1346