blob: e65b3ba7af6a249e3242c94a834543dedc559132 [file] [log] [blame]
Mark Lobodzinski317574e2016-08-29 14:21:14 -06001/*
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08002 *
Lenny Komow3b958392018-01-17 13:53:59 -07003 * Copyright (c) 2014-2018 The Khronos Group Inc.
4 * Copyright (c) 2014-2018 Valve Corporation
5 * Copyright (c) 2014-2018 LunarG, Inc.
Courtney Goeltzenleuchterf821dad2015-12-02 14:53:22 -07006 * Copyright (C) 2015 Google Inc.
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08007 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -06008 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080011 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -060012 * http://www.apache.org/licenses/LICENSE-2.0
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080013 *
Jon Ashburn3ebf1252016-04-19 11:30:31 -060014 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19
Jon Ashburn23d36b12016-02-02 17:47:28 -070020 *
Courtney Goeltzenleuchter05559522015-10-30 11:14:30 -060021 * Author: Jon Ashburn <jon@lunarg.com>
Jon Ashburn23d36b12016-02-02 17:47:28 -070022 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
Mark Young39389872017-01-19 21:10:49 -070023 * Author: Mark Young <marky@lunarg.com>
Lenny Komow3b958392018-01-17 13:53:59 -070024 * Author: Lenny Komow <lenny@lunarg.com>
Courtney Goeltzenleuchter05559522015-10-30 11:14:30 -060025 *
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080026 */
Mark Lobodzinskifaa90812015-11-25 13:26:15 -070027
Jon Ashburn6b4d70c2014-10-22 18:13:16 -060028#define _GNU_SOURCE
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080029#include <stdio.h>
30#include <stdlib.h>
31#include <stdarg.h>
32#include <stdbool.h>
33#include <string.h>
Benjamin Saunders31a48012017-01-29 14:49:54 -080034#include <stddef.h>
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080035
Chia-I Wu13a61a52014-08-04 11:18:20 +080036#include <sys/types.h>
Johannes van Waveren9bd805012015-10-28 11:45:00 -050037#if defined(_WIN32)
Ian Elliott2d4ab1e2015-01-13 17:52:38 -070038#include "dirent_on_windows.h"
Mark Lobodzinski64318ba2017-01-26 13:34:13 -070039#else // _WIN32
Chia-I Wu13a61a52014-08-04 11:18:20 +080040#include <dirent.h>
Mark Lobodzinski64318ba2017-01-26 13:34:13 -070041#endif // _WIN32
Tobin Ehlisb835d1b2015-07-03 10:34:49 -060042#include "vk_loader_platform.h"
Chia-I Wu19300602014-08-04 08:03:57 +080043#include "loader.h"
Jon Ashburn27cd5842015-05-12 17:26:48 -060044#include "gpa_helper.h"
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -060045#include "debug_report.h"
Ian Elliott954fa342015-10-30 15:28:23 -060046#include "wsi.h"
David Pinedo9316d3b2015-11-06 12:54:48 -070047#include "vulkan/vk_icd.h"
Jon Ashburn2077e382015-06-29 11:25:34 -060048#include "cJSON.h"
Jon Ashburnfc1031e2015-11-17 15:31:02 -070049#include "murmurhash.h"
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080050
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +020051#if defined(_WIN32)
52#include <Cfgmgr32.h>
53#include <initguid.h>
54#include <Devpkey.h>
55#endif
56
Mark Youngba7ee022017-03-09 10:41:25 -070057// This is a CMake generated file with #defines for any functions/includes
58// that it found present. This is currently necessary to properly determine
59// if secure_getenv or __secure_getenv are present
Jamie Madille09268a2017-03-21 13:48:13 -040060#if !defined(VULKAN_NON_CMAKE_BUILD)
Mark Youngba7ee022017-03-09 10:41:25 -070061#include "loader_cmake_config.h"
Jamie Madille09268a2017-03-21 13:48:13 -040062#endif // !defined(VULKAN_NON_CMAKE_BUILD)
Mark Youngba7ee022017-03-09 10:41:25 -070063
Mark Young0f183a82017-02-28 09:58:04 -070064// Generated file containing all the extension data
65#include "vk_loader_extensions.c"
66
Jon Ashburn27cd5842015-05-12 17:26:48 -060067struct loader_struct loader = {0};
Jon Ashburn87d6aa92015-08-28 15:19:27 -060068// TLS for instance for alloc/free callbacks
69THREAD_LOCAL_DECL struct loader_instance *tls_instance;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +080070
Courtney Goeltzenleuchter0ef13a02015-12-16 16:19:46 -070071static size_t loader_platform_combine_path(char *dest, size_t len, ...);
Daniel Dadap00b4aba2015-09-30 11:50:51 -050072
Jon Ashburn24cd4be2015-11-01 14:04:06 -070073struct loader_phys_dev_per_icd {
74 uint32_t count;
75 VkPhysicalDevice *phys_devs;
Mark Young0153e0b2016-11-03 14:27:13 -060076 struct loader_icd_term *this_icd_term;
Jon Ashburn24cd4be2015-11-01 14:04:06 -070077};
78
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -060079enum loader_debug {
Jon Ashburn23d36b12016-02-02 17:47:28 -070080 LOADER_INFO_BIT = 0x01,
81 LOADER_WARN_BIT = 0x02,
82 LOADER_PERF_BIT = 0x04,
83 LOADER_ERROR_BIT = 0x08,
84 LOADER_DEBUG_BIT = 0x10,
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -060085};
86
87uint32_t g_loader_debug = 0;
88uint32_t g_loader_log_msgs = 0;
89
Jon Ashburn23d36b12016-02-02 17:47:28 -070090// thread safety lock for accessing global data structures such as "loader"
Jon Ashburn6301a0f2015-05-29 13:15:39 -060091// all entrypoints on the instance chain need to be locked except GPA
Jon Ashburn2077e382015-06-29 11:25:34 -060092// additionally CreateDevice and DestroyDevice needs to be locked
Jon Ashburn6301a0f2015-05-29 13:15:39 -060093loader_platform_thread_mutex loader_lock;
Jon Ashburn6461ef22015-09-22 13:11:00 -060094loader_platform_thread_mutex loader_json_lock;
Jon Ashburn6301a0f2015-05-29 13:15:39 -060095
Mark Lobodzinski729a8d32017-01-26 12:16:30 -070096void *loader_instance_heap_alloc(const struct loader_instance *instance, size_t size, VkSystemAllocationScope alloc_scope) {
Mark Young0ad83132016-06-30 13:02:42 -060097 void *pMemory = NULL;
98#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
99 {
100#else
Chia-I Wu3432a0c2015-10-27 18:04:07 +0800101 if (instance && instance->alloc_callbacks.pfnAllocation) {
Mark Young0f183a82017-02-28 09:58:04 -0700102 // These are internal structures, so it's best to align everything to
103 // the largest unit size which is the size of a uint64_t.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700104 pMemory = instance->alloc_callbacks.pfnAllocation(instance->alloc_callbacks.pUserData, size, sizeof(uint64_t), alloc_scope);
Mark Young0ad83132016-06-30 13:02:42 -0600105 } else {
106#endif
107 pMemory = malloc(size);
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600108 }
Mark Youngf2079b92017-05-02 10:49:46 -0600109
Mark Young0ad83132016-06-30 13:02:42 -0600110 return pMemory;
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -0600111}
112
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700113void loader_instance_heap_free(const struct loader_instance *instance, void *pMemory) {
Mark Young0ad83132016-06-30 13:02:42 -0600114 if (pMemory != NULL) {
115#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
116 {
117#else
118 if (instance && instance->alloc_callbacks.pfnFree) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700119 instance->alloc_callbacks.pfnFree(instance->alloc_callbacks.pUserData, pMemory);
Mark Young0ad83132016-06-30 13:02:42 -0600120 } else {
121#endif
122 free(pMemory);
Mark Youngd077f992016-06-30 11:03:59 -0600123 }
Mark Young4b0b9222016-06-29 18:33:53 -0600124 }
Mark Young4b0b9222016-06-29 18:33:53 -0600125}
126
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700127void *loader_instance_heap_realloc(const struct loader_instance *instance, void *pMemory, size_t orig_size, size_t size,
Mark Young0ad83132016-06-30 13:02:42 -0600128 VkSystemAllocationScope alloc_scope) {
129 void *pNewMem = NULL;
130 if (pMemory == NULL || orig_size == 0) {
131 pNewMem = loader_instance_heap_alloc(instance, size, alloc_scope);
132 } else if (size == 0) {
133 loader_instance_heap_free(instance, pMemory);
134#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
135#else
136 } else if (instance && instance->alloc_callbacks.pfnReallocation) {
Mark Young0f183a82017-02-28 09:58:04 -0700137 // These are internal structures, so it's best to align everything to
138 // the largest unit size which is the size of a uint64_t.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700139 pNewMem = instance->alloc_callbacks.pfnReallocation(instance->alloc_callbacks.pUserData, pMemory, size, sizeof(uint64_t),
140 alloc_scope);
Mark Young0ad83132016-06-30 13:02:42 -0600141#endif
142 } else {
143 pNewMem = realloc(pMemory, size);
144 }
145 return pNewMem;
Mark Young4b0b9222016-06-29 18:33:53 -0600146}
147
Mark Young0ad83132016-06-30 13:02:42 -0600148void *loader_instance_tls_heap_alloc(size_t size) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700149 return loader_instance_heap_alloc(tls_instance, size, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Mark Young4b0b9222016-06-29 18:33:53 -0600150}
Mark Young4b0b9222016-06-29 18:33:53 -0600151
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700152void loader_instance_tls_heap_free(void *pMemory) { loader_instance_heap_free(tls_instance, pMemory); }
Mark Young0ad83132016-06-30 13:02:42 -0600153
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700154void *loader_device_heap_alloc(const struct loader_device *device, size_t size, VkSystemAllocationScope alloc_scope) {
Mark Young0ad83132016-06-30 13:02:42 -0600155 void *pMemory = NULL;
156#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
157 {
158#else
159 if (device && device->alloc_callbacks.pfnAllocation) {
Mark Young0f183a82017-02-28 09:58:04 -0700160 // These are internal structures, so it's best to align everything to
161 // the largest unit size which is the size of a uint64_t.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700162 pMemory = device->alloc_callbacks.pfnAllocation(device->alloc_callbacks.pUserData, size, sizeof(uint64_t), alloc_scope);
Mark Young0ad83132016-06-30 13:02:42 -0600163 } else {
164#endif
165 pMemory = malloc(size);
166 }
167 return pMemory;
168}
169
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700170void loader_device_heap_free(const struct loader_device *device, void *pMemory) {
Mark Young0ad83132016-06-30 13:02:42 -0600171 if (pMemory != NULL) {
172#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
173 {
174#else
175 if (device && device->alloc_callbacks.pfnFree) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700176 device->alloc_callbacks.pfnFree(device->alloc_callbacks.pUserData, pMemory);
Mark Young0ad83132016-06-30 13:02:42 -0600177 } else {
178#endif
179 free(pMemory);
180 }
181 }
182}
183
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700184void *loader_device_heap_realloc(const struct loader_device *device, void *pMemory, size_t orig_size, size_t size,
Mark Young0ad83132016-06-30 13:02:42 -0600185 VkSystemAllocationScope alloc_scope) {
186 void *pNewMem = NULL;
187 if (pMemory == NULL || orig_size == 0) {
188 pNewMem = loader_device_heap_alloc(device, size, alloc_scope);
189 } else if (size == 0) {
190 loader_device_heap_free(device, pMemory);
191#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
192#else
193 } else if (device && device->alloc_callbacks.pfnReallocation) {
Mark Young0f183a82017-02-28 09:58:04 -0700194 // These are internal structures, so it's best to align everything to
195 // the largest unit size which is the size of a uint64_t.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700196 pNewMem = device->alloc_callbacks.pfnReallocation(device->alloc_callbacks.pUserData, pMemory, size, sizeof(uint64_t),
197 alloc_scope);
Mark Young0ad83132016-06-30 13:02:42 -0600198#endif
199 } else {
200 pNewMem = realloc(pMemory, size);
201 }
202 return pNewMem;
203}
204
205// Environment variables
206#if defined(__linux__)
207
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700208static inline char *loader_getenv(const char *name, const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600209 // No allocation of memory necessary for Linux, but we should at least touch
210 // the inst pointer to get rid of compiler warnings.
211 (void)inst;
Mark Youngd8c6b692017-03-09 11:39:41 -0700212 return getenv(name);
213}
214
Mark Youngd8c6b692017-03-09 11:39:41 -0700215static inline char *loader_secure_getenv(const char *name, const struct loader_instance *inst) {
216 // No allocation of memory necessary for Linux, but we should at least touch
217 // the inst pointer to get rid of compiler warnings.
218 (void)inst;
Mark Youngf2f2a662017-03-08 10:11:52 -0700219
Mark Youngba7ee022017-03-09 10:41:25 -0700220#ifdef HAVE_SECURE_GETENV
221 return secure_getenv(name);
222#elif defined(HAVE___SECURE_GETENV)
Mark Youngf2f2a662017-03-08 10:11:52 -0700223 return __secure_getenv(name);
224#else
Mark Youngf2079b92017-05-02 10:49:46 -0600225#pragma message( \
226 "Warning: Falling back to non-secure getenv for environmental lookups! Consider" \
227 " updating to a different libc.")
Mark Youngd8c6b692017-03-09 11:39:41 -0700228 return loader_getenv(name, inst);
Mark Youngf2f2a662017-03-08 10:11:52 -0700229#endif
Mark Young0ad83132016-06-30 13:02:42 -0600230}
Mark Youngf2f2a662017-03-08 10:11:52 -0700231
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700232static inline void loader_free_getenv(char *val, const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600233 // No freeing of memory necessary for Linux, but we should at least touch
234 // the val and inst pointers to get rid of compiler warnings.
235 (void)val;
236 (void)inst;
237}
238
239#elif defined(WIN32)
240
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700241static inline char *loader_getenv(const char *name, const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600242 char *retVal;
243 DWORD valSize;
244
245 valSize = GetEnvironmentVariableA(name, NULL, 0);
246
247 // valSize DOES include the null terminator, so for any set variable
248 // will always be at least 1. If it's 0, the variable wasn't set.
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700249 if (valSize == 0) return NULL;
Mark Young0ad83132016-06-30 13:02:42 -0600250
251 // Allocate the space necessary for the registry entry
252 if (NULL != inst && NULL != inst->alloc_callbacks.pfnAllocation) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700253 retVal = (char *)inst->alloc_callbacks.pfnAllocation(inst->alloc_callbacks.pUserData, valSize, sizeof(char *),
254 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Mark Young0ad83132016-06-30 13:02:42 -0600255 } else {
256 retVal = (char *)malloc(valSize);
257 }
258
259 if (NULL != retVal) {
260 GetEnvironmentVariableA(name, retVal, valSize);
261 }
262
263 return retVal;
264}
265
Mark Youngd8c6b692017-03-09 11:39:41 -0700266static inline char *loader_secure_getenv(const char *name, const struct loader_instance *inst) {
Mark Youngbb3a29c2017-05-19 12:29:43 -0600267 // No secure version for Windows as far as I know
Mark Youngd8c6b692017-03-09 11:39:41 -0700268 return loader_getenv(name, inst);
269}
270
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700271static inline void loader_free_getenv(char *val, const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600272 if (NULL != inst && NULL != inst->alloc_callbacks.pfnFree) {
273 inst->alloc_callbacks.pfnFree(inst->alloc_callbacks.pUserData, val);
274 } else {
275 free((void *)val);
276 }
277}
278
279#else
280
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700281static inline char *loader_getenv(const char *name, const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600282 // stub func
283 (void)inst;
284 (void)name;
285 return NULL;
286}
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700287static inline void loader_free_getenv(char *val, const struct loader_instance *inst) {
Mark Young0ad83132016-06-30 13:02:42 -0600288 // stub func
289 (void)val;
290 (void)inst;
291}
292
293#endif
294
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700295void loader_log(const struct loader_instance *inst, VkFlags msg_type, int32_t msg_code, const char *format, ...) {
Jon Ashburn86723b02015-07-31 15:47:59 -0600296 char msg[512];
Mark Young2c84c0c2017-01-13 10:27:03 -0700297 char cmd_line_msg[512];
Mark Young5de3af72017-04-25 08:08:29 -0600298 size_t cmd_line_size = sizeof(cmd_line_msg);
Jon Ashburnffad94d2015-06-30 14:46:22 -0700299 va_list ap;
300 int ret;
301
Jon Ashburnffad94d2015-06-30 14:46:22 -0700302 va_start(ap, format);
303 ret = vsnprintf(msg, sizeof(msg), format, ap);
Jon Ashburn23d36b12016-02-02 17:47:28 -0700304 if ((ret >= (int)sizeof(msg)) || ret < 0) {
305 msg[sizeof(msg) - 1] = '\0';
Jon Ashburnffad94d2015-06-30 14:46:22 -0700306 }
307 va_end(ap);
308
Courtney Goeltzenleuchter73477392015-12-03 13:48:01 -0700309 if (inst) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700310 util_DebugReportMessage(inst, msg_type, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT, (uint64_t)(uintptr_t)inst, 0, msg_code,
311 "loader", msg);
Courtney Goeltzenleuchter73477392015-12-03 13:48:01 -0700312 }
313
314 if (!(msg_type & g_loader_log_msgs)) {
315 return;
316 }
317
Mark Young2c84c0c2017-01-13 10:27:03 -0700318 cmd_line_msg[0] = '\0';
Mark Young5de3af72017-04-25 08:08:29 -0600319 cmd_line_size -= 1;
320 size_t original_size = cmd_line_size;
Mark Young2c84c0c2017-01-13 10:27:03 -0700321
322 va_start(ap, format);
323 if ((msg_type & LOADER_INFO_BIT) != 0) {
Mark Young6ef95f42017-02-17 09:02:23 -0700324 strncat(cmd_line_msg, "INFO", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700325 cmd_line_size -= 4;
326 }
327 if ((msg_type & LOADER_WARN_BIT) != 0) {
Mark Young5de3af72017-04-25 08:08:29 -0600328 if (cmd_line_size != original_size) {
Mark Young6ef95f42017-02-17 09:02:23 -0700329 strncat(cmd_line_msg, " | ", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700330 cmd_line_size -= 3;
331 }
Mark Young6ef95f42017-02-17 09:02:23 -0700332 strncat(cmd_line_msg, "WARNING", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700333 cmd_line_size -= 7;
334 }
335 if ((msg_type & LOADER_PERF_BIT) != 0) {
Mark Young5de3af72017-04-25 08:08:29 -0600336 if (cmd_line_size != original_size) {
Mark Young6ef95f42017-02-17 09:02:23 -0700337 strncat(cmd_line_msg, " | ", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700338 cmd_line_size -= 3;
339 }
Mark Young6ef95f42017-02-17 09:02:23 -0700340 strncat(cmd_line_msg, "PERF", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700341 cmd_line_size -= 4;
342 }
343 if ((msg_type & LOADER_ERROR_BIT) != 0) {
Mark Young5de3af72017-04-25 08:08:29 -0600344 if (cmd_line_size != original_size) {
Mark Young6ef95f42017-02-17 09:02:23 -0700345 strncat(cmd_line_msg, " | ", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700346 cmd_line_size -= 3;
347 }
Mark Young6ef95f42017-02-17 09:02:23 -0700348 strncat(cmd_line_msg, "ERROR", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700349 cmd_line_size -= 5;
350 }
351 if ((msg_type & LOADER_DEBUG_BIT) != 0) {
Mark Young5de3af72017-04-25 08:08:29 -0600352 if (cmd_line_size != original_size) {
Mark Young6ef95f42017-02-17 09:02:23 -0700353 strncat(cmd_line_msg, " | ", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700354 cmd_line_size -= 3;
355 }
Mark Young6ef95f42017-02-17 09:02:23 -0700356 strncat(cmd_line_msg, "DEBUG", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700357 cmd_line_size -= 5;
358 }
Mark Young5de3af72017-04-25 08:08:29 -0600359 if (cmd_line_size != original_size) {
Mark Young6ef95f42017-02-17 09:02:23 -0700360 strncat(cmd_line_msg, ": ", cmd_line_size);
Mark Young2c84c0c2017-01-13 10:27:03 -0700361 cmd_line_size -= 2;
362 }
Mark Young5de3af72017-04-25 08:08:29 -0600363
364 if (0 < cmd_line_size) {
365 // If the message is too long, trim it down
366 if (strlen(msg) > cmd_line_size) {
367 msg[cmd_line_size - 1] = '\0';
368 }
369 strncat(cmd_line_msg, msg, cmd_line_size);
370 } else {
371 // Shouldn't get here, but check to make sure if we've already overrun
372 // the string boundary
373 assert(false);
374 }
Mark Young2c84c0c2017-01-13 10:27:03 -0700375
Ian Elliott4470a302015-02-17 10:33:47 -0700376#if defined(WIN32)
Mark Young2c84c0c2017-01-13 10:27:03 -0700377 OutputDebugString(cmd_line_msg);
mschottb9cdb782015-07-22 14:11:29 +0200378 OutputDebugString("\n");
Jon Ashburnffad94d2015-06-30 14:46:22 -0700379#endif
Mark Young5de3af72017-04-25 08:08:29 -0600380
Mark Young2c84c0c2017-01-13 10:27:03 -0700381 fputs(cmd_line_msg, stderr);
Jon Ashburnffad94d2015-06-30 14:46:22 -0700382 fputc('\n', stderr);
383}
384
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700385VKAPI_ATTR VkResult VKAPI_CALL vkSetInstanceDispatch(VkInstance instance, void *object) {
Jon Ashburnc3c58772016-03-29 11:16:01 -0600386 struct loader_instance *inst = loader_get_instance(instance);
387 if (!inst) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700388 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
389 "vkSetInstanceDispatch: Can not retrieve Instance "
390 "dispatch table.");
Jon Ashburnc3c58772016-03-29 11:16:01 -0600391 return VK_ERROR_INITIALIZATION_FAILED;
392 }
393 loader_set_dispatch(object, inst->disp);
394 return VK_SUCCESS;
395}
396
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700397VKAPI_ATTR VkResult VKAPI_CALL vkSetDeviceDispatch(VkDevice device, void *object) {
Jon Ashburned8f2312016-03-31 10:52:22 -0600398 struct loader_device *dev;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700399 struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, NULL);
Jon Ashburned8f2312016-03-31 10:52:22 -0600400
Mark Young0153e0b2016-11-03 14:27:13 -0600401 if (NULL == icd_term) {
Jon Ashburned8f2312016-03-31 10:52:22 -0600402 return VK_ERROR_INITIALIZATION_FAILED;
403 }
404 loader_set_dispatch(object, &dev->loader_dispatch);
405 return VK_SUCCESS;
406}
407
Lenny Komowf7c09382017-08-31 16:35:08 -0600408#if defined(_WIN32)
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200409// Find the list of registry files (names VulkanDriverName/VulkanDriverNameWow) in hkr.
410//
411// This function looks for filename in given device handle, filename is then added to return list
412// function return true if filename was appended to reg_data list
413// If error occures result is updated with failure reason
Lenny Komowf7c09382017-08-31 16:35:08 -0600414bool loaderGetDeviceRegistryEntry(const struct loader_instance *inst, char **reg_data, PDWORD total_size, DEVINST dev_id, LPCTSTR value_name, VkResult *result)
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200415{
416 HKEY hkrKey = INVALID_HANDLE_VALUE;
Lenny Komowf7c09382017-08-31 16:35:08 -0600417 DWORD requiredSize, data_type;
418 char *manifest_path = NULL;
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200419 bool found = false;
420
421 if (NULL == total_size || NULL == reg_data) {
422 *result = VK_ERROR_INITIALIZATION_FAILED;
423 return false;
424 }
425
Lenny Komowf7c09382017-08-31 16:35:08 -0600426 CONFIGRET status = CM_Open_DevNode_Key(dev_id, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hkrKey, CM_REGISTRY_SOFTWARE);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200427 if (status != CR_SUCCESS) {
428 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Lenny Komowf7c09382017-08-31 16:35:08 -0600429 "loaderGetDeviceRegistryEntry: Failed to open registry key for DeviceID(%d)", dev_id);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200430 *result = VK_ERROR_INITIALIZATION_FAILED;
431 return false;
432 }
433
434 // query value
435 LSTATUS ret = RegQueryValueEx(
436 hkrKey,
Lenny Komowf7c09382017-08-31 16:35:08 -0600437 value_name,
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200438 NULL,
439 NULL,
440 NULL,
441 &requiredSize);
442
443 if (ret != ERROR_SUCCESS) {
Lenny Komowf7c09382017-08-31 16:35:08 -0600444 if (ret == ERROR_FILE_NOT_FOUND) {
445 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
446 "loaderGetDeviceRegistryEntry: Device ID(%d) Does not contain a value for \"%s\"", dev_id, value_name);
447 } else {
448 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
449 "loaderGetDeviceRegistryEntry: DeviceID(%d) Failed to obtain %s size", dev_id, value_name);
450 }
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200451 goto out;
452 }
453
Lenny Komowf7c09382017-08-31 16:35:08 -0600454 manifest_path = loader_instance_heap_alloc(inst, requiredSize, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
455 if (manifest_path == NULL) {
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200456 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
457 "loaderGetDeviceRegistryEntry: Failed to allocate space for DriverName.");
458 *result = VK_ERROR_OUT_OF_HOST_MEMORY;
459 goto out;
460 }
461
462 ret = RegQueryValueEx(
463 hkrKey,
Lenny Komowf7c09382017-08-31 16:35:08 -0600464 value_name,
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200465 NULL,
Lenny Komowf7c09382017-08-31 16:35:08 -0600466 &data_type,
Jamie Madilla11ae0b2017-11-08 14:48:32 -0500467 (BYTE *)manifest_path,
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200468 &requiredSize
469 );
470
471 if (ret != ERROR_SUCCESS) {
472 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Lenny Komowf7c09382017-08-31 16:35:08 -0600473 "loaderGetDeviceRegistryEntry: DeviceID(%d) Failed to obtain %s", value_name);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200474
475 *result = VK_ERROR_INITIALIZATION_FAILED;
476 goto out;
477 }
478
Lenny Komowf7c09382017-08-31 16:35:08 -0600479 if (data_type != REG_SZ && data_type != REG_MULTI_SZ) {
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200480 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Lenny Komowf7c09382017-08-31 16:35:08 -0600481 "loaderGetDeviceRegistryEntry: Invalid %s data type. Expected REG_SZ or REG_MULTI_SZ.", value_name);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200482 *result = VK_ERROR_INITIALIZATION_FAILED;
483 goto out;
484 }
485
486 if (NULL == *reg_data) {
487 *reg_data = loader_instance_heap_alloc(inst, *total_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
488 if (NULL == *reg_data) {
489 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Lenny Komowf7c09382017-08-31 16:35:08 -0600490 "loaderGetDeviceRegistryEntry: Failed to allocate space for registry data for key %s", manifest_path);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200491 *result = VK_ERROR_OUT_OF_HOST_MEMORY;
492 goto out;
493 }
494 *reg_data[0] = '\0';
495 } else if (strlen(*reg_data) + requiredSize + 1 > *total_size) {
496 void *new_ptr = loader_instance_heap_realloc(inst, *reg_data, *total_size, *total_size * 2,
497 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
498 if (NULL == new_ptr) {
499 loader_log(
500 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
501 "loaderGetDeviceRegistryEntry: Failed to reallocate space for registry value of size %d for key %s",
Lenny Komowf7c09382017-08-31 16:35:08 -0600502 *total_size * 2, manifest_path);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200503 *result = VK_ERROR_OUT_OF_HOST_MEMORY;
504 goto out;
505 }
506 *reg_data = new_ptr;
507 *total_size *= 2;
508 }
509
Lenny Komowf7c09382017-08-31 16:35:08 -0600510 for (char *curr_filename = manifest_path; curr_filename[0] != '\0'; curr_filename += strlen(curr_filename) + 1) {
511 if (strlen(*reg_data) == 0) {
512 (void)snprintf(*reg_data, requiredSize + 1, "%s", curr_filename);
513 } else {
514 (void)snprintf(*reg_data + strlen(*reg_data), requiredSize + 2, "%c%s", PATH_SEPARATOR, curr_filename);
515 }
Jamie Madillaca1de12017-12-03 11:59:17 -0500516 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "%s: Located json file \"%s\" from PnP registry: %s", __FUNCTION__, curr_filename, value_name);
Lenny Komowf7c09382017-08-31 16:35:08 -0600517
518 if (data_type == REG_SZ) {
519 break;
520 }
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200521 }
522 found = true;
523
524out:
Lenny Komowf7c09382017-08-31 16:35:08 -0600525 if (manifest_path != NULL) {
526 loader_instance_heap_free(inst, manifest_path);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200527 }
528 RegCloseKey(hkrKey);
529 return found;
530}
531
532// Find the list of registry files (names VulkanDriverName/VulkanDriverNameWow) in hkr .
533//
534// This function looks for display devices and childish software components
535// for a list of files which are added to a returned list (function return
536// value).
537// Function return is a string with a ';' separated list of filenames.
538// Function return is NULL if no valid name/value pairs are found in the key,
539// or the key is not found.
540//
541// *reg_data contains a string list of filenames as pointer.
542// When done using the returned string list, the caller should free the pointer.
Lenny Komowf7c09382017-08-31 16:35:08 -0600543VkResult loaderGetDeviceRegistryFiles(const struct loader_instance *inst, char **reg_data, PDWORD reg_data_size, LPCTSTR value_name) {
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200544 static const char* softwareComponentGUID = "{5c4c3332-344d-483c-8739-259e934c9cc8}";
545 static const char* displayGUID = "{4d36e968-e325-11ce-bfc1-08002be10318}";
546 const ULONG flags = CM_GETIDLIST_FILTER_CLASS | CM_GETIDLIST_FILTER_PRESENT;
547
548 char childGuid[MAX_GUID_STRING_LEN + 2]; // +2 for brackets {}
549 ULONG childGuidSize = sizeof(childGuid);
550
551 DEVINST devID = 0, childID = 0;
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200552 char *pDeviceNames = NULL;
553 ULONG deviceNamesSize = 0;
554 VkResult result = VK_SUCCESS;
555 bool found = false;
556
557 if (NULL == reg_data) {
558 result = VK_ERROR_INITIALIZATION_FAILED;
559 return result;
560 }
561
562 // if after obtaining the DeviceNameSize, new device is added start over
563 do {
564 CM_Get_Device_ID_List_Size(&deviceNamesSize, displayGUID, flags);
565
566 if (pDeviceNames != NULL) {
567 loader_instance_heap_free(inst, pDeviceNames);
568 }
569
570 pDeviceNames = loader_instance_heap_alloc(inst, deviceNamesSize, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
571 if (pDeviceNames == NULL) {
572 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
573 "loaderGetDeviceRegistryFiles: Failed to allocate space for display device names.");
574 result = VK_ERROR_OUT_OF_HOST_MEMORY;
Slawomir Cygan018bfd52017-08-25 10:54:03 +0200575 return result;
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200576 }
577 } while (CM_Get_Device_ID_List(displayGUID, pDeviceNames, deviceNamesSize, flags) == CR_BUFFER_SMALL);
578
579 if (pDeviceNames) {
580
581 for (char *deviceName = pDeviceNames; *deviceName; deviceName += strlen(deviceName) + 1) {
582 CONFIGRET status = CM_Locate_DevNode(&devID, deviceName, CM_LOCATE_DEVNODE_NORMAL);
583 if (CR_SUCCESS != status) {
584 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
585 "loaderGetRegistryFiles: failed to open DevNode %s", deviceName);
586 continue;
587 }
588 ULONG ulStatus, ulProblem;
589 status = CM_Get_DevNode_Status(&ulStatus, &ulProblem, devID, 0);
590
591 if (CR_SUCCESS != status)
592 {
593 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
594 "loaderGetRegistryFiles: failed to probe device status %s", deviceName);
595 continue;
596 }
597 if ((ulStatus & DN_HAS_PROBLEM) && (ulProblem == CM_PROB_NEED_RESTART || ulProblem == DN_NEED_RESTART))
598 {
Lenny Komowe17a12a2017-08-10 09:25:49 -0600599 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200600 "loaderGetRegistryFiles: device %s is pending reboot, skipping ...", deviceName);
601 continue;
602 }
603
Lenny Komowe17a12a2017-08-10 09:25:49 -0600604 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200605 "loaderGetRegistryFiles: opening device %s", deviceName);
606
Lenny Komowf7c09382017-08-31 16:35:08 -0600607 if (loaderGetDeviceRegistryEntry(inst, reg_data, reg_data_size, devID, value_name, &result)) {
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200608 found = true;
609 continue;
610 }
Igor Ostrowski21532732017-10-06 18:26:23 +0200611 else if (result == VK_ERROR_OUT_OF_HOST_MEMORY) {
612 break;
613 }
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200614
615 status = CM_Get_Child(&childID, devID, 0);
616 if (status != CR_SUCCESS) {
Lenny Komowe17a12a2017-08-10 09:25:49 -0600617 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200618 "loaderGetRegistryFiles: unable to open child-device error:%d", status);
619 continue;
620 }
621
622 do {
623 char buffer[MAX_DEVICE_ID_LEN];
624 CM_Get_Device_ID(childID, buffer, MAX_DEVICE_ID_LEN, 0);
625
Lenny Komowe17a12a2017-08-10 09:25:49 -0600626 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200627 "loaderGetRegistryFiles: Opening child device %d - %s", childID, buffer);
628
629 status = CM_Get_DevNode_Registry_Property(childID, CM_DRP_CLASSGUID, NULL, &childGuid, &childGuidSize, 0);
630 if (status != CR_SUCCESS) {
631 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
632 "loaderGetRegistryFiles: unable to obtain GUID for:%d error:%d", childID, status);
633
634 result = VK_ERROR_INITIALIZATION_FAILED;
635 continue;
636 }
637
638 if (strcmp(childGuid, softwareComponentGUID) != 0) {
639 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
640 "loaderGetRegistryFiles: GUID for %d is not SoftwareComponent skipping", childID);
641 continue;
642 }
643
Lenny Komowf7c09382017-08-31 16:35:08 -0600644 if (loaderGetDeviceRegistryEntry(inst, reg_data, reg_data_size, childID, value_name, &result)) {
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200645 found = true;
646 break; // check next-display-device
647 }
648
649 } while (CM_Get_Sibling(&childID, childID, 0) == CR_SUCCESS);
650 }
651
652 loader_instance_heap_free(inst, pDeviceNames);
653 }
654
655 if (!found && result != VK_ERROR_OUT_OF_HOST_MEMORY) {
656 result = VK_ERROR_INITIALIZATION_FAILED;
657 }
658
659 return result;
660}
661
Tony Barbourea968902015-07-29 14:26:21 -0600662static char *loader_get_next_path(char *path);
Mark Young2c84c0c2017-01-13 10:27:03 -0700663
664// Find the list of registry files (names within a key) in key "location".
665//
666// This function looks in the registry (hive = DEFAULT_VK_REGISTRY_HIVE) key as
667// given in "location"
668// for a list or name/values which are added to a returned list (function return
669// value).
670// The DWORD values within the key must be 0 or they are skipped.
671// Function return is a string with a ';' separated list of filenames.
672// Function return is NULL if no valid name/value pairs are found in the key,
673// or the key is not found.
674//
675// *reg_data contains a string list of filenames as pointer.
676// When done using the returned string list, the caller should free the pointer.
Slawomir Cygan8f9f2552017-08-09 11:36:52 +0200677VkResult loaderGetRegistryFiles(const struct loader_instance *inst, char *location, bool use_secondary_hive, char **reg_data, PDWORD reg_data_size) {
Jon Ashburnffad94d2015-06-30 14:46:22 -0700678 LONG rtn_value;
Lenny Komowda849dc2017-03-01 17:22:29 -0700679 HKEY hive = DEFAULT_VK_REGISTRY_HIVE, key;
Piers Daniell524ec732015-11-05 16:58:26 -0700680 DWORD access_flags;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700681 char name[2048];
Tony Barbourea968902015-07-29 14:26:21 -0600682 char *loc = location;
683 char *next;
Lenny Komowda849dc2017-03-01 17:22:29 -0700684 DWORD idx;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700685 DWORD name_size = sizeof(name);
686 DWORD value;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700687 DWORD value_size = sizeof(value);
Mark Young2c84c0c2017-01-13 10:27:03 -0700688 VkResult result = VK_SUCCESS;
689 bool found = false;
690
691 if (NULL == reg_data) {
692 result = VK_ERROR_INITIALIZATION_FAILED;
693 goto out;
694 }
Tony Barbourea968902015-07-29 14:26:21 -0600695
Jon Ashburn23d36b12016-02-02 17:47:28 -0700696 while (*loc) {
Tony Barbourea968902015-07-29 14:26:21 -0600697 next = loader_get_next_path(loc);
Piers Daniell524ec732015-11-05 16:58:26 -0700698 access_flags = KEY_QUERY_VALUE;
Tony Barbourea968902015-07-29 14:26:21 -0600699 rtn_value = RegOpenKeyEx(hive, loc, 0, access_flags, &key);
Lenny Komowda849dc2017-03-01 17:22:29 -0700700 if (ERROR_SUCCESS == rtn_value) {
701 idx = 0;
702 while ((rtn_value = RegEnumValue(key, idx++, name, &name_size, NULL, NULL, (LPBYTE)&value, &value_size)) ==
703 ERROR_SUCCESS) {
704 if (value_size == sizeof(value) && value == 0) {
705 if (NULL == *reg_data) {
Slawomir Cygan8f9f2552017-08-09 11:36:52 +0200706 *reg_data = loader_instance_heap_alloc(inst, *reg_data_size, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Lenny Komowda849dc2017-03-01 17:22:29 -0700707 if (NULL == *reg_data) {
708 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngbb3a29c2017-05-19 12:29:43 -0600709 "loaderGetRegistryFiles: Failed to allocate space for registry data for key %s", name);
Slawomir Cygane5830322018-01-16 17:17:07 +0100710 RegCloseKey(key);
Lenny Komowda849dc2017-03-01 17:22:29 -0700711 result = VK_ERROR_OUT_OF_HOST_MEMORY;
712 goto out;
713 }
714 *reg_data[0] = '\0';
Slawomir Cygan8f9f2552017-08-09 11:36:52 +0200715 } else if (strlen(*reg_data) + name_size + 1 > *reg_data_size) {
716 void *new_ptr = loader_instance_heap_realloc(inst, *reg_data, *reg_data_size, *reg_data_size * 2,
Mark Youngbb3a29c2017-05-19 12:29:43 -0600717 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
718 if (NULL == new_ptr) {
719 loader_log(
720 inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
721 "loaderGetRegistryFiles: Failed to reallocate space for registry value of size %d for key %s",
Slawomir Cygan8f9f2552017-08-09 11:36:52 +0200722 *reg_data_size * 2, name);
Slawomir Cygane5830322018-01-16 17:17:07 +0100723 RegCloseKey(key);
Lenny Komowda849dc2017-03-01 17:22:29 -0700724 result = VK_ERROR_OUT_OF_HOST_MEMORY;
725 goto out;
726 }
Mark Youngbb3a29c2017-05-19 12:29:43 -0600727 *reg_data = new_ptr;
Slawomir Cygan8f9f2552017-08-09 11:36:52 +0200728 *reg_data_size *= 2;
Lenny Komowda849dc2017-03-01 17:22:29 -0700729 }
Mark Youngf2079b92017-05-02 10:49:46 -0600730 loader_log(
731 inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Located json file \"%s\" from registry \"%s\\%s\"", name,
732 hive == DEFAULT_VK_REGISTRY_HIVE ? DEFAULT_VK_REGISTRY_HIVE_STR : SECONDARY_VK_REGISTRY_HIVE_STR, location);
Lenny Komowda849dc2017-03-01 17:22:29 -0700733 if (strlen(*reg_data) == 0) {
734 (void)snprintf(*reg_data, name_size + 1, "%s", name);
735 } else {
736 (void)snprintf(*reg_data + strlen(*reg_data), name_size + 2, "%c%s", PATH_SEPARATOR, name);
737 }
738 found = true;
739 }
740 name_size = 2048;
741 }
Slawomir Cygane5830322018-01-16 17:17:07 +0100742 RegCloseKey(key);
Jon Ashburnffad94d2015-06-30 14:46:22 -0700743 }
Tony Barbourea968902015-07-29 14:26:21 -0600744
Lenny Komowda849dc2017-03-01 17:22:29 -0700745 // Advance the location - if the next location is in the secondary hive, then reset the locations and advance the hive
746 if (use_secondary_hive && (hive == DEFAULT_VK_REGISTRY_HIVE) && (*next == '\0')) {
747 loc = location;
748 hive = SECONDARY_VK_REGISTRY_HIVE;
749 } else {
750 loc = next;
Tony Barbourea968902015-07-29 14:26:21 -0600751 }
Jon Ashburnffad94d2015-06-30 14:46:22 -0700752 }
Tony Barbourea968902015-07-29 14:26:21 -0600753
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +0200754 if (!found && result != VK_ERROR_OUT_OF_HOST_MEMORY) {
Mark Young2c84c0c2017-01-13 10:27:03 -0700755 result = VK_ERROR_INITIALIZATION_FAILED;
756 }
757
758out:
759
760 return result;
Jon Ashburnffad94d2015-06-30 14:46:22 -0700761}
762
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700763#endif // WIN32
Ian Elliott4470a302015-02-17 10:33:47 -0700764
Mark Young0f183a82017-02-28 09:58:04 -0700765// Combine path elements, separating each element with the platform-specific
766// directory separator, and save the combined string to a destination buffer,
Mark Youngdee312c2017-03-08 13:38:35 -0700767// not exceeding the given length. Path elements are given as variable args,
Mark Young0f183a82017-02-28 09:58:04 -0700768// with a NULL element terminating the list.
769//
770// \returns the total length of the combined string, not including an ASCII
771// NUL termination character. This length may exceed the available storage:
772// in this case, the written string will be truncated to avoid a buffer
773// overrun, and the return value will greater than or equal to the storage
774// size. A NULL argument may be provided as the destination buffer in order
775// to determine the required string length without actually writing a string.
Jon Ashburn23d36b12016-02-02 17:47:28 -0700776static size_t loader_platform_combine_path(char *dest, size_t len, ...) {
Courtney Goeltzenleuchter0ef13a02015-12-16 16:19:46 -0700777 size_t required_len = 0;
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500778 va_list ap;
779 const char *component;
780
781 va_start(ap, len);
782
Jon Ashburn23d36b12016-02-02 17:47:28 -0700783 while ((component = va_arg(ap, const char *))) {
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500784 if (required_len > 0) {
785 // This path element is not the first non-empty element; prepend
786 // a directory separator if space allows
787 if (dest && required_len + 1 < len) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700788 (void)snprintf(dest + required_len, len - required_len, "%c", DIRECTORY_SYMBOL);
Daniel Dadap00b4aba2015-09-30 11:50:51 -0500789 }
790 required_len++;
791 }
792
793 if (dest && required_len < len) {
794 strncpy(dest + required_len, component, len - required_len);
795 }
796 required_len += strlen(component);
797 }
798
799 va_end(ap);
800
801 // strncpy(3) won't add a NUL terminating byte in the event of truncation.
802 if (dest && required_len >= len) {
803 dest[len - 1] = '\0';
804 }
805
806 return required_len;
807}
808
Mark Young0f183a82017-02-28 09:58:04 -0700809// Given string of three part form "maj.min.pat" convert to a vulkan version number.
Mark Young60861ac2016-09-02 11:39:26 -0600810static uint32_t loader_make_version(char *vers_str) {
Jon Ashburn23d36b12016-02-02 17:47:28 -0700811 uint32_t vers = 0, major = 0, minor = 0, patch = 0;
Mark Young60861ac2016-09-02 11:39:26 -0600812 char *vers_tok;
Jon Ashburnc7237a72015-08-03 09:08:46 -0600813
Mark Young60861ac2016-09-02 11:39:26 -0600814 if (!vers_str) {
Jon Ashburnc7237a72015-08-03 09:08:46 -0600815 return vers;
Jon Ashburnc7237a72015-08-03 09:08:46 -0600816 }
Mark Young60861ac2016-09-02 11:39:26 -0600817
818 vers_tok = strtok(vers_str, ".\"\n\r");
819 if (NULL != vers_tok) {
820 major = (uint16_t)atoi(vers_tok);
821 vers_tok = strtok(NULL, ".\"\n\r");
822 if (NULL != vers_tok) {
823 minor = (uint16_t)atoi(vers_tok);
824 vers_tok = strtok(NULL, ".\"\n\r");
825 if (NULL != vers_tok) {
826 patch = (uint16_t)atoi(vers_tok);
827 }
828 }
829 }
Jon Ashburnc7237a72015-08-03 09:08:46 -0600830
831 return VK_MAKE_VERSION(major, minor, patch);
Jon Ashburnc7237a72015-08-03 09:08:46 -0600832}
833
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700834bool compare_vk_extension_properties(const VkExtensionProperties *op1, const VkExtensionProperties *op2) {
Chia-I Wu3432a0c2015-10-27 18:04:07 +0800835 return strcmp(op1->extensionName, op2->extensionName) == 0 ? true : false;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600836}
837
Mark Young0f183a82017-02-28 09:58:04 -0700838// Search the given ext_array for an extension matching the given vk_ext_prop
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700839bool has_vk_extension_property_array(const VkExtensionProperties *vk_ext_prop, const uint32_t count,
Jon Ashburn23d36b12016-02-02 17:47:28 -0700840 const VkExtensionProperties *ext_array) {
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600841 for (uint32_t i = 0; i < count; i++) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700842 if (compare_vk_extension_properties(vk_ext_prop, &ext_array[i])) return true;
Jon Ashburnbd6c4882015-07-02 12:59:25 -0600843 }
844 return false;
845}
846
Mark Young0f183a82017-02-28 09:58:04 -0700847// Search the given ext_list for an extension matching the given vk_ext_prop
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700848bool has_vk_extension_property(const VkExtensionProperties *vk_ext_prop, const struct loader_extension_list *ext_list) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600849 for (uint32_t i = 0; i < ext_list->count; i++) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700850 if (compare_vk_extension_properties(&ext_list->list[i], vk_ext_prop)) return true;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600851 }
852 return false;
853}
854
Mark Young0f183a82017-02-28 09:58:04 -0700855// Search the given ext_list for a device extension matching the given ext_prop
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700856bool has_vk_dev_ext_property(const VkExtensionProperties *ext_prop, const struct loader_device_extension_list *ext_list) {
Jon Ashburnb8726962016-04-08 15:03:35 -0600857 for (uint32_t i = 0; i < ext_list->count; i++) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700858 if (compare_vk_extension_properties(&ext_list->list[i].props, ext_prop)) return true;
Jon Ashburnb8726962016-04-08 15:03:35 -0600859 }
860 return false;
861}
862
Mark Young0f183a82017-02-28 09:58:04 -0700863// Search the given layer list for a layer matching the given layer name
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700864static struct loader_layer_properties *loader_get_layer_property(const char *name, const struct loader_layer_list *layer_list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600865 for (uint32_t i = 0; i < layer_list->count; i++) {
866 const VkLayerProperties *item = &layer_list->list[i].info;
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700867 if (strcmp(name, item->layerName) == 0) return &layer_list->list[i];
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -0600868 }
869 return NULL;
870}
871
Mark Young0f183a82017-02-28 09:58:04 -0700872// Get the next unused layer property in the list. Init the property to zero.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700873static struct loader_layer_properties *loader_get_next_layer_property(const struct loader_instance *inst,
874 struct loader_layer_list *layer_list) {
Jon Ashburne13ecc92015-08-03 17:19:30 -0600875 if (layer_list->capacity == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700876 layer_list->list =
877 loader_instance_heap_alloc(inst, sizeof(struct loader_layer_properties) * 64, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburne13ecc92015-08-03 17:19:30 -0600878 if (layer_list->list == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700879 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
880 "loader_get_next_layer_property: Out of memory can "
881 "not add any layer properties to list");
Jon Ashburne13ecc92015-08-03 17:19:30 -0600882 return NULL;
883 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700884 memset(layer_list->list, 0, sizeof(struct loader_layer_properties) * 64);
Jon Ashburne13ecc92015-08-03 17:19:30 -0600885 layer_list->capacity = sizeof(struct loader_layer_properties) * 64;
886 }
887
Mark Young0f183a82017-02-28 09:58:04 -0700888 // Ensure enough room to add an entry
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700889 if ((layer_list->count + 1) * sizeof(struct loader_layer_properties) > layer_list->capacity) {
Mark Youngbb3a29c2017-05-19 12:29:43 -0600890 void *new_ptr = loader_instance_heap_realloc(inst, layer_list->list, layer_list->capacity, layer_list->capacity * 2,
891 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
892 if (NULL == new_ptr) {
893 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loader_get_next_layer_property: realloc failed for layer list");
Mark Young0ad83132016-06-30 13:02:42 -0600894 return NULL;
Jon Ashburne13ecc92015-08-03 17:19:30 -0600895 }
Mark Youngbb3a29c2017-05-19 12:29:43 -0600896 layer_list->list = new_ptr;
Jon Ashburne13ecc92015-08-03 17:19:30 -0600897 layer_list->capacity *= 2;
898 }
899
900 layer_list->count++;
901 return &(layer_list->list[layer_list->count - 1]);
902}
903
Mark Youngdee312c2017-03-08 13:38:35 -0700904// Remove all layer properties entries from the list
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700905void loader_delete_layer_properties(const struct loader_instance *inst, struct loader_layer_list *layer_list) {
Cort Stratton6974a132017-11-28 12:11:05 -0800906 uint32_t i, j, k;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700907 struct loader_device_extension_list *dev_ext_list;
Cort Stratton6974a132017-11-28 12:11:05 -0800908 struct loader_dev_ext_props *ext_props;
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700909 if (!layer_list) return;
Jon Ashburnb82c1852015-08-11 14:49:54 -0600910
Jon Ashburne13ecc92015-08-03 17:19:30 -0600911 for (i = 0; i < layer_list->count; i++) {
Mark Youngf2079b92017-05-02 10:49:46 -0600912 if (NULL != layer_list->list[i].component_layer_names) {
913 loader_instance_heap_free(inst, layer_list->list[i].component_layer_names);
914 layer_list->list[i].component_layer_names = NULL;
915 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700916 loader_destroy_generic_list(inst, (struct loader_generic_list *)&layer_list->list[i].instance_extension_list);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700917 dev_ext_list = &layer_list->list[i].device_extension_list;
Cort Stratton6974a132017-11-28 12:11:05 -0800918 if (dev_ext_list->capacity > 0 && NULL != dev_ext_list->list) {
919 for (j = 0; j < dev_ext_list->count; j++) {
920 ext_props = &dev_ext_list->list[j];
921 if (ext_props->entrypoint_count > 0) {
922 for (k = 0; k < ext_props->entrypoint_count; k++) {
923 loader_instance_heap_free(inst, ext_props->entrypoints[k]);
924 }
925 loader_instance_heap_free(inst, ext_props->entrypoints);
926 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700927 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -0700928 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700929 loader_destroy_generic_list(inst, (struct loader_generic_list *)dev_ext_list);
Jon Ashburne13ecc92015-08-03 17:19:30 -0600930 }
931 layer_list->count = 0;
932
Jon Ashburnb82c1852015-08-11 14:49:54 -0600933 if (layer_list->capacity > 0) {
934 layer_list->capacity = 0;
Mark Young0ad83132016-06-30 13:02:42 -0600935 loader_instance_heap_free(inst, layer_list->list);
Jon Ashburnb82c1852015-08-11 14:49:54 -0600936 }
Jon Ashburne13ecc92015-08-03 17:19:30 -0600937}
938
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700939static VkResult loader_add_instance_extensions(const struct loader_instance *inst,
940 const PFN_vkEnumerateInstanceExtensionProperties fp_get_props, const char *lib_name,
941 struct loader_extension_list *ext_list) {
Courtney Goeltzenleuchter36eeb742015-12-21 16:41:47 -0700942 uint32_t i, count = 0;
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600943 VkExtensionProperties *ext_props;
Mark Young3a587792016-08-19 15:25:08 -0600944 VkResult res = VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600945
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600946 if (!fp_get_props) {
Mark Young0f183a82017-02-28 09:58:04 -0700947 // No EnumerateInstanceExtensionProperties defined
Mark Young3a587792016-08-19 15:25:08 -0600948 goto out;
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600949 }
950
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600951 res = fp_get_props(NULL, &count, NULL);
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600952 if (res != VK_SUCCESS) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700953 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
954 "loader_add_instance_extensions: Error getting Instance "
955 "extension count from %s",
Mark Youngb6399312017-01-10 14:22:15 -0700956 lib_name);
Mark Young3a587792016-08-19 15:25:08 -0600957 goto out;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600958 }
Jon Ashburn953bb3c2015-06-10 16:11:42 -0600959
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600960 if (count == 0) {
Mark Young0f183a82017-02-28 09:58:04 -0700961 // No ExtensionProperties to report
Mark Young3a587792016-08-19 15:25:08 -0600962 goto out;
Courtney Goeltzenleuchter5c6cf472015-07-06 22:28:18 -0600963 }
964
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600965 ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
Mark Young39389872017-01-19 21:10:49 -0700966 if (NULL == ext_props) {
967 res = VK_ERROR_OUT_OF_HOST_MEMORY;
968 goto out;
969 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600970
Jon Ashburn5c042ea2015-08-04 11:14:18 -0600971 res = fp_get_props(NULL, &count, ext_props);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600972 if (res != VK_SUCCESS) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700973 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
974 "loader_add_instance_extensions: Error getting Instance "
975 "extensions from %s",
Mark Youngb6399312017-01-10 14:22:15 -0700976 lib_name);
Mark Young3a587792016-08-19 15:25:08 -0600977 goto out;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600978 }
Tony Barbour59a47322015-06-24 16:06:58 -0600979
Jon Ashburn9fd4cc42015-04-10 14:33:07 -0600980 for (i = 0; i < count; i++) {
Courtney Goeltzenleuchter53043732015-07-12 13:20:05 -0600981 char spec_version[64];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600982
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700983 bool ext_unsupported = wsi_unsupported_instance_extension(&ext_props[i]);
Jon Ashburn6fa520f2016-03-25 12:49:35 -0600984 if (!ext_unsupported) {
Mark Young02df1a82017-04-18 19:52:18 -0600985 (void)snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", VK_VERSION_MAJOR(ext_props[i].specVersion),
986 VK_VERSION_MINOR(ext_props[i].specVersion), VK_VERSION_PATCH(ext_props[i].specVersion));
Mark Lobodzinski729a8d32017-01-26 12:16:30 -0700987 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Instance Extension: %s (%s) version %s", ext_props[i].extensionName,
988 lib_name, spec_version);
Mark Young6267ae62017-01-12 12:27:19 -0700989
Mark Young3a587792016-08-19 15:25:08 -0600990 res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
991 if (res != VK_SUCCESS) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -0700992 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
993 "loader_add_instance_extensions: Failed to add %s "
994 "to Instance extension list",
Mark Young3a587792016-08-19 15:25:08 -0600995 lib_name);
996 goto out;
997 }
Jon Ashburn6fa520f2016-03-25 12:49:35 -0600998 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -0600999 }
Mark Young6267ae62017-01-12 12:27:19 -07001000
Mark Young3a587792016-08-19 15:25:08 -06001001out:
1002 return res;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001003}
1004
Mark Young0f183a82017-02-28 09:58:04 -07001005// Initialize ext_list with the physical device extensions.
1006// The extension properties are passed as inputs in count and ext_props.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001007static VkResult loader_init_device_extensions(const struct loader_instance *inst, struct loader_physical_device_term *phys_dev_term,
1008 uint32_t count, VkExtensionProperties *ext_props,
1009 struct loader_extension_list *ext_list) {
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001010 VkResult res;
1011 uint32_t i;
1012
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001013 res = loader_init_generic_list(inst, (struct loader_generic_list *)ext_list, sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06001014 if (VK_SUCCESS != res) {
1015 return res;
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001016 }
1017
1018 for (i = 0; i < count; i++) {
1019 char spec_version[64];
Mark Young02df1a82017-04-18 19:52:18 -06001020 (void)snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", VK_VERSION_MAJOR(ext_props[i].specVersion),
1021 VK_VERSION_MINOR(ext_props[i].specVersion), VK_VERSION_PATCH(ext_props[i].specVersion));
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001022 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Device Extension: %s (%s) version %s", ext_props[i].extensionName,
1023 phys_dev_term->this_icd_term->scanned_icd->lib_name, spec_version);
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001024 res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001025 if (res != VK_SUCCESS) return res;
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001026 }
1027
1028 return VK_SUCCESS;
1029}
1030
Jon Ashburn1530c342016-02-26 13:14:27 -07001031VkResult loader_add_device_extensions(const struct loader_instance *inst,
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001032 PFN_vkEnumerateDeviceExtensionProperties fpEnumerateDeviceExtensionProperties,
1033 VkPhysicalDevice physical_device, const char *lib_name,
Jon Ashburn1530c342016-02-26 13:14:27 -07001034 struct loader_extension_list *ext_list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001035 uint32_t i, count;
1036 VkResult res;
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001037 VkExtensionProperties *ext_props;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001038
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001039 res = fpEnumerateDeviceExtensionProperties(physical_device, NULL, &count, NULL);
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001040 if (res == VK_SUCCESS && count > 0) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001041 ext_props = loader_stack_alloc(count * sizeof(VkExtensionProperties));
Mark Young9a3ddd42016-10-21 16:25:47 -06001042 if (!ext_props) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001043 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1044 "loader_add_device_extensions: Failed to allocate space"
1045 " for device extension properties.");
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001046 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young9a3ddd42016-10-21 16:25:47 -06001047 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001048 res = fpEnumerateDeviceExtensionProperties(physical_device, NULL, &count, ext_props);
Mark Young9a3ddd42016-10-21 16:25:47 -06001049 if (res != VK_SUCCESS) {
Jon Ashburn24cd4be2015-11-01 14:04:06 -07001050 return res;
Mark Young9a3ddd42016-10-21 16:25:47 -06001051 }
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001052 for (i = 0; i < count; i++) {
1053 char spec_version[64];
Mark Young02df1a82017-04-18 19:52:18 -06001054 (void)snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", VK_VERSION_MAJOR(ext_props[i].specVersion),
1055 VK_VERSION_MINOR(ext_props[i].specVersion), VK_VERSION_PATCH(ext_props[i].specVersion));
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001056 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Device Extension: %s (%s) version %s", ext_props[i].extensionName,
1057 lib_name, spec_version);
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001058 res = loader_add_to_ext_list(inst, ext_list, 1, &ext_props[i]);
Mark Youngb6399312017-01-10 14:22:15 -07001059 if (res != VK_SUCCESS) {
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001060 return res;
Mark Youngb6399312017-01-10 14:22:15 -07001061 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001062 }
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001063 } else {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001064 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1065 "loader_add_device_extensions: Error getting physical "
1066 "device extension info count from library %s",
Jon Ashburn23d36b12016-02-02 17:47:28 -07001067 lib_name);
Jon Ashburn00eb6c02015-11-02 17:40:01 -07001068 return res;
1069 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001070
Jon Ashburn24cd4be2015-11-01 14:04:06 -07001071 return VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001072}
1073
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001074VkResult loader_init_generic_list(const struct loader_instance *inst, struct loader_generic_list *list_info, size_t element_size) {
Mark Young84ba0482016-09-02 11:45:00 -06001075 size_t capacity = 32 * element_size;
1076 list_info->count = 0;
1077 list_info->capacity = 0;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001078 list_info->list = loader_instance_heap_alloc(inst, capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburn6e6a2162015-12-10 08:51:10 -07001079 if (list_info->list == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001080 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1081 "loader_init_generic_list: Failed to allocate space "
1082 "for generic list");
Mark Young3a587792016-08-19 15:25:08 -06001083 return VK_ERROR_OUT_OF_HOST_MEMORY;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001084 }
Mark Young84ba0482016-09-02 11:45:00 -06001085 memset(list_info->list, 0, capacity);
1086 list_info->capacity = capacity;
Mark Young3a587792016-08-19 15:25:08 -06001087 return VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001088}
1089
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001090void loader_destroy_generic_list(const struct loader_instance *inst, struct loader_generic_list *list) {
Mark Young0ad83132016-06-30 13:02:42 -06001091 loader_instance_heap_free(inst, list->list);
Jon Ashburn6e6a2162015-12-10 08:51:10 -07001092 list->count = 0;
1093 list->capacity = 0;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001094}
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001095
Mark Young0f183a82017-02-28 09:58:04 -07001096// Append non-duplicate extension properties defined in props to the given ext_list.
1097// Return - Vk_SUCCESS on success
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001098VkResult loader_add_to_ext_list(const struct loader_instance *inst, struct loader_extension_list *ext_list,
1099 uint32_t prop_list_count, const VkExtensionProperties *props) {
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001100 uint32_t i;
1101 const VkExtensionProperties *cur_ext;
1102
1103 if (ext_list->list == NULL || ext_list->capacity == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001104 VkResult res = loader_init_generic_list(inst, (struct loader_generic_list *)ext_list, sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06001105 if (VK_SUCCESS != res) {
1106 return res;
1107 }
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001108 }
1109
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001110 for (i = 0; i < prop_list_count; i++) {
1111 cur_ext = &props[i];
1112
1113 // look for duplicates
1114 if (has_vk_extension_property(cur_ext, ext_list)) {
1115 continue;
1116 }
1117
1118 // add to list at end
1119 // check for enough capacity
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001120 if (ext_list->count * sizeof(VkExtensionProperties) >= ext_list->capacity) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06001121 void *new_ptr = loader_instance_heap_realloc(inst, ext_list->list, ext_list->capacity, ext_list->capacity * 2,
1122 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1123 if (new_ptr == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001124 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1125 "loader_add_to_ext_list: Failed to reallocate "
1126 "space for extension list");
Jon Ashburn24cd4be2015-11-01 14:04:06 -07001127 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Youngb6399312017-01-10 14:22:15 -07001128 }
Mark Youngbb3a29c2017-05-19 12:29:43 -06001129 ext_list->list = new_ptr;
Jon Ashburn24cd4be2015-11-01 14:04:06 -07001130
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001131 // double capacity
1132 ext_list->capacity *= 2;
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001133 }
1134
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001135 memcpy(&ext_list->list[ext_list->count], cur_ext, sizeof(VkExtensionProperties));
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001136 ext_list->count++;
1137 }
Jon Ashburn24cd4be2015-11-01 14:04:06 -07001138 return VK_SUCCESS;
Jon Ashburn5c042ea2015-08-04 11:14:18 -06001139}
1140
Mark Youngdee312c2017-03-08 13:38:35 -07001141// Append one extension property defined in props with entrypoints defined in entries to the given
Mark Young0f183a82017-02-28 09:58:04 -07001142// ext_list. Do not append if a duplicate.
1143// Return - Vk_SUCCESS on success
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001144VkResult loader_add_to_dev_ext_list(const struct loader_instance *inst, struct loader_device_extension_list *ext_list,
1145 const VkExtensionProperties *props, uint32_t entry_count, char **entrys) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001146 uint32_t idx;
1147 if (ext_list->list == NULL || ext_list->capacity == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001148 VkResult res = loader_init_generic_list(inst, (struct loader_generic_list *)ext_list, sizeof(struct loader_dev_ext_props));
Mark Young3a587792016-08-19 15:25:08 -06001149 if (VK_SUCCESS != res) {
1150 return res;
1151 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001152 }
1153
Jon Ashburnb8726962016-04-08 15:03:35 -06001154 // look for duplicates
1155 if (has_vk_dev_ext_property(props, ext_list)) {
1156 return VK_SUCCESS;
1157 }
1158
Jon Ashburn23d36b12016-02-02 17:47:28 -07001159 idx = ext_list->count;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001160 // add to list at end
1161 // check for enough capacity
Jon Ashburn23d36b12016-02-02 17:47:28 -07001162 if (idx * sizeof(struct loader_dev_ext_props) >= ext_list->capacity) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06001163 void *new_ptr = loader_instance_heap_realloc(inst, ext_list->list, ext_list->capacity, ext_list->capacity * 2,
1164 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001165
Mark Youngbb3a29c2017-05-19 12:29:43 -06001166 if (NULL == new_ptr) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001167 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngbb3a29c2017-05-19 12:29:43 -06001168 "loader_add_to_dev_ext_list: Failed to reallocate space for device extension list");
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001169 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Youngb6399312017-01-10 14:22:15 -07001170 }
Mark Youngbb3a29c2017-05-19 12:29:43 -06001171 ext_list->list = new_ptr;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001172
1173 // double capacity
1174 ext_list->capacity *= 2;
1175 }
1176
Gabríel Arthúr Pétursson71510142017-06-03 01:38:49 +00001177 memcpy(&ext_list->list[idx].props, props, sizeof(*props));
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001178 ext_list->list[idx].entrypoint_count = entry_count;
Mark Young3f7a3b32017-06-26 14:03:08 -06001179 if (entry_count == 0) {
1180 ext_list->list[idx].entrypoints = NULL;
1181 } else {
1182 ext_list->list[idx].entrypoints =
1183 loader_instance_heap_alloc(inst, sizeof(char *) * entry_count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1184 if (ext_list->list[idx].entrypoints == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001185 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1186 "loader_add_to_dev_ext_list: Failed to allocate space "
Mark Young3f7a3b32017-06-26 14:03:08 -06001187 "for device extension entrypoint list in list %d",
1188 idx);
1189 ext_list->list[idx].entrypoint_count = 0;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001190 return VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young0ad83132016-06-30 13:02:42 -06001191 }
Mark Young3f7a3b32017-06-26 14:03:08 -06001192 for (uint32_t i = 0; i < entry_count; i++) {
1193 ext_list->list[idx].entrypoints[i] =
1194 loader_instance_heap_alloc(inst, strlen(entrys[i]) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1195 if (ext_list->list[idx].entrypoints[i] == NULL) {
1196 for (uint32_t j = 0; j < i; j++) {
1197 loader_instance_heap_free(inst, ext_list->list[idx].entrypoints[j]);
1198 }
1199 loader_instance_heap_free(inst, ext_list->list[idx].entrypoints);
1200 ext_list->list[idx].entrypoint_count = 0;
1201 ext_list->list[idx].entrypoints = NULL;
1202 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1203 "loader_add_to_dev_ext_list: Failed to allocate space "
1204 "for device extension entrypoint %d name",
1205 i);
1206 return VK_ERROR_OUT_OF_HOST_MEMORY;
1207 }
1208 strcpy(ext_list->list[idx].entrypoints[i], entrys[i]);
1209 }
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001210 }
1211 ext_list->count++;
1212
1213 return VK_SUCCESS;
1214}
1215
Mark Youngf2079b92017-05-02 10:49:46 -06001216// Prototype of loader_add_meta_layer function since we use it in the loader_add_implicit_layer, but can also
1217// call loader_add_implicit_layer from loader_add_meta_layer.
1218bool loader_add_meta_layer(const struct loader_instance *inst, const struct loader_layer_properties *prop,
Mark Young283fe1c2017-05-04 12:16:35 -06001219 struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
1220 const struct loader_layer_list *source_list);
1221
1222// Search the given layer list for a list matching the given VkLayerProperties
1223bool has_vk_layer_property(const VkLayerProperties *vk_layer_prop, const struct loader_layer_list *list) {
1224 for (uint32_t i = 0; i < list->count; i++) {
1225 if (strcmp(vk_layer_prop->layerName, list->list[i].info.layerName) == 0) return true;
1226 }
1227 return false;
1228}
1229
1230// Search the given layer list for a layer matching the given name
1231bool has_layer_name(const char *name, const struct loader_layer_list *list) {
1232 for (uint32_t i = 0; i < list->count; i++) {
1233 if (strcmp(name, list->list[i].info.layerName) == 0) return true;
1234 }
1235 return false;
1236}
Mark Youngf2079b92017-05-02 10:49:46 -06001237
Mark Young0f183a82017-02-28 09:58:04 -07001238// Search the given search_list for any layers in the props list. Add these to the
1239// output layer_list. Don't add duplicates to the output layer_list.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001240static VkResult loader_add_layer_names_to_list(const struct loader_instance *inst, struct loader_layer_list *output_list,
Mark Young283fe1c2017-05-04 12:16:35 -06001241 struct loader_layer_list *expanded_output_list, uint32_t name_count,
1242 const char *const *names, const struct loader_layer_list *source_list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001243 struct loader_layer_properties *layer_prop;
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06001244 VkResult err = VK_SUCCESS;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001245
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001246 for (uint32_t i = 0; i < name_count; i++) {
Mark Young283fe1c2017-05-04 12:16:35 -06001247 const char *source_name = names[i];
1248 layer_prop = loader_get_layer_property(source_name, source_list);
Mark Youngf2079b92017-05-02 10:49:46 -06001249 if (NULL == layer_prop) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001250 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1251 "loader_add_layer_names_to_list: Unable to find layer"
1252 " %s",
Mark Young283fe1c2017-05-04 12:16:35 -06001253 source_name);
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06001254 err = VK_ERROR_LAYER_NOT_PRESENT;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001255 continue;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001256 }
1257
Mark Youngf2079b92017-05-02 10:49:46 -06001258 // If not a meta-layer, simply add it.
1259 if (0 == (layer_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
Mark Young283fe1c2017-05-04 12:16:35 -06001260 if (!has_vk_layer_property(&layer_prop->info, output_list)) {
1261 loader_add_to_layer_list(inst, output_list, 1, layer_prop);
1262 }
1263 if (!has_vk_layer_property(&layer_prop->info, expanded_output_list)) {
1264 loader_add_to_layer_list(inst, expanded_output_list, 1, layer_prop);
1265 }
Mark Youngf2079b92017-05-02 10:49:46 -06001266 } else {
Mark Young283fe1c2017-05-04 12:16:35 -06001267 if (!has_vk_layer_property(&layer_prop->info, output_list) ||
1268 !has_vk_layer_property(&layer_prop->info, expanded_output_list)) {
1269 loader_add_meta_layer(inst, layer_prop, output_list, expanded_output_list, source_list);
Mark Youngf2079b92017-05-02 10:49:46 -06001270 }
1271 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001272 }
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06001273
1274 return err;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001275}
1276
Mark Young0f183a82017-02-28 09:58:04 -07001277// Manage lists of VkLayerProperties
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001278static bool loader_init_layer_list(const struct loader_instance *inst, struct loader_layer_list *list) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001279 list->capacity = 32 * sizeof(struct loader_layer_properties);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001280 list->list = loader_instance_heap_alloc(inst, list->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001281 if (list->list == NULL) {
1282 return false;
1283 }
1284 memset(list->list, 0, list->capacity);
1285 list->count = 0;
1286 return true;
1287}
1288
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001289void loader_destroy_layer_list(const struct loader_instance *inst, struct loader_device *device,
Jon Ashburn23d36b12016-02-02 17:47:28 -07001290 struct loader_layer_list *layer_list) {
Mark Young0ad83132016-06-30 13:02:42 -06001291 if (device) {
1292 loader_device_heap_free(device, layer_list->list);
1293 } else {
1294 loader_instance_heap_free(inst, layer_list->list);
1295 }
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001296 layer_list->count = 0;
1297 layer_list->capacity = 0;
1298}
1299
Mark Young0f183a82017-02-28 09:58:04 -07001300// Append non-duplicate layer properties defined in prop_list to the given layer_info list
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001301VkResult loader_add_to_layer_list(const struct loader_instance *inst, struct loader_layer_list *list, uint32_t prop_list_count,
Mark Young0ad83132016-06-30 13:02:42 -06001302 const struct loader_layer_properties *props) {
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001303 uint32_t i;
1304 struct loader_layer_properties *layer;
1305
1306 if (list->list == NULL || list->capacity == 0) {
Jon Ashburne39a4f82015-08-28 13:38:21 -06001307 loader_init_layer_list(inst, list);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001308 }
1309
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001310 if (list->list == NULL) return VK_SUCCESS;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001311
1312 for (i = 0; i < prop_list_count; i++) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001313 layer = (struct loader_layer_properties *)&props[i];
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001314
Mark Youngf2079b92017-05-02 10:49:46 -06001315 // Look for duplicates, and skip
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001316 if (has_vk_layer_property(&layer->info, list)) {
1317 continue;
1318 }
1319
Mark Youngf2079b92017-05-02 10:49:46 -06001320 // Check for enough capacity
1321 if (((list->count + 1) * sizeof(struct loader_layer_properties)) >= list->capacity) {
1322 size_t new_capacity = list->capacity * 2;
Mark Youngbb3a29c2017-05-19 12:29:43 -06001323 void *new_ptr =
Mark Youngf2079b92017-05-02 10:49:46 -06001324 loader_instance_heap_realloc(inst, list->list, list->capacity, new_capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Youngbb3a29c2017-05-19 12:29:43 -06001325 if (NULL == new_ptr) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001326 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngbb3a29c2017-05-19 12:29:43 -06001327 "loader_add_to_layer_list: Realloc failed for when attempting to add new layer");
Mark Young0ad83132016-06-30 13:02:42 -06001328 return VK_ERROR_OUT_OF_HOST_MEMORY;
1329 }
Mark Youngbb3a29c2017-05-19 12:29:43 -06001330 list->list = new_ptr;
Mark Youngf2079b92017-05-02 10:49:46 -06001331 list->capacity = new_capacity;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001332 }
1333
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001334 memcpy(&list->list[list->count], layer, sizeof(struct loader_layer_properties));
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001335 list->count++;
1336 }
Mark Young0ad83132016-06-30 13:02:42 -06001337
1338 return VK_SUCCESS;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06001339}
1340
Mark Youngf2079b92017-05-02 10:49:46 -06001341// Check the individual implicit layer for the enable/disable environment variable settings. Only add it after
1342// every check has passed indicating it should be used.
1343static void loader_add_implicit_layer(const struct loader_instance *inst, const struct loader_layer_properties *prop,
Mark Young283fe1c2017-05-04 12:16:35 -06001344 struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
1345 const struct loader_layer_list *source_list) {
Jean-Francois Roybd7ceab2017-07-06 14:10:13 -07001346 bool enable = loader_is_implicit_layer_enabled(inst, prop);
Mark Youngf2079b92017-05-02 10:49:46 -06001347 if (enable) {
Mark Youngf2079b92017-05-02 10:49:46 -06001348 if (0 == (prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
Mark Youngc8b807a2017-07-14 17:11:31 -06001349 if (NULL != target_list && !has_vk_layer_property(&prop->info, target_list)) {
Mark Young283fe1c2017-05-04 12:16:35 -06001350 loader_add_to_layer_list(inst, target_list, 1, prop);
1351 }
1352 if (NULL != expanded_target_list && !has_vk_layer_property(&prop->info, expanded_target_list)) {
1353 loader_add_to_layer_list(inst, expanded_target_list, 1, prop);
1354 }
Mark Youngf2079b92017-05-02 10:49:46 -06001355 } else {
Mark Young283fe1c2017-05-04 12:16:35 -06001356 if (!has_vk_layer_property(&prop->info, target_list) ||
1357 (NULL != expanded_target_list && !has_vk_layer_property(&prop->info, expanded_target_list))) {
1358 loader_add_meta_layer(inst, prop, target_list, expanded_target_list, source_list);
1359 }
Mark Youngf2079b92017-05-02 10:49:46 -06001360 }
1361 }
1362}
1363
1364// Add the component layers of a meta-layer to the active list of layers
1365bool loader_add_meta_layer(const struct loader_instance *inst, const struct loader_layer_properties *prop,
Mark Young283fe1c2017-05-04 12:16:35 -06001366 struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
1367 const struct loader_layer_list *source_list) {
Mark Youngf2079b92017-05-02 10:49:46 -06001368 bool found = true;
1369
1370 // We need to add all the individual component layers
1371 for (uint32_t comp_layer = 0; comp_layer < prop->num_component_layers; comp_layer++) {
1372 bool found_comp = false;
1373 const struct loader_layer_properties *search_prop =
1374 loader_get_layer_property(prop->component_layer_names[comp_layer], source_list);
1375 if (search_prop != NULL) {
1376 found_comp = true;
Mark Young283fe1c2017-05-04 12:16:35 -06001377
1378 // If the component layer is itself an implicit layer, we need to do the implicit layer enable
1379 // checks
Mark Youngf2079b92017-05-02 10:49:46 -06001380 if (0 == (search_prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) {
Mark Young283fe1c2017-05-04 12:16:35 -06001381 loader_add_implicit_layer(inst, search_prop, target_list, expanded_target_list, source_list);
Mark Youngf2079b92017-05-02 10:49:46 -06001382 } else {
Mark Young283fe1c2017-05-04 12:16:35 -06001383 if (NULL != expanded_target_list && !has_vk_layer_property(&search_prop->info, expanded_target_list)) {
1384 loader_add_to_layer_list(inst, expanded_target_list, 1, search_prop);
1385 }
Mark Youngf2079b92017-05-02 10:49:46 -06001386 }
1387 }
1388 if (!found_comp) {
1389 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
1390 "loader_add_meta_layer: Failed to find layer name %s component layer "
1391 "%s to activate",
1392 search_prop->info.layerName, prop->component_layer_names[comp_layer]);
1393 found = false;
1394 }
1395 }
Mark Youngc8b807a2017-07-14 17:11:31 -06001396
1397 // Add this layer to the overall target list (not the expanded one)
1398 if (found && !has_vk_layer_property(&prop->info, target_list)) {
1399 loader_add_to_layer_list(inst, target_list, 1, prop);
1400 }
1401
Mark Youngf2079b92017-05-02 10:49:46 -06001402 return found;
1403}
1404
1405// Search the source_list for any layer with a name that matches the given name and a type
1406// that matches the given type. Add all matching layers to the target_list.
1407// Do not add if found loader_layer_properties is already on the target_list.
1408void loader_find_layer_name_add_list(const struct loader_instance *inst, const char *name, const enum layer_type_flags type_flags,
Mark Young283fe1c2017-05-04 12:16:35 -06001409 const struct loader_layer_list *source_list, struct loader_layer_list *target_list,
1410 struct loader_layer_list *expanded_target_list) {
Jon Ashburn56151d62015-10-05 09:03:21 -06001411 bool found = false;
Mark Youngf2079b92017-05-02 10:49:46 -06001412 for (uint32_t i = 0; i < source_list->count; i++) {
1413 struct loader_layer_properties *source_prop = &source_list->list[i];
1414 if (0 == strcmp(source_prop->info.layerName, name) && (source_prop->type_flags & type_flags) == type_flags) {
Mark Youngf2079b92017-05-02 10:49:46 -06001415 // If not a meta-layer, simply add it.
1416 if (0 == (source_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER)) {
Mark Youngc8b807a2017-07-14 17:11:31 -06001417 if (NULL != target_list && !has_vk_layer_property(&source_prop->info, target_list) &&
Mark Young283fe1c2017-05-04 12:16:35 -06001418 VK_SUCCESS == loader_add_to_layer_list(inst, target_list, 1, source_prop)) {
1419 found = true;
1420 }
Mark Youngc8b807a2017-07-14 17:11:31 -06001421 if (NULL != expanded_target_list && !has_vk_layer_property(&source_prop->info, expanded_target_list) &&
Mark Young283fe1c2017-05-04 12:16:35 -06001422 VK_SUCCESS == loader_add_to_layer_list(inst, expanded_target_list, 1, source_prop)) {
Mark Youngf2079b92017-05-02 10:49:46 -06001423 found = true;
1424 }
1425 } else {
Mark Young283fe1c2017-05-04 12:16:35 -06001426 found = loader_add_meta_layer(inst, source_prop, target_list, expanded_target_list, source_list);
Mark Young0ad83132016-06-30 13:02:42 -06001427 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001428 }
1429 }
Jon Ashburn56151d62015-10-05 09:03:21 -06001430 if (!found) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001431 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
Mark Youngf2079b92017-05-02 10:49:46 -06001432 "loader_find_layer_name_add_list: Failed to find layer name %s to activate", name);
Jon Ashburn56151d62015-10-05 09:03:21 -06001433 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001434}
1435
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001436static VkExtensionProperties *get_extension_property(const char *name, const struct loader_extension_list *list) {
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06001437 for (uint32_t i = 0; i < list->count; i++) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001438 if (strcmp(name, list->list[i].extensionName) == 0) return &list->list[i];
Jon Ashburnfc2e38c2015-04-14 09:15:32 -06001439 }
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06001440 return NULL;
Jon Ashburnfc2e38c2015-04-14 09:15:32 -06001441}
1442
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001443static VkExtensionProperties *get_dev_extension_property(const char *name, const struct loader_device_extension_list *list) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001444 for (uint32_t i = 0; i < list->count; i++) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001445 if (strcmp(name, list->list[i].props.extensionName) == 0) return &list->list[i].props;
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07001446 }
1447 return NULL;
1448}
1449
Mark Young0f183a82017-02-28 09:58:04 -07001450// For Instance extensions implemented within the loader (i.e. DEBUG_REPORT
1451// the extension must provide two entry points for the loader to use:
1452// - "trampoline" entry point - this is the address returned by GetProcAddr
1453// and will always do what's necessary to support a
1454// global call.
1455// - "terminator" function - this function will be put at the end of the
1456// instance chain and will contain the necessary logic
1457// to call / process the extension for the appropriate
1458// ICDs that are available.
1459// There is no generic mechanism for including these functions, the references
1460// must be placed into the appropriate loader entry points.
1461// GetInstanceProcAddr: call extension GetInstanceProcAddr to check for GetProcAddr
1462// requests
1463// loader_coalesce_extensions(void) - add extension records to the list of global
1464// extension available to the app.
1465// instance_disp - add function pointer for terminator function
1466// to this array.
1467// The extension itself should be in a separate file that will be linked directly
1468// with the loader.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001469VkResult loader_get_icd_loader_instance_extensions(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list,
1470 struct loader_extension_list *inst_exts) {
Jon Ashburn5c6a46f2015-08-14 14:49:22 -06001471 struct loader_extension_list icd_exts;
Mark Young3a587792016-08-19 15:25:08 -06001472 VkResult res = VK_SUCCESS;
Mark Young2b2ece72017-02-10 11:19:02 -07001473 char *env_value;
1474 bool filter_extensions = true;
Mark Young3a587792016-08-19 15:25:08 -06001475
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001476 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Build ICD instance extension list");
Mark Young3a587792016-08-19 15:25:08 -06001477
Mark Young2b2ece72017-02-10 11:19:02 -07001478 // Check if a user wants to disable the instance extension filtering behavior
1479 env_value = loader_getenv("VK_LOADER_DISABLE_INST_EXT_FILTER", inst);
1480 if (NULL != env_value && atoi(env_value) != 0) {
1481 filter_extensions = false;
1482 }
1483 loader_free_getenv(env_value, inst);
1484
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001485 // traverse scanned icd list adding non-duplicate extensions to the list
Mark Young0153e0b2016-11-03 14:27:13 -06001486 for (uint32_t i = 0; i < icd_tramp_list->count; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001487 res = loader_init_generic_list(inst, (struct loader_generic_list *)&icd_exts, sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06001488 if (VK_SUCCESS != res) {
1489 goto out;
1490 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001491 res = loader_add_instance_extensions(inst, icd_tramp_list->scanned_list[i].EnumerateInstanceExtensionProperties,
1492 icd_tramp_list->scanned_list[i].lib_name, &icd_exts);
Mark Young3a587792016-08-19 15:25:08 -06001493 if (VK_SUCCESS == res) {
Mark Young2b2ece72017-02-10 11:19:02 -07001494 if (filter_extensions) {
1495 // Remove any extensions not recognized by the loader
1496 for (int32_t j = 0; j < (int32_t)icd_exts.count; j++) {
1497 // See if the extension is in the list of supported extensions
1498 bool found = false;
1499 for (uint32_t k = 0; LOADER_INSTANCE_EXTENSIONS[k] != NULL; k++) {
1500 if (strcmp(icd_exts.list[j].extensionName, LOADER_INSTANCE_EXTENSIONS[k]) == 0) {
1501 found = true;
1502 break;
1503 }
Lenny Komow4053b812016-12-29 16:27:28 -07001504 }
Lenny Komow4053b812016-12-29 16:27:28 -07001505
Mark Young2b2ece72017-02-10 11:19:02 -07001506 // If it isn't in the list, remove it
1507 if (!found) {
1508 for (uint32_t k = j + 1; k < icd_exts.count; k++) {
1509 icd_exts.list[k - 1] = icd_exts.list[k];
1510 }
1511 --icd_exts.count;
1512 --j;
Lenny Komow4053b812016-12-29 16:27:28 -07001513 }
Lenny Komow4053b812016-12-29 16:27:28 -07001514 }
1515 }
1516
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001517 res = loader_add_to_ext_list(inst, inst_exts, icd_exts.count, icd_exts.list);
Mark Young3a587792016-08-19 15:25:08 -06001518 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001519 loader_destroy_generic_list(inst, (struct loader_generic_list *)&icd_exts);
Mark Young3a587792016-08-19 15:25:08 -06001520 if (VK_SUCCESS != res) {
1521 goto out;
1522 }
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001523 };
1524
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001525 // Traverse loader's extensions, adding non-duplicate extensions to the list
Jon Ashburne39a4f82015-08-28 13:38:21 -06001526 debug_report_add_instance_extensions(inst, inst_exts);
Mark Young3a587792016-08-19 15:25:08 -06001527
1528out:
1529 return res;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001530}
1531
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001532struct loader_icd_term *loader_get_icd_and_device(const VkDevice device, struct loader_device **found_dev, uint32_t *icd_index) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001533 *found_dev = NULL;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001534 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
Lenny Komow27167312017-03-31 13:43:35 -06001535 uint32_t index = 0;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001536 for (struct loader_icd_term *icd_term = inst->icd_terms; icd_term; icd_term = icd_term->next) {
1537 for (struct loader_device *dev = icd_term->logical_device_list; dev; dev = dev->next)
Mark Young65cb3662016-11-07 13:27:02 -07001538 // Value comparison of device prevents object wrapping by layers
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001539 if (loader_get_dispatch(dev->icd_device) == loader_get_dispatch(device) ||
1540 loader_get_dispatch(dev->chain_device) == loader_get_dispatch(device)) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001541 *found_dev = dev;
Mark Young16573c72016-06-28 10:52:43 -06001542 if (NULL != icd_index) {
1543 *icd_index = index;
1544 }
Mark Young0153e0b2016-11-03 14:27:13 -06001545 return icd_term;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001546 }
Mark Young16573c72016-06-28 10:52:43 -06001547 index++;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001548 }
1549 }
1550 return NULL;
1551}
1552
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001553void loader_destroy_logical_device(const struct loader_instance *inst, struct loader_device *dev,
Mark Young0ad83132016-06-30 13:02:42 -06001554 const VkAllocationCallbacks *pAllocator) {
1555 if (pAllocator) {
1556 dev->alloc_callbacks = *pAllocator;
1557 }
Mark Young283fe1c2017-05-04 12:16:35 -06001558 if (NULL != dev->expanded_activated_layer_list.list) {
1559 loader_deactivate_layers(inst, dev, &dev->expanded_activated_layer_list);
1560 }
1561 if (NULL != dev->app_activated_layer_list.list) {
1562 loader_destroy_layer_list(inst, dev, &dev->app_activated_layer_list);
Mark Young0ad83132016-06-30 13:02:42 -06001563 }
1564 loader_device_heap_free(dev, dev);
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001565}
1566
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001567struct loader_device *loader_create_logical_device(const struct loader_instance *inst, const VkAllocationCallbacks *pAllocator) {
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001568 struct loader_device *new_dev;
Mark Young0ad83132016-06-30 13:02:42 -06001569#if (DEBUG_DISABLE_APP_ALLOCATORS == 1)
1570 {
1571#else
1572 if (pAllocator) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001573 new_dev = (struct loader_device *)pAllocator->pfnAllocation(pAllocator->pUserData, sizeof(struct loader_device),
1574 sizeof(int *), VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
Mark Young0ad83132016-06-30 13:02:42 -06001575 } else {
1576#endif
1577 new_dev = (struct loader_device *)malloc(sizeof(struct loader_device));
1578 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001579
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001580 if (!new_dev) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001581 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1582 "loader_create_logical_device: Failed to alloc struct "
1583 "loader_device");
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001584 return NULL;
1585 }
1586
1587 memset(new_dev, 0, sizeof(struct loader_device));
Mark Young0ad83132016-06-30 13:02:42 -06001588 if (pAllocator) {
1589 new_dev->alloc_callbacks = *pAllocator;
1590 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001591
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001592 return new_dev;
1593}
1594
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001595void loader_add_logical_device(const struct loader_instance *inst, struct loader_icd_term *icd_term, struct loader_device *dev) {
Mark Young0153e0b2016-11-03 14:27:13 -06001596 dev->next = icd_term->logical_device_list;
1597 icd_term->logical_device_list = dev;
Piers Daniell295fe402016-03-29 11:51:11 -06001598}
1599
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001600void loader_remove_logical_device(const struct loader_instance *inst, struct loader_icd_term *icd_term,
1601 struct loader_device *found_dev, const VkAllocationCallbacks *pAllocator) {
Jon Ashburn781a7ae2015-11-19 15:43:26 -07001602 struct loader_device *dev, *prev_dev;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001603
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001604 if (!icd_term || !found_dev) return;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001605
1606 prev_dev = NULL;
Mark Young0153e0b2016-11-03 14:27:13 -06001607 dev = icd_term->logical_device_list;
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001608 while (dev && dev != found_dev) {
1609 prev_dev = dev;
1610 dev = dev->next;
1611 }
1612
1613 if (prev_dev)
1614 prev_dev->next = found_dev->next;
1615 else
Mark Young0153e0b2016-11-03 14:27:13 -06001616 icd_term->logical_device_list = found_dev->next;
Mark Young0ad83132016-06-30 13:02:42 -06001617 loader_destroy_logical_device(inst, found_dev, pAllocator);
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001618}
1619
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001620static void loader_icd_destroy(struct loader_instance *ptr_inst, struct loader_icd_term *icd_term,
Mark Young0ad83132016-06-30 13:02:42 -06001621 const VkAllocationCallbacks *pAllocator) {
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001622 ptr_inst->total_icd_count--;
Mark Young0153e0b2016-11-03 14:27:13 -06001623 for (struct loader_device *dev = icd_term->logical_device_list; dev;) {
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -06001624 struct loader_device *next_dev = dev->next;
Mark Young0ad83132016-06-30 13:02:42 -06001625 loader_destroy_logical_device(ptr_inst, dev, pAllocator);
Courtney Goeltzenleuchter1f157ac2015-06-14 19:57:15 -06001626 dev = next_dev;
1627 }
Jon Ashburndc6fcad2015-06-10 10:06:06 -06001628
Mark Young0153e0b2016-11-03 14:27:13 -06001629 loader_instance_heap_free(ptr_inst, icd_term);
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001630}
1631
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001632static struct loader_icd_term *loader_icd_create(const struct loader_instance *inst) {
Mark Young0153e0b2016-11-03 14:27:13 -06001633 struct loader_icd_term *icd_term;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001634
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001635 icd_term = loader_instance_heap_alloc(inst, sizeof(struct loader_icd_term), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0153e0b2016-11-03 14:27:13 -06001636 if (!icd_term) {
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001637 return NULL;
Mark Youngdb13a2a2016-09-06 13:53:03 -06001638 }
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001639
Mark Young0153e0b2016-11-03 14:27:13 -06001640 memset(icd_term, 0, sizeof(struct loader_icd_term));
Courtney Goeltzenleuchter55001bb2014-10-28 10:29:27 -06001641
Mark Young0153e0b2016-11-03 14:27:13 -06001642 return icd_term;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08001643}
1644
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001645static struct loader_icd_term *loader_icd_add(struct loader_instance *ptr_inst, const struct loader_scanned_icd *scanned_icd) {
Mark Young0153e0b2016-11-03 14:27:13 -06001646 struct loader_icd_term *icd_term;
Chia-I Wu13a61a52014-08-04 11:18:20 +08001647
Mark Young0153e0b2016-11-03 14:27:13 -06001648 icd_term = loader_icd_create(ptr_inst);
1649 if (!icd_term) {
Chia-I Wu13a61a52014-08-04 11:18:20 +08001650 return NULL;
Mark Youngdb13a2a2016-09-06 13:53:03 -06001651 }
Chia-I Wu13a61a52014-08-04 11:18:20 +08001652
Mark Young0153e0b2016-11-03 14:27:13 -06001653 icd_term->scanned_icd = scanned_icd;
1654 icd_term->this_instance = ptr_inst;
Jon Ashburn3d002332015-08-20 16:35:30 -06001655
Mark Young0f183a82017-02-28 09:58:04 -07001656 // Prepend to the list
Mark Young0153e0b2016-11-03 14:27:13 -06001657 icd_term->next = ptr_inst->icd_terms;
1658 ptr_inst->icd_terms = icd_term;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001659 ptr_inst->total_icd_count++;
Chia-I Wu13a61a52014-08-04 11:18:20 +08001660
Mark Young0153e0b2016-11-03 14:27:13 -06001661 return icd_term;
Chia-I Wu13a61a52014-08-04 11:18:20 +08001662}
Mark Young0153e0b2016-11-03 14:27:13 -06001663
Mark Young0f183a82017-02-28 09:58:04 -07001664// Determine the ICD interface version to use.
1665// @param icd
1666// @param pVersion Output parameter indicating which version to use or 0 if
1667// the negotiation API is not supported by the ICD
1668// @return bool indicating true if the selected interface version is supported
1669// by the loader, false indicates the version is not supported
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001670bool loader_get_icd_interface_version(PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version, uint32_t *pVersion) {
Jon Ashburn17b4c862016-04-25 11:09:37 -06001671 if (fp_negotiate_icd_version == NULL) {
1672 // ICD does not support the negotiation API, it supports version 0 or 1
1673 // calling code must determine if it is version 0 or 1
1674 *pVersion = 0;
1675 } else {
1676 // ICD supports the negotiation API, so call it with the loader's
1677 // latest version supported
1678 *pVersion = CURRENT_LOADER_ICD_INTERFACE_VERSION;
1679 VkResult result = fp_negotiate_icd_version(pVersion);
1680
1681 if (result == VK_ERROR_INCOMPATIBLE_DRIVER) {
1682 // ICD no longer supports the loader's latest interface version so
1683 // fail loading the ICD
1684 return false;
1685 }
1686 }
1687
1688#if MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION > 0
1689 if (*pVersion < MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION) {
1690 // Loader no longer supports the ICD's latest interface version so fail
1691 // loading the ICD
1692 return false;
1693 }
1694#endif
1695 return true;
1696}
Chia-I Wu13a61a52014-08-04 11:18:20 +08001697
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001698void loader_scanned_icd_clear(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list) {
Mark Youngf2079b92017-05-02 10:49:46 -06001699 if (0 != icd_tramp_list->capacity) {
1700 for (uint32_t i = 0; i < icd_tramp_list->count; i++) {
1701 loader_platform_close_library(icd_tramp_list->scanned_list[i].handle);
1702 loader_instance_heap_free(inst, icd_tramp_list->scanned_list[i].lib_name);
1703 }
1704 loader_instance_heap_free(inst, icd_tramp_list->scanned_list);
1705 icd_tramp_list->capacity = 0;
1706 icd_tramp_list->count = 0;
1707 icd_tramp_list->scanned_list = NULL;
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001708 }
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001709}
1710
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001711static VkResult loader_scanned_icd_init(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list) {
Mark Young0ad83132016-06-30 13:02:42 -06001712 VkResult err = VK_SUCCESS;
Mark Young0153e0b2016-11-03 14:27:13 -06001713 loader_scanned_icd_clear(inst, icd_tramp_list);
1714 icd_tramp_list->capacity = 8 * sizeof(struct loader_scanned_icd);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001715 icd_tramp_list->scanned_list = loader_instance_heap_alloc(inst, icd_tramp_list->capacity, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0153e0b2016-11-03 14:27:13 -06001716 if (NULL == icd_tramp_list->scanned_list) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001717 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1718 "loader_scanned_icd_init: Realloc failed for layer list when "
1719 "attempting to add new layer");
Mark Young0ad83132016-06-30 13:02:42 -06001720 err = VK_ERROR_OUT_OF_HOST_MEMORY;
1721 }
1722 return err;
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001723}
1724
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001725static VkResult loader_scanned_icd_add(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list,
1726 const char *filename, uint32_t api_version) {
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001727 loader_platform_dl_handle handle;
Tony Barbour1d2cd3f2015-07-03 10:33:54 -06001728 PFN_vkCreateInstance fp_create_inst;
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001729 PFN_vkEnumerateInstanceExtensionProperties fp_get_inst_ext_props;
Jon Ashburnc624c882015-07-16 10:17:29 -06001730 PFN_vkGetInstanceProcAddr fp_get_proc_addr;
Mark Young39389872017-01-19 21:10:49 -07001731 PFN_GetPhysicalDeviceProcAddr fp_get_phys_dev_proc_addr = NULL;
Jon Ashburn17b4c862016-04-25 11:09:37 -06001732 PFN_vkNegotiateLoaderICDInterfaceVersion fp_negotiate_icd_version;
Mark Young0153e0b2016-11-03 14:27:13 -06001733 struct loader_scanned_icd *new_scanned_icd;
Jon Ashburn17b4c862016-04-25 11:09:37 -06001734 uint32_t interface_vers;
Mark Young3a587792016-08-19 15:25:08 -06001735 VkResult res = VK_SUCCESS;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001736
Mark Young0f183a82017-02-28 09:58:04 -07001737 // TODO implement smarter opening/closing of libraries. For now this
1738 // function leaves libraries open and the scanned_icd_clear closes them
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001739 handle = loader_platform_open_library(filename);
Mark Youngb6399312017-01-10 14:22:15 -07001740 if (NULL == handle) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001741 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, loader_platform_open_library_error(filename));
Mark Young3a587792016-08-19 15:25:08 -06001742 goto out;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001743 }
1744
Jon Ashburn17b4c862016-04-25 11:09:37 -06001745 // Get and settle on an ICD interface version
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001746 fp_negotiate_icd_version = loader_platform_get_proc_address(handle, "vk_icdNegotiateLoaderICDInterfaceVersion");
Jon Ashburn17b4c862016-04-25 11:09:37 -06001747
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001748 if (!loader_get_icd_interface_version(fp_negotiate_icd_version, &interface_vers)) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001749 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1750 "loader_scanned_icd_add: ICD %s doesn't support interface"
1751 " version compatible with loader, skip this ICD.",
Mark Young0ad83132016-06-30 13:02:42 -06001752 filename);
Mark Young3a587792016-08-19 15:25:08 -06001753 goto out;
Jon Ashburn17b4c862016-04-25 11:09:37 -06001754 }
1755
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001756 fp_get_proc_addr = loader_platform_get_proc_address(handle, "vk_icdGetInstanceProcAddr");
Mark Youngb6399312017-01-10 14:22:15 -07001757 if (NULL == fp_get_proc_addr) {
Jon Ashburn17b4c862016-04-25 11:09:37 -06001758 assert(interface_vers == 0);
1759 // Use deprecated interface from version 0
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001760 fp_get_proc_addr = loader_platform_get_proc_address(handle, "vkGetInstanceProcAddr");
Mark Youngb6399312017-01-10 14:22:15 -07001761 if (NULL == fp_get_proc_addr) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001762 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngdee312c2017-03-08 13:38:35 -07001763 "loader_scanned_icd_add: Attempt to retrieve either "
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001764 "\'vkGetInstanceProcAddr\' or "
1765 "\'vk_icdGetInstanceProcAddr\' from ICD %s failed.",
Mark Youngb6399312017-01-10 14:22:15 -07001766 filename);
Mark Young3a587792016-08-19 15:25:08 -06001767 goto out;
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001768 } else {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001769 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
1770 "loader_scanned_icd_add: Using deprecated ICD "
1771 "interface of \'vkGetInstanceProcAddr\' instead of "
1772 "\'vk_icdGetInstanceProcAddr\' for ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001773 filename);
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001774 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001775 fp_create_inst = loader_platform_get_proc_address(handle, "vkCreateInstance");
Mark Youngb6399312017-01-10 14:22:15 -07001776 if (NULL == fp_create_inst) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001777 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1778 "loader_scanned_icd_add: Failed querying "
1779 "\'vkCreateInstance\' via dlsym/loadlibrary for "
1780 "ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001781 filename);
Mark Young3a587792016-08-19 15:25:08 -06001782 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001783 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001784 fp_get_inst_ext_props = loader_platform_get_proc_address(handle, "vkEnumerateInstanceExtensionProperties");
Mark Youngb6399312017-01-10 14:22:15 -07001785 if (NULL == fp_get_inst_ext_props) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001786 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1787 "loader_scanned_icd_add: Could not get \'vkEnumerate"
1788 "InstanceExtensionProperties\' via dlsym/loadlibrary "
1789 "for ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001790 filename);
Mark Young3a587792016-08-19 15:25:08 -06001791 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001792 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001793 } else {
Jon Ashburn17b4c862016-04-25 11:09:37 -06001794 // Use newer interface version 1 or later
Mark Young39389872017-01-19 21:10:49 -07001795 if (interface_vers == 0) {
Jon Ashburn17b4c862016-04-25 11:09:37 -06001796 interface_vers = 1;
Mark Young39389872017-01-19 21:10:49 -07001797 }
Jon Ashburn17b4c862016-04-25 11:09:37 -06001798
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001799 fp_create_inst = (PFN_vkCreateInstance)fp_get_proc_addr(NULL, "vkCreateInstance");
Mark Youngb6399312017-01-10 14:22:15 -07001800 if (NULL == fp_create_inst) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001801 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1802 "loader_scanned_icd_add: Could not get "
1803 "\'vkCreateInstance\' via \'vk_icdGetInstanceProcAddr\'"
1804 " for ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001805 filename);
Mark Young3a587792016-08-19 15:25:08 -06001806 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001807 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07001808 fp_get_inst_ext_props =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001809 (PFN_vkEnumerateInstanceExtensionProperties)fp_get_proc_addr(NULL, "vkEnumerateInstanceExtensionProperties");
Mark Youngb6399312017-01-10 14:22:15 -07001810 if (NULL == fp_get_inst_ext_props) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001811 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
1812 "loader_scanned_icd_add: Could not get \'vkEnumerate"
1813 "InstanceExtensionProperties\' via "
1814 "\'vk_icdGetInstanceProcAddr\' for ICD %s",
Mark Young0ad83132016-06-30 13:02:42 -06001815 filename);
Mark Young3a587792016-08-19 15:25:08 -06001816 goto out;
Jon Ashburn69a5f7a2016-01-11 14:41:35 -07001817 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001818 fp_get_phys_dev_proc_addr = loader_platform_get_proc_address(handle, "vk_icdGetPhysicalDeviceProcAddr");
Jon Ashburnfd4d09d2016-01-07 09:44:27 -07001819 }
Jon Ashburn46d1f582015-01-28 11:01:35 -07001820
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001821 // check for enough capacity
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001822 if ((icd_tramp_list->count * sizeof(struct loader_scanned_icd)) >= icd_tramp_list->capacity) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06001823 void *new_ptr = loader_instance_heap_realloc(inst, icd_tramp_list->scanned_list, icd_tramp_list->capacity,
1824 icd_tramp_list->capacity * 2, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1825 if (NULL == new_ptr) {
Mark Young3a587792016-08-19 15:25:08 -06001826 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001827 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngbb3a29c2017-05-19 12:29:43 -06001828 "loader_scanned_icd_add: Realloc failed on icd library list for ICD %s", filename);
Mark Young3a587792016-08-19 15:25:08 -06001829 goto out;
Mark Young0ad83132016-06-30 13:02:42 -06001830 }
Mark Youngbb3a29c2017-05-19 12:29:43 -06001831 icd_tramp_list->scanned_list = new_ptr;
1832
Jon Ashburn23d36b12016-02-02 17:47:28 -07001833 // double capacity
Mark Young0153e0b2016-11-03 14:27:13 -06001834 icd_tramp_list->capacity *= 2;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001835 }
1836
Mark Young39389872017-01-19 21:10:49 -07001837 new_scanned_icd = &(icd_tramp_list->scanned_list[icd_tramp_list->count]);
Mark Young0153e0b2016-11-03 14:27:13 -06001838 new_scanned_icd->handle = handle;
1839 new_scanned_icd->api_version = api_version;
1840 new_scanned_icd->GetInstanceProcAddr = fp_get_proc_addr;
Mark Young39389872017-01-19 21:10:49 -07001841 new_scanned_icd->GetPhysicalDeviceProcAddr = fp_get_phys_dev_proc_addr;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001842 new_scanned_icd->EnumerateInstanceExtensionProperties = fp_get_inst_ext_props;
Mark Young0153e0b2016-11-03 14:27:13 -06001843 new_scanned_icd->CreateInstance = fp_create_inst;
1844 new_scanned_icd->interface_version = interface_vers;
Jon Ashburn46d1f582015-01-28 11:01:35 -07001845
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001846 new_scanned_icd->lib_name = (char *)loader_instance_heap_alloc(inst, strlen(filename) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0153e0b2016-11-03 14:27:13 -06001847 if (NULL == new_scanned_icd->lib_name) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001848 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loader_scanned_icd_add: Out of memory can't add ICD %s", filename);
Mark Young3a587792016-08-19 15:25:08 -06001849 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young3a587792016-08-19 15:25:08 -06001850 goto out;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06001851 }
Mark Young0153e0b2016-11-03 14:27:13 -06001852 strcpy(new_scanned_icd->lib_name, filename);
1853 icd_tramp_list->count++;
Mark Young3a587792016-08-19 15:25:08 -06001854
1855out:
1856
1857 return res;
Jon Ashburn9fd4cc42015-04-10 14:33:07 -06001858}
Ian Elliott2d4ab1e2015-01-13 17:52:38 -07001859
Jon Ashburn23d36b12016-02-02 17:47:28 -07001860static void loader_debug_init(void) {
Mark Young0ad83132016-06-30 13:02:42 -06001861 char *env, *orig;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001862
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001863 if (g_loader_debug > 0) return;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001864
1865 g_loader_debug = 0;
1866
Mark Young0f183a82017-02-28 09:58:04 -07001867 // Parse comma-separated debug options
Mark Young0ad83132016-06-30 13:02:42 -06001868 orig = env = loader_getenv("VK_LOADER_DEBUG", NULL);
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001869 while (env) {
Mark Young0ad83132016-06-30 13:02:42 -06001870 char *p = strchr(env, ',');
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001871 size_t len;
1872
1873 if (p)
1874 len = p - env;
1875 else
1876 len = strlen(env);
1877
1878 if (len > 0) {
Michael Worcester25c73e72015-12-10 18:06:24 +00001879 if (strncmp(env, "all", len) == 0) {
1880 g_loader_debug = ~0u;
1881 g_loader_log_msgs = ~0u;
1882 } else if (strncmp(env, "warn", len) == 0) {
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001883 g_loader_debug |= LOADER_WARN_BIT;
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07001884 g_loader_log_msgs |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001885 } else if (strncmp(env, "info", len) == 0) {
1886 g_loader_debug |= LOADER_INFO_BIT;
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07001887 g_loader_log_msgs |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001888 } else if (strncmp(env, "perf", len) == 0) {
1889 g_loader_debug |= LOADER_PERF_BIT;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001890 g_loader_log_msgs |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001891 } else if (strncmp(env, "error", len) == 0) {
1892 g_loader_debug |= LOADER_ERROR_BIT;
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07001893 g_loader_log_msgs |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001894 } else if (strncmp(env, "debug", len) == 0) {
1895 g_loader_debug |= LOADER_DEBUG_BIT;
Courtney Goeltzenleuchter7415d5a2015-12-09 15:48:16 -07001896 g_loader_log_msgs |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001897 }
1898 }
1899
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001900 if (!p) break;
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001901
1902 env = p + 1;
1903 }
Jon Ashburn38a497f2016-01-04 14:01:38 -07001904
Mark Young0ad83132016-06-30 13:02:42 -06001905 loader_free_getenv(orig, NULL);
Courtney Goeltzenleuchter880a2a72015-06-08 15:11:18 -06001906}
1907
Jon Ashburn23d36b12016-02-02 17:47:28 -07001908void loader_initialize(void) {
Jon Ashburn6461ef22015-09-22 13:11:00 -06001909 // initialize mutexs
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001910 loader_platform_thread_create_mutex(&loader_lock);
Jon Ashburn6461ef22015-09-22 13:11:00 -06001911 loader_platform_thread_create_mutex(&loader_json_lock);
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001912
1913 // initialize logging
1914 loader_debug_init();
Jon Ashburn87d6aa92015-08-28 15:19:27 -06001915
1916 // initial cJSON to use alloc callbacks
1917 cJSON_Hooks alloc_fns = {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001918 .malloc_fn = loader_instance_tls_heap_alloc, .free_fn = loader_instance_tls_heap_free,
Jon Ashburn87d6aa92015-08-28 15:19:27 -06001919 };
1920 cJSON_InitHooks(&alloc_fns);
Jon Ashburn8810c5f2015-08-18 18:04:47 -06001921}
1922
Jon Ashburn2077e382015-06-29 11:25:34 -06001923struct loader_manifest_files {
1924 uint32_t count;
1925 char **filename_list;
1926};
1927
Lenny Komow158e9d92018-01-15 15:43:36 -07001928void loader_release() {
1929 // release mutexs
1930 loader_platform_thread_delete_mutex(&loader_lock);
1931 loader_platform_thread_delete_mutex(&loader_json_lock);
1932}
1933
Mark Young0f183a82017-02-28 09:58:04 -07001934// Get next file or dirname given a string list or registry key path
1935//
1936// \returns
1937// A pointer to first char in the next path.
1938// The next path (or NULL) in the list is returned in next_path.
1939// Note: input string is modified in some cases. PASS IN A COPY!
Jon Ashburn23d36b12016-02-02 17:47:28 -07001940static char *loader_get_next_path(char *path) {
Jon Ashburn2077e382015-06-29 11:25:34 -06001941 uint32_t len;
1942 char *next;
1943
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07001944 if (path == NULL) return NULL;
Frank Henigman57173102016-11-24 22:15:20 -05001945 next = strchr(path, PATH_SEPARATOR);
Jon Ashburn2077e382015-06-29 11:25:34 -06001946 if (next == NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07001947 len = (uint32_t)strlen(path);
Jon Ashburn2077e382015-06-29 11:25:34 -06001948 next = path + len;
Jon Ashburn23d36b12016-02-02 17:47:28 -07001949 } else {
Jon Ashburn2077e382015-06-29 11:25:34 -06001950 *next = '\0';
1951 next++;
1952 }
1953
1954 return next;
1955}
1956
Mark Young0f183a82017-02-28 09:58:04 -07001957// Given a path which is absolute or relative, expand the path if relative or
1958// leave the path unmodified if absolute. The base path to prepend to relative
1959// paths is given in rel_base.
1960//
1961// @return - A string in out_fullpath of the full absolute path
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001962static void loader_expand_path(const char *path, const char *rel_base, size_t out_size, char *out_fullpath) {
Jon Ashburn15315172015-07-07 15:06:25 -06001963 if (loader_platform_is_path_absolute(path)) {
Daniel Dadap00b4aba2015-09-30 11:50:51 -05001964 // do not prepend a base to an absolute path
1965 rel_base = "";
Jon Ashburn15315172015-07-07 15:06:25 -06001966 }
Daniel Dadap00b4aba2015-09-30 11:50:51 -05001967
1968 loader_platform_combine_path(out_fullpath, out_size, rel_base, path, NULL);
Jon Ashburn15315172015-07-07 15:06:25 -06001969}
1970
Mark Young0f183a82017-02-28 09:58:04 -07001971// Given a filename (file) and a list of paths (dir), try to find an existing
1972// file in the paths. If filename already is a path then no searching in the given paths.
1973//
1974// @return - A string in out_fullpath of either the full path or file.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001975static void loader_get_fullpath(const char *file, const char *dirs, size_t out_size, char *out_fullpath) {
Daniel Dadap00b4aba2015-09-30 11:50:51 -05001976 if (!loader_platform_is_path(file) && *dirs) {
1977 char *dirs_copy, *dir, *next_dir;
1978
1979 dirs_copy = loader_stack_alloc(strlen(dirs) + 1);
1980 strcpy(dirs_copy, dirs);
1981
Jon Ashburn23d36b12016-02-02 17:47:28 -07001982 // find if file exists after prepending paths in given list
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001983 for (dir = dirs_copy; *dir && (next_dir = loader_get_next_path(dir)); dir = next_dir) {
1984 loader_platform_combine_path(out_fullpath, out_size, dir, file, NULL);
Jon Ashburn2077e382015-06-29 11:25:34 -06001985 if (loader_platform_file_exists(out_fullpath)) {
1986 return;
1987 }
Jon Ashburn2077e382015-06-29 11:25:34 -06001988 }
1989 }
Daniel Dadap00b4aba2015-09-30 11:50:51 -05001990
Karl Schultze2ef9e62017-01-13 14:01:35 -07001991 (void)snprintf(out_fullpath, out_size, "%s", file);
Jon Ashburn2077e382015-06-29 11:25:34 -06001992}
1993
Mark Young0f183a82017-02-28 09:58:04 -07001994// Read a JSON file into a buffer.
1995//
1996// @return - A pointer to a cJSON object representing the JSON parse tree.
1997// This returned buffer should be freed by caller.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07001998static VkResult loader_get_json(const struct loader_instance *inst, const char *filename, cJSON **json) {
Mark Young3a587792016-08-19 15:25:08 -06001999 FILE *file = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06002000 char *json_buf;
Mark Young93ecb1d2016-01-13 13:47:16 -07002001 size_t len;
Mark Young3a587792016-08-19 15:25:08 -06002002 VkResult res = VK_SUCCESS;
2003
2004 if (NULL == json) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002005 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loader_get_json: Received invalid JSON file");
Mark Young3a587792016-08-19 15:25:08 -06002006 res = VK_ERROR_INITIALIZATION_FAILED;
2007 goto out;
2008 }
2009
2010 *json = NULL;
2011
Jon Ashburn23d36b12016-02-02 17:47:28 -07002012 file = fopen(filename, "rb");
Jon Ashburnaa4ea472015-08-27 08:30:50 -06002013 if (!file) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002014 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loader_get_json: Failed to open JSON file %s", filename);
Mark Youngb6399312017-01-10 14:22:15 -07002015 res = VK_ERROR_INITIALIZATION_FAILED;
Mark Young3a587792016-08-19 15:25:08 -06002016 goto out;
Jon Ashburnaa4ea472015-08-27 08:30:50 -06002017 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002018 fseek(file, 0, SEEK_END);
2019 len = ftell(file);
2020 fseek(file, 0, SEEK_SET);
Jon Ashburn23d36b12016-02-02 17:47:28 -07002021 json_buf = (char *)loader_stack_alloc(len + 1);
Jon Ashburn2077e382015-06-29 11:25:34 -06002022 if (json_buf == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002023 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2024 "loader_get_json: Failed to allocate space for "
2025 "JSON file %s buffer of length %d",
Mark Youngb6399312017-01-10 14:22:15 -07002026 filename, len);
2027 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young3a587792016-08-19 15:25:08 -06002028 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06002029 }
2030 if (fread(json_buf, sizeof(char), len, file) != len) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002031 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loader_get_json: Failed to read JSON file %s.", filename);
Mark Youngb6399312017-01-10 14:22:15 -07002032 res = VK_ERROR_INITIALIZATION_FAILED;
Mark Young3a587792016-08-19 15:25:08 -06002033 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06002034 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002035 json_buf[len] = '\0';
2036
Mark Young0f183a82017-02-28 09:58:04 -07002037 // Parse text from file
Mark Young3a587792016-08-19 15:25:08 -06002038 *json = cJSON_Parse(json_buf);
2039 if (*json == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002040 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2041 "loader_get_json: Failed to parse JSON file %s, "
2042 "this is usually because something ran out of "
2043 "memory.",
Mark Youngb6399312017-01-10 14:22:15 -07002044 filename);
2045 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young3a587792016-08-19 15:25:08 -06002046 goto out;
2047 }
2048
2049out:
2050 if (NULL != file) {
2051 fclose(file);
2052 }
2053
2054 return res;
Jon Ashburn2077e382015-06-29 11:25:34 -06002055}
2056
Mark Young0f183a82017-02-28 09:58:04 -07002057// Do a deep copy of the loader_layer_properties structure.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002058VkResult loader_copy_layer_properties(const struct loader_instance *inst, struct loader_layer_properties *dst,
Mark Young0ad83132016-06-30 13:02:42 -06002059 struct loader_layer_properties *src) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002060 uint32_t cnt, i;
Jon Ashburn23d36b12016-02-02 17:47:28 -07002061 memcpy(dst, src, sizeof(*src));
Mark Youngb6399312017-01-10 14:22:15 -07002062 dst->instance_extension_list.list = loader_instance_heap_alloc(
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002063 inst, sizeof(VkExtensionProperties) * src->instance_extension_list.count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -06002064 if (NULL == dst->instance_extension_list.list) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002065 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2066 "loader_copy_layer_properties: Failed to allocate space "
2067 "for instance extension list of size %d.",
Mark Youngb6399312017-01-10 14:22:15 -07002068 src->instance_extension_list.count);
Mark Young0ad83132016-06-30 13:02:42 -06002069 return VK_ERROR_OUT_OF_HOST_MEMORY;
2070 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002071 dst->instance_extension_list.capacity = sizeof(VkExtensionProperties) * src->instance_extension_list.count;
2072 memcpy(dst->instance_extension_list.list, src->instance_extension_list.list, dst->instance_extension_list.capacity);
Mark Youngb6399312017-01-10 14:22:15 -07002073 dst->device_extension_list.list = loader_instance_heap_alloc(
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002074 inst, sizeof(struct loader_dev_ext_props) * src->device_extension_list.count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -06002075 if (NULL == dst->device_extension_list.list) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002076 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2077 "loader_copy_layer_properties: Failed to allocate space "
2078 "for device extension list of size %d.",
Mark Youngb6399312017-01-10 14:22:15 -07002079 src->device_extension_list.count);
Mark Young0ad83132016-06-30 13:02:42 -06002080 return VK_ERROR_OUT_OF_HOST_MEMORY;
2081 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002082 memset(dst->device_extension_list.list, 0, sizeof(struct loader_dev_ext_props) * src->device_extension_list.count);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002083
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002084 dst->device_extension_list.capacity = sizeof(struct loader_dev_ext_props) * src->device_extension_list.count;
2085 memcpy(dst->device_extension_list.list, src->device_extension_list.list, dst->device_extension_list.capacity);
2086 if (src->device_extension_list.count > 0 && src->device_extension_list.list->entrypoint_count > 0) {
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002087 cnt = src->device_extension_list.list->entrypoint_count;
Mark Young0ad83132016-06-30 13:02:42 -06002088 dst->device_extension_list.list->entrypoints =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002089 loader_instance_heap_alloc(inst, sizeof(char *) * cnt, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -06002090 if (NULL == dst->device_extension_list.list->entrypoints) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002091 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2092 "loader_copy_layer_properties: Failed to allocate space "
2093 "for device extension entrypoint list of size %d.",
Mark Youngb6399312017-01-10 14:22:15 -07002094 cnt);
Mark Young0ad83132016-06-30 13:02:42 -06002095 return VK_ERROR_OUT_OF_HOST_MEMORY;
2096 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002097 memset(dst->device_extension_list.list->entrypoints, 0, sizeof(char *) * cnt);
Mark Young0ad83132016-06-30 13:02:42 -06002098
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002099 for (i = 0; i < cnt; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002100 dst->device_extension_list.list->entrypoints[i] = loader_instance_heap_alloc(
2101 inst, strlen(src->device_extension_list.list->entrypoints[i]) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young0ad83132016-06-30 13:02:42 -06002102 if (NULL == dst->device_extension_list.list->entrypoints[i]) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002103 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2104 "loader_copy_layer_properties: Failed to "
2105 "allocate space for device extension entrypoint "
2106 "%d name of length",
Mark Youngb6399312017-01-10 14:22:15 -07002107 i);
Mark Young0ad83132016-06-30 13:02:42 -06002108 return VK_ERROR_OUT_OF_HOST_MEMORY;
2109 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002110 strcpy(dst->device_extension_list.list->entrypoints[i], src->device_extension_list.list->entrypoints[i]);
Jon Ashburn39fbd4e2015-12-10 18:17:34 -07002111 }
2112 }
Mark Young0ad83132016-06-30 13:02:42 -06002113
2114 return VK_SUCCESS;
Jon Ashburn3d002332015-08-20 16:35:30 -06002115}
2116
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002117static bool loader_find_layer_name_list(const char *name, const struct loader_layer_list *layer_list) {
Mark Youngf2079b92017-05-02 10:49:46 -06002118 if (NULL == layer_list) {
2119 return false;
2120 }
2121 for (uint32_t j = 0; j < layer_list->count; j++) {
2122 if (!strcmp(name, layer_list->list[j].info.layerName)) {
2123 return true;
2124 }
2125 }
Jon Ashburn86a527a2016-02-10 20:59:26 -07002126 return false;
2127}
2128
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002129bool loader_find_layer_name_array(const char *name, uint32_t layer_count, const char layer_list[][VK_MAX_EXTENSION_NAME_SIZE]) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002130 if (!layer_list) return false;
Jon Ashburn86a527a2016-02-10 20:59:26 -07002131 for (uint32_t j = 0; j < layer_count; j++)
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002132 if (!strcmp(name, layer_list[j])) return true;
Jon Ashburn86a527a2016-02-10 20:59:26 -07002133 return false;
2134}
2135
Mark Youngf2079b92017-05-02 10:49:46 -06002136const char *std_validation_str = "VK_LAYER_LUNARG_standard_validation";
Jon Ashburn86a527a2016-02-10 20:59:26 -07002137
Mark Youngf2079b92017-05-02 10:49:46 -06002138// Adds the legacy VK_LAYER_LUNARG_standard_validation as a meta-layer if it
2139// fails to find it in the list already. This is usually an indication that a
2140// newer loader is being used with an older layer set.
2141static bool loader_add_legacy_std_val_layer(const struct loader_instance *inst, struct loader_layer_list *layer_instance_list) {
2142 uint32_t i;
2143 bool success = true;
2144 struct loader_layer_properties *props = loader_get_next_layer_property(inst, layer_instance_list);
2145 const char std_validation_names[6][VK_MAX_EXTENSION_NAME_SIZE] = {
Mark Youngc8b807a2017-07-14 17:11:31 -06002146 "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_object_tracker",
2147 "VK_LAYER_LUNARG_core_validation", "VK_LAYER_GOOGLE_unique_objects"};
Mark Youngf2079b92017-05-02 10:49:46 -06002148 uint32_t layer_count = sizeof(std_validation_names) / sizeof(std_validation_names[0]);
2149
2150 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
2151 "Adding VK_LAYER_LUNARG_standard_validation using the loader legacy path. This is"
2152 " not an error.");
2153
2154 if (NULL == props) {
2155 goto out;
Jon Ashburn491cd042016-05-16 14:01:18 -06002156 }
Jon Ashburn71483442016-02-11 18:59:43 -07002157
Jon Ashburn491cd042016-05-16 14:01:18 -06002158 memset(props, 0, sizeof(struct loader_layer_properties));
Mark Youngf2079b92017-05-02 10:49:46 -06002159 props->type_flags = VK_LAYER_TYPE_FLAG_INSTANCE_LAYER | VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER | VK_LAYER_TYPE_FLAG_META_LAYER;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002160 strncpy(props->info.description, "LunarG Standard Validation Layer", sizeof(props->info.description));
Jon Ashburn491cd042016-05-16 14:01:18 -06002161 props->info.implementationVersion = 1;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002162 strncpy(props->info.layerName, std_validation_str, sizeof(props->info.layerName));
Jon Ashburn491cd042016-05-16 14:01:18 -06002163 props->info.specVersion = VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION);
Jon Ashburn491cd042016-05-16 14:01:18 -06002164
Mark Youngf2079b92017-05-02 10:49:46 -06002165 props->component_layer_names =
2166 loader_instance_heap_alloc(inst, sizeof(char[MAX_STRING_SIZE]) * layer_count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2167 if (NULL == props->component_layer_names) {
2168 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2169 "Failed to allocate space for legacy VK_LAYER_LUNARG_standard_validation"
2170 " meta-layer component_layers information.");
2171 success = false;
2172 goto out;
2173 }
Jon Ashburn491cd042016-05-16 14:01:18 -06002174 for (i = 0; i < layer_count; i++) {
Mark Youngf2079b92017-05-02 10:49:46 -06002175 strncpy(props->component_layer_names[i], std_validation_names[i], MAX_STRING_SIZE - 1);
2176 props->component_layer_names[i][MAX_STRING_SIZE - 1] = '\0';
Jon Ashburn86a527a2016-02-10 20:59:26 -07002177 }
Jon Ashburn491cd042016-05-16 14:01:18 -06002178
Mark Youngf2079b92017-05-02 10:49:46 -06002179out:
2180
2181 if (!success && NULL != props && NULL != props->component_layer_names) {
2182 loader_instance_heap_free(inst, props->component_layer_names);
2183 props->component_layer_names = NULL;
2184 }
2185
2186 return success;
2187}
2188
2189// Verify that all component layers in a meta-layer are valid.
2190static bool verify_meta_layer_comp_layers(const struct loader_instance *inst, struct loader_layer_properties *prop,
2191 struct loader_layer_list *instance_layers) {
2192 bool success = true;
Mark Youngc82a0622017-05-05 11:17:17 -06002193 const uint32_t expected_major = VK_VERSION_MAJOR(prop->info.specVersion);
2194 const uint32_t expected_minor = VK_VERSION_MINOR(prop->info.specVersion);
Mark Youngf2079b92017-05-02 10:49:46 -06002195
2196 for (uint32_t comp_layer = 0; comp_layer < prop->num_component_layers; comp_layer++) {
2197 if (!loader_find_layer_name_list(prop->component_layer_names[comp_layer], instance_layers)) {
2198 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2199 "Meta-layer %s can't find component layer %s at index %d."
2200 " Skipping this layer.",
2201 prop->info.layerName, prop->component_layer_names[comp_layer], comp_layer);
2202 success = false;
2203 break;
2204 } else {
2205 struct loader_layer_properties *comp_prop =
2206 loader_get_layer_property(prop->component_layer_names[comp_layer], instance_layers);
2207 if (comp_prop == NULL) {
2208 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2209 "Meta-layer %s can't find property for component layer %s at index %d."
2210 " Skipping this layer.",
2211 prop->info.layerName, prop->component_layer_names[comp_layer], comp_layer);
2212 success = false;
2213 break;
2214 }
2215
2216 // Check the version of each layer, they need to at least match MAJOR and MINOR
Mark Youngc82a0622017-05-05 11:17:17 -06002217 uint32_t cur_major = VK_VERSION_MAJOR(comp_prop->info.specVersion);
2218 uint32_t cur_minor = VK_VERSION_MINOR(comp_prop->info.specVersion);
2219 if (cur_major != expected_major || cur_minor != expected_minor) {
2220 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2221 "Meta-layer uses API version %d.%d, but component layer %d uses API "
2222 "version %d.%d. Skipping this layer.",
2223 expected_major, expected_minor, comp_layer, cur_major, cur_minor);
2224 success = false;
2225 break;
Mark Youngf2079b92017-05-02 10:49:46 -06002226 }
2227
2228 // Make sure the layer isn't using it's own name
2229 if (!strcmp(prop->info.layerName, prop->component_layer_names[comp_layer])) {
2230 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2231 "Meta-layer %s lists itself in its component layer list at index %d."
2232 " Skipping this layer.",
2233 prop->info.layerName, comp_layer);
2234 success = false;
2235 break;
2236 }
2237 if (comp_prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) {
2238 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
2239 "verify_meta_layer_comp_layers: Adding meta-layer %s which also contains meta-layer %s",
2240 prop->info.layerName, comp_prop->info.layerName);
2241
2242 // Make sure if the layer is using a meta-layer in its component list that we also verify that.
2243 if (!verify_meta_layer_comp_layers(inst, comp_prop, instance_layers)) {
2244 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2245 "Meta-layer %s component layer %s can not find all component layers."
2246 " Skipping this layer.",
2247 prop->info.layerName, prop->component_layer_names[comp_layer]);
2248 success = false;
2249 break;
2250 }
2251 }
2252
2253 // Add any instance and device extensions from component layers to this layer
2254 // list, so that anyone querying extensions will only need to look at the meta-layer
2255 for (uint32_t ext = 0; ext < comp_prop->instance_extension_list.count; ext++) {
2256 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Meta-layer %s component layer %s adding instance extension %s",
2257 prop->info.layerName, prop->component_layer_names[comp_layer],
2258 comp_prop->instance_extension_list.list[ext].extensionName);
2259 if (!has_vk_extension_property(&comp_prop->instance_extension_list.list[ext], &prop->instance_extension_list)) {
2260 loader_add_to_ext_list(inst, &prop->instance_extension_list, 1, &comp_prop->instance_extension_list.list[ext]);
2261 }
2262 }
2263
2264 for (uint32_t ext = 0; ext < comp_prop->device_extension_list.count; ext++) {
2265 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Meta-layer %s component layer %s adding device extension %s",
2266 prop->info.layerName, prop->component_layer_names[comp_layer],
2267 comp_prop->device_extension_list.list[ext].props.extensionName);
2268 if (!has_vk_dev_ext_property(&comp_prop->device_extension_list.list[ext].props, &prop->device_extension_list)) {
2269 loader_add_to_dev_ext_list(inst, &prop->device_extension_list,
2270 &comp_prop->device_extension_list.list[ext].props, 0, NULL);
2271 }
2272 }
Mark Young0ad83132016-06-30 13:02:42 -06002273 }
Mark Youngf2079b92017-05-02 10:49:46 -06002274 }
2275 if (success) {
2276 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Meta-layer %s all %d component layers appear to be valid.",
2277 prop->info.layerName, prop->num_component_layers);
2278 }
2279 return success;
2280}
2281
2282// Verify that all meta-layers in a layer list are valid.
2283static void verify_all_meta_layers(const struct loader_instance *inst, struct loader_layer_list *instance_layers) {
Mark Young697317f2017-05-09 10:31:12 -06002284 for (int32_t i = 0; i < (int32_t)instance_layers->count; i++) {
Mark Youngf2079b92017-05-02 10:49:46 -06002285 struct loader_layer_properties *prop = &instance_layers->list[i];
2286
2287 // If this is a meta-layer, make sure it is valid
2288 if ((prop->type_flags & VK_LAYER_TYPE_FLAG_META_LAYER) && !verify_meta_layer_comp_layers(inst, prop, instance_layers)) {
2289 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
2290 "Removing meta-layer %s from instance layer list since it appears invalid.", prop->info.layerName);
2291
2292 // Delete the component layers
Mark Youngf2079b92017-05-02 10:49:46 -06002293 loader_instance_heap_free(inst, prop->component_layer_names);
Mark Youngf2079b92017-05-02 10:49:46 -06002294
Mark Young70ede4c2017-05-09 15:23:33 -06002295 // Remove the current invalid meta-layer from the layer list. Use memmove since we are
2296 // overlapping the source and destination addresses.
2297 memmove(&instance_layers->list[i], &instance_layers->list[i + 1],
2298 sizeof(struct loader_layer_properties) * (instance_layers->count - 1 - i));
Mark Youngf2079b92017-05-02 10:49:46 -06002299
Mark Young70ede4c2017-05-09 15:23:33 -06002300 // Decrement the count (because we now have one less) and decrement the loop index since we need to
2301 // re-check this index.
2302 instance_layers->count--;
Mark Young697317f2017-05-09 10:31:12 -06002303 i--;
Mark Youngf2079b92017-05-02 10:49:46 -06002304 }
Jon Ashburn491cd042016-05-16 14:01:18 -06002305 }
Jon Ashburn86a527a2016-02-10 20:59:26 -07002306}
2307
Mark Young39389872017-01-19 21:10:49 -07002308// This structure is used to store the json file version
Mark Youngdee312c2017-03-08 13:38:35 -07002309// in a more manageable way.
Mark Young39389872017-01-19 21:10:49 -07002310typedef struct {
2311 uint16_t major;
2312 uint16_t minor;
2313 uint16_t patch;
2314} layer_json_version;
2315
Lenny Komow3cf3ac72017-12-19 16:38:37 -07002316static inline bool is_valid_layer_json_version(const layer_json_version *layer_json) {
2317 // Supported versions are: 1.0.0, 1.0.1, 1.1.0, 1.1.1, and 1.1.2.
2318 if ((layer_json->major == 1 && layer_json->minor == 1 && layer_json->patch < 3) ||
2319 (layer_json->major == 1 && layer_json->minor == 0 && layer_json->patch < 2)) {
2320 return true;
2321 }
2322 return false;
2323}
2324
2325static inline bool layer_json_supports_layers_tag(const layer_json_version *layer_json) {
2326 // Supported versions started in 1.0.1, so anything newer
2327 if ((layer_json->major > 1 || layer_json->minor > 0 || layer_json->patch > 1)) {
2328 return true;
2329 }
2330 return false;
2331}
2332
2333static inline bool layer_json_supports_pre_instance_tag(const layer_json_version *layer_json) {
2334 // Supported versions started in 1.1.2, so anything newer
2335 return layer_json->major > 1 || layer_json->minor > 1 || (layer_json->minor == 1 && layer_json->patch > 1);
2336}
2337
Mark Youngf2079b92017-05-02 10:49:46 -06002338static VkResult loader_read_json_layer(const struct loader_instance *inst, struct loader_layer_list *layer_instance_list,
2339 cJSON *layer_node, layer_json_version version, cJSON *item, cJSON *disable_environment,
2340 bool is_implicit, char *filename) {
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002341 char *temp;
Mark Youngf2079b92017-05-02 10:49:46 -06002342 char *name, *type, *library_path_str, *api_version;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002343 char *implementation_version, *description;
Mark Youngf2079b92017-05-02 10:49:46 -06002344 cJSON *ext_item, *library_path, *component_layers;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002345 VkExtensionProperties ext_prop;
Mark Youngf2079b92017-05-02 10:49:46 -06002346 VkResult result = VK_ERROR_INITIALIZATION_FAILED;
2347 struct loader_layer_properties *props = NULL;
2348 int i, j;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002349
Mark Young0f183a82017-02-28 09:58:04 -07002350// The following are required in the "layer" object:
2351// (required) "name"
2352// (required) "type"
Nekotekinad431e132017-06-11 13:13:07 +03002353// (required) "library_path"
2354// (required) "api_version"
2355// (required) "implementation_version"
2356// (required) "description"
2357// (required for implicit layers) "disable_environment"
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002358#define GET_JSON_OBJECT(node, var) \
2359 { \
2360 var = cJSON_GetObjectItem(node, #var); \
2361 if (var == NULL) { \
2362 layer_node = layer_node->next; \
2363 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
2364 "Didn't find required layer object %s in manifest " \
2365 "JSON file, skipping this layer", \
2366 #var); \
Mark Youngf2079b92017-05-02 10:49:46 -06002367 goto out; \
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002368 } \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002369 }
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002370#define GET_JSON_ITEM(node, var) \
2371 { \
2372 item = cJSON_GetObjectItem(node, #var); \
2373 if (item == NULL) { \
2374 layer_node = layer_node->next; \
2375 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
2376 "Didn't find required layer value %s in manifest JSON " \
2377 "file, skipping this layer", \
2378 #var); \
Mark Youngf2079b92017-05-02 10:49:46 -06002379 goto out; \
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002380 } \
2381 temp = cJSON_Print(item); \
2382 if (temp == NULL) { \
2383 layer_node = layer_node->next; \
2384 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, \
2385 "Problem accessing layer value %s in manifest JSON " \
2386 "file, skipping this layer", \
2387 #var); \
Mark Youngf2079b92017-05-02 10:49:46 -06002388 result = VK_ERROR_OUT_OF_HOST_MEMORY; \
2389 goto out; \
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002390 } \
2391 temp[strlen(temp) - 1] = '\0'; \
2392 var = loader_stack_alloc(strlen(temp) + 1); \
2393 strcpy(var, &temp[1]); \
2394 cJSON_Free(temp); \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002395 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002396 GET_JSON_ITEM(layer_node, name)
2397 GET_JSON_ITEM(layer_node, type)
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002398 GET_JSON_ITEM(layer_node, api_version)
2399 GET_JSON_ITEM(layer_node, implementation_version)
2400 GET_JSON_ITEM(layer_node, description)
Mark Youngf2079b92017-05-02 10:49:46 -06002401
2402 // Add list entry
2403 if (!strcmp(type, "DEVICE")) {
2404 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, "Device layers are deprecated skipping this layer");
2405 layer_node = layer_node->next;
2406 goto out;
2407 }
2408
2409 // Allow either GLOBAL or INSTANCE type interchangeably to handle
2410 // layers that must work with older loaders
2411 if (!strcmp(type, "INSTANCE") || !strcmp(type, "GLOBAL")) {
2412 if (layer_instance_list == NULL) {
2413 layer_node = layer_node->next;
2414 goto out;
2415 }
2416 props = loader_get_next_layer_property(inst, layer_instance_list);
2417 if (NULL == props) {
2418 // Error already triggered in loader_get_next_layer_property.
2419 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2420 goto out;
2421 }
2422 props->type_flags = VK_LAYER_TYPE_FLAG_INSTANCE_LAYER;
2423 if (!is_implicit) {
2424 props->type_flags |= VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER;
2425 }
2426 } else {
2427 layer_node = layer_node->next;
2428 goto out;
2429 }
2430
2431 // Library path no longer required unless component_layers is also not defined
2432 library_path = cJSON_GetObjectItem(layer_node, "library_path");
2433 component_layers = cJSON_GetObjectItem(layer_node, "component_layers");
2434 if (NULL != library_path) {
2435 if (NULL != component_layers) {
2436 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2437 "Indicating meta-layer-specific component_layers, but also "
2438 "defining layer library path. Both are not compatible, so "
2439 "skipping this layer");
2440 goto out;
2441 }
2442 props->num_component_layers = 0;
2443 props->component_layer_names = NULL;
2444
2445 temp = cJSON_Print(library_path);
2446 if (NULL == temp) {
2447 layer_node = layer_node->next;
2448 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2449 "Problem accessing layer value library_path in manifest JSON "
2450 "file, skipping this layer");
2451 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2452 goto out;
2453 }
2454 temp[strlen(temp) - 1] = '\0';
2455 library_path_str = loader_stack_alloc(strlen(temp) + 1);
2456 strcpy(library_path_str, &temp[1]);
2457 cJSON_Free(temp);
2458
2459 char *fullpath = props->lib_name;
2460 char *rel_base;
2461 if (NULL != library_path_str) {
2462 if (loader_platform_is_path(library_path_str)) {
2463 // A relative or absolute path
2464 char *name_copy = loader_stack_alloc(strlen(filename) + 1);
2465 strcpy(name_copy, filename);
2466 rel_base = loader_platform_dirname(name_copy);
2467 loader_expand_path(library_path_str, rel_base, MAX_STRING_SIZE, fullpath);
2468 } else {
2469 // A filename which is assumed in a system directory
2470 loader_get_fullpath(library_path_str, DEFAULT_VK_LAYERS_PATH, MAX_STRING_SIZE, fullpath);
2471 }
2472 }
2473 } else if (NULL != component_layers) {
2474 if (version.major == 1 && (version.minor < 1 || version.patch < 1)) {
2475 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2476 "Indicating meta-layer-specific component_layers, but using older "
2477 "JSON file version.");
2478 }
2479 int count = cJSON_GetArraySize(component_layers);
2480 props->num_component_layers = count;
2481
2482 // Allocate buffer for layer names
2483 props->component_layer_names =
2484 loader_instance_heap_alloc(inst, sizeof(char[MAX_STRING_SIZE]) * count, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2485 if (NULL == props->component_layer_names) {
2486 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2487 goto out;
2488 }
2489
2490 // Copy the component layers into the array
2491 for (i = 0; i < count; i++) {
2492 cJSON *comp_layer = cJSON_GetArrayItem(component_layers, i);
2493 if (NULL != comp_layer) {
2494 temp = cJSON_Print(comp_layer);
2495 if (NULL == temp) {
2496 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2497 goto out;
2498 }
2499 temp[strlen(temp) - 1] = '\0';
2500 strncpy(props->component_layer_names[i], temp + 1, MAX_STRING_SIZE - 1);
2501 props->component_layer_names[i][MAX_STRING_SIZE - 1] = '\0';
2502 cJSON_Free(temp);
2503 }
2504 }
2505
2506 // This is now, officially, a meta-layer
2507 props->type_flags |= VK_LAYER_TYPE_FLAG_META_LAYER;
2508 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Encountered meta-layer %s", name);
2509
2510 // Make sure we set up other things so we head down the correct branches below
2511 library_path_str = NULL;
2512 } else {
2513 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2514 "Layer missing both library_path and component_layers fields. One or the "
2515 "other MUST be defined. Skipping this layer");
2516 goto out;
2517 }
2518
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002519 if (is_implicit) {
2520 GET_JSON_OBJECT(layer_node, disable_environment)
2521 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002522#undef GET_JSON_ITEM
2523#undef GET_JSON_OBJECT
2524
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002525 strncpy(props->info.layerName, name, sizeof(props->info.layerName));
2526 props->info.layerName[sizeof(props->info.layerName) - 1] = '\0';
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002527 props->info.specVersion = loader_make_version(api_version);
2528 props->info.implementationVersion = atoi(implementation_version);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002529 strncpy((char *)props->info.description, description, sizeof(props->info.description));
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002530 props->info.description[sizeof(props->info.description) - 1] = '\0';
2531 if (is_implicit) {
2532 if (!disable_environment || !disable_environment->child) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002533 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2534 "Didn't find required layer child value disable_environment"
2535 "in manifest JSON file, skipping this layer");
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002536 layer_node = layer_node->next;
Mark Youngf2079b92017-05-02 10:49:46 -06002537 goto out;
Jon Ashburnfb8ac012015-08-12 16:39:32 -06002538 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002539 strncpy(props->disable_env_var.name, disable_environment->child->string, sizeof(props->disable_env_var.name));
2540 props->disable_env_var.name[sizeof(props->disable_env_var.name) - 1] = '\0';
2541 strncpy(props->disable_env_var.value, disable_environment->child->valuestring, sizeof(props->disable_env_var.value));
2542 props->disable_env_var.value[sizeof(props->disable_env_var.value) - 1] = '\0';
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002543 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002544
Mark Young0f183a82017-02-28 09:58:04 -07002545// Now get all optional items and objects and put in list:
2546// functions
2547// instance_extensions
2548// device_extensions
2549// enable_environment (implicit layers only)
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002550#define GET_JSON_OBJECT(node, var) \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002551 { var = cJSON_GetObjectItem(node, #var); }
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002552#define GET_JSON_ITEM(node, var) \
2553 { \
2554 item = cJSON_GetObjectItem(node, #var); \
2555 if (item != NULL) { \
2556 temp = cJSON_Print(item); \
2557 if (temp != NULL) { \
2558 temp[strlen(temp) - 1] = '\0'; \
2559 var = loader_stack_alloc(strlen(temp) + 1); \
2560 strcpy(var, &temp[1]); \
2561 cJSON_Free(temp); \
Mark Youngf2079b92017-05-02 10:49:46 -06002562 } else { \
2563 result = VK_ERROR_OUT_OF_HOST_MEMORY; \
2564 goto out; \
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002565 } \
2566 } \
Jon Ashburn23d36b12016-02-02 17:47:28 -07002567 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002568
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002569 cJSON *instance_extensions, *device_extensions, *functions, *enable_environment;
Mark Young39389872017-01-19 21:10:49 -07002570 cJSON *entrypoints = NULL;
2571 char *vkGetInstanceProcAddr = NULL;
2572 char *vkGetDeviceProcAddr = NULL;
2573 char *vkNegotiateLoaderLayerInterfaceVersion = NULL;
2574 char *spec_version = NULL;
2575 char **entry_array = NULL;
Jon Ashburn075ce432015-12-17 17:38:24 -07002576
Mark Young39389872017-01-19 21:10:49 -07002577 // Layer interface functions
2578 // vkGetInstanceProcAddr
2579 // vkGetDeviceProcAddr
2580 // vkNegotiateLoaderLayerInterfaceVersion (starting with JSON file 1.1.0)
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002581 GET_JSON_OBJECT(layer_node, functions)
2582 if (functions != NULL) {
Mark Young39389872017-01-19 21:10:49 -07002583 if (version.major > 1 || version.minor >= 1) {
2584 GET_JSON_ITEM(functions, vkNegotiateLoaderLayerInterfaceVersion)
2585 if (vkNegotiateLoaderLayerInterfaceVersion != NULL)
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002586 strncpy(props->functions.str_negotiate_interface, vkNegotiateLoaderLayerInterfaceVersion,
Mark Young39389872017-01-19 21:10:49 -07002587 sizeof(props->functions.str_negotiate_interface));
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002588 props->functions.str_negotiate_interface[sizeof(props->functions.str_negotiate_interface) - 1] = '\0';
Mark Young39389872017-01-19 21:10:49 -07002589 } else {
2590 props->functions.str_negotiate_interface[0] = '\0';
2591 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002592 GET_JSON_ITEM(functions, vkGetInstanceProcAddr)
2593 GET_JSON_ITEM(functions, vkGetDeviceProcAddr)
Mark Young39389872017-01-19 21:10:49 -07002594 if (vkGetInstanceProcAddr != NULL) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002595 strncpy(props->functions.str_gipa, vkGetInstanceProcAddr, sizeof(props->functions.str_gipa));
Mark Young39389872017-01-19 21:10:49 -07002596 if (version.major > 1 || version.minor >= 1) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002597 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2598 "Indicating layer-specific vkGetInstanceProcAddr "
2599 "function is deprecated starting with JSON file "
2600 "version 1.1.0. Instead, use the new "
2601 "vkNegotiateLayerInterfaceVersion function to "
2602 "return the GetInstanceProcAddr function for this"
2603 "layer");
Mark Young39389872017-01-19 21:10:49 -07002604 }
2605 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002606 props->functions.str_gipa[sizeof(props->functions.str_gipa) - 1] = '\0';
Mark Young39389872017-01-19 21:10:49 -07002607 if (vkGetDeviceProcAddr != NULL) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002608 strncpy(props->functions.str_gdpa, vkGetDeviceProcAddr, sizeof(props->functions.str_gdpa));
Mark Young39389872017-01-19 21:10:49 -07002609 if (version.major > 1 || version.minor >= 1) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002610 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2611 "Indicating layer-specific vkGetDeviceProcAddr "
2612 "function is deprecated starting with JSON file "
2613 "version 1.1.0. Instead, use the new "
2614 "vkNegotiateLayerInterfaceVersion function to "
2615 "return the GetDeviceProcAddr function for this"
2616 "layer");
Mark Young39389872017-01-19 21:10:49 -07002617 }
2618 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002619 props->functions.str_gdpa[sizeof(props->functions.str_gdpa) - 1] = '\0';
2620 }
Mark Young39389872017-01-19 21:10:49 -07002621
2622 // instance_extensions
2623 // array of {
2624 // name
2625 // spec_version
2626 // }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002627 GET_JSON_OBJECT(layer_node, instance_extensions)
2628 if (instance_extensions != NULL) {
2629 int count = cJSON_GetArraySize(instance_extensions);
2630 for (i = 0; i < count; i++) {
2631 ext_item = cJSON_GetArrayItem(instance_extensions, i);
2632 GET_JSON_ITEM(ext_item, name)
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002633 if (name != NULL) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002634 strncpy(ext_prop.extensionName, name, sizeof(ext_prop.extensionName));
2635 ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] = '\0';
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002636 }
Mark Young0ad83132016-06-30 13:02:42 -06002637 GET_JSON_ITEM(ext_item, spec_version)
2638 if (NULL != spec_version) {
2639 ext_prop.specVersion = atoi(spec_version);
2640 } else {
2641 ext_prop.specVersion = 0;
2642 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002643 bool ext_unsupported = wsi_unsupported_instance_extension(&ext_prop);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002644 if (!ext_unsupported) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002645 loader_add_to_ext_list(inst, &props->instance_extension_list, 1, &ext_prop);
Jon Ashburn075ce432015-12-17 17:38:24 -07002646 }
Jon Ashburnfb8ac012015-08-12 16:39:32 -06002647 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002648 }
Mark Young39389872017-01-19 21:10:49 -07002649
2650 // device_extensions
2651 // array of {
2652 // name
2653 // spec_version
2654 // entrypoints
2655 // }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002656 GET_JSON_OBJECT(layer_node, device_extensions)
2657 if (device_extensions != NULL) {
2658 int count = cJSON_GetArraySize(device_extensions);
2659 for (i = 0; i < count; i++) {
2660 ext_item = cJSON_GetArrayItem(device_extensions, i);
2661 GET_JSON_ITEM(ext_item, name)
2662 GET_JSON_ITEM(ext_item, spec_version)
2663 if (name != NULL) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002664 strncpy(ext_prop.extensionName, name, sizeof(ext_prop.extensionName));
2665 ext_prop.extensionName[sizeof(ext_prop.extensionName) - 1] = '\0';
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002666 }
Mark Young0ad83132016-06-30 13:02:42 -06002667 if (NULL != spec_version) {
2668 ext_prop.specVersion = atoi(spec_version);
2669 } else {
2670 ext_prop.specVersion = 0;
2671 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002672 // entrypoints = cJSON_GetObjectItem(ext_item, "entrypoints");
2673 GET_JSON_OBJECT(ext_item, entrypoints)
2674 int entry_count;
2675 if (entrypoints == NULL) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002676 loader_add_to_dev_ext_list(inst, &props->device_extension_list, &ext_prop, 0, NULL);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002677 continue;
2678 }
2679 entry_count = cJSON_GetArraySize(entrypoints);
Mark Young0ad83132016-06-30 13:02:42 -06002680 if (entry_count) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002681 entry_array = (char **)loader_stack_alloc(sizeof(char *) * entry_count);
Mark Young0ad83132016-06-30 13:02:42 -06002682 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002683 for (j = 0; j < entry_count; j++) {
2684 ext_item = cJSON_GetArrayItem(entrypoints, j);
2685 if (ext_item != NULL) {
2686 temp = cJSON_Print(ext_item);
Mark Young0ad83132016-06-30 13:02:42 -06002687 if (NULL == temp) {
2688 entry_array[j] = NULL;
Mark Youngf2079b92017-05-02 10:49:46 -06002689 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2690 goto out;
Mark Young0ad83132016-06-30 13:02:42 -06002691 }
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002692 temp[strlen(temp) - 1] = '\0';
2693 entry_array[j] = loader_stack_alloc(strlen(temp) + 1);
2694 strcpy(entry_array[j], &temp[1]);
Mark Young0ad83132016-06-30 13:02:42 -06002695 cJSON_Free(temp);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002696 }
2697 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002698 loader_add_to_dev_ext_list(inst, &props->device_extension_list, &ext_prop, entry_count, entry_array);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002699 }
2700 }
2701 if (is_implicit) {
2702 GET_JSON_OBJECT(layer_node, enable_environment)
2703
2704 // enable_environment is optional
2705 if (enable_environment) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002706 strncpy(props->enable_env_var.name, enable_environment->child->string, sizeof(props->enable_env_var.name));
2707 props->enable_env_var.name[sizeof(props->enable_env_var.name) - 1] = '\0';
2708 strncpy(props->enable_env_var.value, enable_environment->child->valuestring, sizeof(props->enable_env_var.value));
2709 props->enable_env_var.value[sizeof(props->enable_env_var.value) - 1] = '\0';
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002710 }
2711 }
Mark Youngf2079b92017-05-02 10:49:46 -06002712
Lenny Komow3cf3ac72017-12-19 16:38:37 -07002713 // Read in the pre-instance stuff
2714 cJSON *pre_instance = cJSON_GetObjectItem(layer_node, "pre_instance_functions");
2715 if (pre_instance) {
2716 if (!layer_json_supports_pre_instance_tag(&version)) {
2717 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2718 "Found pre_instance_functions section in layer from \"%s\". "
2719 "This section is only valid in manifest version 1.1.2 or later. The section will be ignored",
2720 filename);
2721 } else if (!is_implicit) {
2722 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2723 "Found pre_instance_functions section in explicit layer from "
2724 "\"%s\". This section is only valid in implicit layers. The section will be ignored",
2725 filename);
2726 } else {
2727 cJSON *inst_ext_json = cJSON_GetObjectItem(pre_instance, "vkEnumerateInstanceExtensionProperties");
2728 if (inst_ext_json) {
2729 char *inst_ext_name = cJSON_Print(inst_ext_json);
2730 size_t len = strlen(inst_ext_name) >= MAX_STRING_SIZE ? MAX_STRING_SIZE - 3 : strlen(inst_ext_name) - 2;
2731 strncpy(props->pre_instance_functions.enumerate_instance_extension_properties, inst_ext_name + 1, len);
2732 props->pre_instance_functions.enumerate_instance_extension_properties[len] = '\0';
2733 cJSON_Free(inst_ext_name);
2734 }
2735
2736 cJSON *inst_layer_json = cJSON_GetObjectItem(pre_instance, "vkEnumerateInstanceLayerProperties");
2737 if (inst_layer_json) {
2738 char *inst_layer_name = cJSON_Print(inst_layer_json);
2739 size_t len = strlen(inst_layer_name) >= MAX_STRING_SIZE ? MAX_STRING_SIZE - 3 : strlen(inst_layer_name) - 2;
2740 strncpy(props->pre_instance_functions.enumerate_instance_layer_properties, inst_layer_name + 1, len);
2741 props->pre_instance_functions.enumerate_instance_layer_properties[len] = '\0';
2742 cJSON_Free(inst_layer_name);
2743 }
2744 }
2745 }
2746
Mark Youngf2079b92017-05-02 10:49:46 -06002747 result = VK_SUCCESS;
2748
2749out:
2750
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002751#undef GET_JSON_ITEM
2752#undef GET_JSON_OBJECT
Mark Youngf2079b92017-05-02 10:49:46 -06002753
2754 if (VK_SUCCESS != result && NULL != props) {
2755 props->num_component_layers = 0;
2756 if (NULL != props->component_layer_names) {
2757 loader_instance_heap_free(inst, props->component_layer_names);
2758 }
2759 props->component_layer_names = NULL;
2760 }
2761
2762 return result;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002763}
2764
Mark Young0f183a82017-02-28 09:58:04 -07002765// Given a cJSON struct (json) of the top level JSON object from layer manifest
2766// file, add entry to the layer_list. Fill out the layer_properties in this list
2767// entry from the input cJSON object.
2768//
2769// \returns
2770// void
2771// layer_list has a new entry and initialized accordingly.
2772// If the json input object does not have all the required fields no entry
2773// is added to the list.
Mark Youngf2079b92017-05-02 10:49:46 -06002774static VkResult loader_add_layer_properties(const struct loader_instance *inst, struct loader_layer_list *layer_instance_list,
2775 cJSON *json, bool is_implicit, char *filename) {
Mark Young39389872017-01-19 21:10:49 -07002776 // The following Fields in layer manifest file that are required:
Nekotekinad431e132017-06-11 13:13:07 +03002777 // - "file_format_version"
Mark Young39389872017-01-19 21:10:49 -07002778 // - If more than one "layer" object are used, then the "layers" array is
Mark Youngdee312c2017-03-08 13:38:35 -07002779 // required
Mark Youngf2079b92017-05-02 10:49:46 -06002780 VkResult result = VK_ERROR_INITIALIZATION_FAILED;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002781 cJSON *item, *layers_node, *layer_node;
Mike Stroyan81908212017-03-14 13:09:12 -06002782 layer_json_version json_version = {0, 0, 0};
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002783 char *vers_tok;
2784 cJSON *disable_environment = NULL;
2785 item = cJSON_GetObjectItem(json, "file_format_version");
2786 if (item == NULL) {
Mark Youngf2079b92017-05-02 10:49:46 -06002787 goto out;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002788 }
2789 char *file_vers = cJSON_PrintUnformatted(item);
Mark Young0ad83132016-06-30 13:02:42 -06002790 if (NULL == file_vers) {
Mark Youngf2079b92017-05-02 10:49:46 -06002791 goto out;
Mark Young0ad83132016-06-30 13:02:42 -06002792 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002793 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Found manifest file %s, version %s", filename, file_vers);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002794 // Get the major/minor/and patch as integers for easier comparison
2795 vers_tok = strtok(file_vers, ".\"\n\r");
2796 if (NULL != vers_tok) {
Mark Young39389872017-01-19 21:10:49 -07002797 json_version.major = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002798 vers_tok = strtok(NULL, ".\"\n\r");
2799 if (NULL != vers_tok) {
Mark Young39389872017-01-19 21:10:49 -07002800 json_version.minor = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002801 vers_tok = strtok(NULL, ".\"\n\r");
2802 if (NULL != vers_tok) {
Mark Young39389872017-01-19 21:10:49 -07002803 json_version.patch = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002804 }
2805 }
2806 }
Mark Young39389872017-01-19 21:10:49 -07002807
2808 if (!is_valid_layer_json_version(&json_version)) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002809 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2810 "loader_add_layer_properties: %s invalid layer "
Mark Youngf2079b92017-05-02 10:49:46 -06002811 "manifest file version %d.%d.%d. May cause errors.",
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002812 filename, json_version.major, json_version.minor, json_version.patch);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002813 }
Mark Young0ad83132016-06-30 13:02:42 -06002814 cJSON_Free(file_vers);
Mark Young39389872017-01-19 21:10:49 -07002815
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002816 // If "layers" is present, read in the array of layer objects
2817 layers_node = cJSON_GetObjectItem(json, "layers");
2818 if (layers_node != NULL) {
2819 int numItems = cJSON_GetArraySize(layers_node);
Mark Young39389872017-01-19 21:10:49 -07002820 if (!layer_json_supports_layers_tag(&json_version)) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002821 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2822 "loader_add_layer_properties: \'layers\' tag not "
2823 "supported until file version 1.0.1, but %s is "
2824 "reporting version %s",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002825 filename, file_vers);
2826 }
2827 for (int curLayer = 0; curLayer < numItems; curLayer++) {
2828 layer_node = cJSON_GetArrayItem(layers_node, curLayer);
2829 if (layer_node == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002830 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2831 "loader_add_layer_properties: Can not find "
2832 "\'layers\' array element %d object in manifest "
2833 "JSON file %s. Skipping this file",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002834 curLayer, filename);
Mark Youngf2079b92017-05-02 10:49:46 -06002835 goto out;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002836 }
Mark Youngf2079b92017-05-02 10:49:46 -06002837 result = loader_read_json_layer(inst, layer_instance_list, layer_node, json_version, item, disable_environment,
2838 is_implicit, filename);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002839 }
2840 } else {
2841 // Otherwise, try to read in individual layers
2842 layer_node = cJSON_GetObjectItem(json, "layer");
2843 if (layer_node == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002844 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
2845 "loader_add_layer_properties: Can not find \'layer\' "
2846 "object in manifest JSON file %s. Skipping this file.",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002847 filename);
Mark Youngf2079b92017-05-02 10:49:46 -06002848 goto out;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002849 }
2850 // Loop through all "layer" objects in the file to get a count of them
2851 // first.
2852 uint16_t layer_count = 0;
2853 cJSON *tempNode = layer_node;
2854 do {
2855 tempNode = tempNode->next;
2856 layer_count++;
2857 } while (tempNode != NULL);
Mark Young39389872017-01-19 21:10:49 -07002858
2859 // Throw a warning if we encounter multiple "layer" objects in file
2860 // versions newer than 1.0.0. Having multiple objects with the same
2861 // name at the same level is actually a JSON standard violation.
2862 if (layer_count > 1 && layer_json_supports_layers_tag(&json_version)) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002863 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2864 "loader_add_layer_properties: Multiple \'layer\' nodes"
2865 " are deprecated starting in file version \"1.0.1\". "
2866 "Please use \'layers\' : [] array instead in %s.",
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002867 filename);
2868 } else {
2869 do {
Mark Youngf2079b92017-05-02 10:49:46 -06002870 result = loader_read_json_layer(inst, layer_instance_list, layer_node, json_version, item, disable_environment,
2871 is_implicit, filename);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06002872 layer_node = layer_node->next;
2873 } while (layer_node != NULL);
2874 }
2875 }
Mark Youngf2079b92017-05-02 10:49:46 -06002876
2877out:
2878
2879 return result;
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06002880}
2881
Mark Young0f183a82017-02-28 09:58:04 -07002882// Find the Vulkan library manifest files.
2883//
2884// This function scans the "location" or "env_override" directories/files
2885// for a list of JSON manifest files. If env_override is non-NULL
2886// and has a valid value. Then the location is ignored. Otherwise
2887// location is used to look for manifest files. The location
2888// is interpreted as Registry path on Windows and a directory path(s)
2889// on Linux. "home_location" is an additional directory in the users home
2890// directory to look at. It is expanded into the dir path
2891// $XDG_DATA_HOME/home_location or $HOME/.local/share/home_location depending
2892// on environment variables. This "home_location" is only used on Linux.
2893//
2894// \returns
2895// VKResult
2896// A string list of manifest files to be opened in out_files param.
2897// List has a pointer to string for each manifest filename.
2898// When done using the list in out_files, pointers should be freed.
2899// Location or override string lists can be either files or directories as
Mark Youngf2079b92017-05-02 10:49:46 -06002900// follows:
Mark Young0f183a82017-02-28 09:58:04 -07002901// | location | override
2902// --------------------------------
2903// Win ICD | files | files
2904// Win Layer | files | dirs
2905// Linux ICD | dirs | files
2906// Linux Layer| dirs | dirs
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07002907static VkResult loader_get_manifest_files(const struct loader_instance *inst, const char *env_override, const char *source_override,
Mark Youngf2079b92017-05-02 10:49:46 -06002908 bool is_layer, bool warn_if_not_present, const char *location,
2909 const char *relative_location, struct loader_manifest_files *out_files) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06002910 const char *override = NULL;
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002911 char *override_getenv = NULL;
Mark Young0ad83132016-06-30 13:02:42 -06002912 char *loc, *orig_loc = NULL;
2913 char *reg = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06002914 char *file, *next_file, *name;
2915 size_t alloced_count = 64;
2916 char full_path[2048];
2917 DIR *sysdir = NULL;
Jon Ashburnffad94d2015-06-30 14:46:22 -07002918 bool list_is_dirs = false;
Jon Ashburn2077e382015-06-29 11:25:34 -06002919 struct dirent *dent;
Mark Young0ad83132016-06-30 13:02:42 -06002920 VkResult res = VK_SUCCESS;
Jon Ashburn2077e382015-06-29 11:25:34 -06002921
2922 out_files->count = 0;
2923 out_files->filename_list = NULL;
2924
Jamie Madill00c3c912016-04-06 18:26:46 -04002925 if (source_override != NULL) {
2926 override = source_override;
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002927 } else if (env_override != NULL) {
Johannes van Waveren9bd805012015-10-28 11:45:00 -05002928#if !defined(_WIN32)
Jon Ashburncc407a22016-04-15 09:25:03 -06002929 if (geteuid() != getuid() || getegid() != getgid()) {
Mark Young0f183a82017-02-28 09:58:04 -07002930 // Don't allow setuid apps to use the env var:
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002931 env_override = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06002932 }
2933#endif
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002934 if (env_override != NULL) {
Mark Youngd8c6b692017-03-09 11:39:41 -07002935 override = override_getenv = loader_secure_getenv(env_override, inst);
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05002936 }
Jon Ashburn2077e382015-06-29 11:25:34 -06002937 }
2938
Jon Ashburnb6822212016-02-16 15:34:16 -07002939#if !defined(_WIN32)
Benjamin Saunders31a48012017-01-29 14:49:54 -08002940 if (relative_location == NULL) {
Jon Ashburnb6822212016-02-16 15:34:16 -07002941#else
Benjamin Saunders31a48012017-01-29 14:49:54 -08002942 relative_location = NULL;
Jon Ashburn2077e382015-06-29 11:25:34 -06002943 if (location == NULL) {
Jon Ashburnb6822212016-02-16 15:34:16 -07002944#endif
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002945 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2946 "loader_get_manifest_files: Can not get manifest files with "
2947 "NULL location, env_override=%s",
Mark Youngb6399312017-01-10 14:22:15 -07002948 (env_override != NULL) ? env_override : "");
Mark Young0ad83132016-06-30 13:02:42 -06002949 res = VK_ERROR_INITIALIZATION_FAILED;
2950 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06002951 }
2952
Johannes van Waveren9bd805012015-10-28 11:45:00 -05002953#if defined(_WIN32)
Jon Ashburnffad94d2015-06-30 14:46:22 -07002954 list_is_dirs = (is_layer && override != NULL) ? true : false;
Johannes van Waveren9bd805012015-10-28 11:45:00 -05002955#else
2956 list_is_dirs = (override == NULL || is_layer) ? true : false;
Jon Ashburnffad94d2015-06-30 14:46:22 -07002957#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06002958 // Make a copy of the input we are using so it is not modified
Jon Ashburnffad94d2015-06-30 14:46:22 -07002959 // Also handle getting the location(s) from registry on Windows
2960 if (override == NULL) {
Benjamin Saunders31a48012017-01-29 14:49:54 -08002961 size_t loc_size = 0;
2962#if !defined(_WIN32)
Mark Youngd8c6b692017-03-09 11:39:41 -07002963 const char *xdgconfdirs = loader_secure_getenv("XDG_CONFIG_DIRS", inst);
2964 const char *xdgdatadirs = loader_secure_getenv("XDG_DATA_DIRS", inst);
Mark Youngf2079b92017-05-02 10:49:46 -06002965 if (xdgconfdirs == NULL || xdgconfdirs[0] == '\0') xdgconfdirs = FALLBACK_CONFIG_DIRS;
2966 if (xdgdatadirs == NULL || xdgdatadirs[0] == '\0') xdgdatadirs = FALLBACK_DATA_DIRS;
Benjamin Saunders31a48012017-01-29 14:49:54 -08002967 const size_t rel_size = strlen(relative_location);
2968 // Leave space for trailing separators
Mark Youngf2079b92017-05-02 10:49:46 -06002969 loc_size += strlen(xdgconfdirs) + strlen(xdgdatadirs) + 2 * rel_size + 2;
Benjamin Saunders31a48012017-01-29 14:49:54 -08002970 for (const char *x = xdgconfdirs; *x; ++x)
2971 if (*x == PATH_SEPARATOR) loc_size += rel_size;
2972 for (const char *x = xdgdatadirs; *x; ++x)
2973 if (*x == PATH_SEPARATOR) loc_size += rel_size;
2974 loc_size += strlen(SYSCONFDIR) + rel_size + 1;
2975#if defined(EXTRASYSCONFDIR)
2976 loc_size += strlen(EXTRASYSCONFDIR) + rel_size + 1;
2977#endif
2978#else
2979 loc_size += strlen(location) + 1;
2980#endif
2981 loc = loader_stack_alloc(loc_size);
Jon Ashburnffad94d2015-06-30 14:46:22 -07002982 if (loc == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07002983 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
2984 "loader_get_manifest_files: Failed to allocate "
2985 "%d bytes for manifest file location.",
Benjamin Saunders31a48012017-01-29 14:49:54 -08002986 loc_size);
Mark Young0ad83132016-06-30 13:02:42 -06002987 res = VK_ERROR_OUT_OF_HOST_MEMORY;
2988 goto out;
Jon Ashburnffad94d2015-06-30 14:46:22 -07002989 }
Benjamin Saunders31a48012017-01-29 14:49:54 -08002990 char *loc_write = loc;
2991#if !defined(_WIN32)
2992 const char *loc_read;
Karl Schultz52f5daa2017-02-12 12:34:03 -07002993 size_t start, stop;
Benjamin Saunders31a48012017-01-29 14:49:54 -08002994
2995 loc_read = &xdgconfdirs[0];
Karl Schultz52f5daa2017-02-12 12:34:03 -07002996 start = 0;
2997 while (loc_read[start] != '\0') {
2998 while (loc_read[start] == PATH_SEPARATOR) {
2999 start++;
3000 }
3001 stop = start;
3002 while (loc_read[stop] != PATH_SEPARATOR && loc_read[stop] != '\0') {
3003 stop++;
3004 }
3005 const size_t s = stop - start;
3006 if (s) {
3007 memcpy(loc_write, &loc_read[start], s);
Benjamin Saunders31a48012017-01-29 14:49:54 -08003008 loc_write += s;
3009 memcpy(loc_write, relative_location, rel_size);
3010 loc_write += rel_size;
3011 *loc_write++ = PATH_SEPARATOR;
Karl Schultz52f5daa2017-02-12 12:34:03 -07003012 start = stop;
Benjamin Saunders31a48012017-01-29 14:49:54 -08003013 }
3014 }
3015
3016 memcpy(loc_write, SYSCONFDIR, strlen(SYSCONFDIR));
3017 loc_write += strlen(SYSCONFDIR);
3018 memcpy(loc_write, relative_location, rel_size);
3019 loc_write += rel_size;
3020 *loc_write++ = PATH_SEPARATOR;
3021
3022#if defined(EXTRASYSCONFDIR)
3023 memcpy(loc_write, EXTRASYSCONFDIR, strlen(EXTRASYSCONFDIR));
3024 loc_write += strlen(EXTRASYSCONFDIR);
3025 memcpy(loc_write, relative_location, rel_size);
3026 loc_write += rel_size;
3027 *loc_write++ = PATH_SEPARATOR;
3028#endif
3029
3030 loc_read = &xdgdatadirs[0];
Karl Schultz52f5daa2017-02-12 12:34:03 -07003031 start = 0;
3032 while (loc_read[start] != '\0') {
3033 while (loc_read[start] == PATH_SEPARATOR) {
3034 start++;
3035 }
3036 stop = start;
3037 while (loc_read[stop] != PATH_SEPARATOR && loc_read[stop] != '\0') {
3038 stop++;
3039 }
3040 const size_t s = stop - start;
3041 if (s) {
3042 memcpy(loc_write, &loc_read[start], s);
Benjamin Saunders31a48012017-01-29 14:49:54 -08003043 loc_write += s;
3044 memcpy(loc_write, relative_location, rel_size);
3045 loc_write += rel_size;
3046 *loc_write++ = PATH_SEPARATOR;
Karl Schultz52f5daa2017-02-12 12:34:03 -07003047 start = stop;
Benjamin Saunders31a48012017-01-29 14:49:54 -08003048 }
3049 }
Karl Schultz52f5daa2017-02-12 12:34:03 -07003050
Benjamin Saunders31a48012017-01-29 14:49:54 -08003051 --loc_write;
3052#else
3053 memcpy(loc_write, location, strlen(location));
3054 loc_write += strlen(location);
3055#endif
3056 assert(loc_write - loc < (ptrdiff_t)loc_size);
3057 *loc_write = '\0';
3058
Johannes van Waveren9bd805012015-10-28 11:45:00 -05003059#if defined(_WIN32)
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +02003060 VkResult regHKR_result = VK_SUCCESS;
3061
Slawomir Cygan8f9f2552017-08-09 11:36:52 +02003062 DWORD reg_size = 4096;
3063
Lenny Komowf7c09382017-08-31 16:35:08 -06003064 if (!strncmp(loc, DEFAULT_VK_DRIVERS_INFO, sizeof(DEFAULT_VK_DRIVERS_INFO))) {
3065 regHKR_result = loaderGetDeviceRegistryFiles(inst, &reg, &reg_size, LoaderPnpDriverRegistry());
3066 } else if (!strncmp(loc, DEFAULT_VK_ELAYERS_INFO, sizeof(DEFAULT_VK_ELAYERS_INFO))) {
3067 regHKR_result = loaderGetDeviceRegistryFiles(inst, &reg, &reg_size, LoaderPnpELayerRegistry());
3068 } else if (!strncmp(loc, DEFAULT_VK_ILAYERS_INFO, sizeof(DEFAULT_VK_ILAYERS_INFO))) {
3069 regHKR_result = loaderGetDeviceRegistryFiles(inst, &reg, &reg_size, LoaderPnpILayerRegistry());
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +02003070 }
3071
Slawomir Cygan8f9f2552017-08-09 11:36:52 +02003072 VkResult reg_result = loaderGetRegistryFiles(inst, loc, is_layer, &reg, &reg_size);
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +02003073
3074 if ((VK_SUCCESS != reg_result && VK_SUCCESS != regHKR_result) || NULL == reg) {
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003075 if (!is_layer) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003076 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3077 "loader_get_manifest_files: Registry lookup failed "
3078 "to get ICD manifest files. Possibly missing Vulkan"
3079 " driver?");
Slawomir Cygan9a2fa0e2017-07-03 16:47:52 +02003080 if (VK_SUCCESS == regHKR_result || VK_ERROR_OUT_OF_HOST_MEMORY == regHKR_result) {
3081 res = regHKR_result;
3082 } else if (VK_SUCCESS == reg_result || VK_ERROR_OUT_OF_HOST_MEMORY == reg_result) {
Mark Young2c84c0c2017-01-13 10:27:03 -07003083 res = reg_result;
3084 } else {
3085 res = VK_ERROR_INCOMPATIBLE_DRIVER;
3086 }
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003087 } else {
Mark Youngf8c20102016-11-07 16:26:17 -07003088 if (warn_if_not_present) {
Mark Young2c84c0c2017-01-13 10:27:03 -07003089 // This is only a warning for layers
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003090 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3091 "loader_get_manifest_files: Registry lookup failed "
3092 "to get layer manifest files.");
Mark Youngf8c20102016-11-07 16:26:17 -07003093 }
Mark Young2c84c0c2017-01-13 10:27:03 -07003094 if (reg_result == VK_ERROR_OUT_OF_HOST_MEMORY) {
3095 res = reg_result;
3096 } else {
3097 // Return success for now since it's not critical for layers
3098 res = VK_SUCCESS;
3099 }
Mark Lobodzinski510e20d2016-02-11 09:26:16 -07003100 }
Mark Young0ad83132016-06-30 13:02:42 -06003101 goto out;
Jon Ashburn24265ac2015-07-31 09:33:21 -06003102 }
Mark Young0ad83132016-06-30 13:02:42 -06003103 orig_loc = loc;
3104 loc = reg;
Jon Ashburnffad94d2015-06-30 14:46:22 -07003105#endif
Jon Ashburn23d36b12016-02-02 17:47:28 -07003106 } else {
Courtney Goeltzenleuchter7f5aafc2015-07-05 11:28:29 -06003107 loc = loader_stack_alloc(strlen(override) + 1);
Jon Ashburnffad94d2015-06-30 14:46:22 -07003108 if (loc == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003109 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3110 "loader_get_manifest_files: Failed to allocate space for "
3111 "override environment variable of length %d",
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003112 strlen(override) + 1);
Mark Young0ad83132016-06-30 13:02:42 -06003113 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3114 goto out;
Jon Ashburnffad94d2015-06-30 14:46:22 -07003115 }
3116 strcpy(loc, override);
3117 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003118
Liam Middlebrook9b14e892015-07-23 18:32:20 -07003119 // Print out the paths being searched if debugging is enabled
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003120 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Searching the following paths for manifest files: %s\n", loc);
Liam Middlebrook9b14e892015-07-23 18:32:20 -07003121
Jon Ashburn2077e382015-06-29 11:25:34 -06003122 file = loc;
3123 while (*file) {
3124 next_file = loader_get_next_path(file);
Jon Ashburnffad94d2015-06-30 14:46:22 -07003125 if (list_is_dirs) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003126 sysdir = opendir(file);
3127 name = NULL;
3128 if (sysdir) {
3129 dent = readdir(sysdir);
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003130 if (dent == NULL) break;
Jon Ashburn2077e382015-06-29 11:25:34 -06003131 name = &(dent->d_name[0]);
3132 loader_get_fullpath(name, file, sizeof(full_path), full_path);
3133 name = full_path;
3134 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07003135 } else {
Johannes van Waveren9bd805012015-10-28 11:45:00 -05003136#if defined(_WIN32)
3137 name = file;
3138#else
Jon Ashburnffad94d2015-06-30 14:46:22 -07003139 // only Linux has relative paths
Jon Ashburn2077e382015-06-29 11:25:34 -06003140 char *dir;
3141 // make a copy of location so it isn't modified
Jason Ekstrandcc7550e2015-10-10 08:33:37 -07003142 dir = loader_stack_alloc(strlen(loc) + 1);
Jon Ashburn2077e382015-06-29 11:25:34 -06003143 if (dir == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003144 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3145 "loader_get_manifest_files: Failed to allocate "
3146 "space for relative location path length %d",
Mark Youngb6399312017-01-10 14:22:15 -07003147 strlen(loc) + 1);
Mark Young0ad83132016-06-30 13:02:42 -06003148 goto out;
Jon Ashburn2077e382015-06-29 11:25:34 -06003149 }
Jason Ekstrandcc7550e2015-10-10 08:33:37 -07003150 strcpy(dir, loc);
Jon Ashburn2077e382015-06-29 11:25:34 -06003151
3152 loader_get_fullpath(file, dir, sizeof(full_path), full_path);
3153
3154 name = full_path;
Jon Ashburnffad94d2015-06-30 14:46:22 -07003155#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06003156 }
3157 while (name) {
Mark Young0f183a82017-02-28 09:58:04 -07003158 // Look for files ending with ".json" suffix
Jon Ashburn23d36b12016-02-02 17:47:28 -07003159 uint32_t nlen = (uint32_t)strlen(name);
3160 const char *suf = name + nlen - 5;
Lenny Komow408e0bd2017-08-09 16:01:59 -06003161
3162 // Check if the file is already present
3163 bool file_already_loaded = false;
3164 for (uint32_t i = 0; i < out_files->count; ++i) {
3165 if (!strcmp(out_files->filename_list[i], name)) {
3166 file_already_loaded = true;
3167 }
3168 }
3169
3170 if (!file_already_loaded && (nlen > 5) && !strncmp(suf, ".json", 5)) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003171 if (out_files->count == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003172 out_files->filename_list =
3173 loader_instance_heap_alloc(inst, alloced_count * sizeof(char *), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Mark Youngbb3a29c2017-05-19 12:29:43 -06003174 if (NULL == out_files->filename_list) {
3175 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3176 "loader_get_manifest_files: Failed to allocate space for manifest file name list");
3177 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3178 goto out;
3179 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07003180 } else if (out_files->count == alloced_count) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06003181 void *new_ptr =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003182 loader_instance_heap_realloc(inst, out_files->filename_list, alloced_count * sizeof(char *),
3183 alloced_count * sizeof(char *) * 2, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Mark Youngbb3a29c2017-05-19 12:29:43 -06003184 if (NULL == new_ptr) {
3185 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3186 "loader_get_manifest_files: Failed to reallocate space for manifest file name list");
3187 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3188 goto out;
3189 }
3190 out_files->filename_list = new_ptr;
Jon Ashburn23d36b12016-02-02 17:47:28 -07003191 alloced_count *= 2;
Jon Ashburn2077e382015-06-29 11:25:34 -06003192 }
Mark Young0ad83132016-06-30 13:02:42 -06003193 out_files->filename_list[out_files->count] =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003194 loader_instance_heap_alloc(inst, strlen(name) + 1, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
Jon Ashburn23d36b12016-02-02 17:47:28 -07003195 if (out_files->filename_list[out_files->count] == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003196 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3197 "loader_get_manifest_files: Failed to allocate "
3198 "space for manifest file %d list",
Mark Youngb6399312017-01-10 14:22:15 -07003199 out_files->count);
Mark Young0ad83132016-06-30 13:02:42 -06003200 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3201 goto out;
Jon Ashburn23d36b12016-02-02 17:47:28 -07003202 }
3203 strcpy(out_files->filename_list[out_files->count], name);
3204 out_files->count++;
Lenny Komow408e0bd2017-08-09 16:01:59 -06003205 } else if(file_already_loaded) {
3206 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3207 "Skipping manifest file %s - The file has already been read once", name);
Jon Ashburn23d36b12016-02-02 17:47:28 -07003208 } else if (!list_is_dirs) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003209 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, "Skipping manifest file %s, file name must end in .json",
3210 name);
Jon Ashburn23d36b12016-02-02 17:47:28 -07003211 }
3212 if (list_is_dirs) {
3213 dent = readdir(sysdir);
Mark Young0ad83132016-06-30 13:02:42 -06003214 if (dent == NULL) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003215 break;
Mark Young0ad83132016-06-30 13:02:42 -06003216 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07003217 name = &(dent->d_name[0]);
3218 loader_get_fullpath(name, file, sizeof(full_path), full_path);
3219 name = full_path;
3220 } else {
3221 break;
3222 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003223 }
Mark Young0ad83132016-06-30 13:02:42 -06003224 if (sysdir) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003225 closedir(sysdir);
Mark Young0ad83132016-06-30 13:02:42 -06003226 sysdir = NULL;
3227 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003228 file = next_file;
Jon Ashburn67e262e2016-02-18 12:45:39 -07003229#if !defined(_WIN32)
Benjamin Saunders31a48012017-01-29 14:49:54 -08003230 if (relative_location != NULL && (next_file == NULL || *next_file == '\0') && override == NULL) {
Mark Youngd8c6b692017-03-09 11:39:41 -07003231 char *xdgdatahome = loader_secure_getenv("XDG_DATA_HOME", inst);
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003232 size_t len;
3233 if (xdgdatahome != NULL) {
Mark Young6ef95f42017-02-17 09:02:23 -07003234 size_t alloc_len = strlen(xdgdatahome) + 2 + strlen(relative_location);
3235 char *home_loc = loader_stack_alloc(alloc_len);
Jon Ashburn67e262e2016-02-18 12:45:39 -07003236 if (home_loc == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003237 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3238 "loader_get_manifest_files: Failed to allocate "
3239 "space for manifest file XDG Home location");
Mark Young0ad83132016-06-30 13:02:42 -06003240 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3241 goto out;
Jon Ashburn67e262e2016-02-18 12:45:39 -07003242 }
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003243 strcpy(home_loc, xdgdatahome);
Jon Ashburn67e262e2016-02-18 12:45:39 -07003244 // Add directory separator if needed
Benjamin Saunders31a48012017-01-29 14:49:54 -08003245 if (relative_location[0] != DIRECTORY_SYMBOL) {
Jon Ashburn67e262e2016-02-18 12:45:39 -07003246 len = strlen(home_loc);
3247 home_loc[len] = DIRECTORY_SYMBOL;
Jon Ashburn1530c342016-02-26 13:14:27 -07003248 home_loc[len + 1] = '\0';
Jon Ashburn67e262e2016-02-18 12:45:39 -07003249 }
Mark Young6ef95f42017-02-17 09:02:23 -07003250 strncat(home_loc, relative_location, alloc_len);
Jon Ashburn67e262e2016-02-18 12:45:39 -07003251 file = home_loc;
3252 next_file = loader_get_next_path(file);
Benjamin Saunders31a48012017-01-29 14:49:54 -08003253 relative_location = NULL;
Jon Ashburn67e262e2016-02-18 12:45:39 -07003254
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003255 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Searching the following path for manifest files: %s\n",
3256 home_loc);
Jon Ashburn67e262e2016-02-18 12:45:39 -07003257 list_is_dirs = true;
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003258
3259 } else {
Mark Youngd8c6b692017-03-09 11:39:41 -07003260 char *home = loader_secure_getenv("HOME", inst);
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003261 if (home != NULL) {
Mark Young6ef95f42017-02-17 09:02:23 -07003262 size_t alloc_len = strlen(home) + 16 + strlen(relative_location);
3263 char *home_loc = loader_stack_alloc(alloc_len);
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003264 if (home_loc == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003265 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3266 "loader_get_manifest_files: Failed to allocate "
3267 "space for manifest file Home location");
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003268 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3269 goto out;
3270 }
Mark Young6ef95f42017-02-17 09:02:23 -07003271 strncpy(home_loc, home, alloc_len);
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003272
3273 len = strlen(home);
3274 if (home[len] != DIRECTORY_SYMBOL) {
3275 home_loc[len] = DIRECTORY_SYMBOL;
3276 home_loc[len + 1] = '\0';
3277 }
Mark Young6ef95f42017-02-17 09:02:23 -07003278 strncat(home_loc, ".local/share", alloc_len);
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003279
Benjamin Saunders31a48012017-01-29 14:49:54 -08003280 if (relative_location[0] != DIRECTORY_SYMBOL) {
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003281 len = strlen(home_loc);
3282 home_loc[len] = DIRECTORY_SYMBOL;
3283 home_loc[len + 1] = '\0';
3284 }
Mark Young6ef95f42017-02-17 09:02:23 -07003285 strncat(home_loc, relative_location, alloc_len);
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003286 file = home_loc;
3287 next_file = loader_get_next_path(file);
Benjamin Saunders31a48012017-01-29 14:49:54 -08003288 relative_location = NULL;
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003289
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003290 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Searching the following path for manifest files: %s\n",
3291 home_loc);
John Drinkwater9ac3f4f2016-08-01 17:00:00 +01003292 list_is_dirs = true;
3293 } else {
3294 // without knowing HOME, we just.. give up
3295 }
Jon Ashburn67e262e2016-02-18 12:45:39 -07003296 }
3297 }
3298#endif
Jon Ashburn2077e382015-06-29 11:25:34 -06003299 }
Mark Young0ad83132016-06-30 13:02:42 -06003300
3301out:
3302 if (VK_SUCCESS != res && NULL != out_files->filename_list) {
3303 for (uint32_t remove = 0; remove < out_files->count; remove++) {
3304 loader_instance_heap_free(inst, out_files->filename_list[remove]);
3305 }
3306 loader_instance_heap_free(inst, out_files->filename_list);
3307 out_files->count = 0;
3308 out_files->filename_list = NULL;
3309 }
3310
3311 if (NULL != sysdir) {
3312 closedir(sysdir);
3313 }
3314
Frank Henigmanb1c27cb2016-11-24 20:02:09 -05003315 if (override_getenv != NULL) {
3316 loader_free_getenv(override_getenv, inst);
3317 }
3318
Mark Young0ad83132016-06-30 13:02:42 -06003319 if (NULL != reg && reg != orig_loc) {
3320 loader_instance_heap_free(inst, reg);
3321 }
3322 return res;
Jon Ashburn2077e382015-06-29 11:25:34 -06003323}
3324
Jon Ashburn23d36b12016-02-02 17:47:28 -07003325void loader_init_icd_lib_list() {}
Jon Ashburn8810c5f2015-08-18 18:04:47 -06003326
Jon Ashburn23d36b12016-02-02 17:47:28 -07003327void loader_destroy_icd_lib_list() {}
Mark Young0f183a82017-02-28 09:58:04 -07003328
3329// Try to find the Vulkan ICD driver(s).
3330//
3331// This function scans the default system loader path(s) or path
3332// specified by the \c VK_ICD_FILENAMES environment variable in
3333// order to find loadable VK ICDs manifest files. From these
3334// manifest files it finds the ICD libraries.
3335//
3336// \returns
3337// Vulkan result
3338// (on result == VK_SUCCESS) a list of icds that were discovered
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003339VkResult loader_icd_scan(const struct loader_instance *inst, struct loader_icd_tramp_list *icd_tramp_list) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003340 char *file_str;
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003341 uint16_t file_major_vers = 0;
3342 uint16_t file_minor_vers = 0;
3343 uint16_t file_patch_vers = 0;
3344 char *vers_tok;
Jon Ashburn2077e382015-06-29 11:25:34 -06003345 struct loader_manifest_files manifest_files;
Mark Young0ad83132016-06-30 13:02:42 -06003346 VkResult res = VK_SUCCESS;
3347 bool lockedMutex = false;
3348 cJSON *json = NULL;
Mark Young3a587792016-08-19 15:25:08 -06003349 uint32_t num_good_icds = 0;
Jon Ashburn2077e382015-06-29 11:25:34 -06003350
Mark Young0ad83132016-06-30 13:02:42 -06003351 memset(&manifest_files, 0, sizeof(struct loader_manifest_files));
3352
Mark Young0153e0b2016-11-03 14:27:13 -06003353 res = loader_scanned_icd_init(inst, icd_tramp_list);
Mark Young0ad83132016-06-30 13:02:42 -06003354 if (VK_SUCCESS != res) {
3355 goto out;
3356 }
3357
Jon Ashburn2077e382015-06-29 11:25:34 -06003358 // Get a list of manifest files for ICDs
Benjamin Saunders31a48012017-01-29 14:49:54 -08003359 res = loader_get_manifest_files(inst, "VK_ICD_FILENAMES", NULL, false, true, DEFAULT_VK_DRIVERS_INFO, RELATIVE_VK_DRIVERS_INFO,
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003360 &manifest_files);
Mark Young0ad83132016-06-30 13:02:42 -06003361 if (VK_SUCCESS != res || manifest_files.count == 0) {
3362 goto out;
3363 }
Mark Youngf2079b92017-05-02 10:49:46 -06003364
Jon Ashburn6461ef22015-09-22 13:11:00 -06003365 loader_platform_thread_lock_mutex(&loader_json_lock);
Mark Young0ad83132016-06-30 13:02:42 -06003366 lockedMutex = true;
Jon Ashburn2077e382015-06-29 11:25:34 -06003367 for (uint32_t i = 0; i < manifest_files.count; i++) {
3368 file_str = manifest_files.filename_list[i];
Mark Young0ad83132016-06-30 13:02:42 -06003369 if (file_str == NULL) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003370 continue;
Mark Young0ad83132016-06-30 13:02:42 -06003371 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003372
Mark Youngdcd5f7e2017-04-25 10:35:54 -06003373 VkResult temp_res = loader_get_json(inst, file_str, &json);
3374 if (NULL == json || temp_res != VK_SUCCESS) {
Mark Youngd66edd52017-03-10 17:31:18 -07003375 if (NULL != json) {
3376 cJSON_Delete(json);
3377 json = NULL;
3378 }
Mark Youngdcd5f7e2017-04-25 10:35:54 -06003379 // If we haven't already found an ICD, copy this result to
3380 // the returned result.
3381 if (num_good_icds == 0) {
3382 res = temp_res;
3383 }
3384 if (temp_res == VK_ERROR_OUT_OF_HOST_MEMORY) {
Mark Youngd66edd52017-03-10 17:31:18 -07003385 break;
3386 } else {
3387 continue;
3388 }
Mark Young0ad83132016-06-30 13:02:42 -06003389 }
Mark Youngdcd5f7e2017-04-25 10:35:54 -06003390 res = temp_res;
Mark Young3a587792016-08-19 15:25:08 -06003391
Jon Ashburn005617f2015-11-17 17:35:40 -07003392 cJSON *item, *itemICD;
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003393 item = cJSON_GetObjectItem(json, "file_format_version");
Jon Ashburn6461ef22015-09-22 13:11:00 -06003394 if (item == NULL) {
Mark Young3a587792016-08-19 15:25:08 -06003395 if (num_good_icds == 0) {
3396 res = VK_ERROR_INITIALIZATION_FAILED;
3397 }
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003398 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3399 "loader_icd_scan: ICD JSON %s does not have a"
3400 " \'file_format_version\' field. Skipping ICD JSON.",
Mark Youngb6399312017-01-10 14:22:15 -07003401 file_str);
Derrick Owens62e16ef2016-09-09 15:49:07 -04003402 cJSON_Delete(json);
3403 json = NULL;
Mark Young3a587792016-08-19 15:25:08 -06003404 continue;
Jon Ashburn6461ef22015-09-22 13:11:00 -06003405 }
Mark Youngd66edd52017-03-10 17:31:18 -07003406
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003407 char *file_vers = cJSON_Print(item);
Mark Young0ad83132016-06-30 13:02:42 -06003408 if (NULL == file_vers) {
Mark Youngd66edd52017-03-10 17:31:18 -07003409 // Only reason the print can fail is if there was an allocation issue
Mark Young3a587792016-08-19 15:25:08 -06003410 if (num_good_icds == 0) {
3411 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3412 }
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003413 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3414 "loader_icd_scan: Failed retrieving ICD JSON %s"
3415 " \'file_format_version\' field. Skipping ICD JSON",
Mark Youngb6399312017-01-10 14:22:15 -07003416 file_str);
Derrick Owenscd92b8b2016-09-09 15:45:13 -04003417 cJSON_Delete(json);
3418 json = NULL;
Mark Young3a587792016-08-19 15:25:08 -06003419 continue;
Mark Young0ad83132016-06-30 13:02:42 -06003420 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003421 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Found ICD manifest file %s, version %s", file_str, file_vers);
Mark Youngd66edd52017-03-10 17:31:18 -07003422
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003423 // Get the major/minor/and patch as integers for easier comparison
3424 vers_tok = strtok(file_vers, ".\"\n\r");
3425 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04003426 file_major_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003427 vers_tok = strtok(NULL, ".\"\n\r");
3428 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04003429 file_minor_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003430 vers_tok = strtok(NULL, ".\"\n\r");
3431 if (NULL != vers_tok) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04003432 file_patch_vers = (uint16_t)atoi(vers_tok);
Mark Youngc3a6d2e2016-06-13 14:49:53 -06003433 }
3434 }
3435 }
Mark Youngd66edd52017-03-10 17:31:18 -07003436
3437 if (file_major_vers != 1 || file_minor_vers != 0 || file_patch_vers > 1) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003438 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3439 "loader_icd_scan: Unexpected manifest file version "
3440 "(expected 1.0.0 or 1.0.1), may cause errors");
Mark Youngd66edd52017-03-10 17:31:18 -07003441 }
Mark Young0ad83132016-06-30 13:02:42 -06003442 cJSON_Free(file_vers);
Mark Youngd66edd52017-03-10 17:31:18 -07003443
Jon Ashburn005617f2015-11-17 17:35:40 -07003444 itemICD = cJSON_GetObjectItem(json, "ICD");
3445 if (itemICD != NULL) {
3446 item = cJSON_GetObjectItem(itemICD, "library_path");
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003447 if (item != NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003448 char *temp = cJSON_Print(item);
Jon Ashburn86251302015-08-25 16:48:24 -06003449 if (!temp || strlen(temp) == 0) {
Mark Young3a587792016-08-19 15:25:08 -06003450 if (num_good_icds == 0) {
3451 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3452 }
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003453 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3454 "loader_icd_scan: Failed retrieving ICD JSON %s"
3455 " \'library_path\' field. Skipping ICD JSON.",
Mark Youngb6399312017-01-10 14:22:15 -07003456 file_str);
Mark Young0ad83132016-06-30 13:02:42 -06003457 cJSON_Free(temp);
Jon Ashburn86251302015-08-25 16:48:24 -06003458 cJSON_Delete(json);
Mark Young0ad83132016-06-30 13:02:42 -06003459 json = NULL;
Jon Ashburn86251302015-08-25 16:48:24 -06003460 continue;
Jon Ashburn2077e382015-06-29 11:25:34 -06003461 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07003462 // strip out extra quotes
Jon Ashburn86251302015-08-25 16:48:24 -06003463 temp[strlen(temp) - 1] = '\0';
3464 char *library_path = loader_stack_alloc(strlen(temp) + 1);
Mark Young3a587792016-08-19 15:25:08 -06003465 if (NULL == library_path) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003466 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3467 "loader_icd_scan: Failed to allocate space for "
3468 "ICD JSON %s \'library_path\' value. Skipping "
3469 "ICD JSON.",
Mark Youngb6399312017-01-10 14:22:15 -07003470 file_str);
Mark Young3a587792016-08-19 15:25:08 -06003471 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3472 cJSON_Free(temp);
3473 cJSON_Delete(json);
3474 json = NULL;
3475 goto out;
3476 }
Jon Ashburn86251302015-08-25 16:48:24 -06003477 strcpy(library_path, &temp[1]);
Mark Young0ad83132016-06-30 13:02:42 -06003478 cJSON_Free(temp);
Mark Young3a587792016-08-19 15:25:08 -06003479 if (strlen(library_path) == 0) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003480 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3481 "loader_icd_scan: ICD JSON %s \'library_path\'"
3482 " field is empty. Skipping ICD JSON.",
Jon Ashburn23d36b12016-02-02 17:47:28 -07003483 file_str);
Jon Ashburn86251302015-08-25 16:48:24 -06003484 cJSON_Delete(json);
Mark Young0ad83132016-06-30 13:02:42 -06003485 json = NULL;
Jon Ashburn86251302015-08-25 16:48:24 -06003486 continue;
3487 }
Jamie Madill2fcbd152016-04-27 16:33:23 -04003488 char fullpath[MAX_STRING_SIZE];
Jon Ashburn86251302015-08-25 16:48:24 -06003489 // Print out the paths being searched if debugging is enabled
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003490 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Searching for ICD drivers named %s, using default dir %s",
3491 library_path, DEFAULT_VK_DRIVERS_PATH);
Daniel Dadap00b4aba2015-09-30 11:50:51 -05003492 if (loader_platform_is_path(library_path)) {
Jon Ashburn86251302015-08-25 16:48:24 -06003493 // a relative or absolute path
Daniel Dadap00b4aba2015-09-30 11:50:51 -05003494 char *name_copy = loader_stack_alloc(strlen(file_str) + 1);
3495 char *rel_base;
Jon Ashburn86251302015-08-25 16:48:24 -06003496 strcpy(name_copy, file_str);
3497 rel_base = loader_platform_dirname(name_copy);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003498 loader_expand_path(library_path, rel_base, sizeof(fullpath), fullpath);
Daniel Dadap00b4aba2015-09-30 11:50:51 -05003499 } else {
Jamie Madill2fcbd152016-04-27 16:33:23 -04003500 // a filename which is assumed in a system directory
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003501 loader_get_fullpath(library_path, DEFAULT_VK_DRIVERS_PATH, sizeof(fullpath), fullpath);
Jon Ashburn86251302015-08-25 16:48:24 -06003502 }
Jon Ashburn005617f2015-11-17 17:35:40 -07003503
3504 uint32_t vers = 0;
3505 item = cJSON_GetObjectItem(itemICD, "api_version");
3506 if (item != NULL) {
Jon Ashburn23d36b12016-02-02 17:47:28 -07003507 temp = cJSON_Print(item);
Mark Young0ad83132016-06-30 13:02:42 -06003508 if (NULL == temp) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003509 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3510 "loader_icd_scan: Failed retrieving ICD JSON %s"
3511 " \'api_version\' field. Skipping ICD JSON.",
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003512 file_str);
Mark Youngb6399312017-01-10 14:22:15 -07003513
Mark Young0ad83132016-06-30 13:02:42 -06003514 // Only reason the print can fail is if there was an
3515 // allocation issue
Mark Youngb6399312017-01-10 14:22:15 -07003516 if (num_good_icds == 0) {
3517 res = VK_ERROR_OUT_OF_HOST_MEMORY;
3518 }
3519
3520 cJSON_Free(temp);
3521 cJSON_Delete(json);
3522 json = NULL;
3523 continue;
Mark Young0ad83132016-06-30 13:02:42 -06003524 }
Jon Ashburn005617f2015-11-17 17:35:40 -07003525 vers = loader_make_version(temp);
Mark Young0ad83132016-06-30 13:02:42 -06003526 cJSON_Free(temp);
Mark Youngb6399312017-01-10 14:22:15 -07003527 } else {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003528 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3529 "loader_icd_scan: ICD JSON %s does not have an"
3530 " \'api_version\' field.",
Mark Youngb6399312017-01-10 14:22:15 -07003531 file_str);
Jon Ashburn005617f2015-11-17 17:35:40 -07003532 }
Mark Youngb6399312017-01-10 14:22:15 -07003533
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003534 res = loader_scanned_icd_add(inst, icd_tramp_list, fullpath, vers);
Mark Young3a587792016-08-19 15:25:08 -06003535 if (VK_SUCCESS != res) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003536 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3537 "loader_icd_scan: Failed to add ICD JSON %s. "
3538 " Skipping ICD JSON.",
Mark Youngb6399312017-01-10 14:22:15 -07003539 fullpath);
Mark Youngd66edd52017-03-10 17:31:18 -07003540 cJSON_Delete(json);
3541 json = NULL;
Mark Youngb6399312017-01-10 14:22:15 -07003542 continue;
Mark Young3a587792016-08-19 15:25:08 -06003543 }
3544 num_good_icds++;
Mark Young0ad83132016-06-30 13:02:42 -06003545 } else {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003546 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3547 "loader_icd_scan: Failed to find \'library_path\' "
3548 "object in ICD JSON file %s. Skipping ICD JSON.",
Jon Ashburn23d36b12016-02-02 17:47:28 -07003549 file_str);
Mark Young0ad83132016-06-30 13:02:42 -06003550 }
3551 } else {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003552 loader_log(inst, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
3553 "loader_icd_scan: Can not find \'ICD\' object in ICD JSON "
3554 "file %s. Skipping ICD JSON",
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003555 file_str);
Mark Young0ad83132016-06-30 13:02:42 -06003556 }
Jon Ashburn2077e382015-06-29 11:25:34 -06003557
Mark Young0ad83132016-06-30 13:02:42 -06003558 cJSON_Delete(json);
3559 json = NULL;
3560 }
3561
3562out:
Mark Youngb6399312017-01-10 14:22:15 -07003563
Mark Young0ad83132016-06-30 13:02:42 -06003564 if (NULL != json) {
Jon Ashburn2077e382015-06-29 11:25:34 -06003565 cJSON_Delete(json);
3566 }
Mark Youngd66edd52017-03-10 17:31:18 -07003567
Mark Young0ad83132016-06-30 13:02:42 -06003568 if (NULL != manifest_files.filename_list) {
3569 for (uint32_t i = 0; i < manifest_files.count; i++) {
3570 if (NULL != manifest_files.filename_list[i]) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003571 loader_instance_heap_free(inst, manifest_files.filename_list[i]);
Mark Young0ad83132016-06-30 13:02:42 -06003572 }
3573 }
3574 loader_instance_heap_free(inst, manifest_files.filename_list);
3575 }
3576 if (lockedMutex) {
3577 loader_platform_thread_unlock_mutex(&loader_json_lock);
3578 }
Mark Youngd66edd52017-03-10 17:31:18 -07003579
Mark Young0ad83132016-06-30 13:02:42 -06003580 return res;
Chia-I Wu5f72d0f2014-08-01 11:21:23 +08003581}
3582
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003583void loader_layer_scan(const struct loader_instance *inst, struct loader_layer_list *instance_layers) {
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003584 char *file_str;
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003585 struct loader_manifest_files manifest_files[2]; // [0] = explicit, [1] = implicit
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003586 cJSON *json;
Jon Ashburn075ce432015-12-17 17:38:24 -07003587 uint32_t implicit;
Mark Young0ad83132016-06-30 13:02:42 -06003588 bool lockedMutex = false;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003589
Mark Young0ad83132016-06-30 13:02:42 -06003590 memset(manifest_files, 0, sizeof(struct loader_manifest_files) * 2);
3591
3592 // Get a list of manifest files for explicit layers
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003593 if (VK_SUCCESS != loader_get_manifest_files(inst, LAYERS_PATH_ENV, LAYERS_SOURCE_PATH, true, true, DEFAULT_VK_ELAYERS_INFO,
Benjamin Saunders31a48012017-01-29 14:49:54 -08003594 RELATIVE_VK_ELAYERS_INFO, &manifest_files[0])) {
Mark Young0ad83132016-06-30 13:02:42 -06003595 goto out;
3596 }
3597
3598 // Get a list of manifest files for any implicit layers
Jon Ashburn23d36b12016-02-02 17:47:28 -07003599 // Pass NULL for environment variable override - implicit layers are not
3600 // overridden by LAYERS_PATH_ENV
Benjamin Saunders31a48012017-01-29 14:49:54 -08003601 if (VK_SUCCESS != loader_get_manifest_files(inst, NULL, NULL, true, false, DEFAULT_VK_ILAYERS_INFO, RELATIVE_VK_ILAYERS_INFO,
Mark Youngf8c20102016-11-07 16:26:17 -07003602 &manifest_files[1])) {
Mark Young0ad83132016-06-30 13:02:42 -06003603 goto out;
3604 }
Jon Ashburn90c6a0e2015-06-04 15:30:58 -06003605
Mark Young0ad83132016-06-30 13:02:42 -06003606 // Make sure we have at least one layer, if not, go ahead and return
3607 if (manifest_files[0].count == 0 && manifest_files[1].count == 0) {
3608 goto out;
3609 }
3610
3611 // cleanup any previously scanned libraries
Jon Ashburne39a4f82015-08-28 13:38:21 -06003612 loader_delete_layer_properties(inst, instance_layers);
Jon Ashburnb2ef1372015-07-16 17:19:31 -06003613
Jon Ashburn6461ef22015-09-22 13:11:00 -06003614 loader_platform_thread_lock_mutex(&loader_json_lock);
Mark Young0ad83132016-06-30 13:02:42 -06003615 lockedMutex = true;
Jon Ashburn075ce432015-12-17 17:38:24 -07003616 for (implicit = 0; implicit < 2; implicit++) {
Jamie Madill970ebcf2016-07-06 11:19:42 -04003617 for (uint32_t i = 0; i < manifest_files[implicit].count; i++) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003618 file_str = manifest_files[implicit].filename_list[i];
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003619 if (file_str == NULL) continue;
Courtney Goeltzenleuchtera9e4af42015-06-01 14:49:17 -06003620
Jon Ashburn075ce432015-12-17 17:38:24 -07003621 // parse file into JSON struct
Mark Young3a587792016-08-19 15:25:08 -06003622 VkResult res = loader_get_json(inst, file_str, &json);
3623 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3624 break;
3625 } else if (VK_SUCCESS != res || NULL == json) {
Jon Ashburn075ce432015-12-17 17:38:24 -07003626 continue;
3627 }
3628
Mark Youngf2079b92017-05-02 10:49:46 -06003629 VkResult local_res = loader_add_layer_properties(inst, instance_layers, json, (implicit == 1), file_str);
Jon Ashburn075ce432015-12-17 17:38:24 -07003630 cJSON_Delete(json);
Mark Youngf2079b92017-05-02 10:49:46 -06003631
3632 if (VK_SUCCESS != local_res) {
3633 goto out;
3634 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003635 }
Jon Ashburn2d0c4bb2015-07-06 15:40:35 -06003636 }
Jon Ashburn86a527a2016-02-10 20:59:26 -07003637
Mark Youngf2079b92017-05-02 10:49:46 -06003638 // See if "VK_LAYER_LUNARG_standard_validation" already in list.
3639 bool found_std_val = false;
3640 for (uint32_t i = 0; i < instance_layers->count; i++) {
3641 struct loader_layer_properties *props = &instance_layers->list[i];
3642 if (strcmp(props->info.layerName, std_validation_str) == 0) {
3643 found_std_val = true;
3644 break;
3645 }
3646 }
3647
3648 // If we didn't find the VK_LAYER_LUNARG_standard_validation meta-layer in
3649 // the list, then we need to add it manually. This is likely because we're
3650 // dealing with a new loader, but an old layer folder.
3651 if (!found_std_val && !loader_add_legacy_std_val_layer(inst, instance_layers)) {
3652 goto out;
3653 }
3654
3655 // Verify any meta-layers in the list are valid and all the component layers are
3656 // actually present in the available layer list
3657 verify_all_meta_layers(inst, instance_layers);
Jon Ashburn86a527a2016-02-10 20:59:26 -07003658
Mark Young0ad83132016-06-30 13:02:42 -06003659out:
3660
3661 for (uint32_t manFile = 0; manFile < 2; manFile++) {
3662 if (NULL != manifest_files[manFile].filename_list) {
3663 for (uint32_t i = 0; i < manifest_files[manFile].count; i++) {
3664 if (NULL != manifest_files[manFile].filename_list[i]) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003665 loader_instance_heap_free(inst, manifest_files[manFile].filename_list[i]);
Mark Young0ad83132016-06-30 13:02:42 -06003666 }
3667 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003668 loader_instance_heap_free(inst, manifest_files[manFile].filename_list);
Mark Young0ad83132016-06-30 13:02:42 -06003669 }
3670 }
3671 if (lockedMutex) {
3672 loader_platform_thread_unlock_mutex(&loader_json_lock);
3673 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06003674}
3675
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003676void loader_implicit_layer_scan(const struct loader_instance *inst, struct loader_layer_list *instance_layers) {
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003677 char *file_str;
3678 struct loader_manifest_files manifest_files;
3679 cJSON *json;
3680 uint32_t i;
3681
3682 // Pass NULL for environment variable override - implicit layers are not
3683 // overridden by LAYERS_PATH_ENV
Mark Youngf2079b92017-05-02 10:49:46 -06003684 VkResult res = loader_get_manifest_files(inst, NULL, NULL, true, false, DEFAULT_VK_ILAYERS_INFO, RELATIVE_VK_ILAYERS_INFO,
3685 &manifest_files);
Mark Young0ad83132016-06-30 13:02:42 -06003686 if (VK_SUCCESS != res || manifest_files.count == 0) {
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003687 return;
3688 }
3689
Mark Young0f183a82017-02-28 09:58:04 -07003690 // Cleanup any previously scanned libraries
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003691 loader_delete_layer_properties(inst, instance_layers);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003692
3693 loader_platform_thread_lock_mutex(&loader_json_lock);
3694
3695 for (i = 0; i < manifest_files.count; i++) {
3696 file_str = manifest_files.filename_list[i];
3697 if (file_str == NULL) {
3698 continue;
3699 }
3700
3701 // parse file into JSON struct
Mark Young3a587792016-08-19 15:25:08 -06003702 res = loader_get_json(inst, file_str, &json);
3703 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3704 break;
3705 } else if (VK_SUCCESS != res || NULL == json) {
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003706 continue;
3707 }
3708
Mark Youngf2079b92017-05-02 10:49:46 -06003709 res = loader_add_layer_properties(inst, instance_layers, json, true, file_str);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003710
Mark Young0ad83132016-06-30 13:02:42 -06003711 loader_instance_heap_free(inst, file_str);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003712 cJSON_Delete(json);
Mark Youngf2079b92017-05-02 10:49:46 -06003713
3714 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
3715 break;
3716 }
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003717 }
Mark Young0ad83132016-06-30 13:02:42 -06003718 loader_instance_heap_free(inst, manifest_files.filename_list);
Jeremy Hayes3e2bd5a2016-04-01 11:40:26 -06003719 loader_platform_thread_unlock_mutex(&loader_json_lock);
3720}
3721
Jean-Francois Roybd7ceab2017-07-06 14:10:13 -07003722// Check if an implicit layer should be enabled.
3723bool loader_is_implicit_layer_enabled(const struct loader_instance *inst, const struct loader_layer_properties *prop) {
3724 bool enable = false;
3725 char *env_value = NULL;
3726
3727 // if no enable_environment variable is specified, this implicit layer
3728 // should always be enabled. Otherwise check if the variable is set
3729 if (prop->enable_env_var.name[0] == 0) {
3730 enable = true;
3731 } else {
3732 env_value = loader_secure_getenv(prop->enable_env_var.name, inst);
3733 if (env_value && !strcmp(prop->enable_env_var.value, env_value)) enable = true;
3734 loader_free_getenv(env_value, inst);
3735 }
3736
3737 // disable_environment has priority, i.e. if both enable and disable
3738 // environment variables are set, the layer is disabled. Implicit
3739 // layers are required to have a disable_environment variables
3740 env_value = loader_secure_getenv(prop->disable_env_var.name, inst);
3741 if (env_value && !strcmp(prop->disable_env_var.value, env_value)) enable = false;
3742 loader_free_getenv(env_value, inst);
3743
3744 return enable;
3745}
3746
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003747static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpdpa_instance_internal(VkInstance inst, const char *pName) {
Mark Young39389872017-01-19 21:10:49 -07003748 // inst is not wrapped
3749 if (inst == VK_NULL_HANDLE) {
3750 return NULL;
3751 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003752 VkLayerInstanceDispatchTable *disp_table = *(VkLayerInstanceDispatchTable **)inst;
Mark Young39389872017-01-19 21:10:49 -07003753 void *addr;
3754
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003755 if (disp_table == NULL) return NULL;
Mark Young39389872017-01-19 21:10:49 -07003756
3757 bool found_name;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003758 addr = loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
Mark Young39389872017-01-19 21:10:49 -07003759 if (found_name) {
3760 return addr;
3761 }
3762
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003763 if (loader_phys_dev_ext_gpa(loader_get_instance(inst), pName, true, NULL, &addr)) return addr;
Mark Young39389872017-01-19 21:10:49 -07003764
3765 // Don't call down the chain, this would be an infinite loop
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003766 loader_log(NULL, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, "loader_gpdpa_instance_internal() unrecognized name %s", pName);
Mark Young39389872017-01-19 21:10:49 -07003767 return NULL;
3768}
3769
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003770static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpdpa_instance_terminator(VkInstance inst, const char *pName) {
Mark Young39389872017-01-19 21:10:49 -07003771 // inst is not wrapped
3772 if (inst == VK_NULL_HANDLE) {
3773 return NULL;
3774 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003775 VkLayerInstanceDispatchTable *disp_table = *(VkLayerInstanceDispatchTable **)inst;
Mark Young39389872017-01-19 21:10:49 -07003776 void *addr;
3777
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003778 if (disp_table == NULL) return NULL;
Mark Young39389872017-01-19 21:10:49 -07003779
3780 bool found_name;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003781 addr = loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
Mark Young39389872017-01-19 21:10:49 -07003782 if (found_name) {
3783 return addr;
3784 }
3785
3786 // Get the terminator, but don't perform checking since it should already
3787 // have been setup if we get here.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003788 if (loader_phys_dev_ext_gpa(loader_get_instance(inst), pName, false, NULL, &addr)) {
Mark Young39389872017-01-19 21:10:49 -07003789 return addr;
3790 }
3791
3792 // Don't call down the chain, this would be an infinite loop
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003793 loader_log(NULL, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, "loader_gpdpa_instance_terminator() unrecognized name %s", pName);
Mark Young39389872017-01-19 21:10:49 -07003794 return NULL;
3795}
3796
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003797static VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpa_instance_internal(VkInstance inst, const char *pName) {
Mark Young39389872017-01-19 21:10:49 -07003798 if (!strcmp(pName, "vkGetInstanceProcAddr")) {
3799 return (PFN_vkVoidFunction)loader_gpa_instance_internal;
3800 }
3801 if (!strcmp(pName, "vk_layerGetPhysicalDeviceProcAddr")) {
3802 return (PFN_vkVoidFunction)loader_gpdpa_instance_terminator;
3803 }
3804 if (!strcmp(pName, "vkCreateInstance")) {
3805 return (PFN_vkVoidFunction)terminator_CreateInstance;
3806 }
3807 if (!strcmp(pName, "vkCreateDevice")) {
3808 return (PFN_vkVoidFunction)terminator_CreateDevice;
3809 }
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07003810
Jon Ashburn27cd5842015-05-12 17:26:48 -06003811 // inst is not wrapped
3812 if (inst == VK_NULL_HANDLE) {
3813 return NULL;
3814 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003815 VkLayerInstanceDispatchTable *disp_table = *(VkLayerInstanceDispatchTable **)inst;
Jon Ashburn27cd5842015-05-12 17:26:48 -06003816 void *addr;
3817
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003818 if (disp_table == NULL) return NULL;
Jon Ashburn27cd5842015-05-12 17:26:48 -06003819
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003820 bool found_name;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003821 addr = loader_lookup_instance_dispatch_table(disp_table, pName, &found_name);
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003822 if (found_name) {
Jon Ashburn27cd5842015-05-12 17:26:48 -06003823 return addr;
Jon Ashburn3d526cb2015-04-13 18:10:06 -06003824 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06003825
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003826 // Don't call down the chain, this would be an infinite loop
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003827 loader_log(NULL, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0, "loader_gpa_instance_internal() unrecognized name %s", pName);
Jon Ashburnc7d3e732016-03-08 09:30:30 -07003828 return NULL;
Jon Ashburn3d526cb2015-04-13 18:10:06 -06003829}
3830
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003831VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL loader_gpa_device_internal(VkDevice device, const char *pName) {
Jon Ashburncc407a22016-04-15 09:25:03 -06003832 struct loader_device *dev;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003833 struct loader_icd_term *icd_term = loader_get_icd_and_device(device, &dev, NULL);
Mark Young16573c72016-06-28 10:52:43 -06003834
Mark Young0f183a82017-02-28 09:58:04 -07003835 // Return this function if a layer above here is asking for the vkGetDeviceProcAddr.
3836 // This is so we can properly intercept any device commands needing a terminator.
3837 if (!strcmp(pName, "vkGetDeviceProcAddr")) {
3838 return (PFN_vkVoidFunction)loader_gpa_device_internal;
3839 }
3840
Mark Young65cb3662016-11-07 13:27:02 -07003841 // NOTE: Device Funcs needing Trampoline/Terminator.
3842 // Overrides for device functions needing a trampoline and
3843 // a terminator because certain device entry-points still need to go
3844 // through a terminator before hitting the ICD. This could be for
3845 // several reasons, but the main one is currently unwrapping an
3846 // object before passing the appropriate info along to the ICD.
3847 // This is why we also have to override the direct ICD call to
3848 // vkGetDeviceProcAddr to intercept those calls.
Mark Young0f183a82017-02-28 09:58:04 -07003849 PFN_vkVoidFunction addr = get_extension_device_proc_terminator(pName);
3850 if (NULL != addr) {
3851 return addr;
Mark Young16573c72016-06-28 10:52:43 -06003852 }
3853
Mark Young0f183a82017-02-28 09:58:04 -07003854 return icd_term->dispatch.GetDeviceProcAddr(device, pName);
Piers Daniell295fe402016-03-29 11:51:11 -06003855}
3856
Mark Young0f183a82017-02-28 09:58:04 -07003857// Initialize device_ext dispatch table entry as follows:
3858// If dev == NULL find all logical devices created within this instance and
3859// init the entry (given by idx) in the ext dispatch table.
3860// If dev != NULL only initialize the entry in the given dev's dispatch table.
3861// The initialization value is gotten by calling down the device chain with
3862// GDPA.
3863// If GDPA returns NULL then don't initialize the dispatch table entry.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003864static void loader_init_dispatch_dev_ext_entry(struct loader_instance *inst, struct loader_device *dev, uint32_t idx,
Jon Ashburn23d36b12016-02-02 17:47:28 -07003865 const char *funcName)
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003866
Jon Ashburn23d36b12016-02-02 17:47:28 -07003867{
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003868 void *gdpa_value;
3869 if (dev != NULL) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003870 gdpa_value = dev->loader_dispatch.core_dispatch.GetDeviceProcAddr(dev->chain_device, funcName);
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003871 if (gdpa_value != NULL) dev->loader_dispatch.ext_dispatch.dev_ext[idx] = (PFN_vkDevExt)gdpa_value;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003872 } else {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003873 for (struct loader_icd_term *icd_term = inst->icd_terms; icd_term != NULL; icd_term = icd_term->next) {
Mark Young0153e0b2016-11-03 14:27:13 -06003874 struct loader_device *ldev = icd_term->logical_device_list;
Karl Schultz2558bd32016-02-24 14:39:39 -07003875 while (ldev) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003876 gdpa_value = ldev->loader_dispatch.core_dispatch.GetDeviceProcAddr(ldev->chain_device, funcName);
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003877 if (gdpa_value != NULL) ldev->loader_dispatch.ext_dispatch.dev_ext[idx] = (PFN_vkDevExt)gdpa_value;
Karl Schultz2558bd32016-02-24 14:39:39 -07003878 ldev = ldev->next;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003879 }
3880 }
3881 }
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003882}
3883
Mark Young0f183a82017-02-28 09:58:04 -07003884// Find all dev extension in the hash table and initialize the dispatch table
3885// for dev for each of those extension entrypoints found in hash table.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003886void loader_init_dispatch_dev_ext(struct loader_instance *inst, struct loader_device *dev) {
Mark Young39389872017-01-19 21:10:49 -07003887 for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) {
3888 if (inst->dev_ext_disp_hash[i].func_name != NULL)
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003889 loader_init_dispatch_dev_ext_entry(inst, dev, i, inst->dev_ext_disp_hash[i].func_name);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003890 }
3891}
3892
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003893static bool loader_check_icds_for_dev_ext_address(struct loader_instance *inst, const char *funcName) {
Mark Young0153e0b2016-11-03 14:27:13 -06003894 struct loader_icd_term *icd_term;
3895 icd_term = inst->icd_terms;
3896 while (NULL != icd_term) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003897 if (icd_term->scanned_icd->GetInstanceProcAddr(icd_term->instance, funcName))
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003898 // this icd supports funcName
3899 return true;
Mark Young0153e0b2016-11-03 14:27:13 -06003900 icd_term = icd_term->next;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003901 }
3902
3903 return false;
3904}
3905
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003906static bool loader_check_layer_list_for_dev_ext_address(const struct loader_layer_list *const layers, const char *funcName) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07003907 // Iterate over the layers.
Jon Ashburncc407a22016-04-15 09:25:03 -06003908 for (uint32_t layer = 0; layer < layers->count; ++layer) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07003909 // Iterate over the extensions.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003910 const struct loader_device_extension_list *const extensions = &(layers->list[layer].device_extension_list);
3911 for (uint32_t extension = 0; extension < extensions->count; ++extension) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07003912 // Iterate over the entry points.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003913 const struct loader_dev_ext_props *const property = &(extensions->list[extension]);
3914 for (uint32_t entry = 0; entry < property->entrypoint_count; ++entry) {
Jon Ashburncc407a22016-04-15 09:25:03 -06003915 if (strcmp(property->entrypoints[entry], funcName) == 0) {
Jeremy Hayes1eb1f622016-03-03 16:03:03 -07003916 return true;
3917 }
3918 }
3919 }
3920 }
3921
3922 return false;
3923}
3924
Jon Ashburn23d36b12016-02-02 17:47:28 -07003925static void loader_free_dev_ext_table(struct loader_instance *inst) {
Mark Young39389872017-01-19 21:10:49 -07003926 for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) {
3927 loader_instance_heap_free(inst, inst->dev_ext_disp_hash[i].func_name);
3928 loader_instance_heap_free(inst, inst->dev_ext_disp_hash[i].list.index);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003929 }
Mark Young39389872017-01-19 21:10:49 -07003930 memset(inst->dev_ext_disp_hash, 0, sizeof(inst->dev_ext_disp_hash));
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003931}
3932
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003933static bool loader_add_dev_ext_table(struct loader_instance *inst, uint32_t *ptr_idx, const char *funcName) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003934 uint32_t i;
3935 uint32_t idx = *ptr_idx;
Mark Young39389872017-01-19 21:10:49 -07003936 struct loader_dispatch_hash_list *list = &inst->dev_ext_disp_hash[idx].list;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003937
Mark Young39389872017-01-19 21:10:49 -07003938 if (!inst->dev_ext_disp_hash[idx].func_name) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003939 // no entry here at this idx, so use it
3940 assert(list->capacity == 0);
Mark Young39389872017-01-19 21:10:49 -07003941 inst->dev_ext_disp_hash[idx].func_name =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003942 (char *)loader_instance_heap_alloc(inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young39389872017-01-19 21:10:49 -07003943 if (inst->dev_ext_disp_hash[idx].func_name == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003944 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3945 "loader_add_dev_ext_table: Failed to allocate memory "
3946 "for func_name %s",
Mark Youngb6399312017-01-10 14:22:15 -07003947 funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003948 return false;
3949 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003950 strncpy(inst->dev_ext_disp_hash[idx].func_name, funcName, strlen(funcName) + 1);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003951 return true;
3952 }
3953
3954 // check for enough capacity
3955 if (list->capacity == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003956 list->index = loader_instance_heap_alloc(inst, 8 * sizeof(*(list->index)), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003957 if (list->index == NULL) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06003958 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loader_add_dev_ext_table: Failed to allocate memory for list index",
Mark Youngb6399312017-01-10 14:22:15 -07003959 funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003960 return false;
3961 }
3962 list->capacity = 8 * sizeof(*(list->index));
3963 } else if (list->capacity < (list->count + 1) * sizeof(*(list->index))) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06003964 void *new_ptr = loader_instance_heap_realloc(inst, list->index, list->capacity, list->capacity * 2,
3965 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
3966 if (NULL == new_ptr) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003967 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngbb3a29c2017-05-19 12:29:43 -06003968 "loader_add_dev_ext_table: Failed to reallocate memory for list index", funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003969 return false;
3970 }
Mark Youngbb3a29c2017-05-19 12:29:43 -06003971 list->index = new_ptr;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003972 list->capacity *= 2;
3973 }
3974
Jon Ashburn23d36b12016-02-02 17:47:28 -07003975 // find an unused index in the hash table and use it
Mark Young39389872017-01-19 21:10:49 -07003976 i = (idx + 1) % MAX_NUM_UNKNOWN_EXTS;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003977 do {
Mark Young39389872017-01-19 21:10:49 -07003978 if (!inst->dev_ext_disp_hash[i].func_name) {
3979 assert(inst->dev_ext_disp_hash[i].list.capacity == 0);
3980 inst->dev_ext_disp_hash[i].func_name =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003981 (char *)loader_instance_heap_alloc(inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young39389872017-01-19 21:10:49 -07003982 if (inst->dev_ext_disp_hash[i].func_name == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003983 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3984 "loader_add_dev_ext_table: Failed to allocate memory "
3985 "for func_name %s",
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003986 funcName);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003987 return false;
3988 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07003989 strncpy(inst->dev_ext_disp_hash[i].func_name, funcName, strlen(funcName) + 1);
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003990 list->index[list->count] = i;
3991 list->count++;
3992 *ptr_idx = i;
3993 return true;
3994 }
Mark Young39389872017-01-19 21:10:49 -07003995 i = (i + 1) % MAX_NUM_UNKNOWN_EXTS;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07003996 } while (i != idx);
3997
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07003998 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
3999 "loader_add_dev_ext_table: Could not insert into hash table; is "
4000 "it full?");
Mark Youngb6399312017-01-10 14:22:15 -07004001
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004002 return false;
4003}
4004
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004005static bool loader_name_in_dev_ext_table(struct loader_instance *inst, uint32_t *idx, const char *funcName) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004006 uint32_t alt_idx;
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004007 if (inst->dev_ext_disp_hash[*idx].func_name && !strcmp(inst->dev_ext_disp_hash[*idx].func_name, funcName)) return true;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004008
4009 // funcName wasn't at the primary spot in the hash table
4010 // search the list of secondary locations (shallow search, not deep search)
Mark Young39389872017-01-19 21:10:49 -07004011 for (uint32_t i = 0; i < inst->dev_ext_disp_hash[*idx].list.count; i++) {
4012 alt_idx = inst->dev_ext_disp_hash[*idx].list.index[i];
4013 if (!strcmp(inst->dev_ext_disp_hash[*idx].func_name, funcName)) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004014 *idx = alt_idx;
4015 return true;
4016 }
4017 }
4018
4019 return false;
4020}
4021
Mark Young0f183a82017-02-28 09:58:04 -07004022// This function returns generic trampoline code address for unknown entry
4023// points.
4024// Presumably, these unknown entry points (as given by funcName) are device
4025// extension entrypoints. A hash table is used to keep a list of unknown entry
4026// points and their mapping to the device extension dispatch table
4027// (struct loader_dev_ext_dispatch_table).
4028// \returns
4029// For a given entry point string (funcName), if an existing mapping is found
4030// the
4031// trampoline address for that mapping is returned. Otherwise, this unknown
4032// entry point
4033// has not been seen yet. Next check if a layer or ICD supports it. If so then
4034// a
4035// new entry in the hash table is initialized and that trampoline address for
4036// the new entry is returned. Null is returned if the hash table is full or
4037// if no discovered layer or ICD returns a non-NULL GetProcAddr for it.
Jon Ashburn23d36b12016-02-02 17:47:28 -07004038void *loader_dev_ext_gpa(struct loader_instance *inst, const char *funcName) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004039 uint32_t idx;
4040 uint32_t seed = 0;
4041
Mark Young39389872017-01-19 21:10:49 -07004042 idx = murmurhash(funcName, strlen(funcName), seed) % MAX_NUM_UNKNOWN_EXTS;
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004043
4044 if (loader_name_in_dev_ext_table(inst, &idx, funcName))
4045 // found funcName already in hash
4046 return loader_get_dev_ext_trampoline(idx);
4047
4048 // Check if funcName is supported in either ICDs or a layer library
Mark Young39389872017-01-19 21:10:49 -07004049 if (!loader_check_icds_for_dev_ext_address(inst, funcName) &&
Lenny Komowb1685e02017-08-29 16:08:39 -06004050 !loader_check_layer_list_for_dev_ext_address(&inst->app_activated_layer_list, funcName)) {
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004051 // if support found in layers continue on
4052 return NULL;
4053 }
4054
4055 if (loader_add_dev_ext_table(inst, &idx, funcName)) {
4056 // successfully added new table entry
Mark Youngdee312c2017-03-08 13:38:35 -07004057 // init any dev dispatch table entries as needed
Jon Ashburnfc1031e2015-11-17 15:31:02 -07004058 loader_init_dispatch_dev_ext_entry(inst, NULL, idx, funcName);
4059 return loader_get_dev_ext_trampoline(idx);
4060 }
4061
4062 return NULL;
4063}
4064
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004065static bool loader_check_icds_for_phys_dev_ext_address(struct loader_instance *inst, const char *funcName) {
Mark Young39389872017-01-19 21:10:49 -07004066 struct loader_icd_term *icd_term;
4067 icd_term = inst->icd_terms;
4068 while (NULL != icd_term) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004069 if (icd_term->scanned_icd->interface_version >= MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION &&
4070 icd_term->scanned_icd->GetPhysicalDeviceProcAddr(icd_term->instance, funcName))
Mark Young39389872017-01-19 21:10:49 -07004071 // this icd supports funcName
4072 return true;
4073 icd_term = icd_term->next;
4074 }
4075
4076 return false;
4077}
4078
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004079static bool loader_check_layer_list_for_phys_dev_ext_address(struct loader_instance *inst, const char *funcName) {
Mark Young283fe1c2017-05-04 12:16:35 -06004080 struct loader_layer_properties *layer_prop_list = inst->expanded_activated_layer_list.list;
4081 for (uint32_t layer = 0; layer < inst->expanded_activated_layer_list.count; ++layer) {
Mark Young39389872017-01-19 21:10:49 -07004082 // If this layer supports the vk_layerGetPhysicalDeviceProcAddr, then call
4083 // it and see if it returns a valid pointer for this function name.
4084 if (layer_prop_list[layer].interface_version > 1) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004085 const struct loader_layer_functions *const functions = &(layer_prop_list[layer].functions);
Mark Young39389872017-01-19 21:10:49 -07004086 if (NULL != functions->get_physical_device_proc_addr &&
Tony Barbour55bd5392017-05-17 12:17:18 -06004087 NULL != functions->get_physical_device_proc_addr((VkInstance)inst->instance, funcName)) {
Mark Young39389872017-01-19 21:10:49 -07004088 return true;
4089 }
4090 }
4091 }
4092
4093 return false;
4094}
4095
Mark Young39389872017-01-19 21:10:49 -07004096static void loader_free_phys_dev_ext_table(struct loader_instance *inst) {
4097 for (uint32_t i = 0; i < MAX_NUM_UNKNOWN_EXTS; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004098 loader_instance_heap_free(inst, inst->phys_dev_ext_disp_hash[i].func_name);
4099 loader_instance_heap_free(inst, inst->phys_dev_ext_disp_hash[i].list.index);
Mark Young39389872017-01-19 21:10:49 -07004100 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004101 memset(inst->phys_dev_ext_disp_hash, 0, sizeof(inst->phys_dev_ext_disp_hash));
Mark Young39389872017-01-19 21:10:49 -07004102}
4103
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004104static bool loader_add_phys_dev_ext_table(struct loader_instance *inst, uint32_t *ptr_idx, const char *funcName) {
Mark Young39389872017-01-19 21:10:49 -07004105 uint32_t i;
4106 uint32_t idx = *ptr_idx;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004107 struct loader_dispatch_hash_list *list = &inst->phys_dev_ext_disp_hash[idx].list;
Mark Young39389872017-01-19 21:10:49 -07004108
4109 if (!inst->phys_dev_ext_disp_hash[idx].func_name) {
4110 // no entry here at this idx, so use it
4111 assert(list->capacity == 0);
4112 inst->phys_dev_ext_disp_hash[idx].func_name =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004113 (char *)loader_instance_heap_alloc(inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young39389872017-01-19 21:10:49 -07004114 if (inst->phys_dev_ext_disp_hash[idx].func_name == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004115 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4116 "loader_add_phys_dev_ext_table() can't allocate memory for "
4117 "func_name");
Mark Young39389872017-01-19 21:10:49 -07004118 return false;
4119 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004120 strncpy(inst->phys_dev_ext_disp_hash[idx].func_name, funcName, strlen(funcName) + 1);
Mark Young39389872017-01-19 21:10:49 -07004121 return true;
4122 }
4123
4124 // check for enough capacity
4125 if (list->capacity == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004126 list->index = loader_instance_heap_alloc(inst, 8 * sizeof(*(list->index)), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young39389872017-01-19 21:10:49 -07004127 if (list->index == NULL) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004128 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loader_add_phys_dev_ext_table() can't allocate list memory");
Mark Young39389872017-01-19 21:10:49 -07004129 return false;
4130 }
4131 list->capacity = 8 * sizeof(*(list->index));
4132 } else if (list->capacity < (list->count + 1) * sizeof(*(list->index))) {
Mark Youngbb3a29c2017-05-19 12:29:43 -06004133 void *new_ptr = loader_instance_heap_realloc(inst, list->index, list->capacity, list->capacity * 2,
4134 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
4135 if (NULL == new_ptr) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004136 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, "loader_add_phys_dev_ext_table() can't reallocate list memory");
Mark Young39389872017-01-19 21:10:49 -07004137 return false;
4138 }
Mark Youngbb3a29c2017-05-19 12:29:43 -06004139 list->index = new_ptr;
Mark Young39389872017-01-19 21:10:49 -07004140 list->capacity *= 2;
4141 }
4142
4143 // find an unused index in the hash table and use it
4144 i = (idx + 1) % MAX_NUM_UNKNOWN_EXTS;
4145 do {
4146 if (!inst->phys_dev_ext_disp_hash[i].func_name) {
4147 assert(inst->phys_dev_ext_disp_hash[i].list.capacity == 0);
4148 inst->phys_dev_ext_disp_hash[i].func_name =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004149 (char *)loader_instance_heap_alloc(inst, strlen(funcName) + 1, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young39389872017-01-19 21:10:49 -07004150 if (inst->phys_dev_ext_disp_hash[i].func_name == NULL) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004151 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngdee312c2017-03-08 13:38:35 -07004152 "loader_add_dev_ext_table() can't reallocate "
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004153 "func_name memory");
Mark Young39389872017-01-19 21:10:49 -07004154 return false;
4155 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004156 strncpy(inst->phys_dev_ext_disp_hash[i].func_name, funcName, strlen(funcName) + 1);
Mark Young39389872017-01-19 21:10:49 -07004157 list->index[list->count] = i;
4158 list->count++;
4159 *ptr_idx = i;
4160 return true;
4161 }
4162 i = (i + 1) % MAX_NUM_UNKNOWN_EXTS;
4163 } while (i != idx);
4164
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004165 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4166 "loader_add_phys_dev_ext_table() couldn't insert into hash table; is "
4167 "it full?");
Mark Young39389872017-01-19 21:10:49 -07004168 return false;
4169}
4170
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004171static bool loader_name_in_phys_dev_ext_table(struct loader_instance *inst, uint32_t *idx, const char *funcName) {
Mark Young39389872017-01-19 21:10:49 -07004172 uint32_t alt_idx;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004173 if (inst->phys_dev_ext_disp_hash[*idx].func_name && !strcmp(inst->phys_dev_ext_disp_hash[*idx].func_name, funcName))
Mark Young39389872017-01-19 21:10:49 -07004174 return true;
4175
4176 // funcName wasn't at the primary spot in the hash table
4177 // search the list of secondary locations (shallow search, not deep search)
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004178 for (uint32_t i = 0; i < inst->phys_dev_ext_disp_hash[*idx].list.count; i++) {
Mark Young39389872017-01-19 21:10:49 -07004179 alt_idx = inst->phys_dev_ext_disp_hash[*idx].list.index[i];
4180 if (!strcmp(inst->phys_dev_ext_disp_hash[*idx].func_name, funcName)) {
4181 *idx = alt_idx;
4182 return true;
4183 }
4184 }
4185
4186 return false;
4187}
4188
4189// This function returns a generic trampoline and/or terminator function
4190// address for any unknown physical device extension commands. A hash
4191// table is used to keep a list of unknown entry points and their
4192// mapping to the physical device extension dispatch table (struct
4193// loader_phys_dev_ext_dispatch_table).
4194// For a given entry point string (funcName), if an existing mapping is
4195// found, then the trampoline address for that mapping is returned in
4196// tramp_addr (if it is not NULL) and the terminator address for that
4197// mapping is returned in term_addr (if it is not NULL). Otherwise,
4198// this unknown entry point has not been seen yet.
4199// If it has not been seen before, and perform_checking is 'true',
4200// check if a layer or and ICD supports it. If so then a new entry in
4201// the hash table is initialized and the trampoline and/or terminator
4202// addresses are returned.
4203// Null is returned if the hash table is full or if no discovered layer or
4204// ICD returns a non-NULL GetProcAddr for it.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004205bool loader_phys_dev_ext_gpa(struct loader_instance *inst, const char *funcName, bool perform_checking, void **tramp_addr,
Mark Young39389872017-01-19 21:10:49 -07004206 void **term_addr) {
4207 uint32_t idx;
4208 uint32_t seed = 0;
4209 bool success = false;
4210
4211 if (inst == NULL) {
4212 goto out;
4213 }
4214
4215 if (NULL != tramp_addr) {
4216 *tramp_addr = NULL;
4217 }
4218 if (NULL != term_addr) {
4219 *term_addr = NULL;
4220 }
4221
4222 // We should always check to see if any ICD supports it.
4223 if (!loader_check_icds_for_phys_dev_ext_address(inst, funcName)) {
4224 // If we're not checking layers, or we are and it's not in a layer, just
4225 // return
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004226 if (!perform_checking || !loader_check_layer_list_for_phys_dev_ext_address(inst, funcName)) {
Mark Young39389872017-01-19 21:10:49 -07004227 goto out;
4228 }
4229 }
4230
4231 idx = murmurhash(funcName, strlen(funcName), seed) % MAX_NUM_UNKNOWN_EXTS;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004232 if (perform_checking && !loader_name_in_phys_dev_ext_table(inst, &idx, funcName)) {
Mark Young39389872017-01-19 21:10:49 -07004233 uint32_t i;
4234 bool added = false;
4235
4236 // Only need to add first one to get index in Instance. Others will use
4237 // the same index.
4238 if (!added && loader_add_phys_dev_ext_table(inst, &idx, funcName)) {
4239 added = true;
4240 }
4241
4242 // Setup the ICD function pointers
4243 struct loader_icd_term *icd_term = inst->icd_terms;
4244 while (NULL != icd_term) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004245 if (MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION <= icd_term->scanned_icd->interface_version &&
Mark Young39389872017-01-19 21:10:49 -07004246 NULL != icd_term->scanned_icd->GetPhysicalDeviceProcAddr) {
4247 icd_term->phys_dev_ext[idx] =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004248 (PFN_PhysDevExt)icd_term->scanned_icd->GetPhysicalDeviceProcAddr(icd_term->instance, funcName);
Mark Young39389872017-01-19 21:10:49 -07004249
4250 // Make sure we set the instance dispatch to point to the
4251 // loader's terminator now since we can at least handle it
4252 // in one ICD.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004253 inst->disp->phys_dev_ext[idx] = loader_get_phys_dev_ext_termin(idx);
Mark Young39389872017-01-19 21:10:49 -07004254 } else {
4255 icd_term->phys_dev_ext[idx] = NULL;
4256 }
4257
4258 icd_term = icd_term->next;
4259 }
4260
4261 // Now, search for the first layer attached and query using it to get
4262 // the first entry point.
Mark Young283fe1c2017-05-04 12:16:35 -06004263 for (i = 0; i < inst->expanded_activated_layer_list.count; i++) {
4264 struct loader_layer_properties *layer_prop = &inst->expanded_activated_layer_list.list[i];
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004265 if (layer_prop->interface_version > 1 && NULL != layer_prop->functions.get_physical_device_proc_addr) {
Mark Young39389872017-01-19 21:10:49 -07004266 inst->disp->phys_dev_ext[idx] =
Tony Barbour55bd5392017-05-17 12:17:18 -06004267 (PFN_PhysDevExt)layer_prop->functions.get_physical_device_proc_addr((VkInstance)inst->instance, funcName);
Mark Young39389872017-01-19 21:10:49 -07004268 if (NULL != inst->disp->phys_dev_ext[idx]) {
4269 break;
4270 }
4271 }
4272 }
4273 }
4274
4275 if (NULL != tramp_addr) {
4276 *tramp_addr = loader_get_phys_dev_ext_tramp(idx);
4277 }
4278
4279 if (NULL != term_addr) {
4280 *term_addr = loader_get_phys_dev_ext_termin(idx);
4281 }
4282
4283 success = true;
4284
4285out:
4286 return success;
4287}
4288
Jon Ashburn23d36b12016-02-02 17:47:28 -07004289struct loader_instance *loader_get_instance(const VkInstance instance) {
Mark Young0f183a82017-02-28 09:58:04 -07004290 // look up the loader_instance in our list by comparing dispatch tables, as
4291 // there is no guarantee the instance is still a loader_instance* after any
4292 // layers which wrap the instance object.
Jon Ashburne0e64572015-09-30 12:56:42 -06004293 const VkLayerInstanceDispatchTable *disp;
4294 struct loader_instance *ptr_instance = NULL;
Mark Young39389872017-01-19 21:10:49 -07004295 disp = loader_get_instance_layer_dispatch(instance);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004296 for (struct loader_instance *inst = loader.instances; inst; inst = inst->next) {
Mark Young39389872017-01-19 21:10:49 -07004297 if (&inst->disp->layer_inst_disp == disp) {
Jon Ashburne0e64572015-09-30 12:56:42 -06004298 ptr_instance = inst;
4299 break;
4300 }
4301 }
4302 return ptr_instance;
4303}
4304
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004305static loader_platform_dl_handle loader_open_layer_lib(const struct loader_instance *inst, const char *chain_type,
4306 struct loader_layer_properties *prop) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004307 if ((prop->lib_handle = loader_platform_open_library(prop->lib_name)) == NULL) {
Mark Youngb986b5f2017-05-16 09:48:55 -06004308 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0, loader_platform_open_library_error(prop->lib_name));
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004309 } else {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004310 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Loading layer library %s", prop->lib_name);
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004311 }
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004312
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004313 return prop->lib_handle;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004314}
4315
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004316static void loader_close_layer_lib(const struct loader_instance *inst, struct loader_layer_properties *prop) {
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004317 if (prop->lib_handle) {
4318 loader_platform_close_library(prop->lib_handle);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004319 loader_log(inst, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Unloading layer library %s", prop->lib_name);
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004320 prop->lib_handle = NULL;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06004321 }
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004322}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06004323
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004324void loader_deactivate_layers(const struct loader_instance *instance, struct loader_device *device,
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004325 struct loader_layer_list *list) {
Mark Young0f183a82017-02-28 09:58:04 -07004326 // Delete instance list of enabled layers and close any layer libraries
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004327 for (uint32_t i = 0; i < list->count; i++) {
4328 struct loader_layer_properties *layer_prop = &list->list[i];
Courtney Goeltzenleuchter80bfd0e2015-12-17 09:51:22 -07004329
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004330 loader_close_layer_lib(instance, layer_prop);
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07004331 }
Mark Young0ad83132016-06-30 13:02:42 -06004332 loader_destroy_layer_list(instance, device, list);
Jon Ashburnb8358052014-11-18 09:06:04 -07004333}
4334
Mark Young0f183a82017-02-28 09:58:04 -07004335// Go through the search_list and find any layers which match type. If layer
4336// type match is found in then add it to ext_list.
Mark Youngf2079b92017-05-02 10:49:46 -06004337static void loader_add_implicit_layers(const struct loader_instance *inst, struct loader_layer_list *target_list,
Mark Young283fe1c2017-05-04 12:16:35 -06004338 struct loader_layer_list *expanded_target_list,
Mark Youngf2079b92017-05-02 10:49:46 -06004339 const struct loader_layer_list *source_list) {
4340 for (uint32_t src_layer = 0; src_layer < source_list->count; src_layer++) {
4341 const struct loader_layer_properties *prop = &source_list->list[src_layer];
4342 if (0 == (prop->type_flags & VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER)) {
Mark Young283fe1c2017-05-04 12:16:35 -06004343 loader_add_implicit_layer(inst, prop, target_list, expanded_target_list, source_list);
Jon Ashburn0c26e712015-07-02 16:10:32 -06004344 }
4345 }
Jon Ashburn0c26e712015-07-02 16:10:32 -06004346}
4347
Mark Youngf2079b92017-05-02 10:49:46 -06004348// Get the layer name(s) from the env_name environment variable. If layer is found in
4349// search_list then add it to layer_list. But only add it to layer_list if type_flags matches.
Lenny Komow3b958392018-01-17 13:53:59 -07004350static void loader_add_env_layers(const struct loader_instance *inst, const enum layer_type_flags type_flags, const char *env_name,
Mark Young283fe1c2017-05-04 12:16:35 -06004351 struct loader_layer_list *target_list, struct loader_layer_list *expanded_target_list,
4352 const struct loader_layer_list *source_list) {
Jon Ashburneb6d5682015-07-02 14:10:53 -06004353 char *next, *name;
Mark Youngf2079b92017-05-02 10:49:46 -06004354 char *layer_env = loader_secure_getenv(env_name, inst);
4355 if (layer_env == NULL) {
4356 goto out;
Ian Elliott4470a302015-02-17 10:33:47 -07004357 }
Mark Youngf2079b92017-05-02 10:49:46 -06004358 name = loader_stack_alloc(strlen(layer_env) + 1);
Jon Ashburneb6d5682015-07-02 14:10:53 -06004359 if (name == NULL) {
Mark Youngf2079b92017-05-02 10:49:46 -06004360 goto out;
Ian Elliott4470a302015-02-17 10:33:47 -07004361 }
Mark Youngf2079b92017-05-02 10:49:46 -06004362 strcpy(name, layer_env);
Jon Ashburn38a497f2016-01-04 14:01:38 -07004363
Jon Ashburn23d36b12016-02-02 17:47:28 -07004364 while (name && *name) {
Jon Ashburneb6d5682015-07-02 14:10:53 -06004365 next = loader_get_next_path(name);
Mark Young283fe1c2017-05-04 12:16:35 -06004366 loader_find_layer_name_add_list(inst, name, type_flags, source_list, target_list, expanded_target_list);
Jon Ashburneb6d5682015-07-02 14:10:53 -06004367 name = next;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07004368 }
Jon Ashburnd38bfb12014-10-14 19:15:22 -06004369
Mark Youngf2079b92017-05-02 10:49:46 -06004370out:
4371
4372 if (layer_env != NULL) {
4373 loader_free_getenv(layer_env, inst);
4374 }
4375
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004376 return;
Jon Ashburnd38bfb12014-10-14 19:15:22 -06004377}
4378
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004379VkResult loader_enable_instance_layers(struct loader_instance *inst, const VkInstanceCreateInfo *pCreateInfo,
4380 const struct loader_layer_list *instance_layers) {
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06004381 VkResult err;
4382
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06004383 assert(inst && "Cannot have null instance");
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004384
Mark Young283fe1c2017-05-04 12:16:35 -06004385 if (!loader_init_layer_list(inst, &inst->app_activated_layer_list)) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004386 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4387 "loader_enable_instance_layers: Failed to initialize"
Mark Young283fe1c2017-05-04 12:16:35 -06004388 " application version of the layer list");
4389 return VK_ERROR_OUT_OF_HOST_MEMORY;
4390 }
4391
4392 if (!loader_init_layer_list(inst, &inst->expanded_activated_layer_list)) {
4393 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4394 "loader_enable_instance_layers: Failed to initialize"
4395 " expanded version of the layer list");
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06004396 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburnbd6c4882015-07-02 12:59:25 -06004397 }
4398
Mark Young0f183a82017-02-28 09:58:04 -07004399 // Add any implicit layers first
Mark Young283fe1c2017-05-04 12:16:35 -06004400 loader_add_implicit_layers(inst, &inst->app_activated_layer_list, &inst->expanded_activated_layer_list, instance_layers);
Jon Ashburn0c26e712015-07-02 16:10:32 -06004401
Mark Young0f183a82017-02-28 09:58:04 -07004402 // Add any layers specified via environment variable next
Lenny Komow3b958392018-01-17 13:53:59 -07004403 loader_add_env_layers(inst, VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER, ENABLED_LAYERS_ENV, &inst->app_activated_layer_list,
Mark Young283fe1c2017-05-04 12:16:35 -06004404 &inst->expanded_activated_layer_list, instance_layers);
Jon Ashburnbd6c4882015-07-02 12:59:25 -06004405
Mark Young0f183a82017-02-28 09:58:04 -07004406 // Add layers specified by the application
Mark Young283fe1c2017-05-04 12:16:35 -06004407 err = loader_add_layer_names_to_list(inst, &inst->app_activated_layer_list, &inst->expanded_activated_layer_list,
4408 pCreateInfo->enabledLayerCount, pCreateInfo->ppEnabledLayerNames, instance_layers);
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06004409
4410 return err;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004411}
4412
Mark Young39389872017-01-19 21:10:49 -07004413// Determine the layer interface version to use.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004414bool loader_get_layer_interface_version(PFN_vkNegotiateLoaderLayerInterfaceVersion fp_negotiate_layer_version,
4415 VkNegotiateLayerInterface *interface_struct) {
Mark Young39389872017-01-19 21:10:49 -07004416 memset(interface_struct, 0, sizeof(VkNegotiateLayerInterface));
Mark Young21aa6d62017-03-29 13:39:27 -06004417 interface_struct->sType = LAYER_NEGOTIATE_INTERFACE_STRUCT;
Mark Young39389872017-01-19 21:10:49 -07004418 interface_struct->loaderLayerInterfaceVersion = 1;
4419
4420 if (fp_negotiate_layer_version != NULL) {
4421 // Layer supports the negotiation API, so call it with the loader's
4422 // latest version supported
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004423 interface_struct->loaderLayerInterfaceVersion = CURRENT_LOADER_LAYER_INTERFACE_VERSION;
Mark Young39389872017-01-19 21:10:49 -07004424 VkResult result = fp_negotiate_layer_version(interface_struct);
4425
4426 if (result != VK_SUCCESS) {
4427 // Layer no longer supports the loader's latest interface version so
4428 // fail loading the Layer
4429 return false;
4430 }
4431 }
4432
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004433 if (interface_struct->loaderLayerInterfaceVersion < MIN_SUPPORTED_LOADER_LAYER_INTERFACE_VERSION) {
Mark Young39389872017-01-19 21:10:49 -07004434 // Loader no longer supports the layer's latest interface version so
4435 // fail loading the layer
4436 return false;
4437 }
4438
4439 return true;
4440}
4441
Mark Young0f183a82017-02-28 09:58:04 -07004442// Given the list of layers to activate in the loader_instance
4443// structure. This function will add a VkLayerInstanceCreateInfo
4444// structure to the VkInstanceCreateInfo.pNext pointer.
4445// Each activated layer will have it's own VkLayerInstanceLink
4446// structure that tells the layer what Get*ProcAddr to call to
4447// get function pointers to the next layer down.
4448// Once the chain info has been created this function will
4449// execute the CreateInstance call chain. Each layer will
4450// then have an opportunity in it's CreateInstance function
4451// to setup it's dispatch table when the lower layer returns
4452// successfully.
4453// Each layer can wrap or not-wrap the returned VkInstance object
4454// as it sees fit.
4455// The instance chain is terminated by a loader function
4456// that will call CreateInstance on all available ICD's and
4457// cache those VkInstance objects for future use.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004458VkResult loader_create_instance_chain(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator,
4459 struct loader_instance *inst, VkInstance *created_instance) {
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004460 uint32_t activated_layers = 0;
4461 VkLayerInstanceCreateInfo chain_info;
4462 VkLayerInstanceLink *layer_instance_link_info = NULL;
4463 VkInstanceCreateInfo loader_create_info;
4464 VkResult res;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004465
Mark Young39389872017-01-19 21:10:49 -07004466 PFN_vkGetInstanceProcAddr next_gipa = loader_gpa_instance_internal;
4467 PFN_vkGetInstanceProcAddr cur_gipa = loader_gpa_instance_internal;
4468 PFN_GetPhysicalDeviceProcAddr next_gpdpa = loader_gpdpa_instance_internal;
4469 PFN_GetPhysicalDeviceProcAddr cur_gpdpa = loader_gpdpa_instance_internal;
Jon Ashburn27cd5842015-05-12 17:26:48 -06004470
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004471 memcpy(&loader_create_info, pCreateInfo, sizeof(VkInstanceCreateInfo));
Jon Ashburn27cd5842015-05-12 17:26:48 -06004472
Mark Young283fe1c2017-05-04 12:16:35 -06004473 if (inst->expanded_activated_layer_list.count > 0) {
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004474 chain_info.u.pLayerInfo = NULL;
4475 chain_info.pNext = pCreateInfo->pNext;
4476 chain_info.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
4477 chain_info.function = VK_LAYER_LINK_INFO;
4478 loader_create_info.pNext = &chain_info;
Courtney Goeltzenleuchterf579fa62015-06-10 17:39:03 -06004479
Mark Young283fe1c2017-05-04 12:16:35 -06004480 layer_instance_link_info = loader_stack_alloc(sizeof(VkLayerInstanceLink) * inst->expanded_activated_layer_list.count);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004481 if (!layer_instance_link_info) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004482 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4483 "loader_create_instance_chain: Failed to alloc Instance"
4484 " objects for layer");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004485 return VK_ERROR_OUT_OF_HOST_MEMORY;
Jon Ashburn27cd5842015-05-12 17:26:48 -06004486 }
4487
Mark Young39389872017-01-19 21:10:49 -07004488 // Create instance chain of enabled layers
Mark Young283fe1c2017-05-04 12:16:35 -06004489 for (int32_t i = inst->expanded_activated_layer_list.count - 1; i >= 0; i--) {
4490 struct loader_layer_properties *layer_prop = &inst->expanded_activated_layer_list.list[i];
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004491 loader_platform_dl_handle lib_handle;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004492
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004493 lib_handle = loader_open_layer_lib(inst, "instance", layer_prop);
Mark Young39389872017-01-19 21:10:49 -07004494 if (!lib_handle) {
Courtney Goeltzenleuchter524b7e32016-01-14 16:06:06 -07004495 continue;
Mark Young39389872017-01-19 21:10:49 -07004496 }
4497
4498 if (NULL == layer_prop->functions.negotiate_layer_interface) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004499 PFN_vkNegotiateLoaderLayerInterfaceVersion negotiate_interface = NULL;
Mark Young39389872017-01-19 21:10:49 -07004500 bool functions_in_interface = false;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004501 if (strlen(layer_prop->functions.str_negotiate_interface) == 0) {
4502 negotiate_interface = (PFN_vkNegotiateLoaderLayerInterfaceVersion)loader_platform_get_proc_address(
4503 lib_handle, "vkNegotiateLoaderLayerInterfaceVersion");
Mark Young39389872017-01-19 21:10:49 -07004504 } else {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004505 negotiate_interface = (PFN_vkNegotiateLoaderLayerInterfaceVersion)loader_platform_get_proc_address(
4506 lib_handle, layer_prop->functions.str_negotiate_interface);
Mark Young39389872017-01-19 21:10:49 -07004507 }
4508
4509 // If we can negotiate an interface version, then we can also
4510 // get everything we need from the one function call, so try
4511 // that first, and see if we can get all the function pointers
4512 // necessary from that one call.
4513 if (NULL != negotiate_interface) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004514 layer_prop->functions.negotiate_layer_interface = negotiate_interface;
Mark Young39389872017-01-19 21:10:49 -07004515
4516 VkNegotiateLayerInterface interface_struct;
4517
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004518 if (loader_get_layer_interface_version(negotiate_interface, &interface_struct)) {
Mark Youngdee312c2017-03-08 13:38:35 -07004519 // Go ahead and set the properties version to the
Mark Young39389872017-01-19 21:10:49 -07004520 // correct value.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004521 layer_prop->interface_version = interface_struct.loaderLayerInterfaceVersion;
Mark Young39389872017-01-19 21:10:49 -07004522
4523 // If the interface is 2 or newer, we have access to the
4524 // new GetPhysicalDeviceProcAddr function, so grab it,
4525 // and the other necessary functions, from the
4526 // structure.
4527 if (interface_struct.loaderLayerInterfaceVersion > 1) {
4528 cur_gipa = interface_struct.pfnGetInstanceProcAddr;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004529 cur_gpdpa = interface_struct.pfnGetPhysicalDeviceProcAddr;
Mark Young39389872017-01-19 21:10:49 -07004530 if (cur_gipa != NULL) {
4531 // We've set the functions, so make sure we
4532 // don't do the unnecessary calls later.
4533 functions_in_interface = true;
4534 }
4535 }
4536 }
4537 }
4538
4539 if (!functions_in_interface) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004540 if ((cur_gipa = layer_prop->functions.get_instance_proc_addr) == NULL) {
Mark Young39389872017-01-19 21:10:49 -07004541 if (strlen(layer_prop->functions.str_gipa) == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004542 cur_gipa =
4543 (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
4544 layer_prop->functions.get_instance_proc_addr = cur_gipa;
Mark Young39389872017-01-19 21:10:49 -07004545 } else {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004546 cur_gipa = (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle,
4547 layer_prop->functions.str_gipa);
Mark Young39389872017-01-19 21:10:49 -07004548 }
4549
4550 if (NULL == cur_gipa) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004551 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4552 "loader_create_instance_chain: Failed to"
4553 " find \'vkGetInstanceProcAddr\' in "
4554 "layer %s",
Mark Young39389872017-01-19 21:10:49 -07004555 layer_prop->lib_name);
4556 continue;
4557 }
4558 }
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004559 }
4560 }
4561
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004562 layer_instance_link_info[activated_layers].pNext = chain_info.u.pLayerInfo;
4563 layer_instance_link_info[activated_layers].pfnNextGetInstanceProcAddr = next_gipa;
4564 layer_instance_link_info[activated_layers].pfnNextGetPhysicalDeviceProcAddr = next_gpdpa;
Mark Young39389872017-01-19 21:10:49 -07004565 next_gipa = cur_gipa;
4566 if (layer_prop->interface_version > 1 && cur_gpdpa != NULL) {
4567 layer_prop->functions.get_physical_device_proc_addr = cur_gpdpa;
4568 next_gpdpa = cur_gpdpa;
4569 }
4570
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004571 chain_info.u.pLayerInfo = &layer_instance_link_info[activated_layers];
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004572
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004573 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Insert instance layer %s (%s)", layer_prop->info.layerName,
4574 layer_prop->lib_name);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004575
4576 activated_layers++;
4577 }
Jon Ashburn27cd5842015-05-12 17:26:48 -06004578 }
4579
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004580 PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)next_gipa(*created_instance, "vkCreateInstance");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004581 if (fpCreateInstance) {
Jon Ashburnc3c58772016-03-29 11:16:01 -06004582 VkLayerInstanceCreateInfo create_info_disp;
4583
Jon Ashburncc407a22016-04-15 09:25:03 -06004584 create_info_disp.sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO;
Jon Ashburned8f2312016-03-31 10:52:22 -06004585 create_info_disp.function = VK_LOADER_DATA_CALLBACK;
Jon Ashburnc3c58772016-03-29 11:16:01 -06004586
4587 create_info_disp.u.pfnSetInstanceLoaderData = vkSetInstanceDispatch;
4588
4589 create_info_disp.pNext = loader_create_info.pNext;
4590 loader_create_info.pNext = &create_info_disp;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004591 res = fpCreateInstance(&loader_create_info, pAllocator, created_instance);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004592 } else {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004593 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4594 "loader_create_instance_chain: Failed to find "
4595 "\'vkCreateInstance\'");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004596 // Couldn't find CreateInstance function!
4597 res = VK_ERROR_INITIALIZATION_FAILED;
4598 }
4599
Mark Young39389872017-01-19 21:10:49 -07004600 if (res == VK_SUCCESS) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004601 loader_init_instance_core_dispatch_table(&inst->disp->layer_inst_disp, next_gipa, *created_instance);
Jon Ashburn4e8c4162016-03-08 15:21:30 -07004602 inst->instance = *created_instance;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004603 }
4604
4605 return res;
Jon Ashburn27cd5842015-05-12 17:26:48 -06004606}
4607
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004608void loader_activate_instance_layer_extensions(struct loader_instance *inst, VkInstance created_inst) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004609 loader_init_instance_extension_dispatch_table(&inst->disp->layer_inst_disp, inst->disp->layer_inst_disp.GetInstanceProcAddr,
4610 created_inst);
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06004611}
4612
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004613VkResult loader_create_device_chain(const struct loader_physical_device_tramp *pd, const VkDeviceCreateInfo *pCreateInfo,
4614 const VkAllocationCallbacks *pAllocator, const struct loader_instance *inst,
4615 struct loader_device *dev) {
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004616 uint32_t activated_layers = 0;
4617 VkLayerDeviceLink *layer_device_link_info;
4618 VkLayerDeviceCreateInfo chain_info;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004619 VkDeviceCreateInfo loader_create_info;
4620 VkResult res;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06004621
Jamie Madill35127872017-03-15 16:17:46 -04004622 PFN_vkGetDeviceProcAddr fpGDPA = NULL, nextGDPA = loader_gpa_device_internal;
4623 PFN_vkGetInstanceProcAddr fpGIPA = NULL, nextGIPA = loader_gpa_instance_internal;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06004624
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004625 memcpy(&loader_create_info, pCreateInfo, sizeof(VkDeviceCreateInfo));
4626
Mark Young0f183a82017-02-28 09:58:04 -07004627 // Before we continue, we need to find out if the KHX_device_group extension is in the enabled list. If it is, we then
4628 // need to look for the corresponding VkDeviceGroupDeviceCreateInfoKHX struct in the device list. This is because we
4629 // need to replace all the incoming physical device values (which are really loader trampoline physical device values)
4630 // with the layer/ICD version.
4631 if (inst->enabled_known_extensions.khx_device_group_creation == 1) {
4632 struct VkStructureHeader *pNext = (struct VkStructureHeader *)loader_create_info.pNext;
4633 struct VkStructureHeader *pPrev = (struct VkStructureHeader *)&loader_create_info;
4634 while (NULL != pNext) {
4635 if (VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHX == pNext->sType) {
4636 VkDeviceGroupDeviceCreateInfoKHX *cur_struct = (VkDeviceGroupDeviceCreateInfoKHX *)pNext;
4637 if (0 < cur_struct->physicalDeviceCount && NULL != cur_struct->pPhysicalDevices) {
4638 VkDeviceGroupDeviceCreateInfoKHX *temp_struct = loader_stack_alloc(sizeof(VkDeviceGroupDeviceCreateInfoKHX));
4639 VkPhysicalDevice *phys_dev_array = NULL;
4640 if (NULL == temp_struct) {
4641 return VK_ERROR_OUT_OF_HOST_MEMORY;
4642 }
4643 memcpy(temp_struct, cur_struct, sizeof(VkDeviceGroupDeviceCreateInfoKHX));
4644 phys_dev_array = loader_stack_alloc(sizeof(VkPhysicalDevice) * cur_struct->physicalDeviceCount);
4645 if (NULL == phys_dev_array) {
4646 return VK_ERROR_OUT_OF_HOST_MEMORY;
4647 }
4648
4649 // Before calling down, replace the incoming physical device values (which are really loader trampoline
4650 // physical devices) with the next layer (or possibly even the terminator) physical device values.
4651 struct loader_physical_device_tramp *cur_tramp;
4652 for (uint32_t phys_dev = 0; phys_dev < cur_struct->physicalDeviceCount; phys_dev++) {
4653 cur_tramp = (struct loader_physical_device_tramp *)cur_struct->pPhysicalDevices[phys_dev];
4654 phys_dev_array[phys_dev] = cur_tramp->phys_dev;
4655 }
4656 temp_struct->pPhysicalDevices = phys_dev_array;
4657
4658 // Replace the old struct in the pNext chain with this one.
4659 pPrev->pNext = (const void *)temp_struct;
4660 pNext = (struct VkStructureHeader *)(temp_struct);
4661 }
4662 break;
4663 }
4664
4665 pPrev = pNext;
4666 pNext = (struct VkStructureHeader *)(pPrev->pNext);
4667 }
4668 }
4669
Mark Young283fe1c2017-05-04 12:16:35 -06004670 layer_device_link_info = loader_stack_alloc(sizeof(VkLayerDeviceLink) * dev->expanded_activated_layer_list.count);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004671 if (!layer_device_link_info) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004672 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4673 "loader_create_device_chain: Failed to alloc Device objects"
4674 " for layer. Skipping Layer.");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004675 return VK_ERROR_OUT_OF_HOST_MEMORY;
David Pinedoa0a8a242015-06-24 15:29:18 -06004676 }
Jon Ashburn94e70492015-06-10 10:13:10 -06004677
Mark Young283fe1c2017-05-04 12:16:35 -06004678 if (dev->expanded_activated_layer_list.count > 0) {
Jon Ashburn72690f22016-03-29 12:52:13 -06004679 chain_info.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
4680 chain_info.function = VK_LAYER_LINK_INFO;
4681 chain_info.u.pLayerInfo = NULL;
Mark Young39389872017-01-19 21:10:49 -07004682 chain_info.pNext = loader_create_info.pNext;
Jon Ashburn72690f22016-03-29 12:52:13 -06004683 loader_create_info.pNext = &chain_info;
4684
Mark Young39389872017-01-19 21:10:49 -07004685 // Create instance chain of enabled layers
Mark Young283fe1c2017-05-04 12:16:35 -06004686 for (int32_t i = dev->expanded_activated_layer_list.count - 1; i >= 0; i--) {
4687 struct loader_layer_properties *layer_prop = &dev->expanded_activated_layer_list.list[i];
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004688 loader_platform_dl_handle lib_handle;
Mark Young39389872017-01-19 21:10:49 -07004689 bool functions_in_interface = false;
Courtney Goeltzenleuchterca173b82015-06-25 18:01:43 -06004690
Jon Ashburn4dc1d8a2016-04-20 13:21:17 -06004691 lib_handle = loader_open_layer_lib(inst, "device", layer_prop);
Mark Young39389872017-01-19 21:10:49 -07004692 if (!lib_handle) {
Courtney Goeltzenleuchter524b7e32016-01-14 16:06:06 -07004693 continue;
Jon Ashburn21c21ee2015-09-09 11:29:24 -06004694 }
Mark Young39389872017-01-19 21:10:49 -07004695
Mark Young0f183a82017-02-28 09:58:04 -07004696 // If we can negotiate an interface version, then we can also get everything we need from the one function
4697 // call, so try that first, and see if we can get all the function pointers necessary from that one call.
Mark Young39389872017-01-19 21:10:49 -07004698 if (NULL == layer_prop->functions.negotiate_layer_interface) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004699 PFN_vkNegotiateLoaderLayerInterfaceVersion negotiate_interface = NULL;
4700 if (strlen(layer_prop->functions.str_negotiate_interface) == 0) {
4701 negotiate_interface = (PFN_vkNegotiateLoaderLayerInterfaceVersion)loader_platform_get_proc_address(
4702 lib_handle, "vkNegotiateLoaderLayerInterfaceVersion");
Mark Young39389872017-01-19 21:10:49 -07004703 } else {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004704 negotiate_interface = (PFN_vkNegotiateLoaderLayerInterfaceVersion)loader_platform_get_proc_address(
4705 lib_handle, layer_prop->functions.str_negotiate_interface);
Mark Young39389872017-01-19 21:10:49 -07004706 }
4707
4708 if (NULL != negotiate_interface) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004709 layer_prop->functions.negotiate_layer_interface = negotiate_interface;
Mark Young39389872017-01-19 21:10:49 -07004710
4711 VkNegotiateLayerInterface interface_struct;
4712
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004713 if (loader_get_layer_interface_version(negotiate_interface, &interface_struct)) {
Mark Youngdee312c2017-03-08 13:38:35 -07004714 // Go ahead and set the properties version to the correct value.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004715 layer_prop->interface_version = interface_struct.loaderLayerInterfaceVersion;
Mark Young39389872017-01-19 21:10:49 -07004716
Mark Young0f183a82017-02-28 09:58:04 -07004717 // If the interface is 2 or newer, we have access to the new GetPhysicalDeviceProcAddr
4718 // function, so grab it, and the other necessary functions, from the structure.
Mark Young39389872017-01-19 21:10:49 -07004719 if (interface_struct.loaderLayerInterfaceVersion > 1) {
4720 fpGIPA = interface_struct.pfnGetInstanceProcAddr;
4721 fpGDPA = interface_struct.pfnGetDeviceProcAddr;
4722 if (fpGIPA != NULL && fpGDPA) {
4723 // We've set the functions, so make sure we
4724 // don't do the unnecessary calls later.
4725 functions_in_interface = true;
4726 }
4727 }
4728 }
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004729 }
4730 }
4731
Mark Young39389872017-01-19 21:10:49 -07004732 if (!functions_in_interface) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004733 if ((fpGIPA = layer_prop->functions.get_instance_proc_addr) == NULL) {
Mark Young39389872017-01-19 21:10:49 -07004734 if (strlen(layer_prop->functions.str_gipa) == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004735 fpGIPA = (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle, "vkGetInstanceProcAddr");
Mark Young39389872017-01-19 21:10:49 -07004736 layer_prop->functions.get_instance_proc_addr = fpGIPA;
4737 } else
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004738 fpGIPA =
4739 (PFN_vkGetInstanceProcAddr)loader_platform_get_proc_address(lib_handle, layer_prop->functions.str_gipa);
Mark Young39389872017-01-19 21:10:49 -07004740 if (!fpGIPA) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004741 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4742 "loader_create_device_chain: Failed to find "
4743 "\'vkGetInstanceProcAddr\' in layer %s. Skipping"
4744 " layer.",
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004745 layer_prop->lib_name);
Mark Young39389872017-01-19 21:10:49 -07004746 continue;
4747 }
4748 }
4749 if ((fpGDPA = layer_prop->functions.get_device_proc_addr) == NULL) {
4750 if (strlen(layer_prop->functions.str_gdpa) == 0) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004751 fpGDPA = (PFN_vkGetDeviceProcAddr)loader_platform_get_proc_address(lib_handle, "vkGetDeviceProcAddr");
Mark Young39389872017-01-19 21:10:49 -07004752 layer_prop->functions.get_device_proc_addr = fpGDPA;
4753 } else
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004754 fpGDPA =
4755 (PFN_vkGetDeviceProcAddr)loader_platform_get_proc_address(lib_handle, layer_prop->functions.str_gdpa);
Mark Young39389872017-01-19 21:10:49 -07004756 if (!fpGDPA) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004757 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Failed to find vkGetDeviceProcAddr in layer %s",
4758 layer_prop->lib_name);
Mark Young39389872017-01-19 21:10:49 -07004759 continue;
4760 }
4761 }
4762 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004763 layer_device_link_info[activated_layers].pNext = chain_info.u.pLayerInfo;
4764 layer_device_link_info[activated_layers].pfnNextGetInstanceProcAddr = nextGIPA;
4765 layer_device_link_info[activated_layers].pfnNextGetDeviceProcAddr = nextGDPA;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004766 chain_info.u.pLayerInfo = &layer_device_link_info[activated_layers];
4767 nextGIPA = fpGIPA;
4768 nextGDPA = fpGDPA;
4769
Lenny Komow7ddd4322017-10-16 15:03:37 -06004770 loader_log(inst, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0, "Inserted device layer %s (%s)", layer_prop->info.layerName,
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004771 layer_prop->lib_name);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004772
4773 activated_layers++;
Jon Ashburn94e70492015-06-10 10:13:10 -06004774 }
Jon Ashburn94e70492015-06-10 10:13:10 -06004775 }
4776
Jon Ashburncc407a22016-04-15 09:25:03 -06004777 VkDevice created_device = (VkDevice)dev;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004778 PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)nextGIPA(inst->instance, "vkCreateDevice");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004779 if (fpCreateDevice) {
Jon Ashburned8f2312016-03-31 10:52:22 -06004780 VkLayerDeviceCreateInfo create_info_disp;
4781
Jon Ashburncc407a22016-04-15 09:25:03 -06004782 create_info_disp.sType = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO;
Jon Ashburned8f2312016-03-31 10:52:22 -06004783 create_info_disp.function = VK_LOADER_DATA_CALLBACK;
4784
4785 create_info_disp.u.pfnSetDeviceLoaderData = vkSetDeviceDispatch;
4786
4787 create_info_disp.pNext = loader_create_info.pNext;
4788 loader_create_info.pNext = &create_info_disp;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004789 res = fpCreateDevice(pd->phys_dev, &loader_create_info, pAllocator, &created_device);
Piers Daniellefbbfc12016-04-05 17:28:06 -06004790 if (res != VK_SUCCESS) {
4791 return res;
4792 }
Mark Young65cb3662016-11-07 13:27:02 -07004793 dev->chain_device = created_device;
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004794 } else {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004795 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4796 "loader_create_device_chain: Failed to find \'vkCreateDevice\' "
4797 "in layer %s");
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004798 // Couldn't find CreateDevice function!
4799 return VK_ERROR_INITIALIZATION_FAILED;
4800 }
Jon Ashburn94e70492015-06-10 10:13:10 -06004801
Mark Young65cb3662016-11-07 13:27:02 -07004802 // Initialize device dispatch table
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004803 loader_init_device_dispatch_table(&dev->loader_dispatch, nextGDPA, dev->chain_device);
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07004804
4805 return res;
Jon Ashburn6b4d70c2014-10-22 18:13:16 -06004806}
Jon Ashburnd38bfb12014-10-14 19:15:22 -06004807
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004808VkResult loader_validate_layers(const struct loader_instance *inst, const uint32_t layer_count,
4809 const char *const *ppEnabledLayerNames, const struct loader_layer_list *list) {
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004810 struct loader_layer_properties *prop;
4811
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004812 for (uint32_t i = 0; i < layer_count; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004813 VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, ppEnabledLayerNames[i]);
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004814 if (result != VK_STRING_ERROR_NONE) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004815 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4816 "loader_validate_layers: Device ppEnabledLayerNames "
4817 "contains string that is too long or is badly formed");
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004818 return VK_ERROR_LAYER_NOT_PRESENT;
4819 }
4820
Jon Ashburn23d36b12016-02-02 17:47:28 -07004821 prop = loader_get_layer_property(ppEnabledLayerNames[i], list);
Mark Youngf2079b92017-05-02 10:49:46 -06004822 if (NULL == prop) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004823 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngc8b807a2017-07-14 17:11:31 -06004824 "loader_validate_layers: Layer %d does not exist in the list of available layers", i);
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06004825 return VK_ERROR_LAYER_NOT_PRESENT;
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004826 }
4827 }
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004828 return VK_SUCCESS;
4829}
4830
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004831VkResult loader_validate_instance_extensions(const struct loader_instance *inst, const struct loader_extension_list *icd_exts,
4832 const struct loader_layer_list *instance_layers,
4833 const VkInstanceCreateInfo *pCreateInfo) {
Jon Ashburn5c042ea2015-08-04 11:14:18 -06004834 VkExtensionProperties *extension_prop;
Mark Young48cea0c2017-05-26 14:39:54 -06004835 char *env_value;
4836 bool check_if_known = true;
Lenny Komow3b958392018-01-17 13:53:59 -07004837 VkResult res = VK_SUCCESS;
4838
4839 struct loader_layer_list active_layers;
4840 struct loader_layer_list expanded_layers;
4841 memset(&active_layers, 0, sizeof(active_layers));
4842 memset(&expanded_layers, 0, sizeof(expanded_layers));
4843 if (!loader_init_layer_list(inst, &active_layers)) {
4844 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4845 goto out;
4846 }
4847 if (!loader_init_layer_list(inst, &expanded_layers)) {
4848 res = VK_ERROR_OUT_OF_HOST_MEMORY;
4849 goto out;
4850 }
4851
4852 // Build the lists of active layers (including metalayers) and expanded layers (with metalayers resolved to their components)
4853 loader_add_implicit_layers(inst, &active_layers, &expanded_layers, instance_layers);
4854 loader_add_env_layers(inst, VK_LAYER_TYPE_FLAG_EXPLICIT_LAYER, ENABLED_LAYERS_ENV, &active_layers, &expanded_layers,
4855 instance_layers);
4856 res = loader_add_layer_names_to_list(inst, &active_layers, &expanded_layers, pCreateInfo->enabledLayerCount,
4857 pCreateInfo->ppEnabledLayerNames, instance_layers);
4858 if (VK_SUCCESS != res) {
4859 goto out;
4860 }
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004861
Jon Ashburnf19916e2016-01-11 13:12:43 -07004862 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004863 VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004864 if (result != VK_STRING_ERROR_NONE) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004865 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young48cea0c2017-05-26 14:39:54 -06004866 "loader_validate_instance_extensions: Instance ppEnabledExtensionNames contains "
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004867 "string that is too long or is badly formed");
Lenny Komow3b958392018-01-17 13:53:59 -07004868 res = VK_ERROR_EXTENSION_NOT_PRESENT;
4869 goto out;
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004870 }
4871
Mark Young48cea0c2017-05-26 14:39:54 -06004872 // Check if a user wants to disable the instance extension filtering behavior
4873 env_value = loader_getenv("VK_LOADER_DISABLE_INST_EXT_FILTER", inst);
4874 if (NULL != env_value && atoi(env_value) != 0) {
4875 check_if_known = false;
Lenny Komow4053b812016-12-29 16:27:28 -07004876 }
Mark Young48cea0c2017-05-26 14:39:54 -06004877 loader_free_getenv(env_value, inst);
Lenny Komow4053b812016-12-29 16:27:28 -07004878
Mark Young48cea0c2017-05-26 14:39:54 -06004879 if (check_if_known) {
4880 // See if the extension is in the list of supported extensions
4881 bool found = false;
4882 for (uint32_t j = 0; LOADER_INSTANCE_EXTENSIONS[j] != NULL; j++) {
4883 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], LOADER_INSTANCE_EXTENSIONS[j]) == 0) {
4884 found = true;
4885 break;
4886 }
4887 }
4888
4889 // If it isn't in the list, return an error
4890 if (!found) {
4891 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
4892 "loader_validate_instance_extensions: Extension %s not found in list of known instance extensions.",
4893 pCreateInfo->ppEnabledExtensionNames[i]);
Lenny Komow3b958392018-01-17 13:53:59 -07004894 res = VK_ERROR_EXTENSION_NOT_PRESENT;
4895 goto out;
Mark Young48cea0c2017-05-26 14:39:54 -06004896 }
Lenny Komow4053b812016-12-29 16:27:28 -07004897 }
4898
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004899 extension_prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[i], icd_exts);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004900
4901 if (extension_prop) {
4902 continue;
4903 }
4904
4905 extension_prop = NULL;
4906
Lenny Komow3b958392018-01-17 13:53:59 -07004907 // Not in global list, search expanded layer extension list
4908 for (uint32_t j = 0; NULL == extension_prop && j < expanded_layers.count; ++j) {
4909 extension_prop =
4910 get_extension_property(pCreateInfo->ppEnabledExtensionNames[i], &expanded_layers.list[j].instance_extension_list);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004911 }
4912
4913 if (!extension_prop) {
Mark Youngb6399312017-01-10 14:22:15 -07004914 // Didn't find extension name in any of the global layers, error out
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004915 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young48cea0c2017-05-26 14:39:54 -06004916 "loader_validate_instance_extensions: Instance extension %s not supported by available ICDs or enabled "
4917 "layers.",
4918 pCreateInfo->ppEnabledExtensionNames[i]);
Lenny Komow3b958392018-01-17 13:53:59 -07004919 res = VK_ERROR_EXTENSION_NOT_PRESENT;
4920 goto out;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004921 }
4922 }
Lenny Komow3b958392018-01-17 13:53:59 -07004923
4924out:
4925 loader_destroy_layer_list(inst, NULL, &active_layers);
4926 loader_destroy_layer_list(inst, NULL, &expanded_layers);
4927 return res;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004928}
4929
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004930VkResult loader_validate_device_extensions(struct loader_physical_device_tramp *phys_dev,
4931 const struct loader_layer_list *activated_device_layers,
4932 const struct loader_extension_list *icd_exts, const VkDeviceCreateInfo *pCreateInfo) {
Jon Ashburn5c042ea2015-08-04 11:14:18 -06004933 VkExtensionProperties *extension_prop;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004934 struct loader_layer_properties *layer_prop;
4935
Jon Ashburnf19916e2016-01-11 13:12:43 -07004936 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004937 VkStringErrorFlags result = vk_string_validate(MaxLoaderStringLength, pCreateInfo->ppEnabledExtensionNames[i]);
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004938 if (result != VK_STRING_ERROR_NONE) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004939 loader_log(phys_dev->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young48cea0c2017-05-26 14:39:54 -06004940 "loader_validate_device_extensions: Device ppEnabledExtensionNames contains "
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004941 "string that is too long or is badly formed");
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07004942 return VK_ERROR_EXTENSION_NOT_PRESENT;
4943 }
4944
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004945 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
Jon Ashburn014438f2016-03-01 19:51:07 -07004946 extension_prop = get_extension_property(extension_name, icd_exts);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004947
4948 if (extension_prop) {
4949 continue;
4950 }
4951
Mark Youngb6399312017-01-10 14:22:15 -07004952 // Not in global list, search activated layer extension lists
Jon Ashburn471f44c2016-01-13 12:51:43 -07004953 for (uint32_t j = 0; j < activated_device_layers->count; j++) {
4954 layer_prop = &activated_device_layers->list[j];
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004955
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004956 extension_prop = get_dev_extension_property(extension_name, &layer_prop->device_extension_list);
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004957 if (extension_prop) {
Mark Youngb6399312017-01-10 14:22:15 -07004958 // Found the extension in one of the layers enabled by the app.
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004959 break;
4960 }
4961 }
4962
4963 if (!extension_prop) {
Mark Youngb6399312017-01-10 14:22:15 -07004964 // Didn't find extension name in any of the device layers, error out
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004965 loader_log(phys_dev->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young48cea0c2017-05-26 14:39:54 -06004966 "loader_validate_device_extensions: Device extension %s not supported by selected physical device "
4967 "or enabled layers.",
4968 pCreateInfo->ppEnabledExtensionNames[i]);
Courtney Goeltzenleuchter55659b72015-09-14 18:01:17 -06004969 return VK_ERROR_EXTENSION_NOT_PRESENT;
Courtney Goeltzenleuchter366b27a2015-07-06 20:14:18 -06004970 }
4971 }
Courtney Goeltzenleuchter3b8c5ff2015-07-06 17:45:08 -06004972 return VK_SUCCESS;
4973}
4974
Mark Youngb6399312017-01-10 14:22:15 -07004975// Terminator functions for the Instance chain
4976// All named terminator_<Vulakn API name>
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004977VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
4978 const VkAllocationCallbacks *pAllocator, VkInstance *pInstance) {
Mark Young0153e0b2016-11-03 14:27:13 -06004979 struct loader_icd_term *icd_term;
Jon Ashburn5c042ea2015-08-04 11:14:18 -06004980 VkExtensionProperties *prop;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004981 char **filtered_extension_names = NULL;
4982 VkInstanceCreateInfo icd_create_info;
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06004983 VkResult res = VK_SUCCESS;
Mark Young8b4edb52016-11-11 09:31:55 -07004984 bool one_icd_successful = false;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07004985
Jon Ashburncc407a22016-04-15 09:25:03 -06004986 struct loader_instance *ptr_instance = (struct loader_instance *)*pInstance;
Tony Barbour3c78ff42015-12-04 13:24:39 -07004987 memcpy(&icd_create_info, pCreateInfo, sizeof(icd_create_info));
4988
Jon Ashburnf19916e2016-01-11 13:12:43 -07004989 icd_create_info.enabledLayerCount = 0;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004990 icd_create_info.ppEnabledLayerNames = NULL;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004991
Mark Youngb6399312017-01-10 14:22:15 -07004992 // NOTE: Need to filter the extensions to only those supported by the ICD.
4993 // No ICD will advertise support for layers. An ICD library could
4994 // support a layer, but it would be independent of the actual ICD,
4995 // just in the same library.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07004996 filtered_extension_names = loader_stack_alloc(pCreateInfo->enabledExtensionCount * sizeof(char *));
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06004997 if (!filtered_extension_names) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07004998 loader_log(ptr_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Young48cea0c2017-05-26 14:39:54 -06004999 "terminator_CreateInstance: Failed create extension name array for %d extensions",
Mark Youngb6399312017-01-10 14:22:15 -07005000 pCreateInfo->enabledExtensionCount);
Mark Young3a587792016-08-19 15:25:08 -06005001 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5002 goto out;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06005003 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005004 icd_create_info.ppEnabledExtensionNames = (const char *const *)filtered_extension_names;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06005005
Mark Young0153e0b2016-11-03 14:27:13 -06005006 for (uint32_t i = 0; i < ptr_instance->icd_tramp_list.count; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005007 icd_term = loader_icd_add(ptr_instance, &ptr_instance->icd_tramp_list.scanned_list[i]);
Mark Young0153e0b2016-11-03 14:27:13 -06005008 if (NULL == icd_term) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005009 loader_log(ptr_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngc8b807a2017-07-14 17:11:31 -06005010 "terminator_CreateInstance: Failed to add ICD %d to ICD trampoline list.", i);
Mark Young3a587792016-08-19 15:25:08 -06005011 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5012 goto out;
Mark Young0ad83132016-06-30 13:02:42 -06005013 }
Mark Young6267ae62017-01-12 12:27:19 -07005014
Lenny Komowa44cc852017-09-12 22:54:21 -06005015 // If any error happens after here, we need to remove the ICD from the list,
5016 // because we've already added it, but haven't validated it
5017
Mark Young0ad83132016-06-30 13:02:42 -06005018 icd_create_info.enabledExtensionCount = 0;
5019 struct loader_extension_list icd_exts;
Courtney Goeltzenleuchter746db732015-07-06 17:42:01 -06005020
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005021 loader_log(ptr_instance, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0, "Build ICD instance extension list");
Mark Young0f183a82017-02-28 09:58:04 -07005022 // traverse scanned icd list adding non-duplicate extensions to the list
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005023 res = loader_init_generic_list(ptr_instance, (struct loader_generic_list *)&icd_exts, sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06005024 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
5025 // If out of memory, bail immediately.
5026 goto out;
5027 } else if (VK_SUCCESS != res) {
Mark Young7e471292016-09-06 09:53:45 -06005028 // Something bad happened with this ICD, so free it and try the
5029 // next.
Mark Young0153e0b2016-11-03 14:27:13 -06005030 ptr_instance->icd_terms = icd_term->next;
5031 icd_term->next = NULL;
5032 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Mark Young3a587792016-08-19 15:25:08 -06005033 continue;
5034 }
5035
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005036 res = loader_add_instance_extensions(ptr_instance, icd_term->scanned_icd->EnumerateInstanceExtensionProperties,
5037 icd_term->scanned_icd->lib_name, &icd_exts);
Mark Youngdb13a2a2016-09-06 13:53:03 -06005038 if (VK_SUCCESS != res) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005039 loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)&icd_exts);
Mark Youngdb13a2a2016-09-06 13:53:03 -06005040 if (VK_ERROR_OUT_OF_HOST_MEMORY == res) {
5041 // If out of memory, bail immediately.
5042 goto out;
5043 } else {
Mark Young0f183a82017-02-28 09:58:04 -07005044 // Something bad happened with this ICD, so free it and try the next.
Mark Young0153e0b2016-11-03 14:27:13 -06005045 ptr_instance->icd_terms = icd_term->next;
5046 icd_term->next = NULL;
5047 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Mark Youngdb13a2a2016-09-06 13:53:03 -06005048 continue;
5049 }
Mark Young3a587792016-08-19 15:25:08 -06005050 }
Courtney Goeltzenleuchter36eeb742015-12-21 16:41:47 -07005051
Mark Young0ad83132016-06-30 13:02:42 -06005052 for (uint32_t j = 0; j < pCreateInfo->enabledExtensionCount; j++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005053 prop = get_extension_property(pCreateInfo->ppEnabledExtensionNames[j], &icd_exts);
Mark Young0ad83132016-06-30 13:02:42 -06005054 if (prop) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005055 filtered_extension_names[icd_create_info.enabledExtensionCount] = (char *)pCreateInfo->ppEnabledExtensionNames[j];
Mark Young0ad83132016-06-30 13:02:42 -06005056 icd_create_info.enabledExtensionCount++;
Jon Ashburn46888392015-01-29 15:45:51 -07005057 }
5058 }
Mark Young0ad83132016-06-30 13:02:42 -06005059
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005060 loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)&icd_exts);
Mark Young0ad83132016-06-30 13:02:42 -06005061
Mark Young8b4edb52016-11-11 09:31:55 -07005062 VkResult icd_result =
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005063 ptr_instance->icd_tramp_list.scanned_list[i].CreateInstance(&icd_create_info, pAllocator, &(icd_term->instance));
Mark Young8b4edb52016-11-11 09:31:55 -07005064 if (VK_ERROR_OUT_OF_HOST_MEMORY == icd_result) {
Mark Young3a587792016-08-19 15:25:08 -06005065 // If out of memory, bail immediately.
Mark Young8b4edb52016-11-11 09:31:55 -07005066 res = VK_ERROR_OUT_OF_HOST_MEMORY;
Mark Young3a587792016-08-19 15:25:08 -06005067 goto out;
Mark Young8b4edb52016-11-11 09:31:55 -07005068 } else if (VK_SUCCESS != icd_result) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005069 loader_log(ptr_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
5070 "terminator_CreateInstance: Failed to CreateInstance in "
5071 "ICD %d. Skipping ICD.",
Mark Youngb6399312017-01-10 14:22:15 -07005072 i);
Mark Young0153e0b2016-11-03 14:27:13 -06005073 ptr_instance->icd_terms = icd_term->next;
5074 icd_term->next = NULL;
5075 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Mark Young3a587792016-08-19 15:25:08 -06005076 continue;
5077 }
Mark Young0ad83132016-06-30 13:02:42 -06005078
Mark Young0f183a82017-02-28 09:58:04 -07005079 if (!loader_icd_init_entries(icd_term, icd_term->instance,
5080 ptr_instance->icd_tramp_list.scanned_list[i].GetInstanceProcAddr)) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005081 loader_log(ptr_instance, VK_DEBUG_REPORT_WARNING_BIT_EXT, 0,
5082 "terminator_CreateInstance: Failed to CreateInstance and find "
5083 "entrypoints with ICD. Skipping ICD.");
Lenny Komowa44cc852017-09-12 22:54:21 -06005084 ptr_instance->icd_terms = icd_term->next;
5085 icd_term->next = NULL;
5086 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Mark Young3a587792016-08-19 15:25:08 -06005087 continue;
Mark Young0ad83132016-06-30 13:02:42 -06005088 }
Mark Young8b4edb52016-11-11 09:31:55 -07005089
5090 // If we made it this far, at least one ICD was successful
5091 one_icd_successful = true;
Jon Ashburn46888392015-01-29 15:45:51 -07005092 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005093
Mark Young0f183a82017-02-28 09:58:04 -07005094 // If no ICDs were added to instance list and res is unchanged from it's initial value, the loader was unable to
5095 // find a suitable ICD.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005096 if (VK_SUCCESS == res && (ptr_instance->icd_terms == NULL || !one_icd_successful)) {
Mark Young3a587792016-08-19 15:25:08 -06005097 res = VK_ERROR_INCOMPATIBLE_DRIVER;
5098 }
5099
5100out:
5101
5102 if (VK_SUCCESS != res) {
Mark Young0153e0b2016-11-03 14:27:13 -06005103 while (NULL != ptr_instance->icd_terms) {
5104 icd_term = ptr_instance->icd_terms;
5105 ptr_instance->icd_terms = icd_term->next;
5106 if (NULL != icd_term->instance) {
Mark Young0f183a82017-02-28 09:58:04 -07005107 icd_term->dispatch.DestroyInstance(icd_term->instance, pAllocator);
Mark Young3a587792016-08-19 15:25:08 -06005108 }
Mark Young0153e0b2016-11-03 14:27:13 -06005109 loader_icd_destroy(ptr_instance, icd_term, pAllocator);
Courtney Goeltzenleuchter40caf0b2015-07-06 09:06:34 -06005110 }
Ian Elliotteb450762015-02-05 15:19:15 -07005111 }
Jon Ashburn46888392015-01-29 15:45:51 -07005112
Mark Young3a587792016-08-19 15:25:08 -06005113 return res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005114}
5115
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005116VKAPI_ATTR void VKAPI_CALL terminator_DestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) {
Courtney Goeltzenleuchterdeceded2015-06-08 15:04:02 -06005117 struct loader_instance *ptr_instance = loader_instance(instance);
Karl Schultze2ef9e62017-01-13 14:01:35 -07005118 if (NULL == ptr_instance) {
5119 return;
5120 }
Mark Young0153e0b2016-11-03 14:27:13 -06005121 struct loader_icd_term *icd_terms = ptr_instance->icd_terms;
5122 struct loader_icd_term *next_icd_term;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005123
5124 // Remove this instance from the list of instances:
5125 struct loader_instance *prev = NULL;
5126 struct loader_instance *next = loader.instances;
5127 while (next != NULL) {
5128 if (next == ptr_instance) {
5129 // Remove this instance from the list:
5130 if (prev)
5131 prev->next = next->next;
Jon Ashburnc5c49602015-02-03 09:26:59 -07005132 else
5133 loader.instances = next->next;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005134 break;
5135 }
5136 prev = next;
5137 next = next->next;
5138 }
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005139
Mark Young0153e0b2016-11-03 14:27:13 -06005140 while (NULL != icd_terms) {
5141 if (icd_terms->instance) {
Mark Young0f183a82017-02-28 09:58:04 -07005142 icd_terms->dispatch.DestroyInstance(icd_terms->instance, pAllocator);
Tony Barbourf20f87b2015-04-22 09:02:32 -06005143 }
Mark Young0153e0b2016-11-03 14:27:13 -06005144 next_icd_term = icd_terms->next;
5145 icd_terms->instance = VK_NULL_HANDLE;
5146 loader_icd_destroy(ptr_instance, icd_terms, pAllocator);
Jon Ashburna6fd2612015-06-16 14:43:19 -06005147
Mark Young0153e0b2016-11-03 14:27:13 -06005148 icd_terms = next_icd_term;
Jon Ashburn46888392015-01-29 15:45:51 -07005149 }
Jon Ashburn491cd042016-05-16 14:01:18 -06005150
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005151 loader_delete_layer_properties(ptr_instance, &ptr_instance->instance_layer_list);
Mark Young0153e0b2016-11-03 14:27:13 -06005152 loader_scanned_icd_clear(ptr_instance, &ptr_instance->icd_tramp_list);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005153 loader_destroy_generic_list(ptr_instance, (struct loader_generic_list *)&ptr_instance->ext_list);
Mark Young39389872017-01-19 21:10:49 -07005154 if (NULL != ptr_instance->phys_devs_term) {
Mark Young0193d652016-12-28 16:10:10 -07005155 for (uint32_t i = 0; i < ptr_instance->phys_dev_count_term; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005156 loader_instance_heap_free(ptr_instance, ptr_instance->phys_devs_term[i]);
Lenny Komow8a1f8a52016-12-20 15:35:11 -07005157 }
Mark Young0ad83132016-06-30 13:02:42 -06005158 loader_instance_heap_free(ptr_instance, ptr_instance->phys_devs_term);
Lenny Komow8a1f8a52016-12-20 15:35:11 -07005159 }
Mark Youngd66edd52017-03-10 17:31:18 -07005160 if (NULL != ptr_instance->phys_dev_groups_term) {
5161 for (uint32_t i = 0; i < ptr_instance->phys_dev_group_count_term; i++) {
5162 loader_instance_heap_free(ptr_instance, ptr_instance->phys_dev_groups_term[i]);
5163 }
5164 loader_instance_heap_free(ptr_instance, ptr_instance->phys_dev_groups_term);
5165 }
Jon Ashburnfc1031e2015-11-17 15:31:02 -07005166 loader_free_dev_ext_table(ptr_instance);
Mark Young39389872017-01-19 21:10:49 -07005167 loader_free_phys_dev_ext_table(ptr_instance);
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005168}
5169
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005170VKAPI_ATTR VkResult VKAPI_CALL terminator_CreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo,
5171 const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) {
Mark Young0ad83132016-06-30 13:02:42 -06005172 VkResult res = VK_SUCCESS;
Mark Young0153e0b2016-11-03 14:27:13 -06005173 struct loader_physical_device_term *phys_dev_term;
5174 phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
5175 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Jon Ashburn24cd4be2015-11-01 14:04:06 -07005176
Jon Ashburncc407a22016-04-15 09:25:03 -06005177 struct loader_device *dev = (struct loader_device *)*pDevice;
Mark Young0f183a82017-02-28 09:58:04 -07005178 PFN_vkCreateDevice fpCreateDevice = icd_term->dispatch.CreateDevice;
Mark Young0ad83132016-06-30 13:02:42 -06005179 struct loader_extension_list icd_exts;
5180
Mark Young65cb3662016-11-07 13:27:02 -07005181 dev->phys_dev_term = phys_dev_term;
5182
Mark Young0ad83132016-06-30 13:02:42 -06005183 icd_exts.list = NULL;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06005184
Jon Ashburn1530c342016-02-26 13:14:27 -07005185 if (fpCreateDevice == NULL) {
Mark Young0153e0b2016-11-03 14:27:13 -06005186 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07005187 "terminator_CreateDevice: No vkCreateDevice command exposed "
5188 "by ICD %s",
Mark Young0153e0b2016-11-03 14:27:13 -06005189 icd_term->scanned_icd->lib_name);
Mark Young0ad83132016-06-30 13:02:42 -06005190 res = VK_ERROR_INITIALIZATION_FAILED;
5191 goto out;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06005192 }
5193
Jon Ashburn1530c342016-02-26 13:14:27 -07005194 VkDeviceCreateInfo localCreateInfo;
5195 memcpy(&localCreateInfo, pCreateInfo, sizeof(localCreateInfo));
Jon Ashburn1530c342016-02-26 13:14:27 -07005196
Mark Youngb6399312017-01-10 14:22:15 -07005197 // NOTE: Need to filter the extensions to only those supported by the ICD.
Mark Younge1ea9012017-03-09 14:17:40 -07005198 // No ICD will advertise support for layers. An ICD library could support a layer,
5199 // but it would be independent of the actual ICD, just in the same library.
Jon Ashburn1530c342016-02-26 13:14:27 -07005200 char **filtered_extension_names = NULL;
Mark Younge1ea9012017-03-09 14:17:40 -07005201 if (0 < pCreateInfo->enabledExtensionCount) {
5202 filtered_extension_names = loader_stack_alloc(pCreateInfo->enabledExtensionCount * sizeof(char *));
5203 if (NULL == filtered_extension_names) {
5204 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5205 "terminator_CreateDevice: Failed to create extension name "
5206 "storage for %d extensions %d",
5207 pCreateInfo->enabledExtensionCount);
5208 return VK_ERROR_OUT_OF_HOST_MEMORY;
5209 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06005210 }
5211
Jon Ashburn1530c342016-02-26 13:14:27 -07005212 localCreateInfo.enabledLayerCount = 0;
5213 localCreateInfo.ppEnabledLayerNames = NULL;
5214
5215 localCreateInfo.enabledExtensionCount = 0;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005216 localCreateInfo.ppEnabledExtensionNames = (const char *const *)filtered_extension_names;
Jon Ashburn1530c342016-02-26 13:14:27 -07005217
Mark Youngb6399312017-01-10 14:22:15 -07005218 // Get the physical device (ICD) extensions
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005219 res = loader_init_generic_list(icd_term->this_instance, (struct loader_generic_list *)&icd_exts, sizeof(VkExtensionProperties));
Mark Young3a587792016-08-19 15:25:08 -06005220 if (VK_SUCCESS != res) {
Mark Young0ad83132016-06-30 13:02:42 -06005221 goto out;
Jon Ashburn014438f2016-03-01 19:51:07 -07005222 }
5223
Mark Young0f183a82017-02-28 09:58:04 -07005224 res = loader_add_device_extensions(icd_term->this_instance, icd_term->dispatch.EnumerateDeviceExtensionProperties,
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005225 phys_dev_term->phys_dev, icd_term->scanned_icd->lib_name, &icd_exts);
Jon Ashburn014438f2016-03-01 19:51:07 -07005226 if (res != VK_SUCCESS) {
Mark Young0ad83132016-06-30 13:02:42 -06005227 goto out;
Jon Ashburn014438f2016-03-01 19:51:07 -07005228 }
5229
Jon Ashburn1530c342016-02-26 13:14:27 -07005230 for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {
5231 const char *extension_name = pCreateInfo->ppEnabledExtensionNames[i];
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005232 VkExtensionProperties *prop = get_extension_property(extension_name, &icd_exts);
Jon Ashburn1530c342016-02-26 13:14:27 -07005233 if (prop) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005234 filtered_extension_names[localCreateInfo.enabledExtensionCount] = (char *)extension_name;
Jon Ashburn1530c342016-02-26 13:14:27 -07005235 localCreateInfo.enabledExtensionCount++;
Mark Young9a3ddd42016-10-21 16:25:47 -06005236 } else {
Lenny Komow8314e542018-01-03 10:37:54 -07005237 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_DEBUG_BIT_EXT, 0,
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005238 "vkCreateDevice extension %s not available for "
5239 "devices associated with ICD %s",
Mark Young0153e0b2016-11-03 14:27:13 -06005240 extension_name, icd_term->scanned_icd->lib_name);
Jon Ashburn1530c342016-02-26 13:14:27 -07005241 }
5242 }
5243
Mark Young0f183a82017-02-28 09:58:04 -07005244 // Before we continue, If KHX_device_group is the list of enabled and viable extensions, then we then need to look for the
5245 // corresponding VkDeviceGroupDeviceCreateInfoKHX struct in the device list and replace all the physical device values (which
5246 // are really loader physical device terminator values) with the ICD versions.
5247 if (icd_term->this_instance->enabled_known_extensions.khx_device_group_creation == 1) {
5248 struct VkStructureHeader *pNext = (struct VkStructureHeader *)localCreateInfo.pNext;
5249 struct VkStructureHeader *pPrev = (struct VkStructureHeader *)&localCreateInfo;
5250 while (NULL != pNext) {
5251 if (VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHX == pNext->sType) {
5252 VkDeviceGroupDeviceCreateInfoKHX *cur_struct = (VkDeviceGroupDeviceCreateInfoKHX *)pNext;
5253 if (0 < cur_struct->physicalDeviceCount && NULL != cur_struct->pPhysicalDevices) {
5254 VkDeviceGroupDeviceCreateInfoKHX *temp_struct = loader_stack_alloc(sizeof(VkDeviceGroupDeviceCreateInfoKHX));
5255 VkPhysicalDevice *phys_dev_array = NULL;
5256 if (NULL == temp_struct) {
5257 return VK_ERROR_OUT_OF_HOST_MEMORY;
5258 }
5259 memcpy(temp_struct, cur_struct, sizeof(VkDeviceGroupDeviceCreateInfoKHX));
5260 phys_dev_array = loader_stack_alloc(sizeof(VkPhysicalDevice) * cur_struct->physicalDeviceCount);
5261 if (NULL == phys_dev_array) {
5262 return VK_ERROR_OUT_OF_HOST_MEMORY;
5263 }
5264
5265 // Before calling down, replace the incoming physical device values (which are really loader terminator
5266 // physical devices) with the ICDs physical device values.
5267 struct loader_physical_device_term *cur_term;
5268 for (uint32_t phys_dev = 0; phys_dev < cur_struct->physicalDeviceCount; phys_dev++) {
5269 cur_term = (struct loader_physical_device_term *)cur_struct->pPhysicalDevices[phys_dev];
5270 phys_dev_array[phys_dev] = cur_term->phys_dev;
5271 }
5272 temp_struct->pPhysicalDevices = phys_dev_array;
5273
5274 // Replace the old struct in the pNext chain with this one.
5275 pPrev->pNext = (const void *)temp_struct;
5276 pNext = (struct VkStructureHeader *)(temp_struct);
5277 }
5278 break;
5279 }
5280
5281 pPrev = pNext;
5282 pNext = (struct VkStructureHeader *)(pPrev->pNext);
5283 }
5284 }
5285
Lenny Komow34d78d22017-05-24 15:47:15 -06005286 // Handle loader emulation for structs that are not supported by the ICD:
5287 // Presently, the emulation leaves the pNext chain alone. This means that the ICD will receive items in the chain which
5288 // are not recognized by the ICD. If this causes the ICD to fail, then the items would have to be removed here. The current
5289 // implementation does not remove them because copying the pNext chain would be impossible if the loader does not recognize
5290 // the any of the struct types, as the loader would not know the size to allocate and copy.
5291 if (icd_term->dispatch.GetPhysicalDeviceFeatures2KHR == NULL) {
5292 const void *pNext = localCreateInfo.pNext;
5293 while (pNext != NULL) {
5294 switch (*(VkStructureType *)pNext) {
5295 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR: {
5296 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
5297 "vkCreateDevice: Emulating handling of VkPhysicalDeviceFeatures2KHR in pNext chain for ICD \"%s\"",
5298 icd_term->scanned_icd->lib_name);
5299 const VkPhysicalDeviceFeatures2KHR *features = pNext;
5300
5301 // Verify that VK_KHR_get_physical_device_properties2 is enabled
5302 if (icd_term->this_instance->enabled_known_extensions.khr_get_physical_device_properties2) {
5303 localCreateInfo.pEnabledFeatures = &features->features;
5304 }
5305
5306 // Leave this item in the pNext chain for now
5307
5308 pNext = features->pNext;
5309 break;
5310 }
5311
5312 case VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHX: {
5313 loader_log(
5314 icd_term->this_instance, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, 0,
5315 "vkCreateDevice: Emulating handling of VkDeviceGroupDeviceCreateInfoKHX in pNext chain for ICD \"%s\"",
5316 icd_term->scanned_icd->lib_name);
5317 const VkDeviceGroupDeviceCreateInfoKHX *group_info = pNext;
5318
5319 // The group must contain only this one device, since physical device groups aren't actually supported
5320 if (group_info->physicalDeviceCount != 1 || group_info->pPhysicalDevices[0] != physicalDevice) {
5321 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5322 "vkCreateDevice: Emulation failed to create device from device group info");
5323 res = VK_ERROR_INITIALIZATION_FAILED;
5324 goto out;
5325 }
5326
5327 // Nothing needs to be done here because we're leaving the item in the pNext chain and because the spec states
5328 // that the physicalDevice argument must be included in the device group, and we've already checked that it is
5329
5330 pNext = group_info->pNext;
5331 break;
5332 }
5333
5334 // Multiview properties are also allowed, but since VK_KHX_multiview is a device extension, we'll just let the ICD
5335 // handle that error when the user enables the extension here
5336 default: {
5337 const struct VkStructureHeader *header = pNext;
5338 pNext = header->pNext;
5339 break;
5340 }
5341 }
5342 }
5343 }
5344
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005345 res = fpCreateDevice(phys_dev_term->phys_dev, &localCreateInfo, pAllocator, &dev->icd_device);
Jon Ashburn1530c342016-02-26 13:14:27 -07005346 if (res != VK_SUCCESS) {
Mark Young0153e0b2016-11-03 14:27:13 -06005347 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
Mark Youngb6399312017-01-10 14:22:15 -07005348 "terminator_CreateDevice: Failed in ICD %s vkCreateDevice"
5349 "call",
Mark Young0153e0b2016-11-03 14:27:13 -06005350 icd_term->scanned_icd->lib_name);
Mark Young0ad83132016-06-30 13:02:42 -06005351 goto out;
Jon Ashburn1530c342016-02-26 13:14:27 -07005352 }
5353
Mark Young65cb3662016-11-07 13:27:02 -07005354 *pDevice = dev->icd_device;
Mark Young0153e0b2016-11-03 14:27:13 -06005355 loader_add_logical_device(icd_term->this_instance, icd_term, dev);
Jon Ashburn1530c342016-02-26 13:14:27 -07005356
Mark Young0f183a82017-02-28 09:58:04 -07005357 // Init dispatch pointer in new device object
Jon Ashburn1530c342016-02-26 13:14:27 -07005358 loader_init_dispatch(*pDevice, &dev->loader_dispatch);
5359
Mark Young0ad83132016-06-30 13:02:42 -06005360out:
5361 if (NULL != icd_exts.list) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005362 loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&icd_exts);
Mark Young0ad83132016-06-30 13:02:42 -06005363 }
5364
Jon Ashburn1530c342016-02-26 13:14:27 -07005365 return res;
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06005366}
5367
Mark Young6267ae62017-01-12 12:27:19 -07005368VkResult setupLoaderTrampPhysDevs(VkInstance instance) {
Jon Ashburn24cd4be2015-11-01 14:04:06 -07005369 VkResult res = VK_SUCCESS;
Mark Young6267ae62017-01-12 12:27:19 -07005370 VkPhysicalDevice *local_phys_devs = NULL;
5371 struct loader_instance *inst;
5372 uint32_t total_count = 0;
5373 struct loader_physical_device_tramp **new_phys_devs = NULL;
Jon Ashburn4c392fb2015-01-28 19:57:09 -07005374
Mark Young6267ae62017-01-12 12:27:19 -07005375 inst = loader_get_instance(instance);
5376 if (NULL == inst) {
5377 res = VK_ERROR_INITIALIZATION_FAILED;
5378 goto out;
5379 }
Mark Youngd66edd52017-03-10 17:31:18 -07005380
Mark Youngbb3a29c2017-05-19 12:29:43 -06005381 // Query how many GPUs there
Mark Youngd66edd52017-03-10 17:31:18 -07005382 res = inst->disp->layer_inst_disp.EnumeratePhysicalDevices(instance, &total_count, NULL);
5383 if (res != VK_SUCCESS) {
5384 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5385 "setupLoaderTrampPhysDevs: Failed during dispatch call "
5386 "of \'vkEnumeratePhysicalDevices\' to lower layers or "
5387 "loader to get count.");
5388 goto out;
5389 }
5390
5391 // Really use what the total GPU count is since Optimus and other layers may mess
5392 // the count up.
Mark Young6267ae62017-01-12 12:27:19 -07005393 total_count = inst->total_gpu_count;
5394
5395 // Create an array for the new physical devices, which will be stored
5396 // in the instance for the trampoline code.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005397 new_phys_devs = (struct loader_physical_device_tramp **)loader_instance_heap_alloc(
5398 inst, total_count * sizeof(struct loader_physical_device_tramp *), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young6267ae62017-01-12 12:27:19 -07005399 if (NULL == new_phys_devs) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005400 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5401 "setupLoaderTrampPhysDevs: Failed to allocate new physical device"
5402 " array of size %d",
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005403 total_count);
Mark Youngd8382d72016-12-23 16:59:58 -07005404 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5405 goto out;
5406 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005407 memset(new_phys_devs, 0, total_count * sizeof(struct loader_physical_device_tramp *));
Jon Ashburn014438f2016-03-01 19:51:07 -07005408
Mark Young6267ae62017-01-12 12:27:19 -07005409 // Create a temporary array (on the stack) to keep track of the
5410 // returned VkPhysicalDevice values.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005411 local_phys_devs = loader_stack_alloc(sizeof(VkPhysicalDevice) * total_count);
Mark Young6267ae62017-01-12 12:27:19 -07005412 if (NULL == local_phys_devs) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005413 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5414 "setupLoaderTrampPhysDevs: Failed to allocate local "
5415 "physical device array of size %d",
Mark Young6267ae62017-01-12 12:27:19 -07005416 total_count);
5417 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5418 goto out;
5419 }
5420 memset(local_phys_devs, 0, sizeof(VkPhysicalDevice) * total_count);
5421
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005422 res = inst->disp->layer_inst_disp.EnumeratePhysicalDevices(instance, &total_count, local_phys_devs);
Mark Young6267ae62017-01-12 12:27:19 -07005423 if (VK_SUCCESS != res) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005424 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5425 "setupLoaderTrampPhysDevs: Failed during dispatch call "
5426 "of \'vkEnumeratePhysicalDevices\' to lower layers or "
Mark Youngd66edd52017-03-10 17:31:18 -07005427 "loader to get content.");
Mark Young6267ae62017-01-12 12:27:19 -07005428 goto out;
5429 }
5430
5431 // Copy or create everything to fill the new array of physical devices
5432 for (uint32_t new_idx = 0; new_idx < total_count; new_idx++) {
Mark Young6267ae62017-01-12 12:27:19 -07005433 // Check if this physical device is already in the old buffer
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005434 for (uint32_t old_idx = 0; old_idx < inst->phys_dev_count_tramp; old_idx++) {
5435 if (local_phys_devs[new_idx] == inst->phys_devs_tramp[old_idx]->phys_dev) {
Mark Young6267ae62017-01-12 12:27:19 -07005436 new_phys_devs[new_idx] = inst->phys_devs_tramp[old_idx];
5437 break;
5438 }
Mark Youngd8382d72016-12-23 16:59:58 -07005439 }
5440
Mark Young6267ae62017-01-12 12:27:19 -07005441 // If this physical device isn't in the old buffer, create it
5442 if (NULL == new_phys_devs[new_idx]) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005443 new_phys_devs[new_idx] = (struct loader_physical_device_tramp *)loader_instance_heap_alloc(
5444 inst, sizeof(struct loader_physical_device_tramp), VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young6267ae62017-01-12 12:27:19 -07005445 if (NULL == new_phys_devs[new_idx]) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005446 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5447 "setupLoaderTrampPhysDevs: Failed to allocate "
5448 "physical device trampoline object %d",
Mark Young6267ae62017-01-12 12:27:19 -07005449 new_idx);
5450 total_count = new_idx;
Mark Youngd8382d72016-12-23 16:59:58 -07005451 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5452 goto out;
5453 }
5454
Mark Young6267ae62017-01-12 12:27:19 -07005455 // Initialize the new physicalDevice object
5456 loader_set_dispatch((void *)new_phys_devs[new_idx], inst->disp);
5457 new_phys_devs[new_idx]->this_instance = inst;
5458 new_phys_devs[new_idx]->phys_dev = local_phys_devs[new_idx];
Mark Young559d7502016-09-26 11:38:46 -06005459 }
Lenny Komowa5e01122016-12-22 15:29:43 -07005460 }
Mark Young559d7502016-09-26 11:38:46 -06005461
Lenny Komowa5e01122016-12-22 15:29:43 -07005462out:
Mark Youngd8382d72016-12-23 16:59:58 -07005463
Mark Young6267ae62017-01-12 12:27:19 -07005464 if (VK_SUCCESS != res) {
5465 if (NULL != new_phys_devs) {
5466 for (uint32_t i = 0; i < total_count; i++) {
5467 loader_instance_heap_free(inst, new_phys_devs[i]);
Lenny Komowa5e01122016-12-22 15:29:43 -07005468 }
5469 loader_instance_heap_free(inst, new_phys_devs);
Mark Young6267ae62017-01-12 12:27:19 -07005470 }
5471 total_count = 0;
5472 } else {
5473 // Free everything that didn't carry over to the new array of
5474 // physical devices
5475 if (NULL != inst->phys_devs_tramp) {
5476 for (uint32_t i = 0; i < inst->phys_dev_count_tramp; i++) {
5477 bool found = false;
5478 for (uint32_t j = 0; j < total_count; j++) {
5479 if (inst->phys_devs_tramp[i] == new_phys_devs[j]) {
5480 found = true;
5481 break;
5482 }
5483 }
5484 if (!found) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005485 loader_instance_heap_free(inst, inst->phys_devs_tramp[i]);
Mark Young6267ae62017-01-12 12:27:19 -07005486 }
5487 }
5488 loader_instance_heap_free(inst, inst->phys_devs_tramp);
5489 }
Mark Youngd8382d72016-12-23 16:59:58 -07005490
Mark Young6267ae62017-01-12 12:27:19 -07005491 // Swap in the new physical device list
5492 inst->phys_dev_count_tramp = total_count;
5493 inst->phys_devs_tramp = new_phys_devs;
5494 }
5495
5496 return res;
5497}
5498
5499VkResult setupLoaderTermPhysDevs(struct loader_instance *inst) {
5500 VkResult res = VK_SUCCESS;
5501 struct loader_icd_term *icd_term;
5502 struct loader_phys_dev_per_icd *icd_phys_dev_array = NULL;
5503 struct loader_physical_device_term **new_phys_devs = NULL;
Mark Young6267ae62017-01-12 12:27:19 -07005504
5505 inst->total_gpu_count = 0;
5506
5507 // Allocate something to store the physical device characteristics
5508 // that we read from each ICD.
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005509 icd_phys_dev_array =
5510 (struct loader_phys_dev_per_icd *)loader_stack_alloc(sizeof(struct loader_phys_dev_per_icd) * inst->total_icd_count);
Mark Young6267ae62017-01-12 12:27:19 -07005511 if (NULL == icd_phys_dev_array) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005512 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5513 "setupLoaderTermPhysDevs: Failed to allocate temporary "
5514 "ICD Physical device info array of size %d",
Mark Young6267ae62017-01-12 12:27:19 -07005515 inst->total_gpu_count);
5516 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5517 goto out;
5518 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005519 memset(icd_phys_dev_array, 0, sizeof(struct loader_phys_dev_per_icd) * inst->total_icd_count);
Mark Young6267ae62017-01-12 12:27:19 -07005520 icd_term = inst->icd_terms;
5521
5522 // For each ICD, query the number of physical devices, and then get an
5523 // internal value for those physical devices.
Karl Schultz47dd59d2017-01-20 13:19:20 -07005524 for (uint32_t icd_idx = 0; NULL != icd_term; icd_term = icd_term->next, icd_idx++) {
Mark Young0f183a82017-02-28 09:58:04 -07005525 res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &icd_phys_dev_array[icd_idx].count, NULL);
Mark Young6267ae62017-01-12 12:27:19 -07005526 if (VK_SUCCESS != res) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005527 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5528 "setupLoaderTermPhysDevs: Call to "
5529 "ICD %d's \'vkEnumeratePhysicalDevices\' failed with"
5530 " error 0x%08x",
Karl Schultz47dd59d2017-01-20 13:19:20 -07005531 icd_idx, res);
Mark Young6267ae62017-01-12 12:27:19 -07005532 goto out;
5533 }
5534
Karl Schultz47dd59d2017-01-20 13:19:20 -07005535 icd_phys_dev_array[icd_idx].phys_devs =
5536 (VkPhysicalDevice *)loader_stack_alloc(icd_phys_dev_array[icd_idx].count * sizeof(VkPhysicalDevice));
5537 if (NULL == icd_phys_dev_array[icd_idx].phys_devs) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005538 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5539 "setupLoaderTermPhysDevs: Failed to allocate temporary "
5540 "ICD Physical device array for ICD %d of size %d",
Karl Schultz47dd59d2017-01-20 13:19:20 -07005541 icd_idx, inst->total_gpu_count);
Mark Young6267ae62017-01-12 12:27:19 -07005542 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5543 goto out;
5544 }
5545
Mark Young0f183a82017-02-28 09:58:04 -07005546 res = icd_term->dispatch.EnumeratePhysicalDevices(icd_term->instance, &(icd_phys_dev_array[icd_idx].count),
5547 icd_phys_dev_array[icd_idx].phys_devs);
Mark Young6267ae62017-01-12 12:27:19 -07005548 if (VK_SUCCESS != res) {
5549 goto out;
5550 }
Karl Schultz47dd59d2017-01-20 13:19:20 -07005551 inst->total_gpu_count += icd_phys_dev_array[icd_idx].count;
5552 icd_phys_dev_array[icd_idx].this_icd_term = icd_term;
Mark Young6267ae62017-01-12 12:27:19 -07005553 }
5554
5555 if (0 == inst->total_gpu_count) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005556 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5557 "setupLoaderTermPhysDevs: Failed to detect any valid"
5558 " GPUs in the current config");
Mark Young6267ae62017-01-12 12:27:19 -07005559 res = VK_ERROR_INITIALIZATION_FAILED;
5560 goto out;
5561 }
5562
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005563 new_phys_devs = loader_instance_heap_alloc(inst, sizeof(struct loader_physical_device_term *) * inst->total_gpu_count,
5564 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young6267ae62017-01-12 12:27:19 -07005565 if (NULL == new_phys_devs) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005566 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5567 "setupLoaderTermPhysDevs: Failed to allocate new physical"
5568 " device array of size %d",
Mark Young6267ae62017-01-12 12:27:19 -07005569 inst->total_gpu_count);
5570 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5571 goto out;
5572 }
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005573 memset(new_phys_devs, 0, sizeof(struct loader_physical_device_term *) * inst->total_gpu_count);
Mark Young6267ae62017-01-12 12:27:19 -07005574
5575 // Copy or create everything to fill the new array of physical devices
5576 uint32_t idx = 0;
5577 for (uint32_t icd_idx = 0; icd_idx < inst->total_icd_count; icd_idx++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005578 for (uint32_t pd_idx = 0; pd_idx < icd_phys_dev_array[icd_idx].count; pd_idx++) {
Mark Young6267ae62017-01-12 12:27:19 -07005579 // Check if this physical device is already in the old buffer
5580 if (NULL != inst->phys_devs_term) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005581 for (uint32_t old_idx = 0; old_idx < inst->phys_dev_count_term; old_idx++) {
5582 if (icd_phys_dev_array[icd_idx].phys_devs[pd_idx] == inst->phys_devs_term[old_idx]->phys_dev) {
Mark Young6267ae62017-01-12 12:27:19 -07005583 new_phys_devs[idx] = inst->phys_devs_term[old_idx];
5584 break;
5585 }
5586 }
5587 }
5588 // If this physical device isn't in the old buffer, then we
5589 // need to create it.
5590 if (NULL == new_phys_devs[idx]) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005591 new_phys_devs[idx] = loader_instance_heap_alloc(inst, sizeof(struct loader_physical_device_term),
5592 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
Mark Young6267ae62017-01-12 12:27:19 -07005593 if (NULL == new_phys_devs[idx]) {
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005594 loader_log(inst, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5595 "setupLoaderTermPhysDevs: Failed to allocate "
5596 "physical device terminator object %d",
Mark Young6267ae62017-01-12 12:27:19 -07005597 idx);
5598 inst->total_gpu_count = idx;
5599 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5600 goto out;
5601 }
5602
5603 loader_set_dispatch((void *)new_phys_devs[idx], inst->disp);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005604 new_phys_devs[idx]->this_icd_term = icd_phys_dev_array[icd_idx].this_icd_term;
Mark Young6267ae62017-01-12 12:27:19 -07005605 new_phys_devs[idx]->icd_index = (uint8_t)(icd_idx);
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005606 new_phys_devs[idx]->phys_dev = icd_phys_dev_array[icd_idx].phys_devs[pd_idx];
Mark Young6267ae62017-01-12 12:27:19 -07005607 }
5608 idx++;
5609 }
5610 }
5611
5612out:
5613
5614 if (VK_SUCCESS != res) {
Mark Young156e8552017-02-03 16:27:42 -07005615 if (NULL != new_phys_devs) {
5616 // We've encountered an error, so we should free the new buffers.
Mark Young6267ae62017-01-12 12:27:19 -07005617 for (uint32_t i = 0; i < inst->total_gpu_count; i++) {
5618 loader_instance_heap_free(inst, new_phys_devs[i]);
5619 }
Mark Young156e8552017-02-03 16:27:42 -07005620 loader_instance_heap_free(inst, new_phys_devs);
Mark Young6267ae62017-01-12 12:27:19 -07005621 }
Mark Young156e8552017-02-03 16:27:42 -07005622 inst->total_gpu_count = 0;
Mark Young6267ae62017-01-12 12:27:19 -07005623 } else {
5624 // Free everything that didn't carry over to the new array of
5625 // physical devices. Everything else will have been copied over
5626 // to the new array.
5627 if (NULL != inst->phys_devs_term) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005628 for (uint32_t cur_pd = 0; cur_pd < inst->phys_dev_count_term; cur_pd++) {
Mark Young6267ae62017-01-12 12:27:19 -07005629 bool found = false;
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005630 for (uint32_t new_pd_idx = 0; new_pd_idx < inst->total_gpu_count; new_pd_idx++) {
5631 if (inst->phys_devs_term[cur_pd] == new_phys_devs[new_pd_idx]) {
Mark Young6267ae62017-01-12 12:27:19 -07005632 found = true;
5633 break;
5634 }
5635 }
5636 if (!found) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005637 loader_instance_heap_free(inst, inst->phys_devs_term[cur_pd]);
Mark Young6267ae62017-01-12 12:27:19 -07005638 }
5639 }
5640 loader_instance_heap_free(inst, inst->phys_devs_term);
5641 }
5642
5643 // Swap out old and new devices list
5644 inst->phys_dev_count_term = inst->total_gpu_count;
5645 inst->phys_devs_term = new_phys_devs;
5646 }
5647
5648 return res;
5649}
5650
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005651VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount,
5652 VkPhysicalDevice *pPhysicalDevices) {
Mark Young6267ae62017-01-12 12:27:19 -07005653 struct loader_instance *inst = (struct loader_instance *)instance;
5654 VkResult res = VK_SUCCESS;
5655
Mark Youngd66edd52017-03-10 17:31:18 -07005656 // Always call the setup loader terminator physical devices because they may
5657 // have changed at any point.
5658 res = setupLoaderTermPhysDevs(inst);
5659 if (VK_SUCCESS != res) {
5660 goto out;
Mark Young6267ae62017-01-12 12:27:19 -07005661 }
5662
5663 uint32_t copy_count = inst->total_gpu_count;
5664 if (NULL != pPhysicalDevices) {
5665 if (copy_count > *pPhysicalDeviceCount) {
5666 copy_count = *pPhysicalDeviceCount;
5667 res = VK_INCOMPLETE;
5668 }
5669
5670 for (uint32_t i = 0; i < copy_count; i++) {
5671 pPhysicalDevices[i] = (VkPhysicalDevice)inst->phys_devs_term[i];
Jon Ashburn014438f2016-03-01 19:51:07 -07005672 }
Courtney Goeltzenleuchterd971b612015-06-17 20:51:59 -06005673 }
Mark Young559d7502016-09-26 11:38:46 -06005674
Courtney Goeltzenleuchter00150eb2016-01-08 12:18:43 -07005675 *pPhysicalDeviceCount = copy_count;
5676
Mark Young6267ae62017-01-12 12:27:19 -07005677out:
5678
Jon Ashburn24cd4be2015-11-01 14:04:06 -07005679 return res;
Jon Ashburn1beab2d2015-01-26 14:51:40 -07005680}
5681
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005682VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
5683 VkPhysicalDeviceProperties *pProperties) {
5684 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06005685 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Young0f183a82017-02-28 09:58:04 -07005686 if (NULL != icd_term->dispatch.GetPhysicalDeviceProperties) {
5687 icd_term->dispatch.GetPhysicalDeviceProperties(phys_dev_term->phys_dev, pProperties);
Mark Youngb6399312017-01-10 14:22:15 -07005688 }
Tony Barbour59a47322015-06-24 16:06:58 -06005689}
5690
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005691VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice,
5692 uint32_t *pQueueFamilyPropertyCount,
5693 VkQueueFamilyProperties *pProperties) {
5694 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06005695 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Young0f183a82017-02-28 09:58:04 -07005696 if (NULL != icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties) {
5697 icd_term->dispatch.GetPhysicalDeviceQueueFamilyProperties(phys_dev_term->phys_dev, pQueueFamilyPropertyCount, pProperties);
Mark Youngb6399312017-01-10 14:22:15 -07005698 }
Tony Barbour59a47322015-06-24 16:06:58 -06005699}
5700
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005701VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice,
5702 VkPhysicalDeviceMemoryProperties *pProperties) {
5703 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06005704 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Young0f183a82017-02-28 09:58:04 -07005705 if (NULL != icd_term->dispatch.GetPhysicalDeviceMemoryProperties) {
5706 icd_term->dispatch.GetPhysicalDeviceMemoryProperties(phys_dev_term->phys_dev, pProperties);
Mark Youngb6399312017-01-10 14:22:15 -07005707 }
Jon Ashburn3da71f22015-05-14 12:43:38 -06005708}
5709
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005710VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice,
5711 VkPhysicalDeviceFeatures *pFeatures) {
5712 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06005713 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Young0f183a82017-02-28 09:58:04 -07005714 if (NULL != icd_term->dispatch.GetPhysicalDeviceFeatures) {
5715 icd_term->dispatch.GetPhysicalDeviceFeatures(phys_dev_term->phys_dev, pFeatures);
Mark Youngb6399312017-01-10 14:22:15 -07005716 }
Chris Forbesbc0bb772015-06-21 22:55:02 +12005717}
5718
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005719VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format,
5720 VkFormatProperties *pFormatInfo) {
5721 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06005722 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Young0f183a82017-02-28 09:58:04 -07005723 if (NULL != icd_term->dispatch.GetPhysicalDeviceFormatProperties) {
5724 icd_term->dispatch.GetPhysicalDeviceFormatProperties(phys_dev_term->phys_dev, format, pFormatInfo);
Mark Youngb6399312017-01-10 14:22:15 -07005725 }
Chris Forbesbc0bb772015-06-21 22:55:02 +12005726}
5727
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005728VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format,
5729 VkImageType type, VkImageTiling tiling,
5730 VkImageUsageFlags usage, VkImageCreateFlags flags,
5731 VkImageFormatProperties *pImageFormatProperties) {
5732 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06005733 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Young0f183a82017-02-28 09:58:04 -07005734 if (NULL == icd_term->dispatch.GetPhysicalDeviceImageFormatProperties) {
Mark Youngb6399312017-01-10 14:22:15 -07005735 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5736 "Encountered the vkEnumerateDeviceLayerProperties "
5737 "terminator. This means a layer improperly continued.");
Chia-I Wu17241042015-10-31 00:31:16 +08005738 return VK_ERROR_INITIALIZATION_FAILED;
Mark Youngb6399312017-01-10 14:22:15 -07005739 }
Mark Young0f183a82017-02-28 09:58:04 -07005740 return icd_term->dispatch.GetPhysicalDeviceImageFormatProperties(phys_dev_term->phys_dev, format, type, tiling, usage, flags,
5741 pImageFormatProperties);
Jon Ashburn754864f2015-07-23 18:49:07 -06005742}
5743
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005744VKAPI_ATTR void VKAPI_CALL terminator_GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format,
5745 VkImageType type, VkSampleCountFlagBits samples,
5746 VkImageUsageFlags usage, VkImageTiling tiling,
5747 uint32_t *pNumProperties,
5748 VkSparseImageFormatProperties *pProperties) {
5749 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Young0153e0b2016-11-03 14:27:13 -06005750 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Young0f183a82017-02-28 09:58:04 -07005751 if (NULL != icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties) {
5752 icd_term->dispatch.GetPhysicalDeviceSparseImageFormatProperties(phys_dev_term->phys_dev, format, type, samples, usage,
5753 tiling, pNumProperties, pProperties);
Mark Youngb6399312017-01-10 14:22:15 -07005754 }
Mark Lobodzinski16e8bef2015-07-03 15:58:09 -06005755}
5756
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005757VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice,
5758 const char *pLayerName, uint32_t *pPropertyCount,
5759 VkExtensionProperties *pProperties) {
Mark Young0153e0b2016-11-03 14:27:13 -06005760 struct loader_physical_device_term *phys_dev_term;
Courtney Goeltzenleuchter499b3ba2015-02-27 15:19:33 -07005761
Mark Young3a587792016-08-19 15:25:08 -06005762 struct loader_layer_list implicit_layer_list = {0};
5763 struct loader_extension_list all_exts = {0};
5764 struct loader_extension_list icd_exts = {0};
Jon Ashburn471f44c2016-01-13 12:51:43 -07005765
Jon Ashburndc5d9202016-02-29 13:00:51 -07005766 assert(pLayerName == NULL || strlen(pLayerName) == 0);
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06005767
Mark Young0f183a82017-02-28 09:58:04 -07005768 // Any layer or trampoline wrapping should be removed at this point in time can just cast to the expected
5769 // type for VkPhysicalDevice.
Mark Young0153e0b2016-11-03 14:27:13 -06005770 phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Jon Ashburn471f44c2016-01-13 12:51:43 -07005771
Mark Young0f183a82017-02-28 09:58:04 -07005772 // This case is during the call down the instance chain with pLayerName == NULL
Mark Young0153e0b2016-11-03 14:27:13 -06005773 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Jon Ashburndc5d9202016-02-29 13:00:51 -07005774 uint32_t icd_ext_count = *pPropertyCount;
5775 VkResult res;
Jon Ashburn471f44c2016-01-13 12:51:43 -07005776
Mark Young0f183a82017-02-28 09:58:04 -07005777 // Get the available device extensions
5778 res = icd_term->dispatch.EnumerateDeviceExtensionProperties(phys_dev_term->phys_dev, NULL, &icd_ext_count, pProperties);
Mark Young3a587792016-08-19 15:25:08 -06005779 if (res != VK_SUCCESS) {
5780 goto out;
5781 }
Jon Ashburn23d36b12016-02-02 17:47:28 -07005782
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005783 if (!loader_init_layer_list(icd_term->this_instance, &implicit_layer_list)) {
Mark Young3a587792016-08-19 15:25:08 -06005784 res = VK_ERROR_OUT_OF_HOST_MEMORY;
5785 goto out;
5786 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07005787
Mark Young283fe1c2017-05-04 12:16:35 -06005788 loader_add_implicit_layers(icd_term->this_instance, &implicit_layer_list, NULL, &icd_term->this_instance->instance_layer_list);
Mark Young0f183a82017-02-28 09:58:04 -07005789 // We need to determine which implicit layers are active, and then add their extensions. This can't be cached as
5790 // it depends on results of environment variables (which can change).
Jon Ashburndc5d9202016-02-29 13:00:51 -07005791 if (pProperties != NULL) {
Mark Young0f183a82017-02-28 09:58:04 -07005792 // Initialize dev_extension list within the physicalDevice object
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005793 res = loader_init_device_extensions(icd_term->this_instance, phys_dev_term, icd_ext_count, pProperties, &icd_exts);
Mark Young3a587792016-08-19 15:25:08 -06005794 if (res != VK_SUCCESS) {
5795 goto out;
5796 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07005797
Mark Young0f183a82017-02-28 09:58:04 -07005798 // We need to determine which implicit layers are active, and then add their extensions. This can't be cached as
5799 // it depends on results of environment variables (which can change).
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005800 res = loader_add_to_ext_list(icd_term->this_instance, &all_exts, icd_exts.count, icd_exts.list);
Mark Young3a587792016-08-19 15:25:08 -06005801 if (res != VK_SUCCESS) {
5802 goto out;
5803 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07005804
Mark Young283fe1c2017-05-04 12:16:35 -06005805 loader_add_implicit_layers(icd_term->this_instance, &implicit_layer_list, NULL,
5806 &icd_term->this_instance->instance_layer_list);
Jon Ashburn471f44c2016-01-13 12:51:43 -07005807
Jon Ashburndc5d9202016-02-29 13:00:51 -07005808 for (uint32_t i = 0; i < implicit_layer_list.count; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005809 for (uint32_t j = 0; j < implicit_layer_list.list[i].device_extension_list.count; j++) {
5810 res = loader_add_to_ext_list(icd_term->this_instance, &all_exts, 1,
5811 &implicit_layer_list.list[i].device_extension_list.list[j].props);
Mark Young3a587792016-08-19 15:25:08 -06005812 if (res != VK_SUCCESS) {
5813 goto out;
5814 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07005815 }
Jon Ashburn471f44c2016-01-13 12:51:43 -07005816 }
Jon Ashburndc5d9202016-02-29 13:00:51 -07005817 uint32_t capacity = *pPropertyCount;
5818 VkExtensionProperties *props = pProperties;
Jon Ashburn471f44c2016-01-13 12:51:43 -07005819
Jon Ashburndc5d9202016-02-29 13:00:51 -07005820 for (uint32_t i = 0; i < all_exts.count && i < capacity; i++) {
5821 props[i] = all_exts.list[i];
5822 }
Mark Young0f183a82017-02-28 09:58:04 -07005823
5824 // Wasn't enough space for the extensions, we did partial copy now return VK_INCOMPLETE
Jon Ashburndc5d9202016-02-29 13:00:51 -07005825 if (capacity < all_exts.count) {
5826 res = VK_INCOMPLETE;
5827 } else {
5828 *pPropertyCount = all_exts.count;
5829 }
Jon Ashburndc5d9202016-02-29 13:00:51 -07005830 } else {
Mark Young0f183a82017-02-28 09:58:04 -07005831 // Just return the count; need to add in the count of implicit layer extensions
5832 // don't worry about duplicates being added in the count
Jon Ashburndc5d9202016-02-29 13:00:51 -07005833 *pPropertyCount = icd_ext_count;
5834
5835 for (uint32_t i = 0; i < implicit_layer_list.count; i++) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005836 *pPropertyCount += implicit_layer_list.list[i].device_extension_list.count;
Jon Ashburndc5d9202016-02-29 13:00:51 -07005837 }
5838 res = VK_SUCCESS;
Jon Ashburnb82c1852015-08-11 14:49:54 -06005839 }
Jon Ashburndc5d9202016-02-29 13:00:51 -07005840
Mark Young3a587792016-08-19 15:25:08 -06005841out:
5842
5843 if (NULL != implicit_layer_list.list) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005844 loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&implicit_layer_list);
Mark Young3a587792016-08-19 15:25:08 -06005845 }
5846 if (NULL != all_exts.list) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005847 loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&all_exts);
Mark Young3a587792016-08-19 15:25:08 -06005848 }
5849 if (NULL != icd_exts.list) {
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005850 loader_destroy_generic_list(icd_term->this_instance, (struct loader_generic_list *)&icd_exts);
Mark Young3a587792016-08-19 15:25:08 -06005851 }
5852
Jon Ashburndc5d9202016-02-29 13:00:51 -07005853 return res;
Courtney Goeltzenleuchter110fdf92015-06-29 15:39:26 -06005854}
5855
Mark Lobodzinski729a8d32017-01-26 12:16:30 -07005856VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
5857 VkLayerProperties *pProperties) {
5858 struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
Mark Youngb6399312017-01-10 14:22:15 -07005859 struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
Mark Lobodzinski64318ba2017-01-26 13:34:13 -07005860 loader_log(icd_term->this_instance, VK_DEBUG_REPORT_ERROR_BIT_EXT, 0,
5861 "Encountered the vkEnumerateDeviceLayerProperties "
5862 "terminator. This means a layer improperly continued.");
Mark Youngb6399312017-01-10 14:22:15 -07005863 // Should never get here this call isn't dispatched down the chain
Jon Ashburndc5d9202016-02-29 13:00:51 -07005864 return VK_ERROR_INITIALIZATION_FAILED;
Jon Ashburn95a77ba2015-05-15 15:09:35 -06005865}
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005866
Jon Ashburnf2b4e382016-02-10 20:50:19 -07005867VkStringErrorFlags vk_string_validate(const int max_length, const char *utf8) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005868 VkStringErrorFlags result = VK_STRING_ERROR_NONE;
Karl Schultz2558bd32016-02-24 14:39:39 -07005869 int num_char_bytes = 0;
Jon Ashburnf2b4e382016-02-10 20:50:19 -07005870 int i, j;
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005871
Courtney Goeltzenleuchter7a3486d2016-12-21 16:24:34 -07005872 for (i = 0; i <= max_length; i++) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005873 if (utf8[i] == 0) {
5874 break;
Courtney Goeltzenleuchter7a3486d2016-12-21 16:24:34 -07005875 } else if (i == max_length) {
5876 result |= VK_STRING_ERROR_LENGTH;
5877 break;
Mark Lobodzinski36b4de22016-02-12 11:30:14 -07005878 } else if ((utf8[i] >= 0x20) && (utf8[i] < 0x7f)) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005879 num_char_bytes = 0;
Jon Ashburnf2b4e382016-02-10 20:50:19 -07005880 } else if ((utf8[i] & UTF8_ONE_BYTE_MASK) == UTF8_ONE_BYTE_CODE) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005881 num_char_bytes = 1;
Jon Ashburnf2b4e382016-02-10 20:50:19 -07005882 } else if ((utf8[i] & UTF8_TWO_BYTE_MASK) == UTF8_TWO_BYTE_CODE) {
Mark Lobodzinskie9f09ef2016-02-02 18:53:34 -07005883 num_char_bytes = 2;
5884 } else if ((utf8[i] & UTF8_THREE_BYTE_MASK) == UTF8_THREE_BYTE_CODE) {
5885 num_char_bytes = 3;
5886 } else {
5887 result = VK_STRING_ERROR_BAD_DATA;
5888 }
5889
5890 // Validate the following num_char_bytes of data
5891 for (j = 0; (j < num_char_bytes) && (i < max_length); j++) {
5892 if (++i == max_length) {
5893 result |= VK_STRING_ERROR_LENGTH;
5894 break;
5895 }
5896 if ((utf8[i] & UTF8_DATA_BYTE_MASK) != UTF8_DATA_BYTE_CODE) {
5897 result |= VK_STRING_ERROR_BAD_DATA;
5898 }
5899 }
5900 }
5901 return result;
5902}
Lenny Komow3cf3ac72017-12-19 16:38:37 -07005903
5904VKAPI_ATTR VkResult VKAPI_CALL
5905terminator_EnumerateInstanceExtensionProperties(const VkEnumerateInstanceExtensionPropertiesChain *chain, const char *pLayerName,
5906 uint32_t *pPropertyCount, VkExtensionProperties *pProperties) {
5907 struct loader_extension_list *global_ext_list = NULL;
5908 struct loader_layer_list instance_layers;
5909 struct loader_extension_list local_ext_list;
5910 struct loader_icd_tramp_list icd_tramp_list;
5911 uint32_t copy_size;
5912 VkResult res = VK_SUCCESS;
5913
5914 // tls_instance = NULL;
5915 memset(&local_ext_list, 0, sizeof(local_ext_list));
5916 memset(&instance_layers, 0, sizeof(instance_layers));
Lenny Komow3cf3ac72017-12-19 16:38:37 -07005917
5918 // Get layer libraries if needed
5919 if (pLayerName && strlen(pLayerName) != 0) {
5920 if (vk_string_validate(MaxLoaderStringLength, pLayerName) != VK_STRING_ERROR_NONE) {
5921 assert(VK_FALSE &&
5922 "vkEnumerateInstanceExtensionProperties: "
5923 "pLayerName is too long or is badly formed");
5924 res = VK_ERROR_EXTENSION_NOT_PRESENT;
5925 goto out;
5926 }
5927
5928 loader_layer_scan(NULL, &instance_layers);
5929 for (uint32_t i = 0; i < instance_layers.count; i++) {
5930 struct loader_layer_properties *props = &instance_layers.list[i];
5931 if (strcmp(props->info.layerName, pLayerName) == 0) {
5932 global_ext_list = &props->instance_extension_list;
5933 break;
5934 }
5935 }
5936 } else {
5937 // Scan/discover all ICD libraries
5938 memset(&icd_tramp_list, 0, sizeof(icd_tramp_list));
5939 res = loader_icd_scan(NULL, &icd_tramp_list);
5940 if (VK_SUCCESS != res) {
5941 goto out;
5942 }
5943 // Get extensions from all ICD's, merge so no duplicates
5944 res = loader_get_icd_loader_instance_extensions(NULL, &icd_tramp_list, &local_ext_list);
5945 if (VK_SUCCESS != res) {
5946 goto out;
5947 }
5948 loader_scanned_icd_clear(NULL, &icd_tramp_list);
5949
5950 // Append enabled implicit layers.
5951 loader_implicit_layer_scan(NULL, &instance_layers);
5952 for (uint32_t i = 0; i < instance_layers.count; i++) {
5953 if (!loader_is_implicit_layer_enabled(NULL, &instance_layers.list[i])) {
5954 continue;
5955 }
5956 struct loader_extension_list *ext_list = &instance_layers.list[i].instance_extension_list;
5957 loader_add_to_ext_list(NULL, &local_ext_list, ext_list->count, ext_list->list);
5958 }
5959
5960 global_ext_list = &local_ext_list;
5961 }
5962
5963 if (global_ext_list == NULL) {
5964 res = VK_ERROR_LAYER_NOT_PRESENT;
5965 goto out;
5966 }
5967
5968 if (pProperties == NULL) {
5969 *pPropertyCount = global_ext_list->count;
5970 goto out;
5971 }
5972
5973 copy_size = *pPropertyCount < global_ext_list->count ? *pPropertyCount : global_ext_list->count;
5974 for (uint32_t i = 0; i < copy_size; i++) {
5975 memcpy(&pProperties[i], &global_ext_list->list[i], sizeof(VkExtensionProperties));
5976 }
5977 *pPropertyCount = copy_size;
5978
5979 if (copy_size < global_ext_list->count) {
5980 res = VK_INCOMPLETE;
5981 goto out;
5982 }
5983
5984out:
5985
5986 loader_destroy_generic_list(NULL, (struct loader_generic_list *)&local_ext_list);
5987 loader_delete_layer_properties(NULL, &instance_layers);
5988 return res;
5989}
5990
5991VKAPI_ATTR VkResult VKAPI_CALL terminator_EnumerateInstanceLayerProperties(const VkEnumerateInstanceLayerPropertiesChain *chain,
5992 uint32_t *pPropertyCount,
5993 VkLayerProperties *pProperties) {
5994 VkResult result = VK_SUCCESS;
5995 struct loader_layer_list instance_layer_list;
5996 tls_instance = NULL;
5997
Lenny Komow3cf3ac72017-12-19 16:38:37 -07005998 uint32_t copy_size;
5999
6000 // Get layer libraries
6001 memset(&instance_layer_list, 0, sizeof(instance_layer_list));
6002 loader_layer_scan(NULL, &instance_layer_list);
6003
6004 if (pProperties == NULL) {
6005 *pPropertyCount = instance_layer_list.count;
6006 goto out;
6007 }
6008
6009 copy_size = (*pPropertyCount < instance_layer_list.count) ? *pPropertyCount : instance_layer_list.count;
6010 for (uint32_t i = 0; i < copy_size; i++) {
6011 memcpy(&pProperties[i], &instance_layer_list.list[i].info, sizeof(VkLayerProperties));
6012 }
6013
6014 *pPropertyCount = copy_size;
6015
6016 if (copy_size < instance_layer_list.count) {
6017 result = VK_INCOMPLETE;
6018 goto out;
6019 }
6020
6021out:
6022
6023 loader_delete_layer_properties(NULL, &instance_layer_list);
6024 return result;
6025}
Lenny Komow158e9d92018-01-15 15:43:36 -07006026
6027#if defined(_WIN32)
6028BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved) {
6029 switch (reason) {
6030 case DLL_PROCESS_ATTACH:
6031 loader_initialize();
6032 break;
6033 case DLL_PROCESS_DETACH:
6034 if (NULL == reserved) {
6035 loader_release();
6036 }
6037 break;
6038 default:
6039 // Do nothing
6040 break;
6041 }
6042 return TRUE;
6043}
6044#else
6045__attribute__((constructor)) void loader_init_library() { loader_initialize(); }
6046
6047__attribute__((destructor)) void loader_free_library() { loader_release(); }
6048#endif