1/*
2 * Copyright (c) 2015-2022 The Khronos Group Inc.
3 * Copyright (c) 2015-2022 Valve Corporation
4 * Copyright (c) 2015-2022 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 * Author: Charles Giessen <charles@lunarg.com>
21 */
22
23#include "extension_manual.h"
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28
29#include "allocation.h"
30#include "debug_utils.h"
31#include "loader.h"
32#include "log.h"
33#include "wsi.h"
34
35// ---- Manually added trampoline/terminator functions
36
37// These functions, for whatever reason, require more complex changes than
38// can easily be automatically generated.
39
40// ---- VK_NV_external_memory_capabilities extension trampoline/terminators
41
42VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceExternalImageFormatPropertiesNV(
43    VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage,
44    VkImageCreateFlags flags, VkExternalMemoryHandleTypeFlagsNV externalHandleType,
45    VkExternalImageFormatPropertiesNV *pExternalImageFormatProperties) {
46    const VkLayerInstanceDispatchTable *disp;
47    VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
48    if (VK_NULL_HANDLE == unwrapped_phys_dev) {
49        loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
50                   "vkGetPhysicalDeviceExternalImageFormatPropertiesNV: Invalid physicalDevice "
51                   "[VUID-vkGetPhysicalDeviceExternalImageFormatPropertiesNV-physicalDevice-parameter]");
52        abort(); /* Intentionally fail so user can correct issue. */
53    }
54    disp = loader_get_instance_layer_dispatch(physicalDevice);
55
56    return disp->GetPhysicalDeviceExternalImageFormatPropertiesNV(unwrapped_phys_dev, format, type, tiling, usage, flags,
57                                                                  externalHandleType, pExternalImageFormatProperties);
58}
59
60VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceExternalImageFormatPropertiesNV(
61    VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage,
62    VkImageCreateFlags flags, VkExternalMemoryHandleTypeFlagsNV externalHandleType,
63    VkExternalImageFormatPropertiesNV *pExternalImageFormatProperties) {
64    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
65    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
66
67    if (!icd_term->dispatch.GetPhysicalDeviceExternalImageFormatPropertiesNV) {
68        if (externalHandleType) {
69            return VK_ERROR_FORMAT_NOT_SUPPORTED;
70        }
71
72        if (!icd_term->dispatch.GetPhysicalDeviceImageFormatProperties) {
73            return VK_ERROR_INITIALIZATION_FAILED;
74        }
75
76        pExternalImageFormatProperties->externalMemoryFeatures = 0;
77        pExternalImageFormatProperties->exportFromImportedHandleTypes = 0;
78        pExternalImageFormatProperties->compatibleHandleTypes = 0;
79
80        return icd_term->dispatch.GetPhysicalDeviceImageFormatProperties(
81            phys_dev_term->phys_dev, format, type, tiling, usage, flags, &pExternalImageFormatProperties->imageFormatProperties);
82    }
83
84    return icd_term->dispatch.GetPhysicalDeviceExternalImageFormatPropertiesNV(
85        phys_dev_term->phys_dev, format, type, tiling, usage, flags, externalHandleType, pExternalImageFormatProperties);
86}
87
88// ---- VK_EXT_display_surface_counter extension trampoline/terminators
89
90VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceCapabilities2EXT(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
91                                                                        VkSurfaceCapabilities2EXT *pSurfaceCapabilities) {
92    const VkLayerInstanceDispatchTable *disp;
93    VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
94    if (VK_NULL_HANDLE == unwrapped_phys_dev) {
95        loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
96                   "vkGetPhysicalDeviceExternalImageFormatPropertiesNV: Invalid physicalDevice "
97                   "[VUID-vkGetPhysicalDeviceSurfaceCapabilities2EXT-physicalDevice-parameter]");
98        abort(); /* Intentionally fail so user can correct issue. */
99    }
100    disp = loader_get_instance_layer_dispatch(physicalDevice);
101    return disp->GetPhysicalDeviceSurfaceCapabilities2EXT(unwrapped_phys_dev, surface, pSurfaceCapabilities);
102}
103
104VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceSurfaceCapabilities2EXT(
105    VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilities2EXT *pSurfaceCapabilities) {
106    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
107    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
108
109    VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)(surface);
110    uint8_t icd_index = phys_dev_term->icd_index;
111
112    // Unwrap the surface if needed
113    VkSurfaceKHR unwrapped_surface = surface;
114    if (NULL != icd_surface->real_icd_surfaces && NULL != (void *)(uintptr_t)(icd_surface->real_icd_surfaces[icd_index])) {
115        unwrapped_surface = icd_surface->real_icd_surfaces[icd_index];
116    }
117
118    if (NULL != icd_term->dispatch.GetPhysicalDeviceSurfaceCapabilities2EXT) {
119        // Pass the call to the driver
120        return icd_term->dispatch.GetPhysicalDeviceSurfaceCapabilities2EXT(phys_dev_term->phys_dev, unwrapped_surface,
121                                                                           pSurfaceCapabilities);
122    } else {
123        // Emulate the call
124        loader_log(icd_term->this_instance, VULKAN_LOADER_INFO_BIT, 0,
125                   "vkGetPhysicalDeviceSurfaceCapabilities2EXT: Emulating call in ICD \"%s\" using "
126                   "vkGetPhysicalDeviceSurfaceCapabilitiesKHR",
127                   icd_term->scanned_icd->lib_name);
128
129        VkSurfaceCapabilitiesKHR surface_caps;
130        VkResult res =
131            icd_term->dispatch.GetPhysicalDeviceSurfaceCapabilitiesKHR(phys_dev_term->phys_dev, unwrapped_surface, &surface_caps);
132        pSurfaceCapabilities->minImageCount = surface_caps.minImageCount;
133        pSurfaceCapabilities->maxImageCount = surface_caps.maxImageCount;
134        pSurfaceCapabilities->currentExtent = surface_caps.currentExtent;
135        pSurfaceCapabilities->minImageExtent = surface_caps.minImageExtent;
136        pSurfaceCapabilities->maxImageExtent = surface_caps.maxImageExtent;
137        pSurfaceCapabilities->maxImageArrayLayers = surface_caps.maxImageArrayLayers;
138        pSurfaceCapabilities->supportedTransforms = surface_caps.supportedTransforms;
139        pSurfaceCapabilities->currentTransform = surface_caps.currentTransform;
140        pSurfaceCapabilities->supportedCompositeAlpha = surface_caps.supportedCompositeAlpha;
141        pSurfaceCapabilities->supportedUsageFlags = surface_caps.supportedUsageFlags;
142        pSurfaceCapabilities->supportedSurfaceCounters = 0;
143
144        if (pSurfaceCapabilities->pNext != NULL) {
145            loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0,
146                       "vkGetPhysicalDeviceSurfaceCapabilities2EXT: Emulation found unrecognized structure type in "
147                       "pSurfaceCapabilities->pNext - this struct will be ignored");
148        }
149
150        return res;
151    }
152}
153
154// ---- VK_EXT_direct_mode_display extension trampoline/terminators
155
156VKAPI_ATTR VkResult VKAPI_CALL ReleaseDisplayEXT(VkPhysicalDevice physicalDevice, VkDisplayKHR display) {
157    const VkLayerInstanceDispatchTable *disp;
158    VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
159    if (VK_NULL_HANDLE == unwrapped_phys_dev) {
160        loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
161                   "vkReleaseDisplayEXT: Invalid physicalDevice [VUID-vkReleaseDisplayEXT-physicalDevice-parameter]");
162        abort(); /* Intentionally fail so user can correct issue. */
163    }
164    disp = loader_get_instance_layer_dispatch(physicalDevice);
165    return disp->ReleaseDisplayEXT(unwrapped_phys_dev, display);
166}
167
168VKAPI_ATTR VkResult VKAPI_CALL terminator_ReleaseDisplayEXT(VkPhysicalDevice physicalDevice, VkDisplayKHR display) {
169    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
170    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
171
172    if (icd_term->dispatch.ReleaseDisplayEXT == NULL) {
173        loader_log(icd_term->this_instance, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT, 0,
174                   "ICD \"%s\" associated with VkPhysicalDevice does not support vkReleaseDisplayEXT - Consequently, the call is "
175                   "invalid because it should not be possible to acquire a display on this device",
176                   icd_term->scanned_icd->lib_name);
177        abort();
178    }
179    return icd_term->dispatch.ReleaseDisplayEXT(phys_dev_term->phys_dev, display);
180}
181
182// ---- VK_EXT_acquire_xlib_display extension trampoline/terminators
183
184#if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT)
185VKAPI_ATTR VkResult VKAPI_CALL AcquireXlibDisplayEXT(VkPhysicalDevice physicalDevice, Display *dpy, VkDisplayKHR display) {
186    const VkLayerInstanceDispatchTable *disp;
187    VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
188    if (VK_NULL_HANDLE == unwrapped_phys_dev) {
189        loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
190                   "vkAcquireXlibDisplayEXT: Invalid physicalDevice [VUID-vkAcquireXlibDisplayEXT-physicalDevice-parameter]");
191        abort(); /* Intentionally fail so user can correct issue. */
192    }
193    disp = loader_get_instance_layer_dispatch(physicalDevice);
194    return disp->AcquireXlibDisplayEXT(unwrapped_phys_dev, dpy, display);
195}
196
197VKAPI_ATTR VkResult VKAPI_CALL terminator_AcquireXlibDisplayEXT(VkPhysicalDevice physicalDevice, Display *dpy,
198                                                                VkDisplayKHR display) {
199    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
200    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
201
202    if (icd_term->dispatch.AcquireXlibDisplayEXT != NULL) {
203        // Pass the call to the driver
204        return icd_term->dispatch.AcquireXlibDisplayEXT(phys_dev_term->phys_dev, dpy, display);
205    } else {
206        // Emulate the call
207        loader_log(icd_term->this_instance, VULKAN_LOADER_INFO_BIT, 0,
208                   "vkAcquireXLibDisplayEXT: Emulating call in ICD \"%s\" by returning error", icd_term->scanned_icd->lib_name);
209
210        // Fail for the unsupported command
211        return VK_ERROR_INITIALIZATION_FAILED;
212    }
213}
214
215VKAPI_ATTR VkResult VKAPI_CALL GetRandROutputDisplayEXT(VkPhysicalDevice physicalDevice, Display *dpy, RROutput rrOutput,
216                                                        VkDisplayKHR *pDisplay) {
217    const VkLayerInstanceDispatchTable *disp;
218    VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
219    if (VK_NULL_HANDLE == unwrapped_phys_dev) {
220        loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
221                   "vkGetRandROutputDisplayEXT: Invalid physicalDevice [VUID-vkGetRandROutputDisplayEXT-physicalDevice-parameter]");
222        abort(); /* Intentionally fail so user can correct issue. */
223    }
224    disp = loader_get_instance_layer_dispatch(physicalDevice);
225    return disp->GetRandROutputDisplayEXT(unwrapped_phys_dev, dpy, rrOutput, pDisplay);
226}
227
228VKAPI_ATTR VkResult VKAPI_CALL terminator_GetRandROutputDisplayEXT(VkPhysicalDevice physicalDevice, Display *dpy, RROutput rrOutput,
229                                                                   VkDisplayKHR *pDisplay) {
230    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
231    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
232
233    if (icd_term->dispatch.GetRandROutputDisplayEXT != NULL) {
234        // Pass the call to the driver
235        return icd_term->dispatch.GetRandROutputDisplayEXT(phys_dev_term->phys_dev, dpy, rrOutput, pDisplay);
236    } else {
237        // Emulate the call
238        loader_log(icd_term->this_instance, VULKAN_LOADER_INFO_BIT, 0,
239                   "vkGetRandROutputDisplayEXT: Emulating call in ICD \"%s\" by returning null display",
240                   icd_term->scanned_icd->lib_name);
241
242        // Return a null handle to indicate this can't be done
243        *pDisplay = VK_NULL_HANDLE;
244        return VK_SUCCESS;
245    }
246}
247
248#endif  // VK_USE_PLATFORM_XLIB_XRANDR_EXT
249
250#if defined(VK_USE_PLATFORM_WIN32_KHR)
251VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfacePresentModes2EXT(VkPhysicalDevice physicalDevice,
252                                                                        const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
253                                                                        uint32_t *pPresentModeCount,
254                                                                        VkPresentModeKHR *pPresentModes) {
255    const VkLayerInstanceDispatchTable *disp;
256    VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
257    if (VK_NULL_HANDLE == unwrapped_phys_dev) {
258        loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
259                   "vkGetPhysicalDeviceSurfacePresentModes2EXT: Invalid physicalDevice "
260                   "[VUID-vkGetPhysicalDeviceSurfacePresentModes2EXT-physicalDevice-parameter]");
261        abort(); /* Intentionally fail so user can correct issue. */
262    }
263    disp = loader_get_instance_layer_dispatch(physicalDevice);
264    return disp->GetPhysicalDeviceSurfacePresentModes2EXT(unwrapped_phys_dev, pSurfaceInfo, pPresentModeCount, pPresentModes);
265}
266
267VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceSurfacePresentModes2EXT(
268    VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, uint32_t *pPresentModeCount,
269    VkPresentModeKHR *pPresentModes) {
270    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
271    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
272    if (NULL == icd_term->dispatch.GetPhysicalDeviceSurfacePresentModes2EXT) {
273        loader_log(icd_term->this_instance, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT, 0,
274                   "ICD associated with VkPhysicalDevice does not support GetPhysicalDeviceSurfacePresentModes2EXT");
275        abort();
276    }
277    VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)(pSurfaceInfo->surface);
278    uint8_t icd_index = phys_dev_term->icd_index;
279    if (NULL != icd_surface->real_icd_surfaces && NULL != (void *)(uintptr_t)icd_surface->real_icd_surfaces[icd_index]) {
280        VkPhysicalDeviceSurfaceInfo2KHR surface_info_copy;
281        surface_info_copy.sType = pSurfaceInfo->sType;
282        surface_info_copy.pNext = pSurfaceInfo->pNext;
283        surface_info_copy.surface = icd_surface->real_icd_surfaces[icd_index];
284        return icd_term->dispatch.GetPhysicalDeviceSurfacePresentModes2EXT(phys_dev_term->phys_dev, &surface_info_copy,
285                                                                           pPresentModeCount, pPresentModes);
286    }
287    return icd_term->dispatch.GetPhysicalDeviceSurfacePresentModes2EXT(phys_dev_term->phys_dev, pSurfaceInfo, pPresentModeCount,
288                                                                       pPresentModes);
289}
290
291VKAPI_ATTR VkResult VKAPI_CALL GetDeviceGroupSurfacePresentModes2EXT(VkDevice device,
292                                                                     const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
293                                                                     VkDeviceGroupPresentModeFlagsKHR *pModes) {
294    const VkLayerDispatchTable *disp = loader_get_dispatch(device);
295    if (NULL == disp) {
296        loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
297                   "vkGetDeviceGroupSurfacePresentModes2EXT: Invalid device "
298                   "[VUID-vkGetDeviceGroupSurfacePresentModes2EXT-device-parameter]");
299        abort(); /* Intentionally fail so user can correct issue. */
300    }
301    return disp->GetDeviceGroupSurfacePresentModes2EXT(device, pSurfaceInfo, pModes);
302}
303
304VKAPI_ATTR VkResult VKAPI_CALL terminator_GetDeviceGroupSurfacePresentModes2EXT(VkDevice device,
305                                                                                const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
306                                                                                VkDeviceGroupPresentModeFlagsKHR *pModes) {
307    uint32_t icd_index = 0;
308    struct loader_device *dev;
309    struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, &icd_index);
310    if (NULL == icd_term || NULL == dev ||
311        NULL == dev->loader_dispatch.extension_terminator_dispatch.GetDeviceGroupSurfacePresentModes2EXT) {
312        loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
313                   "vkGetDeviceGroupSurfacePresentModes2EXT Terminator: Invalid device handle. This is likely the result of a "
314                   "layer wrapping device handles and failing to unwrap them in all functions. "
315                   "[VUID-vkGetDeviceGroupSurfacePresentModes2EXT-device-parameter]");
316        abort(); /* Intentionally fail so user can correct issue. */
317    }
318    if (NULL == pSurfaceInfo) {
319        loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
320                   "vkGetDeviceGroupSurfacePresentModes2EXT: Invalid pSurfaceInfo pointer "
321                   "[VUID-vkGetDeviceGroupSurfacePresentModes2EXT-pSurfaceInfo-parameter]");
322        abort(); /* Intentionally fail so user can correct issue. */
323    }
324    VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pSurfaceInfo->surface;
325    if (NULL != icd_surface->real_icd_surfaces && NULL != (void *)(uintptr_t)icd_surface->real_icd_surfaces[icd_index]) {
326        VkPhysicalDeviceSurfaceInfo2KHR surface_info_copy;
327        surface_info_copy.sType = pSurfaceInfo->sType;
328        surface_info_copy.pNext = pSurfaceInfo->pNext;
329        surface_info_copy.surface = icd_surface->real_icd_surfaces[icd_index];
330        return dev->loader_dispatch.extension_terminator_dispatch.GetDeviceGroupSurfacePresentModes2EXT(device, &surface_info_copy,
331                                                                                                        pModes);
332    }
333    return dev->loader_dispatch.extension_terminator_dispatch.GetDeviceGroupSurfacePresentModes2EXT(device, pSurfaceInfo, pModes);
334}
335
336#endif  // VK_USE_PLATFORM_WIN32_KHR
337
338// ---- VK_EXT_tooling_info extension trampoline/terminators
339
340VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceToolPropertiesEXT(VkPhysicalDevice physicalDevice, uint32_t *pToolCount,
341                                                                  VkPhysicalDeviceToolPropertiesEXT *pToolProperties) {
342    const VkLayerInstanceDispatchTable *disp;
343    VkPhysicalDevice unwrapped_phys_dev = loader_unwrap_physical_device(physicalDevice);
344    if (VK_NULL_HANDLE == unwrapped_phys_dev) {
345        loader_log(NULL, VULKAN_LOADER_FATAL_ERROR_BIT | VULKAN_LOADER_ERROR_BIT | VULKAN_LOADER_VALIDATION_BIT, 0,
346                   "vkGetPhysicalDeviceToolPropertiesEXT: Invalid physicalDevice "
347                   "[VUID-vkGetPhysicalDeviceToolPropertiesEXT-physicalDevice-parameter]");
348        abort(); /* Intentionally fail so user can correct issue. */
349    }
350    disp = loader_get_instance_layer_dispatch(physicalDevice);
351    return disp->GetPhysicalDeviceToolPropertiesEXT(unwrapped_phys_dev, pToolCount, pToolProperties);
352}
353
354VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceToolPropertiesEXT(VkPhysicalDevice physicalDevice, uint32_t *pToolCount,
355                                                                             VkPhysicalDeviceToolPropertiesEXT *pToolProperties) {
356    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
357    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
358
359    bool tooling_info_supported = false;
360    uint32_t ext_count = 0;
361    VkExtensionProperties *ext_props = NULL;
362    VkResult res = VK_SUCCESS;
363    VkResult enumerate_res = VK_SUCCESS;
364
365    enumerate_res = icd_term->dispatch.EnumerateDeviceExtensionProperties(phys_dev_term->phys_dev, NULL, &ext_count, NULL);
366    if (enumerate_res != VK_SUCCESS) {
367        goto out;
368    }
369
370    ext_props = loader_instance_heap_alloc(icd_term->this_instance, sizeof(VkExtensionProperties) * ext_count,
371                                           VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
372    if (!ext_props) {
373        res = VK_ERROR_OUT_OF_HOST_MEMORY;
374        goto out;
375    }
376
377    enumerate_res = icd_term->dispatch.EnumerateDeviceExtensionProperties(phys_dev_term->phys_dev, NULL, &ext_count, ext_props);
378    if (enumerate_res != VK_SUCCESS) {
379        goto out;
380    }
381
382    for (uint32_t i = 0; i < ext_count; i++) {
383        if (strncmp(ext_props[i].extensionName, VK_EXT_TOOLING_INFO_EXTENSION_NAME, VK_MAX_EXTENSION_NAME_SIZE) == 0) {
384            tooling_info_supported = true;
385            break;
386        }
387    }
388
389    if (tooling_info_supported && icd_term->dispatch.GetPhysicalDeviceToolPropertiesEXT) {
390        res = icd_term->dispatch.GetPhysicalDeviceToolPropertiesEXT(phys_dev_term->phys_dev, pToolCount, pToolProperties);
391    }
392
393out:
394    // In the case the driver didn't support the extension, make sure that the first layer doesn't find the count uninitialized
395    if (!tooling_info_supported || !icd_term->dispatch.GetPhysicalDeviceToolPropertiesEXT) {
396        *pToolCount = 0;
397    }
398
399    loader_instance_heap_free(icd_term->this_instance, ext_props);
400
401    return res;
402}
403