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.
37VkResult setupLoaderTrampPhysDevGroups(VkInstance instance);
38VkResult setupLoaderTermPhysDevGroups(struct loader_instance *inst);
39
40// ---- VK_KHX_device_group extension trampoline/terminators
41
42VKAPI_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
92out:
93
94    loader_platform_thread_unlock_mutex(&loader_lock);
95    return res;
96}
97
98VKAPI_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
126out:
127
128    return res;
129}
130
131// ---- VK_NV_external_memory_capabilities extension trampoline/terminators
132
133VKAPI_ATTR VkResult VKAPI_CALL
134GetPhysicalDeviceExternalImageFormatPropertiesNV(
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
148VKAPI_ATTR VkResult VKAPI_CALL
149terminator_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
183VKAPI_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
190VKAPI_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
235VKAPI_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
243VKAPI_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
295VKAPI_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
303VKAPI_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
329VKAPI_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
338VKAPI_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
367VKAPI_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
376VKAPI_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
423VKAPI_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
431VKAPI_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
457VKAPI_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
466VKAPI_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
526VKAPI_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
535VKAPI_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
585VKAPI_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
595VKAPI_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
662VKAPI_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
670VKAPI_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
722VKAPI_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
729VKAPI_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
745VKAPI_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
752VKAPI_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
770VKAPI_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
778VKAPI_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
802VKAPI_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
811VKAPI_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
845VKAPI_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
854VKAPI_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
891VKAPI_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
900VKAPI_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
936VkResult 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
1080out:
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
1117VkResult 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
1310out:
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