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@lunarg.com>
19  * Author: Lenny Komow <lenny@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