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