1/*
2 *
3 * Copyright (c) 2014-2021 The Khronos Group Inc.
4 * Copyright (c) 2014-2021 Valve Corporation
5 * Copyright (c) 2014-2021 LunarG, Inc.
6 * Copyright (C) 2015 Google Inc.
7 * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
8 * Copyright (c) 2023-2023 RasterGrid Kft.
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 *     http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21
22 *
23 * Author: Jon Ashburn <jon@lunarg.com>
24 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
25 * Author: Mark Young <marky@lunarg.com>
26 * Author: Lenny Komow <lenny@lunarg.com>
27 * Author: Charles Giessen <charles@lunarg.com>
28 *
29 */
30
31// Terminators which have simple logic belong here, since they are mostly "pass through"
32// Function declarations are in vk_loader_extensions.h, thus not needed here
33
34#include "allocation.h"
35#include "loader_common.h"
36#include "loader.h"
37#include "log.h"
38
39// Terminators for 1.0 functions
40
41VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
42                                                                  VkPhysicalDeviceProperties *pProperties) {
43    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
44    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
45    if (NULL != icd_term->dispatch.GetPhysicalDeviceProperties) {
46        icd_term->dispatch.GetPhysicalDeviceProperties(phys_dev_term->phys_dev, pProperties);
47    }
48}
49
50VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice,
51                                                                             uint32_t *pQueueFamilyPropertyCount,
52                                                                             VkQueueFamilyProperties *pProperties) {
53    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
54    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
55    if (NULL != icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties) {
56        icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties(phys_dev_term->phys_dev, pQueueFamilyPropertyCount, pProperties);
57    }
58}
59
60VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice,
61                                                                        VkPhysicalDeviceMemoryProperties *pProperties) {
62    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
63    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
64    if (NULL != icd_term->dispatch.GetPhysicalDeviceMemoryProperties) {
65        icd_term->dispatch.GetPhysicalDeviceMemoryProperties(phys_dev_term->phys_dev, pProperties);
66    }
67}
68
69VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice,
70                                                                VkPhysicalDeviceFeatures *pFeatures) {
71    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
72    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
73    if (NULL != icd_term->dispatch.GetPhysicalDeviceFeatures) {
74        icd_term->dispatch.GetPhysicalDeviceFeatures(phys_dev_term->phys_dev, pFeatures);
75    }
76}
77
78VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format,
79                                                                        VkFormatProperties *pFormatInfo) {
80    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
81    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
82    if (NULL != icd_term->dispatch.GetPhysicalDeviceFormatProperties) {
83        icd_term->dispatch.GetPhysicalDeviceFormatProperties(phys_dev_term->phys_dev, format, pFormatInfo);
84    }
85}
86
87VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format,
88                                                                                 VkImageType type, VkImageTiling tiling,
89                                                                                 VkImageUsageFlags usage, VkImageCreateFlags flags,
90                                                                                 VkImageFormatProperties *pImageFormatProperties) {
91    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
92    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
93    if (NULL == icd_term->dispatch.GetPhysicalDeviceImageFormatProperties) {
94        loader_log(
95            icd_term->this_instance, VULKAN_LOADER_ERROR_BIT, 0,
96            "The icd's vkGetPhysicalDeviceImageFormatProperties was null, returning with VK_ERROR_INITIALIZATION_FAILED instead.");
97        return VK_ERROR_INITIALIZATION_FAILED;
98    }
99    return icd_term->dispatch.GetPhysicalDeviceImageFormatProperties(phys_dev_term->phys_dev, format, type, tiling, usage, flags,
100                                                                     pImageFormatProperties);
101}
102
103VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format,
104                                                                                   VkImageType type, VkSampleCountFlagBits samples,
105                                                                                   VkImageUsageFlags usage, VkImageTiling tiling,
106                                                                                   uint32_t *pNumProperties,
107                                                                                   VkSparseImageFormatProperties *pProperties) {
108    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
109    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
110    if (NULL != icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties) {
111        icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties(phys_dev_term->phys_dev, format, type, samples, usage,
112                                                                        tiling, pNumProperties, pProperties);
113    }
114}
115
116VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
117                                                                         VkLayerProperties *pProperties) {
118    (void)pPropertyCount;
119    (void)pProperties;
120    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
121    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
122    loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT, 0,
123               "Encountered the vkEnumerateDeviceLayerProperties terminator.  This means a layer improperly continued.");
124    // Should never get here this call isn't dispatched down the chain
125    return VK_ERROR_INITIALIZATION_FAILED;
126}
127
128// Terminators for 1.1 functions
129
130VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice,
131                                                                 VkPhysicalDeviceFeatures2 *pFeatures) {
132    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
133    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
134    const struct loader_instance *inst = icd_term->this_instance;
135
136    assert(inst != NULL);
137
138    // Get the function pointer to use to call into the ICD. This could be the core or KHR version
139    PFN_vkGetPhysicalDeviceFeatures2 fpGetPhysicalDeviceFeatures2 = NULL;
140    if (loader_check_version_meets_required(LOADER_VERSION_1_1_0, inst->app_api_version)) {
141        fpGetPhysicalDeviceFeatures2 = icd_term->dispatch.GetPhysicalDeviceFeatures2;
142    }
143    if (fpGetPhysicalDeviceFeatures2 == NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
144        fpGetPhysicalDeviceFeatures2 = icd_term->dispatch.GetPhysicalDeviceFeatures2KHR;
145    }
146
147    if (fpGetPhysicalDeviceFeatures2 != NULL) {
148        // Pass the call to the driver
149        fpGetPhysicalDeviceFeatures2(phys_dev_term->phys_dev, pFeatures);
150    } else {
151        // Emulate the call
152        loader_log(icd_term->this_instance, VULKAN_LOADER_INFO_BIT, 0,
153                   "vkGetPhysicalDeviceFeatures2: Emulating call in ICD \"%s\" using vkGetPhysicalDeviceFeatures",
154                   icd_term->scanned_icd->lib_name);
155
156        // Write to the VkPhysicalDeviceFeatures2 struct
157        icd_term->dispatch.GetPhysicalDeviceFeatures(phys_dev_term->phys_dev, &pFeatures->features);
158
159        const VkBaseInStructure *pNext = pFeatures->pNext;
160        while (pNext != NULL) {
161            switch (pNext->sType) {
162                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES: {
163                    // Skip the check if VK_KHR_multiview is enabled because it's a device extension
164                    // Write to the VkPhysicalDeviceMultiviewFeaturesKHR struct
165                    VkPhysicalDeviceMultiviewFeaturesKHR *multiview_features = (VkPhysicalDeviceMultiviewFeaturesKHR *)pNext;
166                    multiview_features->multiview = VK_FALSE;
167                    multiview_features->multiviewGeometryShader = VK_FALSE;
168                    multiview_features->multiviewTessellationShader = VK_FALSE;
169
170                    pNext = multiview_features->pNext;
171                    break;
172                }
173                default: {
174                    loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0,
175                               "vkGetPhysicalDeviceFeatures2: Emulation found unrecognized structure type in pFeatures->pNext - "
176                               "this struct will be ignored");
177
178                    pNext = pNext->pNext;
179                    break;
180                }
181            }
182        }
183    }
184}
185
186VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
187                                                                   VkPhysicalDeviceProperties2 *pProperties) {
188    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
189    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
190    const struct loader_instance *inst = icd_term->this_instance;
191
192    assert(inst != NULL);
193
194    // Get the function pointer to use to call into the ICD. This could be the core or KHR version
195    PFN_vkGetPhysicalDeviceProperties2 fpGetPhysicalDeviceProperties2 = NULL;
196    if (loader_check_version_meets_required(LOADER_VERSION_1_1_0, inst->app_api_version)) {
197        fpGetPhysicalDeviceProperties2 = icd_term->dispatch.GetPhysicalDeviceProperties2;
198    }
199    if (fpGetPhysicalDeviceProperties2 == NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
200        fpGetPhysicalDeviceProperties2 = icd_term->dispatch.GetPhysicalDeviceProperties2KHR;
201    }
202
203    if (fpGetPhysicalDeviceProperties2 != NULL) {
204        // Pass the call to the driver
205        fpGetPhysicalDeviceProperties2(phys_dev_term->phys_dev, pProperties);
206    } else {
207        // Emulate the call
208        loader_log(icd_term->this_instance, VULKAN_LOADER_INFO_BIT, 0,
209                   "vkGetPhysicalDeviceProperties2: Emulating call in ICD \"%s\" using vkGetPhysicalDeviceProperties",
210                   icd_term->scanned_icd->lib_name);
211
212        // Write to the VkPhysicalDeviceProperties2 struct
213        icd_term->dispatch.GetPhysicalDeviceProperties(phys_dev_term->phys_dev, &pProperties->properties);
214
215        const VkBaseInStructure *pNext = pProperties->pNext;
216        while (pNext != NULL) {
217            switch (pNext->sType) {
218                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES: {
219                    VkPhysicalDeviceIDPropertiesKHR *id_properties = (VkPhysicalDeviceIDPropertiesKHR *)pNext;
220
221                    // Verify that "VK_KHR_external_memory_capabilities" is enabled
222                    if (icd_term->this_instance->enabled_known_extensions.khr_external_memory_capabilities) {
223                        loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0,
224                                   "vkGetPhysicalDeviceProperties2: Emulation cannot generate unique IDs for struct "
225                                   "VkPhysicalDeviceIDProperties - setting IDs to zero instead");
226
227                        // Write to the VkPhysicalDeviceIDPropertiesKHR struct
228                        memset(id_properties->deviceUUID, 0, VK_UUID_SIZE);
229                        memset(id_properties->driverUUID, 0, VK_UUID_SIZE);
230                        id_properties->deviceLUIDValid = VK_FALSE;
231                    }
232
233                    pNext = id_properties->pNext;
234                    break;
235                }
236                default: {
237                    loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0,
238                               "vkGetPhysicalDeviceProperties2KHR: Emulation found unrecognized structure type in "
239                               "pProperties->pNext - this struct will be ignored");
240
241                    pNext = pNext->pNext;
242                    break;
243                }
244            }
245        }
246    }
247}
248
249VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format,
250                                                                         VkFormatProperties2 *pFormatProperties) {
251    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
252    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
253    const struct loader_instance *inst = icd_term->this_instance;
254
255    assert(inst != NULL);
256
257    // Get the function pointer to use to call into the ICD. This could be the core or KHR version
258    PFN_vkGetPhysicalDeviceFormatProperties2 fpGetPhysicalDeviceFormatProperties2 = NULL;
259    if (loader_check_version_meets_required(LOADER_VERSION_1_1_0, inst->app_api_version)) {
260        fpGetPhysicalDeviceFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceFormatProperties2;
261    }
262    if (fpGetPhysicalDeviceFormatProperties2 == NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
263        fpGetPhysicalDeviceFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceFormatProperties2KHR;
264    }
265
266    if (fpGetPhysicalDeviceFormatProperties2 != NULL) {
267        // Pass the call to the driver
268        fpGetPhysicalDeviceFormatProperties2(phys_dev_term->phys_dev, format, pFormatProperties);
269    } else {
270        // Emulate the call
271        loader_log(icd_term->this_instance, VULKAN_LOADER_INFO_BIT, 0,
272                   "vkGetPhysicalDeviceFormatProperties2: Emulating call in ICD \"%s\" using vkGetPhysicalDeviceFormatProperties",
273                   icd_term->scanned_icd->lib_name);
274
275        // Write to the VkFormatProperties2 struct
276        icd_term->dispatch.GetPhysicalDeviceFormatProperties(phys_dev_term->phys_dev, format, &pFormatProperties->formatProperties);
277
278        if (pFormatProperties->pNext != NULL) {
279            loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0,
280                       "vkGetPhysicalDeviceFormatProperties2: Emulation found unrecognized structure type in "
281                       "pFormatProperties->pNext - this struct will be ignored");
282        }
283    }
284}
285
286VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceImageFormatProperties2(
287    VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo,
288    VkImageFormatProperties2 *pImageFormatProperties) {
289    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
290    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
291    const struct loader_instance *inst = icd_term->this_instance;
292
293    assert(inst != NULL);
294
295    // Get the function pointer to use to call into the ICD. This could be the core or KHR version
296    PFN_vkGetPhysicalDeviceImageFormatProperties2 fpGetPhysicalDeviceImageFormatProperties2 = NULL;
297    if (loader_check_version_meets_required(LOADER_VERSION_1_1_0, inst->app_api_version)) {
298        fpGetPhysicalDeviceImageFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceImageFormatProperties2;
299    }
300    if (fpGetPhysicalDeviceImageFormatProperties2 == NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
301        fpGetPhysicalDeviceImageFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceImageFormatProperties2KHR;
302    }
303
304    if (fpGetPhysicalDeviceImageFormatProperties2 != NULL) {
305        // Pass the call to the driver
306        return fpGetPhysicalDeviceImageFormatProperties2(phys_dev_term->phys_dev, pImageFormatInfo, pImageFormatProperties);
307    } else {
308        // Emulate the call
309        loader_log(icd_term->this_instance, VULKAN_LOADER_INFO_BIT, 0,
310                   "vkGetPhysicalDeviceImageFormatProperties2: Emulating call in ICD \"%s\" using "
311                   "vkGetPhysicalDeviceImageFormatProperties",
312                   icd_term->scanned_icd->lib_name);
313
314        // If there is more info in  either pNext, then this is unsupported
315        if (pImageFormatInfo->pNext != NULL || pImageFormatProperties->pNext != NULL) {
316            return VK_ERROR_FORMAT_NOT_SUPPORTED;
317        }
318
319        // Write to the VkImageFormatProperties2KHR struct
320        return icd_term->dispatch.GetPhysicalDeviceImageFormatProperties(
321            phys_dev_term->phys_dev, pImageFormatInfo->format, pImageFormatInfo->type, pImageFormatInfo->tiling,
322            pImageFormatInfo->usage, pImageFormatInfo->flags, &pImageFormatProperties->imageFormatProperties);
323    }
324}
325
326VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,
327                                                                              uint32_t *pQueueFamilyPropertyCount,
328                                                                              VkQueueFamilyProperties2 *pQueueFamilyProperties) {
329    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
330    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
331    const struct loader_instance *inst = icd_term->this_instance;
332
333    assert(inst != NULL);
334
335    // Get the function pointer to use to call into the ICD. This could be the core or KHR version
336    PFN_vkGetPhysicalDeviceQueueFamilyProperties2 fpGetPhysicalDeviceQueueFamilyProperties2 = NULL;
337    if (loader_check_version_meets_required(LOADER_VERSION_1_1_0, inst->app_api_version)) {
338        fpGetPhysicalDeviceQueueFamilyProperties2 = icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties2;
339    }
340    if (fpGetPhysicalDeviceQueueFamilyProperties2 == NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
341        fpGetPhysicalDeviceQueueFamilyProperties2 = icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties2KHR;
342    }
343
344    if (fpGetPhysicalDeviceQueueFamilyProperties2 != NULL) {
345        // Pass the call to the driver
346        fpGetPhysicalDeviceQueueFamilyProperties2(phys_dev_term->phys_dev, pQueueFamilyPropertyCount, pQueueFamilyProperties);
347    } else {
348        // Emulate the call
349        loader_log(icd_term->this_instance, VULKAN_LOADER_INFO_BIT, 0,
350                   "vkGetPhysicalDeviceQueueFamilyProperties2: Emulating call in ICD \"%s\" using "
351                   "vkGetPhysicalDeviceQueueFamilyProperties",
352                   icd_term->scanned_icd->lib_name);
353
354        if (pQueueFamilyProperties == NULL || *pQueueFamilyPropertyCount == 0) {
355            // Write to pQueueFamilyPropertyCount
356            icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties(phys_dev_term->phys_dev, pQueueFamilyPropertyCount, NULL);
357        } else {
358            // Allocate a temporary array for the output of the old function
359            VkQueueFamilyProperties *properties = loader_stack_alloc(*pQueueFamilyPropertyCount * sizeof(VkQueueFamilyProperties));
360            if (properties == NULL) {
361                *pQueueFamilyPropertyCount = 0;
362                loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT, 0,
363                           "vkGetPhysicalDeviceQueueFamilyProperties2: Out of memory - Failed to allocate array for loader "
364                           "emulation.");
365                return;
366            }
367
368            icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties(phys_dev_term->phys_dev, pQueueFamilyPropertyCount,
369                                                                      properties);
370            for (uint32_t i = 0; i < *pQueueFamilyPropertyCount; ++i) {
371                // Write to the VkQueueFamilyProperties2KHR struct
372                memcpy(&pQueueFamilyProperties[i].queueFamilyProperties, &properties[i], sizeof(VkQueueFamilyProperties));
373
374                if (pQueueFamilyProperties[i].pNext != NULL) {
375                    loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0,
376                               "vkGetPhysicalDeviceQueueFamilyProperties2: Emulation found unrecognized structure type in "
377                               "pQueueFamilyProperties[%d].pNext - this struct will be ignored",
378                               i);
379                }
380            }
381        }
382    }
383}
384
385VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice,
386                                                                         VkPhysicalDeviceMemoryProperties2 *pMemoryProperties) {
387    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
388    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
389    const struct loader_instance *inst = icd_term->this_instance;
390
391    assert(inst != NULL);
392
393    // Get the function pointer to use to call into the ICD. This could be the core or KHR version
394    PFN_vkGetPhysicalDeviceMemoryProperties2 fpGetPhysicalDeviceMemoryProperties2 = NULL;
395    if (loader_check_version_meets_required(LOADER_VERSION_1_1_0, inst->app_api_version)) {
396        fpGetPhysicalDeviceMemoryProperties2 = icd_term->dispatch.GetPhysicalDeviceMemoryProperties2;
397    }
398    if (fpGetPhysicalDeviceMemoryProperties2 == NULL && inst->enabled_known_extensions.khr_get_physical_device_properties2) {
399        fpGetPhysicalDeviceMemoryProperties2 = icd_term->dispatch.GetPhysicalDeviceMemoryProperties2KHR;
400    }
401
402    if (fpGetPhysicalDeviceMemoryProperties2 != NULL) {
403        // Pass the call to the driver
404        fpGetPhysicalDeviceMemoryProperties2(phys_dev_term->phys_dev, pMemoryProperties);
405    } else {
406        // Emulate the call
407        loader_log(icd_term->this_instance, VULKAN_LOADER_INFO_BIT, 0,
408                   "vkGetPhysicalDeviceMemoryProperties2: Emulating call in ICD \"%s\" using vkGetPhysicalDeviceMemoryProperties",
409                   icd_term->scanned_icd->lib_name);
410
411        // Write to the VkPhysicalDeviceMemoryProperties2 struct
412        icd_term->dispatch.GetPhysicalDeviceMemoryProperties(phys_dev_term->phys_dev, &pMemoryProperties->memoryProperties);
413
414        if (pMemoryProperties->pNext != NULL) {
415            loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0,
416                       "vkGetPhysicalDeviceMemoryProperties2: Emulation found unrecognized structure type in "
417                       "pMemoryProperties->pNext - this struct will be ignored");
418        }
419    }
420}
421
422VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceSparseImageFormatProperties2(
423    VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2KHR *pFormatInfo, uint32_t *pPropertyCount,
424    VkSparseImageFormatProperties2KHR *pProperties) {
425    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
426    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
427    const struct loader_instance *inst = icd_term->this_instance;
428
429    assert(inst != NULL);
430
431    // Get the function pointer to use to call into the ICD. This could be the core or KHR version
432    PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 fpGetPhysicalDeviceSparseImageFormatProperties2 = NULL;
433    if (loader_check_version_meets_required(LOADER_VERSION_1_1_0, inst->app_api_version)) {
434        fpGetPhysicalDeviceSparseImageFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties2;
435    }
436    if (fpGetPhysicalDeviceSparseImageFormatProperties2 == NULL &&
437        inst->enabled_known_extensions.khr_get_physical_device_properties2) {
438        fpGetPhysicalDeviceSparseImageFormatProperties2 = icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties2KHR;
439    }
440
441    if (fpGetPhysicalDeviceSparseImageFormatProperties2 != NULL) {
442        // Pass the call to the driver
443        fpGetPhysicalDeviceSparseImageFormatProperties2(phys_dev_term->phys_dev, pFormatInfo, pPropertyCount, pProperties);
444    } else {
445        // Emulate the call
446        loader_log(icd_term->this_instance, VULKAN_LOADER_INFO_BIT, 0,
447                   "vkGetPhysicalDeviceSparseImageFormatProperties2: Emulating call in ICD \"%s\" using "
448                   "vkGetPhysicalDeviceSparseImageFormatProperties",
449                   icd_term->scanned_icd->lib_name);
450
451        if (pFormatInfo->pNext != NULL) {
452            loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0,
453                       "vkGetPhysicalDeviceSparseImageFormatProperties2: Emulation found unrecognized structure type in "
454                       "pFormatInfo->pNext - this struct will be ignored");
455        }
456
457        if (pProperties == NULL || *pPropertyCount == 0) {
458            // Write to pPropertyCount
459            icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties(
460                phys_dev_term->phys_dev, pFormatInfo->format, pFormatInfo->type, pFormatInfo->samples, pFormatInfo->usage,
461                pFormatInfo->tiling, pPropertyCount, NULL);
462        } else {
463            // Allocate a temporary array for the output of the old function
464            VkSparseImageFormatProperties *properties =
465                loader_stack_alloc(*pPropertyCount * sizeof(VkSparseImageMemoryRequirements));
466            if (properties == NULL) {
467                *pPropertyCount = 0;
468                loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT, 0,
469                           "vkGetPhysicalDeviceSparseImageFormatProperties2: Out of memory - Failed to allocate array for "
470                           "loader emulation.");
471                return;
472            }
473
474            icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties(
475                phys_dev_term->phys_dev, pFormatInfo->format, pFormatInfo->type, pFormatInfo->samples, pFormatInfo->usage,
476                pFormatInfo->tiling, pPropertyCount, properties);
477            for (uint32_t i = 0; i < *pPropertyCount; ++i) {
478                // Write to the VkSparseImageFormatProperties2KHR struct
479                memcpy(&pProperties[i].properties, &properties[i], sizeof(VkSparseImageFormatProperties));
480
481                if (pProperties[i].pNext != NULL) {
482                    loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0,
483                               "vkGetPhysicalDeviceSparseImageFormatProperties2: Emulation found unrecognized structure type in "
484                               "pProperties[%d].pNext - this struct will be ignored",
485                               i);
486                }
487            }
488        }
489    }
490}
491
492VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceExternalBufferProperties(
493    VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo,
494    VkExternalBufferProperties *pExternalBufferProperties) {
495    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
496    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
497    const struct loader_instance *inst = icd_term->this_instance;
498
499    assert(inst != NULL);
500
501    // Get the function pointer to use to call into the ICD. This could be the core or KHR version
502    PFN_vkGetPhysicalDeviceExternalBufferProperties fpGetPhysicalDeviceExternalBufferProperties = NULL;
503    if (loader_check_version_meets_required(LOADER_VERSION_1_1_0, inst->app_api_version)) {
504        fpGetPhysicalDeviceExternalBufferProperties = icd_term->dispatch.GetPhysicalDeviceExternalBufferProperties;
505    }
506    if (fpGetPhysicalDeviceExternalBufferProperties == NULL && inst->enabled_known_extensions.khr_external_memory_capabilities) {
507        fpGetPhysicalDeviceExternalBufferProperties = icd_term->dispatch.GetPhysicalDeviceExternalBufferPropertiesKHR;
508    }
509
510    if (fpGetPhysicalDeviceExternalBufferProperties != NULL) {
511        // Pass the call to the driver
512        fpGetPhysicalDeviceExternalBufferProperties(phys_dev_term->phys_dev, pExternalBufferInfo, pExternalBufferProperties);
513    } else {
514        // Emulate the call
515        loader_log(icd_term->this_instance, VULKAN_LOADER_INFO_BIT, 0,
516                   "vkGetPhysicalDeviceExternalBufferProperties: Emulating call in ICD \"%s\"", icd_term->scanned_icd->lib_name);
517
518        if (pExternalBufferInfo->pNext != NULL) {
519            loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0,
520                       "vkGetPhysicalDeviceExternalBufferProperties: Emulation found unrecognized structure type in "
521                       "pExternalBufferInfo->pNext - this struct will be ignored");
522        }
523
524        // Fill in everything being unsupported
525        memset(&pExternalBufferProperties->externalMemoryProperties, 0, sizeof(VkExternalMemoryPropertiesKHR));
526
527        if (pExternalBufferProperties->pNext != NULL) {
528            loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0,
529                       "vkGetPhysicalDeviceExternalBufferProperties: Emulation found unrecognized structure type in "
530                       "pExternalBufferProperties->pNext - this struct will be ignored");
531        }
532    }
533}
534
535VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceExternalSemaphoreProperties(
536    VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo,
537    VkExternalSemaphoreProperties *pExternalSemaphoreProperties) {
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    const struct loader_instance *inst = icd_term->this_instance;
541
542    assert(inst != NULL);
543
544    // Get the function pointer to use to call into the ICD. This could be the core or KHR version
545    PFN_vkGetPhysicalDeviceExternalSemaphoreProperties fpGetPhysicalDeviceExternalSemaphoreProperties = NULL;
546    if (loader_check_version_meets_required(LOADER_VERSION_1_1_0, inst->app_api_version)) {
547        fpGetPhysicalDeviceExternalSemaphoreProperties = icd_term->dispatch.GetPhysicalDeviceExternalSemaphoreProperties;
548    }
549    if (fpGetPhysicalDeviceExternalSemaphoreProperties == NULL &&
550        inst->enabled_known_extensions.khr_external_semaphore_capabilities) {
551        fpGetPhysicalDeviceExternalSemaphoreProperties = icd_term->dispatch.GetPhysicalDeviceExternalSemaphorePropertiesKHR;
552    }
553
554    if (fpGetPhysicalDeviceExternalSemaphoreProperties != NULL) {
555        // Pass the call to the driver
556        fpGetPhysicalDeviceExternalSemaphoreProperties(phys_dev_term->phys_dev, pExternalSemaphoreInfo,
557                                                       pExternalSemaphoreProperties);
558    } else {
559        // Emulate the call
560        loader_log(icd_term->this_instance, VULKAN_LOADER_INFO_BIT, 0,
561                   "vkGetPhysicalDeviceExternalSemaphoreProperties: Emulating call in ICD \"%s\"", icd_term->scanned_icd->lib_name);
562
563        if (pExternalSemaphoreInfo->pNext != NULL) {
564            loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0,
565                       "vkGetPhysicalDeviceExternalSemaphoreProperties: Emulation found unrecognized structure type in "
566                       "pExternalSemaphoreInfo->pNext - this struct will be ignored");
567        }
568
569        // Fill in everything being unsupported
570        pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
571        pExternalSemaphoreProperties->compatibleHandleTypes = 0;
572        pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
573
574        if (pExternalSemaphoreProperties->pNext != NULL) {
575            loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0,
576                       "vkGetPhysicalDeviceExternalSemaphoreProperties: Emulation found unrecognized structure type in "
577                       "pExternalSemaphoreProperties->pNext - this struct will be ignored");
578        }
579    }
580}
581
582VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceExternalFenceProperties(
583    VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo,
584    VkExternalFenceProperties *pExternalFenceProperties) {
585    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
586    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
587    const struct loader_instance *inst = icd_term->this_instance;
588
589    assert(inst != NULL);
590
591    // Get the function pointer to use to call into the ICD. This could be the core or KHR version
592    PFN_vkGetPhysicalDeviceExternalFenceProperties fpGetPhysicalDeviceExternalFenceProperties = NULL;
593    if (loader_check_version_meets_required(LOADER_VERSION_1_1_0, inst->app_api_version)) {
594        fpGetPhysicalDeviceExternalFenceProperties = icd_term->dispatch.GetPhysicalDeviceExternalFenceProperties;
595    }
596    if (fpGetPhysicalDeviceExternalFenceProperties == NULL && inst->enabled_known_extensions.khr_external_fence_capabilities) {
597        fpGetPhysicalDeviceExternalFenceProperties = icd_term->dispatch.GetPhysicalDeviceExternalFencePropertiesKHR;
598    }
599
600    if (fpGetPhysicalDeviceExternalFenceProperties != NULL) {
601        // Pass the call to the driver
602        fpGetPhysicalDeviceExternalFenceProperties(phys_dev_term->phys_dev, pExternalFenceInfo, pExternalFenceProperties);
603    } else {
604        // Emulate the call
605        loader_log(icd_term->this_instance, VULKAN_LOADER_INFO_BIT, 0,
606                   "vkGetPhysicalDeviceExternalFenceProperties: Emulating call in ICD \"%s\"", icd_term->scanned_icd->lib_name);
607
608        if (pExternalFenceInfo->pNext != NULL) {
609            loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0,
610                       "vkGetPhysicalDeviceExternalFenceProperties: Emulation found unrecognized structure type in "
611                       "pExternalFenceInfo->pNext - this struct will be ignored");
612        }
613
614        // Fill in everything being unsupported
615        pExternalFenceProperties->exportFromImportedHandleTypes = 0;
616        pExternalFenceProperties->compatibleHandleTypes = 0;
617        pExternalFenceProperties->externalFenceFeatures = 0;
618
619        if (pExternalFenceProperties->pNext != NULL) {
620            loader_log(icd_term->this_instance, VULKAN_LOADER_WARN_BIT, 0,
621                       "vkGetPhysicalDeviceExternalFenceProperties: Emulation found unrecognized structure type in "
622                       "pExternalFenceProperties->pNext - this struct will be ignored");
623        }
624    }
625}
626
627// 1.3 Core terminators
628
629VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceToolProperties(VkPhysicalDevice physicalDevice, uint32_t *pToolCount,
630                                                                          VkPhysicalDeviceToolProperties *pToolProperties) {
631    struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
632    struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
633
634    if (NULL == icd_term->dispatch.GetPhysicalDeviceToolProperties) {
635        loader_log(icd_term->this_instance, VULKAN_LOADER_ERROR_BIT, 0,
636                   "terminator_GetPhysicalDeviceToolProperties: The ICD's vkGetPhysicalDeviceToolProperties was NULL yet "
637                   "the physical device supports Vulkan API Version 1.3.");
638    } else {
639        VkPhysicalDeviceProperties properties;
640        if (icd_term->dispatch.GetPhysicalDeviceProperties) {
641            icd_term->dispatch.GetPhysicalDeviceProperties(phys_dev_term->phys_dev, &properties);
642
643            if (VK_API_VERSION_MINOR(properties.apiVersion) >= 3) {
644                return icd_term->dispatch.GetPhysicalDeviceToolProperties(phys_dev_term->phys_dev, pToolCount, pToolProperties);
645            }
646        }
647    }
648
649    // In the case the driver didn't support 1.3, make sure that the first layer doesn't find the count uninitialized
650    *pToolCount = 0;
651    return VK_SUCCESS;
652}
653