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 
terminator_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties *pProperties)41 VKAPI_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 
terminator_GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties *pProperties)50 VKAPI_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 
terminator_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties *pProperties)60 VKAPI_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 
terminator_GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures *pFeatures)69 VKAPI_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 
terminator_GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties *pFormatInfo)78 VKAPI_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 
terminator_GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties *pImageFormatProperties)87 VKAPI_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 
terminator_GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t *pNumProperties, VkSparseImageFormatProperties *pProperties)103 VKAPI_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 
terminator_EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, VkLayerProperties *pProperties)116 VKAPI_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 
terminator_GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2 *pFeatures)130 VKAPI_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 
terminator_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2 *pProperties)186 VKAPI_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 
terminator_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2 *pFormatProperties)249 VKAPI_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 
terminator_GetPhysicalDeviceImageFormatProperties2( VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, VkImageFormatProperties2 *pImageFormatProperties)286 VKAPI_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 
terminator_GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties2 *pQueueFamilyProperties)326 VKAPI_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 
terminator_GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2 *pMemoryProperties)385 VKAPI_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 
terminator_GetPhysicalDeviceSparseImageFormatProperties2( VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2KHR *pFormatInfo, uint32_t *pPropertyCount, VkSparseImageFormatProperties2KHR *pProperties)422 VKAPI_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 
terminator_GetPhysicalDeviceExternalBufferProperties( VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo, VkExternalBufferProperties *pExternalBufferProperties)492 VKAPI_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 
terminator_GetPhysicalDeviceExternalSemaphoreProperties( VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo, VkExternalSemaphoreProperties *pExternalSemaphoreProperties)535 VKAPI_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 
terminator_GetPhysicalDeviceExternalFenceProperties( VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo, VkExternalFenceProperties *pExternalFenceProperties)582 VKAPI_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 
terminator_GetPhysicalDeviceToolProperties(VkPhysicalDevice physicalDevice, uint32_t *pToolCount, VkPhysicalDeviceToolProperties *pToolProperties)629 VKAPI_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