loader: EnumPhysDev fixes
[platform/upstream/Vulkan-LoaderAndValidationLayers.git] / loader / loader.c
1 /*
2  *
3  * Copyright (c) 2014-2016 The Khronos Group Inc.
4  * Copyright (c) 2014-2016 Valve Corporation
5  * Copyright (c) 2014-2016 LunarG, Inc.
6  * Copyright (C) 2015 Google Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19
20  *
21  * Author: Jon Ashburn <jon@lunarg.com>
22  * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
23  *
24  */
25
26 #define _GNU_SOURCE
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <stdbool.h>
31 #include <string.h>
32
33 #include <sys/types.h>
34 #if defined(_WIN32)
35 #include "dirent_on_windows.h"
36 #else // _WIN32
37 #include <dirent.h>
38 #endif // _WIN32
39 #include "vk_loader_platform.h"
40 #include "loader.h"
41 #include "gpa_helper.h"
42 #include "table_ops.h"
43 #include "debug_report.h"
44 #include "wsi.h"
45 #include "extensions.h"
46 #include "vulkan/vk_icd.h"
47 #include "cJSON.h"
48 #include "murmurhash.h"
49
50 #if defined(__GNUC__)
51 #if (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 17))
52 #define secure_getenv __secure_getenv
53 #endif
54 #endif
55
56 struct loader_struct loader = {0};
57 // TLS for instance for alloc/free callbacks
58 THREAD_LOCAL_DECL struct loader_instance *tls_instance;
59
60 static size_t loader_platform_combine_path(char *dest, size_t len, ...);
61
62 struct loader_phys_dev_per_icd {
63     uint32_t count;
64     VkPhysicalDevice *phys_devs;
65     struct loader_icd_term *this_icd_term;
66 };
67
68 enum loader_debug {
69     LOADER_INFO_BIT = 0x01,
70     LOADER_WARN_BIT = 0x02,
71     LOADER_PERF_BIT = 0x04,
72     LOADER_ERROR_BIT = 0x08,
73     LOADER_DEBUG_BIT = 0x10,
74 };
75
76 uint32_t g_loader_debug = 0;
77 uint32_t g_loader_log_msgs = 0;
78
79 // thread safety lock for accessing global data structures such as "loader"
80 // all entrypoints on the instance chain need to be locked except GPA
81 // additionally CreateDevice and DestroyDevice needs to be locked
82 loader_platform_thread_mutex loader_lock;
83 loader_platform_thread_mutex loader_json_lock;
84
85 const char *std_validation_str = "VK_LAYER_LUNARG_standard_validation";
86
87 // This table contains the loader's instance dispatch table, which contains
88 // default functions if no instance layers are activated.  This contains
89 // pointers to "terminator functions".
90 const VkLayerInstanceDispatchTable instance_disp = {
91     .GetInstanceProcAddr = vkGetInstanceProcAddr,
92     .DestroyInstance = terminator_DestroyInstance,
93     .EnumeratePhysicalDevices = terminator_EnumeratePhysicalDevices,
94     .GetPhysicalDeviceFeatures = terminator_GetPhysicalDeviceFeatures,
95     .GetPhysicalDeviceFormatProperties =
96         terminator_GetPhysicalDeviceFormatProperties,
97     .GetPhysicalDeviceImageFormatProperties =
98         terminator_GetPhysicalDeviceImageFormatProperties,
99     .GetPhysicalDeviceProperties = terminator_GetPhysicalDeviceProperties,
100     .GetPhysicalDeviceQueueFamilyProperties =
101         terminator_GetPhysicalDeviceQueueFamilyProperties,
102     .GetPhysicalDeviceMemoryProperties =
103         terminator_GetPhysicalDeviceMemoryProperties,
104     .EnumerateDeviceExtensionProperties =
105         terminator_EnumerateDeviceExtensionProperties,
106     .EnumerateDeviceLayerProperties = terminator_EnumerateDeviceLayerProperties,
107     .GetPhysicalDeviceSparseImageFormatProperties =
108         terminator_GetPhysicalDeviceSparseImageFormatProperties,
109     .DestroySurfaceKHR = terminator_DestroySurfaceKHR,
110     .GetPhysicalDeviceSurfaceSupportKHR =
111         terminator_GetPhysicalDeviceSurfaceSupportKHR,
112     .GetPhysicalDeviceSurfaceCapabilitiesKHR =
113         terminator_GetPhysicalDeviceSurfaceCapabilitiesKHR,
114     .GetPhysicalDeviceSurfaceFormatsKHR =
115         terminator_GetPhysicalDeviceSurfaceFormatsKHR,
116     .GetPhysicalDeviceSurfacePresentModesKHR =
117         terminator_GetPhysicalDeviceSurfacePresentModesKHR,
118     .CreateDebugReportCallbackEXT = terminator_CreateDebugReportCallback,
119     .DestroyDebugReportCallbackEXT = terminator_DestroyDebugReportCallback,
120     .DebugReportMessageEXT = terminator_DebugReportMessage,
121     .GetPhysicalDeviceExternalImageFormatPropertiesNV =
122         terminator_GetPhysicalDeviceExternalImageFormatPropertiesNV,
123 #ifdef VK_USE_PLATFORM_MIR_KHR
124     .CreateMirSurfaceKHR = terminator_CreateMirSurfaceKHR,
125     .GetPhysicalDeviceMirPresentationSupportKHR =
126         terminator_GetPhysicalDeviceMirPresentationSupportKHR,
127 #endif
128 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
129     .CreateWaylandSurfaceKHR = terminator_CreateWaylandSurfaceKHR,
130     .GetPhysicalDeviceWaylandPresentationSupportKHR =
131         terminator_GetPhysicalDeviceWaylandPresentationSupportKHR,
132 #endif
133 #ifdef VK_USE_PLATFORM_WIN32_KHR
134     .CreateWin32SurfaceKHR = terminator_CreateWin32SurfaceKHR,
135     .GetPhysicalDeviceWin32PresentationSupportKHR =
136         terminator_GetPhysicalDeviceWin32PresentationSupportKHR,
137 #endif
138 #ifdef VK_USE_PLATFORM_XCB_KHR
139     .CreateXcbSurfaceKHR = terminator_CreateXcbSurfaceKHR,
140     .GetPhysicalDeviceXcbPresentationSupportKHR =
141         terminator_GetPhysicalDeviceXcbPresentationSupportKHR,
142 #endif
143 #ifdef VK_USE_PLATFORM_XLIB_KHR
144     .CreateXlibSurfaceKHR = terminator_CreateXlibSurfaceKHR,
145     .GetPhysicalDeviceXlibPresentationSupportKHR =
146         terminator_GetPhysicalDeviceXlibPresentationSupportKHR,
147 #endif
148 #ifdef VK_USE_PLATFORM_ANDROID_KHR
149     .CreateAndroidSurfaceKHR = terminator_CreateAndroidSurfaceKHR,
150 #endif
151     .GetPhysicalDeviceDisplayPropertiesKHR =
152         terminator_GetPhysicalDeviceDisplayPropertiesKHR,
153     .GetPhysicalDeviceDisplayPlanePropertiesKHR =
154         terminator_GetPhysicalDeviceDisplayPlanePropertiesKHR,
155     .GetDisplayPlaneSupportedDisplaysKHR =
156         terminator_GetDisplayPlaneSupportedDisplaysKHR,
157     .GetDisplayModePropertiesKHR = terminator_GetDisplayModePropertiesKHR,
158     .CreateDisplayModeKHR = terminator_CreateDisplayModeKHR,
159     .GetDisplayPlaneCapabilitiesKHR = terminator_GetDisplayPlaneCapabilitiesKHR,
160     .CreateDisplayPlaneSurfaceKHR = terminator_CreateDisplayPlaneSurfaceKHR,
161
162     // NVX_device_generated_commands
163     .GetPhysicalDeviceGeneratedCommandsPropertiesNVX =
164         terminator_GetPhysicalDeviceGeneratedCommandsPropertiesNVX,
165 };
166
167 LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_init);
168
169 void *loader_instance_heap_alloc(const struct loader_instance *instance,
170                                  size_t size,
171                                  VkSystemAllocationScope alloc_scope) {
172     void *pMemory = NULL;
173 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
174     {
175 #else
176     if (instance && instance->alloc_callbacks.pfnAllocation) {
177         /* These are internal structures, so it's best to align everything to
178          * the largest unit size which is the size of a uint64_t.
179         */
180         pMemory = instance->alloc_callbacks.pfnAllocation(
181             instance->alloc_callbacks.pUserData, size, sizeof(uint64_t),
182             alloc_scope);
183     } else {
184 #endif
185         pMemory = malloc(size);
186     }
187     return pMemory;
188 }
189
190 void loader_instance_heap_free(const struct loader_instance *instance,
191                                void *pMemory) {
192     if (pMemory != NULL) {
193 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
194         {
195 #else
196         if (instance && instance->alloc_callbacks.pfnFree) {
197             instance->alloc_callbacks.pfnFree(
198                 instance->alloc_callbacks.pUserData, pMemory);
199         } else {
200 #endif
201             free(pMemory);
202         }
203     }
204 }
205
206 void *loader_instance_heap_realloc(const struct loader_instance *instance,
207                                    void *pMemory, size_t orig_size, size_t size,
208                                    VkSystemAllocationScope alloc_scope) {
209     void *pNewMem = NULL;
210     if (pMemory == NULL || orig_size == 0) {
211         pNewMem = loader_instance_heap_alloc(instance, size, alloc_scope);
212     } else if (size == 0) {
213         loader_instance_heap_free(instance, pMemory);
214 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
215 #else
216     } else if (instance && instance->alloc_callbacks.pfnReallocation) {
217         /* These are internal structures, so it's best to align everything to
218          * the largest unit size which is the size of a uint64_t.
219          */
220         pNewMem = instance->alloc_callbacks.pfnReallocation(
221             instance->alloc_callbacks.pUserData, pMemory, size,
222             sizeof(uint64_t), alloc_scope);
223 #endif
224     } else {
225         pNewMem = realloc(pMemory, size);
226     }
227     return pNewMem;
228 }
229
230 void *loader_instance_tls_heap_alloc(size_t size) {
231     return loader_instance_heap_alloc(tls_instance, size,
232                                       VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
233 }
234
235 void loader_instance_tls_heap_free(void *pMemory) {
236     loader_instance_heap_free(tls_instance, pMemory);
237 }
238
239 void *loader_device_heap_alloc(const struct loader_device *device, size_t size,
240                                VkSystemAllocationScope alloc_scope) {
241     void *pMemory = NULL;
242 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
243     {
244 #else
245     if (device && device->alloc_callbacks.pfnAllocation) {
246         /* These are internal structures, so it's best to align everything to
247          * the largest unit size which is the size of a uint64_t.
248         */
249         pMemory = device->alloc_callbacks.pfnAllocation(
250             device->alloc_callbacks.pUserData, size, sizeof(uint64_t),
251             alloc_scope);
252     } else {
253 #endif
254         pMemory = malloc(size);
255     }
256     return pMemory;
257 }
258
259 void loader_device_heap_free(const struct loader_device *device,
260                              void *pMemory) {
261     if (pMemory != NULL) {
262 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
263         {
264 #else
265         if (device && device->alloc_callbacks.pfnFree) {
266             device->alloc_callbacks.pfnFree(device->alloc_callbacks.pUserData,
267                                             pMemory);
268         } else {
269 #endif
270             free(pMemory);
271         }
272     }
273 }
274
275 void *loader_device_heap_realloc(const struct loader_device *device,
276                                  void *pMemory, size_t orig_size, size_t size,
277                                  VkSystemAllocationScope alloc_scope) {
278     void *pNewMem = NULL;
279     if (pMemory == NULL || orig_size == 0) {
280         pNewMem = loader_device_heap_alloc(device, size, alloc_scope);
281     } else if (size == 0) {
282         loader_device_heap_free(device, pMemory);
283 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
284 #else
285     } else if (device && device->alloc_callbacks.pfnReallocation) {
286         /* These are internal structures, so it's best to align everything to
287          * the largest unit size which is the size of a uint64_t.
288         */
289         pNewMem = device->alloc_callbacks.pfnReallocation(
290             device->alloc_callbacks.pUserData, pMemory, size, sizeof(uint64_t),
291             alloc_scope);
292 #endif
293     } else {
294         pNewMem = realloc(pMemory, size);
295     }
296     return pNewMem;
297 }
298
299 // Environment variables
300 #if defined(__linux__)
301
302 static inline char *loader_getenv(const char *name,
303                                   const struct loader_instance *inst) {
304     // No allocation of memory necessary for Linux, but we should at least touch
305     // the inst pointer to get rid of compiler warnings.
306     (void)inst;
307     return getenv(name);
308 }
309 static inline void loader_free_getenv(char *val,
310                                       const struct loader_instance *inst) {
311     // No freeing of memory necessary for Linux, but we should at least touch
312     // the val and inst pointers to get rid of compiler warnings.
313     (void)val;
314     (void)inst;
315 }
316
317 #elif defined(WIN32)
318
319 static inline char *loader_getenv(const char *name,
320                                   const struct loader_instance *inst) {
321     char *retVal;
322     DWORD valSize;
323
324     valSize = GetEnvironmentVariableA(name, NULL, 0);
325
326     // valSize DOES include the null terminator, so for any set variable
327     // will always be at least 1. If it's 0, the variable wasn't set.
328     if (valSize == 0)
329         return NULL;
330
331     // Allocate the space necessary for the registry entry
332     if (NULL != inst && NULL != inst->alloc_callbacks.pfnAllocation) {
333         retVal = (char *)inst->alloc_callbacks.pfnAllocation(
334             inst->alloc_callbacks.pUserData, valSize, sizeof(char *),
335             VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
336     } else {
337         retVal = (char *)malloc(valSize);
338     }
339
340     if (NULL != retVal) {
341         GetEnvironmentVariableA(name, retVal, valSize);
342     }
343
344     return retVal;
345 }
346
347 static inline void loader_free_getenv(char *val,
348                                       const struct loader_instance *inst) {
349     if (NULL != inst && NULL != inst->alloc_callbacks.pfnFree) {
350         inst->alloc_callbacks.pfnFree(inst->alloc_callbacks.pUserData, val);
351     } else {
352         free((void *)val);
353     }
354 }
355
356 #else
357
358 static inline char *loader_getenv(const char *name,
359                                   const struct loader_instance *inst) {
360     // stub func
361     (void)inst;
362     (void)name;
363     return NULL;
364 }
365 static inline void loader_free_getenv(char *val,
366                                       const struct loader_instance *inst) {
367     // stub func
368     (void)val;
369     (void)inst;
370 }
371
372 #endif
373
374 void loader_log(const struct loader_instance *inst, VkFlags msg_type,
375                 int32_t msg_code, const char *format, ...) {
376     char msg[512];
377     va_list ap;
378     int ret;
379
380     va_start(ap, format);
381     ret = vsnprintf(msg, sizeof(msg), format, ap);
382     if ((ret >= (int)sizeof(msg)) || ret < 0) {
383         msg[sizeof(msg) - 1] = '\0';
384     }
385     va_end(ap);
386
387     if (inst) {
388         util_DebugReportMessage(
389             inst, msg_type, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
390             (uint64_t)(uintptr_t)inst, 0, msg_code, "loader", msg);
391     }
392
393     if (!(msg_type & g_loader_log_msgs)) {
394         return;
395     }
396
397 #if defined(WIN32)
398     OutputDebugString(msg);
399     OutputDebugString("\n");
400 #endif
401     fputs(msg, stderr);
402     fputc('\n', stderr);
403 }
404
405 VKAPI_ATTR VkResult VKAPI_CALL vkSetInstanceDispatch(VkInstance instance,
406                                                      void *object) {
407
408     struct loader_instance *inst = loader_get_instance(instance);
409     if (!inst) {
410         return VK_ERROR_INITIALIZATION_FAILED;
411     }
412     loader_set_dispatch(object, inst->disp);
413     return VK_SUCCESS;
414 }
415
416 VKAPI_ATTR VkResult VKAPI_CALL vkSetDeviceDispatch(VkDevice device,
417                                                    void *object) {
418     struct loader_device *dev;
419     struct loader_icd_term *icd_term =
420         loader_get_icd_and_device(device, &dev, NULL);
421
422     if (NULL == icd_term) {
423         return VK_ERROR_INITIALIZATION_FAILED;
424     }
425     loader_set_dispatch(object, &dev->loader_dispatch);
426     return VK_SUCCESS;
427 }
428
429 #if defined(WIN32)
430 static char *loader_get_next_path(char *path);
431 /**
432 * Find the list of registry files (names within a key) in key "location".
433 *
434 * This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as
435 *given in "location"
436 * for a list or name/values which are added to a returned list (function return
437 *value).
438 * The DWORD values within the key must be 0 or they are skipped.
439 * Function return is a string with a ';'  separated list of filenames.
440 * Function return is NULL if no valid name/value pairs  are found in the key,
441 * or the key is not found.
442 *
443 * \returns
444 * A string list of filenames as pointer.
445 * When done using the returned string list, pointer should be freed.
446 */
447 static char *loader_get_registry_files(const struct loader_instance *inst,
448                                        char *location) {
449     LONG rtn_value;
450     HKEY hive, key;
451     DWORD access_flags;
452     char name[2048];
453     char *out = NULL;
454     char *loc = location;
455     char *next;
456     DWORD idx = 0;
457     DWORD name_size = sizeof(name);
458     DWORD value;
459     DWORD total_size = 4096;
460     DWORD value_size = sizeof(value);
461
462     while (*loc) {
463         next = loader_get_next_path(loc);
464         hive = DEFAULT_VK_REGISTRY_HIVE;
465         access_flags = KEY_QUERY_VALUE;
466         rtn_value = RegOpenKeyEx(hive, loc, 0, access_flags, &key);
467         if (rtn_value != ERROR_SUCCESS) {
468             // We still couldn't find the key, so give up:
469             loc = next;
470             continue;
471         }
472
473         while ((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL,
474                                          NULL, (LPBYTE)&value, &value_size)) ==
475                ERROR_SUCCESS) {
476             if (value_size == sizeof(value) && value == 0) {
477                 if (out == NULL) {
478                     out = loader_instance_heap_alloc(
479                         inst, total_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
480                     if (NULL == out) {
481                         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
482                                    "Out of memory can't alloc space for "
483                                    "registry data");
484                         return NULL;
485                     }
486                     out[0] = '\0';
487                 } else if (strlen(out) + name_size + 1 > total_size) {
488                     out = loader_instance_heap_realloc(
489                         inst, out, total_size, total_size * 2,
490                         VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
491                     if (NULL == out) {
492                         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
493                                    "Out of memory can't realloc space for "
494                                    "registry data");
495                         return NULL;
496                     }
497                     total_size *= 2;
498                 }
499                 if (strlen(out) == 0)
500                     snprintf(out, name_size + 1, "%s", name);
501                 else
502                     snprintf(out + strlen(out), name_size + 2, "%c%s",
503                              PATH_SEPARATOR, name);
504             }
505             name_size = 2048;
506         }
507         loc = next;
508     }
509
510     return out;
511 }
512
513 #endif // WIN32
514
515 /**
516  * Combine path elements, separating each element with the platform-specific
517  * directory separator, and save the combined string to a destination buffer,
518  * not exceeding the given length. Path elements are given as variadic args,
519  * with a NULL element terminating the list.
520  *
521  * \returns the total length of the combined string, not including an ASCII
522  * NUL termination character. This length may exceed the available storage:
523  * in this case, the written string will be truncated to avoid a buffer
524  * overrun, and the return value will greater than or equal to the storage
525  * size. A NULL argument may be provided as the destination buffer in order
526  * to determine the required string length without actually writing a string.
527  */
528
529 static size_t loader_platform_combine_path(char *dest, size_t len, ...) {
530     size_t required_len = 0;
531     va_list ap;
532     const char *component;
533
534     va_start(ap, len);
535
536     while ((component = va_arg(ap, const char *))) {
537         if (required_len > 0) {
538             // This path element is not the first non-empty element; prepend
539             // a directory separator if space allows
540             if (dest && required_len + 1 < len) {
541                 snprintf(dest + required_len, len - required_len, "%c",
542                          DIRECTORY_SYMBOL);
543             }
544             required_len++;
545         }
546
547         if (dest && required_len < len) {
548             strncpy(dest + required_len, component, len - required_len);
549         }
550         required_len += strlen(component);
551     }
552
553     va_end(ap);
554
555     // strncpy(3) won't add a NUL terminating byte in the event of truncation.
556     if (dest && required_len >= len) {
557         dest[len - 1] = '\0';
558     }
559
560     return required_len;
561 }
562
563 /**
564  * Given string of three part form "maj.min.pat" convert to a vulkan version
565  * number.
566  */
567 static uint32_t loader_make_version(char *vers_str) {
568     uint32_t vers = 0, major = 0, minor = 0, patch = 0;
569     char *vers_tok;
570
571     if (!vers_str) {
572         return vers;
573     }
574
575     vers_tok = strtok(vers_str, ".\"\n\r");
576     if (NULL != vers_tok) {
577         major = (uint16_t)atoi(vers_tok);
578         vers_tok = strtok(NULL, ".\"\n\r");
579         if (NULL != vers_tok) {
580             minor = (uint16_t)atoi(vers_tok);
581             vers_tok = strtok(NULL, ".\"\n\r");
582             if (NULL != vers_tok) {
583                 patch = (uint16_t)atoi(vers_tok);
584             }
585         }
586     }
587
588     return VK_MAKE_VERSION(major, minor, patch);
589 }
590
591 bool compare_vk_extension_properties(const VkExtensionProperties *op1,
592                                      const VkExtensionProperties *op2) {
593     return strcmp(op1->extensionName, op2->extensionName) == 0 ? true : false;
594 }
595
596 /**
597  * Search the given ext_array for an extension
598  * matching the given vk_ext_prop
599  */
600 bool has_vk_extension_property_array(const VkExtensionProperties *vk_ext_prop,
601                                      const uint32_t count,
602                                      const VkExtensionProperties *ext_array) {
603     for (uint32_t i = 0; i < count; i++) {
604         if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i]))
605             return true;
606     }
607     return false;
608 }
609
610 /**
611  * Search the given ext_list for an extension
612  * matching the given vk_ext_prop
613  */
614 bool has_vk_extension_property(const VkExtensionProperties *vk_ext_prop,
615                                const struct loader_extension_list *ext_list) {
616     for (uint32_t i = 0; i < ext_list->count; i++) {
617         if (compare_vk_extension_properties(&ext_list->list[i], vk_ext_prop))
618             return true;
619     }
620     return false;
621 }
622
623 /**
624  * Search the given ext_list for a device extension matching the given ext_prop
625  */
626 bool has_vk_dev_ext_property(
627     const VkExtensionProperties *ext_prop,
628     const struct loader_device_extension_list *ext_list) {
629     for (uint32_t i = 0; i < ext_list->count; i++) {
630         if (compare_vk_extension_properties(&ext_list->list[i].props, ext_prop))
631             return true;
632     }
633     return false;
634 }
635
636 /*
637  * Search the given layer list for a layer matching the given layer name
638  */
639 static struct loader_layer_properties *
640 loader_get_layer_property(const char *name,
641                           const struct loader_layer_list *layer_list) {
642     for (uint32_t i = 0; i < layer_list->count; i++) {
643         const VkLayerProperties *item = &layer_list->list[i].info;
644         if (strcmp(name, item->layerName) == 0)
645             return &layer_list->list[i];
646     }
647     return NULL;
648 }
649
650 /**
651  * Get the next unused layer property in the list. Init the property to zero.
652  */
653 static struct loader_layer_properties *
654 loader_get_next_layer_property(const struct loader_instance *inst,
655                                struct loader_layer_list *layer_list) {
656     if (layer_list->capacity == 0) {
657         layer_list->list = loader_instance_heap_alloc(
658             inst, sizeof(struct loader_layer_properties) * 64,
659             VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
660         if (layer_list->list == NULL) {
661             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
662                        "Out of memory can't add any layer properties to list");
663             return NULL;
664         }
665         memset(layer_list->list, 0,
666                sizeof(struct loader_layer_properties) * 64);
667         layer_list->capacity = sizeof(struct loader_layer_properties) * 64;
668     }
669
670     // ensure enough room to add an entry
671     if ((layer_list->count + 1) * sizeof(struct loader_layer_properties) >
672         layer_list->capacity) {
673         layer_list->list = loader_instance_heap_realloc(
674             inst, layer_list->list, layer_list->capacity,
675             layer_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
676         if (layer_list->list == NULL) {
677             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
678                        "realloc failed for layer list");
679             return NULL;
680         }
681         layer_list->capacity *= 2;
682     }
683
684     layer_list->count++;
685     return &(layer_list->list[layer_list->count - 1]);
686 }
687
688 /**
689  * Remove all layer properties entrys from the list
690  */
691 void loader_delete_layer_properties(const struct loader_instance *inst,
692                                     struct loader_layer_list *layer_list) {
693     uint32_t i, j;
694     struct loader_device_extension_list *dev_ext_list;
695     if (!layer_list)
696         return;
697
698     for (i = 0; i < layer_list->count; i++) {
699         loader_destroy_generic_list(
700             inst, (struct loader_generic_list *)&layer_list->list[i]
701                       .instance_extension_list);
702         dev_ext_list = &layer_list->list[i].device_extension_list;
703         if (dev_ext_list->capacity > 0 && NULL != dev_ext_list->list &&
704             dev_ext_list->list->entrypoint_count > 0) {
705             for (j = 0; j < dev_ext_list->list->entrypoint_count; j++) {
706                 loader_instance_heap_free(inst,
707                                           dev_ext_list->list->entrypoints[j]);
708             }
709             loader_instance_heap_free(inst, dev_ext_list->list->entrypoints);
710         }
711         loader_destroy_generic_list(inst,
712                                     (struct loader_generic_list *)dev_ext_list);
713     }
714     layer_list->count = 0;
715
716     if (layer_list->capacity > 0) {
717         layer_list->capacity = 0;
718         loader_instance_heap_free(inst, layer_list->list);
719     }
720 }
721
722 static VkResult loader_add_instance_extensions(
723     const struct loader_instance *inst,
724     const PFN_vkEnumerateInstanceExtensionProperties fp_get_props,
725     const char *lib_name, struct loader_extension_list *ext_list) {
726     uint32_t i, count = 0;
727     VkExtensionProperties *ext_props;
728     VkResult res = VK_SUCCESS;
729
730     if (!fp_get_props) {
731         /* No EnumerateInstanceExtensionProperties defined */
732         goto out;
733     }
734
735     res = fp_get_props(NULL, &count, NULL);
736     if (res != VK_SUCCESS) {
737         loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
738                    "Error getting Instance extension count from %s", lib_name);
739         goto out;
740     }
741
742     if (count == 0) {
743         /* No ExtensionProperties to report */
744         goto out;
745     }
746
747     ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
748
749     res = fp_get_props(NULL, &count, ext_props);
750     if (res != VK_SUCCESS) {
751         loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
752                    "Error getting Instance extensions from %s", lib_name);
753         goto out;
754     }
755
756     for (i = 0; i < count; i++) {
757         char spec_version[64];
758
759         bool ext_unsupported =
760             wsi_unsupported_instance_extension(&ext_props[i]);
761         if (!ext_unsupported) {
762             snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
763                      VK_MAJOR(ext_props[i].specVersion),
764                      VK_MINOR(ext_props[i].specVersion),
765                      VK_PATCH(ext_props[i].specVersion));
766             loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
767                        "Instance Extension: %s (%s) version %s",
768                        ext_props[i].extensionName, lib_name, spec_version);
769             res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
770             if (res != VK_SUCCESS) {
771                 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
772                            "Failed to add %s to Instance extension list",
773                            lib_name);
774                 goto out;
775             }
776         }
777     }
778 out:
779     return res;
780 }
781
782 /*
783  * Initialize ext_list with the physical device extensions.
784  * The extension properties are passed as inputs in count and ext_props.
785  */
786 static VkResult
787 loader_init_device_extensions(const struct loader_instance *inst,
788                               struct loader_physical_device_term *phys_dev_term,
789                               uint32_t count, VkExtensionProperties *ext_props,
790                               struct loader_extension_list *ext_list) {
791     VkResult res;
792     uint32_t i;
793
794     res = loader_init_generic_list(inst, (struct loader_generic_list *)ext_list,
795                                    sizeof(VkExtensionProperties));
796     if (VK_SUCCESS != res) {
797         return res;
798     }
799
800     for (i = 0; i < count; i++) {
801         char spec_version[64];
802
803         snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
804                  VK_MAJOR(ext_props[i].specVersion),
805                  VK_MINOR(ext_props[i].specVersion),
806                  VK_PATCH(ext_props[i].specVersion));
807         loader_log(
808             inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
809             "Device Extension: %s (%s) version %s", ext_props[i].extensionName,
810             phys_dev_term->this_icd_term->scanned_icd->lib_name, spec_version);
811         res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
812         if (res != VK_SUCCESS)
813             return res;
814     }
815
816     return VK_SUCCESS;
817 }
818
819 VkResult loader_add_device_extensions(const struct loader_instance *inst,
820                                       PFN_vkEnumerateDeviceExtensionProperties
821                                           fpEnumerateDeviceExtensionProperties,
822                                       VkPhysicalDevice physical_device,
823                                       const char *lib_name,
824                                       struct loader_extension_list *ext_list) {
825     uint32_t i, count;
826     VkResult res;
827     VkExtensionProperties *ext_props;
828
829     res = fpEnumerateDeviceExtensionProperties(physical_device, NULL, &count,
830                                                NULL);
831     if (res == VK_SUCCESS && count > 0) {
832         ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
833         if (!ext_props) {
834             return VK_ERROR_OUT_OF_HOST_MEMORY;
835         }
836         res = fpEnumerateDeviceExtensionProperties(physical_device, NULL,
837                                                    &count, ext_props);
838         if (res != VK_SUCCESS) {
839             return res;
840         }
841         for (i = 0; i < count; i++) {
842             char spec_version[64];
843
844             snprintf(spec_version, sizeof(spec_version), "%d.%d.%d",
845                      VK_MAJOR(ext_props[i].specVersion),
846                      VK_MINOR(ext_props[i].specVersion),
847                      VK_PATCH(ext_props[i].specVersion));
848             loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
849                        "Device Extension: %s (%s) version %s",
850                        ext_props[i].extensionName, lib_name, spec_version);
851             res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
852             if (res != VK_SUCCESS)
853                 return res;
854         }
855     } else {
856         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
857                    "Error getting physical device extension info count from "
858                    "library %s",
859                    lib_name);
860         return res;
861     }
862
863     return VK_SUCCESS;
864 }
865
866 VkResult loader_init_generic_list(const struct loader_instance *inst,
867                                   struct loader_generic_list *list_info,
868                                   size_t element_size) {
869     size_t capacity = 32 * element_size;
870     list_info->count = 0;
871     list_info->capacity = 0;
872     list_info->list = loader_instance_heap_alloc(
873         inst, capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
874     if (list_info->list == NULL) {
875         return VK_ERROR_OUT_OF_HOST_MEMORY;
876     }
877     memset(list_info->list, 0, capacity);
878     list_info->capacity = capacity;
879     return VK_SUCCESS;
880 }
881
882 void loader_destroy_generic_list(const struct loader_instance *inst,
883                                  struct loader_generic_list *list) {
884     loader_instance_heap_free(inst, list->list);
885     list->count = 0;
886     list->capacity = 0;
887 }
888
889 /*
890  * Append non-duplicate extension properties defined in props
891  * to the given ext_list.
892  * Return
893  *  Vk_SUCCESS on success
894  */
895 VkResult loader_add_to_ext_list(const struct loader_instance *inst,
896                                 struct loader_extension_list *ext_list,
897                                 uint32_t prop_list_count,
898                                 const VkExtensionProperties *props) {
899     uint32_t i;
900     const VkExtensionProperties *cur_ext;
901
902     if (ext_list->list == NULL || ext_list->capacity == 0) {
903         VkResult res = loader_init_generic_list(
904             inst, (struct loader_generic_list *)ext_list,
905             sizeof(VkExtensionProperties));
906         if (VK_SUCCESS != res) {
907             return res;
908         }
909     }
910
911     for (i = 0; i < prop_list_count; i++) {
912         cur_ext = &props[i];
913
914         // look for duplicates
915         if (has_vk_extension_property(cur_ext, ext_list)) {
916             continue;
917         }
918
919         // add to list at end
920         // check for enough capacity
921         if (ext_list->count * sizeof(VkExtensionProperties) >=
922             ext_list->capacity) {
923
924             ext_list->list = loader_instance_heap_realloc(
925                 inst, ext_list->list, ext_list->capacity,
926                 ext_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
927
928             if (ext_list->list == NULL)
929                 return VK_ERROR_OUT_OF_HOST_MEMORY;
930
931             // double capacity
932             ext_list->capacity *= 2;
933         }
934
935         memcpy(&ext_list->list[ext_list->count], cur_ext,
936                sizeof(VkExtensionProperties));
937         ext_list->count++;
938     }
939     return VK_SUCCESS;
940 }
941
942 /*
943  * Append one extension property defined in props with entrypoints
944  * defined in entrys to the given ext_list. Do not append if a duplicate
945  * Return
946  *  Vk_SUCCESS on success
947  */
948 VkResult
949 loader_add_to_dev_ext_list(const struct loader_instance *inst,
950                            struct loader_device_extension_list *ext_list,
951                            const VkExtensionProperties *props,
952                            uint32_t entry_count, char **entrys) {
953     uint32_t idx;
954     if (ext_list->list == NULL || ext_list->capacity == 0) {
955         VkResult res = loader_init_generic_list(
956             inst, (struct loader_generic_list *)ext_list,
957             sizeof(struct loader_dev_ext_props));
958         if (VK_SUCCESS != res) {
959             return res;
960         }
961     }
962
963     // look for duplicates
964     if (has_vk_dev_ext_property(props, ext_list)) {
965         return VK_SUCCESS;
966     }
967
968     idx = ext_list->count;
969     // add to list at end
970     // check for enough capacity
971     if (idx * sizeof(struct loader_dev_ext_props) >= ext_list->capacity) {
972
973         ext_list->list = loader_instance_heap_realloc(
974             inst, ext_list->list, ext_list->capacity, ext_list->capacity * 2,
975             VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
976
977         if (ext_list->list == NULL)
978             return VK_ERROR_OUT_OF_HOST_MEMORY;
979
980         // double capacity
981         ext_list->capacity *= 2;
982     }
983
984     memcpy(&ext_list->list[idx].props, props,
985            sizeof(struct loader_dev_ext_props));
986     ext_list->list[idx].entrypoint_count = entry_count;
987     ext_list->list[idx].entrypoints =
988         loader_instance_heap_alloc(inst, sizeof(char *) * entry_count,
989                                    VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
990     if (ext_list->list[idx].entrypoints == NULL) {
991         ext_list->list[idx].entrypoint_count = 0;
992         return VK_ERROR_OUT_OF_HOST_MEMORY;
993     }
994     for (uint32_t i = 0; i < entry_count; i++) {
995         ext_list->list[idx].entrypoints[i] = loader_instance_heap_alloc(
996             inst, strlen(entrys[i]) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
997         if (ext_list->list[idx].entrypoints[i] == NULL) {
998             for (uint32_t j = 0; j < i; j++) {
999                 loader_instance_heap_free(inst,
1000                                           ext_list->list[idx].entrypoints[j]);
1001             }
1002             loader_instance_heap_free(inst, ext_list->list[idx].entrypoints);
1003             ext_list->list[idx].entrypoint_count = 0;
1004             ext_list->list[idx].entrypoints = NULL;
1005             return VK_ERROR_OUT_OF_HOST_MEMORY;
1006         }
1007         strcpy(ext_list->list[idx].entrypoints[i], entrys[i]);
1008     }
1009     ext_list->count++;
1010
1011     return VK_SUCCESS;
1012 }
1013
1014 /**
1015  * Search the given search_list for any layers in the props list.
1016  * Add these to the output layer_list.  Don't add duplicates to the output
1017  * layer_list.
1018  */
1019 static VkResult
1020 loader_add_layer_names_to_list(const struct loader_instance *inst,
1021                                struct loader_layer_list *output_list,
1022                                uint32_t name_count, const char *const *names,
1023                                const struct loader_layer_list *search_list) {
1024     struct loader_layer_properties *layer_prop;
1025     VkResult err = VK_SUCCESS;
1026
1027     for (uint32_t i = 0; i < name_count; i++) {
1028         const char *search_target = names[i];
1029         layer_prop = loader_get_layer_property(search_target, search_list);
1030         if (!layer_prop) {
1031             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1032                        "Unable to find layer %s", search_target);
1033             err = VK_ERROR_LAYER_NOT_PRESENT;
1034             continue;
1035         }
1036
1037         err = loader_add_to_layer_list(inst, output_list, 1, layer_prop);
1038     }
1039
1040     return err;
1041 }
1042
1043 /*
1044  * Manage lists of VkLayerProperties
1045  */
1046 static bool loader_init_layer_list(const struct loader_instance *inst,
1047                                    struct loader_layer_list *list) {
1048     list->capacity = 32 * sizeof(struct loader_layer_properties);
1049     list->list = loader_instance_heap_alloc(
1050         inst, list->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1051     if (list->list == NULL) {
1052         return false;
1053     }
1054     memset(list->list, 0, list->capacity);
1055     list->count = 0;
1056     return true;
1057 }
1058
1059 void loader_destroy_layer_list(const struct loader_instance *inst,
1060                                struct loader_device *device,
1061                                struct loader_layer_list *layer_list) {
1062     if (device) {
1063         loader_device_heap_free(device, layer_list->list);
1064     } else {
1065         loader_instance_heap_free(inst, layer_list->list);
1066     }
1067     layer_list->count = 0;
1068     layer_list->capacity = 0;
1069 }
1070
1071 /*
1072  * Search the given layer list for a list
1073  * matching the given VkLayerProperties
1074  */
1075 bool has_vk_layer_property(const VkLayerProperties *vk_layer_prop,
1076                            const struct loader_layer_list *list) {
1077     for (uint32_t i = 0; i < list->count; i++) {
1078         if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0)
1079             return true;
1080     }
1081     return false;
1082 }
1083
1084 /*
1085  * Search the given layer list for a layer
1086  * matching the given name
1087  */
1088 bool has_layer_name(const char *name, const struct loader_layer_list *list) {
1089     for (uint32_t i = 0; i < list->count; i++) {
1090         if (strcmp(name, list->list[i].info.layerName) == 0)
1091             return true;
1092     }
1093     return false;
1094 }
1095
1096 /*
1097  * Append non-duplicate layer properties defined in prop_list
1098  * to the given layer_info list
1099  */
1100 VkResult loader_add_to_layer_list(const struct loader_instance *inst,
1101                                   struct loader_layer_list *list,
1102                                   uint32_t prop_list_count,
1103                                   const struct loader_layer_properties *props) {
1104     uint32_t i;
1105     struct loader_layer_properties *layer;
1106
1107     if (list->list == NULL || list->capacity == 0) {
1108         loader_init_layer_list(inst, list);
1109     }
1110
1111     if (list->list == NULL)
1112         return VK_SUCCESS;
1113
1114     for (i = 0; i < prop_list_count; i++) {
1115         layer = (struct loader_layer_properties *)&props[i];
1116
1117         // look for duplicates
1118         if (has_vk_layer_property(&layer->info, list)) {
1119             continue;
1120         }
1121
1122         // add to list at end
1123         // check for enough capacity
1124         if (list->count * sizeof(struct loader_layer_properties) >=
1125             list->capacity) {
1126
1127             list->list = loader_instance_heap_realloc(
1128                 inst, list->list, list->capacity, list->capacity * 2,
1129                 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1130             if (NULL == list->list) {
1131                 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1132                            "realloc failed for layer list when attempting to "
1133                            "add new layer");
1134                 return VK_ERROR_OUT_OF_HOST_MEMORY;
1135             }
1136             // double capacity
1137             list->capacity *= 2;
1138         }
1139
1140         memcpy(&list->list[list->count], layer,
1141                sizeof(struct loader_layer_properties));
1142         list->count++;
1143     }
1144
1145     return VK_SUCCESS;
1146 }
1147
1148 /**
1149  * Search the search_list for any layer with a name
1150  * that matches the given name and a type that matches the given type
1151  * Add all matching layers to the found_list
1152  * Do not add if found loader_layer_properties is already
1153  * on the found_list.
1154  */
1155 void loader_find_layer_name_add_list(
1156     const struct loader_instance *inst, const char *name,
1157     const enum layer_type type, const struct loader_layer_list *search_list,
1158     struct loader_layer_list *found_list) {
1159     bool found = false;
1160     for (uint32_t i = 0; i < search_list->count; i++) {
1161         struct loader_layer_properties *layer_prop = &search_list->list[i];
1162         if (0 == strcmp(layer_prop->info.layerName, name) &&
1163             (layer_prop->type & type)) {
1164             /* Found a layer with the same name, add to found_list */
1165             if (VK_SUCCESS ==
1166                 loader_add_to_layer_list(inst, found_list, 1, layer_prop)) {
1167                 found = true;
1168             }
1169         }
1170     }
1171     if (!found) {
1172         loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
1173                    "Warning, couldn't find layer name %s to activate", name);
1174     }
1175 }
1176
1177 static VkExtensionProperties *
1178 get_extension_property(const char *name,
1179                        const struct loader_extension_list *list) {
1180     for (uint32_t i = 0; i < list->count; i++) {
1181         if (strcmp(name, list->list[i].extensionName) == 0)
1182             return &list->list[i];
1183     }
1184     return NULL;
1185 }
1186
1187 static VkExtensionProperties *
1188 get_dev_extension_property(const char *name,
1189                            const struct loader_device_extension_list *list) {
1190     for (uint32_t i = 0; i < list->count; i++) {
1191         if (strcmp(name, list->list[i].props.extensionName) == 0)
1192             return &list->list[i].props;
1193     }
1194     return NULL;
1195 }
1196
1197 /*
1198  * For Instance extensions implemented within the loader (i.e. DEBUG_REPORT
1199  * the extension must provide two entry points for the loader to use:
1200  * - "trampoline" entry point - this is the address returned by GetProcAddr
1201  * and will always do what's necessary to support a global call.
1202  * - "terminator" function - this function will be put at the end of the
1203  * instance chain and will contain the necessary logic to call / process
1204  * the extension for the appropriate ICDs that are available.
1205  * There is no generic mechanism for including these functions, the references
1206  * must be placed into the appropriate loader entry points.
1207  * GetInstanceProcAddr: call extension GetInstanceProcAddr to check for
1208  * GetProcAddr requests
1209  * loader_coalesce_extensions(void) - add extension records to the list of
1210  * global
1211  * extension available to the app.
1212  * instance_disp - add function pointer for terminator function to this array.
1213  * The extension itself should be in a separate file that will be
1214  * linked directly with the loader.
1215  */
1216
1217 VkResult loader_get_icd_loader_instance_extensions(
1218     const struct loader_instance *inst,
1219     struct loader_icd_tramp_list *icd_tramp_list,
1220     struct loader_extension_list *inst_exts) {
1221     struct loader_extension_list icd_exts;
1222     VkResult res = VK_SUCCESS;
1223
1224     loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
1225                "Build ICD instance extension list");
1226
1227     // traverse scanned icd list adding non-duplicate extensions to the list
1228     for (uint32_t i = 0; i < icd_tramp_list->count; i++) {
1229         res = loader_init_generic_list(inst,
1230                                        (struct loader_generic_list *)&icd_exts,
1231                                        sizeof(VkExtensionProperties));
1232         if (VK_SUCCESS != res) {
1233             goto out;
1234         }
1235         res = loader_add_instance_extensions(
1236             inst, icd_tramp_list->scanned_list[i]
1237                       .EnumerateInstanceExtensionProperties,
1238             icd_tramp_list->scanned_list[i].lib_name, &icd_exts);
1239         if (VK_SUCCESS == res) {
1240             res = loader_add_to_ext_list(inst, inst_exts, icd_exts.count,
1241                                          icd_exts.list);
1242         }
1243         loader_destroy_generic_list(inst,
1244                                     (struct loader_generic_list *)&icd_exts);
1245         if (VK_SUCCESS != res) {
1246             goto out;
1247         }
1248     };
1249
1250     // Traverse loader's extensions, adding non-duplicate extensions to the list
1251     debug_report_add_instance_extensions(inst, inst_exts);
1252
1253 out:
1254     return res;
1255 }
1256
1257 struct loader_icd_term *
1258 loader_get_icd_and_device(const VkDevice device,
1259                           struct loader_device **found_dev,
1260                           uint32_t *icd_index) {
1261     *found_dev = NULL;
1262     uint32_t index = 0;
1263     for (struct loader_instance *inst = loader.instances; inst;
1264          inst = inst->next) {
1265         for (struct loader_icd_term *icd_term = inst->icd_terms; icd_term;
1266              icd_term = icd_term->next) {
1267             for (struct loader_device *dev = icd_term->logical_device_list; dev;
1268                  dev = dev->next)
1269                 // Value comparison of device prevents object wrapping by layers
1270                 if (loader_get_dispatch(dev->icd_device) ==
1271                     loader_get_dispatch(device) ||
1272                     loader_get_dispatch(dev->chain_device) ==
1273                     loader_get_dispatch(device)) {
1274                     *found_dev = dev;
1275                     if (NULL != icd_index) {
1276                         *icd_index = index;
1277                     }
1278                     return icd_term;
1279                 }
1280             index++;
1281         }
1282     }
1283     return NULL;
1284 }
1285
1286 void loader_destroy_logical_device(const struct loader_instance *inst,
1287                                    struct loader_device *dev,
1288                                    const VkAllocationCallbacks *pAllocator) {
1289     if (pAllocator) {
1290         dev->alloc_callbacks = *pAllocator;
1291     }
1292     if (NULL != dev->activated_layer_list.list) {
1293         loader_deactivate_layers(inst, dev, &dev->activated_layer_list);
1294     }
1295     loader_device_heap_free(dev, dev);
1296 }
1297
1298 struct loader_device *
1299 loader_create_logical_device(const struct loader_instance *inst,
1300                              const VkAllocationCallbacks *pAllocator) {
1301     struct loader_device *new_dev;
1302 #if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
1303     {
1304 #else
1305     if (pAllocator) {
1306         new_dev = (struct loader_device *)pAllocator->pfnAllocation(
1307             pAllocator->pUserData, sizeof(struct loader_device), sizeof(int *),
1308             VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1309     } else {
1310 #endif
1311         new_dev = (struct loader_device *)malloc(sizeof(struct loader_device));
1312     }
1313
1314     if (!new_dev) {
1315         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1316                    "Failed to alloc struct loader-device");
1317         return NULL;
1318     }
1319
1320     memset(new_dev, 0, sizeof(struct loader_device));
1321     if (pAllocator) {
1322         new_dev->alloc_callbacks = *pAllocator;
1323     }
1324
1325     return new_dev;
1326 }
1327
1328 void loader_add_logical_device(const struct loader_instance *inst,
1329                                struct loader_icd_term *icd_term,
1330                                struct loader_device *dev) {
1331     dev->next = icd_term->logical_device_list;
1332     icd_term->logical_device_list = dev;
1333 }
1334
1335 void loader_remove_logical_device(const struct loader_instance *inst,
1336                                   struct loader_icd_term *icd_term,
1337                                   struct loader_device *found_dev,
1338                                   const VkAllocationCallbacks *pAllocator) {
1339     struct loader_device *dev, *prev_dev;
1340
1341     if (!icd_term || !found_dev)
1342         return;
1343
1344     prev_dev = NULL;
1345     dev = icd_term->logical_device_list;
1346     while (dev && dev != found_dev) {
1347         prev_dev = dev;
1348         dev = dev->next;
1349     }
1350
1351     if (prev_dev)
1352         prev_dev->next = found_dev->next;
1353     else
1354         icd_term->logical_device_list = found_dev->next;
1355     loader_destroy_logical_device(inst, found_dev, pAllocator);
1356 }
1357
1358 static void loader_icd_destroy(struct loader_instance *ptr_inst,
1359                                struct loader_icd_term *icd_term,
1360                                const VkAllocationCallbacks *pAllocator) {
1361     ptr_inst->total_icd_count--;
1362     for (struct loader_device *dev = icd_term->logical_device_list; dev;) {
1363         struct loader_device *next_dev = dev->next;
1364         loader_destroy_logical_device(ptr_inst, dev, pAllocator);
1365         dev = next_dev;
1366     }
1367
1368     loader_instance_heap_free(ptr_inst, icd_term);
1369 }
1370
1371 static struct loader_icd_term *
1372 loader_icd_create(const struct loader_instance *inst) {
1373     struct loader_icd_term *icd_term;
1374
1375     icd_term = loader_instance_heap_alloc(inst, sizeof(struct loader_icd_term),
1376                                           VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1377     if (!icd_term) {
1378         return NULL;
1379     }
1380
1381     memset(icd_term, 0, sizeof(struct loader_icd_term));
1382
1383     return icd_term;
1384 }
1385
1386 static struct loader_icd_term *
1387 loader_icd_add(struct loader_instance *ptr_inst,
1388                const struct loader_scanned_icd *scanned_icd) {
1389     struct loader_icd_term *icd_term;
1390
1391     icd_term = loader_icd_create(ptr_inst);
1392     if (!icd_term) {
1393         return NULL;
1394     }
1395
1396     icd_term->scanned_icd = scanned_icd;
1397     icd_term->this_instance = ptr_inst;
1398
1399     /* prepend to the list */
1400     icd_term->next = ptr_inst->icd_terms;
1401     ptr_inst->icd_terms = icd_term;
1402     ptr_inst->total_icd_count++;
1403
1404     return icd_term;
1405 }
1406
1407 /**
1408  * Determine the ICD interface version to use.
1409  * @param icd
1410  * @param pVersion Output parameter indicating which version to use or 0 if
1411  * the negotiation API is not supported by the ICD
1412  * @return  bool indicating true if the selected interface version is supported
1413  *          by the loader, false indicates the version is not supported
1414  * version 0   doesn't support vk_icdGetInstanceProcAddr nor
1415  *             vk_icdNegotiateLoaderICDInterfaceVersion
1416  * version 1   supports vk_icdGetInstanceProcAddr
1417  * version 2   supports vk_icdNegotiateLoaderICDInterfaceVersion
1418  */
1419 bool loader_get_icd_interface_version(
1420     PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version,
1421     uint32_t *pVersion) {
1422
1423     if (fp_negotiate_icd_version == NULL) {
1424         // ICD does not support the negotiation API, it supports version 0 or 1
1425         // calling code must determine if it is version 0 or 1
1426         *pVersion = 0;
1427     } else {
1428         // ICD supports the negotiation API, so call it with the loader's
1429         // latest version supported
1430         *pVersion = CURRENT_LOADER_ICD_INTERFACE_VERSION;
1431         VkResult result = fp_negotiate_icd_version(pVersion);
1432
1433         if (result == VK_ERROR_INCOMPATIBLE_DRIVER) {
1434             // ICD no longer supports the loader's latest interface version so
1435             // fail loading the ICD
1436             return false;
1437         }
1438     }
1439
1440 #if MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION > 0
1441     if (*pVersion < MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION) {
1442         // Loader no longer supports the ICD's latest interface version so fail
1443         // loading the ICD
1444         return false;
1445     }
1446 #endif
1447     return true;
1448 }
1449
1450 void loader_scanned_icd_clear(const struct loader_instance *inst,
1451                               struct loader_icd_tramp_list *icd_tramp_list) {
1452     if (icd_tramp_list->capacity == 0)
1453         return;
1454     for (uint32_t i = 0; i < icd_tramp_list->count; i++) {
1455         loader_platform_close_library(icd_tramp_list->scanned_list[i].handle);
1456         loader_instance_heap_free(inst,
1457                                   icd_tramp_list->scanned_list[i].lib_name);
1458     }
1459     loader_instance_heap_free(inst, icd_tramp_list->scanned_list);
1460     icd_tramp_list->capacity = 0;
1461     icd_tramp_list->count = 0;
1462     icd_tramp_list->scanned_list = NULL;
1463 }
1464
1465 static VkResult
1466 loader_scanned_icd_init(const struct loader_instance *inst,
1467                         struct loader_icd_tramp_list *icd_tramp_list) {
1468     VkResult err = VK_SUCCESS;
1469     loader_scanned_icd_clear(inst, icd_tramp_list);
1470     icd_tramp_list->capacity = 8 * sizeof(struct loader_scanned_icd);
1471     icd_tramp_list->scanned_list = loader_instance_heap_alloc(
1472         inst, icd_tramp_list->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1473     if (NULL == icd_tramp_list->scanned_list) {
1474         loader_log(
1475             inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1476             "realloc failed for layer list when attempting to add new layer");
1477         err = VK_ERROR_OUT_OF_HOST_MEMORY;
1478     }
1479     return err;
1480 }
1481
1482 static VkResult
1483 loader_scanned_icd_add(const struct loader_instance *inst,
1484                        struct loader_icd_tramp_list *icd_tramp_list,
1485                        const char *filename, uint32_t api_version) {
1486     loader_platform_dl_handle handle;
1487     PFN_vkCreateInstance fp_create_inst;
1488     PFN_vkEnumerateInstanceExtensionProperties fp_get_inst_ext_props;
1489     PFN_vkGetInstanceProcAddr fp_get_proc_addr;
1490     PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version;
1491     struct loader_scanned_icd *new_scanned_icd;
1492     uint32_t interface_vers;
1493     VkResult res = VK_SUCCESS;
1494
1495     /* TODO implement smarter opening/closing of libraries. For now this
1496      * function leaves libraries open and the scanned_icd_clear closes them */
1497     handle = loader_platform_open_library(filename);
1498     if (!handle) {
1499         loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
1500                    loader_platform_open_library_error(filename));
1501         goto out;
1502     }
1503
1504     // Get and settle on an ICD interface version
1505     fp_negotiate_icd_version = loader_platform_get_proc_address(
1506         handle, "vk_icdNegotiateLoaderICDInterfaceVersion");
1507
1508     if (!loader_get_icd_interface_version(fp_negotiate_icd_version,
1509                                           &interface_vers)) {
1510         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1511                    "ICD (%s) doesn't support interface version compatible"
1512                    "with loader, skip this ICD %s",
1513                    filename);
1514         goto out;
1515     }
1516
1517     fp_get_proc_addr =
1518         loader_platform_get_proc_address(handle, "vk_icdGetInstanceProcAddr");
1519     if (!fp_get_proc_addr) {
1520         assert(interface_vers == 0);
1521         // Use deprecated interface from version 0
1522         fp_get_proc_addr =
1523             loader_platform_get_proc_address(handle, "vkGetInstanceProcAddr");
1524         if (!fp_get_proc_addr) {
1525             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1526                        loader_platform_get_proc_address_error(
1527                            "vk_icdGetInstanceProcAddr"));
1528             goto out;
1529         } else {
1530             loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
1531                        "Using deprecated ICD interface of "
1532                        "vkGetInstanceProcAddr instead of "
1533                        "vk_icdGetInstanceProcAddr for ICD %s",
1534                        filename);
1535         }
1536         fp_create_inst =
1537             loader_platform_get_proc_address(handle, "vkCreateInstance");
1538         if (!fp_create_inst) {
1539             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1540                        "Couldn't get vkCreateInstance via dlsym/loadlibrary "
1541                        "for ICD %s",
1542                        filename);
1543             goto out;
1544         }
1545         fp_get_inst_ext_props = loader_platform_get_proc_address(
1546             handle, "vkEnumerateInstanceExtensionProperties");
1547         if (!fp_get_inst_ext_props) {
1548             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1549                        "Couldn't get vkEnumerateInstanceExtensionProperties "
1550                        "via dlsym/loadlibrary for ICD %s",
1551                        filename);
1552             goto out;
1553         }
1554     } else {
1555         // Use newer interface version 1 or later
1556         if (interface_vers == 0)
1557             interface_vers = 1;
1558
1559         fp_create_inst =
1560             (PFN_vkCreateInstance)fp_get_proc_addr(NULL, "vkCreateInstance");
1561         if (!fp_create_inst) {
1562             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1563                        "Couldn't get vkCreateInstance via "
1564                        "vk_icdGetInstanceProcAddr for ICD %s",
1565                        filename);
1566             goto out;
1567         }
1568         fp_get_inst_ext_props =
1569             (PFN_vkEnumerateInstanceExtensionProperties)fp_get_proc_addr(
1570                 NULL, "vkEnumerateInstanceExtensionProperties");
1571         if (!fp_get_inst_ext_props) {
1572             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1573                        "Couldn't get vkEnumerateInstanceExtensionProperties "
1574                        "via vk_icdGetInstanceProcAddr for ICD %s",
1575                        filename);
1576             goto out;
1577         }
1578     }
1579
1580     // check for enough capacity
1581     if ((icd_tramp_list->count * sizeof(struct loader_scanned_icd)) >=
1582         icd_tramp_list->capacity) {
1583
1584         icd_tramp_list->scanned_list = loader_instance_heap_realloc(
1585             inst, icd_tramp_list->scanned_list, icd_tramp_list->capacity,
1586             icd_tramp_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1587         if (NULL == icd_tramp_list->scanned_list) {
1588             res = VK_ERROR_OUT_OF_HOST_MEMORY;
1589             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1590                        "realloc failed on icd library list");
1591             goto out;
1592         }
1593         // double capacity
1594         icd_tramp_list->capacity *= 2;
1595     }
1596     new_scanned_icd = &(icd_tramp_list->scanned_list[icd_tramp_list->count]);
1597
1598     new_scanned_icd->handle = handle;
1599     new_scanned_icd->api_version = api_version;
1600     new_scanned_icd->GetInstanceProcAddr = fp_get_proc_addr;
1601     new_scanned_icd->EnumerateInstanceExtensionProperties =
1602         fp_get_inst_ext_props;
1603     new_scanned_icd->CreateInstance = fp_create_inst;
1604     new_scanned_icd->interface_version = interface_vers;
1605
1606     new_scanned_icd->lib_name = (char *)loader_instance_heap_alloc(
1607         inst, strlen(filename) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1608     if (NULL == new_scanned_icd->lib_name) {
1609         res = VK_ERROR_OUT_OF_HOST_MEMORY;
1610         loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
1611                    "Out of memory can't add icd");
1612         goto out;
1613     }
1614     strcpy(new_scanned_icd->lib_name, filename);
1615     icd_tramp_list->count++;
1616
1617 out:
1618
1619     return res;
1620 }
1621
1622 static bool loader_icd_init_entrys(struct loader_icd_term *icd_term,
1623                                    VkInstance inst,
1624                                    const PFN_vkGetInstanceProcAddr fp_gipa) {
1625 /* initialize entrypoint function pointers */
1626
1627 #define LOOKUP_GIPA(func, required)                                            \
1628     do {                                                                       \
1629         icd_term->func = (PFN_vk##func)fp_gipa(inst, "vk" #func);              \
1630         if (!icd_term->func && required) {                                     \
1631             loader_log((struct loader_instance *)inst,                         \
1632                        VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,                     \
1633                        loader_platform_get_proc_address_error("vk" #func));    \
1634             return false;                                                      \
1635         }                                                                      \
1636     } while (0)
1637
1638     LOOKUP_GIPA(GetDeviceProcAddr, true);
1639     LOOKUP_GIPA(DestroyInstance, true);
1640     LOOKUP_GIPA(EnumeratePhysicalDevices, true);
1641     LOOKUP_GIPA(GetPhysicalDeviceFeatures, true);
1642     LOOKUP_GIPA(GetPhysicalDeviceFormatProperties, true);
1643     LOOKUP_GIPA(GetPhysicalDeviceImageFormatProperties, true);
1644     LOOKUP_GIPA(CreateDevice, true);
1645     LOOKUP_GIPA(GetPhysicalDeviceProperties, true);
1646     LOOKUP_GIPA(GetPhysicalDeviceMemoryProperties, true);
1647     LOOKUP_GIPA(GetPhysicalDeviceQueueFamilyProperties, true);
1648     LOOKUP_GIPA(EnumerateDeviceExtensionProperties, true);
1649     LOOKUP_GIPA(GetPhysicalDeviceSparseImageFormatProperties, true);
1650     LOOKUP_GIPA(CreateDebugReportCallbackEXT, false);
1651     LOOKUP_GIPA(DestroyDebugReportCallbackEXT, false);
1652     LOOKUP_GIPA(DebugMarkerSetObjectTagEXT, false);
1653     LOOKUP_GIPA(DebugMarkerSetObjectNameEXT, false);
1654     LOOKUP_GIPA(GetPhysicalDeviceSurfaceSupportKHR, false);
1655     LOOKUP_GIPA(GetPhysicalDeviceSurfaceCapabilitiesKHR, false);
1656     LOOKUP_GIPA(GetPhysicalDeviceSurfaceFormatsKHR, false);
1657     LOOKUP_GIPA(GetPhysicalDeviceSurfacePresentModesKHR, false);
1658     LOOKUP_GIPA(GetPhysicalDeviceDisplayPropertiesKHR, false);
1659     LOOKUP_GIPA(GetDisplayModePropertiesKHR, false);
1660     LOOKUP_GIPA(CreateDisplayPlaneSurfaceKHR, false);
1661     LOOKUP_GIPA(GetPhysicalDeviceDisplayPlanePropertiesKHR, false);
1662     LOOKUP_GIPA(GetDisplayPlaneSupportedDisplaysKHR, false);
1663     LOOKUP_GIPA(CreateDisplayModeKHR, false);
1664     LOOKUP_GIPA(GetDisplayPlaneCapabilitiesKHR, false);
1665     LOOKUP_GIPA(DestroySurfaceKHR, false);
1666     LOOKUP_GIPA(CreateSwapchainKHR, false);
1667 #ifdef VK_USE_PLATFORM_WIN32_KHR
1668     LOOKUP_GIPA(CreateWin32SurfaceKHR, false);
1669     LOOKUP_GIPA(GetPhysicalDeviceWin32PresentationSupportKHR, false);
1670 #endif
1671 #ifdef VK_USE_PLATFORM_XCB_KHR
1672     LOOKUP_GIPA(CreateXcbSurfaceKHR, false);
1673     LOOKUP_GIPA(GetPhysicalDeviceXcbPresentationSupportKHR, false);
1674 #endif
1675 #ifdef VK_USE_PLATFORM_XLIB_KHR
1676     LOOKUP_GIPA(CreateXlibSurfaceKHR, false);
1677     LOOKUP_GIPA(GetPhysicalDeviceXlibPresentationSupportKHR, false);
1678 #endif
1679 #ifdef VK_USE_PLATFORM_MIR_KHR
1680     LOOKUP_GIPA(CreateMirSurfaceKHR, false);
1681     LOOKUP_GIPA(GetPhysicalDeviceMirPresentationSupportKHR, false);
1682 #endif
1683 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
1684     LOOKUP_GIPA(CreateWaylandSurfaceKHR, false);
1685     LOOKUP_GIPA(GetPhysicalDeviceWaylandPresentationSupportKHR, false);
1686 #endif
1687     // NV_external_memory_capabilities
1688     LOOKUP_GIPA(GetPhysicalDeviceExternalImageFormatPropertiesNV, false);
1689     // NVX_device_generated_commands
1690     LOOKUP_GIPA(GetPhysicalDeviceGeneratedCommandsPropertiesNVX, false);
1691
1692 #undef LOOKUP_GIPA
1693
1694     return true;
1695 }
1696
1697 static void loader_debug_init(void) {
1698     char *env, *orig;
1699
1700     if (g_loader_debug > 0)
1701         return;
1702
1703     g_loader_debug = 0;
1704
1705     /* parse comma-separated debug options */
1706     orig = env = loader_getenv("VK_LOADER_DEBUG", NULL);
1707     while (env) {
1708         char *p = strchr(env, ',');
1709         size_t len;
1710
1711         if (p)
1712             len = p - env;
1713         else
1714             len = strlen(env);
1715
1716         if (len > 0) {
1717             if (strncmp(env, "all", len) == 0) {
1718                 g_loader_debug = ~0u;
1719                 g_loader_log_msgs = ~0u;
1720             } else if (strncmp(env, "warn", len) == 0) {
1721                 g_loader_debug |= LOADER_WARN_BIT;
1722                 g_loader_log_msgs |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
1723             } else if (strncmp(env, "info", len) == 0) {
1724                 g_loader_debug |= LOADER_INFO_BIT;
1725                 g_loader_log_msgs |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
1726             } else if (strncmp(env, "perf", len) == 0) {
1727                 g_loader_debug |= LOADER_PERF_BIT;
1728                 g_loader_log_msgs |=
1729                     VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
1730             } else if (strncmp(env, "error", len) == 0) {
1731                 g_loader_debug |= LOADER_ERROR_BIT;
1732                 g_loader_log_msgs |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
1733             } else if (strncmp(env, "debug", len) == 0) {
1734                 g_loader_debug |= LOADER_DEBUG_BIT;
1735                 g_loader_log_msgs |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
1736             }
1737         }
1738
1739         if (!p)
1740             break;
1741
1742         env = p + 1;
1743     }
1744
1745     loader_free_getenv(orig, NULL);
1746 }
1747
1748 void loader_initialize(void) {
1749     // initialize mutexs
1750     loader_platform_thread_create_mutex(&loader_lock);
1751     loader_platform_thread_create_mutex(&loader_json_lock);
1752
1753     // initialize logging
1754     loader_debug_init();
1755
1756     // initial cJSON to use alloc callbacks
1757     cJSON_Hooks alloc_fns = {
1758         .malloc_fn = loader_instance_tls_heap_alloc,
1759         .free_fn = loader_instance_tls_heap_free,
1760     };
1761     cJSON_InitHooks(&alloc_fns);
1762 }
1763
1764 struct loader_manifest_files {
1765     uint32_t count;
1766     char **filename_list;
1767 };
1768
1769 /**
1770  * Get next file or dirname given a string list or registry key path
1771  *
1772  * \returns
1773  * A pointer to first char in the next path.
1774  * The next path (or NULL) in the list is returned in next_path.
1775  * Note: input string is modified in some cases. PASS IN A COPY!
1776  */
1777 static char *loader_get_next_path(char *path) {
1778     uint32_t len;
1779     char *next;
1780
1781     if (path == NULL)
1782         return NULL;
1783     next = strchr(path, PATH_SEPARATOR);
1784     if (next == NULL) {
1785         len = (uint32_t)strlen(path);
1786         next = path + len;
1787     } else {
1788         *next = '\0';
1789         next++;
1790     }
1791
1792     return next;
1793 }
1794
1795 /**
1796  * Given a path which is absolute or relative, expand the path if relative or
1797  * leave the path unmodified if absolute. The base path to prepend to relative
1798  * paths is given in rel_base.
1799  *
1800  * \returns
1801  * A string in out_fullpath of the full absolute path
1802  */
1803 static void loader_expand_path(const char *path, const char *rel_base,
1804                                size_t out_size, char *out_fullpath) {
1805     if (loader_platform_is_path_absolute(path)) {
1806         // do not prepend a base to an absolute path
1807         rel_base = "";
1808     }
1809
1810     loader_platform_combine_path(out_fullpath, out_size, rel_base, path, NULL);
1811 }
1812
1813 /**
1814  * Given a filename (file)  and a list of paths (dir), try to find an existing
1815  * file in the paths.  If filename already is a path then no
1816  * searching in the given paths.
1817  *
1818  * \returns
1819  * A string in out_fullpath of either the full path or file.
1820  */
1821 static void loader_get_fullpath(const char *file, const char *dirs,
1822                                 size_t out_size, char *out_fullpath) {
1823     if (!loader_platform_is_path(file) && *dirs) {
1824         char *dirs_copy, *dir, *next_dir;
1825
1826         dirs_copy = loader_stack_alloc(strlen(dirs) + 1);
1827         strcpy(dirs_copy, dirs);
1828
1829         // find if file exists after prepending paths in given list
1830         for (dir = dirs_copy; *dir && (next_dir = loader_get_next_path(dir));
1831              dir = next_dir) {
1832             loader_platform_combine_path(out_fullpath, out_size, dir, file,
1833                                          NULL);
1834             if (loader_platform_file_exists(out_fullpath)) {
1835                 return;
1836             }
1837         }
1838     }
1839
1840     snprintf(out_fullpath, out_size, "%s", file);
1841 }
1842
1843 /**
1844  * Read a JSON file into a buffer.
1845  *
1846  * \returns
1847  * A pointer to a cJSON object representing the JSON parse tree.
1848  * This returned buffer should be freed by caller.
1849  */
1850 static VkResult loader_get_json(const struct loader_instance *inst,
1851                                 const char *filename, cJSON **json) {
1852     FILE *file = NULL;
1853     char *json_buf;
1854     size_t len;
1855     VkResult res = VK_SUCCESS;
1856
1857     if (NULL == json) {
1858         res = VK_ERROR_INITIALIZATION_FAILED;
1859         goto out;
1860     }
1861
1862     *json = NULL;
1863
1864     file = fopen(filename, "rb");
1865     if (!file) {
1866         res = VK_ERROR_INITIALIZATION_FAILED;
1867         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1868                    "Couldn't open JSON file %s", filename);
1869         goto out;
1870     }
1871     fseek(file, 0, SEEK_END);
1872     len = ftell(file);
1873     fseek(file, 0, SEEK_SET);
1874     json_buf = (char *)loader_stack_alloc(len + 1);
1875     if (json_buf == NULL) {
1876         res = VK_ERROR_OUT_OF_HOST_MEMORY;
1877         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1878                    "Out of memory can't get JSON file");
1879         goto out;
1880     }
1881     if (fread(json_buf, sizeof(char), len, file) != len) {
1882         res = VK_ERROR_INITIALIZATION_FAILED;
1883         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1884                    "fread failed can't get JSON file");
1885         goto out;
1886     }
1887     json_buf[len] = '\0';
1888
1889     // parse text from file
1890     *json = cJSON_Parse(json_buf);
1891     if (*json == NULL) {
1892         res = VK_ERROR_OUT_OF_HOST_MEMORY;
1893         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1894                    "Can't parse JSON file %s", filename);
1895         goto out;
1896     }
1897
1898 out:
1899     if (NULL != file) {
1900         fclose(file);
1901     }
1902
1903     return res;
1904 }
1905
1906 /**
1907  * Do a deep copy of the loader_layer_properties structure.
1908  */
1909 VkResult loader_copy_layer_properties(const struct loader_instance *inst,
1910                                       struct loader_layer_properties *dst,
1911                                       struct loader_layer_properties *src) {
1912     uint32_t cnt, i;
1913     memcpy(dst, src, sizeof(*src));
1914     dst->instance_extension_list.list =
1915         loader_instance_heap_alloc(inst, sizeof(VkExtensionProperties) *
1916                                              src->instance_extension_list.count,
1917                                    VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1918     if (NULL == dst->instance_extension_list.list) {
1919         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1920                    "alloc failed for instance extension list");
1921         return VK_ERROR_OUT_OF_HOST_MEMORY;
1922     }
1923     dst->instance_extension_list.capacity =
1924         sizeof(VkExtensionProperties) * src->instance_extension_list.count;
1925     memcpy(dst->instance_extension_list.list, src->instance_extension_list.list,
1926            dst->instance_extension_list.capacity);
1927     dst->device_extension_list.list =
1928         loader_instance_heap_alloc(inst, sizeof(struct loader_dev_ext_props) *
1929                                              src->device_extension_list.count,
1930                                    VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1931     if (NULL == dst->device_extension_list.list) {
1932         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1933                    "alloc failed for device extension list");
1934         return VK_ERROR_OUT_OF_HOST_MEMORY;
1935     }
1936     memset(dst->device_extension_list.list, 0,
1937            sizeof(struct loader_dev_ext_props) *
1938                src->device_extension_list.count);
1939
1940     dst->device_extension_list.capacity =
1941         sizeof(struct loader_dev_ext_props) * src->device_extension_list.count;
1942     memcpy(dst->device_extension_list.list, src->device_extension_list.list,
1943            dst->device_extension_list.capacity);
1944     if (src->device_extension_list.count > 0 &&
1945         src->device_extension_list.list->entrypoint_count > 0) {
1946         cnt = src->device_extension_list.list->entrypoint_count;
1947         dst->device_extension_list.list->entrypoints =
1948             loader_instance_heap_alloc(inst, sizeof(char *) * cnt,
1949                                        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1950         if (NULL == dst->device_extension_list.list->entrypoints) {
1951             loader_log(
1952                 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1953                 "alloc failed for device extension list entrypoint array");
1954             return VK_ERROR_OUT_OF_HOST_MEMORY;
1955         }
1956         memset(dst->device_extension_list.list->entrypoints, 0,
1957                sizeof(char *) * cnt);
1958
1959         for (i = 0; i < cnt; i++) {
1960             dst->device_extension_list.list->entrypoints[i] =
1961                 loader_instance_heap_alloc(
1962                     inst,
1963                     strlen(src->device_extension_list.list->entrypoints[i]) + 1,
1964                     VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1965             if (NULL == dst->device_extension_list.list->entrypoints[i]) {
1966                 loader_log(
1967                     inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1968                     "alloc failed for device extension list entrypoint %d", i);
1969                 return VK_ERROR_OUT_OF_HOST_MEMORY;
1970             }
1971             strcpy(dst->device_extension_list.list->entrypoints[i],
1972                    src->device_extension_list.list->entrypoints[i]);
1973         }
1974     }
1975
1976     return VK_SUCCESS;
1977 }
1978
1979 static bool
1980 loader_find_layer_name_list(const char *name,
1981                             const struct loader_layer_list *layer_list) {
1982     if (!layer_list)
1983         return false;
1984     for (uint32_t j = 0; j < layer_list->count; j++)
1985         if (!strcmp(name, layer_list->list[j].info.layerName))
1986             return true;
1987     return false;
1988 }
1989
1990 static bool loader_find_layer_name(const char *name, uint32_t layer_count,
1991                                    const char **layer_list) {
1992     if (!layer_list)
1993         return false;
1994     for (uint32_t j = 0; j < layer_count; j++)
1995         if (!strcmp(name, layer_list[j]))
1996             return true;
1997     return false;
1998 }
1999
2000 bool loader_find_layer_name_array(
2001     const char *name, uint32_t layer_count,
2002     const char layer_list[][VK_MAX_EXTENSION_NAME_SIZE]) {
2003     if (!layer_list)
2004         return false;
2005     for (uint32_t j = 0; j < layer_count; j++)
2006         if (!strcmp(name, layer_list[j]))
2007             return true;
2008     return false;
2009 }
2010
2011 /**
2012  * Searches through an array of layer names (ppp_layer_names) looking for a
2013  * layer key_name.
2014  * If not found then simply returns updating nothing.
2015  * Otherwise, it uses expand_count, expand_names adding them to layer names.
2016  * Any duplicate (pre-existing) expand_names in layer names are removed.
2017  * Order is otherwise preserved, with the layer key_name being replaced by the
2018  * expand_names.
2019  * @param inst
2020  * @param layer_count
2021  * @param ppp_layer_names
2022  */
2023 VkResult loader_expand_layer_names(
2024     struct loader_instance *inst, const char *key_name, uint32_t expand_count,
2025     const char expand_names[][VK_MAX_EXTENSION_NAME_SIZE],
2026     uint32_t *layer_count, char const *const **ppp_layer_names) {
2027
2028     char const *const *pp_src_layers = *ppp_layer_names;
2029
2030     if (!loader_find_layer_name(key_name, *layer_count,
2031                                 (char const **)pp_src_layers)) {
2032         inst->activated_layers_are_std_val = false;
2033         return VK_SUCCESS; // didn't find the key_name in the list.
2034     }
2035
2036     loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
2037                "Found meta layer %s, replacing with actual layer group",
2038                key_name);
2039
2040     inst->activated_layers_are_std_val = true;
2041     char const **pp_dst_layers = loader_instance_heap_alloc(
2042         inst, (expand_count + *layer_count - 1) * sizeof(char const *),
2043         VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
2044     if (NULL == pp_dst_layers) {
2045         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2046                    "alloc failed for dst layer array");
2047         return VK_ERROR_OUT_OF_HOST_MEMORY;
2048     }
2049
2050     // copy layers from src to dst, stripping key_name and anything in
2051     // expand_names.
2052     uint32_t src_index, dst_index = 0;
2053     for (src_index = 0; src_index < *layer_count; src_index++) {
2054         if (loader_find_layer_name_array(pp_src_layers[src_index], expand_count,
2055                                          expand_names)) {
2056             continue;
2057         }
2058
2059         if (!strcmp(pp_src_layers[src_index], key_name)) {
2060             // insert all expand_names in place of key_name
2061             uint32_t expand_index;
2062             for (expand_index = 0; expand_index < expand_count;
2063                  expand_index++) {
2064                 pp_dst_layers[dst_index++] = expand_names[expand_index];
2065             }
2066             continue;
2067         }
2068
2069         pp_dst_layers[dst_index++] = pp_src_layers[src_index];
2070     }
2071
2072     *ppp_layer_names = pp_dst_layers;
2073     *layer_count = dst_index;
2074
2075     return VK_SUCCESS;
2076 }
2077
2078 void loader_delete_shadow_inst_layer_names(const struct loader_instance *inst,
2079                                            const VkInstanceCreateInfo *orig,
2080                                            VkInstanceCreateInfo *ours) {
2081     /* Free the layer names array iff we had to reallocate it */
2082     if (orig->ppEnabledLayerNames != ours->ppEnabledLayerNames) {
2083         loader_instance_heap_free(inst, (void *)ours->ppEnabledLayerNames);
2084     }
2085 }
2086
2087 void loader_init_std_validation_props(struct loader_layer_properties *props) {
2088     memset(props, 0, sizeof(struct loader_layer_properties));
2089     props->type = VK_LAYER_TYPE_META_EXPLICT;
2090     strncpy(props->info.description, "LunarG Standard Validation Layer",
2091             sizeof(props->info.description));
2092     props->info.implementationVersion = 1;
2093     strncpy(props->info.layerName, std_validation_str,
2094             sizeof(props->info.layerName));
2095     // TODO what about specVersion? for now insert loader's built version
2096     props->info.specVersion = VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION);
2097 }
2098
2099 /**
2100  * Searches through the existing instance layer lists looking for
2101  * the set of required layer names. If found then it adds a meta property to the
2102  * layer list.
2103  * Assumes the required layers are the same for both instance and device lists.
2104  * @param inst
2105  * @param layer_count  number of layers in layer_names
2106  * @param layer_names  array of required layer names
2107  * @param layer_instance_list
2108  */
2109 static void loader_add_layer_property_meta(
2110     const struct loader_instance *inst, uint32_t layer_count,
2111     const char layer_names[][VK_MAX_EXTENSION_NAME_SIZE],
2112     struct loader_layer_list *layer_instance_list) {
2113     uint32_t i;
2114     bool found;
2115     struct loader_layer_list *layer_list;
2116
2117     if (0 == layer_count || (!layer_instance_list))
2118         return;
2119     if (layer_instance_list && (layer_count > layer_instance_list->count))
2120         return;
2121
2122     layer_list = layer_instance_list;
2123
2124     found = true;
2125     if (layer_list == NULL)
2126         return;
2127     for (i = 0; i < layer_count; i++) {
2128         if (loader_find_layer_name_list(layer_names[i], layer_list))
2129             continue;
2130         found = false;
2131         break;
2132     }
2133
2134     struct loader_layer_properties *props;
2135     if (found) {
2136         props = loader_get_next_layer_property(inst, layer_list);
2137         if (NULL == props) {
2138             // Error already triggered in loader_get_next_layer_property.
2139             return;
2140         }
2141         loader_init_std_validation_props(props);
2142     }
2143 }
2144
2145 static void loader_read_json_layer(
2146     const struct loader_instance *inst,
2147     struct loader_layer_list *layer_instance_list, cJSON *layer_node,
2148     cJSON *item, cJSON *disable_environment, bool is_implicit, char *filename) {
2149     char *temp;
2150     char *name, *type, *library_path, *api_version;
2151     char *implementation_version, *description;
2152     cJSON *ext_item;
2153     VkExtensionProperties ext_prop;
2154
2155 /*
2156  * The following are required in the "layer" object:
2157  * (required) "name"
2158  * (required) "type"
2159  * (required) “library_path”
2160  * (required) “api_version”
2161  * (required) “implementation_version”
2162  * (required) “description”
2163  * (required for implicit layers) “disable_environment”
2164  */
2165
2166 #define GET_JSON_OBJECT(node, var)                                             \
2167     {                                                                          \
2168         var = cJSON_GetObjectItem(node, #var);                                 \
2169         if (var == NULL) {                                                     \
2170             layer_node = layer_node->next;                                     \
2171             loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,               \
2172                        "Didn't find required layer object %s in manifest "     \
2173                        "JSON file, skipping this layer",                       \
2174                        #var);                                                  \
2175             return;                                                            \
2176         }                                                                      \
2177     }
2178 #define GET_JSON_ITEM(node, var)                                               \
2179     {                                                                          \
2180         item = cJSON_GetObjectItem(node, #var);                                \
2181         if (item == NULL) {                                                    \
2182             layer_node = layer_node->next;                                     \
2183             loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,               \
2184                        "Didn't find required layer value %s in manifest JSON " \
2185                        "file, skipping this layer",                            \
2186                        #var);                                                  \
2187             return;                                                            \
2188         }                                                                      \
2189         temp = cJSON_Print(item);                                              \
2190         if (temp == NULL) {                                                    \
2191             layer_node = layer_node->next;                                     \
2192             loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,               \
2193                        "Problem accessing layer value %s in manifest JSON "    \
2194                        "file, skipping this layer",                            \
2195                        #var);                                                  \
2196             return;                                                            \
2197         }                                                                      \
2198         temp[strlen(temp) - 1] = '\0';                                         \
2199         var = loader_stack_alloc(strlen(temp) + 1);                            \
2200         strcpy(var, &temp[1]);                                                 \
2201         cJSON_Free(temp);                                                      \
2202     }
2203     GET_JSON_ITEM(layer_node, name)
2204     GET_JSON_ITEM(layer_node, type)
2205     GET_JSON_ITEM(layer_node, library_path)
2206     GET_JSON_ITEM(layer_node, api_version)
2207     GET_JSON_ITEM(layer_node, implementation_version)
2208     GET_JSON_ITEM(layer_node, description)
2209     if (is_implicit) {
2210         GET_JSON_OBJECT(layer_node, disable_environment)
2211     }
2212 #undef GET_JSON_ITEM
2213 #undef GET_JSON_OBJECT
2214
2215     // add list entry
2216     struct loader_layer_properties *props = NULL;
2217     if (!strcmp(type, "DEVICE")) {
2218         loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2219                    "Device layers are deprecated skipping this layer");
2220         layer_node = layer_node->next;
2221         return;
2222     }
2223     // Allow either GLOBAL or INSTANCE type interchangeably to handle
2224     // layers that must work with older loaders
2225     if (!strcmp(type, "INSTANCE") || !strcmp(type, "GLOBAL")) {
2226         if (layer_instance_list == NULL) {
2227             layer_node = layer_node->next;
2228             return;
2229         }
2230         props = loader_get_next_layer_property(inst, layer_instance_list);
2231         if (NULL == props) {
2232             // Error already triggered in loader_get_next_layer_property.
2233             return;
2234         }
2235         props->type = (is_implicit) ? VK_LAYER_TYPE_INSTANCE_IMPLICIT
2236                                     : VK_LAYER_TYPE_INSTANCE_EXPLICIT;
2237     }
2238
2239     if (props == NULL) {
2240         layer_node = layer_node->next;
2241         return;
2242     }
2243
2244     strncpy(props->info.layerName, name, sizeof(props->info.layerName));
2245     props->info.layerName[sizeof(props->info.layerName) - 1] = '\0';
2246
2247     char *fullpath = props->lib_name;
2248     char *rel_base;
2249     if (loader_platform_is_path(library_path)) {
2250         // a relative or absolute path
2251         char *name_copy = loader_stack_alloc(strlen(filename) + 1);
2252         strcpy(name_copy, filename);
2253         rel_base = loader_platform_dirname(name_copy);
2254         loader_expand_path(library_path, rel_base, MAX_STRING_SIZE, fullpath);
2255     } else {
2256         // a filename which is assumed in a system directory
2257         loader_get_fullpath(library_path, DEFAULT_VK_LAYERS_PATH,
2258                             MAX_STRING_SIZE, fullpath);
2259     }
2260     props->info.specVersion = loader_make_version(api_version);
2261     props->info.implementationVersion = atoi(implementation_version);
2262     strncpy((char *)props->info.description, description,
2263             sizeof(props->info.description));
2264     props->info.description[sizeof(props->info.description) - 1] = '\0';
2265     if (is_implicit) {
2266         if (!disable_environment || !disable_environment->child) {
2267             loader_log(
2268                 inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2269                 "Didn't find required layer child value disable_environment"
2270                 "in manifest JSON file, skipping this layer");
2271             layer_node = layer_node->next;
2272             return;
2273         }
2274         strncpy(props->disable_env_var.name, disable_environment->child->string,
2275                 sizeof(props->disable_env_var.name));
2276         props->disable_env_var.name[sizeof(props->disable_env_var.name) - 1] =
2277             '\0';
2278         strncpy(props->disable_env_var.value,
2279                 disable_environment->child->valuestring,
2280                 sizeof(props->disable_env_var.value));
2281         props->disable_env_var.value[sizeof(props->disable_env_var.value) - 1] =
2282             '\0';
2283     }
2284
2285 /**
2286 * Now get all optional items and objects and put in list:
2287 * functions
2288 * instance_extensions
2289 * device_extensions
2290 * enable_environment (implicit layers only)
2291 */
2292 #define GET_JSON_OBJECT(node, var)                                             \
2293     { var = cJSON_GetObjectItem(node, #var); }
2294 #define GET_JSON_ITEM(node, var)                                               \
2295     {                                                                          \
2296         item = cJSON_GetObjectItem(node, #var);                                \
2297         if (item != NULL) {                                                    \
2298             temp = cJSON_Print(item);                                          \
2299             if (temp != NULL) {                                                \
2300                 temp[strlen(temp) - 1] = '\0';                                 \
2301                 var = loader_stack_alloc(strlen(temp) + 1);                    \
2302                 strcpy(var, &temp[1]);                                         \
2303                 cJSON_Free(temp);                                              \
2304             }                                                                  \
2305         }                                                                      \
2306     }
2307
2308     cJSON *instance_extensions, *device_extensions, *functions,
2309         *enable_environment;
2310     cJSON *entrypoints;
2311     char *vkGetInstanceProcAddr, *vkGetDeviceProcAddr, *spec_version;
2312     char **entry_array;
2313     vkGetInstanceProcAddr = NULL;
2314     vkGetDeviceProcAddr = NULL;
2315     spec_version = NULL;
2316     entrypoints = NULL;
2317     entry_array = NULL;
2318     int i, j;
2319
2320     /**
2321     * functions
2322     *     vkGetInstanceProcAddr
2323     *     vkGetDeviceProcAddr
2324     */
2325     GET_JSON_OBJECT(layer_node, functions)
2326     if (functions != NULL) {
2327         GET_JSON_ITEM(functions, vkGetInstanceProcAddr)
2328         GET_JSON_ITEM(functions, vkGetDeviceProcAddr)
2329         if (vkGetInstanceProcAddr != NULL)
2330             strncpy(props->functions.str_gipa, vkGetInstanceProcAddr,
2331                     sizeof(props->functions.str_gipa));
2332         props->functions.str_gipa[sizeof(props->functions.str_gipa) - 1] = '\0';
2333         if (vkGetDeviceProcAddr != NULL)
2334             strncpy(props->functions.str_gdpa, vkGetDeviceProcAddr,
2335                     sizeof(props->functions.str_gdpa));
2336         props->functions.str_gdpa[sizeof(props->functions.str_gdpa) - 1] = '\0';
2337     }
2338     /**
2339     * instance_extensions
2340     * array of
2341     *     name
2342     *     spec_version
2343     */
2344     GET_JSON_OBJECT(layer_node, instance_extensions)
2345     if (instance_extensions != NULL) {
2346         int count = cJSON_GetArraySize(instance_extensions);
2347         for (i = 0; i < count; i++) {
2348             ext_item = cJSON_GetArrayItem(instance_extensions, i);
2349             GET_JSON_ITEM(ext_item, name)
2350             if (name != NULL) {
2351                 strncpy(ext_prop.extensionName, name,
2352                         sizeof(ext_prop.extensionName));
2353                 ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] =
2354                     '\0';
2355             }
2356             GET_JSON_ITEM(ext_item, spec_version)
2357             if (NULL != spec_version) {
2358                 ext_prop.specVersion = atoi(spec_version);
2359             } else {
2360                 ext_prop.specVersion = 0;
2361             }
2362             bool ext_unsupported =
2363                 wsi_unsupported_instance_extension(&ext_prop);
2364             if (!ext_unsupported) {
2365                 loader_add_to_ext_list(inst, &props->instance_extension_list, 1,
2366                                        &ext_prop);
2367             }
2368         }
2369     }
2370     /**
2371     * device_extensions
2372     * array of
2373     *     name
2374     *     spec_version
2375     *     entrypoints
2376     */
2377     GET_JSON_OBJECT(layer_node, device_extensions)
2378     if (device_extensions != NULL) {
2379         int count = cJSON_GetArraySize(device_extensions);
2380         for (i = 0; i < count; i++) {
2381             ext_item = cJSON_GetArrayItem(device_extensions, i);
2382             GET_JSON_ITEM(ext_item, name)
2383             GET_JSON_ITEM(ext_item, spec_version)
2384             if (name != NULL) {
2385                 strncpy(ext_prop.extensionName, name,
2386                         sizeof(ext_prop.extensionName));
2387                 ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] =
2388                     '\0';
2389             }
2390             if (NULL != spec_version) {
2391                 ext_prop.specVersion = atoi(spec_version);
2392             } else {
2393                 ext_prop.specVersion = 0;
2394             }
2395             // entrypoints = cJSON_GetObjectItem(ext_item, "entrypoints");
2396             GET_JSON_OBJECT(ext_item, entrypoints)
2397             int entry_count;
2398             if (entrypoints == NULL) {
2399                 loader_add_to_dev_ext_list(inst, &props->device_extension_list,
2400                                            &ext_prop, 0, NULL);
2401                 continue;
2402             }
2403             entry_count = cJSON_GetArraySize(entrypoints);
2404             if (entry_count) {
2405                 entry_array =
2406                     (char **)loader_stack_alloc(sizeof(char *) * entry_count);
2407             }
2408             for (j = 0; j < entry_count; j++) {
2409                 ext_item = cJSON_GetArrayItem(entrypoints, j);
2410                 if (ext_item != NULL) {
2411                     temp = cJSON_Print(ext_item);
2412                     if (NULL == temp) {
2413                         entry_array[j] = NULL;
2414                         continue;
2415                     }
2416                     temp[strlen(temp) - 1] = '\0';
2417                     entry_array[j] = loader_stack_alloc(strlen(temp) + 1);
2418                     strcpy(entry_array[j], &temp[1]);
2419                     cJSON_Free(temp);
2420                 }
2421             }
2422             loader_add_to_dev_ext_list(inst, &props->device_extension_list,
2423                                        &ext_prop, entry_count, entry_array);
2424         }
2425     }
2426     if (is_implicit) {
2427         GET_JSON_OBJECT(layer_node, enable_environment)
2428
2429         // enable_environment is optional
2430         if (enable_environment) {
2431             strncpy(props->enable_env_var.name,
2432                     enable_environment->child->string,
2433                     sizeof(props->enable_env_var.name));
2434             props->enable_env_var.name[sizeof(props->enable_env_var.name) - 1] =
2435                 '\0';
2436             strncpy(props->enable_env_var.value,
2437                     enable_environment->child->valuestring,
2438                     sizeof(props->enable_env_var.value));
2439             props->enable_env_var
2440                 .value[sizeof(props->enable_env_var.value) - 1] = '\0';
2441         }
2442     }
2443 #undef GET_JSON_ITEM
2444 #undef GET_JSON_OBJECT
2445 }
2446
2447 /**
2448  * Given a cJSON struct (json) of the top level JSON object from layer manifest
2449  * file, add entry to the layer_list. Fill out the layer_properties in this list
2450  * entry from the input cJSON object.
2451  *
2452  * \returns
2453  * void
2454  * layer_list has a new entry and initialized accordingly.
2455  * If the json input object does not have all the required fields no entry
2456  * is added to the list.
2457  */
2458 static void
2459 loader_add_layer_properties(const struct loader_instance *inst,
2460                             struct loader_layer_list *layer_instance_list,
2461                             cJSON *json, bool is_implicit, char *filename) {
2462     /* Fields in layer manifest file that are required:
2463      * (required) “file_format_version”
2464      *
2465      * If more than one "layer" object are to be used, use the "layers" array
2466      * instead.
2467      *
2468      * First get all required items and if any missing abort
2469      */
2470
2471     cJSON *item, *layers_node, *layer_node;
2472     uint16_t file_major_vers = 0;
2473     uint16_t file_minor_vers = 0;
2474     uint16_t file_patch_vers = 0;
2475     char *vers_tok;
2476     cJSON *disable_environment = NULL;
2477     item = cJSON_GetObjectItem(json, "file_format_version");
2478     if (item == NULL) {
2479         return;
2480     }
2481     char *file_vers = cJSON_PrintUnformatted(item);
2482     if (NULL == file_vers) {
2483         return;
2484     }
2485     loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
2486                "Found manifest file %s, version %s", filename, file_vers);
2487     // Get the major/minor/and patch as integers for easier comparison
2488     vers_tok = strtok(file_vers, ".\"\n\r");
2489     if (NULL != vers_tok) {
2490         file_major_vers = (uint16_t)atoi(vers_tok);
2491         vers_tok = strtok(NULL, ".\"\n\r");
2492         if (NULL != vers_tok) {
2493             file_minor_vers = (uint16_t)atoi(vers_tok);
2494             vers_tok = strtok(NULL, ".\"\n\r");
2495             if (NULL != vers_tok) {
2496                 file_patch_vers = (uint16_t)atoi(vers_tok);
2497             }
2498         }
2499     }
2500     if (file_major_vers != 1 || file_minor_vers != 0 || file_patch_vers > 1) {
2501         loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2502                    "%s Unexpected manifest file version (expected 1.0.0 or "
2503                    "1.0.1), may cause errors",
2504                    filename);
2505     }
2506     cJSON_Free(file_vers);
2507     // If "layers" is present, read in the array of layer objects
2508     layers_node = cJSON_GetObjectItem(json, "layers");
2509     if (layers_node != NULL) {
2510         int numItems = cJSON_GetArraySize(layers_node);
2511         if (file_major_vers == 1 && file_minor_vers == 0 &&
2512             file_patch_vers == 0) {
2513             loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2514                        "\"layers\" tag not officially added until file version "
2515                        "1.0.1, but %s is reporting version %s",
2516                        filename, file_vers);
2517         }
2518         for (int curLayer = 0; curLayer < numItems; curLayer++) {
2519             layer_node = cJSON_GetArrayItem(layers_node, curLayer);
2520             if (layer_node == NULL) {
2521                 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2522                            "Can't find \"layers\" array element %d object in "
2523                            "manifest JSON file %s, skipping this file",
2524                            curLayer, filename);
2525                 return;
2526             }
2527             loader_read_json_layer(inst, layer_instance_list, layer_node, item,
2528                                    disable_environment, is_implicit, filename);
2529         }
2530     } else {
2531         // Otherwise, try to read in individual layers
2532         layer_node = cJSON_GetObjectItem(json, "layer");
2533         if (layer_node == NULL) {
2534             loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2535                        "Can't find \"layer\" object in manifest JSON file %s, "
2536                        "skipping this file",
2537                        filename);
2538             return;
2539         }
2540         // Loop through all "layer" objects in the file to get a count of them
2541         // first.
2542         uint16_t layer_count = 0;
2543         cJSON *tempNode = layer_node;
2544         do {
2545             tempNode = tempNode->next;
2546             layer_count++;
2547         } while (tempNode != NULL);
2548         /*
2549          * Throw a warning if we encounter multiple "layer" objects in file
2550          * versions newer than 1.0.0.  Having multiple objects with the same
2551          * name at the same level is actually a JSON standard violation.
2552          */
2553         if (layer_count > 1 &&
2554             (file_major_vers > 1 ||
2555              !(file_minor_vers == 0 && file_patch_vers == 0))) {
2556             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2557                        "Multiple \"layer\" nodes are deprecated starting in "
2558                        "file version \"1.0.1\".  Please use \"layers\" : [] "
2559                        "array instead in %s.",
2560                        filename);
2561         } else {
2562             do {
2563                 loader_read_json_layer(inst, layer_instance_list, layer_node,
2564                                        item, disable_environment, is_implicit,
2565                                        filename);
2566                 layer_node = layer_node->next;
2567             } while (layer_node != NULL);
2568         }
2569     }
2570     return;
2571 }
2572
2573 /**
2574  * Find the Vulkan library manifest files.
2575  *
2576  * This function scans the "location" or "env_override" directories/files
2577  * for a list of JSON manifest files.  If env_override is non-NULL
2578  * and has a valid value. Then the location is ignored.  Otherwise
2579  * location is used to look for manifest files. The location
2580  * is interpreted as  Registry path on Windows and a directory path(s)
2581  * on Linux. "home_location" is an additional directory in the users home
2582  * directory to look at. It is expanded into the dir path
2583  * $XDG_DATA_HOME/home_location or $HOME/.local/share/home_location depending
2584  * on environment variables. This "home_location" is only used on Linux.
2585  *
2586  * \returns
2587  * VKResult
2588  * A string list of manifest files to be opened in out_files param.
2589  * List has a pointer to string for each manifest filename.
2590  * When done using the list in out_files, pointers should be freed.
2591  * Location or override  string lists can be either files or directories as
2592  *follows:
2593  *            | location | override
2594  * --------------------------------
2595  * Win ICD    | files    | files
2596  * Win Layer  | files    | dirs
2597  * Linux ICD  | dirs     | files
2598  * Linux Layer| dirs     | dirs
2599  */
2600 static VkResult
2601 loader_get_manifest_files(const struct loader_instance *inst,
2602                           const char *env_override, const char *source_override,
2603                           bool is_layer, bool warn_if_not_present,
2604                           const char *location, const char *home_location,
2605                           struct loader_manifest_files *out_files) {
2606     const char *override = NULL;
2607     char *override_getenv = NULL;
2608     char *loc, *orig_loc = NULL;
2609     char *reg = NULL;
2610     char *file, *next_file, *name;
2611     size_t alloced_count = 64;
2612     char full_path[2048];
2613     DIR *sysdir = NULL;
2614     bool list_is_dirs = false;
2615     struct dirent *dent;
2616     VkResult res = VK_SUCCESS;
2617
2618     out_files->count = 0;
2619     out_files->filename_list = NULL;
2620
2621     if (source_override != NULL) {
2622         override = source_override;
2623     } else if (env_override != NULL) {
2624 #if !defined(_WIN32)
2625         if (geteuid() != getuid() || getegid() != getgid()) {
2626             /* Don't allow setuid apps to use the env var: */
2627             env_override = NULL;
2628         }
2629 #endif
2630         if (env_override != NULL) {
2631             override = override_getenv = loader_getenv(env_override, inst);
2632         }
2633     }
2634
2635 #if !defined(_WIN32)
2636     if (location == NULL && home_location == NULL) {
2637 #else
2638     home_location = NULL;
2639     if (location == NULL) {
2640 #endif
2641         loader_log(
2642             inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2643             "Can't get manifest files with NULL location, env_override=%s",
2644             (env_override != NULL) ? env_override : "");
2645         res = VK_ERROR_INITIALIZATION_FAILED;
2646         goto out;
2647     }
2648
2649 #if defined(_WIN32)
2650     list_is_dirs = (is_layer && override != NULL) ? true : false;
2651 #else
2652     list_is_dirs = (override == NULL || is_layer) ? true : false;
2653 #endif
2654     // Make a copy of the input we are using so it is not modified
2655     // Also handle getting the location(s) from registry on Windows
2656     if (override == NULL) {
2657         loc = loader_stack_alloc(strlen(location) + 1);
2658         if (loc == NULL) {
2659             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2660                        "Out of memory can't get manifest files");
2661             res = VK_ERROR_OUT_OF_HOST_MEMORY;
2662             goto out;
2663         }
2664         strcpy(loc, location);
2665 #if defined(_WIN32)
2666         reg = loader_get_registry_files(inst, loc);
2667         if (reg == NULL) {
2668             if (!is_layer) {
2669                 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2670                            "Registry lookup failed can't get ICD manifest "
2671                            "files, do you have a Vulkan driver installed");
2672                 // This typically only fails when out of memory, which is
2673                 // critical
2674                 // if this is for the loader.
2675                 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2676             } else {
2677                 if (warn_if_not_present) {
2678                     // warning only for layers
2679                     loader_log(
2680                         inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2681                         "Registry lookup failed can't get layer manifest files");
2682                 }
2683                 // Return success for now since it's not critical for layers
2684                 res = VK_SUCCESS;
2685             }
2686             goto out;
2687         }
2688         orig_loc = loc;
2689         loc = reg;
2690 #endif
2691     } else {
2692         loc = loader_stack_alloc(strlen(override) + 1);
2693         if (loc == NULL) {
2694             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2695                        "Out of memory can't get manifest files");
2696             res = VK_ERROR_OUT_OF_HOST_MEMORY;
2697             goto out;
2698         }
2699         strcpy(loc, override);
2700     }
2701
2702     // Print out the paths being searched if debugging is enabled
2703     loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
2704                "Searching the following paths for manifest files: %s\n", loc);
2705
2706     file = loc;
2707     while (*file) {
2708         next_file = loader_get_next_path(file);
2709         if (list_is_dirs) {
2710             sysdir = opendir(file);
2711             name = NULL;
2712             if (sysdir) {
2713                 dent = readdir(sysdir);
2714                 if (dent == NULL)
2715                     break;
2716                 name = &(dent->d_name[0]);
2717                 loader_get_fullpath(name, file, sizeof(full_path), full_path);
2718                 name = full_path;
2719             }
2720         } else {
2721 #if defined(_WIN32)
2722             name = file;
2723 #else
2724             // only Linux has relative paths
2725             char *dir;
2726             // make a copy of location so it isn't modified
2727             dir = loader_stack_alloc(strlen(loc) + 1);
2728             if (dir == NULL) {
2729                 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2730                            "Out of memory can't get manifest files");
2731                 goto out;
2732             }
2733             strcpy(dir, loc);
2734
2735             loader_get_fullpath(file, dir, sizeof(full_path), full_path);
2736
2737             name = full_path;
2738 #endif
2739         }
2740         while (name) {
2741             /* Look for files ending with ".json" suffix */
2742             uint32_t nlen = (uint32_t)strlen(name);
2743             const char *suf = name + nlen - 5;
2744             if ((nlen > 5) && !strncmp(suf, ".json", 5)) {
2745                 if (out_files->count == 0) {
2746                     out_files->filename_list = loader_instance_heap_alloc(
2747                         inst, alloced_count * sizeof(char *),
2748                         VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
2749                 } else if (out_files->count == alloced_count) {
2750                     out_files->filename_list = loader_instance_heap_realloc(
2751                         inst, out_files->filename_list,
2752                         alloced_count * sizeof(char *),
2753                         alloced_count * sizeof(char *) * 2,
2754                         VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
2755                     alloced_count *= 2;
2756                 }
2757                 if (out_files->filename_list == NULL) {
2758                     loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2759                                "Out of memory can't alloc manifest file list");
2760                     res = VK_ERROR_OUT_OF_HOST_MEMORY;
2761                     goto out;
2762                 }
2763                 out_files->filename_list[out_files->count] =
2764                     loader_instance_heap_alloc(
2765                         inst, strlen(name) + 1,
2766                         VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
2767                 if (out_files->filename_list[out_files->count] == NULL) {
2768                     loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2769                                "Out of memory can't get manifest files");
2770                     res = VK_ERROR_OUT_OF_HOST_MEMORY;
2771                     goto out;
2772                 }
2773                 strcpy(out_files->filename_list[out_files->count], name);
2774                 out_files->count++;
2775             } else if (!list_is_dirs) {
2776                 loader_log(
2777                     inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2778                     "Skipping manifest file %s, file name must end in .json",
2779                     name);
2780             }
2781             if (list_is_dirs) {
2782                 dent = readdir(sysdir);
2783                 if (dent == NULL) {
2784                     break;
2785                 }
2786                 name = &(dent->d_name[0]);
2787                 loader_get_fullpath(name, file, sizeof(full_path), full_path);
2788                 name = full_path;
2789             } else {
2790                 break;
2791             }
2792         }
2793         if (sysdir) {
2794             closedir(sysdir);
2795             sysdir = NULL;
2796         }
2797         file = next_file;
2798 #if !defined(_WIN32)
2799         if (home_location != NULL &&
2800             (next_file == NULL || *next_file == '\0') && override == NULL) {
2801             char *xdgdatahome = secure_getenv("XDG_DATA_HOME");
2802             size_t len;
2803             if (xdgdatahome != NULL) {
2804
2805                 char *home_loc = loader_stack_alloc(strlen(xdgdatahome) + 2 +
2806                                                     strlen(home_location));
2807                 if (home_loc == NULL) {
2808                     loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2809                                "Out of memory can't get manifest files");
2810                     res = VK_ERROR_OUT_OF_HOST_MEMORY;
2811                     goto out;
2812                 }
2813                 strcpy(home_loc, xdgdatahome);
2814                 // Add directory separator if needed
2815                 if (home_location[0] != DIRECTORY_SYMBOL) {
2816                     len = strlen(home_loc);
2817                     home_loc[len] = DIRECTORY_SYMBOL;
2818                     home_loc[len + 1] = '\0';
2819                 }
2820                 strcat(home_loc, home_location);
2821                 file = home_loc;
2822                 next_file = loader_get_next_path(file);
2823                 home_location = NULL;
2824
2825                 loader_log(
2826                     inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
2827                     "Searching the following path for manifest files: %s\n",
2828                     home_loc);
2829                 list_is_dirs = true;
2830
2831             } else {
2832
2833                 char *home = secure_getenv("HOME");
2834                 if (home != NULL) {
2835                     char *home_loc = loader_stack_alloc(strlen(home) + 16 +
2836                                                         strlen(home_location));
2837                     if (home_loc == NULL) {
2838                         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2839                                    "Out of memory can't get manifest files");
2840                         res = VK_ERROR_OUT_OF_HOST_MEMORY;
2841                         goto out;
2842                     }
2843                     strcpy(home_loc, home);
2844
2845                     len = strlen(home);
2846                     if (home[len] != DIRECTORY_SYMBOL) {
2847                         home_loc[len] = DIRECTORY_SYMBOL;
2848                         home_loc[len + 1] = '\0';
2849                     }
2850                     strcat(home_loc, ".local/share");
2851
2852                     if (home_location[0] != DIRECTORY_SYMBOL) {
2853                         len = strlen(home_loc);
2854                         home_loc[len] = DIRECTORY_SYMBOL;
2855                         home_loc[len + 1] = '\0';
2856                     }
2857                     strcat(home_loc, home_location);
2858                     file = home_loc;
2859                     next_file = loader_get_next_path(file);
2860                     home_location = NULL;
2861
2862                     loader_log(
2863                         inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
2864                         "Searching the following path for manifest files: %s\n",
2865                         home_loc);
2866                     list_is_dirs = true;
2867                 } else {
2868                     // without knowing HOME, we just.. give up
2869                 }
2870             }
2871         }
2872 #endif
2873     }
2874
2875 out:
2876     if (VK_SUCCESS != res && NULL != out_files->filename_list) {
2877         for (uint32_t remove = 0; remove < out_files->count; remove++) {
2878             loader_instance_heap_free(inst, out_files->filename_list[remove]);
2879         }
2880         loader_instance_heap_free(inst, out_files->filename_list);
2881         out_files->count = 0;
2882         out_files->filename_list = NULL;
2883     }
2884
2885     if (NULL != sysdir) {
2886         closedir(sysdir);
2887     }
2888
2889     if (override_getenv != NULL) {
2890         loader_free_getenv(override_getenv, inst);
2891     }
2892
2893     if (NULL != reg && reg != orig_loc) {
2894         loader_instance_heap_free(inst, reg);
2895     }
2896     return res;
2897 }
2898
2899 void loader_init_icd_lib_list() {}
2900
2901 void loader_destroy_icd_lib_list() {}
2902 /**
2903  * Try to find the Vulkan ICD driver(s).
2904  *
2905  * This function scans the default system loader path(s) or path
2906  * specified by the \c VK_ICD_FILENAMES environment variable in
2907  * order to find loadable VK ICDs manifest files. From these
2908  * manifest files it finds the ICD libraries.
2909  *
2910  * \returns
2911  * Vulkan result
2912  * (on result == VK_SUCCESS) a list of icds that were discovered
2913  */
2914 VkResult loader_icd_scan(const struct loader_instance *inst,
2915                          struct loader_icd_tramp_list *icd_tramp_list) {
2916     char *file_str;
2917     uint16_t file_major_vers = 0;
2918     uint16_t file_minor_vers = 0;
2919     uint16_t file_patch_vers = 0;
2920     char *vers_tok;
2921     struct loader_manifest_files manifest_files;
2922     VkResult res = VK_SUCCESS;
2923     bool lockedMutex = false;
2924     cJSON *json = NULL;
2925     uint32_t num_good_icds = 0;
2926
2927     memset(&manifest_files, 0, sizeof(struct loader_manifest_files));
2928
2929     res = loader_scanned_icd_init(inst, icd_tramp_list);
2930     if (VK_SUCCESS != res) {
2931         goto out;
2932     }
2933
2934     // Get a list of manifest files for ICDs
2935     res = loader_get_manifest_files(inst, "VK_ICD_FILENAMES", NULL, false,
2936                                     true, DEFAULT_VK_DRIVERS_INFO,
2937                                     HOME_VK_DRIVERS_INFO, &manifest_files);
2938     if (VK_SUCCESS != res || manifest_files.count == 0) {
2939         goto out;
2940     }
2941     loader_platform_thread_lock_mutex(&loader_json_lock);
2942     lockedMutex = true;
2943     for (uint32_t i = 0; i < manifest_files.count; i++) {
2944         file_str = manifest_files.filename_list[i];
2945         if (file_str == NULL) {
2946             continue;
2947         }
2948
2949         res = loader_get_json(inst, file_str, &json);
2950         if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
2951             break;
2952         } else if (VK_SUCCESS != res || NULL == json) {
2953             continue;
2954         }
2955
2956         cJSON *item, *itemICD;
2957         item = cJSON_GetObjectItem(json, "file_format_version");
2958         if (item == NULL) {
2959             if (num_good_icds == 0) {
2960                 res = VK_ERROR_INITIALIZATION_FAILED;
2961             }
2962             cJSON_Delete(json);
2963             json = NULL;
2964             continue;
2965         }
2966         char *file_vers = cJSON_Print(item);
2967         if (NULL == file_vers) {
2968             // Only reason the print can fail is if there was an allocation
2969             // issue
2970             if (num_good_icds == 0) {
2971                 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2972             }
2973             cJSON_Delete(json);
2974             json = NULL;
2975             continue;
2976         }
2977         loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
2978                    "Found manifest file %s, version %s", file_str, file_vers);
2979         // Get the major/minor/and patch as integers for easier comparison
2980         vers_tok = strtok(file_vers, ".\"\n\r");
2981         if (NULL != vers_tok) {
2982             file_major_vers = (uint16_t)atoi(vers_tok);
2983             vers_tok = strtok(NULL, ".\"\n\r");
2984             if (NULL != vers_tok) {
2985                 file_minor_vers = (uint16_t)atoi(vers_tok);
2986                 vers_tok = strtok(NULL, ".\"\n\r");
2987                 if (NULL != vers_tok) {
2988                     file_patch_vers = (uint16_t)atoi(vers_tok);
2989                 }
2990             }
2991         }
2992         if (file_major_vers != 1 || file_minor_vers != 0 || file_patch_vers > 1)
2993             loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2994                        "Unexpected manifest file version (expected 1.0.0 or "
2995                        "1.0.1), may "
2996                        "cause errors");
2997         cJSON_Free(file_vers);
2998         itemICD = cJSON_GetObjectItem(json, "ICD");
2999         if (itemICD != NULL) {
3000             item = cJSON_GetObjectItem(itemICD, "library_path");
3001             if (item != NULL) {
3002                 char *temp = cJSON_Print(item);
3003                 if (!temp || strlen(temp) == 0) {
3004                     loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3005                                "Can't find \"library_path\" in ICD JSON file "
3006                                "%s, skipping",
3007                                file_str);
3008                     if (num_good_icds == 0) {
3009                         res = VK_ERROR_OUT_OF_HOST_MEMORY;
3010                     }
3011                     cJSON_Free(temp);
3012                     cJSON_Delete(json);
3013                     json = NULL;
3014                     continue;
3015                 }
3016                 // strip out extra quotes
3017                 temp[strlen(temp) - 1] = '\0';
3018                 char *library_path = loader_stack_alloc(strlen(temp) + 1);
3019                 if (NULL == library_path) {
3020                     loader_log(
3021                         inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3022                         "Can't allocate space for \"library_path\" in ICD "
3023                         "JSON file %s, skipping",
3024                         file_str);
3025                     res = VK_ERROR_OUT_OF_HOST_MEMORY;
3026                     cJSON_Free(temp);
3027                     cJSON_Delete(json);
3028                     json = NULL;
3029                     goto out;
3030                 }
3031                 strcpy(library_path, &temp[1]);
3032                 cJSON_Free(temp);
3033                 if (strlen(library_path) == 0) {
3034                     loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3035                                "Can't find \"library_path\" in ICD JSON file "
3036                                "%s, skipping",
3037                                file_str);
3038                     cJSON_Delete(json);
3039                     json = NULL;
3040                     continue;
3041                 }
3042                 char fullpath[MAX_STRING_SIZE];
3043                 // Print out the paths being searched if debugging is enabled
3044                 loader_log(
3045                     inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
3046                     "Searching for ICD drivers named %s default dir %s\n",
3047                     library_path, DEFAULT_VK_DRIVERS_PATH);
3048                 if (loader_platform_is_path(library_path)) {
3049                     // a relative or absolute path
3050                     char *name_copy = loader_stack_alloc(strlen(file_str) + 1);
3051                     char *rel_base;
3052                     strcpy(name_copy, file_str);
3053                     rel_base = loader_platform_dirname(name_copy);
3054                     loader_expand_path(library_path, rel_base, sizeof(fullpath),
3055                                        fullpath);
3056                 } else {
3057                     // a filename which is assumed in a system directory
3058                     loader_get_fullpath(library_path, DEFAULT_VK_DRIVERS_PATH,
3059                                         sizeof(fullpath), fullpath);
3060                 }
3061
3062                 uint32_t vers = 0;
3063                 item = cJSON_GetObjectItem(itemICD, "api_version");
3064                 if (item != NULL) {
3065                     temp = cJSON_Print(item);
3066                     if (NULL == temp) {
3067                         // Only reason the print can fail is if there was an
3068                         // allocation issue
3069                         res = VK_ERROR_OUT_OF_HOST_MEMORY;
3070                         goto out;
3071                     }
3072                     vers = loader_make_version(temp);
3073                     cJSON_Free(temp);
3074                 }
3075                 res = loader_scanned_icd_add(inst, icd_tramp_list, fullpath,
3076                                              vers);
3077                 if (VK_SUCCESS != res) {
3078                     goto out;
3079                 }
3080                 num_good_icds++;
3081             } else {
3082                 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3083                            "Can't find \"library_path\" object in ICD JSON "
3084                            "file %s, skipping",
3085                            file_str);
3086             }
3087         } else {
3088             loader_log(
3089                 inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3090                 "Can't find \"ICD\" object in ICD JSON file %s, skipping",
3091                 file_str);
3092         }
3093
3094         cJSON_Delete(json);
3095         json = NULL;
3096     }
3097
3098 out:
3099     if (NULL != json) {
3100         cJSON_Delete(json);
3101     }
3102     if (NULL != manifest_files.filename_list) {
3103         for (uint32_t i = 0; i < manifest_files.count; i++) {
3104             if (NULL != manifest_files.filename_list[i]) {
3105                 loader_instance_heap_free(inst,
3106                                           manifest_files.filename_list[i]);
3107             }
3108         }
3109         loader_instance_heap_free(inst, manifest_files.filename_list);
3110     }
3111     if (lockedMutex) {
3112         loader_platform_thread_unlock_mutex(&loader_json_lock);
3113     }
3114     return res;
3115 }
3116
3117 void loader_layer_scan(const struct loader_instance *inst,
3118                        struct loader_layer_list *instance_layers) {
3119     char *file_str;
3120     struct loader_manifest_files
3121         manifest_files[2]; // [0] = explicit, [1] = implicit
3122     cJSON *json;
3123     uint32_t implicit;
3124     bool lockedMutex = false;
3125
3126     memset(manifest_files, 0, sizeof(struct loader_manifest_files) * 2);
3127
3128     // Get a list of manifest files for explicit layers
3129     if (VK_SUCCESS !=
3130         loader_get_manifest_files(inst, LAYERS_PATH_ENV, LAYERS_SOURCE_PATH,
3131                                   true, true, DEFAULT_VK_ELAYERS_INFO,
3132                                   HOME_VK_ELAYERS_INFO, &manifest_files[0])) {
3133         goto out;
3134     }
3135
3136     // Get a list of manifest files for any implicit layers
3137     // Pass NULL for environment variable override - implicit layers are not
3138     // overridden by LAYERS_PATH_ENV
3139     if (VK_SUCCESS != loader_get_manifest_files(inst, NULL, NULL, true, false,
3140                                                 DEFAULT_VK_ILAYERS_INFO,
3141                                                 HOME_VK_ILAYERS_INFO,
3142                                                 &manifest_files[1])) {
3143         goto out;
3144     }
3145
3146     // Make sure we have at least one layer, if not, go ahead and return
3147     if (manifest_files[0].count == 0 && manifest_files[1].count == 0) {
3148         goto out;
3149     }
3150
3151     // cleanup any previously scanned libraries
3152     loader_delete_layer_properties(inst, instance_layers);
3153
3154     loader_platform_thread_lock_mutex(&loader_json_lock);
3155     lockedMutex = true;
3156     for (implicit = 0; implicit < 2; implicit++) {
3157         for (uint32_t i = 0; i < manifest_files[implicit].count; i++) {
3158             file_str = manifest_files[implicit].filename_list[i];
3159             if (file_str == NULL)
3160                 continue;
3161
3162             // parse file into JSON struct
3163             VkResult res = loader_get_json(inst, file_str, &json);
3164             if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3165                 break;
3166             } else if (VK_SUCCESS != res || NULL == json) {
3167                 continue;
3168             }
3169
3170             loader_add_layer_properties(inst, instance_layers, json,
3171                                         (implicit == 1), file_str);
3172             cJSON_Delete(json);
3173         }
3174     }
3175
3176     // add a meta layer for validation if the validation layers are all present
3177     loader_add_layer_property_meta(inst, sizeof(std_validation_names) /
3178                                              sizeof(std_validation_names[0]),
3179                                    std_validation_names, instance_layers);
3180
3181 out:
3182
3183     for (uint32_t manFile = 0; manFile < 2; manFile++) {
3184         if (NULL != manifest_files[manFile].filename_list) {
3185             for (uint32_t i = 0; i < manifest_files[manFile].count; i++) {
3186                 if (NULL != manifest_files[manFile].filename_list[i]) {
3187                     loader_instance_heap_free(
3188                         inst, manifest_files[manFile].filename_list[i]);
3189                 }
3190             }
3191             loader_instance_heap_free(inst,
3192                                       manifest_files[manFile].filename_list);
3193         }
3194     }
3195     if (lockedMutex) {
3196         loader_platform_thread_unlock_mutex(&loader_json_lock);
3197     }
3198 }
3199
3200 void loader_implicit_layer_scan(const struct loader_instance *inst,
3201                                 struct loader_layer_list *instance_layers) {
3202     char *file_str;
3203     struct loader_manifest_files manifest_files;
3204     cJSON *json;
3205     uint32_t i;
3206
3207     // Pass NULL for environment variable override - implicit layers are not
3208     // overridden by LAYERS_PATH_ENV
3209     VkResult res = loader_get_manifest_files(
3210         inst, NULL, NULL, true, false, DEFAULT_VK_ILAYERS_INFO,
3211         HOME_VK_ILAYERS_INFO, &manifest_files);
3212     if (VK_SUCCESS != res || manifest_files.count == 0) {
3213         return;
3214     }
3215
3216     /* cleanup any previously scanned libraries */
3217     loader_delete_layer_properties(inst, instance_layers);
3218
3219     loader_platform_thread_lock_mutex(&loader_json_lock);
3220
3221     for (i = 0; i < manifest_files.count; i++) {
3222         file_str = manifest_files.filename_list[i];
3223         if (file_str == NULL) {
3224             continue;
3225         }
3226
3227         // parse file into JSON struct
3228         res = loader_get_json(inst, file_str, &json);
3229         if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3230             break;
3231         } else if (VK_SUCCESS != res || NULL == json) {
3232             continue;
3233         }
3234
3235         loader_add_layer_properties(inst, instance_layers, json, true,
3236                                     file_str);
3237
3238         loader_instance_heap_free(inst, file_str);
3239         cJSON_Delete(json);
3240     }
3241     loader_instance_heap_free(inst, manifest_files.filename_list);
3242
3243     // add a meta layer for validation if the validation layers are all present
3244     loader_add_layer_property_meta(inst, sizeof(std_validation_names) /
3245                                              sizeof(std_validation_names[0]),
3246                                    std_validation_names, instance_layers);
3247
3248     loader_platform_thread_unlock_mutex(&loader_json_lock);
3249 }
3250
3251 static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
3252 loader_gpa_instance_internal(VkInstance inst, const char *pName) {
3253     if (!strcmp(pName, "vkGetInstanceProcAddr"))
3254         return (void *)loader_gpa_instance_internal;
3255     if (!strcmp(pName, "vkCreateInstance"))
3256         return (void *)terminator_CreateInstance;
3257     if (!strcmp(pName, "vkCreateDevice"))
3258         return (void *)terminator_CreateDevice;
3259
3260     // inst is not wrapped
3261     if (inst == VK_NULL_HANDLE) {
3262         return NULL;
3263     }
3264     VkLayerInstanceDispatchTable *disp_table =
3265         *(VkLayerInstanceDispatchTable **)inst;
3266     void *addr;
3267
3268     if (disp_table == NULL)
3269         return NULL;
3270
3271     bool found_name;
3272     addr =
3273         loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
3274     if (found_name) {
3275         return addr;
3276     }
3277
3278     // Don't call down the chain, this would be an infinite loop
3279     loader_log(NULL, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3280                "loader_gpa_instance_internal() unrecognized name %s", pName);
3281     return NULL;
3282 }
3283
3284 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
3285 loader_gpa_device_internal(VkDevice device, const char *pName) {
3286     struct loader_device *dev;
3287     struct loader_icd_term *icd_term =
3288         loader_get_icd_and_device(device, &dev, NULL);
3289
3290     // NOTE: Device Funcs needing Trampoline/Terminator.
3291     // Overrides for device functions needing a trampoline and
3292     // a terminator because certain device entry-points still need to go
3293     // through a terminator before hitting the ICD.  This could be for
3294     // several reasons, but the main one is currently unwrapping an
3295     // object before passing the appropriate info along to the ICD.
3296     // This is why we also have to override the direct ICD call to
3297     // vkGetDeviceProcAddr to intercept those calls.
3298     if (!strcmp(pName, "vkGetDeviceProcAddr")) {
3299         return (PFN_vkVoidFunction)loader_gpa_device_internal;
3300     } else if (!strcmp(pName, "vkCreateSwapchainKHR")) {
3301         return (PFN_vkVoidFunction)terminator_vkCreateSwapchainKHR;
3302     } else if (!strcmp(pName, "vkDebugMarkerSetObjectTagEXT")) {
3303         return (PFN_vkVoidFunction)terminator_DebugMarkerSetObjectTagEXT;
3304     } else if (!strcmp(pName, "vkDebugMarkerSetObjectNameEXT")) {
3305         return (PFN_vkVoidFunction)terminator_DebugMarkerSetObjectNameEXT;
3306     }
3307
3308     return icd_term->GetDeviceProcAddr(device, pName);
3309 }
3310
3311 /**
3312  * Initialize device_ext dispatch table entry as follows:
3313  * If dev == NULL find all logical devices created within this instance and
3314  *  init the entry (given by idx) in the ext dispatch table.
3315  * If dev != NULL only initialize the entry in the given dev's dispatch table.
3316  * The initialization value is gotten by calling down the device chain with
3317  * GDPA.
3318  * If GDPA returns NULL then don't initialize the dispatch table entry.
3319  */
3320 static void loader_init_dispatch_dev_ext_entry(struct loader_instance *inst,
3321                                                struct loader_device *dev,
3322                                                uint32_t idx,
3323                                                const char *funcName)
3324
3325 {
3326     void *gdpa_value;
3327     if (dev != NULL) {
3328         gdpa_value = dev->loader_dispatch.core_dispatch.GetDeviceProcAddr(
3329             dev->chain_device, funcName);
3330         if (gdpa_value != NULL)
3331             dev->loader_dispatch.ext_dispatch.dev_ext[idx] =
3332                 (PFN_vkDevExt)gdpa_value;
3333     } else {
3334         for (struct loader_icd_term *icd_term = inst->icd_terms;
3335              icd_term != NULL; icd_term = icd_term->next) {
3336             struct loader_device *ldev = icd_term->logical_device_list;
3337             while (ldev) {
3338                 gdpa_value =
3339                     ldev->loader_dispatch.core_dispatch.GetDeviceProcAddr(
3340                         ldev->chain_device, funcName);
3341                 if (gdpa_value != NULL)
3342                     ldev->loader_dispatch.ext_dispatch.dev_ext[idx] =
3343                         (PFN_vkDevExt)gdpa_value;
3344                 ldev = ldev->next;
3345             }
3346         }
3347     }
3348 }
3349
3350 /**
3351  * Find all dev extension in the hash table  and initialize the dispatch table
3352  * for dev  for each of those extension entrypoints found in hash table.
3353
3354  */
3355 void loader_init_dispatch_dev_ext(struct loader_instance *inst,
3356                                   struct loader_device *dev) {
3357     for (uint32_t i = 0; i < MAX_NUM_DEV_EXTS; i++) {
3358         if (inst->disp_hash[i].func_name != NULL)
3359             loader_init_dispatch_dev_ext_entry(inst, dev, i,
3360                                                inst->disp_hash[i].func_name);
3361     }
3362 }
3363
3364 static bool loader_check_icds_for_address(struct loader_instance *inst,
3365                                           const char *funcName) {
3366     struct loader_icd_term *icd_term;
3367     icd_term = inst->icd_terms;
3368     while (NULL != icd_term) {
3369         if (icd_term->scanned_icd->GetInstanceProcAddr(icd_term->instance,
3370                                                        funcName))
3371             // this icd supports funcName
3372             return true;
3373         icd_term = icd_term->next;
3374     }
3375
3376     return false;
3377 }
3378
3379 static bool loader_check_layer_list_for_address(
3380     const struct loader_layer_list *const layers, const char *funcName) {
3381     // Iterate over the layers.
3382     for (uint32_t layer = 0; layer < layers->count; ++layer) {
3383         // Iterate over the extensions.
3384         const struct loader_device_extension_list *const extensions =
3385             &(layers->list[layer].device_extension_list);
3386         for (uint32_t extension = 0; extension < extensions->count;
3387              ++extension) {
3388             // Iterate over the entry points.
3389             const struct loader_dev_ext_props *const property =
3390                 &(extensions->list[extension]);
3391             for (uint32_t entry = 0; entry < property->entrypoint_count;
3392                  ++entry) {
3393                 if (strcmp(property->entrypoints[entry], funcName) == 0) {
3394                     return true;
3395                 }
3396             }
3397         }
3398     }
3399
3400     return false;
3401 }
3402
3403 static void loader_free_dev_ext_table(struct loader_instance *inst) {
3404     for (uint32_t i = 0; i < MAX_NUM_DEV_EXTS; i++) {
3405         loader_instance_heap_free(inst, inst->disp_hash[i].func_name);
3406         loader_instance_heap_free(inst, inst->disp_hash[i].list.index);
3407     }
3408     memset(inst->disp_hash, 0, sizeof(inst->disp_hash));
3409 }
3410
3411 static bool loader_add_dev_ext_table(struct loader_instance *inst,
3412                                      uint32_t *ptr_idx, const char *funcName) {
3413     uint32_t i;
3414     uint32_t idx = *ptr_idx;
3415     struct loader_dispatch_hash_list *list = &inst->disp_hash[idx].list;
3416
3417     if (!inst->disp_hash[idx].func_name) {
3418         // no entry here at this idx, so use it
3419         assert(list->capacity == 0);
3420         inst->disp_hash[idx].func_name = (char *)loader_instance_heap_alloc(
3421             inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
3422         if (inst->disp_hash[idx].func_name == NULL) {
3423             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3424                        "loader_add_dev_ext_table() can't allocate memory for "
3425                        "func_name");
3426             return false;
3427         }
3428         strncpy(inst->disp_hash[idx].func_name, funcName, strlen(funcName) + 1);
3429         return true;
3430     }
3431
3432     // check for enough capacity
3433     if (list->capacity == 0) {
3434         list->index =
3435             loader_instance_heap_alloc(inst, 8 * sizeof(*(list->index)),
3436                                        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
3437         if (list->index == NULL) {
3438             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3439                        "loader_add_dev_ext_table() can't allocate list memory");
3440             return false;
3441         }
3442         list->capacity = 8 * sizeof(*(list->index));
3443     } else if (list->capacity < (list->count + 1) * sizeof(*(list->index))) {
3444         list->index = loader_instance_heap_realloc(
3445             inst, list->index, list->capacity, list->capacity * 2,
3446             VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
3447         if (list->index == NULL) {
3448             loader_log(
3449                 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3450                 "loader_add_dev_ext_table() can't reallocate list memory");
3451             return false;
3452         }
3453         list->capacity *= 2;
3454     }
3455
3456     // find an unused index in the hash table and use it
3457     i = (idx + 1) % MAX_NUM_DEV_EXTS;
3458     do {
3459         if (!inst->disp_hash[i].func_name) {
3460             assert(inst->disp_hash[i].list.capacity == 0);
3461             inst->disp_hash[i].func_name = (char *)loader_instance_heap_alloc(
3462                 inst, strlen(funcName) + 1,
3463                 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
3464             if (inst->disp_hash[i].func_name == NULL) {
3465                 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3466                            "loader_add_dev_ext_table() can't rallocate "
3467                            "func_name memory");
3468                 return false;
3469             }
3470             strncpy(inst->disp_hash[i].func_name, funcName,
3471                     strlen(funcName) + 1);
3472             list->index[list->count] = i;
3473             list->count++;
3474             *ptr_idx = i;
3475             return true;
3476         }
3477         i = (i + 1) % MAX_NUM_DEV_EXTS;
3478     } while (i != idx);
3479
3480     loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3481                "loader_add_dev_ext_table() couldn't insert into hash table; is "
3482                "it full?");
3483     return false;
3484 }
3485
3486 static bool loader_name_in_dev_ext_table(struct loader_instance *inst,
3487                                          uint32_t *idx, const char *funcName) {
3488     uint32_t alt_idx;
3489     if (inst->disp_hash[*idx].func_name &&
3490         !strcmp(inst->disp_hash[*idx].func_name, funcName))
3491         return true;
3492
3493     // funcName wasn't at the primary spot in the hash table
3494     // search the list of secondary locations (shallow search, not deep search)
3495     for (uint32_t i = 0; i < inst->disp_hash[*idx].list.count; i++) {
3496         alt_idx = inst->disp_hash[*idx].list.index[i];
3497         if (!strcmp(inst->disp_hash[*idx].func_name, funcName)) {
3498             *idx = alt_idx;
3499             return true;
3500         }
3501     }
3502
3503     return false;
3504 }
3505
3506 /**
3507  * This function returns generic trampoline code address for unknown entry
3508  * points.
3509  * Presumably, these unknown entry points (as given by funcName) are device
3510  * extension entrypoints.  A hash table is used to keep a list of unknown entry
3511  * points and their mapping to the device extension dispatch table
3512  * (struct loader_dev_ext_dispatch_table).
3513  * \returns
3514  * For a given entry point string (funcName), if an existing mapping is found
3515  * the
3516  * trampoline address for that mapping is returned. Otherwise, this unknown
3517  * entry point
3518  * has not been seen yet. Next check if a layer or ICD supports it.  If so then
3519  * a
3520  * new entry in the hash table is initialized and that trampoline address for
3521  * the new entry is returned. Null is returned if the hash table is full or
3522  * if no discovered layer or ICD returns a non-NULL GetProcAddr for it.
3523  */
3524 void *loader_dev_ext_gpa(struct loader_instance *inst, const char *funcName) {
3525     uint32_t idx;
3526     uint32_t seed = 0;
3527
3528     idx = murmurhash(funcName, strlen(funcName), seed) % MAX_NUM_DEV_EXTS;
3529
3530     if (loader_name_in_dev_ext_table(inst, &idx, funcName))
3531         // found funcName already in hash
3532         return loader_get_dev_ext_trampoline(idx);
3533
3534     // Check if funcName is supported in either ICDs or a layer library
3535     if (!loader_check_icds_for_address(inst, funcName) &&
3536         !loader_check_layer_list_for_address(&inst->instance_layer_list,
3537                                              funcName)) {
3538         // if support found in layers continue on
3539         return NULL;
3540     }
3541
3542     if (loader_add_dev_ext_table(inst, &idx, funcName)) {
3543         // successfully added new table entry
3544         // init any dev dispatch table entrys as needed
3545         loader_init_dispatch_dev_ext_entry(inst, NULL, idx, funcName);
3546         return loader_get_dev_ext_trampoline(idx);
3547     }
3548
3549     return NULL;
3550 }
3551
3552 struct loader_instance *loader_get_instance(const VkInstance instance) {
3553     /* look up the loader_instance in our list by comparing dispatch tables, as
3554      * there is no guarantee the instance is still a loader_instance* after any
3555      * layers which wrap the instance object.
3556      */
3557     const VkLayerInstanceDispatchTable *disp;
3558     struct loader_instance *ptr_instance = NULL;
3559     disp = loader_get_instance_dispatch(instance);
3560     for (struct loader_instance *inst = loader.instances; inst;
3561          inst = inst->next) {
3562         if (inst->disp == disp) {
3563             ptr_instance = inst;
3564             break;
3565         }
3566     }
3567     return ptr_instance;
3568 }
3569
3570 static loader_platform_dl_handle
3571 loader_open_layer_lib(const struct loader_instance *inst,
3572                       const char *chain_type,
3573                       struct loader_layer_properties *prop) {
3574
3575     if ((prop->lib_handle = loader_platform_open_library(prop->lib_name)) ==
3576         NULL) {
3577         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3578                    loader_platform_open_library_error(prop->lib_name));
3579     } else {
3580         loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
3581                    "Chain: %s: Loading layer library %s", chain_type,
3582                    prop->lib_name);
3583     }
3584
3585     return prop->lib_handle;
3586 }
3587
3588 static void loader_close_layer_lib(const struct loader_instance *inst,
3589                                    struct loader_layer_properties *prop) {
3590
3591     if (prop->lib_handle) {
3592         loader_platform_close_library(prop->lib_handle);
3593         loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
3594                    "Unloading layer library %s", prop->lib_name);
3595         prop->lib_handle = NULL;
3596     }
3597 }
3598
3599 void loader_deactivate_layers(const struct loader_instance *instance,
3600                               struct loader_device *device,
3601                               struct loader_layer_list *list) {
3602     /* delete instance list of enabled layers and close any layer libraries */
3603     for (uint32_t i = 0; i < list->count; i++) {
3604         struct loader_layer_properties *layer_prop = &list->list[i];
3605
3606         loader_close_layer_lib(instance, layer_prop);
3607     }
3608     loader_destroy_layer_list(instance, device, list);
3609 }
3610
3611 /**
3612  * Go through the search_list and find any layers which match type. If layer
3613  * type match is found in then add it to ext_list.
3614  */
3615 static void
3616 loader_add_layer_implicit(const struct loader_instance *inst,
3617                           const enum layer_type type,
3618                           struct loader_layer_list *list,
3619                           const struct loader_layer_list *search_list) {
3620     bool enable;
3621     char *env_value;
3622     uint32_t i;
3623     for (i = 0; i < search_list->count; i++) {
3624         const struct loader_layer_properties *prop = &search_list->list[i];
3625         if (prop->type & type) {
3626             /* Found an implicit layer, see if it should be enabled */
3627             enable = false;
3628
3629             // if no enable_environment variable is specified, this implicit
3630             // layer
3631             // should always be enabled. Otherwise check if the variable is set
3632             if (prop->enable_env_var.name[0] == 0) {
3633                 enable = true;
3634             } else {
3635                 env_value = loader_getenv(prop->enable_env_var.name, inst);
3636                 if (env_value && !strcmp(prop->enable_env_var.value, env_value))
3637                     enable = true;
3638                 loader_free_getenv(env_value, inst);
3639             }
3640
3641             // disable_environment has priority, i.e. if both enable and disable
3642             // environment variables are set, the layer is disabled. Implicit
3643             // layers
3644             // are required to have a disable_environment variables
3645             env_value = loader_getenv(prop->disable_env_var.name, inst);
3646             if (env_value) {
3647                 enable = false;
3648             }
3649             loader_free_getenv(env_value, inst);
3650
3651             if (enable) {
3652                 loader_add_to_layer_list(inst, list, 1, prop);
3653             }
3654         }
3655     }
3656 }
3657
3658 /**
3659  * Get the layer name(s) from the env_name environment variable. If layer
3660  * is found in search_list then add it to layer_list.  But only add it to
3661  * layer_list if type matches.
3662  */
3663 static void loader_add_layer_env(struct loader_instance *inst,
3664                                  const enum layer_type type,
3665                                  const char *env_name,
3666                                  struct loader_layer_list *layer_list,
3667                                  const struct loader_layer_list *search_list) {
3668     char *layerEnv;
3669     char *next, *name;
3670
3671     layerEnv = loader_getenv(env_name, inst);
3672     if (layerEnv == NULL) {
3673         return;
3674     }
3675     name = loader_stack_alloc(strlen(layerEnv) + 1);
3676     if (name == NULL) {
3677         return;
3678     }
3679     strcpy(name, layerEnv);
3680
3681     loader_free_getenv(layerEnv, inst);
3682
3683     while (name && *name) {
3684         next = loader_get_next_path(name);
3685         if (!strcmp(std_validation_str, name)) {
3686             /* add meta list of layers
3687                don't attempt to remove duplicate layers already added by app or
3688                env var
3689              */
3690             loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
3691                        "Expanding meta layer %s found in environment variable",
3692                        std_validation_str);
3693             if (type == VK_LAYER_TYPE_INSTANCE_EXPLICIT)
3694                 inst->activated_layers_are_std_val = true;
3695             for (uint32_t i = 0; i < sizeof(std_validation_names) /
3696                                          sizeof(std_validation_names[0]);
3697                  i++) {
3698                 loader_find_layer_name_add_list(inst, std_validation_names[i],
3699                                                 type, search_list, layer_list);
3700             }
3701         } else {
3702             loader_find_layer_name_add_list(inst, name, type, search_list,
3703                                             layer_list);
3704         }
3705         name = next;
3706     }
3707
3708     return;
3709 }
3710
3711 VkResult
3712 loader_enable_instance_layers(struct loader_instance *inst,
3713                               const VkInstanceCreateInfo *pCreateInfo,
3714                               const struct loader_layer_list *instance_layers) {
3715     VkResult err;
3716
3717     assert(inst && "Cannot have null instance");
3718
3719     if (!loader_init_layer_list(inst, &inst->activated_layer_list)) {
3720         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3721                    "Failed to alloc Instance activated layer list");
3722         return VK_ERROR_OUT_OF_HOST_MEMORY;
3723     }
3724
3725     /* Add any implicit layers first */
3726     loader_add_layer_implicit(inst, VK_LAYER_TYPE_INSTANCE_IMPLICIT,
3727                               &inst->activated_layer_list, instance_layers);
3728
3729     /* Add any layers specified via environment variable next */
3730     loader_add_layer_env(inst, VK_LAYER_TYPE_INSTANCE_EXPLICIT,
3731                          "VK_INSTANCE_LAYERS", &inst->activated_layer_list,
3732                          instance_layers);
3733
3734     /* Add layers specified by the application */
3735     err = loader_add_layer_names_to_list(
3736         inst, &inst->activated_layer_list, pCreateInfo->enabledLayerCount,
3737         pCreateInfo->ppEnabledLayerNames, instance_layers);
3738
3739     return err;
3740 }
3741
3742 /*
3743  * Given the list of layers to activate in the loader_instance
3744  * structure. This function will add a VkLayerInstanceCreateInfo
3745  * structure to the VkInstanceCreateInfo.pNext pointer.
3746  * Each activated layer will have it's own VkLayerInstanceLink
3747  * structure that tells the layer what Get*ProcAddr to call to
3748  * get function pointers to the next layer down.
3749  * Once the chain info has been created this function will
3750  * execute the CreateInstance call chain. Each layer will
3751  * then have an opportunity in it's CreateInstance function
3752  * to setup it's dispatch table when the lower layer returns
3753  * successfully.
3754  * Each layer can wrap or not-wrap the returned VkInstance object
3755  * as it sees fit.
3756  * The instance chain is terminated by a loader function
3757  * that will call CreateInstance on all available ICD's and
3758  * cache those VkInstance objects for future use.
3759  */
3760 VkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo,
3761                                       const VkAllocationCallbacks *pAllocator,
3762                                       struct loader_instance *inst,
3763                                       VkInstance *created_instance) {
3764     uint32_t activated_layers = 0;
3765     VkLayerInstanceCreateInfo chain_info;
3766     VkLayerInstanceLink *layer_instance_link_info = NULL;
3767     VkInstanceCreateInfo loader_create_info;
3768     VkResult res;
3769
3770     PFN_vkGetInstanceProcAddr nextGIPA = loader_gpa_instance_internal;
3771     PFN_vkGetInstanceProcAddr fpGIPA = loader_gpa_instance_internal;
3772
3773     memcpy(&loader_create_info, pCreateInfo, sizeof(VkInstanceCreateInfo));
3774
3775     if (inst->activated_layer_list.count > 0) {
3776
3777         chain_info.u.pLayerInfo = NULL;
3778         chain_info.pNext = pCreateInfo->pNext;
3779         chain_info.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
3780         chain_info.function = VK_LAYER_LINK_INFO;
3781         loader_create_info.pNext = &chain_info;
3782
3783         layer_instance_link_info = loader_stack_alloc(
3784             sizeof(VkLayerInstanceLink) * inst->activated_layer_list.count);
3785         if (!layer_instance_link_info) {
3786             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3787                        "Failed to alloc Instance objects for layer");
3788             return VK_ERROR_OUT_OF_HOST_MEMORY;
3789         }
3790
3791         /* Create instance chain of enabled layers */
3792         for (int32_t i = inst->activated_layer_list.count - 1; i >= 0; i--) {
3793             struct loader_layer_properties *layer_prop =
3794                 &inst->activated_layer_list.list[i];
3795             loader_platform_dl_handle lib_handle;
3796
3797             lib_handle = loader_open_layer_lib(inst, "instance", layer_prop);
3798             if (!lib_handle)
3799                 continue;
3800             if ((fpGIPA = layer_prop->functions.get_instance_proc_addr) ==
3801                 NULL) {
3802                 if (strlen(layer_prop->functions.str_gipa) == 0) {
3803                     fpGIPA = (PFN_vkGetInstanceProcAddr)
3804                         loader_platform_get_proc_address(
3805                             lib_handle, "vkGetInstanceProcAddr");
3806                     layer_prop->functions.get_instance_proc_addr = fpGIPA;
3807                 } else
3808                     fpGIPA = (PFN_vkGetInstanceProcAddr)
3809                         loader_platform_get_proc_address(
3810                             lib_handle, layer_prop->functions.str_gipa);
3811                 if (!fpGIPA) {
3812                     loader_log(
3813                         inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3814                         "Failed to find vkGetInstanceProcAddr in layer %s",
3815                         layer_prop->lib_name);
3816                     continue;
3817                 }
3818             }
3819
3820             layer_instance_link_info[activated_layers].pNext =
3821                 chain_info.u.pLayerInfo;
3822             layer_instance_link_info[activated_layers]
3823                 .pfnNextGetInstanceProcAddr = nextGIPA;
3824             chain_info.u.pLayerInfo =
3825                 &layer_instance_link_info[activated_layers];
3826             nextGIPA = fpGIPA;
3827
3828             loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
3829                        "Insert instance layer %s (%s)",
3830                        layer_prop->info.layerName, layer_prop->lib_name);
3831
3832             activated_layers++;
3833         }
3834     }
3835
3836     PFN_vkCreateInstance fpCreateInstance =
3837         (PFN_vkCreateInstance)nextGIPA(*created_instance, "vkCreateInstance");
3838     if (fpCreateInstance) {
3839         VkLayerInstanceCreateInfo create_info_disp;
3840
3841         create_info_disp.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
3842         create_info_disp.function = VK_LOADER_DATA_CALLBACK;
3843
3844         create_info_disp.u.pfnSetInstanceLoaderData = vkSetInstanceDispatch;
3845
3846         create_info_disp.pNext = loader_create_info.pNext;
3847         loader_create_info.pNext = &create_info_disp;
3848         res =
3849             fpCreateInstance(&loader_create_info, pAllocator, created_instance);
3850     } else {
3851         // Couldn't find CreateInstance function!
3852         res = VK_ERROR_INITIALIZATION_FAILED;
3853     }
3854
3855     if (res != VK_SUCCESS) {
3856         // TODO: Need to clean up here
3857     } else {
3858         loader_init_instance_core_dispatch_table(inst->disp, nextGIPA,
3859                                                  *created_instance);
3860         inst->instance = *created_instance;
3861     }
3862
3863     return res;
3864 }
3865
3866 void loader_activate_instance_layer_extensions(struct loader_instance *inst,
3867                                                VkInstance created_inst) {
3868
3869     loader_init_instance_extension_dispatch_table(
3870         inst->disp, inst->disp->GetInstanceProcAddr, created_inst);
3871 }
3872
3873 VkResult
3874 loader_create_device_chain(const struct loader_physical_device_tramp *pd,
3875                            const VkDeviceCreateInfo *pCreateInfo,
3876                            const VkAllocationCallbacks *pAllocator,
3877                            const struct loader_instance *inst,
3878                            struct loader_device *dev) {
3879     uint32_t activated_layers = 0;
3880     VkLayerDeviceLink *layer_device_link_info;
3881     VkLayerDeviceCreateInfo chain_info;
3882     VkDeviceCreateInfo loader_create_info;
3883     VkResult res;
3884
3885     PFN_vkGetDeviceProcAddr fpGDPA, nextGDPA = loader_gpa_device_internal;
3886     PFN_vkGetInstanceProcAddr fpGIPA, nextGIPA = loader_gpa_instance_internal;
3887
3888     memcpy(&loader_create_info, pCreateInfo, sizeof(VkDeviceCreateInfo));
3889
3890     layer_device_link_info = loader_stack_alloc(
3891         sizeof(VkLayerDeviceLink) * dev->activated_layer_list.count);
3892     if (!layer_device_link_info) {
3893         loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3894                    "Failed to alloc Device objects for layer");
3895         return VK_ERROR_OUT_OF_HOST_MEMORY;
3896     }
3897
3898     if (dev->activated_layer_list.count > 0) {
3899         chain_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
3900         chain_info.function = VK_LAYER_LINK_INFO;
3901         chain_info.u.pLayerInfo = NULL;
3902         chain_info.pNext = pCreateInfo->pNext;
3903         loader_create_info.pNext = &chain_info;
3904
3905         /* Create instance chain of enabled layers */
3906         for (int32_t i = dev->activated_layer_list.count - 1; i >= 0; i--) {
3907             struct loader_layer_properties *layer_prop =
3908                 &dev->activated_layer_list.list[i];
3909             loader_platform_dl_handle lib_handle;
3910
3911             lib_handle = loader_open_layer_lib(inst, "device", layer_prop);
3912             if (!lib_handle)
3913                 continue;
3914             if ((fpGIPA = layer_prop->functions.get_instance_proc_addr) ==
3915                 NULL) {
3916                 if (strlen(layer_prop->functions.str_gipa) == 0) {
3917                     fpGIPA = (PFN_vkGetInstanceProcAddr)
3918                         loader_platform_get_proc_address(
3919                             lib_handle, "vkGetInstanceProcAddr");
3920                     layer_prop->functions.get_instance_proc_addr = fpGIPA;
3921                 } else
3922                     fpGIPA = (PFN_vkGetInstanceProcAddr)
3923                         loader_platform_get_proc_address(
3924                             lib_handle, layer_prop->functions.str_gipa);
3925                 if (!fpGIPA) {
3926                     loader_log(
3927                         inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3928                         "Failed to find vkGetInstanceProcAddr in layer %s",
3929                         layer_prop->lib_name);
3930                     continue;
3931                 }
3932             }
3933             if ((fpGDPA = layer_prop->functions.get_device_proc_addr) == NULL) {
3934                 if (strlen(layer_prop->functions.str_gdpa) == 0) {
3935                     fpGDPA = (PFN_vkGetDeviceProcAddr)
3936                         loader_platform_get_proc_address(lib_handle,
3937                                                          "vkGetDeviceProcAddr");
3938                     layer_prop->functions.get_device_proc_addr = fpGDPA;
3939                 } else
3940                     fpGDPA = (PFN_vkGetDeviceProcAddr)
3941                         loader_platform_get_proc_address(
3942                             lib_handle, layer_prop->functions.str_gdpa);
3943                 if (!fpGDPA) {
3944                     loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
3945                                "Failed to find vkGetDeviceProcAddr in layer %s",
3946                                layer_prop->lib_name);
3947                     continue;
3948                 }
3949             }
3950
3951             layer_device_link_info[activated_layers].pNext =
3952                 chain_info.u.pLayerInfo;
3953             layer_device_link_info[activated_layers]
3954                 .pfnNextGetInstanceProcAddr = nextGIPA;
3955             layer_device_link_info[activated_layers].pfnNextGetDeviceProcAddr =
3956                 nextGDPA;
3957             chain_info.u.pLayerInfo = &layer_device_link_info[activated_layers];
3958             nextGIPA = fpGIPA;
3959             nextGDPA = fpGDPA;
3960
3961             loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
3962                        "Insert device layer %s (%s)",
3963                        layer_prop->info.layerName, layer_prop->lib_name);
3964
3965             activated_layers++;
3966         }
3967     }
3968
3969     VkDevice created_device = (VkDevice)dev;
3970     PFN_vkCreateDevice fpCreateDevice =
3971         (PFN_vkCreateDevice)nextGIPA(inst->instance, "vkCreateDevice");
3972     if (fpCreateDevice) {
3973         VkLayerDeviceCreateInfo create_info_disp;
3974
3975         create_info_disp.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
3976         create_info_disp.function = VK_LOADER_DATA_CALLBACK;
3977
3978         create_info_disp.u.pfnSetDeviceLoaderData = vkSetDeviceDispatch;
3979
3980         create_info_disp.pNext = loader_create_info.pNext;
3981         loader_create_info.pNext = &create_info_disp;
3982         res = fpCreateDevice(pd->phys_dev, &loader_create_info, pAllocator,
3983                              &created_device);
3984         if (res != VK_SUCCESS) {
3985             return res;
3986         }
3987         dev->chain_device = created_device;
3988     } else {
3989         // Couldn't find CreateDevice function!
3990         return VK_ERROR_INITIALIZATION_FAILED;
3991     }
3992
3993     // Initialize device dispatch table
3994     loader_init_device_dispatch_table(&dev->loader_dispatch, nextGDPA,
3995                                       dev->chain_device);
3996
3997     return res;
3998 }
3999
4000 VkResult loader_validate_layers(const struct loader_instance *inst,
4001                                 const uint32_t layer_count,
4002                                 const char *const *ppEnabledLayerNames,
4003                                 const struct loader_layer_list *list) {
4004     struct loader_layer_properties *prop;
4005
4006     for (uint32_t i = 0; i < layer_count; i++) {
4007         VkStringErrorFlags result =
4008             vk_string_validate(MaxLoaderStringLength, ppEnabledLayerNames[i]);
4009         if (result != VK_STRING_ERROR_NONE) {
4010             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4011                        "Loader: Device ppEnabledLayerNames contains string "
4012                        "that is too long or is badly formed");
4013             return VK_ERROR_LAYER_NOT_PRESENT;
4014         }
4015
4016         prop = loader_get_layer_property(ppEnabledLayerNames[i], list);
4017         if (!prop) {
4018             return VK_ERROR_LAYER_NOT_PRESENT;
4019         }
4020     }
4021     return VK_SUCCESS;
4022 }
4023
4024 VkResult loader_validate_instance_extensions(
4025     const struct loader_instance *inst,
4026     const struct loader_extension_list *icd_exts,
4027     const struct loader_layer_list *instance_layers,
4028     const VkInstanceCreateInfo *pCreateInfo) {
4029
4030     VkExtensionProperties *extension_prop;
4031     struct loader_layer_properties *layer_prop;
4032
4033     for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
4034         VkStringErrorFlags result = vk_string_validate(
4035             MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
4036         if (result != VK_STRING_ERROR_NONE) {
4037             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4038                        "Loader: Instance ppEnabledExtensionNames contains "
4039                        "string that is too long or is badly formed");
4040             return VK_ERROR_EXTENSION_NOT_PRESENT;
4041         }
4042
4043         extension_prop = get_extension_property(
4044             pCreateInfo->ppEnabledExtensionNames[i], icd_exts);
4045
4046         if (extension_prop) {
4047             continue;
4048         }
4049
4050         extension_prop = NULL;
4051
4052         /* Not in global list, search layer extension lists */
4053         for (uint32_t j = 0; j < pCreateInfo->enabledLayerCount; j++) {
4054             layer_prop = loader_get_layer_property(
4055                 pCreateInfo->ppEnabledLayerNames[j], instance_layers);
4056             if (!layer_prop) {
4057                 /* Should NOT get here, loader_validate_layers
4058                  * should have already filtered this case out.
4059                  */
4060                 continue;
4061             }
4062
4063             extension_prop =
4064                 get_extension_property(pCreateInfo->ppEnabledExtensionNames[i],
4065                                        &layer_prop->instance_extension_list);
4066             if (extension_prop) {
4067                 /* Found the extension in one of the layers enabled by the app.
4068                  */
4069                 break;
4070             }
4071         }
4072
4073         if (!extension_prop) {
4074             /* Didn't find extension name in any of the global layers, error out
4075              */
4076             return VK_ERROR_EXTENSION_NOT_PRESENT;
4077         }
4078     }
4079     return VK_SUCCESS;
4080 }
4081
4082 VkResult loader_validate_device_extensions(
4083     struct loader_physical_device_tramp *phys_dev,
4084     const struct loader_layer_list *activated_device_layers,
4085     const struct loader_extension_list *icd_exts,
4086     const VkDeviceCreateInfo *pCreateInfo) {
4087     VkExtensionProperties *extension_prop;
4088     struct loader_layer_properties *layer_prop;
4089
4090     for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
4091
4092         VkStringErrorFlags result = vk_string_validate(
4093             MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
4094         if (result != VK_STRING_ERROR_NONE) {
4095             loader_log(phys_dev->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT,
4096                        0, "Loader: Device ppEnabledExtensionNames contains "
4097                           "string that is too long or is badly formed");
4098             return VK_ERROR_EXTENSION_NOT_PRESENT;
4099         }
4100
4101         const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
4102         extension_prop = get_extension_property(extension_name, icd_exts);
4103
4104         if (extension_prop) {
4105             continue;
4106         }
4107
4108         /* Not in global list, search activated layer extension lists */
4109         for (uint32_t j = 0; j < activated_device_layers->count; j++) {
4110             layer_prop = &activated_device_layers->list[j];
4111
4112             extension_prop = get_dev_extension_property(
4113                 extension_name, &layer_prop->device_extension_list);
4114             if (extension_prop) {
4115                 /* Found the extension in one of the layers enabled by the app.
4116                  */
4117                 break;
4118             }
4119         }
4120
4121         if (!extension_prop) {
4122             /* Didn't find extension name in any of the device layers, error out
4123              */
4124             return VK_ERROR_EXTENSION_NOT_PRESENT;
4125         }
4126     }
4127     return VK_SUCCESS;
4128 }
4129
4130 /**
4131  * Terminator functions for the Instance chain
4132  * All named terminator_<Vulakn API name>
4133  */
4134 VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateInstance(
4135     const VkInstanceCreateInfo *pCreateInfo,
4136     const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {
4137     struct loader_icd_term *icd_term;
4138     VkExtensionProperties *prop;
4139     char **filtered_extension_names = NULL;
4140     VkInstanceCreateInfo icd_create_info;
4141     VkResult res = VK_SUCCESS;
4142     bool one_icd_successful = false;
4143
4144     struct loader_instance *ptr_instance = (struct loader_instance *)*pInstance;
4145     memcpy(&icd_create_info, pCreateInfo, sizeof(icd_create_info));
4146
4147     icd_create_info.enabledLayerCount = 0;
4148     icd_create_info.ppEnabledLayerNames = NULL;
4149
4150     /*
4151      * NOTE: Need to filter the extensions to only those
4152      * supported by the ICD.
4153      * No ICD will advertise support for layers. An ICD
4154      * library could support a layer, but it would be
4155      * independent of the actual ICD, just in the same library.
4156      */
4157     filtered_extension_names =
4158         loader_stack_alloc(pCreateInfo->enabledExtensionCount * sizeof(char *));
4159     if (!filtered_extension_names) {
4160         res = VK_ERROR_OUT_OF_HOST_MEMORY;
4161         goto out;
4162     }
4163     icd_create_info.ppEnabledExtensionNames =
4164         (const char *const *)filtered_extension_names;
4165
4166     for (uint32_t i = 0; i < ptr_instance->icd_tramp_list.count; i++) {
4167         icd_term = loader_icd_add(
4168             ptr_instance, &ptr_instance->icd_tramp_list.scanned_list[i]);
4169         if (NULL == icd_term) {
4170             res = VK_ERROR_OUT_OF_HOST_MEMORY;
4171             goto out;
4172         }
4173         icd_create_info.enabledExtensionCount = 0;
4174         struct loader_extension_list icd_exts;
4175
4176         loader_log(ptr_instance, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
4177                    "Build ICD instance extension list");
4178         // traverse scanned icd list adding non-duplicate extensions to the
4179         // list
4180         res = loader_init_generic_list(ptr_instance,
4181                                        (struct loader_generic_list *)&icd_exts,
4182                                        sizeof(VkExtensionProperties));
4183         if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
4184             // If out of memory, bail immediately.
4185             goto out;
4186         } else if (VK_SUCCESS != res) {
4187             // Something bad happened with this ICD, so free it and try the
4188             // next.
4189             ptr_instance->icd_terms = icd_term->next;
4190             icd_term->next = NULL;
4191             loader_icd_destroy(ptr_instance, icd_term, pAllocator);
4192             continue;
4193         }
4194
4195         res = loader_add_instance_extensions(
4196             ptr_instance,
4197             icd_term->scanned_icd->EnumerateInstanceExtensionProperties,
4198             icd_term->scanned_icd->lib_name, &icd_exts);
4199         if (VK_SUCCESS != res) {
4200             loader_destroy_generic_list(
4201                 ptr_instance, (struct loader_generic_list *)&icd_exts);
4202             if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
4203                 // If out of memory, bail immediately.
4204                 goto out;
4205             } else {
4206                 // Something bad happened with this ICD, so free it and try
4207                 // the next.
4208                 ptr_instance->icd_terms = icd_term->next;
4209                 icd_term->next = NULL;
4210                 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
4211                 continue;
4212             }
4213         }
4214
4215         for (uint32_t j = 0; j < pCreateInfo->enabledExtensionCount; j++) {
4216             prop = get_extension_property(
4217                 pCreateInfo->ppEnabledExtensionNames[j], &icd_exts);
4218             if (prop) {
4219                 filtered_extension_names[icd_create_info
4220                                              .enabledExtensionCount] =
4221                     (char *)pCreateInfo->ppEnabledExtensionNames[j];
4222                 icd_create_info.enabledExtensionCount++;
4223             }
4224         }
4225
4226         loader_destroy_generic_list(ptr_instance,
4227                                     (struct loader_generic_list *)&icd_exts);
4228
4229         VkResult icd_result =
4230             ptr_instance->icd_tramp_list.scanned_list[i].CreateInstance(
4231                 &icd_create_info, pAllocator, &(icd_term->instance));
4232         if (VK_ERROR_OUT_OF_HOST_MEMORY == icd_result) {
4233             // If out of memory, bail immediately.
4234             res = VK_ERROR_OUT_OF_HOST_MEMORY;
4235             goto out;
4236         } else if (VK_SUCCESS != icd_result) {
4237             loader_log(ptr_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
4238                        "ICD ignored: failed to CreateInstance in ICD %d", i);
4239             ptr_instance->icd_terms = icd_term->next;
4240             icd_term->next = NULL;
4241             loader_icd_destroy(ptr_instance, icd_term, pAllocator);
4242             continue;
4243         }
4244
4245         if (!loader_icd_init_entrys(icd_term, icd_term->instance,
4246                                     ptr_instance->icd_tramp_list.scanned_list[i]
4247                                         .GetInstanceProcAddr)) {
4248             loader_log(ptr_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
4249                        "ICD ignored: failed to CreateInstance and find "
4250                        "entrypoints with ICD");
4251             continue;
4252         }
4253
4254         // If we made it this far, at least one ICD was successful
4255         one_icd_successful = true;
4256     }
4257
4258     // If no ICDs were added to instance list and res is unchanged
4259     // from it's initial value, the loader was unable to find
4260     // a suitable ICD.
4261     if (VK_SUCCESS == res &&
4262         (ptr_instance->icd_terms == NULL || !one_icd_successful)) {
4263         res = VK_ERROR_INCOMPATIBLE_DRIVER;
4264     }
4265
4266 out:
4267
4268     if (VK_SUCCESS != res) {
4269         while (NULL != ptr_instance->icd_terms) {
4270             icd_term = ptr_instance->icd_terms;
4271             ptr_instance->icd_terms = icd_term->next;
4272             if (NULL != icd_term->instance) {
4273                 icd_term->DestroyInstance(icd_term->instance, pAllocator);
4274             }
4275             loader_icd_destroy(ptr_instance, icd_term, pAllocator);
4276         }
4277     }
4278
4279     return res;
4280 }
4281
4282 VKAPI_ATTR void VKAPI_CALL terminator_DestroyInstance(
4283     VkInstance instance, const VkAllocationCallbacks *pAllocator) {
4284     struct loader_instance *ptr_instance = loader_instance(instance);
4285     struct loader_icd_term *icd_terms = ptr_instance->icd_terms;
4286     struct loader_icd_term *next_icd_term;
4287
4288     // Remove this instance from the list of instances:
4289     struct loader_instance *prev = NULL;
4290     struct loader_instance *next = loader.instances;
4291     while (next != NULL) {
4292         if (next == ptr_instance) {
4293             // Remove this instance from the list:
4294             if (prev)
4295                 prev->next = next->next;
4296             else
4297                 loader.instances = next->next;
4298             break;
4299         }
4300         prev = next;
4301         next = next->next;
4302     }
4303
4304     while (NULL != icd_terms) {
4305         if (icd_terms->instance) {
4306             icd_terms->DestroyInstance(icd_terms->instance, pAllocator);
4307         }
4308         next_icd_term = icd_terms->next;
4309         icd_terms->instance = VK_NULL_HANDLE;
4310         loader_icd_destroy(ptr_instance, icd_terms, pAllocator);
4311
4312         icd_terms = next_icd_term;
4313     }
4314
4315     loader_delete_layer_properties(ptr_instance,
4316                                    &ptr_instance->instance_layer_list);
4317     loader_scanned_icd_clear(ptr_instance, &ptr_instance->icd_tramp_list);
4318     loader_destroy_generic_list(
4319         ptr_instance, (struct loader_generic_list *)&ptr_instance->ext_list);
4320     if (ptr_instance->phys_devs_term) {
4321         for (uint32_t i = 0; i < ptr_instance->total_gpu_count; i++) {
4322             loader_instance_heap_free(ptr_instance,
4323                                       ptr_instance->phys_devs_term[i]);
4324         }
4325         loader_instance_heap_free(ptr_instance, ptr_instance->phys_devs_term);
4326     }
4327     loader_free_dev_ext_table(ptr_instance);
4328 }
4329
4330 VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(
4331     VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
4332     const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
4333     VkResult res = VK_SUCCESS;
4334     struct loader_physical_device_term *phys_dev_term;
4335     phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
4336     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
4337
4338     struct loader_device *dev = (struct loader_device *)*pDevice;
4339     PFN_vkCreateDevice fpCreateDevice = icd_term->CreateDevice;
4340     struct loader_extension_list icd_exts;
4341
4342     dev->phys_dev_term = phys_dev_term;
4343
4344     icd_exts.list = NULL;
4345
4346     if (fpCreateDevice == NULL) {
4347         loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4348                    "No vkCreateDevice command exposed by ICD %s",
4349                    icd_term->scanned_icd->lib_name);
4350         res = VK_ERROR_INITIALIZATION_FAILED;
4351         goto out;
4352     }
4353
4354     VkDeviceCreateInfo localCreateInfo;
4355     memcpy(&localCreateInfo, pCreateInfo, sizeof(localCreateInfo));
4356
4357     /*
4358      * NOTE: Need to filter the extensions to only those
4359      * supported by the ICD.
4360      * No ICD will advertise support for layers. An ICD
4361      * library could support a layer, but it would be
4362      * independent of the actual ICD, just in the same library.
4363      */
4364     char **filtered_extension_names = NULL;
4365     filtered_extension_names =
4366         loader_stack_alloc(pCreateInfo->enabledExtensionCount * sizeof(char *));
4367     if (!filtered_extension_names) {
4368         return VK_ERROR_OUT_OF_HOST_MEMORY;
4369     }
4370
4371     localCreateInfo.enabledLayerCount = 0;
4372     localCreateInfo.ppEnabledLayerNames = NULL;
4373
4374     localCreateInfo.enabledExtensionCount = 0;
4375     localCreateInfo.ppEnabledExtensionNames =
4376         (const char *const *)filtered_extension_names;
4377
4378     /* Get the physical device (ICD) extensions  */
4379     res = loader_init_generic_list(icd_term->this_instance,
4380                                    (struct loader_generic_list *)&icd_exts,
4381                                    sizeof(VkExtensionProperties));
4382     if (VK_SUCCESS != res) {
4383         goto out;
4384     }
4385
4386     res = loader_add_device_extensions(
4387         icd_term->this_instance, icd_term->EnumerateDeviceExtensionProperties,
4388         phys_dev_term->phys_dev, icd_term->scanned_icd->lib_name, &icd_exts);
4389     if (res != VK_SUCCESS) {
4390         goto out;
4391     }
4392
4393     for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
4394         const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
4395         VkExtensionProperties *prop =
4396             get_extension_property(extension_name, &icd_exts);
4397         if (prop) {
4398             filtered_extension_names[localCreateInfo.enabledExtensionCount] =
4399                 (char *)extension_name;
4400             localCreateInfo.enabledExtensionCount++;
4401         } else {
4402             loader_log(icd_term->this_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT,
4403                        0, "vkCreateDevice extension %s not available for "
4404                           "devices associated with ICD %s",
4405                        extension_name, icd_term->scanned_icd->lib_name);
4406         }
4407     }
4408
4409     res = fpCreateDevice(phys_dev_term->phys_dev, &localCreateInfo, pAllocator,
4410                          &dev->icd_device);
4411     if (res != VK_SUCCESS) {
4412         loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4413                    "vkCreateDevice call failed in ICD %s",
4414                    icd_term->scanned_icd->lib_name);
4415         goto out;
4416     }
4417
4418     *pDevice = dev->icd_device;
4419     loader_add_logical_device(icd_term->this_instance, icd_term, dev);
4420
4421     /* Init dispatch pointer in new device object */
4422     loader_init_dispatch(*pDevice, &dev->loader_dispatch);
4423
4424 out:
4425     if (NULL != icd_exts.list) {
4426         loader_destroy_generic_list(icd_term->this_instance,
4427                                     (struct loader_generic_list *)&icd_exts);
4428     }
4429
4430     return res;
4431 }
4432
4433 VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDevices(
4434     VkInstance instance, uint32_t *pPhysicalDeviceCount,
4435     VkPhysicalDevice *pPhysicalDevices) {
4436     struct loader_instance *inst = (struct loader_instance *)instance;
4437     VkResult res = VK_SUCCESS;
4438     struct loader_icd_term *icd_term = NULL;
4439     struct loader_phys_dev_per_icd *icd_phys_devs = NULL;
4440     uint32_t copy_count = 0;
4441     uint32_t new_phys_dev_count = 0;
4442     uint32_t i = 0;
4443     struct loader_physical_device_term **new_phys_devs = NULL;
4444
4445     inst->total_gpu_count = 0;
4446     icd_phys_devs = (struct loader_phys_dev_per_icd *)loader_stack_alloc(
4447         sizeof(struct loader_phys_dev_per_icd) * inst->total_icd_count);
4448     if (NULL == icd_phys_devs) {
4449         res = VK_ERROR_OUT_OF_HOST_MEMORY;
4450         goto out;
4451     }
4452
4453     icd_term = inst->icd_terms;
4454     for (i = 0; i < inst->total_icd_count; i++) {
4455         if (NULL == icd_term) {
4456             loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4457                        "Invalid ICD encountered during"
4458                        "vkEnumeratePhysicalDevices");
4459             assert(false);
4460         }
4461
4462         // Determine how many physical devices are associated with this ICD.
4463         res = icd_term->EnumeratePhysicalDevices(icd_term->instance,
4464                                                  &icd_phys_devs[i].count, NULL);
4465         if (res != VK_SUCCESS) {
4466             goto out;
4467         }
4468
4469         if (NULL != pPhysicalDevices) {
4470             // Create an array to store each physical device for this ICD.
4471             icd_phys_devs[i].phys_devs = (VkPhysicalDevice *)loader_stack_alloc(
4472                 icd_phys_devs[i].count * sizeof(VkPhysicalDevice));
4473             if (NULL == icd_phys_devs[i].phys_devs) {
4474                 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4475                 goto out;
4476             }
4477
4478             // Query the VkPhysicalDevice values for each of the physical devices
4479             // associated with this ICD.
4480             res = icd_term->EnumeratePhysicalDevices(
4481                 icd_term->instance, &(icd_phys_devs[i].count),
4482                 icd_phys_devs[i].phys_devs);
4483             if (res != VK_SUCCESS) {
4484                 goto out;
4485             }
4486
4487             icd_phys_devs[i].this_icd_term = icd_term;
4488         }
4489
4490         inst->total_gpu_count += icd_phys_devs[i].count;
4491
4492         // Go to the next ICD
4493         icd_term = icd_term->next;
4494     }
4495
4496     if (inst->total_gpu_count == 0) {
4497         res = VK_ERROR_INITIALIZATION_FAILED;
4498         goto out;
4499     }
4500
4501     copy_count = inst->total_gpu_count;
4502
4503     if (NULL != pPhysicalDevices) {
4504         new_phys_dev_count = inst->total_gpu_count;
4505
4506         // Cap the number of devices at pPhysicalDeviceCount
4507         if (copy_count > *pPhysicalDeviceCount) {
4508             copy_count = *pPhysicalDeviceCount;
4509         }
4510
4511         // Allocate the new devices list
4512         new_phys_devs = loader_instance_heap_alloc(
4513             inst,
4514             sizeof(struct loader_physical_device_term *) * new_phys_dev_count,
4515             VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4516         if (NULL == new_phys_devs) {
4517             res = VK_ERROR_OUT_OF_HOST_MEMORY;
4518             goto out;
4519         }
4520         memset(new_phys_devs, 0, sizeof(struct loader_physical_device_term *) *
4521                                      new_phys_dev_count);
4522
4523         // Copy or create everything to fill the new array of physical devices
4524         uint32_t idx = 0;
4525         for (uint32_t icd_idx = 0; icd_idx < inst->total_icd_count; icd_idx++) {
4526             for (uint32_t pd_idx = 0; pd_idx < icd_phys_devs[icd_idx].count;
4527                  pd_idx++) {
4528
4529                 // Check if this physical device is already in the old buffer
4530                 if (NULL != inst->phys_devs_term) {
4531                     for (uint32_t old_idx = 0;
4532                          old_idx < inst->phys_dev_count_term;
4533                          old_idx++) {
4534                         if (icd_phys_devs[icd_idx].phys_devs[pd_idx] ==
4535                             inst->phys_devs_term[old_idx]->phys_dev) {
4536                             new_phys_devs[idx] = inst->phys_devs_term[old_idx];
4537                             break;
4538                         }
4539                     }
4540                 }
4541                 // If this physical device isn't in the old buffer, then we
4542                 // need to create it.
4543                 if (NULL == new_phys_devs[idx]) {
4544                     new_phys_devs[idx] = loader_instance_heap_alloc(
4545                         inst, sizeof(struct loader_physical_device_term),
4546                         VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4547                     if (NULL == new_phys_devs[idx]) {
4548                         copy_count = idx;
4549                         res = VK_ERROR_OUT_OF_HOST_MEMORY;
4550                         goto out;
4551                     }
4552
4553                     loader_set_dispatch((void *)new_phys_devs[idx], inst->disp);
4554                     new_phys_devs[idx]->this_icd_term =
4555                         icd_phys_devs[icd_idx].this_icd_term;
4556                     new_phys_devs[idx]->icd_index = (uint8_t)(icd_idx);
4557                     new_phys_devs[idx]->phys_dev =
4558                         icd_phys_devs[icd_idx].phys_devs[pd_idx];
4559                 }
4560
4561                 // Copy wrapped object into application provided array
4562                 if (idx < copy_count) {
4563                     pPhysicalDevices[idx] =
4564                         (VkPhysicalDevice)new_phys_devs[idx];
4565                 }
4566                 idx++;
4567                 if (idx >= new_phys_dev_count) {
4568                     break;
4569                 }
4570             }
4571             if (idx >= new_phys_dev_count) {
4572                 break;
4573             }
4574         }
4575     }
4576
4577 out:
4578
4579     if (NULL != pPhysicalDevices) {
4580         // If there was no error, we still need to free the old buffer and
4581         // assign the new one
4582         if (res == VK_SUCCESS || res == VK_INCOMPLETE) {
4583             // Free everything that didn't carry over to the new array of
4584             // physical devices.  Everything else will have been copied over
4585             // to the new array.
4586             if (NULL != inst->phys_devs_term) {
4587                 for (uint32_t cur_pd = 0; cur_pd < inst->phys_dev_count_term;
4588                      cur_pd++) {
4589                     bool found = false;
4590                     for (uint32_t new_pd_idx = 0;
4591                          new_pd_idx < new_phys_dev_count;
4592                          new_pd_idx++) {
4593                         if (inst->phys_devs_term[cur_pd] ==
4594                                 new_phys_devs[new_pd_idx]) {
4595                             found = true;
4596                             break;
4597                         }
4598                     }
4599                     if (!found) {
4600                         loader_instance_heap_free(inst,
4601                                                   inst->phys_devs_term[cur_pd]);
4602                     }
4603                 }
4604                 loader_instance_heap_free(inst, inst->phys_devs_term);
4605             }
4606
4607             // If we didn't load every device, the result is incomplete
4608             if (copy_count < new_phys_dev_count) {
4609                 res = VK_INCOMPLETE;
4610             }
4611
4612             // Swap out old and new devices list
4613             inst->phys_dev_count_term = new_phys_dev_count;
4614             inst->phys_devs_term = new_phys_devs;
4615
4616         } else {
4617             // Otherwise, we've encountered an error, so we should free the
4618             // new buffers.
4619             for (uint32_t i = 0; i < copy_count; i++) {
4620                 loader_instance_heap_free(inst, new_phys_devs[i]);
4621             }
4622             loader_instance_heap_free(inst, new_phys_devs);
4623
4624             // Set the copy count to 0 since something bad happened.
4625             copy_count = 0;
4626         }
4627     }
4628
4629     *pPhysicalDeviceCount = copy_count;
4630
4631     return res;
4632 }
4633
4634 VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceProperties(
4635     VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties *pProperties) {
4636     struct loader_physical_device_term *phys_dev_term =
4637         (struct loader_physical_device_term *)physicalDevice;
4638     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
4639
4640     if (icd_term->GetPhysicalDeviceProperties)
4641         icd_term->GetPhysicalDeviceProperties(phys_dev_term->phys_dev,
4642                                               pProperties);
4643 }
4644
4645 VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceQueueFamilyProperties(
4646     VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount,
4647     VkQueueFamilyProperties *pProperties) {
4648     struct loader_physical_device_term *phys_dev_term =
4649         (struct loader_physical_device_term *)physicalDevice;
4650     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
4651
4652     if (icd_term->GetPhysicalDeviceQueueFamilyProperties)
4653         icd_term->GetPhysicalDeviceQueueFamilyProperties(
4654             phys_dev_term->phys_dev, pQueueFamilyPropertyCount, pProperties);
4655 }
4656
4657 VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceMemoryProperties(
4658     VkPhysicalDevice physicalDevice,
4659     VkPhysicalDeviceMemoryProperties *pProperties) {
4660     struct loader_physical_device_term *phys_dev_term =
4661         (struct loader_physical_device_term *)physicalDevice;
4662     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
4663
4664     if (icd_term->GetPhysicalDeviceMemoryProperties)
4665         icd_term->GetPhysicalDeviceMemoryProperties(phys_dev_term->phys_dev,
4666                                                     pProperties);
4667 }
4668
4669 VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFeatures(
4670     VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures *pFeatures) {
4671     struct loader_physical_device_term *phys_dev_term =
4672         (struct loader_physical_device_term *)physicalDevice;
4673     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
4674
4675     if (icd_term->GetPhysicalDeviceFeatures)
4676         icd_term->GetPhysicalDeviceFeatures(phys_dev_term->phys_dev, pFeatures);
4677 }
4678
4679 VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFormatProperties(
4680     VkPhysicalDevice physicalDevice, VkFormat format,
4681     VkFormatProperties *pFormatInfo) {
4682     struct loader_physical_device_term *phys_dev_term =
4683         (struct loader_physical_device_term *)physicalDevice;
4684     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
4685
4686     if (icd_term->GetPhysicalDeviceFormatProperties)
4687         icd_term->GetPhysicalDeviceFormatProperties(phys_dev_term->phys_dev,
4688                                                     format, pFormatInfo);
4689 }
4690
4691 VKAPI_ATTR VkResult VKAPI_CALL
4692 terminator_GetPhysicalDeviceImageFormatProperties(
4693     VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
4694     VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags,
4695     VkImageFormatProperties *pImageFormatProperties) {
4696     struct loader_physical_device_term *phys_dev_term =
4697         (struct loader_physical_device_term *)physicalDevice;
4698     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
4699
4700     if (!icd_term->GetPhysicalDeviceImageFormatProperties)
4701         return VK_ERROR_INITIALIZATION_FAILED;
4702
4703     return icd_term->GetPhysicalDeviceImageFormatProperties(
4704         phys_dev_term->phys_dev, format, type, tiling, usage, flags,
4705         pImageFormatProperties);
4706 }
4707
4708 VKAPI_ATTR void VKAPI_CALL
4709 terminator_GetPhysicalDeviceSparseImageFormatProperties(
4710     VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
4711     VkSampleCountFlagBits samples, VkImageUsageFlags usage,
4712     VkImageTiling tiling, uint32_t *pNumProperties,
4713     VkSparseImageFormatProperties *pProperties) {
4714     struct loader_physical_device_term *phys_dev_term =
4715         (struct loader_physical_device_term *)physicalDevice;
4716     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
4717
4718     if (icd_term->GetPhysicalDeviceSparseImageFormatProperties)
4719         icd_term->GetPhysicalDeviceSparseImageFormatProperties(
4720             phys_dev_term->phys_dev, format, type, samples, usage, tiling,
4721             pNumProperties, pProperties);
4722 }
4723
4724 VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceExtensionProperties(
4725     VkPhysicalDevice physicalDevice, const char *pLayerName,
4726     uint32_t *pPropertyCount, VkExtensionProperties *pProperties) {
4727     struct loader_physical_device_term *phys_dev_term;
4728
4729     struct loader_layer_list implicit_layer_list = {0};
4730     struct loader_extension_list all_exts = {0};
4731     struct loader_extension_list icd_exts = {0};
4732
4733     assert(pLayerName == NULL || strlen(pLayerName) == 0);
4734
4735     /* Any layer or trampoline wrapping should be removed at this point in time
4736      * can just cast to the expected type for VkPhysicalDevice. */
4737     phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
4738
4739     /* this case is during the call down the instance chain with pLayerName
4740      * == NULL*/
4741     struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
4742     uint32_t icd_ext_count = *pPropertyCount;
4743     VkResult res;
4744
4745     /* get device extensions */
4746     res = icd_term->EnumerateDeviceExtensionProperties(
4747         phys_dev_term->phys_dev, NULL, &icd_ext_count, pProperties);
4748     if (res != VK_SUCCESS) {
4749         goto out;
4750     }
4751
4752     if (!loader_init_layer_list(icd_term->this_instance,
4753                                 &implicit_layer_list)) {
4754         res = VK_ERROR_OUT_OF_HOST_MEMORY;
4755         goto out;
4756     }
4757
4758     loader_add_layer_implicit(
4759         icd_term->this_instance, VK_LAYER_TYPE_INSTANCE_IMPLICIT,
4760         &implicit_layer_list, &icd_term->this_instance->instance_layer_list);
4761     /* we need to determine which implicit layers are active,
4762      * and then add their extensions. This can't be cached as
4763      * it depends on results of environment variables (which can change).
4764      */
4765     if (pProperties != NULL) {
4766         /* initialize dev_extension list within the physicalDevice object */
4767         res = loader_init_device_extensions(icd_term->this_instance,
4768                                             phys_dev_term, icd_ext_count,
4769                                             pProperties, &icd_exts);
4770         if (res != VK_SUCCESS) {
4771             goto out;
4772         }
4773
4774         /* we need to determine which implicit layers are active,
4775          * and then add their extensions. This can't be cached as
4776          * it depends on results of environment variables (which can
4777          * change).
4778          */
4779         res = loader_add_to_ext_list(icd_term->this_instance, &all_exts,
4780                                      icd_exts.count, icd_exts.list);
4781         if (res != VK_SUCCESS) {
4782             goto out;
4783         }
4784
4785         loader_add_layer_implicit(
4786             icd_term->this_instance, VK_LAYER_TYPE_INSTANCE_IMPLICIT,
4787             &implicit_layer_list,
4788             &icd_term->this_instance->instance_layer_list);
4789
4790         for (uint32_t i = 0; i < implicit_layer_list.count; i++) {
4791             for (uint32_t j = 0;
4792                  j < implicit_layer_list.list[i].device_extension_list.count;
4793                  j++) {
4794                 res = loader_add_to_ext_list(icd_term->this_instance, &all_exts,
4795                                              1,
4796                                              &implicit_layer_list.list[i]
4797                                                   .device_extension_list.list[j]
4798                                                   .props);
4799                 if (res != VK_SUCCESS) {
4800                     goto out;
4801                 }
4802             }
4803         }
4804         uint32_t capacity = *pPropertyCount;
4805         VkExtensionProperties *props = pProperties;
4806
4807         for (uint32_t i = 0; i < all_exts.count && i < capacity; i++) {
4808             props[i] = all_exts.list[i];
4809         }
4810         /* wasn't enough space for the extensions, we did partial copy now
4811          * return VK_INCOMPLETE */
4812         if (capacity < all_exts.count) {
4813             res = VK_INCOMPLETE;
4814         } else {
4815             *pPropertyCount = all_exts.count;
4816         }
4817     } else {
4818         /* just return the count; need to add in the count of implicit layer
4819          * extensions
4820          * don't worry about duplicates being added in the count */
4821         *pPropertyCount = icd_ext_count;
4822
4823         for (uint32_t i = 0; i < implicit_layer_list.count; i++) {
4824             *pPropertyCount +=
4825                 implicit_layer_list.list[i].device_extension_list.count;
4826         }
4827         res = VK_SUCCESS;
4828     }
4829
4830 out:
4831
4832     if (NULL != implicit_layer_list.list) {
4833         loader_destroy_generic_list(
4834             icd_term->this_instance,
4835             (struct loader_generic_list *)&implicit_layer_list);
4836     }
4837     if (NULL != all_exts.list) {
4838         loader_destroy_generic_list(icd_term->this_instance,
4839                                     (struct loader_generic_list *)&all_exts);
4840     }
4841     if (NULL != icd_exts.list) {
4842         loader_destroy_generic_list(icd_term->this_instance,
4843                                     (struct loader_generic_list *)&icd_exts);
4844     }
4845
4846     return res;
4847 }
4848
4849 VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceLayerProperties(
4850     VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
4851     VkLayerProperties *pProperties) {
4852
4853     // should never get here this call isn't dispatched down the chain
4854     return VK_ERROR_INITIALIZATION_FAILED;
4855 }
4856
4857 VkStringErrorFlags vk_string_validate(const int max_length, const char *utf8) {
4858     VkStringErrorFlags result = VK_STRING_ERROR_NONE;
4859     int num_char_bytes = 0;
4860     int i, j;
4861
4862     for (i = 0; i <= max_length; i++) {
4863         if (utf8[i] == 0) {
4864             break;
4865         } else if (i == max_length) {
4866             result |= VK_STRING_ERROR_LENGTH;
4867             break;
4868         } else if ((utf8[i] >= 0x20) && (utf8[i] < 0x7f)) {
4869             num_char_bytes = 0;
4870         } else if ((utf8[i] & UTF8_ONE_BYTE_MASK) == UTF8_ONE_BYTE_CODE) {
4871             num_char_bytes = 1;
4872         } else if ((utf8[i] & UTF8_TWO_BYTE_MASK) == UTF8_TWO_BYTE_CODE) {
4873             num_char_bytes = 2;
4874         } else if ((utf8[i] & UTF8_THREE_BYTE_MASK) == UTF8_THREE_BYTE_CODE) {
4875             num_char_bytes = 3;
4876         } else {
4877             result = VK_STRING_ERROR_BAD_DATA;
4878         }
4879
4880         // Validate the following num_char_bytes of data
4881         for (j = 0; (j < num_char_bytes) && (i < max_length); j++) {
4882             if (++i == max_length) {
4883                 result |= VK_STRING_ERROR_LENGTH;
4884                 break;
4885             }
4886             if ((utf8[i] & UTF8_DATA_BYTE_MASK) != UTF8_DATA_BYTE_CODE) {
4887                 result |= VK_STRING_ERROR_BAD_DATA;
4888             }
4889         }
4890     }
4891     return result;
4892 }